Autor wpisu: matiit, dodany: 22.09.2013 18:21, tagi: php
Witam po przerwie.
Chciałem dzisiaj pokazać fajny feature, który jest wbudowany w Laravel. Wyobraźmy sobie sytuację, że piszemy aplikację dla klienta, który chce „autoryzację”, ale sam przyznaje, że tylko on będzie z niej korzystał. Nie potrzebujemy wyrafinowanego systemu rejestracji, ślicznego logowania itd. Idealnie będzie użyć Basic Auth. Chodzi o zwykłe przeglądarkowe okienko logowania.
Laravel udostępnia nam do realizacji tego celu filtr „auth.basic”. Wystarczy, że zrobimy coś takiego:
Route::get('profile', array('before' => 'auth.basic', function() { // Tylko zalogowani przez HTTP basic auth będą mieli tu dostęp. }));
Po tym kroku wystarczy, że w naszej tabeli users będzie jakiś użytkkownik. Logujemy się podając adres email oraz hasło. Jeśli chcemy coś zmienić – odsyłam do dokumentacji. http://four.laravel.com/docs/security#http-basic-authentication
Post Laravel – Basic Auth, prościej się nie da pojawił się poraz pierwszy w matiit dev blog.
Autor wpisu: kicaj, dodany: 21.09.2013 12:30, tagi: sql, php
Autor wpisu: Jacek Skirzyński, dodany: 20.09.2013 21:29, tagi: php
Wyjątki są lepszą alternatywą dla obsługi błędów w aplikacjach od wywoływania trigger_error
czy zwracania jakiegoś umówionego kodu w wypadku wystąpienia błędu. W związku z tym w ramach kontynuacji wątku z poprzedniego wpisu dziś kilka słów na temat wyjątków w PHP z nastawieniem na obsługę niewyłapanych przez catch
wyjątków.
Obsługa wyjątków
Klasyczne podejście do obsługi wyjątków zakłada użycie throw
i try
/catch
(od PHP 5.5 można również używać finally
). Może to wyglądać w taki sposób:
<?php $id = 1; // kod wykonany bez wzgledu na wystapienie wyjatku echo 'punkt 1' . PHP_EOL; try { echo 'punkt 2' . PHP_EOL; // kod wykonany bez wzgledu na wystapienie wyjatku if (is_int($id)) { echo 'punkt 3' . PHP_EOL; // zrob cos dla podanego ID } else { echo 'punkt 4' . PHP_EOL; throw new Exception('Błędne ID'); } echo 'punkt 5' . PHP_EOL; // kod wykonany TYLKO jezeli nie bylo wyjatku } catch (Exception $ex) { echo 'punkt 6' . PHP_EOL; // kod wykonany tylko w razie wystapienia wyjatku // np. "uratowanie zaistniałej sytuacji", zapis do logu, e-mail do admina } echo 'punkt 7' . PHP_EOL; // kod wykonany bez wzgledu na wystapienie wyjatku
Dla wartości $id = 1;
przebieg będzie wyglądał następująco, punkty: 1, 2, 3, 5, 7. Natomiast dla $id
nie będącego liczbą całkowitą wykonanie podąży ścieżką: 1, 2, 4, 6, 7.
Powyższy przykład jest mocno uproszczony, ale można zaobserwować pewną rzecz – wyjątki pozwalają na łatwe poinformowanie o jakimś problemie jak również jego obsługę i w dodatku są luźno powiązane. W jednym fragmencie wykonanie kodu jest przerywane poprzez rzucenie wyjątku i nie ma potrzeby zajmowania się jego obsługą. Tym zajmuje się inny fragment kodu, który w bloku try
/catch
zamyka wywołania mogące sprawiać problemy.
Większego sensu nabiera to w momencie, kiedy w różnych warstwach aplikacji ma miejsce rzucenie wyjątku i jego złapanie. Dodatkowo wyjątki mogą być rzucane również z poziomu bloku catch
, na przykład warstwa utrwalania danych łapie wyjątek związany z błędem zapisu do bazy, wykonuje cofnięcie transakcji i ponownie wrzuca wyjątek. Następnie jest on łapany w „wyższej” warstwie aplikacji i w ramach jego obsługi jest pokazywany komunikat dla użytkownika o „problemach technicznych z wykonaniem operacji”. Kolejnym przykładem jest stosowanie w aplikacji bibliotek zewnętrznych – autor biblioteki umieszcza w kodzie tylko rzucanie wyjątków. Natomiast złapaniem i obsługą tych wyjątków zajmuje się programista pracujący nad projektem, w którym dana biblioteka została wykorzystana.
Przechwytywanie nie wyłapanych wyjątków
W ramach ludzkiego błędu, zmiany w kodzie biblioteki lub innego powodu może się pojawić rzucenie wyjątku w miejscu, które nie było na to przygotowane. W efekcie zamiast strony/aplikacji w przeglądarce pojawia się komunikat:
Fatal error: Uncaught exception '[typ_wyjatku]' with message '[komunikat_wyjatku]' in [sciezka_pliku] on line [numer_linii]
Sposobem na takie sytuacje jest utworzenie i zarejestrowanie własnej funkcji obsługującej globalnie przypadki nie złapania rzuconych wyjątków – chodzi o funkcję set_exception_handler
. Oprócz wywołania tej funkcji należy wcześniej zdefiniować funkcję, która będzie odpowiadała za faktyczną obsługę wyjątków. Poniżej przykład:
<?php function obsluzWyjatek($wyjatek) { echo 'Wyjatek [' . get_class($wyjatek) .']: '. $wyjatek->getMessage() . PHP_EOL; } set_exception_handler('obsluzWyjatek'); echo 'punkt 1' . PHP_EOL; throw new UnexpectedValueException('Podales zla wartosc'); echo 'punkt 2' . PHP_EOL;
Uruchomienie tego kodu spowoduje wyświetlenie:
punkt 1 Wyjatek [UnexpectedValueException]: Podales zla wartosc
Co istotne nie zostanie wykonany żaden kod po rzuceniu wyjątku (tutaj: wypisanie „punkt 2″) – w zwykłym podejściu „pole rażenia” wyjątku (czyli operacje, które nie zostaną wykonane jeżeli wyjątek się pojawi) jest określone blokiem try
. natomiast w tym wypadku go nie ma, więc wykonanie całej reszty skryptu zostaje udaremnione. Wyjątkiem jest uruchomienie zdefiniowanej funkcji obsługującej nieprzechwycone wyjątki. Co się w niej znajdzie zależy od programisty, natomiast najważniejszy jest fakt, że można się przed takimi sytuacjami zabezpieczyć i zamiast błędu PHP pokazać użytkownikowi chociażby własną wersję „blue screen”. Można również nieco rozbudować obsługę wyjątków w funkcji w zależności od typu (w przykładzie został użyty wyjątek UnexpectedValueException
). W przeciwieństwie do wielu instrukcji catch
wyłapujących wyjątki o określonych, coraz bardziej ogólnych typach, funkcja obsługi jest jedna dla wszystkich typów.
Linki:
- wyjątki w PHP
set_exception_handler()
– manualrestore_exception_handler()
– manual
Autor wpisu: bastard13, dodany: 20.09.2013 13:58, tagi: php, oop
interface PseudoEnum{ const SUCCESS = 1; const FAILURE = 2;}Dobre rozwiązanie? No cóż, osobiście od dawna bolałem nad tym, że takie konstrukcje nie pozwalają nam na jedną z jakże istotnych funkcjonalności, które w przypadku zwykłych obiektów PHP posiada, a które są bezproblemowe w językach, gdzie coś takiego jak enum istnieje. O czym mowa? Chodzi o typowanie. Pomimo cudownych i deskryptywnych nazw, te stałe, jakby na to nie patrzyć, w gruncie rzeczy są int'ami i w chwili, gdy któraś metoda mogła przyjąć wartość tylko i wyłącznie taką, jaka została zadeklarowana wcześniej w naszym pseudo-enumie, to musieliśmy tworzyć do tego celu specjalne metody sprawdzające.Nie mogę powiedzieć, że było to zadowalające rozwiązanie, ale jakoś z tym żyliśmy.Czytaj więcej »
Autor wpisu: Jacek Skirzyński, dodany: 18.09.2013 21:36, tagi: php
Błędy zdarzają się wszędzie i każdemu, natomiast raczej nie jest wskazane „chwalenie się” nimi przed użytkownikami aplikacji.
Konfiguracja
Podstawowyą kwestią jest ich ukrycie na środowisku produkcyjnym przed oczami użytkownika, tym bardziej że w stosie wywołań mogą się pojawić wrażliwe dane użytkownika/aplikacji/systemu/inne. Do ukrycia „wpadki” używa się właściwości display_errors
(php.ini
). Właściwość pozwala włączyć lub wyłączyć pokazywanie błędów oraz skierować je na odpowiednie wyjście:
Off
– wyłączenie pokazywania błędów (do użycia na „produkcji”)stderr
– przekierowanie błędów naSTDERR
(działa tylko z CGI/CLI)On
/stdout
– pokazanie błędów/przekierownie na standardowe wyjście, czyli pokazanie komunikatów w treści strony wyświetlonej użytkownikowi (przydatne w trakcie programowania)
Jednak ukrycie komunikatów błędów w żaden sposób nie rozwiązuje faktycznego problemu w aplikacji. Do tego potrzebne są komunikaty błędów i to tych znaczących. Do filtrowania komunikatów służy dyrektywa error_reporting
. Jest to poziom raportowania błędów, które będą wyświetlane/pokazywane – możliwych wartości jest cała masa, a dodatkowo można je łączyć – lista stałych
.
Obie dyrektywy (w zależności od uprawnień czy konfiguracji środowiska) mogą zostać ustawione na poziomie pliku php.ini
, definicji vhosta, pliku .htaccess
, czy w samym kodzie PHP. Ostatni wariant wygląda następująco:
<?php ini_set('display_errors', 1); error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE); var_dump(ini_get('display_errors')); // pokaże: string '1' (length=1) var_dump(ini_get('error_reporting')); // pokaże: string '22519' (length=5)
W PHP wartości dyrektyw można zmieniać i odczytywać funkcjami ini_set()
/ ini_get()
. Dla dyrektywy error_reporting
jest dedykowana funkcja – wywołana z argumentem zmienia wartość, natomiast bez argumentu zwraca obecną wartość, nie zmienia to jednak faktu, że można używać standardowych funkcji. Oczywiście nie wszystkie dyrektywy można zmieniać w powyższy sposób – tutaj znajduje się lista dyrektyw z oznaczeniem sposobu zmiany wartości i opis poziomów.
Wywołanie błędu
<?php echo 'punkt 1'. PHP_EOL; trigger_error('Test wywolania bledu', E_USER_NOTICE); echo 'punkt 2'. PHP_EOL; trigger_error('Test wywolania bledu', E_USER_ERROR); echo 'punkt 3'. PHP_EOL;
Do wywołania błędu z poziomu kodu służy funkcja trigger_error()
– pierwszy argument to własny komunikat, natomiast drugi to typ błędu. W zależności od tego jak bardzo błąd jest poważny wykonywanie skryptu jest kontynuowane lub przerywane, co widać poniżej w wyniku wykonania powyższego kodu:
punkt 1 Notice: Test wywolania bledu in /home/cim/public_html/Testy/error.php on line 12 Call Stack # Time Memory Function Location 1 0.0001 230360 {main}( ) ../error.php:0 2 0.0002 231520 trigger_error ( ) ../error.php:12 punkt 2 Fatal error: Test wywolania bledu in /home/cim/public_html/Testy/error.php on line 14 Call Stack # Time Memory Function Location 1 0.0001 230360 {main}( ) ../error.php:0 2 0.0003 231520 trigger_error ( ) ../error.php:14
Po wystąpieniu błedu typu „Notice” wykonywanie przebiega dalej (np. pokazanie „punkt 2″), natomiast błąd typu „Fatal error” przerywa wykonanie (brak wyświetlenia „punkt 3″).
Przechwytywanie
Błąd został zgłoszony i przy odpowiedniej konfiguracji został wyświetlony na ekranie. Docelowo jednak efekt ma być zupełnie inny, błędy powinny być zgłaszane do odpowiednich osób. PHP posiada przydatną funkcję – error_log
– która wspomaga wysyłanie e-maili, dodawnie komuniaktów błędów do systemowego logu, tworzenie własnego logu. Jednak można również samemu wysyłać e-maile (poprzez serwer SMTP) czy zapisywać do pliku.
W obu przypadkach należy w jakiś sposób przechwycić informację o wystąpieniu błędu. Realizuje się to poprzez utworzenie własnej funkcji i zarejestrowanie jej za pomocą set_error_handler()
.
<?php define('LOG_SEPARATOR', ';'); ini_set('display_errors', 1); error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE); function obsluga($kodBledu, $komunikat, $plik, $linia, $zmienne) { $elementy = array( date('H:i:s'), $kodBledu, $komunikat, $plik, $linia, //print_r($zmienne, true) ); error_log(implode(LOG_SEPARATOR, $elementy) . PHP_EOL, 3, 'logi_'. date('Ymd') .'.log'); } set_error_handler('obsluga'); echo 'punkt 1'. PHP_EOL; trigger_error('Test wywolania notice', E_USER_NOTICE); echo 'punkt 2'. PHP_EOL; trigger_error('Test wywolania bledu', E_USER_ERROR); echo 'punkt 3'. PHP_EOL;
Powyższy kod spowoduje, że na ekranie zostanie wyświetlone tylko: „punkt 1, punkt 2, punkt 3″. Natomiast zarejestrowana funkcja przechwytująca informację o błędzie obsłuży w sposób „cichy” testowe wywołania błędów. Do funkcji przekazywane są takie informacje jak: poziom błędu, komunikat oraz plik i linia, w których błąd został znaleziony/zgłoszony i zmienne towarzyszące kontekstowi wywołania.
W tym przypadku dodatkowo dane zostały zapisane do pliku (generowanego osobno dla każdego dnia) z logami, gdzie poszczególne dane (oddzielone średnikami) zawarte są w jednym wierszu razem z godziną wystąpienia problemu. W 13 wierszu znajduje się przekazanie do pliku z logami zrzutu zmiennych, które w tej chwili jest nie aktywne, ponieważ zaburzałoby jednowierszowy podział dla zdarzeń. Jednak warto zapisywać również te dane, ponieważ pomagają w odnalezieniu źródła problemu.
Przy rozwiązywaniu problemu lub diagnozie błędu, który występuje w bardzo specyficznych okolicznościach przydatna jest funkcja debug_backtrace()
. Zwraca ona tablicę ze stosem wywołań od uruchomienia skryptu do wywołania jej samej – dla każdego wywołania podane są szczegółowe informacje pozwalające prześledzić kolejne kroki wykonania skryptu.
Zamiana na wyjątki
Ostatnią kwestią, którą poruszę jest zamiana wystąpień klasycznych ostrzeżeń/błędów na wyjątki. W PHP istnieje specjalnie zdefiniowany w tym celu typ wyjątku – ErrorException
. Sposób użycia został pokazany poniżej poprzez modyfikację poprzedniego przykładu.
<?php define('LOG_SEPARATOR', ';'); ini_set('display_errors', 1); error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE); function obsluga($kodBledu, $komunikat, $plik, $linia) { throw new ErrorException($komunikat, $kodBledu, 0, $plik, $linia); } set_error_handler('obsluga'); echo 'punkt 1'. PHP_EOL; trigger_error('Test wywolania notice', E_USER_NOTICE); echo 'punkt 2'. PHP_EOL; trigger_error('Test wywolania bledu', E_USER_ERROR); echo 'punkt 3'. PHP_EOL;
Natomiast efekt uruchomienia będzie się prezentował następująco (tylko początek):
punkt 1 Fatal error: Uncaught exception 'ErrorException' with message 'Test wywolania notice' in ...
Funkcja przechwytująca błędy przekazała swoje parametry do wywołania wyjątku ErrorException
, wyjątek został rzucony… i niestety zakończyło to się błędem, ponieważ wyjątek nie został złapany. Żeby temu zaradzić należałoby każde miejsce, w którym błąd jest zgłaszany ręcznie zamknąć w bloku try
/catch
i/lub zdefiniować globalną funkcję obsługującą nieprzechwycone wyjątki. To jest jednak temat na jeden z następnych wpisów.
Klasyczne błędy generowane przez interpreter lub zgłąszane ręcznie pozwalają na zakomunikowanie programiście, że coś jest nie tak i pomagają w rozwiązaniu problemu. Jednak spełniają rolę tylko informacyjną – zapisanie do logu, wysłanie powiadomienia na e-mail czy pokazanie użytkownikowi strony z informacją o błędzie aplikacji. Natomiast w oparciu o mechanizm obsługi błędów nie ma możliwości reagowania na konkretne i przewidywalne problemy (jeżeli pojawia się wywołanie trigger_error()
to programista przewidział ewentualny problem). Rozwiązaniem jest wykorzystywanie wyjątków, które mogą być przechwytywane globalnie (tak jak błędy) oraz lokalnie dając programiście szanę na obsługę konkretnego zaistniałego problemu (a nie tylko w oparciu o poziom błędu).
Autor wpisu: Łukasz Socha, dodany: 08.09.2013 14:23, tagi: css
W dobie coraz większej ilości wszelakich urządzeń mobilnych tworzenie stron dostosowanych pod różne rozdzielczości jest już praktycznie standardem. Dziś opiszę jedną z technik wykorzystywanych w RWD (Responsive web design), a jest nią Fluid layout.
Krótko mówiąc, Fluid layout polega na tworzeniu „płynnych” układów stron. Możemy zrobić tak, że lewa kolumna (np. nawigacja) będzie mieć stałą szerokość, natomiast środek z treścią strony będzie dostosowywać się do rozdzielczości urządzenia. Przeanalizujmy przykład.
<div class="main"> <div id="left"> Sidebar </div> <div id="center"> <h1>Title</h1> <p>Lorem ipsum...</p> </div? </div>
.main{ width:80%; margin: 0 auto; } #left{ width:200px; float: left; } #center{ margin-left: 250px; }
I to by było na tyle . Jest to prosta w użyciu technika. Dla lewej kolumny wystarczy nadać atrybut float: left. Natomiast dla środkowej kolumny musimy ustawić lewy margines wynoszący co najmniej tyle co szerokość lewej kolumny. Jak to wygląda możecie zobaczyć na tej stronie. W przykładzie ze strony wykorzystano padding, ale w obu sposobach efekt jest taki sam.