如何解决为什么我的 PHP 脚本在 cron 中无法在命令行中运行?

发布于 2024-09-11 08:44:11 字数 841 浏览 4 评论 0原文

我有一个脚本调用同一类中的两个函数 A 和 B。 A 创建一个 Amazon 虚拟服务器,B 销毁一个,均通过 Amazon 命令行工具的 shell_exec() 进行。脚本 doActions.php 从队列中提取操作。如果操作是“创建”,则它会创建一个实例;当行动是“摧毁”时,它会杀死一个人。

当我从命令行执行该脚本时,该脚本可以很好地执行 A 和 B:php script.php。

当我把它放在 cron 上时,它会运行,但只成功运行 B 函数。它会删除并销毁实例,但不会创建它们。

故障点显然是函数 B。它在第一个也是最重要的 shell_exec 处阻塞,不返回任何内容。

echo $string = shell_exec('/home/user/public_html/domain.com/private/ec2-api-tools/bin/ec2-run-instances ami-23b6534a -k gsg-keypair -z us-east-1a');

除非您了解有关 Amazon 命令行工具工作方式的具体信息,否则请向我提出为什么 shell_exec 在一种情况下可以工作而在另一种情况下不起作用的原因。

同一位置的另一个 shell_exec 的行为符合预期:

echo $string = shell_exec ('echo overflow');

我的猜测是它必须使用权限执行某些操作。但是当我运行 shell_exec('whoami') 时,它返回“root”,当我 su 并运行命令时,它工作正常。我很难想出创造性的方法来解决为什么我的 PHP 脚本在 cron 中无法工作而在命令行中却无法工作。你能推荐一些吗?

I've got a script that calls two functions, A and B, from the same class. A creates an Amazon virtual server and B destroys one, both via shell_exec()'s of Amazon's command line tools. The script, doActions.php, pulls actions from a queue. If the action is "create" it creates an instance; when the action is "destroy" it kills one.

The script works fine to execute both A and B when I execute it from the command line: php script.php.

When I put it on a cron, it runs but only successfully runs the B function. It deletes destroys instances but won't create them.

The point of failure is clearly function B. It chokes at the first and most important shell_exec, returning and echoing nothing.

echo $string = shell_exec('/home/user/public_html/domain.com/private/ec2-api-tools/bin/ec2-run-instances ami-23b6534a -k gsg-keypair -z us-east-1a');

Unless you know something specific about the way Amazon's command line tools work, please suggest to me reasons why a shell_exec might work in one case and not the other.

Another shell_exec in the same place behaves as expected:

echo $string = shell_exec ('echo overflow');

My guess is that it has to do something with permissions. But when I have it run shell_exec('whoami') it return "root," and when I su and run the command it works fine. I'm having a hard time thinking of creative ways to troubleshoot why my PHP script won't work in cron when it does from the command line. Can you suggest some?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我三岁 2024-09-18 08:44:11

当某些内容从命令行运行但拒绝在 cron 中执行时,这通常是环境问题(路径或您正在运行的代码所需的其他环境变量)。

首先,您应该修改脚本以在最顶部输出当前环境(shell_exec('env')?),并检查命令行和 cron 的输出。

希望会有一些明显的东西,例如 AMAZON_EC2_VITAL_VAR,但如果没有,您应该将 cron 环境移向命令行,一次一个变量,直到它开始工作。

快速测试以确定这一点。从命令行执行:

env >/tmp/pax_env.sh

然后从首先执行的 shell 脚本运行 PHP 脚本:

. /tmp/pax_env.sh

以便环境相同。

请记住,su 本身并不能为您提供与以特定用户身份直接登录相同的环境(su - 可以,我思考)。您可能需要检查直接以 root 身份登录时的行为。


回复您的评论:

是的,我相信你已经明白了。我可能会将您的答案标记为正确,但需要您对您的聪明解决方案进行一些附录。首先,执行 pax_env.sh 脚本的最佳方法是什么? shell_exec() 有效吗?

永远不要说我不是为了钱工作:-) 不。shell_exec 几乎肯定会运行一个子 shell,因此变量将被设置in该子 shell 但不会影响 PHP 父进程。

我的建议是,如果您想要设置所有这些变量,则创建一个由 /tmp/pax_env.sh 中的所有命令组成的 shell 脚本(可能在每个命令前面加上 export) 后跟您当前在 cron 中运行的命令,大致如下:

export PATH=.:/usr/bin
export PS1=Urk:
export PS2=MoreUrk:
/home/user/pax/scriptB.php

然后从 cron 而不是 运行该脚本> /home/user/pax/scriptB.php 直接。这将确保在调用 PHP 代码之前已设置好环境。

精明的读者会注意到上面的短语“如果你想要设置所有这些变量”。我个人认为将所有命令行变量转储到 cron 作业的 shell 脚本中并不是一个好主意。我更愿意实际找出需要哪些并且只包含那些。这减少了你的 cron 作业必须运行的污染。例如,您的 PHP 脚本不太可能需要 PS1/PS2 提示变量。

如果它有效,您可以设置所有环境变量 - 我只是更喜欢绝对最小值,这样当事情发生变化时我不必太担心。

找出所需内容的一种方法是一次注释掉一个导出,直到脚本再次中断。然后你就知道需要变量了。一旦它与注释掉的最大数量的导出语句一起工作,您就可以完全删除那些注释的导出语句,而剩下的,无论可能性如何,都一定没问题(向阿瑟柯南道尔爵士致歉)。

When something runs from the command line but refuses to do so within cron, it's often an environment issue (path or some other environment variable that's needed by the code you're running).

For a start you should modify the script to output the current environment (shell_exec('env')?) at the very top and examine the output from the command line and cron.

Hopefully, there will be something obvious such as AMAZON_EC2_VITAL_VAR but, if not, you should move the cron environment towards your command line one, one variable at a time, until it starts working.

A quick test to ascertain this. From your command line, do:

env >/tmp/pax_env.sh

Then run your PHP script from a shell script which first executes:

. /tmp/pax_env.sh

so that the environments are identical.

And keep in mind that su on its own doesn't give you the same environment as you'd get from logging in directly as a specific user (su - does, I think). You may want to check the behaviour for when you log in as root directly.


Re your comment:

Yes, I do believe you've got it. I'm likely going to mark your answer as correct but need you to suffer through a few addendums about your clever solution. First of all, what's the best way to execute the pax_env.sh script? Does shell_exec() work?

Never let it be said I didn't work for my money :-) No. The shell_exec will almost certainly be running a sub-shell so the variables would be set in that sub-shell but would not affect the PHP parent process.

My advice, if you wanted all those variables set, would be to create a shell-script consisting of all the commands in /tmp/pax_env.sh (probably prefixing each with export) followed by the command you currently have running in cron, something along the lines of:

export PATH=.:/usr/bin
export PS1=Urk:
export PS2=MoreUrk:
/home/user/pax/scriptB.php

Then run that script from cron rather than /home/user/pax/scriptB.php directly. That will ensure the environment is set up before your PHP code is called.

Astute readers will have noticed the phrase "if you wanted all those variables set" above. I don't personally think it's a good idea to dump all your command line variables into the shell script for the cron job. I'd prefer to actually find out which ones are needed and only include those. That lessens the pollution your cron job has to run under. For example, it's unlikely that the PS1/PS2 prompt variables will be required for your PHP script.

If it works, you can set all the environment variables - I just prefer the absolute minimum so I don't have to worry too much when things change.

A way of finding out what's needed is to comment out one export at a time until your script breaks again. Then you know that variable is needed. Once it works with the maximum amount of export statements commented out, you can just delete those commented export statements altogether and what remains, however improbable, must be okay (with apologies to Sir Arthur Conan Doyle).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文