项目需要要在php中使用paypal支付。
先吐槽下paypal,以前做过国内的一些支付接口,有些经验。想到的是直接找paypal客服要接口文档。
尼玛加paypal客服QQ 不在线。几天如此。这么大的支付居然没技术支持,真不能理解。文档后面还是在官网7找8找才找到了。
正文:
首先要在sandbox环境申请主帐号。连接:https://developer.paypal.com/
申请后用主帐号登录申请卖家以及买家帐号。然后进行一些设置。
注意:如果买家是国外的,那么创建买家帐号的时候就要设置所在国家。这样在支付页面才会以该国家的语言显示界面。
申请帐号以及设置问题请参考文档 连接:https://www.paypal-biz.com/development/documentation/PayPal_Sandbox_Guide_CN_V2.0.pdf
支付过程首先第一步是提交表单给paypal 当然post方式。
<span style="color: #0000ff;"><span style="color: #800000;">form </span><span style="color: #ff0000;">id</span><span style="color: #0000ff;">="form_starPay"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="form_starPay"</span><span style="color: #ff0000;"> action</span><span style="color: #0000ff;">="https://www.sandbox.paypal.com/cgi-bin/webscr"</span><span style="color: #ff0000;"> method</span><span style="color: #0000ff;">="post"</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="cmd"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="_xclick"</span><span style="color: #0000ff;">></span> //告诉paypal该表单是立即购买 <span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="business"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="XXXXXX@XXXXX.com"</span><span style="color: #0000ff;">></span> //卖家帐号 也就是收钱的帐号 <span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="item_name"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="name"</span><span style="color: #0000ff;">></span> //商品名称 <span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="amount"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="10000"</span><span style="color: #0000ff;">></span> //价格 <span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="currency_code"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="JPY"</span><span style="color: #0000ff;">></span> //币种 <span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="return"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="http://localhost/frontend/pay/PDT_order"</span><span style="color: #0000ff;">> //支付成功后网页跳转地址</span> <span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="notify_url"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="http://localhost/frontend/pay/IPN_Order"</span><span style="color: #0000ff;">> </span>//支付成功后paypal后台发送订单通知地址<br><span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="invoice"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">=""</span><span style="color: #0000ff;">> //自定义订单号 paypal原样返回<br></span><span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="custom"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">=""</span><span style="color: #0000ff;">></span><span style="line-height: 1.5;"> // 自定义变量 paypal原样返回<br></span><span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="hidden"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="lc"</span><span style="color: #ff0000;"> value</span><span style="color: #0000ff;">="JP"</span><span style="color: #0000ff;">></span><span style="line-height: 1.5;"> //支付页面语言设置<br></span><span style="color: #0000ff;"><span style="color: #800000;">input </span><span style="color: #ff0000;">style</span><span style="color: #0000ff;">="visibility:hidden"</span><span style="color: #ff0000;"> type</span><span style="color: #0000ff;">="image"</span><span style="color: #ff0000;"> src</span><span style="color: #0000ff;">=" https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif "</span><span style="color: #ff0000;"> border</span><span style="color: #0000ff;">="0"</span><span style="color: #ff0000;"> name</span><span style="color: #0000ff;">="submit"</span><span style="color: #ff0000;"> alt</span><span style="color: #0000ff;">=" PayPal - The safer, easier way to pay online"</span><span style="color: #0000ff;">>//支付按钮<br><br></span><span style="color: #0000ff;"></span><span style="color: #800000;">form</span><span style="color: #0000ff;">></span></span></span></span></span></span></span></span></span></span></span></span></span>
当支付成功后 paypal就会跳转到我们设置的 “return” 地址,会带上一个流水号 我们get方式就可以取到值。流水号键名 “tx”。
拿到流水号然后加上身份标识跟cmd变量就可以到paypal请求刚才支付的订单的交易内容。
例如:cmd=_notify-synch&tx=123sflsfjlw12&tx_token=fsfljvw3lwejloj43jfvdflf2
cmd=_notify-synch是告诉paypal你要做什么,这里是查询订单交易。
tx_token值要在paypal后台取,刚才注册帐号的时候要开通pdt功能才行。
这个过程paypal称为:PDT (Payment Data Transfer 付款数据传输)。
我们接收到返回的一些数据后就可以进行一些支付后的操作,比如发金币,发货等等。
pdt 详细的返回参数最后给出文档。
代码:
<span style="color: #000000;">php </span><span style="color: #008000;">//</span><span style="color: #008000;">获取 PayPal 交易流水号 tx </span> <span style="color: #800080;">$tx_token</span> = <span style="color: #800080;">$_GET</span>['tx'<span style="color: #000000;">]; </span><span style="color: #008000;">//</span><span style="color: #008000;">定义您的身份标记 </span> <span style="color: #800080;">$auth_token</span> = "CHANGE-TO-YOUR-TOKEN"<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">形成验证字符串 </span> <span style="color: #800080;">$req</span> = " cmd=_notify-synch&tx=<span style="color: #800080;">$tx_token</span>&at=<span style="color: #800080;">$auth_token</span>"<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">将交易流水号及身份标记返回 PayPal 验证 </span> <span style="color: #800080;">$header</span> .= "POST /cgi-bin/webscr HTTP/1.0\r\n"<span style="color: #000000;">; </span><span style="color: #800080;">$header</span> .= "Content-Type: application/x-www-form-urlencoded\r\n"<span style="color: #000000;">; </span><span style="color: #800080;">$header</span> .= "Content-Length: " . <span style="color: #008080;">strlen</span>(<span style="color: #800080;">$req</span>) . "\r\n\r\n"<span style="color: #000000;">; </span><span style="color: #800080;">$fp</span> = <span style="color: #008080;">fsockopen</span> ('www.paypal.com', 80, <span style="color: #800080;">$errno</span>, <span style="color: #800080;">$errstr</span>, 30<span style="color: #000000;">); </span><span style="color: #0000ff;">if</span> (!<span style="color: #800080;">$fp</span><span style="color: #000000;">) { </span><span style="color: #008000;">//</span><span style="color: #008000;"> HTTP ERROR </span> } <span style="color: #0000ff;">else</span><span style="color: #000000;"> { </span><span style="color: #008080;">fputs</span> (<span style="color: #800080;">$fp</span>, <span style="color: #800080;">$header</span> . <span style="color: #800080;">$req</span><span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;">获取返回数据 </span> <span style="color: #800080;">$res</span> = ''<span style="color: #000000;">; </span><span style="color: #800080;">$headerdone</span> = <span style="color: #0000ff;">false</span><span style="color: #000000;">; </span><span style="color: #0000ff;">while</span> (!<span style="color: #008080;">feof</span>(<span style="color: #800080;">$fp</span><span style="color: #000000;">)) { </span><span style="color: #800080;">$line</span> = <span style="color: #008080;">fgets</span> (<span style="color: #800080;">$fp</span>, 1024<span style="color: #000000;">); </span><span style="color: #0000ff;">if</span> (<span style="color: #008080;">strcmp</span>(<span style="color: #800080;">$line</span>, "\r\n") == 0<span style="color: #000000;">) { </span><span style="color: #008000;">//</span><span style="color: #008000;">获取头 </span> <span style="color: #800080;">$headerdone</span> = <span style="color: #0000ff;">true</span><span style="color: #000000;">; }</span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (<span style="color: #800080;">$headerdone</span><span style="color: #000000;">){ </span><span style="color: #008000;">//</span><span style="color: #008000;">获取主体内容 </span> <span style="color: #800080;">$res</span> .= <span style="color: #800080;">$line</span><span style="color: #000000;">; } } </span><span style="color: #008000;">//</span><span style="color: #008000;">解析获取内容 </span> <span style="color: #800080;">$lines</span> = <span style="color: #008080;">explode</span>("\n", <span style="color: #800080;">$res</span><span style="color: #000000;">); </span><span style="color: #800080;">$keyarray</span> = <span style="color: #0000ff;">array</span><span style="color: #000000;">(); </span><span style="color: #0000ff;">if</span> (<span style="color: #008080;">strcmp</span> (<span style="color: #800080;">$lines</span>[0], "SUCCESS") == 0<span style="color: #000000;">) { </span><span style="color: #0000ff;">for</span> (<span style="color: #800080;">$i</span>=1; <span style="color: #800080;">$i</span>count(<span style="color: #800080;">$lines</span>);<span style="color: #800080;">$i</span>++<span style="color: #000000;">){ </span><span style="color: #0000ff;">list</span>(<span style="color: #800080;">$key</span>,<span style="color: #800080;">$val</span>) = <span style="color: #008080;">explode</span>("=", <span style="color: #800080;">$lines</span>[<span style="color: #800080;">$i</span><span style="color: #000000;">]); </span><span style="color: #800080;">$keyarray</span>[<span style="color: #008080;">urldecode</span>(<span style="color: #800080;">$key</span>)] = <span style="color: #008080;">urldecode</span>(<span style="color: #800080;">$val</span><span style="color: #000000;">); } </span><span style="color: #008000;">//</span><span style="color: #008000;">检查交易付款状态 payment_status 是否为 „Completed‟ //检查交易流水号 txn_id 是否已经被处理过 //检查接收 EMAIL receiver_email 是否为您的 PayPal 中已经注册的 EMAIL //检查金额 mc_gross 是否正确 //…… //处理此次付款明细 //该付款明细所有变量可参考: //https://www.paypal.com/IntegrationCenter/ic_ipn-pdt-variable-reference.html </span> <span style="color: #800080;">$name</span> = <span style="color: #800080;">$keyarray</span>['first_name'] . ' ' . <span style="color: #800080;">$keyarray</span>['last_name'<span style="color: #000000;">]; </span><span style="color: #800080;">$itemname</span> = <span style="color: #800080;">$keyarray</span>['item_name'<span style="color: #000000;">]; </span><span style="color: #800080;">$amount</span> = <span style="color: #800080;">$keyarray</span>['mc_gross'<span style="color: #000000;">]; </span><span style="color: #0000ff;">echo</span> ("<p></p><h3>Thank you for you purchase!</h3>"<span style="color: #000000;">); </span><span style="color: #0000ff;">echo</span> ("<b>Payment Details:</b><br>\n"<span style="color: #000000;">); </span><span style="color: #0000ff;">echo</span> ("
为了防止用户关掉浏览器,订单通知不到的情况。paypal还提供了一种通知方式:IPN (Instant Payment Notification 即时付款通知);
IPN 是在后台进行http请求通知。
当开通了ipn功能,并且订单状态发生改变的时候,paypal会主动请求我们支付表单中变量“notify_url”提供的地址。
我们在接收到paypal请求后要拿到所有的数据。
然后用 “cmd=_notify-validate”加上刚才的数据,http发送给paypal进行验证,以防请求是伪造的。
代码:
<span style="color: #000000;">php </span><span style="color: #008000;">//</span><span style="color: #008000;">从 PayPal 出读取 POST 信息同时添加变量„cmd‟ </span> <span style="color: #800080;">$req</span> = 'cmd=_notify-validate'<span style="color: #000000;">; </span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$_POST</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$key</span> => <span style="color: #800080;">$value</span><span style="color: #000000;">) { </span><span style="color: #800080;">$value</span> = <span style="color: #008080;">urlencode</span>(<span style="color: #008080;">stripslashes</span>(<span style="color: #800080;">$value</span><span style="color: #000000;">)); </span><span style="color: #800080;">$req</span> .= "&<span style="color: #800080;">$key</span>=<span style="color: #800080;">$value</span>"<span style="color: #000000;">; } </span><span style="color: #008000;">//</span><span style="color: #008000;">建议在此将接受到的信息记录到日志文件中以确认是否收到 IPN 信息 //将信息 POST 回给 PayPal 进行验证 </span> <span style="color: #800080;">$header</span> .= "POST /cgi-bin/webscr HTTP/1.0\r\n"<span style="color: #000000;">; </span><span style="color: #800080;">$header</span> .= "Content-Type:application/x-www-form-urlencoded\r\n"<span style="color: #000000;">; </span><span style="color: #800080;">$header</span> .= "Content-Length:" . <span style="color: #008080;">strlen</span>(<span style="color: #800080;">$req</span>) ."\r\n\r\n"<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">在 Sandbox 情况下,设置: //$fp = fsockopen(„www.sandbox.paypal.com‟,80,$errno,$errstr,30); </span> <span style="color: #800080;">$fp</span> = <span style="color: #008080;">fsockopen</span> ('www.paypal.com', 80, <span style="color: #800080;">$errno</span>, <span style="color: #800080;">$errstr</span>, 30<span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;">将 POST 变量记录在本地变量中 //该付款明细所有变量可参考: //https://www.paypal.com/IntegrationCenter/ic_ipn-pdt-variable-reference.html </span> <span style="color: #800080;">$item_name</span> = <span style="color: #800080;">$_POST</span>['item_name'<span style="color: #000000;">]; </span><span style="color: #800080;">$item_number</span> = <span style="color: #800080;">$_POST</span>['item_number'<span style="color: #000000;">]; </span><span style="color: #800080;">$payment_status</span> = <span style="color: #800080;">$_POST</span>['payment_status'<span style="color: #000000;">]; </span><span style="color: #800080;">$payment_amount</span> = <span style="color: #800080;">$_POST</span>['mc_gross'<span style="color: #000000;">]; </span><span style="color: #800080;">$payment_currency</span> = <span style="color: #800080;">$_POST</span>['mc_currency'<span style="color: #000000;">]; </span><span style="color: #800080;">$txn_id</span> = <span style="color: #800080;">$_POST</span>['txn_id'<span style="color: #000000;">]; </span><span style="color: #800080;">$receiver_email</span> = <span style="color: #800080;">$_POST</span>['receiver_email'<span style="color: #000000;">]; </span><span style="color: #800080;">$payer_email</span> = <span style="color: #800080;">$_POST</span>['payer_email'<span style="color: #000000;">]; </span><span style="color: #008000;">//</span><span style="color: #008000;">… //判断回复 POST 是否创建成功 </span> <span style="color: #0000ff;">if</span> (!<span style="color: #800080;">$fp</span><span style="color: #000000;">) { </span><span style="color: #008000;">//</span><span style="color: #008000;">HTTP 错误 </span> }<span style="color: #0000ff;">else</span><span style="color: #000000;"> { </span><span style="color: #008000;">//</span><span style="color: #008000;">将回复 POST 信息写入 SOCKET 端口 </span> <span style="color: #008080;">fputs</span> (<span style="color: #800080;">$fp</span>, <span style="color: #800080;">$header</span> .<span style="color: #800080;">$req</span><span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;">开始接受 PayPal 对回复 POST 信息的认证信息 </span> <span style="color: #0000ff;">while</span> (!<span style="color: #008080;">feof</span>(<span style="color: #800080;">$fp</span><span style="color: #000000;">)) { </span><span style="color: #800080;">$res</span> = <span style="color: #008080;">fgets</span> (<span style="color: #800080;">$fp</span>, 1024<span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;">已经通过认证 </span> <span style="color: #0000ff;">if</span> (<span style="color: #008080;">strcmp</span> (<span style="color: #800080;">$res</span>, "VERIFIED") == 0<span style="color: #000000;">) { </span><span style="color: #008000;">//</span><span style="color: #008000;">检查付款状态 //检查 txn_id 是否已经处理过 //检查 receiver_email 是否是您的 PayPal 账户中的 EMAIL 地址 //检查付款金额和货币单位是否正确 //处理这次付款,包括写数据库 </span> }<span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (<span style="color: #008080;">strcmp</span> (<span style="color: #800080;">$res</span>, "INVALID") == 0<span style="color: #000000;">) { </span><span style="color: #008000;">//</span><span style="color: #008000;">未通过认证,有可能是编码错误或非法的 POST 信息 </span> <span style="color: #000000;">} } </span><span style="color: #008080;">fclose</span> (<span style="color: #800080;">$fp</span><span style="color: #000000;">); } </span>?>
接口对接就这样好了,搞清楚了流程很简单。
如果币种不是paypal默认的,在订单支付后订单状态一直是pending, 用卖家帐号登录在订单状态哪里点击接收,paypal就会自动设置接收该币种功能。
技术文档地址:https://www.paypal-biz.com/developer/documentation/2134.html