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');
}

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;
}

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.


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

13

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

return (php_sapi_name() === 'cli' OR defined('STDIN'));

6
function is_cli() {
    return !http_response_code();
}

przykład:

if (is_cli()) {
    echo 'command line';
} else {
    echo 'browser';
}

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.


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.


1
Chociaż nie jest to „poprawna” odpowiedź, może być bardziej wiarygodna
— pretendent



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";
}

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";
}

0
// Detect CLI calls
define("IS_CLI_CALL",( strcmp(php_sapi_name(),'cli') == 0 ));

if(IS_CLI_CALL){
   //do you stuff here

}

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.
}

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>";

}

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);
}

-1

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

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

-18

Spróbowałbym:

echo exec('whoami');

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.