我有一个简单的 shell 脚本:
- 在远程机器上创建一个目录。
- 将 .epub 文件复制到远程机器的新目录。
- 运行 kindlegen 将 .epub 转换为 .mobi。
- 远程服务器将新的.mobi 文件复制回原始服务器。
两台服务器都配置了通过公钥进行 SSH 无密码登录。
在命令行运行脚本效果很好。从服务器上使用 PHP shell_exec 命令运行它将执行脚本,但 ssh 和 scp 命令似乎没有执行,或者至少没有输出任何内容,即使我使用 -v 标志。
以下是调用 shell 脚本的 PHP 函数:
function mobi_watermark($userid, $email, $epubpath)
{
$outpath = "/tmp/epub$userid/"; # the book gets marked for each user, store each epub under a unique work folder to avoid collision
shell_exec("chmod -R 777 ".$outpath); # web server creates files under user "nobody".
shell_exec("del.sh"); # deletes old files if they exist
shell_exec("rep.sh $userid $email $epubpath"); # creates the initial .epub and tmp dir
shell_exec("chmod -R 777 ".$outpath);
shell_exec("kindle.sh $outpath"); # this is the mobi conversion, where the problem is
$this->mobi_ufa_download('ufa-187.mobi',$outpath);
}
下面是包含失败命令的 shell 脚本:[ kindle.sh ]
#!/usr/local/bin/bash
# uses the same /tmp$userid path as the other scripts, but on the remote server
TMPPATH=$1
cd $TMPPATH
# create remote dir
ssh -v user@server 'mkdir -v '$TMPPATH
# copy the source epub file to remote
scp -v $TMPPATHfile-name.epub user@server:$TMPPATH
# perform the conversion and copy the .mobi result back to originating server
/usr/bin/ssh -v user@server 'cd '$TMPPATH'; /home/username/kindlegen/kindlegen ./file-name.epub; scp -v file-name.mobi user@originating-server:'$TMPPATH';rm -rf '$TMPPATH
如果我自己从脚本文件或从命令行以单独的命令运行这一系列命令,那么一切都能完美运行。
当通过 php 脚本运行时,如果我决定回显测试命令,我可以看到脚本输出,如果我破坏源文件名,scp 将报告错误,但如果 scp 或 ssh 命令正确,则不会发生任何事情。 -v 标志甚至没有任何详细的调试输出。
我肯定忽略了一些显而易见的东西?我猜是因为 PHP 使用了 SSH 不喜欢的用户“nobody”。如果这是问题所在,有办法解决这个问题吗?
答案1
您可能想尝试添加
</dev/null
在有问题的命令的末尾,以防命令以某种方式需要输入。
答案2
私有 ssh 密钥存储在哪里,在您以该用户身份运行命令的 ~/.ssh/id_... 文件中吗?
如果是这样,那么 apache 就不是以您的用户身份运行的。Apache 需要能够访问 ssh 密钥的副本。您还可以将 -i 添加到 ssh 和 scp 命令中,这样它就不必存在于 apache 的主目录中。
答案3
这shell_exec() 函数可能会给你一些你忽略的信息,因为你没有收集这些信息。尝试
$info=shell_exec("kindle.sh $outpath");
echo "<pre>$output</pre>";
这就是我开始调试这个问题时要做的事情。
编辑:
将 .ssh 和 id_rsa 的权限设置为 777 会给您带来大麻烦,因为如果权限太宽松,ssh 会拒绝工作。请分别将它们重新设置为 700 和 600。
我不明白为什么你没有看到任何结果,试试
$info=shell_exec("kindle.sh 2>&1 $outpath");
echo "<pre>$output</pre>";
这也应该强制将 stderr 输出到 std out。
答案4
当我在从 httpd 和 php 进程执行外部脚本时遇到麻烦时,我尝试在与 httpd 进程相同的用户下手动运行。
su nobody
很有可能 nobody 用户没有设置 shell,您需要启用 shell 才能su
使用它。