« 1 2 »
Autor Zpráva
Kcko
Profil
Ahoj,

pokouším se vytvořit WSDL a SoapClienta.

wsdl zde: wsdl.rjwebdesign.cz/server7.php?wsdl
wsdl jsem si nechal vygenerovat touto knihovnou: github.com/dragosprotung/php2wsdl z této primitivní testovací třídy

<?php

/**
 * Example class with @soap annotation.
 */
class Test
{

  /**
     * Adds two numbers.
     *
     * @soap
     *
     * @param float $p1
     * @param float $p2
     * @return float
     */
    public function add($p1, $p2)
    {
        return ($p1 + $p2);
    }


     /**
     * Make array.
     *
     * @param mixed $el1
     * @param mixed $el2
     * @return array
     */
    public function makeArray($el1, $el2)
    {
        return array($el1, $el2);
    }



    /**
     * @soap
     */
    public function getDayyy()
    {
        return date('j');
    }

    /**
     * @soap
     */
    public function getHour()
    {
        return date('H');
    }
    /**
     * @soap
     */
    public function getSleep($force = 1)
    {
        if ($force)
            return 'chce se nám spát';

        return 'jeste se spat nejde';
    }


}


Když se snažím volat nějakou metodu, např.

$client->add(1, 2); tak to spadne viz wsdl.rjwebdesign.cz/client-call.php
nebo když volám getDayyy() tak to nespadne ale výsledkem je NULL.


Co je špatně?


GITHUB: github.com/Kcko/wsdl
Kcko
Profil
Nechci to nijak vytahovat, nicméně, dotaz jsem položil i na StackOveflow. Nikdo neodpověděl stejně jako tady.

Je problém příliš složitý nebo jsem popsal něco nejasně?
blaaablaaa
Profil
Koukal jsi, co ti vrací __getLastResponse?
Kcko
Profil
blaaablaaa:
Ano koukal, smyslupnou odpověd (XML). Nikde tam nemám chybu o čemsi, čeho bych se mohl chytit.
V exception v message dostanu "[Client] looks like we got no XML document", což je mi k ničemu. Samotné WSDL se zdá být OK.
TomášK.
Profil *
Popsané je to celkem dobře. Zakopaný pes je zřejmě někde v té knihovně a k vyřešení by si jí někdo musel nainstalovat k sobě na server. Tím se značně sníží počet těch, kteří jsou ochotní odpovědět.

Kdybych to měl řešit, tak klienta nahradím za curl, abych tam měl o závislost méně, a pak budu zkoumat, co se děje na serveru přes ladící výpisy.
Kcko
Profil
TomášK.:
Žádnou lepší "Class2WSDL" převodní knihovnu jsem nenašel. Používá se a na Githubu nejsou žádná issue s podobným problémem.
Jakého klienta? Je to nativní třída od PHP 5.3+

Obecně s tím SOAPem jsou nějaké problémy. Když jsem zkoušel NON WSDL režim, tak mi to XML padalo podobně a musel jsem zapnout v php.ini "always populate raw post data" a to bylo jediné řešení, které jsem asi po 2h googlení našel.
A WSDL režim mi nefunguje ani s touto direktivou.

Obecně si myslím, že SOAP je pomalu mrtvý a nahrazuje ho REST, ale stejně bych to chtěl vyřešit, abych věděl.
TomášK.
Profil *
Kcko:
Já proti té knihovně nic nemám, jen jsem říkal, proč si myslím, že nikdo neodpovídá - musel bys natrefit na někoho, kdo tu knihovnu už má nebo je ochotný ji instalovat.

Pochopil jsem, že $client->add(1, 2); je kus kódu, který spustíš na klientoví, a který dá dohromady XML, které pošle na WDSL. Je-li to součást PHP, zřejmě to bude spolehlivé, ale stejně bych radějí viděl, co chodí po drátě. Odchytím tím třeba situaci, kdy mi to vrátí NULL, protože se nepovede nějaká konverze.
blaaablaaa
Profil
Kcko:
Nemelo by na serveru byt jeste tohle + nejaky autoloader?

$server->setClass('Test');
Kcko
Profil
blaaablaaa:
Taky jsem zkoušel a autoloader jsem nahradil za prosté require, s tím problém není, akorát jsem už GH neaktualizoval - výsledek stejný.

TomášK.:
Ano proto jsem založil projekt na GH a je tam composer, takže instalace je otázkou chvíle :-). Holt je to složitejší něž většina zdejších vláken typu proč mi nefunguje insert do db :-)))
blaaablaaa
Profil
Kcko:
Zkus to vygenerovat ještě v něčem jiném, nechápu tam to namespace tempuri.org + chybí tam import toho xsd, ne? (ale moc zkušeností nemám, soap používám zatím jen jako klient)
Kcko
Profil
blaaablaaa:
namespace je vcelku jedno, měl jsem svojí doménu, měl jsem localhost. Import XSD by tam byl, kdybych použil ->setClass.

V čem jiném? Zkoušel jsem 2 pofidérní skripty a další 2 třídy a pak už jsem nic rozumného nenalezl, všechno končí stejnou hláškou.

Zkoušel jsem i na různých PHP verzích (5.3/5.6/7.0/7.1), možná něco s nastavením PHP, ale to se mi moc nezdá.
WSDL struktuře moc nerozumím, okem jsem kontroloval s jiným WSDL dokumentem a bylo tam +/- všechno velmi stejné, takže nevím jak dál postupovat.
Taps
Profil
a co treba toto code.google.com/archive/p/php-wsdl-creator

to by ti nepomohlo?
Kcko
Profil
Taps:
Díky, ale tohle je moc robustní :-) a už i zastaralé.

Nakonec jsem problém vyřešil (ted před 5 min), zajímá to někoho?
Taps
Profil
Kcko:
jasně, že zajímá...rád se něčemu dalšímu novému přiučím.
Kcko
Profil
Taps i pro ostatní:
1) První problém byl v nesprávné service URI při generování WSDL (mylně jsem se domníval, že to má směřovat na nějakou URL nebo na url serveru kde to běží, omyl; musí to směřovat na adresu; kde je puštený SoapServer (tj na nějaký php soubor, kde je to zinicializované, u me to je server.php).

2) Druhý, vážnější problém: Každá metoda, která jde do vygenerovaného WSDL, která se SoapServeru nastavuje, musí být řádně zdokumentovaná a oanotovaná viz github.com/Kcko/wsdl/blob/master/class/Test.php#L51-L56 (Bez tohoto správného nastavení to fungovat nepůjde a nelze se dozvědět proč a kde je chyba, přišel jsem na to náhodou).

Původní repo jsem smazal, znovytvořil a aktualizoval a zjednodušil ukázku clienta a serveru -> github.com/Kcko/wsdl

Třeba to někomu pomůže až to bude potřebovat a bude to objevovat jako já.

Asi už to jediné co mě trápi, je že nechápu proč objekt, mezi jednotlivými voláními, který se SoapServeru nastaví (přes metodu setClass) drží výchozí hodnotu členských proměnných. Lidsky řečeno, pokud zavolám $client->metodaA(), ve které bych nastavil do členské proměnné nějakou hodnotu a pak zavolal $client->B() tak tam ta nová hodnota nebude a bude tam hodnota nastavená výchozí nebo nastavená v constructoru.


Tohle je taky vtipné (github.com/Kcko/wsdl/blob/master/class/Test.php#L84) i když má metoda nastavený výchozí parametr a při volání jej tedy neuvedete
tj. $client->getOneOrTwo(); // v klasickém php by se vrátilo 1, tady se vrátí 2
z čehož plyne, že parametry se musí explicitně uvádět, i když jsou nastaveny jako výchozí.
TomášK
Profil
Asi už to jediné co mě trápi, je že nechápu proč objekt, mezi jednotlivými voláními, který se SoapServeru nastaví (přes metodu setClass) drží výchozí hodnotu členských proměnných.
Na serveru může běžet X serverových procesů. Pokud by si proces pamatoval svůj stav, bude se to chovat nepředvídatelně (nevíš, který proces odpoví). Pokud bys nastavoval hodnotu všem, bude to docela oříšek na synchronizaci a někde by se musel skladovat ten sdílený stav. Dává mi smysl, že se to chová tak, jak píšeš.
Kcko
Profil
TomášK:
Asi tomu rozumím, chová se to jinak než klasický objekt, tedy třída pod SOAP objektem v režimu WSDL (Jakoby jednotlivé metody v objektu, byly nějakým způsobem od sebe zcela odděleny a $this tam moc nefunguje - resp to co nenastavím v __constructoru).
Když se mrkneš do toho mého (již funkčního) příkladu, tak jsem schopen díky authTokenu (vlastní proměnná) rozpoznat přihlášeného uživatele. Už ale nemám možnost jak třeba dalším metodám říci o jakého uživatele (login, authLevel atd) jde, krom toho, že bych ho přihlašoval v každé metodě, která vrací nějaká data, což je trošku divné.
blaaablaaa
Profil
Kcko:
Koukal jsi na tohle www.slideshare.net/mayflowergmbh/stateful-soap-webservices ?
Kcko
Profil
blaaablaaa:
Koukám, ale nevidím tam to na co se ptám.


Tak už vím jak na to. Stačí nastavit SoapServeru persistentní chování setPersistence(SOAP_PERSISTENCE_SESSION); (github.com/Kcko/wsdl/blob/auth/server.php#L23)
A konečně začnou v metodách fungovat přenastavené properties z jiných metod (např. v metodě login() nastavím tedy ten můj authLevel a v další metodě ho vidím změněný) :-)

Víc už to zkoumat asi nebudu. Díky všem.
quatzael
Profil
Kcko:
Já tyhle věci vůbec už neřeším přes SoapClienta, protože to má vždycky nějaký mouchy, kvůli kterým to nejde.
Nejjednodušší je to napsat ručně. Většinou nepotřebuješ zadávat ani všechna nastavení a funguje to spolehlivě.

Něco na tenhle způsob:

  $headers = array(
                        "Content-Type: text/xml;charset=UTF-8",
                        "Accept-Encoding: gzip,deflate",
                        "SOAPAction: http://tempuri.org/IIservice/$urn",
                        "Host: ws.domain.cz",
                        "User-Agent: Apache-HttpClient/4.1.1 (java 1.5)",
                        "Connection: Keep-Alive", 
                        "Content-length: ".strlen($xml)
                    );          
               

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt($ch, CURLOPT_URL, "actual_wsdl_url");
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
            curl_setopt($ch, CURLOPT_TIMEOUT, 100);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); 
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);  
            
            $response = curl_exec($ch);         
             curl_close($ch);
            
              
Kcko
Profil
quatzael:
Ahoj,
tenhle topic, ale vubec nebyl o problému se SoapClientem. Byl tu problém s generováním WSDL a nějakými dalšími věcmi v SoapServeru (tj. to kam se připojuješ).

PS. Touhle zrůdností mám nahradit 1 řádek, sloužící k připojení clienta k serveru jo? Viz github.com/Kcko/wsdl/blob/master/client.php#L10
quatzael
Profil
Kcko:
Aha, ok. Každopádně, já jsem měl se SoapClientem docela neřešitelný problémy a některý WS na něm vůbec nešly zprovoznit..
blaaablaaa
Profil
quatzael:
Ja ho pouzivam na vice projektech a zatim bez problemu. Pro zajimavost, co ti tam neslo?
Kcko
Profil
quatzael, blaaablaaa:
To by mě taky zajímalo, protože co jsem si namátkou zkoušel některé free WSDL služby k testování (a že jich teda moc není), tak všechny fungovaly v pohodě.
quatzael
Profil
blaaablaaa, Kcko:
Pokud si dobře pamatuju, tak přes SoapClienta nešlo zakázat http přenos pomocí kódování chunked, což bylo pro jednu WS nezbytné. To jsem vyřešil právě lehce řádkem:
"Content-length: ".strlen($xml)

Dále byl problém, že metoda __getLastRequest u SoapClient funguje jen tehdy, pokud server neodpoví chybou. To nesmyslně komplikuje testování.

Poslední problém byl v tom, že jsem dělal i REST API, což netuším jestli SoapClient vůbec umí. Pro jistotu jsem to ani nezkoušel..
Kcko
Profil
Pokud si dobře pamatuju, tak přes SoapClienta nešlo zakázat http přenos pomocí kódování chunked, což bylo pro jednu WS nezbytné. To jsem vyřešil právě lehce řádkem:
¨
Pro kterou WS, nic takového jsem na žádné WS nevidel požadovat.

metoda __getLastRequest funguje vždy, když nastavíš v parametrech trace na TRUE.

REST Api a WS jsou 2 celkem rozdílné věci ne?
quatzael
Profil
Kcko:
Pro kterou WS, nic takového jsem na žádné WS nevidel požadovat.
To byly čistě komerční B2B záležitosti. WS od velkých finančních korporací.

metoda __getLastRequest funguje vždy, když nastavíš v parametrech trace na TRUE.
To jsem tam právě tuším nastavoval a přesto to nefungovalo..

REST Api a WS jsou 2 celkem rozdílné věci ne?
To jo, ale oboje jde podobně řešit tím [#20] výše uvedeným postupem..
blaaablaaa
Profil
quatzael:
Taky mi to prijde jako zvlastni pozadavek, soap ws pouzivam i u opravdu velkych projektu mezinarodnich firem a problem nebyl.

REST je jen architektura, clovek si nad tim musi postavit vse sam. Tvuj utrzek kodu resi jen odeslani pozadavku, ale uz ne jeho zpracovani/namapovani na tridu, ...
Kcko
Profil
quatzael:
To jsem tam právě tuším nastavoval a přesto to nefungovalo..
Tomu nevěřím :-)

REST jak píše blaaablaaa je jenom koncept, je to defakto CRUD, který si snadno doděláš sám. SOAP s WSDL je dle mého něco zcela jiného. (Ano taky se dají data tahat nebo i ukládat), ale ty primárně pracuješ s nadefinovaným objektem a jeho metodami; v případě RESTu voláš konkrétní URL a data přijímáš nebo je posiláš (POSTem).
moose
Profil *
Už ste to vyriešili, ale tak len pre zaujímavosť pridám svoj názor vychádzajúci z mojich skúseností: SoapClient v PHP je jedna z tých (naj)horších vecí v PHP. Zvlášť v jednom projekte, kde sme ho používali, keby som bol zodpovedný za PHP časť, tak ho pri prvej príležitosti nahradím za obdobné riešenie cez cURL a ušetril by som nám problémy.

Typicky sa v SOAP svete vygeneruje raz z WSDL klient a ten sa používa. Oproti tomu typické použitie SoapClienta navádza vývojárov k tomu, aby používali WSDL poskytované službou. Nie že by sa to nedalo v SoapCliente spraviť aj normálne, ale toto je typické použitie. Problémom potom je, že ak sa WSDL zmení, tak sa zmení aj chovanie klienta. A WSDL sa môže zmeniť niekoľkými spôsobmi. Napr. dajme tomu, že pole, ktoré prijíma reťazec s base64-zakódovaným obsahom je v XSD opísané ako reťazec. Teraz to chcem zmeniť, aby to bolo opísané ako base64 binárny obsah. Obsah volania idúceho po drôte sa nezmení, takže starí klienti môžu fungovať ďalej. Ale keďže PHP si načítava WSDL stále znova, celé to spadne v runtime, keď SoapClient bude odosielať 2x zakódovaný reťazec. Podobný problém nastane pri hardeningu servera, keď sa admin rozhodne WSDL schovať (pretože každý normálny vývojár si už klienta vygeneroval, takže WSDL nepotrebuje).

Ďalší typický problém SoapClienta nastáva, ak sa to vývojár snaží robiť poriadne a nahrá WSDL do resourcov svojho klienta, z ktorého potom inicializuje SoapClienta. Následne pribudne nové pole, vývojár upraví kód, ale zabudne nahrať nové WSDL. Čo spraví SoapClient? Zahodí všetky polia, ktoré nie sú v XSD definované a nezobrazí žiadne chybové hlásenie. Jasné, chyba vývojára - ale pri normálnom prístupe, keď sa z XSD vygenerujú triedy a tie sa používajú takýto problém nenastane (lebo IDE a build nástroje nepustia).

Predchádzajúce odstavce sú len nepríjemnosti, na ktoré si stačí dať pozor a dá sa žiť aj so SoapClientom. Ale špecificky na tomto projekte som narazil ešte na jednu vec, ktorá to dorazila. Sem-tam sa nám stalo, že server nevygeneroval stránku (odpoveď servera bola prázdna). Stávalo sa to cca raz za týždeň, raz za tri dni a podobne. Keďže sme to nevedeli reprodukovať, zapol som ukladanie core-dumpov, čo potvrdilo, že to naozaj občas crashne v PHP module. Tak som stiahol ladiace symboly pre PHP a s pomocou gdb som našiel, že to padá kvôli tomu - a teraz sa podržte - že je zapnuté kešovanie WSDL pre SoapClienta na disk alebo do pamäte (už si nepamätám, ktoré presne z toho). Tak sme vypli jedno kešovanie a nechali len to druhé a problém bol vyriešený. Iste, problém špecifickej verzie PHP, ale názor som si vytvoril už podľa takého množstva problémov, čo som si so SoapClientom užil (resp. užili si to najmä ľudia zodpovední za PHP časť).
« 1 2 »

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0