<?php
ini_set('date.timezone','Asia/Shanghai');
ini_set("display_errors","On");
error_reporting(E_ALL);
define('FACESYNC_COMMAND_NONE', 0);
define('FACESYNC_REQUEST_FACE_IDS', 1);
define('FACESYNC_RESPONSE_FACE_IDS', 2);
define('FACESYNC_REQUEST_FACE_FEATURES', 3);
define('FACESYNC_RESPONSE_FACE_FEATURES', 4);
define('FACESYNC_REQUEST_FAREWELL', 5);
define('FACESYNC_RESPONSE_FAREWELL', 6);
/*
注意:
//模擬數(shù)據(jù)庫(kù)存放三個(gè)人的數(shù)據(jù)
$test_feature_datas = array(
//張三
array(
//'u32Flag'=> 0,
'u32CheckSum'=> 0, //下面數(shù)據(jù)的校驗(yàn)碼,主要用來(lái)判斷特征結(jié)構(gòu)是否被更新,可以不計(jì)算
'u64FaceId'=> 11111111, //faceid
'u64PersonId'=> 11111111, //personid
'u32UpdateTime'=> 0, //修改時(shí)間,主要用來(lái)判斷特征結(jié)構(gòu)是否被更新
//'u32FeatureCRC'=> 0, //特征校驗(yàn)碼,可以不計(jì)算
'feature'=> '', //特征向量,填base64解碼后的二進(jìn)制數(shù)據(jù),php的字符串直接可以存放二進(jìn)制(不需要轉(zhuǎn)十六進(jìn)制字符)
'info'=> array(
//'u32Permission'=> 0, //權(quán)限
'szName'=> '張三', //姓名
'szNric'=> '123', //證件
'szCardNum'=> '123', //卡號(hào)
//'u32VaildDateBegin'=> 0, //有效期開(kāi)始時(shí)間
//'u32VaildDateEnd'=> 0, //有效期結(jié)束時(shí)間
//'_reserv'=> '' //保留
)
),
//李四
array(
//'u32Flag'=> 0,
'u32CheckSum'=> 0, //下面數(shù)據(jù)的校驗(yàn)碼,主要用來(lái)判斷特征結(jié)構(gòu)是否被更新,可以不計(jì)算
'u64FaceId'=> 22222222, //faceid
'u64PersonId'=> 22222222, //personid
'u32UpdateTime'=> 0, //修改時(shí)間,主要用來(lái)判斷特征結(jié)構(gòu)是否被更新
//'u32FeatureCRC'=> 0, //特征校驗(yàn)碼,可以不計(jì)算
'feature'=> '', //特征向量,填base64解碼后的二進(jìn)制數(shù)據(jù),php的字符串直接可以存放二進(jìn)制(不需要轉(zhuǎn)十六進(jìn)制字符)
'info'=> array(
//'u32Permission'=> 0, //權(quán)限
'szName'=> '李四', //姓名
'szNric'=> '444', //證件
'szCardNum'=> '444', //卡號(hào)
//'u32VaildDateBegin'=> 0, //有效期開(kāi)始時(shí)間
//'u32VaildDateEnd'=> 0, //有效期結(jié)束時(shí)間
//'_reserv'=> '' //保留
)
),
//陳五
array(
//'u32Flag'=> 0,
'u32CheckSum'=> 0, //下面數(shù)據(jù)的校驗(yàn)碼,主要用來(lái)判斷特征結(jié)構(gòu)是否被更新,可以不計(jì)算
'u64FaceId'=> 33333333, //faceid
'u64PersonId'=> 33333333, //personid
'u32UpdateTime'=> 0, //修改時(shí)間,主要用來(lái)判斷特征結(jié)構(gòu)是否被更新
//'u32FeatureCRC'=> 0, //特征校驗(yàn)碼,可以不計(jì)算
'feature'=> '', //特征向量,填base64解碼后的二進(jìn)制數(shù)據(jù),php的字符串直接可以存放二進(jìn)制(不需要轉(zhuǎn)十六進(jìn)制字符)
'info'=> array(
//'u32Permission'=> 0, //權(quán)限
'szName'=> '陳五', //姓名
'szNric'=> '555', //證件
'szCardNum'=> '555', //卡號(hào)
//'u32VaildDateBegin'=> 0, //有效期開(kāi)始時(shí)間
//'u32VaildDateEnd'=> 0, //有效期結(jié)束時(shí)間
//'_reserv'=> '' //保留
)
)
);
class FaceSyncSDK
{
//CRC32校驗(yàn)算法 (要速度快請(qǐng)改查表法,網(wǎng)上沒(méi)有,我不舍得開(kāi)源)
function CRC32_Calc($buf, $offset, $length, $seed=0xFFFFFFFF)
{
$polynomial = 0x04c11db7;
$crc = $seed;
for ($i = $offset; $i < $offset + $length; $i++) {
$c = ord($buf[$i]);
$crc ^= ($c << 24);
for ($j = 0; $j < 8; $j++) {
if ($crc & 0x80000000) {
$crc = (($crc << 1) & 0xffffffff) ^ $polynomial;
} else {
$crc = ($crc << 1) & 0xffffffff;
}
}
}
return $crc;
}
//FACE_ID_SET_T 轉(zhuǎn) 二進(jìn)制
function pack_FACE_ID_SET_T($arr)
{
$bin = '';
$bin .= pack('Q', $arr['u64FaceId']);
$bin .= pack('L', $arr['u32UpdateTime']);
$bin .= pack('L', $arr['u32CheckSum']);
return $bin;
}
//二進(jìn)制 轉(zhuǎn) FACE_ID_SET_T
function unpack_FACE_ID_SET_T($bin, $offset = 64)
{
$format = 'Qu64FaceId/Lu32UpdateTime/Lu32CheckSum';
return unpack($format, $bin, $offset);
}
//FACE_SYNC_CMD_T 轉(zhuǎn) 二進(jìn)制
function pack_FACE_SYNC_CMD_T($arr)
{
$bin = '';
$bin .= pack('L', isset($arr['checksum']) ? $arr['checksum'] : 0); //構(gòu)造時(shí)可忽略參數(shù)
$bin .= pack('L', $arr['command']); //命令,必要的參數(shù)
$bin .= pack('L', isset($arr['groupnum']) ? $arr['groupnum'] : 0); //構(gòu)造時(shí)可忽略參數(shù)
$bin .= pack('a20', isset($arr['serialnum']) ? $arr['serialnum'] : ''); //構(gòu)造時(shí)可忽略參數(shù)
$bin .= pack('a24', isset($arr['_reserv']) ? $arr['_reserv'] : ''); //構(gòu)造時(shí)可忽略參數(shù)
$bin .= pack('L', isset($arr['itemcount']) ? $arr['itemcount'] : 0); //構(gòu)造時(shí)可忽略參數(shù)
$bin .= pack('L', isset($arr['itemsize']) ? $arr['itemsize'] : 0); //構(gòu)造時(shí)可忽略參數(shù)
return $bin;
}
//二進(jìn)制 轉(zhuǎn) FACE_SYNC_CMD_T
function unpack_FACE_SYNC_CMD_T($bin, $offset = 0)
{
$format = 'Lchecksum/Lcommand/Lgroupnum/a20serialnum/a24_reserv/Litemcount/Litemsize';
return unpack($format, $bin, $offset);
}
//FACE_FEATURE_T 轉(zhuǎn) 二進(jìn)制
function pack_FACE_FEATURE_T($arr)
{
$bin = '';
$bin .= pack('L', isset($arr['u32Flag']) ? $arr['u32Flag'] : 0);
$bin .= pack('L', isset($arr['u32CheckSum']) ? $arr['u32CheckSum'] : 0);
$bin .= pack('Q', $arr['u64FaceId']);
$bin .= pack('Q', $arr['u64PersonId']);
$bin .= pack('L', $arr['u32UpdateTime']);
$bin .= pack('L', isset($arr['u32FeatureCRC']) ? $arr['u32FeatureCRC'] : 0);
$bin .= pack('a2048', $arr['feature']);
//PERSON_INFO_T
$bin .= pack('L', isset($arr['info']['u32Permission']) ? $arr['info']['u32Permission'] : 0);
$bin .= pack('a32', isset($arr['info']['szName']) ? $arr['info']['szName'] : '');
$bin .= pack('a20', isset($arr['info']['szNric']) ? $arr['info']['szNric'] : '');
$bin .= pack('a24', isset($arr['info']['szCardNum']) ? $arr['info']['szCardNum'] : '');
$bin .= pack('L', isset($arr['info']['u32VaildDateBegin']) ? $arr['info']['u32VaildDateBegin'] : 0);
$bin .= pack('L', isset($arr['info']['u32VaildDateEnd']) ? $arr['info']['u32VaildDateEnd'] : 0);
$bin .= pack('a8', isset($arr['info']['_reserv']) ? $arr['info']['_reserv'] : '');
return $bin;
}
function parseCommand($inputstream)
{
$recvcmd = self::unpack_FACE_SYNC_CMD_T($inputstream, 0);
//printf("command = 0x%X, checksum = 0x%X\r\n", $recvcmd['command'], $recvcmd['checksum']);
$checksum = self::CRC32_Calc($inputstream, 4, strlen($inputstream)-4, 0xffffffff);
if($recvcmd['checksum'] != $checksum){
//printf("recv_checksum = 0x%X, calc_checksum = 0x%X\r\n", $recvcmd['checksum'], $checksum);
//if($_SERVER['REQUEST_METHOD'] != 'GET'){
return; //校驗(yàn)碼錯(cuò)誤返回
//}
}
if($recvcmd['command'] == FACESYNC_REQUEST_FACE_IDS){ //收到請(qǐng)求人臉列表命令
$checksum = 0xffffffff; //初始種子
$test_feature_datas = $GLOBALS['test_feature_datas']; //模擬讀取數(shù)據(jù)庫(kù)
$itemcount = count($test_feature_datas);
//生成協(xié)議頭
$sendcmd = array(
'command'=> FACESYNC_RESPONSE_FACE_IDS, //回復(fù)人臉列表命令
'itemsize'=> 16, // FACE_ID_SET_T占16字節(jié)
'itemcount'=> $itemcount
);
$cmddata = self::pack_FACE_SYNC_CMD_T($sendcmd);
$checksum = self::CRC32_Calc($cmddata, 4, 60, $checksum); //計(jì)算協(xié)議頭第4字節(jié)開(kāi)始到末尾的校驗(yàn)碼
//生成附加數(shù)據(jù)
$listdata = '';
foreach($test_feature_datas as $obj){
$face_id_set = self::pack_FACE_ID_SET_T($obj); //生成二進(jìn)制列表項(xiàng)
$checksum = self::CRC32_Calc($face_id_set, 0, 16, $checksum); //累計(jì)校驗(yàn)碼
$listdata .= $face_id_set; //二進(jìn)制列表
}
$sendcmd['checksum'] = $checksum; //將最終數(shù)據(jù)包的校驗(yàn)碼填入?yún)f(xié)議頭
$cmddata = self::pack_FACE_SYNC_CMD_T($sendcmd); //重新封包協(xié)議頭
//返回二進(jìn)制流
header("Content-Type: application/octet-stream");
echo $cmddata; //發(fā)送協(xié)議頭
echo $listdata; //發(fā)送附加數(shù)據(jù)
//flush();
}else if($recvcmd['command'] == FACESYNC_REQUEST_FACE_FEATURES){ //收到請(qǐng)求人臉特征命令
$checksum = 0xffffffff; //初始種子
$test_feature_datas = $GLOBALS['test_feature_datas']; //模擬讀取數(shù)據(jù)庫(kù)
$itemcount = $recvcmd['itemcount'];
$faceids = unpack("Q{$itemcount}", $inputstream, 64); //解包收到的N個(gè)人臉I(yè)Ds //這里注意雙引號(hào)
//生成協(xié)議頭
$sendcmd = array(
'command'=> FACESYNC_RESPONSE_FACE_FEATURES, //回復(fù)人臉特征命令
'itemsize'=> 2176, // FACE_FEATURE_T占2176字節(jié)
'itemcount'=> $itemcount
);
$cmddata = self::pack_FACE_SYNC_CMD_T($sendcmd);
$checksum = self::CRC32_Calc($cmddata, 4, 60, $checksum); //計(jì)算協(xié)議頭第4字節(jié)開(kāi)始到末尾的校驗(yàn)碼
//生成附加數(shù)據(jù)
$listdata = '';
$face_feature_item = '';
//查找客戶(hù)端發(fā)來(lái)的faceid(s)對(duì)應(yīng)的特征數(shù)據(jù)
$found = false;
foreach($faceids as $id){
foreach($test_feature_datas as $obj){
if($id == $obj['u64FaceId']){
$face_feature_item = self::pack_FACE_FEATURE_T($obj); //生成二進(jìn)制列表項(xiàng)
$found = true;
break;
}
}
if(!$found){
$face_feature_item = pack('a2176', ''); //如果faceid剛好不存在則填充2176字節(jié)空白數(shù)據(jù)
}
$checksum = self::CRC32_Calc($face_feature_item, 0, 2176, $checksum); //累計(jì)校驗(yàn)碼
$listdata .= $face_feature_item; //二進(jìn)制列表
}
$sendcmd['checksum'] = $checksum; //將最終數(shù)據(jù)包的校驗(yàn)碼填入?yún)f(xié)議頭
$cmddata = self::pack_FACE_SYNC_CMD_T($sendcmd); //重新封包協(xié)議頭
//返回二進(jìn)制流
header("Content-Type: application/octet-stream");
echo $cmddata; //發(fā)送協(xié)議頭
echo $listdata; //發(fā)送附加數(shù)據(jù)
//flush();
}
}
}
//######### Main() ###########
//phpinfo();
//print_r($test_feature_datas);
$inputstream = '';
if($_SERVER['REQUEST_METHOD'] == 'GET')
$inputstream = pack("L16", 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0); //GET測(cè)試返回人臉列表
else
$inputstream = file_get_contents('php://input'); //POST
$facesync = new FaceSyncSDK();
$facesync->parseCommand($inputstream);
?>
上面的文件是原始的數(shù)據(jù)文件,放到類(lèi)型tp框架這種控制器是可以的,但是長(zhǎng)住內(nèi)存框架,我就搞不定了
看手冊(cè) http://wtbis.cn/doc/webman#/response 應(yīng)該不難吧
應(yīng)該是
reutrn response($cmddata.$listdata, 200, ['Content-Type'=>'application/octet-stream']);
public function hello(Request $request)
{
// 創(chuàng)建一個(gè)對(duì)象
$response = response();
// .... 業(yè)務(wù)邏輯省略
// 設(shè)置cookie
$response->cookie('foo', 'value');
// .... 業(yè)務(wù)邏輯省略
// 設(shè)置http頭
$response->header('Content-Type', 'application/json');
$response->withHeaders([
'X-Header-One' => 'Header Value 1',
'X-Header-Tow' => 'Header Value 2',
]);
// .... 業(yè)務(wù)邏輯省略
// 設(shè)置要返回的數(shù)據(jù)
$response->withBody('返回的數(shù)據(jù)');
return $response;
}