Wyrażenia regularne unicode

Problem

Mamy formularz z polami, które musimy zwalidować pod kątem poprawności danych. Pole może zawierać jedynie litery (duże, małe – wszystko jedno).

Jakim wyrażeniem regualarnym realizujemy sprawdzanie? Pierwsza myśl to [a-zA-Z]… niestety walidacja nie zadziała poprawnie, gdyż w zakres [a-z] uwzględnia jedynie 26 liter alfabetu łacińskiego natomiast nie uwzględnia znaków diakrytycznych czyli litery [ą, ć, ę, ł, ń, ó, ś, ź, ż] nie spełnią kryterium walidacji.

Zatem aby walidacja działała poprawnie trzeba by dodać do zbioru [a-zA-Z] litery ze znakami diakrytycznymi. Otrzymujemy zatem wyrażenie: [a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]. Wyrażenie to zadziała poprawnie, jednak jest narażone na potencjalne błędy, łatwo zapomieć o którejś literze lub zrobić literówkę. W przypadku gdy tworzymy aplikacje multijęzykową czynność tą będziemy musieli powtórzyć dla każdego z obsługiwanych języków.

Poprawne rozwiązanie

W programowaniu jak już coś sie robi to należy zrobić to porządnie, tak aby swojego kodu nie trzeba było poprawiać, modyfikować etc…

Z pomocą przychodzi nam kodowanie UNICODE, w które umożliwia napisać reguły na litery posiadające znaki diakrytyczne. Wyrażenie \p{L} oznacza jakąkolwiek literę w jakimkolwiek języku, może by być: Ł, ź, ü, ß czy cookolwiek co jest literą (także nie łacińską). Zatem nasze wyrażenie walidujące pole zawierające włącznie litery będzie wyglądać następująco:

preg_match('#^\pL+$#', 'MałyŁoß');

Gwoli wyjaśnienia \pL to skrót od \p{L} a \p{L} oznacza znak (code point) unicode \p należący do kategorii liter {L}.

Klasy/kategorie znaków w unicode:

\p{L} – wszystkie litery
\p{M} – wszystkie znaki, które samotnie nie występują, musi być połączony z innym znakiem i składa się na np. akcent, umlaut, etc…
\p{Z} – wszystkie znaki niewidoczne
\p{S} – wszystkie symbole, znaki walut, znaki matematyczne
\p{N} – wszystkie znaki numeryczne
\p{P} – wszystkie znaki interpunkcyjne: przecinki, średniki etc…
\p{C} – wszystkie niewidoczne znaki kontrolne i niewykorzystywane znaki code point

Przeczytaj więcej o właściwościach wyrażeń regualrnych w unicode.

Sztuczki w wordpress’ie: przeciążanie standardowych funkcji dostępnych w szablonie

Gdy programujemy w szablonie skórki WordPress’a możemy korzystać z całej masy funkcji dostępnych w engine WordPress’a. Niektóre z nich zwracają wartości, inne od razu drukują na ekran, zwykle są parametryzowane i możliwość konfiguracji jest wystarczająco duża.

Problem

Niestety z czasem zawsze przychodzi pewne 'ale’… chcielibyśmy aby standardowa funkcja wordpressa działała minimalnie inaczej. Zatem musimy zmodyfikować jej kod… ale stop nie możemy tak bezczelnie nadpisywać funkcji wordpress.Takie hamskie haki są niedopuszczalne z kilku powodów:

  • Utrudniamy przyszłe aktualizacje, po każdej aktualizacji będziemy musieli pamiętać aby w pliku XXX w linii YYY wstawić swojego hacka.
  • Ta sama funkcja może być wywoływana w innym pliku szablonu, może to powodować błędne/niechciane działanie. Pozatym gdy zmienimy skórkę na inną to hack pozostanie dalej mimo, że już go nie będziemy potrzebować
  • Hack’owanie kodu jakichkolwiek bibliotek/frameworków czy takich gotowych kombajnów jak wordpress jest sprzeczne z zasadami programowania.

Zatem jak sobie z tym problemem poradzić?

Wszelkie gotowe rozwiązania powinno się rozszerzać nie modyfikując przy tym źródeł samej głównej aplikacji. Jeżeli takie rozszerzenie jest nie możliwe to oznacza, że aplikacja została źle napisana i należy poszukać innej rozszerzalnej.

Czy rozszeżać funkcje w WordPress?

Oczywiście. Posłużymy się w tym celu trochę zapomnianym plikiem szablonów: functions.php. Jeżeli plik functions.php nie istnieje w katalogu głównym naszej skórki to go tworzymy. Plik ten jest automatycznie ładowany wraz z uruchomieniem WordPress’a, można w nim umieszczać swoje dedykowane dla skórki funkcje oraz jak w naszym przypadku funkcje speudo przeciążające.

Zwykle w szablonach nie ma tego pliku, także świadomość programistów wordpress’owych na temat jego jest niewielka. Zatem radze sobie zapamiętać o takiej możliwości!

Dobra, a więc załóżmy, że chcemy zmodyfikować działanie funkcji the_content_rss. Tworzymy zatem w pliku functions.php funkcję my_the_content_rss.

function my_the_content_rss($more_link_text='(more...)', $stripteaser=0, $more_file='', $cut = 0, $encode_html = 0) {
	global $id;

	ob_start();
	the_content_rss('', $stripteaser, $more_file, $cut, $encode_html);
	$bufferContent = ob_get_contents();
	ob_end_clean();

	$bufferContent = preg_replace( '/\.\.\.\s*$/', '', $bufferContent );
	$bufferContent .=  '<span class="read-on"><a href="'. get_permalink() . "#more-$id\" class=\"more-link\">$more_link_text</a></span>";
	
	print $bufferContent;
}

Funkcja my_the_content_rss musi przyjmować co najmniej takie parametry parametry jak oryginalna funkcja the_content_rss. Wywołuje oryginalną funkcję, jako że the_content_rss nie zwraca wartości tylko drukuję ją na ekran musimy zatem poprzez ob_start() włączyć buforowanie, od tej pory wszystkie dane, które miały być drukowane są zapisywane w buforze, następnie poprzez ob_get_contents() odczytujemy ten bufor i kończymy buforowanie ob_end_clean().

Teraz mając w zmiennej $bufferContent wynik działania oryginalnej funkcji możemygo dostosować do naszych indywidualnych wymagań w przykładzie jest to wycięcie „…” oraz wstawienie linka do szczegółów posta.

Tyle. Następnie w szablonie w miejscach, w których potrzebujemy niestandardowy wygląd/dane szablonu wywołujemy zamiast the_content_rss nowo stworzoną funkcję my_the_content_rss.

FirePHP – przyjazne debug’owanie aplikacji internetowych

Debugowanie to poważny problem programistów

Bez względu na to jakimi dobrymi programistami jesteśmy nigdy nie ustrzeżemy się błędów. To normalne, błędy popełnia każdy, różnica pomiędzy dobrym programistą a złym polega m. in. na szybkości wykrycia błędnego kodu i naprawienia go.

Mówiąc o błędnym kodzie nie mam na myśli jedynie błędów syntaktycznych, ale również błędów logicznych, które nie powodują widocznych error’ów a jedynie błędne działanie aplikacji. Takie błędy są dużo trudniejsze do wykrycia.

Aby wykryć błędny kod niezbędne jest zdebugowanie zmiennych, obiektów, zasobów, które wykorzystywane są w tworzonej przez nas aplikacji. Brzmi banalnie, jednak w rzeczywistości nie jest to takie łatwe gdyż:

  • po pierwsze trzeba wstawić w odpowiednie miejsca funkcje var_dump() lub print_r()
  • po drugie funkcje te nie wyświetlają przejrzyste i łatwe do zinterpretowania dane
  • po trzecie debug’owanie na ekran może spowodować błędy aplikacji, a debugowanie do pliku jest niewygodne w odczycie (szczególnie w przypadku aplikacji flash’owych lub AJAX’owych)
  • po czwarte zdarza się, że format zwracanych danych uniemożliwia swobodne dodawanie własnych danych do debugowania (np. XML, JSon).
  • po piąge po skończeniu debugowania trzeba usunąć wszystkie instrukcje debugujące

Rozwiązaniem problemu debugowania jest FirePHP

Dużo tych wad… całe szczęście jest na to rozwiązanie. FirePHP to darmowa, open source’owa biblioteka, która wraz z pluginem do Firebug’a idealnie sprawdza się w roli debugera.

FirePHP debuguje dane w konsoli Firebug’a, informacje do debugowania są umieszczone w specjalnych nagłówkach HTTP przez co 'output’ aplikacji pozostaje w nienaruszonym stanie. Rewelacja prawda?

Instalacja firePHP

Wymagania FirePHP to PHP 5.2+, Firefox z pluginem Firebug.

  • Instalujemy plugina do firefox’a Firebug
  • Instalujemy plugina do Firebug’a FirePHP
  • Ściągamy źródła FirePHP, warto zauważyć, że na stronie dostępne są informacje, jak zintegrować bibliotekę z wieloma znanymi frameworkami (CakePHP, CodeIgniter, Drupal, Kohana, ExpressionEngine, PRADO, Symfony, TYPO3, Zend Framework).
  • Integrujemy FirePHP z naszą aplikacją
  • Odpalamy stronę aplikacji w Firefox z uruchomionymi plugin’ami Firebug i FirePHP
  • Klikamy na ikonę Firebug’a a następnie przechodzimy do konsoli. W konsoli powinny być zaprezentowane zdebugowane zmienne naszej aplikacji.
  • W przypadku problemów przydać się mogą: mini tutorial how to, forum dyskusyjne o FirePHP.

Przykład działania

Pod adresem http://blog.adiasz.pl/examples/firephp/ stworzyłem prosty skrypt AJAX’owy łączący się z bazą i wykonujący prościutkie operacje. Jest zintegrowany z FirePHP, zachęcam do testów. Naprawdę warto! (Oczywiście musicie najpierw zainstalować plugin FireBug i FirePHP). Wszystkie pliki wykorzystane w tym przykładzie dostępne są tutaj.

Przykład powinien zaprezentować coś w stylu:

Na koniec, bardzo ważna informacja: po opublikowaniu projektu musicie wyłączyć debugowanie FirePHP poprzez dyrektywę:

$fp = FirePHP::getInstance( true );
$fp->setEnabled ( false );

W przeciwnym razie każdy internauta posiadający zainstalowany ten plugin będzie miał dostęp do niebezpiecznych z punktu bezpieczeństwa danych. Najlepiej w konfigu aplikacji sterować to poprzez zmienną typu boolean $development = true/false. Samych instrukcji debugujących nie trzeba kasować gdyż nie wiadomo kiedy się jeszcze przydadzą.

ps. FirePHP dostępne jest także dla innych niż PHP języków programowania aplikacji webowych: ASP, Python, Ruby.

Darmowe narzędzia dla webmasterów: statystyki serwisu

Ostatnio w ramach optymalizacji czasu i automatyzacji wykonywanych przez zemnie zadań stworzyłem mini aplikację sprawdzającą statystyki moich serwisów w wyszukiwarkach.

Aktualnie sprawdzam: Google PR, Google link, Google site, Yahoo link, Yahoo site, MSN site. Monitoringu pozycji słów kluczowych na razie nie robiłem, gdyż jest wiele tego typu dobrych i darmowych sprawdzaczy na necie – więc szkoda czasu.

Aplikacja działa tak:
* skrypty sprawdzające statystyki wywoływane są z automatycznie z cron’a, dane zapisują w bazie
* po zalogowaniu prezentowana jest lista najnowszych statystyk
* generowane są dzienne wykresy poszczególnych statystyk serwisów

Prościutkie, teraz zamiast sprawdzać ręcznie tysiące parametrów wystarczy się zalogować do panelu. Wyniki zostaną zaprezentowane szybki i w przejrzysty sposób.

Dla szerokiego internetu udostępniłem wersję uproszczoną – możliwość sprawdzenia wyżej wymienionych statystyk dla podanego adresu: zapraszam na darmowe narzędzia dla webmasterów. Nic odkrywczego, ale może komuś się przyda.

Aplikacja została napisana we framework’u: Kohana, o którym postaram się napisać niedługo, a już teraz polecam się z nim zapoznać.

Interfejs a klasa abstrakcyjna

Interfejsy i klasy abstrakcyjne zostały wprowadzone do php od wersji 5.0. Konstrukcje te znacznie pomagają w uporządkowaniu struktury aplikacji, pozwalają na zachowanie kontroli typów, integralność oraz logiczną budowę aplikacji.

Dzięki wdrożeniu tych konstrukcji do aplikacji możemy w lepszy i logiczniejszy sposób odwzorować rzeczywistość a zarazem ustrzec się potencjalnych błędów, poza tym zyskujemy większą kontrolę nad modelowaną obiektową rzeczywistością.

Klasy abstrakcyjne
Klasy abstrakcyjne służą do modelowania rzeczywistości, którą chcemy przenieść do logiki swojej aplikacji. Klasa abstrakcyjna definiuje w dużej ogólności pewien podstawowy model i zachowanie obiektu.

Powiedzmy, że chcemy chcemy stworzyć wirtualne zoo. W zoo znajdować się będą różnorakie zwierzęta np: małpy, lisy, wiewiórki, motyle, pszczoły, żaby, jaszczurki.

Każde zwierzę opisywane jest przez podstawowe atrybuty jak: wiek, rozmiar oraz cechy taki jak: rodzenie, chodzenie, jedzenie.

Tworzymy zatem podstawową klasę abstrakcyjną 'Zwierze’ zawierającą abstrakcyjne metody: born, go, eat:

abstract class Animal {

	protected $age;
	protected $width;
	protected $height;

	abstract protected function born();
	abstract protected function go();
	abstract protected function eat();

	protected function setAge( $years ) {
		$this->age = $years;
	}

	protected function setSize( $width, $height ) {
		$this->width = $width;
		$this->height = $height;
	}
}

Dzięki użyciu klasy abstrakcyjnej mamy pewność, że nikt nie stworzy obiektu klasy 'Zwierze’. Z logicznego punktu jest to niemożliwe gdyż nie ma zwierzęcia 'Zwierze’ – taki byt w rzeczywistości nie istnieje gdyż jest to zbyt ogólne pojęcie.

Dodatkowo zadeklarowaliśmy metody born, go, eat jako abstrakcyjne co wymusi ich implementacje w klasach dziedziczących – to też jest jak najbardziej logiczne gdyż nie ma zwierzęcia, które nie może wykonywać tych czynności. Metody te deklarujemy jako abstrakcyjne gdyż nie znając zwierzęcia nie wiemy jeszcze jak je zaimplementować. Metody abstrakcyjne muszą być puste.

Zadeklarowaliśmy również podstawowe atrybuty ($age, $width, $height), które każde zwierze posiadać musi, oraz settery które je ustawiają. Przy setterach ustawiamy specyfikator dostępu protected, dzięki temu będą mogły być wywoływane jedynie z poziomu metod klas dziedziczących. Nie ustawiamy ich jako abstrakcyjnych gdyż ich implementacja w klasie 'Animal’ jest wystarczająca i klasy potomne będą z nich korzystać.

Tworzymy teraz klasę konkretnego zwierzęcia np. małpy:

require_once 'animal.php';

class Monkey extends Animal {

	public function born() {/*@TODO*/}
	public function go() {/*@TODO*/}
	public function eat() {/*@TODO*/}

	public function __construct( $age, $size ) {
		$this->setAge( $age );
		$this->setSize( $size[0], $size[1] );
	}
}

$monkey1 = new Monkey( 2, array( 100, 20 ) );
var_dump( $monkey1 );

Musi ona posiadać metody abstrakcyjne, w ciele klasy 'Monkey’, powinny one przybrać docelową formę. Jak widać nie ma setterów, jest za to konstruktor przyjmujący parametry obiektu i wywołuje odpowiednie settery z klasy bazowej 'Animal’.

Interfejs
Klasa abstrakcyjna jest dość mocno związana logicznie z obiektami z niej dziedziczącymi. Widać jasno, że małpa i lis są integralnie związane z definicją zwierzęcia. Interfejs natomiast jedynie narzuca klasie jakie metody powinna posiadać, interface definiuje pewne właściwości, które klasa musi spełniać. Sam w sobie nie definiuje logicznej zależności pomiędzy sobą a klasą go implementującą, definiuje natomiast powiązanie pomiędzy wszystkimi klasami go implementującymi. Agreguje klasy obiektów na których można wykonać pewne operacje.

Kontynuując przykład zoo… załóżmy, że zoo może sprzedawać i kupować zwierzęta zatem możemy stworzyć interface 'Trade’:

interface Trade {
	public function sell();
	public function buy();
}

Dodatkowo, zwierzęta podlegają ubezpieczeniom zatem tworzymy interface 'Insurance’:

interface Insurance {
	public function make();
	public function withdrawn();
}

Jedna klasa może implementować wiele interfejsów, w przykładzie zoo 'Animal’ będzie implementował zarówno 'Trade’, jak i 'Insurance’. Jak widać kolejne interfejsy nie są ze sobą związane jednak wpływają na zachowanie się obiektu zwierzęcia.

class Monkey extends Animal implements Trade, Insurance {
	public function born() {/*@TODO*/}
	public function go() {/*@TODO*/}
	public function eat() {/*@TODO*/}
	
	public function sell() {/*@TODO*/}
	public function buy() {/*@TODO*/}
	
	public function make() {/*@TODO*/}
	public function withdrawn() {/*@TODO*/}
	

	public function __construct( $age, $size ) {
		$this->setAge( $age );
		$this->setSize( $size[0], $size[1] );
	}
}

Ale przecież w zoo są nie tylko zwierzęta ale także budynki i ludzie. Budynki mogą być odprzedawane a ludzie ubezpieczani zatem klasy reprezentujące te obiekty także powinny implementować te interfejsy.

Klasa 'People’ powinna implementować 'Insurance’ a klasa 'Building’ interfejs 'Trade’.

class People implements Insurance {
	public function make() {/*@TODO*/}
	public function withdrawn() {/*@TODO*/}
}
class Building implements Trade {
	public function sell() {/*@TODO*/}
	public function buy() {/*@TODO*/}
}

Widzimy zatem, że klasy reprezentujące zupełnie różne obiekty (zwierzęta, budynki) w pewnym zakresie zachowują się tak podobnie (można je kupić i sprzedać) zatem implementują interface 'Trade’.

Dzięki zapisowi tych zależności nasza aplikacja nabiera logicznego kształtu a dodatkowo dzięki parserowi zyskujemy darmową walidację, gdyż w przypadku braku metody z interfejsu php zwróci błąd – zatem nie zapomnimy o jej implementacji.

WP-Cache – rozwiązania problemów z semget i działaniem

WP-Cache to bardzo przydatny plugin do Word Press’a. Plugin ten zapisuje każdą wygenerowaną stronę w postaci statycznego pliku HTML na serwerze przez co znacznie zmniejsza obciążenie serwera i bazy danych. Długość cache, jak i reguły opisujące pliki/strony, które mają być cache’owane można ustawić z poziomu panelu WP.

Ostatnio zetknąłem się z dwoma problemami w użytkowaniu tego plugina, poniżej rozwiązania:

Problem 1:
Za każdym razem, gdy strona generowana jest po raz pierwszy pojawia się komunikat w górze strony:

Warning: semget() failed for key 0x152b: Permission denied in /XXX/wp-content/plugins/wp-cache/wp-cache-phase2.php on line 98

Rozwiązanie:
Trzeba zedytować plik: wp-content/plugins/wp-cache/wp-cache-phase2.php w linii 98:
zamienić:

$mutex = sem_get($sem_id, 1, 0644 | IPC_CREAT, 1);

na

$mutex = @sem_get($sem_id, 1, 0644 | IPC_CREAT, 1);

Znak @ przed funkcją php blokuje komunikaty o błędach, spowodowanych daną funkcją.

Alternatywą tego rozwiązania jest dopisanie

ini_set( 'display_errors', 0 );

w pliku wp-config.php W tym wypadku zablokujemy wyświetlania się komunikatów o błędach globalnie w całym Word Press’ie.

Problem 2:
WP-Cache jest poprawnie zainstalowane, włączone, jednak strony się nie cache’ują.

Sprawdz czy w katalogu wp-content znajduje się plik

!advanced-cache.php

Jeżeli tak to oznacza, że WP-Cache ma źle podlinkowany plik wp-cache-phase1.php

Rozwiązanie:
Najpierw należy skasować plik !advanced-cache.php.

Następnie przypadku gdy mamy dostęp ssh trzeba z poziomu katalogu wp-content wykonać polecenie unix’owe, które stworzy link symboliczny do tego pliku wykorzystywany przez skrypty WP:

ln -s   plugins/wp-cache/wp-cache-phase1.php advanced-cache.php

Gdy nie mamy ssh musimy zainstalować wtyczkę jeszcze raz (zdeaktywować i aktywować).

Przyjemna komunikacja php – flash czyli AMFPHP

Z pewnością każdy programista php, który w swoim projekcie musiał komunikować się z flash’em na własnej skórze doświadczył, że nie jest to zadanie ani przyjemne ani przyjazne w implementacji.

Aby przekazać dane flash’owi, skrypty muszą generować XML’e, które następnie zasysa flash i przetwarza Action Script’em. Bolączek tego rozwiązania jest wiele, poczynając od dodatkowego czasu potrzebnego na implementacje, wygenerowania XML i późniejszego jego zdekodowania a skończywszy na generowaniu sztucznego transferu, ograniczeniach w wielkości plików XML i trudności w debugowaniu.

Znamy zatem bolączki standardowej komunikacji php-flash, zatem trzeba zadać sobie pytanie czy możemy ich uniknąć? Oczywiście!

AMFPHP czyli przyjazna komunikacja na lini php – flash

AMFPHP to open source’owa implementacja Action Message Format (AMF). Bibliteka ta poprzez RPC (Remote Procedure Call) pośredniczy w komunikacji skryptów Action Script ze skryptami serwerowymi, przesyłane dane są serializowane do postaci binarnej. Wymiana danych następuje poprzez plik gateway.php. AMFPHP zachowuje typu danych: obiekt, tablica, wartości typu int, null, bool będą w tej samej postaci dostępne w Action Script w php.

Powyższy opis może nieco odstraszać egzotycznymi nazwami, to tylko teoria w praktyce nie ma się czego obawiać, zaraz na przykładzie pokaże, że instalacja jak i konfiguracja jest banalna.

1. Ściągamy najnowszą wersję AMFPHP, aktualnie jest to wersja 1.9 beta 2. Znaczkiem beta nie ma się co zanadto przejmować, gdyż wersja ta jest stabilna i dobrze przetestowana.
2. Rozpakowywujemy archiwum powyżej document_root gdyż katalog browser i plik gateway.php muszą być dostępne przez HTTP. Resztę plików można by schować poniżej document_root, jednak na potrzeby tej prezentacji nie będę się w takie szczgóły zagłębiać.
3. W katalogu services tworzymy usługi, które maja postac klas PHP. Kod przykładowej usługi:

<?php
require_once( '/my_application/library/core_classes/game.php' );

class FlashGame {

	private $game;
	
	public function __construct() {
		$this->game = new Game();
	}
	
	/**
	 * Metoda zwraca informacje o grze i uzytkowniku
	 *
	 * @param integer - id gry
	 * @param integer - id usera
	 * @return array
	 */
	public function getResults( $gameID, $userID ) {
		$response['info'] = $this->game->getGameInfo( $gameID );
		$response['user'] = $this->game->getUserInfo( $userID );

		return $response;
	}

	/**
	 * Metoda usua uzytkownika
	 *
	 * @param integer - id usera
	 * @return bool
	 */
	public function remove( $userID ) {
		return (bool)$this->game->remove( $userID );
	}
	
	/**
	 * Metoda zwraca obiekt gry
	 *
	 * @return Object
	 */
	public function getGameObject() {
		return $this->game->getGameObject();
	}
}
?>

Klasy usług powinny być maksymalnie proste i jedynie odwoływać się do klas logiki biznesowej aplikacji. Taka konstrukcja zapewnia jasny i przejrzysty kod aplikacji i jest zgodna z kanonami programowania.

Jeżeli poprawnie wykonaliśmy powyższe operacje to będziemy mogli odpalić browsera i z jego poziomu przetestować działanie. Odpalamy browsera (tutaj przykład), przy pierwszym odpaleniu pyta się nas o ścieżkę do gateway i prezentacje wyników, wybierzmy 'tree view’, i klikamy OK.

Po lewej stronie widzimy dostępne usługi, po dwukrotnym kliknięciu na nazwę usługi pojawiają nam się dostępne metody. Domyślnie widoczne są wszystkie metody, można to zmienić pisząc znak podkreślenia na początku jej nazwy. Każda metoda opisana jest komentarzem wyciągniętym z klasy oraz zawiera pola na wprowadzenie testowych danych. Pola te odpowiadają parametrom przyjmowanym przez tą metodę.

Z poziomu browsera możemy przetestować działanie metod poprzez kliknięcie na przycisk call, wyniki prezentowane są w oknie poniżej. Prezentowany wynik jest identyczny z tym co dostaje Flash. Po publikacji aplikacji należy pamiętać o skasowaniu lub zabezpieczeniu hasłem dostępu katalog browsera.

Zatem podsumujmy co daje nam AMFPHP:

  • oszczędność w implementacji
  • łatwe testowanie i debugowanie aplikacji
  • mniejszy transfer serwera
  • większa szybkość działania aplikacji
  • przejrzystość i skalowalność
  • bezpieczeństwo (dane przesyłane binarnie a XML w postaci jawnej)
  • proste wdrożenie do aplikacji

Tutaj do ściągnięcia jest cała paczka AMFPHP wraz z przykładowymi serwisami.

Automatyczne przeglądanie kont na naszej klasie

Ostatnio zapragnąłem trochę posurfować po największym portalu społecznościowym w Polsce jakim jest Nasza-Klasa. Poniżej prościutki kod odwiedzający losowe konta.

Deklarujemy zmienne do logowania, plik przetrzymujący ciasteczka i nazwę przeglądarki z jaką będzie się przedstawiał nasz automat.

$cookie = 'cookie.txt';

$loginUrl = 'http://nasza-klasa.pl/login';
$login = 'login';
$password = 'pass';
$useragent = 'Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3';

Logujemy się na konto n-k:

$ch = curl_init( $loginUrl );
curl_setopt( $ch, CURLOPT_COOKIEFILE, $cookie );
curl_setopt( $ch, CURLOPT_COOKIEJAR, $cookie );
curl_setopt( $ch, CURLOPT_COOKIE, $cookie);
curl_setopt( $ch, CURLOPT_USERAGENT, $useragent );
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, 'login='.$login.'&password='.$password );
curl_setopt( $ch, CURLOPT_REFERER, 'http://nasza-klasa.pl/' );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1);
$afterLogin = curl_exec($ch);
curl_close($ch);

Wywołujemy adresy losowych kont:

for( $i=1; $i<=100; $i++ ) {
	$profileID = rand( 1000, 15000000 ); // rand
	
	$ch = curl_init( 'http://nasza-klasa.pl/profile/'.$profileID );
	curl_setopt( $ch, CURLOPT_COOKIEJAR, $cookie);
	curl_setopt( $ch, CURLOPT_COOKIEFILE, $cookie);
	curl_setopt( $ch, CURLOPT_COOKIE, $cookie);
	curl_setopt( $ch, CURLOPT_USERAGENT, $useragent );
	curl_setopt( $ch, CURLOPT_HEADER, 0);
	curl_setopt( $ch, CURLOPT_REFERER, 'http://nasza-klasa.pl/' );
	curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1);
	$profile = curl_exec($ch);
	curl_close($ch);
	
	if( !preg_match( '/Nie znaleziono strony \(404\)/', $profile ) ) {
		// konto istnieje
		// z danymi konta możemy zrobić co chcemy...
	} else {
		// nie ma konta takiego konta
	}
}

Ustawiamy w contab'ie wywołanie skryptu co 10 minut:

*/10 * * * * curl -s -o /dev/null PATH_TO_SCRIPT

Z uwagi na bardzo dużą liczbę kont prawdopodobieństwo odwiedzenia w niedługim czasie 2 razy tego samego konta jest stosunkowo niewielkie.

Jednak jeżeli chcemy odwiedzić każde konto jedynie raz to należy zmodyfikować skrypt tak aby przy każdym wywołaniu iterował po kolejnej setce kont. Informacje o ID od którego mamy zacząć możemy zapisywać w bazie danych lub w pliku.

Amazon s3 – sposób na tani hosting plików aplikacji.

Amazon s3 (Simple Storage Service) jest usługą online, która umożliwia składowanie danych na przestrzeni dyskowej serwerów Amazon. W zależności od potrzeb, dane mogą być składowane w USA bądź też w Europie. Usługa s3 wyposarzona jest w API dzięki któremu w prosty sposób można operować na składowanych zasobach.

Usługa ta jest niesamowicie tania, opłaty pobierane są od:

  • zajmowanego miejsca – $0.18 za 1GB / miesiąć
  • zużytego transferu – $0.10 za 1GB transferu IN, $0.10 – $0.17 za 1GB transferu OUT
  • liczby request’ów – $0.012 za 1,000 request’ów PUT, POST, LIST, $0.012 za 10,000 requesty GET i wszelkie inne

Jak widać opłaty są śmiesznie niskie, w przypadku serwisu posiadającego duże ilości multimediów (zdjęcia, wideo etc..) i generującego spory ruch dużo taniej wyjdzie korzystanie z s3 niż korzystanie z jakiegokolwiek hostingu.

Dzięki kalkulatorowi możemy zaplanować i przewidzieć przyszłe koszta i tak możemy wyliczyć, że miesięczny koszt przetrzymywania 10GB i 100GB tranferu kosztować będzie w okolicach $17. Tanio prawda?

Dodatkowo korzystając z usługi Amazon nie trzeba martwić się o utratę danych, bądź ich czasową niedostępność. Infrastruktura s3 jest naprawdę znakomita, jak do tej pory nie było żadnych przypadków przerw w działaniu, a szybkość działania jest naprawdę imponująca.

Jak korzystać?

Aby zacząć korzystać z s3 należy utworzyć konto a następnie aktywować usługę poprzez autoryzację karty kredytowej. Polecam zaznajomić się z obszernym artykułem opisującym filozofie działania Amazon Web Services.

Powstało wiele bibliotek ułatwiających pracę z API s3, na wyróżnienie zasługuje class.s3.php.
Poniżej prościutki przykład użycia tej klasy:

//tworzymy obiekt klasy s3 przekazując identyfikatory naszego konta
$s3 = new S3($AMAZON_KEY, $AMAZON_PRIVATE_KEY);

//tworzymy folder
if( !$s3->bucketExists( 'FOLDER' ) ) {
	$result = $s3->createBucket( 'FOLDER' );
}

//wgrywamy plik
$result = $s3->putObject( 'FOLDER', 'DIST_FILE_NAME', 'PATH_TO_FILE', true );

//od tej chwili możemy się odwoływać do wgranego pliku poprzez http
//http://s3.amazonaws.com/FOLDER/DIST_FILE_NAME

//odczytujemy informacje wgranego obiektu
$objectData = $s3->getObjectInfo( 'FOLDER', 'DIST_FILE_NAME' );

if( !$result ) {
  print $s3->_error ;
}

//kasowanie elementow folderu
$s3->recursiveDelete( 'FOLDER', '' );

Uwaga, klasa ta wymaga dostępu do curl’a bash’owego.
W przypadku gdy funkcja shell_exec() jest zablokowana należy skorzystać z innej biblioteki np. phps3tk.

update 2008-12-19:
Znalazłem bardzo przydatny plugin do Firefox’a Amazon S3 Firefox Organizer(S3Fox), który umożliwia zarządzanie danymi na Amazon s3 z poziomu przeglądarki.

Plugin S3Fox umożliwia praktycznie wszystkie operacje na Amazon S3 jakie udostępnia API: przeglądanie, tworzenie/kasowanie/modyfikowanie folderów, wgrywanie i kasowanie zasobów oraz zarządzanie prawami dostępu do danych.

Dodatkowo generuje log z wykonanych czynności oraz wiele ułatwień. Dzięki niemu możemy przetestować poprawność naszych mechanizmów php’owych, oraz w przypadku jednorazowego upload’u zaoszczędzić czas na pisanie skryptów.

Strona domowa projektu S3Fox.

Proste i skuteczne zabezpiecznie przez spamującym botem.

Tworząc aplikacje internetowe dostępne bez autoryzacji dla wszystkich internautów musimy liczy się z tym, że wszelkie formularze są narażone na setki spamu wstawianego przez różnorakie boty.
Dotyczy to np. formularza kontaktowego lub chociażby formularz komentowania WordPress’a.

Rozwiązań jest wiele: można zaserwować botowi zagadkę logiczną typu „ile to jest 4+4=?” lub wstawić znienawidzony przez wielu kod CAPTCHA, którego odgadnięcie w wielu przypadkach graniczy z cudem.
Ja proponuję inne i dużo prostsze rozwiązane skuteczne w ponad 99%.

Action formularza ustawiamy na # (czyli przeładowanie na bieżącą stronę) a następnie w prostym skrypcie javascriptowym podmieniamy na właściwy adres.

<form action="#" method="post" id="sample_form">
<fieldset>
  <label>Wiadomość:</label>
  <textarea rows="5" cols="5" name="message"></textarea>
  <br />
  <input class="button" type="submit" value="Wyślij" />
  </fieldset>
  <noscript><h3 class="red">Do poprawnego wysłania wiadomości wymagana jest włączona obsługa JavaScript.</h3></noscript>
</form>    

<script type="text/javascript">
<!--
  document.getElementById( "sample_form" ).action = 'http://www.sample.pl/send.php';
//-->
</script>

W ten sposób, jako, że żaden bot jeszcze nie umie (i nie zanosi się na to w najbliższej przyszłości) czytać JSa, parsując stronę HTML nie odnajdzie docelowego skryptu odbierającego dane z formularza a zatem jestesmy pewni, że nie dostaniemy żadnych niechcianych wpisów.
Użytkownikom, nie posiadającym włączonej obsługi javascript ukarze się stosowny napis zawarty w tagu noscript i jeżeli będzie im zależało na wysłaniu formularza to wierzcie mi, że włączą JSa ;-)

W przypadku opensourcowych skryptów typu WordPress istnieje możliwość, że boty będą próbować odwoływać się bezpośrednio do domyślnego pliku odbierającego dane, w takim przypadku wystarczy zmienić jego nazwę choćby z wp-comments-post.php na wp-comments-post-2.php i sprawa załatwiona. Nie wierze aby komukolwiek chciało się ręcznie wpisywać do spamiarki adresy.