¿PHP incluye rutas relativas al archivo o al código de llamada?

110

Tengo problemas para comprender el conjunto de reglas con respecto a las rutas de inclusión relativas de PHP. Si ejecuto el archivo A.PHP- y el archivo A.PHP incluye el archivo B.PHP que incluye el archivo C.PHP, si la ruta relativa a C.PHP está relacionada con la ubicación de B.PHP o con la ubicación de A .PHP? Es decir, ¿importa desde qué archivo se llama la inclusión, o solo cuál es el directorio de trabajo actual y qué determina el directorio de trabajo actual?

Yarin
fuente
Respuesta más precisa que aceptada en mi opinión: stackoverflow.com/a/23902890/1636522 .
hoja

Respuestas:

132

Es relativo al script principal, en este caso A.php. Recuerde que include()solo inserta código en el script que se está ejecutando actualmente.

Es decir, ¿importa desde qué archivo se llama la inclusión?

No.

Si desea que sea ​​importante y hacer una inclusión relativa a B.php, use la __FILE__constante (o __DIR__desde PHP 5.2 IIRC) que siempre apuntará al archivo actual literal en el que se encuentra la línea de código.

include(dirname(__FILE__)."/C.PHP");
Pekka
fuente
@ Pekka- increíble- justo lo que estaba buscando. Para obtener más información, consulte stackoverflow.com/questions/2184810/…
Yarin
7
También puede utilizar __DIR__para ese propósito exacto.
Nick Bedford
1
Esta respuesta es algo exagerada: NO NECESITA include(dirname(__FILE__)."/C.PHP");, porque include("C.PHP");es suficiente (¡Sí! C.PHP puede estar en el mismo directorio que B.PHP) Puede fallar solo cuando hay dos archivos C.PHP en su proyecto.
Johnny Wong
Para hacerlo más claro: es relativo tanto a B.php como a A.php si no tiene el prefijo "./" o "../" en la ruta de inclusión. Vea mi respuesta a continuación.
Johnny Wong
21

@Pekka me llevó allí, pero solo quiero compartir lo que aprendí:

getcwd() devuelve el directorio donde reside el archivo que comenzó a ejecutar.

dirname(__FILE__) devuelve el directorio del archivo que contiene el código que se está ejecutando actualmente.

Con estas dos funciones, siempre puede crear una ruta de inclusión relativa a lo que necesita.

por ejemplo, si b.php y c.php comparten un directorio, b.php puede incluir c.php como:

include(dirname(__FILE__).'/c.php');

sin importar desde dónde se haya llamado a b.php.

De hecho, esta es la forma preferida de establecer rutas relativas, ya que el código adicional libera a PHP de tener que iterar a través de include_path en el intento de localizar el archivo de destino.

Fuentes:

¿Diferencia entre getcwd () y dirname (__ FILE__)? ¿Qué debo usar?

Por qué debería usar dirname (__ FILE__)

Yarin
fuente
Me gustaría agregar algo, tenía un archivo llamado csb.php, incluía un archivo de funciones de una carpeta, y el archivo de funciones incluía un archivo llamado t.php de la misma carpeta que el archivo de funciones, cuando intenté incluir un archivo llamado csb.php de la carpeta t.php, comenzó a incluir el mismo csb.php que llamó al archivo de funciones, pero cuando cambié el segundo csb.php a csbe.php, comenzó a funcionar de inmediato. Por lo tanto, parece que prioriza la primera carpeta y luego la segunda carpeta de inclusión.
Miguel Vieira
17
  1. Si la ruta de inclusión no comienza con ./o ../, por ejemplo:

    include 'C.php'; // precedence: include_path (which include '.' at first),
                     // then path of current `.php` file (i.e. `B.php`), then `.`.
  2. Si la ruta de inclusión comienza con ./o ../, por ejemplo:

    include './C.php';  // relative to '.'
    
    include '../C.php'; // also relative to '.'

El .o ..superior es relativo a getcwd(), que por defecto es la ruta del .phparchivo de entrada (es decir A.php).

Probado en PHP 5.4.3 (Fecha de compilación: 8 de mayo de 2012 00:47:34).

(También tenga en cuenta que chdir()puede cambiar la salida de getcwd()).

Johnny Wong
fuente
Para concluir, primero se busca en la ruta de A.php C.php, luego se busca en la ruta de B.php si no hay prefijo './' o '../' en el archivo include. (Asuma la configuración predeterminada de PHP)
Johnny Wong
Gracias por darme pistas sobre el uso chdir(__DIR__)para solucionar el problema.
HartleySan
[...] getcwd(), que por defecto es la ruta del archivo .php de entrada, [...] no necesariamente cierto. Si ejecuto PHP en la línea de comandos, entonces se getcwd()refiere al directorio de trabajo actual del shell, independientemente del .phparchivo que invoque. Sin embargo, puedo imaginar que si PHP se ejecuta en un entorno de servidor web, el entorno inicializa el directorio de trabajo actual en el .phparchivo de entrada . Probado en macOS con PHP 7.2.2 instalado a través de Homebrew.
herzbube
16

La respuesta aceptada de Pekka es incompleta y, en un contexto general, engañosa. Si el archivo se proporciona como una ruta relativa, la construcción del lenguaje llamado includelo buscará de la siguiente manera.

Primero, pasará por las rutas de la variable de entorno include_path, que se puede configurar con ini_set. Si esto falla, buscará en el directorio del script de llamada dirname(__FILE__)( __DIR__con php> = 5.3.) Si esto también falla, ¡solo entonces buscará en el directorio de trabajo! Resulta que, de forma predeterminada, la variable de entorno include_pathcomienza con ., que es el directorio de trabajo actual. Esa es la única razón por la que busca primero en el directorio de trabajo actual. Consulte http://php.net/manual/en/function.include.php .

Los archivos se incluyen en función de la ruta del archivo proporcionada o, si no se proporciona, la ruta_incluida especificada. Si el archivo no se encuentra en include_path, include finalmente verificará el directorio propio del script de llamada y el directorio de trabajo actual antes de fallar.

Entonces, la respuesta correcta a la primera parte de la pregunta es que sí importa dónde se encuentra el script de llamada incluido. La respuesta a la última parte de la pregunta es que el directorio de trabajo inicial , en un contexto de servidor web, es el directorio del script llamado, el script que incluye todos los demás mientras es manejado por PHP. En un contexto de línea de comandos, el directorio de trabajo inicial es lo que sea cuando se invoca php en el indicador, no necesariamente el directorio donde se encuentra el script llamado. El actual directorio de trabajo, sin embargo, se puede cambiar en tiempo de ejecución con la función de PHP chdir. Consulte http://php.net/manual/en/function.chdir.php .

Este párrafo se agrega para comentar otras respuestas. Algunos han mencionado que confiar en include_pathes menos robusto y, por lo tanto, es preferible utilizar rutas completas como ./patho __DIR__ . /path. Algunos fueron tan lejos como para decir que confiar en el directorio de trabajo en .sí no es seguro, porque se puede cambiar. Sin embargo, algunas veces, debe confiar en los valores del entorno. Por ejemplo, es posible que desee establecerlo include_pathvacío, de modo que el directorio del script de llamada sea el primer lugar en el que buscará, incluso antes del directorio de trabajo actual. Es posible que el código ya esté escrito y actualizado periódicamente desde fuentes externas y no desea volver a insertar el prefijo __DIR__cada vez que se actualice el código.


fuente
"si esto falla, buscará en el directorio del script de llamada dirname(__FILE__) (__DIR__)con php> = 5.3.)" ¿Estás seguro? ¿Dónde está documentado? Espero que esté equivocado, y PHP no usa __FILE__y __DIR__para este propósito, ya que eso rompería rápidamente la inclusión de scripts "hermanos" de los enlazados simbólicamente . : -o (Lo que, afortunadamente, parece funcionar bien aquí, en mi configuración 7.1.)
Sz.
6

Respuesta corta: es relativa al guión incluido.

TFM lo explica correctamente:

Si el archivo no se encuentra en include_path, include verificará el directorio del script de llamada y el directorio de trabajo actual

Entonces, si /app/main.php dice include("./inc.php")que encontrará /app/inc.php .

El ./ no es estrictamente necesario, pero elimina cualquier dependencia de include_path.

No confiaría en encontrar archivos de inclusión en el directorio de trabajo actual en caso de que alguien lo cambie con chdir().

Denis Howe
fuente
Entonces, si comienza la cadena con ./, ¿verifica primero el directorio del script de llamada o primero el directorio de trabajo actual?
Pacerier
2
@Denis Howe No, ya depende del directorio de trabajo actual si su ruta de inclusión comienza con ./. es decir, chdir ("/ app / other") hará que include("./inc.php")falle. Por lo tanto, use include("inc.php")para estar seguro en este caso.
Johnny Wong
@Pacerier si la cadena comienza con ./ o ../, solo verifica el directorio de trabajo actual. (include_path y el directorio del script de llamada (B.php) se ignoran). Vea mi respuesta para más detalles.
Johnny Wong
-2
dir
-> a.php
-> c.php

- dir2 
-> b.php

Para incluir aen blo que necesitainclude("../a.php");

Para incluir ben clo que necesitainclude("dir2/b.php");

Olli
fuente
4
@ Olli- te estás perdiendo el punto de la pregunta: estaba preguntando cómo se determinan las rutas relativas cuando las inclusiones están encadenadas.
Yarin