RSS i SimplePie

SimplePie RSS parser

Google Reader nie jest dostępne już prawie dwa miesiące, a na rynku pojawiło się sporo rozwiązań, które skutecznie wypełniły lub nadal wypełniają lukę pozostawioną przez ten największy jak do tej pory serwis. Niektóre rozwiązania starają się bardzo przypominać rozwiązanie od wujka Google, inne z kolei zmieniają nieco nasze przyzwyczajenia i udostępniają nam nowatorskie interfejsy. Nie chcę jednak pisać o obecnych rozwiązaniach, a o możliwości stworzenia własnego.

SimplePie

Narzędzie, które pozwoli nam konsumować kanały RSS oraz w łatwy sposób wyświetlać treści się tam znajdujące nazywa się SimplePie. Budowane i rozwijane w duchu Open Source na Github, zainstalowane może być za pomocą wspominanego już wielokrotnie tutaj Composera (SimplePie Packagist).

Podstawy

Zakładając, że mamy już zainstalowane SimplePie poprzez Composer, możemy przystąpić do wyboru pierwszego kanału RSS, który będziemy chcieli sparsować i wyświetlić. Posłużę się oczywiście swoim kanałem blogowym i pokażę Wam przykład, gdzie stworzę nowy obiekt SimplePie, ustawię adres URL kanału RSS (set_feed_url()) oraz zainicjalizuję nasz RSS reader poprzez wywołanie metody init() na obiekcie $feed.

<?php

require_once 'vendor/autoload.php';

$url = 'http://mrzepinski.pl/feed';
$feed = new SimplePie();
$feed->set_feed_url($url);
$feed->init();

UWAGA: SimplePie może rzucić wyjątkiem Warning: ./cache is not writeable. Wystarczy w takim wypadku utworzyć folder cache i w przypadku środowiska [L]inux nadać mu odpowiednie uprawnienia (chmod 755 cache).

Tym samym – jeżeli URL, który podaliśmy jest dostępny i jest to kanał RSS / Atom – możemy wykonywać kolejne metody, które pozwolą pobrać dane z kanału RSS.

...
echo '<h1>'.$feed->get_title().'</h1>';
echo '<p>'.$feed->get_description().'</p>';

Dzięki metodom get_title() oraz get_description() pobierzemy odpowiednio tytuł oraz opis naszego kanału RSS.

Jako, że kanały RSS posiadają standard, który zapewnia, że format XML kanału musi być zawsze taki sam, możemy bez problemu pobierać także konkretne informacje o poszczególnych obiektach, które udostępniane są przez RSS. Pobranie pierwszego obiektu wyglądać może następująco:

...
$item = $feed->get_item(0);
echo '<p>Title: <a href="'.$item->get_link().'">'.$item->get_title().'</a></p>';
echo '<p>Author: '.$item->get_author()->get_name().'</p>';
echo '<p>Date: '.$item->get_date('Y-m-d H:i:s').'</p>';
echo $item->get_content(true);

Ważnym czynnikiem jest także ilość dostępnych elementów. Taką informację osiągniemy poprzez wywołanie metody get_item_quantity() w następujący sposób:

...
$itemQty = $feed->get_item_quantity();
for ($i = 0; $i < $itemQty; $i++) {
    ...
}

Rozwiązanie to nie pozwoli nam jednak na paginację pobieranych wyników. Dużo łatwiej będzie nam to osiągnąć poprzez wykorzystanie metody get_items(), która jako pierwszy argument przyjmuje tak zwany offset, (miejsce od którego chcemy zacząć pobierać kolejne elementy), a jako drugi liczbę elementów do pobrania.

...
foreach ($feed->get_items(10, 10) as $item) {
    ...
}

Podsumowanie

Tym samym zbudowaliśmy prosty czytnik RSS. Nie było to specjalnie trudne prawda? Pełną dokumentację dostępnych klas oraz metod znajdziecie w oficjalnym API opisującym wszystkie dostępne funkcje. Do Was należy pobudzenie swojej kreatywności oraz realizacja własnego projektu.

Osom PHP #1 – Composer

Composer

Był już wprawdzie wpis o 24 bibliotekach PHP, które warto poznać, ale.. jest tego znacznie więcej i naprawdę warto być na czasie. Tym samym postaram się dzielić z Wami co jakiś czas wpisami na temat nowości, które sprawiają, że społeczność PHP oraz wszystkie powstające biblioteki, narzędzia, ułatwienia i.. długo by tak wymieniać – przyspieszają naszą pracę, sprawiają, że jesteśmy lepsi oraz bardziej efektywni. Zapraszam do pierwszej części poświęconej narzędziom powiązanym z Composerem.

Dlaczego Composer? Gdyby opisywać historyjkę w Scrum, to według mnie, nie jest to już nice to have, a must have.

Composer Installers

Multi framework, który integruje się z Composerem i pozwala na bardziej rozbudowane zarządzanie wszystkimi instalowanymi paczkami. Dzięki tej bibliotece jesteśmy w stanie na przykład zmieniać nazwy pakietów podczas instalacji, czy też modyfikować ścieżki, gdzie zainstalowane zostaną poszczególne komponenty.

Packagist

Composer w zasadzie nie istniałby dzisiaj, gdyby nie rozbudowane repozytorium wszystkich dostępnych bibliotek. Takie repozytorium stanowi właśnie Packagist. Z jego pomocą odnajdziemy interesujące nad komponenty oraz dowiemy się nieco więcej na temat ich różnych wersji.

Satis

Pozwala na statyczną obsługę repozytorium na podstawie naszego pliku composer.json. Jest to jakby lekka wersja Packagist, która odpowiedzialna może być na przykład za składowanie prywatnych komponentów na potrzeby nasze lub firmy.

Composition

Czyli sprawdzanie naszego środowiska w oparciu o Composer. Dzięki Composition jesteśmy w stanie sprawdzić system na którym pracujemy, wersje zainstalowanych bibliotek, czy ich faktyczną obecność w naszym kodzie. Bardzo przydatne narzędzie.

Poser

Pozwala na tak zwany aliasing. To nic innego jak zmiana nazwy klas, przestrzeni nazw instalowanych bibliotek. Możemy dzięki temu wykorzystywać własne nazwy, które będą nam bardziej odpowiadać.

Version

To wparcie dla wersjonowania naszego kodu. Pozwala zarządzać odpowiednią numeracją wersji według schematu Semantycznego Wersjonowania.

NameSpacer

Z pewnością doskonale znacie i kojarzycie standard z języka PHP, gdzie wykorzystywane są podkreślenia lub prefixy w celu budowy nazw klas, opisu struktury katalogów oraz autoloadera, który nam te klasy ładuje na żądanie. NameSpacer to narzędzie, które pozwoli nam zastąpić ten relikt przeszłości na przestrzenie nazw. Od tak.

Patch Installer

Jak sama nazwa mówi – jest to mechanizm do instalowania tak zwanych patchy z wykorzystaniem Composera.

24 biblioteki PHP, które warto poznać

PHP Libraries

Muszę to napisać – to niezwykłe być dzisiaj deweloperem języka PHP. Dlaczego? Każdego dnia na światło dzienne wychodzi bardzo dużo użytecznych bibliotek i narzędzi, które usprawniają oraz przyspieszają naszą pracę. W dobie Composera oraz Githuba ich odkrycie nie jest już trudnym zadaniem.

Dzisiejszy wpis będzie właśnie o takich bibliotekach. Poniżej przedstawiam listę 24 narzędzi, które powinniście poznać. Jeżeli uważacie, że powinienem dodać do tej listy coś jeszcze, to dajcie oczywiście znać w komentarzach pod wpisem.

  1. Dispatch – Micro Framework

    Dispatch jest mini frameworkiem. Nie udostępnia on pełnej struktury MVC, ale daje możliwość tworzenia reguł URL oraz lepszą organizację naszej aplikacji. Nadaje się świetnie do prostych projektów oraz API.

    // include the library
    include 'dispatch.php';
    
    // define your routes
    get('/greet', function () {
        // render a view
        render('greet-form');
    });
    
    // post handler
    post('/greet', function () {
        $name = from($_POST, 'name');
        // render a view while passing some locals
        render('greet-show', array('name' => $name));
    });
    
    // serve your site
    dispatch();
  2. Klein – Lightning fast router for PHP

    Klein (PHP 5.3+) jest kolejną biblioteką, która pozwala tworzyć routing URL w prosty i przyjemny sposób. Ma ona bardziej specyficzną składnię niżeli Dispatch, ale jest też bardzo szybka.

    respond('GET', '/posts', $callback);
    respond('POST', '/posts/create', $callback);
    respond('PUT', '/posts/[i:id]', $callback);
    respond('DELETE', '/posts/[i:id]', $callback);
    
    // To match multiple request methods:
    respond(array('POST','GET'), $route, $callback);
    
    // Or you might want to handle the requests in the same place
    respond('/posts/[create|edit:action]?/[i:id]?', function ($request, $response) {
        switch ($request->action) {
            // do something
        }
    });
  3. Ham – Routing Library with Caching

    Ham, to kolejny lekki sposób na definicję naszych URL, ale daje nam coś jeszcze. Wykorzystuje on mechanizm XCache oraz APC do cachowania, co pozwala na znacznie szybsze działanie całości.

    require '../ham/ham.php';
    
    $app = new Ham('example');
    $app->config_from_file('settings.php');
    
    $app->route('/pork', function($app) {
        return "Delicious pork.";
    });
    
    $hello = function($app, $name='world') {
        return $app->render('hello.html', array(
            'name' => $name
        ));
    };
    $app->route('/hello/<string>', $hello);
    $app->route('/', $hello);
    
    $app->run();
  4. Assetic – Asset Management

    Assetic jest biblioteką do zarządzania dodatkowymi komponentami. Pozwala na łączenie oraz minimalizację skryptów JavaScript oraz arkuszy CSS. Zmniejsza tym samym ilość zapytań generowanych do serwera oraz redukuje ilość przesyłanych danych do klienta.

    use Assetic\\Asset\\AssetCollection;
    use Assetic\\Asset\\FileAsset;
    use Assetic\\Asset\\GlobAsset;
    
    $js = new AssetCollection(array(
        new GlobAsset('/path/to/js/*'),
        new FileAsset('/path/to/another.js'),
    ));
    
    // the code is merged when the asset is dumped
    echo $js->dump();
  5. ImageWorkshop – Image Manipulation with Layers

    ImageWorkshop – biblioteka Open Source do manipulacji obrazkami na warstwach. Pozwala zmieniać rozmiar obrazków, przycinać, tworzyć miniatury, dodawać znaki wodne i wiele wiele więcej. Jest to nieco lżejsza  wersja biblioteki Imagine.

    // We initialize the norway layer from the picture norway.jpg
    $norwayLayer = ImageWorkshop::initFromPath('/path/to/images/norway.jpg'); 
    
    // We initialize the watermark layer from the picture watermark.png
    $watermarkLayer = ImageWorkshop::initFromPath('/path/to/images/watermark.png'); 
    
    $image = $norwayLayer->getResult(); // This is the generated image ! 
    
    header('Content-type: image/jpeg');
    imagejpeg($image, null, 95); // We choose to show a JPG with a quality of 95%
    exit;
  6. Snappy – Snapshot/PDF Library

    Snappy pozwoli nam na stworzenie snapshotów z dokumentów PDF, HTML, czy nawet bezpośrednio z adresu URL. Biblioteka wykorzystuje wkhtmltopdf, które dostępne jest na Linuxa, Windowsa oraz OSX.

    require_once '/path/to/snappy/src/autoload.php'; 
    
    use Knp\\Snappy\\Pdf; 
    
    // Initialize the library with the
    // path to the wkhtmltopdf binary:
    $snappy = new Pdf('/usr/local/bin/wkhtmltopdf'); 
    
    // Display the resulting pdf in the browser
    // by setting the Content-type header to pdf: 
    
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename="file.pdf"'); 
    
    echo $snappy->getOutput('http://www.github.com');
  7. Idiorm – Lightweight ORM Library

    Idiorm to lekka biblioteka ORM. W sposób obiektowy pozwala ona tworzyć zapytania języka SQL bazując na PDO.

    $user = ORM::for_table('user')
        ->where_equal('username', 'j4mie')
        ->find_one();
    
    $user->first_name = 'Jamie';
    $user->save();
    
    $tweets = ORM::for_table('tweet')
        ->select('tweet.*')
        ->join('user', array(
            'user.id', '=', 'tweet.user_id'
        ))
        ->where_equal('user.username', 'j4mie')
        ->find_many();
    
    foreach ($tweets as $tweet) {
        echo $tweet->text;
    }
  8. Underscore – PHP’s Utility Belt

    Underscore to odpowiednik Underscore.js dla jezyka PHP. Biblioteka w zasadzie w 100% pokrywa się z oryginałem z języka JavaScript. Jest to rozwinięcie składni języka o nowe funkcje, które pozwalają manipulować danymi. Są to funkcje znane i zaczerpnięte z języków funkcyjnych, takich jak na przykład Scala, czy Python.

    __::each(array(1, 2, 3), function($num) { echo $num . ','; }); // 1,2,3,
    
    $multiplier = 2;
    __::each(array(1, 2, 3), function($num, $index) use ($multiplier) {
      echo $index . '=' . ($num * $multiplier) . ',';
    });
    // prints: 0=2,1=4,2=6,
    
    __::reduce(array(1, 2, 3), function($memo, $num) { return $memo + $num; }, 0); // 6
    
    __::find(array(1, 2, 3, 4), function($num) { return $num % 2 === 0; }); // 2
    
    __::filter(array(1, 2, 3, 4), function($num) { return $num % 2 === 0; }); // array(2, 4)
  9. Requests – Easy HTTP Requests

    Requests to tak naprawdę nakładka na cURL pozwalająca wykonywać zapytania HTTP bezpośrednio w języku PHP.

    $headers = array('Accept' => 'application/json');
    $options = array('auth' => array('user', 'pass'));
    $request = Requests::get('https://api.github.com/gists', $headers, $options);
    
    var_dump($request->status_code);
    // int(200)
    
    var_dump($request->headers['content-type']);
    // string(31) "application/json; charset=utf-8"
    
    var_dump($request->body);
    // string(26891) "[…]"
  10. Buzz – Simple HTTP Request Library

    Buzz – kolejna biblioteka PHP do wykonywania zapytań HTTP, będąca tym samym nakładką na cURL. Korzystam z niej często w różnych projektach, ale ostatnio coraz częściej wykorzystuję Guzzle.

    $request = new Buzz\\Message\\Request('HEAD', '/', 'http://google.com');
    $response = new Buzz\\Message\\Response();
    
    $client = new Buzz\\Client\\FileGetContents();
    $client->send($request, $response);
    
    echo $request;
    echo $response;
  11. Goutte – Web Scraping Library

    Goutte – biblioteka, która pozwala pobierać konkretne elementy z innych stron. Posiada API, które daje nam metody do pobierania konkretnych danych. Spójrzcie na przykład poniżej.

    require_once '/path/to/goutte.phar'; 
    
    use Goutte\\Client; 
    
    $client = new Client();
    $crawler = $client->request('GET', 'http://www.symfony-project.org/'); 
    
    // Click on links: 
    
    $link = $crawler->selectLink('Plugins')->link();
    $crawler = $client->click($link); 
    
    // Extract data with a CSS-like syntax: 
    
    $t = $crawler->filter('#data')->text(); 
    
    echo "Here is the text: $t";
  12. Carbon – DateTime Library

    Carbon jest API, a zarazem rozszerzeniem dla DateTime. Biblioteka udostępnia szereg nowych metod do operowania na obiektach daty i czasu. Istnieje jeszcze ‘fork’ projektu na Githubie, który wydaje się być bardziej i częściej rozwijany niż sam pierwowzór – Datum.

    printf("Right now is %s", Carbon::now()->toDateTimeString());
    printf("Right now in Vancouver is %s", Carbon::now('America/Vancouver'));
    
    $tomorrow = Carbon::now()->addDay();
    $lastWeek = Carbon::now()->subWeek();
    $nextSummerOlympics = Carbon::createFromDate(2012)->addYears(4);
    
    $officialDate = Carbon::now()->toRFC2822String();
    
    $howOldAmI = Carbon::createFromDate(1975, 5, 21)->age;
    
    $noonTodayLondonTime = Carbon::createFromTime(12, 0, 0, 'Europe/London');
    
    $endOfWorld = Carbon::createFromDate(2012, 12, 21, 'GMT');
    
    // comparisons are always done in UTC
    if (Carbon::now()->gte($endOfWorld)) {
        die();
    }
    
    if (Carbon::now()->isWeekend()) {
        echo 'Party!';
    }
    
    echo Carbon::now()->subMinutes(2)->diffForHumans(); // '2 minutes ago'
  13. Ubench – Micro Benchmarking Library

    Ubench to mikro framework do przeprowadzania testów wydajnościowych w naszym kodzie PHP. Pozwala monitorować zużycie pamięci oraz czas wykonania.

    use Ubench\\Ubench;
    
    $bench = new Ubench;
    
    $bench->start();
    
    // Execute some code
    
    $bench->end();
    
    // Get elapsed time and memory
    echo $bench->getTime(); // 156ms or 1.123s
    echo $bench->getTime(true); // elapsed microtime in float
    echo $bench->getTime(false, '%d%s'); // 156ms or 1s
    
    echo $bench->getMemoryPeak(); // 152B or 90.00Kb or 15.23Mb
    echo $bench->getMemoryPeak(true); // memory peak in bytes
    echo $bench->getMemoryPeak(false, '%.3f%s'); // 152B or 90.152Kb or 15.234Mb
    
    // Returns the memory usage at the end mark
    echo $bench->getMemoryUsage(); // 152B or 90.00Kb or 15.23Mb
  14. Validation – Input Validation Engine

    Validation – chyba najlepsza i najbardziej kompleksowa biblioteka do walidacji danych w języku PHP. Zresztą spójrzcie sami na przykład:

    use Respect\\Validation\\Validator as v; 
    
    // Simple Validation 
    
    $number = 123;
    v::numeric()->validate($number); //true 
    
    // Chained Validation 
    
    $usernameValidator = v::alnum()->noWhitespace()->length(1,15);
    $usernameValidator->validate('alganet'); //true 
    
    // Validating Object Attributes 
    
    $user = new stdClass;
    $user->name = 'Alexandre';
    $user->birthdate = '1987-07-01'; 
    
    // Validate its attributes in a single chain: 
    
    $userValidator = v::attribute('name', v::string()->length(1,32))
                      ->attribute('birthdate', v::date()->minimumAge(18)); 
    
    $userValidator->validate($user); //true
  15. Filterus – Filtering Library

    Filterus jest kolejną biblioteką do walidacji danych, ale pozwala wyłącznie na.. walidację danych i ich filtrację.

    $f = Filter::factory('string,max:5');
    $str = 'This is a test string'; 
    
    $f->validate($str); // false
    $f->filter($str); // 'This '
  16. Faker – Fake Data Generator

    Faker pozwala na generowanie przykładowych danych na potrzeby naszych projektów. Wykorzystany może być na przykład do wypełnienia naszej bazy danych przykładowymi danymi.

    // require the Faker autoloader
    require_once '/path/to/Faker/src/autoload.php';
    
    // use the factory to create a Faker\Generator instance
    $faker = Faker\\Factory::create();
    
    // generate data by accessing properties
    echo $faker->name; // 'Lucy Cechtelar';
    
    echo $faker->address;
      // "426 Jordy Lodge
      // Cartwrightshire, SC 88120-6700"
    
    echo $faker->text;
      // Sint velit eveniet. Rerum atque repellat voluptatem quia ...
  17. Mustache.php – Elegant Templating Library

    Mustache, to popularny silnik do tworzenia szablonów. Wyobraźcie sobie Smarty lub Twig, ale w nieco lżejszej formie.

    $m = new Mustache_Engine;
    echo $m->render('Hello {{planet}}', array('planet' => 'World!')); // "Hello World!"
  18. Gaufrette – File System Abstraction Layer

    Gaufrette, to pewien sposób abstrakcyjna warstwa do operowania naszym systemem plików. Pozwala na pracę z lokalnymi plikami, serwerami FTP, a nawet chmurą Amazon S3. Uwalnia pisanie projektów od niskopoziomowego myślenia w tym obszarze. Udostępnia także mechanizmy cachowania z wykorzystaniem pamięci.

    use Gaufrette\\Filesystem;
    use Gaufrette\\Adapter\\Ftp as FtpAdapter;
    use Gaufrette\\Adapter\\Local as LocalAdapter; 
    
    // Local files:
    $adapter = new LocalAdapter('/var/media'); 
    
    // Optionally use an FTP adapter:
    // $ftp = new FtpAdapter($path, $host, $username, $password, $port); 
    
    // Initialize the filesystem:
    $filesystem = new Filesystem($adapter); 
    
    // Use it: 
    
    $content = $filesystem->read('myFile');
    $content = 'Hello I am the new content';
    $filesystem->write('myFile', $content);
  19. Omnipay – Payment Processing Library

    Omnipay jest biblioteką, która jest w zasadzie klientem dla wielu systemów płatności. Wykorzystuje ona API udostępniane przez dostawców usług płatności by dać nam jednolity interfejs.

    use Omnipay\\CreditCard;
    use Omnipay\\GatewayFactory;
    
    $gateway = GatewayFactory::create('Stripe');
    $gateway->setApiKey('abc123');
    
    $formData = ['number' => '4111111111111111', 'expiryMonth' => 6, 'expiryYear' => 2016];
    $response = $gateway->purchase(['amount' => 1000, 'card' => $formData]);
    
    if ($response->isSuccessful()) {
        // payment was successful: update database
        print_r($response);
    } elseif ($response->isRedirect()) {
        // redirect to offsite payment gateway
        $response->redirect();
    } else {
        // payment failed: display message to customer
        exit($response->getMessage());
    }
  20. Upload – For Handling File Uploads

    Upload, to biblioteka, która – jak nie trudno się domyślić po nazwie – upraszcza ‘upload’ plików na serwer wraz z walidacją przesyłanych danych.

    $storage = new \\Upload\\Storage\\FileSystem('/path/to/directory');
    $file = new \\Upload\\File('foo', $storage);
    
    // Validate file upload
    $file->addValidations(array(
        // Ensure file is of type "image/png"
        new \\Upload\\Validation\\Mimetype('image/png'),
    
        // Ensure file is no larger than 5M (use "B", "K", M", or "G")
        new \\Upload\\Validation\\Size('5M')
    ));
    
    // Try to upload file
    try {
        // Success!
        $file->upload();
    } catch (\Exception $e) {
        // Fail!
        $errors = $file->getErrors();
    }
  21. HTMLPurifier – HTML XSS Protection

    HTMLPurifier, to biblioteka, która ochronić ma nas przed atakami typu XSS. Zapewnia ochronę poprzez filtrację przesyłanych danych z użyciem parserów oraz zdefiniowanych list szkodliwych wywołań.

    require_once '/path/to/HTMLPurifier.auto.php';
    
    $config = HTMLPurifier_Config::createDefault();
    $purifier = new HTMLPurifier($config);
    $clean_html = $purifier->purify($dirty_html);
  22. ColorJizz-PHP – Color Manipulation Library

    ColorJizz pozwala nam na przechodzenie pomiędzy różnymi formatami reprezentacji poszczególnych kolorów. Hex -> CMYK przestaje być już problemem i vice versa.

    use MischiefCollective\\ColorJizz\\Formats\\Hex;
    
    $red_hex = new Hex(0xFF0000);
    $red_cmyk = $hex->toCMYK();
    echo $red_cmyk; // 0,1,1,0
    
    echo Hex::fromString('red')->hue(-20)->greyscale(); // 555555
  23. PHP Geo – Geo Location Library

    PHP Geo, to biblioteka pozwalająca na obliczanie odległości pomiędzy dwoma punktami na mapie z bardzo dużą precyzją.

    use Location\\Coordinate;
    use Location\\Distance\\Vincenty;
    
    $coordinate1 = new Coordinate(19.820664, -155.468066); // Mauna Kea Summit
    $coordinate2 = new Coordinate(20.709722, -156.253333); // Haleakala Summit
    
    $calculator = new Vincenty();
    $distance = $calculator->getDistance($coordinate1, $coordinate2);
    // returns 128130.850 (meters; ≈128 kilometers)
  24. ShellWrap – Beautiful Shell Wrapper

    ShellWrap, to biblioteka będąca nakładką na komendy w systemie Linux / Unix. Pozwala ona na ich bezpośrednie wykonanie oraz pobranie rezultatu w kodzie PHP.

    require 'ShellWrap.php';
    use \\MrRio\\ShellWrap as sh; 
    
    // List all files in current dir
    echo sh::ls(); 
    
    // Checkout a branch in git
    sh::git('checkout', 'master'); 
    
    // You can also pipe the output of one command, into another
    // This downloads example.com through cURL, follows location, then pipes through grep to
    // filter for 'html'
    echo sh::grep('html', sh::curl('http://example.com', array(
        'location' => true
    ))); 
    
    // Touch a file to create it
    sh::touch('file.html'); 
    
    // Remove file
    sh::rm('file.html'); 
    
    // Remove file again (this fails, and throws an exception because the file doesn't exist) 
    
    try {
        sh::rm('file.html');
    } catch (Exception $e) {
        echo 'Caught failing sh::rm() call';
    }

Autoryzacja API – HMAC PHP

Autoryzacja API

Autoryzacja REST API jest czymś nieco innym niżeli autoryzacja użytkownika na stronie internetowej. Mechanizm  HTTP Basic Auth także tutaj nie pasuje. W przypadku naszego API nie tworzy się żadna sesja, która pozwalałaby na identyfikację konkretnego użytkownika / klienta korzystającego z dostępnych metod. Wykorzystujemy przecież protokół bezstanowy REST.

W minionym tygodniu zmierzyłem się z podobnym problemem w przypadku API, które piszę na potrzeby aplikacji mobilnej. Rozważane były tak naprawdę dwa rozwiązania: OAuth oraz wykorzystanie kluczy publicznych i prywatnych. Otwarty protokół OAuth wydawałby się idealnym rozwiązaniem. Okazuje się jednak, że jest kilka ALE, które komplikują jego implementację:

  • brak standaryzacji – Facebook i Twitter implementują w swoich API OAuth, ale jedno i drugie rozwiązanie różni się od siebie
  • skomplikowana implementacja po stronie serwera oraz aplikacji
  • spory narzut wydajnościowy

Finalne rozwiązanie oparte zostało o zasadę kluczy publicznych i prywatnych, ale zostało ono dostosowane do wymogów aplikacji mobilnej oraz możliwości jakie daje wewnętrzny framework. Chciałbym Wam dzisiaj jednak pokazać rozwiązanie oparte o metodę HMAC, która została zaimplementowana w języku PHP (>= 5.1.2) pod postacią funkcji hash_hmac.

Działanie HMAC

  1. stworzenie tak zwanego content hash przy użyciu private key, który znany jest tylko użytkownikowi (oraz systemowi)
  2. content hash przesyłany jest na serwer razem z public key
  3. serwer odczytuje public key i na jego podstawie szuka użytkownika, który pasuje do owego klucza , a następnie pobiera jego private key
  4. serwer używa pobranego private key do wykonania funkcji hash_hmac, która hashuje treść przesłaną w żądaniu HTTP i porównuje ją z content hash

Klucz publiczny i prywatny

By wygenerować public key i private key można posłużyć się kilkoma metodami. Poniżej pokażę dwie, chyba najprostsze, a zarazem skuteczne sposoby.

  1. Wykorzystanie OpenSSL
    $hash = hash('sha256', openssl_random_pseudo_bytes(32));

    OpenSSL nie jest domyślnym rozszerzeniem w PHP, dlatego też poniższa metoda powinna zastąpić wykorzystanie tej biblioteki.

  2. Wykorzystanie funkcji mt_rand:
    $hash = hash('sha256', mt_rand());

Oba przypadki jako funkcję hashującą wykosztują sha256, której obce są kolizje znane chociażby z funkcji skrótu jaką jest MD5.

Przykład wykorzystania HMAC w PHP

Czas na zabawę, czyli przejście do praktyki. Poniżej kod klienta i serwera, który może posłużyć jako przykład REST API.

Przykład wykorzystuje mechanizm cURL, który dostępny jest raczej w większości instalacji PHP. Zawsze można jednak użyć bardziej niskopoziomowej implementacji z socketami.

Kod klienta

<?php
	$publicKey  = '3441df0babc2a2dda551d7cd39fb235bc4e09cd1e4556bf261bb49188f548348';
	$privateKey = 'e249c439ed7697df2a4b045d97d4b9b7e1854c3ff8dd668c779013653913572e';
	$content    = json_encode(array(
		'test' => 'content'
	));

	$hash = hash_hmac('sha256', $content, $privateKey);

	$headers = array(
		'X-Public: '.$publicKey,
		'X-Hash: '.$hash
	);

	$ch = curl_init('http://test.localhost:8080/api-test/');
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $content);

	$result = curl_exec($ch);
	curl_close($ch);

	echo "RESULT\\n======\\n".print_r($result, true)."\\n\\n";
?>

Kod serwera

Po stronie serwera wykorzystam Slim Framework, który jest tak naprawdę mikroframeworkiem. Idealnie nadaje się on do małych aplikacji, które nie wymagają super mocy. Instalujemy Slim poprzez dodanie do swojego composer.json poniższych linijek:

{
    "require": {
        "slim/slim":"2.*"
    }
}

Composer zainstaluje nam cały framework w katalogu vendor/.

Więcej o Composer znajdziesz na: getcomposer.org

Nasz klient przesyłał do serwera nagłówki X-Public oraz X-Hash, które musimy pobrać po stronie serwera. Private key jest oczywiście hard-coded bezpośrednio w kodzie. W rzeczywistym systemie należałoby odpytać bazę danych i pobrać taką wartość z obiektu użytkownika.

<?php
require_once 'vendor/autoload.php';

$app = new \\Slim\\Slim();
$app->post('/', function() use ($app) {

    $request = $app->request();

    $publicHash  = $request->headers('X-Public');
    $contentHash = $request->headers('X-Hash');
    $privateKey  = 'e249c439ed7697df2a4b045d97d4b9b7e1854c3ff8dd668c779013653913572e';
    $content     = $request->getBody();

    $hash = hash_hmac('sha256', $content, $privateKey);

    if ($hash == $contentHash){
        echo "match!\n";
    }
});
?>

PS. Staram się by wpis miał przyjemną formę i był łatwy do czytania. Udało mi się? Okaże się tym samym kto dotarł do końca.

Zend Framework 2.0 w wersji stabilnej – nowa jakość?


Zend Framework 2.0 w wersji stabilnej - nowa jakość?

Dzień nowych wersji frameworków! Informowałem już o wydaniu kolejnej stabilnej wersji frameworka Symfony 2.1.0, a także dzisiaj wydany został jego główny konkurent, a mianowicie Zend Framework 2.0.

Zenda miałem okazję poznać już 3 lata temu. Były to moje pierwsze kroki z obiektowym programowaniem w PHP. Jak to początki, były niezwykle trudne. Wszystko było nowe. OOP, MVC i wiele innych technik, metodologii oraz koncepcji musiałem zrozumieć i dobrze sobie przyswoić. Do czasu pojawienia się Symfony2 był to mój ulubiony, a w zasadzie jedyny framework, który miałem okazję używać w swoich projektach. Na bazie Zenda napisałem nawet swój własny mini framework, który także posłużył mi do kilku projektów, które z powodzeniem działają do dnia dzisiejszego.

Po blisko 2 latach pracy, a 5 latach od wydania pierwszej wersji Zend Framework światło dzienne ujrzała właśnie jego druga wersja. Framework zaprojektowany i zbudowany został zupełnie od nowa. Całość miała być bardziej spójna, lepiej udokumentowana, zwiększająca produktywność i szybkość uruchamiania i działania aplikacji. Jeżeli rzeczywiście się to udało i moje testy to potwierdzą, to Symfony2 w końcu zyska godnego konkurenta.

Nowa wersja to konieczność napisania naszych aplikacji od zera. Nie ma możliwości migracji lub aktualizacji z pierwszej wersji do obecnej. Całości niestety trzeba nauczyć się od nowa.

Zend Framework 2.0 został podzielony na moduły, które są niezależnymi bytami, które tak samo jak w Symfony2 mogą być używane w wielu aplikacjach. Same moduły mogą być pakowane do archiwum phar, przez co jest to podobne rozwiązanie do użycia Composera. Moduł to także niezależna przestrzeń nazw, własne biblioteki, pliki szablonów, CSS, JavaScript, grafika. Budowanie z klocków staje się coraz bardziej powszechne i popularne.

Nowy Zend, to także nowa obsługa żądań (request). Opiera się ona teraz na zasadzie obsługi eventów, do których możemy się podpinać na różnych poziomach obsługi żądania.

PHP DI (dependency injection), czyli to co kocham w Symfony2. Pozwala na wstrzykiwanie zależności, które zastąpiły twarde odwołania.

Sporo zmienia się także w widokach. Akcje zwracać będą teraz obiekt ViewModel, który odpowiadać będzie za odwołanie się do konkretnego pliku szablonu, jego ustawienia oraz przekazanie zmiennych. Mamy tutaj także możliwość znaną z Twiga, który jest domyślnym systemem szablonów w Symfony2, a mianowicie dziedziczenia szablonów, która pozwala na osadzanie jednego szablonu w innym.

Całość jest rzeczywiście niezwykle spójna i dobrze przemyślana.

Pobieżnie przebrnąłem przez nową dokumentację, która opisuje jak korzystać z różnych standardowych komponentow, takich jak: Zend_Form, Zend_cache itd. Stworzony został także podręcznik, który demonstruje cały cykl tworzenia aplikacji w ZF2. Mamy tutaj do dyspozycji także przypadki użycia poszczególnych metod i zależności między komponentami. Ujednolicone zostały inferfejsy w całym obszarze Zend Framework 2.0, a także ustandaryzowane mechanizmy konfiguracji, za które odpowiada oddzielny komponent.

Zend Framework 2.0 to także praktyczny brak singletonów, które nie pozwalały, a w najmniejszym stopniu komplikowały rozszerzanie lub zmianę funkcjonalności. Komponenty możemy konfigurować pod względem tego, czy pozwalają one na rozszerzalność i współprace z innymi modułami.

Deweloperzy projektu postawili sobie za cel poprawę wydajności rzędu 200 do 300%. Czy im się to udało? Z pewnością będę się mógł przekonać już niedługo.

Nie miałem na razie czasu by poznać ZF2 lepiej, ale myślę, że zmieni się to już niedługo. Mam jednak nadzieję, że twórcy dobrze wykonali swoją pracę i odpowiednio wykorzystali czas poświęcony na budowę nowej wersji. Jeżeli macie już jakieś doświadczenia z ZF2, to oczywiście dajcie znać w komentarzach.


[1], [2]

Ewolucji ciąg dalszy – Symfony 2.1.0 zostało wydane!

Ewolucji ciąg dalszy - Symfony 2.1.0 zostało wydane!

Dzisiaj na oficjalnym blogu społeczności Symfony2 – główny mentor i twórca frameworka – Fabien Potencier ogłosił wszystkim ważną nowinę. Światło dzienne ujrzała nowa wersja frameworka Symfony (PHP) do zastosowań specjalnych. Gałąź 2.1.x projektu została ostatecznie uznana za stabilną.

Jak napisał sam FabienSymfony 2.1.0 to ewolucja projektu, który istnieje już od ponad 2 lat. Przez ten czas zdążył się on zadomowić we wielu środowiskach produkcyjnych i obsługuje on już znaczną ilość stron i aplikacji.

Wersja 2.1.0 frameworka to:

  • około 1,100 “pull request”
  • ponad 3,500 “commitów”
  • 6000 testów jednostkowych
  • 3000 nowych linii w dokumentacji

W nowej wersji dużą uwagę położono na poprawę stabilności działania oraz rozwój obecnych funkcjonalności. Całość działać ma także teraz nieco szybciej, a nowe możliwości mają pozwolić na jeszcze sprawniejszą pracę.

Główną nowością jest dla mnie Composer.  Mówiąc krótko, jest to narzędzie do zarządzania zależnościami napisane w PHP. Composer pozwala na zdefiniowanie bibliotek których wymaga projekt i w łatwy sposób pozwala na ich instalację, zarządzanie i aktualizacje.

Sam mam przyjemność uczyć się i używać Symfony2 od ponad pół roku. Jestem własnie na etapie pisania swojego 5 większego projektu. Każdemu kto pracuje w PHP lub interesuje się całym środowiskiem bardzo polecam rozpoczęcie przygody z frameworkiem. Ci zaś, którzy mieli szansę obcować z wersją 2.0.x mogą dokonać migracji do wersji 2.1.0 za pomocą oficjalnego poradnika.

Obecnie nad Symfony2 pracuje około 550 deweloperów, ale ilość testujących oraz prezentujących swoje opinie jest znacznie większa. Muszę się także przyznać, że we wielu dyskusjach na Githubie uczestniczyłem i niejednokrotnie miałem okazję pracować nad nową wersją frameworka.

Jak tylko zakończę pracę nad moim obecnym projektem, to z pewnością zainteresuję się wersją 2.1.0. Na razie daję sobie jednak trochę czasu.