微信公众平台的消息推送 PHP 的示例代码,版本最多兼容到7,php 8以上不支持,主要是加解密的函数更新了,自己封装了个适应 php 8 的示例 demo,当前 demo 里我使用的是 laravel 框架,涉及到了随机数生成的助手函数 Str::random
<?php
namespace App\Services;
use App\Exceptions\WechatException;
use Illuminate\Support\Str;
use SimpleXMLElement;
class WechatNotifyService
{
private $token;
private $appId;
private $encodingAesKey;
private $aesKey;
private $iv;
public function __construct()
{
$this->token = config('wechat.token');
$this->appId = config('wechat.app_id');
$this->encodingAesKey = config('wechat.aes_key');
$this->aesKey = base64_decode($this->encodingAesKey . '=');
$this->iv = substr($this->aesKey, 0, 16);
}
/**
* 验证签名
*
* @param $signature
* @param $timestamp
* @param $nonce
* @return bool
*/
public function checkSignature($signature, $timestamp, $nonce)
{
$sign = $this->genSign($timestamp, $nonce);
if ($sign == $signature) {
return true;
} else {
return false;
}
}
/**
* 生成签名
*
* @return string
*/
public function genSign($timestamp, $nonce)
{
$tmpArr = array($this->token, $timestamp, $nonce);
sort($tmpArr, SORT_STRING);
$tmpStr = implode($tmpArr);
return sha1($tmpStr);
}
/**
* 解密数据
*
* @return array
* @throws WechatException
*/
public function decrypt($postData, $timestamp, $nonce, $msgSignature)
{
$array = array($postData, $this->token, $timestamp, $nonce);
sort($array, SORT_STRING);
$str = implode($array);
$sign = sha1($str);
if ($sign != $msgSignature) {
throw new WechatException('加密数据签名验证失败');
}
try {
$base64Decode = base64_decode($postData);
$data = openssl_decrypt($base64Decode, 'aes-256-cbc', $this->aesKey, OPENSSL_RAW_DATA, $this->iv);
$filterHeader = substr($data, 20);
$content = preg_replace('/' . $this->appId . '/', '', $filterHeader);
return json_decode($content, true);
} catch (\Throwable $e) {
throw new WechatException('解密数据失败'. $e->getMessage());
}
}
/**
* 加密数据
*
* @return string
*/
public function encrypt($data)
{
$random = Str::random(16);
$len = pack('N', strlen($data));
$content = $random . $len . $data . $this->appId;
$result = openssl_encrypt($content, 'aes-256-cbc', $this->aesKey, OPENSSL_RAW_DATA, $this->iv);
return base64_encode($result);
}
/**
* 加密响应
*
* @param $timestamp
* @param $nonce
* @return string
*/
public function response($timestamp, $nonce)
{
// 创建一个XML文档
$xml = new SimpleXMLElement('<xml></xml>');
$data = json_encode([
'ToUserName' => '',
'FromUserName' => '',
'CreateTime' => time(),
'MsgType' => '',
'Content' => 'success'
]);
$encrypt = $this->encrypt($data);
$sign = $this->genSign($timestamp, $nonce);
// 添加子元素
$xml->addChild('Encrypt', $encrypt);
$xml->addChild('MsgSignature', $sign);
$xml->addChild('TimeStamp', $timestamp);
$xml->addChild('Nonce', $nonce);
return preg_replace('/<\?xml.*\?>/i', '', $xml->asXML());
}
}