PHP调用R,在终端执行时创建图像,而不是从Web UI执行


PHP call R, image created when executed in terminal, but not from Web UI

我正在尝试从PHP运行R脚本,并在R脚本中,我将创建test.jpg图像,并在PHP中,我将在web上显示此图像。

R是2.11.1,OS是ubuntu10.10

问题是:如果我从终端运行,这个。jpg创建成功,但如果我从web运行,没有创建图像。我在同一目录下从终端和web运行脚本。/opt/lampp/根/名称/。如果有人能告诉我一个好的工具来调试这个web,那就太好了。我在。php文件中放了一些echo,我看到函数被调用,但仍然不知道如何解决这个bug)。

.jpg是在我从终端运行时创建的:

php r_caller.php

在这个r_caller.php中,我有一个简单的函数:

<?php php_call_r(){
$cmd = "echo 'argv <- '"r_command.r'"; source(argv)' | " .
     "/usr/bin/R --vanilla --slave";
$ret = system($cmd);
echo $ret;}
?>

和这个php_call_r函数在与r_caller.php相同的文件中调用:

<?php
//some irrelavant codes above
php_call_r();
print("<img src=test.jpg>");
?}

和r_command。在r脚本中,我有简单的命令:

jpeg("test.jpg") 
plot(50, 50)
dev.off()
我真的很感谢你的帮助!

您没有指定您的平台和R版本,但是在unix上jpeg()设备可能需要X11来呈现图像(您可能在交互式会话中有,但在apache中没有)。您最好使用Cairo包或其他不需要X11会话的方法(最近的R允许您在jpeg调用中使用替代类型,您也可以尝试-参见?jpeg)。

(顺便说一句,有一个PHP客户端可以使web请求更快-运行R本身几乎是PHP中最慢的使用R的方式。如果您不想安装任何软件包,那么您可能需要至少使用Rscript)

编辑:既然你已经添加了R版本——那是一个非常古老的版本,你应该认真考虑升级它。你可以尝试用旧的R版本安装Cairo,但你可能还需要回到原来的版本。

还有一件事要考虑,检查你的文件权限-确保www-data有写权限,无论你将在哪里创建文件(例如,查看echo system("pwd");当前目录R将运行)。

检查Apache错误日志,看看是否有错误。尝试在PHP代码的开头添加以下内容:

error_reporting(E_ALL);
ini_set('display_errors','On');

这可能是一个复制/粘贴错误,但是您的php_call_r函数没有正确地定义为函数。我的建议如下:

<?php function php_call_r() {
    $cmd = "echo 'argv <- '"r_command.r'"; source(argv)' | " .
    "/usr/bin/R --vanilla --slave";
    $ret = system($cmd);
    echo $ret;
}
?>

对每个请求从PHP执行R是一个非常糟糕的主意——PHP管道通常不可靠,R的输出是为交互式工作而优化的,而不是传输结果。而且R的启动时间很长,所以你浪费了大量的时间和CPU功率。

更好的方法是使用R worker守护进程,由Rserve或trigger创建——Rserve有PHP客户端,对于trigger,你需要自己编写一个,但这是微不足道的;它可能看起来像这样:

R部分(r.R)

require(triggr);
serve(function(data_from_php){
 cat(sprintf("Called with: %s'n",data_from_php));
 #<<Picture creation code>>
 
 #Break connection notifying PHP that picture is done
 return(endConnection("Done'r'n"));
},9090);
  # ^- Port you want to use for internal communication

PHP部分
<?php
$s=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
echo "Connecting...'n";
                               
if(socket_connect($s,"localhost",9090)){
 echo "Connected!'n"; //v double 'r'n is crucial
 $d="some data for R'r'n'r'n";
 socket_write($s,$d,strlen($d));
 //This blocks until picture is done
 $r=socket_read($s,6);
 //Here we can emit the page featuring <img>
 echo "Response was $r'n";
}
?>

现在你只要在后台或在一些自动复活守护程序下启动r.R,你就完成了。