Je cherche un moyen de PHP pour détecter si un script a été exécuté à partir d'une invocation manuelle sur un shell (je me connecte et l'exécute), ou s'il a été exécuté à partir de l'entrée crontab.
J'ai divers scripts de type de maintenance écrits en php que j'ai définis pour fonctionner dans mon crontab. Parfois, et je dois les exécuter manuellement avant la date prévue ou si quelque chose a échoué/cassé, j'ai besoin de les exécuter plusieurs fois.
Le problème avec cela est que j'ai également des notifications externes définies dans les tâches (publication sur Twitter, envoi d'un e-mail, etc.) que je ne veux PAS avoir à chaque fois que j'exécute le script manuellement.
J'utilise php5 (si c'est important), c'est un environnement de serveur linux assez standard.
Des idées?
Au lieu de détecter quand le script est exécuté à partir de la crontab, il est probablement plus facile de détecter lorsque vous l'exécutez manuellement.
De nombreuses variables d'environnement (dans le tableau $ _ENV) sont définies lorsque vous exécutez un script à partir de la ligne de commande. Leur nature varie en fonction de la configuration de votre serveur et de la façon dont vous vous connectez. Dans mon environnement, les variables d'environnement suivantes sont définies lors de l'exécution manuelle d'un script qui ne sont pas présentes lors de l'exécution depuis cron:
Il y en a aussi d'autres. Ainsi, par exemple, si vous utilisez toujours SSH pour accéder à la boîte, la ligne suivante détectera si le script s'exécute à partir de cron:
$cron = !isset($_ENV['SSH_CLIENT']);
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";
}
Vous pouvez configurer un paramètre supplémentaire ou ajouter une ligne dans votre crontab, peut-être:
CRON=running
Et puis vous pouvez vérifier vos variables d'environnement pour "CRON". Essayez également de vérifier la variable $ Shell, je ne sais pas si/à quoi cron la définit.
Voici ce que j'utilise pour découvrir d'où le script est exécuté. Regardez la fonction php_sapi_name pour plus d'informations: 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: Si php_sapi_name()
n'inclut pas cli (pourrait être cli ou cli_server) alors nous vérifions si $_SERVER['REMOTE_ADDR']
est vide. Lorsqu'il est appelé depuis la ligne de commande, il doit être vide.
Je pense que la solution la plus universelle consiste à ajouter une variable d'environnement à la commande cron et à la rechercher dans le code. Cela fonctionnera sur tous les systèmes.
Si la commande exécutée par le cron est par exemple:
"/usr/bin/php -q /var/www/vhosts/myuser/index.php"
Changez-le en
"CRON_MODE=1 /usr/bin/php -q /var/www/vhosts/myuser/index.php"
Ensuite, vous pouvez le vérifier sur le code:
if (!getenv('CRON_MODE'))
print "Sorry, only CRON can access this script";
La bonne approche consiste à utiliser la fonction posix_isatty () sur par exemple le descripteur de fichier stdout, comme ceci:
if (posix_isatty(STDOUT))
/* do interactive terminal stuff here */
Je ne connais pas PHP spécifiquement mais vous pouvez remonter l'arborescence des processus jusqu'à ce que vous trouviez init ou cron.
En supposant que PHP peut obtenir son propre ID de processus et exécuter des commandes externes, il devrait s'agir d'exécuter ps -ef | grep pid
où pid est votre propre ID de processus et extrayez l'ID de processus parent (PPID) de celui-ci.
Faites de même pour ce PPID jusqu'à ce que vous atteigniez cron en tant que parent ou init en tant que parent.
Par exemple, ceci est mon arbre de processus et vous pouvez voir la chaîne de propriété, 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
Les mêmes processus exécutés sous cron ressembleraient à:
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
Cette solution "remonter dans l'arborescence des processus" signifie que vous n'avez pas à vous soucier d'introduire un paramètre artificiel pour indiquer si vous exécutez sous cron ou non - vous pouvez oublier de le faire dans votre session interactive et bourrer les choses.
Pas que je sache - probablement la solution la plus simple consiste à fournir vous-même un paramètre supplémentaire pour indiquer au script comment il a été invoqué.
Terrifiant. Essayer
if (!isset($_SERVER['HTTP_USER_AGENT'])) {
au lieu. PHP Client binaire ne l'envoie pas. Le type de terme ne fonctionne que lorsque PHP est utilisé comme module (c'est-à-dire Apache) mais lors de l'exécution de php via l'interface CGI, utilisez l'exemple) au dessus!
J'examinerais $_ENV
(var_dump () it) et vérifiez si vous remarquez une différence lorsque vous l'exécutez par rapport à quand le cronjob l'exécute. En dehors de cela, je ne pense pas qu'il y ait un interrupteur "officiel" qui vous indique ce qui s'est passé.
Dans mon environnement, j'ai constaté que TERM
était défini dans $_SERVER
si exécuté à partir de la ligne de commande, mais non défini s'il est exécuté via Apache en tant que demande Web. Je mets ceci en haut de mon script que je pourrais exécuter à partir de la ligne de commande, ou accéder via un navigateur Web:
if (isset($_SERVER{'TERM'}))
{
class::doStuffShell();
}
else
{
class::doStuffWeb();
}
getenv('TERM')
Rembourrage pour les SO 30 min.
Une autre option serait de tester une variable d'environnement spécifique qui est définie lorsque le fichier php est appelé via le Web et non définie si elle est exécutée par la ligne de commande.
Sur mon serveur Web, je teste si la variable d'environnement Apache_RUN_DIR est définie comme ceci:
if (isset($_ENV["Apache_RUN_DIR"])) {
// I'm called by a web user
}
else {
// I'm called by crontab
}
Pour vous assurer qu'il fonctionnera sur votre serveur Web, vous pouvez mettre un fichier php factice sur votre serveur Web avec cette seule déclaration:
<?php var_dump($_ENV); ?>
Ensuite 1) chargez-le avec votre navigateur Web et 2) chargez-le à partir de la ligne de commande comme ceci
/usr/bin/php /var/www/yourpath/dummy.php
Comparez les différences et testez la variable appropriée.
Dans la commande cron, ajoutez ?source=cron
à la fin du chemin du script. Ensuite, dans votre script, cochez $_GET['source']
.
EDIT: désolé, c'est un script Shell donc ne peut pas utiliser qs. Vous pouvez, je pense, passer des arguments sous la forme php script.php arg1 arg2
puis lisez-les avec $argv
.
$_SERVER['SESSIONNAME']
contient Console
s'il est exécuté à partir de la CLI. Peut-être que cela aide.
C'est très simple. Les démons Cron exportent toujours la variable d'environnement MAILTO
. Vérifiez si elle existe et a une valeur non vide - puis vous exécutez à partir de cron.
posix_isatty(STDOUT) return FALSE
si la sortie de l'appel cli est redirigée (pipe ou fichier) ...
if(!$_SERVER['HTTP_Host']) {
blabla();
}
Sur mon serveur Amazon Linux, c'est ce qui a fonctionné pour moi:
$ isCron = ($ _SERVER ['HOME'] == '/');
Le répertoire personnel est défini sur le vôtre si vous l'exécutez. Si vous utilisez Sudo pour l'exécuter, le répertoire personnel est défini sur/root.
Je pense qu'il serait préférable d'exécuter la commande cron avec une option supplémentaire sur la ligne de commande que vous n'exécuteriez pas manuellement.
cron ferait:
command ext_updates=1
manuel ferait:
command
Ajoutez simplement une option dans le script lui-même pour que le paramètre ext_updates ait la valeur par défaut false.