sobota, 9 sierpnia 2008

Firebird i cytaty w PHP


Każdy programista PHP (i nie tylko!) chyba wie, że cytaty wymagają specjalnej kontroli, jej brak może być źródłem ataków typu SQL Injection.
Pamiętałem o tym również i ja i zabezpieczyłem się oczywiście włączając opcję automatycznego dodawania backslashy przy znakach specjalnych - magic_quotes_gpc. Np. wysyłając tekst w formularzu:
\t\e\s\t

Po stronie serwera otrzymam:
\\t\\e\\s\\t

Czyli wszystko fajnie :)

Troszkę się zdziwiłem gdy na mantisie dwa dni temu zobaczyłem zgłoszony błąd od testera, że nie sprawiają mu problemów ataki typu SQL Injection. Do głowy przyszło mi tylko jedna myśl - "WTF!?".
Obadałem kod sprawdzając czy napewno dodawane są backslashe - all ok.
Później uznałem, że trzeba to samemu sprawdzić. Wpisuje w formularzy blabla', wysyłam formularz i boom;] sypneło się:) No tylko dlaczego skoro po stronie serwera otrzymałem: blabla\' ?? Google.pl....
Trochę poszperałem aż trafiłem na artykuł o obsłudze cytatów w Firebird. I tam ciekawostka ! Okazało się, że w Firebirdzie napis: blabla\' oznacza po prostu blabla\' ! :) Żeby zabezpieczyć taki ciąg nie należy dodawać backslasha tylko wpisać blabla'' ! Czyli podwajamy znak specjalny (zachciało im się innowacji:|). Co więcej php ma funkcje do automatycznego wykonywania tego (pod tym względem <3 PHP - ma ogrom przydatnych funkcji) ! :D Wystarczy ustawić zmienną magic_quotes_sybase na On w php.ini i jest ok:)
Jeśli nie ma się dostępu do php.ini trzeba to wykonać przez .htaccess ponieważ ustawienie tego przez ini_set z tego co zauważyłem nie jest możliwe.

Treść .htaccess:
php_value magic_quotes_sybase On


No i problem rozwiązany :)

piątek, 8 sierpnia 2008

Hype - Lies and Speeches

Sponsorem dzisiejszego wieczoru jest zespoł Hype z albumem Lies and Speeches :)
Polecam!
  


Piosenka Anybody here najbardziej wpadła mi w ucho:)

I ogólnie polecam serwis Jamendo.com ! Dużo dobrej muzyki za darmo !!

niedziela, 3 sierpnia 2008

Filip Kubiatowicz mistrzem świata !!

Chciałbym serdecznie pogratulować mojemu koledze Filipowi (aka Nosferatu) za zdobycie tytułu Mistrza Świata w katerogi semi-pro w futbolu stołowym znanym także jako "piłkarzyki" lub "trambambula" (o_O).


Życzę Ci samych takich sukcesów Nosfe !!
Więcej informacji na Wiadomości24.pl

ps. jeszcze trochę i może uda Ci się ze mną wygrać ^^
pps. ale dziś tu nowych postów :P

PHP 5.3 alpha1 dostępna


Czekałem czekałem i się... nie doczekałem :P Miała się pojawić do końca czerwca, pojawiła się pod koniec lipca i to jeszcze alfa :P No ale jest - kamień milowy w rozmowu PHP nareszcie dostępny do testów;]
Pisałem już wcześniej czego możemy się spodziewać w wersji 5.3. Do tej listy doszło jeszcze kilka rzeczy ! :)
- LAMBDA (!!)
- domknięcia
- nowy typ pliku - 'phar' czyli php archive, który może przechowywać w sobie całą aplikację gotową do wdrożenia
- opcjonalny odśmiecacz pamięci
- NOWDOC (tego za bardzo jeszcze nie czaje :P Jak obadam to napisze więcej o co chodzi:P)

warto było czekać :) Co prawda nadal nie mam zainstalowanej tej wersji gdyż wersja pod windowsa jeszcze się nie pojawiła (ma być w ciągu kilku dni), ale jak się pojawi i zapoznam bardziej szczegółowo to coś tu skrobnę ;)

Plik do pobrania czeka : tutaj

RMS w J2ME

Wracamy do tematu J2ME :) Inżynierka będzie m.in. dotyczyła tego wynalazku więc trzeba zgłębiać tajemną wiedzę zanim będzie za późno :P
Dziś trochę o zapisie danych w MIDletach. Telefony komórkowe są urządzeniami typu "co kraj to obyczaj" czyli (w tym przypadku) sposób zapisu danych może być różny na różnych modelach u różnych producentów. Jednak dla J2ME został opracowany uniwersalny sposób dla wszystkich urządzeń o nazwie RMS - Record Management System.

Dane zapisuje się w rekordach, które zawierają się w zbiorach. Rekord jest przez programistę widziany jako tablica bajtów, więc trzeba się samemu troszczyć o to co zawierany dany rekord. Każdy zbiór posiada swojego właściciela (MIDlet) i może być on współdzielony przez wiele MIDletów. Zbiór posiada unikalny identyfikator - nazwe, natomiast rekord w zbiorze posiada unikalny numer.
Nie ma ograniczeń co do liczby zbiorów jakie może utworzyć MIDlet, jedynym ograniczeniem jest dostępna pamięć.

Tworzenie zbioru
Nad zbiorami rekordów w J2ME czuwa klasa RecordStore.
Aby utworzyć jakiś zbiór należy wywołać jej statyczną metodę: openRecordStore(String recordStoreName, boolean createIfNecessary) której parametry kolejną oznaczają nazwę zbioru oraz flagę czy zbiór ma zostac utworzony jeśli nie istnieje.
W MIDP 2.0 dodano dwie nowe metody openRecordStore o innych parametrach i bardziej specjalistycznych zadaniach. M.in. z ustawieniem uprawnień i przypisywaniem danego zbioru do konkretnego MIDletu.

Metoda zwraca nam utworzony (lub otworzony) zbiór na którym możemy wykonywać operacje zapisu i odczytu. Zanim do tego przejdziemy dodam jeszcze, że możemy się spodziewać wystąpienia następujących wyjątków:

RecordStoreNotFoundException - zbiór nie istnieje (w przypadku gdy nie ma być automatycznie utworzony)
RecordStoreFullException - brak dostępnej pamięci
IllegalArgumentException - błędna nazwa zbioru
RecordStoreException - inny błąd

na koniec jeszcze przykład tworzenia nowego zbioru:
RecordStore store = RecordStore.openRecordStore("test", true);

// zrzuci wyjątek jeśli zbiór nie istnieje
RecordStore secondStore = RecordStore.openRecordStore("test2", false);

Zapis w RMS
Na pierwszy ogień weźmiemy zapis danych. Mamy do dyspozycji dwie metody klasy RecordStore:
- int addRecord(byte[] data, int offset, int numBytes)
dodaje nowy rekord do zbioru i zwraca nam ID rekordu. Jako parametry musimy podać kolejne: dane do zapisu, od którego bajtu ma być zapisywane oraz ile bajtów ma zostać zapisanych.
- void setRecord(int recordId, byte[] newData, int offset, int numBytes)
ta metoda służy do zastąpienia rekordu nowym. Dodatkowym parametrem jaki trzeb podać jest ID rekordu który ma być zastąpiony, reszta jak powyżej.

Ponieważ zapisujemy tablice bajtów najlepiej posłużyć się strumieniami. Idealnie nadaje się do tego strumień ByteArrayOutputStream.
Może teraz jakiś przykład:
RecordStore bd = RecordStore.openRecordStore("test", true);

ByteArrayOutputStream arrayStream = new ByteArrayOutputStream();
// do zapisu danych różnych typów
DataOutputStream out = new DataOutputStream(arrayStream);
// wpisujemy do strumienia tekst
out.writeUTF("testujemy zapis!");
// pobieramy tablice bajtów
byte[] data = arrayStream.toByteArray();
// zapisujemy do rekordu
bd.addRecord(data, 0, data.length);

// zamykamy strumień i zbiór
out.close();
bd.closeRecordStore();

Ważne jest aby zamykać strumień i zbiór, urządzenia mobilne nie posiadają dużo pamięci więc należy je oszczędzać.
Dodam jeszcze, że podczas każdej operacji addRecord, setRecord i deleteRecord na zbiorze inkrementowana jest jego wersja. Wersję zbioru można otrzymać poprzez wywołanie int getVersion().

Odczyt w RMS
Jeśli nie znamy zbiorów MIDletu możemy pobrać ich nazwy za pomocą metody statycznej RecordStore.listRecordStores(). Zwraca ona tablicę Stringów lub null w przypadku gdy nie ma żadnego dostępnego zbioru.
Gdy dobierzemy się do konkretnego zbioru i go otworzymy możemy zacząć przeglądać rekordy w nim zawarte.
W tym celu użyjemy klasy RecordEnumeration. Pobranie obiektu tego typu następuję przez wywołanie metody
enumerateRecords(RecordFilter filter, RecordComparator comparator, boolean keepUpdated). Parametry tej metody oznaczają:
- filter - obiekt służący do filtrowania rekordów (o tym innym razem)
- comparator - obiekt służący to porównywania rekordów i ułożenia ich w odpowniednim porządku (o tym innym razem)
- keepUpdate - jeśli prawda to będą brane pod uwagę zmiany w rekordach podczas ich przeglądania. Ta opcja jest dość ważna i może wpłynąć na wydajność aplikacji.

Do samego przeglądania przydadzą nam się jej dwie metody:
- bool hasNextElement() sprawdza czy istnieją jeszcze jakieś elementy
oraz
- byte[] nextRecord() - zwraca kolejny element
Przykład:
RecordStore bd = RecordStore.openRecordStore("test", false);

RecordEnumeration recEnum = bd.enumerateRecords(null, null, false);
while (recEnum.hasNextElement()) {
byte[] data = recEnum.nextRecord();
// jakieś działania
}

bd.closeRecordStore();

Można oczywiście użyć ByteArrayInputStream wraz z DataInputStream do przeglądania konkretnego rekordu:
DataInputStream in = new DataInputStream(
new ByteArrayInputStream(recEnum.nextRecord()));
String text = in.readUTF();

Usuwanie rekordów/zbiorów
Na koniec usuwanie. Mamy do dyspozycji dwie proste metody:
- void deleteRecord(int recordID) - usuwa rekord o podanym ID ze zbioru
- static void deleteRecordStore(String recordStoreName) - usuwa cały zbiór rekordów o podanej nazwie. Uwaga - zbiór musi być zamknięty inaczej otrzymamy wyjątek RecordStoreException.

No to to by było na tyle z podstaw korzystania z RMS. Mam nadzieje, że przedstawiłem to dość klarownie. Nie rozglądałem się ale mam nadzieje, że istnieje jakaś gotowa biblioteka, która zapewniała by kontrole typów które są przechowywane w tych rekordach, bo teraz to trochę "niskopoziomowo" się to obsługuje ;P Zachęcam także to przejrzenia API RMS. Znajduje się tam jeszcze sporo metod o których nie wspomniałem a zapewniają bardziej zaawansowane możliwości.