PHP之 “微信走步数据” ,获取并解密处理的实践操作(关键代码)

应用场景

在微信小程序的开发中,我们经常需要从微信端获取一些处理,以方便我们的程序操作处理,如“从微信端获取走步数据”,“从微信端获取手机号”等,而这些数据,考虑到安全的问题,一般需要根据微信的相关文档,进行数据获取、解密,然后,才能供我们使用!但是,微信的文档写的真是不尽人意,所以,今天,就“走步数据”的获取解密,就关键代码,简单地说说!

相关知识点

对称加密: 在加密和解密过程中使用相同的密钥, 或是两个可以简单地相互推算的密钥的加密算法.(微信步数,采用的就是【对称加密】)
非对称加密: 也称为公开加密, 它需要一个密钥对, 一个是公钥, 一个是私钥, 一个负责加密, 一个负责解密.
对称加密在性能上要优于非对称加密, 但是安全性低于非对称加密.

关键函数

1、对称加密函数
openssl_encrypt($data, $method, $key, $options = 0, $iv = '') : 以指定方式 method 和密钥 key 加密 data, 返回 false 或加密后的数据.
2、对称解密函数
openssl_decrypt($data, $method, $key, $options = 0, $iv = '') : 解密数据.

参数注解
$data : 明文
$method : 加密算法
$key : 密钥
$options :
- 0 : 自动对明文进行 padding, 返回的数据经过 base64 编码.
- 1 : OPENSSL_RAW_DATA, 自动对明文进行 padding, 但返回的结果未经过 base64 编码.
- 2 : OPENSSL_ZERO_PADDING, 自动对明文进行 0 填充, 返回的结果经过 base64 编码. 但是, openssl 不推荐 0 填充的方式, 即使选择此项也不会自动进行 padding, 仍需手动 padding.
$iv : 非空的初始化向量, 不使用此项会抛出一个警告. 如果未进行手动填充, 则返回加密失败.

其他函数

1、openssl_cipher_iv_length($method) : 获取 method 要求的初始化向量的长度.
2、openssl_random_pseudo_bytes($length) : 生成指定长度的伪随机字符串.
3、hash_mac($method, $data, $key, $raw_out) : 生成带有密钥的哈希值.
参数注解:
- method : 加密算法
- data : 明文
- key : 密钥
- raw_output :
- TRUE : 输出原始二进制数据
- FALSE : 输出长度固定的小写 16 进制字符串

加密方式

主流的对称加密方式有DES, AES。这两种加密方式都属于分组加密,具体操作是,先将明文分成多个等长的模块,然后,进行加密。
DES加密
DES加密的秘钥长度为64位(bit),但实际应用中,有效的使用时56位(bit),剩余的8位(bit)作为奇偶校验位。如果秘钥长度不足8个字节(Byte, 1Byte=8bit),
将会用“\0”补充到8个字节,比如,秘钥是“abcde”,补充完整,就是“abcde/0/0/0”,也就是说,“abcde”加密后的密文与“abcde/0/0/0”加密后的密文是一样的。
明文按照64位(bit)分组,64位在UTF-8编码下为8个字节长度,最后一组,不足64位需要填充数据,分组后的明文组和秘钥,按位(bit)替换,或交换,形成密文组。
AES加密
AES加密的分组长度为128位(bit),即每个分组为16个字节Byte(每个字节8位bit)。秘钥的长度,根据加密方式的不同,可以是128位,192位,256位。与DES加密一样,秘钥的长度,超过指定的长度时,超出会无效,不足时,以“\0”,补充到指定的长度。
AES加密的长度表
AEC 密钥长度 ( 位 ) 分组长度 ( 位 )
AES-128 128 128
AES-192 192 128
AES-256 256 128

代码部分

代码一 :此部分代码,负责,接收参数,规避、检测一些特殊情况,为后续解密数据做准备(加密数据,由前端返回,这里不作获取操作)
/**
 * 每次进入小程序,把前端推送的走步数据,存入到【组成员表】
 */
public function save_member_steps()
{
    $request = $this->get;
    //$request['step_data'] = "M4OKIk0kX8Zmx5E/y0xfzyVD+wWgGhcLcd+7GrMyXSmhnXTljZxLqpkNB8Smut1nj440Amdrc3HlI/g5VqY";
    //$request['iv'] = "QUzF4rs6Khat27nZE8Px9w==";
    //$request['openid'] = "oqahZ5LbByVHYBrH5PldKoruXtPI";

    // 获取相关的参数,并判断
    $userid = isset($request['userid']) ? $request['userid'] : 0;
    if(!$userid){
        return $this->export->get_export($this->errors[506]['error_code'], $this->errors, []);
    }
    // 从微信获取步数
    $step_data_str = isset($request['step_data']) && !empty($request['step_data']) ? strval($request['step_data']) : '';
    if(!$step_data_str){
        return $this->export->get_export($this->errors[512]['error_code'], $this->errors, []);
    }
    // 获取步数微信端参数
    $iv = !empty($request['iv']) ? strval($request['iv']) : '';
    // 获取步数微信端参数
    $openid = !empty($request['openid']) ? strval($request['openid']) : '';
    $this->load->dao('active_step_dao');
    // 解密微信端获取步数数据
    $step_datas = $this->process_wx_step_data($openid, $iv, $step_data_str);
    // 步数数据更新到user_step_everyday_log表
    $update_everyday_log = $this->update_step_log_data($userid, $step_datas);
    return  $update_everyday_log ? true : false;
}

/**
 * 获取用户的走步数据,更新到成员表
 * @param $openid
 * @param $iv
 * @param $step_data_str
 * @return array
 */
public function process_wx_step_data($openid, $iv, $step_data_str)
{
    // 从微信记录里获取数据,比对一下,是否正确,如果不正确,更新【组成员步数】,团表里的总步数累加
    $this->load->service('user_wechat_service');
    $step_data = $this->user_wechat_service->auth_step_data($openid, $iv, $step_data_str, 1);
    $stepInfoList = [];
    if(isset($step_data['stepInfoList']) && !empty($step_data['stepInfoList'])){
        $stepInfoList = $step_data['stepInfoList'];
        foreach ($stepInfoList as $key=>$val) {
            $stepInfoList[$key]['time'] = date('Y-m-d', $val['timestamp']);
        }
        $stepInfoList = array_column($stepInfoList, null, 'time');
    }
    return $stepInfoList;
}
代码二 此部分代码,接上代码user_wechat_service->auth_step_data,主要负责,对微信数据进行解密,返回解密后的数据
/**
 * 获取微信端用户【走步】数据
 * @param $openid 用户小程序openid
 * @param $iv 小程序返回的iv字段
 * @param $step_data_str 小程序返回的走步加密字段
 * @param $plat_type 1 用户端  2 教练端
 * @return array
 */
public function auth_step_data($openid, $iv, $step_data_str, $plat_type)
{
    if (empty($openid) || empty($iv) || empty($step_data_str) || empty($plat_type)) {
        return [];
    }
    $decrypt_data = $this->_get_encrypted_data($openid, $step_data_str, $iv, $plat_type);
    return $decrypt_data;
}

/**
 * 对微信加密的数据进行解密
 * @param $openid
 * @param $encrypted_data
 * @param $iv
 * @return string
 */
private function _get_encrypted_data($openid, $encrypted_data, $iv, $plat_type)
{
    $result = '';
    if (empty($openid) || empty($encrypted_data) || empty($iv) || empty($plat_type)) {
        return $result;
    }
    $this->load->dao('user_wechat_dao');
    $user = $this->user_wechat_dao->get_userid($openid, $plat_type);
    if (empty($user)) {
        return $result;
    }
    $this->load->config('dict/wechat_config');
    $dict_name = $plat_type == self::PLAT_TYPE_USER ? 'dict_wechat_user' : 'dict_wechat_coach';
    $app_config = $this->config->item($dict_name);
    $result = $this->_decrypt_data($app_config['app_id'], $user['sessionkey'], $encrypted_data, $iv);
    return $result;
}

/**
 * 最终的步骤 - 解密数据
 * @param $appid
 * @param $session_key
 * @param $encrypted_data
 * @param $iv
 * @desc VALIDATE_LEN_NUM = 24 (长度限制)
 * @return mixed|string
 */
private function _decrypt_data($appid, $session_key, $encrypted_data, $iv)
{
    $result = '';
    if (strlen($session_key) != self::VALIDATE_LEN_NUM || strlen($iv) != self::VALIDATE_LEN_NUM) {
        return $result;
    }

    $aes_key = base64_decode(str_replace(' ','+',$session_key));
    $aes_iv = base64_decode(str_replace(' ','+',$iv));
    $aes_cipher = base64_decode(str_replace(' ','+',$encrypted_data));
    $data = openssl_decrypt($aes_cipher, "AES-128-CBC", $aes_key, 1, $aes_iv);
    $data = json_decode($data, TRUE);

    if (empty($data)) {
        return $result;
    }
    if (!isset($data['watermark']['appid']) || $data['watermark']['appid'] != $appid) {
        return $result;
    }
    return $data;
}

总结

    微信数据的解密,关键的部分,就在于_decrypt_data方法,这里,对没用的字符进行了替换、解码,以及关键部分,使用解密函数openssl_decrypt()解密数据,这个函数对应的就是加密函数 openssl_encrypt(),它俩的参数都一样,分别是[明文,加密算法,秘钥,操作类型(0,1,2),非空的初始化向量],解密,加密,就靠它们了。因此,处理微信加密数据,关键在于“对称加密”的理解和操作实践!
发布了59 篇原创文章 · 获赞 2 · 访问量 5589

猜你喜欢

转载自blog.csdn.net/LDR1109/article/details/100932938