Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: batman, dodany: 23.01.2011 08:00, tagi: php

Programiści PHP mają do dyspozycji dwa kombajny od brudnej roboty. Są to Eclipse oraz NetBeans (kolejność alfabetyczna). Oba narzędzia oferują zbliżone możliwości, więc wybór tego właściwego zależy głównie od aktualnego stanu umysłu, estetyki oraz widzi-mi-się osoby wybierającej. W moim przypadku padło na Eclipse. I wszystko byłoby w należytym porządku, gdyby nie drobny szkopuł – mój Eclipse mnie nie lubi. Nie ważne skąd go ściągnę, gdzie rozpakuję, jak skonfiguruję i tak za kilka dni (maksymalnie kilka tygodni) odmówi posłuszeństwa.

Nie inaczej było tym razem. Związki zawodowe skupione wokół DLTK stwierdziły, że za dużo pracują i ogłosiły strajk. Pół biedy gdyby ogłosiły strajk włoski. Przynajmniej Eclipse działałby jak powinien. Ale nie. Zabarykadowali się w swoim workspace i ani myślały wracać do pracy. Z drobnymi poprawkami jakoś sobie radziłem (ale żeby zabrać nawet podpowiadanie składni klas z tego samego pliku? skandal!), jednak większe zmiany powodowały iż poczułem się jak 5 lat temu – kolorowanie składni, manual i jedziemy.

Oburzony takim obrotem spraw, zakasałem rękawy i zacząłem szukać rozwiązania. Negocjacje ze strajkującymi zacząłem standardowo (jeszcze nie wiedziałem, że chodzi o DLTK) od sprawdzenia co się dzieje w pliku .project. Zawiera on podstawowe informacje o typie projektu oraz uruchamianych builderach. Typowy plik powinien wyglądać podobnie do tego.

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
	<name>Projekt</name>
	<comment></comment>
	<projects>
	</projects>
	<buildSpec>
		<buildCommand>
			<name>org.eclipse.wst.validation.validationbuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>org.eclipse.dltk.core.scriptbuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
	</buildSpec>
	<natures>
		<nature>org.eclipse.php.core.PHPNature</nature>
	</natures>
</projectDescription>

I tak też wyglądał. Czyżby strajk był poważniejszy niż to początkowo zakładałem? Nic to, szukam dalej. Pora na plik .buildpath.

<?xml version="1.0" encoding="UTF-8"?>
<buildpath>
	<buildpathentry kind="src" path=""/>
	<buildpathentry kind="con" path="org.eclipse.php.core.LANGUAGE"/>
</buildpath>

Jednak i tym razem wszystko wygląda poprawnie.

Zaniepokoiłem się nie na żarty i zacząłem układać czarne scenariusze od konieczności ponownej instalacji i konfiguracji wtyczek, na wywaleniu wszystkiego w diabły i zainstalowania NetBeansa. Wtem spowiło mnie ciepłe białe światło i szara istota z dużą głową z wielkimi czarnymi oczami wyszeptała mi do ucha – “sprawdź logi Eclipse’a”.

To było to. W katalogu workspace znajdują się metadane Eclipse’a, a między nimi plik .log, będący niemym świadkiem wszystkich Eclipsowych świństw. Wyczyściłem jego zawartość (uprzednio przygotowując kopię zapasową), a następnie zacząłem podglądać na żywo co się w nim dzieje. Uruchomiłem Eclipse i udawałem, że pracuję. Strajkujący od razu naprostowali łamistrajków. Na szczęście pozostał po tym haniebnym zdarzeniu ślad w postaci wyjątku zgłoszonego przez Javę. Winowajcą był plik model.index.db chowający się w katalogu C:\Users\batman\workspace\.metadata\.plugins\org.eclipse.dltk.core.index.sql.h2. Wykonałem kopię zapasową, usunąłem winowajcę i ponownie zbudowałem projekt. Bingo! Eclipse znowu podpowiada składnię! Kolejny raz korporacja pokonała pracujący w pocie czoła lud.

Autor wpisu: batman, dodany: 21.01.2011 08:00, tagi: php

Piąta odsłona PHP została zaprezentowana światu w roku 2004. Zmiany wprowadzone do języka były wręcz rewolucyjne. Programowanie obiektowe w PHP przestało budzić uśmiech politowania, a szereg usprawnień i nowych funkcjonalności robił ogromne wrażenie. Mimo iż od premiery “obiektowego PHP” minęło ponad sześć lat, nadal niektóre – nawet te podstawowe – funkcjonalności pozostają niezrozumiałe i albo kurzą się w zaciszu manuala albo są wykorzystywane w sposób wołający o pomstę do nieba. Taki właśnie los spotkał wyjątki.

Zanim zaczniemy poznawać wyjątki dostępne w ramach SPL, warto wiedzieć po co w ogóle one powstały. Ich powstaniu przyświecał jeden cel – możliwość sterowania przepływem aplikacji w obliczu błędu. A po naszemu – nawet jeśli coś nie zadziała, aplikacja nie wyłoży się koncertowo, tylko będzie próbowała działać w ograniczonym zakresie.

Poza standardową klasą Exception, będącą nadrzędną klasą dla wyjątków, w PHP (a dokładniej w SPL) mamy dostępnych kolejnych trzynaście klas wyjątków. Każda z nich powstała w innym celu.

BadFunctionCallException

Wyjątek BadFunctionCallException powstał w celu zasygnalizowania niepopranego wywołania funkcji. Co należy przez to rozumieć? Najprościej będzie to wytłumaczyć na przykładzie.

try {

	callMe();

} catch(BadFunctionCallException $e) {
	echo $e;
}

function callMe()
{
	$args = func_num_args();
	if($args < 2) {
		throw new BadFunctionCallException('Za mało argumentów');
	}
}

BadFunctionCallException można również rzucać w przypadku braku niepoprawnej nazwy funkcji do wywołania.

BadMethodCallException

Obiektowy odpowiednik poprzedniej klasy.

try {

	$foo = new Foo();
	$foo->niesitniejacaMetoda();

} catch(BadMethodCallException $e) {
	echo $e;
}

class Foo
{
	public function __call($method, $args)
	{
		switch($method) {
			case 'foo':
				/* do magic */
				break;
			default:
				throw new BadMethodCallException('Nie ma takiej metody');
		}
	}
}

DomainException

Najmniej zrozumiały i najmniej potrzebny (póki co) wyjątek dostępny w PHP. Wyjątek DomainException powinien zostać zgłoszony w momencie próby skorzystania z danych nienależących do bieżącej domeny. Jak na razie na temat tego wyjątku toczą się akademickie dyskusje, z których można dowiedzieć się, że np. obiekt Foo nie znajduje się w domenie dni tygodnia. W przypadku PHP nie spotkałem się jeszcze z praktycznym zastosowaniem tej klasy.

InvalidArgumentException

Wyjątek zgłaszany w momencie otrzymania niespodziewanego/niepoprawnego argumentu.

try {

	$foo = new Foo();
	$foo->bar('abc');

} catch(InvalidArgumentException $e) {
	echo $e;
}

class Foo
{
	public function bar($arg)
	{
		if(!is_numeric($arg)) {
			throw new InvalidArgumentException('Niepoprawny argument');
		}
	}
}

LengthException

Ten typ wyjątku zgłaszany jest w przypadku odebrania danych o niepoprawnej długości. Niepoprawna długość danych oznacza tutaj nieprawidłowy rozmiar odebranego pliku, błędną ilość danych przesłanych ze strumienia, czy też nieoczekiwaną wielkość tablicy.

try {
	$a = array(123, 234, 345);

	// z jakiegos powodu tablica musi zawierać dwa elementy
	if(count($a) != 2) {
		throw new LengthException('Niepoprawna wielkość tablicy');
	}

} catch(LengthException $e) {
	echo $e;
}

LogicException

Kolejny klasa wyjątku, z której nie będziemy zbyt często korzystać. Zgłaszany jest w momencie, gdy wyrażenie logiczne oznacza fałsz.

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

Autor wpisu: batman, dodany: 19.01.2011 08:00, tagi: php

Przed kilkoma dniami Microsoft powiadomił świat o wydaniu stabilnej wersji WebMatrixa. Premiera odbyła się w zaciszu bloga IIS i nie wywołała fali zachwytów ani krytyki. Twitter nie utonął w zalewie wiadomości, a blogi na spokojnie przyjęły pojawianie się… No właśnie. Co się pojawiło? Jeśli miałbym krótko opisać czym jest WebMatrix musiałbym sparafrazować akronim WAMP (LAMP) [...]

Autor wpisu: batman, dodany: 18.01.2011 08:00, tagi: php

W dzisiejszej części ASP.NET MVC dla programistów PHP ponownie zajmiemy się kontrolerami. Tym razem poznamy sposoby przekazywania danych do kontrolera. W przeciwieństwie do Zend Framerowka, w którym operujemy tylko na obiekcie request, ewentualnie na “gołych” danych pobranych z superglobalnych tablic, ASP.NET MVC oferuje kilka dodatkowych sposób odbierania danych. Konteksty Najprostszym sposobem odebrania przychodzących danych jest [...]

Autor wpisu: sokzzuka, dodany: 18.01.2011 00:13, tagi: php, doctrine

Ostatnio wiele mówi się o bazach danych NoSQL (NotOnlySQL). Jako, że nie zauważyłem nic w polskim światku PHP na ten temat, stwierdziłem, że pora wypełnić tę lukę i zagłębić się w temat.

Czym są bazy NoSQL ?

Jak podpowiada nam ciotka wikipedia. Bazy NoSQL są to bazy danych, które nie są klasycznymi relacyjnymi bazami danych jakie znamy (MySQL,PostgreSQL etc). Termin NoSQL nie odpowiada żadnym wspólnym cechom tych baz, a raczej temu, że na pewno nie są one RDBMS-ami.

Popularne bazy NoSQL są magazynami danych. W przeciwieństwie do klasycznych odpowiedników nie posiadają stałego schematu, a dane przechowują jako pary klucz – wartość.

Jako przykład dla naszych rozważań wybrałem bazę MongoDB. Dlaczego akurat tą? Istnieją dwa główne powody. Pierwszym z nich jest to, że twórcy projektu Doctrine, stworzyli również ORM w wersji dla tej bazy. Drugim natomiast to, że baza jest szczególnie przyjazna dla webdeveloperów.

Jej przyjazność objawia się tym, że baza żyje i oddycha Javascriptem. Shell przyjmuje komendy tylko w tym języku. Natomiast odpowiedź na zapytania zwracana jest w formacie JSON. Ciekawą rzeczą, może mniej dla webdeveloperów a bardziej dla zwolenników funkcyjnego podejścia do programowania, jest to, że baza wspiera rozproszony model obliczeń oparty na paradygmacie map-reduce. Na roztrząsanie tego tematu czas przyjdzie później. Natomiast teraz przejdźmy do części praktycznej.

Instalacja

  1. Na stronie projektu, wyszukujemy odpowiednią dla nas paczkę i ściągamy
  2. Rozpakowujemy ją w dowolnym katalogu
  3. W głównym katalogu dysku tworzymy folder data/db
  4. W katalogu gdzie rozpakowaliśmy paczkę z bazą odpalamy plik bin/mongod.exe
  5. Z sourceforge ściągamy driver do php w postaci rozszerzenia (w archiwum są dll-e dla odpowiednich wersji php)

W tej chwili mamy już działającą bazę MongoDB. Kolejnym krokiem będzie zaprzęgnięcie Doctrine’a do pracy.

Struktura projektu:

|--application
|---model
|----MailBox
|------Message.php
|-----User.php
|--lib
|---vendor
|----Doctrine
|--proxies
|--index.php

Do katalogu Doctrine ściągamy ODM (Object Document Mapper).

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

Autor wpisu: Śpiechu, dodany: 17.01.2011 22:43, tagi: php

Odrabiając zaległości na planecie PHP zainteresowałem się biblioteką filtrującą HTML Purifier zareklamowaną przez Kamila Brenka. Po wykonaniu kilku testów „popsucia kodu” i obserwacji jak biblioteka poradzi sobie z naprawieniem uznałem, że przydałoby się takie cudo w WordPressie. No i proszę: w oficjalnym repozytorium pluginów do WordPressa mamy wtyczkę filtrującą komentarze. Zwie się HTML Purified.

Co to w skrócie potrafi:

  • pozwala wybrać mechanizm filtrujący komentarze pomiędzy domyślnym wordpressowym KSES a zachwalanym wyżej HTML Purifier
  • możemy wybrać dozwolone tagi i atrybuty w komentarzach
  • możemy pozwolić wtyczce „naprawić” kod zawarty w komentarzu w 4 trybach:
    1. none — bez ingerencji w kod,
    2. lekki — poprawia wyłącznie elementy nieużywane w ustawionym DOCTYPE
    3. średni — wprowadza „najlepsze praktyki” (tak napisali w dokumentacji)
    4. ciężki — najbardziej zasobożerna transformacja tagów i atrybutów do spełniających standardy

Wtyczka na tyle mi się spodobała, że zrobiłem jej spolszczenie. Miałem nadzieję być w stanie umieścić je samodzielnie w repozytorium SVN wtyczki, ale wywala mi błąd 403. Próby kontaktu z autorem na razie bez odzewu. W razie dodania aktualizacji łaskawie o tym poinformuję.

Póki co ściągajcie ode mnie. (Najlepiej poprzez zapisz link jako…) pl_PL.mo pl_PL.po

Obydwa pliki należy umieścić w katalogu locale wtyczki.

Nie przyjmuję zażaleń apropos śmiesznego brzmienia słów escapowanie i back-ticki. Nie wiem jak to przetłumaczyć na w miarę krótką formę. Może jakieś propozycje?

Autor wpisu: Athlan, dodany: 15.01.2011 16:54, tagi: php.pl, mysql, sql

Nie raz, nie dwa mieliśmy sytuację, która wymagała od nas koniunkcji warunków większej ilości danych lub dane te były tekstowe, ale niedługie. Niby nic, klucze załatwiają sprawę, ale sięgając do kodu gry bukmacherskiej, musiałem ją nieco zoptymalizować pod względem częstego wyciągania danych. Baza rozrosła się dość szybko, dlatego niezbędna była lekka modyfikacja jej struktury.

Moim zadaniem było bardzo częste wyciągnięcie ID meczu, który musiał na raz (AND) być zgodny z żądaną datą, nazwą drużyny pierwszej oraz drugiej. Informacji do warunków dostarczał system. Oprócz daty, są to dane tekstowe, więc połączyłem je ze sobą CONCAT i stworzyłem z nich sumę md5. Indeks, po którym baza szukała, był już krótszy od warunków, bo zawierał zawsze 32 znaki. Pierwszym warunkiem koniunkcji zawsze była suma md5 wymienionych wcześniej pól rekordu, nazwałem to suma kontrolna rekordu, potem faktyczna wartość pól, aby w razie zdublowania sumy kontrolnej (czego się nie spodziewamy, bo zakres wariacji jest ogromny, ale dla idei) wybrać prawidłowy rekord. Do tej pory wystarczało…

Gdy baza rozrasta się, problemem staje się wyszukiwanie. O ile suma kontrolna to już krok w stronę optymalizacji, dla >100k rekordów, baza danych potrzebowała co najmniej 0.05 sekundy na zwrócenie wyniku. Postanowiłem dodać odcisk palca sumy kontrolnej. Najlepszym rozwiązaniem okazało się dodanie jednego bajtu, który zrobił magię w bazie danych. Jedno pole TINYINT – 8 bitów, zakres 0-255 bez znaku. Założenia odcisku palca:

  • jest wartością liczbową oraz zajmuje tylko jeden bajt, aby oszczędzić miejsca w rekordach oraz indeksach bazy danych,
  • nie musi być uniwersalny (unikalny), a jedynie grupować odciski palców w mniejsze, a liczniejsze zbiory.

Rozwiązanie, które zastosowałem przy generowanu odcisku palca sumy kontrolnej, również nie jest skomplikowane:

  1. Odcisk palca to suma kolejnych znaków sumy kontrolnej rekordu, gdzie 0 – 9 zachowują swoje wartości, a litery [a-f] przyjmują kolejno [10-15], dokładnie jak w przeliczaniu pojedynczych wyrazów systemu liczbowego o podstawie 16 (HEX) na dziesiętny.
  2. Skoro jest to suma, to wartość minimalna jest dla samych zer, zatem MIN = 0.
  3. Wartość maksymalną można stworzyć podając same maksymalne wartości F, zatem MAX = 480.
  4. 480 mieści się na 9 bitach (min. 2 bajty, zakres 0-65535 bez znaku, tracimy 65055 wartości), dzieląc liczbę przez 2 tracimy unikalność odcisku dwukrotnie, ale zmieścimy się na ośmiu bitach, czyli jednym bajcie – możemy użyć typu TINYINT (zakres 0-255 bez znaku, nasza to 0-240), zatem tracimy tylko 15 niewykorzystanych wartości.

Przeprowadzamy testy naszego rozwiązania.

Stwórzmy przykładową tabelę danych test_md5_index, która będzie przechowywała wartości tekstowe w polach data_content, data_content2, data_content3. Tabela może zawierać pole dodatkowe, ale te trzy będziemy wykorzystywać w naszym wyszukiwaniu. Ważnym jest to, że warunkiem jest koniunkcja (AND), dlatego możemy stworzyć sumę (analogicznie do sumy logicznej) md5 jako odcisk palca tych pól, który zapiszemy w data_sum varchar(32). Dodatkowo stworzymy odcisk palca odcisku palca – jednobajtowe pole data_sum_index TINYINT.

Od razu zakładamy klucz podstawowy na data_id oraz klucz dla zapytania, który będzie go wykorzystywał, czyli szukanie wspólnie po data_sum_index oraz data_sum.

CREATE TABLE test_md5_index (
  data_id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  data_sum_index tinyint(1) UNSIGNED NOT NULL,
  data_sum varchar(32) NOT NULL,
  data_contents text NOT NULL,
  data_contents2 text NOT NULL,
  data_contents3 text NOT NULL,
  PRIMARY KEY (data_id),
  KEY data_index (data_sum_index, data_sum)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

Pora stworzyć funkcję, która przeliczy nam nowy, krótszy odcisk palca na podstawie poprzedniego:

CREATE FUNCTION TestIndexChecksum(sSum VARCHAR(32)) RETURNS TINYINT
BEGIN
 
  DECLARE sSumPart VARCHAR(1);
  DECLARE iSumPart TINYINT;
  DECLARE iSum SMALLINT DEFAULT 0;
  DECLARE i INT;
 
  IF (SELECT sSum NOT REGEXP '^([a-z0-9]){32}$') THEN RETURN 0; END IF;
 
  SET i = 1;
 
  WHILE i &lt;= LENGTH(sSum) DO
    SET sSumPart = SUBSTR(sSum, i, 1);
    SET iSumPart = (SELECT (CASE WHEN sSumPart = 'a' THEN 10 WHEN sSumPart = 'b' THEN 11 WHEN sSumPart = 'c' THEN 12 WHEN sSumPart = 'd' THEN 13 WHEN sSumPart = 'e' THEN 14 WHEN sSumPart = 'f' THEN 15 ELSE 0 END));
 
    IF iSumPart = 0 THEN
      SET iSumPart = sSumPart;
    END IF;
 
    SET iSum = iSum + iSumPart;
    SET i = i + 1;
  END WHILE;
 
  RETURN iSum / 2;
END;

Aby przeprowadzać testy, stwórzmy sobie procedurę, która wstawi nam N losowo, jakkolwiek wypełnionych rekordów do bazy danych:

CREATE PROCEDURE TestIndexesPrepareTest(IN i INT)
BEGIN
  TRUNCATE TABLE test_md5_index;
 
  WHILE i &gt; 0 DO
 
    INSERT INTO test_md5_index SET
      data_contents  = (SELECT REPLACE(CONCAT(RAND() * 32), ".", "")),
      data_contents2 = (SELECT REPLACE(CONCAT(RAND() * 32), ".", "")),
      data_contents3 = (SELECT REPLACE(CONCAT(RAND() * 32), ".", "")),
      data_sum = CONCAT(data_contents, data_contents2, data_contents3),
      data_sum_index = TestIndexChecksum(data_sum);
 
    SET i = i - 1;
  END WHILE;
END;

Po wykonaniu CALL TestIndexesPrepareTest(100000) mamy przygotowane małe środowisko testowe.

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.