public function notify(Request $request) { \Log::debug('payment_notify', ['request' => $request]); $input = XML::parse($request->getContent()); if ($input['return_code'] == 'SUCCESS') { $order = Order::where('wx_out_trade_no', $input['out_trade_no'])->firstOrFail(); $address_id = $order->address_id; # 当前订单收货地址id if ($order->isPaid()) { return 'FAIL'; } $order->update(['wx_transaction_id' => $input['transaction_id'], 'cash_payment' => floatval($input['total_fee']) / 100.0]); $order->paid(); /* 发送消息提醒 */ $default_address = Address::where(['id' => $address_id])->first(); $phone = $default_address->phone; $msg = '尊敬的顾客您好!您的订单已经收到,易康商城将尽快为您安排发货,如有任何问题可以拨打客服电话400-1199-802进行咨询,感谢您的惠顾!'; \MessageSender::sendMessage($phone, $msg); // if ($phone = env('ORDER_ADMIN_PHONE')) { // \Log::error($phone); // \MessageSender::sendMessage($phone, $order->toOrderMessageString()); // } $result = \Wechat::paymentNotify(); return $result; } return 'FAIL'; }
/** * 生成用于回复的数据 * * @return array */ public function buildForReply() { if (!method_exists($this, 'toReply')) { throw new Exception(__CLASS__ . '未实现此方法:toReply()'); } $base = array('ToUserName' => $this->to, 'FromUserName' => $this->from, 'CreateTime' => time(), 'MsgType' => $this->getDefaultMessageType()); return XML::build(array_merge($base, $this->toReply())); }
/** * 获取订单结果. * * @param string $order_id 商户订单ID * @param bool|false $force 是否忽略缓存强制更新 * * @return Bag * * @throws Exception * @throws \Overtrue\Wechat\Exception */ public function getTransaction($order_id, $force = false) { $params = array(); $params['appid'] = $this->appId; $params['mch_id'] = $this->mchId; $params['out_trade_no'] = $order_id; $params['nonce_str'] = md5(uniqid(microtime())); $signGenerator = new SignGenerator($params); $signGenerator->onSortAfter(function (SignGenerator $that) { $that->key = $this->mchKey; }); $params['sign'] = $signGenerator->getResult(); $request = XML::build($params); $http = new Http(); $response = $http->request(static::QUERYORDER_URL, Http::POST, $request); if (empty($response)) { throw new Exception('Get ORDER Failure:'); } $transaction = XML::parse($response); //返回签名数据校验 if (empty($transaction) || empty($transaction['sign'])) { return false; } $sign = $transaction['sign']; unset($transaction['sign']); $signGenerator = new SignGenerator($transaction); $signGenerator->onSortAfter(function (SignGenerator $that) { $that->key = $this->mchKey; }); if ($sign !== $signGenerator->getResult()) { return false; } // 返回结果判断 if (isset($transaction['result_code']) && $transaction['result_code'] === 'FAIL') { throw new Exception($transaction['err_code'] . ': ' . $transaction['err_code_des']); } if (isset($transaction['return_code']) && $transaction['return_code'] === 'FAIL') { throw new Exception($transaction['return_code'] . ': ' . $transaction['return_msg']); } return $transactionInfo = new Bag($transaction); }
/** * 查询红包信息 * * @param string $mchBillNumber * * @return array */ public function query($mchBillNumber) { if (empty($mchBillNumber)) { throw new Exception('mch_id is required'); } $param['mch_billno'] = $mchBillNumber; $param['nonce_str'] = uniqid('pre_'); $param['mch_id'] = $this->business->mch_id; $param['appid'] = $this->business->appid; $param['bill_type'] = 'MCHT'; $signGenerator = new SignGenerator($param); $me = $this; $signGenerator->onSortAfter(function (SignGenerator $that) use($me) { $that->key = $me->business->mch_key; }); $sign = $signGenerator->getResult(); $param['sign'] = $sign; $request = XML::build($param); //设置Http使用的证书 $options['sslcert_path'] = $this->business->getClientCert(); $options['sslkey_path'] = $this->business->getClientKey(); $http = new Http(); $response = $http->request(static::API_QUERY, Http::POST, $request, $options); if (empty($response)) { throw new Exception('Get LuckMoneyInfo failed.'); } $result = XML::parse($response); return $result; }
/** * 初始化POST请求数据 * * @return Bag */ protected function prepareInput() { if ($this->input instanceof Bag) { return; } if (version_compare(PHP_VERSION, '5.6.0', '<')) { if (!empty($GLOBALS['HTTP_RAW_POST_DATA'])) { $xmlInput = $GLOBALS['HTTP_RAW_POST_DATA']; } else { $xmlInput = file_get_contents('php://input'); } if (empty($_REQUEST['echostr']) && empty($xmlInput) && !empty($_REQUEST['signature'])) { throw new Exception("没有读取到消息 XML,请在 php.ini 中打开 always_populate_raw_post_data=On", 500); } } else { $xmlInput = file_get_contents('php://input'); } $input = XML::parse($xmlInput); if (!empty($_REQUEST['encrypt_type']) && $_REQUEST['encrypt_type'] === 'aes') { $this->security = true; $input = $this->getCrypt()->decryptMsg($_REQUEST['msg_signature'], $_REQUEST['nonce'], $_REQUEST['timestamp'], $xmlInput); } $this->input = new Bag(array_merge($_REQUEST, (array) $input)); }
/** * 获取统一下单结果 * * @param bool|false $force 是否忽略缓存强制更新 * * @return array * @throws Exception * @throws \Overtrue\Wechat\Exception */ public function getResponse($force = false) { if (is_null($this->business)) { throw new Exception('Business is required'); } if (is_null($this->order)) { throw new Exception('Order is required'); } if ($this->unifiedOrder !== null && $force === false) { return $this->unifiedOrder; } $params = $this->order->toArray(); $params['appid'] = $this->business->appid; $params['mch_id'] = $this->business->mch_id; $signGenerator = new SignGenerator($params); $signGenerator->onSortAfter(function (SignGenerator $that) { $that->key = $this->business->mch_key; }); $params['sign'] = $signGenerator->getResult(); $request = XML::build($params); $http = new Http(); $response = $http->request(static::UNIFIEDORDER_URL, Http::POST, $request); if (empty($response)) { throw new Exception('Get UnifiedOrder Failure:'); } $unifiedOrder = XML::parse($response); if (isset($unifiedOrder['result_code']) && $unifiedOrder['result_code'] === 'FAIL') { throw new Exception($unifiedOrder['err_code'] . ': ' . $unifiedOrder['err_code_des']); } if (isset($unifiedOrder['return_code']) && $unifiedOrder['return_code'] === 'FAIL') { throw new Exception($unifiedOrder['return_code'] . ': ' . $unifiedOrder['return_msg']); } return $this->unifiedOrder = $unifiedOrder; }
/** * 初始化POST请求数据 * * @return Bag */ protected function prepareInput() { if ($this->input instanceof Bag) { return; } $xmlInput = !empty($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents('php://input'); $input = XML::parse($xmlInput); if (!empty($_REQUEST['encrypt_type']) && $_REQUEST['encrypt_type'] === 'aes') { $this->security = true; $input = $this->getCrypt()->decryptMsg($_REQUEST['msg_signature'], $_REQUEST['nonce'], $_REQUEST['timestamp'], $xmlInput); } $this->input = new Bag(array_merge($_REQUEST, (array) $input)); }
/** * 检验消息的真实性,并且获取解密后的明文. * <ol> * <li>利用收到的密文生成安全签名,进行签名验证</li> * <li>若验证通过,则提取xml中的加密消息</li> * <li>对消息进行解密</li> * </ol> * * @param string $msgSignature 签名串,对应URL参数的msg_signature * @param string $timestamp 时间戳 对应URL参数的timestamp * @param string $nonce 随机串,对应URL参数的nonce * @param string $postXML 密文,对应POST请求的数据 * @param string &$msg 解密后的原文,当return返回0时有效 * * @return array */ public function decryptMsg($msgSignature, $nonce, $timestamp, $postXML) { //提取密文 $array = XML::parse($postXML); if (empty($array)) { throw new Exception('Invalid xml.', self::ERROR_PARSE_XML); } $encrypted = $array['Encrypt']; //验证安全签名 $signature = $this->getSHA1($this->token, $timestamp, $nonce, $encrypted); if ($signature !== $msgSignature) { throw new Exception('Invalid Signature.', self::ERROR_INVALID_SIGNATURE); } return XML::parse($this->decrypt($encrypted, $this->appId)); }
/** * 获取退款结果 * @return array * @throws Exception */ public function getResponse() { if (is_null($this->business)) { throw new Exception('Business is required'); } static::$params['appid'] = $this->business->appid; static::$params['mch_id'] = $this->business->mch_id; $this->checkParams(); $signGenerator = new SignGenerator(static::$params); $signGenerator->onSortAfter(function (SignGenerator $that) { $that->key = $this->business->mch_key; }); static::$params['sign'] = $signGenerator->getResult(); $request = XML::build(static::$params); //设置Http使用的证书 $options['sslcert_path'] = $this->business->getClientCert(); $options['sslkey_path'] = $this->business->getClientKey(); $http = new Http(); $response = $http->request(static::REFUNDORDER_URL, Http::POST, $request, $options); if (empty($response)) { throw new Exception('Get Refund Failure:'); } $refundOrder = XML::parse($response); if (isset($refundOrder['return_code']) && $refundOrder['return_code'] === 'FAIL') { throw new Exception($refundOrder['return_code'] . ': ' . $refundOrder['return_msg']); } //返回签名数据校验 if (empty($refundOrder) || empty($refundOrder['sign'])) { throw new Exception('param sign is missing or empty'); } $sign = $refundOrder['sign']; unset($refundOrder['sign']); $signGenerator = new SignGenerator($refundOrder); $signGenerator->onSortAfter(function (SignGenerator $that) { $that->key = $this->business->mch_key; }); if ($sign !== $signGenerator->getResult()) { throw new Exception('check sign error'); } //返回结果判断 if (isset($refundOrder['result_code']) && $refundOrder['result_code'] === 'FAIL') { throw new Exception($refundOrder['err_code'] . ': ' . $refundOrder['err_code_des']); } if (isset($refundOrder['return_code']) && $refundOrder['return_code'] === 'FAIL') { throw new Exception($refundOrder['return_code'] . ': ' . $refundOrder['return_msg']); } return $this->refundInfo = $refundOrder; }
/** * 检验消息的真实性,并且获取解密后的明文. * <ol> * <li>利用收到的密文生成安全签名,进行签名验证</li> * <li>若验证通过,则提取xml中的加密消息</li> * <li>对消息进行解密</li> * </ol> * * @param string $msgSignature 签名串,对应URL参数的msg_signature * @param string $nonce 随机串,对应URL参数的nonce * @param string $timestamp 时间戳 对应URL参数的timestamp * @param string $postXML 密文,对应POST请求的数据 * * @return array */ public function decryptMsg($msgSignature, $nonce, $timestamp, $content, $isXml = true) { if ($isXml !== true) { $encrypted = $content; } else { //提取密文 $array = XML::parse($content); if (empty($array)) { throw new Exception('Invalid xml.', self::ERROR_PARSE_XML); } $encrypted = $array['Encrypt']; } Logger::info('Crypt', 'encrypted : ' . $encrypted); //验证安全签名 $signature = $this->getSHA1($this->token, $timestamp, $nonce, $encrypted); if ($signature !== $msgSignature) { throw new Exception('Invalid Signature.', self::ERROR_INVALID_SIGNATURE); } $decrypted = $this->decrypt($encrypted, $this->appId); if ($isXml !== true) { return $decrypted; } return XML::parse($decrypted); }
/** * 获取POST请求数据 * * @return Bag */ public function getInput() { if ($this->input) { return $this->input; } $xmlInput = !empty($GLOBALS["HTTP_RAW_POST_DATA"]) ? $GLOBALS["HTTP_RAW_POST_DATA"] : file_get_contents("php://input"); $input = XML::parse($xmlInput); if (!empty($_REQUEST['encrypt_type']) && $_REQUEST['encrypt_type'] === 'aes') { $this->security = true; $input = $this->service('crypt')->decryptMsg($_REQUEST['msg_signature'], $_REQUEST['nonce'], $_REQUEST['timestamp'], $xmlInput); } return new Bag(array_merge($_REQUEST, (array) $input)); }
/** * 回复消息, 如果不回复, 微信会一直发送请求到notify_url * * @param string $code * @param string $msg * * @return string */ public function reply($code = 'SUCCESS', $msg = 'OK') { $params = ['return_code' => $code, 'return_msg' => $msg]; return XML::build($params); }
/** * 获取统一下单结果 * * @param bool|false $force 是否忽略缓存强制更新 * * @return array * @throws Exception * @throws \Overtrue\Wechat\Exception */ public function getResponse($force = false) { if (is_null($this->business)) { throw new Exception('Business is required'); } if (is_null($this->order)) { throw new Exception('Order is required'); } if ($this->unifiedOrder !== null && $force === false) { return $this->unifiedOrder; } $params = $this->order->toArray(); $params['appid'] = $this->business->appid; $params['mch_id'] = $this->business->mch_id; ksort($params); $sign = http_build_query($params); $sign = urldecode($sign) . '&key=' . $this->business->mch_key; $sign = strtoupper(md5($sign)); $params['sign'] = $sign; $request = XML::build($params); $http = new Http(new AccessToken($this->business->appid, $this->business->appsecret)); $response = $http->request(static::UNIFIEDORDER_URL, Http::POST, $request); if (empty($response)) { throw new Exception('Get UnifiedOrder Failure:'); } $unifiedOrder = XML::parse($response); if (isset($unifiedOrder['result_code']) && $unifiedOrder['result_code'] === 'FAIL') { throw new Exception($unifiedOrder['err_code'] . ': ' . $unifiedOrder['err_code_des']); } if (isset($unifiedOrder['return_code']) && $unifiedOrder['return_code'] === 'FAIL') { throw new Exception($unifiedOrder['return_code'] . ': ' . $unifiedOrder['return_msg']); } return $this->unifiedOrder = $unifiedOrder; }
/** * 初始化POST请求数据 * * @return Bag */ protected function prepareInput() { if ($this->input instanceof Bag) { return; } if (!empty($GLOBALS['HTTP_RAW_POST_DATA'])) { $xmlInput = $GLOBALS['HTTP_RAW_POST_DATA']; } else { $xmlInput = file_get_contents('php://input'); } $input = XML::parse($xmlInput); // if (!empty($_REQUEST['encrypt_type']) && $_REQUEST['encrypt_type'] === 'aes') { if (true) { // 企业号只有加密模式, 所以直接进入aes流程 $this->security = true; if (isset($_REQUEST["echostr"])) { $input = $this->getCrypt()->decryptVerifyMsg($_REQUEST['msg_signature'], $_REQUEST['nonce'], $_REQUEST['timestamp'], $_REQUEST['echostr']); } else { $input = $this->getCrypt()->decryptMsg($_REQUEST['msg_signature'], $_REQUEST['nonce'], $_REQUEST['timestamp'], $xmlInput); } } $this->input = new Bag(array_merge($_REQUEST, (array) $input)); }