PHP - Wie kann am besten festgestellt werden, ob der aktuelle Aufruf von einer CLI oder einem Webserver stammt?

Antworten:

308

php_sapi_nameist die Funktion, die Sie verwenden möchten, da sie eine Kleinbuchstabenzeichenfolge des Schnittstellentyps zurückgibt. Zusätzlich gibt es die PHP-Konstante PHP_SAPI.

Die Dokumentation finden Sie hier: http://php.net/php_sapi_name

Um beispielsweise festzustellen, ob PHP über die CLI ausgeführt wird, können Sie folgende Funktion verwenden:

function isCommandLineInterface()
{
    return (php_sapi_name() === 'cli');
}
Joe Lencioni
quelle
11
return php_sapi_name() == 'cli';
Einfacher
11
Ich habe nachgeforscht: Wenn Sie das Skript damit aufrufen, php-cgifunktioniert dies nicht. Im Gegenzug wird cgi-fcgiString zurückgegeben. Wenn Sie das Skript als Webseite aus einem Browser laden, erhalten Sie apache2handler. Hoffe das hilft. Ich musste verwenden, php-cgium $_GETVariablen einzuführen : php-cgi myscript.php arg1=one arg2=two. Das Testen auf ungleich apache2handlersollte für sollte in Ordnung sein apache.
Sebastian
3
Eine kleine Einschränkung zu dieser Methode: Sie wird nicht zurückgegeben, "cli"wenn sie von einem Cron-Job ausgeführt wird. Es gibt eine Reihe verschiedener Schlüssel, aus denen Sie auswählen können $_SERVER, um zuverlässiger zu bestimmen, ob die Anforderung über HTTP eingegangen ist oder nicht.
Omninonsense
2
@omninonsense Ich habe mit PHP 7.2.7 getestet und es gibt cli zurück.
Jose Nobile
38

Ich benutze diese Funktion seit einigen Jahren

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
quelle
10
array_key_exists('REQUEST_METHOD', $_SERVER) return true;WAT?
Biziclop
@biziclop, die Überprüfung auf array_key_exists('REQUEST_METHOD', $_SERVER)ist korrekt, um die Erkennung der Quelle der Anforderung zu unterstützen . In der CLI HAT das $_SERVERSuper Global-Array den Schlüssel NICHTREQUEST_METHOD , es existiert nur, wenn die Anforderung über das Web erfolgt. Daher ist der Autor bei der Suche nach dem Schlüssel absolut im Ziel.
Julio Marchi
1
@ JulioMarchi: aber sollte es nicht return false;oder tun if ( ! array_key_exists(…)) return true;?
Biziclop
2
@biziclop, du hast vollkommen recht !!!! Wie könnte ich so ein riesiges kleines Detail vermissen ??? Schande über mich... :). Sicherlich, wenn der Schlüssel 'REQUEST_METHOD'wird nicht gefunden, dann sollte die Funktion zurückgeben FALSE„CLI“ anzuzeigen. Ich entschuldige mich dafür, dass ich den Umfang der Funktion selbst nicht beachtet habe ... Der Autor sollte das Problem beheben, da die Funktion tatsächlich funktioniert!
Julio Marchi
Diese Funktion funktionierte in meinem Fall nicht mit php_sapi_name (), da ich zwischen Webanforderungen und Cronjob-Ausführungen unterscheiden musste und das Ergebnis von php_sapi_name () in beiden Fällen "php-cgi" war.
luis.ap.uyen
35

php_sapi_name()ist wirklich nicht der beste Weg, um diese Prüfung durchzuführen, da dies von der Prüfung anhand vieler möglicher Werte abhängt. Die php-cgi-Binärdatei kann über die Befehlszeile, über ein Shell-Skript oder als Cron-Job aufgerufen werden. In den meisten Fällen sollten diese auch als 'cli' behandelt werden, geben jedoch php_sapi_name()unterschiedliche Werte für diese zurück (beachten Sie, dass dies nicht der Fall ist). Dies ist bei der einfachen Version von PHP nicht der Fall, aber Sie möchten, dass Ihr Code überall funktioniert, oder?). Ganz zu schweigen davon, dass es nächstes Jahr möglicherweise neue Möglichkeiten gibt, PHP zu verwenden, die wir derzeit unmöglich kennen. Ich würde lieber nicht darüber nachdenken, wenn alles, was mich interessiert, das Wetter ist, sollte ich meine Ausgabe in HTML einwickeln oder nicht.

Glücklicherweise hat PHP eine Möglichkeit, dies speziell zu überprüfen. Verwenden Sie einfach http_response_code()ohne Parameter und es wird TRUE zurückgegeben, wenn es von einer Umgebung vom Typ Webserver ausgeführt wird, und FALSE, wenn es von einer Umgebung vom Typ CLI ausgeführt wird. Hier ist der Code:

$is_web=http_response_code()!==FALSE;

Dies funktioniert sogar, wenn Sie versehentlich (?) Einen Antwortcode aus einem Skript festgelegt haben, das über die CLI (oder etwas Ähnliches wie die CLI) ausgeführt wird, bevor Sie dies aufrufen.

krowe2
quelle
4
Diese Frage war schon alt, als ich sie beantwortete. Das Up-Voting dieser Antwort wäre wahrscheinlich nützlicher gewesen, als eine andere Antwort zu veröffentlichen, die ein Duplikat ist, außer ohne die Erklärung.
Krowe2
Zu "Dies funktioniert sogar, wenn Sie versehentlich (?) Einen Antwortcode aus einem Skript festgelegt haben, das über die CLI ([...]) ausgeführt wird, bevor Sie dies aufrufen.": (Zumindest) ab PHP 7.4.3 nicht wahr. http_response_code()Setzt den Code / gibt den Set-Code zurück, wenn er über die CLI ausgeführt wird. Verifiziert von <?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();. Wenn dies der http_response_code()===falseFall ist, ist es sicher, eine CLI anzunehmen, aber wenn nicht, müssen Sie auch andere Metriken überprüfen.
Sebastian B.
23

Ich denke, er meint, wenn PHP CLI aufgerufen wird oder wenn es eine Antwort von einer Webanforderung ist. Der beste Weg wäre, zu verwenden, php_sapi_name()was, wenn es eine Webanforderung ausführt, Apache wiedergibt, wenn es das ist, was es ausgeführt wird.

Um einige der PHP- Dokumente aufzulistenphp_sapi_name() :

  • aolserver
  • Apache
  • apache2filter
  • apache2handler
  • Caudium
  • cgi (bis PHP 5.3)
  • cgi-fcgi
  • cli
  • Cli-Server ( Eingebauter Webserver ab PHP 5.4)
  • Kontinuität
  • einbetten
  • fpm-fcgi
  • Isapi
  • Litespeed
  • milter
  • nsapi
  • phttpd
  • pi3web
  • Roxen
  • thttpd
  • Smoking
  • Webjames
Marc Towler
quelle
13

Dies sollte alle Fälle behandeln (einschließlich php-cgi)

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

Beispiel:

if (is_cli()) {
    echo 'command line';
} else {
    echo 'browser';
}
Terry Lin
quelle
2
Aus dem Handbuch geht hervor, dass "FALSE" zurückgegeben wird, wenn "response_code" nicht angegeben und in einer Webserverumgebung (z. B. von einer CLI-Anwendung) nicht aufgerufen wird. TRUE wird zurückgegeben, wenn "response_code" bereitgestellt und auf einem Webserver nicht aufgerufen wird Umgebung (aber nur, wenn kein vorheriger Antwortstatus festgelegt wurde) ". Sie haben Ihre Logik rückwärts gebracht.
Krowe2
1
+1. Tolle. Nach so vielen Jahren erfolgloser Forschung ... vergebe ich Ihnen hiermit den Nobelpreis für PHPics, der an @ krowe2 für seinen unschätzbaren Beitrag zur tatsächlichen Umsetzung weitergegeben wird. Herzliche Glückwünsche!
Gr.
Es ist möglich, dass etwas den Antwortcode festgelegt hat ... http_response_code(200);... wenn ich jetzt anrufe http_response_code(), wird 200 zurückgegeben;
Brad Kent
@BradKent Dies ist NUR dann der Fall, wenn Sie dies aus einer Webumgebung aufrufen. In diesem Fall funktioniert diese Prüfung weiterhin, solange Sie den Statuscode nicht auf Null gesetzt haben (was ohnehin ein ungültiger HTTP-Statuscode ist). Meine Version funktioniert auch in diesem Fall, da sie speziell gegen FALSE prüft. Wenn http_response_code();es aus einer CLI-Umgebung aufgerufen wird, wird unabhängig vom tatsächlichen Statuscode immer FALSE zurückgegeben. Ich habe dies bereits in meiner Antwort erklärt, aber Sie hätten dies auch herausfinden können, indem Sie die Handbuchseite unter "Rückgabewerte" gelesen oder es ausprobiert haben.
Krowe2
@ krowe2 php -r 'http_response_code(200); echo http_response_code()."\n";' gibt "200" aus Wenn Sie nicht garantieren können, dass eine Bibliothek oder ein ignorantes Framework den Antwortcode nicht festgelegt hat http_response_code(auch nicht in einer CLI-Umgebung), funktioniert dies. Persönlich benutze ich$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
Brad Kent
4

Ich habe das benutzt:

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

Dies ist von Drush Codebasis, environment.inc, wo sie ähnliche Prüfungen durchführen müssen.

Ranjan
quelle
4
Wenn register_argc_argvgesetzt, wird die Übergabe einer beliebigen Anzahl von GET-Werten dazu führen argc, dass nicht 0 ist.
3

Versuchen

isset($_SERVER['REQUEST_METHOD'])

Wenn es eingestellt ist, befinden Sie sich in einem Browser.

Alternativ können Sie überprüfen, ob

isset($_SERVER['argv'])

Dies ist jedoch unter Windows CLI, IDK möglicherweise nicht der Fall.

Gnud
quelle
1
Obwohl es nicht die "richtige" Antwort ist, könnte es die zuverlässigere sein
Challet
2

Laut http://jp2.php.net/manual/en/features.commandline.php Es gibt eine Reihe von Konstanten, die nur festgelegt werden, wenn sie über die CLI ausgeführt werden. Diese Konstanten sind STDIN, STDOUT und STDERR. Wenn Sie einen dieser Tests durchführen, werden Sie feststellen, ob er sich im CLI-Modus befindet

Jonathan Fingland
quelle
2

Joomla Weg

if (array_key_exists('REQUEST_METHOD', $_SERVER)) die();
Sander
quelle
0

Ich würde vorschlagen, zu überprüfen, ob einige der Einträge des Arrays $ _SERVER gesetzt sind.

Z.B:

if (isset($_SERVER['REQUEST_METHOD'])) {
        print "HTTP request\n";
} else {
        print "CLI invocation\n";
}
rodion
quelle
Dies funktioniert nicht mit der php-cgiKommandozeile, es wird eingestellt GETfür:php-cgi -f file.php arg1=2
Sebastian
0

Meine bevorzugte Methode:

if (array_key_exists('SHELL', $_ENV)) {
  echo "Console invocation";
}
else {
  echo "HTTP invocation";
}
Travis Beale
quelle
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
quelle
0

Eine einfache Möglichkeit besteht darin, die $argvVariable abzufragen (was Sie wahrscheinlich sowieso für Befehlszeilenparameter tun werden). Auch wenn keine Parameter vorhanden sind, wird $argvein leeres Array zurückgegeben.

Wenn es gesetzt ist, wurde cli verwendet. Sie können dann davon ausgehen, dass alle anderen Aufrufe über einen oder andere Webserver erfolgen.

z.B:

if (isset($argv)) {
  // Do the cli thing.
}
lucsan
quelle
0

Basierend auf der obigen Antwort von Silver Moon verwende ich diese Funktion, um korrekte Zeilenumbrüche zurückzugeben:

/**
* 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
quelle
0

Die richtige Antwort auf diese Frage hängt von der tatsächlichen Absicht ab:

  • Ist der SAPI der entscheidende Faktor (Webkontext oder nicht)?
  • Oder werden die Informationen als "Laufen in einem tty" interpretiert?

Wenn erstere, reichen die gegebenen Antworten und Kommentare aus, um eine Lösung zu finden, die funktioniert.

In letzterem Fall schlagen die hier angegebenen Rezepte fehl, wenn das Tool als Cronjob oder als Hintergrundjob von einem anderen Daemon ausgeführt wird. In diesem Fall empfehle ich, weiter zu testen, ob STDINes sich um ein TTY handelt:

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

Wie viele komplizierte Lösungen. Wie wäre es mit ...

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

Ich würde versuchen:

echo exec('whoami');

Normalerweise werden Webserver unter einem anderen Benutzernamen ausgeführt, daher sollte dies aussagekräftig sein.

Stefan Mai
quelle