Php调用Python脚本踩过的一些坑
暑假这段时间,利用空闲时间在帮别人写一些东西。因为最终是要写成接口给别人用,所以为了开发方便,我就打算用python来写,但是其中有一个验证码识别的模块。因为这个模块必须要先处理图片再识别,所以只能用python来实现。所以就只能让php来接受处理然后调用python脚本来识别验证码。其中踩了一些坑,所以总结记录下来。
首先线上环境是LAMP,我是直接用的阿里云的轻量应用服务器,是真的方便,也给大家推荐一波。
这里我是用system函数来实现的。因为system函数本身具有打印命令执行输出的功能,程序中的输出可在PHP页面中显示,更加方便。
如果程序成功执行,则system的返回值为程序输出的最后一行,如果执行失败,返回false。第二个参数是可选的,用来得到命令执行后的状态码,0表示成功调用外部程序,1表示调用失败。
$command
[, int &$return_var
] ) : string同 C 版本的 system() 函数一样, 本函数执行 command
参数所指定的命令, 并且输出执行结果。
如果 PHP 运行在服务器模块中, system() 函数还会尝试在每行输出完毕之后, 自动刷新 web 服务器的输出缓存。
command 要执行的命令。
return_var 如果提供 return_var 参数, 则外部命令执行后的返回状态将会被设置到此变量中。
成功则返回命令输出的最后一行, 失败则返回 FALSE
假设我们的代码如下:
<?php echo("php调用Python脚本\n"); $cmd = "python zgao.py arg1 arg2"; //shell下命令行的方式 system($cmd,$ret); echo("result is $ret ");
这里Python脚本要接收参数,也需要用到sys.argv,这个大家应该都知道。那么我们会遇到哪些问题呢?
第一个坑:exec,system等函数默认被禁用
因为我们需要执行python脚本,所以需要调用到system这些函数来执行系统命令。这是我踩的第一个坑,一开始不知道这些危险函数是被禁用的。所以直接在php代码里用了,结果根本不执行这个函数。
需要在php.ini文件中修改,由于在我的环境中php.ini是个只读文件,所以要先修改权限,安全起见只给自己加上rw即可,找到disable_functions。
chmod 600 php.ini && vim php.ini
systemctl restart php-fpm
记住修改后一定要重启才能生效。
第二个坑:输出Python脚本报错信息到文件中
由于我是在本地将Python脚本写好后再放到服务器里调试,通常本地执行没有任何问题但是经常会因为两边的运行环境不同而出现一些莫名其妙的bug。
当时我在服务器用system调用执行Python脚本,脚本里print输出了一些中文,但是就是会报错,不是php报错,而是py脚本报错了。但是system函数本身不会返回Python脚本执行的报错,所以就很苦恼。查了资料后发现可以利用输出重定向。
熟悉linux的朋友应该都知道0,1,2三个数字分代表STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,即标准输入,标准输出(用户终端),标准错误(出错信息输出)
0: 标准输入 STDIN_FILENO
1:标准输出 STDOUT_FILENO
2:标准错误 STDERR_FILENO
将2和重定向到1可以使用:2>&1,将出错信息重定向到标准输出。
同理我们也可以直接将错误信息输出到文件中当做错误日志。
用 2>>xxx.log 即可,注意>>是追加写入,>是覆盖写入。
第三个坑:安全问题!检查参数,防止命令执行
因为这个过程中肯定涉及到传参。system调用执行系统命令,本身就是一个危险函数,如果恰好这个参数有可能是用户可控的,那么极有可能会有命令执行的漏洞。
同样以上面的代码为例。
$cmd = “python zgao.py arg1 arg2”;
假设你没有检查这个arg1参数,又是用户可控的情况。
如果我想搞破坏我会怎么去构造参数
arg1 = xxx & sudo rm -rf /* ;
然后这条指令会是什么样
$cmd = “python zgao.py xxx & sudo rm -rf /* ;”;
这下就变成了两条指令了,为什么要用&,这样即使前一条命令执行出错也会执行后面的语句。如果你恰好又是用的root权限或者拥有sudo权限的用户运行的代码,那么就等着跑路吧!哈哈。
这些就是我在实践过程中,自己踩过的坑,把他们都记录下来。如果你在这个问题也遇到过其他的坑,欢迎给我留言,我会补充上的,作为经验总结。
赞赏微信赞赏支付宝赞赏
2条评论