PHP 스크립트에서 호출 여부 include()
, require()
, fopen()
등, 또는 이들의 유도체 include_once
, require_once
또는 심지어, move_uploaded_file()
하나는 종종 오류 또는 경고로 실행 :
스트림을 열지 못했습니다 : 해당 파일이나 디렉토리가 없습니다.
문제의 근본 원인을 빨리 찾는 좋은 방법은 무엇입니까?
PHP 스크립트에서 호출 여부 include()
, require()
, fopen()
등, 또는 이들의 유도체 include_once
, require_once
또는 심지어, move_uploaded_file()
하나는 종종 오류 또는 경고로 실행 :
스트림을 열지 못했습니다 : 해당 파일이나 디렉토리가 없습니다.
문제의 근본 원인을 빨리 찾는 좋은 방법은 무엇입니까?
답변:
이 오류가 발생할 수있는 여러 가지 이유가 있으므로 먼저 확인해야 할 사항에 대한 점검표가 상당히 도움이됩니다.
다음 줄의 문제를 해결한다고 가정 해 보겠습니다.
require "/path/to/file"
또는 호출 한 것을 자신의 변수 로 옮기 require*
거나 include*
복사하고 복사 한 후 터미널에서 액세스 해보십시오.
$path = "/path/to/file";
echo "Path : $path";
require "$path";
그런 다음 터미널에서 :
cat <file path pasted>
/users/tony/htdocs
모범 사례 :
런타임시 절대 경로를 생성하면서 주위를 움직일 때 스크립트를 강력하게 만들기 위해 두 가지 옵션이 있습니다.
require __DIR__ . "/relative/path/from/current/file"
. __DIR__
마법 상수는 현재 파일의 디렉토리를 반환합니다.SITE_ROOT
상수를 직접 정의 하십시오.
config.php
에 config.php
쓰고
define('SITE_ROOT', __DIR__);
사이트 루트 폴더를 참조하려는 모든 파일에서를 포함하고 원하는 곳 config.php
에서 SITE_ROOT
상수 를 사용하십시오 .
require_once __DIR__."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
이 두 가지 방법은 포함 경로와 같은 ini 설정에 의존하지 않기 때문에 응용 프로그램의 이식성을 향상시킵니다.
상대적으로 또는 절대적으로 절대적으로 파일을 포함하지 않는 또 다른 방법은 include 경로 에 의존하는 것 입니다. Zend 프레임 워크와 같은 라이브러리 또는 프레임 워크의 경우가 종종 있습니다.
이러한 포함은 다음과 같습니다.
include "Zend/Mail/Protocol/Imap.php"
이 경우 "Zend"가있는 폴더가 포함 경로의 일부인지 확인해야합니다.
다음을 사용하여 포함 경로를 확인할 수 있습니다.
echo get_include_path();
다음을 사용하여 폴더를 추가 할 수 있습니다.
set_include_path(get_include_path().":"."/path/to/new/folder");
서버 프로세스 (Apache 또는 PHP)를 실행하는 사용자에게는 해당 파일을 읽거나 쓸 수있는 권한이 없을 수 있습니다.
서버가 실행중인 사용자를 확인하려면 posix_getpwuid 를 사용할 수 있습니다 .
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
파일에 대한 권한을 찾으려면 터미널에 다음 명령을 입력하십시오.
ls -l <path/to/file>
권한 기호 표기법을 봅니다.
위의 방법 중 어느 것도 작동하지 않으면 일부 PHP 설정으로 인해 해당 파일에 액세스하는 것이 금지되었을 수 있습니다.
세 가지 설정이 관련 될 수 있습니다.
phpinfo()
또는 사용하여 확인할 수 있습니다ini_get("open_basedir")
ini_get("allow_url_include")
하고 설정할 수 있습니다ini_set("allow_url_include", "1")
위의 방법으로 문제를 진단 할 수없는 경우 다음과 같은 특별한 상황이 발생할 수 있습니다.
상대 경로 또는 절대 경로를 사용하여 Zend 프레임 워크와 같은 라이브러리를 포함시킬 수 있습니다. 예를 들면 다음과 같습니다.
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
그러나 여전히 같은 종류의 오류가 발생합니다.
포함 된 파일 (성공적으로)에 다른 파일에 대한 include 문이 있고 두 번째 include 문은 해당 라이브러리의 경로를 include 경로에 추가했다고 가정하기 때문에 발생할 수 있습니다.
예를 들어 앞에서 언급 한 Zend 프레임 워크 파일은 다음과 같습니다.
include "Zend/Mail/Protocol/Exception.php"
상대 경로 또는 절대 경로에 의한 포함이 아닙니다. Zend 프레임 워크 디렉토리가 포함 경로에 추가되었다고 가정합니다.
이 경우 실용적인 해결책은 포함 경로에 디렉토리를 추가하는 것입니다.
Security-Enhanced Linux를 실행중인 경우 서버에서 파일에 대한 액세스를 거부하여 문제의 원인 일 수 있습니다.
시스템에서 SELinux가 사용 가능한지 확인하려면sestatus
터미널 에서 명령을 실행하십시오 . 명령이 존재하지 않으면 시스템에 SELinux가없는 것입니다. 존재하는 경우 적용 여부를 알려야합니다.
SELinux 정책이 문제 의 원인인지 확인하려면 일시적으로 해제하십시오. 그러나 보호 기능이 완전히 비활성화되므로 신중해야합니다. 프로덕션 서버에서는이 작업을 수행하지 마십시오.
setenforce 0
SELinux를 끄는 데 더 이상 문제가 없으면 이것이 근본 원인입니다.
이를 해결하려면 SELinux를 적절히 구성해야합니다.
다음과 같은 컨텍스트 유형이 필요합니다.
httpd_sys_content_t
서버가 읽을 수있는 파일httpd_sys_rw_content_t
읽기 및 쓰기 액세스를 원하는 파일httpd_log_t
로그 파일httpd_cache_t
캐시 디렉토리예를 들어, httpd_sys_content_t
컨텍스트 유형을 웹 사이트 루트 디렉토리에 지정하려면 다음을 실행하십시오.
semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root
파일이 홈 디렉토리에 있으면 httpd_enable_homedirs
부울 을 켜야합니다 .
setsebool -P httpd_enable_homedirs 1
어쨌든 SELinux가 정책에 따라 파일에 대한 액세스를 거부하는 여러 가지 이유가있을 수 있습니다. 그래서 당신은 그것에 문의해야합니다. 다음 은 웹 서버용 SELinux 구성에 대한 자습서입니다.
Symfony를 사용 중이고 서버에 업로드 할 때이 오류가 발생하는 경우 업로드 app/cache
되었거나 캐시가 지워지지 않아 앱의 캐시가 재설정되지 않았을 수 있습니다 .
다음 콘솔 명령을 실행하여이를 테스트하고 수정할 수 있습니다.
cache:clear
zip->close()
zip 내부의 일부 파일에 파일 이름에 ASCII가 아닌 문자 (예 : "é")가있는 경우 호출 할 때도이 오류가 발생할 수 있습니다 .
잠재적 인 해결책은 utf8_decode()
대상 파일을 작성하기 전에 파일 이름을 랩핑하는 것 입니다.
크레딧 프랜 카노 이 문제에 대한 해결책을 식별하고 제안에 대한
selinux
여기에 대한 언급이 좋은 생각이라고 생각합니다. 당신은 필요 이상이어야합니다 httpd_sys_content_t
포함 된 파일에 허가 (아파치가 사용하는 읽기 전용 디렉토리와 파일).
chcon
일시적이며 restorecon
재부팅 또는 재부팅 후에도 지속되지 않습니다 . semanage
파일 컨텍스트를 변경하는 데 사용해야 할 수도 있습니다 . 다음은 정상의 인 웹 사이트에 대한 간단한 튜토리얼
(정말로 좋은) 기존 답변에 추가하려면
open_basedir
웹 서버 구성에서 지정할 수 있기 때문에 사용자를 방해 할 수 있습니다. 고유 한 전용 서버를 실행하면이 문제를 쉽게 해결할 수 있지만 Plesk, cPanel 등과 같은 일부 공유 호스팅 소프트웨어 패키지는 도메인별로 구성 지시문을 구성합니다. 소프트웨어가 구성 파일 (예 :)을 빌드 httpd.conf
하기 때문에 호스팅 소프트웨어는 다시 시작할 때 파일을 덮어 쓰기 때문에 해당 파일을 직접 변경할 수 없습니다.
Plesk를 함께, 그들은 제공된 오버라이드 (override) 할 수있는 장소 제공 httpd.conf
이라고를 vhost.conf
. 서버 관리자 만이 파일을 쓸 수 있습니다. Apache의 구성은 다음과 같습니다
<Directory /var/www/vhosts/domain.com>
<IfModule mod_php5.c>
php_admin_flag engine on
php_admin_flag safe_mode off
php_admin_value open_basedir "/var/www/vhosts/domain.com:/tmp:/usr/share/pear:/local/PEAR"
</IfModule>
</Directory>
서버 관리자가 사용하는 호스팅 및 웹 서버 소프트웨어 설명서를 참조하십시오.
웹 서버를 통해 파일을 실행하는 것은 명령 행 또는 크론 작업 실행과 매우 다르다는 점에 유의해야합니다. 가장 큰 차이점은 웹 서버에 자체 사용자 및 권한이 있다는 것입니다. 보안상의 이유로 사용자는 상당히 제한되어 있습니다. 예를 들어 Apache는 종종 apache
( www-data
또는 httpd
서버에 따라)입니다. 크론 작업 또는 CLI 실행에는 사용자가 실행하는 모든 권한이 있습니다 (예 : 루트로 PHP 스크립트를 실행하면 root 권한으로 실행 됨).
많은 사람들이 다음을 수행하여 권한 문제를 해결할 것입니다 (Linux 예제).
chmod 777 /path/to/file
파일이나 디렉토리가 이제 세계 쓰기 가능하기 때문에 이것은 현명한 아이디어가 아닙니다. 서버를 소유하고 있고 유일한 사용자 인 경우에는 큰 문제가되지 않지만 공유 호스팅 환경에있는 경우 서버의 모든 사용자에게 서버 액세스 권한을 부여한 것입니다.
액세스가 필요한 사용자를 결정하고 해당 사용자에게만 액세스 권한을 부여하면됩니다. 어떤 사용자가 액세스해야하는지 알고 나면
해당 사용자는 파일 및 상위 디렉토리 (특히 파일을 작성하려는 경우 상위 디렉토리)를 소유합니다 . 대부분의 공유 호스팅 환경에서는 사용자가 루트 아래에있는 모든 파일을 소유해야하므로 문제가되지 않습니다. 리눅스 예제는 아래와 같습니다.
chown apache:apache /path/to/file
사용자 및 해당 사용자 만 액세스 할 수 있습니다. 리눅스에서 좋은 습관은 chmod 600
(소유자 만 읽고 쓸 수 있음) 또는 chmod 644
(소유자는 쓸 수 있지만 누구나 읽을 수 있음)
내 코드는 모든 컴퓨터에서 제대로 작동했지만이 코드에서만 문제가 발생하기 시작했습니다. 에코 "document_root"경로를 디버깅에 사용하고 오류를 자세히 살펴 보았습니다.
경고 : include ( D : /MyProjects/testproject//functions/connections.php ) : 스트림을 열지 못했습니다 :
문제가있는 위치를 쉽게 확인할 수 있습니다. 문제는 // 함수 전입니다
$document_root = $_SERVER['DOCUMENT_ROOT'];
echo "root: $document_root";
include($document_root.'/functions/connections.php');
따라서 단순히 래딩 /를 포함에서 제거하면 정상적으로 작동합니다. 흥미로운 점은이 동작이 버전마다 다릅니다. 랩톱, Macbook Pro 및이 PC에서 동일한 코드를 실행하면 모두 정상적으로 작동했습니다. 이것이 누군가를 돕기를 바랍니다.
그게 내 사건이야 실제로는 질문 # 4485874 에 연결되지만 여기서는 곧 설명하겠습니다.
을 요구하려고 할 때 path/to/script.php?parameter=value
, PHP는 script.php?parameter=value
UNIX에서 이와 같은 경로를 가질 수 있기 때문에 이라는 파일을 찾습니다 .
당신이 정말로, 포함 된 스크립트로 일부 데이터를 전달해야 할 경우 단지로 선언 $variable=...
또는 $GLOBALS[]=...
당신 같은 또는 다른 방법.
삼바 주식
Linux 테스트 서버가 있고 Windows 클라이언트에서 작업하는 경우 Samba 공유가 chmod 명령을 방해합니다 . 따라서 다음을 사용하더라도
chmod -R 777 myfolder
리눅스 측면에서 유닉스 그룹 \ www-data가 여전히 쓰기 액세스 권한을 가지고 있지 않을 수 있습니다. 공유가 Windows 관리자가 루트에 매핑되도록 설정 한 경우의 한 가지 해결 방법 : Windows에서 권한을 열고 복사하여 폴더의 상속을 비활성화 한 다음 www-data에 대한 모든 액세스 권한을 부여하십시오.
또 다른 가능한 원인 : 텍스트 편집기에서 파일 이름 바꾸기 및 / 또는 파일 이동. 이 오류가 계속 발생하는 파일을 삭제하고 새 파일을 작성하여 문제를 해결하기 전까지 위의 모든 단계를 성공하지 못했습니다.