├── alipay ├── cacert.pem ├── key │ ├── rsa_private_key.pem │ └── alipay_public_key_app.pem ├── log.txt ├── config.php ├── lib │ ├── alipay_rsa.function.php │ └── alipay_core.function.php ├── alipay_submit.class.php └── alipay_notify.class.php ├── README.md ├── AlipayCallback.php ├── index.php ├── notify.php ├── Alipay.php └── tb_pay_log.sql /alipay/cacert.pem: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /alipay/key/rsa_private_key.pem: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /alipay/key/alipay_public_key_app.pem: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /alipay/log.txt: -------------------------------------------------------------------------------- 1 | 集成时请注意: 2 | 本文件log.txt请不要删除。 3 | 该文本用于写日志函数。 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 支付宝支付APP服务器端代码逻辑处理 2 | 3 | 4 | index.php:支付宝APP支付(服务器端完成统一下单,将数据传输给APP,APP调起返回的支付信息完成支付) 5 | 6 | notify.php:支付宝APP支付异步通知,更改订单状态。 7 | 8 | config.php:支付宝开发者配置文件 9 | 10 | tb_pay_log.sql:支付日志数据库文件 11 | 12 | 13 | 有问题可以发送到此邮箱:shangheguang#yeah.net 把#替换为@ 14 | 15 | 16 | 17 | 111 18 | -------------------------------------------------------------------------------- /AlipayCallback.php: -------------------------------------------------------------------------------- 1 | alipay_config = $alipay_config; 20 | } 21 | 22 | //支付宝页面跳转同步通知 23 | public function checkReturn() { 24 | $alipayNotify = new AlipayNotify($this->alipay_config); 25 | return $alipayNotify->verifyReturn(); 26 | } 27 | 28 | //支付宝服务器异步通知 29 | public function checkNotify() { 30 | $alipayNotify = new AlipayNotify($this->alipay_config); 31 | return $alipayNotify->verifyNotify(); 32 | } 33 | 34 | //解密 35 | public function decrypt($prestr) { 36 | $alipayNotify = new AlipayNotify($this->alipay_config); 37 | return $alipayNotify->decrypt($prestr); 38 | } 39 | 40 | //__destruct 41 | function __destruct() { 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /alipay/config.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | out_trade_no = date('YmdHis') . substr(time(), - 5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));//订单号 12 | $Alipay->subject = '描述信息';//支付描述信息 13 | $Alipay->body = '主体信息';//支付描述信息 14 | $Alipay->total_fee = 1;//订单总金额,1元 15 | $Alipay->it_b_pay = (time()+86400).'m';//订单支付的过期时间(eg:一天过期); 16 | $Alipay->notify_url = 'http://www.baidu.cn/v1/alipay/notify/'; 17 | 18 | //数据以JSON的形式返回给APP 19 | $app_response = $Alipay->doPay(); 20 | if ($app_response == false) { 21 | $errorCode = 100; 22 | $errorMsg = 'sign error'; 23 | echoResult($errorCode, $errorMsg); 24 | } else { 25 | $errorCode = 0; 26 | $errorMsg = 'success'; 27 | $responseData = array( 28 | 'notify_url' => $Alipay->notify_url, 29 | 'app_response' => $Alipay->doPay() 30 | ); 31 | echoResult($errorCode, $errorMsg, $responseData); 32 | } 33 | 34 | //接口输出 35 | function echoResult($errorCode = 0, $errorMsg = 'success', $responseData = array()) 36 | { 37 | $arr = array( 38 | 'errorCode' => $errorCode, 39 | 'errorMsg' => $errorMsg, 40 | 'responseData' => $responseData, 41 | ); 42 | exit(json_encode($arr)); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /notify.php: -------------------------------------------------------------------------------- 1 | alipay_config); 13 | $verify_result = $AlipayNotify->verifyNotify(); 14 | if ($verify_result) { 15 | //通知的原始数据 16 | $requestReturnData = file_get_contents("php://input"); 17 | //商户订单号 18 | $out_trade_no = isset($_REQUEST['out_trade_no']) ? $_REQUEST['out_trade_no'] : ''; 19 | //支付宝交易号 20 | $trade_no = isset($_REQUEST['trade_no']) ? $_REQUEST['trade_no'] : ''; 21 | //交易状态 22 | $trade_status = isset($_REQUEST['trade_status']) ? $_REQUEST['trade_status'] : ''; 23 | //支付金额 24 | $total_fee = isset($_REQUEST['total_fee']) ? $_REQUEST['total_fee'] : ''; 25 | //支付时间 26 | $pay_date = isset($_REQUEST['gmt_payment']) ? $_REQUEST['gmt_payment'] : ''; 27 | /* 28 | @todo 29 | 1.更改订单状态为已支付。(需自己完善) 30 | 2.添加付款信息到数据库,方便对账。(需自己完善) 31 | */ 32 | $pay_arr = array( 33 | 'pay_type' => isset($_REQUEST['pay_type']) ? $_REQUEST['pay_type'] : '', 34 | 'action' => 'notify', 35 | 'domain_type' => isset($_REQUEST['domain_type']) ? $_REQUEST['domain_type'] : '', 36 | 'out_trade_no' => $out_trade_no, 37 | 'trade_no' => $trade_no, 38 | 'trade_status' => $trade_status, 39 | 'trade_return_data' => $requestReturnData, 40 | ); 41 | //判断状态 42 | if (in_array($trade_status, array('TRADE_FINISHED', 'TRADE_SUCCESS'))) { 43 | //更新订单。。。。。。 44 | //处理后同步返回给支付宝 45 | exit('success'); 46 | } 47 | } 48 | exit('fail'); 49 | 50 | 51 | -------------------------------------------------------------------------------- /alipay/lib/alipay_rsa.function.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /alipay/alipay_submit.class.php: -------------------------------------------------------------------------------- 1 | alipay_config = $alipay_config; 21 | } 22 | 23 | function AlipaySubmit($alipay_config) { 24 | $this->__construct($alipay_config); 25 | } 26 | 27 | /** 28 | * 生成要请求给支付宝的参数数组 29 | * @param $para_temp 请求前的参数数组 30 | * @return 要请求的参数数组 31 | */ 32 | function buildRequestPara($para_temp) { 33 | //除去待签名参数数组中的空值和签名参数 34 | $para_filter = paraFilter($para_temp); 35 | 36 | //对待签名参数数组排序 37 | $para_sort = argSort($para_filter); 38 | 39 | //生成签名结果 40 | $mysign = $this->buildRequestMysign($para_sort); 41 | 42 | //签名结果与签名方式加入请求提交参数组中 43 | $para_sort['sign'] = urlencode($mysign); 44 | $para_sort['sign_type'] = strtoupper(trim($this->alipay_config['sign_type'])); 45 | 46 | return $para_sort; 47 | } 48 | 49 | /** 50 | * 生成签名结果 51 | * @param $para_sort 已排序要签名的数组 52 | * return 签名结果字符串 53 | */ 54 | function buildRequestMysign($para_sort) { 55 | //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 56 | $prestr = $this->createAppLinkstring($para_sort); 57 | 58 | $mysign = ""; 59 | switch (strtoupper(trim($this->alipay_config['sign_type']))) { 60 | case "RSA" : 61 | $mysign = rsaSign($prestr, $this->alipay_config['private_key_path']); 62 | break; 63 | case "0001" : 64 | $mysign = rsaSign($prestr, $this->alipay_config['private_key_path']); 65 | break; 66 | default : 67 | $mysign = ""; 68 | } 69 | 70 | return $mysign; 71 | } 72 | 73 | /** 74 | * 把数组所有元素,按照“参数="参数值"”的模式用“&”字符拼接成字符串 75 | * @param $para 需要拼接的数组 76 | * return 拼接完成以后的字符串 77 | */ 78 | function createAppLinkstring($para) { 79 | $arg = ""; 80 | while (list ($key, $val) = each ($para)) { 81 | $arg.=$key."=\"".$val."\"&"; 82 | } 83 | //去掉最后一个&字符 84 | $arg = substr($arg,0,count($arg)-2); 85 | 86 | //如果存在转义字符,那么去掉转义 87 | if(get_magic_quotes_gpc()){$arg = stripslashes($arg);} 88 | 89 | return $arg; 90 | } 91 | } 92 | ?> -------------------------------------------------------------------------------- /Alipay.php: -------------------------------------------------------------------------------- 1 | alipay_config = $alipay_config; 45 | } 46 | 47 | public function chkParam() { 48 | 49 | //用户网站订单号 50 | if (empty($this->out_trade_no)) { 51 | die('out_trade_no error'); 52 | } 53 | 54 | //支付标题 55 | if (empty($this->subject)) { 56 | die('subject error'); 57 | } 58 | 59 | //支付描述 60 | if (empty($this->body)) { 61 | $this->body = $this->subject; 62 | } 63 | 64 | //检测支付金额 65 | if (empty($this->total_fee) || !is_numeric($this->total_fee)) { 66 | die('total_fee error'); 67 | } 68 | 69 | //回调URL地址 70 | if (empty($this->notify_url)) { 71 | die('notify_url error'); 72 | } 73 | if (!preg_match("#^http:\/\/#i", $this->notify_url)) { 74 | $this->notify_url = "http://" . $_SERVER['HTTP_HOST'] . $this->notify_url; 75 | } 76 | 77 | } 78 | 79 | //生成提交支付宝参数数组 80 | public function createAppPara() { 81 | 82 | //检测构造参数 83 | $this->chkParam(); 84 | 85 | //构造要请求的参数数组,无需改动 86 | $parameter = array( 87 | "partner" => $this->alipay_config['partner'], 88 | "seller_id" => $this->seller_email, 89 | "out_trade_no" => $this->out_trade_no, 90 | "subject" => $this->subject, 91 | "body" => $this->body, 92 | "total_fee" => $this->total_fee, 93 | "notify_url" => $this->notify_url, 94 | "service" => "mobile.securitypay.pay", 95 | "_input_charset" => trim(strtolower($this->alipay_config['input_charset'])), 96 | "it_b_pay" => $this->it_b_pay, 97 | "sign_type" => trim(strtoupper($this->alipay_config['sign_type'])), 98 | "sign" => "", 99 | ); 100 | //建立请求 101 | $AlipaySubmit = new AlipaySubmit($this->alipay_config); 102 | return $AlipaySubmit->buildRequestPara($parameter); 103 | } 104 | 105 | //生成提交支付宝参数字符串 106 | public function createAppLink() { 107 | 108 | $parameter_sort = $this->createAppPara(); 109 | if (!isset($parameter_sort['sign']) || empty($parameter_sort['sign'])) { 110 | return false; 111 | } 112 | 113 | $AlipaySubmit = new AlipaySubmit($this->alipay_config); 114 | return $AlipaySubmit->createAppLinkstring($parameter_sort); 115 | } 116 | 117 | //生成支付 118 | public function doPay() { 119 | 120 | return $this->createAppLink(); 121 | } 122 | 123 | //__destruct 124 | function __destruct() { 125 | } 126 | } 127 | 128 | -------------------------------------------------------------------------------- /tb_pay_log.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 4.6.0 3 | -- http://www.phpmyadmin.net 4 | -- 5 | -- Host: localhost 6 | -- Generation Time: 2016-07-19 06:16:09 7 | -- 服务器版本: 5.6.19 8 | -- PHP Version: 7.0.5 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | SET time_zone = "+00:00"; 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8mb4 */; 18 | 19 | -- 20 | -- Database: `test` 21 | -- 22 | 23 | -- -------------------------------------------------------- 24 | 25 | -- 26 | -- 表的结构 `tb_pay_log` 27 | -- 28 | 29 | CREATE TABLE `tb_pay_log` ( 30 | `id` bigint(20) UNSIGNED NOT NULL, 31 | `pay_type` tinyint(4) UNSIGNED NOT NULL DEFAULT '0' COMMENT '支付渠道类型[1:支付宝,2微信]', 32 | `action` varchar(10) NOT NULL DEFAULT '' COMMENT '[return,notify]', 33 | `domain_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '来源域名(1www 2m 3ios 4android)', 34 | `out_trade_no` varchar(30) NOT NULL DEFAULT '' COMMENT '商家订单编号', 35 | `trade_no` varchar(30) NOT NULL DEFAULT '' COMMENT '平台交易号', 36 | `trade_status` varchar(30) NOT NULL DEFAULT '' COMMENT '交易状态', 37 | `trade_return_data` text NOT NULL COMMENT '平台返回数据', 38 | `create_ip` varchar(30) NOT NULL DEFAULT '' COMMENT '用户支付IP', 39 | `create_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间' 40 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 41 | 42 | -- 43 | -- 转存表中的数据 `tb_pay_log` 44 | -- 45 | 46 | INSERT INTO `tb_pay_log` (`id`, `pay_type`, `action`, `domain_type`, `out_trade_no`, `trade_no`, `trade_status`, `trade_return_data`, `create_ip`, `create_date`) VALUES 47 | (1, 2, 'notify', 3, '20160108230835657155974231', '1009880762201601082587876156', 'SUCCESS', '\n\n\n\n\n\n\n\n\n\n\n\n\n\n47200\n\n\n', '140.207.54.75', '2016-01-08 23:08:52'), 48 | (2, 1, 'notify', 3, '20151221230600103605339363', '2015122121001004100010912642', 'TRADE_FINISHED', 'discount=0.00&payment_type=1&subject=标题&trade_no=2015111821001004460078599104&buyer_email=243882284@qq.com&gmt_create=2015-12-18 22:01:37¬ify_type=trade_status_sync&quantity=1&out_trade_no=20151218220127472878962898&seller_id=2033901888618287¬ify_time=2016-03-18 22:02:34&body=主题&trade_status=TRADE_FINISHED&is_total_fee_adjust=N&total_fee=120.00&gmt_payment=2015-12-18 22:01:38&seller_email=shangheguang@yeah.com&gmt_close=2016-03-18 22:02:34&price=120.00&buyer_id=1288702326699464¬ify_id=e9063f932b7bc86b85366a5b7451a27jjs&use_coupon=N&sign_type=RSA&sign=ANpF7OIJHIatkrBpbrY1dQKQqKlK8PQOlbZiOQX5r19S5FE7Eb9ArC5tN5n19X2fIEtRcD9rLctM9F1uc4VAxMOt8j+DWZa+5YuBHGMuoA+0E3WDTBeAq59veLtbno1PL1vPWpEaz8zXbRH1Nt55XC3oTCR8Wfvdt2/eTbTAjLM=', '110.75.225.147', '2016-03-21 23:06:36'); 49 | 50 | -- 51 | -- Indexes for dumped tables 52 | -- 53 | 54 | -- 55 | -- Indexes for table `tb_pay_log` 56 | -- 57 | ALTER TABLE `tb_pay_log` 58 | ADD PRIMARY KEY (`id`); 59 | 60 | -- 61 | -- 在导出的表使用AUTO_INCREMENT 62 | -- 63 | 64 | -- 65 | -- 使用表AUTO_INCREMENT `tb_pay_log` 66 | -- 67 | ALTER TABLE `tb_pay_log` 68 | MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; 69 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 70 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 71 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 72 | -------------------------------------------------------------------------------- /alipay/alipay_notify.class.php: -------------------------------------------------------------------------------- 1 | alipay_config = $alipay_config; 32 | } 33 | function AlipayNotify($alipay_config) { 34 | $this->__construct($alipay_config); 35 | } 36 | /** 37 | * 针对notify_url验证消息是否是支付宝发出的合法消息 38 | * @return 验证结果 39 | */ 40 | function verifyNotify(){ 41 | if(empty($_POST)) {//判断POST来的数组是否为空 42 | return false; 43 | } 44 | else { 45 | //生成签名结果 46 | $isSign = $this->getSignVeryfy($_POST, $_POST["sign"]); 47 | //获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息) 48 | $responseTxt = 'true'; 49 | if (! empty($_POST["notify_id"])) {$responseTxt = $this->getResponse($_POST["notify_id"]);} 50 | 51 | //写日志记录 52 | //if ($isSign) { 53 | // $isSignStr = 'true'; 54 | //} 55 | //else { 56 | // $isSignStr = 'false'; 57 | //} 58 | //$log_text = "responseTxt=".$responseTxt."\n notify_url_log:isSign=".$isSignStr.","; 59 | //$log_text = $log_text.createLinkString($_POST); 60 | //logResult($log_text); 61 | 62 | //验证 63 | //$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关 64 | //isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关 65 | if (preg_match("/true$/i",$responseTxt) && $isSign) { 66 | return true; 67 | } else { 68 | return false; 69 | } 70 | } 71 | } 72 | 73 | /** 74 | * 针对return_url验证消息是否是支付宝发出的合法消息 75 | * @return 验证结果 76 | */ 77 | function verifyReturn(){ 78 | if(empty($_GET)) {//判断POST来的数组是否为空 79 | return false; 80 | } 81 | else { 82 | //生成签名结果 83 | $isSign = $this->getSignVeryfy($_GET, $_GET["sign"]); 84 | //获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息) 85 | $responseTxt = 'true'; 86 | if (! empty($_GET["notify_id"])) {$responseTxt = $this->getResponse($_GET["notify_id"]);} 87 | 88 | //写日志记录 89 | //if ($isSign) { 90 | // $isSignStr = 'true'; 91 | //} 92 | //else { 93 | // $isSignStr = 'false'; 94 | //} 95 | //$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.","; 96 | //$log_text = $log_text.createLinkString($_GET); 97 | //logResult($log_text); 98 | 99 | //验证 100 | //$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关 101 | //isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关 102 | if (preg_match("/true$/i",$responseTxt) && $isSign) { 103 | return true; 104 | } else { 105 | return false; 106 | } 107 | } 108 | } 109 | 110 | /** 111 | * 获取返回时的签名验证结果 112 | * @param $para_temp 通知返回来的参数数组 113 | * @param $sign 返回的签名结果 114 | * @return 签名验证结果 115 | */ 116 | function getSignVeryfy($para_temp, $sign) { 117 | //除去待签名参数数组中的空值和签名参数 118 | $para_filter = paraFilter($para_temp); 119 | 120 | //对待签名参数数组排序 121 | $para_sort = argSort($para_filter); 122 | 123 | //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 124 | $prestr = createLinkstring($para_sort); 125 | 126 | $isSgin = false; 127 | switch (strtoupper(trim($this->alipay_config['sign_type']))) { 128 | case "RSA" : 129 | $isSgin = rsaVerify($prestr, trim($this->alipay_config['ali_public_key_path']), $sign); 130 | break; 131 | case "0001" : 132 | $isSgin = rsaVerify($prestr, trim($this->alipay_config['ali_public_key_path']), $sign); 133 | break; 134 | default : 135 | $isSgin = false; 136 | } 137 | 138 | return $isSgin; 139 | } 140 | 141 | /** 142 | * 获取远程服务器ATN结果,验证返回URL 143 | * @param $notify_id 通知校验ID 144 | * @return 服务器ATN结果 145 | * 验证结果集: 146 | * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空 147 | * true 返回正确信息 148 | * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟 149 | */ 150 | function getResponse($notify_id) { 151 | $transport = strtolower(trim($this->alipay_config['transport'])); 152 | $partner = trim($this->alipay_config['partner']); 153 | $veryfy_url = ''; 154 | if($transport == 'https') { 155 | $veryfy_url = $this->https_verify_url; 156 | } 157 | else { 158 | $veryfy_url = $this->http_verify_url; 159 | } 160 | $veryfy_url = $veryfy_url."partner=" . $partner . "¬ify_id=" . $notify_id; 161 | $responseTxt = getHttpResponseGET($veryfy_url, $this->alipay_config['cacert']); 162 | 163 | return $responseTxt; 164 | } 165 | } 166 | ?> 167 | -------------------------------------------------------------------------------- /alipay/lib/alipay_core.function.php: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------