PHP skriptos, zvanot include()
, require()
, fopen()
vai to atvasinājumus, piemēram, include_once
, require_once
vai pat move_uploaded_file()
, bieži sastopamies ar kļūdu vai brīdinājumu:
Neizdevās atvērt plūsmu: nav šāda faila vai direktorijas.
Kāds ir labs process, lai ātri atrastu problēmas pamatcēloni?
Ir daudz iemeslu, kāpēc var rasties šī kļūda, tāpēc labs kontrolsaraksts, kas jāpārbauda vispirms, ievērojami palīdz. Pieņemsim, ka mēs novēršam šādu rindu:
require "/path/to/file"
require*
vai include*
, uz savu mainīgo, echo, nokopējiet to un mēģiniet tam piekļūt no termināļa:
$path = "/path/to/file";
echo "Path : $path";
require "$path";
Tad terminālī:
cat <ielīmēts <faila ceļš>
/users/tony/htdocs
.require __DIR__ . "/relative/path/from/current/file"
. __DIR__
maģiskā konstante atgriež pašreizējā faila direktoriju.SITE_ROOT
:config.php
.config.php
ierakstiet
define('SITE_ROOT', DIR);config.php
un pēc tam izmantojiet konstanti SITE_ROOT
visur, kur vēlaties:
require_once DIR."/../config.php";
...
require_once SITE_ROOT."/other/file.php";
Šīs 2 prakses arī padara jūsu lietojumprogrammu portatīvāku, jo tā nav atkarīga no ini iestatījumiem, piemēram, include ceļa.
Vēl viens veids, kā iekļaut failus, ne relatīvi, ne tīri absolūti, ir paļauties uz include path. Tas bieži vien attiecas uz bibliotēkām vai ietvarstruktūrām, piemēram, Zend ietvarstruktūru. Šāda iekļaušana izskatīsies šādi :
include "Zend/Mail/Protocol/Imap.php"
Tādā gadījumā jums būs jāpārliecinās, ka mape, kurā atrodas "Zend", ir daļa no include ceļa. Jūs varat pārbaudīt iekļaušanas ceļu ar :
echo get_include_path();
Jūs varat tam pievienot mapi ar :
set_include_path(get_include_path().":"."/path/to/new/folder");
Iespējams, ka lietotājam, kas vada servera procesu (Apache vai PHP), vienkārši'nav tiesību lasīt no šī faila vai rakstīt tajā. Lai pārbaudītu, ar kāda lietotāja vārdu darbojas serveris, varat izmantot posix_getpwuid :
$user = posix_getpwuid(posix_geteuid());
var_dump($user);
Lai noskaidrotu faila atļaujas, terminālī ievadiet šādu komandu:
ls -l <path/to/file>
un apskatiet atļauju simboliskā notācija.
Ja neviens no iepriekš minētajiem variantiem nedarbojās, iespējams, problēma ir tā, ka daži PHP iestatījumi aizliedz piekļūt šim failam. Varētu būt svarīgi trīs iestatījumi :
phpinfo()
vai izmantojot ini_get("open_basedir")
.ini_get("allow_url_include")
un iestatīt ar ini_set("allow_url_include", "1")
.
Ja neviens no iepriekš minētajiem neļāva diagnosticēt problēmu, šeit ir dažas īpašas situācijas, kas varētu notikt :
Var gadīties, ka jūs iekļaujat bibliotēku, piemēram, Zend framework, izmantojot relatīvo vai absolūto ceļu. Piemēram :
require "/usr/share/php/libzend-framework-php/Zend/Mail/Protocol/Imap.php"
Bet tad jūs joprojām saņemat tāda paša veida kļūdu. Tas varētu notikt tāpēc, ka datnē, kuru esat (veiksmīgi) iekļāvis, ir iekļauts paziņojums include citai datnei, un šis otrais paziņojums include pieņem, ka esat pievienojis šīs bibliotēkas ceļu iekļaušanas ceļam. Piemēram, iepriekš minētajā Zend framework failā varētu būt šāds include :
include "Zend/Mail/Protocol/Exception.php"
kas nav ne iekļaušana pēc relatīvā ceļa, ne pēc absolūtā ceļa. Tiek pieņemts, ka Zend framework direktorija ir pievienota include ceļam.
Šādā gadījumā vienīgais praktiskais risinājums ir pievienot direktoriju include ceļam.
Ja jūs izmantojat Security-Enhanced Linux, tad tas varētu būt problēmas cēlonis, liedzot piekļuvi datnei no servera.
Lai pārbaudītu, vai jūsu sistēmā ir ieslēgts SELinux, terminālī palaidiet komandu sestatus
. Ja komanda nepastāv, tad jūsu sistēmā SELinux nav ieslēgts. Ja tā eksistē, tad tā jums pateiks, vai tā ir vai nav ieviesta.
Lai pārbaudītu, vai SELinux politika ir problēmas iemesls, varat mēģināt to uz laiku izslēgt. Tomēr esiet APRĪDZĪGI, jo tas pilnībā atslēgs aizsardzību. Nedariet to savā ražošanas serverī.
setenforce 0
Ja pēc SELinux izslēgšanas problēmas vairs nerodas, tad tas ir galvenais iemesls. Lai to atrisinātu, jums būs attiecīgi jākonfigurē SELinux. Būs nepieciešami šādi konteksta tipi :
httpd_sys_content_t
failiem, kurus vēlaties, lai jūsu serveris varētu lasīt.httpd_sys_rw_content_t
failiem, kuriem vēlaties nodrošināt piekļuvi lasīšanai un rakstīšanai.httpd_log_t
žurnāla failiemhttpd_cache_t
kešatmiņas direktorijai
Piemēram, lai vietnes saknes direktorijam piešķirtu httpd_sys_content_t
konteksta tipu, izpildiet :semanage fcontext -a -t httpd_sys_content_t "/path/to/root(/.*)?"
restorecon -Rv /path/to/root
Ja jūsu fails atrodas mājas direktorijā, jums būs nepieciešams arī ieslēgt httpd_enable_homedirs
boolean :
setsebool -P httpd_enable_homedirs 1
Jebkurā gadījumā var būt dažādi iemesli, kāpēc SELinux varētu liegt piekļuvi failam, atkarībā no jūsu politikas. Tāpēc jums par to būs jāinteresējas. Šeit ir pamācība par SELinux konfigurēšanu tīmekļa serverim.
Ja jūs izmantojat Symfony un piedzīvo šo kļūdu, augšupielādējot uz serveri, tad tā var būt tāda, ka lietotnes kešatmiņa nav atiestatīta vai nu tāpēc, ka ir augšupielādēta app/cache
, vai arī tāpēc, ka kešatmiņa nav iztīrīta.
To var pārbaudīt un novērst, izpildot šādu konsoles komandu:
cache:clear
Acīmredzot šī kļūda var rasties arī pēc zip->close()
izsaukuma, ja dažu ZIP failu nosaukumos ir rakstzīmes, kas nav ASCII, piemēram, "é".
Iespējamais risinājums ir pirms mērķa faila izveides ietīt faila nosaukumu utf8_decode()
.
Kredīti Fran Cano par šīs problēmas identificēšanu un risinājuma ierosināšanu.
Lai papildinātu (patiešām labu) esošo atbildi
open_basedir
ir viens no tiem, kas var jūs pārsteigt, jo to var norādīt tīmekļa servera konfigurācijā. Tas ir viegli novēršams, ja izmantojat savu īpašo serveri, taču ir dažas koplietojamās hostinga programmatūras paketes (piemēram, Plesk, cPanel u. c.), kas konfigurē konfigurācijas direktīvu katrai domēnai atsevišķi. Tā kā programmatūra izveido konfigurācijas failu (t. i., httpd.conf
), jūs nevarat tieši mainīt šo failu, jo hostinga programmatūra to vienkārši pārrakstīs, kad tā tiks restartēta.
Plesk nodrošina vietu, kur var aizstāt nodrošināto httpd.conf
, ko sauc par vhost.conf
. Šo failu var ierakstīt tikai servera administrators. Apache konfigurācija izskatās apmēram šādi
<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>
Palūdziet servera administratoram iepazīties ar viņa izmantotās hostinga un tīmekļa servera programmatūras rokasgrāmatu.
Ir svarīgi atzīmēt, ka faila izpilde, izmantojot tīmekļa serveri, ļoti atšķiras no komandrindas vai cron uzdevuma izpildes. Lielākā atšķirība ir tā, ka tīmekļa serverim ir savs lietotājs un atļaujas. Drošības apsvērumu dēļ šis lietotājs ir diezgan ierobežots. Piemēram, Apache bieži ir apache
, www-data
vai httpd
(atkarībā no servera). Cron darbam vai CLI izpildei ir tādas atļaujas, kādas ir lietotājam, kas to izpilda (t. i., PHP skripta izpilde kā root tiks izpildīta ar root atļaujām).
Bieži vien cilvēki atrisina atļauju problēmu, veicot šādu darbību (Linux piemērs).
chmod 777 /path/to/file
Tā nav gudra ideja, jo fails vai direktorija tagad ir rakstāma visā pasaulē. Ja serveris pieder jums un jūs esat vienīgais lietotājs, tad tas nav nekas briesmīgs, bet, ja jūs izmantojat koplietošanas hostinga vidi, tad jūs vienkārši esat piešķīris piekļuvi visiem servera lietotājiem.
Jums ir jānosaka lietotājs(-i), kam nepieciešama piekļuve, un tikai tiem jāpiešķir piekļuve. Kad zināt, kuriem lietotājiem ir nepieciešama piekļuve, jums būs jāpārliecinās, ka
šim lietotājam pieder fails un, iespējams, arī mātes direktorijs (īpaši mātes direktorijs, ja vēlaties rakstīt failus). Lielākajā daļā koplietošanas hostinga vidēs tas nebūs problēma, jo jūsu lietotājam pieder visi faili zem jūsu saknes. Linux piemērs ir parādīts turpmāk
chown apache:apache /path/to/file
Lietotājam, un tikai šim lietotājam, ir piekļuve. Linux operētājsistēmā laba prakse būtu chmod 600
(tikai īpašnieks var lasīt un rakstīt) vai chmod 644
(īpašnieks var rakstīt, bet visi var lasīt).
Plašāku diskusiju par Linux/Unix atļaujām un lietotājiem var lasīt šeit.
Vēl viens iespējamais iemesls: Failu pārdēvēšana un/vai pārvietošana teksta redaktorā. Es izgāju cauri visiem iepriekš minētajiem soļiem bez panākumiem, līdz es izdzēsu failu, kas turpināja mest šo kļūdu, un izveidoju jaunu failu, kas atrisināja problēmu.