Values; $Sign = $this->MakeSign($Parameters); $this->Values['sign'] = $Sign; return $Sign; } /** * 获取签名,详见签名生成算法的值 * @return mixed **/ public function GetSign() { return $this->Values['sign']; } /** * 判断签名,详见签名生成算法是否存在 * @return bool **/ public function IsSignSet() { return array_key_exists('sign', $this->Values); } /** * 输出xml字符 * @param mixed $Parameters * @return string **/ public function ToXml($Parameters = null) { if (is_null($Parameters)) $Parameters = $this->Values; if (is_object($Parameters)) $Parameters = (array)$Parameters; elseif (!is_array($Parameters)) return ''; $Result = ''; foreach ($Parameters as $Key => $Value) { if (is_numeric($Value)) $Result .= "<{$Key}>{$Value}"; elseif (is_object($Value) || is_array($Value)) $Result .= "<{$Key}>" . $this->ToXml($Value) . ""; else $Result .= "<{$Key}>"; } return "{$Result}"; } /** * 将xml转为array * @param string $Parameters * @return mixed */ public function FromXml($Parameters) { if (!$Parameters) return null; /// 将XML转为array /// 禁止引用外部xml实体 libxml_disable_entity_loader(true); $this->Values = json_decode(json_encode(simplexml_load_string($Parameters, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $this->Values; } /** * 格式化参数格式化成url参数 * @param mixed $Parameters * @return string; */ public function ToUrlParams($Parameters = null) { if (is_null($Parameters)) $Parameters = $this->Values; if (empty($Parameters)) return ''; if (is_object($Parameters)) $Parameters = (array)$Parameters; elseif (!is_array($Parameters)) return $Parameters; $Result = ''; foreach ($Parameters as $Key => $Value) { if (is_object($Value) || is_array($Value)) $Result .= $Key . '=' . $this->ToUrlParams($Value) . '&'; elseif (strcasecmp($Key, 'sign') != 0 && strcasecmp($Value, '') != 0) $Result .= "{$Key}={$Value}&"; } return trim($Result, '&'); } /** * 生成签名 * @param mixed $Parameters * @return string 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值 */ public function MakeSign($Parameters = null) { if (is_null($Parameters)) $Parameters = $this->Values; if (is_object($Parameters)) $Parameters = (array)$Parameters; elseif (!is_array($Parameters)) return strtoupper(md5("{$Parameters}&key={$this->SignKey}")); //签名步骤一:按字典序排序参数 ksort($Parameters); $String = $this->ToUrlParams($Parameters); //签名步骤二:在string后加入KEY $String = "{$String}&key={$this->SignKey}"; //签名步骤三:MD5加密 $String = md5($String); //签名步骤四:所有字符转为大写 $Result = strtoupper($String); return $Result; } /** * 获取设置的值 */ public function GetValues() { return $this->Values; } public function GetSignKey() { return $this->SignKey; } public function SetSignKey($SignKey) { $this->SignKey = $SignKey; } } /// 红包数据对象 class RedPackData extends WechatBaseData { public $RequestUrl = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack'; /// 请求URL /* nonce_str:随机字符串,不长于32位 sign:签名,详见签名生成算法 mch_billno:商户订单号(每个订单号必须唯一。取值范围:0~9,a~z,A~Z)接口根据商户订单号支持重入,如出现超时可再调用。 mch_id:微信支付分配的商户号 wxappid:微信分配的公众账号ID(企业号corpid即为此appId)。接口传入的所有appid应该为公众号的appid(在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。 send_name:红包发送者名称 re_openid:接受红包的用户,用户在wxappid下的openid total_amount:付款金额,单位分 total_num:红包发放总人数 wishing:红包祝福语 client_ip:调用接口的机器Ip地址 act_name:活动名称 remark:备注信息 scene_id:场景id,发放红包使用场景,红包金额大于200时必传(PRODUCT_1:商品促销、PRODUCT_2:抽奖、PRODUCT_3:虚拟物品兑奖、PRODUCT_4:企业内部福利、PRODUCT_5:渠道分润、PRODUCT_6:保险回馈、PRODUCT_7:彩票派奖、PRODUCT_8:税务刮奖) risk_info:活动信息(posttime:用户操作的时间戳,mobile:业务系统账号的手机号,国家代码-手机号。不需要+号,deviceid :mac 地址或者设备唯一标识,clientversion :用户操作的客户端版本;把值为非空的信息用key=value进行拼接,再进行urlencode,urlencode(posttime=xx& mobile =xx&deviceid=xx)) consume_mch_id:资金授权商户号,服务商替特约商户发放时使用 */ protected function SetValue($Key, $Value) { $this->Values[$Key] = $Value; } /// 微信分配的公众账号ID(企业号corpid即为此appId)。接口传入的所有appid应该为公众号的appid(在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。 public function SetAppId($app_id) { $this->SetValue('wxappid', $app_id); } /// 微信支付分配的商户号 public function SetMchId($mch_id) { $this->SetValue('mch_id', $mch_id); } /// 商户订单号(每个订单号必须唯一。取值范围:0~9,a~z,A~Z)接口根据商户订单号支持重入,如出现超时可再调用。 public function SetMchBillNo($mch_billno) { $this->SetValue('mch_billno', $mch_billno); } /// 红包发送者名称 public function SetSendName($send_name) { $this->SetValue('send_name', $send_name); } /// 接受红包的用户,用户在wxappid下的openid public function SetOpenId($open_id) { $this->SetValue('re_openid', $open_id); } /// 付款金额,单位分 public function SetAmount($amount) { $this->SetValue('total_amount', $amount); } /// 红包发放总人数 public function SetNumber($number) { $this->SetValue('total_num', $number); } /// 红包祝福语 public function SetWishing($wishing) { $this->SetValue('wishing', $wishing); } /// 调用接口的机器Ip地址 public function SetClientIp($client_ip) { $this->SetValue('client_ip', $client_ip); } /// 活动名称 public function SetActiveName($act_name) { $this->SetValue('act_name', $act_name); } /// 备注信息 public function SetRemark($remark) { $this->SetValue('remark', $remark); } /// 场景id,发放红包使用场景,红包金额大于200时必传(PRODUCT_1:商品促销、PRODUCT_2:抽奖、PRODUCT_3:虚拟物品兑奖、PRODUCT_4:企业内部福利、PRODUCT_5:渠道分润、PRODUCT_6:保险回馈、PRODUCT_7:彩票派奖、PRODUCT_8:税务刮奖) public function SetSceneId($scene_id) { $this->SetValue('scene_id', $scene_id); } /// 活动信息(posttime:用户操作的时间戳,mobile:业务系统账号的手机号,国家代码-手机号。不需要+号,deviceid :mac 地址或者设备唯一标识,clientversion :用户操作的客户端版本;把值为非空的信息用key=value进行拼接,再进行urlencode,urlencode(posttime=xx& mobile =xx&deviceid=xx)) public function SetRiskInfo($risk_info) { if (is_object($risk_info)) $risk_info = (array)$risk_info; elseif(!is_array($risk_info)) $this->SetValue('risk_info', $risk_info); $risk_info = urlencode("posttime={$risk_info['posttime']}&mobile={$risk_info['mobile']}&deviceid={$risk_info['deviceid']}&clientversion={$risk_info['clientversion']}"); $this->SetValue('risk_info', $risk_info); } /// 资金授权商户号,服务商替特约商户发放时使用 public function SetConsumeMchId($consume_mch_id) { $this->SetValue('consume_mch_id', $consume_mch_id); } /// 随机字符串,不长于32位 public function SetNonceString($nonce_str) { $this->SetValue('nonce_str', $nonce_str); } } class wechat extends BaseMethod { /** * @var RedPackData */ private $RedPackData; /** * @var int */ private $RequestErrorCode; /** * 公钥 */ private $PublicKey = '/cert/0000000000/apiclient_cert.pem'; /** * 私钥 */ private $PrivateKey = '/cert/0000000000/apiclient_key.pem'; /** * ca证书 */ private $RootCA = '/cert/0000000000/rootca.pem'; /** * wechat constructor. */ public function __construct() { /// todo: parent::__construct(); $this->PublicKey = __DIR__ . '/cert/1399351902/apiclient_cert.pem'; $this->PrivateKey = __DIR__ . '/cert/1399351902/apiclient_key.pem'; $this->RootCA = __DIR__ . '/cert/1399351902/rootca.pem'; $this->RedPackData = new RedPackData(); /// 初始化红包设置信息 //$this->RedPackData->SetSignKey('0t3xm3w1foyhcmhlux31mwrmybqh4cgd'); /// 支付key //$this->RedPackData->SetAppId('wxb534983dcd6d77c6'); /// 公众账号appid //$this->RedPackData->SetMchId('1345625501'); /// 商户号 $this->RedPackData->SetSignKey('YSWDSJ20160620201606202016062020'); /// 支付key $this->RedPackData->SetAppId('wxfd77eb9fb989e822'); /// 公众账号appid $this->RedPackData->SetMchId('1399351902'); /// 商户号 $this->RedPackData->SetMchBillNo(''); /// 商户订单号 $this->RedPackData->SetActiveName('test'); /// 活动名称 $this->RedPackData->SetSendName('友乐互动游戏'); /// 商户名称 $this->RedPackData->SetOpenId(''); /// 接受红包的用户,用户在wxappid下的openid $this->RedPackData->SetAmount(100); /// 付款金额,单位分 $this->RedPackData->SetNumber(1); /// 发送红包总人数 $this->RedPackData->SetWishing('test'); /// 红包祝福语 $this->RedPackData->SetRemark('test'); /// 备注信息 $this->RedPackData->SetNonceString($this->create_nonce_str(32)); /// 随机字符串,不长于32位 $this->RedPackData->SetClientIp($_SERVER['SERVER_ADDR']); /// 客户端ip } /** * 产生随机字符串,不长于32位 * @param int $length * @return string 产生的随机字符串 */ public static function create_nonce_str($length = 32) { $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; $str = ''; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } /** * @param string $Url 连接地址 * @param string $Data 发送的数据 * @param int $Second * @param array $Header * @return bool|mixed */ private function curl_post_ssl($Url, $Data, $Second = 30, $Header = array()) { $ch = curl_init(); /// 超时时间 curl_setopt($ch, CURLOPT_TIMEOUT, $Second); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); /// 这里设置代理,如果有的话 /// curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98'); /// curl_setopt($ch,CURLOPT_PROXYPORT, 8080); curl_setopt($ch, CURLOPT_URL, $Url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); /// 以下两种方式需选择一种 /// 第一种方法,cert 与 key 分别属于两个.pem文件 /// 默认格式为PEM,可以注释 curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM'); //curl_setopt($ch, CURLOPT_SSLCERT, getcwd() . $this->PublicKey); curl_setopt($ch, CURLOPT_SSLCERT, $this->PublicKey); /// 默认格式为PEM,可以注释 curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM'); //curl_setopt($ch, CURLOPT_SSLKEY, getcwd() . $this->PrivateKey); curl_setopt($ch, CURLOPT_SSLKEY, $this->PrivateKey); /// ca证书 curl_setopt($ch, CURLOPT_CAINFO, $this->RootCA); /// 第二种方式,两个文件合成一个.pem文件 ///curl_setopt($ch, CURLOPT_SSLCERT, getcwd() . '/all.pem'); if (count($Header) >= 1) curl_setopt($ch, CURLOPT_HTTPHEADER, $Header); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $Data); $Result = curl_exec($ch); if ($Result) { $this->RequestErrorCode = 0; curl_close($ch); return $Result; } else { $this->RequestErrorCode = curl_errno($ch); //echo "call faild, errorCode: {$this->RequestErrorCode}\n\n\n\n"; curl_close($ch); return null; } } /** * 被请求方法示例:参数固定为RequestParameter和ReturnParameter对象,返回值固定为true(成功)和false(失败) * @param RequestParameter $Request * @param ReturnParameter $Return * @return bool */ public function SendRedPack($Request, &$Return) { ///https://proxytest.tscce.cn/api/Index.php?method=pay.wechat.SendRedPack&format=json&charset=utf-8×tamp=1&version=1.0&biz_content={"act_name":"活动名称","open_id":"ogLT2v3XvvB1aphibzHyL8On4_sk","fee":"100","wishing":"红包祝福语","remark":"备注信息"}&user_auth_token=xxxxxxxx $bill_no = date('YmdHis') . rand(1000, 9999); /// 订单号 $act_name = @$Request->biz_content['act_name']; /// 活动名称 $open_id = @$Request->biz_content['open_id']; /// 接受红包的用户,用户在wxappid下的openid /// ogLT2v3XvvB1aphibzHyL8On4_sk $fee = @$Request->biz_content['fee']; /// 付款金额,单位分 $wishing = @$Request->biz_content['wishing']; /// 红包祝福语 $remark = @$Request->biz_content['remark']; /// 备注信息 $this->RedPackData->SetMchBillNo($bill_no); $this->RedPackData->SetActiveName($act_name); $this->RedPackData->SetOpenId($open_id); $this->RedPackData->SetAmount($fee); $this->RedPackData->SetWishing($wishing); $this->RedPackData->SetRemark($remark); $this->RedPackData->SetSign(); /// 签名 /// 发送数据 $xml = $this->curl_post_ssl($this->RedPackData->RequestUrl, $this->RedPackData->ToXml()); if (empty($xml)) { $Return->SetErrors(ERRORCODE_WECHATERROR, "curl call faild! error code: {$this->RequestErrorCode}"); return false; } $res = (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); if (empty($res)) { $Return->SetErrors(ERRORCODE_WECHATERROR, $xml); return false; } if (strcasecmp('success', $res['return_code']) != 0) { $Return->SetErrors(ERRORCODE_WECHATERROR, $res['return_msg']); return false; } if (strcasecmp('success', $res['result_code']) != 0) { $Return->SetErrors(ERRORCODE_WECHATERROR, $res['err_code_des']); return false; } return true; } }