Vissza az előzőleg látogatott oldalra (nem elérhető funkció)Vissza a modul kezdőlapjáraUgrás a tananyag előző oldaláraUgrás a tananyag következő oldaláraFogalom megjelenítés (nem elérhető funckió)Fogalmak listája (nem elérhető funkció)Oldal nyomtatása (nem elérhető funkció)Oldaltérkép megtekintéseSúgó megtekintése

Tanulási útmutató

Összefoglalás

A leckében áttekintjük azokat a feladatokat, amelyek egy webes alkalmazás fejlesztése során nagyon gyakran előjönnek. Ezek egy részét igyekszünk általánosan tárgyalni, a megvalósítást azonban már CodeIgniterben mutatjuk be.

Követelmény

A leckét elsajátítva a hallgatónak képesnek kell lenni webes alkalmazását kiegészíteni a fejezetben olvasható funkciókkal.

Önállóan megoldható feladatok

Webes alkalmazások gyakori feladatai

Az alábbiakban olyan problémákkal foglalkozunk, amelyek gyakran merülnek fel webes alkalmazások fejlesztése során. Az ezekre adott megoldások egy része független a keretrendszerektől, mások viszont keretrendszer-specifikusak. Ha lehet, akkor az alábbiakban mutatunk független megoldásokat is, és azt is megmutatjuk, hogyan lehet ezeket CodeIgniterben megoldani.

Az alábbiakban tárgyalt megoldások megvalósításait az innen letölthető állományokkal lehet kipróbálni, forrásukat részletesebben megnézni.

  • Fájl letöltése: A bemutatókészítő alkalmazás bővített verziója CodeIgniter keretrendszerben. című háttéranyag letöltése
  • Információ az állományról: A webszerverre tegyünk fel egy CodeIgniter keretrendszert. Az application könyvtárat töröljük ki, majd helyére másoljuk oda a tömörített állomány tartalmát. Indítás az index.php/main URL-lel lehetséges. A fejezet példáinak forrása az egyes állományok szerkesztőben való megnyitásával elemezhető. Ne feledjük a használat előtt a megfelelő beállításokat a konfigurációs állományokban megtenni.
  • Fájlméret: 4.74 MB

Függvénykönyvtárak, kisegítő függvények gyakori használata

Végigtekintve az előző rész példaalkalmazásának megoldásán láthatjuk, hogy bizonyos helpereket, modelleket szinte mindegyik vezérlőben használtunk. Ha nem szeretnénk a vezérlő minden metódusába leírni ezek betöltését, akkor a betöltést végző kódot ($this->load->...) tegyük a vezérlő konstruktorába (__construct() függvény). A konstruktor a vezérlő példányosításakor hívódik meg, tehát mindenféleképpen a vezérlőpéldány metódushívása előtt. Így minden metódus támaszkodhat a konstruktorban lefutott kód eredményére, így a betöltésekre is.

<?php
public function __construct() {
    parent::__construct();
    $this->load->model('bemutato_model');
    $this->load->helper('url');
}
?>

Ha vannak olyan modellek, könyvtárak vagy helperek, amelyeket minden vagy szinte minden vezérlőben használnánk, akkor a CodeIgniterben lehetőséget nyújt ezek automatikus betöltésére. Ehhez a config/autoload.php állományt kell szerkesztenünk, és egy tömb elemeként kell felsorolnunk, mik kerüljenek automatikus betöltésre. Az alábbi példában az URL Helpert töltjük be automatikusan, de el lehetne gondolkozni a bemutato_model betöltéséről is.

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$autoload['packages'] = array();
$autoload['libraries'] = array();
$autoload['helper'] = array('url');
$autoload['config'] = array();
$autoload['language'] = array();
$autoload['model'] = array();
?>

Vissza a tartalomjegyzékhez

Oldalsablon használata

A példaalkalmazás nézetei egész oldalakat tartalmaznak. Mindegyikben megvan a <!doctype>, a <head>, az oldal általános fejléce és lábléce. Egy új nézetet úgy kell létrehozni, hogy egy másikat lemásolunk, kitöröljük belőle az előző oldal specifikus részeit, majd az új oldal tartalmával töltjük fel az állandó részeket meghagyva. Ezzel a módszerrel az a nagy gond, hogy ha az állandó rész megváltozik, akkor azt minden nézetben végig kell vezetni. A megoldás természetesen az, hogy az oldal elrendezéséért felelős állandó részeket, tipikusan a fejlécet, menüt, láblécet külön állományokba emeljük, és a fő tartalmi rész elé és mögé rakjuk. Az oldal így kiemelt állandó részeit hívjuk oldalsablonnak. Így egy nézethez tipikusan három fájl szükséges: az oldalsablon eleje, az adott oldal tartalmi része, és az oldalsablon vége.

A tervezés szakaszában láttuk, hogy milyen tipikus oldalak vannak. Példaalkalmazásunkban elrendezés szempontjából kétféle sablont dolgozhatunk ki első körben: a publikusan elérhető oldalak sablonját, ami nagyjából a fejlécből és a láblécből áll csak, valamint a bejelentkezett felhasználóhoz tartozó oldalak sablonját, ahol a fejléc és a lábléc mellett a bal oldali menüt is nyugodtan hozzávehetjük. Készítsük el a főoldal (views/fooldal.php) alapján a publikusan hozzáférhető oldalak sablonját. A views/template_main_1.php állományban található a sablon első fele:

<!DOCTYPE html>
<html>
    <head>
        <title>DYSS</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link type="text/css" href="<?php echo base_url('styles/dyss.css'); ?>" rel="stylesheet" />
    </head>
    <body>
        <header>
            <div>
                <h1><?php echo anchor('main/index', 'DYSS'); ?></h1>
                <p><a href="<?php echo site_url('bemutato/lista/1'); ?>" class="button"><span>gyozke fiókja</span></a></p>
            </div>
        </header>

A views/template_main_2.php a sablon másik felét tartalmazza:

        <footer>© Horváth Győző, Eötvös Loránd Tudományegyetem, Informatika Kar</footer>
    </body>
</html>

Megvalósítás MiniMVC-ben

A legegyszerűbb MNV-s megközelítésben (pl. a MiniMVC-nkben) egy oldalt a következőképpen lehet megjeleníteni:

<?php
include('views/template_main_1.php');
include('views/fooldal.php');
include('views/template_main_2.php');
?>

Először megjelenítjük a sablon első felét, majd az oldal tartalmát, végül a sablon második felét. Ennek a megoldásnak nagy hátránya, hogy a sablonunk két fájlra van szakítva. Miért ne lehetne az oldalsablon is egy ugyanolyan nézet, mint az oldalak egyedi nézetei? A sablonban ekkor csupán azt kellene jelezni, hogy hova kell az egyedi oldalakat mint tartalom betölteni. Ezt az elképzelést mutatja az alábbi példa, ahol a MiniMVC-s keretrendszerünkben megvalósított bemutatólistában a $content változó tartalmazná az oldal egyedi kódját (mini_mvc/views/template.php).

<!DOCTYPE html>
<html>
    <head>
        <title>DYSS</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link type="text/css" href="views/styles/dyss.css" rel="stylesheet" />
        <link type="text/css" href="views/styles/keplista.css" rel="stylesheet" />
    </head>
    <body>
        <header>
            <div>
                <h1><a href="#">DYSS</a></h1>
                <p><a href="#" class="button"><span>gyozke fiókja</span></a></p>
            </div>
        </header>
        <div id="content">
            <aside>
                <nav>
                    <ul>
                        <li><a href="#">Bemutatóim</a></li>
                        <li><a href="#">Profilom</a></li>
                        <li><a href="#">Kilépés</a></li>
                    </ul>
                </nav>
            </aside>
            <div id="main_content">
                <?php echo $content; ?>
            </div>
            <div class="separator"></div>
        </div>
        <footer>© Horváth Győző, Eötvös Loránd Tudományegyetem, Informatika Kar</footer>
    </body>
</html>

Ahhoz, hogy ezt megtehessük, az oldal egyedi tartalmát szövegként elő kellene állítani a nézetből, és ezt a szöveget kellene a $content változóba rakni. De hogyan tudjuk az egyedi oldal HTML és PHP kódját úgy futtatni, hogy az ne kiíródjon, hanem szövegként térjen vissza? Sajnos ez az include() paranccsal nem megy. A megoldást a PHP kimeneti puffere adja. Ha ezt bekapcsoljuk, akkor minden kiírás nem rögtön a kimenetre kerül, hanem egy átmeneti tárolóba, pufferbe. A puffer tartalmát pedig le tudjuk kérdezni. Így nem kell mást csinálnunk, mint a pufferelést bekapcsolni, include() paranccsal értelmeztetni a nézetet, majd a puffer tartalmával visszatérni. E megoldás köré készített osztályt mutatja az alábbi kódrészlet.

<?php
class View {

    private $vars = array();

    public function render($filename) {
        extract($this->vars);
        if (is_file($filename)) {
            ob_start();
            include $filename;
            $contents = ob_get_contents();
            ob_end_clean();
            return $contents;
        }
        return false;
    }

    public function set($name, $value) {
        $this->vars[$name] = $value;
        return $this;
    }

}
?>

A View osztály tartalmaz egy tömböt, amely a nézet számára szükséges adatok tárolására szolgál. A render() metódus felelős a fent említett folyamatért. Első lépésként a tömbben tárolt kulcs-érték párokból változókat készít az extract() utasítással. A változó neve az elem kulcsa, értéke a tömbelem értéke lesz. Mivel metóduson belül történik mindez, ezért a globális névteret sem szemeteljük tele. Az ob_start() paranccsal indul a pufferelés. Az include() paranccsal értelmeztetjük a nézet kódját, majd az ob_get_contents() utasítással kérjük le az értelmezett HTML szöveget, és ezt adjuk vissza. Az osztály tartalmaz még egy set() metódust is, ami arra szolgál, hogy a nézetnek szükséges változókat ebben tároljuk. Az osztályt az elővezérlőben tesszük minden vezérlő számára elérhetővé (ld. mini_mvc/system/front_controller.php), és az egyes konkrét vezérlőkben az alábbi módon használjuk (ld. mini_mvc/controllers/bemutato.php):

<?php
function index() {
    //...
    $bemutatok = $modell->bemutatok_lekerese($felhasznalo_id, $cim);

    $view = new View();
    $view->set('bemutatok', $bemutatok);

    $content = $view->render('views/bemutato_lista.php');
    include('views/template.php');
}
?>

A megjelenítéshez létre kell hozni a View osztály egy példányát, majd annak átadni a nézet paramétereit (set()), és az adott nézetre meghívni a render() metódust. A $content-be így kerül a nézet kódja, és ez kerül behelyettesítésre a template.php sablon meghívásakor. (Megjegyezhetjük, hogy a sablon megjelenítéséhez is használhatnánk a View osztályt.)

Megvalósítás CodeIgniterben

CodeIgniterben is lehetőségünk van mindkét megoldási módra. Ha az oldalsablonunk kétfelé van szedve, akkor úgy, ahogy fent, először az első felét, majd a konkrét oldalt, majd a másik felét kell megjeleníteni a $this->load->view() paranccsal.

<?php
public function index() {
    //...
    $this->load->view('template_main_1');
    $this->load->view('fooldal', array(
        'legnepszerubbek'   => $legnepszerubbek,
        'legfrissebbek'     => $legfrissebbek,
        'cimkek'            => $cimkek,
    ));
    $this->load->view('template_main_2');
}
?>

CodeIgniterben is megoldható azonban az, hogy az oldalszerkezetért felelős sablon egy állományban legyen, és egy abban lévő változón keresztül kerüljön betöltésre az aktuális oldal nézete. A $this->load->view() függvény ugyanis képes arra, hogy a nézetet ne automatikusan a kimenetre küldje, hanem az értelmezés eredményét szövegként adja vissza. Ehhez nem kell mást tenni, mint utolsó paraméterének (a nézet meghatározása, és a nézet paraméterei) igaz értéket adni.

<?php
$content = $this->load->view('fooldal', array(
    'legnepszerubbek'   => $legnepszerubbek,
    'legfrissebbek'     => $legfrissebbek,
    'cimkek'            => $cimkek,
), true);
$this->load->view('template_main', array(
    'content'           => $content,
));
?>

További fejlesztésként elérhetjük azt is, hogy a feleslegesen ismétlődő részek köré egy interfészt építünk, aminek már csak a megfelelő paramétereket kell átadnunk. A fenti logikában igazából három hasznos paraméter van: az aktuális nézet neve, paraméterei, valamint a sablon neve. Az interfészt sokféleképpen elhelyezhetjük: tehetjük a vezérlők ősosztályába metódusként, tehetjük hook-ba vagy külön osztályba. Mi ez utóbbit választottuk, mert így a sablonkezelési logika egy mindentől független osztályba kerülhet. A megoldást library-ként készítettük el (libraries/Template.php).

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

class Template
{
    private $CI;
    private $template_file;
    private $template_data = array();
    
    public function __construct($template = 'template') {
        $this->CI =& get_instance();
        $this->template_file = $template;
    }
    
    public function set_template($template) {
        $this->template_file = $template;
    }
    
    public function set_data($key, $value) {
        $this->template_data[$key] = $value;
    }

    public function display($view = '', $data = array()) {
        $this->template_data['content'] = $this->CI->load->view($view, $data, TRUE);
        $this->CI->load->view($this->template_file, $this->template_data);
    }
    
}
?>

Az osztály privát tagváltozókban tárolja a sablon nevét és a sablon paramétereit. A lényeg a display() metódusban van, ahol először a sablonparaméterek közé content kulccsal felvételre kerül a paraméterként megadott értelmezett nézet eredménye, majd magának a sablonnak a megjelenítése következik a sablonparaméterek alapján. Az osztály további metódusokat tartalmaz, amelyekkel a sablon neve (set_template()) és a sablon paraméterei állíthatók be (set_data()). A Template library-t a következőképpen használhatjuk:

<?php
$this->load->library('template');
$this->template->set_template('template_main');
$this->template->display('cimke_lista', array(
    'cimke' => $cimke,
    'bemutatok' => $cimke_lista,
));
?>

Vissza a tartalomjegyzékhez

Hitelesítés és jogosultságellenőrzés (autentikáció és autorizáció)

A legtöbb webes alkalmazásban a megjelenő információ függhet attól, hogy ismerjük-e azt, aki az oldalt megnézni. Ennek az információnak birtokában sokféleképpen működhetnek az oldalak. Nézzünk néhány példát:

A hozzáférés kérdéskörét ketté kell bontanunk hitelesítésre (autentikáció) és jogosultságellenőrzésre (autorizáció). A hitelesítés során arra vagyunk kíváncsiak, hogy ismerjük-e az oldal látogatóját, és ha igen, akkor ki ő, és milyen felhasználói csoportba, szerepkörbe tartozik. A hitelesítés alapvetően kétféle kategóriát különböztet meg: az ismeretlen felhasználót (névtelen vagy vendég felhasználónak is szokták nevezni), és az azonosított felhasználót, akiről a belépés során számos információt tárol (felhasználónév, szerepkör, stb.).

A jogosultságellenőrzés során az dől el, hogy az adott felhasználónak az adott erőforráshoz milyen hozzáférése van. A felhasználó a hitelesítés során dől el. Az erőforrás bármi lehet; általában oldalakra gondolhatunk ez alatt, de elképzelhető, hogy az oldalnak csak egy részéről, egy komponenséről van szó (ld. a beléptető űrlapot), de lehet ez üzleti objektum, modell, bármi. A hozzáférés jellege is sokrétű lehet. Általában vagy engedélyezett a hozzáférés, vagy nem, de ennél árnyaltabb skála is lehetséges, például megtekintési, szerkesztési, jóváhagyási jog egy adott erőforráson (ld. pl. a tartalomkezelő rendszereket).

A hitelesítés általában a munkamenet-kezeléssel (session) kapcsolódik össze. A munkamenet során a kliens egy kulccsal (token) azonosítja magát a szerver felé, és a szerver ehhez a kulcshoz egy adattárat biztosít. Sikeres belépést követően a munkamenetben elhelyezünk egy speciális bejegyzést, amely jelzi, hogy az azonosítás egyszer már sikeresen megtörtént. Innentől kezdve csak ennek a bejegyzésnek a meglétét kell ellenőrizni: ha megvan, akkor ismerjük a látogatót, ha nincs, akkor nem ismerjük.

A hitelesítéshez szorosan kapcsolódik a hitelesítési adatokat (tipikusan felhasználónév-jelszó páros) kezelő felület is. Ide tartozik ezek bekérése, regisztrálása, elfelejtett jelszó újraküldése, stb. Ezeket a funkciókat a megfelelő vezérlő intézi el. A hitelesítést általában külön osztályban érdemes megvalósítani, aminek van beléptető, ellenőrző, regisztráló, törlő, stb. metódusa. Ha az adatok adatbázisban vannak, akkor modell is társulhat az előzőekhez.

A jogosultságellenőrzés eléggé feladatfüggő, bár léteznek általános megoldások. Ezekre ACL-ként szoktak hivatkozni, amely az angol Access Control List (hozzáférést vezérlő lista) rövidítéséből származik. Az ACL-ek általában ahhoz nyújtanak programozási felületet, hogy meghatározzuk, illetve lekérdezzük azt, hogy kinek milyen erőforráshoz milyen hozzáférési jogosultsága van. Ezeket a szabályokat megadhatjuk programkóddal, de természetesen deklaratív formában is konfigurációs állományban vagy adatbázisban.

Az ellenőrzés általános pszeudo-algoritmusa valami ilyesmi lehet:

Ha ismerlek akkor

Ha van jogod az erőforráshoz? akkor

Megtekintheted

különben

Nem tekintheted meg

Elágazás vége

különben

Ha van jogod az erőforráshoz? akkor

Megtekintheted

különben

Beléptető oldal

Elágazás vége

Elágazás vége

Egy másik formában:

user = Ki vagy?()

Ha van jogod az erőforráshoz? akkor

Megtekintheted

különben

Ha nem ismerlek akkor

Beléptető oldal

különben

Nem tekintheted meg

Elágazás vége

Elágazás vége

Nem mindig szükséges azonban az általános megoldásokat használni. A jogosultságellenőrzésnél néha sokkal egyszerűbb esetek fordulnak elő, amihez felesleges egy komplett ACL modult kezelni. Ilyenek lehetnek azok az alkalmazások, amelyeket csak azonosítás után használhatunk. Ekkor arra egyszerűsödik a folyamat, hogy ha ismeretlen látogató jön, akkor őt a beléptető oldalra irányítjuk. Akkor sem kell összetett rendszert implementálnunk, ha az erőforrások “csak” oldalak, és bináris a hozzáférés, vagy megtekinthető, vagy nem.

A hitelesítés és jogosultságellenőrzés általában a vezérlőben kap helyet, hiszen ez még annak a területnek a része, ahol a kliensről érkező adatokat a modell felé próbáljuk terelni. Itt képezzük le a HTTP kérést (és ennek része az az információ is, hogy ki küldi a kérést) a modell üzleti objektumaira. A vezérlőben is több helyen helyezkedhet el.

Az általános gondolatok után nézzük meg, hogy példaalkalmazásunkban milyen módon valósíthatjuk meg a hitelesítési és jogosultságellenőrzési funkciókat. Az alkalmazásnak vannak publikus oldalai, amelyekhez bárki hozzáfér. Ezeken fel kell készülnünk arra, hogy a bejelentkezéstől függően más jelenjen meg, pl. a bejelentkezési űrlapnál. Ezeken kívül a bejelentkezett felhasználók kezelhetik a bemutatóikat, ezek olyan oldalak, amelyekhez a vendégek nem férhetnek hozzá. Mivel a publikus oldal vezérlői a Main osztályban vannak, a védett oldalak pedig a Bemutato osztályban, ezért magától adódik, hogy az ellenőrzést osztály szinten kell elvégezni. A Bemutato osztály konstruktorában kell megvizsgálni, hogy a kérés mögött azonosított felhasználó áll-e. Ha nem, akkor a bejelentkezési oldalra kell irányítani.

A hitelesítésért egy új osztály, a libraries/Hitelesito.php állományban elhelyezkedő Hitelesito osztály felel. A felhasznalo tábla adataival kapcsolatos műveletekért a models/felhasznalo_model.php állományban található modell a felelős. A Hitelesítő osztály login() metódusa egy felhasználói azonosítót és egy jelszót kap paraméterül, és ezeket veti össze az adatbázis felhasznalo táblájában lévő értékekkel. Ha az azonosító és jelszó is egyezik, akkor a munkamenetbe tárolásra kerül a felhasználó táblaazonosítója, azonosítója és egy belepve érték, jelezvén, hogy sikeres hitelesítési folyamaton vagyunk túl. A logout() metódus a munkamenet törlésével lépteti ki a felhasználót. Az is_authenticated() metódus pedig arról ad tájékoztatást, hogy a felhasználó belépett-e már. Ezen kívül a create() metódus egy új felhasználót hoz létre és léptet be.

A munkamenethez a CodeIgniter Session osztályát használtuk. Ezt egyrészt a config/autoload.php állományban automatikusan betöltjük, másrészt a config/config.php fájlban be kell állítani az encryption_key kulcsot egy tetszőleges 32 hosszú szövegre. Ugyancsak automatikusan tölti be a keretrendszer a Hitelesítő osztályt is, így már csak a metódusait kell használni a vezérlőkön belül a $this->hitelesito objektumon keresztül.

A beléptető képernyőhöz két új állomány tartozik. Egyrészt a views/auth.php állományban található meg a beléptetés nézete. Ebben az előző részekben ismertetett módon szerepel egy űrlap, ahol a felhasználói azonosítót és a jelszavat lehet megadni. Az ehhez tartozó vezérlő a controllers/auth.php állományban van. Két metódusa közül az index() a beléptető képernyőért és a beléptetésért felel, a logout() a kiléptetésért. Az előbbi egyetlen érdekesebb pontja az űrlapadatok feldolgozása utáni rész. Ebben sikeres adatellenőrzés után a Hitelesítő osztály login() metódusával megpróbáljuk beléptetni a felhasználót. Ha ez sikerre vezet, akkor a főoldalra irányítjuk, ha azonban nem, akkor egy errors tömbben átadjuk a hibát a nézetnek. A nézetnek az űrlapellenőrzési hibák mellett az errors tömböt is figyelembe kell vennie a kiíráskor.

<?php
if ($this->form_validation->run() == FALSE)
{
    $this->template->display('auth');
}
else
{
    $azonosito = $this->input->post('azonosito');
    $jelszo = $this->input->post('jelszo');
    if ( $this->hitelesito->login($azonosito, $jelszo) ) {
        redirect('main/index');
    } else {
        $errors = array(
            'auth_error' => 'Rossz azonosító vagy jelszó!',
        );
        $this->template->display('auth', array(
            'errors'    => $errors,
        ));
    }
}
?>

Ennyi előkészület után a vezérlők megfelelő védelmét kell biztosítani a konstruktorukban. Először is minden vezérlő konstruktorában szerepel egy kódrészlet, amely azért felelős, hogy a nézetnek a megfelelő információkat átadja. Ezt a $this->load->vars() paranccsal teszi meg.

<?php
if ($this->hitelesito->is_authenticated()) {
    $data = array(
        'belepve'   => true,
        'azonosito' => $this->session->userdata('azonosito'),
        'id'        => $this->session->userdata('id'),
    );
}
else {
    $data = array(
        'belepve'   => false,
    );
}
$this->load->vars($data);
?>

Zavaró lehet, hogy minden vezérlőben ugyanaz a kódrészlet ismétlődik, hiszen így ennek karbantartása nehézkessé válhat. Ekkor minden vezérlő elé egy ősosztályt tehetünk. Erre maga a keretrendszer is lehetőséget azzal, hogy a core/ könyvtárba felvegyünk egy MY_Controller.php nevű állományt, és ebben egy MY_Controller nevű osztályt. Ez az osztály a CI_Controller-ből származik, a többi vezérlő pedig majd ebből. Gyakorlatilag a MY_Controller osztályt a vezérlőink és az alap CI_Controller vezérlők közé illesztjük. A MY_Controller osztály konstruktorába másolva a fenti kódot, az minden vezérlőre lefut.

A Bemutato vezérlőben azt is meg kell oldanunk, hogy ha hitelesítetlen felhasználó érkezik, akkor a bejelentkezési képernyőre kell irányítanunk.

<?php
if (!$this->hitelesito->is_authenticated()) {
    redirect('auth/index');
}
?>

Ha több védett vezérlőnk lenne, akkor itt is kódismétléssel találnánk szemben magunkat. Ekkor felvehetünk egy új vezérlőt a controllers/ mappába, amely a MY_Controller-ből származik, és ennek konstruktorába írjuk a fenti kódot. A Bemutato vezérlő pedig ebből az új köztes osztályból származik. Ehhez expliciten be kell emelnünk az új osztály kódját az require_once() paranccsal, valahogy így:

<?php
require_once(APPPATH . '/controllers/KoztesOs.php');
?>

A Bemutato vezérlőben ezek után az eddig beégetett felhasználói táblaazonosítókat ki lehet cserélni a munkamenetben tároltra.

Utolsó lépésként a nézeteket kell módosítani, hogy figyelembe vegyék a vezérlőktől érkező hitelesítési információkat. Ez igazából csak az oldalsablonokat érinti, azoknak az elején található az alkalmazás fejléce. Ott kell mást kiírnunk aszerint, hogy ismeretlen vagy hitelesített felhasználóval van-e dolgunk.

<?php if ($belepve) : ?>
    <p>
        <a href="<?php echo site_url('bemutato/lista'); ?>" class="button">
            <span><?php echo $azonosito; ?> fiókja</span>
        </a> 
        <a href="<?php echo site_url('auth/logout'); ?>" class="button">
            <span>Kilépés</span>
        </a>
    </p>
<?php else : ?>
    <p>
        <a href="<?php echo site_url('auth/index'); ?>" class="button">
            <span>Lépj be!</span>
        </a> vagy 
        <a href="<?php echo site_url('auth/regisztralas'); ?>" class="button">
            <span>Regisztrálj!</span>
        </a>
    </p>
<?php endif; ?>

Vissza a tartalomjegyzékhez

Hibakezelés

CodeIgniter keretrendszer kétféle hibakezelési segítséget ad. Az egyik a hibaüzenetek megjelenítésére szolgál. Két függvény használható erre, a show_error() és a show_404() függvények. Ezeket meghívva az errors/ mappában lévő sablonok kerülnek megjelenítésre, első esetben az error_general.php, másik esetben az error_404.php. A hibaüzenetek megjelenítését az index.php fájl elején tudjuk szabályozni az ENVIRONMENT konstans értéként keresztül: developement esetén megjelennek a hibaüzenetek, egyéb esetben nem.

Példa

A Bemutato vezérlőben létrehoztunk egy profil() metódust a következőképpen:

<?php
public function profil() {
    show_error('Baj van');
    echo 'Még valami';
}
?>

Ezt meghívva a képernyőn a megfelelő hibaüzenet jelenik meg, az utána lévő kódrészlet már nem kerül futtatásra.

A másik, CodeIgniter nyújtotta lehetőség a különböző üzenetek fájlba írása, a logolás. Erre a log_message() függvény szolgál, amelynek első paramétere a hiba jellege, második paramétere a hiba leírása. Ezzel a függvénnyel akkor is nyomon tudjuk követni alkalmazásunk állapotát, ha a hibaüzenetek nem jelennek is meg a felületen. A logfájlokat a logs/ mappában találjuk. A logolás mértékét a config/config.php állomány szabályozhatjuk a log_threshold kulcsszón keresztül. Éles alkalmazásban csak akkor kapcsoljuk be, ha fontos hibát keresünk, mivel a fájlba logolás lassíthatja a kiszolgálást.

A kód szervezéséről szólva pedig érdemes a kivételkezelés technikáját alkalmazni. Egyedi kivételeket képezhetünk a PHP-s Exception osztály származtatásával. A kivételeket érdemes vezérlő szinten (metódusszinten) kezelni, hiszen az egyes kivételekre a megfelelő nézet betöltésével szükséges reagálnunk.

Vissza a tartalomjegyzékhez

CodeIgniter és PDO

A CodeIgniter 2.1.0-ás verzióját megelőzően nem támogatta a PDO-t. A keretrendszer saját adatbázis-elérési réteget definiált, saját absztrakt függvényein keresztül lehetett az SQL utasításokat végrehajtani. A query() függvény paraméterének pl. meg lehet adni paraméterezett SQL utasításokat is, amelyeket maga a keretrendszer old fel, a ?-ek helyébe a megfelelő értékeket rakva. Ennek hátterében itt is a mysql_real_escape_string() áll.

Nem gátolja azonban semmi a fejlesztőt abban, hogy natív adatbázisfüggvényeket használjon. Természetesen nem kötelező kihasználni a CodeIgniter nyújtotta absztrakt réteget, így egy modellen belül használhatjuk e tananyag elején megismert kódokat, legyen az akár mysqli bővítményt használó, vagy PDO. Megfelelő helyen (pl. egy modell konstruktorában) csatlakozni kell az adatbázishoz, majd a modell metódusában a natív kódot használva elvégezhetjük a megfelelő műveletet. Ilyen lehet pl. BLOB-ok hatékony kezelését megoldani, de ilyen módon jelenhet meg PDO kód is a modellekben. Vegyük észre, hogy mind a CodeIgniter, mind a PDO nyújtotta lehetőség ugyanaz: egy absztrakt adatbázis-elérési rétegen keresztül kommunikálni az adatbázissal. Természetesen a CodeIgniter Active Record mintáját nem használhatjuk PDO-val.

A CodeIgniter 2.1.0-ás verziójával megjelent az adatbázis-vezérlők között a PDO támogatás is. Ez azt jelenti, hogy a CodeIgniter absztrakciós rétege a PDO absztrakciós réteget használja, és így az Active Record minta műveletei (update(), insert(), delete()) is működnek. Sajnos egyelőre a paraméterek adatkötését még mindig a CodeIgniter végzi szövegösszefűzéssel a PDO bindParam() függvénye helyett, így BLOB-ok hatékony kezelése és az adatkötéssel járó extra biztonság kihasználása még mindig nem megoldott.

Megjegyzés

Itt érdemes megjegyeznünk, hogy természetesen sok egyéb módon is hatékonyabbá tehetjük az adatbázissal kapcsolatos tevékenységeinket. Megemlíthetjük itt az előkészített utasítások használatát vagy az eredmények átmeneti tárolását (cache-elését). Ezek a témakörök azonban túlmutatnak jelen tananyagunk keretein.

Vissza a tartalomjegyzékhez

URI útvonalak személyre szabása (URI Routing)

Minden alkalmazásvezérlővel rendelkező keretrendszer meghatározza, hogy az URL-ben megadott útvonal alapján hogyan érhető el az aktuális vezérlő. A MiniMVC-s keretrendszerünkben explicit GET paraméterek szerepeltek:

index.php?class=osztály&method=függvény

CodeIgniterben egy olvashatóbb, keresőbarát, útvonalakhoz hasonló szegmens-alapú megoldás található:

index.php/osztály/függvény

Általában meg is marad ez az egy-egy kapcsolat az URL és a neki megfelelő osztály és függvény között. Azonban néha szükségünk lehet beszédesebb vagy egyszerűbb útvonalak megadására, azaz előfordulhat, hogy szeretnénk másképp megfeleltetni az URL-ben szereplő szöveget és a hívandó osztálymetódust.

Példaalkalmazásunkban több helyen élhetünk ezzel a lehetőséggel. Egy bemutatót megtekinteni a main/bemutato/id útvonalon lehet, ennél sokkal beszédesebb lenne a bemutato/id. Ugyancsak felesleges a main szócska az útvonalból egy adott címkéjű, valamint egy adott felhasználóhoz tartozó bemutatólista esetén. Ezeknél is main/cimke/címkeszöveg, valamint main/felhasznalo/azonosító helyett beszédesebb a cimke/címkeszöveg és a felhasznalo/azonosító útvonal. Végül példaképpen még a bemutato/lista útvonalat is lecserélhetnénk bemutatoim útvonalra.

CodeIgniterben a fenti igények kielégítését az ún. routing segítségével lehet elvégezni, ami az URL-ben megadott útvonalnak egy másik útvonalra való leképezését jelenti. Ennek megadása a config/routes.php állományban van. Itt a $route tömb kulcsaként kell megadni azt az útvonalat, amit leképezni szeretnénk, értékeként pedig azt az útvonalat, amire leképezni szeretnénk. A kulcsban használhatunk helyettesítő karakterek, így pl. a :num csak számokat, az :any bármilyen karaktert tartalmazó szegmenset azonosít. Ezek mellett használhatunk tetszőleges reguláris kifejezést is a szegmensek azonosítására. Ha a kulcsban zárójelbe teszünk egy kifejezést, akkor arra az értékben $szám formájában hivatkozhatunk.

Példaalkalmazásunk fenti igényei a következőképpen néznek ki a config/route.php állományban:

<?php
$route['default_controller'] = "welcome";
$route['404_override'] = '';
$route['bemutato/(:num)'] = 'main/bemutato/$1';
$route['cimke/(:any)'] = 'main/cimke/$1';
$route['felhasznalo/(:any)'] = 'main/felhasznalo/$1';
$route['bemutatoim'] = 'bemutato/lista';
?>

Az első két sort kötelező megtartani és az elején szerepeltetni, mert ezek befolyásolják az alapértelemezett vezérlőt és hibaállományt.

Egy másik lehetőség az, hogy egy vezérlőosztályon belül a metódust képezzük le egy másik metódusra. Ehhez az osztályban definiálni kell egy _remap() függvényt, ami az URL-ben szereplő metódust tartalmazza. A _remap() függvényen belül átállíthatjuk a $this->method értékét, így ez fog meghívódni.

Vissza a tartalomjegyzékhez

A felület többnyelvűsítése (i18n)

Gyakran fordul elő, hogy egy alkalmazás felületét több nyelven is elérhetővé kell tenni. A következőkben két konkrét lépést mutatunk meg:

Az alkalmazás nyelvéért egy konfigurációs beállítás felel. A config/config.php fájlban a language beállítást kell meghatároznunk. Alapértelmezetten english az értéke, ezt lehet tetszőleges értékre, pl. magyar esetén magyar-ra vagy hungarian-re állítani. Ezt az értéket egyébként futás közben is beállíthatjuk a következő utasítással.

$this->config->set_item('language', 'hungarian');

Bármire is állítjuk be, létre kell hozni egy ugyanilyen nevű mappát az application/language könyvtárban. A keretrendszer a megfelelő nyelvi állományokat mindig a konfigurációban beállított mappában keresi. Ha nem találja az application mappában, akkor a system/language mappában keres neki megfelelőt.

A keretrendszer hibaüzeneteinek magyarosításához állítsuk be a config/config.php állományban a language értékét hungarian-re, majd az application/language mappában hozzunk létre egy hungarian nevű könyvtárat. Ebbe másoljuk át az összes fájlt a system/language/english könyvtárból. Nem elég csak azt, amit éppen fordítani kívánunk, ugyanis a keretrendszer a többi állományt is (ha netalán szüksége lenne rá) vagy az application/language/hungarian, vagy a system/language/hungarian mappában keres. Ha nem találja, hibaüzenetet ad.

Az űrlapellenőrzéskor megjelenő hibaüzenetek magyarosításához a form_validation_lang.php állomány szerkesztésére van szükség. Ebben a $lang tömb megfelelő értékeit kell magyarra fordítani. A %s karakterek helyére a rendszer megfelelő szövegeket ír, ezeket hagyjuk meg. Űrlapellenőrzéskor ide kerülnek a mezők megnevezései.

A másik esetben mi magunk szeretnénk felületen megjelenő többnyelvű szövegeket definiálni. Ehhez a megfelelő nyelvi mappában, pl. a hungarian mappában, létre kell hoznunk egy új állományt. Az állomány nevének _lang.php-val kell végződnie (pl. error_lang.php). A fájlban egy $lang nevű tömbben kell megadni a címke-érték párokat. Pl.:

$lang['hello'] = 'Üdvözöljük!';

Ezt a fájlt betölteni a

$this->lang->load('error', 'hungarian')

utasítással lehet. A második paramétert elhagyva az alapértelmezett nyelvhez tartozó fájl töltődik be. A betöltött nyelvi fájlokból egy címkéhez tartozó bejegyzést pedig a

$this->lang->line('címke');

utasítás ad vissza.

A CodeIgniter rendelkezésünkre bocsát egy Language Helpert, amely egy lang() függvényt biztosít az előbbi utasítás helyett. Ez kiválóan használható a nézetekben, ahol így rövidebben ki tudjuk íratni a szöveget. A Language Helpert és egyébként bármilyen nyelvi állományt a config/autoload.php-ban is automatikusan betölthetünk, ha azokra gyakran van szükség.

Példaképpen a bejelentkezett felhasználók menüjét többnyelvűsítettük. Ehhez a language/hungarian mappában létrehoztunk egy template_lang.php állományt, amelybe a következő sorokat vettük fel:

<?php
$lang['template_bemutatoim'] = 'Bemutatóim';
$lang['template_profilom'] = 'Profilom';
$lang['template_kilepes'] = 'Kilépés';
?>

Ezt a fájlt lemásoltuk a language/english mappába, és lefordítottuk angolra a szövegeit.

<?php
$lang['template_bemutatoim'] = 'My slideshows';
$lang['template_profilom'] = 'My profile';
$lang['template_kilepes'] = 'Logout';
?>

Következő lépésként automatikusan betöltöttük a Language Helpert és az imént definiált nyelvi állományt. A config/autoload.php megfelelő sorai így néznek ki:

<?php
$autoload['helper'] = array('url', 'language');
$autoload['language'] = array('template');
?>

E nélkül a megfelelő vezérlőben kellene mind a helpert, mind a nyelvi állományt betölteni a $this->load->helper('language') és a $this->lang->load('template') utasításokkal.

Végül a views/template.php állományban kellett a beégetett magyar feliratokat lang() hívásokra cserélni.

<li><?php echo anchor('bemutato/lista', lang('template_bemutatoim')); ?></li>
<li><?php echo anchor('bemutato/lista', lang('template_profilom')); ?></li>
<li><?php echo anchor('bemutato/lista', lang('template_kilepes')); ?></li>

Ha most a config/config.php-ban váltogatjuk az english és hungarian értékeket, akkor a menü hol angolul, hol magyarul jelenik meg.

Megjegyzés

Egy bonyolultabb alkalmazásban arra is van lehetőség, hogy a nyelv választását a felhasználó tegye meg a felületen keresztül. Ekkor vagy az útvonalban, vagy GET paraméterrel jelzik, vagy a munkamenetben tárolják a beállított nyelvi értéket. Ez azonban a jelen anyag keretein túl mutat.

Vissza a tartalomjegyzékhez

Saját konfigurációs állományok kezelése

CodeIgniterben lehetőségünk van saját konfigurációs beállításokat létrehozni. Ennek egyik módja, hogy a config/config.php állományban adunk a $config tömbhöz újabb elemeket. Ezt az állományt a CodeIgniter automatikusan betölti, így a saját beállításaink is elérhetőek lesznek. A másik lehetőség, hogy külön állományban definiáljuk a beállításokat. Ehhez a config mappában létre kell hozni egy új állományt, és benne ugyanúgy egy $config tömböt kell a megfelelő kulcs-érték párokkal feltölteni. Ezt a fájlt a

$this->config->load('fájlnév')

utasítással lehet betölteni.

Bármelyik utat is választottuk, a betöltött konfigurációs állományokból a

$this->config->item('kulcs')

utasítással lehet a kulcshoz tartozó értéket kinyerni.

A következő példa nem a példaalkalmazásunkhoz kapcsolódik. Képzeljük el, hogy a hitelesítés során a felhasználónév-jelszó párosok nem adatbázisban, hanem egyszerű szöveges állományként egy konfigurációs állományban helyezkednek el, valahogy így:

<?php
$config['credentials']  = array(
    'user1'     =>  'password1',
    'user2'     =>  'password2',
    'user3'     =>  'password3',
);
?>

A hitelesítés során a megadott felhasználónevet és jelszót kell összevetni a konfigurációs állomány bejegyzéseivel.

<?php
$this->CI->config->load('credentials');
$cred = $this->CI->config->item('credentials');

if (array_key_exists($user, $cred) && $cred[$user] === $password) {
    //felhasználó beléptetése
    //munkamenetadatok beállítás
}
?>

Vissza a tartalomjegyzékhez

Fel a lap tetejére
Ú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.