paypal开发者账号申请地址
https://developer.paypal.com/
创建开发者账号后有一个买家账号 一个卖家账号 就可以测试paypal支付了
支付方式一:
paypal支付页面
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Paypal订单支付</title> </head> <body> <form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="POST" name="form_starPay"> <!-- // Live https://www.paypal.com/cgi-bin/webscr --> <input type=\'hidden\' name=\'cmd\' value=\'_xclick\'> <!-- //告诉paypal该表单是立即购买 --> <input type=\'hidden\' name=\'business\' value=\'test-facilitator@test.com\'> <!-- //卖家帐号 也就是收钱的帐号 --> <input type=\'hidden\' name=\'item_name\' value=\'支付订单:20180828080706000039\'> <!-- //商品名称 item_number --> <input type=\'hidden\' name=\'item_number\' value=\'20180828080706000039\'> <!-- //物品号 item_number --> <input type=\'hidden\' name=\'amount\' value=\'0.01\'> <!-- .// 订单金额 --> <input type=\'hidden\' name=\'currency_code\' value=\'HKD\'> <!-- .// 货币 --> <input type=\'hidden\' name=\'return\' value=\'http://test.cq.com/\'> <!-- .// 支付成功后网页跳转地址 --> <input type=\'hidden\' name=\'notify_url\' value=\'https://www.test.net/api/order/notify\'> <!-- .//支付成功后paypal后台发送订单通知地址 --> <input type=\'hidden\' name=\'cancel_return\' value=\'http://test.cq.com/\'> <!-- .//用户取消交易返回地址 --> <input type=\'hidden\' name=\'invoice\' value=\'20180828080706000039\'> <!-- .//自定义订单号 --> <input type=\'hidden\' name=\'charset\' value=\'utf-8\'> <!-- .// 字符集 --> <input type=\'hidden\' name=\'no_shipping\' value=\'1\'> <!-- .// 不要求客户提供收货地址 --> <input type=\'hidden\' name=\'no_note\' value=\'1\'> <!-- .// 付款说明 --> <input type=\'hidden\' name=\'rm\' value=\'2\'> <!-- 不知道是什么 --> <input type="image" name="submit" src="https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif" /> </form> 正在跳转Paypal支付,请稍等。。。 <script> function sub(){ document.form_starPay.submit(); } onload(sub()) </script> </body> </html>
支付回调,并进行ipn验证 将回调字段添加上$data[\'cmd\'] = \'_notify-validate\';返回进行验证
/** * 支付回调函数 * @author gyj <375023402@qq.com> * @createtime 2018-08-24T11:38:23+0800 * @return */ public function notify(){ if(!$this->request->isPost()) die(); //记录支付回调信息 if(!empty($_POST)){ $notify_str = "支付回调信息:\r\n"; foreach ($_POST as $key => $value) { $notify_str.=$key."=".$value.";\r\n"; } } log_result($notify_str,"paypal"); //ipn验证 $data = $_POST; $data[\'cmd\'] = \'_notify-validate\'; $url = config(\'paypal.gateway\');//支付异步验证地址 $res = https_request($url,$data); //记录支付ipn验证回调信息 log_result($res,\'paypal\'); if (!empty($res)) { if (strcmp($res, "VERIFIED") == 0) { if ($_POST[\'payment_status\'] == \'Completed\' || $_POST[\'payment_status\'] == \'Pending\') { //付款完成,这里修改订单状态 $order_res = $this->order_pay($_POST); if(!$order_res){ log_result(\'update order result fail\',\'paypal\'); } return \'success\'; } } elseif (strcmp($res, "INVALID") == 0) { //未通过认证,有可能是编码错误或非法的 POST 信息 return \'fail\'; } } else { //未通过认证,有可能是编码错误或非法的 POST 信息 return \'fail\'; } return \'fail\'; }
附上log_result函数 和https_result函数
log_result函数:
/** * 记录自定义日志 * @author gyj <375023402@qq.com> * @createtime 2018-08-24 14:12:01 * @param $msg 错误信息 * @param $type 写入类型 wechat aliyun * @return [type] [description] */ if(!function_exists(\'log_result\')){ function log_result($msg=\'\',$type=\'normal\') { $dir = dirname(LOG_PATH)."/log/".$type."/"; if(!is_dir($dir)){ mkdir($dir,0777); } $dir .= date(\'Ym\')."/"; $file = $dir.date(\'d\').".log"; if(!is_dir($dir)){ mkdir($dir,0777); } file_put_contents($file,date(\'Y-m-d H:i:s\')."\r\n".$msg."\r\n---------------------------------------------------------------\r\n", FILE_APPEND); } }
https_result函数:
/** * 发送post请求 * @author ganyuanjiang <3164145970@qq.com> * @createtime 2017-07-26 14:06:04 * @param string $url 请求地址 * @param array $post_data post键值对数据 * @return string */ if (!function_exists(\'https_request\')) { function https_request($url,$data=null){ header("Content-type: text/html; charset=utf-8"); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_USERAGENT, \'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)\'); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $tmpInfo = curl_exec($ch); if (curl_errno($ch)) { return curl_error($ch); } curl_close($ch); return $tmpInfo; } }
附上paypal支付记录表:
/* Navicat MySQL Data Transfer Source Server : localhost Source Server Version : 50553 Source Host : localhost:3306 Source Database : museum Target Server Type : MYSQL Target Server Version : 50553 File Encoding : 65001 Date: 2018-08-30 17:44:49 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for yu_paypal -- ---------------------------- DROP TABLE IF EXISTS `yu_paypal`; CREATE TABLE `yu_paypal` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT \'自增编号\', `cmd` char(20) NOT NULL DEFAULT \'\' COMMENT \'购物车系统\', `amount` decimal(11,2) unsigned NOT NULL DEFAULT \'0.00\' COMMENT \'订单支付金额\', `currency_code` char(10) NOT NULL DEFAULT \'\' COMMENT \'货币类型\', `return` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'支付成功跳转页面\', `no_shipping` char(5) CHARACTER SET utf8mb4 NOT NULL DEFAULT \'\', `no_note` char(5) NOT NULL DEFAULT \'\', `cancel_return` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'订单取消支付跳转链接\', `notify_url` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'支付回调\', `rm` char(5) NOT NULL DEFAULT \'\', `transaction_subject` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'交易主体\', `txn_type` char(50) NOT NULL DEFAULT \'\' COMMENT \'类型\', `payment_date` char(50) NOT NULL DEFAULT \'\' COMMENT \'支付时间\', `first_name` char(50) NOT NULL DEFAULT \'\' COMMENT \'名\', `last_name` char(50) NOT NULL DEFAULT \'\' COMMENT \'姓\', `residence_country` char(20) NOT NULL DEFAULT \'\' COMMENT \'居住国家\', `pending_reason` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'支付原因\', `item_name` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'支付商品名称\', `payment_gross` decimal(11,2) unsigned NOT NULL DEFAULT \'0.00\' COMMENT \'支付总额\', `mc_currency` char(20) NOT NULL DEFAULT \'\' COMMENT \'返回货币类型\', `business` char(100) NOT NULL DEFAULT \'\' COMMENT \'paypal商家账号\', `payment_type` char(20) NOT NULL DEFAULT \'\' COMMENT \'支付类型\', `protection_eligibility` char(100) NOT NULL DEFAULT \'\' COMMENT \'保护资质\', `verify_sign` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'验证字符串\', `payer_status` char(50) NOT NULL DEFAULT \'\' COMMENT \'付款人状态\', `test_ipn` char(20) NOT NULL DEFAULT \'\' COMMENT \'测试穿透网络\', `payer_email` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'支付者账号\', `txn_id` char(50) NOT NULL DEFAULT \'\' COMMENT \'txn编号\', `quantity` int(11) unsigned NOT NULL DEFAULT \'0\' COMMENT \'数量\', `receiver_email` char(100) NOT NULL DEFAULT \'\' COMMENT \'收款账号\', `invoice` char(20) NOT NULL DEFAULT \'\' COMMENT \'订单号\', `payer_id` char(50) NOT NULL DEFAULT \'\' COMMENT \'付款人编号\', `receiver_id` char(50) NOT NULL DEFAULT \'\' COMMENT \'收款人编号\', `item_number` char(50) NOT NULL DEFAULT \'\' COMMENT \'物品号\', `payment_status` char(100) NOT NULL DEFAULT \'\' COMMENT \'支付状态\', `mc_gross` decimal(11,2) unsigned NOT NULL DEFAULT \'0.00\' COMMENT \'订单金额\', `custom` varchar(255) NOT NULL DEFAULT \'\' COMMENT \'客户\', `charset` char(10) NOT NULL DEFAULT \'\' COMMENT \'编码\', `notify_version` char(5) NOT NULL DEFAULT \'\' COMMENT \'支付回调版本\', `ipn_track_id` char(20) NOT NULL DEFAULT \'\' COMMENT \'ipn追踪编号\', `payment_fee` char(50) NOT NULL DEFAULT \'\' COMMENT \'支付金额\', `mc_fee` decimal(11,2) unsigned NOT NULL DEFAULT \'0.00\' COMMENT \'交易金额\', `create_time` int(11) unsigned NOT NULL DEFAULT \'0\' COMMENT \'创建时间\', `update_time` int(11) unsigned NOT NULL DEFAULT \'0\' COMMENT \'更新时间\', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT=\'paypal支付表\';
支付方式二:
1.引入官方demo
2.配置
登入paypal 开发者管理 找到client id 和secret
回调地址配置
<?php // +---------------------------------------------------------------------- // | PAYPAL[ PAYPAL ] // +---------------------------------------------------------------------- // | Copyright (c) 2018 https://www.cq.com All rights reserved. // +---------------------------------------------------------------------- // | Base on ( ThinkPHP 5.0 http://thinkphp.cn) // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: gyj <375023402@qq.com> // +---------------------------------------------------------------------- // | CreateTime: 2018-09-13 15:34:49 // +---------------------------------------------------------------------- namespace app\api\controller; require \'../extend/PayPal/autoload.php\'; use app\api\controller\Common; use app\api\controller\Order; use think\db; use PayPal\Api\Amount; use PayPal\Api\Details; use PayPal\Api\Item; use PayPal\Api\ItemList; use PayPal\Api\Payer; use PayPal\Api\Payment; use PayPal\Api\RedirectUrls; use PayPal\Api\Transaction; use PayPal\Api\ExecutePayment; use PayPal\Api\PaymentExecution; class Paypal extends Common { /** * 初始化 * @author gyj <375023402@qq.com> * @createtime 2018-09-13T15:38:07+0800 * @return */ public function _initialize(){ // Autoload SDK package for composer based installations $this->apiContext = new \PayPal\Rest\ApiContext( new \PayPal\Auth\OAuthTokenCredential( \'Client ID\', \'Secret\' ) ); } /** * 创建paypal支付订单 * @author gyj <375023402@qq.com> * @createtime 2018-09-13T15:43:35+0800 * @return */ public function pay($order_no=\'\',$pay=0){ //parameters validate if (empty($order_no) || empty($pay)) { $this->error(\'Lack of parameters of order_no or pay\'); } // Create new payer and method $payer = new Payer(); $payer->setPaymentMethod("paypal"); // Set redirect URLs $redirectUrls = new RedirectUrls(); $redirectUrls->setReturnUrl(config(\'paypal.return\')) ->setCancelUrl(config(\'paypal.cancel_return\')); // Set payment amount $amount = new Amount(); $amount->setCurrency(config(\'paypal.currency_code\')) ->setTotal($pay); // Set transaction object $transaction = new Transaction(); $transaction->setAmount($amount) ->setDescription("yucolab order pay,order_no:".$order_no) ->setInvoiceNumber($order_no); // Create the full payment object $payment = new Payment(); $payment->setIntent(\'sale\') ->setPayer($payer) ->setRedirectUrls($redirectUrls) ->setTransactions(array($transaction)); // Create payment with valid API context try { $payment->create($this->apiContext); // Get PayPal redirect URL and redirect the customer $approvalUrl = $payment->getApprovalLink(); // Redirect the customer to $approvalUrl } catch (PayPal\Exception\PayPalConnectionException $ex) { echo $ex->getCode(); echo $ex->getData(); die($ex); } catch (Exception $ex) { die($ex); } $this->redirect($approvalUrl); } /** * 支付提交 * @author gyj <375023402@qq.com> * @createtime 2018-09-13T15:44:15+0800 * @return */ public function execute(){ // Get payment object by passing paymentId $paymentId = $_GET[\'paymentId\']; $payment = Payment::get($paymentId, $this->apiContext); $payerId = $_GET[\'PayerID\']; // Execute payment with payer ID $execution = new PaymentExecution(); $execution->setPayerId($payerId); try { // Execute payment $result = $payment->execute($execution, $this->apiContext); } catch (PayPal\Exception\PayPalConnectionException $ex) { echo $ex->getCode(); echo $ex->getData(); die($ex); } catch (Exception $ex) { die($ex); } //success page $this->redirect(config(\'paypal.success_url\')); } /** * 取消支付 * @author gyj <375023402@qq.com> * @createtime 2018-09-13T16:00:31+0800 * @return */ public function cancel(){ //cancel page $this->redirect(config(\'paypal.cancel_url\')); } /** * 回调函数 * @author gyj <375023402@qq.com> * @createtime 2018-09-14T16:38:20+0800 * @return */ public function notify(){ if(!$this->request->isPost()) die(); //获取回调结果 $json_data = get_JsonData(); if(!empty($json_data)){ log_result("paypal notify info:\r\n".json_encode($json_data),"paypal"); } //组装支付回调信息 $data[\'invoice\'] = $json_data[\'resource\'][\'invoice_number\']; $data[\'txn_id\'] = $json_data[\'id\']; $data[\'total\'] = $json_data[\'resource\'][\'amount\'][\'total\']; $data[\'status\'] = $json_data[\'status\']?$json_data[\'status\']:\'\'; $data[\'state\'] = $json_data[\'resource\'][\'state\']; $data[\'result\'] = json_encode($json_data); $data[\'create_time\'] = time(); try { //查询订单信息 $where_order[\'status\'] = 0; $where_order[\'order_no\'] = $data[\'invoice\']; $order_info = db(\'order\')->where($where_order)->find(); if(!$order_info){ throw new \Exception("no pay order not find,order_no:".$data[\'invoice\']." "); } if($order_info[\'pay\'] != $data[\'total\']){ $is_eq = ($order_info[\'pay\'] == $data[\'total\'])?"yes":"no"; throw new \Exception("order pay neq paypal total:order_info=".$order_info[\'pay\']."&paypal total=".$data[\'total\']."&result=".$is_eq); } //数据库记录支付回调信息 $res = db(\'paypal\')->insert($data); if(!$res){ throw new \Exception("Payment callback:Update paypal payment information failed-update fail"); } //判断支付结果,如果支付完成 修改订单状态 if($json_data[\'resource\'][\'state\'] == \'completed\'){ //订单状态修改 $order = new Order(); $order->pay($data); } } catch (\Exception $e) { //记录错误日志 log_result("paypal notify fail:".$e->getMessage(),"paypal"); return "fail"; } return "success"; } }
回调返回json
{ "id": "WH-35K39776SH675420T-56W661149E290963N", "event_version": "1.0", "create_time": "2018-09-14T10:49:03.910Z", "resource_type": "sale", "event_type": "PAYMENT.SALE.COMPLETED", "summary": "Payment completed for HKD 66.0 HKD", "resource": { "id": "16R917890C546780W", "state": "completed", "amount": { "total": "66.00", "currency": "HKD", "details": { "subtotal": "66.00" } }, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": { "value": "4.59", "currency": "HKD" }, "invoice_number": "20180914172359000001", "parent_payment": "PAY-4DS45691CB844050NLONZD2Y", "create_time": "2018-09-14T10:48:42Z", "update_time": "2018-09-14T10:48:42Z", "links": [ { "href": "https://api.sandbox.paypal.com/v1/payments/sale/16R917890C546780W", "rel": "self", "method": "GET" }, { "href": "https://api.sandbox.paypal.com/v1/payments/sale/16R917890C546780W/refund", "rel": "refund", "method": "POST" }, { "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-4DS45691CB844050NLONZD2Y", "rel": "parent_payment", "method": "GET" } ] }, "links": [ { "href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-35K39776SH675420T-56W661149E290963N", "rel": "self", "method": "GET" }, { "href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-35K39776SH675420T-56W661149E290963N/resend", "rel": "resend", "method": "POST" } ] }
附上函数:
获取json数据转换成数组
/**获取json数据 * @param $uid 用户主键id * @param $salt 用户盐值 * @return string token字符串 */ function get_JsonData(){ $json = file_get_contents(\'php://input\'); if ($json) { $json = str_replace("\'", \'\', $json); $json = json_decode($json,true); } return $json; }
paypal数据库
/* Navicat MySQL Data Transfer Source Server : 127.0.0.1 Source Server Version : 50553 Source Host : 127.0.0.1:3306 Source Database : museum Target Server Type : MYSQL Target Server Version : 50553 File Encoding : 65001 Date: 2018-09-17 11:22:29 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for yu_paypal -- ---------------------------- DROP TABLE IF EXISTS `yu_paypal`; CREATE TABLE `yu_paypal` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT \'自增编号\', `invoice` char(20) NOT NULL DEFAULT \'\' COMMENT \'订单号\', `txn_id` char(100) NOT NULL DEFAULT \'\' COMMENT \'回调编号\', `total` decimal(11,2) unsigned NOT NULL DEFAULT \'0.00\' COMMENT \'支付金额\', `status` char(50) NOT NULL DEFAULT \'\' COMMENT \'请求状态\', `state` char(50) NOT NULL DEFAULT \'\' COMMENT \'支付状态\', `result` text NOT NULL COMMENT \'回调结果\', `create_time` int(11) unsigned NOT NULL DEFAULT \'0\' COMMENT \'创建时间\', PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT=\'paypal回调结果\';