Como determinar melhor se a chamada atual é da CLI ou servidor da web?

Respostas:

308

php_sapi_nameé a função que você deseja usar, pois retorna uma sequência minúscula do tipo de interface. Além disso, há a constante PHP PHP_SAPI.

A documentação pode ser encontrada aqui: http://php.net/php_sapi_name

Por exemplo, para determinar se o PHP está sendo executado na CLI, você pode usar esta função:

function isCommandLineInterface()
{
    return (php_sapi_name() === 'cli');
}
Joe Lencioni
fonte
11
Mais simples:return php_sapi_name() == 'cli';
Savageman
11
Eu fiz uma pesquisa: se você invocar o script com php-cgiisso não funcionará. Por sua vez, ele retornará cgi-fcgiString. Se você carregar o script como uma página da web a partir de um navegador, será possível apache2handler. Espero que isto ajude. Eu precisava usar php-cgipara introduzir $_GETvariáveis: php-cgi myscript.php arg1=one arg2=two. Testar para não igual a apache2handlerdeve estar ok para apache.
Sebastian
3
Uma pequena ressalva sobre esse método: ele não retornará "cli"quando executado a partir de um trabalho cron. Há um número de diferentes chaves para você escolher de dentro $_SERVERpara determinar com mais segurança se a solicitação veio via HTTP ou não.
omninonsense
2
@omninonsense Eu testei com o PHP 7.2.7 e ele retorna cli.
Jose Nobile
38

Uso essa função há alguns anos

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
fonte
10
array_key_exists('REQUEST_METHOD', $_SERVER) return true;WAT?
biziclop
@biziclop, a verificação array_key_exists('REQUEST_METHOD', $_SERVER)está correta para ajudar na detecção da fonte da solicitação . Quando na CLI , a $_SERVERmatriz Super Global NÃO TERÁ a chave REQUEST_METHOD, ela só existe quando a solicitação é feita via Web; portanto, o autor está absolutamente no alvo ao procurá-la.
Julio Marchi
1
@ JulioMarchi: mas não deveria return false;ou deveria if ( ! array_key_exists(…)) return true;?
biziclop
2
@ Biziclop, você está totalmente certo !!!! Como eu poderia desperdiçar estas enorme pequeno detalhe ??? Que vergonha... :). Certamente, se a CHAVE NÃO'REQUEST_METHOD' for encontrada, a função deverá retornar para indicar "CLI". Peço desculpas por não prestar atenção ao escopo da própria função ... O autor deve corrigi-lo porque a função realmente funciona! FALSE
Julio Marchi
Essa função funcionou no meu caso, não php_sapi_name (), pois eu precisava distinguir entre solicitações da web e execuções de cronjob, e o resultado php_sapi_name () foi "php-cgi" nos dois casos.
Luis.ap.uyen
36

php_sapi_name()realmente não é a melhor maneira de executar essa verificação, pois depende da verificação de muitos valores possíveis. O binário php-cgi pode ser chamado a partir da linha de comando, de um script shell ou como um trabalho cron e (na maioria dos casos) eles também devem ser tratados como 'cli', mas php_sapi_name()retornarão valores diferentes para eles (observe que isso não é '' o caso da versão simples do PHP, mas você deseja que seu código funcione em qualquer lugar, certo?). Sem mencionar que no próximo ano poderá haver novas maneiras de usar PHP que não podemos saber agora. Prefiro não pensar nisso, quando tudo que me interessa é o clima, devo incluir minha saída em HTML ou não.

Felizmente, o PHP tem uma maneira de verificar isso especificamente. Basta usar http_response_code()sem nenhum parâmetro e ele retornará TRUE se executado em um ambiente do tipo servidor da web e FALSE se executado em um ambiente do tipo CLI. Aqui está o código:

$is_web=http_response_code()!==FALSE;

Isso funcionará mesmo se você acidentalmente (?) Definir um código de resposta de um script em execução na CLI (ou algo como a CLI) antes de chamá-lo.

krowe2
fonte
4
Esta questão já era antiga quando a respondi. A votação antecipada desta resposta provavelmente teria sido mais útil do que postar outra resposta duplicada, exceto sem a explicação.
krowe2
Com relação a "Isso funcionará mesmo se você acidentalmente (?) Definir um código de resposta de um script executado na CLI [...] (...) antes de chamá-lo.": (Pelo menos) a partir do PHP 7.4.3, isso é Não é verdade. http_response_code()define código / retorna código definido ao executar a partir da CLI. Verificado por <?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();. Portanto, se http_response_code()===falseé uma aposta segura assumir o CLI, mas se não, você precisa verificar também outras métricas.
Sebastian B.
23

Eu acho que ele quer dizer se o PHP CLI está sendo chamado ou se é uma resposta de uma solicitação da web. A melhor maneira seria usar o php_sapi_name()que, se estivesse executando uma solicitação da Web, ecoaria o Apache se era isso que estava executando.

Para listar algumas extraídas dos documentosphp_sapi_name() php em :

  • aolserver
  • apache
  • apache2filter
  • apache2handler
  • caudium
  • cgi (até PHP 5.3)
  • cgi-fcgi
  • cli
  • cli-server (servidor web embutido a partir do PHP 5.4)
  • continuidade
  • Embutir
  • fpm-fcgi
  • isapi
  • litespeed
  • milter
  • nsapi
  • phttpd
  • pi3web
  • Roxen
  • thttpd
  • smoking
  • webjames
Marc Towler
fonte
13

Isso deve lidar com todos os casos (incluindo php-cgi)

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

exemplo:

if (is_cli()) {
    echo 'command line';
} else {
    echo 'browser';
}
Terry Lin
fonte
2
No manual, "FALSE será retornado se o response_code não for fornecido e não for invocado em um ambiente de servidor da web (como em um aplicativo CLI). TRUE será retornado se o response_code for fornecido e não for invocado em um servidor da web ambiente (mas apenas quando nenhum status de resposta anterior foi definido) ". Você conseguiu sua lógica de trás para frente.
krowe2
1
+1. Surpreendente. Depois de tantos anos de pesquisa infrutífera ... por meio deste, concedo a você o Prêmio Nobel Memorial em PHPics, compartilhado com @ krowe2 por sua inestimável contribuição de realmente fazê-lo funcionar. Parabéns!
Sz.
É possível que algo tenha definido o código de resposta ... http_response_code(200);... se eu ligar agora, http_response_code()ele retornará 200;
Brad Kent
@BradKent APENAS se você chamar isso de um ambiente web e, nesse caso, essa verificação ainda funcionará desde que você não tenha definido o código de status como zero (que é um código de status HTTP inválido). Minha versão funcionará mesmo nesse caso, porque verifica especificamente contra FALSE. Se http_response_code();for chamado de um ambiente CLI, ele sempre retornará FALSE, independentemente do código de status real. Eu já expliquei isso na minha resposta, mas você também pode descobrir isso lendo a página do manual em "Return Values" ou tentando.
precisa saber é o seguinte
@ krowe2 php -r 'http_response_code(200); echo http_response_code()."\n";' produz "200" A menos que você possa garantir que alguma biblioteca ou estrutura ignorante não tenha definido o código de resposta http_response_code(mesmo em um ambiente CLI), isso funcionará. Pessoalmente, eu uso$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
Brad Kent
4

Eu usei isso:

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

Isto é da base de código Drush, environment.inc, onde eles têm verificação semelhante a fazer.

Ranjan
fonte
4
Se register_argc_argvestiver definido, a passagem de qualquer quantidade de valores GET fará com argcque não seja 0. #
3

Experimentar

isset($_SERVER['REQUEST_METHOD'])

se estiver definido, você está em um navegador.

Como alternativa, você pode verificar se

isset($_SERVER['argv'])

mas isso pode não ser verdade no Windows CLI, IDK.

gnud
fonte
1
Embora não seja a "correta" responder que poderia ser o mais confiável
challet
2

Joomla Way

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

Eu sugeriria verificar se algumas das entradas da matriz $ _SERVER estão definidas.

Por exemplo:

if (isset($_SERVER['REQUEST_METHOD'])) {
        print "HTTP request\n";
} else {
        print "CLI invocation\n";
}
rodion
fonte
Isto irá não trabalho com php-cgilinha de comando, ele irá configurá-lo para GETpara:php-cgi -f file.php arg1=2
Sebastian
0

Meu método preferido:

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

Uma maneira fácil é interrogar a $argvvariável (o que você provavelmente fará para os parâmetros da linha de comando). Mesmo se não houver parâmetros, $argvretorna uma matriz vazia.

Se estiver definido, o cli foi usado. Você pode então assumir que todas as outras invocações são feitas através de um servidor web ou outro.

por exemplo:

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

Com base na resposta de Silver Moon acima , estou usando esta função para retornar quebras de linha corretas:

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

A resposta correta para esta pergunta depende da intenção real por trás dela:

  • O SAPI é o fator decisivo (contexto da Web ou não)?
  • Ou a informação é interpretada como 'executando em um tty'?

Se o primeiro, as respostas e os comentários escritos são suficientes para encontrar uma solução que funcione.

Neste último caso, as receitas fornecidas aqui falharão se a ferramenta for executada como cronjob ou como trabalho em segundo plano de outro daemon - nesse caso, sugiro testar mais se STDINé um TTY:

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

Como, tantas soluções complicadas. E se ...

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

Eu tentaria:

echo exec('whoami');

Normalmente, os servidores da web são executados com um nome de usuário diferente, o que deve ser revelador.

Stefan Mai
fonte