其实这个文档仅仅作为参考,如果应用到线上请完成签名验证
1.因为微信支付sdk非常全全面,而我值需要扫码支付即可,所以就把主要的代码提出来了
<?php class WxApi { private $config = array(); private $unifiedorder_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; private $sign = NULL ; public function __construct($config = array()){ $this -> config = $config ; } /** * @desc 统一下单接口 * * */ public function unifiedOrder($input = array()){ $return = array(); //检查必填参数 if(!$input['out_trade_no']){ $return['code_status'] = 1 ; $return['code_messate'] = '缺少统一支付接口必填参数out_trade_no!' ; }else if(!$input['body']){ $return['code_status'] = 2 ; $return['code_messate'] = '缺少统一支付接口必填参数body!' ; }else if(!$input['total_fee']){ $return['code_status'] = 3 ; $return['code_messate'] = '缺少统一支付接口必填参数total_fee!' ; }else if(!$input['trade_type']){ $return['code_status'] = 4 ; $return['code_messate'] = '缺少统一支付接口必填参数trade_type!' ; } if($input['trade_type'] == 'JSAPI' && !$input['openid']){ $return['code_status'] = 5 ; $return['code_messate'] = '统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!' ; } if($input['trade_type'] == 'NATIVE' && !$input['product_id']){ $return['code_status'] = 5 ; $return['code_messate'] = 'trade_type=NATIVE时,此参数必传。此参数为二维码中包含的商品ID,商户自行定义。' ; } if(!$input['notify_url'] && $this -> config['notify_url'] != '' ){ $input['notify_url'] = $this -> config['notify_url']; } //当缺少必要参数时需要返回数据重新配置必须的参数 if(!empty($return)){ return $return ; } $input['appid'] = $this -> config['appid']; $input['mch_id'] = $this -> config['mch_id']; $input['spbill_create_ip'] = $this -> config['ip']; $input['nonce_str'] = $this -> getNonceStr(); //签名 $sign = $this -> setMySign($input); //var_dump($sign);die; $input['sign'] = $sign ; $xml = $this -> arrayToXml($input); //开始请求订单 $response = $this -> postXmlCurl($this -> config,$xml,$this -> unifiedorder_url,false,6); $result = $this -> xmlToArray($response); //这里需要验证一下签名,暂时先不验证 方便测试 //self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 return $result; } private function setMySign($params,$signType = TRUE){ //签名步骤一:按字典序排序参数并拼接字符串 ksort($params); //var_dump($params); $string = ""; foreach ($params as $k => $v){ if($k != "sign" && $v != "" && !is_array($v)){ $string .= $k . "=" . $v . "&"; } } $string = trim($string, "&"); //echo $string ; //签名步骤二:在string后加入KEY $string = $string . "&key=" . $this -> config['key']; //签名步骤三:MD5加密或者HMAC-SHA256 if($this -> config['sign_type'] == "MD5"){ $string = md5($string); } else if($this -> config['sign_type'] == "HMAC-SHA256") { $string = hash_hmac("sha256",$string ,$this -> config['key']); } //签名步骤四:所有字符转为大写 $result = strtoupper($string); $this -> sign = $result ; return $result; } /** * * 产生随机字符串,不长于32位 * @param int $length * @return 产生的随机字符串 */ public static function getNonceStr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } /** * 输出xml字符 * @throws WxPayException **/ private function arrayToXml($array = array()) { if(!is_array($array) || count($array) <= 0) { throw new WxPayException("数组数据异常!"); } $xml = "<xml>"; foreach ($array as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; } /** * 将xml转为array * @param string $xml * @throws WxPayException */ private function xmlToArray($xml) { if(!$xml){ throw new WxPayException("xml数据异常!"); } //将XML转为array //禁止引用外部xml实体 libxml_disable_entity_loader(true); $array = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $array; } /** * 以post方式提交xml到对应的接口url * * @param WxPayConfigInterface $config 配置对象 * @param string $xml 需要post的xml数据 * @param string $url url * @param bool $useCert 是否需要证书,默认不需要 * @param int $second url执行超时时间,默认30s * @throws WxPayException */ private static function postXmlCurl($config, $xml, $url, $useCert = false, $second = 30) { $ch = curl_init(); $curlVersion = curl_version(); $ua = "WXPaySDK/3.0.9 (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." " . $config['mch_id']; //设置超时 curl_setopt($ch, CURLOPT_TIMEOUT, $second); $proxyHost = "0.0.0.0"; $proxyPort = 0; //$config->GetProxy($proxyHost, $proxyPort); //如果有配置代理这里就设置代理 if($proxyHost != "0.0.0.0" && $proxyPort != 0){ curl_setopt($ch,CURLOPT_PROXY, $proxyHost); curl_setopt($ch,CURLOPT_PROXYPORT, $proxyPort); } curl_setopt($ch,CURLOPT_URL, $url); if(stripos($url,"https://")!==FALSE){ curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); }else{ curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验 } curl_setopt($ch,CURLOPT_USERAGENT, $ua); //设置header curl_setopt($ch, CURLOPT_HEADER, FALSE); //要求结果为字符串且输出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); if($useCert == true){ //设置证书 //使用证书:cert 与 key 分别属于两个.pem文件 //证书文件请放入服务器的非web目录下 $sslCertPath = $config['sslcert_path']; $sslKeyPath = $config['sslkey_path']; $config->GetSSLCertPath($sslCertPath, $sslKeyPath); curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY, $sslKeyPath); } //post提交方式 curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); //运行curl $data = curl_exec($ch); //返回结果 if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); curl_close($ch); die("curl出错,错误码:$error"); } } }
2.使用方法:
require EXTEND_PATH . 'sdk.php'; class pay{ $payConfig = array( 'appid' => 'wx5f9d09f208cfa', 'mch_id' => '124002', 'key' => '8b15d56f894fab8035ac241cb39', 'app_secret' => '2e3fd5b24241646917265ee', 'sslcert_path' => '', 'sslkey_path' => '', 'ip' => '', 'sign_type' => 'MD5', ); /** * @desc 初始化方法 */ public function __construct(){ $this -> weixinConfig['sslcert_path'] = EXTEND_PATH . '/weixinpaysdk-3.0.9/cert/apiclient_cert.pem'; $this -> weixinConfig['sslkey_path'] = EXTEND_PATH . '/weixinpaysdk-3.0.9/cert/apiclient_key.pem'; $request = Request::instance(); $this -> weixinConfig['ip'] = $request -> ip(0,true); } /** * @desc 微信订单 * @author 646943067@qq.com * @version 1.0 * @date 2018-12-14 */ public function getWeixinOrder(){ $wxpayObj = new WxApi($this -> weixinConfig); $time = time(); $input = array( 'body' => '测试内容', 'attach' => '鸭题鸭课程PC版本', 'out_trade_no' => '1234567891', 'total_fee' => '1', 'time_start' => date("YmdHis",$time), 'time_expire' => date("YmdHis", $time + 600), 'notify_url' => 'http://paysdk.weixin.qq.com/notify.php', 'trade_type' => 'NATIVE', 'product_id' => '1000000003', ); $result = $wxpayObj -> unifiedOrder($input); $QRcode = new QRcode(); $level = 'L'; $size =4; ob_start(); $QRcode->png($result['code_url'],false,$level,$size,2); $imageString ="data:image/jpg;base64," . base64_encode(ob_get_contents()); ob_end_clean(); echo "<img src='$imageString' />"; } } $obj = new pay(); $obj -> getWeixinOrder();