微信支付回调验证签名处理 - yangzailu

时间:2024-03-03 13:42:32

微信支付回调验证签名处理

微信支付回调验证签名:一定要验证签名,可能不造成伪造数据,或者数据库造到灌水;

<?php 
/**
 * 微信支付回调类
 * @name CallbackAction.class.php
 * @author yangzl 
 * @date(20180820)
 */

class CallbackAction extends Action{
    /**
     * @param 获取微信支付回调接口
     * @return [type] [descripti
     * @date(20180820)
     * @author yangzl
     */
    public function getPayMentCallBack(){
        $curl_request = $_SERVER[\'REQUEST_METHOD\']; //获取请求方式
        if($curl_request == \'POST\'){ 
            $xmldata=file_get_contents("php://input");
            libxml_disable_entity_loader(true);
            //把微信支付回调结果写入日志
            $this->writeLogs(RUNTIME_PATH.\'Logs/\',\'getPayMentCallBack\',"\r\n-------------------".date(\'Y-m-d H:i:s\')."微信支付回调结果---------\r\n---响应数据:".json_encode(simplexml_load_string($xmldata, \'SimpleXMLElement\', LIBXML_NOCDATA))."\r\n------------\r\n");
            //处理微信支付返回的xml数据
            $data = json_encode(simplexml_load_string($xmldata, \'SimpleXMLElement\', LIBXML_NOCDATA));
            $sign_return = json_decode($data,true)[\'sign\'];
            $sign = $this->appgetSign(json_decode($data,true));
            //给微信返回接收成功通知,生成xml数据
            $this->returnXml();
            if($sign == $sign_return){
                //把数据提交给订单处理方法
                $this->proOrders($data);
            }
            
        }
    }



/*
 * 格式化参数格式化成url参数  生成签名sign
*/
 public  function appgetSign($data){
    require_once WEB_LIB."WxPay.Config.php";
    $config = new WxPayConfig();
    $appwxpay_key = $config->GetKey();
    //签名步骤一:按字典序排序参数
    ksort($data);
    $String = $this->callbackToUrlParams($data);
    //签名步骤二:在string后加入KEY
    if($appwxpay_key){
        $String = $String."&key=".$appwxpay_key;
    }
    //签名步骤三:MD5加密
    $String = md5($String);
    //签名步骤四:所有字符转为大写
    $result_ = strtoupper($String);
    return $result_;
  }
 


    /**
     * 格式化参数格式化成url参数
     */
    public function callbackToUrlParams($Parameters){
        $buff = "";
        foreach ($Parameters as $k => $v){
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }



    /**
     * @param  拼装xml数据返回 
     * @author  yangzl <[<email address>]>
     */
    public  function returnXml(){
        header("Content-type:text/xml;");
        $xml = "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n";
        $xml .= "<xml>\n";
        $xml .= "<return_code>SUCCESS</return_code>\n";
        $xml .= "<return_msg>OK</return_msg>\n";
        $xml .= "</xml>\n";
        echo  $xml;
    }



/**
 * @param 支付回调程序处理
 * @author yangzl
 * @date(20180820)
 */
public function proOrders($data){
    if (!$data) {
        $date = date("Y-m-d H:i:s",time());
        log::write( "proOrders方法错误".$date);
    }
    //处理则返回数据入库 分表
    $orders_info = json_decode($data,true);
    $orders_model = new OrdersModel();
    $branch_id = json_decode($orders_info[\'attach\'],true)[\'branch_id\'];
    //查询排重
    $result_pay_data = $orders_model->get_pay_data($branch_id,$orders_info[\'transaction_id\']);

    if(!$result_pay_data){ //不存在
        //存数据
         $table_id = json_decode($orders_info[\'attach\'],true)[\'table_id\']; 
        //根据tableid查询桌台信息
        $tables_model = new TablesModel();
        $table_info = $tables_model->get_table_by_id( $table_id, $branch_id);
        if($table_info[\'is_delete\'] == \'0\'){
            $title = $table_info[\'title\'];  
        }
        //回调支付信息
        $pay_info = array(
            \'branch_id\' => $branch_id,
            \'transaction_id\' => $orders_info[\'transaction_id\'],
            \'cash_fee\' => sprintf("%.2f",$orders_info[\'cash_fee\']/100),
            \'pay_type\' => 1,
            \'mch_id\' =>$orders_info[\'mch_id\'],
            \'result_code\' => $orders_info[\'result_code\'] == \'SUCCESS\' ? 1 : 0,
            \'orders_id\' =>$orders_info[\'out_trade_no\'],
            \'time_end\' => $orders_info[\'time_end\'],
            \'title\' => $title,
            \'openid\'=> $orders_info[\'openid\'],
            \'pay_source\' => 1,
            \'is_subscribe\' => $orders_info[\'is_subscribe\'] == \'Y\' ? 1 : 0,  //是否关注公众账号
            \'sub_mch_id\' => $orders_info[\'sub_mch_id\'],
            \'total_fee\' =>sprintf("%.2f",$orders_info[\'total_fee\']/100),
            \'bank_type\' => $orders_info[\'bank_type\'],
        );
        //存数据
        $add_data = $orders_model->add_pay_info($branch_id,$pay_info);  
        if(!$add_data){
            log::write( "支付数据存储失败".$orders_info[\'transaction_id\']);
            return false;
        }
        if($orders_info[\'result_code\'] == \'SUCCESS\'){
                //查询订单信息
                // $order_data = $orders_model->get_orders_data($table_id, $branch_id);
            
               $order_data = $orders_model->get_orders_tem($table_id, $branch_id);

                if(!$order_data){
                     log::write( "查询订单信息失败".time());
                    return false;
                }
                
                $this->writeLogs(RUNTIME_PATH.\'Logs/\',\'proOrders\',"\r\n-------------------".date(\'Y-m-d H:i:s\')."查询订单信息---------\r\n---响应数据:".json_encode($order_data)."\r\n------------\r\n");
                //数据处理
                $data_handle = $orders_model->data_handle($order_data,$table_id,$branch_id,$orders_info[\'cash_fee\']/100,$orders_info[\'transaction_id\']);

                $this->writeLogs(RUNTIME_PATH.\'Logs/\',\'proOrders\',"\r\n-------------------".date(\'Y-m-d H:i:s\')."微信支付数据处理结果---------\r\n---响应数据:".json_encode($data_handle)."\r\n------------\r\n");

                //支付方式入库
                $pay_data = array(
                        \'orders_id\' => $data_handle[\'orders_id\'],  //订单编号
                        \'branch_id\' => (int)$branch_id,  // 店铺 ID
                        \'pay_sn\'    =>  $orders_info[\'transaction_id\'],    // 支付 SN
                        \'pay_total\' =>  sprintf("%.2f",$orders_info[\'cash_fee\']/100),   // 支付金额
                        \'pay_type\'  =>  1,  // 支付类型 
                        \'table_id\'  =>  $table_id,  // 桌台ID
                );
            //添加副表
            $pay_sn = $orders_model->add_orders_pay_sn($pay_data);
            $pay_state = $data_handle[\'state\'];
            
            if($pay_state == 1){  //完成订单
                //完成订单后,没有确认的订单也全部清空 add yangzl                
                $del_redis_orders = $orders_model->del_redis_orders_p($branch_id, $table_id);
                if (!$del_redis_orders){
                     log::write( "现金订单完成后收尾".$table_id);
                }
                //设置状态
                $table_model = new TablesModel();
                $state = $table_model->set_table_state($table_id, $branch_id, 4);
            }
            // 服务员下单一对一推送
            $table_base = $table_model->get_table_by_id($table_id,$branch_id);
            $table_title = $table_base[\'title\'];
            Push::app_push_waiter_checkout($table_id, $table_title, \'1\');
            exit();

        }else{ //支付失败
            log::write( "支付订单号数据支付失败::支付订单号".$orders_info[\'transaction_id\']);
            exit();
        }
    }else{
        log::write( "支付订单号数据已处理".$orders_info[\'transaction_id\']);
        $this->returnXml();
        exit();
    }
}




     /**********写入日志方法***********/
    /**
     * 日志记录
     * @param  $path     string   日志文件目录
     * @param  $file     string   日志文件名,不包含后缀
     * @param  $content  string   记录内容
     * @param  @author yangzl     
     * @return void  
     **/
    public function writeLogs($path,$file,$content,$more=true){
        $newpath = \'\';
        if (!file_exists($path)) {
            mkdir ($path);
            @chmod ($path, 0777 );
        }
        if($more){
            $newpath .= $path.$file.@date(\'Y-m-d\').".log";
        }else{
            $newpath .= $path.$file.".log";
        }       
        $content .="\r\n"."----------------------------------------------------------------------------------------------------------------"."\r\n";
        $this->write_file($newpath,$content,"a+");
    }


 /**
     * 写内容
     * @param  $filename   string   日志文件名
     * @param  $data       string   记录内容
     * @param  $method     
     * @author yanzl
     **/
    private function write_file($filename,$data,$method="rb+",$iflock=1){
        @touch($filename);
        $handle=@fopen($filename,$method);
        if($iflock){
            @flock($handle,LOCK_EX);
        }
        @fputs($handle,$data);
        if($method=="rb+") @ftruncate($handle,strlen($data));
        @fclose($handle);
        @chmod($filename,0777); 
        if( is_writable($filename) ){
            return 1;
        }else{
            return 0;
        }
    }
}


 ?>