Aktuálně: Postihly zákazy tvou profesi? Poptávka po ajťácích prudce roste, využij podzimní akce 30% výuky zdarma!
Pouze tento týden sleva až 80 % na e-learning týkající se JavaScript
JavaScript týden

Lekce 6 - Knihovna ArrayUtils pro práci s poli v PHP

V minulé lekci, Dokončení knihovny StringUtils v PHP, jsme do StringUtils dopsali převod na pomlčky mezi snake_case a CamelCase. Také jsme si vyzkoušeli vygenerovat heslo.

Důležitou datovou strukturou v PHP jsou pole. Asi vás nepřekvapí, že i pro pole se najde několik užitečných funkcí, které si dnes zabalíme do třídy ArrayUtils.

ArrayUtils

Nejprve si založíme naši třídu:

class ArrayUtils
{
}

Filtrování pole podle klíčů

Často se nám stává, že potřebujeme profiltrovat pole tak, aby obsahovalo jen některé klíče. Pokud používáte místní databázový wrapper nad PDO, jistě víte, že pomocí něj můžeme např. jednoduše vložit nový řádek do tabulky "uzivatel" tímto způsobem:

$uzivatel = array(
    'jmeno' => 'Jan',
    'prijmeni' => 'Novak',
    'email' => '[email protected]',
);
Db::insert('uzivatel', $uzivatel);

Kód výše by se mohl využít např. pro nějakou registraci. Pokud předáme data z formuláře, bude sice fungovat, ale vystavujeme se nebezpečnému riziku a to sice, že uživatel si může nějaká formulářová pole přidat a ta se poté vloží do dotazu (např. "admin" = 1):

// Tento kód není bezpečný
Db::insert('uzivatel', $_POST);

Hodilo by se nám pole $_POST profiltrovat tak, aby obsahovalo jen určitý výčet klíčů. Uvedený postup se samozřejmě neváže jen na pole $_POST, ale využijeme ho i v dalších případech.

Do třídy přidáme následující metodu:

public static function filterKeys(array $input, array $keys)
{
    return array_intersect_key($input, array_flip($keys));
}
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Metoda filterKeys() přijímá v argumentech vstupní pole a dále pole klíčů, které chceme ponechat. Co se týče kódu, pomocí array_flip() získáme pole, které má jako klíče ty klíče, které chceme ponechat. Pomocí array_intersec­t_key() následně provedeme průnik klíčů dvou polí a vrátíme výsledek.

Ukažme si využití v původním příkladu, kde zabezpečíme získání dat z $_POST:

$klice = array('jmeno', 'prijmeni', 'email');
Db::insert('uzivatel', ArrayUtils::filterKeys($_POST, $klice));

Když je klíčů více, je výhodné dát jim nějaký prefix (předponu) a filtrovat podle něj.

public static function filterKeysPrefix($prefix, array $input)
{
    $output = array();
    foreach ($input as $key => $value)
    {
        if (mb_strpos($key, $prefix) === 0)
            $output[$key] = $value;
    }
    return $output;
}

Funkce filterKeysPrefix() přijímá prefix a vstupní pole. Ve výsledném poli zůstanou jen ty klíče, které začínají řetězcem $prefix. Kód by měl být srozumitelný.

Mapování párů klíč-hodnota a hodnot

Když vybíráme data z databáze, přijdou nám vždy jako pole polí, např. takto:

Array
(
    [0] => Array
        (
            [uzivatel_id] => 1
            [jmeno] => Jan Novák
            [email] => [email protected]
        )

    [1] => Array
        (
            [uzivatel_id] => 2
            [jmeno] => Jana Nováková
            [email] => [email protected]
        )

    [2] => Array
        (
            [uzivatel_id] => 3
            [jmeno] => Josef Nový
            [email] => [email protected]
        )
)

Mapování párů

Nyní si představte, že budeme v aplikaci chtít přidat formulář s výběrem uživatele pomocí HTML selectu (popisek bude jméno uživatele a hodnota odesílaná na server bude jeho ID). Pokud pro to použijeme nějaký formulářový framework, je velmi pravděpodobné, že bude chtít data ve formátu klíč-hodnota:

Array
(
    [Jan Novák] => 1
    [Jana Nováková] => 2
    [Josef Nový] => 3
)

Pro mapování výsledku databázového dotazu na takovéto asociativní pole přidejme do naší třídy metodu mapPairs():

public static function mapPairs(array $rows, $keyKey, $valueKey)
{
    $pairs = array();
    foreach ($rows as $row)
    {
        $key = $row[$keyKey];
        // Kontrola kolizí klíče
        if (isset($pairs[$key]))
        {
            $i = 1;
            while (isset($pairs[$key . ' (' . $i . ')']))
            {
                $i++;
            }
            $key .= ' (' . $i . ')';
        }
        $pairs[$key] = $row[$valueKey];
    }
    return $pairs;
}

Metodě předáme pole a poté 2 názvy klíčů. První klíč se stane ve výsledném poli klíčem a druhý hodnotou.

Výše zmíněné pole tedy získáme tímto způsobem:

$uzivatele = Db::queryAll('SELECT jmeno, uzivatel_id FROM uzivatel');
$polozky = ArrayUtils::mapPairs($uzivatele, 'jmeno', 'uzivatel_id');

Všimněte si, že metoda řeší i případ, když se 2 uživatelé jmenují stejně. V takovém případě začne položky číslovat.

Mapování hodnot

Podobně budeme občas potřebovat získat pole nějakých hodnot, např. emailů všech uživatelů, kterým pošleme newsletter. Budeme chtít získat následující pole:

Array
(
    [0] => [email protected]
    [1] => [email protected]
    [2] => [email protected]
)

Metoda mapSingles() není nijak složitá:

public static function mapSingles(array $rows, $singleKey)
{
    $singles = array();
    foreach ($rows as $row)
    {
        $singles[] = $row[$singleKey];
    }
    return $singles;
}

A použití:

$emaily = ArrayUtils::mapSingles(Db::queryAll('SELECT email FROM uzivatel'), 'email');

V příští lekci, Dokončení knihovny ArrayUtils v PHP, se zaměříme na práci s prefixy, konverzi notací a převod pole do XML a naopak.


 

Předchozí článek
Dokončení knihovny StringUtils v PHP
Všechny články v sekci
Knihovny pro PHP
Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
6 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn university Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (5)

 

 

Komentáře

Avatar
Mára Toner
Člen
Avatar
Mára Toner:26.11.2018 14:57

Zdravím, jak je to ale s bezpečností u metody filterKeysPrefix() ? Co zabrání uživateli, aby si tam ten prefix dal? Uživatel ho samozřejmě bude znát, protože tím prefixem budou začínat i ostatní pole v formuláři. Pak je to ale z bezpečnostního hlediska nesmysl, nebo ne?

Odpovědět
26.11.2018 14:57
If at first you don't succeed; call it version 1.0
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 1 zpráv z 1.