从 PHP 执行 R 脚本

Executing R script from PHP

index.php:

<?php
    echo exec("Rscript foo.R");
?>

foo.R:

#!/usr/bin/env Rscript
print("Before!")
#library(rJava);
print("After!");

网页输出:

[1] "After!"

现在这是预期的输出,因为 exec returns 命令结果的最后一行。 现在,因为我想访问需要 rJavaRMongo 库的 mongodb 数据库,所以我稍微修改了上面的代码。

foo.R:

#!/usr/bin/env Rscript
print("Before!")
library(rJava);
print("After!");

网页输出:

[1] "Before!"

现在我不明白这个输出。我期望与以前相同的输出,即 [1] "After!"。就好像从库导入行开始的 R 代码根本不存在。我已经在 R shell 中测试了上面的代码(以及我在从 mongodb 抓取的数据上使用 kmeans 的省略代码)并且它按预期工作。

在本应从 PHP 执行的 R 脚本中导入库有什么问题?


更新 1:
有趣的是,如果我从命令行调用 index.php,修改后的 foo.R 会按照我的预期被调用和执行。

$ php index.php 
Loading required package: methods
[1] "After!"

所以我的结论是,我的普通用户帐户可以执行 index.php,这又可以在 foo.R 中加载库,但似乎 www-data 用户帐户没有权限在 foo.R 中加载库R

所以现在的问题是如何授予 www-data 加载 R 库的权限?


更新 2:
我通过将 apache 用户从 www-data 更改为当前用户暂时解决了这个问题,但我知道这是一个巨大的安全风险,我正在寻找替代解决方案。

首先,当 www-user 加载 R 库失败时,您应该准确检查 Apache 日志中出现的错误。两个最可能的罪魁祸首是权限错误和库搜索路径不正确。

如果库是为本地用户而不是系统范围安装的,那么 www-data 将无法找到它们,但 Apache 日志中的错误应该会显示此信息。

另一种选择是不使用 PHP 直接执行 R 脚本。

您可以使用像 Redis 这样的键值数据库或像 Rabbitmq 这样的排队系统。与其直接执行脚本,不如向这些系统中的任何一个发送消息。

在命令行中执行 php 脚本,轮询这些系统中的任何一个以查找任何新消息,当它收到消息时,它会执行脚本并使用脚本的结果进行响应。

所以它将成为一个双向消息传递系统:

Script A ----> Queue ----> Script B  ----> R Script
R Script --result--> Script B ----> Queue ----> Script A

这是一个最初实施起来有点复杂的系统,但绝对安全且可扩展。

我建议你看看 Celery