Internet megosztás Ubuntu-val

Biztos létezik már egy pár HowTo, ami ezzel a kérdéssel foglalkozik, ám nekem több mint egy órámba tellett értelmes megoldást találni, így inkább leírom. A címben nem véletlenül Ubuntu-ra hivatkozok, ugyanis az egyes Linux disztribúciókban némely beállítás különbözhet, annak ellenére, hogy az IP szintű csomagszűrés a kernel része. Nos, aki csak emiatt tévedt ide, nem kertelek tovább íme a beállítás:

Biztos létezik már egy pár HowTo, ami ezzel a kérdéssel foglalkozik, ám nekem több mint egy órámba tellett értelmes megoldást találni, így inkább leírom. A címben nem véletlenül Ubuntu-ra hivatkozok, ugyanis az egyes Linux disztribúciókban némely beállítás különbözhet, annak ellenére, hogy az IP szintű csomagszűrés a kernel része. Nos, aki csak emiatt tévedt ide, nem kertelek tovább íme a beállítás:

Feltételezve, hogy az A számítógépen létezik felépített internet kapcsolat, amit a /dev/eth0 hálókártyán keresztűl szeretnénk megosztani a B számítógép számára. Az A gépen a következő parancsokat kell lefuttatni root-ként:


ifconfig eth0 192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.255
iptables --flush -t nat
iptables --table nat --append POSTROUTING --out-interface wlan1 -j MASQUERADE
iptables --append FORWARD --in-interface eth0 -j ACCEPT
echo 1 > /proc/sys/net/ipv4/ip_forward

Az első sor az eth0 hálózatát állítja be, az eth0-ra csatlakoztatott gépeknek 192.168.1.* tartományból adunk IP címet, az A gépnek 192.168.1.1-et. Természetesen ha ez a beállítás más eszközzel (pl. GUI-val, KNetworkManager, vagy hasonlóval) történik, akkor ez a sor kihagyhandó. Az ezt követő három sor az IP csomagszűrőt állítja be, hogy az eth0 eszközön érkezett IP csomagokat egyszerűen továbbítsa a wlan1 interfészen, ami jelen esetben az internet kapcsolatot adja. Az iptables részletes működését én itt nem írom le, egyrészt mert túl hosszú lenne, más részt én sem vagyok biztos benne, hogy 100%-ig értem. Az utolsó sor szinte minden linux disztrón más. Ez engedélyezi rendszer szinten az IP csomagok továbbítását.

Ha a szervert beállítottuk, a kliens beállítássa már jóval egyszerűbb. Rendszerfüggetlenül fogalmazva, a szerverrel kompatibilis módon be kell állítani a hálózatot, pl. 192.168.1.2 IP címet adunk neki, majd alapértelmezett átjárónak a szerver címét adjuk meg. Ha a kliens gép is linux, és parancssorból kívánjuk beállítani, akkor a következőt kell tenni:


ifconfig eth0 192.168.1.2 netmask 255.255.255.0 broadcast 192.168.1.255
route add default gw 192.168.1.1 eth0

Java osztályok tárolása MySQL adatbázisban

A cím talán megtévesztő lehet, most nem arról van szó, hogy hogyan lehet szérializált osztálypéldányokat tárolni adatbázisban. Ehelyett magukat a Java osztályokat (típusokat) tárolom ilyen módon. Ez megtehető, hiszen a Java futásidőben tölti be az osztályokat, egészen pontosan az osztály első aktív használata elött. A továbbiakban a cikk feltételezi a Java és a MySQL alapszintű ismeretét, és a [[http://java.sun.com/javase/technologies/database/|JDBC]] használatát se fogom részletezni. Kezdetnek essen pár szó a Java osztálybetöltő mechanizmusáról.

A cím talán megtévesztő lehet, most nem arról van szó, hogy hogyan lehet szérializált osztálypéldányokat tárolni adatbázisban. Ehelyett magukat a Java osztályokat (típusokat) tárolom ilyen módon. Ez megtehető, hiszen a Java futásidőben tölti be az osztályokat, egészen pontosan az osztály első aktív használata elött. A továbbiakban a cikk feltételezi a Java és a MySQL alapszintű ismeretét, és a [[http://java.sun.com/javase/technologies/database/|JDBC]] használatát se fogom részletezni. Kezdetnek essen pár szó a Java osztálybetöltő mechanizmusáról.

A Java ClassLoader osztály használható arra, hogy egy keresett osztályt betöltsön a memóriába. Minden JVM indulásakor létrejön egy alapértelmezett rendszer ClassLoader, és ha nem teszünk semmit ez marad végig az egyetlen ilyen jellegű objektum a JVM-ben. A ClassLoader-ek működésének megértéséhez meg kell ismernünk néhány metódusát:

  • A konstruktor: ClassLoader(ClassLoader parent) : Minden ClassLoader-nek létezik pontosan egy szűlője (kivéve az alapértelmezett ClassLoader-t), ugyanis mielött az adott ClassLoader megpróbálná betölteni a keresett osztályt, megkérdezi a szülőt, hogy ő be tudja-e tölteni, és csak akkor próbálkozik meg, ha a még nincs betöltve, és a szülő sem tudja betölteni.
  • Class loadClass(String name) :ez hívódik meg, amikor felmerül az igény egy osztály betöltésére. Ez a metódus elöször meghívja a szülő ClassLoader hasonló metódusát, és ha az ClassNotFoundException-t dob, akkor meghívja ezen osztály findClass metódusát.
  • Class findClass(String name) :a fentiekből látszik, hogy ez a metódus hívódik meg akkor, ha már ránk hárult az osztály betöltésének a feladata. Ha új ClassLoader-t írunk, rendszerint ezt a függvényt akarjuk felülírni.
  • Class defineClass(String name, byte[] b, int off, int len) :ez a lényeg. Ez a függvény hozza létre az osztályt a memóriában a beolvasott bytecode-ból, aminek meg kell egyeznie egy “.class” fájl tartalmával.

Már látszik a turpisság: a fentiek alapján lehet írni egy ClassLoader-t, ami nem fájlból, hanem adatbázisból olvassa be a megfelelő bytesorozatot. Első lépésként írjuk meg az adatbázis réteget, ami a kérdéses bytecode-ot tudja menteni/kiolvasni az adatbázisból (az adatbázisba a bytecode-ot Base64 kódolásban mentem, amit egy segédosztály végez. Lásd: lent. Ugyanúgy nem térek ki a File beolvasására, annak a megoldásában is a Google segített):


package mysqlclasses;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class ClassSaver {

public static byte[] getBytesFromFile(File file) throws IOException {
.....
}

public static void saveToDB(Connection con, String name, byte[] data){
try{
Statement s = con.createStatement();
s.execute("CREATE TABLE IF NOT EXISTS classes (name VARCHAR(120) NOT NULL,bytecode TEXT)");

String bytecode = new String(Base64Coder.encode(data));

ResultSet rs = s.executeQuery("SELECT * FROM classes WHERE name = '"+name+"'");
if (rs.next()){
//update
s.execute("UPDATE classes SET bytecode = '"+bytecode+"' WHERE name = '"+name+"'");
}else{
//insert
s.execute("INSERT INTO classes SET name = '"+name+"', bytecode = '"+bytecode+"'");
}
}catch(Exception e){
System.err.println(e.getMessage());
}
}

public static byte[] loadFromDB(Connection con, String name){
try{
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT * FROM classes WHERE name = '"+name+"'");
if (rs.next()){
return Base64Coder.decode(rs.getString("bytecode"));
}else{
return null;
}
}catch(Exception e){
System.err.println(e.getMessage());
return null;
}

}
}

Ezek után következzék a MySQLClassLoader:


package mysqlclasses;

import java.sql.Connection;

/**
* @author balage
*
*/
public class MySQLClassLoader extends ClassLoader {

Connection con;

public MySQLClassLoader(Connection sqlcon) {
con = sqlcon;
}

public MySQLClassLoader(Connection sqlcon,ClassLoader arg0) {
super(arg0);
con = sqlcon;
}

@Override
protected Class< ?> findClass(String name) throws ClassNotFoundException{
System.out.println("Searching for class: "+name);
byte[] data = ClassSaver.loadFromDB(con, name);
if (data != null){
return defineClass(name, data, 0, data.length);
}else{
throw new ClassNotFoundException();
}
}

}

Meglepően egyszerű, nemde? A kipróbálásához létrhozunk pár egyszerű osztályt:

package test;

public interface Test {
public void some();
}


package test;

public class TestA implements Test {

@Override
public void some() {
System.out.println("I'm an A instance.");
}

}


package test;

public class TestB implements Test {

@Override
public void some() {
System.out.println("I'm a B instance.");
}

}

Az egyszerűbb tesztelés érdekében hoztam létre egy Interface-t is, ami fordítás időben ismert, így egyszerűen meghívható a some() metódus. A létrehozott osztályokkat most le kell fordítani, és be lehet írni az adatbázisba:


Class.forName("com.mysql.jdbc.Driver");

Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "balage", "");

Test a = new TestA();
a.some();
Test b = new TestB();
b.some();

ClassSaver.saveToDB(con, a.getClass().getName(), ClassSaver.getBytesFromFile(new File("bin/test/TestA.class")));
ClassSaver.saveToDB(con, b.getClass().getName(), ClassSaver.getBytesFromFile(new File("bin/test/TestB.class")));

Ezen a ponton érdemes ellenőrizni az adatbázis tartalmát, ahol jól láthatóan szerepel egy “classes” tábla, benne a két osztály bytecode-jával. Ezek után lehet kiovasni onnan őket a következő kóddal (Arra vigyázzunk, hogy a kiolvasandó osztályok NE legyenek elérhetőek a classpath-ban, különben az adatbázis helyett az alapértelmezett ClassLoader fogja őket betölteni!):


Class.forName("com.mysql.jdbc.Driver");

Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "balage", "");
MySQLClassLoader loader = new MySQLClassLoader(con);

Class< ?> clsa = loader.loadClass("test.TestA");
Test a = (Test)clsa.newInstance();

a.some();

Ha mindent jól csinálunk, a kimeneten a TestA osztály üdvözlőüzenete elött látni fogjuk a MySQLClassLoader-ben elrejtett kiírást is, ami egyértelműen jelzi, hogy valóban ő olvasta be az osztályt. Siker. Mielött még kikiáltanám a cikk végét, had tegyek pár megjegyzést, ami szükséges lehet a módszer komolyabb használatához:

Jól láthatóan szövegként hivatkozunk a betölteni kívánt test.TestA osztályra. Ekkor felmerül a kérdés, mi van azokkal az osztályokkal, amikre a betöltött test.TestA osztály hivatkozik? Például létrehoz egy test.TestB osztályt, ami ugyancsak az adatbázisból érhető el, és nem szerepel a megadott classpath-ban. A válasz egyszerű. Azokat akkor próbálja betölteni, amikor aktívan használni próbáljuk. Akkor az osztály nevét átadja az alapértelmezett ClassLoader-nek, ami megkeresi a classpath-ban és.. ClassNotFoundException. A probléma ott van, hogy arra már nem a mi MySQLClassLoader-ünket használja. A teendő tehát: alapértelmezetté kell tenni a létrehozott MySQLClassLoader-t, amit megtehetünk az aktuális Thread ismeretében:


MySQLClassLoader loader = new MySQLClassLoader(con);
Thread.currentThread().setContextClassLoader(loader);

Ezen sor után a futásidőben felmerült osztályhivatkozásokat már az általunk megadott ClassLoader-rel fogja betölteni. Kiemelném, hogy ekkor is létezik a MySQLClassLoader szűlője, ami prioritást élvez, azaz mindig az próbálja meg betölteni a keresett osztályt elsőként (persze csak akkor, ha nincs még betöltve).

Még egy probléma: az általunk létrehozot ClassLoader-t csak futásidőben tudjuk használni, a javac fordításkor csak a beépített ClassLoader-t tudja használni, azaz fordításkor minden hivatkozott osztálynak kéznél kell lennie, csak fordítás után lehet az egyes osztályokat bepakolni az adatbázisba. Ami után viszont az adatbázisból hivatkozott .class fájlok törölhetőek a classpath-ból. A programunkat indító osztálynak, és a MySQLClassLoader-nek viszont minden esetben elérhetőnek kell lennie a classpath-ban, ugyanis a java indulásakor csak az alapértelmezett ClassLoader áll rendelkezésünkre.

Végezetül pár hasznos link:

  • [[http://java.sun.com/docs/books/tutorial/ext/basics/load.html]] Egy részletesebb leírás a Java ClassLoader-ek működéséről
  • [[http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Class.html]] A Class metaosztály javadoc-ja
  • [[http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html]] A ClassLoader osztály javadoc-ja
  • [[http://www.source-code.biz/snippets/java/2.htm]] A Base64 kódolást végző osztály
  • [[http://www.java-tips.org/java-se-tips/java.io/reading-a-file-into-a-byte-array.html]] Egy függvény, ami egy fájlból beolvassa a byte-okat tömbbe

PHP debug Eclipse PDT-ben

Bevezetés

Gondolom, többekkel előfordult már, hogy volt egy olyan PHP-kódja, ami valami miatt nem az elvárható eredménnyel futott le. Ilyenkor nincs mit csinálni, lehet debuggolni. És ekkor szembesül az ember azzal, hogy az nem lesz olyan egyszerű…

A legegyszerűbb PHP-telepítésnél nincs debugger, azaz lépésenként nem lehet futtatni, töréspontokat elhelyezni, változók értékeit vizsgálni. Mármint automatikus módon. Amit lehet csinálni, az az, hogy megsaccolni, hol a hiba, és ezután a megfelelő helyeken a megfelelő változók értékeit kiíratni (akár echo, print_r vagy var_dump segítségével). Ha az adott helyen az elvárható érték adódik, akkor lehet továbblépni. A módszer működik, bár kissé favágás jellegű.

Persze nem én vagyok az első felhasználó, aki ezzel a problémával szembesül. A Zend cég kínál PHP IDE-t, a megfelelő áron. Itt csak az árral volt a probléma (a kalózkodással kíméljetek, valószínűleg én is szoftveres leszek, ezután illene, hogy én azért gondoskodjak a legális szoftverhasználatról a lehetőségeken belül).

Léteznek ingyenes megoldások is, de ezek többnyire a szolgáltatások terén hagynak kívánnivalót maguk után. De most végre sikerült találnom egy megoldást (több helyen kifejtve az interneten Setting up Eclipse PDT and XDebug Debugging PHP5 with Eclipse PDT under OSX: a piece of cake!), az Eclipse rendszer megfelelő beállítását.

Bevezetés

Gondolom, többekkel előfordult már, hogy volt egy olyan PHP-kódja, ami valami miatt nem az elvárható eredménnyel futott le. Ilyenkor nincs mit csinálni, lehet debuggolni. És ekkor szembesül az ember azzal, hogy az nem lesz olyan egyszerű…

A legegyszerűbb PHP-telepítésnél nincs debugger, azaz lépésenként nem lehet futtatni, töréspontokat elhelyezni, változók értékeit vizsgálni. Mármint automatikus módon. Amit lehet csinálni, az az, hogy megsaccolni, hol a hiba, és ezután a megfelelő helyeken a megfelelő változók értékeit kiíratni (akár echo, print_r vagy var_dump segítségével). Ha az adott helyen az elvárható érték adódik, akkor lehet továbblépni. A módszer működik, bár kissé favágás jellegű.

Persze nem én vagyok az első felhasználó, aki ezzel a problémával szembesül. A Zend cég kínál PHP IDE-t, a megfelelő áron. Itt csak az árral volt a probléma (a kalózkodással kíméljetek, valószínűleg én is szoftveres leszek, ezután illene, hogy én azért gondoskodjak a legális szoftverhasználatról a lehetőségeken belül).

Léteznek ingyenes megoldások is, de ezek többnyire a szolgáltatások terén hagynak kívánnivalót maguk után. De most végre sikerült találnom egy megoldást (több helyen kifejtve az interneten Setting up Eclipse PDT and XDebug Debugging PHP5 with Eclipse PDT under OSX: a piece of cake!), az Eclipse rendszer megfelelő beállítását.

Rövid összegzés

Azok kedvéért, akik vagy nagyon értenek hozzá, vagy csak bizonyos részek érdeklik őket, álljon itt egy rövid összefoglaló a lépésekről (a lépéseket természetesen nem feltétlen ebben a sorrendben kell végrehajtani, de érdemes pl. az Eclipse-et feltelepíteni, mielőtt össze akarod kapcsolni az XDebug-gal 🙂 ):

  • Alapvető PHP környezet beállítása
  • XDebug telepítése a PHP-hoz
  • Az Eclipse PDT projekt telepítése
  • Az Eclipse-hez XDebug plugin telepítése
  • Egyéb nyalánkságok

Feltételezések

Annak érdekében, hogy a cikk olvasható maradjon, és ne tegyen ki kisebb könyveket, bizonyos feltételezésekkel élek az olvasó ismereteire vonatkozóan:

Az alapvető PHP környezet telepítését nem részletezném. Ha gondot okoz, akkor nem javaslom a cikk további olvasását sem, ugyanis az Eclipse nem egy könnyen megtanulható, egyszerű eszköz, és a megfelelő beállítás szintén gondot okozhat. Esetleg ha feltétlen ragaszkodsz hozzá, léteznek olyan csomagok, amik egyben tartalmaznak Apache-ot, PHP-t és MySQL-t (pl. MAMP, WAMP, LAMP, stb.). A cikk további részében feltételezem továbbá, hogy a php.ini szerkesztése (megtalálása) nem okoz gondot.

Nincs módom/időm az összes elérhető rendszeren és verzióval tesztelni a környezetet, így csak korlátozott tapasztalatokat tudok megosztani. Az íráskor az Eclipse Core pluginek a jelenlegi legfrissebb, 3.3-as verzióval futnak, a PHP 5.2-es verziójú Apache (2.2.4) modulként futtatva. Az XDebug a 2-es verziónál tart (helyenként 0.2-esként hivatkoznak rá). A saját rendszerem Mac OSX 10.4 alapon fut, és erre a fent említett programok általam lettek lefordítva. A debugger ezen a rendszeren tökéletesen működött, gondot nem tapasztaltam.

PHP és XDebug

Az XDebug telepítése érdekesebb kérdés – szükség van egy lefordított modulra belőle – Windowsra és Linuxra van belőle a hivatalos XDebug oldalon, legalábbis bizonyos PHP verziókhoz, ha más platformon futtatod (mint én az OSX-szel), vagy nem megfelelő a PHP verzió, akkor lehet fordítani, vagy esetleg a Komodo IDE-jébe befordított változat is használható, amint az egyik OSX-es forrás is ajánlja. A fordítással kapcsolatban volt egy félmondatos megjegyzés, hogy azért nem azt követi, mert állítólag ahhoz a PHP-t (és azzal együtt az Apache-ot is) le kellene fordítania.

Erre én nagy bátran arra gondoltam, hogy mivel úgyis MacPorts-sal (korábban DarwinPorts) telepítettem fel a rendszert, és ezáltal lefordítottam, gondoltam, bátor leszek, és lefordítom inkább forrásból, minthogy egy harmadik gyártó programját kelljen használni, vagy hogy másik fizetős szoftvert telepítsek ezért a gépemre (pontosabban a demóját). Még egyszer: Linuxra és Windowsra van bináris változat is, azokat lehet használni, csak arra kell ügyelni, hogy a saját PHP verziónkhoz való változatot töltsük le.

Ha megvan a bináris változat, akkor jöhet a bűvészkedés a php.ini fájllal. A következő néhány sort kell beszúrni a fájlba: zend_extension=/xdebug/bináris/elérési/útja/xdebug.so
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000
. Ha ez megvan, akkor újraindítandó a szerver (feltéve, hogy a php apache modulként van telepítve). Ezután a phpinfo lekérésével (akár parancssorból a php -i -vel, akár pedig a phpinfo(); parancs meghívásával egy scriptfájlban) az elején, amikor a Zend Engine verzióját kiírja, meg kell, hogy jelenjen az XDebug verziója is. Esetleg a php -m paranccsal a modulok listájában is meg lehet keresni az XDebug modult (mind a modulok, mind a Zend modulok között szerepelnie kell). Az említett módszerek közül bármelyikre elegendő megvizsgálni, nincs szükség az összes vizsgálat végrehajtására. Ha megvan, örülhetünk. Ha nem, akkor jöhet a vadászat, hogy mit rontottunk el. Ilyen esetekben némi segítséget jelenthet a hivatalos XDebug oldalon található dokumentáció.

A telepített XDebug megjelenik a phpinfo()-ban

Megjegyzés:Windows felhasználók esetén a lefordított bináris nem .so, hanem .dll kiterjesztéssel rendelkezik, és érdemes lehet a php bővítményei közé rakni (de természetesen ez nem kötelező); valamint a fájlnevet is megfelelően módosítani kell.

Abban az esetben, ha rossz XDebug binárist kaptunk, itt elképzelhető, hogy a PHP nem indul el – velem előfordult. A fordítás során ugyanis egy gusztustalan hibába futottam: sikerült 4.3-as PHP-hoz lefordítanom az XDebug-ot, és ez az 5.2-es PHP-val nem működik együtt, méghozzá olyan szinten, hogy a PHP el sem indult, hanem mindenféle különös hibaüzenetet dobált. Hogy ez hogyan jött elő? Az OSX 10.4 gyárilag tartalmaz egy 4.3-as PHP-t, amit elég nehézkes eltávolítani a rendszerből, ezért inkább MacPortsszal mellételepítettem az 5.2-es változatot. Ugyanakkor a fordításkor egyéb paraméterek megadása nélkül a 4.3-ast találta meg. Amikor a fordításkor megfelelő paraméterrel megadtam az 5.2-es PHP elérési útját, az így kapott binárissal rögtön elindult a PHP.

Eclipse

Mi is az az Eclipse? Egy teljesen nyílt IDE (gyengébbek kedvéért: integrált fejlesztői környezet). Nyílt azért is, mert teljesen nyílt forráskódú, és azért is, mert pluginalapú. Ez azt jelenti, hogy ha egy másik nyelvhez akarsz fejlesztői környezetet használni, azt ugyanúgy el lehet készíteni az Eclipse IDE felett, és ugyanazokat az elemeket képes is használni (például az Eclipse PDT-vel együtt feltelepülnek azok a pluginek is, amivel a Java fejlesztést lehet végezni). Mindezek felett az Eclipse Java nyelven íródott, ezért nagyszerűen egyforma (lassan) működik az összes nagyobb operációs rendszeren (persze a gépigénye megvan, rengeteg memóriát eszik például).

Netes bogarászás alapján az Eclipse PDT (Php Development Tool) plugincsomag kellően jó választásnak tűnik. Ha korábban nem volt telepített Eclipse és csomagkezelőből sem tölthető le akár mert az operációs rendszerhez nincs csomagkezelő (pl. Windows), akár mert az elérhető csomagkezelő nem tartalmazza (pl. OSX-en a MacPorts), akkor legegyszerűbb a
PDT Project oldaláról lehúzni. Egyébként a frissítések között is megadható az http://download.eclipse.org/tools/pdt/updates/ URL, és azon keresztül is telepíthető. Ez használható a Linuxon csomagkezelőből telepített Eclipse esetén is (a beépített frissítések egyébként a Help menü Software Updates pontja alatt érhető el – a lehető leglogikusabb hely a funkcióhoz :-p). Az Eclipse csomagkezelőjét használó funkciót nem teszteltem, de Balage tapasztalatai alapján a 3.2-es core modulokkal nem működik, 3.3-assal nem sikerült tesztelnie.

Léteznek egyéb PHP kiterjesztések is az Eclipse rendszerhez, de azok vagy abbamaradtak (pl. a PHPEclipse csomag utolsó kiadása 2005-ös), vagy még nem jutottak el egy bizonyos érettségi fokra. Természetesen a PDT Project sem jutott fejlődésének csúcspontjára, de előnye, hogy a PHP-t támogató Zend (is) mögötte áll, és arra készül, hogy az egész platformját átírja Eclipse alapra, miután a projekt megfelelő szintre eljutott.

Maga a telepítés teljesen magától értetődő, nem is fektetnék rá nagyobb hangsúlyt.

Eclipse és XDebug

Módosítás: 2007. szeptember 26-án.

Na, ez szép fázis. Az Eclipse PDT jelen helyzetben nem támogatja beépítve az XDebug-ot. Persze nincs semmi veszve, hisz az Eclipse pluginelhető rendszer, és a feladathoz létezik plugin. Ezt az Eclipse plugint kell még telepíteni az azEclipse Bugzilla-ról (a tervek szerint ez a funkció később bekerül az Eclipse PDT-be, de az még arrébb van). A megfelelő verzió választása itt is fontos lehet. Fontos: nem véletlenül nincs más helyen letölthető verzió. Szerencsére az Eclipse pluginek telepítése és eltávolítása egyaránt egyszerű művelet: bemásolás az Eclipse pluginkönyvtárába a pluginkönyvtár a telepített Eclipse struktúrában könnyen megtalálható, illetve eltávolítás ebből a könyvtárból. Természetesen eközben célszerű, ha maga az Eclipse nem fut, vagy ha mégis, akkor a változások érvényre juttatásához újra kell indítani. Természetesen ez a plugin nem érhető el egyelőre az Update Manageren keresztül.

Nekem ez a rész teljesen simán működött, a plugin létrehozta a szükséges új View-kat, beállítópanel(rész)eket. De mivel ez még nem hivatalos plugin, nem biztos, hogy mindenhol tökéletesen működni fog, óvatos kezelést igényel.

A 2007. szeptember 17-én megjelent Eclipse PDT már beépítve tartalmazza az XDebug-on keresztüli debuggoláshoz szükséges plugineket – és megváltoztatták a módot is, ahogy XDebug-os debug session-öket lehet létrehozni. Mostantól nem külön debugtípus az XDebug-on keresztüli, hanem a debug mód egyik paramétere a választott debugger.

Ha korábban az én írásom alapján állítottad össze a rendszert, és használtad a debuggert, és hagytad az Eclipse-nek, hogy frissítse magát, akkor azt vehetted észre, hogy mindenféle hibaüzenet nélkül megszűnik a debuggolás, a töréspontoknál nem áll meg futás közben, stb.

A probléma megoldására két megoldás van: az egyszerűbb az, hogy eltávolítod a meglevő Eclipse-et, és újratelepíted az új verziót (ezzel biztosan eltűnik minden hivatkozás az időközben elavulttá vált Bugzillán közölt pluginre), vagy ha nagyon profi vagy, akkor megpróbálhatod kézzel kihackelni a pluginek közül a kapcsolódó részeket.

Ha ezzel is megvagy, akkor már (elvileg) van egy teljesen működőképes PHP-debuggolásra alkalmas fejlesztői környezeted.

Amikor persze a Debug-ot meghívod, figyelni kell rá, hogy a felajánlott lehetőségek közül azokat válaszd, amiknek a nevében XDebug van – a másik másfajta debuggerhez való.

Egyéb nyalánkságok

Természetesen a lehetőségek itt még messze nem merültek ki. Például az Eclipse-et könnyű rávenni arra, hogy CVS vagy SVN verziókezelő rendszerrel szinkronizálja a projektet. A CVS támogatás a legtöbb Eclipse-verzióban benne van (konkrétabban én még nem láttam olyat, amiben ne lenne benne 🙂 ). Az SVN-hez legegyszerűbb a Subclipse plugin letöltése. Részletes telepítési útmutató a projekt oldalán található. A használata elsőre furcsa lehet (a Workspace view-ban a Project jobb gombos menüjében a Team menüben találhatóak az ehhez tartozó részek).

Hasznos lehet, ha a PHP projekt olyan mappába kerül, amit a webszerver is lát. Ez Eclipse alatt kis fejtörést igényel, ugyanis az Eclipse workspace alapon működik – viszont a workspace mappát nem (feltétlenül) érdemes a helyi gépen levő webszerver elérhetőségébe tenni. Én azt csináltam, hogy a workspace-t a saját mappámban hoztam létre, míg amikor ezen belül projekteket hoztam létre, azoknál gondoskodtam róla, hogy az Apache által kezelt mappába jöjjön létre a megfelelő mappa (ez az új projekt varázsló egyik pontjánál elérhető szolgáltatás, alapértelmezetten le van tiltva).

Az aktuális projekthez tartozó debug útvonalakat (pl. a felparaméterezett index-fájl, stb.) érdemes felvenni a rögzített debug módok listájára, sokkal gyorsabban felhasználható, különösen, ha hozzám hasonlóan olyan url-en keresztül érhető el a php-fájl, amit az Eclipse nem jól „tippel” meg.

Azok a bizonyos utolsó szavak

Balage volt olyan kedves, hogy a cikk egy félkész változatát tesztelte a Kubuntu Linux-án. A tapasztalata szerint a rendszer csomagkezelője által telepített 3.2-es Eclipse-core nem volt kompatibilis a linken elérhető Eclipse PDT-vel, az Eclipse honlapjáról letölthető változat meg nem igazán akart futni (pl. üres splash screen, csomagkezelője első nekifutásra kifagyott). Nem is sikerült megoldani így a gondot. Azoknak, akik hasonló cipőben járnak, tudom ajánlani az EasyEclipse PHP módját. Lényegesen egyszerűbben telepíthető, mint a teljes Eclipse csomag, benne van többek között a Subclipse plugin is, és nagyobb hangsúlyt fektetnek a kompatibilitásra, ugyanakkor ezért a rugalmasságban kell fizetni: nem biztos, hogy bármely Eclipse plugin gond nélkül együttműködik vele, illetve csak csomagként lehet frissíteni tudomásom szerint. Én ezt sem teszteltem, de Balage-nál megoldotta a gondokat.

És végül egy bizonyos „copyright” célú megjegyzés: az csak a véletlen műve, hogy nem olyan régen János egy hasonló témájú írást jelenített meg az oldalán: PHP fejlesztői környezet berendezése. Nem használtam fel semmit az írásából, nem a Zend debuggerét használtam fel. Erre két okom is volt: nem rajongok a csak egy dll/so formátumban terjesztett megoldásért teljesen nyílt rendszer összerakásakor (ugyan nem nézem meg a forrást, de csak megnyugtatóbb, ha én fordítom le… az meg már tényleg csak mellékes, hogy a Windows-nál is zártabb OSX felett építem fel ezt a rendszert… 🙂 ), valamint én ehhez találtam leírást. Az meg már csak hab a tortán, hogy ezzel elméletben remote debuggingra is lehetőség van, de ezt már végképp nem használom ki.

Sok sikert mindenkinek a rendszer használatához, ha van, aki megosztja a tapasztalatait, örömmel venném, ha kiegészíthetném vele ezt a leírást.