PHP-스트림을 열지 못했습니다 : 해당 파일이나 디렉토리가 없습니다

php require fopen include-path


PHP 스크립트에서 include() , require() , fopen() 또는 include_once , require_once , 심지어 move_uploaded_file() 과 같은 파생어를 호출하든 종종 오류 또는 경고가 발생합니다.

스트림을 열지 못했습니다 : 해당 파일이나 디렉토리가 없습니다.

문제의 근본 원인을 빨리 찾는 좋은 방법은 무엇입니까?




Answer 1 Vic Seedoubleyew


이 오류가 발생할 수있는 여러 가지 이유가 있으므로 먼저 확인해야 할 사항에 대한 점검표가 상당히 도움이됩니다.

다음 줄의 문제를 해결한다고 가정 해 보겠습니다.

require "/path/to/file"


Checklist


1. 파일 경로에 오타가 있는지 확인

  • 수동으로 확인 (경로를 시각적으로 확인)
  • 또는 require* 또는 include* 에 의해 호출 된 것을 자신의 변수 로 옮기고 , 에코하고, 복사 한 후 터미널에서 액세스 해보십시오.

    $path = "/path/to/file";
    
    echo "Path : $path";
    
    require "$path";

    그런 다음 터미널에서 :

    cat <file path pasted>


2. 상대 경로와 절대 경로를 고려하여 파일 경로가 올바른지 확인하십시오.

  • 슬래시 "/"로 시작하면 웹 사이트 폴더의 루트 (문서 루트)가 아니라 서버의 루트입니다.
    • 예를 들어, 웹 사이트의 디렉토리는 /users/tony/htdocs 일 수 있습니다.
  • 슬래시로 시작하지 않으면 포함 경로 (아래 참조)에 의존하거나 경로가 상대적입니다. 상대적인 경우 PHP는 현재 작업 디렉토리 의 경로를 상대적으로 계산 합니다.
    • 따라서 웹 사이트 루트의 경로 또는 입력하는 파일과 관련이 없습니다.
    • 따라서 항상 절대 파일 경로를 사용하십시오

모범 사례 :

런타임시 절대 경로를 생성하면서 주위를 움직일 때 스크립트를 강력하게 만들려면 두 가지 옵션이 있습니다.

  1. 사용 require __DIR__ . "/relative/path/from/current/file" . __DIR__ 의 마법 상수는 현재 파일의 디렉토리를 반환합니다.
  2. 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 설정에 의존하지 않기 때문에 응용 프로그램의 이식성을 향상시킵니다.


3. 포함 경로 확인

상대적으로 또는 절대적으로 절대적으로 파일을 포함하지 않는 또 다른 방법은 include 경로 에 의존하는 것 입니다. Zend 프레임 워크와 같은 라이브러리 또는 프레임 워크의 경우가 종종 있습니다.

이러한 포함은 다음과 같습니다.

include "Zend/Mail/Protocol/Imap.php"

이 경우 "Zend"가있는 폴더가 포함 경로의 일부인지 확인해야합니다.

다음을 사용하여 포함 경로를 확인할 수 있습니다.

echo get_include_path();

다음을 사용하여 폴더를 추가 할 수 있습니다.

set_include_path(get_include_path().":"."/path/to/new/folder");


4. 서버가 해당 파일에 액세스 할 수 있는지 확인하십시오

서버 프로세스 (Apache 또는 PHP)를 실행하는 사용자에게는 해당 파일을 읽거나 쓸 수있는 권한이 없을 수 있습니다.

서버가 실행중인 사용자를 확인하려면 posix_getpwuid 를 사용할 수 있습니다 .

$user = posix_getpwuid(posix_geteuid());

var_dump($user);

파일에 대한 권한을 찾으려면 터미널에 다음 명령을 입력하십시오.

ls -l <path/to/file>

권한 기호 표기법을 봅니다.


5. PHP 설정 확인

위의 방법 중 어느 것도 작동하지 않으면 일부 PHP 설정으로 인해 해당 파일에 액세스하는 것이 금지되었을 수 있습니다.

세 가지 설정이 관련 될 수 있습니다.

  1. open_basedir
    • 이것이 설정되면 PHP는 지정된 디렉토리 외부 (심볼릭 링크를 통해서도) 외부의 어떤 파일에도 접근 할 수 없습니다.
    • 그러나 기본 동작은 설정되어 있지 않아야하며,이 경우 제한이 없습니다.
    • phpinfo() 를 호출 하거나 ini_get("open_basedir") 을 사용하여 확인할 수 있습니다.
    • php.ini 파일 또는 httpd.conf 파일을 편집하여 설정을 변경할 수 있습니다
  2. 안전 모드
    • 이것이 켜져 있으면 제한이 적용될 수 있습니다. 그러나 이것은 PHP 5.4에서 제거되었습니다. 안전 모드를 지원하는 버전을 계속 사용중인 경우 여전히 지원되는 PHP 버전으로 업그레이드하십시오 .
  3. allow_url_fopen 및 allow_url_include
    • 이것은 로컬 파일 시스템에 파일을 포함하려고 할 때가 아닌 http : //와 같은 네트워크 프로세스를 통해 파일을 포함하거나 여는 경우에만 적용됩니다
    • 이것은 ini_get("allow_url_include") 로 확인 하고 ini_set("allow_url_include", "1") 설정할 수 있습니다


코너 케이스

위의 방법으로 문제를 진단 할 수없는 경우 다음과 같은 특별한 상황이 발생할 수 있습니다.


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 프레임 워크 디렉토리가 포함 경로에 추가되었다고 가정합니다.

이 경우 실용적인 해결책은 포함 경로에 디렉토리를 추가하는 것입니다.


2. SELinux

Security-Enhanced Linux를 실행중인 경우 서버에서 파일에 대한 액세스를 거부하여 문제의 원인 일 수 있습니다.

시스템에서 SELinux가 사용 가능한지 확인하려면 터미널에서 sestatus 명령을 실행하십시오 . 명령이 존재하지 않으면 시스템에 SELinux가없는 것입니다. 존재하는 경우 적용 여부를 알려야합니다.

SELinux 정책이 문제 의 원인인지 확인하려면 일시적으로 해제하십시오. 그러나 보호 기능이 완전히 비활성화되므로 신중해야합니다. 프로덕션 서버에서는이 작업을 수행하지 마십시오.

setenforce 0

SELinux를 끄는 데 더 이상 문제가 없으면 이것이 근본 원인입니다.

이를 해결하려면 SELinux를 적절히 구성해야합니다.

다음과 같은 컨텍스트 유형이 필요합니다.

  • httpd_sys_content_t 서버가 읽을 수있는 파일에 대한 httpd_sys_content_t
  • httpd_sys_rw_content_t 읽기 및 쓰기 액세스를 원하는 파일의 경우 httpd_sys_rw_content_t
  • httpd_log_t 로그 파일에 대한 httpd_log_t
  • httpd_cache_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 구성에 대한 자습서입니다.


3. 심포니

Symfony를 사용 중이고 서버에 업로드 할 때이 오류가 발생하면 app/cache 가 업로드되었거나 캐시가 지워지지 않았기 때문에 앱 의 캐시가 재설정되지 않았을 수 있습니다 .

다음 콘솔 명령을 실행하여이를 테스트하고 수정할 수 있습니다.

cache:clear


4. Zip 파일 내의 비 ACSII 문자

zip 내의 일부 파일에 파일 이름에 ASCII가 아닌 문자 (예 : "é" zip->close() 경우 zip-> close () 를 호출 할 때도이 오류가 발생할 수 있습니다 .

잠재적 인 해결책은 대상 파일을 작성하기 전에 파일 이름을 utf8_decode() 로 랩핑하는 것 입니다.

크레딧 프랜 카노 이 문제에 대한 해결책을 식별하고 제안에 대한




Answer 2 Machavity


(정말로 좋은) 기존 답변에 추가하려면

공유 호스팅 소프트웨어

open_basedir 은 웹 서버 구성에서 지정할 수 있기 때문에 문제를 일으킬 수 있습니다. 고유 한 전용 서버를 실행하면이 문제를 쉽게 해결할 수 있지만 Plesk, cPanel 등의 일부 도메인에 따라 구성 지시문을 구성하는 공유 호스팅 소프트웨어 패키지가 있습니다. 소프트웨어는 구성 파일 (예 : httpd.conf )을 빌드 하므로 호스팅 소프트웨어는 다시 시작할 때 파일을 덮어 쓰기 때문에 해당 파일을 직접 변경할 수 없습니다.

Plesk를 사용하면 vhost.conf 라는 제공된 httpd.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

파일 또는 디렉토리가 이제 세계 쓰기 가능하므로 이것은 현명한 아이디어가 아닙니다. 서버를 소유하고 있고 유일한 사용자 인 경우에는 큰 문제가되지 않지만 공유 호스팅 환경에있는 경우 서버의 모든 사용자에게 액세스 권한을 부여한 것입니다.

액세스가 필요한 사용자를 결정하고 해당 사용자에게만 액세스 권한을 부여하면됩니다. 어떤 사용자가 액세스해야하는지 알고 나면

  1. 해당 사용자는 파일 및 상위 디렉토리 (특히 파일을 작성하려는 경우 상위 디렉토리)를 소유합니다 . 대부분의 공유 호스팅 환경에서는 사용자가 루트 아래에있는 모든 파일을 소유해야하므로 문제가되지 않습니다. 리눅스 예제는 아래와 같습니다.

    chown apache:apache /path/to/file
  2. 사용자 및 해당 사용자 만 액세스 할 수 있습니다. Linux에서는 chmod 600 (소유자 만 읽고 쓸 수 있음) 또는 chmod 644 (소유자는 쓸 수 있지만 누구나 읽을 수 있음) 가 좋습니다.

여기에서 Linux / Unix 권한 및 사용자에 대한 자세한 설명을 읽을 수 있습니다.




Answer 3 Hammad Khan


  1. 정확한 오류를 봐

내 코드는 모든 컴퓨터에서 제대로 작동했지만이 코드에서만 문제가 발생하기 시작했습니다. 에코 "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에서 동일한 코드를 실행하면 모두 정상적으로 작동했습니다. 이것이 누군가를 돕기를 바랍니다.

  1. 브라우저에서 파일 위치를지나 복사하여 파일이 있는지 확인하십시오. 때로는 파일이 예기치 않게 삭제되고 (나와 함께 발생) 내 경우에도 문제가되었습니다.



Answer 4 Paul Lynn


쿼리 매개 변수가있는 스크립트 추가

그게 내 사건이야 실제로는 질문 # 4485874 에 연결되지만 여기서는 곧 설명하겠습니다.
당신이 필요로 할 때 path/to/script.php?parameter=value 라는 이름의 파일, PHP의 모습을 script.php?parameter=value UNIX는 수 있기 때문에,이 같은 경로가 있습니다.
포함 된 스크립트에 일부 데이터를 전달해야하는 경우 $variable=... 또는 $GLOBALS[]=... 또는 다른 방법으로 선언하십시오 .




Answer 5 Stephan Brunker


삼바 주식

Linux 테스트 서버가 있고 Windows 클라이언트에서 작업하는 경우 Samba 공유가 chmod 명령을 방해합니다 . 따라서 다음을 사용하더라도

chmod -R 777 myfolder

리눅스 측면에서 유닉스 그룹 \ www-data가 여전히 쓰기 액세스 권한을 가지고 있지 않을 수 있습니다. 공유가 Windows 관리자가 루트에 매핑되도록 설정 한 경우의 한 가지 해결 방법 : Windows에서 권한을 열고 복사하여 폴더의 상속을 비활성화 한 다음 www-data에 대한 모든 액세스 권한을 부여하십시오.