PHP - Impossible d'ouvrir le flux: aucun fichier ou répertoire de ce type

167

Dans les scripts PHP, que vous appeliez include(), require(), fopen()ou leurs dérivés tels que include_once, require_onceou même, move_uploaded_file(), on se heurte souvent à une erreur ou un avertissement:

Échec de l'ouverture du flux: aucun fichier ou répertoire de ce type.

Quel est le bon processus pour trouver rapidement la cause profonde du problème?

Vic Seedoubleyew
la source
5
J'ai nettoyé les commentaires hors sujet sur cet article. Veuillez conserver les méta-discussions en méta. Cependant, veuillez noter que la discussion sur la viabilité des questions canoniques a été faite maintes et maintes fois. Voir l'exemple ici .
Madara's Ghost
1
J'ai eu le même problème, la seule solution qui a toujours fonctionné est: -1 Allez dans le fichier pour inclure, bouton droit, propriétés, copiez le chemin complet Par exemple: C: /......../ file.php 2- l'inclure. En fait, j'ai vu que cette question avait une réponse, et la réponse est validée, mais pour moi, dans certains cas, cela n'a pas fonctionné, jusqu'à ce que je trouve la voie décrite ci-dessus.
Rshad
@Rash merci pour votre contribution. Malheureusement, votre solution est erronée, car elle mentionnera le nom du chemin absolu, ce qui est faux. La raison pour laquelle c'est faux, c'est qu'au moment où vous copiez votre projet ailleurs ou le déplacerez dans votre ordinateur, tout se cassera.
Vic Seedoubleyew

Réponses:

260

Il y a de nombreuses raisons pour lesquelles on pourrait rencontrer cette erreur et donc une bonne liste de contrôle de ce qu'il faut vérifier en premier aide considérablement.

Considérons que nous résolvons la ligne suivante:

require "/path/to/file"


Liste de contrôle


1. Vérifiez le chemin du fichier pour les fautes de frappe

  • soit vérifier manuellement (en vérifiant visuellement le chemin)
  • ou déplacez tout ce qui est appelé par require*ou include*vers sa propre variable, faites-en écho, copiez-le et essayez d'y accéder depuis un terminal:

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

    Ensuite, dans un terminal:

    cat <file path pasted>


2. Vérifiez que le chemin du fichier est correct en ce qui concerne les considérations relatives au chemin absolu ou relatif

  • s'il commence par une barre oblique "/", il ne fait pas référence à la racine du dossier de votre site Web (la racine du document), mais à la racine de votre serveur.
    • par exemple, le répertoire de votre site Web pourrait être /users/tony/htdocs
  • s'il ne commence pas par une barre oblique, alors il s'appuie sur le chemin d'inclusion (voir ci-dessous) ou le chemin est relatif. S'il est relatif, PHP calculera par rapport au chemin du répertoire de travail actuel .
    • donc, pas par rapport au chemin de la racine de votre site Web, ou au fichier dans lequel vous tapez
    • pour cette raison, utilisez toujours des chemins de fichiers absolus

Les meilleures pratiques :

Afin de rendre votre script robuste au cas où vous déplacez des éléments, tout en générant un chemin absolu à l'exécution, vous avez 2 options:

  1. utiliser require __DIR__ . "/relative/path/from/current/file". La __DIR__constante magique renvoie le répertoire du fichier courant.
  2. définissez SITE_ROOTvous-même une constante:

    • à la racine du répertoire de votre site Web, créez un fichier, par exemple config.php
    • dans config.php, écris

      define('SITE_ROOT', __DIR__);
    • dans chaque fichier où vous souhaitez référencer le dossier racine du site, incluez config.php, puis utilisez la SITE_ROOTconstante où vous le souhaitez:

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

Ces 2 pratiques rendent également votre application plus portable car elle ne repose pas sur des paramètres ini comme le chemin d'inclusion.


3. Vérifiez votre chemin d’inclusion

Une autre façon d'inclure des fichiers, ni de manière relativement ni purement absolue, consiste à s'appuyer sur le chemin d'inclusion . C'est souvent le cas pour les bibliothèques ou les frameworks tels que le framework Zend.

Une telle inclusion ressemblera à ceci:

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

Dans ce cas, vous voudrez vous assurer que le dossier où se trouve "Zend" fait partie du chemin d'inclusion.

Vous pouvez vérifier le chemin d’inclusion avec:

echo get_include_path();

Vous pouvez y ajouter un dossier avec:

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


4. Vérifiez que votre serveur a accès à ce fichier

Il se peut que dans l'ensemble, l'utilisateur exécutant le processus serveur (Apache ou PHP) n'ait tout simplement pas l'autorisation de lire ou d'écrire dans ce fichier.

Pour vérifier sous quel utilisateur le serveur tourne, vous pouvez utiliser posix_getpwuid :

$user = posix_getpwuid(posix_geteuid());

var_dump($user);

Pour connaître les autorisations sur le fichier, tapez la commande suivante dans le terminal:

ls -l <path/to/file>

et regardez la notation symbolique des autorisations


5. Vérifiez les paramètres PHP

Si rien de ce qui précède n'a fonctionné, le problème est probablement que certains paramètres PHP lui interdisent d'accéder à ce fichier.

Trois paramètres peuvent être pertinents:

  1. open_basedir
    • Si cela est défini, PHP ne pourra accéder à aucun fichier en dehors du répertoire spécifié (même pas via un lien symbolique).
    • Cependant, le comportement par défaut est qu'il ne soit pas défini, auquel cas il n'y a pas de restriction
    • Cela peut être vérifié en appelant phpinfo()ou en utilisantini_get("open_basedir")
    • Vous pouvez modifier le paramètre en éditant votre fichier php.ini ou votre fichier httpd.conf
  2. mode sans échec
    • si cette option est activée, des restrictions peuvent s'appliquer. Cependant, cela a été supprimé dans PHP 5.4. Si vous utilisez toujours une version qui prend en charge la mise à niveau en mode sans échec vers une version PHP toujours prise en charge .
  3. allow_url_fopen et allow_url_include
    • cela s'applique uniquement à l'inclusion ou à l'ouverture de fichiers via un processus réseau tel que http: // pas lorsque vous essayez d'inclure des fichiers sur le système de fichiers local
    • ceci peut être vérifié ini_get("allow_url_include")et réglé avecini_set("allow_url_include", "1")


Cas d'angle

Si aucune des solutions ci-dessus n'a permis de diagnostiquer le problème, voici quelques situations spéciales qui pourraient se produire:


1. L'inclusion d'une bibliothèque reposant sur le chemin d'inclusion

Il peut arriver que vous incluiez une bibliothèque, par exemple, le framework Zend, en utilisant un chemin relatif ou absolu. Par exemple :

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

Mais vous obtenez toujours le même type d'erreur.

Cela peut se produire car le fichier que vous avez inclus (avec succès) a lui-même une instruction d'inclusion pour un autre fichier, et cette seconde instruction d'inclusion suppose que vous avez ajouté le chemin de cette bibliothèque au chemin d'inclusion.

Par exemple, le fichier de framework Zend mentionné précédemment pourrait avoir les éléments suivants:

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

qui n'est ni une inclusion par chemin relatif, ni par chemin absolu. Il suppose que le répertoire du framework Zend a été ajouté au chemin d'inclusion.

Dans un tel cas, la seule solution pratique est d'ajouter le répertoire à votre chemin d'inclusion.


2. SELinux

Si vous utilisez Linux à sécurité renforcée, cela peut être la raison du problème en refusant l'accès au fichier depuis le serveur.

Pour vérifier si SELinux est activé sur votre système, exécutez la sestatuscommande dans un terminal. Si la commande n'existe pas, alors SELinux n'est pas sur votre système. S'il existe, il devrait vous dire s'il est appliqué ou non.

Pour vérifier si les politiques SELinux sont la cause du problème, vous pouvez essayer de la désactiver temporairement. Cependant, soyez prudent, car cela désactivera complètement la protection. Ne faites pas cela sur votre serveur de production.

setenforce 0

Si vous n'avez plus le problème avec SELinux désactivé, c'est la cause principale.

Pour le résoudre , vous devrez configurer SELinux en conséquence.

Les types de contexte suivants seront nécessaires:

  • httpd_sys_content_t pour les fichiers que vous souhaitez que votre serveur puisse lire
  • httpd_sys_rw_content_t pour les fichiers sur lesquels vous souhaitez un accès en lecture et en écriture
  • httpd_log_t pour les fichiers journaux
  • httpd_cache_t pour le répertoire cache

Par exemple, pour attribuer le httpd_sys_content_ttype de contexte au répertoire racine de votre site Web, exécutez:

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

Si votre fichier se trouve dans un répertoire personnel, vous devrez également activer le httpd_enable_homedirsbooléen:

setsebool -P httpd_enable_homedirs 1

Dans tous les cas, il peut y avoir une variété de raisons pour lesquelles SELinux refuserait l'accès à un fichier, en fonction de vos politiques. Vous devrez donc vous renseigner à ce sujet. Voici un tutoriel spécifiquement sur la configuration de SELinux pour un serveur Web.


3. Symfony

Si vous utilisez Symfony et que vous rencontrez cette erreur lors du téléchargement sur un serveur, il se peut que le cache de l'application n'ait pas été réinitialisé, soit parce qu'il app/cachea été téléchargé, soit parce que le cache n'a pas été effacé.

Vous pouvez tester et résoudre ce problème en exécutant la commande de console suivante:

cache:clear


4. Caractères non ACSII dans le fichier Zip

Apparemment, cette erreur peut également se produire lors de l'appel zip->close()lorsque certains fichiers à l'intérieur du zip ont des caractères non ASCII dans leur nom de fichier, tels que «é».

Une solution potentielle consiste à insérer le nom du fichier utf8_decode()avant de créer le fichier cible.

Remerciements à Fran Cano pour avoir identifié et suggéré une solution à ce problème

Vic Seedoubleyew
la source
4
Je pense que la mention de selinuxpeut être une bonne idée ici. vous aurez au moins besoin d'une httpd_sys_content_tautorisation (répertoires et fichiers en lecture seule utilisés par Apache) sur les fichiers inclus.
bansi le
Merci beaucoup pour la suggestion. Comme je ne connais pas SELinux, j'ai fait quelques lectures et essayé de répondre à ce cas. N'hésitez pas à nous faire part de vos commentaires ou à suggérer des modifications si ce n'est pas correct. Merci encore pour le commentaire !
Vic Seedoubleyew
chconest temporaire et ne survivra pas à restoreconun redémarrage ou à un redémarrage. vous devrez peut-être utiliser semanagepour modifier le contexte du fichier. Voici un bon tutoriel simple pour site web
bansi
Une autre possibilité à ajouter: la mise en cache du chemin réel: lyte.id.au/2014/05/01/what-the-hell-php
chrishiestand
@chrishiest et merci beaucoup! Cet article est vraiment intéressant! Vous souvenez-vous du déroulement des événements qui ont conduit à cette erreur? Est-ce qu'au départ, l'utilisateur n'avait pas accès en lecture à un fichier, puis il a été modifié, mais le cache considérait toujours qu'il n'était pas lisible, donc il a jeté cette erreur lors de l'ouverture du fichier?
Vic Seedoubleyew
16

Pour ajouter à la (vraiment bonne) réponse existante

Logiciel d'hébergement partagé

open_basedirest celui qui peut vous surprendre car il peut être spécifié dans une configuration de serveur Web. Bien que cela soit facilement résolu si vous exécutez votre propre serveur dédié, il existe des logiciels d'hébergement partagé (comme Plesk, cPanel, etc.) qui configureront une directive de configuration par domaine. Étant donné que le logiciel crée le fichier de configuration (c'est-à-dire httpd.conf), vous ne pouvez pas modifier ce fichier directement car le logiciel d'hébergement l'écrasera simplement lorsqu'il redémarrera.

Avec Plesk, ils fournissent un endroit pour remplacer le httpd.confappelé vhost.conf. Seul l'administrateur du serveur peut écrire ce fichier. La configuration d'Apache ressemble à ceci

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

Demandez à l'administrateur de votre serveur de consulter le manuel du logiciel d'hébergement et de serveur Web qu'ils utilisent.

Autorisations de fichier

Il est important de noter que l'exécution d'un fichier via votre serveur Web est très différente d'une ligne de commande ou d'une exécution de tâche cron. La grande différence est que votre serveur Web a son propre utilisateur et ses propres autorisations. Pour des raisons de sécurité, cet utilisateur est assez restreint. Apache, par exemple, est souvent apache, www-dataou httpd(selon votre serveur). Une tâche cron ou une exécution CLI a toutes les autorisations dont dispose l'utilisateur qui l'exécute (c'est-à-dire que l'exécution d'un script PHP en tant que root s'exécutera avec les autorisations de root).

Souvent, les gens résoudront un problème d'autorisations en procédant comme suit (exemple Linux)

chmod 777 /path/to/file

Ce n'est pas une idée intelligente, car le fichier ou le répertoire est désormais accessible en écriture dans le monde entier. Si vous possédez le serveur et que vous êtes le seul utilisateur, ce n'est pas si grave, mais si vous êtes dans un environnement d'hébergement partagé, vous venez de donner à tout le monde l'accès à votre serveur.

Ce que vous devez faire est de déterminer le ou les utilisateurs qui ont besoin d'un accès et de ne donner accès qu'à ceux auxquels ils ont accès. Une fois que vous savez quels utilisateurs ont besoin d'accéder, vous voudrez vous assurer que

  1. Cet utilisateur possède le fichier et éventuellement le répertoire parent (en particulier le répertoire parent si vous souhaitez écrire des fichiers). Dans la plupart des environnements d'hébergement partagé, ce ne sera pas un problème, car votre utilisateur doit posséder tous les fichiers sous votre racine. Un exemple Linux est présenté ci-dessous

     chown apache:apache /path/to/file
  2. L'utilisateur, et seul cet utilisateur, a accès. Sous Linux, une bonne pratique serait chmod 600(seul le propriétaire peut lire et écrire) ou chmod 644(le propriétaire peut écrire mais tout le monde peut lire)

Vous pouvez lire une discussion plus approfondie sur les autorisations et les utilisateurs Linux / Unix ici

Machavity
la source
7
  1. Regardez l' erreur exacte

Mon code fonctionnait bien sur toutes les machines, mais seulement sur celle-ci a commencé à poser problème (qui fonctionnait auparavant, je suppose). Utilisé le chemin echo "document_root" pour déboguer et a également examiné de près l'erreur, trouvé ceci

Avertissement: include ( D: /MyProjects/testproject//functions/connections.php ): impossible d'ouvrir le flux:

Vous pouvez facilement voir où se trouvent les problèmes. Les problèmes sont // avant les fonctions

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

Donc, supprimez simplement le chargement / de include et cela devrait fonctionner correctement. Ce qui est intéressant, c'est que ce comportement est différent selon les versions. Je lance le même code sur ordinateur portable, Macbook Pro et ce PC, tout a bien fonctionné jusqu'à ce que. J'espère que cela aide quelqu'un.

  1. Copiez au-delà de l'emplacement du fichier dans le navigateur pour vous assurer que le fichier existe. Parfois, les fichiers sont supprimés de manière inattendue (c'est arrivé avec moi) et c'était aussi le problème dans mon cas.
Hammad Khan
la source
En quoi est-ce différent de l'étape 1 de la liste de contrôle ci-dessous?
Vic Seedoubleyew le
Étape 2 une vérification supplémentaire, non liée à l'étape 1. Naviguez simplement vers le chemin proposé dans le navigateur et voyez si vous voyez le fichier là-bas (pas dans l'explorateur Windows mais dans le navigateur).
Hammad Khan du
2

Ajouter un script avec des paramètres de requête

C'était mon cas. Il renvoie en fait à la question n ° 4485874 , mais je vais l'expliquer ici sous peu.
Lorsque vous essayez d'exiger path/to/script.php?parameter=value, PHP recherche le fichier nommé script.php?parameter=value, car UNIX vous permet d'avoir des chemins comme celui-ci.
Si vous avez vraiment besoin de passer des données à script inclus, juste déclarer comme $variable=...ou $GLOBALS[]=...ou toute autre manière que vous aimez.

Paul Lynn
la source
2

Partages Samba

Si vous disposez d'un serveur de test Linux et que vous travaillez à partir d'un client Windows, le partage Samba interfère avec la commande chmod . Donc, même si vous utilisez:

chmod -R 777 myfolder

du côté Linux, il est tout à fait possible que le groupe Unix \ www-data n'ait toujours pas d'accès en écriture. Une solution de travail si votre partage est configuré pour que les administrateurs Windows soient mappés à la racine: à partir de Windows, ouvrez les autorisations, désactivez l'héritage pour votre dossier avec copie, puis accordez un accès complet à www-data.

Stéphan Brunker
la source
1

Autre cause possible: renommer et / ou déplacer des fichiers dans un éditeur de texte. J'ai suivi toutes les étapes ci-dessus sans succès jusqu'à ce que je supprime le fichier qui continuait à générer cette erreur et en ai créé un nouveau, ce qui a résolu le problème.

zMeadz
la source
1
si je comprends bien ce que vous voulez dire, cela aurait été résolu instantanément par la première vérification de la liste
Vic Seedoubleyew
# 1 n'est pas explicite sur les causes potentielles
zMeadz
oui, mais vous ne vous souciez pas des causes, vous vous souciez de trouver le moyen de résoudre le problème. Plus important encore, l'étape numéro 1 aurait résolu votre problème
Vic Seedoubleyew