Lyhyesti: Nimiavaruudet ovat PHP:ssä eräänlaisia kansioita luokkien nimille: App\Rechnung\Pdf ja Bibliothek\Pdf voivat olla rinnakkain häiritsemättä toisiaan. Automaattinen lataus huolehtii siitä, että PHP lataa luokan vasta, kun sitä tarvitaan ensimmäisen kerran. Standardi PSR-4 määrittää, miten luokan nimestä tulee tiedostopolku; Composer tuottaa sen jälkeen sopivan lataajan. Koska tämä lataaja suoritetaan jokaisella pyynnöllä, se kuuluu tietoturvapoikkeaman jälkeen ensimmäisiin tarkastettaviin asioihin.
Miksi PHP tarvitsee nimiavaruuksia
Nimiavaruuksia on ollut versiosta PHP 5.3.0 lähtien. Sitä ennen kaikki luokat ja funktiot jakoivat yhden ainoan globaalin nimiavaruuden. Jos kaksi kirjastoa oli nimeltään Logger, syntyi törmäys. Kehittäjät auttoivat itseään pitkillä nimillä, kuten Firma_Modul_Unterbereich_Logger.
PHP-käsikirja mainitsee kaksi ongelmaa, jotka nimiavaruudet ratkaisevat: nimitörmäykset oman koodin, PHP:n sisäisten luokkien ja kolmansien osapuolten kirjastojen välillä sekä ylipitkät nimet, jotka syntyivät vain näiden törmäysten kiertämiseksi. Päättäjälle tämä tarkoittaa: vasta nimiavaruudet ovat tehneet käytännölliseksi yhdistää projektissa kymmeniä vieraita paketteja, kuten Composerin kanssa nykyisin tehdään.
Nimiavaruudet käytännössä: namespace, use, aliakset
Tiedosto ilmoittaa nimiavaruutensa ensimmäisessä lauseessa. Käskyllä use tuodaan luokkia muista nimiavaruuksista, halutessa lyhyemmällä nimellä.
<?php
declare(strict_types=1);
namespace App\Rechnung;
use App\Kunde\Kunde;
use Psr\Log\LoggerInterface as Log;
final class PdfErzeuger
{
public function __construct(private Log $log) {}
public function erzeugen(Kunde $kunde): string
{
$this->log->info('PDF erzeugt', ['kunde' => $kunde->id]);
return \sprintf('Rechnung für %s', $kunde->name);
}
}
Tämän luokan täydellinen nimi on App\Rechnung\PdfErzeuger. Alussa oleva kenoviiva kohdassa \sprintf viittaa nimenomaisesti globaaliin PHP-funktioon.
Automaattinen lataus: luokat ladataan tarpeen mukaan
Ilman automaattista latausta jokaisen komentosarjan pitäisi liittää tarvitsemansa tiedostot käskyllä require. Funktiolla spl_autoload_register() rekisteröidään sen sijaan funktio, jonka PHP kutsuu heti, kun tuntematon luokka, rajapinta, trait tai enum otetaan käyttöön. Se saa luokan nimen ja lataa sopivan tiedoston.
<?php
spl_autoload_register(function (string $klasse): void {
$praefix = 'App\\';
$basis = __DIR__ . '/src/';
if (!str_starts_with($klasse, $praefix)) {
return; // ei vastuulla, seuraava lataaja on vuorossa
}
$datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
if (is_file($datei)) {
require $datei;
}
});
Funktiota spl_autoload_register() voi kutsua useita kertoja. PHP kysyy silloin rekisteröityjä lataajia vuorotellen, kunnes jokin on ladannut luokan. Käytännössä suurissa sovelluksissa on usein useita: Composerin lataaja kirjastoille, CMS:n oma sekä lisäosien tai moduulien lataajat. Ylläpitäjälle tämä tarkoittaa: se, mikä koodi pyynnöllä todella ladataan, määräytyy kaikkien näiden lataajien yhteispelistä eikä pelkästään kansiorakenteesta.
Käsikirja neuvoo painokkaasti olemaan heittämättä poikkeuksia lataajassa; PSR-4 kieltää sen nimenomaisesti. Vanhempi funktio __autoload() merkittiin vanhentuneeksi versiossa PHP 7.2.0 ja poistettiin versiossa PHP 8.0.0.
PSR-4: luokan nimestä tiedostopolkuun
PSR-4 on PHP-FIG:n standardi. Täydellinen luokan nimi alkaa valmistajan nimiavaruudella. Nimiavaruuden etuliite yhdistetään perushakemistoon, loppuosa nimestä muodostaa alikansiot, ja tiedosto päättyy .php. Isojen ja pienten kirjainten on täsmättävä tarkasti. Näin yhdistäminen näkyy tiedostossa composer.json:
{
"autoload": {
"psr-4": { "App\\": "src/" }
}
}
| Luokan nimi | Tiedosto |
|---|---|
App\Kunde\Kunde |
src/Kunde/Kunde.php |
App\Rechnung\PdfErzeuger |
src/Rechnung/PdfErzeuger.php |
App\Rechnung\Pdf\Vorlage |
src/Rechnung/Pdf/Vorlage.php |
Klassinen kompastuskivi on isojen ja pienten kirjainten käyttö. Windows- tai macOS-kehityskoneilla tiedostojärjestelmä ei usein erota tiedostoja Kunde.php ja kunde.php toisistaan, mutta Linux-palvelimella erottaa. Paikallisesti toimiva sovellus ei silloin löydä luokkaa palvelimella. PSR-4:n sääntö käyttää nimiä täsmälleen oikein kirjoitettuina estää tällaiset yllätykset toimituksessa.
Tiedoston psr-4 lisäksi Composer tuntee classmap-määrityksen koodille, jolla ei ole vakiorakennetta, sekä files-määrityksen tiedostoille, jotka ladataan jokaisella pyynnöllä, esimerkiksi apufunktioille. Muita PHP-FIG:n standardeja kuvaa sivu PSR-standardit.
Lataajan optimointi tuotannossa
Tuotannossa lataajan on parasta olla etsimättä enää tiedostojärjestelmästä vaan hakea valmiista listasta. Composer tarjoaa tähän kaksi tasoa:
composer install --no-dev --optimize-autoloadermuuntaa PSR-4-säännöt luokkalistaksi. Composerin dokumentaation mukaan se on suositeltu tuotantoon.--classmap-authoritativemenee pidemmälle: luokat ladataan yksinomaan listasta. Listaan kuulumattomia tiedostoja lataaja ei silloin lataa lainkaan.- Lista luodaan uudelleen jokaisen toimituksen yhteydessä, jotta uudet luokat löytyvät.
Automaattinen lataus ja tietoturva PHP2Shellin jälkeen
PHP2Shell koskee PHP-tulkkia, ei lataajaa. Pakollisia pysyvät päivitys versioon PHP 8.5.12, 8.4.27, 8.3.36 tai 8.2.35 ja kaikkien worker-prosessien uudelleenkäynnistys. Mahdollisen poikkeaman jälkeen lataaja ansaitsee kuitenkin erityistä huomiota: vendor/autoload.php ja kaikki kohdassa files mainitut tiedostot suoritetaan jokaisella pyynnöllä. Sinne livahtanut rivi vaikuttaa siis koko verkkosivustoon ilman, että latauskansiossa on huomiota herättävää uutta tiedostoa.
Tarkistakaa siksi, vastaavatko vendor ja lataustiedostot versionhallinnan tarkastettua tilaa. Hyödyllisiä ovat artikkelit Äskettäin muuttuneiden tiedostojen löytäminen ja CMS:n ydintiedostojen vertailu alkuperäiseen. Epäselvässä tilanteessa lukitustiedostosta uudelleen tuotettu vendor on turvallisempi kuin yksittäinen korjaus.
Miten PHP SOS auttaa konkreettisesti?
- Vertaamme tiedostoja
vendor, lataaja ja sisäänkäyntitiedostot tarkastettuun tilaan ja merkitsemme jokaisen poikkeaman. - Palautamme pakettikannan lukitustiedostosta ja otamme käyttöön optimoidun lataajan.
- Tarkistamme, että verkkojuuressa on vain julkinen kansio eikä lähdekoodi ole suoraan tavoitettavissa URL-osoitteella.
- Saastumistapauksessa hoidamme puhdistuksen haittaohjelmien poiston puitteissa ja dokumentoimme tuloksen.
Usein kysytyt kysymykset
Mistä lähtien PHP:ssä on ollut nimiavaruuksia?
Versiosta PHP 5.3.0 lähtien. Käsikirjan mukaan ne ratkaisevat kaksi ongelmaa: nimitörmäykset oman koodin, PHP:n ja kolmansien osapuolten kirjastojen välillä sekä ylipitkät luokkanimet, jotka syntyivät vain tällaisten törmäysten välttämiseksi.
Mikä on ero PSR-0:n ja PSR-4:n välillä?
Molemmat kuvaavat luokkien nimet tiedostopoluiksi. PSR-4:ssä nimiavaruuden etuliitettä ei toisteta tiedostopolussa, mikä tuottaa matalamman hakemistorakenteen. PHP-FIG on luokitellut PSR-0:n vanhentuneeksi, ja PSR-4 on suositeltu standardi.
Toimiiko __autoload() vielä?
Ei toimi. __autoload() merkittiin vanhentuneeksi versiossa PHP 7.2.0 ja poistettiin versiossa PHP 8.0.0. Nykyisin lataajat rekisteröidään funktiolla spl_autoload_register(), käytännössä yleensä Composerin tuottaman lataajan kautta.
Pitääkö lataaja luoda uudelleen, kun luo uuden luokan?
Puhtailla PSR-4-säännöillä ei tarvitse; Composerin dokumentaation mukaan se on juuri PSR-4:n etu. Jos tuotannossa käytetään optimoitua luokkalistaa, se on luotava uudelleen jokaisen toimituksen yhteydessä.