Charlie 8 năm trước cách đây
mục cha
commit
ca6debe6be
31 tập tin đã thay đổi với 624 bổ sung4014 xóa
  1. 1 1
      www/protected/modules/o2o/models/CouponCode.php
  2. 2 0
      www/protected/vendors/pingpp/.gitignore
  3. 35 13
      www/protected/vendors/pingpp/CHANGELOG.md
  4. 75 0
      www/protected/vendors/pingpp/LICENSE
  5. 47 16
      www/protected/vendors/pingpp/README.md
  6. 1 1
      www/protected/vendors/pingpp/VERSION
  7. 1 3723
      www/protected/vendors/pingpp/data/ca-certificates.crt
  8. 8 7
      www/protected/vendors/pingpp/example/event.php
  9. 45 0
      www/protected/vendors/pingpp/example/identification.php
  10. 69 37
      www/protected/vendors/pingpp/example/pay.php
  11. 0 0
      www/protected/vendors/pingpp/example/pingpp_rsa_public_key.pem
  12. 17 19
      www/protected/vendors/pingpp/example/redenvelope.php
  13. 11 6
      www/protected/vendors/pingpp/example/refund.php
  14. 8 4
      www/protected/vendors/pingpp/example/retrieve.php
  15. 31 14
      www/protected/vendors/pingpp/example/transfer.php
  16. 64 16
      www/protected/vendors/pingpp/example/webhooks.php
  17. 0 24
      www/protected/vendors/pingpp/example/webhooks_verify.php
  18. 27 0
      www/protected/vendors/pingpp/example/your_rsa_private_key.pem
  19. 9 0
      www/protected/vendors/pingpp/example/your_rsa_public_key.pem
  20. 3 1
      www/protected/vendors/pingpp/init.php
  21. 43 107
      www/protected/vendors/pingpp/lib/ApiRequestor.php
  22. 2 3
      www/protected/vendors/pingpp/lib/ApiResource.php
  23. 1 1
      www/protected/vendors/pingpp/lib/AttachedObject.php
  24. 0 2
      www/protected/vendors/pingpp/lib/Card.php
  25. 26 0
      www/protected/vendors/pingpp/lib/Error/Api.php
  26. 18 0
      www/protected/vendors/pingpp/lib/JsonSerializable.php
  27. 46 3
      www/protected/vendors/pingpp/lib/Pingpp.php
  28. 14 8
      www/protected/vendors/pingpp/lib/PingppObject.php
  29. 9 1
      www/protected/vendors/pingpp/lib/RedEnvelope.php
  30. 11 7
      www/protected/vendors/pingpp/lib/Util/RequestOptions.php
  31. 0 0
      www/protected/vendors/pingpp/lib/WxpubOAuth.php

+ 1 - 1
www/protected/modules/o2o/models/CouponCode.php

@@ -1,7 +1,7 @@
 <?php
 class CouponCode extends MongoAr
 {
-    public $_id;    //评价的object id
+    public $_id;    //object id
 
     public $code;   //兑换码
 

+ 2 - 0
www/protected/vendors/pingpp/.gitignore

@@ -1,2 +1,4 @@
 .DS_Store
 .idea/
+vendor/
+composer.lock

+ 35 - 13
www/protected/vendors/pingpp/CHANGELOG.md

@@ -1,49 +1,71 @@
+# 2.1.5
+* 新增:  
+transfer 更新接口
+
+# 2.1.4
+* 新增:  
+identification 接口
+
+# 2.1.3
+* 修改:  
+更正本地 CA 证书
+
+# 2.1.2
+* 修改:  
+更新本地 CA 证书  
+添加请求签名
+
+# 2.1.1
+* 修改:  
+添加 PUT 方法  
+添加 JSON 序列化方法
+
 # 2.1.0
-* 增加:<br>
+* 增加:  
 应用内快捷支付对应接口
 
 # 2.0.7
-* 修改:<br>
+* 修改:  
 补充 channel_error 错误类型
 
 # 2.0.6
-* 增加:<br>
+* 增加:  
 微信企业付款 transfer
 
 # 2.0.5
-* 增加:<br>
+* 增加:  
 京东手机网页支付
 event 查询和 event 列表查询
 
 # 2.0.4
-* 更改:<br>
+* 更改:  
 微信公众号获取 JS-SDK 签名兼容 nginx
 
 # 2.0.3
-* 增加:<br>
+* 增加:  
 增加微信公众号获取 JS-SDK 签名的接口
 
 # 2.0.2
-* 增加:<br>
+* 增加:  
 新增微信红包
 
 # 2.0.1
-* 更改:<br>
+* 更改:  
 添加 composer 支持,调用方法变更,具体请参考 [example](/example)
 
 # 2.0.0
-* 更改:<br>
+* 更改:  
 添加新渠道:百付宝、百付宝WAP、微信公众号支付
 
 # 1.0.4
-* 更改:<br>
+* 更改:  
 移除旧的 refund 方法
 
 # 1.0.3
-* 更改:<br>
-所有 PingPP 改成 Pingpp<br>
+* 更改:  
+所有 PingPP 改成 Pingpp  
 Pingpp_Object 转成 JSON 时,用 stdClass 代替 array
 
 # 1.0.2
-* 更改:<br>
+* 更改:  
 cURL 使用 TLSv1.x

+ 75 - 0
www/protected/vendors/pingpp/LICENSE

@@ -0,0 +1,75 @@
+<?php
+/**
+ * Class PingppEnvInspect
+ * 在使用 Ping++ PHP SDK 前,请执行该文件来检查运行环境是否满足使用 SDK 条件
+ * Before using Ping++ PHP SDK, please run this file to ensure the runtime environment is supported
+ */
+
+require dirname(__FILE__) . '/init.php';
+
+class PingppEnvInspect
+{
+    public static function start()
+    {
+        $apiBaseArr = parse_url(\Pingpp\Pingpp::$apiBase);
+        static::$apiHost = $apiBaseArr['host'];
+        static::versionCheck();
+        foreach (static::$extFunc as $funcName => $msg)
+        {
+            if (!function_exists($funcName))
+            {
+                throw new Exception($msg);
+            }
+        }
+        static::domainResolveCheck();
+        static::connectionCheck();
+        echo "Your PHP system passed the runtime environment inspection successfully.";
+    }
+
+    private static $extFunc
+        = array(
+            "curl_init"          => 'Pingpp needs the CURL PHP extension.',
+            "openssl_sign"       => 'Pingpp needs the OpenSSL PHP extension.',
+            "json_decode"        => 'Pingpp needs the JSON PHP extension.',
+            "mb_detect_encoding" => 'Pingpp needs the Multibyte String PHP extension.',
+        );
+    private static $minPingppVersion = "5.3";
+    private static $apiHost;
+    private static $apiKey = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC';
+    private static $exampleChargeId = 'ch_uT48KOnvf5aDqjfj58XnzzL4';
+
+    private static function versionCheck()
+    {
+        $phpVersion = phpversion();
+        if (version_compare($phpVersion, static::$minPingppVersion, '<'))
+        {
+            throw new Exception(sprintf('Your server is running PHP version %1$s but Pingpp version requires %2$s at least.', $phpVersion, static::$minPingppVersion));
+        }
+    }
+
+    private static function domainResolveCheck()
+    {
+        if (gethostbyname(static::$apiHost) == static::$apiHost)
+        {
+            throw new Exception(sprintf('Could not resolve %1$s, please check your network or dns settings.', static::$apiHost));
+        }
+    }
+
+    private static function connectionCheck()
+    {
+        try {
+            \Pingpp\Pingpp::setApiKey(static::$apiKey);
+            \Pingpp\Charge::retrieve(static::$exampleChargeId);
+        } catch (Exception $e) {
+            if ($e instanceof \Pingpp\Error\ApiConnection) {
+                throw $e;
+            }
+        }
+    }
+}
+
+try {
+    PingppEnvInspect::start();
+} catch (Exception $e) {
+    echo $e->getMessage();
+}

+ 47 - 16
www/protected/vendors/pingpp/README.md

@@ -1,30 +1,28 @@
 Pingpp PHP SDK
 =================
 ## 简介
-lib 文件夹下是 PHP SDK 文件,<br>
+lib 文件夹下是 PHP SDK 文件,  
 example 文件夹里面是简单的接入示例,该示例仅供参考。
 
 ## 版本要求
-PHP 版本 5.3 及以上
+PHP 版本 5.3 及以上  
+你可以执行目录下的环境检测脚本,来进行一些基本检测
+``` bash
+php PingppEnvInspect.php
+```
 
 ## 安装
 ### 使用 Composer
-在你自己的 `composer.json` 中添加以下代码
-```
-{
-  "require": {
-    "pingplusplus/pingpp-php": "dev-master"
-  }
-}
-```
-然后执行
+执行
 ```
-composer install
+composer require pingplusplus/pingpp-php
 ```
+
 使用 Composer 的 autoload 引入
 ```php
 require_once('vendor/autoload.php');
 ```
+
 ### 手动引入
 ``` php
 require_once('/path/to/pingpp-php/init.php');
@@ -36,6 +34,12 @@ require_once('/path/to/pingpp-php/init.php');
 \Pingpp\Pingpp::setApiKey('YOUR-KEY');
 ```
 
+### 设置请求签名密钥
+密钥需要你自己生成,公钥请填写到 [Ping++ Dashboard](https://dashboard.pingxx.com)
+```php
+\Pingpp\Pingpp::setPrivateKeyPath('/path/to/your_rsa_private_key.pem');
+```
+
 ### 支付
 ```php
 $ch = \Pingpp\Charge::create(
@@ -53,6 +57,9 @@ $ch = \Pingpp\Charge::create(
 );
 ```
 
+> 由于 PHP 5.3 不支持 `JsonSerializable` JSON 序列化接口,当你需要将其放入其他数组或者对象时,
+> 建议先将其转成数组,例:`$arr = array('charge' => json_decode($ch, true))`。
+
 ### charge 查询
 ```php
 \Pingpp\Charge::retrieve('CHARGE_ID');
@@ -128,7 +135,6 @@ $signature = \Pingpp\WxpubOauth::getSignature($charge, $ticket, $url);
 pingpp.createPayment(charge, callback, signature, false);
 ```
 
-
 ### event 查询
 
 ```php
@@ -141,7 +147,6 @@ pingpp.createPayment(charge, callback, signature, false);
 ```
 **详细信息请参考 [API 文档](https://pingxx.com/document/api?php)。**
 
-
 ### 微信企业付款
 ```php
 \Pingpp\Transfer::create(
@@ -193,7 +198,7 @@ pingpp.createPayment(charge, callback, signature, false);
 ### 更新 customer
 ```php
 $cus = \Pingpp\Customer::retrieve('CUS_ID');
-$cus['description'] = 'Customer Desscription';
+$cus['description'] = 'Customer Description';
 $cus->save();
 ```
 
@@ -221,4 +226,30 @@ $card = $cus->sources->retrieve('CARD_ID');
 ```php
 $cus = \Pingpp\Customer::retrieve('CUS_ID');
 $cus->sources->retrieve('CARD_ID')->delete();
-```
+```
+
+### 身份证认证
+``` php
+\Pingpp\Identification::identify(array(
+    'type' => 'id_card',
+    'app' => $app_id,
+    'data' => array(
+        'id_name' => '张三', // 姓名
+        'id_number' => '310181198910107641' // 身份证号
+    )
+));
+```
+
+### 银行卡认证
+``` php
+\Pingpp\Identification::identify(array(
+    'type' => 'bank_card',
+    'app' => $app_id,
+    'data' => array(
+        'id_name' => '张三', // 姓名
+        'id_number' => '310181198910107641', // 身份证号,
+        'card_number' => '6201111122223333', // 银行卡号
+        'phone_number' => '18623234545' // 银行预留手机号,不支持 178 号段
+    )
+));
+```

+ 1 - 1
www/protected/vendors/pingpp/VERSION

@@ -1 +1 @@
-2.1.0
+2.1.5

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 3723
www/protected/vendors/pingpp/data/ca-certificates.crt


+ 8 - 7
www/protected/vendors/pingpp/example/event.php

@@ -6,14 +6,15 @@
  * Time: 17:30
  */
 
-require_once(dirname(__FILE__) . '/../init.php');
-
-
+require dirname(__FILE__) . '/../init.php';
 
+// api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key
 \Pingpp\Pingpp::setApiKey('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
 
-//查询指定的 event 对象
-\Pingpp\Event::retrieve('evt_zRFRk6ekazsH7t7yCqEeovhk');
+// 查询指定的 event 对象,通过 event 对象的 id 查询一个已创建的 event 对象
+$evt = \Pingpp\Event::retrieve('evt_zRFRk6ekazsH7t7yCqEeovhk');
+echo $evt;
 
-//查询 event 列表
-\Pingpp\Event::all(array('type'=>'charge.succeeded'));
+// 查询 event 列表,返回之前创建 event 对象的一个列表。列表是按创建时间进行排序,总是将最新的 event 对象显示在最前
+$evts = \Pingpp\Event::all(array('type' => 'charge.succeeded'));
+echo $evts;

+ 45 - 0
www/protected/vendors/pingpp/example/identification.php

@@ -0,0 +1,45 @@
+<?php
+require dirname(__FILE__) . '/../init.php';
+
+// api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key
+$api_key = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC';
+// app_id 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击你创建的应用->应用首页->应用 ID(App ID)
+$app_id = 'app_1Gqj58ynP0mHeX1q';
+
+// 设置 API Key
+\Pingpp\Pingpp::setApiKey($api_key);
+
+// 设置私钥
+\Pingpp\Pingpp::setPrivateKeyPath(__DIR__ . '/your_rsa_private_key.pem');
+
+// 调用身份证认证接口
+try {
+    $result = \Pingpp\Identification::identify(array(
+        'type' => 'id_card',
+        'app' => $app_id,
+        'data' => array(
+            'id_name' => '张三', // 姓名
+            'id_number' => '310181198910107641' // 身份证号
+        )
+    ));
+    echo $result;
+} catch (\Pingpp\Error\Base $e) {
+    echo $e->getMessage();
+}
+
+// 调用银行卡认证接口
+try {
+    $result = \Pingpp\Identification::identify(array(
+        'type' => 'bank_card',
+        'app' => $app_id,
+        'data' => array(
+            'id_name' => '张三', // 姓名
+            'id_number' => '310181198910107641', // 身份证号,
+            'card_number' => '6201111122223333', // 银行卡号
+            'phone_number' => '18623234545' // 银行预留手机号,不支持 178 号段
+        )
+    ));
+    echo $result;
+} catch (\Pingpp\Error\Base $e) {
+    echo $e->getMessage();
+}

+ 69 - 37
www/protected/vendors/pingpp/example/pay.php

@@ -1,12 +1,20 @@
 <?php
-/* *
+/**
  * Ping++ Server SDK
  * 说明:
- * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写, 并非一定要使用该代码。
- * 该代码仅供学习和研究 Ping++ SDK 使用,只是提供一个参考。
-*/
+ * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。
+ * 接入支付流程参考开发者中心:https://www.pingxx.com/docs/server/charge ,文档可筛选后端语言和接入渠道。
+ * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。
+ */
 
-require_once(dirname(__FILE__) . '/../init.php');
+require dirname(__FILE__) . '/../init.php';
+
+// api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key
+$api_key = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC';
+// app_id 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击你创建的应用->应用首页->应用 ID(App ID)
+$app_id = 'app_1Gqj58ynP0mHeX1q';
+
+// 此处为 Content-Type 是 application/json 时获取 POST 参数的示例
 $input_data = json_decode(file_get_contents('php://input'), true);
 if (empty($input_data['channel']) || empty($input_data['amount'])) {
     echo 'channel or amount is empty';
@@ -16,78 +24,102 @@ $channel = strtolower($input_data['channel']);
 $amount = $input_data['amount'];
 $orderNo = substr(md5(time()), 0, 12);
 
-//$extra 在使用某些渠道的时候,需要填入相应的参数,其它渠道则是 array() .具体见以下代码或者官网中的文档。其他渠道时可以传空值也可以不传。
+/**
+ * 设置请求签名密钥,密钥对需要你自己用 openssl 工具生成,如何生成可以参考帮助中心:https://help.pingxx.com/article/123161;
+ * 生成密钥后,需要在代码中设置请求签名的私钥(rsa_private_key.pem);
+ * 然后登录 [Dashboard](https://dashboard.pingxx.com)->点击右上角公司名称->开发信息->商户公钥(用于商户身份验证)
+ * 将你的公钥复制粘贴进去并且保存->先启用 Test 模式进行测试->测试通过后启用 Live 模式
+ */
+
+// 设置私钥内容方式1
+\Pingpp\Pingpp::setPrivateKeyPath(__DIR__ . '/your_rsa_private_key.pem');
+
+// 设置私钥内容方式2
+// \Pingpp\Pingpp::setPrivateKey(file_get_contents(__DIR__ . '/your_rsa_private_key.pem'));
+
+/**
+ * $extra 在使用某些渠道的时候,需要填入相应的参数,其它渠道则是 array()。
+ * 以下 channel 仅为部分示例,未列出的 channel 请查看文档 https://pingxx.com/document/api#api-c-new;
+ * 或直接查看开发者中心:https://www.pingxx.com/docs/server/charge;包含了所有渠道的 extra 参数的示例;
+ */
 $extra = array();
 switch ($channel) {
     case 'alipay_wap':
         $extra = array(
-            'success_url' => 'http://www.yourdomain.com/success',
-            'cancel_url' => 'http://www.yourdomain.com/cancel'
-        );
-        break;
-    case 'upmp_wap':
-        $extra = array(
-            'result_url' => 'http://www.yourdomain.com/result?code='
+            // success_url 和 cancel_url 在本地测试不要写 localhost ,请写 127.0.0.1。URL 后面不要加自定义参数
+            'success_url' => 'http://example.com/success',
+            'cancel_url' => 'http://example.com/cancel'
         );
         break;
     case 'bfb_wap':
         $extra = array(
-            'result_url' => 'http://www.yourdomain.com/result?code=',
-            'bfb_login' => true
+            'result_url' => 'http://example.com/result',// 百度钱包同步回调地址
+            'bfb_login' => true// 是否需要登录百度钱包来进行支付
         );
         break;
     case 'upacp_wap':
         $extra = array(
-            'result_url' => 'http://www.yourdomain.com/result'
+            'result_url' => 'http://example.com/result'// 银联同步回调地址
         );
         break;
     case 'wx_pub':
         $extra = array(
-            'open_id' => 'Openid'
+            'open_id' => 'openidxxxxxxxxxxxx'// 用户在商户微信公众号下的唯一标识,获取方式可参考 pingpp-php/lib/WxpubOAuth.php
         );
         break;
     case 'wx_pub_qr':
         $extra = array(
-            'product_id' => 'Productid'
+            'product_id' => 'Productid'// 为二维码中包含的商品 ID,1-32 位字符串,商户可自定义
         );
         break;
     case 'yeepay_wap':
         $extra = array(
-            'product_category' => '1',
-            'identity_id'=> 'your identity_id',
-            'identity_type' => 1,
-            'terminal_type' => 1,
-            'terminal_id'=>'your terminal_id',
-            'user_ua'=>'your user_ua',
-            'result_url'=>'http://www.yourdomain.com/result'
+            'product_category' => '1',// 商品类别码参考链接 :https://www.pingxx.com/api#api-appendix-2
+            'identity_id'=> 'your identity_id',// 商户生成的用户账号唯一标识,最长 50 位字符串
+            'identity_type' => 1,// 用户标识类型参考链接:https://www.pingxx.com/api#yeepay_identity_type
+            'terminal_type' => 1,// 终端类型,对应取值 0:IMEI, 1:MAC, 2:UUID, 3:other
+            'terminal_id'=>'your terminal_id',// 终端 ID
+            'user_ua'=>'your user_ua',// 用户使用的移动终端的 UserAgent 信息
+            'result_url'=>'http://example.com/result'// 前台通知地址
         );
         break;
     case 'jdpay_wap':
         $extra = array(
-            'success_url' => 'http://www.yourdomain.com',
-            'fail_url'=> 'http://www.yourdomain.com',
-            'token' => 'dsafadsfasdfadsjuyhfnhujkijunhaf'
+            'success_url' => 'http://example.com/success',// 支付成功页面跳转路径
+            'fail_url'=> 'http://example.com/fail',// 支付失败页面跳转路径
+            /**
+            *token 为用户交易令牌,用于识别用户信息,支付成功后会调用 success_url 返回给商户。
+            *商户可以记录这个 token 值,当用户再次支付的时候传入该 token,用户无需再次输入银行卡信息
+            */
+            'token' => 'dsafadsfasdfadsjuyhfnhujkijunhaf' // 选填
         );
         break;
 }
 
-\Pingpp\Pingpp::setApiKey('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
+
+\Pingpp\Pingpp::setApiKey($api_key);// 设置 API Key
 try {
     $ch = \Pingpp\Charge::create(
         array(
+            //请求参数字段规则,请参考 API 文档:https://www.pingxx.com/api#api-c-new
             'subject'   => 'Your Subject',
             'body'      => 'Your Body',
-            'amount'    => $amount,
-            'order_no'  => $orderNo,
+            'amount'    => $amount,//订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100)
+            'order_no'  => $orderNo,// 推荐使用 8-20 位,要求数字或字母,不允许其他字符
             'currency'  => 'cny',
             'extra'     => $extra,
-            'channel'   => $channel,
-            'client_ip' => $_SERVER['REMOTE_ADDR'],
-            'app'       => array('id' => 'app_1Gqj58ynP0mHeX1q')
+            'channel'   => $channel,// 支付使用的第三方支付渠道取值,请参考:https://www.pingxx.com/api#api-c-new
+            'client_ip' => $_SERVER['REMOTE_ADDR'],// 发起支付请求客户端的 IP 地址,格式为 IPV4,如: 127.0.0.1
+            'app'       => array('id' => $app_id)
         )
     );
-    echo $ch;
+    echo $ch;// 输出 Ping++ 返回的支付凭据 Charge
 } catch (\Pingpp\Error\Base $e) {
-    header('Status: ' . $e->getHttpStatus());
-    echo($e->getHttpBody());
+    // 捕获报错信息
+    if ($e->getHttpStatus() != NULL) {
+        header('Status: ' . $e->getHttpStatus());
+        echo $e->getHttpBody();
+    } else {
+        echo $e->getMessage();
+    }
 }

+ 0 - 0
www/protected/vendors/pingpp/example/rsa_public_key.pem → www/protected/vendors/pingpp/example/pingpp_rsa_public_key.pem


+ 17 - 19
www/protected/vendors/pingpp/example/redenvelope.php

@@ -2,39 +2,37 @@
 /* *
  * Ping++ Server SDK
  * 说明:
- * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写, 并非一定要使用该代码。
- * 该代码仅供学习和研究 Ping++ SDK 使用,只是提供一个参考。
+ * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。
+ * 接入红包流程参考开发者中心:https://www.pingxx.com/docs/server/red-envelope ,文档可筛选后端语言和接入渠道。
+ * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。
 */
 
-require_once(dirname(__FILE__) . '/../init.php');
+require dirname(__FILE__) . '/../init.php';
 
-/*
- * To set your key
- * key:the livekey or testkey from your app message from pingpp on the dashboard
- */
-\Pingpp\Pingpp::setApiKey('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
+// api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key
+$api_key = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC';
+// app_id 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击你创建的应用->应用首页->应用 ID(App ID)
+$app_id = 'app_1Gqj58ynP0mHeX1q';
+
+\Pingpp\Pingpp::setApiKey($api_key);
 try {
-    /*
-     * To Create RedEnvelope
-     */
     $red = \Pingpp\RedEnvelope::create(
         array(
             'subject'     => 'Your Subject',
             'body'        => 'Your Body',
-            'amount'      => 100,
-            'order_no'    => '1234567890',
+            'amount'      => 100,// 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,金额限制在 100 ~ 20000 之间,即 1 ~ 200 元)
+            'order_no'    => date('YmdHis') . (microtime(true) % 1) * 1000 . mt_rand(0, 9999),// 红包使用的商户订单号。wx(新渠道)、wx_pub 规定为 1 ~ 28 位不能重复的数字
             'currency'    => 'cny',
             'extra'       => array(
-                'nick_name' => 'Nick Name',
-                'send_name' => 'Send Name'
+                'send_name' => 'Send Name'// 商户名称,最多 32 个字节
             ),
-            'recipient'   => 'Openid',
-            'channel'     => 'wx_pub',
-            'app'         => array('id' => 'app_1Gqj58ynP0mHeX1q'),
+            'recipient'   => 'Openid',// 接收者 id, 为用户在 wx(新渠道)、wx_pub 下的 open_id
+            'channel'     => 'wx_pub',// 目前支持 wx(新渠道)、 wx_pub
+            'app'         => array('id' => $app_id),
             'description' => 'Your Description'
         )
     );
-    echo $red;
+    echo $red;// 输出 Ping++ 返回的红包对象 Red_envelope
 } catch (\Pingpp\Error\Base $e) {
     header('Status: ' . $e->getHttpStatus());
     echo($e->getHttpBody());

+ 11 - 6
www/protected/vendors/pingpp/example/refund.php

@@ -2,17 +2,22 @@
 /* *
  * Ping++ Server SDK
  * 说明:
- * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写, 并非一定要使用该代码。
- * 该代码仅供学习和研究 Ping++ SDK 使用,只是提供一个参考。
+ * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。
+ * 接入退款流程参考开发者中心:https://www.pingxx.com/docs/server/refund ,文档可筛选后端语言和接入渠道。
+ * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。
  */
 
-require_once(dirname(__FILE__) . '/../init.php');
+require dirname(__FILE__) . '/../init.php';
 
+// api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key
 \Pingpp\Pingpp::setApiKey('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
-$ch = \Pingpp\Charge::retrieve('CHARGE_ID');
-$ch->refunds->create(
+
+// 通过发起一次退款请求创建一个新的 refund 对象,只能对已经发生交易并且没有全额退款的 charge 对象发起退款
+$ch = \Pingpp\Charge::retrieve('ch_a9CmfHTGGaz1urHiL8m5OiX1');// Charge 对象的 id
+$re = $ch->refunds->create(
     array(
-        'amount' => 10,
+        'amount' => 1,// 退款的金额, 单位为对应币种的最小货币单位,例如:人民币为分(如退款金额为 1 元,此处请填 100)。必须小于等于可退款金额,默认为全额退款
         'description' => 'Your Descripton'
     )
 );
+echo $re;// 输出 Ping++ 返回的退款对象 Refund

+ 8 - 4
www/protected/vendors/pingpp/example/retrieve.php

@@ -2,11 +2,15 @@
 /* *
  * Ping++ Server SDK
  * 说明:
- * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写, 并非一定要使用该代码。
- * 该代码仅供学习和研究 Ping++ SDK 使用,只是提供一个参考。
+ * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。
+ * 接入查询流程参考开发者中心:https://www.pingxx.com/docs/server/charge ,文档可筛选后端语言和接入渠道。
+ * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。
  */
 
-require_once(dirname(__FILE__) . '/../init.php');
+require dirname(__FILE__) . '/../init.php';
 
+// api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key
 \Pingpp\Pingpp::setApiKey('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
-$ch = \Pingpp\Charge::retrieve('ch_ejbLGCCaDWjT0ijzDSybL0mT');
+// 通过 Charge 对象的 id 查询一个已创建的 Charge 对象
+$ch = \Pingpp\Charge::retrieve('ch_a9CmfHTGGaz1urHiL8m5OiX1');
+echo $ch;// 输出 Ping++ 返回 Charge 对象

+ 31 - 14
www/protected/vendors/pingpp/example/transfer.php

@@ -2,30 +2,47 @@
 /* *
  * Ping++ Server SDK
  * 说明:
- * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写, 并非一定要使用该代码。
- * 该代码仅供学习和研究 Ping++ SDK 使用,只是提供一个参考。
+ * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。
+ * 接入企业付款流程参考开发者中心:https://www.pingxx.com/docs/server/transfer ,文档可筛选后端语言和接入渠道。
+ * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。
 */
 
-require_once(dirname(__FILE__) . '/../init.php');
+require dirname(__FILE__) . '/../init.php';
 
-\Pingpp\Pingpp::setApiKey('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
+// api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key
+$api_key = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC';
+// app_id 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击你创建的应用->应用首页->应用 ID(App ID)
+$app_id = 'app_1Gqj58ynP0mHeX1q';
+
+\Pingpp\Pingpp::setApiKey($api_key);
+
+// 创建 Transfer
 try {
     $tr = \Pingpp\Transfer::create(
         array(
-            'amount'   => 100,
-            'order_no'  => '123456d7890',
+            'amount'    => 100,// 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,企业付款最小发送金额为 1 元)
+            'order_no'  => date('mdHis') . mt_rand(1, 9999),// 企业转账使用的商户内部订单号。wx(新渠道)、wx_pub 规定为 1 ~ 50 位不能重复的数字字母组合、unionpay 为不 1~16 位数字
             'currency'  => 'cny',
-            'channel'   => 'wx_pub',
-            'app'       => array('id' => 'app_1Gqj58ynP0mHeX1q'),
-            'type'      => 'b2c',
-            'recipient' => 'o9zpMs9jIaLynQY9N6yxcZ',
-            'description'=>'testing',
-            'extra'=>array('user_name'=>'User Name', 'force_check'=>true)
-
+            'channel'   => 'unionpay',// 目前支持 wx(新渠道)、 wx_pub、unionpay
+            'app'       => array('id' => $app_id),
+            'type'      => 'b2c',// 付款类型,当前仅支持 b2c 企业付款。
+            'recipient' => 'o9zpMs9jIaLynQY9N6yxcZ',// 接收者 id, 为用户在 wx(新渠道)、wx_pub 下的 open_id
+            'description' => 'testing',
+            'extra' => array(
+                'user_name' => 'User Name', //收款人姓名。当该参数为空,则不校验收款人姓名,选填
+                'force_check' => false// 是否强制校验收款人姓名。仅当 user_name 参数不为空时该参数生效,选填
+            )
         )
     );
-    echo $tr;
+    echo $tr;// 输出 Ping++ 返回的企业付款对象 Transfer
 } catch (\Pingpp\Error\Base $e) {
     header('Status: ' . $e->getHttpStatus());
     echo($e->getHttpBody());
 }
+
+// 查询 Transfer
+$tr = \Pingpp\Transfer::retrieve('TRANSFER_ID');
+
+// 取消 Transfer
+$tr['status'] = 'canceled';
+$tr->save();

+ 64 - 16
www/protected/vendors/pingpp/example/webhooks.php

@@ -2,26 +2,74 @@
 /* *
  * Ping++ Server SDK
  * 说明:
- * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写, 并非一定要使用该代码。
- * 该代码仅供学习和研究 Ping++ SDK 使用,只是提供一个参考。
+ * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。
+ * 接入 webhooks 流程参考开发者中心:https://www.pingxx.com/docs/webhooks/webhooks
+ * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。
  */
 
-$input_data = json_decode(file_get_contents('php://input'), true);
-if($input_data['type'] == 'charge.succeeded')
-{
-    //TODO update database
-    http_response_code(200);// PHP 5.4 or greater
+require dirname(__FILE__) . '/../init.php';
 
+/* *
+ * 验证 webhooks 签名方法:
+ * raw_data:Ping++ 请求 body 的原始数据即 event ,不能格式化;
+ * signature:Ping++ 请求 header 中的 x-pingplusplus-signature 对应的 value 值;
+ * pub_key_path:读取你保存的 Ping++ 公钥的路径;
+ * pub_key_contents:Ping++ 公钥,获取路径:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Ping++ 公钥
+ */
+function verify_signature($raw_data, $signature, $pub_key_path) {
+    $pub_key_contents = file_get_contents($pub_key_path);
+    // php 5.4.8 以上,第四个参数可用常量 OPENSSL_ALGO_SHA256
+    return openssl_verify($raw_data, base64_decode($signature), $pub_key_contents, 'sha256');
 }
 
-else if($input_data['type'] == 'refund.succeeded')
-{
-    //TODO update database
-    http_response_code(200);// PHP 5.4 or greater
-}
-else
-{
-    //TODO update database
-    http_response_code(500);// PHP 5.4 or greater
+$raw_data = file_get_contents('php://input');
+// 示例
+// $raw_data = '{"id":"evt_eYa58Wd44Glerl8AgfYfd1sL","created":1434368075,"livemode":true,"type":"charge.succeeded","data":{"object":{"id":"ch_bq9IHKnn6GnLzsS0swOujr4x","object":"charge","created":1434368069,"livemode":true,"paid":true,"refunded":false,"app":"app_vcPcqDeS88ixrPlu","channel":"wx","order_no":"2015d019f7cf6c0d","client_ip":"140.227.22.72","amount":100,"amount_settle":0,"currency":"cny","subject":"An Apple","body":"A Big Red Apple","extra":{},"time_paid":1434368074,"time_expire":1434455469,"time_settle":null,"transaction_no":"1014400031201506150354653857","refunds":{"object":"list","url":"/v1/charges/ch_bq9IHKnn6GnLzsS0swOujr4x/refunds","has_more":false,"data":[]},"amount_refunded":0,"failure_code":null,"failure_msg":null,"metadata":{},"credential":{},"description":null}},"object":"event","pending_webhooks":0,"request":"iar_Xc2SGjrbdmT0eeKWeCsvLhbL"}';
+
+$headers = \Pingpp\Util\Util::getRequestHeaders();
+// 签名在头部信息的 x-pingplusplus-signature 字段
+$signature = isset($headers['X-Pingplusplus-Signature']) ? $headers['X-Pingplusplus-Signature'] : NULL;
+// 示例
+// $signature = 'BX5sToHUzPSJvAfXqhtJicsuPjt3yvq804PguzLnMruCSvZ4C7xYS4trdg1blJPh26eeK/P2QfCCHpWKedsRS3bPKkjAvugnMKs+3Zs1k+PshAiZsET4sWPGNnf1E89Kh7/2XMa1mgbXtHt7zPNC4kamTqUL/QmEVI8LJNq7C9P3LR03kK2szJDhPzkWPgRyY2YpD2eq1aCJm0bkX9mBWTZdSYFhKt3vuM1Qjp5PWXk0tN5h9dNFqpisihK7XboB81poER2SmnZ8PIslzWu2iULM7VWxmEDA70JKBJFweqLCFBHRszA8Nt3AXF0z5qe61oH1oSUmtPwNhdQQ2G5X3g==';
+
+// Ping++ 公钥,获取路径:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Ping++ 公钥
+$pub_key_path = __DIR__ . "/pingpp_rsa_public_key.pem";
+
+$result = verify_signature($raw_data, $signature, $pub_key_path);
+if ($result === 1) {
+    // 验证通过
+} elseif ($result === 0) {
+    http_response_code(400);
+    echo 'verification failed';
+    exit;
+} else {
+    http_response_code(400);
+    echo 'verification error';
+    exit;
 }
 
+$event = json_decode($raw_data, true);
+if ($event['type'] == 'charge.succeeded') {
+    $charge = $event['data']['object'];
+    // ...
+    http_response_code(200); // PHP 5.4 or greater
+} elseif ($event['type'] == 'refund.succeeded') {
+    $refund = $event['data']['object'];
+    // ...
+    http_response_code(200); // PHP 5.4 or greater
+} else {
+    /**
+     * 其它类型 ...
+     * - summary.daily.available
+     * - summary.weekly.available
+     * - summary.monthly.available
+     * - transfer.succeeded
+     * - red_envelope.sent
+     * - red_envelope.received
+     * ...
+     */
+    http_response_code(200);
+
+    // 异常时返回非 2xx 的返回码
+    // http_response_code(400);
+}

+ 0 - 24
www/protected/vendors/pingpp/example/webhooks_verify.php

@@ -1,24 +0,0 @@
-<?php
-// 验证 webhooks 签名
-function verify_signature($raw_data, $signature, $pub_key_path) {
-    $pub_key_contents = file_get_contents($pub_key_path);
-    // php 5.4.8 以上,第四个参数可用常量 OPENSSL_ALGO_SHA256
-    return openssl_verify($raw_data, base64_decode($signature), $pub_key_contents, 'sha256');
-}
-
-// POST 原始请求数据是待验签数据,请根据实际情况获取
-// $raw_data = file_get_contents('php://input');
-$raw_data = '{"id":"evt_eYa58Wd44Glerl8AgfYfd1sL","created":1434368075,"livemode":true,"type":"charge.succeeded","data":{"object":{"id":"ch_bq9IHKnn6GnLzsS0swOujr4x","object":"charge","created":1434368069,"livemode":true,"paid":true,"refunded":false,"app":"app_vcPcqDeS88ixrPlu","channel":"wx","order_no":"2015d019f7cf6c0d","client_ip":"140.227.22.72","amount":100,"amount_settle":0,"currency":"cny","subject":"An Apple","body":"A Big Red Apple","extra":{},"time_paid":1434368074,"time_expire":1434455469,"time_settle":null,"transaction_no":"1014400031201506150354653857","refunds":{"object":"list","url":"/v1/charges/ch_bq9IHKnn6GnLzsS0swOujr4x/refunds","has_more":false,"data":[]},"amount_refunded":0,"failure_code":null,"failure_msg":null,"metadata":{},"credential":{},"description":null}},"object":"event","pending_webhooks":0,"request":"iar_Xc2SGjrbdmT0eeKWeCsvLhbL"}';
-// 签名在头部信息的 x-pingplusplus-signature 字段
-$signature = 'BX5sToHUzPSJvAfXqhtJicsuPjt3yvq804PguzLnMruCSvZ4C7xYS4trdg1blJPh26eeK/P2QfCCHpWKedsRS3bPKkjAvugnMKs+3Zs1k+PshAiZsET4sWPGNnf1E89Kh7/2XMa1mgbXtHt7zPNC4kamTqUL/QmEVI8LJNq7C9P3LR03kK2szJDhPzkWPgRyY2YpD2eq1aCJm0bkX9mBWTZdSYFhKt3vuM1Qjp5PWXk0tN5h9dNFqpisihK7XboB81poER2SmnZ8PIslzWu2iULM7VWxmEDA70JKBJFweqLCFBHRszA8Nt3AXF0z5qe61oH1oSUmtPwNhdQQ2G5X3g==';
-// 请从 https://dashboard.pingxx.com 获取「Webhooks 验证 Ping++ 公钥」
-$pub_key_path = __DIR__ . "/rsa_public_key.pem";
-
-$result = verify_signature($raw_data, $signature, $pub_key_path);
-if ($result === 1) {
-    echo 'verification succeeded';
-} elseif ($result === 0) {
-    echo 'verification failed';
-} else {
-    echo 'verification error';
-}

+ 27 - 0
www/protected/vendors/pingpp/example/your_rsa_private_key.pem

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAx2MktxcKBEqdYRi2IgYcupPQIN5cxgiBL5udCCBJBNBbXPaq
+uOE1qspfhB1KUzHXATnCONiSzubLcBTnwi2tz0ErRCeJZSERRCpbKx4eu6b1neUT
+Wkga7xpZxWONEvkmZo5Nlhf4fXRPUYnO/bdGCNGpQ/HSJfWLtzmhCqO1aJwVhcDm
+DMYz4bTkZavhFBdVyXf/8n7UKylk03eymlKJ1swQpeFcxaKfzsk1mJU7mc93mCWj
+aR+VWkNbw4AQHDyHgbzH+zYARzCluiy5hXdixGEP+iO4ZBk48rEs1hKTvGz1k+jh
+LCdkdpBRjq0pK/htjA3Ce8pF2AJs+fgN6ZUumQIDAQABAoIBAFa4MEfRpXGoYjrQ
+3KZ/sg8UKvmgvQkEuetS60GViSym0pXkUuyGRyk5S8HSW3lDvBe0X10KFRAYIXNm
+JEa4R1hVJ9REveVWNIRJR83BE+zZ+QnrkDc8FTrZYyIO4lTWOHVyfxxA4Lrv02/L
+WFPRWoyLY+tBSf1ohpPyZLCT81rDglT1Z4svX020y8tXvnQqQiOjl4q7Zu4b26HU
+TQ463ntMEhM5u7y9MFcxGRaOpF/gARlMGqDu6T8h/oYMiOSLoXOuTR7B80yaX/Mj
+RZfUBoZMb5thX9qBLQ7dYnTkwaxwerYPrYvQrW9vtsswZ5NeIbEmCZyorUe8DOmQ
+hT1+HmECgYEA/iQERHhZKHXnP0gvhl/uEOGOvLjD5H1D6zClzOHMmOcIF5OuEQb0
+VcSMV+8emN7SCp/b/LVgKa27Mla9eXm+EXABRFcI7qGYsYXfbCD7EYX3TaJSp/30
+jyLBy+MsHCTEiLeylSh7kHqgTR8tKND8UIzXo9aM7JqwFqleeXGyh7MCgYEAyNiU
+EUzyBAv9sui3ZgVYRiVvTilk2HVTY6u61/mMOLsTrX3eYQaqb4GRJJShJO9mmsxX
+RHBEZQJvUqqF9PapOsyv8HKuF5+UP6svHnJo7sn9gCvV/h1HTHqzFcYSvUaXnrym
+D/0Tthf8CDeuGp5UFWMoFZF14HTr1oQROGAASoMCgYA0bZmzxmAeSLR8CZhEUGX8
+dYvMwxEmgfERA+gwbCSZJpA0zPKL8LNXPkT1nw7g2pbaOkBX0dMUxhJoQBy2grcD
+QegBATOGhy/I76U32VXyN4DdMy96GJnrLXBtb2AaLjudOMhOnRtgouuO/W+DjBmB
+RIz377sC1KafBjHHO/1ooQKBgDQqfJrZv2ppquVTKH9pF/pwMq68daL7JkOXERqT
+iGYbwQqozJ+q2Y3Iu2gi6o/rVl0SggAWoM0TitKP0+dCQcYx7+imAK3GFv1KexyP
+Xs3WzO8Dc7ti42fr3qPjJG7g7PSfzwoME5iSNjX0MFZdlT1Q2dJwS4uXEsJO3yIj
+XS/9AoGBALRApgtUA7Odw4tjCLGvxXuLFnyRkg6hFqoXAP2j8H9bJDOlSSVwQTFd
+ahbcIDtQJS57vXUGK2uspbFKLm1WCFzPVyuxDIW6oue/kO+YxxU3NA58zk8oaORq
+eA3YvHc7ZmRjVnVkxnXjKofrL6jF5A+lXSXnXchrv2ZYI+1pOsIV
+-----END RSA PRIVATE KEY-----

+ 9 - 0
www/protected/vendors/pingpp/example/your_rsa_public_key.pem

@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2MktxcKBEqdYRi2IgYc
+upPQIN5cxgiBL5udCCBJBNBbXPaquOE1qspfhB1KUzHXATnCONiSzubLcBTnwi2t
+z0ErRCeJZSERRCpbKx4eu6b1neUTWkga7xpZxWONEvkmZo5Nlhf4fXRPUYnO/bdG
+CNGpQ/HSJfWLtzmhCqO1aJwVhcDmDMYz4bTkZavhFBdVyXf/8n7UKylk03eymlKJ
+1swQpeFcxaKfzsk1mJU7mc93mCWjaR+VWkNbw4AQHDyHgbzH+zYARzCluiy5hXdi
+xGEP+iO4ZBk48rEs1hKTvGz1k+jhLCdkdpBRjq0pK/htjA3Ce8pF2AJs+fgN6ZUu
+mQIDAQAB
+-----END PUBLIC KEY-----

+ 3 - 1
www/protected/vendors/pingpp/init.php

@@ -28,7 +28,8 @@ require(dirname(__FILE__) . '/lib/Error/RateLimit.php');
 require(dirname(__FILE__) . '/lib/Error/Channel.php');
 
 // Plumbing
-require(dirname(__FILE__) . '/lib/Object.php');
+require(dirname(__FILE__) . '/lib/JsonSerializable.php');
+require(dirname(__FILE__) . '/lib/PingppObject.php');
 require(dirname(__FILE__) . '/lib/ApiRequestor.php');
 require(dirname(__FILE__) . '/lib/ApiResource.php');
 require(dirname(__FILE__) . '/lib/SingletonApiResource.php');
@@ -47,6 +48,7 @@ require(dirname(__FILE__) . '/lib/Card.php');
 require(dirname(__FILE__) . '/lib/Token.php');
 require(dirname(__FILE__) . '/lib/CardInfo.php');
 require(dirname(__FILE__) . '/lib/SmsCode.php');
+require(dirname(__FILE__) . '/lib/Identification.php');
 
 // wx_pub OAuth 2.0 method
 require(dirname(__FILE__) . '/lib/WxpubOAuth.php');

+ 43 - 107
www/protected/vendors/pingpp/lib/ApiRequestor.php

@@ -11,14 +11,6 @@ class ApiRequestor
 
     private $_apiBase;
 
-    private static $_preFlight = array();
-
-    private static function blacklistedCerts()
-    {
-        return array(
-        );
-    }
-
     public function __construct($apiKey = null, $apiBase = null)
     {
         $this->_apiKey = $apiKey;
@@ -150,11 +142,6 @@ class ApiRequestor
 
     private function _requestRaw($method, $url, $params, $headers)
     {
-        if (!array_key_exists($this->_apiBase, self::$_preFlight) ||
-            !self::$_preFlight[$this->_apiBase]) {
-            self::$_preFlight[$this->_apiBase] = $this->checkSslCert($this->_apiBase);
-        }
-
         $myApiKey = $this->_apiKey;
         if (!$myApiKey) {
             $myApiKey = Pingpp::$apiKey;
@@ -164,7 +151,7 @@ class ApiRequestor
             $msg = 'No API key provided.  (HINT: set your API key using '
                 . '"Pingpp::setApiKey(<API-KEY>)".  You can generate API keys from '
                 . 'the Pingpp web interface.  See https://pingxx.com/document/api for '
-                . 'details, or email support@pingxx.com if you have any questions.';
+                . 'details.';
             throw new Error\Authentication($msg);
         }
 
@@ -187,9 +174,12 @@ class ApiRequestor
         if (Pingpp::$apiVersion) {
             $defaultHeaders['Pingplusplus-Version'] = Pingpp::$apiVersion;
         }
-        if ($method == 'post') {
+        if ($method == 'post' || $method == 'put') {
             $defaultHeaders['Content-type'] = 'application/json;charset=UTF-8';
         }
+        if ($method == 'put') {
+            $defaultHeaders['X-HTTP-Method-Override'] = 'PUT';
+        }
         $requestHeaders = Util\Util::getRequestHeaders();
         if (isset($requestHeaders['Pingpp-Sdk-Version'])) {
             $defaultHeaders['Pingpp-Sdk-Version'] = $requestHeaders['Pingpp-Sdk-Version'];
@@ -236,16 +226,28 @@ class ApiRequestor
         $curl = curl_init();
         $method = strtolower($method);
         $opts = array();
+        $requestSignature = NULL;
         if ($method == 'get') {
             $opts[CURLOPT_HTTPGET] = 1;
             if (count($params) > 0) {
                 $encoded = self::encode($params);
                 $absUrl = "$absUrl?$encoded";
             }
-        } else if ($method == 'post') {
-            $opts[CURLOPT_POST] = 1;
-            $opts[CURLOPT_POSTFIELDS] = json_encode($params);
-        } else if ($method == 'delete') {
+        } elseif ($method == 'post' || $method == 'put') {
+            if ($method == 'post') {
+                $opts[CURLOPT_POST] = 1;
+            } else {
+                $opts[CURLOPT_CUSTOMREQUEST] = 'PUT';
+            }
+            $rawRequestBody = json_encode($params);
+            $opts[CURLOPT_POSTFIELDS] = $rawRequestBody;
+            if ($this->privateKey()) {
+                $signResult = openssl_sign($rawRequestBody, $requestSignature, $this->privateKey(), 'sha256');
+                if (!$signResult) {
+                    throw new Error\Api("Generate signature failed");
+                }
+            }
+        } elseif ($method == 'delete') {
             $opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
             if (count($params) > 0) {
                 $encoded = self::encode($params);
@@ -255,6 +257,10 @@ class ApiRequestor
             throw new Error\Api("Unrecognized method $method");
         }
 
+        if ($requestSignature) {
+            $headers[] = 'Pingplusplus-Signature: ' . base64_encode($requestSignature);
+        }
+
         $absUrl = Util\Util::utf8($absUrl);
         $opts[CURLOPT_URL] = $absUrl;
         $opts[CURLOPT_RETURNTRANSFER] = true;
@@ -310,111 +316,41 @@ class ApiRequestor
         case CURLE_COULDNT_CONNECT:
         case CURLE_COULDNT_RESOLVE_HOST:
         case CURLE_OPERATION_TIMEOUTED:
-            $msg = "Could not connect to Pingpp ($apiBase).  Please check your "
+            $msg = "Could not connect to Ping++ ($apiBase).  Please check your "
                 . "internet connection and try again.  If this problem persists, "
                 . "you should check Pingpp's service status at "
-                . "https://pingxx.com, or";
+                . "https://pingxx.com/status.";
             break;
         case CURLE_SSL_CACERT:
         case CURLE_SSL_PEER_CERTIFICATE:
-            $msg = "Could not verify Pingpp's SSL certificate.  Please make sure "
+            $msg = "Could not verify Ping++'s SSL certificate.  Please make sure "
                 . "that your network is not intercepting certificates.  "
-                . "(Try going to $apiBase in your browser.)  "
-                . "If this problem persists,";
+                . "(Try going to $apiBase in your browser.)";
             break;
         default:
-            $msg = "Unexpected error communicating with Pingpp.  "
-                . "If this problem persists,";
+            $msg = "Unexpected error communicating with Ping++.";
         }
-        $msg .= " let us know at support@pingxx.com.";
 
         $msg .= "\n\n(Network error [errno $errno]: $message)";
         throw new Error\ApiConnection($msg);
     }
 
-    private function checkSslCert($url)
-    {
-        /* Preflight the SSL certificate presented by the backend. This isn't 100%
-         * bulletproof, in that we're not actually validating the transport used to
-         * communicate with Pingpp, merely that the first attempt to does not use a
-         * revoked certificate.
-
-         * Unfortunately the interface to OpenSSL doesn't make it easy to check the
-         * certificate before sending potentially sensitive data on the wire. This
-         * approach raises the bar for an attacker significantly.
-         */
-
-        if (!function_exists('stream_context_get_params') ||
-            !function_exists('stream_socket_enable_crypto')) {
-            error_log(
-                'Warning: This version of PHP is too old to check SSL certificates '.
-                'correctly. Pingpp cannot guarantee that the server has a '.
-                'certificate which is not blacklisted'
-            );
-            return true;
-        }
-
-        $url = parse_url($url);
-        $port = isset($url["port"]) ? $url["port"] : 443;
-        $url = "ssl://{$url["host"]}:{$port}";
-
-        $sslContext = stream_context_create(
-            array('ssl' => array(
-                'capture_peer_cert' => true,
-                'verify_peer'   => true,
-                'cafile'        => $this->caBundle(),
-            ))
-        );
-        $result = stream_socket_client(
-            $url, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $sslContext
-        );
-        if ($errno !== 0) {
-            $apiBase = Pingpp::$apiBase;
-            throw new Error\ApiConnection(
-                'Could not connect to Pingpp ($apiBase).  Please check your '.
-                'internet connection and try again.  If this problem persists, '.
-                'you should check Pingpp\'s service status at '.
-                'https://pingxx.com. Reason was: '.$errstr
-            );
-        }
-
-        $params = stream_context_get_params($result);
-
-        $cert = $params['options']['ssl']['peer_certificate'];
-
-        openssl_x509_export($cert, $pem_cert);
-
-        if (self::isBlackListed($pem_cert)) {
-            throw new Error\ApiConnection(
-                'Invalid server certificate. You tried to connect to a server '.
-                'that has a revoked SSL certificate, which means we cannot '.
-                'securely send data to that server.  Please email '.
-                'support@pingxx.com if you need help connecting to the '.
-                'correct API server.'
-            );
-        }
-
-        return true;
-    }
-
-    /* Checks if a valid PEM encoded certificate is blacklisted
-     * @return boolean
-     */
-    public static function isBlackListed($certificate)
+    private function caBundle()
     {
-        $certificate = trim($certificate);
-        $lines = explode("\n", $certificate);
-
-        // Kludgily remove the PEM padding
-        array_shift($lines); array_pop($lines);
-
-        $der_cert = base64_decode(implode("", $lines));
-        $fingerprint = sha1($der_cert);
-        return in_array($fingerprint, self::blacklistedCerts());
+        return dirname(__FILE__) . '/../data/ca-certificates.crt';
     }
 
-    private function caBundle()
+    private function privateKey()
     {
-        return dirname(__FILE__) . '/../data/ca-certificates.crt';
+        if (!Pingpp::$privateKey) {
+            if (!Pingpp::$privateKeyPath) {
+                return NULL;
+            }
+            if (!file_exists(Pingpp::$privateKeyPath)) {
+                throw new Error\Api('Private key file not found at: ' . Pingpp::$privateKeyPath);
+            }
+            Pingpp::$privateKey = file_get_contents(Pingpp::$privateKeyPath);
+        }
+        return Pingpp::$privateKey;
     }
 }

+ 2 - 3
www/protected/vendors/pingpp/lib/ApiResource.php

@@ -2,7 +2,7 @@
 
 namespace Pingpp;
 
-abstract class ApiResource extends Object
+abstract class ApiResource extends PingppObject
 {
     private static $HEADERS_TO_PERSIST = array('Pingpp-Version' => true);
 
@@ -128,7 +128,6 @@ abstract class ApiResource extends Object
     protected static function _create($params = null, $options = null)
     {
         self::_validateParams($params);
-        $base = static::baseUrl();
         $url = static::classUrl();
 
         list($response, $opts) = static::_staticRequest('post', $url, $params, $options);
@@ -140,7 +139,7 @@ abstract class ApiResource extends Object
         $params = $this->serializeParameters();
         if (count($params) > 0) {
             $url = $this->instanceUrl();
-            list($response, $opts) = $this->_request('post', $url, $params, $options);
+            list($response, $opts) = $this->_request('put', $url, $params, $options);
             $this->refreshFrom($response, $opts);
         }
         return $this;

+ 1 - 1
www/protected/vendors/pingpp/lib/AttachedObject.php

@@ -3,7 +3,7 @@
 namespace Pingpp;
 
 // e.g. metadata on Pingpp objects.
-class AttachedObject extends Object
+class AttachedObject extends PingppObject
 {
     /**
      * Updates this object.

+ 0 - 2
www/protected/vendors/pingpp/lib/Card.php

@@ -57,6 +57,4 @@ class Customer extends ApiResource
     {
         return $this->_delete($params, $opts);
     }
-
-    
 }

+ 26 - 0
www/protected/vendors/pingpp/lib/Error/Api.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Pingpp;
+
+class Identification extends ApiResource
+{
+    /**
+     * @param array|null $params
+     * @param array|string|null $options
+     *
+     * @return Identification result.
+     */
+    public static function identify($params = null, $options = null)
+    {
+        return self::_create($params, $options);
+    }
+
+    /**
+     * @return string The API URL for this Pingpp identification.
+     */
+     public static function classUrl()
+     {
+         $base = static::className();
+         return "/v1/${base}";
+     }
+}

+ 18 - 0
www/protected/vendors/pingpp/lib/JsonSerializable.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace Pingpp;
+
+// JsonSerializable only exists in PHP 5.4+. Stub if out if it doesn't exist
+if (interface_exists('\JsonSerializable', false)) {
+    interface JsonSerializable extends \JsonSerializable
+    {
+    }
+} else {
+    // PSR2 wants each interface to have its own file.
+    // @codingStandardsIgnoreStart
+    interface JsonSerializable
+    {
+        // @codingStandardsIgnoreEnd
+        public function jsonSerialize();
+    }
+}

+ 46 - 3
www/protected/vendors/pingpp/lib/Pingpp.php

@@ -11,17 +11,27 @@ class Pingpp
     /**
      * @var string The base URL for the Pingpp API.
      */
-    public static $apiBase = 'https://api.pingxx.com/';
+    public static $apiBase = 'https://api.pingxx.com';
     /**
      * @var string|null The version of the Pingpp API to use for requests.
      */
-    public static $apiVersion = "2015-10-10";
+    public static $apiVersion = "2016-07-20";
     /**
      * @var boolean Defaults to true.
      */
     public static $verifySslCerts = true;
 
-    const VERSION = '2.1.0';
+    const VERSION = '2.1.5';
+
+    /**
+     * @var string The private key path to be used for signing requests.
+     */
+    public static $privateKeyPath;
+
+    /**
+     * @var string The PEM formatted private key to be used for signing requests.
+     */
+    public static $privateKey;
 
     /**
      * @return string The API key used for requests.
@@ -73,4 +83,37 @@ class Pingpp
     {
         self::$verifySslCerts = $verify;
     }
+
+    /**
+     * @return string
+     */
+    public static function getPrivateKeyPath()
+    {
+        return self::$privateKeyPath;
+    }
+
+    /**
+     * @param string $path
+     */
+    public static function setPrivateKeyPath($path)
+    {
+        self::$privateKeyPath = $path;
+    }
+
+
+    /**
+     * @return string
+     */
+    public static function getPrivateKey()
+    {
+        return self::$privateKey;
+    }
+
+    /**
+     * @param string $key
+     */
+    public static function setPrivateKey($key)
+    {
+        self::$privateKey = $key;
+    }
 }

+ 14 - 8
www/protected/vendors/pingpp/lib/Object.php → www/protected/vendors/pingpp/lib/PingppObject.php

@@ -5,7 +5,7 @@ namespace Pingpp;
 use ArrayAccess;
 use InvalidArgumentException;
 
-class Object implements ArrayAccess
+class PingppObject implements ArrayAccess, JsonSerializable
 {
     /**
      * @var array Attributes that should not be sent to the API because they're
@@ -21,7 +21,7 @@ class Object implements ArrayAccess
     public static function init()
     {
         self::$permanentAttributes = new Util\Set(array('_opts', 'id'));
-        self::$nestedUpdatableAttributes = new Util\Set(array('metadata'));
+        self::$nestedUpdatableAttributes = new Util\Set(array());
     }
 
     protected $_opts;
@@ -133,7 +133,7 @@ class Object implements ArrayAccess
      * @param stdObject $values
      * @param array $opts
      *
-     * @return Object The object constructed from the given values.
+     * @return PingppObject The object constructed from the given values.
      */
     public static function constructFrom($values, $opts)
     {
@@ -200,19 +200,25 @@ class Object implements ArrayAccess
 
         // Get nested updates.
         foreach (self::$nestedUpdatableAttributes->toArray() as $property) {
-            if (isset($this->$property) && $this->$property instanceOf Object) {
+            if (isset($this->$property) && $this->$property instanceOf PingppObject) {
                 $params[$property] = $this->$property->serializeParameters();
             }
         }
         return $params;
     }
 
+    public function jsonSerialize()
+    {
+        return $this->__toStdObject();
+    }
+
     public function __toJSON()
     {
-        if (defined('JSON_PRETTY_PRINT'))
-            return json_encode($this->__toStdObject(), JSON_PRETTY_PRINT);
-        else
+        if (defined('JSON_PRETTY_PRINT')) {
+            return json_encode($this->__toStdObject(), JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
+        } else {
             return json_encode($this->__toStdObject());
+        }
     }
 
     public function __toString()
@@ -235,4 +241,4 @@ class Object implements ArrayAccess
 }
 
 
-Object::init();
+PingppObject::init();

+ 9 - 1
www/protected/vendors/pingpp/lib/RedEnvelope.php

@@ -37,5 +37,13 @@ class Transfer extends ApiResource
         return self::_create($params, $options);
     }
 
-
+    /** 更新 transfer 对象
+     * @param array|string|null $options
+     *
+     * @return Transfer The created transfer.
+     */
+    public function save($options = null)
+    {
+        return $this->_save($options);
+    }
 }

+ 11 - 7
www/protected/vendors/pingpp/lib/Util/RequestOptions.php

@@ -2,7 +2,7 @@
 
 namespace Pingpp\Util;
 
-use Pingpp\Object;
+use Pingpp\PingppObject;
 use stdClass;
 
 abstract class Util
@@ -41,7 +41,7 @@ abstract class Util
             if ($k[0] == '_') {
                 continue;
             }
-            if ($v instanceof Object) {
+            if ($v instanceof PingppObject) {
                 $results[$k] = $keep_object ? $v->__toStdObject(true) : $v->__toArray(true);
             } else if (is_array($v)) {
                 $results[$k] = self::convertPingppObjectToArray($v, $keep_object);
@@ -66,7 +66,7 @@ abstract class Util
             if ($k[0] == '_') {
                 continue;
             }
-            if ($v instanceof Object) {
+            if ($v instanceof PingppObject) {
                 $results->$k = $v->__toStdObject(true);
             } else if (is_array($v)) {
                 $results->$k = self::convertPingppObjectToArray($v, true);
@@ -82,7 +82,7 @@ abstract class Util
      *
      * @param stdObject $resp The response from the Pingpp API.
      * @param array $opts
-     * @return Object|array
+     * @return PingppObject|array
      */
     public static function convertToPingppObject($resp, $opts)
     {
@@ -105,12 +105,12 @@ abstract class Util
                 array_push($mapped, self::convertToPingppObject($i, $opts));
             return $mapped;
         } else if (is_object($resp)) {
-            if (isset($resp->object) 
+            if (isset($resp->object)
                 && is_string($resp->object)
                 && isset($types[$resp->object])) {
                     $class = $types[$resp->object];
                 } else {
-                    $class = 'Pingpp\\Object';
+                    $class = 'Pingpp\\PingppObject';
                 }
             return $class::constructFrom($resp, $opts);
         } else {
@@ -121,7 +121,11 @@ abstract class Util
     public static function getRequestHeaders()
     {
         if (function_exists('getallheaders')) {
-            return getallheaders();
+            $headers = array();
+            foreach (getallheaders() as $name => $value) {
+                $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('-', ' ', $name))))] = $value;
+            }
+            return $headers;
         }
         $headers = array();
         foreach ($_SERVER as $name => $value) {

+ 0 - 0
www/protected/vendors/pingpp/lib/WxpubOAuth.php


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác