PHP - comment déterminer au mieux si l'invocation actuelle provient de la CLI ou du serveur Web?

Réponses:

308

php_sapi_nameest la fonction que vous souhaiterez utiliser car elle renvoie une chaîne minuscule du type d'interface. De plus, il y a la constante PHP PHP_SAPI.

La documentation peut être trouvée ici: http://php.net/php_sapi_name

Par exemple, pour déterminer si PHP est exécuté à partir de la CLI, vous pouvez utiliser cette fonction:

function isCommandLineInterface()
{
    return (php_sapi_name() === 'cli');
}
Joe Lencioni
la source
11
Plus simple:return php_sapi_name() == 'cli';
Savageman
11
J'ai fait une recherche: si vous invoquez le script avec php-cgicela ne fonctionnera pas. À son tour, il retournera cgi-fcgiString. Si vous chargez le script en tant que page Web à partir d'un navigateur, vous obtiendrez apache2handler. J'espère que cela t'aides. Je avais besoin d'utiliser php-cgiafin d'introduire des $_GETvariables: php-cgi myscript.php arg1=one arg2=two. Tester une valeur différente de apache2handlerdevrait être acceptable apache.
Sebastian
3
Une petite mise en garde à propos de cette méthode: elle ne reviendra pas"cli" lorsqu'elle est exécutée à partir d'une tâche cron. Il y a un certain nombre de clés différentes parmi lesquelles choisir $_SERVERpour déterminer de manière plus fiable si la demande est venue via HTTP ou non.
omninonsense
2
@omninonsense J'ai testé avec PHP 7.2.7 et il renvoie cli.
Jose Nobile
38

J'utilise cette fonction depuis quelques années

function is_cli()
{
    if ( defined('STDIN') )
    {
        return true;
    }

    if ( php_sapi_name() === 'cli' )
    {
        return true;
    }

    if ( array_key_exists('SHELL', $_ENV) ) {
        return true;
    }

    if ( empty($_SERVER['REMOTE_ADDR']) and !isset($_SERVER['HTTP_USER_AGENT']) and count($_SERVER['argv']) > 0) 
    {
        return true;
    } 

    if ( !array_key_exists('REQUEST_METHOD', $_SERVER) )
    {
        return true;
    }

    return false;
}
Silver Moon
la source
10
array_key_exists('REQUEST_METHOD', $_SERVER) return true;WAT?
biziclop
@biziclop, la vérification array_key_exists('REQUEST_METHOD', $_SERVER)est correcte pour aider à la détection de la source de la requête . En CLI , le $_SERVERtableau Super Global N'AURA PAS la clé REQUEST_METHOD, elle n'existe que lorsque la demande est faite via le Web, par conséquent, l'auteur est absolument sur la cible lors de la vérification.
Julio Marchi
1
@JulioMarchi: mais ne devrait-il pas return false;ou faire if ( ! array_key_exists(…)) return true;?
biziclop le
2
@biziclop, vous avez tout à fait raison !!!! Comment pourrais-je manquer un si petit détail aussi énorme ??? Honte sur moi... :). Sûrement, si la CLE 'REQUEST_METHOD'n'est PAS trouvée, alors la fonction devrait revenir FALSEpour indiquer "CLI". Mes excuses pour ne pas avoir fait attention à la portée de la fonction elle-même ... L'auteur devrait le corriger car la fonction fonctionne réellement!
Julio Marchi
Cette fonction fonctionnait dans mon cas, pas php_sapi_name (), car j'avais besoin de faire la distinction entre les requêtes Web et les exécutions cronjob, et le résultat php_sapi_name () était "php-cgi" dans les deux cas.
luis.ap.uyen
36

php_sapi_name()n'est vraiment pas la meilleure façon d'effectuer cette vérification car elle dépend de la vérification par rapport à de nombreuses valeurs possibles. Le binaire php-cgi peut être appelé à partir de la ligne de commande, à partir d'un script shell ou en tant que tâche cron et (dans la plupart des cas) ceux-ci doivent également être traités comme 'cli' mais renverront des php_sapi_name()valeurs différentes pour ceux-ci (notez que ce n'est pas t le cas avec la version simple de PHP mais vous voulez que votre code fonctionne n'importe où, non?). Sans oublier que l'année prochaine, il pourrait y avoir de nouvelles façons d'utiliser PHP que nous ne pouvons probablement pas connaître maintenant. Je préfère ne pas y penser quand je ne me soucie que de la météo, je devrais encapsuler ma sortie en HTML ou non.

Heureusement, PHP a un moyen de vérifier cela spécifiquement. Utilisez simplement http_response_code()sans aucun paramètre et il retournera TRUE s'il est exécuté à partir d'un environnement de type serveur Web et FALSE s'il est exécuté à partir d'un environnement de type CLI. Voici le code:

$is_web=http_response_code()!==FALSE;

Cela fonctionnera même si vous définissez accidentellement (?) Un code de réponse à partir d'un script s'exécutant à partir de la CLI (ou quelque chose comme la CLI) avant d'appeler cela.

krowe2
la source
4
Cette question était déjà ancienne quand j'y ai répondu. Faire voter cette réponse aurait probablement été plus utile que de publier une autre réponse qui est un double, sauf sans l'explication.
krowe2
Concernant "Cela fonctionnera même si vous définissez accidentellement (?) Un code de réponse à partir d'un script s'exécutant à partir de la CLI ([...]) avant d'appeler ceci.": (Au moins) à partir de PHP 7.4.3, c'est pas vrai. http_response_code()définit le code / renvoie le code défini lors de l'exécution à partir de la CLI. Vérifié par <?php function t() { echo var_export(http_response_code(), true) . ' -> ' . (http_response_code() !== false ? 'web' : 'cli') . "\n"; } t(); http_response_code(200); t(); http_response_code(false); t();. Donc, si http_response_code()===falsealors c'est une valeur sûre d'assumer la CLI, mais sinon vous devez vérifier également d'autres métriques.
Sebastian B.28
23

Je pense qu'il veut dire si PHP CLI est invoqué ou s'il s'agit d'une réponse à une requête Web. Le meilleur moyen serait d'utiliser php_sapi_name()ce qui, s'il exécutait une requête Web, ferait écho à Apache si c'est ce qu'il exécutait.

Pour lister quelques extraits de la documentationphp_sapi_name() php sur :

  • aolserver
  • apache
  • apache2filter
  • apache2handler
  • caudium
  • cgi (jusqu'à PHP 5.3)
  • cgi-fcgi
  • cli
  • cli-server (serveur Web intégré à partir de PHP 5.4)
  • continuité
  • intégrer
  • fpm-fcgi
  • isapi
  • litespeed
  • plus doux
  • nsapi
  • phttpd
  • pi3web
  • roxen
  • thttpd
  • smoking
  • webjames
Marc Towler
la source
13

Cela devrait gérer tous les cas (y compris php-cgi)

return (php_sapi_name() === 'cli' OR defined('STDIN'));
rbawaskar
la source
6
function is_cli() {
    return !http_response_code();
}

exemple:

if (is_cli()) {
    echo 'command line';
} else {
    echo 'browser';
}
Terry Lin
la source
2
Dans le manuel, "FALSE sera retourné si response_code n'est pas fourni et il n'est pas appelé dans un environnement de serveur Web (comme à partir d'une application CLI). TRUE sera retourné si response_code est fourni et il n'est pas appelé dans un serveur Web environnement (mais uniquement lorsqu'aucun état de réponse précédent n'a été défini) ". Vous avez rétrogradé votre logique.
krowe2
1
+1. Incroyable. Après tant d'années de recherches infructueuses ... Je vous décerne par la présente le prix Nobel Memorial en PHPics, partagé avec @ krowe2 pour sa contribution inestimable à faire en sorte que cela fonctionne. Toutes nos félicitations!
Sz.
Il est possible que quelque chose ait défini le code de réponse ... http_response_code(200);... si je l'appelle maintenant, http_response_code()il renvoie 200;
Brad Kent
@BradKent C'est UNIQUEMENT si vous appelez cela à partir d'un environnement Web et, dans ce cas, cette vérification fonctionnera toujours tant que vous n'avez pas défini le code d'état sur zéro (qui est de toute façon un code d'état HTTP invalide). Ma version fonctionnera même dans ce cas car elle vérifie spécifiquement FALSE. Si http_response_code();est appelé à partir d'un environnement CLI, il retournera toujours FALSE quel que soit le code d'état réel. Je l'ai déjà expliqué dans ma réponse, mais vous auriez pu également le découvrir en lisant la page de manuel sous "Valeurs de retour" ou en l'essayant.
krowe2
@ krowe2 renvoie php -r 'http_response_code(200); echo http_response_code()."\n";' "200" Sauf si vous pouvez garantir qu'une bibliothèque ou un framework ignorant n'a pas défini le code de réponse avec http_response_code(même dans un environnement cli), alors cela fonctionnera. Personnellement, j'utilise$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
Brad Kent
4

J'ai utilisé ceci:

php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)

Cela vient de Drush codebase, environment.inc où ils ont une vérification similaire à faire.

Ranjan
la source
4
Si register_argc_argvest défini, le fait de transmettre une quantité quelconque de valeurs GET entraînera une valeur différente argcde 0.
3

Essayer

isset($_SERVER['REQUEST_METHOD'])

s'il est défini, vous êtes dans un navigateur.

Alternativement, vous pouvez vérifier si

isset($_SERVER['argv'])

mais cela pourrait ne pas être vrai sur Windows CLI, IDK.

gnud
la source
1
Bien que ce ne soit pas la réponse "correcte", elle pourrait être la plus fiable
challet
2

façon joomla

if (array_key_exists('REQUEST_METHOD', $_SERVER)) die();
Ponceuse
la source
0

Je suggérerais de vérifier si certaines des entrées du tableau $ _SERVER sont définies.

Par exemple:

if (isset($_SERVER['REQUEST_METHOD'])) {
        print "HTTP request\n";
} else {
        print "CLI invocation\n";
}
Rodion
la source
Cela ne fonctionnera pas avec la php-cgiligne de commande, il le définira sur GETpour:php-cgi -f file.php arg1=2
Sebastian
0

Ma méthode préférée:

if (array_key_exists('SHELL', $_ENV)) {
  echo "Console invocation";
}
else {
  echo "HTTP invocation";
}
Travis Beale
la source
0
// Detect CLI calls
define("IS_CLI_CALL",( strcmp(php_sapi_name(),'cli') == 0 ));

if(IS_CLI_CALL){
   //do you stuff here

}
Hắc Huyền Minh
la source
0

Un moyen simple est d'interroger la $argvvariable, (ce que vous ferez probablement pour les paramètres de ligne de commande de toute façon). Même s'il n'y a pas de paramètres $argvrenvoie un tableau vide.

S'il est défini, alors cli a été utilisé. Vous pouvez alors supposer que toutes les autres invocations se font via un serveur Web ou autre.

par exemple:

if (isset($argv)) {
  // Do the cli thing.
}
Lucsan
la source
0

Sur la base de la réponse de Silver Moon ci - dessus , j'utilise cette fonction pour renvoyer les sauts de ligne corrects:

/**
* Linebreak function
* @return "/n" if cli, else return <br>
*/
protected static function lb(){

    return (defined('STDIN') || php_sapi_name() === 'cli' || isset($_ENV['SHELL']) ||
    (empty($_SERVER['REMOTE_ADDR']) && !isset($_SERVER['HTTP_USER_AGENT']) && count($_SERVER['argv']) > 0) ||
    !isset($_SERVER['REQUEST_METHOD'])) ? "\n" : "<br>";

}
a20
la source
0

La bonne réponse à cette question dépend de l'intention réelle qui la sous-tend:

  • Le SAPI est-il le facteur décisif (contexte web ou non)?
  • Ou les informations sont-elles interprétées comme «s'exécutant dans un tty»?

Si le premier les réponses données et les commentaires écrits suffisent pour trouver une solution qui fonctionne.

Dans ce dernier cas, les recettes données ici échoueront si l'outil est exécuté en tant que cronjob, ou en tant que travail d'arrière-plan d'un autre démon - dans ce cas, je suggère de tester davantage s'il STDINs'agit d'un TTY:

function at_tty() {
    return defined("\STDIN") && posix_isatty(\STDIN);
}
Tom Regner
la source
-1

Comment, tant de solutions compliquées. Que diriez-vous ...

if($_SERVER['REQUEST_SCHEME']=="http" or $_SERVER['REQUEST_SCHEME']=="https"){
    // must be browser :)
}
adrianTNT
la source
-18

J'essaierais:

echo exec('whoami');

Habituellement, les serveurs Web sont exécutés sous un nom d'utilisateur différent, donc cela devrait être révélateur.

Stefan Mai
la source