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

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

W poprzednim poście opisującym internacjonalizacje w Cake'u mogłoby się wydawać, że wyczerpałem temat. Jednak w używaniu Translate Behavior występują inne problemy, które należy rozwiązać - niestety samodzielnie. Pierwszy z problemów, który spotyka nas używając Translate Behavior jest brak możliwości zwracania treści tłumaczonych dynamicznie z modeli z którymi mamy relacje (hasMany i belongsTo).

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:

Autor wpisu: bastard13, dodany: 20.09.2013 13:58, tagi: php, oop

Ostatnio, przeglądając jedno z reviewew mój kolega z zespołu rozpoczął rozmowę na temat naszych pseudo-enumów w aplikacji.Nie odkryliśmy tutaj koła na nowo i nasze "klasy enumeracyjne" wyglądały tak, jak w większości frameworków, bibliotek i aplikacji, które widziałem, a które zostały napisane w PHP:
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 na STDERR (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).

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

Autor wpisu: Jacek Skirzyński, dodany: 07.09.2013 23:18, tagi: php

Pliki projektu mogą być różnie rozlokowane w katalogach a ich łączenie odbywa się z wykorzystaniem funkcji include()/require() i ich wariantów *_once()1. Podawanie ścieżek bezwzględnych zupełnie mija się z celem ponieważ inna będzie na komputerze programisty inna na hostingu. Natomiast zmienianie ich przy przegrywaniu jest stratą czasu i narażaniem się na ewentualne problemy (przy zapomnieniu o zmianie czy błędzie w ścieżce).

Rozwiązaniem tego problemu jest dyrektywa konfiguracyjna include_path i używanie ścieżek względnych.

Bieżącą wartość dyrektywy można sprawdzić w następujący sposób:

<?php
print get_include_path(); // u mnie: .:/usr/share/php:/usr/share/pear

Znak kropki w wyniku odnosi się do bieżącego katalogu, natomiast dwukropek to separator ścieżek (można ustawić ich wiele). /usr/share/php i /usr/share/pear to ścieżki, które będą przeszukiwane przy próbie dołączenia plików z użyciem ścieżki względnej.

Jest już przykład odczytania wartość include_path, teraz czas na zmianę wartości i odpowiedź na pytanie: po co to robić?

Do zmiany wartości służy funkcja set_include_path() z pomocą wspomnianej funkcji do odczytu bieżącej wartości oraz stałej PATH_SEPARATOR.

<?php
// wariant 1
set_include_path('/jakas/sciezka/do/katalogu'); 
print get_include_path(); 
// pokaże: /jakas/sciezka/do/katalogu

// wariant 2
set_include_path(get_include_path() . PATH_SEPARATOR . '/jakas/sciezka/do/katalogu');
print get_include_path(); 
// pokaże: .:/usr/share/php:/usr/share/pear:/jakas/sciezka/do/katalogu

Wariant pierwszy pokazuje jak ustawić tylko swoje wartości include_path nadpisując przy tym poprzednie (należy uważać z takim użyciem, ponieważ usunięcie znaku kropki może spowodować wiele komplikacji). Wariant drugi jest dużo mniej inwazyjny i zamiast usuwania poprzednich wartości zwyczajnie dodaje do nich nową oddzielając ją za pomocą stałej (separatorem są znaki dwukropka).

Ostatnią kwestią jest przydatność możliwości zmiany tej dyrektywy. Jedną z sytuacji jest używanie pakietów PEAR, których nie ma globalnie na hostingu i jest jakiś problem z ich zainstalowaniem przez administratora. Rozwiązaniem może być utworzenie w obrębie konta własnego zbioru pakietów PEAR i dodanie ścieżki do tego katalogu do include_path. Późniejsze użycie tych pakietów jest takie samo jak tych dostępnych globalnie.

1 – najwygodniejszym sposobem dołączania plików z klasami jest użycie autoładowania (które ostatecznie również sprowadza się do dołączania plików), o którym również postaram się niedługo coś napisać

Autor wpisu: Jacek Skirzyński, dodany: 05.09.2013 23:45, tagi: php

W najbliższym czasie odbędzie się konferencja PHPCon 2013. A dokładnie to 25-27 października 2013 w Szczyrku. Jest to chyba największa w kraju konferencja związana z językiem PHP a dodatkowo przyjeżdżają też prelegenci z zagranicy. W ubiegłbym tygodniu zakończyło się głosowanie na tegoroczną agendę, z którą można się zapoznać tutaj. Wszyscy zainteresowani konferencją mogą uzyskać więcej informacji na stronie konferencji, a nawet zapisać się – rejestracja uczestników jest jeszcze otwarta.

Jednak oprócz informacji na temat tegorocznego PHPCon chcę też zwrócić uwagę na materiały konferencyjne z poprzednich edycji, ponieważ na prawdę są warte uwagi.

Linki:

  1. Strona tegoroczej edycji PHPCon
  2. Materiały z PHPCon 2010
  3. Materiały z PHPCon 2011
  4. Materiały z PHPCon 2012
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.