Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: singles, dodany: 29.10.2011 18:39, tagi: php

Niedawno natrafiłem na problem polegający na konieczności wybrania z istniejącego pliku XML kilku losowych elementów. Tzn, dla przykładu – mamy plik z 50 pytaniami (nie wnikam w powody, dla których są one właśnie w XML, tylko uznaję to za pewnik), a przy każdym odświeżeniu strony do klienta ma trafiać zestaw kilku innych, losowo wylosowanych pytań. Nie jest to problem spotykany często, mam jednak nadzieję, że przedstawione tutaj rozwiązanie komuś się przyda.

Problem

Przypuśćmy, że mamy nastepujacy plik (mocno uproszczony przykład):

<?xml version="1.0" encoding="UTF-8"?>
<questions>
    <question>
        <subject>Question 1</subject>
        <answer1>Answer 1</answer1>
        <answer2>Answer 2</answer2>
    <question>
 <!-- etc -->
</questions>

Jak wspomniałem wcześniej, zależy nam każdorazowym wybraniu innego zestawu pytań i zwróceniu ich w postaci prawidłowo sformatowanego dokumentu XML.

Możliwe rozwiązania

Po przejrzeniu w sieci informacji na ten temat, najcześciej natrafiałem na podejście pt. „Zamień XMLa na arraya, wylosuj klucze, i z powrotem stwórz z tego XMLa.”

Niestety, w PHP (bez zastosowania dodatkowych bibliotek czy funkcji) nie jest to rzecz, którą da się załatwić w kilku linijkach. Dodatkowo, dochodzi tutaj kwestia dwukrotnej konwersji.

Podejście drugie polega na wykorzystaniu wyrażeń regularnych. Istnieje jednak dość powszczechna zasada, aby do parsowania HTMLa czy też XMLa nie używać wyrażeń regularnych, ponieważ nie mamy pewności czy dokument został sformatowany prawidłowo.

Możemy także wykorzystać XPath, wybierając po jednym elemencie o indeksie z zakresu (1 – liczba potenacjalnych elementów), pamiętając o tym, że elementy nie mogą się powtórzyć.

Jednakże, podejście drugie i trzecie ma to do siebie, że do wylosowanych elementów musimy dodać otaczającą ją resztę dokumentu, która nie zawsze może być tak uproszczona jak w naszym przykładze.

DOM na ratunek

A gdyby zamiast wybierania losowych elementów, które później zwracamy w postaci nowo utworzonego dokumentu XML, usuwać węzły z oryginalnego dokumentu? Wynikowo otrzymamy zestaw danych w tym samym formacie, bez konieczności dbania o resztę struktury dokumentu czy też parsowania.

W celu wykonania zadania, posłużyłem się klasą DOMDocument (domyślnie dostępna w PHP), która udostępnia zestaw metod znanych z JavaScriptu jako części DOM API. Poniżej przedstawiam kawałek kodu wykorzystujący wspomniane przeze mnie podejście.

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

Autor wpisu: Łukasz Socha, dodany: 27.10.2011 16:13, tagi: oop, php, mvc

pobierz w .pdf(przeznaczone do wydruku)

W drugiej części artykułu o wzorcu MVC stworzymy część skryptu, odpowiedzialną za obsługę kategorii.

Tworzymy kontroler kategorii

Na początek stwórzmy plik index.php w głównym katalogu:

<?php
include 'controller/categories.php';
if($_GET['task']=='categories') {
    $ob = new CategoriesController();
    $ob->$_GET['action']();
}

Na podstawie zmiennej $_GET['task'] tworzony jest odpowiedni obiekt kontrolera (w tym wypadku CategoriesController). Zmienna $_GET['action'] określa z kolei akcję kontrolera.

Co robi kontroler? Na podstawie przekazanych wartości zmiennych (z adresu lub pól formularza) „wybiera” odpowiednią akcję skryptu oraz inicjuje odpowiednie modele i widoki. Kontroler nie powinien obrabiać danych. Ma on za zadanie tylko wywoływać odpowiednie reakcje logiki aplikacji oraz widoku odpowiedzialnego za wyświetlanie informacji. Przyjrzyjmy się plikowi controller/categories.php:

<?php
/**
 * @author Łukasz Socha <kontakt@lukasz-socha.pl>
 * @version: 1.0
 * @license http://www.gnu.org/copyleft/lesser.html
 */

include 'controller/controller.php';

class CategoriesController extends Controller{
    public function index() {
        $view=$this->loadView('categories');
        $view->index();
    }
    public function add() {
        $view=$this->loadView('categories');
        $view->add();
    }
    public function insert() {
        $model=$this->loadModel('categories');
        $model->insert(&$_POST);
        $this->redirect('?task=categories&action=index');
    }
    public function delete() {
        $model=$this->loadModel('categories');
        $model->delete($_GET['id']);;
        $this->redirect('?task=categories&action=index');
    }
}

Przeanalizujmy reakcje dla następujących adresów URL:

  • ?task=categories&action=index – zostanie wywołana metoda index(), która inicjuje obiekt widoku categories, następnie zostaje wywołana metoda index()
  • ?task=categories&action=add – zostanie wywołana metoda add(), która inicjuje obiekt widoku categories, następnie zostaje wywołana metoda add()
  • ?task=categories&action=insert – zostanie wywołana metoda insert(), która inicjuje obiekt modelu categories, następnie zostaje wywołana metoda insert()
  • ?task=categories&action=delete – zostanie wywołana metoda delete(), która inicjuje obiekt modelu categories, następnie zostaje wywołana metoda delete()

Mamy już utworzony kontroler. Przejdźmy teraz do modelu.

Tworzymy model kategorii

Model jest najbardziej istotnym elementem we wzorcu MVC – to on jest odpowiedzialny za logikę aplikacji. Ma za zadanie pobieranie/edycję danych z bazy danych (lub innych źródeł) oraz przetworzenie ich według wymagań skryptu, np: poddać filtracji, wykonać obliczenia itp.

Przeanalizujmy plik model/categories.php:

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

Autor wpisu: widmogrod, dodany: 27.10.2011 08:25, tagi: php

Właśnie ochłonąłem po PHPCon2011 i chcę wam napisać co się działo… bo się działo!!

Konferencja zgromadziła w jednym miejscu blisko 180 programistów PHP. Przez te trzy dni przeprowadzono bardzo wiele ciekawych prezentacji. Między prelegentami były takie takie osoby jak Derick Rethans, twórca Xdebug, który opowiedział o profilowaniu aplikacji; David Coallier, prezes PHP PEAR Group i współtwórca trzonu PHP – przedstawił informację o przyszłości PHP; Z prelegentów z polski można wymienić chociażby Krzyśka Szłapińskiego z Allegro, który opowiedział o architekturze Allegro (Lista wszystkich prezentacji jest dostępna pod tym adresem: http://phpcon.pl/2011/agenda).

Ogromna ilość prezentacji świetny klimat spowodował że rozmowy kuluarowe trwały do białego rana. Bardzo ciekawym elementem pierwszego dnia było lighting talking. Każdy z gości mógł bez wcześniejszej rejestracji wystąpić przed wszystkimi z krótką prezentacją. Dlatego korzystając z okazji zabrałem głos i przedstawiłem krótką historię rozwoju Zend Framework 2 :) (niedługo artykuł na ten temat ukaże się na blogu).

Jedynym elementem, z całek konferencji, do którego można by mieć zarzut to brak dłuższych przerw pomiędzy prezentacjami. Prelekcje były usiane tak gęsto mi osobiście zabrakło czasu na odpoczynek czy nawet dyskusję na temat poszczególnych tematów.

Wszystkim którzy byli dziękuję za świetną imprezę! tych których zabrakło lub nie byli szczerze zapraszam na przyszły rok! konferencja jest niesamowita :)

Autor wpisu: Piotr Śliwa, dodany: 26.10.2011 23:47, tagi: php

Często jest tak, że wydajność nie jest naszym absolutnym priorytetem, ale nie raz staje się ważna gdy faktycznie pod tym względem popełniliśmy zbyt wiele zaniedbań. Równie często zdarza się sytuacja, w której jednym z kluczowych wymagań niefunkcjonalnych jest właśnie odpowiednia wydajność. Optymalizacje można dokonywać po stronie serwerów (architektura, konfiguracja serwera, bazy danych itp.) oraz po stronie samej aplikacji (keszowanie dodatkowych elementów, trzymanie cache w pamięci operacyjnej, refaktoryzacja i optymalizacja kodu). W tym krótkim wpisie skoncentruję się na optymalizacji na poziomie kodu aplikacji.

W aplikacji zawsze jest jakieś wąskie gardło, kod który daje największy narzut pod względem czasu wykonania lub zużywania pamięci. Taki kod należy znaleźć i zoptymalizować. Ale w jaki sposób szukać? Należy użyć narzędzia profilującego, takie narzędzie dostarcza nam np. biblioteka xdebug lub Zend Server. Aby zmusić xdebug do zbierania danych na temat czasów wykonywania poszczególnych funkcji w odpalonym skrypcie, należy w php.ini ustawić dyrektywę "xdebug.profiler_enable" na 1. Dyrektywa "xdebug.profiler_output_dir" wskazuje na katalog, w którym te dane będą zbierane. Ok, mamy dane, ale jak je przeglądać? Do przeglądania danych zebranych przez xdebug można wykorzystać np. Webgrind.

Zend Server dostarcza nam narzędzie profilujące, które integruje się z Zend Studio (podobna funkcjonalność do xdebug ale ładniejszy interfejs ;)) oraz Code Tracer, który ma bardzo potężne możliwości i dobrze się sprawdza w analizie kodu pod kątem zużywania pamięci.

Oczywistymi kandydatami na wąskie gardło są funkcje, których wykonanie w sumie zajmuje relatywnie dużo czasu. Gdy feralny kod jest wywoływany sporo razy powinniśmy w miarę możliwości ograniczyć liczbę wywołań oraz ewentualnie dokonać optymalizacji w tym kodzie. Gdy liczba wywołań jest niewielka to pozostaje nam jedynie optymalizacja kodu. Na optymalizację mogą składać się niewielkie kroki, takie jak: zmiana rodzaju pętli (np. z foreach na for), jednokrotne wykonywanie obliczeń i przypisywanie wyniku do zmiennej lokalnej zamiast wielokrotnego wyznaczania tej wartości, zmiana struktury danych, wykorzystanie wydajniejszych wbudowanych mechanizmów języka. Dzięki takim kosmetycznym poprawkom możemy zyskać stosunkowo niedużo. Niekiedy nieoptymalny kod nie poprawimy tymi drobnymi krokami i należy go przepisać na nowo, używając innego, wydajniejszego algorytmu.

Profilując projekt nad którym pracuję dowiedziałem się, że najczęściej wywoływaną funkcją (a zarazem będącą w absolutnej czołówce pod względem czasu wykonywania) jest metoda Doctrine_Configurable::getAttribute() (Doctrine w wersji 1.1, która już nie jest dostępna).

Kod metody:

[PHP]
  1. public function getAttribute($attribute)
  2. {
  3. if (is_string($attribute)) {
  4. $upper = strtoupper($attribute);
  5.  
  6. $const = 'Doctrine::ATTR_' . $upper;
  7.  
  8. if (defined($const)) {
  9. $attribute = constant($const);
  10. $this->_state = $attribute;
  11. } else {
  12. throw new Doctrine_Exception('Unknown attribute: "' . $attribute . '"');
  13. }
  14. }
  15.  
  16. $attribute = (int) $attribute;
  17.  
  18. if ($attribute < 0) {
  19. throw new Doctrine_Exception('Unknown attribute.');
  20. }
  21.  
  22. if (isset($this->attributes[$attribute])) {
  23. return $this->attributes[$attribute];
  24. }
  25.  
  26. if ($this->parent) {
  27. return $this->parent->getAttribute($attribute);
  28. }
  29. return null;
  30. }

Jest ona niepozorna, bo cóż może robić? Zwraca wartość atrybutu, ale po drodze konwertując nazwę atrybutu z ciągu znaków do liczby całkowitej (wykorzystując stałe klasowe) i wywołując rekurencyjnie tą samą metodę rodzica (Chain of responsibility), jeśli atrybut nie jest ustawiony. Metoda ta jest wywoływana strasznie wiele razy (m. in. z powodu rekurencyjnych wywołań), dlatego też ma znaczący wpływ na wydajność. Nasuwają mi się dwie mikro optymalizacje (oprócz makro optymalizacji mającej na celu wyrzucenia tego typu hierarchicznej konfiguracji, co zresztą zostało poczynione w Doctrine 2 ;)) mające na celu optymalizację kodu oraz ograniczenie liczby wywołań:

  • przyjmowanie jako argument tej metody tylko wartości stałych klasowych (brak wsparcia dla nazw atrybutów jako ciąg znaków, który później jest konwertowany)
  • ustawianie wartości atrybutu wartościom zwróconą przez rodzica, jeśli atrybut nie jest ustawiony (w celu ograniczenia liczby wywołań rekurencyjnych)

Pierwsza wspomniana modyfikacja została wprowadzona w wersji Doctrine 1.2 (link do źródła klasy), ale druga nie (być może ze względu na to, że mogła uszkodzić kod).

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

Autor wpisu: Kamil Adryjanek, dodany: 26.10.2011 21:43, tagi: symfony, php

Default symfony 1.4 file validator can validate only some basic file attributes. Sometimes we need more, for example we want to prevent small images from being uploaded. Code below presents my custom sfImageFileValidator which allows you to apply some dimensions constraints to image file validation, e.g. max_height or max_width.

&lt;/p&gt;<br />
&lt;p&gt;&amp;lt;?php&lt;/p&gt;<br />
&lt;p&gt;/**&lt;br /&gt;<br />
 * sfImageFileValidator allows you to apply constraints to image file upload, it extend the sfFileValidator functions.&lt;br /&gt;<br />
 *&lt;br /&gt;<br />
 * @author     Kamil Adryjanek &amp;lt;kamil.adryjanek@gmail.com&amp;gt;&lt;br /&gt;<br />
 */&lt;br /&gt;<br />
class sfImageFileValidator extends sfValidatorFile&lt;br /&gt;<br />
{&lt;br /&gt;<br />
    /**&lt;br /&gt;<br />
     * Configures the current validator.&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     * Available options:&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     *  * max_height:             The maximum file height in pixels&lt;br /&gt;<br />
     *  * min_height:             The minimum file height in pixels&lt;br /&gt;<br />
     *  * max_width:              The maximum file width in pixels&lt;br /&gt;<br />
     *  * min_width:              The minimum file width in pixels&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     * Available error codes:&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     *  * max_height&lt;br /&gt;<br />
     *  * min_height&lt;br /&gt;<br />
     *  * max_width&lt;br /&gt;<br />
     *  * min_width&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     * @param array $options   An array of options&lt;br /&gt;<br />
     * @param array $messages  An array of error messages&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     * @see sfValidatorBase&lt;br /&gt;<br />
     */&lt;br /&gt;<br />
    public function configure($options = array(), $messages = array())&lt;br /&gt;<br />
    {&lt;br /&gt;<br />
        parent::configure($options, $messages);&lt;/p&gt;<br />
&lt;p&gt;        $this-&amp;gt;addOption(&amp;amp;#039;max_height&amp;amp;#039;);&lt;br /&gt;<br />
        $this-&amp;gt;addOption(&amp;amp;#039;min_height&amp;amp;#039;);&lt;br /&gt;<br />
        $this-&amp;gt;addOption(&amp;amp;#039;max_width&amp;amp;#039;);&lt;br /&gt;<br />
        $this-&amp;gt;addOption(&amp;amp;#039;min_width&amp;amp;#039;);&lt;/p&gt;<br />
&lt;p&gt;        $this-&amp;gt;addMessage(&amp;amp;#039;max_height&amp;amp;#039;, &amp;amp;#039;File is too high (maximum is %max_height% pixels, %height% given).&amp;amp;#039;);&lt;br /&gt;<br />
        $this-&amp;gt;addMessage(&amp;amp;#039;min_height&amp;amp;#039;, &amp;amp;#039;File is too short (minimum is %min_height% pixels, %height% given).&amp;amp;#039;);&lt;br /&gt;<br />
        $this-&amp;gt;addMessage(&amp;amp;#039;max_width&amp;amp;#039;, &amp;amp;#039;File is too wide (maximum is %max_width% pixels, %width% given).&amp;amp;#039;);&lt;br /&gt;<br />
        $this-&amp;gt;addMessage(&amp;amp;#039;min_width&amp;amp;#039;, &amp;amp;#039;File is too thin (minimum is %min_width% pixels, %width% given).&amp;amp;#039;);&lt;br /&gt;<br />
    }&lt;/p&gt;<br />
&lt;p&gt;    /**&lt;br /&gt;<br />
     * This validator always returns a sfValidatedFile object.&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     * The input value must be an array with the following keys:&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     *  * tmp_name: The absolute temporary path to the file&lt;br /&gt;<br />
     *  * name:     &lt;div style=&quot;display: none&quot;&gt;&lt;a href='http://viagralowestprice.com/'&gt;buy viagra uk&lt;/a&gt;&lt;/div&gt; The original file name (optional)&lt;br /&gt;<br />
     *  * type:     The file content type (optional)&lt;br /&gt;<br />
     *  * error:    The error code (optional)&lt;br /&gt;<br />
     *  * size:     The file size in bytes (optional)&lt;br /&gt;<br />
     *&lt;br /&gt;<br />
     * @see sfValidatorBase&lt;br /&gt;<br />
     */&lt;br /&gt;<br />
    protected function doClean($value)&lt;br /&gt;<br />
    {&lt;br /&gt;<br />
        if (!is_array($value) || !isset($value[&amp;amp;#039;tmp_name&amp;amp;#039;])) {&lt;br /&gt;<br />
            throw new sfValidatorError($this, &amp;amp;#039;invalid&amp;amp;#039;, array(&amp;amp;#039;value&amp;amp;#039; =&amp;gt; (string) $value));&lt;br /&gt;<br />
        }&lt;/p&gt;<br />
&lt;p&gt;        // get image dimensions&lt;br /&gt;<br />
        list($wi&amp;lt;div style=&amp;quot;display: none&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;http://isidoreguest.devhub.com/blog/1440105-how-do-you-know-when-your-sons-father-wants-you-back/&amp;quot;&amp;gt;How To Make Ex Want You Back Leave The Girl&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;dth, $height) = getimagesize($value[&amp;amp;#039;tmp_name&amp;amp;#039;]);&lt;/p&gt;<br />
&lt;p&gt;        // check file height&lt;br /&gt;<br />
        if ($this-&amp;gt;hasOption(&amp;amp;#039;max_height&amp;amp;#039;) &amp;amp;&amp;amp; $this-&amp;gt;getOption(&amp;amp;#039;max_height&amp;amp;#039;) &amp;lt; (int) $height) {&lt;br /&gt;<br />
            throw new sfValidatorError($this, &amp;amp;#039;max_height&amp;amp;#039;, array(&amp;amp;#039;max_height&amp;amp;#039; =&amp;gt; $this-&amp;gt;getOption(&amp;amp;#039;max_height&amp;amp;#039;), &amp;amp;#039;height&amp;amp;#039; =&amp;gt; (int) $height));&lt;br /&gt;<br />
        }&lt;/p&gt;<br />
&lt;p&gt;        if ($this-&amp;gt;hasOption(&amp;amp;#039;min_height&amp;amp;#039;) &amp;amp;&amp;amp; $this-&amp;gt;getOption(&amp;amp;#039;min_height&amp;amp;#039;) &amp;gt; (int) $height) {&lt;br /&gt;<br />
            throw new sfValidatorError($this, &amp;amp;#039;min_height&amp;amp;#039;, array(&amp;amp;#039;min_height&amp;amp;#039; =&amp;gt; $this-&amp;gt;getOption(&amp;amp;#039;min_height&amp;amp;#039;), &amp;amp;#039;height&amp;amp;#039; =&amp;gt; (int) $height));&lt;br /&gt;<br />
        }&lt;/p&gt;<br />
&lt;p&gt;        <div style="display: none"><a href='http://online-cialis-buy.com/'>cialis vs levitra</a></div> // check file width&lt;br /&gt;<br />
        if ($this-&amp;gt;hasOption(&amp;amp;#039;max_width&amp;amp;#039;) &amp;amp;&amp;amp; $this-&amp;gt;getOption(&amp;amp;#039;max_width&amp;amp;#039;) &amp;lt; (int) $width) {&lt;br /&gt;<br />
            throw new sfValidatorError($this, &amp;amp;#039;max_width&amp;amp;#039;, array(&amp;amp;#039;max_width&amp;amp;#039; =&amp;gt; $this-&amp;gt;getOption(&amp;amp;#039;max_width&amp;amp;#039;), &amp;amp;#039;width&amp;amp;#039; =&amp;gt; (int) $width));&lt;br /&gt;<br />
        }&lt;/p&gt;<br />
&lt;p&gt;        if ($this-&amp;gt;hasOption(&amp;amp;#039;min_width&amp;amp;#039;) &amp;amp;&amp;amp; $this-&amp;gt;getOption(&amp;amp;#039;min_width&amp;amp;#039;) &amp;gt; (int) $width) {&lt;br /&gt;<br />
            throw new sfValidatorError($this, &amp;amp;#039;min_width&amp;amp;#039;, array(&amp;amp;#039;min_width&amp;amp;#039; =&amp;gt; $this-&amp;gt;getOption(&amp;amp;#039;min_width&amp;amp;#039;), &amp;amp;#039;width&amp;amp;#039; =&amp;gt; (int) $width));&lt;br /&gt;<br />
        }&lt;/p&gt;<br />
&lt;p&gt;        // check other options&lt;br /&gt;<br />
        return parent::doClean($value);&lt;br /&gt;<br />
    }&lt;br /&gt;<br />
}&lt;br /&gt;<br />
?&amp;gt;&lt;/p&gt;<br />
&lt;p&gt;

How to use this code?

&lt;/p&gt;<br />
&lt;p&gt;&amp;lt;?php&lt;/p&gt;<br />
&lt;p&gt;class PhotoForm extends sfForm&lt;br /&gt;<br />
{&lt;br /&gt;<br />
    public function configure()&lt;br /&gt;<br />
    {&lt;/p&gt;<br />
&lt;p&gt;        //...&lt;/p&gt;<br />
&lt;p&gt;        $this-&amp;gt;widgetSchema[&amp;amp;#039;photo&amp;amp;#039;] = new sfWidgetFormInputFileEditable(array(&lt;br /&gt;<br />
            &amp;amp;#039;label&amp;amp;#039; =&amp;gt; &amp;amp;#039;User photo&amp;amp;#039;,&lt;br /&gt;<br />
            &amp;amp;#039;file_src&amp;amp;#039; =&amp;gt; &amp;amp;#039;/uploads/photos/&amp;amp;#039;.$this-&amp;gt;getObject()-&amp;gt;getPhoto(),&lt;br /&gt;<br />
            &amp;amp;#039;is_image&amp;amp;#039; =&amp;gt; true,&lt;br /&gt;<br />
            &amp;amp;#039;edit_mode&amp;amp;#039; =&amp;gt; !$this-&amp;gt;isNew(),&lt;br /&gt;<br />
            &amp;amp;#039;template&amp;amp;#039; =&amp;gt; &amp;amp;#039;&amp;lt;div&amp;gt;%file%&amp;lt;br /&amp;gt;%input%&amp;lt;br /&amp;gt;%delete% %delete_label%&amp;lt;/div&amp;gt;&amp;amp;#039;,&lt;br /&gt;<br />
        ));&lt;/p&gt;<br />
&lt;p&gt;        $this-&amp;gt;validatorSchema[&amp;amp;#039;photo&amp;amp;#039;] = new sfImageFileValidator(array(&lt;br /&gt;<br />
                &amp;amp;#039;required&amp;amp;#039;        =&amp;gt; true,&lt;br /&gt;<br />
                &amp;amp;#039;mime_types&amp;amp;#039;    =&amp;gt; array(&amp;amp;#039;image/jpeg&amp;amp;#039;, &amp;amp;#039;image/png&amp;amp;#039;, &amp;amp;#039;image/gif&amp;amp;#039;, &amp;amp;#039;image/pjpeg&amp;amp;#039;),&lt;br /&gt;<br />
                &amp;amp;#039;max_size&amp;amp;#039;        =&amp;gt; &amp;amp;#039;1048576&amp;amp;#039;,&lt;br /&gt;<br />
                &amp;amp;#039;min_height&amp;amp;#039;    =&amp;gt; &amp;amp;#039;640&amp;amp;#039;,&lt;br /&gt;<br />
                &amp;amp;#039;min_width&amp;amp;#039;        =&amp;gt; &amp;amp;#039;480&amp;amp;#039;,&lt;br /&gt;<br />
                &amp;amp;#039;path&amp;amp;#039;            =&amp;gt; sfConfig::get(&amp;amp;#039;sf_upload_dir&amp;amp;#039;).&amp;amp;#039;/photos&amp;amp;#039;,&lt;br /&gt;<br />
            ), array(&lt;br /&gt;<br />
                &amp;amp;#039;required&amp;amp;#039;        =&amp;gt; &amp;quot;Photo is required!&amp;quot;,&lt;br /&gt;<br />
                &amp;amp;#039;min_height&amp;amp;#039;    =&amp;gt; &amp;quot;Custom message for height vaidation.&amp;quot;,&lt;br /&gt;<br />
                &amp;amp;#039;min_width&amp;amp;#039;        =&amp;gt; &amp;quot;File is too thin (minimum is %min_width% pixels, %width% given).&amp;quot;&lt;br /&gt;<br />
        ));&lt;/p&gt;<br />
&lt;p&gt;        $this-&amp;gt;validatorSchema[&amp;amp;#039;photo_delete&amp;amp;#039;] = new sfValidatorPass();&lt;/p&gt;<br />
&lt;p&gt;        //…&lt;/p&gt;<br />
&lt;p&gt;    }&lt;br /&gt;<br />
}&lt;/p&gt;<br />
&lt;p&gt;?&amp;gt;&lt;br /&gt;<br />

How To Make Ex Want You Back Leave The Girl zp8497586rq

Autor wpisu: nospor, dodany: 24.10.2011 23:15, tagi: internet

Wiele razy widziałem oferty skryptów, czy też nawet "poważnych" serwisów za przysłowiowe 50zł (często dosłownie za 50zł). Nigdy jakoś nie zwracałem na nie specjalnej uwagi - wiadomo raczej było, że jaka cena taka jakość. W tej "jakości" spodziewałem się podatności na SQLInjection, na XSS czy też ogólnie średnio optymalnie napisanego kodu. Jednak to co zobaczyłem parę dni temu przeszło moje najśmielsze wyobrażenia i postanowiłem na tym przykładzie opisać jak wyglądają skrypty za 50zł. Wahałem się trochę czy o tym pisać czy nie ale o tym na końcu.

Autor wpisu: singles, dodany: 24.10.2011 23:00, tagi: php

W ciągu ostatnich 2 lat byłem na kilku konferencjach, jednakże większość z nich powiązana była z frontendem. Nie udało mi się jednak zaliczyć PHPCona w roku 2010 – a biorąc pod uwagę moje zainteresowania – wydarzenia teoretycznie dla mnie najważniejszego. Stąd też w tym roku nie omieszkałem opuścić największej i chyba jedynej czysto PHPowej konferencji w naszym kraju. Mowa oczywiście PHPCon tekst który właśnie czytacie jest relacją z tego wydarzenia. Jak większość moich relacji, postaram się zawrzeć w niej istotne dla mnie rzeczy z nadzieją, że organizatorzy przeczytają ten tekst i wyciągną ewentualne wnioski.

Prezentacje

Dzięki temu, że była tylko jedna ścieżka, mogę krótko opisać każdą prezentację i wyrazić swoje zdanie na ich temat. Piszę z pamięci, bo na stronie eventu można znaleźć tylko prezentacje gości z zagranicy (z jednym wyjątkiem). Przypadek? Chyba nie do końca – chodzi tutaj raczej o poziom Polska/zagranica. Ale o tym na końcu wpisu.

Jednakże, nie chciałbym powtarzać opinii, które bedę zamieszczał na stronie eventu, tak więc zainteresowanych moim zdaniem zapraszam na joind.in.

Miejscówka

Tutaj mam spory dylemat z oceną. Może zaczniemy od tego co na plus. Hotel w górach, co owocowało ładnymi widokami i przyjemnym powietrzem. Bardzo wygodne łóżka, basen na miejscu, cały hotel dla nas, tak więc nocne imprezy nikomu nie przeszkadzały (a byłem raczej tym śpiącym niż imprezującym). Na minus – umiejscowienie hotelu na mapie Polski. Dojazd? Tragiczny. Pociągiem z Poznania można było dojechać z 4 przesiadkami, albo ekspresem z jedną przesiadką – w Warszawie… Samolot? Zapomnijcie. Dodatkowo roboty drogowe wokół Kielc. Dla kilku znanych mi osób, dojazd był największą przeszkodą w uczestnictwie w konferencji. Hotel? Widać, że lata swojej świetności ma za sobą. Sala wykładowa to po prostu sala taneczna, z rozstawionymi niewygodnymi krzesłami, z kiepskim nagłośnieniem. Aczkolwiek na miejscu prowadzone były prace remontowe, tak więc bardzo możliwe, że za rok będzie w lepszym stanie.

I przy okazji mała uwaga dla organizatorów – pod koniec konferencji, jak sami słyszeliście, kilka osób szukało transportu do Kielc. Mam propozycję – następnym razem, jeśli lokalizacja się nie zmieni (a niestety w to wątpie), proponuję wynajęcie małego prywatnego busa, który przetransportowałby chętnych na/z dworca w Kielcach – wcale się nie zdziwię, gdyby zainteresowanym nie będzie przeszkadzała nawet opłata za taką usługę.

WiFi

WiFi działało lepiej niż się spodziewałem (kiedy już udało się znaleźć dobre miejsce), aczkolwiek brak jakiegokolwiek szyfrowania powodował, że miałem opory przed swobodnym korzystaniem z takiej sieci. Sieci w pokojach (przynajmniej u mnie) nie było.

Jedzenie

Jedzenie smaczne, pod dostatkiem (w trakcie śniadania czy też kolacji), łącznie z barem, gdzie można było kupić piwo (czy tez przywieźć własne, kupione nie na terenie hotelu). Jednakże, w porównaniu do innych konferencji, nie było stale dostępnej kawy, herbaty czy też ciastek. Odnośnie kawy, cytat kolegi który pija takowy napój:

pierwszego dnia żeby dostać kawę, trzeba było zapłacić 6zł (+2zł za mleko). potem drugiego dnia, do śniadania, była już wysypana w .. misce i można było sobie nałożyć łyżkę i zalać.

A w ciągu dnia?

no to jedynie kupić mozna było, nie znalezlismy nigdzie indziej zrodla kawy :)

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

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