123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- <?php
- namespace App\Libs\Pay\Merchants;
- use Exception;
- use GuzzleHttp\Client;
- use Log;
- class SandPay
- {
- const API_HOST = 'https://cashier.sandpay.com.cn/gateway/api/';
- const API_TEST_HOST = 'http://61.129.71.103:8003/gateway/';
- const NOTIFY_HOST = 'http://47.97.120.133:8094/';
- const NOTIFY_TEST_HOST = 'http://managepre.aizhuishu.com/';
- private $notify_url;
- private $front_url;
- private $pay_url;
- private $query_order_url;
- private $private_key;
- private $public_key;
- private $client;
- private $mer_id;
- private $app_id;
- public function __construct(array $config)
- {
- $this->pay_url = (self::API_HOST) . 'order/pay';
- $this->query_order_url = (self::API_HOST) . 'order/query';
- $this->mer_id = $config['mer_id'];
- $this->app_id = $config['app_id'];
- $this->private_key = $this->loadPk12Cert(storage_path($config['private_key_path']), $config['cert_pwd']);
- $this->public_key = $this->loadX509Cert(storage_path($config['public_key_path']));
- $this->notify_url = env('SANDPAY_CALL_BACK_URL');
- //$this->notify_url = (env('APP_ENV') == 'online' ? self::NOTIFY_HOST : self::NOTIFY_TEST_HOST) . 'pay/sandpay_back';
- $this->front_url = (env('APP_ENV') == 'online' ? self::NOTIFY_HOST : self::NOTIFY_TEST_HOST) . 'pay/sandpay_back';
- $this->client = new Client();
- }
- public function notify(array $params)
- {
- $sign = $params['sign']; //签名
- $signType = $params['signType']; //签名方式
- $data = stripslashes($params['data']); //支付数据
- $result = json_decode($data, true); //data数据
- if ($this->verify($data, $sign, $this->public_key)) {
- //签名验证成功
- return $result;
- } else {
- //签名验证失败
- myLog('sand_pay')->error('sign error: ' . json_encode($params));
- }
- }
- public function send(array $data)
- {
- $params = [
- 'head' => [
- 'version' => '1.0',
- 'method' => 'sandpay.trade.pay',
- 'productId' => '00002020',
- 'accessType' => '1',
- 'mid' => $this->mer_id,
- 'channelType' => '07',
- 'reqTime' => date('YmdHis', time())
- ],
- 'body' => [
- 'orderCode' => $data['trade_no'],
- 'totalAmount' => $this->amountFormat($data['price']/100),
- 'subject' => $data['body'],
- 'body' => $data['body'],
- 'payMode' => 'sand_wx',
- 'payExtra' => json_encode([
- 'subAppid' => $this->app_id,
- 'userId' => $data['openid'],
- ]),
- 'clientIp' => _getIp(),
- 'notifyUrl' => $this->notify_url,
- 'frontUrl' => $this->front_url,
- 'extend' => ''
- ]
- ];
- $result = '';
- try{
- $result = $this->sendPost($this->pay_url, $params);
- }catch (\Exception $e){
- Log::error('SandPay $request param is :');
- Log::error($params);
- Log::error('SandPay error return '.' pay_url: response '.$result);
- }
- $data = json_decode($result['data'], true);
- if ($data['head']['respCode'] == "000000") {
- $credential = json_decode($data['body']['credential'],true);
- return json_decode($credential['params'],true);
- } else {
- myLog('sand_pay')->error('唤起支付失败: ' );
- myLog('sand_pay')->error($result );
- myLog('sand_pay')->error($params );
- return [];
- }
- }
- public function refund(array $data){
- $params = [
- 'head'=>[
- 'version'=>'1.0',
- 'method'=>'sandpay.trade.refund',
- 'productId'=>'00002020',
- 'accessType'=>'1',
- 'mid'=>$this->mer_id,
- 'channelType' => '07',
- 'reqTime' => date('YmdHis')
- ],
- 'body' => [
- 'orderCode' => $data['refund_no'],
- 'refundAmount' => $this->amountFormat($data['price']/100),
- 'oriOrderCode'=>$data['trade_no'],
- 'notifyUrl' => $data['callback'],
- 'refundReason' => '退货',
- 'extend' => isset($data['attach'])?$data['attach']:''
- ]
- ];
- $url = 'https://cashier.sandpay.com.cn/gateway/api/order/refund';
- $result = '';
- try{
- $result = $this->sendPost($url, $params);
- }catch (\Exception $e){
- Log::error('SandPay $request param is :');
- Log::error($params);
- Log::error('SandPay error return '.' pay_url: response '.$result);
- }
- return $result;
- }
- public function query(array $data){
- $params = [
- 'head'=>[
- 'version'=>'1.0',
- 'method'=>'sandpay.trade.query',
- 'productId'=>'00002020',
- 'accessType'=>'1',
- 'mid'=>$this->mer_id,
- 'channelType' => '07',
- 'reqTime' => date('YmdHis')
- ],
- 'body' => [
- 'orderCode' => $data['trade_no'],
- 'extend' => ''
- ]
- ];
- $result = '';
- $url = 'https://cashier.sandpay.com.cn/gateway/api/order/query';
- try{
- $result = $this->sendPost($url, $params);
- }catch (\Exception $e){
- }
- return $result;
- }
- /**
- * 格式金额
- */
- private function amountFormat(float $amount)
- {
- $amount = (string) (int) ($amount * 100);
- $length = strlen($amount);
- for ($i = 0; $i < 12 - $length; $i++) {
- $amount = '0' . $amount;
- }
- return $amount;
- }
- /**
- * 请求接口
- * @param array $data
- * @return array
- */
- private function sendPost(string $url, array $data)
- {
- // step1: 私钥签名
- $sign = $this->sign($data, $this->private_key);
- // step2: 拼接post数据
- $post = array(
- 'charset' => 'utf-8',
- 'signType' => '01',
- 'data' => json_encode($data),
- 'sign' => $sign
- );
- // step3: post请求
- $result = $this->http_post_json($url, $post);
- $arr = $this->parse_result($result);
- try {
- //step4: 公钥验签
- $this->verify($arr['data'], $arr['sign'], $this->public_key);
- return $arr;
- } catch (Exception $e) {
- echo $e->getMessage();
- return [];
- }
- }
- private function parse_result($result)
- {
- $arr = array();
- $response = urldecode($result);
- $arrStr = explode('&', $response);
- foreach ($arrStr as $str) {
- $p = strpos($str, "=");
- $key = substr($str, 0, $p);
- $value = substr($str, $p + 1);
- $arr[$key] = $value;
- }
- return $arr;
- }
- /**
- * 发送请求
- * @param $url
- * @param $param
- * @return array|null
- * @throws Exception
- */
- private function http_post_json(string $url, array $param)
- {
- try {
- $response = $this->client->post($url, ['form_params' => $param, 'Content-Type' => 'application/x-www-form-urlencoded']);
- $content = $response->getBody()->getContents();
- return $content;
- /*$content = urldecode($content);
- parse_str($content, $result);
- return $result;*/
- } catch (Exception $e) {
- throw $e;
- }
- }
- /**
- * 获取公钥
- * @param $path
- * @return mixed
- * @throws Exception
- */
- private function loadX509Cert($path)
- {
- try {
- $file = file_get_contents($path);
- if (!$file) {
- throw new Exception('loadx509Cert::file_get_contents ERROR');
- }
- $cert = chunk_split(base64_encode($file), 64, "\n");
- $cert = "-----BEGIN CERTIFICATE-----\n" . $cert . "-----END CERTIFICATE-----\n";
- $res = openssl_pkey_get_public($cert);
- $detail = openssl_pkey_get_details($res);
- openssl_free_key($res);
- if (!$detail) {
- throw new Exception('loadX509Cert::openssl_pkey_get_details ERROR');
- }
- return $detail['key'];
- } catch (Exception $e) {
- throw $e;
- }
- }
- /**
- * 获取私钥
- * @param $path
- * @param $pwd
- * @return mixed
- * @throws Exception
- */
- private function loadPk12Cert($path, $pwd)
- {
- try {
- $file = file_get_contents($path);
- if (!$file) {
- throw new Exception('loadPk12Cert::file
- _get_contents');
- }
- if (!openssl_pkcs12_read($file, $cert, $pwd)) {
- throw new Exception('loadPk12Cert::openssl_pkcs12_read ERROR');
- }
- return $cert['pkey'];
- } catch (Exception $e) {
- throw $e;
- }
- }
- /**
- * 私钥签名
- * @param $plainText
- * @param $path
- * @return string
- * @throws Exception
- */
- function sign($plainText, $path)
- {
- $plainText = json_encode($plainText);
- try {
- $resource = openssl_pkey_get_private($path);
- $result = openssl_sign($plainText, $sign, $resource);
- openssl_free_key($resource);
- if (!$result) {
- throw new Exception('签名出错' . $plainText);
- }
- return base64_encode($sign);
- } catch (Exception $e) {
- throw $e;
- }
- }
- /**
- * 公钥验签
- * @param $plainText
- * @param $sign
- * @param $path
- * @return int
- * @throws Exception
- */
- function verify($plainText, $sign, $path)
- {
- $resource = openssl_pkey_get_public($path);
- $result = openssl_verify($plainText, base64_decode($sign), $resource);
- openssl_free_key($resource);
- if (!$result) {
- throw new Exception('签名验证未通过,plainText:' . $plainText . '。sign:' . $sign, '02002');
- }
- return $result;
- }
- /**
- * 公钥加密AESKey
- * @param $plainText
- * @param $puk
- * @return string
- * @throws Exception
- */
- function RSAEncryptByPub($plainText, $puk)
- {
- if (!openssl_public_encrypt($plainText, $cipherText, $puk, OPENSSL_PKCS1_PADDING)) {
- throw new Exception('AESKey 加密错误');
- }
- return base64_encode($cipherText);
- }
- /**
- * 私钥解密AESKey
- * @param $cipherText
- * @param $prk
- * @return string
- * @throws Exception
- */
- function RSADecryptByPri($cipherText, $prk)
- {
- if (!openssl_private_decrypt(base64_decode($cipherText), $plainText, $prk, OPENSSL_PKCS1_PADDING)) {
- throw new Exception('AESKey 解密错误');
- }
- return (string) $plainText;
- }
- /**
- * AES加密
- * @param $plainText
- * @param $key
- * @return string
- * @throws Exception
- */
- function AESEncrypt($plainText, $key)
- {
- $plainText = json_encode($plainText);
- $result = openssl_encrypt($plainText, 'AES-128-ECB', $key, 1);
- if (!$result) {
- throw new Exception('报文加密错误');
- }
- return base64_encode($result);
- }
- /**
- * AES解密
- * @param $cipherText
- * @param $key
- * @return string
- * @throws Exception
- */
- function AESDecrypt($cipherText, $key)
- {
- $result = openssl_decrypt(base64_decode($cipherText), 'AES-128-ECB', $key, 1);
- if (!$result) {
- throw new Exception('报文解密错误', 2003);
- }
- return $result;
- }
- /**
- * 生成AESKey
- * @param $size
- * @return string
- */
- function aes_generate($size)
- {
- $str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- $arr = array();
- for ($i = 0; $i < $size; $i++) {
- $arr[] = $str[mt_rand(0, 61)];
- }
- return implode('', $arr);
- }
- }
|