Vissza az előzőleg látogatott oldalra (nem elérhető funkció)Vissza a tananyag kezdőlapjára (P)Ugrás a tananyag előző oldalára (E)Ugrás a tananyag következő oldalára (V)Fogalom megjelenítés (nem elérhető funkció)Fogalmak listája (nem elérhető funkció)Oldal nyomtatása (nem elérhető funkció)Oldaltérkép megtekintése (D)Keresés az oldalon (nem elérhető funkció)Súgó megtekintése (S)

Bevezetés a kliens- és szerveroldali webalkalmazások készítésébe / Szerveroldali szkriptek kódszervezése

Tanulási útmutató

Összefoglalás

Ebben a fejezetben a szerveroldali szkriptek kódjának szervezési kérdéseit és eszközeit tekintjük át. Megnézzük a legelemibb jelölésektől kezdve a bonyolultabb fájlszintű szervezést kívánó megoldásokig a lehetőségeket.

Szerveroldali szkriptek kódszervezése

Szerveroldali megoldásaink során is valószínűleg sok kis függvény keletkezik. Ahogy ezek száma nő, a kód úgy válhat nehezen áttekinthetővé. A függvények egy része általános célú segédfüggvény (ld. például fájl- vagy adatbázis-használat), mások az adott feladat megoldásához szükségesek. A következőkben azokat a lehetőségeket tekintjük át, amelyek segítenek kódjaink megfelelő elrendezésében.

Megjegyzések

Érdemes megjegyzésben feltüntetni az adott függvény funkcióját, paramétereit, rövid leírását. Másik lehetőségként érdemes a nagyobb összefüggő blokkokat vízszintes vonallal elválasztani. Az előző fejezetekben erre több példa is látható.

Példaként vegyük a fájlkezelésnél vett filmlistás példát. Új film beszúrásakor a kódot a következőképpen megjegyzésekkel ellátni:

Forráskód
<?php
//--------------------------------------------------------
//Fájlkezeléssel kapcsolatos segédfüggvények
 
//Adatszerkezet JSON fájlból betöltése
function fajlbol_betolt($fajlnev, $alap = array()) {
    //...
}
 
//Adatszerkezet JSON fájlba mentése
function fajlba_ment($fajlnev, $adat) {
    //...
}
 
//--------------------------------------------------------
//Adatfeldolgozás
 
//Új film beszúrása
function film_beszur($cim, $rendezo, $ev) {
    //...
}
 
//--------------------------------------------------------
//Kérés feldolgozása (főprogram)
 
$hibak = array();
//...
 
if ($_POST) {
    //...
 
    if (!$hibak) {
        //...
    }
}
 
//---------------------------------------------------------
//Kimenet
?>
<!doctype html>
<html>
    <!-- ... -->
</html>

Vissza a tartalomjegyzékhez

A kód funkcionális részei

A megjegyzések nagyobb blokkjai jól jelölik a funkcionálisan összetartozó részeit. Általánosságban a következő részek különböztethetők meg:

Vissza a tartalomjegyzékhez

Fájlokba szervezés

A funkcionálisan elkülönülő részeket érdemes külön fájlban tárolni a hosszútávú karbantarthatóság és a kód újrafelhasználása érdekében. A fájlokba kiszervezett függvények beemelésére több megoldás is van. Mindegyik úgy működik, mintha a fájl tartalmát a helyükre másolnánk.

Példánkra visszatérve a következő fájlokat érdemes létrehozni:

A kiszervezés után az eddig meghívott ujfilm_fajl.php állomány a következőképpen néz ki:

Forráskód
<?php
//Függvények beemelése
include('fileio.php');
include('filmadat.php');
 
//Kérés feldolgozása
//...
 
include('ujfilm_sablon.php');

Vissza a tartalomjegyzékhez

Könyvtárakba szervezés

Mivel egy adott kérést feldolgozó szkript a fenti szervezésnek köszönhetően több fájlba esett szét, egy bonyolultabb alkalmazás esetében ez azt jelentené, hogy az alkalmazás könyvtárában az állományok száma nagyon hamar áttekinthetetlen mértékben megnövekszik. Ennek elkerülése érdekében érdemes a fájlokat a szerepük szerinti könyvtárba helyezni. A könyvtárstruktúra egyedi kialakítás kérdése, de a fent vázolt funkcióknak megfelelően az alábbi könyvtárakat különíthetjük el első körben:

Példánkban a főszkript a következőképpen alakul:

Forráskód
<?php
//Függvények beemelése
include('kozos/fileio.php');
include('adat/filmadat.php');
 
//Kérés feldolgozása
//...
 
include('kimenet/ujfilm_sablon.php');

Vissza a tartalomjegyzékhez

Védett fájlok

A több fájlba szétszedéssel azonban megjelennek olyan állományok a fájlrendszerben, amelyek önmagukban nem képesek kéréseket feldolgozni (fenti példánkban ilyen a fileio.php, a filmadat.php és ujfilm_sablon.php). Ezen fájloknál szükség van a közvetlen meghívást elkerülni. A védelmet különböző szinteken lehet megtenni.

Tokenes védelem

Az első lehetőség az, hogy a kérést ténylegesen kiszolgáló szkript elején definiálunk egy tokent. A védendő szkriptek elején pedig ennek a tokennek a jelenlétét vizsgáljuk. Ha ezeket a védett fájlokat közvetlenül hívjuk meg, akkor hiányzik a token, hibaüzenettel leáll a futtatás. Ha főszkriptet hívjuk meg, akkor viszont létezik a token, és lefut a védett fájl tartalma.

A főszkript elején a token definiálása nem más, mint egy konstans létrehozása (példánkban ez az ujfilm_fajl.php állomány):

Forráskód
<?php
define('TOKEN', 'Védelem');
 
//...
?>

A védett fájlok elején pedig a következő sort szükséges elhelyezni:

Forráskód
<?php if ( ! defined('TOKEN')) exit('Közvetlenül nem elérhető!');

Könyvtár alapú védelem

Az Apache webszerver egyik modulja lehetőséget ad könyvtár alapú konfigurációk, többek között hozzáférési jogosultságok ellenőrzésére. Ehhez a könyvtárban egy .htaccess nevű állományt kell elhelyezni. Ha már állományaink könyvtárba vannak szervezve, akkor minden könyvtárban egy-egy .htaccess állományt szükséges elhelyezni, amely az illetéktelen kiszolgálástól óv. Tartalma:

deny from all

Fájlrendszer alapú védelem

A webszerverek csak egy meghatározott mappának és azok alkönyvtárainak elérését engedélyezik kívülről. Ezt a könyvtárat hívják webes gyökérkönyvtárának. A PHP azonban tetszőlegesen használhatja a fájlrendszert. Így adja magát, hogy a kívülről védendő fájlokat tegyük a webes gyökérkönyvtáron kívülre.

Vissza a tartalomjegyzékhez

Osztályok

A fájlokba való szervezés még nem oldja meg azt a problémát, ha két különböző részfeladat ugyanazt a függvénynevet használja, vagy ugyanolyan nevű globális változókat hoz létre. Eleve a globális változók használata több szempontból kétséges. Jó lenne valamilyen módon egységbe zárni az adott funkcióhoz tartozó adatokat és függvényeket. Erre – ahogy JavaScriptben is – az objektumok szolgálnak. PHP-ban objektumokat a klasszikus objektum-orientáltság elvének megfelelően osztályok példányosításával hozhatunk létre.

A PHP 5-ös verziójától kezdve kifinomult és hatékony nyelvi elemek biztosítják az osztályok kezelését. A PHP-ban szinte minden megtalálható, ami a többi korszerű OOP-s nyelvben is megvan:

Osztályok létrehozása

Osztályokat a class kulcsszóval vezetjük be. Az osztályon belül adattagokat és metódusokat definiálhatunk. Ezek kívülről való elérhetőségét a public, protected és private kulcsszavakkal szabályozhatjuk. Egy metóduson belül az aktuális objektumra a $this mutat, az adattagokat a -> operátorral érjük el. A példányosításkor a konstruktorfüggvény fut le, ebben lehet az objektum alapértékeit beállítani.

Forráskód
<?php
class Gyerek {
    public $kor;
    public $nev;
 
    public function __construct($nev, $kor) {
        $this->nev = $nev;
        $this->kor = $kor;
    }
 
    public function bemutatkozik() {
        echo "A nevem: {$this->nev}\n";
    }
 
    public function alszik() {
        echo "Zzzzzzz....\n";
    }
}
?>

Objektumok példányosítása

Az osztály egy példányát a new kulcsszóval tudjuk létrehozni. A példánynak kívülről csak a publikus adattagjait és metódusait érhetjük el.

Forráskód
<?php
$zsofi = new Gyerek('Zsófia', 7);
$matyi = new Gyerek('Mátyás', 2);
 
$zsofi->bemutatkozik();
$matyi->bemutatkozik();
 
$zsofi->nev = 'Zsozsó';
$zsofi->bemutatkozik();
?>

Eredménye:

A nevem: Zsófia A nevem: Mátyás A nevem: Zsozsó

Getterek és setterek

Az adattagokat érdemes kívülről elrejteni és publikus metódusokon keresztül elérni.

Forráskód
<?php
class Gyerek {
    private $kor;
    private $nev;
 
    public function __construct($nev, $kor) {
        $this->nev = $nev;
        $this->kor = $kor;
    }
 
    public function getNev() {
        return $this->nev;
    }
 
    public function setNev($value) {
        $this->nev = $value;
    }   
 
    public function getKor() {
        return $this->kor;
    }
 
    public function setKor($value) {
        $this->kor = $value;
    }   
 
    public function bemutatkozik() {
        echo "A nevem: {$this->nev}\n";
    }
 
    public function alszik() {
        echo "Zzzzzzz....\n";
    }
}
?>

Használata:

Forráskód
<?php
$sari = new Gyerek('Sári', 7);
$sari->bemutatkozik();
 
$sari->setNev('Sarah');
$sari->bemutatkozik();
?>

Eredménye:

A nevem: Sári A nevem: Dávid A nevem: Sarah

Öröklés

A tulajdonságok újrahasznosítását örökléssel érjük el. Erre PHP-ban az extends kulcsszó való. A konstruktorfüggvényben érdemes a szülő konstruktorfüggvényét meghívni.

Forráskód
<?php
class Ovodas extends Gyerek {
    private $jel;
 
    public function __construct($nev, $kor, $jel) {
        parent::__construct($nev, $kor);
        $this->jel = $jel;
    }
 
    public function getJel() {
        return $this->jel;
    }
 
    public function setJel($value) {
        $this->jel = $value;
    }
 
    public function miAJeled() {
        echo "A jelem: {$this->jel}\n";
    }
}
?>

Használata:

Forráskód
<?php
$zsofi = new Gyerek('Zsófia', 7);
$zsofi->bemutatkozik();
 
$david = new Ovodas('Dávid', 4, 'perec');
$david->bemutatkozik();
$david->miAJeled();
?>

Eredménye:

A nevem: Zsófia A nevem: Dávid A jelem: perec

Vissza a tartalomjegyzékhez

Funkciók osztályokba szervezése

Példánkban a sablonokon kívül minden kiemelt függvénycsoportot osztályokba szervezhetünk.

A fájlkezelő segédfüggvényeket érdemes statikus metódusnak felvenni, mivel nem dolgoznak saját adattal. A fileio.php tehát így néz ki:

Forráskód
<?php if ( ! defined('TOKEN')) exit('Közvetlenül nem elérhető!');
 
class FileIO {
    public static function fajlbol_betolt($fajlnev, $alap = array()) {
        $s = @file_get_contents($fajlnev);
        return ($s === false 
            ? $alap 
            : json_decode($s, true));
    }
 
    public static function fajlba_ment($fajlnev, $adat) {
        $s = json_encode($adat);
        return file_put_contents($fajlnev, $s, LOCK_EX);
    }
}

A filmadatok feldolgozásához kapcsolódó funkciók egy osztályba kerülnek. Azért, hogy elkerüljük a folyamatos betöltést és mentést, az osztály példányosításakor betöltjük egy privát adatmezőbe a filmek listáját, és azzal dolgozunk a további műveletekben. A példány megszűnésekor (destruktor) a tömböt elmentjük fájlba.

Forráskód
<?php if ( ! defined('TOKEN')) exit('Közvetlenül nem elérhető!');
 
class FilmAdat {
 
    private $filmek;
    private $fajlnev;
 
    public function __construct($fajlnev = '') {
        if (!$fajlnev) {
            die('Nincs adatfájl!');
        }
        $this->fajlnev = $fajlnev;
        $this->filmek = FileIO::fajlbol_betolt($this->fajlnev);
    }
 
    public function __destruct() {
        FileIO::fajlba_ment($this->fajlnev, $this->filmek);
    }
 
    public function osszes_film() {
        return $this->filmek;
    }
 
    public function film_beszur($cim, $rendezo, $ev) {
        $this->filmek[] = array(
            'cim'       =>  $cim,
            'rendezo'   =>  $rendezo,
            'ev'        =>  $ev,
        );
        return true;
    }
}

A listázó főszkript (lista_fajl.php) így változik:

Forráskód
<?php
define('TOKEN', 'Védelem');
 
include('kozos/fileio.php');
include('adat/filmadat.php');
 
$fajlnev = dirname(__FILE__) . '/filmek.json';
$filmadat = new FilmAdat($fajlnev);
$filmek = $filmadat->osszes_film();
 
include('kimenet/lista_sablon.php');

Az új film felvevésekor a filmadat objektumot csak mentéskor példányosítjuk (ujfilm_fajl.php):

Forráskód
<?php
define('TOKEN', 'Védelem');
 
include('kozos/fileio.php');
include('adat/filmadat.php');
 
//-----------------------------------------------------
 
$fajlnev = dirname(__FILE__) . '/filmek.json';
$hibak = array();
$cim = '';
$rendezo = '';
$ev = '';
 
if ($_POST) {
    $cim = $_POST['cim'];
    $rendezo = $_POST['rendezo'];
    $ev = $_POST['ev'];
 
    if ($cim == '') {
        $hibak[] = 'Cím kötelező!';
    }
    if ($rendezo == '') {
        $hibak[] = 'Rendező kötelező!';
    }
    if (!is_numeric($ev) || strlen($ev) != 4) {
        $hibak[] = 'Rossz évszám!';
    }
 
    if (!$hibak) {
        $filmadat = new FilmAdat($fajlnev);
        if ($filmadat->film_beszur($cim, $rendezo, $ev)) {
            header('Location: lista_fajl.php');
        };
    }
}
 
include('kimenet/ujfilm_sablon.php');

Vissza a tartalomjegyzékhez

Új Széchenyi terv
A projekt az Európai Unió támogatásával, az Európai Szociális Alap társfinanszirozásával valósul meg.

A tananyag az ELTE - PPKE informatika tananyagfejlesztési projekt (TÁMOP-4.1.2.A/1-11/1-2011-0052) keretében valósult meg.
A tananyag elkészítéséhez az ELTESCORM keretrendszert használtuk.