Ubuntu Apache环境下PHP调用Python报Argument list too long如何解决
问题根因
你遇到的Argument list too long报错是Linux内核限制的进程命令行参数总长度上限(ARG_MAX)导致的,该参数是内核编译时预设的,Ubuntu系统默认值通常在2MB左右,可执行getconf ARG_MAX查看本地具体数值,和进程栈大小无关,因此调整ulimit的stack size参数无法生效,修改该限制需要重新编译内核,性价比极低,最优解法是替换大体积参数的传递方式。
可行解决方案
方案1:标准输入传递(最推荐)
将小体积参数仍通过命令行传递,大体积的JSON参数通过进程标准输入传输,无长度限制,同时无需处理特殊字符转义,还能规避命令注入风险。
PHP侧修改代码
替换原有exec逻辑为proc_open调用,通过管道写入JSON参数:
// 仅传递小参数到命令行 $command = "python ../path/of/file/script.py {$arg1} {$arg2} {$arg3}"; // 定义进程管道规则 $descriptorspec = [ 0 => ["pipe", "r"], // 标准输入,用于向Python传参 1 => ["pipe", "w"], // 标准输出,用于读取Python返回结果 2 => ["pipe", "w"] // 标准错误,用于排查执行异常 ]; $process = proc_open($command, $descriptorspec, $pipes); if (is_resource($process)) { // 直接写入JSON到标准输入,无需转义特殊字符 fwrite($pipes[0], json_encode($arg4)); fclose($pipes[0]); // 读取执行输出 $output = explode("\n", trim(stream_get_contents($pipes[1]))); fclose($pipes[1]); $errorInfo = stream_get_contents($pipes[2]); fclose($pipes[2]); // 获取执行返回码 $returnVal = proc_close($process); }
Python侧修改代码
从标准输入读取JSON参数:
import sys import json # 原有小参数仍从argv获取 arg1 = sys.argv[1] arg2 = sys.argv[2] arg3 = sys.argv[3] # 从标准输入加载大JSON参数 arg4 = json.load(sys.stdin)
方案2:临时文件中转(改造成本最低)
将大JSON写入系统临时文件,仅把临时文件路径作为参数传递给Python,Python读取文件内容后可自行删除或由PHP侧清理。
PHP侧修改代码
// 生成系统临时文件 $tmpFilePath = tempnam(sys_get_temp_dir(), 'py_arg_'); file_put_contents($tmpFilePath, json_encode($arg4)); // 仅传递临时文件路径作为第4个参数 $command = "python ../path/of/file/script.py {$arg1} {$arg2} {$arg3} {$tmpFilePath}"; $output = null; $returnVal = null; exec($command, $output, $returnVal); // 清理临时文件 unlink($tmpFilePath);
Python侧修改代码
import sys import json arg1 = sys.argv[1] arg2 = sys.argv[2] arg3 = sys.argv[3] # 读取临时文件内容 with open(sys.argv[4], 'r', encoding='utf-8') as f: arg4 = json.load(f)
额外注意
原有直接拼接参数到命令行的写法存在命令注入风险,哪怕做了单引号转义也无法完全规避,替换为上述两种方案后可彻底解决该安全隐患。
内容的提问来源于stack exchange,提问作者Sebastián
相关产品推荐
相关产品推荐

