Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Pouze tento týden sleva až 80 % na e-learning týkající se C a C++. Zároveň využij akce až 80 % zdarma při nákupu e-learningu - více informací.
c++ week

Lekce 8 - Výpis článků z databáze v PHP (MVC)

V minulé lekci, Databázový wrapper, jsme si vytvořili databázový wrapper nad PHP ovladačem PDO. Databázi máme již také připravenou, nic nám nebrání s ní komunikovat.

Připojení

Jako první se musíme k databázi připojit. To provedeme v index.php, těsně před vytvořením směrovače:

// Připojení k databázi
Db::pripoj("127.0.0.1", "root", "", "mvc_db");

Údaje si samozřejmě změňte podle svého webhostingu, takto jsou vyplněné pro localhost. Databázi máme v aplikaci přístupnou, pojďme se ji na něco zeptat.

Model - Správce článků

Vytvoříme třídu s logikou ohledně práce s články, která bude obsahovat jednotlivé SQL dotazy. Třída bude samozřejmě v modelech a jmenovat se bude SpravceClanku. Pro každou databázovou entitu si v našem systému vytvoříme nějakou podobnou třídu. SpravceClanku bude mít následující podobu:

<?php

// Třída poskytuje metody pro správu článků v redakčním systému
class SpravceClanku
{

    // Vrátí článek z databáze podle jeho URL
    public function vratClanek($url)
    {
        return Db::dotazJeden('
            SELECT `clanky_id`, `titulek`, `obsah`, `url`, `popisek`, `klicova_slova`
            FROM `clanky`
            WHERE `url` = ?
        ', array($url));
    }

    // Vrátí seznam článků v databázi
    public function vratClanky()
    {
        return Db::dotazVsechny('
            SELECT `clanky_id`, `titulek`, `url`, `popisek`
            FROM `clanky`
            ORDER BY `clanky_id` DESC
        ');
    }

}

Třída má celkem 2 metody:

  • vratClanek() vrací jeden článek z databáze podle jeho URL. Získávání dat od uživatele není záležitost modelu, všimněte si, že URL mu jednoduše přijde v argumentu metody a neřeší odkud se vzalo. Do podmínky SQL dotazu proměnnou nevložíme přímo, ale místo její hodnoty vložíme zástupný znak (otazník). Všechny parametry SQL dotazu následně předáme databázi jako hodnoty v poli, ona si je do dotazu sama a bezpečně dosadí.
  • vratClanky() vrací seznam všech článků (bez jejich obsahu). Články jsou seřazené sestupně podle ID, tedy od nejnovějších po nejstarší. Všimněte si, že nevybíráme jejich obsah, metodu budeme používat pouze pro výpis seznamu.

Pohledy

Budeme potřebovat 2 pohledy. Jeden pro článek a druhý pro seznam článků.

clanek.phtml

U článku vypíšeme nadpis a potom jeho obsah. Pohled bude následující:

<header>
    <h1><?= $titulek ?></h1>
</header>
<section>
    <?= $obsah ?>
</section>
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Druhý pohled necháme na konec lekce.

Kontroler

Máme model, máme pohled, zbývá náš známý prostředník - kontroler, který vše spojí dohromady. ClanekKontroler bude mít následující podobu:

class ClanekKontroler extends Kontroler
{
    public function zpracuj($parametry)
    {
        // Vytvoření instance modelu, který nám umožní pracovat s články
        $spravceClanku = new SpravceClanku();

        // Získání článku podle URL
        $clanek = $spravceClanku->vratClanek($parametry[0]);
        // Pokud nebyl článek s danou URL nalezen, přesměrujeme na ChybaKontroler
        if (!$clanek)
            $this->presmeruj('chyba');

        // Hlavička stránky
        $this->hlavicka = array(
            'titulek' => $clanek['titulek'],
            'klicova_slova' => $clanek['klicova_slova'],
            'popis' => $clanek['popis'],
        );

        // Naplnění proměnných pro šablonu
        $this->data['titulek'] = $clanek['titulek'];
        $this->data['obsah'] = $clanek['obsah'];

        // Nastavení šablony
        $this->pohled = 'clanek';
    }
}

Kontroler si vytvoří model a získá od něj článek podle URL adresy. Pokud článek nebyl nalezený, vyhodnotí se proměnná s ním jako false a přesměrujeme na ChybaKontroler. Hlavičku stránky nastavíme podle článku, dále pohledu předáme titulek a obsah, aby článek mohl vypsat. Nakonec nastavíme pohled na clanek.phtml.

Pojďme si vše vyzkoušet. Když aplikaci zapneme, uvidíme vypsaný úvodní článek:

Úvod
localhost/cla­nek/uvod

Můžete si zkusit zadat URL neexistujícího článku, budete přesměrování na chybovou stránku.

clanky.phtml

Seznam článků bude o něco složitější, protože potřebujeme vypsat jejich seznam z pole článků, které dostaneme od databáze. Jak že to ale uděláme, když zatím umíme vypisovat jen jednotlivé proměnné a zde potřebujeme vypsat obsah kolekce? Pojďme si rozšířit naše znalosti o PHP syntaxi, přesněji o šablonové verzi cyklů.

Šablonová syntaxe PHP

Kromě direktivy <?= nám PHP nabízí šablonové ekvivalenty nejběžnějších konstrukcí jazyka. Můžeme tak do pohledu (šablony) vložit minimální část logiky, která nebude znepřehledňovat HTML kód. Tyto šablonové ekvivalenty nám totiž umožňují vkládat PHP do HTML.

Bez znalosti šablonové syntaxe PHP by výpis seznamu článků do tabulky vypadal asi takto:

<h1>Seznam článků</h1>
<table>
    <?php
        foreach ($clanky as $clanek)
        {
            echo('<tr><td><h2>
                    <a href="clanek/' . $clanek['url'] . '">
                            ' . $clanek['titulek'] . '</a>
                    </h2>' . $clanek['popisek']);
            echo('</td></tr>');
        }
    ?>
</table>

HTML je nezvýrazněné, šablona nepřehledná., ztrácíme se v uvozovkách jak řetězce spojujeme. Pojďme kód převést do šablonové verze:

<h1>Seznam článků</h1>
<table>
<?php foreach ($clanky as $clanek) : ?>
    <tr>
        <td>
            <h2><a href="clanek/<?= $clanek['url'] ?>"><?= $clanek['titulek'] ?></a></h2>
            <?= $clanek['popisek'] ?>
        </td>
    </tr>
<?php endforeach ?>
</table>

Všimněte si, že cyklus foreach má za sebou napsanou dvojtečku a potom se ukončí PHP direktiva. Toto je šablonová verze foreach, která pro každý prvek vyechuje HTML kód, který je napsaný pod ním a to až do značky endforeach. Podobně lze přepsat i cykly for a while nebo podmínky if. HTML je zapsané jako HTML, ne jako string. Proměnné vložíme do HTML pomocí <?=, jak jsme zvyklí. Soubor clanky.phtml si s tímto obsahem ve složce pohledy vytvořte.

Pozn.: V šablonách stále neošetřujeme HTML entity a vystavujeme se tak útoku XSS. Napravíme to hned v příštím dílu.

Úprava ClanekKontroler

Seznam článků bude vypisovat ClanekKontroler a to v případě, když mu nezadáme žádný parametr. Kontroler jednoduše podmínkou rozpůlíme na dvě části. Jedna vypisuje konkrétní článek a druhá seznam. Pro tyto akce by se daly použít 2 kontrolery, ale obvykle se zapisují do jednoho, když spolu úzce souvisí. Metodu zpracuj() upravíme do následující podoby:

public function zpracuj($parametry)
{
    // Vytvoření instance modelu, který nám umožní pracovat s články
    $spravceClanku = new SpravceClanku();

    // Je zadáno URL článku
    if (!empty($parametry[0]))
    {
        // Získání článku podle URL
        $clanek = $spravceClanku->vratClanek($parametry[0]);
        // Pokud nebyl článek s danou URL nalezen, přesměrujeme na ChybaKontroler
        if (!$clanek)
            $this->presmeruj('chyba');

        // Hlavička stránky
        $this->hlavicka = array(
            'titulek' => $clanek['titulek'],
            'klicova_slova' => $clanek['klicova_slova'],
            'popis' => $clanek['popisek'],
        );

        // Naplnění proměnných pro šablonu
        $this->data['titulek'] = $clanek['titulek'];
        $this->data['obsah'] = $clanek['obsah'];

        // Nastavení šablony
        $this->pohled = 'clanek';
    }
    else
    // Není zadáno URL článku, vypíšeme všechny
    {
        $clanky = $spravceClanku->vratClanky();
        $this->data['clanky'] = $clanky;
        $this->pohled = 'clanky';
    }
}

Nyní přejděme na kontroler clanek a nezadáme URL článku, který se má zobrazit. Zobrazí se seznam všech článků na webu:

Your page
localhost/clanek/

V příští lekci, Zabezpečení šablon, se budeme věnovat zabezpečení šablon proti XSS.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 1749x (14.46 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

Předchozí článek
Databázový wrapper
Všechny články v sekci
MVC - Jednoduchý redakční systém v PHP objektově
Přeskočit článek
(nedoporučujeme)
Zabezpečení šablon
Článek pro vás napsal David Čápka
Avatar
Uživatelské hodnocení:
50 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity

 

 

Komentáře
Zobrazit starší komentáře (60)

Avatar
Vojtech Palec:12.2.2020 15:52

Tabulka

 
Odpovědět
12.2.2020 15:52
Avatar
Vojtech Palec:12.2.2020 21:17

A teď jsem našel pomocí f12 v editor stylů

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="cs" xml:lang="cs">
<head>
<title>Objekt nenalezen!</title>
<link rev="made" href="mailto:[email protected]" />
<style type="text/css"><!--/*--><![CDATA[/*><!--*/
    body { color: #000000; background-color: #FFFFFF; }
    a:link { color: #0000CC; }
    p, address {margin-left: 3em;}
    span {font-size: smaller;}
/*]]>*/--></style>
</head>

<body>
<h1>Objekt nenalezen!</h1>
<p>


    Požadované URL nebylo na tomto serveru nalezeno.



    Zdá se, že odkaz na
    <a href="http://localhost/Clanek/uvod">odkazující
    stránce</a> je chybný nebo zastaralý. Informujte, prosím, autora
    <a href="http://localhost/Clanek/uvod">této stránky</a>
    o&nbsp;chybě.



</p>
<p>
Pokud si myslíte, že toto je chyba serveru, kontaktujte, prosím,
<a href="mailto:[email protected]">webmastera</a>.

</p>

<h2>Error 404</h2>
<address>
  <a href="/">localhost</a><br />
  <span>Apache/2.4.41 (Win64) OpenSSL/1.1.1c PHP/7.4.1</span>
</address>
</body>
</html>
 
Odpovědět
12.2.2020 21:17
Avatar
Lava
Člen
Avatar
Odpovídá na Vojtech Palec
Lava:13.2.2020 6:38

Vsak to vyzera, ze ti natiahlo aj sablona.phtml aj clanek.phtml. akurat css nemas, ale to nevidim ani v zdrojaku. Ta chyba, co si poslal, to sa ti kde zobrazuje?

Odpovědět
13.2.2020 6:38
Aspartám, sacharín, to je môj vitamín
Avatar
Odpovídá na Lava
Vojtech Palec:13.2.2020 7:32

Css mi funguje, když rozkliknu třeba kontakt, nebo na hlavní stránce. A ta chyba je z editor stylů, když stisknu f12 na prohlížeči ve Firefoxu :-)

 
Odpovědět
13.2.2020 7:32
Avatar
Marcel Sup
Člen
Avatar
Odpovídá na Vojtech Palec
Marcel Sup:18.8.2021 9:36

Ty css styly mi dělali přesně to samé, co tobě. Bylo to tím, že systém si v tomto případě hrabal pro css styl do již podřízeného adresáře ../clanek/sty­le.css, kde samozřejmě tento styl nenašel. Šlo mi to nahradit úpravou adresy pro css styly v šabloně rozlozeni, kde místo jednoduché adresy style.css se nahradí absolutní adresou http://..../style.css.

 
Odpovědět
18.8.2021 9:36
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
jozef.stropko:21.9.2021 17:47

Neviem, či poradím. Po kliknutí na link úvod, keď som mal v adrese /localhost/cmscvic­ny03/clanok/u­vod napríklad clanok/uvod, tak mi to zobrazilo chybovú stránku, po opätovnom kliknutí na úvod mi to zobrazilo úvodný článok a takto keď som na link úvod klikal niekoľkokrát po sebe, zobrazovalo sa to striedavo, raz úvodný článok, raz chybová stránka. Tag a s odkazom úvod mal v atribúte href tiež "clanok/uvod". Po kliknutí na iný link keď bol v query stringu clanok/uvod napr. na kontakt mi to zobrazilo chybovú stránku iba raz a potom to už zobrazovalo všetko normálne. Keď však bol v adrese iba clanok (bez ďalších názvov podstránok za lomítkom), tak odkazy fungovali ako mali aj po niekoľko násobnom kliknutí a to aj keď som do v atribúte tagu a s odkazom na úvod odstránil úvod a ponechal som iba clanok..

V šablóne rozlozenie som nemal tag <base href="" /> (do atribútu href treba zadať názov zložky s projektom). Po vložení tagu base s vyplneným atribútom href mi to už funguje tak ako má.

Editováno 21.9.2021 17:48
 
Odpovědět
21.9.2021 17:47
Avatar
Andrej Molčányi:8.10.2021 16:32

Ak používate MySQL-DB vo verzii 8 (a viac), a pri jej inštalácii ste si zvolili (defaultnu opciu) "Use Strong Password Encryption for Authentication", tak sa vám ani PHP-čkom 7 nepodarí prihlásiť cez PDO do databázy, lebo takýto spôsob autentifikácie zatiaľ PHP nepodporuje!

Riešením je vytvoriť si nového DB užívateľa (napr. mvc_user), s pôvodnou (Legacy) autentifikáciou pomocou direktívy mysql_native_pas­sword:

create user 'mvc_user'@'localhost' identified with mysql_native_password by 'jeho_nove_heslo';

... kde jeho_nove_heslo si zvoľte sami podľa svojho vkusu.

Nezabudnite mu ale ešte aj prideliť i práva pre prístup k (v tomto príklade pužívanej) DB:

grant all privileges on mvc_db.* to 'mvc_user'@'localhost' with grant option;

... inak sa pod ním síce prihlásite, ale vašu DB neuvidí.

Editováno 8.10.2021 16:33
 
Odpovědět
8.10.2021 16:32
Avatar
David Vlček
Člen
Avatar
David Vlček:26.10.2021 22:05

Ahoj, nevím jestli už to tu někdo nepsal, ale pokud máte server na Raspberry, Raspbian 10 a PHP7.3, jako já, tak v klihovně je BUG.
Peru se tím celý večer. Databáze hlásí chybu 500. Oprava je tu:

Otevřete knihovnu na řádku 604 a přepište funkci:
sudo nano +604 /usr/share/phpmy­admin/librari­es/sql.lib.php

function PMA_isRememberSortingOrder($analyzed_sql_results)
{
    return $GLOBALS['cfg']['RememberSorting']
        && ! ($analyzed_sql_results['is_count']
            || $analyzed_sql_results['is_export']
            || $analyzed_sql_results['is_func']
            || $analyzed_sql_results['is_analyse'])
        && $analyzed_sql_results['select_from']
        && ((empty($analyzed_sql_results['select_expr']))
            || (count($analyzed_sql_results['select_expr'] == 1)
                && ($analyzed_sql_results['select_expr'][0] == '*')))
        && count($analyzed_sql_results['select_tables']) == 1;
}

Taky jsem měl problém s přihlašováním na roota, i na localhostu, jak se tu popisuje. Prostě má zákaz se přihlásit.
Musel jsem udělat nového uživatele.

Snad tohle někomu pomůže, nebo někdo možná poradí jak si upravit konfiguraci mysql, aby nebyl problém s rootem. :-)

Odpovědět
26.10.2021 22:05
Nevěřím, že každý dokáže všechno co chce. Věřím ale, že by to měl zkusit.
Avatar
Jan Zahradník:11. ledna 20:57

Ahoj, v první verzi kontroleru ClanekKontroler je chyba viz. níže

// Hlavička stránky
        $this->hlavicka = array(
            'titulek' => $clanek['titulek'],
            'klicova_slova' => $clanek['klicova_slova'],
            'popis' => $clanek['popis'],
  • v proměnné clanek má být uvedeno 'popisek' a nikoliv 'popis'. Jinak to zobrazí chybovou hlášku nad hlavičkou stránky.
 
Odpovědět
11. ledna 20:57
Avatar
Petr Vocel
Redaktor
Avatar
Petr Vocel:13. května 20:04

Stalo se mi totéž a dost dlouho trvá než na to přijdete. Chtělo by to opravit a ty dvy znaky "ek" doplnit. Jinak je vidět kolik lidí to zkouší vytvořit samo a pak teprve porovnávat když to nefunguje.

 
Odpovědět
13. května 20:04
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 70. Zobrazit vše