Dabartinė padėtis: PHP2Shell. Du kritiniai PHP pažeidžiamumai (CVSS 9,2) leidžia vykdyti kenkėjišką kodą be prisijungimo. Pataisos nuo 2026-10-21.Ką dabar daryti →

Vardų erdvės ir autoloading (PSR-4)

Vardų erdvės tvarko PHP kodą, o autoloading įkelia klases būtent tada, kai jų prireikia. Čia matote, kaip PSR-4 susieja klasių pavadinimus su failais ir kodėl po incidento autoloader reikia patikrinti.

Būsena 4 min. skaitymoPHP žinios

Trumpai: Vardų erdvės PHP yra tarsi aplankai klasių pavadinimams: App\Rechnung\Pdf ir Bibliothek\Pdf gali egzistuoti greta, netrukdydamos viena kitai. Autoloading užtikrina, kad PHP klasę įkeltų tik tada, kai jos pirmą kartą prireikia. Standartas PSR-4 nustato, kaip iš klasės pavadinimo gaunamas failo kelias; Composer paskui sukuria tinkamą autoloader. Kadangi šis autoloader veikia per kiekvieną užklausą, po saugumo incidento jis patenka tarp pirmųjų dalykų, kuriuos reikia patikrinti.

Kodėl PHP reikia vardų erdvių

Vardų erdvės egzistuoja nuo PHP 5.3.0. Anksčiau visos klasės ir funkcijos dalijosi viena globalia vardų erdve. Jei dvi bibliotekos vadindavosi Logger, kildavo trikdis. Kūrėjai išsisukdavo ilgais pavadinimais, tokiais kaip Firma_Modul_Unterbereich_Logger.

PHP vadovas nurodo dvi problemas, kurias išsprendžia vardų erdvės: pavadinimų kolizijas tarp savo kodo, vidinių PHP klasių ir trečiųjų šalių bibliotekų, taip pat pernelyg ilgus pavadinimus, atsiradusius tik tokioms kolizijoms apeiti. Sprendimų priėmėjams tai reiškia: tik vardų erdvės padarė praktiška viename projekte derinti dešimtis svetimų paketų, kaip šiandien įprasta su Composer.

Vardų erdvės praktikoje: namespace, use, slapyvardžiai

Failas savo vardų erdvę deklaruoja pirmajame sakinyje. Su use į failą įtraukiamos klasės iš kitų vardų erdvių, pageidaujant trumpesniu pavadinimu.

<?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);
    }
}

Visas šios klasės pavadinimas yra App\Rechnung\PdfErzeuger. Pirmaujantis atvirkštinis brūkšnys prie \sprintf aiškiai nurodo globaliąją PHP funkciją.

Autoloading: klasių įkėlimas pagal poreikį

Be autoloading kiekvienas skriptas visus reikalingus failus turėtų įtraukti su require. Vietoj to su spl_autoload_register() užregistruojama funkcija, kurią PHP iškviečia, kai tik panaudojama nežinoma klasė, sąsaja, trait ar enum. Ji gauna klasės pavadinimą ir įkelia tinkamą failą.

<?php
spl_autoload_register(function (string $klasse): void {
    $praefix = 'App\\';
    $basis   = __DIR__ . '/src/';

    if (!str_starts_with($klasse, $praefix)) {
        return; // neatsakingas, eilė kitam autoloader
    }
    $datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
    if (is_file($datei)) {
        require $datei;
    }
});

spl_autoload_register() galima iškviesti kelis kartus. Tuomet PHP užregistruotų autoloader'ių teiraujasi paeiliui, kol vienas klasę įkelia. Praktikoje didelės programos dažnai turi kelis: Composer autoloader bibliotekoms, savą CMS autoloader ir kitus iš papildinių ar modulių. Administratoriams tai reiškia: koks kodas per užklausą iš tikrųjų įkeliamas, lemia visų šių autoloader'ių sąveika, o ne vien aplankų struktūra.

Vadovas primygtinai nerekomenduoja autoloader'yje mesti išimčių; PSR-4 tai aiškiai draudžia. Senesnė funkcija __autoload() su PHP 7.2.0 pažymėta kaip pasenusi, o su PHP 8.0.0 pašalinta.

PSR-4: nuo klasės pavadinimo iki failo kelio

PSR-4 yra PHP-FIG standartas. Visas klasės pavadinimas prasideda gamintojo vardų erdve. Vardų erdvės prefiksas priskiriamas bazinį katalogui, likusi pavadinimo dalis tampa poaplankiais, o failas baigiasi .php. Didžiosios ir mažosios raidės turi tiksliai sutapti. Taip priskyrimas atrodo faile composer.json:

{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}
Klasės pavadinimas Failas
App\Kunde\Kunde src/Kunde/Kunde.php
App\Rechnung\PdfErzeuger src/Rechnung/PdfErzeuger.php
App\Rechnung\Pdf\Vorlage src/Rechnung/Pdf/Vorlage.php

Klasikinis suklupimo akmuo yra didžiosios ir mažosios raidės. Kūrimo kompiuteriuose su Windows ar macOS failų sistema dažnai neskiria Kunde.php ir kunde.php, o Linux serveryje skiria. Programa, kuri lokaliai veikia, serveryje klasės nerastų. PSR-4 taisyklė naudoti pavadinimus tiksliai teisinga rašyba tokių netikėtumų diegiant išvengia.

Be psr-4 Composer žino classmap kodui be standartinės struktūros ir files failams, kurie įkeliami per kiekvieną užklausą, pavyzdžiui, pagalbinėms funkcijoms. Kitus PHP-FIG standartus aprašo puslapis PSR standartai.

Autoloader optimizavimas produkcijoje

Produkcijoje autoloader geriausia nebeieško failų sistemoje, o žiūri į paruoštą sąrašą. Composer tam siūlo du lygius:

  1. composer install --no-dev --optimize-autoloader PSR-4 taisykles paverčia klasių sąrašu. Pasak Composer dokumentacijos, tai rekomenduojama produkcijai.
  2. --classmap-authoritative eina toliau: klasės įkeliamos išimtinai iš sąrašo. Neįtrauktų failų autoloader tuomet apskritai neįkelia.
  3. Kiekvieno diegimo metu sąrašas sukuriamas iš naujo, kad būtų rastos naujos klasės.

Autoloading ir saugumas po PHP2Shell

PHP2Shell liečia PHP interpretatorių, o ne autoloader. Privaloma lieka atnaujinti iki PHP 8.5.12, 8.4.27, 8.3.36 ar 8.2.35 ir paleisti iš naujo visus darbinius procesus (worker). Tačiau po galimo incidento autoloader nusipelno ypatingo dėmesio: vendor/autoload.php ir visi po files įrašyti failai vykdomi per kiekvieną užklausą. Ten įterpta eilutė veikia visoje svetainėje, nors įkėlimų aplanke nėra krentančio į akis naujo failo.

Todėl patikrinkite, ar vendor ir autoload failai atitinka patikrintą būseną iš versijų valdymo sistemos. Naudingi straipsniai Neseniai pakeistų failų paieška ir CMS branduolio failų palyginimas su originalu. Abejojant, iš lock failo iš naujo sukurtas vendor yra saugesnis nei bet koks pavienis taisymas.

Kaip PHP SOS padeda konkrečiai?

  • Lyginame vendor, autoloader ir įėjimo failus su patikrinta būsena ir pažymime kiekvieną nukrypimą.
  • Atkuriame paketų rinkinį iš lock failo ir įrengiame optimizuotą autoloader.
  • Tikriname, ar žiniatinklio šakniniame kataloge yra tik viešasis aplankas ir ar šaltinio kodas nepasiekiamas tiesiogiai per URL.
  • Užkrėtimo atveju atliekame valymą pagal kenkėjiškos programinės įrangos šalinimo paslaugą ir dokumentuojame rezultatą.

Dažni klausimai

Nuo kada PHP yra vardų erdvės?

Nuo PHP 5.3.0. Pasak vadovo, jos išsprendžia dvi problemas: pavadinimų kolizijas tarp savo kodo, PHP ir trečiųjų šalių bibliotekų bei pernelyg ilgus klasių pavadinimus, atsiradusius tik tokioms kolizijoms išvengti.

Kuo skiriasi PSR-0 ir PSR-4?

Abu susieja klasių pavadinimus su failų keliais. PSR-4 atveju vardų erdvės prefiksas nekartojamas failo kelyje, todėl katalogai būna plokštesni. PHP-FIG PSR-0 laiko pasenusiu, PSR-4 yra rekomenduojamas standartas.

Ar __autoload() dar veikia?

Ne. __autoload() su PHP 7.2.0 pažymėtas kaip pasenęs, o su PHP 8.0.0 pašalintas. Šiandien autoloader'iai registruojami su spl_autoload_register(), praktikoje dažniausiai per Composer sukurtą autoloader.

Ar sukūrus naują klasę autoloader reikia generuoti iš naujo?

Esant vien PSR-4 taisyklėms ne; pasak Composer dokumentacijos, tai kaip tik yra PSR-4 privalumas. Kas produkcijoje naudoja optimizuotą klasių sąrašą, turi jį sugeneruoti iš naujo kiekvieno diegimo metu.

Šaltiniai

Skubus kontaktas

Kiekviena valanda svarbi. Parašykite mums dabar.

Trumpai aprašykite sistemą, PHP versiją ir pastebėjimus. Mes atsakysime, išsiaiškinsime padėtį ir dirbsime nuotoliu, kol incidentas bus užbaigtas ir dokumentuotas.

Skubi pagalba