BLACK FRIDAY! Slevy až 80 % jsou všude. Tak je nepropásni a přejdi do rostoucího IT oboru!
The real BF 2020

5. diel - Prvý objektová komponenta v PHP - Galéria obrázkov

V minulej lekcii, Zapuzdrenie v PHP , sme si vysvetlili zapuzdrenie. Na dnešnej PHP tutoriál som sľúbil, že si vytvoríme niečo reálne použiteľného. Pôjde o galériu obrázkov.

Motivácia

Často chceme na našich stránkach zobraziť nejakú galériu obrázkov, či už ide o fotky z dovolenky alebo o screenshoty nášho programu. Písať ručne HTML tabuľku s obrázkami je trochu prácne, hlavne keď ich je v danej zložke veľa. Budeme teda chcieť zautomatizovať výpis obrázkov z nejakej zložky do prehľadnej tabuľky a najlepšie pomocou objektovej komponenty, ktorú budeme môcť používať viackrát a trebárs aj na viacerých weboch.

Založenie štruktúry projektu

Vytvoríme si novú zložku pre projekt, ja som ju pomenoval "galérie". V nej vytvoríme súbor index.php a zložku "tridy", v ktorej vytvoríme súbor Galerie.php. Nakoniec vytvoríme priečinok s obrázkami, tú som pomenoval jednoducho "obrazky". Do nej si pripravíme niekoľko obrázkov, ja som použil tie východiskové "Ukážky obrázkov" z operačného systému Windows. Ku každému obrázku je nutné vytvoriť ešte jeho miniatúru (napríklad v GIMP). Mohlo by to za nás robiť PHP pri nahrávaní obrázkov, ale nahrávanie už nie je predmetom tohto tutoriálu a môžeme ho dorobiť niekedy inokedy. Zvolil som si, že miniatúra bude široká 160px a jej názov bude vždy končiť na _nahled. Vaša zložka by mohla vyzerať napríklad nejako takto:

Zložka s obrázkami pre PHP Galérii

Galéria

Máme pripravené dáta a štruktúru, pusťme sa do programovania. Začneme samozrejme triedou Galéria, ktorej inštancia bude reprezentovať galériu obrázkov. Poďme si premyslieť, aké atribúty bude trieda mať.

Atribúty

Budeme chcieť určiť koľko náhľadov sa má zobraziť v jednom riadku, teda koľko stĺpcov bude mať tabuľka s obrázkami. Ďalej budeme chcieť samozrejme uchovávať cestu k priečinku s obrázkami. Ani jeden atribút nie je dôvod sprístupňovať zvonku, stačí, keď si ich necháme zadať v konstruktoru.

Kód triedy s týmito atribútmi a konštruktor bude vyzerať nasledovne:

class Galerie
{

    private $slozka;
    private $sloupcu;

    public function __construct($slozka, $sloupcu)
    {
        $this->slozka = $slozka;
        $this->sloupcu = $sloupcu;
    }

}

Metódy

Prejdime k metódam. Jednu v triede už samozrejme máme (konštruktor), pridáme tam 2 ďalšie.

Nacitaj

Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!

Metóda nacitaj () prehľadá priečinok a uloží si do pamäte náhľady obrázkov. Na prehľadanie zložky nám PHP ponúka triedu Directory. Spomínate si, ako sme si hovorili, že sa v PHP začínajú objavovať objekty? Directory je jedným z nich. Bohužiaľ možno inštanciu vytvoriť len pomocou funkcie dir (), no, nič nie je dokonalé. Na inštanciu nás zaujímajú 2 metódy:

  • read () - Načíta obsah ďalšieho súboru alebo priečinka v priečinku a vráti ho ako textový reťazec
  • close () - Ukončí čítanie zložky

Naša metóda nacitaj () by mohla vyzerať nateraz takto:

public function nacti()
{
    $slozka = dir($this->slozka);

    while ($polozka = $slozka->read())
    {

    }
    $slozka->close();
}

Vytvoríme si inštanciu Directory a pomocou metódy read () čítame postupne zložky a súbory v tejto zložke. Metóda vráti false v prípade, že sme sa prehrýzli až na "koniec" zložky (za posledný súbor alebo priečinok). Vďaka tomu môžeme dať načítanie názvu súboru do while cyklu, ktorý skončí vo chvíli, keď načítame posledný. Názov budeme mať vnútri cyklu dostupný v premennej $ polozka. Možno je trochu nezvyklé, že v podmienke while cykle vykonávame rovno aj priradenie do premennej, ale robí sa to tak veľmi často.

Každý súbor teraz načítame 2x (miniatúra + originál) ak tomu nám funkcie ešte vráti vždy 2 zložky navyše. Sú to zložky s názvom "." a "..", ktoré označujú súčasnú a nadradenú zložku. My budeme chcieť zobrazovať len miniatúry, preto do cyklu umiestnime podmienku, že nás zaujímajú iba súbory, ktoré obsahujú v názve "_nahled.". Tieto súbory si uložíme do poľa. Keďže chceme, aby bolo toto pole prístupné pre metódu vypis (), musíme ho pridať triede ako privátne atribút:

private $soubory = array();

Teraz sa presuňme do tela cyklu while a pridajme názov súboru do nášho poľa zakaždým, keď sa jedná o náhľad. Použijeme na to funkciu strpos (), ktorá vracia pozíciu podreťazca v reťazci. Ak sa v názve položky vyskytuje od druhého znaku niekde text "_nahled.", Bude položka pridaná do nášho poľa. Ak nie, funkcia vráti false.

if (strpos($polozka, '_nahled.'))
{
    $this->soubory[] = $polozka;
}
  • Funkcia strpos () vráti 0 v prípade, že reťazec podreťazcom začína (pretože 0 označuje prvú pozíciu). V našom prípade by sa hodnota 0 vyhodnotila ako nepravda a podmienka by neplatila. To je správne, súbor _nahled.jpg by sa viazal k obrázku bez názvu a nie je teda platný. Ak by sme však chceli opodmínkovat kompletne výskyt podreťazca, napríklad v inej aplikácii, používa sa na odlíšenie 0 a hodnoty false operátor! == takto: *
if (strpos($polozka, '_nahled.') !== false)
{
    $this->soubory[] = $polozka;
}

Teraz podmienka neprejde len s hodnotou false a prejde s hodnotou 0. V našom prípade sa nám však skôr hodí prvý variant.

Vypis

Tú zložitejšie časť máme za sebou, presuňme sa teraz k výpisu HTML tabuľky, teda k metóde vypis (). Aj keď by načítanie aj výpis mohli byť v jednej metóde, jedná sa o 2 logické úlohy a preto je lepšie ich rozdeliť do 2 metód. Metóda by mala robiť vždy jednu vec a mali by sme ju byť schopní popísať bez spojky a. Teda "Metóda zobraz () zobrazí HTML tabuľku s náhľadmi", nie "Metóda zobraz () načíta a zobrazí galériu".

Metóda vypis () vyechuje začiatok tabuľky. Ďalej proiterujeme cyklom foreach miniatúry a tie vyechujeme do bunky tabuľky ako tag img. Okolo tagu img samozrejme urobíme odkaz na originálny obrázok. Ten získame veľmi jednoducho, stačí v názve miniatúry nahradiť "_nahled." za ".". Nahradenie prevedieme funkcií str_replace (). Aby nebola celá tabuľka v jednom riadku, budeme si počítať koľký stĺpec vypisujeme. Akonáhle dosiahneme hodnoty nastavené v atribútu $ stlpcov, uzavrieme riadok, začneme nový a vynulujeme počítadlo stĺpcov.

Kód metódy vypis () by mohol vyzerať nejako takto:

public function vypis()
{
    echo('<table id="galerie"><tr>');
    $sloupec = 0;
    foreach ($this->soubory as $soubor)
    {
        $nahled = $this->slozka . '/' . $soubor;
        $obrazek = $this->slozka . '/' . str_replace('_nahled.', '.', $soubor);
        echo('<td><a href="' . htmlspecialchars($obrazek) . '"><img src="' . htmlspecialchars($nahled) . '" alt=""></a></td>');
        $sloupec++;
        if ($sloupec >= $this->sloupcu)
        {
            echo('</tr><tr>');
            $sloupec = 0;
        }
    }
    echo('</tr></table>');
}

Použitie

Presunieme sa do index.php, vložíme sem základné HTML štruktúru a vytvoríme inštanciu galérie. Do konstruktoru odovzdáme zložku a počet stĺpcov. Následne zavoláme nacitaj () a vypis ().

<!DOCTYPE html>

<html lang="cs-cz">
    <head>
            <meta charset="utf-8" />
            <title>Galerie obrázků</title>
    </head>

    <body>
        <h1>Galerie obrázků</h1>
        <?php
        require_once('tridy/Galerie.php');

        $galerie = new Galerie('obrazky', 5);
        $galerie->nacti();
        $galerie->vypis();

        ?>
    </body>
</html>

Máme hotovo.

Keď pridáme minimum CSS, môže vaše aplikácie vyzerať napríklad takto (zdrojový kód ako vždy nižšie k stiahnutiu, na zobrazovanie originálne obrázkov som ešte pridal javascriptový plugin Lightbox):

Objektová galérie obrázkov v PHP

Možná vylepšenia

Metóda vypis () nie je úplne ideálne, pretože sa HTML kód strechu a preto je práca s ním trochu neprehľadná. Ďalším, už spomínaným vylepšením, by mohol byť nahrávač obrázkov, ktorý nám na FTP nahrá obrázky do galérie a sám vytvorí miniatúry. Pre naše účely je však aplikácia dostačujúce a myslím, že má aj tak praktické využitie.

Naprogramovali sme objektovú komponent, ktorú môžeme používať na rôznych weboch, pre rôzne zložky a na rôzne široké tabuľky.

V budúcej lekcii, Referenčnej a primitívne dátové typy v PHP , budeme pokračovať s našimi ľuďmi, ktorých sa ešte len tak nepustíme. Vysvetlíme si ako PHP pracuje s referenčnými dátovými typmi.


 

Stiahnuť

Stiahnuté 2808x (6.54 MB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP

 

Predchádzajúci článok
Zapuzdrenie v PHP
Všetky články v sekcii
Objektovo orientované programovanie (OOP) v PHP
Článok pre vás napísal David Čápka
Avatar
Ako sa ti páči článok?
Ešte nikto nehodnotil, buď prvý!
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 sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity (1)

 

 

Komentáre

Avatar
Karel Labonek:14.5.2018 19:38

Ahojki, vzřešil jsi ten problém s načtením fotek, mě to píše toto:

Přístup odmítnut!
Nemáte právo pro přístup do požadovaného adresáře. Buď neexistuje žádný dokument s obsahem (tzv. index), nebo je adresář chráněn proti čtení.

Pokud si myslíte, že toto je chyba serveru, kontaktujte, prosím, webmastera.

Error 403
webkatka
Apache/2.4.33 (Win32) OpenSSL/1.1.0g PHP/7.2.4

nemáš radu?

 
Odpovedať
14.5.2018 19:38
Avatar
Jiří Pecher:18.10.2019 20:40

Ahoj, výraz "vyechuje" je mi jasný :-) Co však prosím znamená výraz "proiterujeme"? ;-)

Editované 18.10.2019 20:40
Odpovedať
18.10.2019 20:40
"Když nemám co dělat, pracuji."
Avatar
Odpovedá na Jiří Pecher
Michal Šmahel:18.10.2019 23:30

Ahoj, vychází to z iterátoru. Více si můžeš přečíst různě po internetu (např. tady). Úplně zjednodušeně se jedná o projití nějaké kolekce (v PHP je kolekcí vlastně i klasické pole) prvek po prvku. V PHP se k tomu často používá cyklus foreach (jako např. i v článku).


Když by ses chtěl dozvědět trochu více: Iterátor je návrhový vzor, který ti zajišťuje možnost "jednoduchého" projití nějaké kolekce (v PHP pole, jinak různé seznamy, množiny apod.), aniž bys musel složitě řešit, jak je tato kolekce uvnitř vlastně řešena. Iterátor zajistí určité rozhraní, díky němuž lze kolekci vložit do běžného foreach cyklu, který s ním díky jeho implementaci dokáže pracovat jako např. s klasickým PHP polem. Opět velmi zjednodušeno, ale myslím, že nemá smysl to více rozebírat. Prozatím je to jistě až až, v případě zájmu samozřejmě můžeš pročíst internet. Bez dalších podkladů a znalosti rozhraní a obecné teorie kolem návrhových vzorů to však nemá příliš smysl nějak hlouběji zkoumat.

Odpovedať
18.10.2019 23:30
Nejdůležitější je motivace, ovšem musí být doprovázena činy.
Avatar
Dávid Dopirák:21. novembra 16:40

Ahoj,
Chcel by som vedieť, ako ináč zapísať:

while($polozka = $zlozkaNacitaj->read())

Skúšal som to zapísať:

$polozka = $zlozkaNacitaj->read();

       while($polozka) ...

ale pak mi to vôbec nechce načítať. Pýtam sa na základe toho čo je napísané tu:

Možná je trochu nezvyklé, že v podmínce while cyklu provádíme rovnou i přiřazení do proměnné, ale dělá se to tak velmi často.

Díky

 
Odpovedať
21. novembra 16:40
Avatar
Milan Turyna
Redaktor
Avatar
Odpovedá na Dávid Dopirák
Milan Turyna:21. novembra 18:45

Nejsem na pocitaci takze ti neposlu ukazkovy kod, kazdopadne cyklus while funguje na principu ze bude vykonávat určitou akci dokud podminka bude platit, v momentalnim pripade dokud $polozka bude true. While cyklus nepouzivam kazdopadne metoda pravděpodobne vraci dalsi hodnotu z nejakeho seznamu/pole/re­sultsetu a kdybys promennou nastavil jiz pred cyklem tak by se cyklus provedl pouze jednou protoze by se hodnota promenne nemenila a po jednom opakovani by byla false.

Pokud ji ovsem nastavime ve while() tak metoda read pokazde zmeni obsah promenne a presune offset na dalsi element - dalsi radek, az se proiteruji vsechny radky, tak uz nebude co vracet a cyklus se skonci protoze promenna uz nebude true.

Neumim moc vysvetlovat teorii, radsi bych ti to popsal v praxi na kodu.

https://www.itnetwork.cz/…-for-a-while

Fungovat by tez mohlo:

$polozka = $xxx->read();
$i=0;
while ($polozka) {
   $polozka = $xxx->read();
   echo $i++;
}
//1
//2
//3
//4
//5
// az do celkoveho poctu elementu
Editované 21. novembra 18:46
 
Odpovedať
21. novembra 18:45
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!
Avatar
Odpovedá na Milan Turyna
Dávid Dopirák:21. novembra 22:47

Chápem to teda správne, že v mojom prípade som celú podmienku zadal akoby mimo cyklu ? A preto mi "nekonečný" cyklus while po 2 minútach vypíše hlášku??

Fatal error: Maximum execution time of 120 seconds exceeded in D:\xampp\htdoc­s\triedyOOP\tri­edy\Galeria.php on line 32

Hovoril si, že nepoužívaš while. Používaš teda vždy cyklus for s konečným počtom opakovaní ?

 
Odpovedať
21. novembra 22:47
Avatar
Milan Turyna
Redaktor
Avatar
Odpovedá na Dávid Dopirák
Milan Turyna:22. novembra 8:23

Spletl jsem si to, polozka nebude false po jednom opakovani ale pokud mas aspon mas aspon jeden element v poli tak zustane po celou dobu true a potom ano, napise ti to ten error protoze to je jako kdybys vzal

while(true) {... }
 /*
bude to provadet opakovani do ty doby, dokud server neselze popripade dokud se nedojde k maximalnimu nastavenemu casu pro spusteni skriptu
*/

Používám foreach všude kde to jde a jinak for, ale v celku na tom cyklu neni nic spatneho, jen proste me vyhovuji vice tyto dva.

Editované 22. novembra 8:25
 
Odpovedať
22. novembra 8:23
Avatar
Odpovedá na Milan Turyna
Dávid Dopirák:22. novembra 9:35

Díky. Dal by som palec hore ale ešte nemám skill. ;)

 
Odpovedať
22. novembra 9:35
Avatar
Lukáš Vavřík:22. novembra 9:51

Přátelé máte v tutoriálu chybu.

Přepsal jsem si ho tak jak je to v tutoriálu uvedené a snažil se tomu porozumět. Když to použiji přesně tak jak to tu je tak to nefunguje a vyhazuje mi to v cyklu "foreach" chybu.

Po stažení zdrojového kódu jsem objevil, že v cyklu "while" je navíc

..  (is_file($this->slozka . '/' . $polozka) ...

bez této části to nefunguje.
Toto by chtělo opravit a trochu rozvést. Díky

 
Odpovedať
22. novembra 9:51
Avatar
Odpovedá na Lukáš Vavřík
Lukáš Vavřík:22. novembra 9:56

Aha :D tak já měl chybu ještě někde jinde :D Pardon. Škoda že tu nejdou komentáře mazat či editovat

 
Odpovedať
22. novembra 9:56
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zatiaľ nikto nevložil komentár - buď prvý!