Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu php Kanał ATOM (tag: php)

Autor wpisu: Aiv, dodany: 14.04.2011 22:36, tagi: php

Dostałem ostatnio sporo różnych stron do „odwirusowania”. Zamieszczę w kolejnych wpisać kilka kodów wraz z wstępnym odwróceniem niektórych zaciemnień. Doklejane na początku wszystkich plików PHP:Continue reading: Ataki na web aplikacje – cz. 1

Autor wpisu: Tomasz Kowalczyk, dodany: 12.04.2011 23:08, tagi: php

Dzisiejszy wpis po raz kolejny [poprzednio pisałem o flagach bitowych] zabiera nas w świat manipulacji niskopoziomowymi danymi, odzierając nieco PHP z jego wygodnej, wysokopoziomowej abstrakcji. Skupimy się w nim na wewnętrznym sposobie reprezentacji liczb i odczytywaniu informacji o wartościach ich kolejnych bajtów. Fotografia: Nic McPhee, CC-BY-SA. Wstęp: Liczby. Liczby w PHP można przedstawić na wiele [...]

Autor wpisu: Śpiechu, dodany: 10.04.2011 19:54, tagi: php, mysql

Tytuł zabrzmiał jak w Matriksie. Chodzi oczywiście o łączenie aplikacji PHP z bazą danych. Dzisiaj pokażę w jaki sposób w niewielkich projektach radzę sobie z przygotowaniem obiektu PDO do pracy z bazą danych. Trudno żebym w niewielkiej „stronce” zaprzęgał jakiś Zend Framework.

Napisałem sobie dawno temu klasę narzędziową do tworzenia obiektu PDO. Implementuję w niej wzorzec projektowy singleton, a więc mam pewność, że gdziekolwiek w kodzie żądam PDO, zawsze dostaję ten sam obiekt. Jeżeli chodzi o sam singleton, to na jego temat można przeczytać zarówno we Wzorcach Projektowych1 jak i w Design Patterns.2 Zresztą to w Googlu wyskoczy pierdylion wyników ;-)

Używanie klasy jest dziecinnie proste. Należy sobie jednorazowo przeedytować stałe klasy dotyczące połączenia z bazą, a następnie w kodzie wywoływać metodę DBHandler::getPDO()

Poniżej podaję kod klasy. Bierzcie i jedzcie ;-)

<?php
class DBHandlerException extends PDOException {
}
 
/**
 * @author Dawid 'Spiechu' Spiechowicz
 * @license see http://spiechu.pl/o-publikowanym-kodzie/
 */
class DBHandler {
 
  /**
   * Dane bazy danych
   */
  const DB_HOST = 'localhost';
  const DB_NAME = 'nazwa bazy';
  const DB_USER = 'nazwa usera';
  const DB_PASS = 'haslo';
 
  /**
   * Sterownik bazy danych
   */
  const DB_DRIVER = 'mysql';
 
  /**
   * Czy wyswietlac dokladne komunikaty bledow
   */
  const DEBUG_MODE = true;
 
  /**
   * @var PDO singleton PDO
   */
  private static $pdo = null;
 
  /**
   * Zwraca singleton PDO lub wyswietla komunikat bledu i zwraca null.
   * @return PDO|null
   */
  public static function getPDO() {
    try {
      if (self::$pdo === null) {
        self::$pdo = self::createPDO();
      }
      return self::$pdo;
    }
    catch (DBHandlerException $e) {
      echo $e->getMessage();
      return null;
    }
  }
 
  /**
   * @return PDO zwraca nowa instancje PDO
   * @throws DBHandlerException
   */
  private static function createPDO() {
    if (!extension_loaded('PDO')) throw new DBHandlerException('Brak modulu PDO');
    try {
      $pdo = new PDO(
         self::DB_DRIVER . ':host=' . self::DB_HOST . ';dbname=' . self::DB_NAME, 
         self::DB_USER, 
         self::DB_PASS,
         array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
      $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
      return $pdo;
    }
    catch(PDOException $e) {
      if (self::DEBUG_MODE == true) {
        throw new DBHandlerException("Blad bazy danych : {$e->getMessage()}");
      }
      else {
        throw new DBHandlerException('Blad bazy danych');
      }
    }
  }
 
  /**
   * Zapobiega tworzeniu obiektu.
   */
  private function __construct() {
    throw new Exception('Nie mozna stworzyc tego obiektu!');
  }
 
  /**
   * Zapobiega klonowaniu obiektu.
   */
  private function __clone() {
    throw new Exception('Nie mozna klonowac tego obiektu!');
  }
}

Powyżej widać kilka sztuczek. Przede wszystkim konstruktor ma zasięg prywatny, co zapobiega stworzeniu instancji klasy z zewnątrz. Mało tego, próba wywołania go z wnętrza klasy spowoduje wyrzucenie wyjątku. To samo z metodą __clone().

Przy konfiguracji obiektu PDO ustawiam tryb błędów na wyjątki, które wyłapuję i w zależności od ustawionej stałej DEBUG_MODE wyświetlam komunikaty błędów PDO lub nie. Fragment $pdo->query('SET NAMES utf8') ustawia kodowanie znaków na Unicode. Niestety nie znalazłem lepszej metody. Rezultaty zapytań domyślnie będą dostępne w postaci tablicy asocjacyjnej.

  1. E. Gamma (i in.) : Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku. Gliwice : Helion, 2010, s. 130–136.
  2. E. Freeman (i in.) : Head First Design Patterns. Gliwice : Helion, 2005, s. 197–216.

Autor wpisu: singles, dodany: 09.04.2011 23:18, tagi: php, zend_framework, doctrine

Zend Framework składa się z wielu komponentów, a jednym z nich jest ten odpowiedzialny za komunikację z bazą danych – Zend_Db. Jednakże, celem tego wpisu nie jest opisywanie Zend_Db – to zostało zrobione już w dokumentacji. Celem tego wpisu jest wyrażenie mojej opinii na temat tego co mi się w Zend_Db podoba, a co nie – jest to oczywiście wpis czysto subiektywny. Traktuje ten wpis także jako przyczynek do dyskusji na temat, czy Zend_Db jest naprawdę tak złym komponentem, za jakiego ma go wielu programistów PHP – m.in patrz komentarze do wpisu u batmana. Chciałbym się także odnieść do podanych tam „zarzutów”. Niektóre z przedstawionych przeze mnie zalet bądź wad mogą Wam się wydawać śmieszne bądź banalne, ale kilka takich rzeczy połączonych ze sobą wpływa na wygodę korzystania z danego rozwiązania. Tak więc zaczynamy!

Zalety

Oparty głównie na PDO

Coraz więcej frameworków idzie tą drogą, co uważam za niewątpliwy plus. PDO de facto jest standardem w PHP i bardzo dobrze, że twórcy zdecydowanej większości frameworków się tego trzymają. Dzięki temu, kiedy przychodzi potrzeba napisania bardziej zaawansowanego zapytania możemy skorzystać ze znanych nam metod i oczekiwać tego samego, czego oczekiwaliśmy korzystając z czystego PDO.

Wygoda podczas stosowania klauzuli WHERE

Kwestia oczywiście w pełni subiektywna. Mam na myśli korzystanie głównie z metody fetchAll i automatycznego bindowania parametrów jako odpowiedni typ danych. Przykład:

$model->fetchAll(array(
    'item_id = ?' => 12, //bind as PDO::PARAM_INT, cast it using (string)12 to automatically bind as PDO::PARAM_STR
    'name = ?' => 'foobar', //PDO::PARAM_STR
    'category_id IN (?)' => arrray(1, 2, 4, 7) // bind each array element separately as PDO::PARAM_INT -> gives you: category_id IN (?, ?, ?, ?)
));

Stosunkowo mała liczba plików

Zend_Db w obecnej wersji frameworka (1.11.5) waży ok. 600KB i mieści się w 53 plikach – z czego 17 z nich to puste klasy wyjątków Exception.php. Dla porównania – Doctrine2 DBAL (czyli sama warstwa abstrakcji bazy danych) to 144 pliki, w tym 10 od wyjątków. Oczywiście, w obu przypadkach można te liczby jeszcze bardziej zmniejszyć, wyrzucając niepotrzebne adaptery.

ActiveRecord

Podoba mi się fakt, że mogę zdefiniować własne metody odnoszące się bezpośrednio do rekordu O ile twórcy ZF piszą o Zend_Db_Table_Row jako o implementacji Row Data Gateway, jednakże z punktu widzenia używającego go programisty niedaleko mu do ActiveRecord. Mam na myśli możliwość definiowania własnych metod odnoszących się do konkretnego rekordu. Banalny przykład:

// /application/models/Product.php
class Model_Product extends Zend_Db_Table_Abstract
{
    protected $_name = 'product';
    protected $_rowClass= 'Model_ProductRow'; //use Model_ProductRow instead Zend_Db_Table_Row
}
 
// application/models/ProductRow.php
class Model_ProductRow extends Zend_Db_Table_Row_Abstract
{
    public function getPriceWithTax()
    {
        return $this->price * 0.23; //where price is column in database defining price without VAT tax rate
    }
}

To samo tyczy się obiektów kolekcji – w przypadku Zend Frameworka dziedziczących po klasie Zend_Db_Table_Rowset. Mogę ustawić własną klasę, gdzie zaimplementuje potrzebne mi metody kolekcji.

Wspracie dla interfejsów ArrayAccess oraz Iterable w przypadku obiektów i kolekcji

Kolejna rzecz, która wpływa na wygodę. Mogę odnosić się do właściwości obiektu używając notacji tablicowej. Mogę także iterować po obiekcie kolekcji używając foreach, bez wykonywania za każdym razem toArray().

Zend_Db_Select == QueryBuilder

O ile na początku korzystanie z Zend_Db_Select sprawiało mi sporą trudność (moim kolegom z zespołu także), tak po pewnym czasie jest to dla nas natywny sposób pisania bardziej skomplikowanych zapytań podczas korzystania z ZF. Właśnie dzięki jego obiektowej naturze i wykorzystaniu fluent interface mogę dowolnie łączyć warunki zapytania bądź zmieniać je korzystając z metody reset(). Przykład:

class Model_Foo extends Zend_Db_Table_Abstract
{
    private $_name = 'foo';
 
    // use fluent interface and add condition
    public function fetchWithLeftJoinWhereBarIsntNull()
    {
        $select = $this->_getBaseSelect();
        $select->where('bar IS NOT NULL');
        return parent::fetchAll();
    }
 
    // user reset() and remove LEFT JOIN
    public function fetchWithoutLeftJoin()
    {
        $select = $this->_getBaseSelect();
        $select->reset(Zend_Db_Select::LEFT_JOIN);
        return parent::fetchAll($select);
    }
 
    private function _getBaseSelect()
    {
        $select = $this->select();
        $select->from('table1')
               ->setIntegrityCheck(false) // allow to join another tables
               ->joinInner('table2', 'table1.id = table2.table1_id')
               ->joinLeft('table3', 'table1.id = table3.table1_id');
 
        return $select;
    }
}

Wady

Brak nazwanych relacji

O używaniu relacji w Zend Framework pisał już batman we wpisie Zend_Db i relacje. Jednak mi nie odpowiada fakt, że korzystając domyślnej metody opisywanej praktycznie wszędzie muszę odnosić się do rekordów podrzędnych po nazwie klasy, a nie nazwie zdefiniowanej relacji. Chciałbym, abym mógł napisać tak:

$params = $userRow->findDependentRowset('UserParamsRelationWithCustomName'); //instead of specifying model class

Nazwa klasy zawsze może się zmienić, a to ułatwia refactoring. Dodatkowo, chciałbym móc w ramach relacji zdefiniować dodatkowe parametry dotyczące połączenia – nie tylko kolumnę, po jakiej ma się ono odbyć, ale także warunki do kolumn dodatkowych. Istnieje co prawda Zend_Db_Table_Definition, jednak rozwiązanie to ma dwie wady. Po pierwsze wymaga osobnej definicji dla każdej klasy modelu, co jest niewygodne. Po drugie, nadal nie pozwala na definiowanie dodatkowych warunków dla połączeń.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Tomasz Kowalczyk, dodany: 08.04.2011 18:46, tagi: symfony, framework, php

Realizuję w tym momencie bardzo przyjemny projekt - przyjemny dlatego, że powstaje "od zera" i mam możliwość wyboru narzędzi, w jakich będę go tworzył. Chciałem spróbować wykorzystać do tego testowany od pewnego czasu framework Symfony2, jednak idąc za radą udzieloną mi przez batmana podczas konferencji 4Developers wracam na "stare śmieci", czyli stabilną wersję symfony. Jak [...]

Autor wpisu: sokzzuka, dodany: 08.04.2011 13:50, tagi: php

Pewnie kilka razy w życiu każdy z nas zetknął się albo i też używał operatora trójargumentowego znanego też jako „ternary operator” bądź „operator Elvisa” (skrócona wersja w Groovym, ciekawe kto wymyślił tą nazwę). Jest to skrócona składnia dla prostego przypadku „if” i wygląda on mniej więcej tak:

$foo = 5;
$bar = ($foo==5) ? "Foo równa się 5" : "Foo nie równa się 5";
echo $bar;

Najczęściej chyba operatora Elvisa używa się by sprawdzić czy jakaś zmienna jest ustawiona, czyli:

$bar = (isset($foo)) ? $foo : 666;
echo $bar; //666

Ostatnio na grupie php.internals toczy się dyskusja czy aby nie uczynić drugiego przypadku domyślnym tj:

$bar = $foo ? $foo: 666;
echo $bar; //666

Dzięki takiej zmianie jest krócej o te kilka uderzeń w klawiaturę by ustawić domyślna wartość jakiej zmiennej. Jest zarówno wielu zwolenników jak i przeciwników tej zmiany. Najważniejsze jednak jest, że Rasmus Lerdorf (BDFL php) uważa, że nie należy zmieniać już istniejącego zachowania ponieważ zrywa to wsteczną kompatybilność kodu. Wobec tego, zaproponowany został kolejny operator w postaci „??” mający to samo zastosowanie co poprzedni oprócz tego, że sprawdza tylko, czy jakaś wartość istnieje:

$value = $a[$key] ?? : 'Not set';

Niektórych też już poniosła fantazja i zaproponowali wersję:

$value = 'Not set' unless $a['key'];

Ciekaw jestem, czy często używacie operatora trójargumentowego, oraz jakie macie zdanie nt. ww. propozycji ?

Autor wpisu: batman, dodany: 06.04.2011 09:00, tagi: php

Czwartego kwietnia 2011 roku odbyła się trzecia edycja konferencji 4Developers. Podobnie jak w poprzednich latach, konferencja została podzielona na cztery równoległe ścieżki tematyczne. W tym roku były to Java, Zarządzanie projektami IT, Wydajność i skalowalność oraz PHP. Nowością w stosunku do poprzednich edycji były panele dyskusyjne, pozwalające wymienić się informacjami na tematy takie jak Function Point Analysis, Java, SQL vs NoSQL oraz systemy kontroli wersji. Nie zabrakło również ciekawych konkursów, konsol do gier (Xbox + Kinect oraz PS3 + Move), smacznego obiadu oraz pięknych hostess.

Konferencja rozpoczęła się od półgodzinnego poślizgu spowodowanego “drobnymi problemami technicznymi” związanymi z dźwiękiem oraz obrazem. Po uporaniu się z technikaliami, 4Developers ruszyło z kopyta.

Z racji wykonywanego przeze mnie zawodu oraz “okołozawodowych zainteresowań”, wymieszałem wykłady ze ścieżek PHP oraz Wydajność i skalowalność. Podobnie jak w przypadku poprzedniej edycji i tym razem pojawił się problem nakładania się na siebie interesujących tematów, przez co na koniec dnia pozostał niedosyt. Obejrzenie slajdów, a nawet nagranego wykładu, nie jest tym samym, co uczestnictwo w wykładzie. Poza tym wygospodarowanie kilku godzin na obejrzenie pominiętego materiału nie należy w moim przypadku do zadań prostych.

Jak wrażenia?

Po wybranych przeze mnie ścieżkach spodziewałem się wykładów stricte technicznych, na których prezentowane będą niezliczone ilości kodu przeplatane ciekawostkami dotyczącymi omawianej technologii. Okazało się, że w zdecydowanej większości były to długie opowieści, okraszone niewielką ilością przykładów i w niektórych momentach danymi statystycznymi. Odnoszę wrażenie, iż prezentowane informacje były wtórne i nawet jeśli z jakieś technologii nie korzystałem, to po wysłuchaniu wykładu na jej temat, wiem niewiele więcej. Najbardziej rozczarowałem się wykładem na temat drugiej wersji Zend Frameworka. Poza jednym skąpym przykładem i przewidywaną datą wydania (beta około maja, a wersja stabilna pod koniec roku), wkład wyglądał jak odczyt milestone’ów z zendowej wiki.

In plus mogę zaliczyć możliwość spotkania na żywo z Radkiem Benkel oraz Tomkiem Kowalczykiem. Niestety z racji rychłego wyjazdu oraz bieżących spraw, zabrakło czasu na dłuższą rozmowę. Mam nadzieję, że przy następnej okazji czasu będzie znacznie więcej.

Co dalej?

Na trzecią edycję 4Developers zapisałem się od razu po odebraniu maila z informacją o rozpoczęciu zapisów. Zrobiłem to w ciemno, ponieważ nie wiedziałem jakie będą ścieżki, a tym bardziej tematy wykładów. Jeśli zdecyduję się na następną edycję, to nie wcześniej niż w momencie, gdy agenda będzie uzupełniona.

Podsumowując. Konferencja 4Developers 2011 nie spełniła moich oczekiwań, co nie oznacza, że była kiepska. Odnoszę wrażenie, iż po pewnym czasie “w branży”, człowiek poznaje na tyle dużo technologii (choćby z nazwy i lektury strony about danej technologii), że ciężko jest go czymś zaskoczyć. Pozostaje mieć nadzieję, iż kolejna edycja konferencji będzie mniej przegadana, a bardziej techniczna.

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.