thinkphp微信支払いと微信返金
以下のコードは自分のappid商家号商家鍵を修正して実行テストを行うことができます.
微信支払い
微信返金
返金には注文書番号と注文金額の2つの必要なパラメータが必要です
微信支払い
//
public function index(){
//
$data = [];
$data['sorts'] = input('sorts');//
$data['sciencename']=input('sciencename');//
$data['price']=input('price');//
$data['create_time']=time();//
$data['phone']=input('phone');//
$data['userid']=input('userid');// id
$data['menuid']=input('menuid');// id
$data['scienceid'] = input('scienceid');// ID
$data['num'] = input('num');// ID
if(input('type')){
$data['type']=input('type');//1
}
$user = Db::name('user_info')->where(array('id' => $data['userid']))->field('openid')->find();// openID
// ,
$fee = $data['price'];//
$appid = ' appid';//appid. appid
$body = $data['sorts'];
$mch_id = ' '; //
$nonce_str = $this->nonce_str();//
$notify_url = 'https://ht.hongtuzhijian.top/api/order/notifyurl'; // url
$openid = $user['openid'];
$time = time();
$year = date('Y',$time);
$rand = rand(000000000,999999999);
$out_trade_no = $year.$rand;//
//$out_trade_no = $this->order_number($openid);//
$spbill_create_ip = $_SERVER["REMOTE_ADDR"];// ip;
$total_fee = $fee*100;// , *100
$trade_type = 'JSAPI';//
$data['order_no']=$out_trade_no;
//echo json_encode($data);exit;
$order = Db::name('user_order')->insert($data);
//
$post['appid'] = $appid;
$post['body'] = $body;
$post['mch_id'] = $mch_id;
$post['nonce_str'] = $nonce_str;//
$post['notify_url'] = $notify_url;
$post['openid'] = $openid;
$post['out_trade_no'] = $out_trade_no;
$post['spbill_create_ip'] = $spbill_create_ip;// ip
$post['total_fee'] = $total_fee;//
$post['trade_type'] = $trade_type;
$sign = $this->sign($post);//
$post_xml = '
' .$appid.'
'.$body.'
' .$mch_id.'
' .$nonce_str.'
' .$notify_url.'
' .$openid.'
' .$out_trade_no.'
' .$spbill_create_ip.'
' .$total_fee.'
' .$trade_type.'
' .$sign.'
';
//print_r($post_xml);die;
// prepay_id
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//
$xml = $this->http_request($url,$post_xml);
$array = $this->xml($xml);//
//echo json_encode($array);exit;
//print_r($array);
unset($data);
//
if($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS'){
$time = time();
$tmp=[];//
$tmp['appId'] = $appid;
$tmp['nonceStr'] = $nonce_str;
$tmp['package'] = 'prepay_id='.$array['PREPAY_ID'];
$tmp['signType'] = 'MD5';
$tmp['timeStamp'] = $time;
$data['state'] = 200;
$data['timeStamp'] = $time;//
$data['nonceStr'] = $nonce_str;//
$data['signType'] = 'MD5';// , MD5
$data['package'] = 'prepay_id='.$array['PREPAY_ID'];// prepay_id
$data['paySign'] = $this->sign($tmp);//
$data['out_trade_no'] = $out_trade_no;
}else{
$data['state'] = 0;
$data['text'] = " ";
$data['RETURN_CODE'] = $array['RETURN_CODE'];
$data['RETURN_MSG'] = $array['RETURN_MSG'];
}
echo json_encode($data);
}
// 32
private function nonce_str(){
$result = '';
$str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
for ($i=0;$i<32;$i++){
$result .= $str[rand(0,48)];
}
return $result;
}
//
private function order_number($openid){
//date('Ymd',time()).time().rand(10,99);//18
return md5($openid.time().rand(10,99));//32
}
// $data
private function sign($data){
$stringA = '';
foreach ($data as $key=>$value){
if(!$value) continue;
if($stringA) $stringA .= '&'.$key."=".$value;
else $stringA = $key."=".$value;
}
$wx_key = ' key';// , key
$stringSignTemp = $stringA.'&key='.$wx_key;
return strtoupper(md5($stringSignTemp));
}
//curl
public function http_request($url,$data = null,$headers=array())
{
$curl = curl_init();
if( count($headers) >= 1 ){
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
// xml
public function xml($xml){
$p = xml_parser_create();
xml_parse_into_struct($p, $xml, $vals, $index);
xml_parser_free($p);
$data = [];
foreach ($index as $key=>$value) {
if($key == 'xml' || $key == 'XML') continue;
$tag = $vals[$value[0]]['tag'];
$value = $vals[$value[0]]['value'];
$data[$tag] = $value;
}
return $data;
}
//
public function notifyurl(){
$res_xml = file_get_contents("php://input");
libxml_disable_entity_loader(true);
$ret = json_decode(json_encode(simplexml_load_string($res_xml,'simpleXMLElement',LIBXML_NOCDATA)),true);
$data = array();
$data['order_sn'] = $ret['out_trade_no'];
$data['trade_no'] = $ret['transaction_id'];
$data['total_fee'] = $ret['total_fee'];
$check_info = DB::name('user_order')->where(array('order_no'=>$data['order_sn']))->find();
if (!$check_info) {
echo json_encode(array('state'=>1,'msg'=>' '));
}
if($ret['return_code'] == 'SUCCESS'){
$up = array();
$up['status'] = 2;
$up['update_time'] = time();
$res = DB::name('user_order')->where(array('order_no'=>$data['order_sn']))->update($up);//
}
//
if ($res) {
$xml = "" ;
$xml.="";
echo $xml;
}
}
微信返金
返金には注文書番号と注文金額の2つの必要なパラメータが必要です
/**
* , , ,
* @var array
*/
private $config = array(
'appid' => ' id', // id
'mch_id' => ' ',//
'pay_apikey' => ' key',// key
);
/**
* $this->name=$value
* @param string $name
* @param string $value
*/
public function __set($name,$value){
if(isset($this->config[$name])) {
$this->config[$name] = $value;
}
}
/**
* $this->name
* @param string $name
* @return multitype
*/
public function __get($name) {
return $this->config[$name];
}
public function __isset($name){
return isset($this->config[$name]);
}
//---------------------------------------------------------- ---------------------------------------------------------
/**
* (POST)
* @param string(28) $out_trade_no , ,
* @param string $out_refund_no
* @param string $total_fee ( : )
* @param string $refund_fee ( : )
* @return string xml
*/
public function refund($row){
$config = $this->config;
//
$refundorder = array(
'appid' => $config['appid'],
'mch_id' => $config['mch_id'],
'nonce_str' => $this->getNonceStr(),
'out_trade_no' => $row['order_no'],
'out_refund_no' => $row['order_no'],
'total_fee' => $row['price']*100,
'refund_fee' => $row['price']*100
);
$refundorder['sign'] = self::makeSign($refundorder);
// ,
$xmldata = self::array2xml($refundorder);
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
$res = self::curl_post_ssl($url, $xmldata);
if(!$res){
return array('status'=>0, 'msg'=>"Can't connect the server" );
}
// file_put_contents
// file_put_contents('./log3.txt',$res,FILE_APPEND);
$content = self::xml2array($res);
// if(strval($content['result_code']) == 'FAIL'){
//return array('status'=>0, 'msg'=>strval($content['err_code']).':'.strval($content['err_code_des']));
// }
if(strval($content['return_code']) == 'SUCCESS'){
//
//
}
// return $content;
}
//--------------------------------------------------------------- ------------------------------------------------------
/**
* XML
* @param array $arr
* @param int $level , 1 Root.
* @return string XML
*/
protected function array2xml($arr, $level = 1) {
$s = $level == 1 ? "" : '';
foreach($arr as $tagname => $value) {
if (is_numeric($tagname)) {
$tagname = $value['TagName'];
unset($value['TagName']);
}
if(!is_array($value)) {
$s .= "$tagname}>".(!is_numeric($value) ? ' : '').$value.(!is_numeric($value) ? ']]>' : '')."{
$tagname}>";
} else {
$s .= "$tagname}>" . $this->array2xml($value, $level + 1)."{
$tagname}>";
}
}
$s = preg_replace("/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/", ' ', $s);
return $level == 1 ? $s."" : $s;
}
/**
* xml array
* @param string $xml xml
* @return array
*/
protected function xml2array($xml){
// xml
libxml_disable_entity_loader(true);
$result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $result;
}
/**
*
* , 32
* @param int $length
* @return
*/
protected 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;
}
/**
*
* @return
*/
protected function makeSign($data){
//
$key = $this->config['pay_apikey'];
//
$data=array_filter($data);
// :
ksort($data);
$string_a=http_build_query($data);
$string_a=urldecode($string_a);
// : string KEY
$string_sign_temp=$string_a."&key=".$key;
// :MD5
$sign = md5($string_sign_temp);
// :
$result=strtoupper($sign);
return $result;
}
/**
* IP
* @return [String] [ip ]
*/
protected function getip() {
static $ip = '';
$ip = $_SERVER['REMOTE_ADDR'];
if(isset($_SERVER['HTTP_CDN_SRC_IP'])) {
$ip = $_SERVER['HTTP_CDN_SRC_IP'];
} elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach ($matches[0] AS $xip) {
if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
}
return $ip;
}
/**
*
*/
protected function curl_post_ssl($url, $xmldata, $second=30,$aHeader=array()){
$config = $this->config;
$ch = curl_init();
//
curl_setopt($ch,CURLOPT_TIMEOUT,$second);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
// ,
//curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
$cert = __DIR__.'/cert/apiclient_cert.pem';
$key = __DIR__.'/cert/apiclient_key.pem';
// PEM,
curl_setopt($ch,CURLOPT_SSLCERT, $cert); //
curl_setopt($ch,CURLOPT_SSLKEY, $key); //
//curl_setopt($ch,CURLOPT_CAINFO,$config['rootca']);
if( count($aHeader) >= 1 ){
curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
}
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS,$xmldata);
$data = curl_exec($ch);
if($data){
curl_close($ch);
return $data;
}else {
$error = curl_errno($ch);
echo "call faild, errorCode:$error
";
curl_close($ch);
return false;
}
}