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

Cesta URL: co se děje, než se načte webová stránka

Když do adresního řádku prohlížeče napíšete webovou adresu a stisknete Enter, spustí se fascinující řetězec procesů, které propojují váš počítač s celým světem. Od překladu doménového jména na IP adresu, přes navázání šifrovaného spojení, až po vykreslení každého pixelu na obrazovce - to všechno se odehraje během zlomků sekundy. Pojďme se podívat, co se mezitím děje pod kapotou webu.

Stav SIMD v Rustu v roce 2025

Různé
Komentáře: 1
SIMD - neboli Single Instruction, Multiple Data - znamená, že procesor může jednou instrukcí zpracovat více datových prvků najednou. Typicky to znamená, že místo sčítání dvou čísel přičtete dvě sady čísel paralelně. To může přinést výrazné zrychlení například při zpracování obrazu, audia nebo numerických výpočtů. Pokud již SIMD znáte, tato tabulka je vše, co budete potřebovat. A pokud s SIMD teprve začínáte, tabulku pochopíte do konce tohoto článku