PHP - Impossibile aprire il flusso: nessun file o directory


166

In script PHP, sia chiamando include(), require(), fopen(), o loro derivati come include_once, require_onceo anche, move_uploaded_file(), spesso si imbatte in un errore o un avvertimento:

Impossibile aprire il flusso: nessun file o directory.

Qual è un buon processo per trovare rapidamente la causa principale del problema?


5
Ho ripulito i commenti fuori tema su questo post. Ti preghiamo di tenere meta discussioni in meta. Tuttavia, tieni presente che la discussione sulla fattibilità delle domande canoniche è stata ripetuta più e più volte. Vedi esempio qui .
Madara's Ghost

1
Ho avuto lo stesso problema, l'unica soluzione che ha funzionato sempre è: -1 Vai al file per includere, tasto destro, proprietà, copia il percorso completo Ad esempio: C: /......../ file.php 2- includilo. In realtà ho visto che questa domanda ha una risposta e la risposta è stata convalidata, ma in alcuni casi non ha funzionato, fino a quando non ho trovato il modo sopra descritto.
Rshad,

@Rash grazie per il contributo. Sfortunatamente la tua soluzione è sbagliata, perché menzionerà il nome del percorso assoluto, e questo è sbagliato. Il motivo per cui questo è sbagliato, è perché nel momento in cui copi il tuo progetto da qualche altra parte o lo sposti nel tuo computer, tutto si romperà.
Vic Seedoubleyew,

Risposte:


260

Ci sono molte ragioni per cui si potrebbe riscontrare questo errore e quindi una buona lista di controllo su cosa controllare prima aiuta considerevolmente.

Consideriamo che stiamo risolvendo i problemi con la seguente riga:

require "/path/to/file"


lista di controllo


1. Controllare il percorso del file per errori di battitura

  • controllare manualmente (controllando visivamente il percorso)
  • o sposta qualunque cosa sia chiamata da require*o include*alla sua stessa variabile, fai eco, copiala e prova ad accedervi da un terminale:

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

    Quindi, in un terminale:

    cat <file path pasted>


2. Verificare che il percorso del file sia corretto per quanto riguarda le considerazioni relative al percorso relativo o assoluto

  • se inizia con una barra "/", non si riferisce alla radice della cartella del tuo sito Web (la radice del documento), ma alla radice del tuo server.
    • ad esempio, potrebbe essere la directory del tuo sito web /users/tony/htdocs
  • se non viene avviato da una barra, si basa sul percorso di inclusione (vedere di seguito) o il percorso è relativo. Se è relativo, PHP calcolerà relativamente al percorso della directory di lavoro corrente .
    • quindi, non relativo al percorso della radice del tuo sito web, o al file in cui stai digitando
    • per questo motivo, utilizzare sempre percorsi di file assoluti

Migliori pratiche :

Al fine di rendere robusto lo script nel caso in cui si spostino cose, pur generando un percorso assoluto in fase di esecuzione, sono disponibili 2 opzioni:

  1. usare require __DIR__ . "/relative/path/from/current/file". La __DIR__costante magica restituisce la directory del file corrente.
  2. definisci SITE_ROOTtu stesso una costante:

    • alla radice della directory del tuo sito web, crea un file, ad es config.php
    • in config.php, scrivi

      define('SITE_ROOT', __DIR__);
    • in ogni file in cui si desidera fare riferimento alla cartella principale del sito, includere config.phpe quindi utilizzare la SITE_ROOTcostante dove preferisci:

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

Queste 2 pratiche rendono anche la tua applicazione più portatile perché non si basa su impostazioni ini come il percorso include.


3. Controlla il tuo percorso di inclusione

Un altro modo per includere i file, né relativamente né semplicemente, è fare affidamento sul percorso include . Questo è spesso il caso di librerie o framework come il framework Zend.

Tale inclusione sarà simile a questa:

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

In tal caso, dovrai assicurarti che la cartella in cui si trova "Zend" sia parte del percorso di inclusione.

Puoi controllare il percorso di inclusione con:

echo get_include_path();

Puoi aggiungere una cartella con:

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


4. Verifica che il tuo server abbia accesso a quel file

Potrebbe essere che tutti insieme, l'utente che esegue il processo del server (Apache o PHP) semplicemente non abbia il permesso di leggere o scrivere su quel file.

Per verificare sotto quale utente è in esecuzione il server è possibile utilizzare posix_getpwuid :

$user = posix_getpwuid(posix_geteuid());

var_dump($user);

Per scoprire le autorizzazioni sul file, digitare il seguente comando nel terminale:

ls -l <path/to/file>

e guarda l' autorizzazione notazione simbolica


5. Controlla le impostazioni di PHP

Se nessuna delle precedenti funzioni ha funzionato, probabilmente il problema è che alcune impostazioni di PHP gli vietano di accedere a quel file.

Tre impostazioni potrebbero essere rilevanti:

  1. open_basedir
    • Se impostato, PHP non sarà in grado di accedere a nessun file al di fuori della directory specificata (nemmeno attraverso un collegamento simbolico).
    • Tuttavia, il comportamento predefinito prevede che non venga impostato, nel qual caso non vi sono restrizioni
    • Questo può essere verificato chiamando phpinfo()o usandoini_get("open_basedir")
    • È possibile modificare l'impostazione modificando il file php.ini o il file httpd.conf
  2. modalità sicura
    • se questa opzione è attivata, potrebbero essere applicate restrizioni. Tuttavia, questo è stato rimosso in PHP 5.4. Se sei ancora su una versione che supporta l'aggiornamento in modalità provvisoria a una versione PHP ancora supportata .
  3. allow_url_fopen e allow_url_include
    • questo vale solo per l'inclusione o l'apertura di file attraverso un processo di rete come http: // non quando si tenta di includere file nel file system locale
    • questo può essere verificato con ini_get("allow_url_include")e impostato conini_set("allow_url_include", "1")


Custodie angolari

Se nessuna delle opzioni precedenti è abilitata a diagnosticare il problema, ecco alcune situazioni speciali che potrebbero verificarsi:


1. L'inclusione della libreria basandosi sul percorso include

Può succedere che tu includa una libreria, ad esempio il framework Zend, usando un percorso relativo o assoluto. Per esempio :

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

Ma poi ricevi ancora lo stesso tipo di errore.

Ciò può accadere perché il file che hai (correttamente) incluso, ha esso stesso un'istruzione include per un altro file e la seconda istruzione include presuppone che tu abbia aggiunto il percorso di quella libreria al percorso include.

Ad esempio, il file framework Zend menzionato in precedenza potrebbe includere quanto segue:

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

che non è né un'inclusione per percorso relativo, né per percorso assoluto. Si presuppone che la directory del framework Zend sia stata aggiunta al percorso include.

In tal caso, l'unica soluzione pratica è aggiungere la directory al percorso di inclusione.


2. SELinux

Se stai eseguendo Security-Enhanced Linux, potrebbe essere la ragione del problema, negando l'accesso al file dal server.

Per verificare se SELinux è abilitato sul tuo sistema, esegui il sestatuscomando in un terminale. Se il comando non esiste, SELinux non è sul tuo sistema. Se esiste, allora dovrebbe dirti se è applicato o meno.

Per verificare se i criteri SELinux sono il motivo del problema, puoi provare a disattivarlo temporaneamente. Tuttavia, ATTENZIONE, poiché ciò disabiliterà completamente la protezione. Non farlo sul server di produzione.

setenforce 0

Se il problema con SELinux non è più disattivato, questa è la causa principale.

Per risolverlo , dovrai configurare SELinux di conseguenza.

Saranno necessari i seguenti tipi di contesto:

  • httpd_sys_content_t per i file che vuoi che il tuo server sia in grado di leggere
  • httpd_sys_rw_content_t per i file su cui si desidera accedere in lettura e scrittura
  • httpd_log_t per i file di registro
  • httpd_cache_t per la directory della cache

Ad esempio, per assegnare il httpd_sys_content_ttipo di contesto alla directory principale del sito Web, eseguire:

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

Se il tuo file si trova in una home directory, dovrai anche attivare il valore httpd_enable_homedirsbooleano:

setsebool -P httpd_enable_homedirs 1

In ogni caso, potrebbero esserci vari motivi per cui SELinux negherebbe l'accesso a un file, a seconda delle vostre politiche. Quindi dovrai indagare su questo. Ecco un tutorial specifico sulla configurazione di SELinux per un server web.


3. Symfony

Se stai usando Symfony e stai riscontrando questo errore durante il caricamento su un server, è possibile che la cache dell'app non sia stata ripristinata, sia perché app/cacheè stata caricata, sia che la cache non è stata cancellata.

Puoi testarlo e correggerlo eseguendo il seguente comando console:

cache:clear


4. Caratteri non ACSII all'interno del file zip

Apparentemente, questo errore può verificarsi anche quando si chiama zip->close()quando alcuni file all'interno dello zip hanno caratteri non ASCII nel loro nome file, come "é".

Una potenziale soluzione è racchiudere il nome del file utf8_decode()prima di creare il file di destinazione.

Ringraziamo Fran Cano per aver identificato e suggerito una soluzione a questo problema


4
Penso che menzionare selinuxpotrebbe essere una buona idea qui. avrai almeno bisogno httpd_sys_content_t(directory e file di sola lettura utilizzati da Apache) dei file inclusi.
Bansi,

Grazie mille per il suggerimento. Dato che non ho familiarità con SELinux, ho fatto qualche lettura e ho cercato di rispondere a questo caso. Non esitare a fornire feedback o suggerire alcune modifiche se non è corretto. Grazie ancora per il commento !
Vic Seedoubleyew,

chconè temporaneo e non sopravviverà restoreconal riavvio o al riavvio. potrebbe essere necessario utilizzare semanageper modificare il contesto del file. Ecco un buon semplice tutorial per il sito web
bansi

Un'altra possibilità da aggiungere: memorizzazione nella cache realpath: lyte.id.au/2014/05/01/what-the-hell-php
chrishiestand

@chrishiestand grazie mille! Quell'articolo è davvero interessante! Ricordi qual è stato il corso degli eventi che hanno portato a quell'errore? Inizialmente l'utente non aveva accesso in lettura a un file, quindi è stato modificato, ma la cache ha comunque considerato che non era leggibile, quindi ha gettato quell'errore all'apertura del file?
Vic Seedoubleyew,

16

Da aggiungere alla (davvero buona) risposta esistente

Software di hosting condiviso

open_basedirè uno che può sconcertarti perché può essere specificato in una configurazione del server web. Mentre questo può essere facilmente risolto se si esegue il proprio server dedicato, ci sono alcuni pacchetti software di hosting condiviso là fuori (come Plesk, cPanel, ecc.) Che configureranno una direttiva di configurazione su base per dominio. Poiché il software crea il file di configurazione (cioè httpd.conf) non è possibile modificarlo direttamente perché il software di hosting lo sovrascriverà al riavvio.

Con Plesk, forniscono un posto per sovrascrivere il httpd.confchiamato fornito vhost.conf. Solo l'amministratore del server può scrivere questo file. La configurazione di Apache è simile a questa

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

Chiedi al tuo amministratore del server di consultare il manuale del software di hosting e web server che usano.

Autorizzazioni file

È importante notare che l'esecuzione di un file tramite il proprio server Web è molto diversa dalla riga di comando o dall'esecuzione di un processo cron. La grande differenza è che il tuo server web ha i propri utenti e autorizzazioni. Per motivi di sicurezza l'utente è piuttosto limitato. Apache, per esempio, è spesso apache, www-datao httpd(a seconda del server). Un cron job o l'esecuzione della CLI ha tutte le autorizzazioni che l'utente ha in esecuzione (ovvero l'esecuzione di uno script PHP come root verrà eseguito con le autorizzazioni di root).

Molte volte le persone risolveranno un problema di permessi procedendo come segue (esempio Linux)

chmod 777 /path/to/file

Questa non è un'idea intelligente, perché il file o la directory sono ora scrivibili dal mondo. Se possiedi il server e sei l'unico utente, questo non è un grosso problema, ma se ti trovi in ​​un ambiente di hosting condiviso hai appena dato l'accesso a tutti al tuo server.

Quello che devi fare è determinare gli utenti che hanno bisogno di accesso e dare solo quelli a cui hanno accesso. Una volta che sai quali utenti devono accedere, devi assicurarti che

  1. Quell'utente possiede il file e possibilmente la directory principale (in particolare la directory principale se si desidera scrivere file). Nella maggior parte degli ambienti di hosting condivisi questo non sarà un problema, perché l'utente dovrebbe possedere tutti i file sottostanti il ​​root. Un esempio di Linux è mostrato sotto

     chown apache:apache /path/to/file
  2. L'utente, e solo quell'utente, ha accesso. In Linux, una buona pratica sarebbe chmod 600(solo il proprietario può leggere e scrivere) o chmod 644(il proprietario può scrivere ma tutti possono leggere)

Puoi leggere una discussione più estesa delle autorizzazioni e degli utenti Linux / Unix qui


7
  1. Guarda l' errore esatto

Il mio codice ha funzionato bene su tutte le macchine, ma solo su questo ha iniziato a dare problemi (che una volta funzionava, credo). Usato echo "document_root" percorso per il debug e anche guardato da vicino l'errore, trovato questo

Avvertenza: include ( D: /MyProjects/testproject//functions/connections.php ): impossibile aprire il flusso:

Puoi facilmente vedere dove sono i problemi. I problemi sono // prima delle funzioni

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

Quindi basta rimuovere il carico / da include e dovrebbe funzionare bene. Ciò che è interessante è che questi comportamenti sono diversi nelle diverse versioni. Ho eseguito lo stesso codice su Laptop, Macbook Pro e questo PC, tutto ha funzionato bene fino a quando. Spero che questo aiuti qualcuno.

  1. Copia oltre il percorso del file nel browser per assicurarti che il file esista. A volte i file vengono eliminati inaspettatamente (è successo con me) ed è stato anche il problema nel mio caso.

In cosa differisce dal passaggio 1 dell'elenco di controllo di seguito?
Vic Seedoubleyew,

Passaggio 2: un ulteriore controllo, non correlato al passaggio 1. È sufficiente accedere al percorso proposto nel browser e vedere se il file è presente (no in Windows Explorer ma nel browser).
Hammad Khan,

2

Aggiungi script con parametri di query

Quello era il mio caso. In realtà si collega alla domanda # 4485874 , ma lo spiegherò qui a breve.
Quando si tenta di richiedere path/to/script.php?parameter=value, PHP cerca il file denominato script.php?parameter=value, poiché UNIX consente di disporre di percorsi come questo.
Se hai davvero bisogno di passare alcuni dati allo script incluso, dichiaralo come $variable=...o $GLOBALS[]=...o come preferisci.


2

Azioni Samba

Se disponi di un server di test Linux e lavori da un client Windows, la condivisione Samba interferisce con il comando chmod . Quindi, anche se usi:

chmod -R 777 myfolder

dal lato Linux è possibile che Unix Group \ www-data non abbia ancora accesso in scrittura. Una soluzione funzionante se la tua condivisione è impostata in modo che gli amministratori di Windows siano mappati su root: da Windows, apri le Autorizzazioni, disabilita l'Eredità per la tua cartella con copia e quindi concedi l'accesso completo per i dati www.


1

Un'altra possibile causa: rinominare e / o spostare i file in un editor di testo. Ho seguito tutti i passaggi precedenti senza successo fino a quando non ho eliminato il file che ha continuato a generare questo errore e ne ho creato uno nuovo, che ha risolto il problema.


1
se capissi cosa intendi correttamente, questo sarebbe stato
risolto

Il n. 1 non è esplicito sulle potenziali cause
zMeadz,

sì, ma non ti importa delle cause, ti interessa trovare il modo di risolvere il problema. Ancora più importante, il passaggio numero 1 avrebbe risolto il tuo problema
Vic Seedoubleyew il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.