Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

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...

Autor wpisu: Vokiel, dodany: 21.09.2009 13:44, tagi: php

W pierwszej części Log class – klasa loggera zdarzeń rozpoczęliśmy prace nad klasą logowania zdarzeń. Utworzyliśmy interfejs klasy, który będzie implementowany. W tej części zajmiemy się implementacją tego interfejsu.

Z racji użycia interfejsu, klasy naszego loggera muszą zawierać 3 publiczne, statyczne metody: error(), warn(), info(). Najłatwiejszym, a zarazem dość przenośnym rodzajem klasy logowania do napisania jest logowanie do pliku. Zatem stwórzmy taką klasę:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class logFile implements log_log {
	public static function error($err){
		echo 'logFile - error |'.$err;
	}
	public static function warn($err){
		echo 'logFile - warn |'.$err;
	}
	public static function info($err){
		echo 'logFile - info |'.$err;
	}
}
?>

Taki zarys musi mieć (ze względu na implementację interfejsu) nasza klasa logFile – logująca do pliku. Jednak to co mamy do tej pory nie jest zbyt użyteczne ;) Zatem zajmijmy się wypełnieniem metod:

Wszystkie z trzech metod mają za zadanie zapisać informację do logu, z tą różnicą, że są to informacją z inną flagą (błąd, ostrzeżenie, informacja). Zatem możemy je połączyć w jedną write(), która będzie zapisywać log do pliku.

<?php
/**
 * Zapis pojedynczego komunikatu
 * @param	string	$logMsg	Pojedynczy komunikat
 */
private function write($logMsg){
    file_put_contents(self::$file_name,$logMsg,FILE_APPEND | LOCK_EX);	
}
?>

Zapis do logu jak widzimy możemy przeprowadzić za pomocą file_put_contents, z ustawionymi flagami FILE_APPEND | LOCK_EX – dopisywaniem do pliku, jeśli istnieje oraz blokowaniem dostępu do pliku na czas zapisu. Dzięki temu logów w naszym pliku będzie przybywało, nie będą zastępowane, nadpisywane.

Po dodaniu metody write trzy wcześniej utworzone powinny ją wywoływać. Zatem w ciele metod dodajemy wywołanie metody write:

<?php
/**
 * Dodanie komunikatu informacyjnego do logów
 * @see log_log#info($msg)
 */
public static function info($msg){
	self::write(self::logPrefix('INFO').$msg);
}
?>

Pojawiła się tu nowa rzecz: self::logPrefix('INFO');. Otóż jest to wywołanie kolejnej metody, która ma za zadania do linii logu dodać informację o rodzaju zdarzenia, które jest logowane. Jak ta metoda wygląda w przypadku logowania do pliku? Następująco:

<?php
/**
 * Dodanie przedrostka do linijki logu
 * @param	string	$flag	Flaga określająca rodzaj zdarzenia
 * @return	string
 */
private function logPrefix($flag){
	return "\n".date('Y-m-d H:i:s')."\t|".$flag."\t|\t";
}
?>

Przyjęty format pliku logu wygląda następująco:

TIMESTAMP	|TYPE	|	MESSAGE

Przykładowo:

2009-09-02 10:50:07	|INFO	|	Pomyślnie zakończono akcję 123
2009-09-02 10:50:07	|WARN	|	Brak aktywnych zadań
2009-09-02 10:50:33	|ERROR	|	Połączenie zerwane

Wykańczając naszą klasę loggera dogramy kilka szczegółów: wybór pliku logu, ustawienie domyślnego logu w przypadku jego braku. Możemy to zrobić na kilka sposobów, jeden z nich:

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

Autor wpisu: Vokiel, dodany: 16.09.2009 13:11, tagi: css, php

W tym artykule skupimy się na szybkiej i łatwej implementacji funkcjonalności zmniejszania rozmiaru oraz łączenia wielu plików CSS w jeden.

Jeśli ktoś używa wtyczki do FF: YSlow może łatwo sprawdzić ile zewnętrznych plików css jest dołączanych do strony. Im więcej tym gorzej. Analizując dokładniej wskazania YSlow możemy zauważyć na co należy zwrócić uwagę odnośnie CSS. Są to m.in:

  • Make fewer HTTP requests – mniej żądań HTTP
  • Avoid CSS expressions – unikanie ostylowania wewnątrz kodu
  • Make JavaScript and CSS external – stworzenie zewnętrznych plików JavaScript oraz CSS
  • Minify JavaScript and CSS – zmniejszenie rozmiaru JavaScript oraz CSS
  • Put CSS at top – dołączenie zewnętrznych arkuszy stylów w nagłówku dokumentu
  • Compress components with gzip – kompresja elementów strony gzip’em
  • Add Expires headers – dodanie nagłówków informujących przeglądarkę o czasie ważności elementów

Co możemy zrobić sami na szybko? Przede wszystkim ograniczyć ilość żądań. Przeglądarki mają to do siebie, że ograniczają ilość jednoczesnych żądań do jednego serwera. Zatem jeśli przeglądarka ma domyślnie ustawione 4 żądania na serwer, a mamy zewnętrznych elementów na stronie 20, to po rozpoczęciu pobierania pierwszych czterech przeglądarka czeka, aż zostaną pobrane, zanim sięgnie po następne. Jeśli połączymy pliki CSS, JavaScript w jeden zmniejszymy tym ilość niezbędnych do wywołania żądań – dzięki temu przeglądarka szybciej pobierze resztę strony.

Zatem do dzieła! Tworzymy plik css_cache.php o takiej postaci:

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
< ?php 
/**
 * Tworzenie pliku cache z pobranych plików css
 * @param	string	$cache_file_name	Nazwa pliku cache
 */
function generateCache($cache_file_name){
    $dir = '.';
    if (is_dir($dir)){
        if ($handle = opendir($dir)) {
            $css_content = '/* Utworzono :'.date('Y-m-d H:i:s').' */';
            while (false !== ($file = readdir($handle))) { 
                if (strtolower(substr(strrchr($file,"."),1)) == 'css'){ 
                    $css_content .= "\n\n".'/* CSS z pliku: '.$file.' */'."\n".preg_replace('/\s+/', ' ', file_get_contents($file));
                }
            }
            closedir($handle);
            file_put_contents($cache_file_name,$css_content);
        }
    }
}
/**
 * Funkcja pobierająca plik cache
 * @param   string  $cache_file_name    Nazwa pliku
 * @param   int $cache_time Czas ważności w sekundach
 * @return unknown_type
 */
function getCache($cache_file_name,$cache_time){
    if (file_exists($cache_file_name)){
        if ($cache_time){ // jest podany termin waznosci cache
            if (filemtime($cache_file_name ) < (time() - $cache_time)) { //cache nieaktualny, pobranie od nowa i utworzenie
                generateCache($cache_file_name);
            }
        }
    }else{// brak cache - utworznie
        generateCache($cache_file_name);
    }
    return file_get_contents($cache_file_name);
}
?>

Następnie użycie plik css.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
< ?php
if(array_key_exists("HTTP_IF_MODIFIED_SINCE",$_SERVER)){
    $if_modified_since = strtotime(preg_replace('/;.*$/','',$_SERVER["HTTP_IF_MODIFIED_SINCE"]));
    if($if_modified_since >= strtotime(filemtime($cache_file_name))){
        header("HTTP/1.0 304 Not Modified");
        exit();
    }
}
/**
 * Nazwa pliku cache
 * @var string
 */
$cache_file_name = 'cache_style.css';
/**
 * Czas ważności cache w sekundach
 * 0 - cache bez terminu ważności
 * @var unknown_type
 */
$cache_time = 0;
require_once 'css_cache.php';
header("Content-type: text/css; charset: UTF-8");
header("Pragma: public");
header("Cache-Control: public");
header('Expires: '.gmdate('D, d M Y H:i:s', strtotime('+1 year').' GMT'));
header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($cache_file_name)).' GMT');
ob_start("ob_gzhandler");
echo getCache($cache_file_name,$cache_time);
ob_end_flush();
?>

Krótkie omówienie: W pliku css_cache.php mamy 2 funkcje: generateCache($cache_file_name) oraz getCache($cache_file_name,$cache_time). Pierwsza z nich tworzy nam jeden zbiorczy plik cache ze wszystkich plików css znalezionych w katalogu (podanym jako parametr $dir – domyślnie obecny). Pliki oznaczane są komentarzem informującym kiedy i z jakiego pliku został utworzony dany fragment, do tego preg_replace załatwia nam sprawę zbędnych pustych znaków. Druga z nich pobiera plik cache. Jeśli został podany parametr $cache_time określający ważność cache, funkcja sprawdza, czy plik cache jest jeszcze aktualny. Jeśli plik nie jest aktualny, lub w ogóle nie istnieje jest tworzony na nowo. Następnie funkcja zwraca zawartość takiego skompresowanego pliku.

W pliku css.php mamy prosty przykład wykorzystania. Na początku sprawdzamy, czy wysłany uprzednio plik jest jeszcze aktualny (nagłówki HTTP_IF_MODIFIED_SINCE), jeśli tak – nie robimy nic – zwracamy informację, że plik nie został zmodyfikowany od czasu ostatniej wizyty. Jeśli jednak plik został zmodyfikowany, bądź jest to pierwsze wejście wysyłane są nagłówki ważności oraz odczytywany jest plik z cache.

Aby wykorzystać system na stronie wystarczy w nagłówku strony podać link do pliku css:

<link rel="stylesheet" type="text/css" href="css.php" />

Autor wpisu: cojack, dodany: 15.09.2009 16:14, tagi: php

Tak więc na phpclasses.org jakiś czas temu pojawiła się nowa klasa o nazwie sTemplate, co lepsze, jest to twór Polaka, co mnie bardzo cieszy a kolejne zdziwienie jakie mnie naszło, że jest to młody chłopak co mnie jeszcze bardziej cieszy, gdyż tacy ludzie są lub będą intelektualną śmietanką jeżeli w dalszym ciągu będą rozwijać swoją wiedzę oraz chcieć poznawać i tworzyć nowe rzeczy. Wracając do rzeczy, autorem tego systemu szablonów jest Sebastian Potasiak, link do jego blogu jest u mnie na stronie zatytułowanej Linki. Do rzeczy z czym to się je? Kolega rozwiązał w dość sprytny sposób ominięcie na wstawianie zmiennych w tpl, czyli jak w itx np {SOME_VARIABLE} lub też w smartach {$some_variable}, przykład:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" lang="pl">
     <head>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          <title class="tytul"></title>
     </head>
     <body>
          <div class="tytul"></div>
          <div class="tresc"></div>
     </body>
</html>

Jak widać nie ma niczego co by można było parsować, a teraz spójrzmy na to:

1
2
3
4
5
6
7
8
9
10
11
<?php
     include('./sTemplate.class.php');
 
     $tpl = new sTemplate;
 
     $zmienne = array(
          'tytul' => 'Moja strona',
          'tresc' => 'To jest przykładowa treść mojej strony.<br />Aby zobaczyć więcej wyślij SMS o treści CHWDP na numer PREFIX_997'
     );
 
     $tpl->load('home', $zmienne);

Co nam to zwróci? A taki kod:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" lang="pl">
     <head>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          <title class="tytul">Moja strona</title>
     </head>
     <body>
          <div class="tytul">Moja strona</div>
          <div class="tresc">To jest przykładowa treść mojej strony.<br />Aby zobaczyć więcej wyślij SMS o treści CHWDP na numer PREFIX_997</div>
     </body>
</html>

Takie sobie to co? Ja widzę parę problemów, dajmy na to że klasa title używamy do wylistowania artykułów, i jeżeli mielibyśmy ciągle taki sam tytuł to trochę do bani co? ;] Więc prosty system szablonów, na bardzo proste strony. Jak się mają benchmarki, a czort go wie ;] W następnym wpisie przedstawię wyniki.

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