<?php
/**
 * Created by PhpStorm.
 * User: z-yang
 * Date: 2017/12/9
 * Time: 12:02
 */

namespace App\Libs\Pay\Merchants;
use Illuminate\Support\Facades\Storage;
use App\Libs\PayClient;
use Log;

class LianLianPay
{

    private $appid;
    private $oid_partner;
    public $private_key_path;
    public $public_key_path;
    public $key;
    private $api_url;
    private $PayClient;
    private $sign_type;
    private $col_oidpartner;
    public function __construct($config=[])
    {
        
        $this->appid = $config['appid'];
        $this->oid_partner = $config['oid_partner'];
        $this->api_url = $config['api_url'];
        $this->key = $config['key'];
        $this->private_key_path = $config['private_key_path'];
        $this->public_key_path = $config['public_key_path'];
        $this->sign_type = 'RSA';
        $this->col_oidpartner = $config['col_oidpartner'];
    }

    function send($data)
    {
        $uid = json_decode($data['remark'],true)['uid'];

        $request_data = [
            'no_order'=>$data['trade_no'],
            'oid_partner'=>$this->oid_partner,
            'appid'=>$this->appid,
            'openid'=>$data['openid'],
            'busi_partner'=>'101001',
            'money_order'=>$data['price']/100,
            'user_id'=>$uid,
            "col_oidpartner"=>$this->col_oidpartner,
            'dt_order'=>date('YmdHis'),
            'notify_url'=>env('LIANLIAN_PAY_CALL_BACK_URL'),
            'pay_type'=>'W',
            'risk_item'=>'',
            'sign_type'=>$this->sign_type,
        ];
        $request_data['risk_item'] = json_encode([
            'frms_ware_category'=>'1004',
            'user_info_mercht_userno'=>$uid,
            'user_info_dt_register'=>'20171112103052',
            'user_info_bind_phone'=>'18606947570'
        ]);

        $request_data = $this->buildRequestPara($request_data);

        $result = $this->getHttpResponseJSON($this->api_url,$request_data);
        \Log::info('lianlian res---------------------');
        \Log::info($result);
        $res = json_decode($result,true);
        if ($res['ret_code'] == '0000') {
            //$pay_data = json_decode($res["payLoad"], true);
            return $res["payLoad"];
        }else{
            return $res;
        }

    }


    /**
     * 生成要请求给连连支付的参数数组
     * @param $para_temp
     * @return
     */
    function buildRequestPara($para_temp) {
        //除去待签名参数数组中的空值和签名参数
        $para_filter = $this->paraFilter($para_temp);
        //对待签名参数数组排序
        $para_sort = $this->argSort($para_filter);
        //生成签名结果
        $mysign = $this->buildRequestMysign($para_sort);
        //签名结果与签名方式加入请求提交参数组中
        $para_sort['sign'] = $mysign;
        $para_sort['sign_type'] = strtoupper(trim($this->sign_type));
        foreach ($para_sort as $key => $value) {
            $para_sort[$key] = $value;
        }
        return $para_sort;
        //return urldecode(json_encode($para_sort));
    }

    /**
     * 除去数组中的空值和签名参数
     * @param $para
     * return 去掉空值与签名参数后的新签名参数组
     */
    function paraFilter($para) {
        $para_filter = array();
        while (list ($key, $val) = each ($para)) {
            if($key == "sign" || $val == "")continue;
            else    $para_filter[$key] = $para[$key];
        }
        return $para_filter;
    }

    /**
     * 对数组排序
     * @param $para
     * return 排序后的数组
     */
    function argSort($para) {
        ksort($para);
        reset($para);
        return $para;
    }

    /**
     * 生成签名结果
     * @param $para_sort
     * return 签名结果字符串
     */
    function buildRequestMysign($para_sort) {
        //把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        $prestr = $this->createLinkstring($para_sort);
        $mysign = "";
        switch (strtoupper(trim($this->sign_type))) {
            case "MD5" :
                $mysign = $this->md5Sign($prestr, $this->key);
                break;
            case "RSA" :
                $private_key = Storage::disk('public')->get($this->private_key_path);
                $mysign = $this->Rsasign($prestr, $private_key);
                break;
            default :
                $mysign = "";
        }
        return $mysign;
    }

    /**
    * 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
    * @param $para
    * return 拼接完成以后的字符串
    */
    public function createLinkstring($para) {
        $arg  = "";
        while (list ($key, $val) = each ($para)) {
            $arg.=$key."=".$val."&";
        }
        //去掉最后一个&字符
        $arg = substr($arg,0,count($arg)-2);
        //file_put_contents("log.txt","转义前:".$arg."\n", FILE_APPEND);
        //如果存在转义字符，那么去掉转义
        if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
        //file_put_contents("log.txt","转义后:".$arg."\n", FILE_APPEND);
        return $arg;
    }


    /**
     * 签名字符串
     * @param $prestr 需要签名的字符串
     * @param $key 私钥
     * return 签名结果
     */
    public function md5Sign($prestr, $key) {
        $prestr = $prestr ."&key=". $key;
        return md5($prestr);
    }

    /**
     * 签名验证
     * @param $prestr
     * @param $sign
     * @param $key
     * @return bool
     */
    public function md5Verify($prestr, $sign, $key) {
        $prestr = $prestr ."&key=". $key;

        $mysgin = md5($prestr);

        if($mysgin == $sign) {
            return true;
        }
        else {
            return false;
        }
    }

    /**RSA签名
     * $data签名数据(需要先排序，然后拼接)
     * 签名用商户私钥，必须是没有经过pkcs8转换的私钥
     * 最后的签名，需要用base64编码
     * return Sign签名
     */

    public function Rsasign($data,$priKey) {
        //转换为openssl密钥，必须是没有经过pkcs8转换的私钥
        $res = openssl_get_privatekey($priKey);

        //调用openssl内置签名方法，生成签名$sign
        openssl_sign($data, $sign, $res,OPENSSL_ALGO_MD5);

        //释放资源
        openssl_free_key($res);
        //base64编码
        $sign = base64_encode($sign);
        return $sign;
    }


    /**RSA验签
     * $data待签名数据(需要先排序，然后拼接)
     * $sign需要验签的签名,需要base64_decode解码
     * 验签用连连支付公钥
     * return 验签是否通过 bool值
     */
    public function Rsaverify($data, $sign)  {
        \Log::info('Rsaverify param is');
        \Log::info($data);
        \Log::info($sign);
        //读取连连支付公钥文件
        $pubKey = Storage::disk('public')->get($this->public_key_path);
        \Log::info($pubKey);
        //转换为openssl格式密钥
        //$res = openssl_get_publickey($pubKey);
        $res = openssl_pkey_get_public($pubKey);
        \Log::info('public key--is');
        \Log::info($res);
        //调用openssl内置方法验签，返回bool值
        $result = openssl_verify($data, base64_decode($sign), $res,OPENSSL_ALGO_MD5);

        //释放资源
        openssl_free_key($res);

        //返回资源是否成功
        return $result;
    }

    /**
    *
    * 签名验证
    */
    public function rsaCheck($data){
        $sign = $data['sign'];
        $no_sign_data = $this->argSort($this->paraFilter($data));
        //$private_key = Storage::disk('public')->get($this->private_key_path);
        //$check_sing = $this->Rsasign($this->createLinkstring($no_sign_data),$private_key);
        $res =  $this->Rsaverify($this->createLinkstring($no_sign_data),$sign);
        \Log::info('lianlian-----------------check');
        \Log::info($res);
        return $res;
    }


    public  function getHttpResponseJSON($url, $para) {
        $json = json_encode($para);

        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //信任任何证书
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($curl, CURLOPT_POSTFIELDS, $json);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json',
                'Content-Length: ' . strlen($json))
        );
        $responseText = curl_exec($curl);
        curl_close($curl);
        return $responseText;
    }
}