รับเส้นทางที่แน่นอนของการเริ่มต้นใช้งานสคริปต์


247

ฉันค้นหาสูงและต่ำและรับวิธีแก้ไขปัญหาและตัวแปรที่มีข้อมูลจำนวนมากเพื่อรับเส้นทางที่สมบูรณ์ แต่พวกเขาดูเหมือนจะทำงานภายใต้เงื่อนไขบางอย่างและไม่อยู่ภายใต้คนอื่น มีวิธีกระสุนเงินวิธีหนึ่งที่จะได้รับเส้นทางที่แน่นอนของสคริปต์ที่ดำเนินการใน PHP? สำหรับฉันสคริปต์จะทำงานจากบรรทัดคำสั่ง แต่โซลูชันควรทำงานได้ดีหากทำงานใน Apache เป็นต้น

การชี้แจง: สคริปต์ที่ดำเนินการในตอนแรกไม่จำเป็นต้องเป็นไฟล์ที่มีการเข้ารหัสโซลูชัน


ความจริงทางคณิตศาสตร์ที่แท้จริง ฉันยอมรับมันเมื่อนานมาแล้วเมื่อฉันมีสคริปต์เดียวเท่านั้น ฉันลบคำตอบที่ยอมรับเพื่อทำให้ชัดเจนว่าไม่ได้แก้ปัญหาเริ่มต้น การจัดเก็บค่าคงที่ FILE เมื่อการดำเนินการเริ่มต้นในสคริปต์เป็นวิธีหนึ่งที่จะไป แต่ไกลจากอุดมคติ
สอบถาม

สคริปต์ที่ร้องขอคือสิ่งที่คุณต้องการ script ปัจจุบัน = ด้วยรหัสโซลูชันนี้
Bitterblue

คำตอบ:


33

ทางออกที่ถูกต้องคือการใช้get_included_filesฟังก์ชั่น:

list($scriptPath) = get_included_files();

สิ่งนี้จะให้เส้นทางที่แน่นอนของสคริปต์เริ่มต้นแม้ว่า:

  • ฟังก์ชั่นนี้จะอยู่ในไฟล์ที่รวมอยู่
  • ไดเรกทอรีการทำงานปัจจุบันแตกต่างจากไดเรกทอรีของสคริปต์เริ่มต้น
  • สคริปต์ถูกเรียกใช้งานด้วย CLI ซึ่งเป็นพา ธ แบบสัมพันธ์

ที่นี่มีสองสคริปต์ทดสอบ สคริปต์หลักและไฟล์ที่รวมอยู่:

# C:\Users\Redacted\Desktop\main.php
include __DIR__ . DIRECTORY_SEPARATOR . 'include.php';
echoScriptPath();

# C:\Users\Redacted\Desktop\include.php
function echoScriptPath() {
    list($scriptPath) = get_included_files();
    echo 'The script being executed is ' . $scriptPath;
}

และผลที่ได้; สังเกตเห็นไดเรกทอรีปัจจุบัน:

C:\>php C:\Users\Redacted\Desktop\main.php
The script being executed is C:\Users\Redacted\Desktop\main.php

วิธีนี้ทำงาน แต่ก็คุ้มค่าการกล่าวขวัญว่าอ่านเอกสารไม่มีการเอ่ยถึงว่าเส้นทางของสคริปต์ทำงานครั้งแรกจะไม่มีครั้งแรกที่get_included_files()รายการของอาร์เรย์ที่ส่งกลับโดย ฉันแนะนำให้เก็บ__FILE__ไว้เป็นค่าคงที่ในตอนต้นของสคริปต์ที่จะเริ่มต้นทำงาน
เปาโล

270

__FILE__ คงที่จะให้เส้นทางที่แน่นอนไปยังไฟล์ปัจจุบัน

อัปเดต :

คำถามนี้เปลี่ยนไปเพื่อถามวิธีเรียกสคริปต์เริ่มต้นแทนที่จะใช้สคริปต์ที่รันอยู่ในปัจจุบัน วิธีที่เชื่อถือได้เท่านั้น (??) ในการทำเช่นนั้นคือการใช้debug_backtraceฟังก์ชั่น

$stack = debug_backtrace();
$firstFrame = $stack[count($stack) - 1];
$initialFile = $firstFrame['file'];

ถ้าฉันใช้รูปแบบตัวควบคุมด้านหน้า จะ__FILE__ส่งคืนตำแหน่งของ index.php หรือตำแหน่งของไฟล์ที่รวมอยู่หรือไม่ ฉันจะรับตำแหน่ง index.php ได้อย่างไร
CMCDragonkai

ดี__FILE__ชี้ไปที่เส้นทางของสคริปต์ปัจจุบัน แต่ฉันไม่พบอะไรเลยที่จะแสดงเส้นทางของ index.php ปัจจุบัน
CMCDragonkai

1
@CMCDragonkai: ถามคำถามแยกต่างหากแล้ว
zerkms

2
ข้อควรระวัง: หากสคริปต์อยู่ในไดเรกทอรีเสมือน apache2 ข้อมูลที่ส่งคืนจะไม่ได้ระบุตำแหน่งของเส้นทางจริงบนเซิร์ฟเวอร์จริง ฉันต้องการสิ่งนี้เพื่อการดีบักและแม้แต่ตัวแปร $ _SERVER ก็ไม่ได้ให้สิ่งนี้ ตัวอย่างเช่นหาก index.php มีอยู่ใน / var / www / vpath1 / html และ / var / www / html / และ / var / www / vpath2 / html และแต่ละรายการเหล่านี้จะถูกแมปกับ / var / www / html ดังนั้น / var / www / html คือสิ่งที่คุณจะเห็นไม่ว่าจะใช้เซิร์ฟเวอร์เสมือนใด
Mark Richards

1
@ChristofferBubach คุณไม่จำเป็นต้องโยนทิ้ง: วัตถุข้อยกเว้นรวบรวมการติดตามสแต็คในระหว่างการก่อสร้าง
zerkms

262

คำตอบถูกย้ายมาที่นี่ - https://stackoverflow.com/a/26944636/2377343


1
เพื่อรับโฟลเดอร์ปัจจุบันของสคริปต์str_replace( basename(__FILE__) , '',str_replace($_SERVER["DOCUMENT_ROOT"],'',str_replace('\\','/',__FILE__ ) ) ) === /folder1/folder2/
Salem

2
นี่คือรายการตัวอย่างที่ครอบคลุมมากที่สุดในการหาเส้นทางไฟล์บางส่วนหรือทั้งหมดที่ฉันเคยเห็นในอินเทอร์เน็ตทั้งหมด
Sean the Bean

241
echo realpath(dirname(__FILE__));

หากคุณวางสิ่งนี้ลงในไฟล์ที่รวมไว้มันจะพิมพ์พา ธ ไปยังการรวมนี้ เพื่อให้ได้เส้นทางของสคริปต์แม่แทนที่ด้วย__FILE__ $_SERVER['PHP_SELF']แต่ระวังว่า PHP_SELF นั้นมีความเสี่ยงด้านความปลอดภัย!


1
นี่คือสิ่งที่ฉันต้องการ
Askam 10'11

13
การใช้ realpath ที่นี่คืออะไร
สามัญสำนึกของคุณ

11
@Col กระสุน: "ตั้งแต่ PHP 4.0.2, __FILE__จะมีพา ธ สัมบูรณ์ที่มี symlinks ที่แก้ไขแล้วในขณะที่เวอร์ชั่นเก่านั้นจะมีพา ธ สัมพัทธ์ภายใต้บางสถานการณ์" เครื่องหมายบวก "dirname () ทำงานอย่างไร้เดียงสาในสตริงอินพุตและไม่ทราบถึงระบบไฟล์จริงหรือคอมโพเนนต์พา ธ เช่น '.. '.
rik

6
โอ้ 4.0.2 ศตวรรษที่แล้ว
สามัญสำนึกของคุณ

2
@rik: ยังสิ่งที่ปัญหาด้านความปลอดภัยสามารถก่อให้เกิดPHP_SELF??
zerkms

38
__DIR__

จากคู่มือ :

ไดเรกทอรีของไฟล์ หากใช้ภายในการรวมไดเร็กทอรีของไฟล์ที่รวมจะถูกส่งคืน dirname(__FILE__)นี้จะเทียบเท่ากับ ชื่อไดเร็กทอรีนี้ไม่มีเครื่องหมายสแลชต่อท้ายยกเว้นว่าเป็นไดเร็กทอรีรูท
__FILE__ มักจะมีเส้นทางที่แน่นอนที่มี symlink แก้ไขในขณะที่รุ่นเก่า (กว่า 4.0.2) มันมีเส้นทางญาติในบางกรณี

หมายเหตุ : __DIR__ถูกเพิ่มใน PHP 5.3.0



8
dirname(__FILE__) 

จะให้เส้นทางที่แน่นอน ของไฟล์ปัจจุบันที่คุณต้องการเส้นทางเส้นทางของไดเรกทอรีเซิร์ฟเวอร์ของคุณ

ไฟล์ตัวอย่าง:

www / http / html / index.php; ถ้าคุณวางรหัสนี้ไว้ใน index.php มันจะกลับมา:

<?php echo dirname(__FILE__); // this will return: www/http/html/

www / http / html / class / myclass.php; หากคุณวางรหัสนี้ไว้ใน myclass.php มันจะกลับมา:

<?php echo dirname(__FILE__); // this will return: www/http/html/class/


7

เพียงใช้ด้านล่าง:

echo __DIR__;

1
Sry ความคิดคือการได้รับสคริปต์การยิงครั้งแรก ... ไม่ใช่คนที่คุณเคยเป็นในตอนนี้ ดังนั้นการรวมของต้นไม้a.php->b.php->c.phpที่ควรจะเป็นเส้นทางของa.phpถ้าตรวจสอบในc.php วิธีเดียวที่ดูเหมือนว่าจะมีความน่าเชื่อถือคือการใช้debug_backtrace ()ฟังก์ชั่น
สอบถาม

5
`realpath(dirname(__FILE__))` 

มันทำให้คุณสคริปต์ปัจจุบัน (สคริปต์ภายในที่คุณวางรหัสนี้) ไดเรกทอรีโดยไม่ต้องต่อท้ายทับ สิ่งนี้สำคัญถ้าคุณต้องการรวมไฟล์อื่น ๆ ด้วยผลลัพธ์


ใช่ แต่ความคิดคือการได้รับเส้นทางที่แน่นอนไปยัง "สคริปต์การยิง" A.php แม้ข้างใน B.php ถ้ามันรวมอยู่ใน A.php สามารถทำได้หรือแน่นอนสามารถทำได้โดยการจัดเก็บสคริปต์เริ่มต้นสำหรับการเข้าถึงในภายหลัง แต่คำถามคือถ้าเป็นไปได้ที่จะได้รับมันโดยไม่ทำอย่างนั้น
Askam

4

หากคุณกำลังมองหาเส้นทางสัมบูรณ์ที่เกี่ยวข้องกับเซิร์ฟเวอร์รูตฉันพบว่าวิธีนี้ใช้ได้ดี:

$_SERVER['DOCUMENT_ROOT'] . dirname($_SERVER['SCRIPT_NAME'])

เมื่อฉันตรวจสอบโซลูชันนี้กับเซิร์ฟเวอร์ต่าง ๆ มันให้เส้นทางกับ linux เช่นตัวคั่น dir โดยไม่คำนึงถึงระบบปฏิบัติการของโฮสต์ (Windows และ Linux) สำหรับฉันนั่นเป็นข้อได้เปรียบ
Bronek

3

นี่คือฟังก์ชั่น PHP ที่มีประโยชน์ที่ฉันเขียนถึงสิ่งนี้อย่างแม่นยำ ตามที่คำถามดั้งเดิมชี้แจงแล้วมันจะส่งคืนพา ธ ที่สคริปต์เริ่มต้นถูกเรียกใช้งานไม่ใช่ไฟล์ที่เราอยู่ในปัจจุบัน

/**
 * Get the file path/dir from which a script/function was initially executed
 * 
 * @param bool $include_filename include/exclude filename in the return string
 * @return string
 */ 
function get_function_origin_path($include_filename = true) {
    $bt = debug_backtrace();
    array_shift($bt);
    if ( array_key_exists(0, $bt) && array_key_exists('file', $bt[0]) ) {
        $file_path = $bt[0]['file'];
        if ( $include_filename === false ) {
            $file_path = str_replace(basename($file_path), '', $file_path);
        }
    } else {
        $file_path = null;
    }
    return $file_path;
}


1
realpath($_SERVER['SCRIPT_FILENAME'])

สำหรับสคริปต์ที่ทำงานภายใต้เว็บเซิร์ฟเวอร์$_SERVER['SCRIPT_FILENAME']จะมีเส้นทางแบบเต็มไปยังสคริปต์ที่เรียกว่าเริ่มต้นดังนั้นอาจเป็น index.php ของคุณrealpath()ไม่จำเป็นในกรณีนี้

สำหรับสคริปต์ที่รันจากคอนโซล$_SERVER['SCRIPT_FILENAME']จะมีพา ธ ที่สัมพันธ์กับสคริปต์เริ่มต้นของคุณจาก dir ที่ทำงานอยู่ในปัจจุบัน ดังนั้นหากคุณไม่เปลี่ยนไดเรกทอรีการทำงานภายในสคริปต์ของคุณมันจะแก้ไขไปยังพา ธ สัมบูรณ์


1

นี่คือสิ่งที่ฉันใช้และทำงานได้ในสภาพแวดล้อม Linux ฉันไม่คิดว่ามันจะทำงานบนเครื่อง Windows ...

//define canonicalized absolute pathname for the script
if(substr($_SERVER['SCRIPT_NAME'],0,1) == DIRECTORY_SEPARATOR) {
    //does the script name start with the directory separator?
    //if so, the path is defined from root; may have symbolic references so still use realpath()
    $script = realpath($_SERVER['SCRIPT_NAME']);
} else {
    //otherwise prefix script name with the current working directory
    //and use realpath() to resolve symbolic references
    $script = realpath(getcwd() . DIRECTORY_SEPARATOR . $_SERVER['SCRIPT_NAME']);
}

1

วิธีง่ายๆในการมีพา ธ สัมบูรณ์ของสคริปต์ที่เรียกใช้ครั้งแรกในสคริปต์นั้นและสคริปต์อื่น ๆ ที่รวมอยู่includeในrequireนั้นrequire_onceคือการใช้ค่าคงที่และเก็บเส้นทางสคริปต์ปัจจุบันไว้ที่จุดเริ่มต้นของสคริปต์หลัก :

define( 'SCRIPT_ROOT', __FILE__ );

วิธีการแก้ปัญหาข้างต้นเหมาะสมเมื่อมีสคริปต์ "หลัก" เดียวที่เป็นสคริปต์includeอื่น ๆ ที่จำเป็นเช่นเดียวกับในเว็บแอปพลิเคชันส่วนใหญ่

หากไม่ใช่กรณีนี้และอาจมี "สคริปต์ในช่อง" หลายรายการเพื่อหลีกเลี่ยงการกำหนดใหม่และเพื่อให้มีเส้นทางที่ถูกต้องเก็บไว้ในค่าคงที่แต่ละสคริปต์อาจเริ่มต้นด้วย:

if( ! defined( 'SCRIPT_ROOT' ) ) {
    define( 'SCRIPT_ROOT`, __FILE__ );
}

หมายเหตุเกี่ยวกับคำตอบที่ยอมรับ (ปัจจุบัน) :

คำตอบระบุว่าเส้นทางสคริปต์ที่ดำเนินการครั้งแรกเป็นองค์ประกอบแรกของอาร์เรย์ที่ส่งกลับโดย get_included_files()คำตอบที่ระบุว่าเส้นทางสคริปต์ดำเนินการในขั้นต้นเป็นองค์ประกอบแรกของอาร์เรย์ที่ส่งกลับโดย

นี้เป็นทางออกที่ฉลาดและเรียบง่ายและ -At เวลาของการ writing- (เรากำลังเกือบ PHP 7.4.0) มันไม่ทำงาน

อย่างไรก็ตามโดยการดูที่เอกสารจะไม่มีการกล่าวถึงว่าสคริปต์ที่เรียกใช้ครั้งแรกนั้นเป็นรายการแรกของอาร์เรย์ที่ส่งคืนโดยget_included_files()รายการของอาร์เรย์ที่ส่งกลับโดย

เราอ่านเท่านั้น

สคริปต์ที่ แต่เดิมเรียกว่าถือเป็น "ไฟล์ที่รวมอยู่" ดังนั้นมันจะถูกแสดงพร้อมกับไฟล์ที่อ้างอิงโดยรวมและตระกูล

ในช่วงเวลาของการเขียน " สคริปต์เดิมเรียกว่า " เป็นคนแรกในอาร์เรย์ แต่ - ทางเทคนิค - ไม่มีการรับประกันว่าสิ่งนี้จะไม่เปลี่ยนแปลงในอนาคต


เกี่ยวกับการจดบันทึกrealpath(), __FILE__และ__DIR__:

อื่น ๆ มีข้อเสนอแนะในคำตอบของพวกเขาใช้__FILE__, __DIR__, dirname(__FILE__), realpath(__DIR__)...

dirname(__FILE__)จะมีค่าเท่ากับ__DIR__(แนะนำใน PHP 5.3.0) __DIR__ใช้เพียงเพื่อ

ทั้งสอง__FILE__และ__DIR__เป็นเส้นทางที่แน่นอนเสมอดังนั้นจึงrealpath()ไม่จำเป็น

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