PHP exec()传递大Base64字符串触发unable to fork问题求助
解决PHP exec传递大Base64到Node脚本时的"unable to fork"问题
问题原因
不是内存限制,是命令行参数总长度超出系统上限。不同操作系统对单个进程的命令行参数总长度有严格限制(比如Linux默认约128KB,Windows更小),大体积图片的Base64编码字符串很容易突破这个限制,导致exec无法fork新进程。
解决方法
方法1:通过标准输入(STDIN)传递数据
这是最可靠的方式,完全避开命令行参数长度限制:
PHP代码修改
<?php $path = './exampleDir/example.png'; $type = pathinfo($path, PATHINFO_EXTENSION); $data = base64_encode(file_get_contents($path)); $base64 = "data:image/".$type.";base64,".$data; $cfPage = "index"; $iwidth = "400"; $iheight = "425"; $iaspect = $iwidth/$iheight; // 构造命令,用escapeshellarg处理参数避免注入和解析错误 $cmd = sprintf( 'node ./scripts/test.js %s %s %s', escapeshellarg($cfPage), escapeshellarg(uniqid()), escapeshellarg($iaspect) ); // 用proc_open创建管道,传递STDIN数据 $descriptorspec = [ 0 => ['pipe', 'r'], // PHP写入,Node读取的标准输入 1 => ['pipe', 'w'], // Node写入,PHP读取的标准输出 2 => ['pipe', 'w'] // 标准错误输出 ]; $process = proc_open($cmd, $descriptorspec, $pipes); if (is_resource($process)) { // 将Base64写入STDIN fwrite($pipes[0], $base64); fclose($pipes[0]); // 可选:读取Node脚本的输出和错误信息 $output = stream_get_contents($pipes[1]); $errors = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); // 等待进程结束并回收资源 proc_close($process); } ?>
Node脚本修改(test.js)
// 从命令行获取常规参数 const cfPage = process.argv[2]; const uniqId = process.argv[3]; const aspect = process.argv[4]; // 从STDIN读取Base64数据 const fs = require('fs'); const base64Data = fs.readFileSync(process.stdin.fd, 'utf8').trim(); // 后续业务逻辑示例 console.log('接收的Base64长度:', base64Data.length);
方法2:通过临时文件传递数据
如果STDIN方式不兼容现有逻辑,可将Base64写入临时文件,让Node脚本读取:
PHP代码修改
<?php $path = './exampleDir/example.png'; $type = pathinfo($path, PATHINFO_EXTENSION); $data = base64_encode(file_get_contents($path)); $base64 = "data:image/".$type.";base64,".$data; $cfPage = "index"; $iwidth = "400"; $iheight = "425"; $iaspect = $iwidth/$iheight; // 创建临时文件存储Base64 $tmpFile = tempnam(sys_get_temp_dir(), 'img_base64_'); file_put_contents($tmpFile, $base64); // 传递临时文件名作为参数 $cmd = sprintf( 'node ./scripts/test.js %s %s %s %s', escapeshellarg($cfPage), escapeshellarg(uniqid()), escapeshellarg($iaspect), escapeshellarg($tmpFile) ); exec($cmd, $output, $exitCode); // 处理完成后删除临时文件 unlink($tmpFile); ?>
Node脚本修改(test.js)
const cfPage = process.argv[2]; const uniqId = process.argv[3]; const aspect = process.argv[4]; const tmpFilePath = process.argv[5]; // 读取临时文件中的Base64数据 const fs = require('fs'); const base64Data = fs.readFileSync(tmpFilePath, 'utf8').trim(); // 后续业务逻辑示例 console.log('接收的Base64长度:', base64Data.length);
注意事项
- 所有命令行参数必须用
escapeshellarg()包裹,避免命令注入攻击和特殊字符导致的解析错误。 - 临时文件方式要确保文件权限正确,且处理完成后立即删除,避免磁盘冗余占用。
内容的提问来源于stack exchange,提问作者이재동
相关产品推荐
相关产品推荐

