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.