Nhận đường dẫn tuyệt đối của tập lệnh chạy ban đầu


247

Tôi đã tìm kiếm cao và thấp và nhận được rất nhiều giải pháp và biến khác nhau chứa thông tin để có được đường dẫn tuyệt đối. Nhưng họ dường như làm việc trong một số điều kiện và không phải dưới những điều kiện khác. Có một cách viên đạn bạc nào để có được đường dẫn tuyệt đối của tập lệnh được thực thi trong PHP không? Đối với tôi, tập lệnh sẽ chạy từ dòng lệnh, nhưng, một giải pháp cũng sẽ hoạt động tốt nếu chạy trong Apache, v.v.

Làm rõ: Tập lệnh được thực thi ban đầu, không nhất thiết là tệp nơi giải pháp được mã hóa.


thực sự mathheadinclouds. Tôi đã chấp nhận nó từ lâu khi tôi chỉ có một kịch bản và nó đã làm việc cho tôi. Tôi đã xóa câu trả lời được chấp nhận để làm cho nó rõ ràng nó không giải quyết được vấn đề ban đầu. Lưu trữ hằng số TẬP TIN khi thực thi bắt đầu trong một kịch bản là một cách để đi, nhưng xa lý tưởng.
inquam

tập lệnh được yêu cầu là những gì bạn muốn, tập lệnh hiện tại = với mã giải pháp này
Bitterblue

Câu trả lời:


33

Giải pháp đúng là sử dụng get_included_fileschức năng:

list($scriptPath) = get_included_files();

Điều này sẽ cung cấp cho bạn đường dẫn tuyệt đối của tập lệnh ban đầu ngay cả khi:

  • Chức năng này được đặt trong một tập tin bao gồm
  • Thư mục làm việc hiện tại khác với thư mục ban đầu của tập lệnh
  • Kịch bản được thực thi với CLI, như một đường dẫn tương đối

Đây là hai kịch bản thử nghiệm; tập lệnh chính và tập tin kèm theo:

# 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;
}

Và kết quả; chú ý thư mục hiện tại:

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

Giải pháp này hoạt động nhưng điều đáng nói là, đọc tài liệu , không có đề cập rằng đường dẫn của tập lệnh chạy ban đầu là mục đầu tiên của mảng được trả về get_included_files(). Tôi đề nghị lưu trữ __FILE__vào một hằng số ở đầu tập lệnh có nghĩa là ban đầu được chạy.
Paolo

270

__FILE__ hằng số sẽ cung cấp cho bạn đường dẫn tuyệt đối đến tập tin hiện tại.

Cập nhật :

Câu hỏi đã được thay đổi để hỏi cách truy xuất tập lệnh được thực hiện ban đầu thay vì tập lệnh hiện đang chạy. Cách duy nhất (??) đáng tin cậy để làm điều đó là sử dụng debug_backtracehàm.

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

Nếu tôi đang sử dụng một mẫu điều khiển phía trước. Sẽ __FILE__trả về vị trí của tệp index.php hoặc vị trí của tệp được bao gồm? Làm thế nào tôi có được vị trí của index.php?
CMCDragonkai

Cũng __FILE__chỉ đến đường dẫn của kịch bản hiện tại. Nhưng tôi không tìm thấy bất cứ điều gì để hiển thị đường dẫn của index.php hiện tại.
CMCDragonkai

1
@CMCDragonkai: sau đó hỏi một câu hỏi riêng
zerkms

2
THẬN TRỌNG: nếu tập lệnh nằm trong thư mục ảo apache2, thông tin được trả về KHÔNG cung cấp vị trí đường dẫn thực trên máy chủ vật lý. Tôi muốn điều này cho mục đích gỡ lỗi và ngay cả các biến $ _SERVER cũng không cung cấp điều này. Ví dụ: nếu index.php tồn tại trong / var / www / vpath1 / html và / var / www / html / và / var / www / vpath2 / html và mỗi trong số này hầu như được ánh xạ tới / var / www / html, thì / var / www / html là những gì bạn sẽ thấy, bất kể máy chủ ảo nào được sử dụng.
Mark Richards

1
@ChristofferBubach bạn thậm chí không cần ném nó: một đối tượng ngoại lệ thu thập dấu vết ngăn xếp trong quá trình xây dựng.
zerkms

262

Câu trả lời đã được chuyển đến đây - https://stackoverflow.com/a/26944636/2377343


1
để lấy thư mục hiện tại của tập lệnhstr_replace( basename(__FILE__) , '',str_replace($_SERVER["DOCUMENT_ROOT"],'',str_replace('\\','/',__FILE__ ) ) ) === /folder1/folder2/
Salem

2
Đây là danh sách các ví dụ toàn diện nhất về các cách để có được một phần hoặc toàn bộ đường dẫn tệp mà tôi đã thấy trên toàn bộ internet.
Sean the Bean

241
echo realpath(dirname(__FILE__));

Nếu bạn đặt tệp này trong một tệp được bao gồm, nó sẽ in đường dẫn đến tệp này. Để có được đường dẫn của tập lệnh cha, thay thế __FILE__bằng $_SERVER['PHP_SELF']. Nhưng hãy lưu ý rằng PHP_SELF là một rủi ro bảo mật!


1
Đây chính xác là những gì tôi muốn
inquam

13
việc sử dụng realpath ở đây là gì?
Ý thức chung của bạn

11
@Col. Mảnh đạn: "Kể từ PHP 4.0.2, __FILE__luôn chứa một đường dẫn tuyệt đối với các liên kết tượng trưng được giải quyết trong khi ở các phiên bản cũ hơn, nó chứa đường dẫn tương đối trong một số trường hợp." cộng với "dirname () hoạt động một cách ngây thơ trên chuỗi đầu vào và không biết hệ thống tập tin thực tế hoặc các thành phần đường dẫn như '..'.
rik

6
ồ, 4.0.2. Thế kỷ trước?
Ý thức chung của bạn

2
@rik: còn nữa, vấn đề bảo mật nào có thể gây ra PHP_SELF??
zerkms

38
__DIR__

Từ hướng dẫn :

Thư mục của tập tin. Nếu được sử dụng bên trong bao gồm, thư mục của tệp được bao gồm sẽ được trả về. Điều này tương đương vớidirname(__FILE__) . Tên thư mục này không có dấu gạch chéo trừ khi nó là thư mục gốc.
__FILE__ luôn chứa một đường dẫn tuyệt đối với các liên kết tượng trưng được giải quyết trong khi ở các phiên bản cũ hơn (4.0.2), nó chứa đường dẫn tương đối trong một số trường hợp.

Lưu ý : __DIR__đã được thêm vào trong PHP 5.3.0.


21

Nếu bạn muốn có được thư mục làm việc hiện tại sử dụnggetcwd()

http://php.net/manual/en/feft.getcwd.php

__FILE__sẽ trả về đường dẫn với tên tệp chẳng hạn trên XAMPP C:\xampp\htdocs\index.phpthay vìC:\xampp\htdocs\


8
dirname(__FILE__) 

sẽ đưa ra lộ trình tuyệt đối của tệp hiện tại mà bạn đang yêu cầu tuyến đường, tuyến đường của thư mục máy chủ của bạn.

tập tin ví dụ:

www / http / html / index.php; nếu bạn đặt mã này vào trong tệp index.php, nó sẽ trả về:

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

www / http / html / class / mygroup.php; nếu bạn đặt mã này bên trong mygroup.php, nó sẽ trả về:

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


7

Chỉ cần sử dụng dưới đây:

echo __DIR__;

1
Sry, ý tưởng là để có được kịch bản bị sa thải đầu tiên ... Không phải là kịch bản bạn xảy ra bây giờ. Vì vậy, một cây bao gồm a.php->b.php->c.phpphải là đường dẫn của a.php nếu được chọn trong c.php . Cách duy nhất có vẻ đáng tin cậy là sử dụng hàm debug_backtrace () .
inquam

5
`realpath(dirname(__FILE__))` 

nó cung cấp cho bạn thư mục hiện tại (tập lệnh bên trong mà bạn đã đặt mã này) mà không có dấu gạch chéo. điều này rất quan trọng nếu bạn muốn bao gồm các tệp khác với kết quả


Phải, nhưng ý tưởng là có thể có được đường dẫn tuyệt đối đến "tập lệnh bắn" A.php ngay cả trong B.php nếu được A.php đưa vào. Nó có thể hoặc tất nhiên được thực hiện bằng cách lưu trữ tập lệnh ban đầu để truy cập sau, nhưng câu hỏi đặt ra là liệu có thể lấy nó mà không làm điều đó không.
inquam

4

Nếu bạn đang tìm đường dẫn tuyệt đối liên quan đến root máy chủ, tôi đã thấy rằng điều này hoạt động tốt:

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

Khi tôi kiểm tra giải pháp này với các máy chủ khác nhau, nó luôn cho tôi đường dẫn với linux như trình phân tách dir bất kể HĐH của máy chủ (Windows và Linux). Với tôi đó là một lợi thế.
Bronek

3

Đây là một hàm PHP hữu ích tôi đã viết chính xác cho điều này. Khi câu hỏi ban đầu làm rõ, nó trả về đường dẫn mà tập lệnh ban đầu được thực thi - không phải là tệp chúng tôi hiện đang ở.

/**
 * 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'])

Đối với tập lệnh chạy dưới máy chủ web $_SERVER['SCRIPT_FILENAME']sẽ chứa đường dẫn đầy đủ đến tập lệnh được gọi ban đầu, vì vậy có lẽ là tệp index.php của bạn.realpath()không bắt buộc trong trường hợp này.

Đối với tập lệnh chạy từ bàn điều khiển $_SERVER['SCRIPT_FILENAME']sẽ chứa đường dẫn tương đối đến tập lệnh được gọi ban đầu của bạn từ thư mục làm việc hiện tại của bạn. Vì vậy, trừ khi bạn thay đổi thư mục làm việc bên trong tập lệnh của mình, nó sẽ giải quyết theo đường dẫn tuyệt đối.


1

Đây là những gì tôi sử dụng và nó hoạt động trong môi trường Linux. Tôi không nghĩ rằng nó sẽ hoạt động trên máy 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

Một cách đơn giản để có đường dẫn tuyệt đối của kịch bản ban đầu được thực hiện , trong đó kịch bản bất kỳ kịch bản khác bao gồm include, require, require_oncelà bằng cách sử dụng một hằng số và lưu trữ có con đường kịch bản hiện tại bắt đầu của kịch bản chính :

define( 'SCRIPT_ROOT', __FILE__ );

Giải pháp trên phù hợp khi có một tập lệnh "chính" duy nhất include là mọi tập lệnh cần thiết khác, như trong hầu hết các ứng dụng web.

Nếu đó không phải là trường hợp và có thể có một số "tập lệnh intital" thì để tránh xác định lại và để có đường dẫn chính xác được lưu trữ bên trong hằng số, mỗi tập lệnh có thể bắt đầu bằng:

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

Một lưu ý về câu trả lời (hiện tại) được chấp nhận :

câu trả lời nói rằng đường dẫn kịch bản được thực hiện ban đầu là phần tử đầu tiên của mảng được trả về bởi get_included_files() .

Đây là một giải pháp thông minh và đơn giản và - trong thời gian viết - (chúng tôi gần như ở PHP 7.4.0) nó hoạt động .

Tuy nhiên, bằng cách xem tài liệu , không có đề cập rằng tập lệnh được thực hiện ban đầu là mục đầu tiên của mảng được trả về bởiget_included_files() .

Chúng tôi chỉ đọc

Tập lệnh được gọi ban đầu được coi là "tệp được bao gồm", do đó, tập lệnh sẽ được liệt kê cùng với các tệp được tham chiếu bởi bao gồm và họ.

Tại thời điểm viết " kịch bản ban đầu được gọi " là tập lệnh đầu tiên trong mảng nhưng - về mặt kỹ thuật - không có gì đảm bảo rằng điều này sẽ không thay đổi trong tương lai.


Một lưu ý về realpath(), __FILE____DIR__:

Những người khác đã gợi ý trong câu trả lời của họ sử dụng __FILE__, __DIR__, dirname(__FILE__), realpath(__DIR__)...

dirname(__FILE__)bằng __DIR__(được giới thiệu trong PHP 5.3.0), vì vậy chỉ cần sử dụng__DIR__ .

Cả hai __FILE____DIR__luôn luôn là con đường tuyệt đối vì vậy realpath()là không cần thiết.

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.