PHP - làm thế nào để xác định tốt nhất nếu lời gọi hiện tại là từ CLI hoặc máy chủ web?


Câu trả lời:


308

php_sapi_namelà chức năng bạn sẽ muốn sử dụng vì nó trả về một chuỗi chữ thường của loại giao diện. Ngoài ra, có hằng số PHP PHP_SAPI.

Tài liệu có thể được tìm thấy ở đây: http://php.net/php_sapi_name

Ví dụ: để xác định xem PHP có đang được chạy từ CLI hay không, bạn có thể sử dụng chức năng này:

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

11
Nói thẳng hơn:return php_sapi_name() == 'cli';
Savageman

11
Tôi đã làm một nghiên cứu: nếu bạn gọi kịch bản với php-cgiđiều này sẽ không hoạt động. Đổi lại, nó sẽ trả về cgi-fcgiString. Nếu bạn tải tập lệnh dưới dạng trang web từ trình duyệt, bạn sẽ nhận được apache2handler. Hi vọng điêu nay co ich. Tôi cần sử dụng php-cgiđể giới thiệu $_GETcác biến : php-cgi myscript.php arg1=one arg2=two. Kiểm tra cho không bằng apache2handlernên được ok cho apache.
Sebastian

3
Một cảnh báo nhỏ về phương pháp này: nó sẽ không trở lại "cli"khi chạy từ công việc định kỳ. Có một số khóa khác nhau để chọn từ bên trong $_SERVERđể xác định đáng tin cậy hơn liệu yêu cầu có đến qua HTTP hay không.
omninonsense

2
@omninonsense Tôi đã thử nghiệm với PHP 7.2.7 và nó trả về cli.
Jose Nobile

38

Tôi đã sử dụng chức năng này trong một vài năm

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;BÌNH THƯỜNG?
biziclop

@biziclop, kiểm tra array_key_exists('REQUEST_METHOD', $_SERVER)chính xác để hỗ trợ phát hiện nguồn yêu cầu . Khi ở CLI , $_SERVERmảng Super Global KHÔNG CÓ khóa REQUEST_METHOD, nó chỉ tồn tại khi yêu cầu được thực hiện qua Web, do đó, tác giả hoàn toàn nhắm mục tiêu khi kiểm tra nó.
Julio Marchi

1
@JulioMarchi: nhưng không nên return false;hay làm gì if ( ! array_key_exists(…)) return true;?
biziclop

2
@biziclop, bạn hoàn toàn đúng !!!! Làm thế nào tôi có thể bỏ lỡ như vậy khổng lồ chi tiết nhỏ ??? Thật xấu hổ cho tôi ... :). Chắc chắn, nếu KEY 'REQUEST_METHOD'KHÔNG được tìm thấy, thì hàm sẽ trả về FALSEđể chỉ "CLI". Tôi xin lỗi vì đã không chú ý đến phạm vi của chính chức năng ... Tác giả nên sửa nó vì chức năng thực sự hoạt động!
Julio Marchi

Hàm này hoạt động trong trường hợp của tôi, không phải php_sapi_name (), vì tôi cần phân biệt giữa yêu cầu web và thực thi cronjob và kết quả php_sapi_name () là "php-cgi" trong cả hai trường hợp.
luis.ap.uyen

35

php_sapi_name()thực sự không phải là cách tốt nhất để thực hiện kiểm tra này bởi vì nó phụ thuộc vào việc kiểm tra đối với nhiều giá trị có thể. Nhị phân php-cgi có thể được gọi từ dòng lệnh, từ tập lệnh shell hoặc như một công việc định kỳ và (trong hầu hết các trường hợp) chúng cũng nên được coi là 'cli' nhưng php_sapi_name()sẽ trả về các giá trị khác nhau cho những điều này (lưu ý rằng đây không phải là ' Trường hợp với phiên bản đơn giản của PHP nhưng bạn muốn mã của mình hoạt động ở bất cứ đâu, phải không?). Chưa kể rằng năm tới có thể có những cách mới để sử dụng PHP mà bây giờ chúng ta không thể biết. Tôi không muốn nghĩ về điều đó khi tất cả những gì tôi quan tâm là thời tiết tôi có nên bọc đầu ra của mình bằng HTML hay không.

May mắn thay, PHP có một cách để kiểm tra cụ thể. Chỉ cần sử dụng http_response_code()mà không có bất kỳ tham số nào và nó sẽ trả về TRUE nếu được chạy từ môi trường loại máy chủ web và FALSE nếu được chạy từ môi trường loại CLI. Đây là mã:

$is_web=http_response_code()!==FALSE;

Điều này thậm chí sẽ hoạt động nếu bạn vô tình (?) Đặt mã phản hồi từ tập lệnh chạy từ CLI (hoặc một cái gì đó giống như CLI) trước khi bạn gọi nó.


4
Câu hỏi này đã cũ khi tôi trả lời nó. Bỏ phiếu lên câu trả lời này có lẽ sẽ hữu ích hơn là đăng một câu trả lời khác trùng lặp trừ khi không có lời giải thích.
krowe2

Về "Điều này thậm chí sẽ hoạt động nếu bạn vô tình (?) Đặt mã phản hồi từ tập lệnh chạy từ CLI ([...]) trước khi bạn gọi điều này.": (Ít nhất) kể từ PHP 7.4.3, đây là không đúng. http_response_code()đặt mã / trả về mã đặt khi chạy từ CLI. Xác minh bởi <?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();. Vì vậy, nếu http_response_code()===falsesau đó, bạn nên đặt cược an toàn để giả sử CLI, nhưng nếu không, bạn cần kiểm tra các số liệu khác.
Sebastian B.

23

Tôi nghĩ rằng anh ta có nghĩa là nếu PHP CLI đang được gọi hoặc nếu đó là một phản hồi từ một yêu cầu web. Cách tốt nhất là sử dụng php_sapi_name()nếu nó đang chạy một yêu cầu web sẽ lặp lại Apache nếu đó là những gì nó đang chạy.

Để liệt kê một số được lấy từ các tài liệuphp_sapi_name() php trên :

  • máy chủ
  • apache
  • apache2filter
  • apache2handler
  • caudium
  • cgi (cho đến PHP 5.3)
  • cgi-fcgi
  • cli
  • cli-server (Máy chủ web tích hợp kể từ PHP 5.4)
  • liên tục
  • nhúng
  • fpm-fcgi
  • isapi
  • litespeed
  • vắt sữa
  • nsapi
  • tiến sĩ
  • pi3web
  • roxen
  • thwd
  • tux
  • webjame

13

Điều này sẽ xử lý tất cả các trường hợp (bao gồm cả php-cgi)

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

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

thí dụ:

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

2
Từ hướng dẫn, "FALSE sẽ được trả về nếu answer_code không được cung cấp và nó không được gọi trong môi trường máy chủ web (chẳng hạn như từ ứng dụng CLI). TRUE sẽ được trả về nếu answer_code được cung cấp và nó không được gọi trong máy chủ web môi trường (nhưng chỉ khi không có trạng thái phản hồi trước đó được đặt) ". Bạn đã nhận được logic của bạn ngược.
krowe2

1
+1. Kinh ngạc. Sau rất nhiều năm nghiên cứu không có kết quả ... Tôi xin trao tặng bạn giải thưởng tưởng niệm Nobel về PHP, đã chia sẻ với @ krowe2 vì sự đóng góp vô giá của ông về việc thực sự làm cho nó hoạt động. Xin chúc mừng!
Sz.

Có thể một cái gì đó có thể đã đặt mã phản hồi ... http_response_code(200);... nếu bây giờ tôi gọi http_response_code()nó sẽ trả về 200;
Brad Kent

@BradKent Đó là CHỈ nếu bạn gọi nó từ môi trường web và trong trường hợp đó, kiểm tra này vẫn hoạt động miễn là bạn không đặt mã trạng thái về 0 (dù sao đó là mã trạng thái HTTP không hợp lệ). Phiên bản của tôi sẽ hoạt động ngay cả trong trường hợp đó vì nó kiểm tra cụ thể với FALSE. Nếu http_response_code();được gọi từ môi trường CLI, nó sẽ luôn trả về SAI bất kể mã trạng thái thực tế. Tôi đã giải thích điều này trong câu trả lời của mình nhưng bạn cũng có thể tìm ra điều này bằng cách đọc trang hướng dẫn trong phần "Giá trị trả về" hoặc bằng cách thử nó.
krowe2

@ krowe2 php -r 'http_response_code(200); echo http_response_code()."\n";' xuất ra "200" Trừ khi bạn có thể đảm bảo rằng một số thư viện hoặc khung không biết gì đã không đặt mã phản hồi với http_response_code(ngay cả trong cli env), thì điều này sẽ hoạt động. Cá nhân, tôi sử dụng$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
Brad Kent

4

Tôi đã sử dụng điều này:

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

Đây là từ Drush codebase, môi trường. Nơi họ có kiểm tra tương tự để thực hiện.


4
Nếu register_argc_argvđược đặt, thì việc chuyển vào bất kỳ số lượng giá trị GET nào sẽ argckhông bằng 0.

3

Thử

isset($_SERVER['REQUEST_METHOD'])

nếu được đặt, bạn đang ở trong trình duyệt.

Thay thế, bạn có thể kiểm tra nếu

isset($_SERVER['argv'])

nhưng điều đó có thể không đúng trên windows CLI, IDK.


1
Mặc dù nó không phải là câu trả lời "chính xác" nhưng nó có thể đáng tin cậy hơn
challet



0

Tôi sẽ đề nghị kiểm tra xem một số mục của mảng $ _SERVER có được đặt không.

Ví dụ:

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

Điều này sẽ không hoạt động với php-cgidòng lệnh, nó sẽ được đặt thành GET:php-cgi -f file.php arg1=2
Sebastian

0

Phương pháp ưa thích của tôi:

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

Một cách dễ dàng là thẩm vấn $argvbiến, (Dù sao bạn cũng có thể sẽ làm cho các tham số dòng lệnh). Ngay cả khi không có tham số $argvtrả về một mảng trống.

Nếu nó được đặt, thì cli đã được sử dụng. Sau đó, bạn có thể giả sử tất cả các yêu cầu khác thông qua một số máy chủ web hoặc khác.

ví dụ:

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

0

Dựa trên câu trả lời của Silver Moon ở trên , tôi đang sử dụng chức năng này để trả về các ngắt dòng chính xác:

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

Câu trả lời chính xác cho câu hỏi này phụ thuộc vào ý định thực sự đằng sau nó:

  • Có phải SAPI là yếu tố quyết định (bối cảnh web hay không)?
  • Hay thông tin được hiểu là "chạy trong một tty"?

Nếu trước đây các câu trả lời được đưa ra và ý kiến ​​được viết là đủ để tìm ra một giải pháp hiệu quả.

Nếu sau này, các công thức được đưa ra ở đây sẽ thất bại nếu công cụ được chạy dưới dạng cronjob hoặc làm công việc nền từ một trình nền khác - trong trường hợp đó tôi đề nghị kiểm tra thêm nếu STDINlà TTY:

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

-1

Làm thế nào, rất nhiều giải pháp phức tạp. Làm thế nào về ...

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

-17

Tôi sẽ thử:

echo exec('whoami');

Thông thường máy chủ web được chạy dưới một tên người dùng khác, vì vậy điều đó nên được nói.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.