PHP调用Python脚本中文参数乱码的根本原因是两者默认不共享字符集上下文,需统一locale、用base64传参、subprocess精确控编码,并确保PHP输出头和文件编码为UTF-8。

PHP调用Python脚本时中文参数变问号或怎么办
根本原因不是“没加编码”,而是PHP和Python之间**默认不共享字符集上下文**,shell_exec、exec这类函数本质是启动新进程,环境变量、locale、stdin/stdout编码全靠系统默认——而Windows和Linux默认差异极大。
常见现象:python script.py 你好在终端直接运行正常,但PHP里用exec("python script.py 你好")传进去变成\xe4\xbd\xa0\xe5\xa5\xbd或直接截断/报错;Python脚本里sys.argv[1]拿到的是乱码字节串,decode('utf-8')失败。
- Linux下优先确认PHP进程的locale:执行
locale命令,确保LANG和LC_ALL含UTF-8(如en_US.UTF-8),否则setlocale(LC_ALL, 'en_US.UTF-8')可能无效 - Windows下cmd默认是GBK,PHP调用时需显式切换:在命令前加
chcp 65001 &&(即UTF-8代码页) - 统一用
escapeshellarg()包裹参数,它会按当前PHP locale处理转义,避免空格、引号引发的截断
Python脚本里怎么安全接收PHP传来的中文参数
不能依赖sys.argv[1].decode('utf-8')硬解,因为Python 2/3行为不同,且Linux下sys.argv在非UTF-8 locale中本身就是乱码字节。
更可靠的做法是让PHP把参数base64编码,Python侧再解码:
立即学习“PHP免费学习笔记(深入)”;
php
// PHP端
$param = base64_encode('你好世界');
exec("python script.py $param", $output);
python
# Python端(兼容2/3)
import sys, base64
try:
arg = sys.argv[1]
text = base64.b64decode(arg).decode('utf-8')
except (IndexError, UnicodeDecodeError):
text = ''
这样绕过了终端编码层,也规避了subprocess中encoding参数在Python 2不可用的问题。
用subprocess比exec更可控,但要注意Python版本
PHP调用Python,本质是跨进程通信。用subprocess能精确控制编码,但必须匹配Python版本:
- Python 3.7+:直接用
subprocess.run(..., encoding='utf-8', errors='replace') - Python 3.6及以下:
stdout返回bytes,需手动.decode('utf-8', 'ignore') - Python 2:没有
encoding参数,必须用subprocess.Popen配合communicate(),且stdin写入前要encode成str
示例(Python 3.7+):
python
import subprocess, sys
result = subprocess.run(
['python', 'script.py'] + sys.argv[1:],
capture_output=True,
encoding='utf-8',
errors='replace'
)
print(result.stdout)
PHP里输出到浏览器还是乱码?别只盯Python
如果最终页面显示,先确认PHP自身输出是否正确:header('Content-Type: text/html; charset=utf-8');必须存在,且PHP文件本身保存为UTF-8无BOM格式。
另外检查Python脚本的print()输出是否被PHP截断——exec()默认只返回最后一行,用shell_exec()或proc_open()才能拿到完整stdout。
最易忽略的一点:某些Linux发行版(如CentOS 7)默认Python 2.7的sys.getdefaultencoding()是ascii,即使你传了UTF-8字节,print也可能抛UnicodeEncodeError。此时需在Python脚本开头加:
python
import sys
if sys.version_info[0] == 2:
reload(sys)
sys.setdefaultencoding('utf-8')
不过这属于临时补丁,长期应迁移到Python 3并显式声明I/O编码。











