本示例使用设备:WIFI/TCP/UDP/HTTP协议RFID液显网络读卡器可二次开发语音播报POE-淘宝网 (taobao.com)
<?php
header("content-type:text/html;charset=GBK");
set_time_limit(0);
$port=39169; //监听端口
if(($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === FALSE){
echo '初始化socket失败: ' . socket_strerror(socket_last_error($socket));
exit;
}
socket_set_nonblock($socket);
// socket_bind(): 将socket资源绑定到指定地址
if(!socket_bind($socket, '0.0.0.0', $port)){
echo '绑定端口失败: ' . socket_strerror(socket_last_error($socket));
exit;
}
// socket_listen(): 监听socket的连接请求
if(!socket_listen($socket)){
echo '监听端口: ' . socket_strerror(socket_last_error($socket));
exit;
}else{echo "TCP服务已启动,正在侦听端口:".$port."\n";}
while(1){
if(($client = socket_accept($socket)) !== FALSE){
while(1){
//这里不循环的话,只能接收到一次消息
$content = socket_read($client, 10240);
$content = trim($content);
if($content){
$response = AnalyzeData($content); //解析接收到的数据,并生成回应数据
socket_write($client, $response);
$Sendinf=''; //将发送的信息用16进制数显示,方便调式
for($i=0;$i<strlen($response);$i++){
$byte = ord($response[$i]);
$b=substr('00'.dechex($byte ),-2);
$Sendinf=$Sendinf.$b.' ';
}
echo "发送数据:".$Sendinf."\n\n";
}
}
}
}
socket_close($socket);
//解析接收到的数据,并根据情况生成不同的回应数据
function AnalyzeData($inMsg)
{
$len = strlen($inMsg);
$bytes = array();
$Getinf='';
for($i=0;$i<$len;$i++)
{
$byte = ord($inMsg[$i]);
$bytes[] = $byte ;
$b=substr('00'.dechex($byte ),-2);
$Getinf=$Getinf.$b.' ';
}
echo "接收数据:".$Getinf. PHP_EOL;
switch($bytes[0]){
case hexdec('0xF3'): //接收到设备的心跳数据包,设备心跳间隔可根据协议自行设置
$Ipaddstr=$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] ;
$Machine=($bytes[5]+$bytes[6]*256) ;
$frame=($bytes[7]+$bytes[8]*256) ;
$Heartbeattype=substr('00'.dechex($bytes[9]),-2);
$heartlen=$bytes[10];
$switch=substr('00'.dechex($bytes[11]),-2);
$keyinput=substr('00'.dechex($bytes[12]),-2);
$Randcode=substr('00'.dechex($bytes[13]),-2).substr('00'.dechex($bytes[14]),-2).substr('00'.dechex($bytes[15]),-2).substr('00'.dechex($bytes[16]),-2);
$SerialNum="";
for($i=17;$i<sizeof($bytes);$i++){
$SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);
}
$Dispinf="数据解析:设备心跳包,设备IP:".$Ipaddstr.",机号:".$Machine.",数据包序号:".$frame.",心跳类型:".$Heartbeattype.",长度:".$heartlen.",继电器状态:".$switch.",按键值:".$keyinput.",随机码:".$Randcode.",硬件序列号:".$SerialNum;
echo $Dispinf."\n\n";
break;
case hexdec('0xC1') or hexdec('0xCF') : //接收IC读卡器上传的读卡号数据、IC卡离开读卡器的信息
if($bytes[0]==hexdec('0xC1')){
$Dispinf="数据解析:IC读卡器读取卡号,";
}else{$Dispinf="数据解析:IC卡离开读卡器,";}
$Ipaddstr=$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] ;
$Machine=($bytes[5]+$bytes[6]*256) ;
$frame=($bytes[7]+$bytes[8]*256) ;
$Cardlen=$bytes[9];
$Card16H="";
for($i=0;$i<$Cardlen;$i++)
{
$Card16H=$Card16H.substr('00'.dechex($bytes[10+$i]),-2);
}
$CardNo=$bytes[10] & 0xff;
$CardNo=$CardNo+($bytes[11] & 0xff) *256;
$CardNo=$CardNo+($bytes[12] & 0xff) *65536;
$CardNo=$CardNo+($bytes[13] & 0xff) *16777216;
$CardNo=substr("0000000000".$CardNo,-10);
$SerialNum ="";
for($i=10+$Cardlen;$i<$len;$i++){
$SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);
}
$Dispinf=$Dispinf."设备IP:".$Ipaddstr.",机号:".$Machine.",数据包序号:".$frame.",卡号长度:".$Cardlen.",16进制卡号:".$Card16H.",转十进制卡号:".$CardNo.",硬件序列号:".$SerialNum;
echo $Dispinf."\n\n";
//此处加入业务对数据库的查、增、删、减等操作
$DispStr="卡号:".$CardNo." ".substr(date('Y-m-d h:i:s', time()),0,16)." "; //全屏显示信息长度>=34
return GetResponseData(4,$DispStr); //生成回应数据
break;
case hexdec('0xD1') or hexdec('0xDF') : //接收ID读卡器上传的读卡号数据、ID卡离开读卡器的信息
if($bytes[0]==hexdec('0xD1')){
$Dispinf="数据解析:ID读卡器读取卡号,";
}else{$Dispinf="数据解析:ID卡离开读卡器,";}
$Ipaddstr=$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] ;
$Machine=($bytes[5]+$bytes[6]*256) ;
$frame=($bytes[7]+$bytes[8]*256) ;
$Card16H="";
for($i=9;$i<14;$i++)
{
$Card16H=$Card16H.substr('00'.dechex($bytes[10+$i]),-2);
}
$CardNo=$bytes[9] & 0xff;
$CardNo=$CardNo+($bytes[10] & 0xff) *256;
$CardNo=$CardNo+($bytes[11] & 0xff) *65536;
$CardNo=$CardNo+($bytes[12] & 0xff) *16777216;
$CardNo=substr("0000000000".$CardNo,-10);
$SerialNum ="";
for($i=14;$i<$len;$i++){
$SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);
}
$Dispinf=$Dispinf."设备IP:".$Ipaddstr.",机号:".$Machine.",数据包序号:".$frame.",16进制卡号:".$Card16H.",转十进制卡号:".$CardNo.",硬件序列号:".$SerialNum;
echo $Dispinf."\n\n";
//此处加入业务对数据库的查、增、删、减等操作
$DispStr="卡号:".$CardNo." ".substr(date('Y-m-d h:i:s', time()),0,16)." "; //全屏显示信息长度>=34
return GetResponseData(4,$DispStr); //生成回应数据
break;
default:
}
}
//根据情况生成不同的回应数据
function GetResponseData($respcode,$DispStr)
{
$sdata = array();
switch($respcode){
case 0: //回只应蜂鸣响声
$sdata[0] = hexdec('0x96'); //指令码
$sdata[1] = 0; //机号低位,
$sdata[2] = 0; //机号高位,高低位都为0表示任意机号
$sdata[3] = 1; //蜂鸣响声代码,取值范围0-12,代表12种不同的蜂鸣响声
$sendBuf = '';
for ($i = 0; $i < 4; $i++) {
$sendBuf = $sendBuf . chr($sdata[$i]);
}
return $sendBuf;
break;
case 1: //回应只开启继电器
$sdata[0] = hexdec('0x78'); //指令码
$sdata[1] = 0; //机号低位,
$sdata[2] = 0; //机号高位,高低位都为0表示任意机号
$sdata[3] = hexdec('0xF0'); //继电器代码 F0表示全部继电器、F1表示1号继电器 、F2表示2号继电器、F3表示3号继电器......
$sdata[4] = hexdec('0x2C'); //继电器开启延时低位16进制
$sdata[5] = hexdec('0x01'); //继电器开启延时高位16进制,高低位取值FFFF表示继电器一直开启
$sendBuf = '';
for ($i = 0; $i < 6; $i++) {
$sendBuf = $sendBuf . chr($sdata[$i]);
}
return $sendBuf;
break;
case 2: //回应只关闭已开启的继电器
$sdata[0] = hexdec('0x78'); //指令码
$sdata[1] = 0; //机号低位,
$sdata[2] = 0; //机号高位,高低位都为0表示任意机号
$sdata[3] = hexdec('0xE0'); //继电器代码 E0表示全部继电器、E1表示1号继电器 、E2表示2号继电器、E3表示3号继电器......
$sdata[4] = hexdec('0x2C'); //继电器关闭延时低位16进制
$sdata[5] = hexdec('0x01'); //继电器关闭延时高位16进制,高低位取值FFFF表示继电器一直关闭
$sendBuf = '';
for ($i = 0; $i < 6; $i++) {
$sendBuf = $sendBuf . chr($sdata[$i]);
}
return $sendBuf;
break;
case 3: //回应蜂鸣响声+文字显示
$sdata[0]=hexdec('0x5A'); //指令码
$sdata[1]=0; //机号低位
$sdata[2]=0; //机号高位,高低位都为0表示任意机号
$sdata[3]=2; //蜂鸣声代码,取值范围0-12,代表12种不同的蜂鸣响声
$sdata[4]=20; //显示时长,单位秒,取值范围0-255,取值255时表示永久显示
$sendBuf='';
for($i=0;$i<5;$i++)
{
$sendBuf=$sendBuf.chr($sdata[$i]);
}
$sendBuf=$sendBuf.$DispStr;
return $sendBuf;
break;
case 4: //回应蜂鸣响声+继电器开关+文字显示+播报TTS语音
$SpeakStr="[v10]"; //[v10]是语音大小,取值范围0-16,可加在任何地方,其他语音策略请看文档说明
$SpeakStr=$SpeakStr."刷卡成功,感谢您使用我们的网络读卡器!";//要播报的TTS语音,每条指令最大不能超过126字符
$Splen = strlen($SpeakStr); //TTS语音长度
//
$sdata[0]=hexdec('0x5C'); //指令码
$sdata[1]=0; //机号低位
$sdata[2]=0; //机号高位,高低位都为0表示任意机号
$sdata[3]=2; //蜂鸣声代码,取值范围0-12,代表12种不同的蜂鸣响声
$sdata[4]=hexdec('0xF0'); //继电器代码 F0表示全部继电器 F1表示1号继电器 F2表示2号继电器
$sdata[5]=hexdec('0x2C'); //继电器开启时长低位
$sdata[6]=hexdec('0x01'); //继电器开启时长高位
$sdata[7]=hexdec('0x14'); //显示保留时间,单位为秒,为0xFF时表示永久显示
$sdata[8]=0; //在显示屏中的哪个位置开始
$sdata[9]=hexdec('0x22'); //显示字符串长度 为全屏显示为 34 个字符
$sdata[10]=$Splen; //语音长度
$suffixStr=chr(hexdec('0x55')).chr(hexdec('0xaa')).chr(hexdec('0x66')).chr(hexdec('0x99')); //固定的抗干扰后缀
$sendBuf='';
for($i=0;$i<11;$i++)
{
$sendBuf=$sendBuf.chr($sdata[$i]);
}
$sendBuf=$sendBuf.substr($DispStr,0,34).$SpeakStr.$suffixStr; //最长显示34个字符
return $sendBuf;
break;
default:
}
}
//获取本机IP地址------------------------------------------------------------------------------------------------------------------------
function get_local_ip()
{
$preg = "/\A((([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\.){3}(([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\Z/";
//获取操作系统为win2000/xp、win7的本机IP真实地址
$Netdriv=array();
exec("ipconfig", $out, $stats);
if (!empty($out)) {
foreach ($out AS $row) {
if (strstr($row, "IP") && strstr($row, ":") && !strstr($row, "IPv6")) {
$tmpIp = explode(":", $row);
if (preg_match($preg, trim($tmpIp[1]))) {
$Netdriv[]=trim($tmpIp[1]);
echo trim($tmpIp[1])."\n";
}
}
}
}
//获取操作系统为linux类型的本机IP真实地址
//exec("ifconfig", $out, $stats);
//if (!empty($out)) {
// if (isset($out[1]) && strstr($out[1], 'addr:')) {
// $tmpArray = explode(":", $out[1]);
// $tmpIp = explode("", $tmpArray[1]);
// if (preg_match($preg, trim($tmpIp[0]))) {
// return trim($tmpIp[0]);
// }
// }
//}
if (!empty($Netdriv)) {
return $Netdriv[0]; //如果有多张网块,可以修改数组取值来绑定相应的网卡
}else{
return '127.0.0.1';
}
}
?>