Windows Server(IIS)下PHP shell_exec调用Python脚本失败的调试
可能的原因及对应解决/调试方法
1. 权限不足
IIS的运行账户(默认是IUSR或应用池对应的账户,比如DefaultAppPool)没有以下权限:
- 执行Python.exe的权限
- 读取Python脚本
nw.py的权限 - 写入
datei.txt所在目录的权限
调试:右键对应文件/文件夹→属性→安全,检查是否有IIS相关账户的权限条目;手动用IIS账户登录服务器,尝试执行Python脚本并写入文件,看是否报错。
解决:给IIS运行账户添加对应权限(读取Python程序和脚本,写入txt目录)。
2. 相对路径陷阱
Python脚本里用open('datei.txt','a')是相对路径,网页调用时,PHP的工作目录不是脚本所在的httpdocs目录,导致文件找不到或写入到了其他位置(比如IIS的默认工作目录)。
调试:在Python脚本里加一行打印当前工作目录:import os; print(os.getcwd()),执行后看输出的路径是否符合预期。
解决:改用绝对路径指定txt文件,比如用脚本所在目录拼接:
import os txt_path = os.path.join(os.path.dirname(__file__), 'datei.txt') with open(txt_path, 'a') as datei: # ...写入逻辑
3. 命令参数格式错误
$_SERVER['REQUEST_URI']包含特殊字符(比如/、?、&),直接拼接进命令会导致命令解析失败,甚至引发安全问题。
调试:在PHP里打印生成的命令:echo htmlspecialchars($command);,复制到控制台执行,看是否报错。
解决:用escapeshellarg()转义参数,确保参数被正确包裹:
$string_escaped = escapeshellarg($_SERVER['REQUEST_URI']); $command = "$python_path $script_path $string_escaped";
4. 环境变量差异
控制台的Python环境和IIS进程的环境不一样,比如控制台能找到Python,但IIS进程加载的环境变量里没有Python路径(不过你已经指定了绝对路径,这个概率低,但仍需排查)。
调试:在命令末尾加2>&1把错误输出转出来,看是否有“找不到Python”之类的提示;或者在Python脚本里打印sys.path看模块路径是否正常。
解决:确保命令里的Python路径绝对正确,或者把Python路径添加到系统环境变量后重启IIS。
5. 错误信息无法捕获
shell_exec()在命令执行失败时可能返回NULL,导致看不到错误。
调试:改用exec()获取返回码和输出,或者给命令加错误重定向:
// 方法1:用exec捕获返回码和输出 exec($command, $output, $return_code); echo "返回码: $return_code<br>"; echo "输出: " . implode("<br>", $output); // 方法2:给命令加错误重定向 $command = "$python_path $script_path $string_escaped 2>&1"; $output = shell_exec($command); echo $output;
修改后的示例代码
PHP脚本
<?php $string = $_SERVER['REQUEST_URI']; $string_escaped = escapeshellarg($string); $python_path = "C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python311\\Python.exe"; $script_path = "C:\\inetpub\\vhosts\\...\\httpdocs\\nw.py"; $command = "$python_path $script_path $string_escaped 2>&1"; exec($command, $output, $return_code); echo "返回码: $return_code<br>"; echo "输出:<br>" . implode("<br>", $output); ?>
Python脚本
import sys import os def main(): if len(sys.argv) < 2: print("缺少参数") sys.exit(1) string = sys.argv[1] txt_path = os.path.join(os.path.dirname(__file__), 'datei.txt') try: with open(txt_path, 'a', encoding='utf-8') as datei: datei.write(f"aaa{string}\n") print(f"写入成功: {string}") except Exception as e: print(f"写入失败: {str(e)}") sys.exit(1) if __name__ == "__main__": main()
内容的提问来源于stack exchange,提问作者admdev

