PHP-Fallo en la apertura del flujo:No existe tal archivo o directorio

php require fopen include-path


En los scripts PHP, ya sea llamando a include() , require() , fopen() o sus derivados, como include_once , require_once o incluso, move_uploaded_file() , a menudo se encuentra un error o advertencia:

No se abrió el flujo:No hay tal archivo o directorio.

¿Cuál es un buen proceso para encontrar rápidamente la raíz del problema?





Answer 1 Vic Seedoubleyew


Hay muchas razones por las que uno podría encontrarse con este error y,por lo tanto,una buena lista de lo que hay que comprobar primero ayuda considerablemente.

Consideremos que estamos resolviendo los problemas de la siguiente línea:

require "/path/to/file"


Checklist


1.Revise la ruta del archivo por si hay errores de escritura

  • o bien comprobar manualmente (comprobando visualmente el camino)
  • o mueva lo que sea llamado por require* o include* a su propia variable, repítalo, cópielo e intente acceder a él desde un terminal:

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

    Luego,en una terminal:

    cat <file path pasted>


2.Verificar que la ruta del archivo es correcta en cuanto a las consideraciones de la ruta relativa vs.la absoluta.

  • si comienza con una barra inclinada hacia adelante "" entonces no se refiere a la raíz de la carpeta de su sitio web (la raíz del documento),sino a la raíz de su servidor.
    • por ejemplo, el directorio de su sitio web podría ser /users/tony/htdocs
  • si no comienza con una barra diagonal, entonces depende de la ruta de inclusión (ver más abajo) o la ruta es relativa. Si es relativo, entonces PHP calculará relativamente la ruta del directorio de trabajo actual .
    • por lo tanto,no en relación con la ruta de la raíz de su sitio web,o con el archivo donde está escribiendo
    • por esa razón,siempre usa rutas de archivo absolutas

Las mejores prácticas :

Para hacer tu guión robusto en caso de que muevas las cosas,mientras sigues generando un camino absoluto en tiempo de ejecución,tienes 2 opciones :

  1. uso require __DIR__ . "/relative/path/from/current/file" . La constante mágica __DIR__ devuelve el directorio del archivo actual.
  2. define una constante SITE_ROOT tú mismo:

    • en la raíz del directorio de su sitio web, cree un archivo, por ejemplo config.php
    • en config.php , escribe

      define('SITE_ROOT', __DIR__);
    • en cada archivo donde desee hacer referencia a la carpeta raíz del sitio, incluya config.php , y luego use la constante SITE_ROOT donde quiera:

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

Estas 2 prácticas también hacen que su aplicación sea más portátil porque no depende de configuraciones ini como la ruta de inclusión.


3.Revise su ruta de inclusión

Otra forma de incluir archivos, ni relativa ni puramente absoluta, es confiar en la ruta de inclusión . Este suele ser el caso de bibliotecas o marcos como el marco Zend.

Tal inclusión se verá así:

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

En ese caso,querrás asegurarte de que la carpeta donde está "Zend" es parte de la ruta de inclusión.

Puedes comprobar la ruta de inclusión con :

echo get_include_path();

Puedes añadirle una carpeta con :

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


4.Compruebe que su servidor tiene acceso a ese archivo

Puede ser que en conjunto,el usuario que ejecuta el proceso del servidor (Apache o PHP)simplemente no tiene permiso para leer o escribir en ese archivo.

Para verificar con qué usuario está ejecutando el servidor, puede usar posix_getpwuid :

$user = posix_getpwuid(posix_geteuid());

var_dump($user);

Para averiguar los permisos del archivo,escriba el siguiente comando en la terminal:

ls -l <path/to/file>

y mira el permiso de notación simbólica


5.Compruebe la configuración de PHP

Si nada de lo anterior funcionó,entonces el problema es probablemente que algunos ajustes de PHP le prohíben acceder a ese archivo.

Tres ajustes podrían ser relevantes:

  1. open_basedir
    • Si esto se establece,PHP no podrá acceder a ningún archivo fuera del directorio especificado (ni siquiera a través de un enlace simbólico).
    • Sin embargo,el comportamiento por defecto es que no se establezca,en cuyo caso no hay ninguna restricción
    • Esto puede verificarse llamando a phpinfo() o usando ini_get("open_basedir")
    • Puedes cambiar la configuración editando tu archivo php.ini o tu archivo httpd.conf
  2. modo seguro
    • si esto está activado, podrían aplicarse restricciones. Sin embargo, esto se ha eliminado en PHP 5.4. Si todavía está en una versión que admite la actualización en modo seguro a una versión de PHP que todavía es compatible .
  3. allow_url_fopen y allow_url_include
    • esto se aplica sólo a la inclusión o apertura de archivos a través de un proceso de red como http:/no cuando se trata de incluir archivos en el sistema de archivos local
    • esto se puede verificar con ini_get("allow_url_include") y establecer con ini_set("allow_url_include", "1")


Los casos de las esquinas

Si ninguno de los anteriores permite diagnosticar el problema,aquí hay algunas situaciones especiales que podrían suceder:


1.La inclusión de la biblioteca que se basa en la ruta de inclusión

Puede suceder que incluya una biblioteca,por ejemplo,el marco de Zend,usando un camino relativo o absoluto.Por ejemplo :

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

Pero entonces sigues teniendo el mismo tipo de error.

Esto podría suceder porque el archivo que ha incluido (con éxito),tiene en sí mismo una declaración de inclusión para otro archivo,y esa segunda declaración de inclusión supone que ha añadido la ruta de esa biblioteca a la ruta de inclusión.

Por ejemplo,el archivo marco de Zend mencionado anteriormente podría incluir :

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

que no es ni una inclusión por vía relativa,ni por vía absoluta.Se asume que el directorio del marco de Zend ha sido añadido a la ruta de inclusión.

En tal caso,la única solución práctica es añadir el directorio a su ruta de inclusión.


2.SELinux

Si está ejecutando un Linux con seguridad mejorada,entonces puede ser la razón del problema,al negar el acceso al archivo desde el servidor.

Para verificar si SELinux está habilitado en su sistema, ejecute el comando sestatus en una terminal. Si el comando no existe, SELinux no está en su sistema. Si existe, entonces debería decirle si se aplica o no.

Para verificar si las políticas de SELinux son la razón del problema, puede intentar desactivarlo temporalmente. Sin embargo, tenga cuidado, ya que esto deshabilitará la protección por completo. No haga esto en su servidor de producción.

setenforce 0

Si ya no tienes el problema con SELinux apagado,entonces esta es la causa principal.

Para resolverlo , deberá configurar SELinux en consecuencia.

Serán necesarios los siguientes tipos de contexto :

  • httpd_sys_content_t para archivos que desea que su servidor pueda leer
  • httpd_sys_rw_content_t para archivos en los que desea acceso de lectura y escritura
  • httpd_log_t para archivos de registro
  • httpd_cache_t para el directorio de caché

Por ejemplo, para asignar el tipo de contexto httpd_sys_content_t al directorio raíz de su sitio web, ejecute:

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

Si su archivo está en un directorio de inicio, también deberá activar el booleano httpd_enable_homedirs :

setsebool -P httpd_enable_homedirs 1

En cualquier caso, podría haber una variedad de razones por las cuales SELinux negaría el acceso a un archivo, dependiendo de sus políticas. Entonces tendrá que investigar sobre eso. Aquí hay un tutorial específicamente sobre la configuración de SELinux para un servidor web.


3.Symfony

Si está utilizando Symfony y experimenta este error al cargar en un servidor, puede ser que la caché de la aplicación no se haya restablecido, ya sea porque la app/cache se ha cargado o porque la caché no se ha borrado.

Puedes probar y arreglar esto ejecutando el siguiente comando de consola:

cache:clear


4.Caracteres no ACSII dentro del archivo Zip

Aparentemente, este error puede ocurrir también al llamar a zip->close() cuando algunos archivos dentro del zip tienen caracteres no ASCII en su nombre de archivo, como "é".

Una posible solución es ajustar el nombre del archivo en utf8_decode() antes de crear el archivo de destino.

Créditos a Fran Cano por identificar y sugerir una solución a este problema




Answer 2 Machavity


Para añadir a la (muy buena)respuesta existente

Software de alojamiento compartido

open_basedir es uno que puede confundirlo porque se puede especificar en la configuración de un servidor web. Si bien esto se soluciona fácilmente si ejecuta su propio servidor dedicado, existen algunos paquetes de software de alojamiento compartido (como Plesk, cPanel, etc.) que configurarán una directiva de configuración por dominio. Debido a que el software crea el archivo de configuración (es decir, httpd.conf ), no puede cambiar ese archivo directamente porque el software de alojamiento simplemente lo sobrescribirá cuando se reinicie.

Con Plesk, que proporcionan un lugar para anular el proporcionado httpd.conf llamada vhost.conf . Solo el administrador del servidor puede escribir este archivo. La configuración de Apache se parece a esto

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

Haga que el administrador de su servidor consulte el manual del software de alojamiento y del servidor web que utilizan.

Permisos de archivo

Es importante tener en cuenta que la ejecución de un archivo a través de su servidor web es muy diferente de la ejecución de una línea de comandos o trabajo cron. La gran diferencia es que su servidor web tiene su propio usuario y permisos. Por razones de seguridad, ese usuario está bastante restringido. Apache, por ejemplo, a menudo es apache , www-data o httpd (dependiendo de su servidor). Un trabajo cron o ejecución de CLI tiene los permisos que tiene el usuario que lo ejecuta (es decir, ejecutar un script PHP como root se ejecutará con permisos de root).

Muchas veces la gente resuelve un problema de permisos haciendo lo siguiente (ejemplo de Linux)

chmod 777 /path/to/file

No es una idea inteligente,porque el archivo o directorio es ahora mundialmente escribible.Si eres el dueño del servidor y eres el único usuario,entonces no es gran cosa,pero si estás en un entorno de alojamiento compartido,acabas de dar acceso a todos los que están en tu servidor.

Lo que hay que hacer es determinar el usuario o usuarios que necesitan acceso y dar acceso sólo a aquellos que lo necesiten.Una vez que sepas qué usuarios necesitan acceso querrás asegurarte de que

  1. Ese usuario posee el archivo y posiblemente el directorio principal (especialmente el directorio principal si desea escribir archivos). En la mayoría de los entornos de alojamiento compartido, esto no será un problema, porque su usuario debe poseer todos los archivos debajo de su raíz. A continuación se muestra un ejemplo de Linux

    chown apache:apache /path/to/file
  2. El usuario, y solo ese usuario, tiene acceso. En Linux, una buena práctica sería chmod 600 (solo el propietario puede leer y escribir) o chmod 644 (el propietario puede escribir pero todos pueden leer)

Puede leer una discusión más extensa sobre los permisos y usuarios de Linux / Unix aquí




Answer 3 Hammad Khan


  1. Mira el error exacto

Mi código funcionó bien en todas las máquinas pero sólo en ésta empezó a dar problemas (que solía funcionar en el Find,supongo).Utilicé la ruta eco "document_root" para depurar y también miré de cerca el error,encontré esto

Advertencia: include ( D: /MyProjects/testproject//functions/connections.php ): no se pudo abrir la transmisión:

Puedes ver fácilmente dónde están los problemas.Los problemas son/antes de las funciones

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

Así que simplemente quita la carga de la caja y debería funcionar bien.Lo que es interesante es que este comportamiento es diferente en las diferentes versiones.Corro el mismo código en la Laptop,Macbook Pro y esta PC,todo funcionó bien hasta...Espero que esto ayude a alguien.

  1. Copiar más allá de la ubicación del archivo en el navegador para asegurarse de que el archivo existe.A veces los archivos se borran de forma inesperada (me pasó a mí)y también fue el problema en mi caso.



Answer 4 Paul Lynn


Añade un guión con parámetros de consulta

Ese fue mi caso. En realidad, enlaza con la pregunta # 4485874 , pero voy a explicarlo aquí en breve.
Cuando intenta requerir path/to/script.php?parameter=value , PHP busca el archivo llamado script.php?parameter=value , porque UNIX le permite tener rutas como esta.
Si realmente necesita pasar algunos datos al script incluido, simplemente declare como $variable=... o $GLOBALS[]=... u otra forma que desee.




Answer 5 Stephan Brunker


Acciones de samba

Si tiene un servidor de prueba de Linux y trabaja desde un cliente de Windows, el recurso compartido de Samba interfiere con el comando chmod . Entonces, incluso si usa:

chmod -R 777 myfolder

en el lado de Linux es totalmente posible que el Grupo Unix\www-data aún no tenga acceso de escritura.Una solución que funciona si su parte está configurada para que los administradores de Windows se asignen a la raíz:Desde Windows,abrir los permisos,deshabilitar la herencia para su carpeta con copia,y luego conceder el acceso completo para los datos www-data.