标签 PHP 下的文章

使用PHP的ProtoBuf扩展

扩展使用的是allegro/php-protobuf,地址见github.

  1. 下载源码。
  2. 编译安装。

     /usr/local/php/bin/phpize
     ./configure --with-php-config=/usr/local/php/bin/php-config
     make && make install
  3. 执行下面的命令,生成对应的PHP类文件。
    /usr/local/php/bin/php ./protoc-gen-php.php ./qcloud_notify.protofg

在第三步生成文件时,遇到下面的错误。

  1. Unable to find the protoc command.的错误。

    解决办法:

     1. 下载protobuf源码。(allegro/php-protobuf要求protobuf版本最低为2.6,我下载的2.6版本)
     2. 编译安装。
     sh ./autogen.sh
     ./configure
     make && make install
  2. 提示ERROR: protoc exited with an exit status when executed with
    解决办法:
    编辑src/Allegro/Protobuf/Compiler/Compiler.php文件.
    找到148行if ($return !== 0) {,改为if ($return != 0) {即可。

PHP跟JS位移操作的区别

JS代码

console.log(193449512 << 5);

输出结果

JS执行结果

PHP代码

echo 193449512 << 5;echo "\n";

输出结果

PHP执行结果

为什么结果会不一样呢?首先怀疑的是PHP的位数是不是32位导致的,看了下PHP信息排除了。

搜索了一番信息,才找到原因。

js 在进行二进制运算时,使用 32 位二进制整数。

而我本机的PHP是64位,所以导致两种运算的结果不一致。

解决方法:

$a = 193449512;
$bin = decbin($a);
$bin = str_pad($bin, 32, '0', STR_PAD_LEFT);

echo bindec(str_pad(substr($bin, 5), 32, '0', STR_PAD_RIGHT));
echo "\n";

// output 1895417088

重新编译PHP7支持PostgreSQL

安装PostgreSQL

apt-get install postgresql postgresql-contrib postgresql-server-dev-9.3 libpq-dev

编译PHP增加PostgreSQL扩展

  1. 先看下之前编译的configure命令。

        php -i | grep configure
  2. 配置编译参数。在上面的configure命令后面加上--with-pdo-pgsql选项。

    ./configure --prefix=/usr/local/php7 --exec-prefix=/usr/local/php7 --bindir=/usr/local/php7/bin --sbindir=/usr/local/php7/sbin --includedir=/usr/local/php7/include --libdir=/usr/local/php7/lib/php --mandir=/usr/local/php7/php/man --with-config-file-path=/usr/local/php7/etc --with-mysql-sock=/var/run/mysql/mysql.sock --with-mcrypt=/usr/include --with-mhash --with-openssl --with-mysqli=shared,mysqlnd --with-pdo-mysql=shared,mysqlnd --with-gd --with-iconv --with-zlib --enable-zip --enable-inline-optimization --disable-debug --disable-rpath --enable-shared --enable-xml --enable-bcmath --enable-shmop --enable-sysvsem --enable-mbregex --enable-mbstring --enable-ftp --enable-gd-native-ttf --enable-pcntl --enable-sockets --with-xmlrpc --enable-soap --without-pear --with-gettext --enable-session --with-curl --with-jpeg-dir --with-freetype-dir --enable-opcache --enable-fpm --with-fpm-user=www --with-fpm-group=www --without-gdbm --disable-fileinfo --with-pdo-pgsql=/usr/lib/postgresql/9.3
  3. 开始编译和安装。

    make && make install
  4. 安装完成后,检查PHP扩展。

    php -m | grep pdo_pgsql

    输出里有pdo_pgsql,就表示PostgreSQL的扩展ok了。

使用SimpleXML输出rss内容

代码说话。

    header('Content-Type: application/xml', true); //set document header content type to be XML

    $rss = new SimpleXMLExtendedModel('<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"></rss>');
    $rss->addAttribute('version', '2.0');

    $channel = $rss->addChild('channel'); //add channel node

    $atom = $channel->addChild('atom:atom:link');
    $atom->addAttribute('href', '你的RSS链接');
    $atom->addAttribute('rel', 'self');
    $atom->addAttribute('type', 'application/rss+xml');

    $channel->addChild('title', 'RSS标题');
    $description = $channel->addChild('description', 'RSS描述');
    $link = $channel->addChild('link', '你的RSS链接');
    $language = $channel->addChild('language', 'zh-Hans');

    $lastBuildDate = new DateTime($date . ' 02:00:00');
    $channel->addChild('lastBuildDate', $lastBuildDate->format(DateTime::RSS));
    $channel->addChild('pubDate', $lastBuildDate->format(DateTime::RSS));

    $generator = $channel->addChild('generator', '创建者');

    // $result 为数据库查询结果
    foreach ($result as $data) {

        $item = $channel->addChild('item');
        $item->addChild('title', 'item的标题');
        $link = $item->addChild('link', 'item的链接');
        $guid = $item->addChild('guid', 'item的链接');
        $guid->addAttribute('isPermaLink', 'true');

        $item->addChild('description')->addCData('item的描述');

        $item = $item->addChild('pubDate', $lastBuildDate->format(DateTime::RSS)); //add pubDate node
    }

    echo $rss->asXML();

期间遇到CDATA的问题,解决方案新增一个扩展类。

class SimpleXMLExtendedModel extends SimpleXMLElement {

    public function addCData($cdata_text) {

        $node= dom_import_simplexml($this);
        $no = $node->ownerDocument;
        $node->appendChild($no->createCDATASection($cdata_text));

        return true;
    }
}

PHP进行tcp连接

业务里用到tcp跟后端服务进行通信。

  1. 原生PHP的写法。

        $host = '服务端IP';
        $port = 端口号;
        $timeout = 5;
    
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if (socket_connect($socket, $host, $port) === false) { // 创建连接
            socket_close($socket);
            $message = 'create socket error';
            throw new Exception($message, socket_last_error());
        }   
    
        if (socket_write($socket, $buffer) === false) { // 发包
            socket_close($socket);
            $message = sprintf("write socket error:%s", socket_strerror(socket_last_error()));
            throw new Exception($message, socket_last_error());
        }   
    
        socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout);
    
        $rspBuffer = socket_read($socket, 65536); // 接收回包
    
        socket_close($socket);
  2. 使用swoole的写法。

        $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
        $ret = $client->connect('服务端IP', 端口号, 0.5, 0);  // 创建连接
        if (!$ret) {
            throw new Exception('connect error', $client->errCode);
        }   
    
        $client->send($buffer); // 发包
    
        $rspBuffer = $client->recv(); // 接收回包

一目了然,使用swoole的写法更加清楚明了。