微信公众号消息处理 DEMO 在 PHP7.0 环境下的代码升级处理

虽然标题写的PHP版本是 7.0,但部分方法在 7.0 只是 Warning,理论上还是能用了,但由于 7.1 或 7.2 中已被废弃,所以还是建议 7.0 环境下也做出修改

由于小程序的DEMO略有不同,所以请谨慎对照,以下改动针对的是微信公众号DEMO


升级原因:

  1. mcrypt_*方法被废弃,需要用openssl代替

  2. 同名构造方法被废弃,需要用__construct代替


具体处理

  1. 首先下载一个官网的PHP版DEMO:传送门

    当然,你也可以手动去下载,如下图

    WX20190611-110626-1

  2. 展开压缩包,里面文件如下

    • demo.php
    • errorCode.php
    • pkcs7Encoder.php (需要升级)
    • ReadMe.txt
    • sha1.php
    • wxBizMsgCrypt.php (需要升级)
    • xmlparse.php
  3. 升级代码

    pkcs7Encoder.php代码:

     <?php
     
     include_once "errorCode.php";
     
     /**
      * PKCS7Encoder class
      *
      * 提供基于PKCS7算法的加解密接口.
      */
     class PKCS7Encoder
     {
       public static $block_size = 32;
     
       /**
        * 对需要加密的明文进行填充补位
        * @param $text 需要进行填充补位操作的明文
        * @return 补齐明文字符串
        */
       function encode($text)
       {
         $block_size = PKCS7Encoder::$block_size;
         $text_length = strlen($text);
         //计算需要填充的位数
         $amount_to_pad = PKCS7Encoder::$block_size - ($text_length % PKCS7Encoder::$block_size);
         if ($amount_to_pad == 0) {
           $amount_to_pad = PKCS7Encoder::block_size;
         }
         //获得补位所用的字符
         $pad_chr = chr($amount_to_pad);
         $tmp = "";
         for ($index = 0; $index < $amount_to_pad; $index++) {
           $tmp .= $pad_chr;
         }
         return $text . $tmp;
       }
     
       /**
        * 对解密后的明文进行补位删除
        * @param decrypted 解密后的明文
        * @return 删除填充补位后的明文
        */
       function decode($text)
       {
     
         $pad = ord(substr($text, -1));
         if ($pad < 1 || $pad > 32) {
           $pad = 0;
         }
         return substr($text, 0, (strlen($text) - $pad));
       }
     
     }
     
     /**
      * Prpcrypt class
      *
      * 提供接收和推送给公众平台消息的加解密接口.
      */
     class Prpcrypt
     {
         public $key;
     
         function __construct($k)
         {
             $this->key = base64_decode($k . "=");
         }
     
         /**
          * 对明文进行加密
          * @param string $text 需要加密的明文
          * @return string 加密后的密文
          */
         public function encrypt($text, $appid)
         {
             $key = $this->key;
             try {
                 //获得16位随机字符串,填充到明文之前
                 $random = $this->getRandomStr();
                 $text = $random . pack("N", strlen($text)) . $text . $appid;
                 $iv = substr($key, 0, 16);
                 
                 $block_size = 32;
                 $text_length = strlen($text);
                 $amount_to_pad = $block_size - ($text_length % $block_size);
                 if ($amount_to_pad == 0) {
                     $amount_to_pad = $block_size;
                 }
                 $pad_chr = chr($amount_to_pad);
                 $tmp = '';
                 for ($index = 0; $index < $amount_to_pad; $index++) {
                     $tmp .= $pad_chr;
                 }
                 $text = $text . $tmp;
     
            
                 $encrypted = openssl_encrypt($text, 'AES-256-CBC', $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
                 $encrypt_msg = base64_encode($encrypted);
                 return $encrypt_msg;
     
                 //print(base64_encode($encrypted));
                 //使用BASE64对加密后的字符串进行编码
                 return array(ErrorCode::$OK, base64_encode($encrypted));
             } catch (Exception $e) {
                 //print $e;
                 return array(ErrorCode::$EncryptAESError, null);
             }
         }
     
         /**
          * 对密文进行解密
          * @param string $encrypted 需要解密的密文
          * @return string 解密得到的明文
          */
         public function decrypt($encrypted, $appid)
         {
             $key = $this->key;
     
             try {
                 //使用BASE64对需要解密的字符串进行解码
                 $ciphertext_dec = base64_decode($encrypted);
                 $iv = substr($key, 0, 16);
                 $decrypted = openssl_decrypt($ciphertext_dec, 'AES-256-CBC', $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
             } catch (Exception $e) {
                 return array(ErrorCode::$DecryptAESError, null);
             }
     
     
             try {
                 //去除补位字符
                 $pkc_encoder = new PKCS7Encoder;
                 $result = $pkc_encoder->decode($decrypted);
                 //去除16位随机字符串,网络字节序和AppId
                 if (strlen($result) < 16)
                   return "";
                 $content = substr($result, 16, strlen($result));
                 $len_list = unpack("N", substr($content, 0, 4));
                 $xml_len = $len_list[1];
                 $xml_content = substr($content, 4, $xml_len);
                 $from_appid = substr($content, $xml_len + 4);
             } catch (Exception $e) {
                 //print $e;
                 return array(ErrorCode::$IllegalBuffer, null);
             }
             if ($from_appid != $appid) {
                 return array(ErrorCode::$ValidateAppidError, null);
             }
             return array(0, $xml_content);
         }
     
     
         /**
          * 随机生成16位字符串
          * @return string 生成的字符串
          */
         function getRandomStr()
         {
     
             $str = "";
             $str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
             $max = strlen($str_pol) - 1;
             for ($i = 0; $i < 16; $i++) {
                 $str .= $str_pol[mt_rand(0, $max)];
             }
             return $str;
         }
     }
     
     ?>
    

    wxBizMsgCrypt.php代码:

     <?php
     
     /**
      * 对公众平台发送给公众账号的消息加解密示例代码.
      *
      * @copyright Copyright (c) 1998-2014 Tencent Inc.
      */
     
     include_once "sha1.php";
     include_once "xmlparse.php";
     include_once "pkcs7Encoder.php";
     include_once "errorCode.php";
     
     /**
      * 1.第三方回复加密消息给公众平台;
      * 2.第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
      */
     class WXBizMsgCrypt
     {
     	private $token;
     	private $encodingAesKey;
     	private $appId;
     
     	/**
     	 * 构造函数
     	 * @param $token string 公众平台上,开发者设置的token
     	 * @param $encodingAesKey string 公众平台上,开发者设置的EncodingAESKey
     	 * @param $appId string 公众平台的appId
     	 */
     	public function __construct($token, $encodingAesKey, $appId)
     	{
     		$this->token = $token;
     		$this->encodingAesKey = $encodingAesKey;
     		$this->appId = $appId;
     	}
     
     	/**
     	 * 将公众平台回复用户的消息加密打包.
     	 * <ol>
     	 *    <li>对要发送的消息进行AES-CBC加密</li>
     	 *    <li>生成安全签名</li>
     	 *    <li>将消息密文和安全签名打包成xml格式</li>
     	 * </ol>
     	 *
     	 * @param $replyMsg string 公众平台待回复用户的消息,xml格式的字符串
     	 * @param $timeStamp string 时间戳,可以自己生成,也可以用URL参数的timestamp
     	 * @param $nonce string 随机串,可以自己生成,也可以用URL参数的nonce
     	 * @param &$encryptMsg string 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,
     	 *                      当return返回0时有效
     	 *
     	 * @return int 成功0,失败返回对应的错误码
     	 */
     	public function encryptMsg($replyMsg, $timeStamp, $nonce, &$encryptMsg)
     	{
     		$pc = new Prpcrypt($this->encodingAesKey);
     
     		//加密
     		$array = $pc->encrypt($replyMsg, $this->appId);
     		$ret = $array[0];
     		if ($ret != 0) {
     			return $ret;
     		}
     
     		if ($timeStamp == null) {
     			$timeStamp = time();
     		}
     		$encrypt = $array[1];
     
     		//生成安全签名
     		$sha1 = new SHA1;
     		$array = $sha1->getSHA1($this->token, $timeStamp, $nonce, $encrypt);
     		$ret = $array[0];
     		if ($ret != 0) {
     			return $ret;
     		}
     		$signature = $array[1];
     
     		//生成发送的xml
     		$xmlparse = new XMLParse;
     		$encryptMsg = $xmlparse->generate($encrypt, $signature, $timeStamp, $nonce);
     		return ErrorCode::$OK;
     	}
     
     
     	/**
     	 * 检验消息的真实性,并且获取解密后的明文.
     	 * <ol>
     	 *    <li>利用收到的密文生成安全签名,进行签名验证</li>
     	 *    <li>若验证通过,则提取xml中的加密消息</li>
     	 *    <li>对消息进行解密</li>
     	 * </ol>
     	 *
     	 * @param $msgSignature string 签名串,对应URL参数的msg_signature
     	 * @param $timestamp string 时间戳 对应URL参数的timestamp
     	 * @param $nonce string 随机串,对应URL参数的nonce
     	 * @param $postData string 密文,对应POST请求的数据
     	 * @param &$msg string 解密后的原文,当return返回0时有效
     	 *
     	 * @return int 成功0,失败返回对应的错误码
     	 */
     	public function decryptMsg($msgSignature, $timestamp = null, $nonce, $postData, &$msg)
     	{
     		if (strlen($this->encodingAesKey) != 43) {
     			return ErrorCode::$IllegalAesKey;
     		}
     
     		$pc = new Prpcrypt($this->encodingAesKey);
     
     		//提取密文
     		$xmlparse = new XMLParse;
     		$array = $xmlparse->extract($postData);
     		$ret = $array[0];
     
     		if ($ret != 0) {
     			return $ret;
     		}
     
     		if ($timestamp == null) {
     			$timestamp = time();
     		}
     
     		$encrypt = $array[1];
     		$touser_name = $array[2];
     
     		//验证安全签名
     		$sha1 = new SHA1;
     		$array = $sha1->getSHA1($this->token, $timestamp, $nonce, $encrypt);
     		$ret = $array[0];
     
     		if ($ret != 0) {
     			return $ret;
     		}
     
     		$signature = $array[1];
     		if ($signature != $msgSignature) {
     			return ErrorCode::$ValidateSignatureError;
     		}
     
     		$result = $pc->decrypt($encrypt, $this->appId);
     		if ($result[0] != 0) {
     			return $result[0];
     		}
     		$msg = $result[1];
     
     		return ErrorCode::$OK;
     	}
     
     }
    
若您觉得我的博文对您有帮助,欢迎点击下方按钮对我打赏
打赏