<?php // +---------------------------------------------------------------------- // | WeChatDeveloper // +---------------------------------------------------------------------- // | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ] // +---------------------------------------------------------------------- // | 官方网站: http://think.ctolog.com // +---------------------------------------------------------------------- // | 开源协议 ( https://mit-license.org ) // +---------------------------------------------------------------------- // | github开源项目:https://github.com/zoujingli/WeChatDeveloper // +---------------------------------------------------------------------- namespace Wechat\Contracts; use Wechat\Exceptions\InvalidArgumentException; use Wechat\Exceptions\InvalidDecryptException; use Wechat\Exceptions\InvalidResponseException; /** * 微信通知处理基本类 * Class Request * @package Wechat\Contracts */ class Request { /** * 公众号APPID * @var string */ protected $appid; /** * 公众号推送XML内容 * @var string */ protected $postxml; /** * 公众号推送加密类型 * @var string */ protected $encryptType; /** * 当前公众号配置对象 * @var Config */ protected $config; /** * 公众号的推送请求参数 * @var Config */ protected $params; /** * 公众号推送内容对象 * @var Config */ protected $receive; /** * 准备回复的消息内容 * @var array */ protected $message; /** * Request constructor. * @param array $options * @throws InvalidResponseException */ public function __construct(array $options) { if (empty($options['appid'])) { throw new InvalidArgumentException("Missing Config -- [appid]"); } if (empty($options['appsecret'])) { throw new InvalidArgumentException("Missing Config -- [appsecret]"); } if (empty($options['token'])) { throw new InvalidArgumentException("Missing Config -- [token]"); } // 参数初始化 $this->config = new Config($options); $this->params = new Config($_REQUEST); $this->appid = $this->config->get('appid'); // 推送消息处理 if ($_SERVER['REQUEST_METHOD'] == "POST") { $this->postxml = file_get_contents("php://input"); $this->encryptType = $this->params->get('encrypt_type'); if ($this->encryptType == 'aes') { if (empty($options['encodingaeskey'])) { throw new InvalidArgumentException("Missing Config -- [encodingaeskey]"); } if (!class_exists('Prpcrypt', false)) { require __DIR__ . '/Prpcrypt.php'; } $prpcrypt = new \Prpcrypt($this->config->get('encodingaeskey')); $result = Tools::xml2arr($this->postxml); $array = $prpcrypt->decrypt($result['Encrypt']); if (intval($array[0]) > 0) { throw new InvalidResponseException($array[1], $array[0]); } list($this->postxml, $this->appid) = [$array[1], $array[2]]; } $this->receive = new Config(Tools::xml2arr($this->postxml)); } elseif ($_SERVER['REQUEST_METHOD'] == "GET" && $this->checkSignature()) { @ob_clean(); exit($this->params->get('echostr')); } else { throw new InvalidResponseException('Invalid interface request.', '0'); } } /** * 验证来自微信服务器 * @param string $str * @return bool */ private function checkSignature($str = '') { $nonce = $this->params->get('nonce'); $timestamp = $this->params->get('timestamp'); $msg_signature = $this->params->get('msg_signature'); $signature = empty($msg_signature) ? $this->params->get('signature') : $msg_signature; $tmpArr = [$this->config->get('token'), $timestamp, $nonce, $str]; sort($tmpArr, SORT_STRING); if (sha1(implode($tmpArr)) == $signature) { return true; } return false; } /** * 获取公众号推送对象 * @return array */ public function getReceive() { return $this->receive->get(); } /** * 回复消息 * @param array $data 消息内容 * @param bool $return 是否返回XML内容 * @return string * @throws InvalidDecryptException */ public function reply(array $data = [], $return = false) { $xml = Tools::arr2xml(empty($data) ? $this->message : $data); if ($this->encryptType == 'aes') { if (!class_exists('Prpcrypt', false)) { require __DIR__ . '/Prpcrypt.php'; } $prpcrypt = new \Prpcrypt($this->config->get('encodingaeskey')); // 如果是第三方平台,加密得使用 component_appid $component_appid = $this->config->get('component_appid'); $appid = empty($component_appid) ? $this->appid : $component_appid; $array = $prpcrypt->encrypt($xml, $appid); if ($array[0] > 0) { throw new InvalidDecryptException('Encrypt Error.', '0'); } list($timestamp, $encrypt) = [time(), $array[1]]; $nonce = rand(77, 999) * rand(605, 888) * rand(11, 99); $tmpArr = [$this->config->get('token'), $timestamp, $nonce, $encrypt]; sort($tmpArr, SORT_STRING); $signature = sha1(implode($tmpArr)); $format = "<xml><Encrypt><![CDATA[%s]]></Encrypt><MsgSignature><![CDATA[%s]]></MsgSignature><TimeStamp>%s</TimeStamp><Nonce><![CDATA[%s]]></Nonce></xml>"; $xml = sprintf($format, $encrypt, $signature, $timestamp, $nonce); } if ($return) { return $xml; } @ob_clean(); echo $xml; } /** * 获取当前微信OPENID * @return string */ public function getOpenid() { return $this->receive->get('FromUserName'); } /** * 获取当前推送消息内容 * @return string */ public function getMsgType() { return $this->receive->get('MsgType'); } /** * 获取当前推送消息ID * @return string */ public function getMsgId() { return $this->receive->get('MsgId'); } /** * 获取当前推送时间 * @return integer */ public function getMsgTime() { return $this->receive->get('CreateTime'); } /** * 获取当前推送公众号 * @return string */ public function getToOpenid() { return $this->receive->get('ToUserName'); } }