Có nhiều lý do tại sao một người có thể gặp phải lỗi này và do đó, một danh sách kiểm tra tốt về những gì cần kiểm tra trước giúp ích đáng kể.
Hãy xem xét rằng chúng tôi đang khắc phục sự cố dòng sau:
require "/path/to/file"
Danh mục
1. Kiểm tra đường dẫn tệp cho lỗi chính tả
- hoặc kiểm tra thủ công (bằng cách kiểm tra trực quan đường dẫn)
hoặc di chuyển bất cứ thứ gì được gọi bởi require*
hoặc include*
đến biến của chính nó, lặp lại nó, sao chép nó và thử truy cập nó từ một thiết bị đầu cuối:
$path = "/path/to/file";
echo "Path : $path";
require "$path";
Sau đó, trong một thiết bị đầu cuối:
cat <file path pasted>
2. Kiểm tra xem đường dẫn tệp có chính xác về các cân nhắc đường dẫn tuyệt đối so với đường dẫn tuyệt đối không
- nếu nó bắt đầu bằng dấu gạch chéo "/" thì nó không đề cập đến thư mục gốc của thư mục trang web của bạn (gốc tài liệu), mà là gốc của máy chủ của bạn.
- ví dụ: thư mục trang web của bạn có thể là
/users/tony/htdocs
- nếu nó không bắt đầu bằng dấu gạch chéo về phía trước thì nó sẽ dựa vào đường dẫn bao gồm (xem bên dưới) hoặc đường dẫn là tương đối. Nếu nó là tương đối, thì PHP sẽ tính toán tương đối với đường dẫn của thư mục làm việc hiện tại .
- do đó, không liên quan đến đường dẫn gốc của trang web của bạn hoặc tệp bạn đang nhập
- Vì lý do đó, luôn luôn sử dụng đường dẫn tệp tuyệt đối
Thực hành tốt nhất :
Để làm cho tập lệnh của bạn mạnh mẽ trong trường hợp bạn di chuyển mọi thứ xung quanh, trong khi vẫn tạo một đường dẫn tuyệt đối khi chạy, bạn có 2 tùy chọn:
- sử dụng
require __DIR__ . "/relative/path/from/current/file"
. Các __DIR__
hằng số ma thuật trả về thư mục của tập tin hiện hành.
tự xác định một SITE_ROOT
hằng số:
- ở thư mục gốc của trang web của bạn, tạo một tệp, ví dụ:
config.php
trong config.php
, viết
define('SITE_ROOT', __DIR__);
trong mọi tệp mà bạn muốn tham chiếu thư mục gốc của trang, bao gồm config.php
, và sau đó sử dụng SITE_ROOT
hằng bất cứ nơi nào bạn muốn:
require_once __DIR__."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
Hai thực tiễn này cũng làm cho ứng dụng của bạn dễ di chuyển hơn vì nó không phụ thuộc vào cài đặt ini như đường dẫn bao gồm.
3. Kiểm tra đường dẫn bao gồm của bạn
Một cách khác để bao gồm các tệp, không tương đối hay hoàn toàn tuyệt đối, là dựa vào đường dẫn bao gồm . Đây thường là trường hợp cho các thư viện hoặc khung như khung Zend.
Bao gồm như vậy sẽ trông như thế này:
include "Zend/Mail/Protocol/Imap.php"
Trong trường hợp đó, bạn sẽ muốn đảm bảo rằng thư mục chứa "Zend" là một phần của đường dẫn bao gồm.
Bạn có thể kiểm tra đường dẫn bao gồm:
echo get_include_path();
Bạn có thể thêm một thư mục vào nó với:
set_include_path(get_include_path().":"."/path/to/new/folder");
4. Kiểm tra xem máy chủ của bạn có quyền truy cập vào tập tin đó không
Có thể là tất cả cùng nhau, người dùng đang chạy quy trình máy chủ (Apache hoặc PHP) đơn giản là không có quyền đọc hoặc ghi vào tệp đó.
Để kiểm tra xem người dùng đang chạy máy chủ nào, bạn có thể sử dụng posix_getpwuid :
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
Để tìm ra các quyền trên tệp, nhập lệnh sau trong thiết bị đầu cuối:
ls -l <path/to/file>
và nhìn vào ký hiệu tượng trưng cho phép
5. Kiểm tra cài đặt PHP
Nếu không có cách nào ở trên hoạt động, thì vấn đề có lẽ là một số cài đặt PHP cấm nó truy cập vào tệp đó.
Ba cài đặt có thể có liên quan:
- open_basingir
- Nếu điều này được đặt, PHP sẽ không thể truy cập bất kỳ tệp nào bên ngoài thư mục được chỉ định (thậm chí không thông qua một liên kết tượng trưng).
- Tuy nhiên, hành vi mặc định là không được đặt trong trường hợp không có hạn chế
- Điều này có thể được kiểm tra bằng cách gọi
phpinfo()
hoặc bằng cách sử dụngini_get("open_basedir")
- Bạn có thể thay đổi cài đặt bằng cách chỉnh sửa tệp php.ini hoặc tệp httpd.conf của bạn
- chế độ an toàn
- nếu điều này được bật các hạn chế có thể áp dụng. Tuy nhiên, điều này đã bị xóa trong PHP 5.4. Nếu bạn vẫn đang ở phiên bản hỗ trợ nâng cấp chế độ an toàn lên phiên bản PHP vẫn đang được hỗ trợ .
- allow_url_fopen và allow_url_include
- điều này chỉ áp dụng cho việc bao gồm hoặc mở tệp thông qua quy trình mạng, chẳng hạn như http: // chứ không phải khi cố gắng bao gồm các tệp trên hệ thống tệp cục bộ
- điều này có thể được kiểm tra
ini_get("allow_url_include")
và thiết lập vớiini_set("allow_url_include", "1")
Trường hợp góc
Nếu không có cách nào ở trên được kích hoạt để chẩn đoán sự cố, đây là một số tình huống đặc biệt có thể xảy ra:
1. Bao gồm thư viện dựa trên đường dẫn bao gồm
Có thể xảy ra việc bạn bao gồm một thư viện, ví dụ, khung Zend, sử dụng đường dẫn tương đối hoặc tuyệt đối. Ví dụ :
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
Nhưng sau đó bạn vẫn nhận được cùng một loại lỗi.
Điều này có thể xảy ra bởi vì tệp mà bạn có (thành công) bao gồm, có một câu lệnh bao gồm cho một tệp khác và câu lệnh bao gồm thứ hai đó giả định rằng bạn đã thêm đường dẫn của thư viện đó vào đường dẫn bao gồm.
Ví dụ: tệp khung Zend được đề cập trước đây có thể bao gồm:
include "Zend/Mail/Protocol/Exception.php"
mà không phải là bao gồm bởi đường dẫn tương đối, cũng không phải là đường dẫn tuyệt đối. Giả định rằng thư mục khung Zend đã được thêm vào đường dẫn bao gồm.
Trong trường hợp như vậy, giải pháp thực tế duy nhất là thêm thư mục vào đường dẫn bao gồm của bạn.
2. TỰ TIN
Nếu bạn đang chạy Linux được tăng cường bảo mật, thì đó có thể là lý do của sự cố, bằng cách từ chối quyền truy cập vào tệp từ máy chủ.
Để kiểm tra xem Selinux có được bật trên hệ thống của bạn không, hãy chạy sestatus
lệnh trong thiết bị đầu cuối. Nếu lệnh không tồn tại, thì SELinux không có trên hệ thống của bạn. Nếu nó tồn tại, thì nó sẽ cho bạn biết liệu nó có được thi hành hay không.
Để kiểm tra xem các chính sách của Selinux có phải là lý do của sự cố hay không, bạn có thể thử tắt nó tạm thời. Tuy nhiên, CẨN THẬN, vì điều này sẽ vô hiệu hóa bảo vệ hoàn toàn. Đừng làm điều này trên máy chủ sản xuất của bạn.
setenforce 0
Nếu bạn không còn gặp sự cố với SELinux nữa, thì đây là nguyên nhân gốc rễ.
Để giải quyết nó , bạn sẽ phải cấu hình SELinux tương ứng.
Các loại bối cảnh sau đây sẽ là cần thiết:
httpd_sys_content_t
cho các tệp mà bạn muốn máy chủ của bạn có thể đọc được
httpd_sys_rw_content_t
cho các tệp mà bạn muốn truy cập đọc và ghi
httpd_log_t
cho các tệp nhật ký
httpd_cache_t
cho thư mục bộ đệm
Ví dụ: để gán httpd_sys_content_t
loại ngữ cảnh cho thư mục gốc trang web của bạn, hãy chạy:
semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root
Nếu tệp của bạn nằm trong thư mục chính, bạn cũng sẽ cần bật httpd_enable_homedirs
boolean:
setsebool -P httpd_enable_homedirs 1
Trong mọi trường hợp, có thể có nhiều lý do tại sao SELinux sẽ từ chối quyền truy cập vào một tệp, tùy thuộc vào chính sách của bạn. Vì vậy, bạn sẽ cần phải hỏi về điều đó. Dưới đây là hướng dẫn cụ thể về cách định cấu hình SELinux cho máy chủ web.
3. Symfony
Nếu bạn đang sử dụng Symfony và gặp phải lỗi này khi tải lên máy chủ thì có thể bộ nhớ cache của ứng dụng chưa được đặt lại, vì app/cache
đã được tải lên hoặc bộ đệm đó chưa bị xóa.
Bạn có thể kiểm tra và sửa lỗi này bằng cách chạy lệnh console sau:
cache:clear
4. Các ký tự không ACSII trong tệp Zip
Rõ ràng, lỗi này cũng có thể xảy ra khi gọi zip->close()
khi một số tệp trong zip có các ký tự không phải ASCII trong tên tệp của chúng, chẳng hạn như "é".
Một giải pháp tiềm năng là bọc tên tệp utf8_decode()
trước khi tạo tệp đích.
Tín dụng cho Fran Cano để xác định và đề xuất giải pháp cho vấn đề này