Events.php 15.1 KB
<?php
/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link http://www.workerman.net/
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */

/**
 * 用于检测业务代码死循环或者长时间阻塞等问题
 * 如果发现业务卡死,可以将下面declare打开(去掉//注释),并执行php start.php reload
 * 然后观察一段时间workerman.log看是否有process_timeout异常
 */

//declare(ticks=1);
use \GatewayWorker\Lib\Gateway;

require_once('Connection.php');

/**
 * 主逻辑
 * 主要是处理 onConnect onMessage onClose 三个方法
 * onConnect 和 onClose 如果不需要可以不用实现并删除
 */
class Events
{
    public static $db = null;

    public static function onWorkerStart($worker)
    {
        self::$db = new \Workerman\MySQL\Connection('rm-m5eblhc9o3515i25neo.mysql.rds.aliyuncs.com', '3306', 'db136s1ehvo1yn73', 'cxz307311SJK', 'gjr');
    }

    /**
     * 当数板仪发来消息时触发
     * @param int $client_id 连接id
     * @param mixed $message 具体消息
     */
    public static function onMessage($client_id, $message)
    {
        if (!$message) {
            return;
        }
        $param = explode(',', $message);
        $start = $param[0];//命令头
        $number = $param[1];//数板仪id号
        $command_number = $param[2];//命令号
        //$content = $param[4];//命令内容
        $crc16 = $param[count($param) - 2];//crc16(签名)
        $end = $param[count($param) - 1];//命令尾
        $date = date('YmdHis');
        //判断命令号
        if ($command_number == "00") {
            //时间同步命令
            $content = $param[3];//命令内容
            //验证签名是否正确
            $str = ",".$number .",". $command_number .",". $content.",";
            if (self::crc16($str) != $crc16) {
                echo "yanzhengshibai";
                return ;
            }
            //判断是否已有数板仪id
            $row = self::$db->select('*')->from('gjr_equipment')->where("number = '$number'")->row();
            $status = "A5";
            if (!empty($row)) {
                //判断状态
                if($row['status'] != 'normal' || $row['end_time'] < time()){
                    $status = "B9";//禁用
                }else {
                    $createtime = time();
                    $arr1 = [
                        'number' => $number,
                        'command_number' => $command_number,
                    ];
                    //记录判断是否订阅
                    $api_subscrib = self::$db->select('*')->from('gjr_api_subscrib')->where("subscrib_ids like '%$row[id],%'")->row();
                    if(!empty($api_subscrib)){
                        $api = self::$db->select('*')->from('gjr_api')->where("id = '$api_subscrib[api_id]'")->row();
                        //请求接口返回状态
                        $arr1['number'] = $number;
                        $result3 = json_decode(self::httpPost($api['callback'],$arr1),true);
                        if($result3['code'] == 1){
                            $is_success = 1;
                            if($result3['data']['status'] == 'normal'){
                                $status = "A5";//正常
                            }else{
                                $status = "B9";//非正常
                            }
                        }else{
                            $staus = "A5";//接口异常
                        }
                    }else {
                        $status = "A5";//未订阅返回正常
                    }
                }
            }
            $str = ",".$number .",". $command_number.",".$status .",". $date.",";
            $arr = ["X", $number, $command_number, $status, $date, self::crc16($str), "Y"];
            $common = implode(',', $arr);
        } else if ($command_number == "01") {
            //数据同步以及状态同步
            $time = $param[3];//时间
            $position = $param[4];//位置信息经纬度
            $address = self::getAddress($position);//位置信息
            $quantity = self::jinzhih_1($param[5], 16);//电池电量
            $wendu = (self::jinzhih_1(substr($param[6], 0, 4),16)-self::jinzhih_1("0X07FF",16))/10;//温度
            $shidu = (self::jinzhih_1(substr($param[6], 4, 8),16)-self::jinzhih_1("0X07FF",16))/10;//湿度
            $papers = self::jinzhih_1($param[8], 16);//本次计数
            $papers_count = self::jinzhih_1($param[9], 16);//累加计数
            $times = self::jinzhih_1($param[10], 16);//计数次数
            $sensor_status = $param[11];//传感器模组状态
            $dianji_status = $param[12];//电机状态
            $yejing_status = $param[13];//液晶状态
            $wenshidu_status = $param[14];//湿度传感器状态
            //验证签名是否正确;
            unset($param[0]);
            unset($param[count($param)-1]);
            unset($param[count($param)-1]);
            print_r($param);
            $str = ",".implode(',',$param).",";
            echo self::crc16($str)."\n";
            echo $crc16;
            if (self::crc16($str) != $crc16) {
                echo "yanzhengshibai2";
                return ;
            }
            //判断是否已数板仪id
            $row = self::$db->select('*')->from('gjr_equipment')->where("number = '$number'")->row();
            $status = "A5";
            if (!empty($row)) {
                //判断状态
                if($row['status'] != 'normal' || $row['end_time'] < time()){
                    $status = "B9";//禁用
                }else {
                    $createtime = time();
                    $arr1 = [
                        'number' => $number,
                        'command_number' => $command_number,
                        'time' => $time,
                        'position' => $position,
                        'address' => $address,
                        'quantity' => $quantity,
                        'wendu' => $wendu,
                        'shidu' => $shidu,
                        'papers' => $papers,
                        'papers_count' => $papers_count,
                        'times' => $times,
                        'sensor_status' => $sensor_status,
                        'dianji_status' => $dianji_status,
                        'yejing_status' => $yejing_status,
                        'wenshidu_status' => $wenshidu_status,
                        'socket_data' => json_encode($param),
                        'createtime' => $createtime,
                    ];
//                    $db->beginTrans();
                    //数板仪器数据同步记录
                    $result1 = self::$db->insert('gjr_equipment_log')->cols($arr1)->query();
                    //记录判断是否订阅
                    $api_subscrib = self::$db->select('*')->from('gjr_api_subscrib')->where("subscrib_ids like '%$row[id],%'")->row();
                    if(!empty($api_subscrib)){
                        $api = self::$db->select('*')->from('gjr_api')->where("id = '$api_subscrib[api_id]'")->row();
                        //请求接口返回状态
                        unset($arr1['socket_data']);
                        unset($arr1['createtime']);
                        $arr1['number'] = $number;
                        $result3 = json_decode(self::httpPost($api['callback'],$arr1),true);
                        if($result3['code'] == 1){
                            $is_success = 1;
                            if($result3['data']['status'] == 'normal'){
                                $status = "A5";//正常
                            }else{
                                $status = "B9";//非正常
                            }
                        }else{
                            $staus = "A5";//接口异常
                        }
                        $arr2 = [
                            'api_id' => $api_subscrib['api_id'],
                            'type' => 1,
                            'subscrib_id' => $api_subscrib['id'],
                            'notice_url' => $api['callback'],
                            'times' => $api['times'],
                            'content' => json_encode($arr1),
                            'createtime' => time(),
                            'is_success' => empty($is_success) ? 0 : $is_success,
                        ];
                        //记录订阅通知记录
                        $result2 = self::$db->insert('gjr_subscrib_log')->cols($arr2)->query();
                    }else {
                        $status = "A5";//未订阅返回正常
                    }
                }
            }
            $str = $number."," . $command_number."," . $status."," . $date;
            $arr = ["X", $number, $command_number, $status, $date, self::crc16($str), "Y"];
            $common = implode(',',$arr);
        }
        //回复i
        Gateway::sendToClient($client_id, $common);
    }

    /**
     * 当用户断开连接时触发
     * @param int $client_id 连接id
     */
    public static function onClose($client_id)
    {
        // 向所有人发送
        //GateWay::sendToAll("$client_id logout\r\n");
    }

    public static function crc16($str, $polynomial = 0x8005, $initValue = 0xffff, $xOrValue = 0, $inputReverse = true, $outputReverse = true)
    {
        $crc = $initValue;

        for ($i = 0; $i < strlen($str); $i++) {
            if ($inputReverse) {
                // 输入数据每个字节按比特位逆转
                $c = ord(self::reverseChar($str{$i}));
            } else {
                $c = ord($str{$i});
            }
            $crc ^= ($c << 8);
            for ($j = 0; $j < 8; ++$j) {
                if ($crc & 0x8000) {
                    $crc = (($crc << 1) & 0xffff) ^ $polynomial;
                } else {
                    $crc = ($crc << 1) & 0xffff;
                }
            }
        }
        if ($outputReverse) {
            // 把低地址存低位,即采用小端法将整数转换为字符串
            $ret = pack('cc', $crc & 0xff, ($crc >> 8) & 0xff);
            // 输出结果按比特位逆转整个字符串
            $ret = self::reverseString($ret);
            // 再把结果按小端法重新转换成整数
            $arr = unpack('vshort', $ret);
            $crc = $arr['short'];
        }
        return sprintf("%x",$crc ^ $xOrValue);
    }
    public static function reverseChar($char)
    {
        $byte = ord($char);
        $tmp = 0;
        for ($i = 0; $i < 8; ++$i) {
            if ($byte & (1 << $i)) {
                $tmp |= (1 << (7 - $i));
            }
        }
        return chr($tmp);
    }
    public static function reverseString($str)
    {
        $m = 0;
        $n = strlen($str) - 1;
        while ($m <= $n) {
            if ($m == $n) {
                $str{$m} = self::reverseChar($str{$m});
                break;
            }
            $ord1 = self::reverseChar($str{$m});
            $ord2 = self::reverseChar($str{$n});
            $str{$m} = $ord2;
            $str{$n} = $ord1;
            $m++;
            $n--;
        }
        return $str;
    }

    /**
     * 根据经纬度获取地址
     * @param $position
     * @return mixed
     */
    public static function getAddress($position)
    {
        $position = explode('E',str_replace('N',"", $position));
        $lat = $position[0];//经度
        $lng = $position[1];//纬度
        $key = "SINBZ-7NG66-W4SSS-MEUYB-ZHVTV-IDFQN";
        $url = "http://apis.map.qq.com/ws/geocoder/v1/?location=$lat,$lng&key=$key";
        $result = self::http_get($url);
        $data = json_decode($result,true);
        if($data['status'] != 0){
            return $data['message'];
        }
        return $data['result']['address'];
    }

    /**
     * get请求
     * @param $url
     * @return mixed
     */
    public static function http_get($url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
        $result = curl_exec($ch);
        // grab URL, and print
        if(curl_errno($ch)){
            print curl_error($ch);
        }
        curl_close($ch);
        return $result;
    }

    /**
     * 进制转换
     * @param $zifu
     * @param $jinzhi
     * @return float|int
     */
    public static function jinzhih_1($zifu, $jinzhi)
    {
        $shu = 0;
        for ($i = 0; $i <= strlen($zifu) - 1; $i++) {
            $linshi = substr($zifu, $i, 1);
            switch ($jinzhi) {
                case 2:
                    $shu = bindec($zifu);
                    $i = strlen($zifu) + 1;
                    break;
                case 8:
                    $shu = octdec($zifu);
                    $i = strlen($zifu) + 1;
                    break;
                case 16:
                    $shu = hexdec($zifu);
                    $i = strlen($zifu) + 1;
                    break;
                case 36:
                    if (ord($linshi) <= 57) {
                        $shu += (ord($linshi) - 48) * pow($jinzhi, strlen($zifu) - $i - 1);
                    } else {
                        $shu = $shu + (ord($linshi) - 55) * pow($jinzhi, strlen($zifu) - $i - 1);
                    }
                    break;
                case 62:
                    if (ord($linshi) <= 57) {
                        $shu += $linshi * pow($jinzhi, strlen($zifu) - $i - 1);
                    } elseif ((ord($linshi) >= 65) && (ord($linshi) <= 90)) {
                        $shu += (ord($linshi) - 55) * pow($jinzhi, strlen($zifu) - $i - 1);
                    } else {
                        $shu += (ord($linshi) - 61) * pow($jinzhi, strlen($zifu) - $i - 1);
                    }
                    break;
            }
        }
        return $shu;
    }

    public static function httpPost($url,$data){ // 模拟提交数据函数
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在
//        curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_POST, true); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS,  $data); // Post提交的数据包
        //curl_setopt($curl, CURLOPT_TIMEOUT, 120); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, false); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回
        $result = curl_exec($curl); // 执行操作
        if (curl_errno($curl)) {
            echo 'Error POST'.curl_error($curl);
        }
        curl_close($curl); // 关键CURL会话
        return $result; // 返回数据
    }
}