PHP - jak najlepiej ustalić, czy bieżące wywołanie pochodzi z CLI czy serwera WWW?

Odpowiedzi:

308

php_sapi_namejest funkcją, której będziesz chciał użyć, ponieważ zwraca ciąg znaków małymi literami typu interfejsu. Ponadto istnieje stała PHP PHP_SAPI.

Dokumentację można znaleźć tutaj: http://php.net/php_sapi_name

Na przykład, aby ustalić, czy PHP jest uruchamiane z interfejsu CLI, możesz użyć tej funkcji:

function isCommandLineInterface()
{
    return (php_sapi_name() === 'cli');
}
Joe Lencioni
źródło
11
Bardziej proste:return php_sapi_name() == 'cli';
Savageman,
11
Zrobiłem badanie: jeśli wywołasz skrypt z php-cgitym, to nie zadziała. Z kolei zwróci cgi-fcgiString. Jeśli załadujesz skrypt jako stronę internetową z przeglądarki, otrzymasz apache2handler. Mam nadzieję że to pomoże. Musiałem użyć php-cgiw celu wprowadzenia $_GETzmiennych: php-cgi myscript.php arg1=one arg2=two. Testowanie na wartość nie równą apache2handlerpowinno być w porządku apache.
Sebastian
3
Małe zastrzeżenie dotyczące tej metody: nie wróci "cli"po uruchomieniu z zadania cron. Istnieje wiele różnych kluczy do wyboru w $_SERVERcelu bardziej niezawodnego określenia, czy żądanie zostało wysłane przez HTTP, czy nie.
omninonsense
2
@ omninonsense Testowałem z PHP 7.2.7 i zwraca cli.
Jose Nobile
38

Korzystam z tej funkcji od kilku lat

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
źródło
10
array_key_exists('REQUEST_METHOD', $_SERVER) return true;WAT
biziclop
@biziclop, pole wyboru array_key_exists('REQUEST_METHOD', $_SERVER)jest poprawne, aby ułatwić wykrycie źródła żądania . Kiedy w CLI The $_SERVERtablica Super globalna nie ma klucza REQUEST_METHOD, to istnieje tylko wtedy, gdy wniosek został złożony za pośrednictwem sieci, a więc autor jest absolutnie na celu sprawdzenie, kiedy do niego.
Julio Marchi,
1
@JulioMarchi: ale czy nie powinno to return false;zrobić if ( ! array_key_exists(…)) return true;?
biziclop
2
@biziclop, masz całkowitą rację !!!! Jak mogłem przeoczyć tak ogromne szczegóły? Wstyd mi ... :). Z pewnością, jeśli NIE'REQUEST_METHOD' zostanie znaleziony KLUCZ , funkcja powinna wrócić, aby wskazać „CLI”. Przepraszam, że nie zwróciłem uwagi na zakres samej funkcji ... Autor powinien to naprawić, ponieważ funkcja faktycznie działa! FALSE
Julio Marchi,
Ta funkcja działała w moim przypadku, a nie php_sapi_name (), ponieważ musiałem rozróżniać żądania sieciowe i wykonania cronjob, a wynikiem php_sapi_name () w obu przypadkach było „php-cgi”.
luis.ap.uyen
36

php_sapi_name()naprawdę nie jest najlepszym sposobem na wykonanie tej kontroli, ponieważ zależy od sprawdzenia wielu możliwych wartości. Plik binarny php-cgi można wywołać z wiersza poleceń, ze skryptu powłoki lub jako zadanie cron i (w większości przypadków) powinny one być również traktowane jako „cli”, ale php_sapi_name()zwracają dla nich różne wartości (zwróć uwagę, że to nie jest ” t przypadku zwykłej wersji PHP, ale chcesz, aby Twój kod działał w dowolnym miejscu, prawda?). Nie wspominając już o tym, że w przyszłym roku mogą istnieć nowe sposoby korzystania z PHP, których nie znamy teraz. Wolałbym o tym nie myśleć, gdy jedyne, na czym mi zależy, to pogoda. Powinienem zawinąć swoje wyniki w HTML, czy nie.

Na szczęście PHP ma sposób, aby to sprawdzić. Po prostu użyj http_response_code()bez żadnych parametrów, a zwróci PRAWDA, jeśli jest uruchamiany ze środowiska typu serwera WWW, lub FALSE, jeśli jest uruchamiany ze środowiska typu CLI. Oto kod:

$is_web=http_response_code()!==FALSE;

Działa to nawet, jeśli przypadkowo (?) Ustawisz kod odpowiedzi ze skryptu uruchomionego z CLI (lub czegoś takiego jak CLI) przed wywołaniem tego.

krowe2
źródło
4
To pytanie było już stare, kiedy na nie odpowiedziałem. Głosowanie w górę tej odpowiedzi prawdopodobnie byłoby bardziej przydatne niż opublikowanie innej odpowiedzi, która jest duplikatem, chyba że bez wyjaśnienia.
krowe2
Odnośnie „To zadziała nawet, jeśli przypadkowo (?) Ustawisz kod odpowiedzi ze skryptu uruchomionego z CLI ([...]) przed wywołaniem tego.”: (Przynajmniej) od PHP 7.4.3, to jest nie prawda. http_response_code()ustawia kod / zwraca ustawiony kod podczas uruchamiania z CLI. Zweryfikowany przez <?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();. Jeśli http_response_code()===falsewięc to bezpiecznie założyć CLI, ale jeśli nie, musisz sprawdzić również inne wskaźniki.
Sebastian B.
23

Myślę, że ma na myśli to, czy PHP CLI jest wywoływane, czy jest to odpowiedź z żądania sieciowego. Najlepszym sposobem byłoby użycie tego, php_sapi_name()który gdyby uruchomił żądanie WWW, powtórzyłby Apache, jeśli tak właśnie działało.

Aby wyświetlić listę kilku dokumentówphp_sapi_name() php :

  • aolserver
  • apacz
  • apache2filter
  • apache2handler
  • ogon
  • cgi (do PHP 5.3)
  • cgi-fcgi
  • cli
  • cli-server ( Wbudowany serwer WWW od PHP 5.4)
  • ciągłość
  • osadzać
  • fpm-fcgi
  • isapi
  • litespeed
  • mleczak
  • nsapi
  • phttpd
  • pi3web
  • roxen
  • thttpd
  • smoking
  • gry internetowe
Marc Towler
źródło
13

To powinno obsłużyć wszystkie przypadki (w tym php-cgi)

return (php_sapi_name() === 'cli' OR defined('STDIN'));
rbawaskar
źródło
6
function is_cli() {
    return !http_response_code();
}

przykład:

if (is_cli()) {
    echo 'command line';
} else {
    echo 'browser';
}
Terry Lin
źródło
2
Z instrukcji „FALSE zostanie zwrócone, jeśli kod odpowiedzi nie zostanie podany i nie zostanie wywołany w środowisku serwera WWW (np. Z aplikacji CLI). PRAWDA zostanie zwrócona, jeśli kod odpowiedzi zostanie podany i nie zostanie wywołany na serwerze WWW środowisko (ale tylko wtedy, gdy nie ustawiono wcześniejszego stanu odpowiedzi) ". Masz swoją logikę do tyłu.
krowe2
1
+1. Niesamowity. Po tylu latach bezowocnych badań ... Niniejszym przyznam Wam Nagrodę Nobla w dziedzinie PHPics, udostępnioną @ @ krowe2 za jego nieoceniony wkład w sprawienie, aby działał. Gratulacje!
Sz.
Możliwe, że coś ustawiło kod odpowiedzi ... http_response_code(200);... jeśli teraz zadzwonię http_response_code(), zwróci 200;
Brad Kent
@BradKent To TYLKO, jeśli wywołasz to ze środowiska internetowego, a w takim przypadku ta kontrola będzie nadal działać, dopóki nie ustawisz kodu stanu na zero (co i tak jest nieprawidłowym kodem statusu HTTP). Moja wersja będzie działać nawet w takim przypadku, ponieważ sprawdza się w szczególności na FAŁSZ. Jeśli http_response_code();jest wywoływana z CLI środowisko zawsze będzie return false niezależnie od rzeczywistego kodu statusu. Wyjaśniłem to już w mojej odpowiedzi, ale możesz to również znaleźć, czytając stronę podręcznika pod „Zwracane wartości” lub wypróbowując.
krowe2
@ krowe2 php -r 'http_response_code(200); echo http_response_code()."\n";' wypisuje „200” O ile nie możesz zagwarantować, że niektóre biblioteki lub środowisko ignorujące nie ustawiło kodu odpowiedzi http_response_code(nawet w środowisku cli), to zadziała. Osobiście używam$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
Brad Kent
4

Użyłem tego:

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

Pochodzi z bazy kodu Drush, environment.inc, gdzie mają podobną kontrolę do wykonania.

Ranjan
źródło
4
Jeśli register_argc_argvjest ustawiony, to przekazanie dowolnej liczby wartości GET spowoduje, że argcnie będzie wynosić 0.
3

Próbować

isset($_SERVER['REQUEST_METHOD'])

jeśli jest ustawiony, jesteś w przeglądarce.

Alternatywnie możesz sprawdzić, czy

isset($_SERVER['argv'])

ale może nie być to prawdą w Windows CLI, IDK.

gnud
źródło
1
Chociaż nie jest to „poprawna” odpowiedź, może być bardziej wiarygodna
pretendent
2

sposób Joomla

if (array_key_exists('REQUEST_METHOD', $_SERVER)) die();
Szlifierka
źródło
0

Sugerowałbym sprawdzenie, czy niektóre wpisy w tablicy $ _SERVER są ustawione.

Na przykład:

if (isset($_SERVER['REQUEST_METHOD'])) {
        print "HTTP request\n";
} else {
        print "CLI invocation\n";
}
rodion
źródło
To nie będzie działać z php-cgiwierszem poleceń, ustawi to GETna:php-cgi -f file.php arg1=2
Sebastian
0

Moja preferowana metoda:

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

Prostym sposobem jest przesłuchanie $argvzmiennej (co prawdopodobnie zrobisz dla parametrów wiersza poleceń). Nawet jeśli nie ma parametrów, $argvzwraca pustą tablicę.

Jeśli jest ustawiony, użyto cli. Następnie możesz założyć, że wszystkie inne wywołania są wysyłane przez jakiś serwer WWW lub inny.

na przykład:

if (isset($argv)) {
  // Do the cli thing.
}
Lucsan
źródło
0

Na podstawie powyższej odpowiedzi Silver Moon używam tej funkcji do zwracania poprawnych podziałów linii:

/**
* 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
źródło
0

Prawidłowa odpowiedź na to pytanie zależy od prawdziwych intencji:

  • Czy SAPI jest czynnikiem decydującym (kontekst internetowy czy nie)?
  • Czy informacje są interpretowane jako „uruchomione w tty”?

Jeśli to pierwsze, podane odpowiedzi i komentarze wystarczą, aby znaleźć rozwiązanie, które działa.

Jeśli to drugie, podane tutaj przepisy nie powiodą się, jeśli narzędzie zostanie uruchomione jako kronika lub zadanie w tle z innego demona - w takim przypadku sugeruję dalsze sprawdzenie, czy STDINjest to TTY:

function at_tty() {
    return defined("\STDIN") && posix_isatty(\STDIN);
}
Tom Regner
źródło
-1

Jak wiele skomplikowanych rozwiązań. Co powiesz na ...

if($_SERVER['REQUEST_SCHEME']=="http" or $_SERVER['REQUEST_SCHEME']=="https"){
    // must be browser :)
}
adrianTNT
źródło
-18

Spróbowałbym:

echo exec('whoami');

Zwykle serwery są uruchamiane pod inną nazwą użytkownika, więc to powinno powiedzieć.

Stefan Mai
źródło