Dans les scripts PHP, que l'on appelle include()
, require()
, fopen()
, ou leurs dérivés comme include_once
, require_once
, ou même, move_uploaded_file()
, on rencontre souvent une erreur ou un avertissement :
Failed to open stream : No such file or directory.
Quel est le bon procédé pour trouver rapidement l'origine du problème ?
Il y a de nombreuses raisons pour lesquelles on peut rencontrer cette erreur et une bonne liste de ce qu'il faut vérifier en premier est donc très utile. Considérons que nous sommes en train de dépanner la ligne suivante :
require "/path/to/file"
require*
ou include*
dans sa propre variable, faites-en l'écho, copiez-le, et essayez d'y accéder depuis un terminal :
$path = "/path/to/file" ;
echo "Chemin : $path" ;
require "$path" ;
Puis, dans un terminal :
cat <chemin du fichier collé>
/users/tony/htdocs
.require __DIR__ . "/relative/path/from/current/file"
. La [constante magique __DIR__
] [magicconst-docs] renvoie le répertoire du fichier courant.SITE_ROOT
:config.php
.config.php
, écrivez
define('SITE_ROOT', DIR);config.php
, puis utilisez la constante SITE_ROOT
où vous le souhaitez :
require_once DIR."/../config.php" ;
...
require_once SITE_ROOT."/autre/file.php" ;
Ces deux pratiques rendent également votre application plus portable car elle ne dépend pas des paramètres ini comme le chemin d'inclusion.
Une autre façon d'inclure des fichiers, ni de façon relative ni de façon absolue, est de s'appuyer sur le [include path][includepath-docs]. 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 devrez 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");
Il se peut que l'utilisateur qui exécute le processus serveur (Apache ou PHP) n'ait tout simplement pas la permission de lire ou d'écrire dans ce fichier. Pour vérifier sous quel utilisateur le serveur est exécuté, vous pouvez utiliser [posix_getpwuid][posixgetpwuid-docs] :
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
Pour connaître les permissions sur le fichier, tapez la commande suivante dans le terminal :
ls -l <path/to/file>
et regardez dans [permission symbolic notation] [permissions-notation].
Si aucune des méthodes ci-dessus n'a fonctionné, il est probable que certains paramètres PHP interdisent l'accès à ce fichier. Trois paramètres peuvent être concernés :
phpinfo()
] [phpinfo-docs] ou en utilisant ini_get("open_basedir" ;)
.ini_get("allow_url_include" ;)
et réglé avec ini_set("allow_url_include" ;, "1" ;)
Si aucun des éléments ci-dessus n'a permis de diagnostiquer le problème, voici quelques situations particulières qui pourraient se produire :
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 arriver parce que le fichier que vous avez inclus (avec succès), a lui-même une déclaration d'inclusion pour un autre fichier, et cette deuxième déclaration d'inclusion suppose que vous avez ajouté le chemin de cette bibliothèque au chemin d'inclusion. Par exemple, le fichier du framework Zend mentionné précédemment pourrait avoir l'include suivant :
include "Zend/Mail/Protocol/Exception.php"
qui n'est ni une inclusion par chemin relatif, ni par chemin absolu. Elle suppose que le répertoire Zend framework 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.
Si vous exécutez Security-Enhanced Linux, 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 commande sestatus
dans un terminal. Si la commande n'existe pas, alors SELinux n'est pas sur votre système. Si elle existe, elle devrait vous indiquer si elle est appliquée ou non.
Pour vérifier si la politique SELinux est la cause du problème, vous pouvez essayer de la désactiver temporairement. Cependant, soyez PRUDENT, car cela désactivera entièrement la protection. Ne faites pas cela sur votre serveur de production.
setenforce 0
Si vous n'avez plus de problème lorsque SELinux est désactivé, alors il s'agit de la cause première. 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 voulez que votre serveur puisse lire.httpd_sys_rw_content_t
pour les fichiers sur lesquels vous voulez un accès en lecture et en écriturehttpd_log_t
pour les fichiers de logshttpd_cache_t
pour le répertoire de cache.
Par exemple, pour attribuer le type de contexte httpd_sys_content_t
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 booléen httpd_enable_homedirs
:
setsebool -P httpd_enable_homedirs 1
Dans tous les cas, il peut y avoir plusieurs raisons pour lesquelles SELinux refuse l'accès à un fichier, en fonction de vos politiques. Vous devrez donc vous renseigner à ce sujet. [Ici][2] est un tutoriel spécifique sur la configuration de SELinux pour un serveur web.
Si vous utilisez Symfony et que vous rencontrez cette erreur lors du téléchargement vers un serveur, il est possible que le cache de l'application n'ait pas été réinitialisé, soit parce que app/cache
a été téléchargé, soit parce que le cache n'a pas été vidé.
Vous pouvez tester et corriger ce problème en exécutant la commande console suivante :
cache:clear
Apparemment, cette erreur peut également se produire lors de l'appel de zip->close()
lorsque certains fichiers dans le zip ont des caractères non-ASCII dans leur nom de fichier, comme "é" ;.
Une solution potentielle est d'envelopper le nom du fichier dans utf8_decode()
avant de créer le fichier cible.
Crédits à [Fran Cano][3] pour avoir identifié et suggéré une solution à ce problème.
[getcwd-docs] : https://secure.php.net/manual/en/function.getcwd.php
[magicconst-docs] : https://secure.php.net/manual/en/language.constants.predefined.php
[includepath-docs] : https://secure.php.net/manual/en/ini.core.php#ini.include-path
[posixgetpwuid-docs] : https://secure.php.net/manual/en/function.posix-getpwuid.php
[permissions-notation] : https://en.wikipedia.org/wiki/File_system_permissions#Symbolic_notation
[docs open_basedir] : https://secure.php.net/manual/en/ini.core.php#ini.open-basedir
[phpinfo-docs] : https://secure.php.net/manual/en/function.phpinfo.php
[safemode-docs] : https://secure.php.net/manual/en/features.safe-mode.php
[allow_url_fopen-docs] : https://secure.php.net/manual/en/filesystem.configuration.php
[1] : http://php.net/eol.php
[2] : http://www.serverlab.ca/tutorials/linux/web-servers-linux/configuring-selinux-policies-for-apache-web-servers/
[3] : https://stackoverflow.com/users/4217158/fran-cano
Pour ajouter à la (très bonne) réponse existante
open_basedir
est une option qui peut vous laisser perplexe car elle peut être spécifiée dans la configuration d'un serveur web. Bien qu'il soit facile de remédier à ce problème si vous utilisez votre propre serveur dédié, il existe des logiciels d'hébergement partagé (comme Plesk, cPanel, etc.) qui configurent une directive de configuration pour chaque domaine. Comme le logiciel crée le fichier de configuration (par exemple httpd.conf
), vous ne pouvez pas modifier ce fichier directement car le logiciel d'hébergement l'écrasera lorsqu'il redémarrera.
Avec Plesk, il y a un endroit pour remplacer le fichier httpd.conf
appelé vhost.conf
. Seul l'administrateur du serveur peut écrire ce fichier. La configuration pour Apache ressemble à quelque chose comme 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 de l'hébergement et du logiciel de serveur Web qu'il utilise.
Il est important de noter que l'exécution d'un fichier via votre serveur web est très différente de l'exécution d'une ligne de commande ou d'une 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-data
ou httpd
(selon votre serveur). Une tâche cron ou une exécution CLI a les permissions de l'utilisateur qui l'exécute (c'est-à-dire qu'un script PHP exécuté en tant que root sera exécuté avec les permissions de root).
Souvent, les gens résolvent un problème de permissions en faisant ce qui suit (exemple Linux)
chmod 777 /path/to/file
Ce n'est pas une bonne idée, car le fichier ou le répertoire est maintenant accessible en écriture dans le monde entier. Si vous possédez le serveur et que vous êtes le seul utilisateur, ce n’est pas un problème, mais si vous êtes dans un environnement d’hébergement partagé, vous venez de donner l’accès à tous les utilisateurs de votre serveur.
Ce que vous devez faire, c'est déterminer le ou les utilisateurs qui ont besoin d'un accès et ne donner accès qu'à eux. Une fois que vous savez quels utilisateurs ont besoin d'un accès, vous devez vous assurer que
Cet utilisateur possède le fichier et éventuellement le répertoire parent (surtout le répertoire parent si vous voulez écrire des fichiers). Dans la plupart des environnements d’hébergement mutualisé, ce n’est pas un problème, car votre utilisateur devrait posséder tous les fichiers situés sous votre racine. Un exemple Linux est présenté ci-dessous
chown apache:apache /path/to/file
L'utilisateur, et seulement cet utilisateur, a l'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 permissions et les utilisateurs Linux/Unix ici
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 provoquait cette erreur et en crée un nouveau, ce qui a réglé le problème.