ugrás a tartalomhoz

Php Soap xsd nem szűr

inf · 2010. Júl. 6. (K), 16.31
Sziasztok!
Csináltam egy Soap tesztet, az a para vele, hogy nem szűri meg az xsd alapján az átvitt objektumokat.

probe.wsdl:

<?xml version="1.0" encoding="utf-8" ?>
<definitions
    name="probe"
    targetNamespace="http://test.omg/probe"
    xmlns:tns="http://test.omg/probe"
   
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://schemas.xmlsoap.org/wsdl/"
>
    <types>
        <xsd:schema>
            <xsd:import schemaLocation="probe.xsd" namespace="http://test.omg/probe" />
        </xsd:schema>
    </types>
    <message name="testRequest">
        <part name="testUser" type="xsd:User" />
    </message>
    <message name="testResponse">
        <part name="testMessage" type="xsd:Message" />
    </message>
    <portType name="probePortType">
        <operation name="test">
            <input message="tns:testRequest"/>
            <output message="tns:testResponse"/>
        </operation>
    </portType>
    <binding name="probeBinding" type="tns:probePortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
        <operation name="test">
            <soap:operation soapAction="http://test.omg/probe/test"/>
            <input>
                <soap:body namespace="http://test.omg/probe" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
            </input>
            <output>
                <soap:body namespace="http://test.omg/probe" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
            </output>
        </operation>
    </binding>
    <service name="probeService">
        <port name="probePort" binding="probeBinding">
            <soap:address location="http://localhost/service/service.php"/>
        </port>
    </service>
</definitions>
probe.xsd:

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test.omg/probe"
>
<xsd:complexType name="User">
<xsd:all>
<xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1" />
</xsd:all>
</xsd:complexType>
<xsd:complexType name="Message">
<xsd:all>
<xsd:element name="code" type="xsd:integer" minOccurs="1" maxOccurs="1" />
<xsd:element name="content" type="xsd:string" minOccurs="1" maxOccurs="1" />
</xsd:all>
</xsd:complexType>
</xsd:schema>
service.php:

class Dispatcher
{
    protected $controller;
   
    public function __construct($controller)
    {
        $this->controller=$controller;
    }
   
    public function __call($method,$arguments)
    {
        if (!method_exists($this->controller,$method))
        {
            throw new SoapFault(404,'Called action '.get_class($this->controller).'.'.$method.' does not exist!');
        }
        $result=call_user_func_array(array($this->controller,$method),$arguments);
        return $result;
    }
}

class WebService
{
    protected $wsdl;
    protected $dispatcher;
    protected $server;
   
    public function setController($class)
    {
        $this->wsdl=$class.'.wsdl';
        if (!file_exists($this->wsdl))
        {
            throw new SoapFault(404,'The '.$class.' wsdl file for service does not exist!');
        }
        if (!class_exists($class,true))
        {
            throw new SoapFault(404,'The '.$class.' service does not exist!');
        }
        $this->dispatcher=new Dispatcher(new $class());
    }
   
    public function run()
    {
        $this->server=new SoapServer($this->wsdl);
        $this->server->setObject($this->dispatcher);
        $this->server->handle();
    }
}
   
class ServiceBus
{
    public function dispatch($controller)
    {
        $service=new WebService();
        $service->setController($controller);
        $service->run();
    }
}


class User
{
    public $name;
    public $test;
}

class Message
{
    public $code;
    public $content;
    public $test;
}

class Probe
{
    public function test($user)
    {
        $message=new Message();
        $message->code=1;
        $message->content=var_export($user,true);
        $message->test='valami';
        return $message;
    }
}

ini_set('soap.wsdl_cache_enabled',0);
$bus=new ServiceBus();
$bus->dispatch('Probe');
client.php:

ini_set("soap.wsdl_cache_enabled","0");     

class User
{
    public $name;
    public $test;
}

class Message
{
    public $code;
    public $content;
}

try{
    $probe=new SoapClient('probe.wsdl');
    $user=new User();
    $user->test='valami';
    $user->name='Egy kis szöveg.';
    $message=$probe->test($user);
    var_dump($message);
}
catch(SoapFault $e)
{
    var_dump($e);
}
A kérés eredménye:

object(stdClass)#3 (3) {
  ["code"]=>
  int(1)
  ["content"]=>
  string(87) "stdClass::__set_state(array(
   'name' => 'Egy kis szöveg.',
   'test' => 'valami',
))"
  ["test"]=>
  string(6) "valami"
}
Mint látható a 'test' példányváltozó lazán átment. Ez normális viselkedés, vagy én rontottam el valamit?
 
1

PHP SOAP

janoszen · 2010. Júl. 6. (K), 16.58
A PHP SOAP interfésszel rengeteg szívásunk volt (pl ez: http://bugs.php.net/bug.php?id=50675) úgyhogy nem biztos hogy jól jársz ha erre építesz. Felhő régebben említette a WSO2-t mint lehetséges csere.
2

Köszi

inf · 2010. Júl. 7. (Sze), 12.57
Köszi, tényleg szopás, megnézem a wso-t. Annyi bonyolultsága van a dolognak, hogy én nem az alkalmazás logika szétosztására akarom használni a soap-ot, hanem js->php adatátvitelre. Szal gyakorlatilag a Controller-eket hívnám meg Soap-pal javascriptből.
3

JSON

Ifju · 2010. Júl. 7. (Sze), 15.50
JSON-RPC nem lenne célszerűbb javascript kiszolgálására?
4

Hát nekem első sorban amiatt

inf · 2010. Júl. 8. (Cs), 02.12
Hát nekem első sorban amiatt tetszett meg a SOAP, mert nagyon szépen lehet vele XSD-vel validáltatni. Gyakorlatilag remote call-t szeretnék, valahogy így:

js:

new Package(
{
	Security: new Class(
	{
		login: Soap.Action
	}).Extends(Soap.WebService),
	User: new Class(
	{
		setEmail: Class.Setter,
		setPassword: Class.Setter
	})
}).bind(window);
//itt a window-ra bindelem a package-t, ez annyit jelent, hogy az ott megadott osztályok window alatt jelennek meg, tehát global namespace-ben...
//a Soap.Action automatikusan hívja az osztály nevének megfelelő service-ben a metódus nevének megfelelő action-t

try
{
	var user=new Security().login(new User().setEmail('test##kukac##test.com').setPassword('myPass'));
	alert('sikeres belépés ['+user.getName()+']');
}
catch(fault)
{
	alert('sikertelen belépés ['+fault.getMessage()+']');
}

//a security.login-ből kijövő user nem ugyanaz, mint amit paraméterként megadtam, mert visszafele már csak name tulajdonsággal küldi a szerver
php:

namespace MyProject\Controllers;

class Security extends \Engine\Soap\WebService
{
	public function login(\MyProject\Models\User $user)
	{
		if ($user->login())
		{
			return $user;
		}
		else
		{
			$fault=new SoapFault();
			$fault->setMessage('gond');
			return $fault;
		}
	}
}

//a frontController ezt példányosítja a javascript kérés alapján
//a wsdl-t az osztály neve alapján tölti be egy fájlból
//a wsdl-ben megadott adat típus hasonló elnevezésű, mint a Model osztály, ebből tudja a rendszer, hogy melyik osztályt kell betölteni (erre még nem találtam ki a konkrét koncepciót)
//az User osztályt autoload-dal tölti be
wsdl:
Gyakorlatilag azt írja le, hogy a login-nál a bejövő ojjektum User osztályú, és email és password példányváltozók értékeit kell, hogy hozza, a kimenő pedig szintén User osztályú, és a name példányváltozót viszi csak vissza. Nyilván így a be és kimenő adatok xml schema típusa eltérő, de az osztályuk azonos. (Egyelőre még nem tudom, hogy ez megvalósítható e complexType restriction-nel, vagy muszáj lesz elnevezésekkel játszani, ezért nem írok konkrét példát.)


Ha ilyen szintű távoli eljáráshívást meg lehet oldani JSON-RPC-vel, akkor szívesen átállok rá, sajnos még nem volt szerencsém megnézni. (A lényeg, hogy js-ben nagyjából sikerült megoldanom, hogy legyenek osztályok, és ugyanolyan példányokat szeretnék használni távoli eljáráshívásra, mint bármilyen oo nyelvben.)
5

Belenéztem

inf · 2010. Júl. 8. (Cs), 02.49
Megnéztem, és szerintem a validálásra nem lesz elég. Az osztály nevének az átvitelét meg lehet oldani, max lefoglalok rá egy kulcsot, viszont a validálása sokkal gyengébb, mint amire egy xsd képes. Egyelőre most xsd-vel fogok foglalkozni pár napig, amíg kitalálom, hogy hogyan lehet vele az átvitt példányváltozókra megszorítást csinálni. Ha összejön, akkor a wso2-t fogom felhasználni, ha nem, akkor lehet, hogy belenézek a json-rpc forrásába, hátha tovább tudom fejleszteni olyanra, ami nekem kell.

Microsoft is csinált valami újabb rendszert távoli dolgokra .NET-ben, de sajnos most nem jut eszembe a neve :S