PHP - จะกำหนดได้ดีที่สุดว่าการเรียกใช้ปัจจุบันมาจาก CLI หรือเว็บเซิร์ฟเวอร์หรือไม่


192

ฉันต้องการตรวจสอบว่าการร้องขอปัจจุบันของ PHP มาจาก command line (CLI) หรือจากเว็บเซิร์ฟเวอร์ (ในกรณีของฉัน Apache กับ mod_php)

มีวิธีแนะนำไหม?


แก้ไขและทำให้กระจ่างคำถาม
Shameem

คำตอบ:


308

php_sapi_nameเป็นฟังก์ชั่นที่คุณจะต้องการใช้เพราะมันจะคืนค่าสตริงตัวพิมพ์เล็กของประเภทอินเตอร์เฟส PHP_SAPIนอกจากนี้ยังมีเป็นค่าคงที่ของ PHP

เอกสารสามารถพบได้ที่นี่: http://php.net/php_sapi_name

ตัวอย่างเช่นเพื่อตรวจสอบว่า PHP กำลังถูกเรียกใช้จาก CLI หรือไม่คุณสามารถใช้ฟังก์ชันนี้:

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

11
ตรงไปตรงมามากขึ้น:return php_sapi_name() == 'cli';
Savageman

11
ฉันทำวิจัย: ถ้าคุณเรียกใช้สคริปต์ด้วยphp-cgiสิ่งนี้จะไม่ทำงาน ในทางกลับกันมันจะส่งกลับcgi-fcgiสตริง apache2handlerถ้าคุณโหลดสคริปต์ที่เป็นหน้าเว็บเบราว์เซอร์ที่คุณจะได้รับ หวังว่านี่จะช่วยได้ ฉันต้องใช้php-cgiเพื่อแนะนำ$_GETตัวแปร: php-cgi myscript.php arg1=one arg2=two. การทดสอบที่ไม่เท่ากับapache2handlerควรจะเป็นapacheเช่นนั้น
เซบาสเตียน

3
ข้อแม้เล็ก ๆ เกี่ยวกับวิธีนี้: มันจะไม่กลับมา"cli"เมื่อทำงานจากงาน cron มีปุ่มตัวเลขที่แตกต่างกันให้เลือกจากด้านในของ$_SERVERเพื่อกำหนดความน่าเชื่อถือมากขึ้นว่าคำขอมาทาง HTTP หรือไม่
omninonsense

2
@omnonsonsense ฉันทดสอบกับ PHP 7.2.7 และส่งคืน cli
Jose Nobile

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อาร์เรย์ซูเปอร์ทั่วโลกจะไม่ได้มีกุญแจสำคัญREQUEST_METHODก็เกิดขึ้นเมื่อมีการยื่นคำขอผ่านทางเว็บดังนั้นผู้เขียนเป็นอย่างในเป้าหมายเมื่อตรวจสอบมัน
Julio Marchi

1
@JulioMarchi: แต่ไม่ควรreturn false;ทำif ( ! array_key_exists(…)) return true;หรือไม่?
biziclop

2
@biziclop คุณพูดถูก !!!! ฉันอาจจะพลาดดังกล่าวมหาศาลรายละเอียดเล็ก ๆ ??? น่าอายจริงๆเรา... :). แน่นอนถ้าคีย์'REQUEST_METHOD'จะไม่พบแล้วฟังก์ชั่นควรกลับFALSEเพื่อบ่งชี้ถึง "CLI" ฉันขอโทษที่ไม่สนใจขอบเขตของฟังก์ชั่นเอง ... ผู้เขียนควรแก้ไขเพราะฟังก์ชั่นใช้งานได้จริง!
Julio Marchi

ฟังก์ชั่นนี้ใช้งานได้ในกรณีของฉันไม่ใช่ php_sapi_name () เนื่องจากฉันต้องการแยกแยะระหว่างคำขอของเว็บและการเรียกใช้ cronjob และผลลัพธ์ php_sapi_name () คือ "php-cgi" ในทั้งสองกรณี
luis.ap.uyen

36

php_sapi_name()ไม่ใช่วิธีที่ดีที่สุดในการตรวจสอบนี้เนื่องจากขึ้นอยู่กับการตรวจสอบกับค่าที่เป็นไปได้มากมาย php-cgi binary สามารถเรียกได้จากบรรทัดคำสั่งจากเชลล์สคริปต์หรือเป็นงาน cron และ (ในกรณีส่วนใหญ่) สิ่งเหล่านี้ควรได้รับการปฏิบัติเช่น 'cli' แต่php_sapi_name()จะส่งกลับค่าที่แตกต่างกันสำหรับสิ่งเหล่านี้ กรณีนี้เป็นรุ่นธรรมดาของ 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 แต่ถ้าไม่คุณต้องตรวจสอบตัวชี้วัดอื่น ๆ ด้วย
Sebastian B.

23

ฉันคิดว่าเขาหมายถึงว่ามีการเรียกใช้ PHP CLI หรือไม่หรือเป็นการตอบสนองจากคำขอทางเว็บ วิธีที่ดีที่สุดคือการใช้php_sapi_name()ซึ่งหากมีการเรียกใช้คำขอเว็บจะสะท้อน Apache ถ้านั่นคือสิ่งที่มันกำลังทำงาน

ในการแสดงรายการบางส่วนที่มาจาก php docs เมื่อphp_sapi_name() :

  • aolserver
  • อาปาเช่
  • apache2filter
  • apache2handler
  • caudium
  • cgi (จนถึง PHP 5.3)
  • cgi-FCGI
  • CLI
  • cli-server ( เว็บเซิร์ฟเวอร์ในตัวนับจาก PHP 5.4)
  • ความต่อเนื่อง
  • ฝัง
  • FPM-FCGI
  • ISAPI
  • LiteSpeed
  • ปลาตัวผู้
  • NSAPI
  • phttpd
  • pi3web
  • Roxen
  • thttpd
  • เสื้อรัดรูปไม่ให้ดิ้นได้
  • webjames


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

ตัวอย่าง:

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

2
จากคู่มือ "FALSE จะถูกส่งคืนหากไม่ได้ให้ response_code และไม่ได้เรียกใช้ในสภาพแวดล้อมของเว็บเซิร์ฟเวอร์ (เช่นจากแอปพลิเคชัน 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 codebase, environment.inc ที่พวกเขามีการตรวจสอบที่คล้ายกันเพื่อให้


4
หากregister_argc_argvตั้งค่าไว้การส่งผ่านค่า GET จำนวนเท่าใดจะทำให้argcไม่เป็น 0

3

ลอง

isset($_SERVER['REQUEST_METHOD'])

หากตั้งไว้แสดงว่าคุณอยู่ในเบราว์เซอร์

อีกวิธีหนึ่งคือคุณสามารถตรวจสอบว่า

isset($_SERVER['argv'])

แต่นั่นอาจไม่เป็นความจริงบน windows CLI, IDK


1
แม้ว่ามันจะไม่ใช่คำตอบที่ "ถูกต้อง" แต่มันอาจเป็นคำตอบที่น่าเชื่อถือมากขึ้น
challet

2

ตามhttp://jp2.php.net/manual/en/features.commandline.phpมีค่าคงที่จำนวนหนึ่งที่ตั้งค่าเฉพาะเมื่อเรียกใช้จาก CLI เท่านั้น ค่าคงที่เหล่านี้คือ STDIN, STDOUT และ STDERR การทดสอบหนึ่งในนั้นจะบอกคุณว่ามันอยู่ในโหมด cli



0

ฉันอยากจะแนะนำให้ตรวจสอบว่ามีการตั้งค่ารายการ$ _SERVERจำนวนหนึ่งไว้หรือไม่

เช่น:

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

สิ่งนี้จะไม่ทำงานกับphp-cgicommand line มันจะตั้งเป็นGET:php-cgi -f file.php arg1=2
Sebastian



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 หรือเป็นแบ็คกราวน์จาก daemon อื่น - ในกรณีนี้ฉันขอแนะนำให้ทดสอบเพิ่มเติมหาก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 :)
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.