SOAP, PHP i Introspekcja

Tworzę ostatnio parę systemów do których potrzebny jest mechanizm RPC lub SOAP. Wertując google mój wybór padł na nieco bardziej skomplikowany SOAP głównie z faktu, że jest on natywnie wspierany prze PHP5 jest oczywiście dostępny poprzez extensions tak więc wypada sprawdzić czy owe wsparcie mamy


if (extension_loaded('soap'))
{
echo "HURAAA!!!";
}

U mnie pokazał się zbawienny HURAA!!!! mogłem zabrać się do pracy z SoapClient oraz SoapServer (w przypadku braku możliwości użycia soap extension na waszym serwerze z php proponuję projekt NuSOAP o której napisano wiele, ale uprzedzam jest pisana pod kątem PHP4, jednak nie wymaga żadnych dodatkowych zewnętrznych bibliotek i też działa oferując dużo możliwości tworzenia serwerów i klientów SOAP ) do pełni szczęścia potrzebny był jeszcze jakiś tool pozwalający na szybkie generowanie WSDL (Web Services Description Language) którego sładnia jest nieco zawiła w szczególności przy większych projektach, tutaj z pomocą przychodzą możliwości PHP5 związane z introspekcją lub jak kto woli reverse engineering.

Jednym z moich założeń jest serwowanie WSDL’a z zewnętrznego źródła (czywiście z zachowaniem odpowiednich założeń polityki bezpieczeństwa, ale ten wpis nie traktuje o nich) co nieco upraszca cały proceder bo WSDL będziemy tworzyć statycznie dla usługi a nie dynamicznie jak to często jest praktykowane (patrz: NuSOAP). Mając napisaną klasę w PHP jedteśmy teoretycznie w stanie parsować pod kątem wygenerowania odpowiednich plików WSDL. Jak większość kod klas które tworze mam udokumentowany całościowo lub w najgorszym przypadku szczątkowe informacje na temat co jest co. Niestety do wygenerowania dobrych plików WSDL potrzebna będzie solidna dokumentacja klasy którą chcemy przerobić na zjadliwą dla SOAP’a.

Poniższy kod nie jest moim kodem został napisany przez George’a Schlossnagle’a , ale po małych zmianach (które wyjaśnię poniżej) jest używalny w moich warunkach.

Kod George’a działa jedynie dla klas dokumentowanych za pomocą PHPDoc’a, którego osobiście nie lubie użwać – wolę starą dobrą składnię /param używaną w Doxygen’nie tak więc musiałem parę rzeczy zmienić.
Klasa WSDL_Gen korzysta z cudownego ficzera którym jest ReflectionClass pozwalający przemielić klasę którą otrzyma w konstruktorze pod kątem metod, typów etc…

Ja do swoich potrzeb zmieniłem regexpy przy var, param i return tak aby paowały do /param a nie @param i wszystko zaczęło śmigać jak należy.

Na sam koniec podczepiłem wszystko do systemu zdalnych bakcupów (bo do tego między innymi wykorzystuję SOAP) i wszystko zaczęło śmigać aż miło.

Klient:


$client = new SoapClient('http://localhost/www/1test.wsdl');
$data = $client->dbdump();
$dump = base64_decode($data);
$fp=fopen('soap_dump.sql',"w");
fwrite($fp,$dump);
fclose($fp);

Server jeszcze banalniejszy:


function dbdump()
{
$backup = new MySqlBackup();
$backup -> list_tables();
$backup -> droptableifexists = true;
$buffer = '';

foreach ($backup->tables as $table) {
$buffer .= $backup->dump_table($table);
}
return base64_encode($buffer);
}

$server = new SoapServer("http://localhost/www/1test.wsdl");
$server -> addFunction("dbdump");
$server -> handle();