Autor wpisu: Athlan, dodany: 19.02.2009 14:19, tagi: apache
Wiele razy zdarzało mi się, że mój serwer padł całkowicie lub przerywał żądania. Wówczas był niedostępny, a zarobki generowane z serwisów diametralnie spadały. Co więcej… użytkownicy poczuli niestabilność maszyny. Dziś po odpowiedniej optymalizacji kodów aplikacji pady są rzadkością, ale wolę się ubezpieczyć przed niespodziewanym downem serwera.
Problem można rozwiązać w prosty sposób: cyklicznie uruchamiany program bash‘a przez crona będzie odpowiadał za poprawne działanie usługi apache. Listing, który zaprezentuję łączy się z adresem url odwołującym się do naszego serwera za pomocą wget
, a następnie wynik działania (response body) zapisze do pliku tymczasowego. Jeżeli plik istnieje oraz ma rozmiar niezerowy, oznacza to, że serwer działa poprawnie. Jeżeli plik nie istnieje, bądź jego wielkość jest równa zero z, oznacza to, że trzeba zrestartować usługę apache, bo nie odpowiada. Zaraz przed zakończeniem programu, plik tymczasowy powinien zostać usunięty. Pozwoliłem sobie opublikować mały program służący do automatycznego restartu usługi apache.
Aby nasz program poprawnie działał, trzeba zastanowić się nad trzema istotnymi rzeczami:
- Ile prób połączenia ma wykonać
wget
oraz jakie mogę być timeouty. - Czy adres url, do którego się odwołujemy będzie zawsze dostępny w przypadku poprawnego działania usługi apache.
- Jaki powinien być interwał uruchamiania napisanego programu.
Na moim serwerze program uruchamia się co minutę, próbuje połączyć się ze stroną dwa razy, a maksymalny czas oczekiwania na odpowiedź przy każdej z prób wynosi 10 sekund.
Program zapisany jest pod /root/check_apache.sh
, a regułka uruchamiania w cronie wygląda następująco:
* * * * * bash /root/check_apache.sh
Przedstawiony problem można rozwiązać na wiele sposobów, przedstawiłem ten najbardziej oczywisty.
Autor wpisu: Tomasz Sh4dow Budzyński, dodany: 15.02.2009 23:01, tagi: php
Autoload w PHP istnieje od wersji 5.0. Bardzo przydatna „magiczna” funkcja, która potrafi zaoszczędzić trochę zasobów serwera. Ładuje pliki z klasą jedynie w czasie gdy jest ona potrzebna. Rozwiązań jest za pewne wiele, niektórzy przeszukują za każdym razem system plików za nazwą klasy, a niektórzy tworzą specjalne konstrukcje katalogów. Są też rozwiązania ze stworzeniem tablicy z nazwami klas i ścieżką do plików. I to rozwiązanie jest moim zdaniem najbardziej efektywne. Jedynym problemem jest tworzenie takiego pliku z tablicami. Oczywiście możemy ręcznie tworzyć tablice, to jest wersja dla najtwardszych. Innym sposobem jest oczywiście stworzenie prostego narzędzie do tworzenia takiej tablicy.
Pierwsza rzecz to musimy wyszukać wszystkie pliki jakie chcemy przeszukać.
<?php $path = './'; $dir = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST ); foreach($dir as $file) { //przetwarzanie plików } ?>
To nam pomoże przeszukać wszystkie pliki php w danym katalogu oraz jego podkatalogach. Jeśli ktoś używa na przykład skryptu Smarty, to pojawia się dużo plików php które napewno nie posiadają żadnej klasy lub też katalogi .svn posiadające dużo plików, gdzie nie znajdziemy niczego nam potrzebnego. Przydało by się to odfiltrować. Np przykład tak:
<?php if( $file->isFile() and end( explode( '.', $file->getFilename() ) ) == 'php' and strpos($file->getFilename(), '%') === false and strpos( $file->getPath().'/'.$file->getFilename(), '.svn') === false ) { //dalsze przetwarzanie plików } ?>
Pre-kompilowane szablony smarty posiadają znaki ‘%’ więc takie pliki możemy odrzucić. Możemy się pokusić o odrzucenie plików z katalogu gdzie zapisywane są pliki smarty, ale w przypadku zmiany nazwy katalogu, trzeba by było modyfikować skrypt. Wszystkie pliki które posiadają w ścieżce fragment ‘.svn’ także będziemy odrzucać, ponieważ na pewno tam nic nie znajdziemy.
Teraz przystąpimy do samego wyszukiwania klas w plikach. Skorzystamy z wbudowanej funkcji w token_get_all, która częściowo przetworzy nam kod PHP na poziom leksykalny, co znacząco ułatwi nam wyszukiwanie potrzebnych nam rzeczy. Zasadę może pokaże na przykładzie:
<?php # przykładowa klasa # <?php # class NazwaKlasy { # //tresc klasy # } var_dump( token_get_all( "<?php\n class NazwaKlasy {\n //treść klasy\n }") ); ?>
Wynikiem będzie wyświetlenie tablicy 2 wymiarowej. W tym konkretnym przykładzie będzie posiadała ona 11 elementów na pierwszym poziomie. Każdy taki element opisuje pojedynczą jednostkę leksykalną. Listę takich jednostek znajdziecie w dokumentacji PHP. Jak znaleźć nazwę klasy. Każdy znaleziony element jest albo string’iem dla znaków takich jak ( ‘{‘, ‘}’, ‘;’, ‘.’, ‘>’, itp.) lub tablicą 3 elementów. Pojedyncze znaki nas nie interesują, więc szukamy tablic. A dokładniej ułożenia kolejnych 3 elementów. Pierwsze to słowo kluczowe ‘class’ (token T_CLASS), następnie odstęp (white space, token T_WHITESPACE) a na końcu ciąg znaków ( token T_STRING ). I właśnie ten ostatni element w połączeniu z nazwą i ścieżką pliku potrzebny. Więc przetworzenie pliku będzie wyglądać mniej więcej tak:
$tokens = token_get_all( file_get_contents( $file->getPath().'/'.$file->getFilename() ) ); //odczytujemy plik i przetwarzamy $count = count($tokens); //zliczamy ilość elementów, poprostu optymalizacja dla pętli for($a=0; $a<$count;$a++ ) { if( is_numeric( $tokens[$a][0] ) ) { //sprawdzamy czy element jest opisany tablicą if( $tokens[$a][0] == T_CLASS and $tokens[$a+1][0] == T_WHITESPACE and $tokens[$a+2][0] == T_STRING ) { //spełnienie warunku dla kolejnych trzech elementów if( isset( $klasy[ trim( $tokens[$a+2][1] ) ] ) ) { //sprawdzenie czy nie istnieją duplikaty klas. $double[] = array( trim( $tokens[$a+2][1] ), $file->getPath().'/'.$file->getFilename() ); } else { $klasy[ trim( $tokens[$a+2][1] ) ] = $file; //tworzenie tablicy ze ścieżkami do plików oraz nazwami klas } } } }
Teraz pozostaje nam tylko otrzymaną tablice zapisać do pliku php. Co chyba nikomu nie sprawi problemu:
<?php file_put_contents('autoload.array.php', "<?php\n"); foreach( $klasy as $class => $file ) { //zapisujemy skrócone ścieżki od aktualnego katalogu w górę file_put_contents('autoload.array.php', '$autoload[\''.$class.'\'] = \''.str_replace( getcwd(), '.', realpath($file) ).'\';'."\n", FILE_APPEND); } ?>
W całości będzie to wyglądać mniej więcej tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php set_time_limit(0); $klasa = array(); $path = './'; $dir = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST ); //przetwarzanie plików foreach($dir as $file) { if( $file->isFile() and end( explode( '.', $file->getFilename() ) ) == 'php' and strpos($file->getFilename(), '%') === false and strpos( $file->getPath().'/'.$file->getFilename(), '.svn') === false) { $tokens = token_get_all( file_get_contents( $file->getPath().'/'.$file->getFilename() ) ); $count = count($tokens); for($a=0; $a<$count;$a++ ) { if( is_numeric( $tokens[$a][0] ) ) { if( $tokens[$a][0] == T_CLASS and $tokens[$a+1][0] == T_WHITESPACE and $tokens[$a+2][0] == T_STRING ) { if( isset( $klasy[ trim( $tokens[$a+2][1] ) ] ) ) { $double[] = array( trim( $tokens[$a+2][1] ), $file->getPath().'/'.$file->getFilename() ); } else { $klasy[ trim( $tokens[$a+2][1] ) ] = $file; } } } } } } //budowanie pliku z tablicą file_put_contents('autoload.array.php', "<?php\n"); foreach( $klasy as $class => $file ) { file_put_contents('autoload.array.php', '$autoload[\''.$class.'\'] = \''.str_replace( getcwd(), '.', realpath($file)).'\';'."\n", FILE_APPEND); } ?> |
Na początku przydaje się dodać set_time_limit() na zero ponieważ przy dużych plikach oraz przy dużej ich ilości cała operacja może chwilkę potrwać. Należy pamiętać, że po dodaniu nowej klasy, przydałoby się uruchomić skrypt ponownie, aby dodał nową klase do tablicy. Teraz pozostaje nam stworzyć jedynie funkcje __autoload, która będzie korzystać z naszej tablicy.
1 2 3 4 5 6 7 8 9 10 11 | $autoload = array(); function __autoload($class_name) { static $autoload; include_once( './autoload.array.php' ); if( isset( $autoload[ $class_name ] ) ) { include_once($autoload[ $class_name ]); return true; } return false; } |
I mamy gotową całą funkcjonalność autoload. Możemy ją poszerzyć o zliczanie ilości plików lub klas, czas wykonywania lub inne mniej lub bardziej przydatne informacje. Wszystko zależy od waszych potrzeb.
Autor wpisu: m1chu, dodany: 15.02.2009 13:55, tagi: php
W niezbędniku prawie każdego blogera leży możliwość menadżerowania swoimi kanałami RSS, bądź Atom. Któż z nas nie zna FeedBurner'a?. Zestawu narzędzi ułatwiających nam, czy to udostępnianie użytkownikom możliwości subskrypcji treści naszej strony, czy po prostu możliwość przejrzenia lub zamieszczenia statystyk w naszym serwisie. Pomimo dostarczonego API nie znajdziemy jednak bezpośrednio w panelu FeedBurner'a kodu pozwalającego na umieszczenie samej liczby subskrybentów bloga. I rozwiązanie tego, pozornie błahego problemu postaram się Wam dziś przedstawić...
Stary, dobry FeedBurner.com...
Niespełna dwa lata temu słynny serwis zajmujący się obsługą kanałów RSS został przejęty za sto milionów dolarów przez Google. Pomimo tego, że minęło aż tyle czasu wielu blogerów nadal korzysta z zasobów starego, wysłużonego, pierwotnego FeedBurner'a. I co może wydawać się dziwne, to właśnie oni mają najbardziej ułatwioną sytuację.
Zarówno stara, jak i nowa odsłona serwisu oferują usługę FeedCount dostępną z poziomu menu Publicize. Pozwala ona na dobranie typu wbudowanego tła wyświetlającego ilość subskrybentów (statyczne, bądź animowane) oraz na dobranie jego barwy i koloru tekstu. Wraz z ustawieniem tych parametrów otrzymujemy kod HTML do wstawienia na naszą stronę. I tu rodzi się problem. Prócz kilku stylistycznych zmian wygląd tychże "chickletów" jest zawsze taki sam i najczęściej nijak pasuje do designu naszego bloga. Co zrobić jeżeli np. chcemy wraz z tekstem przycisku odnoszącego użytkowników do wygenerowanego kanału wstawić także ilość osób śledzących naszą stronę?
Rozwiązanie zaprezentuje na podstawie użytkowania platformy Wordpress (oczywiście ilość subskrybentów - opierając się na dalszym tekście - można zamieścić w każdym innym systemie zarządzania treścią, bądź nawet na własnej, prywatnej stronie). W takim wypadku wystarczy zainteresować się wtyczkami FeedSmith 2.3 (polska wersja) (wg. developerów Wordpress'a kompatybilną ze wszystkimi wersjami 2.x) i Feed Count 1.2 (polska wersja). Pierwsza z nich niezbędna jest do obsługi kanału RSS przez serwis FeedBurner.
Jej instalacja oraz rejestracja w serwisie jest niezbędna do działania drugiej z nich. Jak wykonuje się instalacje wtyczek? Wystarczy wyodrębnić z archiwum odpowiednie pliki (w naszym pierwszym przypadku będzie to FeedBurner_FeedSmith_Plugin.php, w drugim feedcount.php) i umieścić je w katalogu wp-content/plugins/ systemu Wordpress. Następnie wtyczki należy zaktywować w panelu administratora (Wtyczki / Nazwa wtyczki / Włącz).
Obydwa pluginy należy dodatkowo skonfigurować w zakładce Ustawienia. Pierwszy z nich swoje opcje ukrywa w podmenu FeedBurner. Zobaczycie tam dwa pola do uzupełnienia, jedno wymagane, drugie opcjonalne. Pierwsze z nich to pełny odnośnik do feedu strony w serwisie FeedBurner (i dla starej odsłony, i dla nowej na serwerach Google), a drugi to link do kanału RSS komentarzy.
Konfiguracja wtyczki FeedSmith w panelu.
Co do drugiego rozszerzenia to działa ono dla wersji 2.x Wordpress'a, z tymże przy najnowszej 2.7x może sprawiać problemy natury zwracania wyniku w postaci N/A zamiast poprawnej wartości.
Konfiguracja wtyczki Feed Count w panelu.
Autor wpisu: m1chu, dodany: 09.02.2009 13:45, tagi: css
Jedni nie korzystają z nich wcale, niektórzy tylko po to aby zwiększyć funkcjonalność tworzonych przez siebie stron, a u jeszcze innych zauważalny jest przepych tego typu rozwiązań. Biblioteki programistyczne języka JavaScript, bo o ich wykorzystaniu tu mowa to źródło bardzo różnorodnych, nie tylko funkcjonalnych, ale także estetycznych efektów. Sieć aż kipi od dobrych i słabych, lepiej oraz słabiej wytłumaczonych przykładów użycia możliwości MooTools, jQuery, Prototype z Scriptaculous, czy innych mniej powszechnych frameworków.
Jednym z takich efektów jest możliwość stworzenia animowanego, graficznego podświetlenia pojawiającego się np. nad grafiką wywołującą animację. Interaktywność taka została opisana na NetTuts z wykorzystaniem MooTools. My osiągniemy taki wynik dzięki zastosowaniu jQuery (w jednym przykładzie) oraz dodatkowo także za pomocą Prototype wraz z Scriptaculous (w drugim przykładzie).
Oczekiwany efekt.
Krok 1: Za co się chwycić na początku...
Na początek musisz wiedzieć w jakim celu potrzebny jest Ci prezentowany w tym artykule efekt. Menu? Wyświetlanie dodatkowych informacji w graficznej liście produktów? Czy może szybki, animowany splash? Wybór jest Twój i podług niego będziesz musiał zaopatrzyć się w dodatkowe, niezbędne elementy do wykonania podświetlenia.
Chodzi tu mianowicie o grafiki, których musi być dwa razy więcej niż elementów podatnych na działanie mechanizmu. Powiedzmy, jeżeli chcemy w pięcioelementowym menu zastosować w każdym zdarzenie po najechaniu myszką zgodne z przesłaniem tego artykułu to potrzebujemy dziesięciu grafik. Pięć opisujących przyciski menu i drugie tyle będące "treścią" pojawiającą się po podświetleniu.
Po uporaniu się z wizualną częścią problemu oraz strony internetowej możemy ruszyć krok dalej.
Krok 2: Zaopatrujemy się w jQuery i/lub Prototype i Scriptaculous!
jQuery to aktualnie najpopularniejsza biblioteka. I najłatwiej ją skatalogować w czeluścia własnego projektu. Wystarczy ze strony głównej pobrać wersję 1.3.1 production/Minified i umieścić ją w obrębie plików tworzonego przez nas przykładu (niezbędny będzie tylko plik jquery-1.3.1.min.js).
Z Prototype sprawa jest ciut bardziej skomplikowana, bo prócz standardowego frameworka musimy pobrać także dodatkowy interfejs w postaci Scriptaculous, dzięki któremu uzyskamy dostęp do efektu pozwalającego na dynamiczne zmienianie właściwości CSS elementów strony. Ściągamy więc wersję 1.6.0.3 pierwszej biblioteki, oraz paczkę z wersją 1.8.2 drugiej. Z obydwu wyodrębniamy pliki i w ramach folderu tworzonego przez nas projektu umieszczamy tylko prototype.js oraz effects.js (z drugiego archiwum).
Autor wpisu: Athlan, dodany: 06.02.2009 10:42, tagi: internet, php
Projektowałem wiele serwisów, które miały zintegrowane z forum komponenty takie jak:
- rejestracja,
- przypomnienie hasła,
- zmiana hasła, nicku lub adresu email,
- usunięcie konta.
Wówczas nie było żadnego problemu - wystarczyło wszystkie te akcje z forum przekierować na URL’e obsługiwane przez CMS, który zajmował się zmianami tabelach forum. Dlaczego przekierować? Jeżeli ktoś rejestruje się w serwisie, jest zarejestrowany na forum, natomiast, gdy rejestruje się na forum, nie jest rejestrowany w serwisie. To CMS integrujemy z forum, a nie forum z CMS’em (chyba, że zamierzamy inaczej, wtedy na odwrót).
Ostatnio klient zażyczył sobie, żeby zintegrowane było również logowanie. Nie najlepiej widzi mi się implementacja systemu autoryzacji z forum w CMS’ie, więc poszedłem “na łatwiznę”, bowiem miałem do czynienia z phpBB. Do osiągnięcia celu postanowiłem wykonać dwa kroki:
- wysłać żądanie POST do forum na adres logowania z wypełnionymi polami POST z formularza logowania w CMS’ie,
- przechwycić wysłane przez forum ciasteczka i przekazać je użytkownikowi.
Do połączenia się z forum via http użyłem HttpRequest. Wyszło z tego parę linijek kodu.
Autor wpisu: SongoQ, dodany: 04.02.2009 07:46, tagi: php, apache, sql
Przeprowadziłem kilka testów szybkości odczytu z pliku i tabel typu: MEMORY, MyISAM.
Jak był przeprowadzany test:
Test przeprowadzałem na Ubuntu Dapper (apache2, php5.1.x, MySQL 5.0.22) na laptopie, więc wiele rzeczy mogło wpłynąć na na nieprawidłowość testów.
Test podzieliłem na kilka etapów:
- z włączonym cache zapytań
- z wyłączonym cache zapytań
- z pomiarem połączenia z bazą danych
Odnośnie ilości wywołań testu, to był wykonywany 1000 razy, liczone były pojedyńcze czasy testu, a następnie sumowane i liczona z tego średnia testu. Jako danych testowych użyłem wygenerowanego ciągu znaków o długości około 65 KB.
Wyniki:
Odczyt z pliku:
Do odczytu z pliku użyłem funkcji: file_get_contents() Średni czas odczytu jaki uzyskałem to: 0.000357507705688 (szczegółowe informacje)
Odczyt z bazy danych:
Do odczytu z bazy użyłem funkcji mysql_* (połączenie, wybór bazy, wykonanie zapytanie i zwrócenie rekordu). Tabela zawierała 1 rekord z id i polem w którym był zapisany taki sam ciąg znaków jak w przypadku pliku. Dlaczego nie więcej? Chciałem wyeliminować czas jaki będzie potrzebny na przeliczenie jaki rekord ma zostać zwrócony.
Wyłączony zapis cache w MySQL i czas połączenia z bazą pominięty:
Tabela MyISAM - średni czas to: 0.00516110825539 (szczegółowe informacje) Tabela MEMORY - średni czas to: 0.00368802952766 (szczegółowe informacje)
Widać, że odczyt z pliku ma przewagę nad odczytem z bazy danych, a czasy odczytu z tabel typu MyISAM i MEMORY są bardzo do siebie zbliżone.
Włączony zapis cache w MySQL i czas połączenia z bazą pominięty:
Tabela MyISAM - średni czas to: 0.00179107260704 (szczegółowe informacje)