Autor wpisu: bastard13, dodany: 31.05.2012 14:38, tagi: php, oop
klasa abstrakcyjna
Czym jest klasa abstrakcyjna? Nie będę się rozpisywał na temat konstrukcji (jak zwykle:), ponieważ w internecie można znaleźć sporo definicji.We wstępie chciałbym się natomiast skupić na podziale klas abstrakcyjnych. Co prawda, z tego co się orientuję, żadnego oficjalnego podziału nie ma, ale po jakimś czasie programowania można wyróżnić trzy powtarzające się wzorce (nie w znaczeniu wzorców projektowych) klas abstrakcyjnych: Czytaj więcej »Autor wpisu: batman, dodany: 31.05.2012 08:00, tagi: zend_framework
Nieco ponad tydzień temu otrzymałem maila z zapytaniem jak przy pomocy Zend_Layout wykonać układ wielokolumnowy. Wbrew pozorom nie jest to proste do wykonania, ponieważ do wyboru mamy kilka możliwości. Najprostszą z nich byłoby napisanie helpera widoku, który naszpikowany if-ami wyświetlałby stosowną zawartość. O ile w przypadku prostej aplikacji niewymagającej drastycznych zmian wyglądu dynamicznej kolumny, zdałoby to egzamin, tak w momencie gdy kolumny będą znacząco się od siebie różnić w zależności od aktualnej akcji, możemy stworzyć potworka, którego będziemy wstydzili się pokazać nawet niewidomej osobie.
Nie oznacza to, że powinniśmy całkowicie zrezygnować z helperów widoku. Wręcz przeciwnie, będą one stanowić podstawę dynamicznej kolumny. Wystarczy dodać skrypt widoku oraz pobrane z modelu dane, a całość przekazać do layotu. Resztą zajmie się Zend.
Zacznijmy do helpera widoku. Poniższy przykład będzie bardziej niż prosty – ma celu zaprezentowanie idei opisywanego rozwiązania.
class Zend_View_Helper_Column1 extends Zend_View_Helper_Abstract { public function column1(array $data) { $this->view->data = $data; return $this->view->render('column1.phtml'); } }
Helper przyjmuje tablicę z danymi, a następnie wyświetla je przy pomocy skryptu widoku, który prezentuje się następująco.
Aktywni użytkownicy <ul> <?php foreach ($this->data as $userName): ?> <li><?php echo $userName; ?></li> <?php endforeach; ?> </ul>
Mamy już helper oraz skrypt widoku, pora zająć się layoutem. Załóżmy, że nasza aplikacja będzie składać się z dwóch kolumn.
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>multicolumn layout</title> </head> <body> <section class="content"> <?php echo $this->layout()->content; ?> </section> <aside class="aside"> <?php echo $this->layout()->aside; ?> </aside> <div class="clear"></div> </body> </html>
Domyślnie Zend Framework przekazuje do placeholdera o nazwie content zawartość skryptu widoku bieżącej akcji. My wykorzystamy ten sam mechanizm do wyświetlenia dodatkowej kolumny. Stąd właśnie w powyższym kodzie znalazł się placeholder aside. Ponieważ Zend Framework nie wie co ma się w nim znaleźć, nie będzie on nic wyświetlał. Sami musimy zadbać o poinformowanie ZF jaka treść ma wyświetlić. A zrobimy to w akcji kontrolera.
public function indexAction() { $this->_helper->getHelper('Layout')->assign( 'aside', $this->view->column1(array('Jan Kowalski', 'Ewa Nowak')) ); }
W prawdziwej aplikacji dane przekazane do helpera będą pochodzić z modelu, jednak dla uproszczenia przykładu, zastosowałem najzwyklejszą tablicę.
I to już wszystko co jest potrzebne do wykonania wielokolumnowego układu strony z dynamiczną kolumną. Nie jest to uniwersalne rozwiązanie, ponieważ jak to zwykle w życiu bywa, wszystko zależy od aplikacji, nad którą właśnie pracujemy. Niemniej w większości przypadków sprawdzi się doskonale i będzie wymagać jedynie drobnych modyfikacji.
Kompletny kod aplikacji znajdziecie na GitHubie.
Autor wpisu: l3l0, dodany: 29.05.2012 13:29, tagi: symfony
Autor wpisu: Śpiechu, dodany: 26.05.2012 12:46, tagi: php
Zgodnie z obietnicą dzisiaj część dotycząca bezpiecznego uruchamiania zewnętrznych skryptów PHP. Od razu mówię, że nie jestem jakimś guru dot. zabezpieczeń systemów Unix. Zebrałem rozsypane po internecie informacje i spróbowałem złożyć to w całość.
Gist został uaktualniony o klasę ICMPPingProcesser
— rzućcie okiem. Posłuży jako baza do naszych działań.
Jak już wspomniałem w poprzednim wpisie, w Linuksie nie można wykonać polecenia socket_create()
na typowym użytkowniku Apache, czyli www-data. Aby obejść ten problem skorzystałem z polecenia posix_seteuid(0)
zmieniającego użytkownika procesu na roota na czas życia obiektu ICMPPing
. Z kolei aby wykonać to polecenie musimy stać się rootem :-). Z terminala nic trudnego:
sudo php icmp.php http://spiechu.pl
Zostaniemy zapytani o hasło i dostajemy odpowiedź skryptu. Problem pojawia się gdy chcemy wywołać polecenie z poziomu innego skryptu PHP. W Ubuntu nie da się/nie umiem (a próbowałem na wiele sposobów) wpisać hasła dla sudo z poziomu lini komend. Wobec tego trzeba zmusić sudo aby nie pytał o hasło. Oczywiście opcja aby nadać użytkownikowi www-data wszystkie uprawnienia roota na stałe nie wchodzi w grę. Trzeba maksymalnie zawęzić „pole manewru” dla www-data.
Wobec tego przyczepiamy się do pliku /etc/sudoers, który przechowuje uprawnienia związane z poleceniem sudo. Przypominam, że plik sudoers należy edytować wyłącznie za pomocą polecenia visudo, a więc w terminalu:
sudo visudo
i jedziemy z edycją:
# Ustawiamy kilka aliasow # gdy skryptow zrobi sie sporo # bedzie latwiej zarzadzac tym balaganem User_Alias APACHE_USER = www-data Runas_Alias ROOT_USER = root Host_Alias PHP_MACHINE = dave-ubunciak Cmnd_Alias ICMP_SCRIPT = /usr/bin/php /home/dave/icmp.php http\://* # Wlasciwe polecenie APACHE_USER PHP_MACHINE = (ROOT_USER) NOPASSWD: ICMP_SCRIPT
Polecenie można przetłumaczyć tak: Użytkownik www-data na maszynie dave-ubunciak jako root może wykonać skrypt php o nazwie icmp.php bez hasła z parametrem rozpoczynającym się od http://. Wszelkie odstępstwa będą traktowane komunikatem sudo: no tty present and no askpass program specified Sorry, try again. Od tego momentu możemy w dowolnym skrypcie wywoływać:
// na czas developmentu warto na koncu polecenia wpisac // 2>&1 dzieki czemu strumien stderr przekierujemy na wyjscie $process = shell_exec('sudo php /home/user/icmp.php http://www.spiechu.pl'); echo $process;
Co jeszcze można zrobić z samym plikiem icmp.php? Możemy zmienić mu użytkownika i grupę na root i ograniczyć możliwość jego wykonania wyłącznie do roota, czyli:
sudo chown root icmp.php sudo chgrp root icmp.php sudo chmod 400 icmp.php
Na koniec przyczepię się do samego icmp.php. Napisałem klasę ICMPPingProcesser
, która sprawdza czy podany adres www jest prawidłowy i odsiewa wszystko poza podstawowym adresem hosta. Poniżej przytaczam w całości:
class ICMPPingProcesser { /** * @var string */ protected $urlAddress; /** * @param string $urlAddress */ public function __construct($urlAddress) { $this->urlAddress = $urlAddress; } /** * Returns 'Trying {$urlAddress}: PING RESPONSE: Everything OK' * when url address replied correctly * * @return string */ public function ping() { try { $message = ''; $urlToPing = $this->processUrl($this->urlAddress); if (!$this->isUrlExists($urlToPing)) { throw new Exception("{$urlToPing} doesn't exist!"); } $icmp = new ICMPPing(); $respond = $icmp->sendPacket($urlToPing, 'Everything OK'); $message = "Trying {$urlToPing}: "; $message .= "PING RESPONSE: {$icmp->analyzeRespond($respond)}"; return $message; } catch (Exception $e) { $message .= $e->getMessage(); return $message; } } /** * Returns sanitized url host from param * * @param string $urlAddress * @return string url host * @throws Exception when url address is not valid */ protected function processUrl($urlAddress) { $sanitizedUrl = filter_var($urlAddress, FILTER_SANITIZE_URL); if ($sanitizedUrl === false || filter_var($sanitizedUrl, FILTER_VALIDATE_URL) === false) { throw new Exception("{$urlAddress} is not valid URL"); } return parse_url($sanitizedUrl, PHP_URL_HOST); } /** * Checks if url address exists * * @param string $urlAddress * @return boolean */ protected function isUrlExists($urlAddress) { if (gethostbyname($urlAddress) === $urlAddress) { return false; } return true; } } if (PHP_SAPI === 'cli' && isset($_SERVER['argv'][1])) { $pingProcesser = new ICMPPingProcesser($_SERVER['argv'][1]); echo $pingProcesser->ping(); } else { echo 'Not in cli mode or agument not set'; }
Ostatnie kilka linijek sprawdza czy skrypt odpalany jest w trybie lini komend i czy istnieje jakiś argument.
Autor wpisu: d3ut3r, dodany: 25.05.2012 15:44, tagi: php
Raczej każdy kto używa przeglądarki FireFox do codziennej pracy nad kodem (x)HTML/CSS/JS zna genialne narzędzie o nazwie FireBug, użytkownicy którzy dodatkowo pracują z PHP być może korzystali z FirePHP jako, że przesiadłem się z FireFox’a na Chrome szukałem odpowiednika FirePHP dla tej przeglądarki i w końcu znalazłem.
Słowem wstępu dla niewiedzących FirePHP pozwalał nam w stosunkowo prosty sposób wykorzystać konsolę FireBuga do wyświetlania komunikatów ze skryptów PHP. Rozwiązanie w moim przypadku idealne, ponieważ często przychodzi mi poprawiać błędy na istniejących już stronach gdzie nie dopuszczalne jest aby odwiedzający widział moje tajemne wiadomości pomagające w debugowaniu kodu
Rozszerzenie dla Chrome możemy pobrać z tego miejsca dodatkowo musimy pobrać klasę ChromePHP.
Gdy mamy już zainstalowane rozszerzenie w przeglądarce, możemy przystąpić do testów. Stworzyłem przykładowy plik test.php o zawartości:
<?php include('ChromePhp.php'); for ($i=0;$i<=10;$i++){ ChromePhp::info($i); } ?>
Teraz wystarczy otworzyć naszą stronę w przeglądarce, po wczytaniu za pomocą kombinacji ctrl+shift+j uruchamiamy konsolę JavaScript w której znajdziemy wynik działania naszego polecenia ChromePhp::info($i); wszystko powinno wyglądać mniej więcej w ten sposób:
Oczywiście możliwości ChromePhp nie kończą się na wyświetlaniu zwykłego tekstu ChromePhp posiada szereg metod dzięki którym informacje w konsoli będą czytelne i logicznie poukładane.
1. ::warn,::info,::error
To podstawowe i najczęściej używane metody każda z nich wyświetla inny typ komunikatu odpowiednio: ostrzeżenie , informacja , błąd. Wszystkie metody przyjmują do 2 parametrów poprawne użycie może wyglądać tak:
<?php include('ChromePhp.php'); function badDay(){ throw new Exception('To bardzo zły dzień'); } ChromePhp::info('czas z serwera',date('d-m-Y, H:i:s')); try{ badDay(); } catch (Exception $e){ chromePhp::error($e); } chromePhp::warn('aaaa','bbbbb'); ?>
powyższy kod powinien dać nam taki rezultat: