php7.1版本下钉钉回调接口(解决undefined function)
钉钉官方的php demo文档是几年前的了,其中aes加密这块用的是老版本的函数,会报错Fatal error: Call to undefined function mcrypt_get_block_size()错误 ,其他几个mcrypt_开头函数也会报错。最直观的后果就是返回 { ["errcode"]=> int(71009) ["errmsg"]=> string(22) "返回文本非success" }
mcrypt函数适用于php4、php5版本?php7.0及之前使用该函数只要屏蔽掉报错信息在用到mcrypt函数语句的地方前面加@屏蔽就可以正常使用。但是7.1及以上版本就完全弃用了,这时候可以使用openssl函数来操作。只要是用到AES的地方都需要注意匹配你的php版本哦!下面直接将官方demo包的pkcs7Encoder.php内容替换成我的就行了(根据获取的php版本号自动调用AES加解密函数,因为这个问题测试了无数次,请忽略php文件中的杂乱信息)
<?php
include_once "errorCode.php";
class PKCS7Encoder
{
public static $block_size = 32;
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;
}
function decode($text)
{
$pad = ord(substr($text, -1));
if ($pad < 1 || $pad > PKCS7Encoder::$block_size) {
$pad = 0;
}
return substr($text, 0, (strlen($text) - $pad));
}
}
class Prpcrypt
{
public $key;
function __construct($k){
$this->key = base64_decode($k . "="); //为变量赋值
}
/* function Prpcrypt($k)
{
$this->key = base64_decode($k . "=");
}*/
public function encrypt($text, $corpid)
{
try {
//获得16位随机字符串,填充到明文之前
$random = $this->getRandomStr();
$text = $random . pack("N", strlen($text)) . $text . $corpid;
// 网络字节序
$version=substr(PHP_VERSION,0,3);
if($version<'7.1'){//(PHP 4, PHP 5 正常使用) (php6-php7.0 可能会warning提示但是屏蔽错误后可继续使用)(php7.1+ 由openssl_encrypt替代)
// mcrypt 函数在php7.1 以上版本被遗弃,可使用替代函数。。。 这里以@屏蔽错误, @的使用会影响效率
@$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);//mcrypt_get_block_size() 用来获取 cipher (其中包括了加密模式) 加密算法分组大小。
@$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');/// 打开加密算法和模式
$iv = substr($this->key, 0, 16);
//使用自定义的填充方式对明文进行补位填充
$pkc_encoder = new PKCS7Encoder;
$text = $pkc_encoder->encode($text);
@mcrypt_generic_init($module, $this->key, $iv);//mcrypt_generic_init — 初始化加密所需的缓冲区 在每次调用 mcrypt_generic() 或 mdecrypt_generic() 函数之前必须调用本函数。
//加密
@$encrypted = mcrypt_generic($module, $text);//本函数用来加密数据。 传入数据长度必须是 n * 分组大小,否则需要后补 "\0"。 本函数返回加密后的数据。 注意,根据数据补齐不同, 返回的数据可能比输入的数据长度有所增加。
//$moudle为加密描述符,$text为加密前的数据,数据加密函数返回加密后的字符串
@mcrypt_generic_deinit($module);//mcrypt_generic_deinit — 对加密模块进行清理工作 它会清理缓冲区,但是并不关闭模块。 要想关闭加密模块, 你需要自行调用 mcrypt_module_close() 函数。
@mcrypt_module_close($module);
//print(base64_encode($encrypted));
//使用BASE64对加密后的字符串进行编码
}else{
//php 7.1 //echo base64_encode(openssl_encrypt($str, 'aes-128-cbc', $key, true, $iv));
// $data = openssl_encrypt($text, 'aes-128-cbc',$this->key,true,$iv);
// $encrypted = $data;
$iv = substr($this->key, 0, 16);
$aes_encrypt=openssl_encrypt($text, 'AES-256-CBC',$this->key,OPENSSL_RAW_DATA, $iv);
// $msg_encrypt =base64_encode($aes_encrypt);
$encrypted =$aes_encrypt;
//return $data;
//php 7.1
}
return array(ErrorCode::$OK, base64_encode($encrypted));
} catch (Exception $e) {
print $e;
return array(ErrorCode::$EncryptAESError, null);
}
}
public function decrypt($encrypted, $corpid)
{
try {
$ciphertext_dec = base64_decode($encrypted);
$iv = substr($this->key, 0, 16);
$version=substr(PHP_VERSION,0,3);
if($version<'7.1'){
@$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
@mcrypt_generic_init($module, $this->key, $iv);
@$decrypted = mdecrypt_generic($module, $ciphertext_dec);
@mcrypt_generic_deinit($module);
@mcrypt_module_close($module);
}else{
///php7.1 jiemi
//echo openssl_decrypt(base64_decode($strEncode), 'aes-128-cbc', $key, true, $iv);
//$decrypted = openssl_decrypt($ciphertext_dec, 'AES-256-CBC',$this->key, OPENSSL_RAW_DATA, $iv);//使用OPENSSL_RAW_DATA不行
$decrypted = openssl_decrypt($encrypted, 'AES-256-CBC',$this->key,OPENSSL_ZERO_PADDING, $iv);//注意openssl_decrypt第一个参数是base64加密过的字符串,第四个参数是OPENSSL_ZERO_PADDING不是上面加密时的 OPENSSL_RAW_DATA
// $decrypted .='xx';
///php7.1 jiemi
}
} 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_corpid = substr($content, $xml_len + 4);
} catch (Exception $e) {
print $e;
return array(ErrorCode::$DecryptAESError, null);
}
if ($from_corpid != $corpid)
return array(ErrorCode::$ValidateSuiteKeyError, null);
return array(0, $xml_content);
}
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;
}
}
?>
php下使用钉钉回调的方法参考我之前的文章: https://ranjuan.cn/php7-0%E4%B8%8B%E9%92%89%E9%92%89%E5%9B%9E%E8%B0%83%E6%8E%A5%E5%8F%A3%E6%B3%A8%E5%86%8C/
出现“ 返回文本非success ”第一步 ,先把所有错误显示 打印出来,解决掉再去排查其他原因。第二步,直接访问回调url地址看有没有除规定返回的json字符串外有其他输出没有(右键--查看网页源代码 里面找有没有 多余的换行、空格等)。第三步、测试加解密函数。 钉钉的说明文档有点反人类,等哪天有空了写篇文章把钉钉的aes加解密单独分析一下。
2019.11.01提示://注意openssl_decrypt第一个参数是base64加密过的字符串,第四个参数是OPENSSL_ZERO_PADDING不是上面加密时的 OPENSSL_RAW_DATA
基于互联网精神,在注明出处的前提下本站文章可自由转载!
本文链接:https://ranjuan.cn/php7-1版本下钉钉回调接口(解决undefined-function)/
微信赞赏
支付宝赞赏
2条评论