PHP - cara terbaik menentukan apakah permintaan saat ini dari CLI atau server web?

Jawaban:

308

php_sapi_nameadalah fungsi yang Anda ingin gunakan karena mengembalikan string huruf kecil dari tipe antarmuka. Selain itu, ada konstanta PHP PHP_SAPI.

Dokumentasi dapat ditemukan di sini: http://php.net/php_sapi_name

Misalnya, untuk menentukan apakah PHP dijalankan dari CLI, Anda bisa menggunakan fungsi ini:

function isCommandLineInterface()
{
    return (php_sapi_name() === 'cli');
}
Joe Lencioni
sumber
11
Lebih mudah:return php_sapi_name() == 'cli';
Savageman
11
Saya melakukan riset: jika Anda menjalankan skrip dengan php-cgiini tidak akan berhasil. Pada gilirannya, itu akan mengembalikan cgi-fcgiString. Jika Anda memuat skrip sebagai halaman web dari browser, Anda akan mendapatkannya apache2handler. Semoga ini membantu. Saya perlu menggunakan php-cgidalam rangka memperkenalkan $_GETvariabel: php-cgi myscript.php arg1=one arg2=two. Pengujian untuk tidak sama dengan apache2handlerharus ok untuk apache.
Sebastian
3
Peringatan kecil tentang metode ini: itu tidak akan kembali "cli"ketika dijalankan dari pekerjaan cron. Ada beberapa kunci untuk memilih dari dalam $_SERVERuntuk menentukan lebih andal apakah permintaan datang melalui HTTP atau tidak.
omninonsense
2
@omninonsense Saya diuji dengan PHP 7.2.7 dan mengembalikan cli.
Jose Nobile
38

Saya telah menggunakan fungsi ini selama beberapa tahun

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
sumber
10
array_key_exists('REQUEST_METHOD', $_SERVER) return true;WAT?
biziclop
@biziclop, pemeriksaan array_key_exists('REQUEST_METHOD', $_SERVER)sudah benar untuk membantu mendeteksi sumber permintaan . Ketika di CLI , $_SERVERarray Super Global TIDAK AKAN MEMILIKI kunci REQUEST_METHOD, itu hanya ada ketika permintaan dilakukan melalui Web, oleh karena itu, penulis benar-benar tepat sasaran ketika memeriksanya.
Julio Marchi
1
@JulioMarchi: tapi bukankah seharusnya return false;atau tidak if ( ! array_key_exists(…)) return true;?
biziclop
2
@biziclop, Anda sepenuhnya benar !!!! Bagaimana saya bisa melewatkan seperti besar detil kecil ??? Memalukan untukku... :). Tentunya, jika KEY tersebut 'REQUEST_METHOD'adalah TIDAK ditemukan, maka fungsi harus kembali FALSEuntuk menunjukkan "CLI". Permintaan maaf saya karena tidak memperhatikan ruang lingkup fungsi itu sendiri ... Penulis harus memperbaikinya karena fungsi sebenarnya berfungsi!
Julio Marchi
Fungsi ini berfungsi dalam kasus saya, bukan php_sapi_name (), karena saya perlu membedakan antara permintaan web dan eksekusi cronjob, dan hasil php_sapi_name () adalah "php-cgi" dalam kedua kasus.
luis.ap.uyen
36

php_sapi_name()benar-benar bukan cara terbaik untuk melakukan pemeriksaan ini karena ini tergantung pada pemeriksaan terhadap banyak nilai yang mungkin. Biner php-cgi dapat dipanggil dari baris perintah, dari skrip shell atau sebagai tugas cron dan (dalam kebanyakan kasus) ini juga harus diperlakukan sebagai 'cli' tetapi php_sapi_name()akan mengembalikan nilai yang berbeda untuk ini (perhatikan bahwa ini bukan ' t kasus dengan versi PHP biasa tetapi Anda ingin kode Anda bekerja di mana saja, kan?). Belum lagi bahwa tahun depan mungkin ada cara baru untuk menggunakan PHP yang tidak mungkin kita ketahui sekarang. Saya lebih suka tidak memikirkannya ketika saya hanya peduli cuaca saya harus membungkus output saya dalam HTML atau tidak.

Untungnya, PHP memiliki cara untuk memeriksa ini secara khusus. Cukup gunakan http_response_code()tanpa parameter apa pun dan itu akan mengembalikan BENAR jika dijalankan dari lingkungan jenis server web dan SALAH jika dijalankan dari lingkungan jenis CLI. Ini kodenya:

$is_web=http_response_code()!==FALSE;

Ini bahkan akan berfungsi jika Anda secara tidak sengaja (?) Menetapkan kode respons dari skrip yang dijalankan dari CLI (atau sesuatu seperti CLI) sebelum Anda menyebutnya.

krowe2
sumber
4
Pertanyaan ini sudah lama ketika saya menjawabnya. Mem-voting jawaban ini mungkin lebih bermanfaat daripada mengirim jawaban lain yang merupakan duplikat kecuali tanpa penjelasan.
krowe2
Mengenai "Ini bahkan akan berfungsi jika Anda secara tidak sengaja (?) Menetapkan kode respons dari skrip yang dijalankan dari CLI ([...]) sebelum Anda memanggil ini.": (Setidaknya) pada PHP 7.4.3, ini adalah tidak benar. http_response_code()set kode / mengembalikan kode set saat menjalankan dari CLI. Diverifikasi oleh <?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();. Jadi jika http_response_code()===falseitu taruhan yang aman untuk mengasumsikan CLI, tetapi jika tidak, Anda juga perlu memeriksa metrik lainnya.
Sebastian B.
23

Saya pikir maksudnya jika PHP CLI dijalankan atau jika ini merupakan respons dari permintaan web. Cara terbaik adalah menggunakan php_sapi_name()yang jika menjalankan permintaan web akan mengulangi Apache jika itu yang dijalankan.

Untuk daftar beberapa diambil dari dokumenphp_sapi_name() php pada :

  • aolserver
  • apache
  • apache2filter
  • apache2handler
  • kaudium
  • cgi (hingga PHP 5.3)
  • cgi-fcgi
  • cli
  • cli-server (Server web bawaan pada PHP 5.4)
  • kontinuitas
  • menanamkan
  • fpm-fcgi
  • isapi
  • Litespeed
  • ikan jantan
  • nsapi
  • phttpd
  • pi3web
  • roxen
  • thttpd
  • tux
  • webjames
Marc Towler
sumber
13

Ini harus menangani semua kasus (termasuk php-cgi)

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

contoh:

if (is_cli()) {
    echo 'command line';
} else {
    echo 'browser';
}
Terry Lin
sumber
2
Dari manual, "FALSE akan dikembalikan jika response_code tidak disediakan dan itu tidak dipanggil di lingkungan server web (seperti dari aplikasi CLI). TRUE akan dikembalikan jika response_code diberikan dan tidak dipanggil di server web lingkungan (tetapi hanya ketika tidak ada status respons sebelumnya telah ditetapkan) ". Anda mendapatkan logika Anda mundur.
krowe2
1
+1. Luar biasa. Setelah bertahun-tahun melakukan penelitian tanpa hasil ... Saya dengan ini memberikan Anda Hadiah Nobel Memorial dalam PHPics, dibagikan dengan @ krowe2 atas kontribusinya yang tak ternilai untuk menjadikannya berfungsi. Selamat!
Sz.
Mungkin saja ada sesuatu yang telah mengatur kode respons ... http_response_code(200);... jika sekarang saya memanggilnya http_response_code()akan mengembalikan 200;
Brad Kent
@BradKent Itu HANYA jika Anda memanggil ini dari lingkungan web dan, dalam hal ini, pemeriksaan ini masih akan berfungsi selama Anda tidak menetapkan kode status ke nol (yang merupakan kode status HTTP yang tidak valid). Versi saya akan bekerja bahkan dalam kasus itu karena memeriksa terhadap FALSE secara khusus. Jika http_response_code();dipanggil dari lingkungan CLI itu akan selalu mengembalikan FALSE terlepas dari kode status yang sebenarnya. Saya sudah menjelaskan ini dalam jawaban saya, tetapi Anda juga bisa mengetahuinya dengan membaca halaman manual di bawah "Return Values" atau dengan mencobanya.
krowe2
@ krowe2 php -r 'http_response_code(200); echo http_response_code()."\n";' menghasilkan "200" Kecuali Anda dapat menjamin bahwa beberapa pustaka atau kerangka kerja yang bodoh tidak menetapkan kode respons dengan http_response_code(bahkan dalam cli env), maka ini akan berfungsi. Secara pribadi, saya menggunakan$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
Brad Kent
4

Saya menggunakan ini:

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

Ini dari basis kode Drush, environment.inc di mana mereka memiliki pemeriksaan serupa.

Ranjan
sumber
4
Jika register_argc_argvdiatur, maka meneruskan sejumlah nilai GET akan menyebabkan argctidak menjadi 0.
3

Mencoba

isset($_SERVER['REQUEST_METHOD'])

jika diatur, Anda berada di browser.

Atau, Anda dapat memeriksa apakah

isset($_SERVER['argv'])

tapi itu mungkin tidak benar di windows CLI, IDK.

Agak
sumber
1
Meskipun ini bukan jawaban yang "benar", ini mungkin jawaban yang lebih dapat diandalkan
challet
2

cara joomla

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

Saya akan menyarankan untuk memeriksa apakah beberapa entri dari array $ _SERVER disetel.

Misalnya:

if (isset($_SERVER['REQUEST_METHOD'])) {
        print "HTTP request\n";
} else {
        print "CLI invocation\n";
}
rodion
sumber
Ini tidak akan bekerja dengan php-cgibaris perintah, itu akan mengaturnya GETuntuk:php-cgi -f file.php arg1=2
Sebastian
0

Metode pilihan saya:

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

Cara mudah adalah dengan menginterogasi $argvvariabel, (yang mungkin akan Anda lakukan untuk parameter baris perintah). Bahkan jika tidak ada parameter $argvmengembalikan array kosong.

Jika sudah diatur, maka cli digunakan. Anda kemudian dapat menganggap semua permintaan lainnya melalui beberapa server web atau lainnya.

misalnya:

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

Berdasarkan jawaban Silver Moon di atas , saya menggunakan fungsi ini untuk mengembalikan linebreak yang benar:

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

Jawaban yang benar untuk pertanyaan ini tergantung pada maksud sebenarnya di baliknya:

  • Apakah SAPI faktor penentu (konteks web atau tidak)?
  • Atau apakah informasi tersebut diartikan sebagai 'berjalan dalam waktu yang lama'?

Jika yang pertama jawaban yang diberikan dan komentar yang ditulis sudah cukup untuk menemukan solusi yang berhasil.

Jika yang terakhir, resep yang diberikan di sini akan gagal jika alat dijalankan sebagai cronjob, atau sebagai latar belakang-pekerjaan dari daemon lain - dalam hal ini saya menyarankan untuk melakukan tes lebih lanjut apakah STDINTTY:

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

Bagaimana, begitu banyak solusi yang rumit. Bagaimana tentang ...

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

Saya akan mencoba:

echo exec('whoami');

Biasanya webservers dijalankan di bawah nama pengguna yang berbeda, sehingga harus dikatakan.

Stefan Mai
sumber