Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: Vokiel, dodany: 26.09.2009 16:56, tagi: php

W pierwszej części na temat optymalizacji bloga opartego na WordPress skupiliśmy się na kilku elementach: Zmianie memory_limit() poprzez php.ini, .htaccess, lub ini_set() w php. Następnie zapoznaliśmy się z częścią możliwości optymalizacji po stronie front-end’u (cache).

W dzisiejszej części będziemy kontynuować proces optymalizacji do tego stopnia, aby możliwym było bezproblemowe korzystanie z platformy blogowej. Zacznijmy od optymalizacji bazy danych.

Nieużywane szablony

Jeśli uruchamiając blog nie mogliśmy się zdecydować na konkretny szablon (theme), próbowaliśmy kliku z nich, do tego ustawialiśmy w nich jakieś opcje, dodatki, konfiguracje – to po zmianie na inny szablo wpisy dokonane dla poprzednich szablonów pozostaną zapisane w bazie. Jest to dobre rozwiązanie w przypadku, gdy zechcemy zmienić szablon (powrócić do wcześniej ustawionego) – konfiguracja zostaje przywrócona do etapu na jakim ją pozostawiliśmy. Jednak jeśli zdecydujemy się już na ten jedyny, wybrany szablon, zwykle nie będziemy go zmieniać, raczej upiększać, modyfikować. Możemy zatem śmiało usunąć pozostałe, oraz wszystkie wpisy w bazie danych które po nich pozostały. W tym celu logujemy się do menedżera MySQl (SQLyog, PMA) przeglądamy tabelę wp_options w poszukiwaniu wpisów odnoszących się do starych szablonów, wtyczek, które odinstalowaliśmy i usuwamy je.

Nieaktualne ustawienia wtyczek

W moim przypadku usunięcie nieaktualnych wpisów odnoszących do ustawień kilku szablonów oraz wpisów pozostałych po wtyczkach zmniejszyło ilość wierszy w tabeli wp_options o około 80 rekordów (wszystkie z ustawionym autoload na 'yes'). Dodatkowo postanowiłem zmienić opcję autoload dla wybranych wpisów (po uprzednim pełnym backupie bazy). Ustawienia zostały zmienione tylko dla tych wpisów, odnośnie których znaczenia byłem pewien, oraz tych, które nie miały wartości. Samo zużycie pamięci zostało nieznacznie zmienione – w granicach błędu statystycznego. Jednak ilość zwróconych wyników uległa lekkiemu zmniejszeniu oraz zmniejszył się czas trwania zapytań – zatem przyśpieszenie już jakieś nastąpiło.

Indeksy

Przeglądając wyniki z WP Tuner (włączone ustawienia: Show Everything) natknąłem się na kilka niepoprawnych zapytań, na zapytania z narzutem, bez odpowiednio ustawionych indeksów. Niezbędnym okazało się ponowne zalogowanie do MySQL’a celem naniesienia poprawek poprzez dodanie indeksów. Zwykle brak indeksów występuje w przypadku wtyczek.

Szkice, wpisy autosave

Jeśli zakończyliśmy edycję wpisów, oraz wszystkie szkice zostały opublikowane, bądź są nam już niepotrzebne możemy je usunąć. Upewnijmy się tylko uprzednio, czy opublikowane wpisy są już ostateczne i nie będziemy chcieli wracać do poprzednich wersji. Funkcjonalność WordPress’a jaką jest automatyczne zapisywanie szkiców bywa bardzo przydatna. Jednak po zakończonej edycji wpisu, opublikowania go w wersji, która nie wymaga zmian, pozostałe wersje wpisu są już niepotrzebne. Usuniemy je za pomocą zapytania sql:

DELETE FROM wp_posts WHERE post_type = "revision";

Cache

W pierwszej części wspomniałem o systemach cache dostępnych jako wtyczki, a także o możliwości napisania własnych. Poza cache generowanych plików warto ustawiać czas ważności cache takich elementów jak pliki js, css, grafiki, dla przeglądarki. Tak, aby w przypadku braku modyfikacji przeglądarka nie pobierała ponownie tych plików, nawet nie zgłaszała potrzeby ich pobrania.

Jedną z opcji będzie wydłużenie domyślnego czasu ważności plików w zależności od ich rozszerzenia. Do tego celu posłużą nam dyrektywy apache oraz plik .htaccess. Odnajdujemy plik .htaccess w lokalizacji wp-content/cache, edytujemy:

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
# BEGIN supercache
<IfModule mod_mime.c>
  <FilesMatch "\.html\.gz$">
    ForceType text/html
    FileETag None
  </FilesMatch>
  AddEncoding gzip .gz
  AddType text/html .gz
</IfModule>
<IfModule mod_deflate.c>
  SetEnvIfNoCase Request_URI \.gz$ no-gzip
</IfModule>
<IfModule mod_headers.c>
  Header set Cache-Control 'max-age=300, must-revalidate'
</IfModule>
<IfModule mod_expires.c>
  ExpiresActive On
ExpiresDefault A300
ExpiresByType application/x-javascript A3600
ExpiresByType text/css A3600
ExpiresByType image/gif A3600
ExpiresByType image/png A3600
ExpiresByType image/jpeg A3600
ExpiresByType text/plain A300
ExpiresByType application/x-shockwave-flash A3600
ExpiresByType video/x-flv A3600
ExpiresByType application/pdf A3600
ExpiresByType text/html A300
</IfModule>
# END supercache

Interesują nas wpisy od linii 16, czyli w momencie gdy moduł mod_expires.c jest dostępny. Wraz z nim dostajemy możliwość ustawienia domyślnego czasu ważności elementów strony w zależności od ich typu. Jak widzimy domyślnie ustawiony jest na A3600 – czyli 3600 sec = 1 godz. W przypadku, gdy grafiki nie będą się zbyt często zmieniać śmiało możemy wydłużyć ten okres do miesiąca czyli: A2592000. Zatem w liniach 19-23 możemy wpisać nowy czas aktualności plików dla przeglądarki. Poza określaniem czasu w sekundach mod_expires daje możliwość określania czasu za pomocą słownych określeń, np:

1
2
3
4
5
6
# Słowne określenia czasu ważności cache
<IfModule mod_expires.c>
  ExpiresActive On
ExpiresDefault "access plus 1 week"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType text/css "modification plus 5 hours"

Więcej szczegółów na stronie apache – module mod_expires

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

Autor wpisu: Michał Środek, dodany: 26.09.2009 13:21, tagi: php

Z doświadczenia wiem, że programiści dzielą się na dwie grupy: tych co będą szukać optymalizacji na kazdym kroku oraz tych, którzy wolą dokupić dodatkową kość RAM i wyspać się zamiast pracować do późna w nocy ;) . Ja oczywiście należę do tej pierwszej. Już samo użycie php nie jest najoptymalniejszym rozwiązaniem, lecz od czasu do czasu postaram się opisać w kilku słowach jak przyspieszyć swoje skrypty. Zacznijmy od echo.

1
2
3
$cat = 'Mruczek';
echo "Mój kot ma na imię $cat i jest zawsze wesoły.";
echo 'Mój kot ma na imię '.$cat.' i jest zawsze wesoły';

Sposób działania jest prosty. Podczas użycia cudzysłowów ciąg znaków jest przeszukiwany w pod kątem posiadania jakichś zmiennych. Tutaj one istnieją więc skrypt podstawia pod $cat ciąg znaków Mruczek. Następnie wyrzuca na wyjście gotowy napis. W przypadku użycia apostrofów jest troszkę inaczej. PHP nie wyszukuje żadnych zmiennych ponieważ ma jasno określone miejsce w którym te zmienne się znajdują, co sprawia, że całość działa czasami nawet kilkukrotnie szybciej.

Czy dałoby się to jeszcze bardziej przyspieszyć? Oczywiście ;) . Wystarczy posłużyć się operatorem przecinka zamiast kropki.

4
echo 'Mój kot ma na imię ',$cat,' i jest zawsze wesoły';

Większość programistów o tym nie wie ale w przypadku operatora kropki, PHP najpierw tworzy wynikowy ciąg znaków co powoduje dodatkowe obciążenie pamięci. Przy dwóch kropkach tworzone są dwie nowe zmienne String(lub dwie tablice znaków — nie będę się zagłębiał w kod wewnętrzny PHP). Jeśli użyjemy przecinków, PHP po prostu będzie każdy z elementów interpretował jak kolejne parametry(choć pamiętajmy — echo nie jest funkcją!) i wyrzucał je bezpośrednio na wyjście. Pytanie: czy opłaca się buforować wyjście za pomocą kropki(np. w przypadku długiego czasu dostępu do wyjścia)? To już pozostawiam wam do przemyśleń. Poniżej testy prędkości przy użyciu Apache Benchmark:

Wersja z cudzysłowami: Time taken for tests: 100.027 seconds Complete requests: 32772 Failed requests: 0 Write errors: 0 Total transferred: 8206540669 bytes HTML transferred: 8201253107 bytes Requests per second: 327.63 [#/sec] (mean) Time per request: 305.219 [ms] (mean)

Wersja z apostrofami: Time taken for tests: 100.018 seconds Complete requests: 42646 Failed requests: 0 Write errors: 0 Total transferred: 10669918695 bytes HTML transferred: 10663047537 bytes Requests per second: 426.38 [#/sec] (mean) Time per request: 234.531 [ms] (mean)

Wersja z przecinkiem: Time taken for tests: 100.029 seconds Complete requests: 44111 Failed requests: 0

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

Autor wpisu: cojack, dodany: 26.09.2009 10:25, tagi: javascript

Dziś chciałbym Wam przedstawić pewną bardzo fajną i przydatną bibliotekę dla przeglądarki IE (której bardzo nie lubię Nie lubie IE), która pomoże nam zrobić z IE używalną i prawie web-dev friendly.

ie7.js – co to jest?

Biblioteka jest napisana przez Dean Edwards’a w całości w JavaScript (js), nie, nie jest oparta o framework jQuery. Co nam daje ta biblioteka? Poprawia wiele błędów, które uniemożliwiają nam w klarownym sposób tworzenie layoutów pod strony, nie dość że i tak są zgodne z w3c to mimo wszystko czasami zdarzy się że IE się wyburaczy, i mowa tutaj zarówno o IE6 jak i o IE7, chodź ta druga jest już trochę bardziej przystosowana do życia w rodzinie. Możemy też dzięki tej bibliotece cieszyć się przejrzystością plików *.png, dodając tym co chcemy obrazkom infix czyli blabla-trans.png, podkreślony jest infix, czyli to co chcemy dodać.

Naprawmy selektory css w ie

Biblioteka ie7.js naprawia nam takie selektory css jak:

  • rodzic > dziecko
  • rodzic + dziecko
  • rodzic ~ dziecko
  • .multiple.classes
  • :hover
  • :first-child
  • [attr]
  • [attr="value"]
  • [attr~="value"]
  • [attr|="value"]
  • [attr^="value"]
  • [attr$="value"]
  • [attr*="value"]

Naprawmy właściwości css w ie

Biblioteka ie7.js naprawia nam takie właściwości css jak:

  • background-attachment
  • background-image
  • bottom
  • cursor
  • display
  • font-size
  • margin
  • max-height
  • max-width
  • min-height
  • min-width
  • overflow
  • position
  • right

Naprawmy elementy html w ie

Biblioteka ie7.js naprawia nam takie elementy html jak:

  • abbr
  • img – mowa o infixie
  • label

Naprawmy pozostałe błędy w ie

Biblioteka ie7-squish.js naprawia nam takie elementy html jak:

  • Podwójny margin
  • Peekaboo
  • Nieprzewijana treść

Jest też jeszcze opis biblioteki ie8.js która poprawia braki w przeglądarce ie7, ale za dużo treści ma. Na samym dole artykuły wszystkie linki.

Jak używać?

Ażeby strona nam piknie śmigała robimy jedną rzecz gdzieś w nagłówku, pomiędzy atrybutami <head> a </head> wstawiamy o to ten kod:

<!--[if lt IE 8]>
<script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE8.js" type="text/javascript"></script>
<script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/ie7-squish.js" type="text/javascript"></script>
<![endif]-->

To wszystko, oczywiście możemy pobrać to na twardziela hostinga i trzymać, ale po co? ;]

Autor wpisu: stormfly, dodany: 24.09.2009 22:18, tagi: apache

Udało mi się zdiagnozować ciekawy przypadek kiedy regułka rewrite nie działa tak jakbyśmy się tego spodziewali. "Winą" za to obarczam Apache, który posługuje się magicznymi sztuczkami. Utwórzcie sobie przykładowo plik rewrite.php np. ze skryptem: a następnie uruchomcie w...

Autor wpisu: Zyx, dodany: 24.09.2009 08:28, tagi: php

Tydzień temu ukazał się PHPUnit 3.4.0, który wprowadza kilka bardzo użytecznych nowości. Docenią je w szczególności osoby, które mają do przetestowania złożone, obiektowe interfejsy i borykają się z problemem odpowiedniej izolacji testów oraz wpływania na zmienne statyczne, czyli stany globalne aplikacji, które testuje się bardzo ciężko.

Autor wpisu: Vokiel, dodany: 23.09.2009 10:48, tagi: php

Programując w PHP czasami natykamy się na problemy operując na datach w języku polskim. Chcąc uzyskać nazwy miesięcy i/lub dni tygodnia nie zawsze możemy polegać na wbudowanych w PHP funkcjach. Tym bardziej jeśli w grę wchodzi ich odmiana. Bardzo łatwo możemy sobie z tym poradzić. Wystarczy dopisać swoją funkcję.

Konfiguracja wbudowanych funkcji

Do dyspozycji mamy funkcje date() oraz strftime(). Pierwsza z nich niestety nie zwraca daty z lokalnymi nazwami. Za to strftime() jest możliwe do ustawienia.

Co należy ustawić, aby domyślnie PHP korzystał z lokalizacji polskiej?

$arrLocales = array('pl_PL', 'pl','Polish_Poland.28592');
setlocale( LC_ALL, $arrLocales );

Funkcja setlocale() ustawia opcje regionalne. Za pierwszy parametr może przyjmować:

  • LC_ALL dla wszystkich poniżej
  • LC_COLLATE ciąg dla porównania, patrz strcoll ()
  • LC_CTYPE na charakter i klasyfikację konwersji, na przykład strtoupper ()
  • LC_MONETARY dla localeconv ()
  • LC_NUMERIC dla separator (Patrz także localeconv ())
  • LC_TIME do formatowania daty i czasu z strftime ()
  • LC_MESSAGES dla systemu odpowiedzi (dostępna jeśli PHP zostało skompilowane z libintl)

Dzięki temu zabiegowi ustawiliśmy język polski jako domyślny. Jednak problemy zaczynają się w przypadku, gdy zechcemy użyć kodowania innego niż ISO-8859-2 (które jest ustawiane poprzez Polish_Poland.28592'). Musimy niestety przekonwertować zwracane dane z ISO-8859-2 na UTF-8. Zrobimy to za pomocą prostej funkcji:

function strftimeV($format,$timestamp){
	return iconv("ISO-8859-2","UTF-8",ucfirst(strftime($format,$timestamp)));
}

Użycie:

<?php
echo strftimeV('%A %d %B %Y',strtotime('2009-09-02'));
?>

Daje w wyniku Środa 02 wrzesień 2009, co jest troszeczkę nie po polsku.

Utworzenie własnej funkcji obsługi formatu daty

Pozostaje nam stworzenie własnej funkcji, która odpowiednio zamieni format. Na początku skryptu ustawiamy domyślną strefę czasową używaną przez funkcje date/time:

date_default_timezone_set('Europe/Warsaw');

Następnie tworzymy naszą funkcję, która odpowiednio przekonwertuje standardowy format daty dla funkcji date(). Najlepiej aby była zgodna, tak aby w przypadku zamiany jej na zwykłą date() nie trzeba było przepisywać formatów. Niestety w języku polskim mamy odmianę, co skutecznie uniemożliwia nam pełną zgodność. Problem pojawia się właściwie tylko w przypadku miesięcy, dni tygodnia zwykle używa się w formie podstawowej, natomiast miesiące już różnie. Raz jest styczeń, innym razem stycznia. Aby móc skorzystać z kilku form będziemy musieli rozszerzyć format daty o własne znaczniki. Interesujące nas znaczniki formatu daty to l (małe L) oraz F. Dodamy własne oznaczenie f, Które nie występuje na liście parametrów formatu date. Utwórzmy zatem własną funkcję dateV() – czyli funkcję dateVokiel() ;)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function dateV($format,$timestamp=null){
	$to_convert = array(
		'l'=>array('dat'=>'N','str'=>array('Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota','Niedziela')),
		'F'=>array('dat'=>'n','str'=>array('styczeń','luty','marzec','kwiecień','maj','czerwiec','lipiec','sierpień','wrzesień','październik','listopad','grudzień')),
		'f'=>array('dat'=>'n','str'=>array('stycznia','lutego','marca','kwietnia','maja','czerwca','lipca','sierpnia','września','października','listopada','grudnia'))
	);
	if ($pieces = split('[:/.\ \-]', $format)){	
		if ($timestamp === null) { $timestamp = time(); }
		foreach ($pieces as $datepart){
			if (array_key_exists($datepart,$to_convert)){
				$replace[] = $to_convert[$datepart]['str'][(date($to_convert[$datepart]['dat'],$timestamp)-1)];
			}else{
				$replace[] = date($datepart,$timestamp);
			}
		}
		$result = str_replace($pieces,$replace,$format);
		return $result;
	}
}

Krótkie omówienie funkcji dla wywołania:

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

Autor wpisu: cojack, dodany: 22.09.2009 12:15, tagi: php

Tak więc przyszedł czas by omówić klasę dispatcher’a (dyspozytora), jest to pewien wzorzec projektowy, dzięki któremu będziemy mogli zarządzać zdarzeniami. Tak projektowanie oparte na zdarzeniach, jak pewnie łatwo jest się Wam domyślić, gdy piszę o zdarzeniach myślę o przesyłanych przez url get’ach. Kiedy nasza fantazja prowadzi nas ku lepszym i co raz to abstrakcyjnym rozwiązaniom, będziemy mieli umysł otwarty na nowe być może lepsze oraz na pewno ciekawe rozwiązania.

Wracając do tematu, dispatcher, odpowiada za:

  • sprawdzenie czy klasa istnieje
  • załadowanie tej że klasy
  • wywołanie metody z klasy
  • łapanie błędów – to akurat u mnie [;

Akurat dzisiaj nie przedstawię Wam żadnego kodu, tylko odeślę do zbioru klas, na stronie phpclasses. Link Dispatcher

Nie zachęcam do jakiegoś głosowania czy coś. Zachęcam do działania!

Jako iż jeszcze moderatorzy z phpclasses.org nie zaakceptowali mojej klasy (nie wiadomo czemu) wrzucam tutaj kod:

Rdzeń systemu jest oparty o plik Dispatcher.php:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php
/**
 * @li gnu/agpl v3 or later
 * @code utf8
 * @version 0.1
 * @author cojack from Aichra.pl
 * @date 22.09.09
 *
 **/
 
/**
 * We require a event handler
 */
require_once('HandlerShow.php');
 
 
/**
 * @class Dispatcher
 * @throw Exceptions
 * @access final
 * 
 * Can't extend from it, it's a finall class.
 * Class auto call a handled class "name" from event.
 * 
 */
 
final class Dispatcher {
 
  private $_handle;
  private $_response;
 
  /**
   * @method __construct
   * @access public
   * @param string a event name
   * @return void
   * 
   * Method set a event.
   * 
   */
  public function __construct($event) {
    $this->_handle = $event;
  }
 
  /**
   * @method handleEvent
   * @access public
   * @param void
   * @return void
   * 
   * That event handle is a class "name".
   * Method check that handle exist.
   * 
   */
  public function handleEvent() {
    try {
      $name = 'Handler'.ucfirst($this->_handle);
      if ( class_exists("$name") ) {
	$handObj = new $name($this->_handle);
	$this->_response = $handObj->handledEvent();
      } else {
	throw new Exception ('Can\'t be handled this Event');
      }
    } catch (Exception $e) {
      printf ('Error: %s',$e->getMessage());
    }
  }
 
  /**
   * @method getResponse
   * @access public
   * @param void
   * @return plain text etc..
   * 
   * Method return a _response.
   * 
   */
  public function getResponse() {
    return $this->_response;
  }
 
}

Jak widać nie zwracam wyniku z załadowanego eventu wprost do głównego pliku, dlaczego? A no dlatego że ostatnio metaxy zaciekawił mnie systemem szablonów OPT 2, i w oparciu o niego i jego filozofie a jest dosyć ciekawa tworzę aichra lite cms oraz w oparciu o Doctrine, ale nie teraz o tym mowa, chodzi o to że nie muszę od razu w pliku wynikowym zwracać i generować treści, tylko dopiero na końcu, czyli tam gdzie chce, a nie tam gdzie być powinna. Dlatego odpowiedź jest przypisana do zmiennej a nie zwracana.

Klasa jest b.prosta wczytujemy w niej 1 plik bo tylko mamy w tym przykładzie jedną akcję, chodź ja osobiście bym ten plik wczytywał gdzieś indziej i było by to bardziej dynamicznie, ale na potrzeby tej klasy zrobiłem to tak.

A teraz interfejs oraz klasa abstrakcyjna dla eventów:

Plik: Handled.php

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

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.