PHP使用protobuf

服务器环境Ubuntu 18.04.5 LTS
PHP7.2.24

安装protoc

1.获取v3.13.0.1(截止2020.10.14)
wget https://codeload.github.com/protocolbuffers/protobuf/tar.gz/v3.13.0.1
2.解压
tar zxvf v3.13.0.1 
cd protobuf-3.13.0.1

1.生成 configure 脚本;
./autogen.sh
2.编译安装
./configure --prefix=/usr/local/protobuf
make && make install
3.设置全局
export PATH=/usr/local/protobuf/bin:$PATH
4.检查安装成功
protoc  --version
出现`libprotoc 3.13.0`即安装成功

安装php-protobuf拓展

pecl install protobuf

接下来,将
`extension=protobuf.so`添加到 `php.ini` 文件(例如 `/etc/php/7.2/fpm/php.ini`)中。

查看php.ini位置
1.cli命令行 php --ini
2.phpinfo();
3.ps -ef | grep php

在项目根目录

protoc --php_out="protobuf/compile" "protobuf/protos/DmpDataProto.proto"

生成的结构

├── compile
│   ├── GPBMetadata
│   │   └── Protobuf
│   │       └── Protos
│   │           └── DmpDataProto.php
│   └── Toutiao
│       └── Dmp
│           ├── DmpData.php
│           ├── IdItem_DataType.php
│           └── IdItem.php
└── protos
    └── DmpDataProto.proto

composer

composer require  google/protobuf:^3.3

composer.json配置

"autoload": {
        "classmap": [
            "database/seeds",
            "database/factories"
        ],
        "psr-4": {
            "App\\": "app/",
            +"Toutiao\\":"protobuf/compile/Toutiao",
            +"GPBMetadata\\":"protobuf/compile/GPBMetadata/Protobuf/Protos"
        }
    },

生成优化的自动加载文件

composer dump-autoload

使用

//获取序列化的一行
public function decodeOneLine($line)
{
    $idItem = new \Toutiao\Dmp\IdItem();
    $idItem->setDataType(\Toutiao\Dmp\IdItem_DataType::IMEI);
    $idItem->setId(strtolower($line));
    $idItem->setTags('IMEI');
    $binaryString = $idItem->serializeToString();
    return $binaryString;
}
//获取反序列化的一行
public function decodeOneLine($line)
{
    $item = new \Toutiao\Dmp\IdItem();
    $item->mergeFromString($line);
    return $item->getId();
}

主要为为了上传头条dmp包,但是头条是protobuf2,emmm明天再看吧
未完待续

ok
继续分享
我在百度Google搜了不少文章看,其中有篇博文写道:
博文地址

因为版本不兼容的问题,我们用version3 序列化的文件,version2 是解不出来的,通过实验发现每次都是少了一个前缀,因此我在下面的代码手动带上了这个前缀,头条才让我过。如果你不需要可以去掉。
// 手动拼前缀,不需要可以去掉
$prefix = "\n\x19\x10\x00";
$binaryString = $prefix . $binaryString;

我对比了下version3和2的差异
(重装protobuf2的过程与上方比较类似,此处不赘述了)
version3的结果:

root@ubuntu:# hexdump -C test.bin
00000000  1a 0f 38 36 30 37 31 34  30 34 31 39 31 35 36 30  |..86071404191560|
00000010  39 22 04 49 4d 45 49                              |9".IMEI|
00000017

version2的结果:

root@ubuntu:# hexdump -C testV2.bin
00000000  0a 19 10 00 1a 0f 38 36  30 37 31 34 30 34 31 39  |......8607140419|
00000010  31 35 36 30 39 22 04 49  4d 45 49                 |15609".IMEI|
0000001b

果然如博主所言,多了如下这四个字符

Hex(16进制) Bin(二进制) 缩写/字符 解释
0x0a 0000 1010 LF (NL line feed, new line) 换行键
0x19 0001 1001 EM (end of medium) 媒介结束
0x10 0001 0000 DLE (data link escape) 数据链路转义
0x00 0000 0000 NUL(null) 空字符

~~至此,完成。
使用V3版本转化成V2的完整代码如下:~~

ok,实际使用过程中呢,发现了新的问题,就是IMEI类型这么搞是没有问题的,但是IDFA/IMEI_MD5,反正只要不是IMEI,都是有问题的,需要拼接不同的前缀,因此,我觉得这样子是不靠谱的,虽然PHP可以序列化,以及反序列化,但是V3和V2序列化后,头条那边都是不认的,是反序列化失败,然后提工单回复又很慢,最后,只好使用pytohon序列化,写个脚本,PHP去调用这个脚本,然后头条成功接受(因为头条后端这块就是py吧)
这里贴一下py脚本代码,hex打印的部分也留着了,这个是当时对比V3/V2 以及PHP生成的二进制做对比用的

from __future__ import print_function
import DmpDataProtoV2_pb2
import os,sys
import time
import base64

dmp_data  = DmpDataProtoV2_pb2.DmpData()
id_item1 = dmp_data.idList.add()
#dtype = 'IDFA'
dtype = sys.argv[1]
dev_id =  sys.argv[2]
id_item1.dataType = getattr(DmpDataProtoV2_pb2.IdItem,dtype)
#id_item1.dataType = DmpDataProtoV2_pb2.IdItem.IDFA
id_item1.id = str.lower(dev_id)
id_item1.tags.append(dtype)
# id_item1.timestamp = int(time.time())

binary_string  = dmp_data.SerializeToString()
#print(binary_string)
#print "nHex = %r" %(binary_string)
#t = bin(binary_string)
s = base64.b64encode(binary_string)

print (s,end='')
//获取序列化的一行
public function decodeOneLine($line, $v2 = false)
{
    $idItem = new \Toutiao\Dmp\IdItem();
    $idItem->setDataType(\Toutiao\Dmp\IdItem_DataType::IMEI);
    $idItem->setId(strtolower($line));
    $idItem->setTags('IMEI');
    $binaryString = $idItem->serializeToString();
    if ($v2) {
        // 手动拼前缀,转化为V2,不需要可以不传V2参数
        $prefix = "\n\x19\x10\x00";
        $binaryString = $prefix . $binaryString;
    }
    return $binaryString;
}

总结:个人理解还是很浅薄的,只管感觉protobuf像是将key-value格式的json,去掉了key,只传输数据,而key在数据收发端约定好(当然protobuf还有其他的优化)。

最后,原创不易,转载请注明出处啊~

你可能感兴趣的:(php,protobuf)