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条评论