如何将SubtleCrypto加密的Promise结果通过PHP存入MySQL?
问题分析与解决方案
核心误区说明
CURL作为HTTP客户端请求PHP页面时,只会获取PHP输出的静态内容,不会执行页面中的JavaScript代码。你当前基于浏览器SubtleCrypto的加密逻辑在客户端执行,CURL无法直接拿到加密结果,这是核心矛盾。以下分两种场景给出解决方案:
场景一:优先迁移至PHP服务端加密(推荐)
直接在PHP中用OpenSSL扩展实现RSA-OAEP-SHA512加密,CURL调用后可直接返回结果并完成MySQL存储,完全规避客户端异步问题。
PHP代码示例(CURL直接调用的页面)
<?php // 待加密数据(可通过GET/POST参数传入) $rawData = $_POST['data'] ?? 'default_data'; // PEM格式公钥 $publicKey = "-----BEGIN PUBLIC KEY----- 你的公钥内容 -----END PUBLIC KEY-----"; // 配置RSA-OAEP加密参数 $encryptOptions = [ 'padding' => OPENSSL_PKCS1_OAEP_PADDING, 'digest_alg' => 'sha512' ]; // 执行加密 $encryptSuccess = openssl_public_encrypt($rawData, $encryptedBytes, $publicKey, OPENSSL_PKCS1_OAEP_PADDING); if ($encryptSuccess) { // 转Base64方便传输与存储 $encryptedBase64 = base64_encode($encryptedBytes); // 存入MySQL $pdo = new PDO('mysql:host=localhost;dbname=your_db', 'username', 'password'); $stmt = $pdo->prepare("INSERT INTO encrypted_data (content) VALUES (?)"); $stmt->execute([$encryptedBase64]); // 返回加密结果给CURL echo $encryptedBase64; } else { http_response_code(500); echo '加密失败:' . openssl_error_string(); } ?>
场景二:必须使用浏览器SubtleCrypto的情况
若因硬件加密等限制必须用浏览器API,需通过无头浏览器执行JS并获取结果,再同步给CURL调用的服务端。同时修正原JS代码的异步问题:
1. 重构JS加密函数(解决Promise外部访问问题)
先补全依赖工具函数,并将加密逻辑改为返回Promise,用async/await处理异步:
// 字符串转ArrayBuffer function str2ab(str) { const buf = new ArrayBuffer(str.length); new Uint8Array(buf).set([...str].map(c => c.charCodeAt(0))); return buf; } // ArrayBuffer转字符串 function ab2str(buf) { return String.fromCharCode(...new Uint8Array(buf)); } // 加密函数:返回Promise,支持async/await调用 async function encryptData(rawData, publicKeyPem) { const crypto = window.crypto || window.msCrypto; if (!crypto?.subtle) throw new Error('加密API不支持'); // 解析PEM公钥 const pemHeader = "-----BEGIN PUBLIC KEY-----"; const pemFooter = "-----END PUBLIC KEY-----"; const pemContent = publicKeyPem.slice(pemHeader.length, -pemFooter.length); const derBuffer = str2ab(window.atob(pemContent)); try { // 导入公钥 const key = await crypto.subtle.importKey( "spki", derBuffer, { name: "RSA-OAEP", hash: "SHA-512" }, false, ["encrypt"] ); // 执行加密:注意原代码参数顺序错误,修正为(算法配置, 密钥, 待加密数据) const encryptedBuf = await crypto.subtle.encrypt( { name: "RSA-OAEP" }, key, str2ab(rawData) ); // 转Base64返回 return btoa(ab2str(encryptedBuf)); } catch (err) { console.error('加密失败:', err); throw err; } }
2. 用无头浏览器获取加密结果(供CURL调用)
用Node.js的Puppeteer模拟浏览器执行JS,将结果返回给调用方:
const puppeteer = require('puppeteer'); async function fetchEncryptedResult() { const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); // 加载包含加密逻辑的页面 await page.goto('http://your-domain.com/encrypt-page.php'); // 在页面上下文执行加密 const encryptedResult = await page.evaluate(async () => { // 复制上述str2ab、ab2str、encryptData函数到这里 return await encryptData('待加密数据', '你的PEM公钥'); }); // 将结果发送给PHP存入MySQL await fetch('http://your-domain.com/save-to-mysql.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `encrypted_data=${encodeURIComponent(encryptedResult)}` }); await browser.close(); return encryptedResult; } // 执行并输出结果,CURL可调用此脚本的HTTP接口或直接运行 fetchEncryptedResult().then(res => console.log(res));
内容的提问来源于stack exchange,提问作者Ramit.K
相关产品推荐
相关产品推荐

