【PHP】httpsqs_client PHP开源代码修正版

在httpsqs作者博客上可以找到用于在php中操作httpsqs队列的客户端开源代码,实际使用中发现这个客户端代码并不严谨,对于socket stream读写处理的一些异常情况的处理考虑不够,实际中该代码可能只适合作为“短连接"来使用,如果是对于需要”长连接“并考虑处理性能的场合,这个代码需要作一些完善。

以下是在原httpsqs_client.php基础上作一些简单修改后的结果,供参考(其中socket这块,感觉php的stream对socket的处理可能不是很好,很选项不能设置,socket的错误码也不能直接获取到,有时间考虑切换到使用socket扩展库来实现):

<?php
/*
----------------------------------------------------------------------------------------------------------------
HTTP Simple Queue Service - httpsqs client class for PHP v1.7.1


Author: Zhang Yan (http://blog.s135.com), E-mail: net@s135.com
This is free software, and you are welcome to modify and redistribute it under the New BSD License
----------------------------------------------------------------------------------------------------------------
Useage:
<?php
include_once("httpsqs_client.php");
$httpsqs = new httpsqs($httpsqs_host, $httpsqs_port, $httpsqs_auth, $httpsqs_charset);
$result = $httpsqs->put($queue_name, $queue_data); //1. PUT text message into a queue. If PUT successful, return boolean: true. If an error occurs, return boolean: false. If queue full, return text: HTTPSQS_PUT_END
$result = $httpsqs->get($queue_name); //2. GET text message from a queue. Return the queue contents. If an error occurs, return boolean: false. If there is no unread queue message, return text: HTTPSQS_GET_END
$result = $httpsqs->gets($queue_name); //3. GET text message and pos from a queue. Return example: array("pos" => 7, "data" => "text message"). If an error occurs, return boolean: false. If there is no unread queue message, return: array("pos" => 0, "data" => "HTTPSQS_GET_END")
$result = $httpsqs->status($queue_name); //4. View queue status
$result = $httpsqs->status_json($queue_name); //5. View queue status in json. Return example: {"name":"queue_name","maxqueue":5000000,"putpos":130,"putlap":1,"getpos":120,"getlap":1,"unread":10}
$result = $httpsqs->view($queue_name, $queue_pos); //6. View the contents of the specified queue pos (id). Return the contents of the specified queue pos.
$result = $httpsqs->reset($queue_name); //7. Reset the queue. If reset successful, return boolean: true. If an error occurs, return boolean: false
$result = $httpsqs->maxqueue($queue_name, $num); //8. Change the maximum queue length of per-queue. If change the maximum queue length successful, return boolean: true. If  it be cancelled, return boolean: false
$result = $httpsqs->synctime($num); //9. Change the interval to sync updated contents to the disk. If change the interval successful, return boolean: true. If  it be cancelled, return boolean: false
?>
----------------------------------------------------------------------------------------------------------------
*/


class httpsqs_client
{
const KEEPALIVE_TIME = 60;
const HTTPSQS_TIMEOUT = 10;// httpsqs读写超时时间
        public $httpsqs_host;
        public $httpsqs_port;
        public $httpsqs_auth;
        public $httpsqs_charset;
        /* BEGIN: Added by zhongjun 20130515 */
        public $get_result = null;
        /* END: Added by zhongjun 20130515 */
        
        public function __construct($host='127.0.0.1', $port=1218, $auth='', $charset='utf-8') {
                $this->httpsqs_host = $host;
                $this->httpsqs_port = $port;
                $this->httpsqs_auth = $auth;
                $this->httpsqs_charset = $charset;
                return true;
        }


  public function &http_get($query)
    {
    static $socket = NULL;
static $last_time = 0;


// reset $get_result
$this->get_result = null;
$this->get_result = array();

if ($last_time == 0)
{
$last_time = time();
}

$now = time();

if ($now >= $last_time + self::KEEPALIVE_TIME)
{
/* BEGIN: Modified by zhongjun 20130504 */
/* 只是将$socket重置,应该存在发生资源泄漏的可能 */
if (isset($socket))
{
fclose($socket);
$socket = NULL;
}
/* BEGIN: Modified by zhongjun 20130504 */
}

if (is_null($socket))
{
$socket = fsockopen($this->httpsqs_host, $this->httpsqs_port, $errno, $errstr, 1);

if (!$socket)
{
logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "fsockopen failed in http_get");
   
$this->get_result = false;
return $this->get_result;
}

stream_set_timeout($socket, self::HTTPSQS_TIMEOUT);
}

// 组装get报文
   $out = "GET ${query} HTTP/1.1\r\n";
   $out .= "Host: ${host}\r\n";
   $out .= "Connection: Keep-Alive\r\n";
   $out .= "Keep-Alive:".self::KEEPALIVE_TIME."\r\n";
   $out .= "\r\n";
   
   // 发送get请求
   $ret = fwrite($socket, $out);
   if ((false === $ret) || ($ret != strlen($out)))
   {
    // 发送get请求出错,或超时
    logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "write GET request failed in http_get");
   
    fclose($socket);
    $socket = NULL;   
   
    $this->get_result = false;
    return $this->get_result;
   }
   
   // 当请求发送成功时,更新$last_time
   $last_time = $now;
   
   $line = trim(fgets($socket));
   $header .= $line;
   list($proto, $rcode, $result) = explode(" ", $line);
   $len = -1;
   
   while (($line = trim(fgets($socket))) != "")
   {
       $header .= $line."\n";
       if (strstr($line, "Content-Length:"))
       {
           list($cl, $len) = explode(" ", $line); 
       }
       if (strstr($line, "Pos:"))
       {
           list($pos_key, $pos_value) = explode(" ", $line);
       }                   
       if (strstr($line, "Connection: close"))
       {
           $close = true;
       }
   }
   
   if ($len < 0)
   {
// 接收应答消息的http头失败
    logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "read http header failed in http_get");
   
    fclose($socket);
    $socket = NULL;
   
    $this->get_result = false;
    return $this->get_result;
   }
        
   // 接收消息体,最多尝试3次
        $body = fread($socket, $len);
        
        $fread_times = 0;
        while(strlen($body) < $len)
        {
        if ($fread_times > 1)
        {
        break;
        }
       
            $body1 = fread($socket, $len - strlen($body));
            
            $body .= $body1;
            unset($body1);                    
            
            $fread_times++;
        }
        
        if (strlen($body) < $len)
        {
        // fread出错或超时
        logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "read http body failed in http_get, the received body:\n$body");
       
        fclose($socket);
        $socket = NULL;
       
        $this->get_result = false;
        return $this->get_result;
        }   
        
        if ($close)
        {
        logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "http_get: the CONNECTION option is CLOSE in http header");
        fclose($socket);
        $socket = NULL;
        }
        
        $this->get_result["pos"] = (int)$pos_value;
        $this->get_result["data"] = $body;
        
        return $this->get_result;
    }
    




    public function http_post($query, &$body)
    {
    static $socket = NULL;
    static $last_time = 0;
   
    if ($last_time == 0)
    {
    $last_time = time();
    }
   
    $now = time();
   
    if ($now >= $last_time + self::KEEPALIVE_TIME)
    {
    /* BEGIN: Modified by zhongjun 20130504 */
    /* 只是将$socket重置,应该存在发生资源泄漏的可能 */
    if (isset($socket))
    {
    fclose($socket);
    $socket = NULL;
    }
    /* BEGIN: Modified by zhongjun 20130504 */
    }
   
    if (is_null($socket))
    {
    $socket = fsockopen($this->httpsqs_host, $this->httpsqs_port, $errno, $errstr, 1);
   
    if (!$socket)
    {
    logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "fsockopen failed in http_get");
    return false;
    }
   
    // 将socket读写超时设为10秒
    stream_set_timeout($socket, self::HTTPSQS_TIMEOUT);
    }

// 组装put消息
        $out = "POST ${query} HTTP/1.1\r\n";
        $out .= "Host: ${host}\r\n";
        $out .= "Content-Length: " . strlen($body) . "\r\n";
        $out .= "Connection: Keep-Alive\r\n";
$out .= "Keep-Alive:".self::KEEPALIVE_TIME."\r\n";
        $out .= "\r\n";
        $out .= $body;
        
// 发送put命令
        $ret = fwrite($socket, $out);
        if ((false === $ret) || ($ret != strlen($out)))
        {
        // 发送get请求出错,或超时
        logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "write GET request failed in http_post");
        
        fclose($socket);
        $socket = NULL;
        
        return false;
        }


        // 当请求发送成功时,更新$last_time
        $last_time = $now;
        
        $line = trim(fgets($socket));
        $header .= $line;
        list($proto, $rcode, $result) = explode(" ", $line);
        
        $len = -1;        
        while (($line = trim(fgets($socket))) != "")
        {
            $header .= $line;
            if (strstr($line, "Content-Length:"))
            {
                list($cl, $len) = explode(" ", $line);
            }
            if (strstr($line, "Pos:"))
            {
                list($pos_key, $pos_value) = explode(" ", $line);
            }                   
            if (strstr($line, "Connection: close"))
            {
                $close = true;
            }
        }
        
        if ($len < 0)
        {
            // 接收应答消息的http头失败
    logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "read http header failed in http_post");
   
    fclose($socket);
    $socket = NULL;
   
    return false;
        }
        
        $recv_body = @fread($socket, $len);
        
        if (strlen($recv_body) < $len)
        {
        // fread出错或超时
        logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "read http body failed in http_post, the received body:\n$recv_body");
         
        fclose($socket);
        $socket = NULL;
         
        return false;
        }
        
        if ($close)
        {
        logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "http_post: the CONNECTION option is CLOSE in http header");
        fclose($socket);
        $socket = NULL;
        }


        $result_array["pos"] = (int)$pos_value;
        $result_array["data"] = $recv_body;
        
        return $result_array;
    }
        
   
    
    public function put(&$queue_name, &$queue_data)
    {
    $tPostBegin = time();
        $result = $this->http_post("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=put", $queue_data);
        $tPostEnd = time();
        
        $tTime = $tPostEnd - $tPostBegin;
        if ($tTime > self::HTTPSQS_TIMEOUT)
        {
        logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "httpsqs put takes $tTime seconds, and result is :".$result["data"]);
        }
        
        if ($result["data"] == "HTTPSQS_PUT_OK") 
        {
            return true;
        } 
        else if ($result["data"] == "HTTPSQS_PUT_END") 
        {
            return $result["data"];
        }


        return false;
    }
    
    public function &get(&$queue_name)
    {
    $tGetBegin = time();
        $result = &$this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=get");
    $tGetEnd = time();
        
        $tTime = $tGetEnd - $tGetBegin;
        if ($tTime > self::HTTPSQS_TIMEOUT)
        {
        logmsg($_SERVER['SCRIPT_FILENAME'], LOGID_DEBUG_LOG, "httpsqs get takes $tTime seconds, and result is :$result");
        }
        
   return $result["data"];
    }
    
     public function get_alive($queue_name)
    {
        $result = $this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=get");
                if ($result == false || $result["data"] == "HTTPSQS_ERROR" || $result["data"] == false) {
                        return false;
                }
      return $result["data"];
 //       return $result;
    }
   
        
    public function gets($queue_name)
    {
        $result = $this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=get");
                if ($result == false || $result["data"] == "HTTPSQS_ERROR" || $result["data"] == false) {
                        return false;
                }
        return $result;
    }   
        
    public function status($queue_name)
    {
        $result = $this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=status");
                if ($result == false || $result["data"] == "HTTPSQS_ERROR" || $result["data"] == false) {
                        return false;
                }
        return $result["data"];
    }
        
    public function view($queue_name, $queue_pos)
    {
        $result = $this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=view&pos=".$queue_pos);
                if ($result == false || $result["data"] == "HTTPSQS_ERROR" || $result["data"] == false) {
                        return false;
                }
        return $result["data"];
    }
        
    public function reset($queue_name)
    {
        $result = $this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=reset");
                if ($result["data"] == "HTTPSQS_RESET_OK") {
                        return true;
                }
        return false;
    }
        
    public function maxqueue($queue_name, $num)
    {
        $result = $this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=maxqueue&num=".$num);
                if ($result["data"] == "HTTPSQS_MAXQUEUE_OK") {
                        return true;
                }
        return false;
    }
        
    public function status_json($queue_name)
    {
        $result = $this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=".$queue_name."&opt=status_json");
                if ($result == false || $result["data"] == "HTTPSQS_ERROR" || $result["data"] == false) {
                        return false;
                }
        return $result["data"];
    }


    public function synctime($num)
    {
        $result = $this->http_get("/?auth=".$this->httpsqs_auth."&charset=".$this->httpsqs_charset."&name=httpsqs_synctime&opt=synctime&num=".$num);
                if ($result["data"] == "HTTPSQS_SYNCTIME_OK") {
                        return true;
                }
        return false;
    }
}
?>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值