May 12, 2014
Koltozes
Mostanaban sok egyeb teendom miatt, teljesen elhanyagoltam a blogot. Egy ujat inditok, ezuttal angol nyelven. A tema leginkabb Php (Symfony2, Laravel) lesz ott is. Hamarosan erkezik az elso poszt: code-chronicle
Oct 4, 2012
Symfony2 - saját jelszó kódoló (encoder) készítése
A napokban kezdtem el fejleszteni egy hobbi projektet Symfony2-ben és az ezzel kapcsolatos tapasztalataimat osztom majd meg a mostani - és lesznek majd később is Symfony2-vel kapcsolatos posztok - bejegyzésben.
Tehát Symfony2-ben van egy nagyon ügyes csomagunk (bundle - Symfony2-ben minden csomagokba van rendezve, fel lehet fogni egyfajta plugin-ként, amiben a forrástól kezdve a hozzá tartozó erőforrások [css, js...] is megtalálhatók) amit Security néven érhetünk el. Ez a könyvtár biztosítja számunkra (természetesen nem muszáj ezt használni) az authentikációt, authorizációt és ezáltal képes a teljes bejelentkezést lebonyolítani, némi konfiguráció árán.
A komponens konfigurációjában lehetőség van az encoder tulajdonságainak beállítására, amellyel megadhatjuk milyen fajta egyirányú kódolást (hash) szeretnénk alkalmazni (plusz még, hogy hány iteráción keresztül álljon elő ez a hash és hogy base64 formában szeretnénk-e tárolni) jelszavaink tárolásakor.
Alapértelmezett esetben elég szép számmal kapunk hash algoritmusokat, amelyeket használhatunk,. Viszont mi szeretnénk írni egy saját encoder-t, nem elégszünk meg az általánosan használt jelszó kódolási eljárásokkal (pl. md5, sha1).
A komponens konfigurációjában lehetőség van az encoder tulajdonságainak beállítására, amellyel megadhatjuk milyen fajta egyirányú kódolást (hash) szeretnénk alkalmazni (plusz még, hogy hány iteráción keresztül álljon elő ez a hash és hogy base64 formában szeretnénk-e tárolni) jelszavaink tárolásakor.
Alapértelmezett esetben elég szép számmal kapunk hash algoritmusokat, amelyeket használhatunk,. Viszont mi szeretnénk írni egy saját encoder-t, nem elégszünk meg az általánosan használt jelszó kódolási eljárásokkal (pl. md5, sha1).
Hogy miért nem? Az említett algoritmusok túlságosan gyorsak. Amennyiben valaki megszerez egy adatbázist és rendelkezik megfelelő szivárvány táblával, mai GPU-kal gyorsan sikerrel járhat a jelszavak törésében. Persze még mindig jobb az md5 vagy az sha1 használata, mint a plaintext.
Mivel javíthatunk felhasználóink jelszavainak kódolásán?
Mivel javíthatunk felhasználóink jelszavainak kódolásán?
- Megköveteljük, hogy a felhasználó milyen formájú, hosszúságú jelszavat adhat meg (pl. szükséges kis- és nagybetű, szám illetve, hogy x hosszúságú legyen. Lehet extrémebben is, mondjuk hogy ismert, egyszerű szavakat kiszűrünk, azokat nem tartalmazhatja a bevitt adat.)
- Sózással. Az egyszerű jelszót kicsit megfűszerezzük egy hosszabb, véletlenszerű karakterekből álló lánccal.
- Kiegészítő eljárás bevonása a kódolásba: például a key stretching, azaz a kulcs nyújtása.
- Valamilyen erősebb kódolású, nem feltétlenül gyors (egyirányú kódolási) algoritmust használunk.
Az első ponttal az a probléma, hogy a felhasználó "életét" nehezítjük meg. A sózás viszont csak abban az esetben hatékony, ha minden látogatóhoz külön, egyedi sót alkalmazunk. Amennyiben így teszünk, nem lehetetlenítjük el, de legalább megnehezítjük a támadó dolgát. Ebben az esetben a krekkernek minden egyes felhasználóhoz külön szivárvány táblát kell generálnia (tegyük fel, hogy hozzáférést szerzett az adatbázishoz, azzal együtt ugyebár a sóhoz is).
Kiegészítő eljárásként a kulcs ún. nyújtását említettem meg, amely technika arra hivatott, hogy megerősítse az egyébként gyenge kódolást, hogy hatékonyabb legyen egy esetleges brute force ellen (egyébként a Symfony2 is ezt a technikát használja). Az eljárás után egy megerősített kulcsot kapunk. Az funkció lényege tehát, hogy több ideig tart ellenőrizni egy bizonyos megfelelést a hash-re. Legegyszerűbben az algoritmust leíró pszeudo kód alapján érthető meg:
key = ""
for 1 to 65536 do
key = hash(key + password + salt)
Az utolsó pont szintén a kulcs nyújtását használja fel alapgondolatként, itt konkrétan a bcrypt, nevű függvényre gondoltam. A kódolással kapcsolatos problémáink gyökere az algoritmus sebességén alapul. Amennyiben nekünk rövid ideig fog tartani az adott hash előállítása, akkor a jelszavainkat törő személynek is, ezért próbáljunk inkább lassabb funkciót használni, hogy még tovább tartson az esetleges szivárvány táblák előállítása. Ez irányú erőfeszítésünkre (lassítás) nyújt segítséget az előbb említett bcrypt egy cost (vagy ha úgy tetszik work factor) paraméterrel. Ő egy két számjegyű érték, amely a [04-31] intervallumban kell, hogy szerepeljen. A kiválasztott szám az iterációs lépések kettes alapú logaritmusa. Adjunk meg cost paraméternek a 12-t, ekkor az iterációk száma (key stretching - előző pszeudo kód) 212 lesz, azaz 4096 (log24096=12). Egyik kedvenc szkript nyelvünkön (a másik ugyebár a Python :]) a crypt funkcióval használható.
Az elméleti kiruccanás után térjünk át a Symfony2 specifikus részre. Nos, alap esetben a következőképpen fest a konfigurációnk (app/config/security.yml), ha nem kívánjuk kiegészíteni a kódolási mechanizmusunkat például a bcrypt-el:
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: sha1
iterations: 128
encode_as_base64: false
A konfig magáért beszél, megadjuk a kívánt algoritmust, az iterációk számát és hogy base64 kódolásban szeretnénk-e letárolni az eredményt. Ahhoz, hogy saját encoder-t készítsünk, implementálnunk kell a Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface felületet:
A fenti kódhoz nem is fűznék kommentárt, elég kicsi ahhoz, hogy érthető legyen. Ha készen vagyunk az implementálással, akkor a következő lépésként beköthetjük a saját kódolónkat:
namespace B3ha\UserBundle\Service;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
class BCryptEncoder implements PasswordEncoderInterface
{
/**
* @var integer Must be in range 4-31
*/
protected $cost;
/**
*
* @param integer $cost
*/
public function __construct($cost)
{
$cost = (int)$cost;
if ($cost < 4 || 31 < $cost) {
throw new \Symfony\Component\Config\Definition\Exception\Exception(
'Cost parameter must be in range 4-31');
}
$this->cost = sprintf('%02d', $cost);
}
public function encodePassword($raw, $salt)
{
return crypt($raw, "\$2a\${$this->cost}\${$salt}");
}
public function isPasswordValid($encoded, $raw, $salt)
{
return $encoded === $this->encodePassword($raw, $salt);
}
}
A fenti kódhoz nem is fűznék kommentárt, elég kicsi ahhoz, hogy érthető legyen. Ha készen vagyunk az implementálással, akkor a következő lépésként beköthetjük a saját kódolónkat:
encoders:
B3ha\UserBundle\Entity\User:
id: b3ha.user.bcrypt_encoder
Érdemes service-ként (ActualBundle/Resources/config/services.yml, majd a fő konfig fájlban ezt importálni) megvalósítani (akár a ServiceContainer-ről is lehet későbbiekben poszt) az encoder-t, ezt a lenti kód mutatja:
parameters:
# Cost parameter must be in range 04-31
b3ha.user.bcrypt_encoder.cost: 12
services:
b3ha.user.bcrypt_encoder:
class: B3ha\UserBundle\Service\BCryptEncoder
arguments: [%b3ha.user.bcrypt_encoder.cost%]
Nem tértem ki minden részletre, mert ez a poszt inkább az elméleti részről és a Symfony2-ben már kicsit jártasabb kódereknek szólt. Részletes leírásokat természetesen a symfony.com oldalon találhattok, ha kérdésetek, kiegészítésetek vagy javításotok lenne írjatok bátran.
Feb 21, 2012
Imap "érdekességek" :/
Bő két hónapja esett meg az a szerencsétlenség, hogy volt alkalmam összefutni a php imap libbel. Ami főleg azért volt számomra szerencsétlen, mert előjött pár olyan idegőrlő "érdekesség", amely nem tett túl jót a neurális hálózatomnak.
A doksi írást senki sem szereti, ez tény. Viszont aki nem, vagy csak részben ír dokumentációt másokkal szúr ki, ez esetben velem (és gondolom még sok más fejlesztővel is).
Az imap-al kapcsolatos alapvető felhasználásra nem térek ki, ezek a pontok azoknak lehetnek hasznosak, akik már valamennyire működő kódot hoztak össze, vagy ezt elolvasva a jövőben talán visszaemlékeznek az egyes részekre.
Lássunk tehát néhány hasznos információt a php-s imap-al kapcsolatban, amikkel volt "szerencsém" találkozni:
- Postafiók megnyitás (ez jól le van dokumentálva, de az egyik vázlatpont miatt nem árt, ha látjuk)
imap_open(string $mailbox , string $username , string $password [, int $options = NIL...);
szerver specifikáció: {host:port/flag}
(hasznos option: \OP_HALOPEN -> csak kapcsolatot nyit, de mappát nem) - Függvények hibát dobnak a @ operátor ellenére is
egyszer bejelentett bugmásszor bejelentett bug
- A lib szereti cache-elni a dolgokat, ezért: imap_gc(...); !
- imap_append options paraméternek az imap_clearflag_full függvénynél az options paraméter értékei is megadhatóak (The flags which you can unset are "\\Seen", "\\Answered", "\\Flagged", "\\Deleted", and "\\Draft" (as defined by » RFC2060)). Például egy levelet olvasottként akarunk az egyik mappába helyezni.
- Karakterkódolás: Nos, itt nem sikerült tökéletes megoldást előállítanom, így nincs is mit publikálnom sajnos (egy kisebb szkriptről volt szó, amely egyszer volt használatos és nem volt elvárt pl a magyar ékezetes betűk használata). A lényeg, hogy az ékezetes betűkkel rengeteget lehet szívni. Nem folytam nagyon bele, de valszeg rosszak a saját kódolási függvényei: imap_utf7_encode imap_utf7_decode
- A végére még egy gyöngyszem, az imap_mail_move. Itt az a csodálatos, hogy a szerver spec (első pontban tárgyalt) nem olyan formában kell, hogy szerepeljen, mint ahogy (szinte - pl a copynál is a move-hoz hasonló, viszont append-nél már nem) minden más függvénynél (azaz {host:port/flag}/Folder), hanem neki csakis a Folder rész szükséges.
- Ráadásként pedig az imap_getmailboxes visszatérési értéke, amely hiányosan van dokumentálva, de szerencsére az egyik kommentelő előkotorta a C forrásból a maradékot :)
Kb ezek voltak amikkel találkoztam és emlékeztem is rájuk. Lehetséges persze, hogy más függvényeknél is előjehetnek hasonlók. A cél, a figyelem felhívása volt a labilis pontokra, azok számára akiknek esetleg ezzel a könyvtárral kell dolgozniuk a jövőben.
Oct 14, 2011
SOAP Messages with Attachments
A héten futottam bele egy feladatba [problémába :)], amelynél webszolgáltatáson keresztül, nem csupán xml adatstruktúrát, de csatolt állományokat is fel kellett dolgoznom.
Egy report szerverről (java alapú) volt szó, amelynek ha elküldünk egy megfelelően felépített xml-t - mint paramétert - SOAP-on keresztül, akkor az annak megfelelő dokumentumot legenerálja, majd úgyszintén webszolgáltatáson keresztül szolgáltatja vissza. Ki lehet találni, hogy az elküldésnél még minden rendben volt, viszont amikor a válasz üzenet visszaérkezett, akkor jelentkezett a - igazából várt - probléma.
Tegyük fel, hogy pdf kiterjesztésben kérem el a dokumentumot. Ilyenkor a válasz üzenet multipart/related tartalom típussal (Content-Type) fog érkezni. Röviden ez azt jelenti (részletesebben itt), hogy bár egy üzenet érkezik válaszként, az több különálló részre lesz osztva. A Content-Type fejlécben megadott boundary értékével lesznek az egyes részek elválasztva, amelyek külön-külön fejlécekkel és egyedi azonosítóval (Content-Id) rendelkeznek. A boundary információ mellett - related esetben - egy start attribútumot is találunk, értéke egy Content-Id-ra való hivatkozás. Azaz a start jelöli ki - esetünkben - a SOAP envelope-ot. Az, hogy az envelope-on belül milyen hivatkozások vannak a csatolt állományokra, minket most nem érdekel, csak a különböző részeket szeretnénk feldolgozni. Amikor éppen nem az envelope-ot dolgozzuk fel, akkor figyelni kell a Content-Transfer-Encoding fejlécet, mert ez lehet bináris, de akár base64 kódolású is. A leírtak nagyrészt (A kód közel véglegesnek tekinthető, de még vár rá néhány teszteset) lefedik a SOAP Messages with Attachments fogalmát.
Nézzük egy (kölcsönzött) példát a kapott válaszüzenetre:
MIME-Version: 1.0
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml;
start="<http://claiming-it.com/claim061400a.xml>"
Content-Description: This is the optional message description.
--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <http://claiming-it.com/claim061400a.xml>
Content-Location: http://claiming-it.com/claim061400a.xml
<?xml version='1.0' ?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
...
<theSignedForm href="http://claiming-it.com/claim061400a.tiff"/>
...
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
--MIME_boundary
Content-Type: image/tiff
Content-Transfer-Encoding: binary
Content-ID: <http://claiming-it.com/claim061400a.tiff>
Content-Location: http://claiming-it.com/claim061400a.tiff
...binary TIFF image...
--MIME_boundary--
Egy ehhez hasonló üzenetet kellene tehát feldolgoznunk, hogy utána az egyes részek kényelmesen lekérhetőek legyenek. A gond viszont az, hogy a natív PHP SoapClient osztály az ilyen típusú üzeneteket nem támogatja, így másfelé kell nézelődnünk.
A problémára két megoldást találtam. Kibővítem a meglévő SoapClient osztályt, vagy egy kész könyvtárat használok (sem NuSOAP-ban, sem ZendFwSoap-ban nem találtam a feature-t [Ha valaki tud wso2-höz hasonló könyvtárat, kommentben kérem ossza meg]). A kész könyvtár a WSO2 Web Service Framework for PHP lenne, amely nagyon sok funkciót tud, köztük az SwA helyett ajánlott MTOM-ot (ez a kettő lényegében megegyezik, csupán az MTOM előrehaladottabb a csatolások belinkelésével).
A kibővítés mellett döntöttem, egyrészt mert a jövőre tekintve is elegendőnek tűnik a majd lentebb látható megoldás, másrészt a kódegység tartása (natív PHP SOAP osztályokat használok az érintett projektben) végett az összes SOAP-al kapcsolatos kódrészt át kellett volna írni, a könytárnak megfelelőre.
Mostmár rátérhetünk a gyakorlati részre, a kódra. Itt nem szeretnék hosszas magyarázatokba bocsátkozni, a lényeg annyi, hogy a SoapClient osztály __doRequest metódusát fogjuk felülírni. Ez az a metódus amely elküldi a kérést, majd visszatér a válasszal. Nekünk akkor kell beavatkoznunk, ha több részes üzenetet fedezünk fel a válaszban, egyébként az eddigi működést támogatjuk. Lekéréskor az összes részt, vagy csupán egyet is elkérhetünk. Egy résznek van fejléc része, amely kulcs-érték párokat tartalmaz és van tartalma, ezenkívül meg tudja mondani magáról, hogy ő maga-e az envelope.
Oct 11, 2011
Zend action controller, függvénybeli paraméterekkel
Alap esetben az url-ben szereplő paraméterek lekérdezésére a következő lehetőségünk van:
$this->_request->getQuery('query_string_parameter_name'); // zf request object
A cél eléréséhez a Zend_Controller_Action osztály dispatch metódusát kell felülírnunk. Azért van erre a függvényre szükségünk, mert ő lesz aki meghívja a megfelelő controller adott action metódusát, amelyet paraméterben megkap (egyszerű string-ként).
A kód megtekintése előtt csupán annyit emelnék még ki, hogy két lehetőségünk van az url-ben paramétereket átadni az adott akciónak:
- module/controller/action?p1name=p1value&p2name=p2value
- module/controller/action/p1name/p1value/p2name/p2value
(2. esetben a module, controller és az action kulcsok foglaltak)
Ui.: A fenti megoldás csupán teszt jellegű, éles környezetben nincs használva. Ezen kívül még annyi, hogy validációnál hátrányban lehetünk ilyen jellegű felhasználás esetén (változókban vannak a bemeneti értékek, a könnyebben kezelhető tömb helyett).
Sep 3, 2011
online Gomoku
Pár hete készült el a gomoku nevű (magyarul ötödölő vagy amőba, kinek hogy tetszik) játékom. Ezzel kapcsolatban íródik a mostani poszt. A technikai alapokról osztok meg néhány gondolatot.
Felületről megközelítve CSS3 és SVG(Raphael) technológiákról beszélhetünk, míg szerver oldalról természetesen :) egy PHP szerver biztosítja a kliensek közti kommunikációt (WebSocket). A PHP-ban íródott alkalmazásszerver jelenleg 100 játékosra van kofigurálva, a játékosok belépéskor azonosítókat kapnak. Az azonosító és megadott kóddal "fejlécezett" üzenetekkel kommunikálnak a szerverrel oda-vissza. Amikor egy játékos a felületen lép egyet, akkor a szervernek elküldi a lépést azonosító üzenet kódot és a lépés x, y koordinátáját. Ezt az üzenetet a szerver megkapja, majd elküldi a megfelelő játékosnak, aki az üzenetet küldő fél ellenfele.
A design nem saját, kölcsönöztem, míg a szerver alacsonyabb szint kódjáért a phpwebsocket google code-on hosztolt kód a felelős. A teszt verziót itt érhetitek el. Leginkább Chrome-ban próbálkozzatok vele, Fx4-ben a websocket le van tiltva (Fx5-6-ot ezidáig még nem próbáltam ki, így arról nem tudok nyilatkozni). (Amennyiben nincs a szerveren játékos, de ki szeretnétek próbálni, egyszerűen nyissatok még egy tabot neki.)
| Belépéskor |
| Játék vége, győztesként |
Aug 19, 2011
NetBeans vs CodeCoverage
Jelen posztban a NetBeans és a PHPUnit kapcsolatáról lesz szó. Régóta ki szerettem volna próbálni, hogy mit is tud az egyik kedvenc IDE-m kezdeni az egységtesztelésből már ismert Code Coverage-el. Pár hete le is töltöttem a 7.0-s változatot, de mire odáig jutottam hogy ténylegesen rászánjam azt a 2x10 percet a dologra, már ki is jött a 7.0.1-es (Aug1.), így már azon teszteltem (6.9-es verziótól már tartalmazza ezt a feature-t).
Kezdetben van nekünk egy "User" osztályunk két metódussal. A fontos most a "setName()", amely egy paramétert vár ("name), ami ha nem "string" típusú vagy ha az, de a hossza kisebb, mint három, akkor kivételt dob a függvény. Előbbi esetben a kivétel "InvalidArgumentException", míg utóbbiban "LengthException" típusú. Amennyiben nincs kivétel, a "name" attribútum értékül kapja a paraméterként adottat.
Következő lépés, hogy létrehozzunk egy tesztet az említett osztály "setName" metódusára. Az alábbi módon könnyíthetjük meg a munkánkat:
Elkészült a tesztelő osztályunk mindenféle földi jóval. A metódusok helyesen "incomple" jelzést kaptak.
Visszamegyünk a "User" osztályunkra, ahol meg szeretnénk nézni, hogy az apró kódunk hány százalékát fedtük le eddig egységteszttel. Kemény 7.69%-on vagyunk, amit teljes egészében a konstruktor tesz ki. Ahogy a képen is láthatjuk a konstruktor zöld színű, míg az eddig le nem fedett részek pirosak.
Nekünk ez a lefedettség kevés (A 7.69% valóban kevés lehet, de halkan megemlíteném, hogy a 100%-os lefedettséget senki se szeresse elérni. Külön cikket megér, van is róla pár angol nyelvű, érdemes böngészni), így írunk egy tesztet a "setName" metódusra. Ebben a tesztben egy nem "string" típusú paramétert adunk át a függvénynek, amire válaszul InvalidArgumentException-t várunk (expected annotáció a kommentben).
Miután kész a függvényünk, visszatérve a "User" osztályunkhoz láthatjuk, hogy az említett kivételt le is fedtük a tesztünkel. 30.77% ami a mai napra nekünk elég is, hiszen nem szeretnénk túlzásba vinni a kódolást a 28° melegben ezen a szép napon.
Kezdetben van nekünk egy "User" osztályunk két metódussal. A fontos most a "setName()", amely egy paramétert vár ("name), ami ha nem "string" típusú vagy ha az, de a hossza kisebb, mint három, akkor kivételt dob a függvény. Előbbi esetben a kivétel "InvalidArgumentException", míg utóbbiban "LengthException" típusú. Amennyiben nincs kivétel, a "name" attribútum értékül kapja a paraméterként adottat.
![]() |
| User osztály |
Következő lépés, hogy létrehozzunk egy tesztet az említett osztály "setName" metódusára. Az alábbi módon könnyíthetjük meg a munkánkat:
![]() |
| Unit test generálás |
Elkészült a tesztelő osztályunk mindenféle földi jóval. A metódusok helyesen "incomple" jelzést kaptak.
![]() |
| UserTest osztály |
Visszamegyünk a "User" osztályunkra, ahol meg szeretnénk nézni, hogy az apró kódunk hány százalékát fedtük le eddig egységteszttel. Kemény 7.69%-on vagyunk, amit teljes egészében a konstruktor tesz ki. Ahogy a képen is láthatjuk a konstruktor zöld színű, míg az eddig le nem fedett részek pirosak.
![]() |
| CodeCoverage 7.69% |
Nekünk ez a lefedettség kevés (A 7.69% valóban kevés lehet, de halkan megemlíteném, hogy a 100%-os lefedettséget senki se szeresse elérni. Külön cikket megér, van is róla pár angol nyelvű, érdemes böngészni), így írunk egy tesztet a "setName" metódusra. Ebben a tesztben egy nem "string" típusú paramétert adunk át a függvénynek, amire válaszul InvalidArgumentException-t várunk (expected annotáció a kommentben).
![]() |
| testSetName |
Miután kész a függvényünk, visszatérve a "User" osztályunkhoz láthatjuk, hogy az említett kivételt le is fedtük a tesztünkel. 30.77% ami a mai napra nekünk elég is, hiszen nem szeretnénk túlzásba vinni a kódolást a 28° melegben ezen a szép napon.
![]() |
| CodeCoverage 30.77% |
Jul 14, 2011
php oauth
Épp most tettem ki github-ra egy a PECL-oauth csomagra épülő könyvtárat, amellyel egyszerűen tudunk PHP alól access token-t szerezni a különböző oauth belépést támogató alkalmazásokba, mint például a twitter vagy a facebook.
Azzal a céllal készítettem a csomagot, hogy egyszerűen hozzá tudjuk adni a már meglévő alkalmazásunkhoz és kevés kódolással megvalósulhasson a beléptetés. Egy másik fontos szempont volt a bővíthetősége, mégpedig hogy egy meglévő sémát felhasználva tudjunk más "app"-okat hozzátenni a könyvtárhoz. Ehhez az alábbi struktúrát használom:
A könyvtár itt érhető el: link. (Szükséges hozzá a már említett pecl oauth csomag)
Jul 6, 2011
FUEL(PHP) keretrendszer
| FUEL framework |
Egy viszonylag új keretrendszert szeretnék röviden ismertetni. Mégpedig a FUEL nevezetűt, melynek a fejlesztése 2010 év vége felé kezdődött. Az 1.0-s verzió még nem végleges, de már RC3-nál járnak a srácok.
Ez egy, a körülötte lévő közösség által is irányított PHP-s keretrendszer. Céljuk egy egyszerű, de rugalmas keret kialakítása, amely több másik rendszertől is ellesi a jobb ötleteket, megvalósításokat (pl. Kohana, CodeIgniter) és ezeket a sajátjaikhoz társítják. A keretrendszer az 5.3-as PHP-t veszi alapul, így annak minden előnyét kihasználja.
Főbb feature lista:
- HMVC requests
- ViewModels
- Packages
- Auth Package
- ORM Package
- Parser Package (Jelenleg még erősen fejlesztés alatt)
(Persze a "core" osztályok közt megtalálhatóak az általános "helper"-ek)
Akinek tetszik a rendszer, az bátran be is kapcsolódhat a fejlesztésbe: GitHub, Fórum. Akit pedig ennél bővebben érdekel, az minden infot megtalál az oldalon.
Parser package:
A parser package-ről írnék még néhány sort, mert ennek a fejlesztéséhez magam is hozzátettem egy kicsit. Ez egy több template kezelő könyvtárat is támogató csomag. Kiterjesztve, kiegészítve a core View osztályt lehetővé teszi, hogy nagyon egyszerűen használhatóak legyenek a különböző sablonozó nyelvek (pl: Twit, Dwoo, Haml). Ehhez a csomaghoz járultam hozzá egy Smarty konfiguráció beépítésével, amely be is került a developer ágba.
Vélemények a keretrendszerről?
Jun 24, 2011
Wsdl készítés NuSoap alapokon
Az előző posztban "Zendéknél" jártunk Wsdl ügyben, míg most a NuSoap-ot vesszük kicsit szemügyre. Ez a library akkor lehet nagyon hasznos számunkra, ha egyszerűen szeretnénk komolyabb struktúrát leírni. Gondolok itt főleg az egyes függvények kimenetére, amely sok esetben tartalmazhat akár hierarchikus adatszerkezetet is. Mindezt egy megfelelő xsd-vel állítjuk majd elő "document" stílussal és "literal" kódolással.
A kódot nem teljesen kezdőknek szánom, hanem olyanoknak akik már legalább egyszer láttak/használtak NuSoap-ot (csak például egyszerűbb funkcionalitással). A következő típusok kerülnek bemutatásra röviden: simpleType, complexType, Enum. Lássuk a kódot!
May 16, 2011
Wsdl készítés Zend alapokon
Update:
A Zend_Soap_Wsdl osztályt az alábbi helyen érhetitek el. A fent kiterjesztett osztály az rpc stílusú Wsdl előallítását teszi lehetővé, ami sok esetben kevés lehet. Gondolok itt a dokumentum stílusra vagy éppen szükségünk lehet xsd előállítására is. Ilyenkor jöhet jól a Zend_Soap_AutoDiscover osztály, amely legenerálja nekünk a megadott paraméterek szerint a megfelelő Wsdl-t (docblock-ok használatára figyeljünk, ugyanis ezek fontos szerepet játszanak a generálásban).
Apr 29, 2011
Digitális aláírás PHP használatával
A digitális aláírásról bizonyára már mindenki hallott és talán már a gyakorlatban is találkozott vele - nem összekeverendő az elektronikus aláírással. A digitális aláíráshoz tartozó elméleti résszel (nyilvános kulcsú titkosítás) most nem foglalkozom - érdemes utánaolvasni -, jelenleg kizárólag a digitális aláírásra és annak gyakorlati megvalósítására koncentrálunk PHP alól.
Mi is az a digitális aláírás?
Tfh hogy van egy doksink amit, mint feladó el szeretnénk küldeni egy címzettnek. Eddig könnyűnek is tűnik a feladat. Viszont mi mindezt úgy szeretnénk megtenni, hogy a címzett biztos lehessen abban, hogy a dokumentum tőlünk származik és nem módosította senki más.
Aláírás és ellenőrzés folyamata - Wiki-től kölcsönözve - a következő:
Aláírás:
A doksiból képzünk egy hash-t (pl sha1_file()), melyet aztán titkosítunk a privát kulcsunkkal. A dokumentumhoz valamilyen formában hozzácsapjuk az aláírást (attached/detached) és a tanusítványt, majd küldhetjük is a címzetteknek.
Ellenőrzés:
Megkaptuk a dokumentumot az aláírással és a tanusítvánnyal együtt. Elolvasás előtt meg szeretnénk bizonyosodni arról, hogy valóban a megfelelő feladó készítette a dokumentumot. Szóval a két körös forduló első részében fogjuk az aláírást és feloldjuk a tanusítványban található publikus kulccsal. Ekkor rendelkezésre áll a küldő által biztosított hash. Ezt össze kell hasonlítanunk a dokumentum hash-ével. Így a második körben mi is - akár csak a küldő - hasheljük a dokumentumot és ha megegyezik az aláírásból feloldott hash-el, nyert ügyünk van.
Azt hogy a küldő milyen hashelő algoritmust használt, az aláírásból deríthetjük ki ill. annak egy meta infojából. Tehát az aláírás a titkosított hash-en kívül tartalmazza a hashelő algoritmust és tartalmazhat egyéb információkat is (pl verziószám).
A tanusítványról pedig tudjuk, hogy a publikus kulcson kívül a szabványának megfelelően még sokféle adatot tartalmaz. Az x.509-es tanusítvány felépítése: link.
Ennyit a digitális aláírás elméleti részéről és most nézzük meg mindezt, hogyan ültethetjük át a gyakorlatba. Először privát kulcsot és tanusítványt kell készítenünk, majd PHP-val aláírást készítő és ellenőrző szkriptet. Mindkét esetben az OpenSSL-t fogjuk használni.
Privát kulcs generálás:
Tanusítvány kérelem:
openssl req -new -nodes -key private.key -out cert_request.csr
Tanusítvány:
openssl x509 -req -days 100 -in cert_request.csr -signkey private.key -out cert.pem
PHP-ban az OpenSSL modult fogjuk használni a digitális aláírás készítéséhez és annak ellenőrzéséhez. Akár magunk is végigjárhatjuk ezt a két folyamatot végighaladva egyesével az alfeladatokon:
Aláírás:
- privát kulcs kiolvasása
- file-ról hash készítés
- hash titkosítása a privát kulccsal
Ellenőrzés:
- tanusítványból a publikus kulcs kiolvasása
- az aláírás titkosított részének feloldása a nyilvános kulccsal
- hash készítése a file-ról
- a kapott hash ellenőrzése a az aláírásban már feloldottal
Az OpenSSL viszont biztosít számunkra egy-egy függvényt az előbbi két feladatra: sign, verify. Mielőtt azonban a kódolásra térnék találjunk ki egy struktúrát az aláírásnak: Vegyük alapul a PGP inline (attached) aláírási módját (amit egyébként az email-ek aláírásánál is használatos). Ez a módszer plain text-nél megfelelő de binárisnál már jobban járunk ha külön file-t (detached signature file) készítünk az aláírásnak.
-----BEGIN SIGNED MESSAGE-----
Hash: -Algoritmus- (pl md5, sha1)
-Tartalom-
-----BEGIN SIGNATURE-----
Version: -Verziószám-
-Titkosított hash-
-----END SIGNATURE-----
Kész a struktúránk, nézzük az aláíró kódot:
Lefuttatva az aláírást az alábbi eredményhez hasonlót kapunk:
-----BEGIN SIGNED MESSAGE-----
Hash: sha1
This is a simple document, digitally signed with PHP[OpenSSL] by b3ha
-----BEGIN SIGNATURE-----
Version: 1.0
G1qngHs3HJmkZLyNz8AkatvCdvx00Svf+bhWCKUwauL6af/bxlh/xrxBiOCG0bFee/Iv6VG
F+L1gWd74f8HCccnQ64lGpfsCCKlyfV4g3iqAJndp4a7KG3ieZd0Qa4UjIkajUpSLXRPocJ
dx4InDTIFhYHEvZu0NzBraQmkePEU=
-----END SIGNATURE-----
Majd az ellenőrzést végző szkript:
Hasznos, érdekes linkek:
http://stackoverflow.com/questions/589834/what-rsa-key-length-should-i-use-for-my-ssl-certificates
http://www.sslshopper.com/csr-decoder.html
http://www.sslshopper.com/certificate-decoder.html
http://www.w3.org/TR/xmldsig-core/
Apr 21, 2011
Rövidített URL feloldása
Tegnap az egyik hobbi projektem fejlesztése során belefutottam abba az esetbe, hogy nem elég a böngészőm címsorába bemásolni a rövidített - vélhetően izgalmas dolgokat tartalmazó - url-t, hanem programkódból is szükségem volt annak feloldására, kiterjesztésére. Nézzük is meg, hogy mire jutottam az általam kreált feladattal, milyen megoldásokat találtam (amennyiben tudtok jobb megoldást, api-t várom őket kommentekben).
A kiszemelt rövidített url, amely feloldásra vár legyen a következő: http://goo.gl/NOgUV Sebesség mérésként, pedig 5 egymás utáni futás átlagértékét veszem figyelembe.
Kezdetnek nézzünk egy nagyon egyszerű megoldást. A get_headers függvény segít nekünk úgy, hogy egy http kérést indítva a megadott url-re visszaadja nekünk a kapott válasz headerjét. A válaszból szimplán kivesszük a Location kulcs-hoz tartozó értéket és már kész is vagyunk (érdemes a függvény $format paraméterét 0-tól különböző értékre állítani, így kulcs-érték párokba szervezi a header tartalmat).
Futási idő: ~0.9s
Egy másik "brute force" módszer, hogy Curl-al lekérjük az oldalt, majd az átviteli információk-ból szűrjük le a számunkra szükséges url-t.
Futási idő: ~0.76s
Futási idő: ~0.76s
Szerencsére rendelkezésre állnak különböző api-k is, melyekkel jóval gyorsabban jutunk eredményre. Ezek közül kettőre pillantunk rá: Google URL Shortener API, LongURL . Működésükről annyit, hogy egy megadott - paraméterezhetőséget biztosító - uri-ra kell ellátogatni, hogy feloldhassuk a rövidített url-t. A megfelelő url kiemenete valamilyen formában (json, xml...) a kiterjesztett url és néhány egyéb adat.
Php alól ezen adatok beolvasására lehetőségünk van például a file_get_contents vagy a fopen függvénnyel. Az említett függvényeknél viszont kreálhatunk egy gyorsabbat is, amennyiben lehetőségünk van a Curl használatára.
Végül, túllépve az adatok beolvasásán jöjjön a két api hívás:
Futási idő: ~0.26s
Futási idő: ~0.21s
A Google feloldója nyilván csak a Google által rövidített url-eket fogja tudni kiterjeszteni, ezzel szemben a LongURL API sok-sok domain-t ismer.
Apr 12, 2011
Apr 9, 2011
i18n class
Felkerült egy apró i18n osztály a githubos repoim közé, amit egy szerver oldali nyelvesítés példájaként készítettem. A különböző nyelvekhez tartozó fordítások beolvasásához egy property adapter osztály segítkezik - a kódból látható, hogy egyszerűen írhatunk más formátumra is beolvasót.
Ide kapcsolódó előző posztok:A könyvtár egyszerűbb kódokhoz a Zend_Translate vagy épp az FLP alternatívájaként szolgálhat.
Update: Valamiért lefelejtettem a legfontosabbat :) a linket
Update: Valamiért lefelejtettem a legfontosabbat :) a linket
Apr 8, 2011
.properties
A főleg Java-ban használt property fájlról, ha valaki még nem hallott, akkor épp itt az ideje. Egészen hasznos a platformfüggetlen property állományokban tárolni például az i18n-hez tartozó kulcs-érték párokat.
Wiki oldalon fent lévő példa struktúra:
# You are reading the ".properties" entry.
! The exclamation mark can also mark text as comments.
website = http://en.wikipedia.org/
language = English
# The backslash below tells the application to continue reading
# the value onto the next line.
message = Welcome to \
Wikipedia!
# Add spaces to the key
key\ with\ spaces = This is the value that could be looked up with the key "key with spaces".
# Unicode
tab : \u0009 A kommenteket a # és ! karakterek jelölik és lehetőség van sortörésre is a \ karakterrel. Többféle formátum is támogatott a key=value mellett, például key = value vagy éppen key : value, ki melyiket preferálja.
Nemzetköziesítésnél miután az alapértelmezett property fájl nyelvi kódját megbeszéltük magunkkal, adhatunk több helyszínt a property fájlunk mellé - úgymint en, hu stb (Természetesen lehetőség van a nyelvi kódon túl ország kód és variáns megadására is).
![]() | |
| NetBeans-ben így nézünk ki |
PHP alól a felolvasására az előző posztban látható egy példa. Érdemes figyelni az unicode karakterek dekódolására felolvasáskor, mivel az állományok kódolása ISO-8859-1.
Akad még egy fontos dolog a property állományoknál, ez pedig a szerkesztésük módja. NetBeans-ben például nagyon egyszerű a módosításuk ugyanis egy táblázatban látjuk a kulcsot és a különböző nyelvekhez tartozó értékeket.
![]() |
| NetBeans-ben szerkesztünk |
Ennél többre nem is térnék ki, mivel egyszerű dologról van szó és mert hamarosan egy apró i18n osztályt is bemutatok majd.
Apr 4, 2011
Mar 25, 2011
PHP-Struct
Az előző poszt egy blogmark volt, amely a más nyelvekből ismerős Struct típustvezette be PHP-ba. Megvalósítottam egy egyszerű Struct osztályt:Mar 21, 2011
Blogmark: Struct classes in PHP
A napokban bukkantam rá egy egész érdekes cikkre, amely stuktúra kialakításával foglalkozik PHP alól. Konkrétan a más nyelvekben beépített Struct-ot veszi alapul és osztályként definiálja.
Dícséri a PHP tömböt, de felhívja a figyelmet a használatával járó hiányosságokra (persze bonyolultabb struktúrákról beszélünk). Bármilyen struktúrát kialakíthatunk és gyorsan kezelhetünk PHP tömb segítségével, de dokumentálni nem fogjuk tudni megfelelően. Honnan fogja tudni a tömböt használó, hogy a struktúrában hol, milyen kulcsok helyezkednek el. Nagyjából sehonnan, mert szabványos dokumentációt nem nagyon fogunk tudni írni rá. Kicsit az adatbáziskezelésből ismert BLOB jut az eszembe ennél a pontnál. A blogposzt egy megoldást kínál a dokumentálható, jól használható struktúrák kezelésére.
Blogmark itt.
ui.: a kommenteket is érdemes elolvasni.
Mar 8, 2011
SSLClient
Nem olyan régen volt szükségem egy TCP kliens létrehozására, hogy kommunikálni tudjak egy szerverrel méghozzá SSL protokollon keresztül. PHP alatt hihetetlenül egyszerűen megvalósítható a dolog stream-ek segítségével. Egy apró osztályban meg is valósítottam az alap függvényeket, következzen tehát a kód.
Subscribe to:
Posts (Atom)












