Přejít k navigační liště

Zdroják » PHP » Symfony po krůčkách – HTTP fundamentalista

Symfony po krůčkách – HTTP fundamentalista

Články PHP

Stěžejní Symfony komponentou je HttpFoundation. Bere si na mušku naprostý základ webových aplikací – HTTP protokol. Je skvěle napsaná a snadno se používá. V dnešním díle si ukážeme, jak nám s použitím HttpFoundation knihovny aplikace pěkně prokoukne.

Od PHP k Symfony

Napsat webovou aplikaci v čístém PHP je snadné, ale bohužel nepohodlné a často se u toho naseká mnoho chyb. Data od uživatele musíme číst z několika superglobálních polí $_GET, $_POST, $_COOKIE, $_FILES a $_SESSION . K poslání odpovědi je třeba vypsat text a nastavit HTTP hlavičky

echo sprintf('Hello %s!', $_GET['name']);
header('Content-Type: text/html; charset=utf-8');

Pokud si zkusíme takto jednoduchý příklad, moc dobře nepořídíme. PHP zobrazí chybové hlášení Warning: Cannot modify header information - headers already sent, protože HTTP hlavičky se musí nastavit dříve než cokoliv vypíšeme. Další chyby a problémy vyvstanou ve chvíli, kdy začneme zpracovávat soubory, parsovat HTTP hlavičky a budeme chtít psát čistý a testovatelný kód.

Všechny uvedené problémy řeší Symfony komponenta HttpFoundation.  Je tak dobrá, že ji používá nejen Symfony framework, ale také Drupal, Laravel, eZ Publish a další. Nabízí skvělé objektové rozhraní, snadno se používá, přesně implementuje HTTP protokol a dokonce způsobila malou revoluci. Díky ní se Symfony neoznačuje jako MVC či MVP framework, ale honosí se titulem HTTP framework. Princip fungování Symfony aplikace je znázorněno na následujícím obrázku:

Komunikace mezi klientem a serverem pomocí HTTP protokolu

První příklad

Pojďme si komponentu HttpFoundation vyzkoušet. Nainstalujeme ji přes Composer

composer require symfony/http-foundation

Jak přepsat úvodní příklad pomocí komponenty HttpFoundation? Velmi jednoduše. Uděláme jen přesně to, co po nás chce HTTP protokol a co je uvedeno na obrázku.

<?php

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

require_once __DIR__.'/vendor/autoload.php';

$request = Request::createFromGlobals();

$response = new Response(sprintf('Hello %s!', $request->query->get('name')));
$response->send();

Vytvoříme objekt $request, který reprezentuje HTTP požadavek od klienta. Potom vytvoříme objekt $response, který představuje HTTP odpověď, a zavoláme na něm metodu send(), která tuto odpověď pošle klientovi. A to je vše!

Request – HTTP požadavek

Objekt třídy Request zapouzdřuje všechna superglobální PHP pole s uživatelskými vstupy. Nejjednoduší způsob, jak jej vytvořit, je pomocí helperu

$request = Request::createFromGlobals();

Můžeme použít i zápis, z kterého na první pohled vidíme, co se přesně stane

$request = new Request($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);

A jelikož Symfony myslí na všechno, tak objekt $request lze vytvořit i z obyčejné URL adresy a parametrů

$request = Request::create(
    'https://spazef0rze:1234@example.org:443/admin?action=edit', 
    'POST', 
    ['title' => 'Test']
);

Všechna data jsou dostupná přes veřejné atributy třídy Request

$request->query;   // $_GET
$request->request; // $_POST
$request->cookies; // $_COOKIE
$request->files;   // $_FILES
$request->server;  // $_SERVER
$request->headers; // $_SERVER['HTTP_...']

Symfony nejde jen o skvěle použitelné API, ale také o rychlost. S těmito daty pracujeme v aplikaci nejčastěji, a proto jsou dostupné jako třídní atributy, ke kterým PHP přistupuje daleko rychleji než k metodám.

Data nejsou uložena v obyčejném poli, ale jsou zapouzdřena v objektech třídy ParameterBag. Ta obsahuje spoustu užitečných metod, které nám ušetří psaní zbytečného kódu:

Uložení HTTP dat v třídě Request z HttpFoundation komponenty

$request->query->all(); // $_GET
$request->query->get('action', 'list'); // array_key_exists($_GET, 'action') ? $_GET['action'] : 'list'
$request->cookies->has('PWID'); // isset($_COOKIE['PWID']);
$request->request->keys(); // array_keys($_POST)

Navíc můžeme uživatelská data snadno filtrovat:

$request->query->getInt('id'); // převede $_GET['id'] na číslo
$request->query->getAlpha('action'); // z $_GET['action'] odstraní znaky, které nejsou v abecedě
$request->query->getDigits('order'); // z $_GET['order'] odstraní nečíselné znaky
$request->request->filter('email', null, FILTER_VALIDATE_EMAIL);
// vrátí hodnotu z $_POST['email'] pokud obsahuje validní email

Kdo v čistém PHP psal REST API, ví, jak složitě se dostávájí z POST pořadavku data (např. JSON řetězec). Třída Request na to má metodu

$content = $request->getContent();

Práci s daty máme skvěle zvládnutou. Tím možnosti komponenty HttpFoundation nekončí. O HTTP požadavku poskytuje veškeré informace. Pro představu zmíním pár metod:

$request->isSecure(); // HTTPS protokol?
$request->getMethod(); // název HTTP metody
$request->isMethod('POST'); // odesláno přes POST?
$request->isMethodSafe(); // posláno přes GET nebo HEAD?
$request->isXmlHttpRequest(); // AJAX
$request->isNoCache(); // je nastavena hlavička no-cache?
$request->getLanguages(); // podporované jazyky prohlížeče
$request->getCharset();
$request->getEncodings();
$request->getAcceptableContentType();
$request->getPathInfo(); // významná část URL adresy nutná pro routování

Response – HTTP odpověď

Objekt třídy Response obsahuje veškeré informace nutné k poslání odpovědi. Zkrátka, nic jiného k vykreslení webové stránky není potřeba. Vytvořit odpověď je snadné

use Symfony\Component\HttpFoundation\Response;

$response = new Response('Hello World!');

// nebo se všemi argumenty
$response = new Response('Hello World!', Response::HTTP_OK, ['content-type' => 'text/html'];

Největší výhodou tohoto přístupu je, že se neovlivňují globální proměnné, nenastavují žádné hlavičky a neposílá se obsah. Takto vytvořenou odpověď můžete kdekoliv v aplikaci zahodit a vytvořit novou. Nic se tím nepokazí. Vytvořenou odpověď lze upravovat:

$response->setContent('Hello Martin!');
$response->setStatusCode(Response::HTTP_NOT_FOUND); // vrátí 404
$response->setCharset('UTF-8');
$response->headers->set('Content-Type', 'text/plain');

Až jsme s odpovědí spokojeni, tak ji pošleme zavoláním metody

$response->send();

Pokud chceme mít jistotu, že vše v odpovědi je nastaveno správně, musíme před samotným odesláním zavolat

$response->prepare($request);
$response->send();

Zatímco třída pro HTTP požadavek byla jen jedna, Pro HTTP odpověď nabízí komponenta HttpFoundation tříd několik. Pokud chceme provést přesměrování, použijeme

use Symfony\Component\HttpFoundation\RedirectResponse;

$response = new RedirectResponse('https://www.zdrojak.cz');

Pro poslání souboru se skvěle hodí

use Symfony\Component\HttpFoundation\BinaryFileResponse;

$response = new BinaryFileResponse('path/to/file.txt');

Tato třída automaticky nastaví HTTP hlavičky RangeIf-Range, a X-Sendfile.

Pokud chceme změnit název souboru, pod kterým nám ho prohlížeč nabídne uložit, stačí zavolat metodu

use Symfony\Component\HttpFoundation\ResponseHeaderBag;

$response->setContentDisposition(
    ResponseHeaderBag::DISPOSITION_ATTACHMENT, 
    'filename.txt'
);

A pro JSON zvolíme

use Symfony\Component\HttpFoundation\JsonResponse;

$response = new JsonResponse(['data' => 123]);

Zase o krok dále

V dnešním díle jsme si ukázali:

  • jak funguje komunikace mezi prohlížečem a serverem,
  • jak nainstalovat a začít používat HttpFoundation,
  • jak místo několika superglobálních PHP polí používat jeden jediný objekt třídy Request,
  • jak vykreslovat stránky či vracet soubory a JSON data pomocí tříd Response,
  • ale hlavně, jak psát webové aplikace čistě pomocí Symfony komponenty HttpFoundation.

Kam jít dál?

Všechny možnosti komponenty HttpFoundation jsou krásně popsány v oficiální dokumentaci. Kapitola Symfony and HTTP Fundamentals podrobně vysvětluje propojení Symfony frameworku s HTTP protokolem.

Komentáře

Odebírat
Upozornit na
guest
1 Komentář
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
Zobrazit všechny komentáře
Marek

Super praca Martin, diky

Přístupnost není jen o splnění norem: nový pohled na inkluzivní design

Přístupnost a inkluze možná nepatří mezi nejžhavější témata digitálního světa – dokud o nich nezačne mluvit Vitaly Friedman. Na WebExpo 2024 předvedl, že inkluzivní design není jen o splněných checkboxech, ale hlavně o lidech. S energií sobě vlastní obrátil zažité přístupy naruby a ukázal, že skutečně přístupný web je nejen možný, ale i nezbytný.

Efektivnější vývoj UI nebo API: Co si odnést z WebExpo 2025?

Různé
Komentáře: 0
Jak snadno implementovat moderní uživatelské rozhraní? Které funkce brzdí rychlost vašeho webu? A kdy raději sami přibrzdit, abychom využitím AI nepřekročili etické principy? Debatu aktuálních dev témat rozdmýchá sedmnáctý ročník technologické konference WebExpo, která proběhne v Praze od 28. do 30. května. Který talk či workshop si rozhodně nenechat ujít? Toto je náš redakční výběr z vývojářských hroznů.

Zapřáhněte AI jako nikdy předtím. Květnová konference WebExpo přivítá hvězdy technologického světa

Od 28. do 30. května 2025 promění pražský Palác Lucerna na tři dny technologická konference WebExpo. Na programu je více než 80 přednášek a workshopů od expertů z celého světa. WebExpo tradičně propojuje vývojáře, designéry, marketéry i byznysové lídry a nabízí praktické dovednosti, strategické myšlení a přináší nejnovější trendy nejen v oblasti AI.