Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: Śpiechu, dodany: 10.10.2010 13:52, tagi: php

Czytając mądrą książkę dotyczącą optymalizacji witryn internetowych natrafiłem na narzędzie jpegtran, które wykona dla nas kawał dobrej roboty bezstratnie zmniejszając wielkość plików jpg.1 Dodatkowo przy okazji możemy wyrzucić część lub całość metadanych z pliku.

Użytkownicy czasem sami sobie robią krzywdę wrzucając zdjęcia do internetu robione komórkami z GPSem. Raz, że komórki podają swój model i inne parametry (np. przysłony), a dwa, że zapisują w metadanych dokładną lokalizację wykonanego zdjęcia (a tym samym np. czyjegoś domu).

Zmniejszenie wielkości pliku za pomocą jpegtran polega na optymalizacji tablic Hauffmana i ewentualnie dodanie trybu progresywnego (w miarę ładowania się zdjęcia polepsza się jego jakość na stronie WWW). Co ciekawe, dodanie progresywności również zaoszczędza kilka KB w zdjęciu.

Walka toczy się o ok. 20% wielkości pliku, czyli dosyć sporo. Jpegtran można sobie w Ubuntu znaleźć w Synapticu w ramach pakietu libjpeg-progs. Co do Windowsa radźcie sobie sami ;-)

Na koniec przedstawię owoc mojej godzinnej pracy: klasę, za pomocą której w php możemy sterować poczynaniami jpegtran. Jak zwykle po angielsku, ale za to komentarze i errory po polsku żeby nie było że jakiś stronniczy jestem. Jak to cudo działa? Na etapie tworzenia obiektu przyjmuje 2 parametry:

  1. Co zrobić z metadanymi pliku
    • none — wyrzucić wszystkie metadane
    • comments — zostawić tylko komentarze (mogą zawierać dane na temat licencji i/lub właściciela)
    • all — zostawić metadane tak jak są
  2. Jakie wykonać operacje na pliku
    • optimise — przeprowadza optymalizację tablic Hauffmana
    • progressive — dodaje tryb progresywny

Wystarczy sobie utworzyć obiekt JpegOptimiser i można za pomocą metody processImage przetwarzać obrazki, np. tak:

$jpg = new JpgOptimiser('none', array('optimise','progressive'));
$jpg->processImage('test.jpg', 'test_wyjsciowy.jpg');

Poniżej kod klasy:

<?php
class JpgOptimiser {
 
    /**
     * @var array tablica dopuszczalnych parametrow operacji graficznych
     */
    protected static $VALID_PROCS = array('optimise', 'progressive');
 
    /**
     * @var array tablica dopuszczalnych parametrow operacji na metadanych
     */
    protected static $VALID_META = array('none','all','comments');
 
    /**
     * @var array tablica najczestszych bledow z wyjscia i komunikat bledu
     */
    protected static $REGEX_OUTPUT_ERRORS = array(
            array('/jpegtran: not found/', 'nie wykryto jpegtran'),
            array('/can\'t open/', 'nie mozna otworzyc pliku'),
            array('/not a jpeg/i', 'to nie jest plik jpg')
    );
 
    /**
     * @var string przygotowana lista argumentow do uruchomienia w konsoli
     */
    protected $argsChain;
 
    /**
     * Wybor listy operacji do wykonania.
     * @param string $meta operacje wykonywane na metadanych; dopuszczalne: none, comments, all
     * @param array $procs operacje graficzne; dopuszczalne: optimise, progressive
     */
    public function __construct($meta = 'none', array $procs = array('optimise', 'progressive')) {
        $this->argsChain  = $this->parseArgs($procs, self::$VALID_PROCS, ' -');
        $this->argsChain .= $this->parseArgs(array($meta), self::$VALID_META, ' -copy ');
    }
 
    /**
     * @param array $args tablica parametrow wejsciowych
     * @param array $valid tablica parametrow dopuszczalnych
     * @param string $prefix znak poprzedzajacy argument
     * @return string przetworzony ciag argumentow
     */
    private function parseArgs(array $args, array $valid, $prefix) {
        $output = '';
        foreach ($args as $arg) {
            if (in_array($arg, $valid)) {
                // dorzucam myslnik przed parametrem i spacje na koncu
                $output .= $prefix . $arg . ' ';
            }
        }
        return $output;
    }
 
    /**
     * Przetwarzanie pliku.
     * Docelowo lepszym rozwiazaniem bedzie uzywanie SPLFileInfo.
     * @param string $srcFile nazwa pliku wejscowego
     * @param string $dstFile nazwa pliku wyjscowego (moze byc taka sama jak wejscowy)
     * @return bool
     */
    public function processImage($srcFile, $dstFile) {
        $output = shell_exec('jpegtran' . $this->argsChain . '-outfile ' . escapeshellarg($dstFile) . ' ' . escapeshellarg($srcFile) . ' 2>&1');
        try {
            return $this->isProcessingOK($output);
        }
        catch(Exception $e) {
            echo $e->getMessage();
            return false;
        }
    }
 
    /**
     * @param mixed $output
     * @return bool
     * @throws Exception
     */
    private function isProcessingOK($output) {
        if ($output === null) {
            return true;
        }
        else {
            // szukam znanych komunikatow bledow
            foreach (self::$REGEX_OUTPUT_ERRORS as $error) {
                if (preg_match($error[0], $output) != 0) {
                    throw new Exception($error[1]);
                }
            }
            // nie znaleziono znanych, rzucam cala tresc wyjscia
            throw new Exception($output);
        }
    }
}
  1. S. Souders : Jeszcze wydajniejsze witryny internetowe. Przyspieszanie działania serwisów WWW. Gliwice : Helion, 2010, s. 156–157.

Autor wpisu: batman, dodany: 10.10.2010 08:00, tagi: jquery, zend_framework

Jeśli mielibyście wskazać najpopularniejszą funkcjonalność wyszukiwarki (poza samym wyszukiwaniem), byłoby to najprawdopodobniej podpowiadanie wpisywanych słów. Autocomplete, bo o nim mowa, jest dostępny w Zend Frameworku w ramach biblioteki ZendX_JQuery. Jego zastosowanie jest wyjątkowo proste i sprowadza się do dodania do formularza jednego pola.

Polem tym jest ZendX_JQuery_Form_Element_Autocomplete. Wystarczy, że wskażemy adres, z którego będą wczytywane i mamy gotowy do użycia komponent.

Przykładowy formularz wygląda następująco

class Application_Form_Autocomplete extends Batman_Form
{
    protected function _renderForm()
    {
        $ac = new ZendX_JQuery_Form_Element_AutoComplete('ac');
        $ac->setJQueryParam('source', '/jquery/autocompletedata')
           ->setJQueryParam('minLength', 3)
           ->setJQueryParam('select', new Zend_Json_Expr('acSelected'))
           ->setLabel('Wpisz coś:');

        $this->addElement($ac);
    }
}

Jeśli chcemy, aby autocomplete działał, musimy ustawić przynajmniej jedną opcję – source. Bez tej opcji wyrzucony zostanie wyjątek informujący o braku źródła danych. Jako źródło podany został adres, z którego będą zwracane dane w postaci JSON. Pozostałe parametry są opcjonalne, a ich listę znajdziecie w dokumentacji jQuery. Jeżeli chcieli byście skorzystać z funkcji zwrotnych (w powyższym przykładzie jest to funkcja acSelected), musicie pamiętać o stworzeniu obiektu Zend_Json_Expr. Dzięki temu ciąg przekazany jako parametr nie zostanie zamieniony na zwykły string.

Akcja kontrolera odpowiedzialna za zwrócenie danych nie różni się niczym od pozostałych akcji, za wyjątkiem wywołania helpera json.

public function autocompletedataAction()
{
    // Wpisana przez użytkownika fraza
    $term = $this->_getParam('term');

    // Dane zwrócone do użytkownika. Mogą pochodzić z bazy danych, plików, itp
    $data = array(
        array(
    		'id' => 1,
    		'label' => 'pierwsza pozycja'
	    ),
        array(
    		'id' => 2,
    		'label' => 'druga pozycja'
	    )
    );

    $this->_helper->json($data);
}

Dane wpisywane w polu autocomplete przekazywane są w zmiennej term. Na jej podstawie można wyszukać odpowiednie informacje w bazie, pliku lub dowolnym innym źródle danych. Ważne, aby zapisać te dane w postaci tablicy. Jeśli zależy wam na dodatkowych danych, możecie stworzyć w tablicy kolejne klucze i wypełnić je odpowiednimi danymi. Dane te będą dostępne z poziomu Javascript po odebraniu odpowiedzi ze skryptu. Na samym końcu akcji wykorzystany został helper json, który jest odpowiedzialny za ustawienie odpowiedniego typu odpowiedzi oraz za wyłączenie layoutu.

I to wszystko. Jeden prosty formularz oraz jedna akcja i mamy zaimplementowaną funkcjonalność autocomplete.

Autor wpisu: matipl, dodany: 08.10.2010 14:39, tagi: php

php-logoJakoś małym echem w blogosferze rozeszła sie informacja włączenia dodatku PHP-FPM (FastCGI Process Manager) do wersji 5.3.3 PHP.

A jest to duży skok na przód. PHP-FPM jest to patch zawarty w jądrze PHP, który pozwala zarządzać procesami FastCGI: uruchamiać, zatrzymywać, restartować. Jest to wspaniała wiadomość dla wszystkich osób korzystających z PHP poprzez FastCGI (np. nginx, lighttpd). Do tej pory trzeba było sie np. kłopotać z spawn-fcgi.

Większość osób, które dokonują standardowej instalacji Apache jako serwer WWW + PHP nawet nie zdają sobie sprawy jak to działa. Apache domyślnie obsługuje PHP poprzez własny moduł (mod_php) – w skrócie Apache ładuje całe środowisko w siebie. Dzięki wykorzystaniu FastCGI i FPM otrzymujemy:

  • mniejsze zużycie pamięci (dodatkowe workery nginx nie potrzebują środowiska PHP)
  • lepsze zarządzanie uprawnieniami PHP bez gimnastyki
  • gdy PHP padnie nginx nadal działa
  • inteligentne zarządzanie wspólnymi procesami PHP (obniża zużycie pamięci)

Jedyne co należy obecnie zrobić to podczas konfiguracji PHP (przed kompilacją) dodać –enable-fpm. Skompilowany zarządca będzie czekał w sapi/fpm jako php-fpm. W tym samym katalogu macie również plik konfiguracyjny (php-fpm.conf) oraz skrypt inicjacyjny init.d.php-fpm.

Ja na wszelkich maszynach dedykowanych pod serwery WWW + PHP korzystam właśnie z tej wybuchowej mieszanki.

Autor wpisu: batman, dodany: 08.10.2010 08:00, tagi: jquery, zend_framework

Czym jest serwis internetowy? Jest to zbiór formularzy oraz danych dodanych przy pomocy tych formularzy. Gdyby nie formularze, Internet taki jakim go znamy. Wyobrażacie sobie w jaki sposób dodawalibyście cokolwiek na ścianę facebooka bez formularzy?

W przypadku formularzy najczęstszym schematem jest ścieżka:

  • strona początkowa (informacje na temat formularza lub dane zebrane przy jego pomocy)
  • formularz (obsługa błędów, operacje na wprowadzonych danych)
  • strona końcowa (podziękowania za wysłanie formularza lub powrót do strony początkowej).

Prawda, że nudne? Okazuje się, że wyrwanie się z tego schematu wcale nie jest takie trudne. Wystarczy formularz wyświetlić na warstwie, a dane zapisać AJAXem w tle. Oczywiście nie można zapomnieć o sytuacji kryzysowej, w której z jakiegoś powodu (np. błąd w skrypcie) zostaliśmy pozbawieni możliwości korzystania z Javascript.

Wszystko to, co przed chwilą opisałem można zrealizować niewielkim nakładem prac przy pomocy komponentu Zend_Form, biblioteki jQuery oraz pluginu FancyBox. Najciekawsze w tym wszystkim jest to, iż nie musimy wcale pisać dodatkowego kodu. Wszystkim zajmą się mechanizmy wbudowane w Zend Frameworka oraz konwencja, której trzeba się trzymać podczas stosowania tego sposobu.

Zacznijmy od formularza. Będzie to prosty formularz zbierający dane o użytkownikach (w przykładzie wykorzystałem klasę Batman_Form opisaną we wpisie Uniwersalne dekorowanie Zend_Form).

class Application_Form_FancyboxExample extends Batman_Form
{
    protected function _renderForm()
    {
        $this->setName('form_fancybox_example');
        $this->setAction('/index/fancyboxform');

        $firstname = new Zend_Form_Element_Text('firstname');
        $firstname->setLabel('Imie')
                  ->setRequired(true)
                  ->addValidator(new Zend_Validate_NotEmpty(), true);

        $lastname = new Zend_Form_Element_Text('lastname');
        $lastname->setLabel('Nazwisko')
                 ->setRequired(true)
                 ->addValidator(new Zend_Validate_NotEmpty(), true);

        $submit = new Zend_Form_Element_Submit('btn_save');
        $submit->setLabel('Zapisz')
               ->setIgnore(true);

        $this->addElement($firstname);
        $this->addElement($lastname);
        $this->addElement($submit);
    }
}

Kluczowym tutaj elementem jest zastosowanie akcji, która jednoznacznie wskazuje na akcję, odpowiedzialną za przetworzenie formularza. Ten prosty zabieg umożliwi nam obsłużenie formularza w przypadku braku Javascript.

Następnie musimy stworzyć widok, który będzie zawierał link do formularza.

<a href="/index/fancyboxform" id="link">dodaj uzytkownika</a>

Na koniec pozostaje stworzenie akcji

public function fancyboxformAction()
{
    $form = new Application_Form_FancyboxExample();
    if($this->_request->isPost()) {
        $postData = $this->_request->getPost();
        if($form->isValid($postData)) {

            // zrob cos z danymi

            $this->_redirect('/index/fancyboxexample');
        }
    }
    $this->view->form = $form;
}

i widoku z formularzem.

<h1>Formularz</h1>
<?php echo $this->form; ?>

Jak dotąd nie zrobiliśmy nic ponad stworzenie standardowego, nudnego formularza wraz z jego obsługą. Pora na magię.

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

Autor wpisu: batman, dodany: 06.10.2010 08:00, tagi: jquery

Godzina 3.41, noc z soboty na niedzielę po niezłej zabawie. Wybudzony ze snu deweloper, zapytany o najlepszą bibliotekę Javascript bez chwili zastanowienia odpowie – jQuery. Wydawać by się mogło, że nic już się nie da dodać do tej biblioteki. A jednak. Na oficjalnym blogu jQuery, pojawiła się informacja o zaakceptowaniu trzech pluginów stworzonych przez Microsoft jako oficjalnych pluginów jQuery. Pluginy te to jQuery Templates, jQuery Data Link oraz jQuery Globalization. Dwa pierwsze będą utrzymywane w ramach podstawowej biblioteki, ostatni w ramach jQuery UI. Co więcej, jQuery Templates zostanie włączone do biblioteki od wersji 1.5.

O co tyle szumu? Okazuje się, że wspomniane pluginy znacznie usprawniają pracę z biblioteką. Dzięki pierwszemu z nich – jQuery Templates – programista zyskuje potężne narzędzie w postaci szablonów, które w bardzo prosty sposób może osadzić na stronie. Szablony te można wypełnić danymi pochodzącymi z tablicy lub zwróconymi z AJAXa.

<script type="text/javascript">
	var movies = [
		{ Name: "The Red Violin", ReleaseYear: "1998" },
		{ Name: "Eyes Wide Shut", ReleaseYear: "1999" },
		{ Name: "The Inheritance", ReleaseYear: "1976" }
	];

	var markup = "<li><b>${Name}</b> (${ReleaseYear})</li>";

	// Compile the markup as a named template
	$.template( "movieTemplate", markup );

	// Render the template with the movies data and insert
	// the rendered HTML under the "movieList" element
	$.tmpl( "movieTemplate", movies ).appendTo( "#movieList" );
</script>

<ul id="movieList"></ul>

Plugin jQuery Data Link znacznie upraszcza “bindowanie” właściwości jednego obiektu do właściwości innego obiektu. Jest to bardzo przydatna funkcjonalność w przypadku formularzy, gdzie wprowadzane dane można od razu powiązać z odpowiednim obiektem.

<!DOCTYPE html>
<html>
<head>
	<style>
	</style>
	<script src="http://github.com/nje/jquery-datalink/raw/e3e3be4312c9b224a8d9b25031f4ac876e4f70fd/jquery.js"></script>
	<script src="http://github.com/nje/jquery-datalink/raw/master/jQuery.datalink.js"></script>
</head>
<body>
	<form>
		<div>
			First Name:
			<input type="text" name="firstName" />
		</div>
		<div>
			Last Name:
			<input type="text" name="lastName" />
		</div>
	</form>
    Object.firstName: <span id="objFirst"></span><br/>
    Object.lastName <span id="objLast"></span>
	<script>
		var person = { };
		$("form").link(person);
		
		// Chain link the person object to these elements to show the results
		$("#objFirst").link(person, {
			firstName: {
				name: "objFirst",
				convertBack: function(value, source, target) {
					$(target).text(value);
				}
			}
		});

		$("#objLast").link(person, {
			lastName: {
				name: "objLast",
				convertBack: function(value, source, target) {
					$(target).text(value);
				}
			}
		});
	</script>
</body>
</html>

Ostatni plugin – jQuery Globalization – dostarcza API do bezproblemowego konwertowania zlokalizowanych danych. Dzięki niemu, programiści będą mogli bez problemu dokonywać konwersji dat oraz wartości liczbowych.

Pluginy można pobrać z następujących adresów:

Dokumentacja jest dostępna pod adresami:

Autor wpisu: Blame, dodany: 05.10.2010 15:36, tagi: javascript

Z racji tego, że powstało już baardzo wiele sposobów na zaokrąglone rogi pomyślałem, że nie będę pisał o niczym nowym. Ten wpis będzie zbiorem tych licznych rozwiązań wykorzystujących zarówno HTML, CSS jak i JavaScript. Na końcu każdej metody pozwoliłem sobie pokazać wady i zalety jej stosowania. Zapraszam do lektury :)

Sposób pierwszy – CSS3

Jak wiadomo, najnowsza wersja arkuszy stylów pozwala na uzyskanie krągłości na naszej stronie. Aby to zrobić wystarczy nadać danemu elementowi odpowiedni selektor, np. klasę a następnie dodać mu poniższe style:

-khtml-border-radius: 10px / 10px;

-webkit-border-radius: 10px / 10px;

-moz-border-radius: 10px / 10px;

border-radius: 10px / 10px;

Dla wyjaśnienia, pierwsza wartość to szerokość zaokrąglenia, z kolei wartość po slash’u „/” definiuje jego wysokość. W tym wypadku godna polecenia jest strona CSS Border Radius Generator dzięki której wpisując odpowiednie wartości w pola przy rogach możemy na bieżąco obserwować kształt boków a następnie skopiować cały kod CSS.

 

Zalety

  • Wymaga niewielkich zmian w kodzie,
  • Używa najnowszych rozwiązań.

Wady

  • Rozwiązanie obsługiwane tylko przez najnowsze przeglądarki.

 

 

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

Autor wpisu: batman, dodany: 05.10.2010 09:12, tagi: javascript, jquery

jQuery. Poradnik programisty jest jedną z pierwszych książek traktujących o jQuery w Polsce. Podchodząc do jej lektury miałem mieszane uczucia. Spis treści wskazywał raczej na tłumaczenie dokumentacji, a ilość stron (raptem 270) utwierdzała mnie w tym przekonaniu. Niemniej byłem ciekawy, czy książka ma coś do zaoferowania osobie, która na co dzień korzysta z tytułowej biblioteki. Bardzo mnie zastanawiała kwestia sposobu, w jaki jest ona zorganizowana. Czy autor poprzestał na przetłumaczeniu ogólnodostępnej dokumentacji, czy też odrobił pracę domową i stworzył solidny przewodnik? Wreszcie czy będzie to suchy tekst, o którym zapomnę dzień po zakończeniu lektury, czy też często będę do niej powracał, szukając rozwiązania jakiegoś problemu?

Książka została podzielona na trzy części: abecadło, interfejs API oraz wtyczki. Pierwsza część jest przeglądem możliwości jQuery, druga zawiera pełny opis biblioteki, a ostatnia w bardzo przystępny sposób prezentuje proces tworzenia wtyczek. Każda z części została dodatkowo podzielona na rozdziały, odzwierciedlające zagadnienia związane z jQuery, np. selektory, manipulacja drzewem DOM, czy AJAX. Co więcej, każdy z rozdziałów został tak przygotowany, by teoria stanowiła jak najmniejszą jego część. Po krótkim wstępie wyjaśniającym bieżące zagadnienie, autor na przykładach pokazuje praktyczne możliwości biblioteki. Przykłady te nie są oderwanymi od rzeczywistości zadaniami akademickimi (takie też się zdarzają), tylko pełnoprawnymi skryptami, które można później wykorzystać, np. wtyczka karuzela do przeglądania zdjęć.

Podczas objaśniania kilku przykładów, autor posłużył się rozszerzeniami przeglądarki Firefox i delikatnie sugerował, że każdy, kto na poważnie myśli o korzystaniu z jQuery, również powinien z nich korzystać. Mowa tutaj o rozszerzeniach Firebug, LiveHttpHeaders oraz Web Developer Toolbar.

Na początku tej recenzji podzieliłem się z wami moimi obawami w stosunku do tej książki. Czy się potwierdziły? Nie. Okazało się, że były one mocno przesadzone. Książkę mogę śmiało polecić wszystkim, którzy chcieliby zapoznać się z jQuery. Wbrew moim przewidywaniom nie jest to bezmyślnie przetłumaczona dokumentacja, tylko dobrze zaplanowana książka, płynnie przechodząca między zagadnieniami. Jeśli znacie jQuery na tyle dobrze, że nie musicie zaglądać do dokumentacji i macie na koncie kilka wtyczek, książka będzie raczej stanowiła suplement dokumentacji, niż źródło wiedzy. Nie da się nie odnieść wrażenia, że została przygotowana pod kątem osób stawiających pierwsze kroki w świecie jQuery.

Podsumowując. jQuery. Poradnik programisty jest solidną książką, która powinna znaleźć się w biblioteczce każdego, kto chciałby rozpocząć przygodę z tą biblioteką. Jeśli nadal zastanawiasz się nad wyborem biblioteki Javascript, z której będziesz korzystał, ta książka znacznie ułatwi Ci wybór.

 

Powyższa recenzja ukazała się również na łamach serwisu Software.com.pl, pod adresem http://software.com.pl/recenzja-jquery-poradnik-programisty/

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