PHP - як найкраще визначити, чи є поточне виклик від CLI або веб-сервера?


192

Мені потрібно визначити, чи поточне виклик PHP відбувається з командного рядка (CLI) або з веб-сервера (у моєму випадку Apache з mod_php).

Будь-які рекомендовані методи?


редагував та уточнював питання.
Shameem

Відповіді:


308

php_sapi_nameце функція, яку ви хочете використовувати, оскільки вона повертає рядкові рядки типу інтерфейсу. Крім того, є константа PHP PHP_SAPI.

Документацію можна знайти тут: http://php.net/php_sapi_name

Наприклад, щоб визначити, чи запускається PHP від ​​CLI, ви можете використовувати цю функцію:

function isCommandLineInterface()
{
    return (php_sapi_name() === 'cli');
}

11
Більш прямо:return php_sapi_name() == 'cli';
Савагеман

11
Я зробив дослідження: якщо ви будете викликати сценарій, php-cgiце не спрацює. У свою чергу, він поверне cgi-fcgiString. Якщо ви завантажите скрипт як веб-сторінку з браузера, ви отримаєте apache2handler. Сподіваюся, це допомагає. Мені потрібно використовувати php-cgiдля того , щоб ввести $_GETзмінні: php-cgi myscript.php arg1=one arg2=two. Тестування на не рівне значення apache2handlerповинно бути нормальним apache.
Себастьян

3
Невеликий застереження щодо цього методу: він не повернеться, "cli"коли буде запущено з роботи з кроном. Існує кілька клавіш, які можна вибрати зсередини, $_SERVERщоб визначити надійніше, чи надходив запит через HTTP чи ні.
omninonsense

2
@omninonsense Я перевірив PHP 7.2.7, і він повертає cli.
Хосе Нобіле

38

Я використовую цю функцію вже кілька років

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;ВАТ?
biziclop

@biziclop, array_key_exists('REQUEST_METHOD', $_SERVER)правильність перевірки на предмет виявлення джерела запиту . Коли в CLI , то $_SERVERсупер Global масив НЕ МАЄ ключ REQUEST_METHOD, він існує тільки тоді , коли робиться запит через Інтернет, отже, автор абсолютно на ціль при його перевірці.
Хуліо Марчі

1
@JulioMarchi: але чи не слід це return false;робити чи робити if ( ! array_key_exists(…)) return true;?
бізиклоп

2
@biziclop, ти абсолютно правий !!!! Як я міг пропустити таку величезну маленьку деталь ??? Мені так соромно... :). Звичайно, якщо ключ 'REQUEST_METHOD'буде НЕ знайдений, то функція повинна повертати FALSEвказати «CLI». Мої вибачення за те, що не звернули уваги на сферу самої функції ... Автор повинен це виправити, оскільки функція насправді працює!
Хуліо Марчі

Ця функція працювала в моєму випадку, а не php_sapi_name (), оскільки мені потрібно було розрізняти веб-запити та виконання cronjob, а результат php_sapi_name () був "php-cgi" в обох випадках.
luis.ap.uyen

36

php_sapi_name()насправді не найкращий спосіб здійснити цю перевірку, оскільки це залежить від перевірки проти багатьох можливих значень. Бінарний файл php-cgi можна викликати з командного рядка, із сценарію оболонки або як завдання cron, і (у більшості випадків) вони також повинні трактуватися як "cli", але для php_sapi_name()них повертаються різні значення (зверніть увагу, що це не " t справа в звичайній версії PHP, але ви хочете, щоб ваш код працював де завгодно, правда?). Не кажучи вже про те, що в наступному році можуть з’явитися нові способи використання PHP, про які ми зараз не можемо знати. Я б краще не замислювався над цим, коли все, що мені цікаво, - це погоду, я повинен обернути свої результати в HTML чи ні.

На щастя, PHP має можливість перевірити це конкретно. Просто використовуйте http_response_code()без будь-яких параметрів, і він поверне TRUE, якщо він працює із середовища типу веб-сервера, і FALSE, якщо працює з середовища типу CLI Ось код:

$is_web=http_response_code()!==FALSE;

Це навіть спрацює, якщо ви випадково (?) Встановили код відповіді зі скрипту, запущеного з CLI (або чогось подібного до CLI), перш ніж викликати це.


4
Це питання було вже старим, коли я відповів на нього. Ця відповідь, можливо, була б кориснішою, ніж публікація іншої відповіді, яка є дублікатом, за винятком пояснень.
krowe2

Щодо "Це навіть спрацює, якщо ви випадково (?) Встановили код відповіді зі скрипту, запущеного з CLI ([...]) перед тим, як викликати це.": (Принаймні) станом на PHP 7.4.3, це неправда. http_response_code()встановлює код / ​​повертає набір коду при запуску з CLI. Підтверджено <?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();. Тож якщо http_response_code()===falseтоді надійно вважати CLI, але якщо ні, то вам також потрібно перевірити інші показники.
Себастьян Б.

23

Я думаю, що він має на увазі, якщо викликається PHP CLI або це відповідь з веб-запиту. Найкращим способом було б використання php_sapi_name()якого, якби він запускав веб-запит, відлунюватиме Apache, якщо це те, що він працює.

Щоб перелічити декілька взятих із PHP документів наphp_sapi_name() :

  • aolserver
  • апаш
  • apache2filter
  • apache2handler
  • каудіум
  • cgi (до PHP 5.3)
  • cgi-fcgi
  • клі
  • cli-сервер ( вбудований веб-сервер на PHP 5.4)
  • наступність
  • вбудовувати
  • fpm-fcgi
  • ісапі
  • ближній швидкість
  • мілтер
  • nsapi
  • phttpd
  • pi3web
  • роксен
  • thttpd
  • смокінг
  • webjames

13

Це має вирішувати всі випадки (включаючи php-cgi)

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

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

приклад:

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

2
З посібника "FALSE буде повернуто, якщо код відповіді не надано і він не викликається у середовищі веб-сервера (наприклад, із програми CLI). TRUE буде повернуто, якщо надано код відповіді та не буде викликано його на веб-сервері оточення (але лише тоді, коли попередній статус відповіді не встановлено) ". Ви зрозуміли свою логіку назад.
krowe2

1
+1. Дивовижний. Після стількох років безрезультатних досліджень ... Я цим нагороджую Нобелівську меморіальну премію з PHPics, яку поділився з @ krowe2 за його неоціненний внесок у те, щоб насправді змусити її працювати. Вітаємо!
Sz.

Можливо, щось може встановити код відповіді ... http_response_code(200);... якщо я зараз зателефоную, http_response_code()він поверне 200;
Бред Кент

@BradKent Це ТІЛЬКИ, якщо ви дзвоните це з веб-середовища, і, у такому випадку, ця перевірка все ще буде працювати, доки ви не встановили нульовий код статусу (що так чи інакше є недійсним кодом статусу HTTP). Моя версія буде працювати навіть у тому випадку, оскільки вона спеціально перевіряє FALSE. Якщо http_response_code();виклик із середовища CLI, він завжди поверне FALSE незалежно від фактичного коду статусу. Я вже пояснив це у своїй відповіді, але ви також могли це дізнатись, прочитавши сторінку керівництва у розділі "Повернення значень" або спробувавши її.
krowe2

@ krowe2 php -r 'http_response_code(200); echo http_response_code()."\n";' виводить "200" Якщо ви не зможете гарантувати, що якась бібліотека чи необізнана рамка не встановила код відповіді http_response_code(навіть у cli env), тоді це спрацює. Особисто я використовую$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
Бред Кент

4

Я використав це:

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

Це з кодової бази даних Drush, Environment.inc, де вони мають зробити аналогічну перевірку.


4
Якщо register_argc_argvвстановлено, то передача будь-якої кількості значень GET призведе argcдо не 0.

3

Спробуйте

isset($_SERVER['REQUEST_METHOD'])

якщо це встановлено, ви перебуваєте в браузері.

Крім того, ви можете перевірити, чи немає

isset($_SERVER['argv'])

але це може бути неправдою для Windows CLI, IDK.


1
Хоча це не «правильна» відповідь, це може бути і більш надійним
оскаржуйте



0

Я б запропонував перевірити, чи встановлені деякі записи масиву $ _SERVER .

Наприклад:

if (isset($_SERVER['REQUEST_METHOD'])) {
        print "HTTP request\n";
} else {
        print "CLI invocation\n";
}

Це не працюватиме з php-cgiкомандним рядком, він встановить його GETдля:php-cgi -f file.php arg1=2
Себастьян



0

Простий спосіб - допитати $argvзмінну (Що ви, мабуть, зробите для параметрів командного рядка). Навіть якщо немає параметрів, $argvповертає порожній масив.

Якщо він встановлений, тоді використовувався cli. Тоді ви можете припустити, що всі інші виклики здійснюються через якийсь веб-сервер чи інший.

наприклад:

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

0

Виходячи з відповіді Silver Moon вище , я використовую цю функцію для повернення правильних рядків:

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

Правильна відповідь на це питання залежить від реального наміру, що стоїть за ним:

  • Чи вирішальним фактором є веб-контекст SAPI (веб-контекст чи ні)?
  • Або трактується інформація як "запущена в tty"?

Якщо попередніх відповідей та написаних коментарів достатньо, щоб знайти рішення, яке працює.

Якщо останнє, наведені тут рецепти не зможуть, якщо інструмент запускається як cronjob, або як фонове завдання іншого демона - у такому випадку я пропоную додатково перевірити, чи STDINє TTY:

function at_tty() {
    return defined("\STDIN") && posix_isatty(\STDIN);
}

-1

Як, стільки складних рішень. Як щодо ...

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

-18

Я б спробував:

echo exec('whoami');

Зазвичай веб-сервери працюють під іншим ім'ям користувача, так що це має бути важливо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.