Kódvisszafejtési örömök

Minden webfejlesztővel előfordul, hogy valaki másnak a kódjához kell hozzányúlnia. Még egy átlagos webalkalmazás is annyira összetett, hogy eltarthat egy jó darabig amíg az ember fel tudja térképezni, hogy valójában melyik kódrészlet mire hivatott vagy, hogy mit hol keressen.

Nemrégiben kaptam egy komplett rendszert, hibajavítási és fejlesztési célzattal. A rendszer egy igazi állatorvosi ló, minden elképzelhető tervezési, megvalósítási és kódolási hiba megtalálható benne, habár többé kevésbé működött. A régi rendszergazda elzárkózott mindenféle kommunikációtól, emailben elküldött egy SQL dumpot és zippelve a php fájlokat.

Azt gondoltam, hogy ha megosztom itt a rendszer feltérképezése során gyűjtött tapasztalatokat akkor ezzel segíthetek másoknak ebben a meglehetősen fájdalmas folyamatban.

Dokumentáció

Amennyiben a kapott kód egyedi fejlesztésű akkor eddigi tapasztalataim alapján a dokumentáció meglétének esélye 0.005% vagy kevesebb. Ha létezik fejlesztői dokumentáció és elég részletes akkor a visszafejtési folyamat be is fejeződött minden ott van amire szükségünk van. Amennyiben nem vagyunk ennyire szerencsések, akkor tovább kell haladnunk.

Szerver környezet

A következő lépés, hogy kiderítsük, hogy a szerver milyen környezettel működött a régi működési helyen. Szerencsés esetben a régi rendszergazda hajlandó a rendelkezésünkre bocsátani egy phpinfo() kimenetet. Ebből értékes információkat szerezhetünk a korábbi környezetről amiben a rendszer működött. PHP és MySQL verziók, egyéb beállítások, telepített kiegészítések.

Esetünkben nem voltam ilyen szerencsés nem kaptam semmit. Mivel a mi szerverünkön PHP 5 és MySQL 5 volt gondoltam, hogy ezzel nem lesz gond. Az alkalmazás nagyjából életre kelt. Ahogy végigkattintgattam a lehetőségeket, próbálgattam a funkciókat láttam, hogy a regisztrációnál használt catchpa nem töltődik be. Persze a felderítést bekapcsolt hibaüzenet kimenettel kell végigvinni, így a hibaüzenetből láttam, hogy hiányzik egy modul a PHP-ből, feltelepítettük. Még így sem ment, az új hibaüzenetből látszott, hogy valami összetevőt egy nem létező elérési úton keresett ami a régi szerverre utalt. Megkerestem a kérdéses sort, átalakítottam azt egy létező útra és működött.

Ezen felül időnként ilyen-olyan fura működésbeli problémák jöttek elő. Mivel eddigre már párszor belenéztem a kódba ami borzalmas volt, kezdtem gyanítani, hogy elég jelentős problémáink lesznek. Első gondolatom a register globals volt. Kipróbáltam mi van ha bekapcsolom, persze a fura hibák megszűntek. A register globals-tól való függés kiirtása a függés mértékétől függően igen összetett folyamat lehet. Úgy néztem a kódból, hogy csak foltokban támaszkodik rá, így első körben ahol láttam, hogy dekralálatlan lokális változóra hivatkozik, ott gyorsan átalakítottam a kódot, úgy hogy működjön.

Kódolás

A következő lépés szokott a legfájdalmasabb lenni. Nyissunk meg 10-15 darab fájlt és nézzük meg, hogy az előző programozó milyen kódolási stílust használt. A magam részéről sokkoló kép fogadott, ennél szörnyűbbet csak 6 éves koromban láttam amikor az Alfa Holdbázis egyik részében egy űrszörny gőzölgő csontvázakat köpött ki.

A kód rosszabb volt mint borzalmas. Behúzások össze vissza, a tab méretek fájlonként mások voltak 1 és 10 között, már ahol egyáltalán voltak behúzások nem egy sorba lett ömlesztve 30 sornyi programkód. Totális rémálom.

Az oldal frames volt ami tovább fokozta az irtózatomat. A framektől viszonylag gyorsan megszabadultam, ahol nagyon muszáj volt ehhez megcsinálnom átjavítgattam a behúzásokat.

Visszafejtés

A kód visszafejtése során a legalapvetőbb kérdés, hogy hogyan épül fel az adatbázis. Milyen táblák vannak, milyen kapcsolatban állnak egymással, mely táblák tárolnak tételek, melyek összesítéseket, mi az egész adatbázis felépítési logikája. Aztán meg kell néznünk a fájlrendszer felépítését, majd az egyes modulokét. Ez a sorrend nem feltétlen időrendi sorrend, inkább csoportok amikhez a visszafejtés során időről időre vissza kell térnünk.

Az adatbázis

35 adatbázis táblám volt, szerencsére mindegyik táblanév előtagjaként ott volt, hogy melyik modulhoz tartozik. Fogtam a MySQL Workbenchet, csináltam vele egy reverse engineering-et, szétdobáltam az egyes modulok tábláit külön csoportokban és berajzoltam az egyértelmű modellkapcsolatokat. Így már volt egy rajzom amin nagyjából látszott, hogy melyik adattáblában mi van.

Sajnos ez az ábra nem volt elegendő ez alapján még nem tudtam beazonosítani, hogy például egy megrendelés elküldésekor melyik táblákba kerül adat. Kicsit turkáltam a kódban, megtaláltam a táblákat de simán a kódból nem állt össze a kép, hogy melyik tábla mire szolgál. Muszáj volt az adatokat segítségül hívni.

Ez után azt csináltam, hogy fogtam egy táblázatkezelőt és nyitottam benne annyi munkalapot ahány adattáblám volt. Szerencsére a modulok vizsgálata során (lásd később) kiderült, hogy a meglévő 6 modul közül egy ami nagyon lényeges, így egyelőre csak ezzel csináltam meg az adatok alapján az adatbázis logikai visszafejtését. Tehát a 35 tábla közül csak 10 volt ami a szóban forgó modulhoz tartozott, ennyi munkalapot nyitottam a táblázatkezelőben. A munkalapok első sorába beírtam az adatbázis tábla nevét és, hogy a mentés pillanatában hány rekordot tartalmazott. Aztán fogtam és a phpMyAdmin betekintő felületén (ha a táblában sok rekord volt akkor az utolsó lapról) kimásoltam a táblázatos formában megjelenített rekordokat és beillesztettem a táblázatkezelő adat munkalapjára. Ezzel kaptam az adatokból egy kis kivonatot, láttam, hogy melyik táblában milyen adatok vannak az egyes mezőkben eltárolva, hány rekord van táblánként. Már ebből láttam, hogy melyek azok a táblák amelyek beállításokat tartalmaznak, mivel ezeknek kisebb a rekordszámuk, és melyek azok amelyek a megrendelésekkel kapcsolatosak.

Fogtam és kinyomtattam 9 munkalapot (1-et azért nem mert az a modulbeállításokat tartalmazta, itt nem kellett). A borzalmak itt tovább fokozódtak. Az adatbázis tervezője szemlátomást nem értette, hogy tulajdonképpen mire is való a normalizálás, mivel pár helyen a kapcsolt adatoknak nem az id-je, hanem azok értéke szerepelt. Mind az admin mind a felhasználói jelszavak titkosítatlanul vannak tárolva. Persze ezek nem segítenek az adatbázis szervezési logikájának a feltérképezésében, csupán tudatták velem, hogy semmin ne lepődjek meg. Amikor azonban láttam, hogy a megrendelések html táblázatként! vannak az adatbázisban eltárolva akkor úgy hanyatt borultam, hogy vagy fél óráig fekve maradtam utána.

Sajnos ezzel még mindig nem tudtam megfejteni, hogy pontosan mi is történik az adatbázis szinten, így nem volt más választásom, mint fogtam, csináltam egy SQL dumpot, elküldtem egy rendelést, csináltam egy új dumpot és megnéztem diff-el a két dump eltéréseit.

Fájlok

A fájlrendszer felépítése jó esetben ad némi támpontot ahhoz, hogy mi is történik odabenn. Láttam, hogy az admin rész könyvtár szinten is le van választva, illetve, hogy az egyes modulok külön könyvtárakba kerülnek. Hát, jobb mint a semmi.

Ilyen kódvisszafejtési alkalmakkor jól jön valami olyan eszköz amely megmutatja, hogy az egyes fájlok, hogy include-olják egymást. Nem igazán bő a kínálat ezzel kapcsolatban, de a Care2x Development Blogon találtam egy leírást, hogy hogyan lehet élete kelteni egy ilyen szolgáltatást nyújtó inclued nevezetű csomagot.

Karakterkódolások

Talán hamarabb kellett volna említenem, de meg kell néznünk a karakterkódolásokat is. Egységes volt (szerencsére), mind a fájlok, mind az AB iso-8859-2-t használt. Utf-nek jobban örültem volna, de egyelőre ezt nem piszkálom, van elég bajom e nélkül is.

Végszó

Ennyi tudás birtokában már jó eséllyel meg fogjuk találni, hogy mit hol és hogyan kell megváltoztatnunk a rendszeren, hogy teljesítse az új követelményeket. Remélem, hogy ez a leírás segít mindenkinek aki rákényszerül arra, hogy minden támpont nélkül más kódjában turkáljon, azon módosításokat, fejlesztéseket eszközöljön.

Ha sok mindent kell módosítani akkor előbb utóbb el fogunk jutni arra a pontra, hogy egyszerűbb / olcsóbb lenne az egész rendszert újraírni. Ha ebbe az irányba fordulunk akkor egyből ott lesz a kérdés (többek között), hogy hogyan pumpáljuk át az adatokat egy biztosan más felépítésű és rendszerű adatbázisba. De erről majd máskor…

8 thoughts on “Kódvisszafejtési örömök

  1. szia!

    teljességgel átérzem a helyzetet, nemegyszer kellett katasztrofális rendszereket helyretegyek. olyanokat, hogy ugyan az a kód 5-6 helyen megvolt, ésatöbbi, amit fent írtál. de amit akartam: a karakterkódoláson segítenek a különböző tördelés-újraszervező funkciók egyes szerkesztőkben. pl. a zend studionak (bár azt hiszem az alap eclipse-ben, vagy pdt-ben is benne van) kifejezetten barátságos az ilyen jellegű funkciója. még ami segíthet: query log 🙂 így a nélkül, hogy belepiszkálnál a kódba (a fentiekből feltételezem, nem használ adatbázisréteget, így nem tudod központilag a php kódba berakni), látni fogod a query-ket 🙂 szép napot, jó munkát

  2. fájlok, mind az AB iso-8859-2-t használt. Utf-nek jobban örültem volna, de egyenlőre ezt nem piszkálom, van elég bajom e nélkül is.

    egyenlőre = egyelőre

    kk.

  3. Hali!

    Gratulálok, nekem “teljesen átjött” (valamelyik retardált-képző kűggyé-nekünk-sok-esemest műsor szereplőjének egy kifejezését kölcsönözve). Ugyan, más komplett rendszerét még nem kellett tuningolnom, de fordult már elő velem is olyan, hogy az előző fejlesztő “elérhetetlensége” miatt pici módosítást kellett eszközölnöm (ami folytán a kiguvadt szem – folyamatos hajtépés gyakran előjött).

    “[…] ennél szörnyűbbet csak 6 éves koromban láttam amikor az Alfa Holdbázis egyik részében egy űrszörny gőzölgő csontvázakat köpött ki.”

    😀 Nekem az a kedvenc részem a sorozatból (én is még zsenge koromban láttam először).

    Nemrég találtam rá a blogodra, de határozottan állítom: csak így tovább (élvezet olvasgatni).

  4. Hali,

    nekem kifejezetten a következő résszel, az adatok áttöltésével volt régebben jó játszmám. Egy Borland Paradox adatfájltból kellett volna kiszednünk ami benne volt és átraknunk az akkor Visual FoxPro alatt fejlesztett programunkba (nem most volt, na), ami dbf táblákkal dolgozott (megnyugtatásképpen: SQL már volt benne). A probléma többrétű volt. Először is mit kezdjünk egy Paradox adatbázissal, mert ilyet még nem ettünk. De ismerős ismerőse valahogy kiexportálta CSV fájlba, így ezen túljutottunk. Ezután mezőnevek hiányában (ez kimaradt az exportból) megpróbáltuk kitalálni, hogy melyik oszlop mi lehet. A következő lépés az volt, hogy a mi tábláink mezőinek valahogy megfeleltettük az abban levő adatokat — már amit lehetett persze. Aztán ami meg nagyon nem akart beleilleni, az ment összefűzve a leírás mezőbe 🙂
    Ezt természetesen egyeztettük a megrendelővel is, csak hogy tudja, hogy mi fog elveszni. Na ez elég nehéz lépés volt, eleve nem is értette a problémát, hiszen csak egyik adatbázist kell átmásolni a másik adatbázisba. Hát igen…
    A projekt végül sikeres lett és beimportáltunk mindent, de sok gürcölés volt vele.

    Amúgy meg hajrá, Rrd, jó a blog, én is rengeteget tanulok innen!

  5. Nekem volt egy kódom, ahol beszédes változó nevek voltak:

    $dart_vader = select valahonnan valami.

    0 db. komment, stb.

    Csak apróbb javítgatásokat tudtam/kellett a kódón eszközölnöm. Aztán az újraírás mellett döntöttek. Hoztak, szerintem jónéhány hibás döntést is. Már nem dolgozom a projecten, de az új kód még nem megy.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöljük.