PHP - Stream konnte nicht geöffnet werden: Keine solche Datei oder kein solches Verzeichnis

166

In PHP - Skripte, ob Aufruf include(), require(), fopen(), oder deren Derivate, wie include_once, require_onceoder sogar, move_uploaded_file()läuft man oft in einen Fehler oder eine Warnung:

Fehler beim Öffnen des Streams: Keine solche Datei oder kein solches Verzeichnis.

Was ist ein guter Prozess, um die Grundursache des Problems schnell zu finden?

Vic Seedoubleyew
quelle
5
Ich habe die Off-Topic-Kommentare zu diesem Beitrag bereinigt. Bitte halten Sie Metadiskussionen in Meta. Bitte beachten Sie jedoch, dass die Diskussion über die Lebensfähigkeit kanonischer Fragen immer und immer wieder durchgeführt wurde. Siehe Beispiel hier .
Madaras Geist
1
Ich habe das gleiche Problem, die einzige Lösung, die immer funktioniert hat, ist: -1 Gehen Sie zu der Datei, um die Eigenschaften einzuschließen, und kopieren Sie den vollständigen Pfad. Beispiel: C: /......../ file.php 2- schließen Sie es ein. Eigentlich habe ich gesehen, dass diese Frage beantwortet und die Antwort validiert wurde, aber für mich hat es in einigen Fällen nicht funktioniert, bis ich den oben beschriebenen Weg gefunden habe.
Rshad
@Rash danke für deinen Beitrag. Leider ist Ihre Lösung falsch, da der absolute Pfadname erwähnt wird, und das ist falsch. Der Grund, warum dies falsch ist, liegt darin, dass in dem Moment, in dem Sie Ihr Projekt an einen anderen Ort kopieren oder in Ihren Computer verschieben, alles kaputt geht.
Vic Seedoubleyew

Antworten:

259

Es gibt viele Gründe, warum dieser Fehler auftreten kann, und daher hilft eine gute Checkliste, was zuerst überprüft werden muss, erheblich.

Nehmen wir an, wir beheben die folgende Zeile:

require "/path/to/file"


Checkliste


1. Überprüfen Sie den Dateipfad auf Tippfehler

  • entweder manuell überprüfen (indem Sie den Pfad visuell überprüfen)
  • oder verschieben Sie alles, was von require*oder include*in eine eigene Variable aufgerufen wird , geben Sie es wieder, kopieren Sie es und versuchen Sie, von einem Terminal aus darauf zuzugreifen:

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

    Dann in einem Terminal:

    cat <file path pasted>


2. Überprüfen Sie, ob der Dateipfad in Bezug auf relative und absolute Pfadüberlegungen korrekt ist

  • Wenn es mit einem Schrägstrich "/" beginnt, bezieht es sich nicht auf das Stammverzeichnis des Ordners Ihrer Website (das Dokumentstammverzeichnis), sondern auf das Stammverzeichnis Ihres Servers.
    • Das Verzeichnis Ihrer Website könnte beispielsweise sein /users/tony/htdocs
  • Wenn es nicht mit einem Schrägstrich beginnt, stützt es sich entweder auf den Include-Pfad (siehe unten) oder der Pfad ist relativ. Wenn es relativ ist, berechnet PHP relativ zum Pfad des aktuellen Arbeitsverzeichnisses .
    • Daher nicht relativ zum Pfad des Stammverzeichnisses Ihrer Website oder zu der Datei, in die Sie eingeben
    • Verwenden Sie daher immer absolute Dateipfade

Empfohlene Vorgehensweise :

Um Ihr Skript robust zu machen, falls Sie Dinge verschieben und gleichzeitig zur Laufzeit einen absoluten Pfad generieren, haben Sie zwei Möglichkeiten:

  1. verwenden require __DIR__ . "/relative/path/from/current/file". Die __DIR__magische Konstante gibt das Verzeichnis der aktuellen Datei zurück.
  2. Definieren Sie selbst eine SITE_ROOTKonstante:

    • Erstellen Sie im Stammverzeichnis Ihrer Website eine Datei, z config.php
    • in config.php, schreibe

      define('SITE_ROOT', __DIR__);
    • Fügen Sie in jede Datei, in der Sie auf den Site-Stammordner verweisen möchten, config.phpdie SITE_ROOTKonstante ein und verwenden Sie sie, wo immer Sie möchten :

      require_once __DIR__."/../config.php";
      ...
      require_once SITE_ROOT."/other/file.php";

Diese beiden Methoden machen Ihre Anwendung auch portabler, da sie nicht auf INI-Einstellungen wie dem Include-Pfad basiert.


3. Überprüfen Sie Ihren Include-Pfad

Eine andere Möglichkeit, Dateien weder relativ noch rein absolut einzuschließen , besteht darin, sich auf den Einschlusspfad zu verlassen . Dies ist häufig bei Bibliotheken oder Frameworks wie dem Zend-Framework der Fall.

Eine solche Aufnahme sieht folgendermaßen aus:

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

In diesem Fall sollten Sie sicherstellen, dass der Ordner, in dem sich "Zend" befindet, Teil des Include-Pfads ist.

Sie können den Include-Pfad überprüfen mit:

echo get_include_path();

Sie können einen Ordner hinzufügen mit:

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


4. Überprüfen Sie, ob Ihr Server Zugriff auf diese Datei hat

Es kann sein, dass der Benutzer, der den Serverprozess ausführt (Apache oder PHP), einfach keine Berechtigung zum Lesen oder Schreiben in diese Datei hat.

Um zu überprüfen, unter welchem ​​Benutzer der Server ausgeführt wird, können Sie posix_getpwuid verwenden :

$user = posix_getpwuid(posix_geteuid());

var_dump($user);

Geben Sie den folgenden Befehl in das Terminal ein, um die Berechtigungen für die Datei herauszufinden:

ls -l <path/to/file>

und schauen Sie sich die symbolische Notationsnotation an


5. Überprüfen Sie die PHP-Einstellungen

Wenn keines der oben genannten Verfahren funktioniert hat, besteht das Problem wahrscheinlich darin, dass einige PHP-Einstellungen den Zugriff auf diese Datei untersagen.

Drei Einstellungen könnten relevant sein:

  1. open_basedir
    • Wenn dies eingestellt ist, kann PHP nicht auf Dateien außerhalb des angegebenen Verzeichnisses zugreifen (nicht einmal über einen symbolischen Link).
    • Das Standardverhalten ist jedoch, dass es nicht festgelegt wird. In diesem Fall gibt es keine Einschränkung
    • Dies kann entweder durch Aufrufen phpinfo()oder durch Verwenden überprüft werdenini_get("open_basedir")
    • Sie können die Einstellung ändern, indem Sie entweder Ihre php.ini-Datei oder Ihre httpd.conf-Datei bearbeiten
  2. Sicherheitsmodus
    • Wenn dies aktiviert ist, gelten möglicherweise Einschränkungen. Dies wurde jedoch in PHP 5.4 entfernt. Wenn Sie sich noch in einer Version befinden, die ein Upgrade im abgesicherten Modus auf eine PHP-Version unterstützt, die noch unterstützt wird .
  3. allow_url_fopen und allow_url_include
    • Dies gilt nur für das Einschließen oder Öffnen von Dateien über einen Netzwerkprozess wie http: //, nicht für den Versuch, Dateien in das lokale Dateisystem aufzunehmen
    • Dies kann mit überprüft ini_get("allow_url_include")und eingestellt werdenini_set("allow_url_include", "1")


Eckkoffer

Wenn keine der oben genannten Optionen zur Diagnose des Problems aktiviert ist, können folgende spezielle Situationen auftreten:


1. Die Aufnahme einer Bibliothek unter Verwendung des Einschlusspfads

Es kann vorkommen, dass Sie eine Bibliothek, z. B. das Zend-Framework, über einen relativen oder absoluten Pfad einschließen. Zum Beispiel :

require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"

Aber dann erhalten Sie immer noch die gleiche Art von Fehler.

Dies kann passieren, weil die Datei, die Sie (erfolgreich) aufgenommen haben, selbst eine include-Anweisung für eine andere Datei hat und diese zweite include-Anweisung davon ausgeht, dass Sie den Pfad dieser Bibliothek zum include-Pfad hinzugefügt haben.

Die zuvor erwähnte Zend-Framework-Datei kann beispielsweise Folgendes enthalten:

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

Dies ist weder eine Einbeziehung durch den relativen Pfad noch durch den absoluten Pfad. Es wird davon ausgegangen, dass das Zend-Framework-Verzeichnis zum Include-Pfad hinzugefügt wurde.

In einem solchen Fall besteht die einzige praktische Lösung darin, das Verzeichnis zu Ihrem Include-Pfad hinzuzufügen.


2. SELinux

Wenn Sie Security-Enhanced Linux ausführen, kann dies der Grund für das Problem sein, indem Sie den Zugriff auf die Datei vom Server aus verweigern.

Führen Sie den sestatusBefehl in einem Terminal aus, um zu überprüfen, ob SELinux auf Ihrem System aktiviert ist . Wenn der Befehl nicht vorhanden ist, befindet sich SELinux nicht auf Ihrem System. Wenn es existiert, sollte es Ihnen sagen, ob es erzwungen wird oder nicht.

Um zu überprüfen, ob SELinux-Richtlinien der Grund für das Problem sind, können Sie versuchen, es vorübergehend zu deaktivieren. Seien Sie jedoch VORSICHTIG, da dadurch der Schutz vollständig deaktiviert wird. Tun Sie dies nicht auf Ihrem Produktionsserver.

setenforce 0

Wenn Sie das Problem mit SELinux nicht mehr deaktiviert haben, ist dies die Hauptursache.

Um dies zu lösen , müssen Sie SELinux entsprechend konfigurieren.

Folgende Kontexttypen sind erforderlich:

  • httpd_sys_content_t für Dateien, die Ihr Server lesen soll
  • httpd_sys_rw_content_t für Dateien, auf die Sie Lese- und Schreibzugriff wünschen
  • httpd_log_t für Protokolldateien
  • httpd_cache_t für das Cache-Verzeichnis

httpd_sys_content_tFühren Sie beispielsweise Folgendes aus, um den Kontexttyp Ihrem Website-Stammverzeichnis zuzuweisen :

semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root

Wenn sich Ihre Datei in einem Home-Verzeichnis befindet, müssen Sie auch den httpd_enable_homedirsBooleschen Wert aktivieren:

setsebool -P httpd_enable_homedirs 1

In jedem Fall kann es verschiedene Gründe geben, warum SELinux abhängig von Ihren Richtlinien den Zugriff auf eine Datei verweigert. Sie müssen sich also danach erkundigen. Hier finden Sie ein Tutorial speziell zum Konfigurieren von SELinux für einen Webserver.


3. Symfony

Wenn Sie Symfony verwenden und dieser Fehler beim Hochladen auf einen Server auftritt, wurde der Cache der App möglicherweise nicht zurückgesetzt, entweder weil app/cacheer hochgeladen wurde oder der Cache nicht gelöscht wurde.

Sie können dies testen und beheben, indem Sie den folgenden Konsolenbefehl ausführen:

cache:clear


4. Nicht-ACSII-Zeichen in der Zip-Datei

Anscheinend kann dieser Fehler auch beim Aufrufen auftreten, zip->close()wenn einige Dateien in der Zip-Datei Nicht-ASCII-Zeichen in ihrem Dateinamen enthalten, z. B. "é".

Eine mögliche Lösung besteht darin, den Dateinamen utf8_decode()vor dem Erstellen der Zieldatei einzuschließen.

Dank an Fran Cano für die Identifizierung und den Lösungsvorschlag für dieses Problem

Vic Seedoubleyew
quelle
4
Ich denke, dass die Erwähnung selinuxhier eine gute Idee sein kann. Sie benötigen mindestens die Berechtigung httpd_sys_content_t(schreibgeschützte Verzeichnisse und von Apache verwendete Dateien) für die enthaltenen Dateien.
Bansi
Vielen Dank für den Vorschlag. Da ich mit SELinux nicht vertraut bin, habe ich etwas gelesen und versucht, diesen Fall zu beantworten. Bitte zögern Sie nicht, Feedback zu geben oder einige Änderungen vorzuschlagen, wenn dies nicht korrekt ist. Nochmals vielen Dank für den Kommentar!
Vic Seedoubleyew
chconist vorübergehend und überlebt einen restoreconoder einen Neustart nicht. Möglicherweise müssen Sie verwenden semanage, um den Kontext der Datei zu ändern. Hier ist ein gutes einfaches Tutorial für die Website
Bansi
Eine weitere Möglichkeit zum Hinzufügen: Realpath Caching: lyte.id.au/2014/05/01/what-the-hell-php
chrishiestand
@chrishiestand vielen Dank! Dieser Artikel ist wirklich interessant! Erinnerst du dich, wie die Ereignisse zu diesem Fehler geführt haben? War es so, dass der Benutzer anfangs keinen Lesezugriff auf eine Datei hatte, dann wurde sie geändert, aber der Cache hielt sie immer noch für nicht lesbar, sodass dieser Fehler beim Öffnen der Datei auftrat?
Vic Seedoubleyew
16

Zur (wirklich guten) bestehenden Antwort hinzufügen

Shared Hosting Software

open_basedirist eine, die Sie überraschen kann, weil sie in einer Webserverkonfiguration angegeben werden kann. Während dies leicht behoben werden kann, wenn Sie Ihren eigenen dedizierten Server betreiben, gibt es einige gemeinsam genutzte Hosting-Softwarepakete (wie Plesk, cPanel usw.), die eine Konfigurationsanweisung auf Domänenbasis konfigurieren. Da die Software die Konfigurationsdatei erstellt (dh httpd.conf), können Sie diese Datei nicht direkt ändern, da die Hosting-Software sie beim Neustart nur überschreibt.

Mit Plesk bieten sie einen Ort , der bereitgestellte außer Kraft zu setzen httpd.confgenannt vhost.conf. Nur der Serveradministrator kann diese Datei schreiben. Die Konfiguration für Apache sieht ungefähr so ​​aus

<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>

Lassen Sie Ihren Serveradministrator das Handbuch für die von ihm verwendete Hosting- und Webserver-Software konsultieren.

Dateiberechtigungen

Es ist wichtig zu beachten, dass sich die Ausführung einer Datei über Ihren Webserver stark von der Ausführung einer Befehlszeile oder eines Cron-Jobs unterscheidet. Der große Unterschied besteht darin, dass Ihr Webserver über eigene Benutzer und Berechtigungen verfügt. Aus Sicherheitsgründen ist dieser Benutzer ziemlich eingeschränkt. Apache, zum Beispiel, ist oft apache, www-dataoder httpd(je nach Server). Ein Cron-Job oder eine CLI-Ausführung verfügt über alle Berechtigungen, über die der Benutzer verfügt (dh das Ausführen eines PHP-Skripts als Root wird mit den Berechtigungen von Root ausgeführt).

Häufig lösen Benutzer ein Berechtigungsproblem wie folgt (Linux-Beispiel)

chmod 777 /path/to/file

Dies ist keine kluge Idee, da die Datei oder das Verzeichnis jetzt weltweit beschreibbar ist. Wenn Sie den Server besitzen und der einzige Benutzer sind, ist dies keine große Sache. Wenn Sie sich jedoch in einer gemeinsam genutzten Hosting-Umgebung befinden, haben Sie gerade allen Benutzern Ihres Servers Zugriff gewährt.

Sie müssen lediglich die Benutzer ermitteln, die Zugriff benötigen, und nur diesen Benutzern Zugriff gewähren. Sobald Sie wissen, welche Benutzer Zugriff benötigen, möchten Sie dies sicherstellen

  1. Dieser Benutzer besitzt die Datei und möglicherweise das übergeordnete Verzeichnis (insbesondere das übergeordnete Verzeichnis, wenn Sie Dateien schreiben möchten). In den meisten gemeinsam genutzten Hosting-Umgebungen ist dies kein Problem, da Ihr Benutzer alle Dateien unter Ihrem Stammverzeichnis besitzen sollte. Ein Linux-Beispiel ist unten gezeigt

     chown apache:apache /path/to/file
  2. Der Benutzer und nur dieser Benutzer hat Zugriff. Unter Linux wäre eine gute Vorgehensweise chmod 600(nur der Besitzer kann lesen und schreiben) oder chmod 644(der Besitzer kann schreiben, aber jeder kann lesen).

Sie können eine erweiterte Diskussion über Linux / Unix - Rechte und Benutzer lesen Sie hier

Machavity
quelle
7
  1. Schauen Sie sich den genauen Fehler an

Mein Code funktionierte auf allen Computern einwandfrei, aber nur auf diesem gab es Probleme (was früher funktioniert hat, denke ich). Verwendete Echo "document_root" Pfad zum Debuggen und sah sich auch den Fehler genau an, fand dies

Warnung: include ( D: /MyProjects/testproject//functions/connections.php ): Stream konnte nicht geöffnet werden:

Sie können leicht erkennen, wo die Probleme liegen. Die Probleme sind // vor Funktionen

$document_root = $_SERVER['DOCUMENT_ROOT'];
echo "root: $document_root";
include($document_root.'/functions/connections.php');

Entfernen Sie einfach die Ladung / aus dem Include und es sollte gut funktionieren. Interessant ist, dass dieses Verhalten in verschiedenen Versionen unterschiedlich ist. Ich habe den gleichen Code auf Laptop, Macbook Pro und diesem PC ausgeführt, alles hat einwandfrei funktioniert, bis. Hoffe das hilft jemandem.

  1. Kopieren Sie über den Dateispeicherort im Browser hinaus, um sicherzustellen, dass die Datei vorhanden ist. Manchmal werden Dateien unerwartet gelöscht (ist bei mir passiert) und es war auch das Problem in meinem Fall.
Hammad Khan
quelle
Wie unterscheidet sich das von Schritt 1 der folgenden Checkliste?
Vic Seedoubleyew
Schritt 2 eine zusätzliche Prüfung, die nicht mit Schritt 1 zusammenhängt. Navigieren Sie einfach zum vorgeschlagenen Pfad im Browser und prüfen Sie, ob Sie die Datei dort sehen (nicht im Windows Explorer, sondern im Browser).
Hammad Khan
2

Skript mit Abfrageparametern hinzufügen

Das war mein Fall. Es ist tatsächlich mit der Frage Nr. 4485874 verknüpft , aber ich werde es hier in Kürze erklären.
Wenn Sie versuchen, dies zu fordern path/to/script.php?parameter=value, sucht PHP nach einer Datei mit dem Namen script.php?parameter=value, da Sie unter UNIX solche Pfade verwenden können.
Wenn Sie wirklich brauchen , sind einige Daten enthalten Skript übergeben, erklären es einfach als $variable=...oder $GLOBALS[]=...oder andere Art und Weise Sie mögen.

Paul Lynn
quelle
2

Samba-Aktien

Wenn Sie einen Linux-Testserver haben und von einem Windows-Client aus arbeiten, stört die Samba-Freigabe den Befehl chmod . Also, auch wenn Sie verwenden:

chmod -R 777 myfolder

Auf der Linux-Seite ist es durchaus möglich, dass die Unix Group \ www-data noch keinen Schreibzugriff hat. Eine funktionierende Lösung, wenn Ihre Freigabe so eingerichtet ist, dass Windows-Administratoren dem Stamm zugeordnet sind: Öffnen Sie unter Windows die Berechtigungen, deaktivieren Sie die Vererbung für Ihren Ordner mit Kopie und gewähren Sie dann den vollständigen Zugriff für WWW-Daten.

Stephan Brunker
quelle
1

Eine weitere mögliche Ursache: Umbenennen und / oder Verschieben von Dateien in einem Texteditor. Ich habe alle oben genannten Schritte ohne Erfolg ausgeführt, bis ich die Datei gelöscht habe, die diesen Fehler immer wieder ausgelöst hat, und eine neue erstellt habe, mit der das Problem behoben wurde.

zMeadz
quelle
1
Wenn ich verstehe, was Sie richtig meinen, wäre dies sofort durch die erste Überprüfung in der Liste
behoben worden
# 1 ist nicht explizit über mögliche Ursachen
zMeadz
Ja, aber Sie kümmern sich nicht um die Ursachen, sondern darum, den Weg zu finden, um das Problem zu beheben. Noch wichtiger ist, Schritt 1 hätte Ihr Problem gelöst
Vic Seedoubleyew