PayPal的Restful-API方式退款、WEB支付、回调

记录之用。

1.移动App中想要接入PayPal支付,婉转的采用PayPal的一种最简便的方式(网页版)。

   <h1>PayPal支付</h1>
      <div class="orderinfo">
	  <ul>
		<li><label>商品名称:</label>流量支付</li>
		<li><label>订单编号:</label>{$out_trade_no}</li>
		<li><label>金额:</label>${$order_total}</li>
	 </ul>
	 <form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post">
		<input type="hidden" name="cmd" value="_xclick">
		<input type="hidden" name="business" value="[email protected]">
		<input type="hidden" name="item_name" value="SIGMA SD1000"> <!-- 商品名称 -->
		<input type="hidden" name="amount" value="{$order_total}"> <!-- 商品总价格 -->
		<input type="hidden" name="currency_code" value="USD">
		<input type="hidden" name="custom" value="{$id}"> <!-- 传递订单id -->
		<input type="hidden" name="return" value="http://zjb.xxxxx.com"> <!-- 支付完成后的返回 -->
		<input type="hidden" name="notify_url" value="http://zjb.xxxxx.com/zmwx/index.php/xxxx/Order/paypal"> <!-- 回调通知地址 -->
		<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif "
		border="0" name="submit" alt=" PayPal - The safer, easier way to pay online">
	 </form>
	</div>

这方式就是支付的时候体验不太好,容易500的错误,网络的限制。

2.支付完成后那就是回调了(这里使用的PayPal的IPN回调机制):

/**
     * PayPal回调通知
     */
    public function paypal()
    {
        $ipn = file_get_contents(‘php://input‘);
//      $ipn = "mc_gross=399.00&protection_eligibility=Eligible&address_status=confirmed&payer_id=XEMQ4LGLL3E8U&address_street=%BF%C6%D4%B0%C2%B72%BA%C5A8%D2%F4%C0%D6%B4%F3%CF%C3&payment_date=19%3A18%3A52+Apr+07%2C+2017+PDT&payment_status=Completed&charset=gb2312&address_zip=518000&first_name=li&mc_fee=15.86&address_country_code=CN&address_name=%C9%EE%DB%DA%CA%D0%A1%A1%CA%A5%C2%EB%BF%C6%BC%BC&notify_version=3.8&custom=664&payer_status=verified&business=yu.yu-facilitator%40zmartec.com&address_country=China&address_city=%C9%EE%DB%DA%CA%D0&quantity=1&verify_sign=AomRS5l2W2xlt2An.GaSrAzpCl-NAi.rf7W.QGkzsUIdF5RMnpDPvDzw&payer_email=zmartec%40zmartec.com&txn_id=32U88448K71697337&payment_type=instant&last_name=tao&address_state=GUANGDONG&receiver_email=yu.yu-facilitator%40zmartec.com&payment_fee=15.86&receiver_id=PEAD5Y5KWXRJU&txn_type=web_accept&item_name=SIGMA%2BSD1000&mc_currency=USD&item_number=&residence_country=US&test_ipn=1&transaction_subject=&payment_gross=399.00&ipn_track_id=b2b22318a3e9";
        vendor(‘PaypalIPN.PaypalIPN‘) or die("方案7引入失败");
        $pipn = new \PaypalIPN();
        $ipn_response = $pipn->verifyIPN($ipn);
        
        // 验证通过&转换数据类型为array
        if (true === $ipn_response) {
            $raw_post_array = explode(‘&‘, $ipn);
            $myPost = array();
            foreach ($raw_post_array as $keyval) {
                $keyval = explode(‘=‘, $keyval);
                if (count($keyval) == 2) {
                    // 转换urlencode的+为%2B
                    if ($keyval[0] === ‘payment_date‘) {
                        if (substr_count($keyval[1], ‘+‘) === 1) {
                            $keyval[1] = str_replace(‘+‘, ‘%2B‘, $keyval[1]);
                        }
                    }
                    $myPost[$keyval[0]] = urldecode($keyval[1]);
                }
            }
            $fields = "od.`uid`,od.`currency`,od.`product_id`";
            $order_detail = $this->_model->orderDetail($myPost[‘custom‘], $fields);
            // 卡号iccid
            $iccid = $this->_model->getIccidByid($order_detail[0][‘uid‘]);print_r($iccid);
            $iccid = $iccid[0][‘iccid‘];
            // 套餐包id
            $product_id = $this->_model->getProductIdById($order_detail[0][‘product_id‘]);
            $product_id = $product_id[0][‘product_id‘];
            // ①检查payment_status状态
            if ("Completed" == $myPost[‘payment_status‘]) {
                // ②确保txn_id不重复
                if ($this->_model->checkPayPalTxn($myPost[‘txn_id‘])) {
                    // ③确保邮件未被更改
                    if ($this->paypayl_receiver_email == $myPost[‘receiver_email‘]) {
                        // ④确保价格、商品与订单符合
                        if ($order_detail[0][‘order_total‘] == $myPost[‘mc_gross‘] && $order_detail[0][‘currency‘] == $myPost[‘mc_currency‘]) {
                            $data = array(
                                ‘status‘=>‘completed‘,
                                ‘payment_methods‘ => ‘PayPal‘,
                                ‘trade_no‘=>$myPost[‘txn_id‘],
                                ‘changed_time‘=>time()
                            );
                            $pay_result = $this->_model->saveOrderData( $data , $myPost[‘custom‘] );
                            $this->hong_cha_package_order($order_detail[0][‘out_trade_no‘], $myPost[‘custom‘], $product_id, $iccid, $order_detail[0][‘product_amount‘]);
                        } else {
                            echo "货币、价格与订单不符,请联系管理员.";
                        }
                    } else {
                        echo "订单信息被修改,请联系管理员.";
                    }
                } else {
                    echo "订单已被处理,请勿重复.";
                }
            } else {
                echo "订单未支付完成.";
            }
        } else {
            echo "数据被黑,无法验证通过.";
        }
    }

3.支付、回调之后就不可避免的要退款了:

    /**
     * PayPal退款
     */
    public function paypal_refund()
    {
        $txn_id = I(‘txn_id‘);
        $id = I(‘id‘);
        if ($this->is_data_valid(array($txn_id))) {
            $url = "https://api.sandbox.paypal.com/v1/payments/sale/$txn_id/refund";
            $post_data = "{}";
            $access_token = $this->ger_access_token();
            $header = array(
                "Content-Type: application/json",
                "Authorization: Bearer $access_token"
            );
            $output = http_post_paypal($url, $post_data, $header);
    
            if (false === $output || false === $access_token) {
                $this->_data[‘data‘] = ‘‘;
                $this->_data[‘error‘] = true;
                $this->_data[‘message‘] = ‘网络异常,请您稍后重试‘;
            }
    
            $output = json_decode($output, TRUE);
            if ($txn_id == $output[‘sale_id‘] && "completed" == $output[‘completed‘]) {
                $this->_model->saveOrderData( array(‘status‘=>‘refund_success‘, ‘changed_time‘=>time()), $id );
                $this->_data[‘data‘] = ‘‘;
                $this->_data[‘error‘] = false;
                $this->_data[‘message‘] = ‘退款已提交‘;
            } elseif ("TRANSACTION_REFUSED" == $output[‘name‘]) {
                $this->_data[‘data‘] = ‘‘;
                $this->_data[‘error‘] = false;
                $this->_data[‘message‘] = ‘退款已提交,请勿重复‘;
            }
        }

        $this->response($this->_data, ‘json‘);
    }

function.php文件:

/**
     * curl POST请求 用作PayPal回调
     * @param string $url
     * @param string $post_data
     * @return array
     */
    function http_post_paypal($url, $post_data, $header=array(), $client_id=‘‘, $secret=‘‘) {
    
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        if ($client_id && $secret) {
            curl_setopt($ch, CURLOPT_USERPWD, "[$client_id]:[$secret]"); // 传递一个连接中需要的用户名和密码,格式为:"[username]:[password]"。
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true) ; // 获取数据返回
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header) ; // 在启用 CURLOPT_RETURNTRANSFER 时候将获取数据返回array(‘Expect:‘)
        $output = curl_exec($ch);
        
        if ( curl_errno($ch) ){
            return false;
        }
    
        return $output;
    }

ps:退款的时候需要获取token,有碰到问题的可以参考另一篇文章http://tengteng412.blog.51cto.com/4751263/1917336

时间: 2024-10-05 09:08:58

PayPal的Restful-API方式退款、WEB支付、回调的相关文章

Restful 架构方式的 web service

现在公司项目用的apache wink 搭建的web service ,感觉挺好用的.顺便学习一个这种架构方式 . 个人理解apache 实现Restful 架构方式技术有两种,如果有其他新的知识或不同意看法的,大家可以留言,一起学习,本人出道不久,各位一起共勉吧. apache CXF  与  apahce WINK 分别实现了Restful 风格.其实之前的web service 实现 大多数使用 RPC 与 SOAP 来实现进行消息传递实现的,现在主流的Restful 渐渐把它们取代,XM

Yii2 Restful Api 401

采用Yii2 Restful Api方式为APP提供数据,默认你已经做好了所有的编码和配置工作.采用Postman测试接口: 出现这个画面的一个可能原因是:access_token的写法有误,如果你使用的是下边配置的话,请把access_token 改为access-token,即http://api.yingxiang.com/v1/users?access-token=123,原因在于QueryParamAuth这个类接收的就是access-token,不信自己点进去看.

用 Spring 快速搭建 Web 应用(支持 RESTful API)

Spring 是个好框架……不过 Java 开发的一个通病是前期配置太麻烦.正好手头上有个新项目,我考虑后决定用 Java 做,看了新出的 Spring 4,还有 Spring Boot,可以快速地做出一个 Web Demo.不过我不太喜欢大量使用注解的方式,而且 Spring 4 出来的时间不久,资料也不多,所以还是打算用 Spring 3 来做. Spring 3 的配置比较多,网上不少文章会教你一步步搭建环境,涉及到细节就是怎么说的都有了.另一个不爽的地方是,有些概念解释不清,对初次使用的

1.1.3 以Self Host方式寄宿Web API

寄宿Web API不一定需要IIS的支持,我们可以采用Self Host的方式使用任意类型的应用程序(控制台.Windows Forms应用.WPF)作为宿主. 对于SelfHost这样一个空的控制台应用来说,除了需要引用WebApi的项目,还需要引用以下程序集 System.Web.Http System.Web.Http.SelfHost System.Net.Http 对于Web Host的方式寄宿Web API需要做的唯一一件事情是路由注册.但是对于Self Host来说,除了必须的路由

ASP.NET Core Web API 开发-RESTful API实现

REST 介绍: 符合REST设计风格的Web API称为RESTful API. 具象状态传输(英文:Representational State Transfer,简称REST)是Roy Thomas Fielding博士于2000年在他的博士论文 "Architectural Styles and the Design of Network-based Software Architectures" 中提出来的一种万维网软件架构风格. 目前在三种主流的Web服务实现方案中,因为R

ASP.NET Web Api 实践系列(二)Get/Post方式调用Web Api

本文给出Get/Post方式访问Web Api的帮助方法,对于Put/Delete方式的调用跟Post调用类似. 一.Web Api调用帮助类 下面给出Web Api调用帮助类的代码: 1 using System; 2 using System.Collections.Generic; 3 using System.Net.Http; 4 using System.Net.Http.Headers; 5 using System.Text; 6 using System.Web; 7 8 na

CloudFoundry命令行和Kubernetes命令行的Restful API消费方式

先说CloudFoundry的命令行工具CLI.我们在CloudFoundry环境下工作,第一个使用的命令就是cf login. 如果在环境变量里维护CF_TRACE的值为true: 则我们能发现,诸如cf login这种命令,实际上也是通过消费Restful API来完成的. 下图是cf login这个命令的api endpoint请求细节,供大家参考: API endpoint: https://api.cf.eu10.hana.ondemand.com REQUEST: [2018-09-

RESTful API设计规范收集

说明:其实没有绝对的规范,达到90%即可. 理解RESTful架构:http://www.ruanyifeng.com/blog/2011/09/restful.html RESTful API 设计指南:http://www.ruanyifeng.com/blog/2014/05/restful_api.html GitHub标准RESTful API:https://api.github.com/ 教程收集: http://novoland.github.io/%E8%AE%BE%E8%AE

Yii2框架RESTful API教程(二) - 格式化响应,授权认证和速率限制

之前写过一篇Yii2框架RESTful API教程(一) - 快速入门,今天接着来探究一下Yii2 RESTful的格式化响应,授权认证和速率限制三个部分 一.目录结构 先列出需要改动的文件.目录如下: web ├─ common │ └─ models │ └ User.php └─ frontend ├─ config │ └ main.php └─ controllers └ BookController.php 二.格式化响应 Yii2 RESTful支持JSON和XML格式,如果想指定

flask开发restful api

在此之前,向大家说明的是,我们整个框架用的是flask + sqlalchemy + redis.如果没有开发过web,还是先去学习一下,这边只是介绍如果从开发web转换到开发移动端.如果flask还不是很熟悉,我建议先到这个网站简单学习一下,非常非常简单.http://dormousehole.readthedocs.org/en/latest/ 一直想写一些特别的东西,能让大家学习讨论的东西.但目前网上的很多博客,老么就按照官方文档照本宣读,要么直接搬代码,什么都不说明.我写这个系列的博客,