In PHP scripts, of het nu gaat om include()
, require()
, fopen()
, of hun afgeleiden zoals include_once
, require_once
, of zelfs, move_uploaded_file()
, loopt men vaak tegen een fout of waarschuwing aan:
Mislukt om stream te openen : No such file or directory.
Wat is een goed proces om snel de hoofdoorzaak van het probleem te vinden?
Er zijn vele redenen waarom men deze fout zou kunnen tegenkomen en dus helpt een goede checklist van wat eerst te controleren aanzienlijk. Laten we eens overwegen dat we de volgende regel aan het oplossen zijn:
require "/path/to/file"
require*
of include*
naar zijn eigen variabele, echo het, kopieer het, en probeer het te openen vanaf een terminal:
$path = "/path/to/file";
echo "Path : $path";
require "$path";
Dan, in een terminal:
cat /users/tony/htdocs
kunnen zijnrequire __DIR__ . "/relative/path/from/current/file"
. De __DIR__
magische constante geeft de directory van het huidige bestand.SITE_ROOT
constante :config.php
config.php
, schrijf
define('SITE_ROOT', DIR);config.php
, en gebruik dan de SITE_ROOT
constante waar u maar wilt :
require_once DIR."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
Deze 2 praktijken maken je applicatie ook meer portable omdat het niet afhankelijk is van ini instellingen zoals het include pad.
Een andere manier om bestanden te includen, noch relatief noch puur absoluut, is door te vertrouwen op het include path. Dit is vaak het geval voor bibliotheken of frameworks zoals het Zend framework. Zo'n inclusie zal er als volgt uitzien :
include "Zend/Mail/Protocol/Imap.php"
In dat geval moet je er zeker van zijn dat de map waar "Zend" staat, deel uitmaakt van het include pad. Je kan het include pad controleren met :
echo get_include_path();
Je kan er een map aan toevoegen met :
set_include_path(get_include_path().":"."/path/to/new/folder");
Het kan zijn dat de gebruiker die het serverproces draait (Apache of PHP) gewoonweg geen toestemming heeft om te lezen van of te schrijven naar dat bestand. Om te controleren onder welke gebruiker de server draait kun je gebruik maken van posix_getpwuid :
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
Om de permissies van het bestand te achterhalen, typ het volgende commando in de terminal:
ls -l <path/to/file>
en kijk naar [permission symbolic notation][permissies-notatie]
Als niets van het bovenstaande werkt, dan is het probleem waarschijnlijk dat sommige PHP instellingen de toegang tot dat bestand verbieden. Drie instellingen zouden relevant kunnen zijn :
phpinfo()
aan te roepen of door ini_get("open_basedir")
te gebruiken.ini_get("allow_url_include")
en ingesteld met ini_set("allow_url_include", "1")
Als geen van de bovenstaande mogelijkheden het probleem kan diagnosticeren, zijn hier enkele speciale situaties die zich kunnen voordoen :
Het kan gebeuren dat je een bibliotheek include, bijvoorbeeld, het Zend framework, gebruik makend van een relatief of absoluut pad. Bijvoorbeeld :
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
Maar dan krijg je nog steeds dezelfde foutmelding. Dit kan gebeuren omdat het bestand dat je (met succes) geinclude hebt, zelf een include statement heeft voor een ander bestand, en dat tweede include statement veronderstelt dat je het pad van die bibliotheek aan het include pad hebt toegevoegd. Bijvoorbeeld, het eerder vermelde Zend framework bestand zou de volgende include kunnen hebben :
include "Zend/Mail/Protocol/Exception.php"
wat noch een inclusie is via relatief pad, noch via absoluut pad. Het is in de veronderstelling dat de Zend raamwerk directory toegevoegd is aan het include pad.
In zo'n geval is de enige praktische oplossing de directory aan je include pad toe te voegen.
Als je Security-Enhanced Linux draait, dan kan dat de reden van het probleem zijn, door de toegang tot het bestand vanaf de server te weigeren.
Om te controleren of SELinux is ingeschakeld op uw systeem, voert u het sestatus
commando uit in een terminal. Als het commando niet bestaat, dan is SELinux niet op uw systeem ingeschakeld. Als het wel bestaat, dan zou het u moeten vertellen of het wordt afgedwongen of niet.
Om te controleren of SELinux-beleid de reden is van het probleem, kunt u proberen het tijdelijk uit te schakelen. Wees echter VOORZICHTIG, want dit zal de beveiliging volledig uitschakelen. Doe dit niet op uw productieserver.
setenforce 0
Als je het probleem niet meer hebt met SELinux uitgeschakeld, dan is dit de hoofdoorzaak. Om het op te lossen, moet je SELinux dienovereenkomstig configureren. De volgende context types zullen nodig zijn :
httpd_sys_content_t
voor bestanden waarvan je wilt dat je server ze kan lezenhttpd_sys_rw_content_t
voor bestanden waar u lees- en schrijftoegang op wilt hebbenhttpd_log_t
voor log bestandenhttpd_cache_t
voor de cache map
Bijvoorbeeld, om het httpd_sys_content_t
context type toe te wijzen aan de root directory van uw website, voert u :semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root
Als je bestand in een home directory staat, moet je ook de httpd_enable_homedirs
boolean aanzetten:
setsebool -P httpd_enable_homedirs 1
In elk geval kunnen er verschillende redenen zijn waarom SELinux de toegang tot een bestand zou weigeren, afhankelijk van uw beleid. Dus u zult dat moeten onderzoeken. Hier is een tutorial specifiek over het configureren van SELinux voor een webserver.
Als je Symfony gebruikt, en deze fout ervaart bij het uploaden naar een server, dan kan het zijn dat de cache van de app's niet gereset is, ofwel omdat app/cache
geupload is, of dat cache niet's gewist is.
Je kunt dit testen en oplossen door het volgende console commando uit te voeren:
cache:clear
Blijkbaar kan deze fout ook optreden bij het aanroepen van zip->close()
wanneer sommige bestanden in de zip niet-ASCII karakters in hun bestandsnaam hebben, zoals "é".
Een mogelijke oplossing is om de bestandsnaam te wikkelen in utf8_decode()
voordat het doelbestand wordt gemaakt.
Met dank aan Fran Cano voor het identificeren en aandragen van een oplossing voor dit probleem
Om toe te voegen aan het (echt goede) bestaande antwoord
open_basedir
is er een die je kan stuntelen omdat het kan worden opgegeven in een webserverconfiguratie. Hoewel dit gemakkelijk te verhelpen is als je je eigen dedicated server draait, zijn er sommige shared hosting software pakketten die er zijn (zoals Plesk, cPanel, etc) die een configuratie richtlijn op een per-domein basis zullen configureren. Omdat de software het configuratiebestand bouwt (d.w.z. httpd.conf
) kunt u dat bestand niet direct wijzigen omdat de hosting software het gewoon zal overschrijven wanneer het opnieuw opstart.
Met Plesk, bieden ze een plaats aan om de httpd.conf
te overschrijven, genaamd vhost.conf
. Alleen de server admin kan dit bestand schrijven. De configuratie voor Apache ziet er ongeveer zo uit
<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>
Laat je server admin de handleiding raadplegen van de hosting en web server software die ze gebruiken.
Het's belangrijk om op te merken dat het uitvoeren van een bestand via uw webserver heel anders is dan een command line of cron job uitvoering. Het grote verschil is dat je webserver zijn eigen gebruiker en permissies heeft. Om veiligheidsredenen is die gebruiker nogal beperkt. Apache, bijvoorbeeld, is vaak apache
, www-data
of httpd
(afhankelijk van je server). Een cron job of CLI uitvoering heeft de permissies die de gebruiker heeft die het uitvoert (bv. een PHP script uitvoeren als root zal met de permissies van root gebeuren).
Vaak lossen mensen een permissieprobleem op door het volgende te doen (Linux voorbeeld)
chmod 777 /path/to/file
Dit is geen slim idee, want het bestand of de directory is nu wereld beschrijfbaar. Als je de eigenaar bent van de server en de enige gebruiker bent dan is dit't zo'n big deal, maar als je're op een gedeelde hosting omgeving zit dan heb je'net iedereen op je server toegang gegeven.
Wat u moet doen is de gebruiker(s) bepalen die toegang nodig hebben en alleen die toegang geven. Zodra u weet welke gebruikers toegang nodig hebben, zult u ervoor willen zorgen dat
Die gebruiker is eigenaar van het bestand en eventueel de bovenliggende map (vooral de bovenliggende map als je bestanden wilt schrijven). In de meeste gedeelde hosting omgevingen zal dit'geen probleem zijn, omdat uw gebruiker eigenaar zou moeten zijn van alle bestanden onder uw root. Een Linux voorbeeld staat hieronder
chown apache:apache /path/to/file
De gebruiker, en alleen die gebruiker, heeft toegang. In Linux, zou een goede gewoonte zijn chmod 600
(alleen de eigenaar kan lezen en schrijven) of chmod 644
(eigenaar kan schrijven maar iedereen kan lezen)
Je kunt een uitgebreidere discussie over Linux/Unix permissies en gebruikers hier lezen
Een andere mogelijke oorzaak: Het hernoemen en/of verplaatsen van bestanden terwijl je in een tekstverwerker zit. Ik heb alle bovenstaande stappen doorlopen zonder succes totdat ik het bestand dat deze foutmelding gaf verwijderde en een nieuw bestand aanmaakte, wat het probleem oploste.