Reputation: 8372
I'm looking for way to PHP to detect if a script was run from a manual invocation on a shell (me logging in and running it), or if it was run from the crontab entry.
I have various maintenance type scripts written in php that i have set to run in my crontab. Occasionally, and I need to run them manually ahead of schedule or if something failed/broken, i need to run them a couple times.
The problem with this is that I also have some external notifications set into the tasks (posting to twitter, sending an email, etc) that I DONT want to happen everytime I run the script manually.
I'm using php5 (if it matters), its a fairly standard linux server environment.
Any ideas?
Upvotes: 71
Views: 49678
Reputation: 51
(array) $argv
will be set when the cron job runs.
The first value of the array will be the /path/to/file you used when creating the cron job.
The following values in $argv
will be any parameters that followed the /path/to/file.
For example, if your cron job command looks like this:
php /path/to/file.php first second third
The value of $argv will be: ["/path/to/file.php", "first", "second", "third"]
You can then:
if (isset($argv) && is_array($argv) && in_array('first', $argv)) { /* do something */ }
Upvotes: 1
Reputation: 11
On my Amazon Linux server this is what worked for me:
$isCron = ( $_SERVER['HOME'] == '/' );
The home directory is set to yours if you just run it. If you use sudo to run it, the home directory is set to /root.
Upvotes: 0
Reputation: 823
Here's what I use to discover where the script is executed from. Look at the php_sapi_name function for more information: http://www.php.net/manual/en/function.php-sapi-name.php
$sapi_type = php_sapi_name();
if(substr($sapi_type, 0, 3) == 'cli' || empty($_SERVER['REMOTE_ADDR'])) {
echo "shell";
} else {
echo "webserver";
}
EDIT:
If php_sapi_name()
does not include cli (could be cli or cli_server) then we check if $_SERVER['REMOTE_ADDR']
is empty. When called from the command line, this should be empty.
Upvotes: 31
Reputation: 344
Another option would be to test a specific environment variable that is set when the php file is invoked through the web and not set if runned by the commandline.
On my web server I'm testing if the APACHE_RUN_DIR environment variable is set like this :
if (isset($_ENV["APACHE_RUN_DIR"])) {
// I'm called by a web user
}
else {
// I'm called by crontab
}
To make sure it will work on your web server, you can put a dummy php file on your web server with this single statement :
<?php var_dump($_ENV); ?>
Then 1) load it with your web browser and 2) load it from the commandline like this
/usr/bin/php /var/www/yourpath/dummy.php
Compare the differences and test the appropriate variable.
Upvotes: 2
Reputation: 1265
This is very easy. Cron Daemons always export MAILTO
environment variable. Check if it exists and has a non-empty value - then you running from cron.
Upvotes: 0
Reputation: 1975
if (php_sapi_name() == 'cli') {
if (isset($_SERVER['TERM'])) {
echo "The script was run from a manual invocation on a shell";
} else {
echo "The script was run from the crontab entry";
}
} else {
echo "The script was run from a webserver, or something else";
}
Upvotes: 56
Reputation: 28795
In the cron command, add ?source=cron
to the end of the script path. Then, in your script, check $_GET['source']
.
EDIT: sorry, it's a shell script so can't use qs. You can, I think, pass arguments in the form php script.php arg1 arg2
and then read them with $argv
.
Upvotes: 2
Reputation: 12138
$_SERVER['SESSIONNAME']
contains Console
if run from the CLI. Maybe that helps.
Upvotes: 1
Reputation:
I think it would be better to run the cron commmand with an additional option at the command line that you wouldn't run manually.
cron would do:
command ext_updates=1
manual would do:
command
Just add an option in the script itself to have the ext_updates param to have a default value of false.
Upvotes: 0
Reputation: 1
It's easy for me... Just count($_SERVER['argc'])
and if you have a result higher than zero it will be running out of a server. You just need to add to your $_SERVER['argv']
your custom variable, like "CronJob"=true;
Upvotes: -4
Reputation: 61
Creepy. Try
if (!isset($_SERVER['HTTP_USER_AGENT'])) {
instead. PHP Client Binary dont send it. Term Type just works when PHP is used as module (ie apache) but when running php through CGI interface, use the example above!
Upvotes: 6
Reputation: 201
I think that the most universal solution is to add an environment variable to the cron command, and look for it on the code. It will work on every system.
If the command executed by the cron is, for example:
"/usr/bin/php -q /var/www/vhosts/myuser/index.php"
Change it to
"CRON_MODE=1 /usr/bin/php -q /var/www/vhosts/myuser/index.php"
Then you can check it on the code:
if (!getenv('CRON_MODE'))
print "Sorry, only CRON can access this script";
Upvotes: 20
Reputation: 27
posix_isatty(STDOUT) return FALSE
if the output of the cli call is redirected (pipe or file)...
Upvotes: 1
Reputation: 171
The right approach is to use the posix_isatty() function on e.g. the stdout file descriptor, like so:
if (posix_isatty(STDOUT))
/* do interactive terminal stuff here */
Upvotes: 17
Reputation: 17827
In my environment, I found that TERM
was set in $_SERVER
if run from the command line, but not set if run via Apache as a web request. I put this at the top of my script that I might run from the command line, or might access via a web browser:
if (isset($_SERVER{'TERM'}))
{
class::doStuffShell();
}
else
{
class::doStuffWeb();
}
Upvotes: 4
Reputation: 6266
Instead of detecting when the script is run from the crontab, it's probably easier to detect when you're running it manually.
There are a lot of environment variables (in the $_ENV array) that are set when you run a script from the command line. What these are will vary depending on your sever setup and how you log in. In my environment, the following environment variables are set when running a script manually that aren't present when running from cron:
There are others too. So for example if you always use SSH to access the box, then the following line would detect if the script is running from cron:
$cron = !isset($_ENV['SSH_CLIENT']);
Upvotes: 48
Reputation: 881363
I don't know about PHP specifically but you could walk up the process tree until you found either init or cron.
Assuming PHP can get it's own process ID and run external commands, it should be a matter of executing ps -ef | grep pid
where pid is your own process ID and extract the parent process ID (PPID) from it.
Then do the same to that PPID until you either reach cron as a parent or init as a parent.
For example, this is my process tree and you can see the ownership chain, 1 -> 6386 -> 6390 -> 6408.
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 16:21 ? 00:00:00 /sbin/init
allan 6386 1 0 19:04 ? 00:00:00 gnome-terminal --geom...
allan 6390 6386 0 19:04 pts/0 00:00:00 bash
allan 6408 6390 0 19:04 pts/0 00:00:00 ps -ef
The same processes run under cron would look like:
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 16:21 ? 00:00:00 /sbin/init
root 5704 1 0 16:22 ? 00:00:00 /usr/sbin/cron
allan 6390 5704 0 19:04 pts/0 00:00:00 bash
allan 6408 6390 0 19:04 pts/0 00:00:00 ps -ef
This "walking up the process tree" solution means you don't have to worry about introducing an artificial parameter to indicate whether you're running under cron or not - you may forget to do it in your interactive session and stuff things up.
Upvotes: 6
Reputation: 132254
You can setup an extra parameter, or add a line in your crontab, perhaps:
CRON=running
And then you can check your environment variables for "CRON". Also, try checking the $SHELL variable, I'm not sure if/what cron sets it to.
Upvotes: 33
Reputation: 22408
I would look into $_ENV
(var_dump() it) and check if you notice a difference when you run it vs. when the cronjob runs it. Aside from that I don't think there is an "official" switch that tells you what happened.
Upvotes: 5
Reputation: 99751
Not that I know of - probably the simplest solution is providing an extra parameter yourself to tell the script how it was invoked.
Upvotes: 5