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


166

PHP 스크립트에서 호출 여부 include(), require(), fopen()등, 또는 이들의 유도체 include_once, require_once또는 심지어, move_uploaded_file()하나는 종종 오류 또는 경고로 실행 :

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

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


5
이 게시물에 대한 주제 외 의견을 정리했습니다. 메타 토론은 메타로 유지하십시오. 그러나 정식 질문 실행 가능성에 대한 논의는 계속해서 반복되었습니다. 여기 예를 참조 하십시오 .
Madara 's Ghost

1
나는 똑같은 문제가 있는데, 항상 효과가 있었던 유일한 해결책은 다음과 같습니다. 2- 포함하십시오. 실제로 나는이 질문에 대한 답을 얻었고 그 대답은 검증되었지만, 어떤 경우에는 위에 설명 된 방법을 찾을 때까지 작동하지 않았다.
Rshad

기여해 주셔서 감사합니다. 불행히도 솔루션은 잘못된 경로 이름을 언급하기 때문에 잘못되었습니다. 이것이 잘못된 이유는 프로젝트를 다른 곳으로 복사하거나 컴퓨터 내부로 옮기는 순간 모든 것이 망가지기 때문입니다.
Vic Seedoubleyew

답변:


259

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

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

require "/path/to/file"


점검표


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_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 구성에 대한 자습서입니다.


3. 심포니

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

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

cache:clear


4. Zip 파일 내의 비 ACSII 문자

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

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

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


4
나는 selinux여기에 대한 언급이 좋은 생각이라고 생각합니다. 당신은 필요 이상이어야합니다 httpd_sys_content_t포함 된 파일에 허가 (아파치가 사용하는 읽기 전용 디렉토리와 파일).
bansi

제안 해 주셔서 감사합니다. SELinux에 익숙하지 않기 때문에 몇 가지를 읽고이 사건에 대답하려고했습니다. 정확하지 않은 경우 의견을 보내거나 수정 사항을 제안 해주세요. 의견에 다시 한번 감사드립니다!
Vic Seedoubleyew

chcon일시적이며 restorecon재부팅 또는 재부팅 후에도 지속되지 않습니다 . semanage파일 컨텍스트를 변경하는 데 사용해야 할 수도 있습니다 . 다음은 정상의 인 웹 사이트에 대한 간단한 튜토리얼
bansi은

추가 할 수있는 또 다른 가능성 : realpath 캐싱 : lyte.id.au/2014/05/01/what-the-hell-php
chrishiestand

@ chrishiestand 감사합니다! 그 기사는 정말 흥미 롭습니다! 그 오류를 일으킨 사건의 과정을 기억하십니까? 처음에 사용자가 파일에 대한 읽기 액세스 권한을 가지고 있지 않았으며 변경되었지만 캐시가 여전히 읽을 수 없다고 간주했기 때문에 파일을 열 때 오류가 발생합니까?
빅 Seedoubleyew

16

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

공유 호스팅 소프트웨어

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

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

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

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

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

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


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

아래 체크리스트의 1 단계와 어떻게 다른가요?
Vic Seedoubleyew

2 단계 1 단계와 관련되지 않은 추가 검사 브라우저에서 제안 된 경로로 이동하여 파일이 표시되는지 확인하십시오 (Windows 탐색기는 없지만 브라우저에서는).
Hammad Khan

2

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

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


2

삼바 주식

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

chmod -R 777 myfolder

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


1

또 다른 가능한 원인 : 텍스트 편집기에서 파일 이름 바꾸기 및 / 또는 파일 이동. 이 오류가 계속 발생하는 파일을 삭제하고 새 파일을 작성하여 문제를 해결하기 전까지 위의 모든 단계를 성공하지 못했습니다.


1
내가 무슨 뜻인지 제대로 이해한다면, 목록의 첫 번째 확인으로 문제가 발생했을 것입니다.
Vic Seedoubleyew

# 1은 잠재적 인 원인에 대해 명시 적이 지 않습니다
zMeadz

그렇습니다. 그러나 원인에 대해서는 신경 쓰지 않고 문제를 해결하는 방법을 찾으십시오. 더 중요한 것은 1 단계가 문제를 해결했을 것입니다
Vic Seedoubleyew
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.