Aktualizacja PunBB i polskie tłumaczenie
0Jakiś czas temu wyszła nowa wersja PunBB oznaczona numerem 1.4.2. Konieczne było zaktualizowanie polskiego pliku językowego. Polski pakiet językowy do forum PunBB 1.4.2
Oprócz tego w dziale download umieściłem najnowsze wersje moich rozszerzeń do PunBB
Framework idealny? Controller
0Zawsze irytowało mnie w ZF (i nie tylko w nim), że metody do uruchomienia są jak takie zwykłe pojemniki na kod. Dlaczego nie posiadają one żadnych argumentów. Wszystko się wyciąga z jakichś magicznie powstałych nagle obiektów, które znalazły się kontrolerze (np $this->_request) – skąd on się tu wziął? Inna sprawa to, że “parametry” wyciąga się z funkcji “getParam”. No dobrze, ale skąd ten param? Z adresu? Z posta? geta? cookies? sesji? Skąd to się wzięło. Jest oczywiście to brane z tablicy $_REQUEST o ile mnie pamięć nie myli a ona może być inaczej zbudowana na różnych maszynach i różnych konfiguracjach – np parametry z GET będą przez POST albo odwrotnie. To jest kolejna z rzeczy, która moim zdaniem ułatwia użytkownikowi źle napisać kod. Nie jest tajemnicą, że parametry przesyłane są do PHP za pomocą różnych metod… gdzie najpularniejsze to POST i GET. Parametr w GET i POST może istnieć i mieć taką samą nazwę a służyć do zupełnie innej rzeczy a dodatkowo można jeszcze sztucznie tworzyć parametry przekazywane z requestu. W ZF wygląda to tak:
public function editAction()
{
$id = $this->_request->getParam('id'); // Ale skąd to Id?
$title = $this->_request->getParam('title'); // To z geta, posta czy z adresu url?
$this->view->title = $title;
$this->view->id = $id;
}
Nowy tytuł to <?php echo $this->title ?> o id: <?php echo $this->id ?>
Nie wiadomo skąd się co bierze. Poza tym Zend zakłada, że ja jakiś szablon potrzebuje i musze mu zmienna przekazać, zeby coś odpowiedziec. Ani mi do tej funkcji nic nei “wchodzi” ani z niej nie wychodzi.
Moja idea również zainspirowana django wygląda tak:
// Adres routingu
'article/edit,(?<id>\d+).html => Article.edit
public function edit($request, $id)
{
// id mam jako argument funkcji z adresu
$title = $request->getPost('title'); // Aha no to ktoś postem puścił
return new Response('Nowy tytuł to ' . $title . ' o id: '. $id);
}
Tutaj parametrem wejściowym jest request oraz parametry adresu. Poza tym sam decyduje o tym co odpowiem. Czy skorzystam z szablonu czy chcę po prostu napisac sobie “Hello” i tyle.
Framework idealny? Routing
0Pierwszy z cyklu już bardziej konkretnych przemyśleń i wizji dotyczących poszczególnych komponentów “idealnego frameworka”. Tym razem chciałbym omówić moją wizję routingu gdyż jakby od niego wszystko się zaczyna.
Routing w praktyce
Routing – to dzięki temu rozwiązaniu gdy użytkownik wywołuje konkretne żądanie (adres i typ) router przekazuje polecenie do odpowiedniej części systemu. To on rozpoznaje i wykonuje pracę listonosza – dostaje konkretny adres i przekazuje tam dany list. We wczesnych rozwiązaniach routing istniał w bardzo uproszczonej formie. Requesty w postaci:
?action=kontakt
oznaczał tylko tyle, że jest gdzieś wielki “switch” albo zestaw “else if” w których w zależności od wartości parametru “action” wykonywany był konkretny blok kodu. Oczywiście później zostało to usprawnione o bardziej zamknięte funkcje, dodano inne parametry akcji. W zasadzie można by nazwać takie rozwiązanie bardzo prostym routingiem.
We współczesnych rozwiązaniach możemy spotkać routing w bardziej zaawansowanej formie, gdyż wiele frameworków stara się implementować wzorzec MVC – chociaż osobiście nie znam żadnego, który by w pełni ten wzorzec implementował. MVC narzuca istnienie komponentów takich jak Model, Widok i Kontroler. Za kontroler przyjęta została klasa PHP która posiada różnorakie metody (akcje). W związku z tym aby nieco ułatwić dostęp do wykonywania poszczególnych akcji utworzono podstawowy wzór:
/controller/action
gdzie controller jest nazwą klasy kontrolera a action nazwą metody, która się w tej klasie ma uruchomić. Rozwiązanie proste i przyjemne. Podobne rozwiązanie funkcjonuje np w Zend Framework albo w Ruby on Rails. To rozwiązanie jest dobre do momentu gdy chcemy jednak zrobić coś bardziej skomplikowanego, np gdy:
- Specjalista SEO stwierdził, że adres ma jednak wyglądać w postaci /nazwa_uzytkownika albo /kontroler,akcja.html
- Trzeba podzielić funkcjonalności na bardziej logiczne części (np moduły)
- Konkretne adresy maja funkcjonować w ramach konkretnej domeny (subdomeny) w wielomodułowym lub wieloaplikacyjnym systemie
Jak sobie poradził z tym np Zend Framework? Ano jak to ZF, czyli “Zbuduj sobie sam”. Efekt jest taki, że robiąc bardzo prosty adres, potrzebuję kilku linijek (przykład dla pliku INI)
routes.forum_topic_add.route = "nowy-temat" routes.forum_topic_add.type = "Zend_Controller_Router_Route" routes.forum_topic_add.defaults.controller = topic routes.forum_topic_add.defaults.action = new
Whaaaat? Chciałem tylko podać adres i wskazać go na konkretną akcję do wykonania. O co tu chodzi? Poza tym to jest przecież jeszcze prosty adres. Nie ma tu żadnych wyrażeń regularnych. Gdybym chciał tak zrobić musiałbym dostawić jeszcze kilka dodatkowych linijek na każdy parametr. Dodatkowo, żeby nie było za prosto musiałbym zmieć router Zend_Controller_Router_Route na Zend_Controller_Router_Route_Regex – bo tamten już wyrażeń nie rozumie. Jeszcze, żeby było ciekawie poszczególne adresy można łączyć w łańcuchy a te łańcuchy w kolejne łańcuchy już z routerami i innym typie – np Static (tak jest jeszcze jeden typ). Tylko po co? Czy naprawdę programista musi mieć aż tak dokładną kontrolę nad tym?
Wydaje mi się, że programista powinien po prostu pomyśleć sobie adres i wskazać którą metodę/funkcję ma on uruchomić. Wyobrażam to sobie tak:
nowy-temat = topic.new
I co tu potrzeba więcej? Adres taki i taki, ma kierować na taką i taką funkcję. Po co mi takie dokładne pisanie gdzie jaki kontroler a jaka akcja a jaki to typ routingu. Tym powinien już się przejmować framework a nie programista.
No dobra dobra, ale przecież to jest taki prosty przykład. A co z parametrami? W zendzie można użyć kontrolera Route albo Static. Np tak:
routes.archive.route = "archive/:year/*" routes.archive.defaults.controller = archive routes.archive.defaults.action = show routes.archive.defaults.year = 2000 routes.archive.reqs.year = "\d+"
Powyższe rozwiązanie mówi tyle, że: jest wzór archive/:year. Ma ono odpalić kontroler archive i metodę show. A parametr :year ma być liczbą a gdy a domyślnie ma przyjąć wartość 2000. W celach optymalizacji używa domyślnego routera, który uznaje za parametry wyrażenia po znaku “:” i separuje je po slashu. Tylko, że jest dodatkowa walidacja na to aby parametr year był liczbą. Moim zdaniem zupełnie niepotrzebna komplikacja. Przykład poniżej jest nieco inne podejście:
routes.archive.type = "Zend_Controller_Router_Route_Regex" routes.archive.route = "archive/(\d+)" routes.archive.defaults.controller = "archive" routes.archive.defaults.action = "show" routes.archive.map.1 = "year"
Wzór routingu już jest zapisany bezpośrednio w adresie ale z kolei teraz trzeba w osobnym miejscu ponazywać poszczególne parametry. Znowu jakimś nowym cudacznym sposobem, który wymaga uruchomienia jakiegoś specjalnie napisanego parsera, gdzie jedne robi tak, a inny tak. Moim zdaniem idealny framework powinien oferować kompleksowe. jednolite rozwiązanie problemu. Programiści Zend Framework chyba sami nie znają za bardzo możliwości języka w którym piszą, bo jak inaczej wytłumaczyć fakt nie skorzystania z podstawowej umiejętności wyrażeń regularnych jaką jest named subpattern. Widziałem multum przykładów z różnymi konfiguracjami routingu ale nigdy nie widziałem tego prostego zastosowania. Ze strony PHP
preg_match('/(?<name>\w+): (?<digit>\d+)/', $str, $matches);
dzięki temu funkcja do wyrażeń regularnych automatycznie podstawia nam klucze sparsowanych parametrów jednocześnie dbając o poprawną walidację związaną z podanym typem wyrażenia. Sam nie jestem orłem jeśli chodzi o wyrażenia regularne ale to jest na tyle proste, że każdy to zrozumie. Dzięki temu można budować dowolnie skomplikowane adresy do routera. i bardzo proste i bardzo skomplikowane zachowując całkowitą spójność w sposobie ich tworzenia.
forum/(?<title>\w+),(?<id>\d+).html = forum.show
forum/(?<title>\w+),(?<id>\d+),new-topic.html = forum.new_topic
user/(?<name>\w+)/profile.html = user.profile
kontakt.html = article.contact
show_teaser = entry.show_teaser
program,(?<channel>\d+),(?<date>\d{2,4}-\d{2}-\d{2}).html = tv.schedule
itd itd. Wystarczy tylko wskazywać te konkretne adresy na konkretne akcje. Dla mnie takie rozwiązanie jest o wiele bardziej sensowne, spójne i czytelne niż to które proponuje Zend Framework. To rozwiązanie i pomysł zaczerpnięte jest z Django – frameworka w jezyku Python.
No dobrze, ale ktoś powie: “W ten sposób wszystkie adresy z założenia przeszukuje się wyrażeniami regularnymi a w ZF można wskazać co jest proste a co nie, dzięki temu działa to szybciej.” Ja odpowiem tak: Co zadziała szybciej? Utworzenie 70 instancji klas typu routera i przetworzenie w nich adresu + sparsowanie parametrów i walidacji (każdy router jeszcze robi to inaczej) czy przeszukanie 70 wyrażeń regularnych? Poza tym funkcje do wyrażeń regularnych są dosyć dobrze zoptymalizowane i nie robią niepotrzebnej roboty z parsowaniem wyrażeń jeśli ich tam faktycznie nie ma.
Sposób realizacji routingu ma także odwzorowanie w nieco innym podejściu do wywoływania akcji ale to już w kolejnym poście traktującym o Akcji.
Framework idealny? Wstęp
0Chciałbym poruszyć dosyć głęboki a być może i kontrowersyjny temat dotyczący wizji frameworka, który byłby jak najbardziej idealny. Oczywiście moje przemyślenia są mocno subiektywne jednakże są one podparte doświadczeniem nad pracą z różnymi rozwiązaniami. Ten post to jedynie ogólny wstęp do cyklu artykułów w których pojedynczo będę traktował o różnych aspektach budowy frameworka – wybierając zawsze (moim zdaniem) najlepsze rozwiązanie.
Moja idea/wzór będzie dotyczyła frameworka w języku PHP, gdyż uważam, że obecnie nie ma dobrego rozwiązania. Z czego to wynika? Moim zdaniem jest kilka powodów:
- PHP sam w sobie. W porównaniu z innymi językami takimi jak Ruby czy Python można śmiało powiedzieć, że składniowo PHP nie jest zbyt elegancki. Ponadto jego bardzo duże możliwości nie są zbyt powszechnie wykorzystywane a z innych, istotnych dziedzinach niestety nie daje rady. Bardzo często trzeba się ratować rozwiązaniami zastępczymi, które niepotrzebnie wprowadzają dodatkowy nakład pracy, zabierają moc obliczeniową i zmuszają do nauki nowych, niekoniecznie potrzebnych rzeczy.
- Mnogość frameworków do PHP. To wynika właściwie z tego, że istniejące rozwiązania nie są idealne i rożne osoby/grupy starają się zrobić coś swojego. Zend framework miał być odpowiedzią na ten problem, ale moim zdaniem jest on bardzo daleki od ideału. O tym za chwilę.
- Przejrzałe rozwiązania. Im większe community danego frameworka tym trudniej wprowadzić w nim rewolucyjne zmiany, gdyż napotykają one na opór ze strony osób dla których refactoring ich systemu nie jest opłacalny podczas gdy chcieliby mieć poprawione błędy. W związku z tym powstają niekiety nowe “major” version danego frameworka na przykładzie których widać jak bardzo twórcy zmienili tok myślenia podczas pracy nad poprzednią wersją – niestety muszą oni także brać pod uwagę istniejące community aby wszyscy byli “zadowoleni” i niestety bardzo szybko taki framework znów zmienia się w “potworka”. Przykładem takiego postępowania jest Symfony Framework a i zaryzykuję stwierdzenie, że także nowy Zend Framework. Zupełne inne podejście reprezentuje grupa, która jest odpowiedzialna za Prado Framework. Zauważyli oni konieczność zrobienia czegoś zupełnie nowego – Yii Framework i jest to rzeczywiście zupełnie inne podejście – bardzie współczesne i odpowiadające obecnym czasom.
PHP zyskał ostatnimi czasy kilka naprawdę bardzo fajnych możliwości
- Przestrzenie nazw (namespace)
- Traits
- Mikroserwer
- Funkcje anonimowe
- Ładniejszy zapis tablic
- i parę innych ciekawych rzeczy.
Biorąc pod uwagę powyższe fakty oraz mniej lub bardziej głębokie przemyślenia odnośnie idealnego frameworka doszedłem do tego co faktycznie musiałoby się w nim znaleźć aby uznać go za idealnym. Oczywiście idealnym z mojego punktu widzenia i przypominam, że dotyczy to PHP.
Cechy idealnego frameworka wg mnie:
Przyjemność programowania.
Myślę, że programowanie jest wtedy przyjemne gdy nasza praca przekłada się bezpośrednio na to co chcemy zrobić a nie na godziny konfiguracji i rozwiązywania problemów próbując wykonać podstawowe zadania. Oczywiście z czasem można dojść do wprawy działając na zasadzie “kopiuj – wklej” ale po co w ogóle to robić? Framework powinien sobie siedzieć “w tle”, odzywać się wtedy kiedy powinien i nie kazać mi nauczyć się najpierw mówić w jego języku. Framework ma służyć mi a nie odwrotnie. Jak najbardziej pewne reguły powinny obowiązywać, które wynikają z oczywistej logiki i powinny być zautomatyzowane (w końcu to framework) ale nie wolno popadać w skrajności dotyczące całkowitej automatyzacji albo całkowitej elastyczności. Przykładem skrajności w całkowitej elastyczności jest Zend Framework. Zastosowałbym pewną analogię do złożenia samochodu:
Jeśli zastanawiałbym się nad skonstruowaniem nowego modelu samochodu a nie miałbym zaplecza inżynierów, chciałbym mieć podstawowe komponenty takie jak np rama czy silnik, to w normalnej sytuacji dostałbym kompletny silnik o konkretnych parametrach, do którego muszę powpinać kabelki i wmontowany jest on w prostą ramę. Mogę od tego zacząć i pozmieniać jeśli miałbym taką potrzebę. Natomiast programiści Zend Framework przysłaliby mi zestaw różnych kartonów z których musiałbym sobie wszystko złożyć. Rama nie byłaby skręcona odpowiednimi wkrętami bo może chciałbym ja zbić gwoździami, albo skleić kropelką. Silnik również byłby w częściach bo może życzyłbym sobie aby tłoki zamontować na dachu. Fajnie? Może i tak, ale wtedy to nie jest framework tylko zestaw różnych części z których sam sobie składam to co chcę. Na dodatek części te znajdują się na wytopionych matrycach, z ktorych interesuje mnie tylko po jednej części ale te części zależą od innych zestawów części. Problem tylko polega na tym, że ja tak ładnie nie złożę tej ramy ani nie spasuję dobrze elementów silnika – albo się jeszcze pomylę. Na dodatek zostanie mi mnóstwo dodatkowych części o które wcale nie prosiłem ale muszę je teraz odłożyć gdzieś w garażu bo nie wiem czy tak naprawdę są one mi potrzebne czy nie.
Zamiast skupić się na moim wyposażeniu wnętrza, elektronice, karoserii… siedzę nad problemami ze złożeniem podstawowych elementów. A to mi się coś zacina, a tu okazało się, że trzeba nasmarować, a to tak a to siak. Czy to powinno definiować framework? Moim zdaniem nie.
Szybkość działania
Nikt mi nie powie, że Zend Framework czy Symfony Framework jest szybki. Są dużymi, bardzo złożonymi frameworkami i funkcjonuje to bardzo prosta zasada… im więcej kodu tym więcej czasu potrzeba na jego wykonanie. Poza tym zbyt duża elastyczność, luźno powiązane komponenty sprawiają, że łączenie ze sobą rzeczy, których nie powinno się łączyć jest dosyć proste to zrobienia. Efekt jest taki, że “działa” ale “jak działa” to jest już inna historia.
Tak sobie wyobrażam stronę zbudowaną np na Zend Framework. Można? Można. Czy o to chodzi? Moim zdaniem niekoniecznie. Nie chodzi wcale o to, że Zend Framework czy Symfony Framework ma bardzo dużo różnych fajnych gotowych komponentów. To świetnie, że tak jest, ale problem polega na tym, że sam framework od wielu z nich jest bardzo uzależniony i przy każdym rozruchu musi do nich zaglądać, podnosić i przetwarzać. Dobre rozwiązanie polegałoby na tym aby sam framework składał się z porządnego, ściśle i stabilnie działającego silnika i miał w pakiecie dodatkowe komponenty które są od niego niezależne. Czy framework powinien standardowo pozwalać na to aby przewrócić swój sposób działania do góry nogami? Czy nie prościej wtedy zrobić coś od nowa? Czy nie jest to wtedy dowód na to, że to co mamy nie spełnia naszych oczekiwań? Więc może warto wybrać jakieś alternatywne rozwiązanie, które okaże się prostsze, tańsze i lepiej dostosowane do konkretnych potrzeb.
Każde z tych zadań może być zupełnie inne byleby było zgodne ze sposobem w jaki framework mógłby sobie z nim poradzić.
Gdy istnieje konkretna potrzeba framework może wziąć na “swoje barki” to zadanie jakie ma wykonać. Robi to po prostu, tak jak został stworzony. Wyobrażam sobie, że framework jest jak ciągnik ciężarówki. Wielka, potężna maszyna, w której wszystkie trybiki, idealnie spasowane i naoliwione pracują perfekcyjnie. Ktoś wcześniej tak złożony ciągnik przetestował i dopracował w najmniejszych szczegółach. Jedyne zadanie tego ciągnika to zabrać na “swój pokład” naczepę. Ta naczepa to może być dowolna rzecz, dowolny towar byleby jego łącze było zgodne z łączem ciągnika. Ten sam ciągnik może ciągnąć różne naczepy. Każda naczepa może być zrobiona przez inną firmę, która nie ma w ogóle pojęcia jaki ciągnik będzie używany do jej ciągnięcia. Dla mnie takie rozwiązanie jest idealne.
Bezpieczeństwo
Istotne jest bezpieczeństwo takiego rozwiązania. Ale jak wiadomo każdy z aspektów związanych z programowaniem stron ma inne niebezpieczne miejsca na które należy zwrócić uwagę.
- HTML. Trzeba zwrócić uwagę na escapowanie danych. Na zamykanie danych ze zmiennych attrybutów w cudzysłowiach. Na zamienianie encji
- Javascript – Trzeba escapować dane w inny sposób
- SQL – Trzeba zwrócić uwagę na zabezpieczenie przed SQL injcection oraz przed podaniem nieprawidłowego typu (np string w miejsce inta)
- PHP – Trzeba zwrócić uwagę na typowanie zmiennych, przepełnienia bufora, zużycie pamięci i inne możliwe sposoby włamania się na serwer
PunBB AdSense Manager
0Rozszerzenie do PunBB, dzięki któremu można zarządzać reklamami na forum. Pozwala na dodanie reklamy w nagłówku oraz reklamy za pierwszym postem.
PunBB SEO Optimizer
0Rozszerzenie, do PunBB 1.4 które dba o to aby właściwie przekierowywać schematy adresów między sobą na te, które powinny być docelowo. Dodatkowo wprowadza tytuł forum do treści linka tematu, dzięki czemu adres jest bardziej szczegółowy
PunBB Image Assistant
0Przygotowalem plugin do PunBB, dzięki któremu można w sposób łatwy i wygodny dodawać zdjęcia do postów a także używać już wcześniej wgranych.
PunBB Google Analytics Integration
0Jakoś mnie wzięło ostatnio na robienie rozszerzeń do forum PunBB.
Tym razem: PunBB Google Analytics Integration 1.0.0
Rozszerzenie pasuje do wersji 1.4 forum PunBB
Paczka językowa do PunBB 1.4
0Jeśli ktoś interesuje się forum PunBB http://punbb.informer.com/ to przygotowałem właśnie do najnowszej wersji polską paczkę językową.
punbb-1.4.1-lang_pack-pl-1.0.0
Dyskusja i aktualizacje na forum PunBB: http://punbb.informer.com/forums/post/142372
XAMPP, Windows i najnowszy PHP
0Wiele osób korzysta z pakietu XAMPP jako serwer developerski na platformie Windows. Z mojego doświadczenia mogę powiedzieć, że sprawdza się on bardzo dobrze. Przez wszystkie wersje pakietu nie miałem problemów aż do wersji 1.7.4. Niestety mimo wielu prób, szukania informacji na forum, stosowania najprzeróżniejszych rozwiązań nie udało mi się doprowadzić tego pakietu do stanu używalności. Głównym problemem jest to, że najnowsza wersja została skompilowana pod platformę VC9 (która jest przystosowana do serwera IIS), a większość pakietów jest dostępna w wersji VC6. Poza tym w wersji VC9 na serwerze Apache nie działa to ze sobą zbyt dobrze.
Do tej pory używałem wersji 1.7.3, która działa bez najmniejszych problemów, ale ma już swoje lata a potrzebny był mi nowszy PHP (w tej wersji jest to 5.3.1)
Jak więc posiadać dobrze działający pakiet XAMPP z najnowszą wersją PHP?
- Ściągnij i zainstaluj wersję 1.7.3, która działa bez najmniejszych problemów http://sourceforge.net/projects/xampp/files/XAMPP%20Windows/1.7.3/ chyba, że już posiadasz ten pakiet.
- Ściągnij paczkę PHP dla Windows (obecnie najnowsza wersja 5.3.6 jest dostępna tylko w wersji VC9 a nam potrzebna VC6, więc ściągnij stąd http://windows.php.net/downloads/releases/archives/ pakiet o nazwie php-5.3.5-Win32-VC6-x86.zip
- Wypakuj pakiet php-5.3.5-Win32-VC6-x86.zip gdzieś na dysk
- Przekopiuj zawartość wypakowanego katalogu do C:\xampp\php
- Podmień stary plik php.ini na nowy php.ini-development lub php.ini-production
- Ciesz się XAMPP’em z najnowszym PHP


![TIR[1]](http://quadric.goblix.pl/wp-content/uploads/2012/02/TIR1-300x240.jpg)