分类 前端 下的文章

在 PHP 中实现与 OpenSSL 兼容的 ‌AES 加密(含 Salted__ 头)‌,需手动处理盐值生成和密钥派生。以下是完整实现代码及分步说明:

一、加密实现代码

<?php
/**
 * AES 加密(兼容 OpenSSL 的 "Salted__" 格式)
 * @param string $data 明文数据
 * @param string $password 加密密码
 * @param string $method 加密算法,如 'AES-256-CBC'
 * @return string Base64 编码的加密数据(含 Salted__ 头)
 */
function opensslEncryptWithSalt($data, $password, $method = 'AES-256-CBC') {
    // 生成 8 字节随机盐
    $salt = openssl_random_pseudo_bytes(8);
    
    // 通过盐和密码派生密钥与 IV
    $keyIv = deriveKeyAndIV($password, $salt, $method);
    $key = $keyIv['key'];
    $iv = $keyIv['iv'];
    
    // 加密数据
    $encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
    
    // 拼接 Salted__ 头 + 盐 + 密文
    $result = "Salted__" . $salt . $encrypted;
    
    // Base64 编码便于传输
    return base64_encode($result);
}

/**
 * 派生密钥和 IV(模拟 OpenSSL 的 EVP_BytesToKey)
 */
function deriveKeyAndIV($password, $salt, $method) {
    $digest = 'md5'; // OpenSSL 默认使用 MD5
    $keySize = 32;   // AES-256 需要 32 字节密钥
    $ivSize = 16;    // CBC 模式需要 16 字节 IV
    
    $derived = '';
    $data = '';
    $length = 0;
    
    while ($length < $keySize + $ivSize) {
        $data = $data . $password . $salt;
        $md5 = hash($digest, $data, true);
        $data = $md5;
        $derived .= $md5;
        $length += strlen($md5);
    }
    
    return [
        'key' => substr($derived, 0, $keySize),
        'iv'  => substr($derived, $keySize, $ivSize)
    ];
}

二、解密实现代码

<?php
/**
 * AES 解密(兼容 OpenSSL 的 "Salted__" 格式)
 * @param string $encryptedData Base64 编码的加密数据
 * @param string $password 解密密码
 * @param string $method 加密算法,如 'AES-256-CBC'
 * @return string 解密后的明文
 */
function opensslDecryptWithSalt($encryptedData, $password, $method = 'AES-256-CBC') {
    // 解码 Base64
    $data = base64_decode($encryptedData);
    
    // 提取盐(前 8 字节,跳过 "Salted__" 头)
    $salt = substr($data, 8, 8);
    
    // 提取密文(去除头部的 16 字节:Salted__ + 盐)
    $encrypted = substr($data, 16);
    
    // 派生密钥和 IV
    $keyIv = deriveKeyAndIV($password, $salt, $method);
    $key = $keyIv['key'];
    $iv = $keyIv['iv'];
    
    // 解密数据
    return openssl_decrypt($encrypted, $method, $key, OPENSSL_RAW_DATA, $iv);
}

三、使用示例

<?php
// 加密示例
$plaintext = "Hello, World!";
$password = "mySecretPassword";
$encrypted = opensslEncryptWithSalt($plaintext, $password);
echo "加密结果: " . $encrypted . "\n";

// 解密示例
$decrypted = opensslDecryptWithSalt($encrypted, $password);
echo "解密结果: " . $decrypted . "\n";

四、核心逻辑说明

‌1. 盐值生成‌

- 阅读剩余部分 -

0.png
1.png

解决方法有两种:

  1. 修改一下 @babel/runtime/helpers/typeof.js 文件,内容修改为代码片段的。目的是添加"@babel/helpers - typeof";这一句在代码中,让babel识别出这是一个特殊的helper文件,不对它进行处理。
  2. 参考配置说明 https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html 修改一下 babelSetting 的 outputPath 成其他路径。

- 阅读剩余部分 -

问题

每当使用微信开发者工具预览小程序时,均会在控制台(Console)看到警告(Warn)信息:Now you can provide attr wx:key for a wx:for to improve performance

原因

uniapp的v-for写法导致。

修改前的写法如下:

<view class="comment-content" v-for="(item,index) in commentList">
    <!-- 评论用户头像 -->
    <view class="comment-content-left">
        <image class="comment-content-headImage" :src="item.formHead" mode="center"></image>
    </view>
    <view class="comment-content-right">
        <!-- 评论用户名 -->
        <view class="comment-content-name">{{item.formNick}}</view>
        <!-- 评论内容 -->
        <view class="comment-content-text">{{item.content}}</view>
        <!-- 评论日期 -->
        <view class="comment-content-time">{{item.commentTime}}</view>
    </view>
</view>

解决方法

v-for 搭配 key 使用。

- 阅读剩余部分 -

实现 "回车!=提交" 的问题,一般可以从 "按钮的type类型" 和 "输入框个数" 两处着手。

默认情况下,单个输入框,无论按钮的 type="submit" 还是 type="button" 类型,回车即提交。

1、当 type="submit" 时,无论有几个 type="text" 输入框,回车均表示提交。(submit)

2、当 type="button" 时,且存在多个输入框,回车不提交。(button)

3、解决单个输入框的回车即提交问题,参考第二点:可以增加一个输入框并隐藏 input="text" style="display:none;";然后 type 类型为 button。

在实际应用中,input 输入框很少只有一个的情况,那么只需记住第二条即可应对。

使用 JS 事件阻止表单提交,不在本文讨论范围,当然也是可以实现的。