PHP Socket UDP网络读卡器使用示例

PHP Socket UDP网络读卡器使用示例

<?PHP
  header("content-type:text/html;charset=GBK");
  
  $ThisIp=get_local_ip();   //获取电脑IP地址         
  $server = 'udp://'.$ThisIp.':39169';  
  $socket = stream_socket_server($server, $errno, $errstr, STREAM_SERVER_BIND);  
  if (!$socket) 
  {  
      die("$errstr ($errno)");  
  }  
  echo "系统绑定的IP :".$ThisIp.":39169\n";
  
  $LastBuf= array(9);      //保存最后接收到的信息,用于比较是否重复接收的信息
  
  do{ 
      //监听UDP端口,并将接收到的数据以16进制方式显示出来,正式项目只解析数据不需要显示
      $inMsg = stream_socket_recvfrom($socket, 1024, 0, $peer);  
      $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 "From Ip :$peer\n";  
       echo "GetData :{$Getinf}\n\n";  
       
       //对接收到的数进行解析
       if($len >8){              
          if($bytes[0]==$LastBuf[0] && $bytes[1]==$LastBuf[1] && $bytes[2]==$LastBuf[2] && $bytes[3]==$LastBuf[3] && $bytes[4]==$LastBuf[4] && $bytes[5]==$LastBuf[5] && $bytes[6]==$LastBuf[6] && $bytes[7]==$LastBuf[7] && $bytes[8]==$LastBuf[8]){
              DisableSendAge($bytes,$peer ) ;  //接收到相同的信息,确定接收到刷卡器数据,否则读卡器会重发三次,不用处理
               
          }else{
                   for($i=0;$i<9;$i++){        //将本次接收到且已解析处理的信息保存,用于下次接收到信息时比对是否重复接收到的信息
                         $LastBuf[$i]=$bytes[$i];
                   } 
                         
                   switch($bytes[0]){   
                        case hexdec('0xF2'):     //接收到读卡器开机、搜索在线设备的返回信息
                                 echo "接收到读卡器开机、搜索在线设备的返回信息\n";
                                 echo "指令码 :".substr('00'.dechex($bytes[0]),-2)."\n";  
                                 echo "设备IP :".$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] . "\n";   
                                 echo "掩  码 :".$bytes[5].".".$bytes[6].".".$bytes[7] .".".$bytes[8] . "\n";     
                                 echo "通讯端口:".($bytes[9]+$bytes[10]*256) . "\n"; 
                                 echo "网  关 :".$bytes[13].".".$bytes[14].".".$bytes[15] .".".$bytes[16] . "\n";   
                                 $MAC="";
                                 for($i=17;$i<23;$i++){ 
                                    $MAC=$MAC.substr('00'.dechex($bytes[$i]),-2);    
                                    if($i<22){$MAC=$MAC."-";}
                                 } 
                                 echo "网关MAC:".$MAC."\n";   
                                 $ServiceIp=$bytes[23].".".$bytes[24].".".$bytes[25] .".".$bytes[26];                                 
                                 echo "远程服务器IP:".$ServiceIp . "\n";   //如果$ServiceIp!=$ThisIp,需将设备的服务器IP设为$ThisIp,否则无法接收到数据。                                 
                                 $MAC="";
                                 for($i=27;$i<33;$i++){ 
                                    $MAC=$MAC.substr('00'.dechex($bytes[$i]),-2);    
                                    if($i<32){$MAC=$MAC."-";}
                                 }
                                 echo "服务器MAC:".$MAC."\n";   
                                 echo "网络标识:".substr('00'.dechex($bytes[33]),-2)."\n";  
                                 echo "响声标识:".substr('00'.dechex($bytes[34]),-2)."\n";  
                                 $MAC="16-88-";
                                 for($i=35;$i<39;$i++){ 
                                    $MAC=$MAC.substr('00'.dechex($bytes[$i]),-2);    
                                    if($i<38){$MAC=$MAC."-";}
                                 }
                                 echo "读卡器MAC:".$MAC."\n";  
                                 if(sizeof($bytes)>39){
                                     $SerialNum="";
                                     for($i=39;$i<sizeof($bytes);$i++){ 
                                        $SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);    
                                     }
                                     echo "设备唯一序号:".$SerialNum."\n";  
                                 }
                                 echo "\n";
                                 break;
                        case hexdec('0xF3'):     //接收到读卡器的心跳信息
                                 echo "接收到读卡器心跳数据信息\n";
                                 echo "指令码 :".substr('00'.dechex($bytes[0]),-2)."\n";  
                                 echo "设备IP :".$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] . "\n"; 
                                 echo "机号   :".($bytes[5]+$bytes[6]*256) . "\n";      
                                 echo "包序号 :".($bytes[7]+$bytes[8]*256) . "\n";   
                                 echo "心跳类型:".substr('00'.dechex($bytes[9]),-2)."\n";      
                                 echo "长度   :".substr('00'.dechex($bytes[10]),-2)."\n";  
                                 echo "继电器状态:".substr('00'.dechex($bytes[11]),-2)."\n";  
                                 echo "外部输入状态:".substr('00'.dechex($bytes[12]),-2)."\n";
                                 echo "随机动态码:".substr('00'.dechex($bytes[13]),-2).substr('00'.dechex($bytes[14]),-2).substr('00'.dechex($bytes[15]),-2).substr('00'.dechex($bytes[16]),-2)."\n";    
                                 $SerialNum="";
                                 for($i=17;$i<sizeof($bytes);$i++){ 
                                     $SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);    
                                 }
                                 echo "设备唯一序号:".$SerialNum."\n\n";  
                                 break;
                        case hexdec('0xD1'):     //接收到ID卡信息   
                                 DisableSendAge($bytes,$peer ) ;  //确定接收到刷卡器数据,否则读卡器会重发三次                                
                                 echo "接收到的信息为ID读卡器上传的卡号\n";                    
                                 echo "指令码 :".substr('00'.dechex($bytes[0]),-2)."\n";  
                                 echo "设备IP :".$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] . "\n";                                            
                                 echo "机号 :".($bytes[5]+$bytes[6]*256) . "\n";      
                                 echo "包序号 :".($bytes[7]+$bytes[8]*256) . "\n";                                                                             
                                 $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);
                                 echo "十进制卡号 :".$CardNo . "\n";    
                                 $SerialNum ="";
                                 for($i=14;$i<$len;$i++){ 
                                    $SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);    
                                 }        
                                 echo "设备*** :".$SerialNum  . "\n";          
                                 $DispStr="卡号:".$CardNo."  ".substr(date('Y-m-d h:i:s', time()),0,16)."            "; //全屏显示信息长度>=34
                                 
                                 //可以在此处加入业务的数据库查、增、删等操作                                 
                                 //将系统处理结果发送到设备上显示,根据设备类型使用以下不同的发送显示、声音指令
                                 
                                 SendDispBeep($DispStr,$peer); //向读卡器发送显示及蜂鸣响声
                                 //SendDispSpk($DispStr,$peer);//向读卡器发送显示+继电器+固定组合语音   
                                 //SendDispTTS($DispStr,$peer);//向读卡器发送显示+继电器+TTS语音
                                 break;                            
                        case hexdec('0xC1'):     //接收到IC卡信息                                                                                                        
                                 DisableSendAge($bytes,$peer ) ;  //确定接收到刷卡器数据,否则读卡器会重发三次                                
                                 echo "接收到的信息为IC读卡器上传的卡号\n";                    
                                 echo "指令码 :".substr('00'.dechex($bytes[0]),-2)."\n";  
                                 echo "设备IP :".$bytes[1].".".$bytes[2].".".$bytes[3] .".".$bytes[4] . "\n";                                            
                                 echo "机号 :".($bytes[5]+$bytes[6]*256) . "\n";      
                                 echo "包序号 :".($bytes[7]+$bytes[8]*256) . "\n";                                                                             
                                 $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);
                                 echo "十进制卡号 :".$CardNo . "\n";    
                                 $SerialNum ="";
                                 for($i=14;$i<$len;$i++){ 
                                    $SerialNum=$SerialNum.substr('00'.dechex($bytes[$i]),-2);    
                                 }        
                                 echo "设备*** :".$SerialNum  . "\n";          
                                 $DispStr="卡号:".$CardNo."  ".substr(date('Y-m-d h:i:s', time()),0,16)."            "; //全屏显示信息长度>=34
                                 
                                 //可以在此处加入业务的数据库查、增、删等操作                                 
                                 //将系统处理结果发送到设备上显示,根据设备类型使用以下不同的发送显示、声音指令
                                 
                                 //SendDispBeep($DispStr,$peer); //向读卡器发送显示及蜂鸣响声
                                 SendDispSpk($DispStr,$peer);//向读卡器发送显示+继电器+固定组合语音   
                                 //SendDispTTS($DispStr,$peer);//向读卡器发送显示+继电器+TTS语音
                                 break;  
                        default:
                
                   }
         }          
       }
  } while ($inMsg !== false);
  
//向读卡器发送显示+继电器+TTS语音-----------------------------------------------------------------------------------------------------
function SendDispTTS($DispStr,$peer)
{
  $SpeakStr="[v10]".$DispStr;           //[v10]是语音大小,取值范围0-16,可加在任何地方,其他语音策略请看文档说明
  $SpeakStr=$SpeakStr."感谢您的使用";     //要播报的TTS语音,每条指令最大不能超过126字符
  $Splen = strlen($SpeakStr);           //TTS语音长度
  
  $bytes[0]=hexdec('0x5C');             //指令码 
  $bytes[1]=0;                          //机号低,机号为0表示广播   
  $bytes[2]=0;                          //机号高
  $bytes[3]=2;                          //蜂鸣声代码
  $bytes[4]=hexdec('0xF0');             //继电器代码 F0表示全部继电器 F1表示1号继电器 F2表示2号继电器
  
  $bytes[5]=hexdec('0x20');             //继电器开启时长低位
  $bytes[6]=0;                          //继电器开启时长高位
  
  $bytes[7]=hexdec('0x14');             //显示保留时间,单位为秒,为0xFF时表示永久显示
  $bytes[8]=0;                          //在显示屏中的哪个位置开始
  $bytes[9]=hexdec('0x22');             //显示字符串长度 为全屏显示为 34 个字符
  $bytes[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($bytes[$i]);
  }
  $sendBuf=$sendBuf.substr($DispStr,0,34).$SpeakStr.$suffixStr;   //最长显示34个字符
    
  $handle = stream_socket_client("udp://".$peer, $errno, $errstr);
  fwrite($handle, $sendBuf);  
  
  $Sendinf='';                    //将发送的信息用16进制数显示,方便调式
  for($i=0;$i<strlen($sendBuf);$i++){ 
            $byte = ord($sendBuf[$i]);                               
            $b=substr('00'.dechex($byte ),-2);                
            $Sendinf=$Sendinf.$b.' ';
  }      
  echo "SendTo IP:".$peer."\n";
  echo "SendData :{$Sendinf}\n\n";         
 }   
//向读卡器发送显示+继电器+固定组合语音-------------------------------------------------------------------------------------------------
function SendDispSpk($DispStr,$peer)

  $Splen=3;                             //语音代码条数,最多21条
  $SpeakStr=chr(55).chr(41).chr(53);    //语音代码,根据条数增加,代码取值见通讯协议
  
  $bytes[0]=hexdec('0x5B');             //指令码 
  $bytes[1]=0;                          //机号低,机号为0表示广播   
  $bytes[2]=0;                          //机号高
  $bytes[3]=2;                          //蜂鸣声代码
  $bytes[4]=hexdec('0xF0');             //继电器代码 F0表示全部继电器 F1表示1号继电器 F2表示2号继电器
  
  $bytes[5]=hexdec('0x20');             //继电器开启时长低位
  $bytes[6]=0;                          //继电器开启时长高位
  
  $bytes[7]=hexdec('0x14');             //显示保留时间,单位为秒,为0xFF时表示永久显示
  $bytes[8]=0;                          //在显示屏中的哪个位置开始
  $bytes[9]=hexdec('0x24');             //显示字符串长度 为全屏显示为 34 个字符
  $bytes[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($bytes[$i]);
  }
  $sendBuf=$sendBuf.substr($DispStr,0,36).$SpeakStr.$suffixStr;   //最长显示34个字符
    
  $handle = stream_socket_client("udp://".$peer, $errno, $errstr);
  fwrite($handle, $sendBuf);  
  
  $Sendinf='';                    //将发送的信息用16进制数显示,方便调式
  for($i=0;$i<strlen($sendBuf);$i++){ 
            $byte = ord($sendBuf[$i]);                               
            $b=substr('00'.dechex($byte ),-2);                
            $Sendinf=$Sendinf.$b.' ';
  }      
  echo "SendTo IP:".$peer."\n";
  echo "SendData :{$Sendinf}\n\n";         
 }    
//向读卡器发送显示及蜂鸣响声-----------------------------------------------------------------------------------------------------
function SendDispBeep($DispStr,$peer)
{
  $bytes[0]=hexdec('0x5A');             //指令码
  $bytes[1]=0;                          //机号低,机号为0表示广播   
  $bytes[2]=0;                          //机号高
  $bytes[3]=2;                          //蜂鸣声代码
  $bytes[4]=20;                         //显示时长
  
  $sendBuf='';
  for($i=0;$i<5;$i++) 
  {
      $sendBuf=$sendBuf.chr($bytes[$i]);
  }
  $sendBuf=$sendBuf.$DispStr;
  
  $handle = stream_socket_client("udp://".$peer, $errno, $errstr);
  fwrite($handle, $sendBuf);  
  
  $Sendinf='';                    //将发送的信息用16进制数显示,方便调式
  for($i=0;$i<strlen($sendBuf);$i++){ 
            $byte = ord($sendBuf[$i]);                               
            $b=substr('00'.dechex($byte ),-2);                
            $Sendinf=$Sendinf.$b.' ';
  }    
  echo "SendTo IP:".$peer."\n";  
  echo "SendData :{$Sendinf}\n\n";    
 }              
//确定接收到刷卡器数据,以免读卡器重复发送--------------------------------------------------------------------------------------------------
function DisableSendAge($bytes,$peer)
{
  $bytes[0]=105; 
  $sendBuf='';
  for($i=0;$i<9;$i++) 
  {
      $sendBuf=$sendBuf.chr($bytes[$i]);
  }
  $handle = stream_socket_client("udp://".$peer, $errno, $errstr);
  fwrite($handle, $sendBuf);  

  $Sendinf='';                    //将发送的信息用16进制数显示,方便调式
  for($i=0;$i<strlen($sendBuf);$i++){ 
            $byte = ord($sendBuf[$i]);                               
            $b=substr('00'.dechex($byte ),-2);                
            $Sendinf=$Sendinf.$b.' ';
  }      
  echo "SendTo IP:".$peer."\n";
  echo "SendData :{$Sendinf}\n\n";      
 }              
//获取本机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真实地址
    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]))) {
                    return trim($tmpIp[1]);
                }
            }
        }
    }    
    //获取操作系统为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]);
            }
        }
    }
    return '127.0.0.1';
}  

?>