PHP İle SOAP Server ‘a Bağlanmak (SOAP Client)
Merhaba arkadaşlar, bu yazımızda PHP ile SoapClient kullanımı inceleyerek SoapServer ‘a bağlantı kurmayı inceleyeceğiz.
Başlamadan önce SoapServer nedir sorusuna buradaki yazımızda incelemeye aldığımız konudur diyoruz ve o yazıda anlattığımız dosyalardan olan client.php ‘yi kullanacağımızı hatırlatalım.
SoapClient Nedir ?
SoapClient, web servislerine bağlanmamız için gereken bir kütüphanedir. Yukarıda bahsettiğimiz yazıda Soap hakkında bilgiler vermeye çalıştığımız için burada çok fazla tanımlarına değinmeyeceğiz.
client.php dosyasının içeriği
<?php // wsdl cache 'ini devre disi birak ini_set("soap.wsdl_cache_enabled", "0"); try { // SOAPClient nesnesi olustur $client = new SoapClient("http://ws.mustafakirimli.com/rpc/productsService.php?wsdl"); // SOAPClient uzerinden karsi sunucudaki getAllNotebooks metodunu cagir $notebooks = $client->getAllNotebooks(); echo "Metod basarili bir sekilde calistirildi.<br/>Sonuc asagidadir.<br/>"; echo "<pre>"; // Sonucu ekrana bas var_dump($notebooks); echo "</pre>"; } catch (Exception $exc) { // Hata olusursa yakala echo "Soap Hatasi Olustu: " . $exc->getMessage(); } ?>
Ve gördüğünüz gibi buradaki yazımızda anlattığımız web servisine bağlanıp veri çeken dosyamızın içeriği yukarıdaki gibidir. Bu dosya kendisinden başka hiç bir dosyaya ihtiyaç duymaz. Kütüphane PHP5 ile gelmektedir (kısıtlamalar için SoapServer yazısına bakınız).
Adım adım dosyamızı incelemeye çalışalım.
- Öncelikle wsdl cache ‘i devre dışı bırakıyoruz.
- Sonrasında olası hatalar ve karşı sunucudan gelen istisna fırmatmaları için (exception) kalan tüm kodları try{ .. }catch(){} bloğu arasına alıyoruz.
- Daha sonra SoapClient nesnemizi WSDL url sini parametre olarak verip olusturuyoruz.
- Karşı sunucudan metodumuzu (parametre gerekiyorsa parametre ekleyerek) sanki kendi sunucumuzdaymış gibi çağırıyoruz.
- Gelen sonucu işleyip veriyi işliyoruz ve işlem bitmiş oluyor.
- Ve catch bloğu içerisinde eğer hata varsa ekrana basıyoruz (eğer bir istisna oluşup yorumlayıcı buraya kadar geldiyse zira kod hatasız çalışırsa bu satırlara hiç gelmeyecektir).
Web servisimizin kullanımına bir başka örnek olan mod/client_getAllBooks.php dosyasının içeriği aşağıdadır.
<?php header('Content-type: text/html; charset=utf-8'); // wsdl cache 'ini devre disi birak ini_set("soap.wsdl_cache_enabled", "0"); try { // SOAPClient nesnesi olustur $client = new SoapClient("http://ws.mustafakirimli.com/rpc/productsService.php?wsdl"); // SOAPClient uzerinden karsi sunucudaki getAllBooks metodunu cagir $books = $client->getAllBooks(); for ($i = 0, $count = count($books->Book); $i < $count; $i++) { echo "ISBN:" . $books->Book[$i]->ISBN . "<br/>\n"; echo "Yazar:" . $books->Book[$i]->author . "<br/>\n"; // Stok durumunu kontrol et $bookStatus = $client->checkBookStatus($books->Book[$i]->ISBN); echo "Stok:" . $bookStatus . "<br/>\n"; echo "<br/><br/>"; } } catch (Exception $exc) { // Hata olusursa yakala echo "<br/>\nSoap Hatasi Olustu: " . $exc->faultcode; } ?>
Bu sayfanın çıktısı şu şekildedir:
ISBN:9781234567890 Yazar:Ahmet AY Stok:VAR ISBN:9781234567891 Yazar:Mehmet YILDIZ Stok:YOK ISBN:9781234567892 Yazar:Ali YILMAZ Soap Hatasi Olustu: Kitap bulunamadı!
Çıktıda gözünüze takılan bir nokta Soap hatası olabilir. Bu hatayı bir önceki yazımızda SoapServer ‘i oluştururken bilerek bir hata yaptık ve orada verdirdik. Gerçek hayatta her şey tıkır tıkır işlemediğinden hataların nasıl yönetilebileceğine dair örnekler vermeye çalıştık. Bu hata bazen böylede alınabilir. Mesela siz tüm kitapları çekmek için istek göndermişsinizdir ve kitap detaylarını işlerken stok kontrolü yapmak için sunucuya tekrar istekte bulunup tok durumunu isterseniz. O anda sunucudaki teknik bir nedenden dolayı gerçektende kitabın tanım tablosu okunamayabilir ve size hata dönebilir.
Bir Kaç Debugging Örneği ve SoapClient Metodu
Buradan sonra SoapClient ile gelen yerleşik fonksiyonları ve Soap debugging üzerine inceleme yapacağız. Bunları yaptığımızda bir web servisinin implementasyonunda karşınıza çıkabilecek sorunları nasıl yönetebileceğini yada nasıl debug edebileceğinizi inceleceğiz.
client_debug.php dosyamızın içeriği
<?php // wsdl cache 'ini devre disi birak ini_set("soap.wsdl_cache_enabled", "0"); try { // SOAPClient nesnesi olustur ve trace modunu ac $client = new SoapClient("http://ws.mustafakirimli.com/rpc/productsService.php?wsdl", array("trace" => 1)); // Metodlari ekrana bas echo "Karsi sunucudaki kullanilabilir metodlar:<br/><pre>"; // Karsi sunucudaki kullanilabilir metodlari listele $allMethods = $client->__getFunctions(); print_r($allMethods); echo "</pre>"; echo "<br/><br/><br/>"; // SOAPClient uzerinden karsi sunucudaki getAllNotebooks metodunu cagir $notebooks = $client->getAllNotebooks(); echo "getAllNotebooks metodunun sonucu asagidadir.<br/>"; echo "<pre>"; // Sonucu ekrana bas var_dump($notebooks); echo "</pre>"; echo "<br/><br/><br/>"; // Son istegi ekrana bas echo "Son yapilan istek asagidadir<br/><pre>"; echo htmlentities($client->__getLastRequest()); echo "</pre>"; echo "<br/><br/><br/>"; // Son istegin header kismini ekrana bas echo "Son yapilan istegin header kismi<br/><pre>"; echo htmlentities($client->__getLastRequestHeaders()); echo "</pre>"; echo "<br/><br/><br/>"; // Son yapilan istege sunucunun verdigi yanit echo "Son yapilan metod cagrisinin yaniti<br/><pre>"; echo htmlentities($client->__getLastResponse()); echo "</pre>"; echo "<br/><br/><br/>"; // Son yapilan istege sunucunun verdigi yanitin header kismi echo "Son yapilan metod cagrisinin yanitinin header kismi<br/><pre>"; echo htmlentities($client->__getLastResponseHeaders()); echo "</pre>"; echo "<br/><br/><br/>"; } catch (Exception $exc) { // Hata olusursa yakala echo "Soap Hatasi Olustu: " . $exc->getMessage(); } ?>
Yukarıdaki kodları bölüm bölüm incelemeye çalışalım;
ini_set("soap.wsdl_cache_enabled", "0");
Daha öncede bahsettiğimiz gibi bu satır wsdl cachelemesini devre dışı bırakır.
..
$client = new SoapClient("http://ws.mustafakirimli.com/rpc/productsService.php?wsdl", array("trace" => 1));
Bu satırda web servisinin url sini SoapClient ‘a ilk parametre olarak veriyorz. client.php ‘den farklı olarak SoapClient sınıfına içinci parametreyi gönderiyoruz. Bu parametre yukarıda gördüğünüz gibi array(“trace” => 1).
Bunu yaptığınızda SoapClient trace modunu açar. Trace moduyla __getLastRequest, __getLastRequestHeaders, __getLastResponse, __getLastResponseHeaders metodlarını kullanabilirsiniz. Trace modunu açmadanda bu metodlar çalışır ancak hiç bir değer döndürmezler.
..
$allMethods = $client->__getFunctions();
__getFunctions metodu bize karşı sunucudan çağırabileceğimiz (WSDL ile izin verilen) fonksiyonlar listesini verir. Metod array döner. Bu metodu kullanabilmek için trace moduna gerek yoktur.
Örnek çıktısı:
Array ( [0] => NotebookList getAllNotebooks() [1] => string checkNotebookStatus(string $notebookCode) [2] => BookList getAllBooks() [3] => string checkBookStatus(string $ISBN) )
Çıktının ilk satırına biraz daha yakından bakalım isterseniz. Çünkü özel tanımlanmış tip dönen bir fonksiyon görüyoruz. Fonksiyonumuz (getAllNotebooks) hiç bir parametre almıyor ve NotebookList tipinde bir değer dönüyor. NotebookList ‘in neler içerdiğini nasıl anlayabileceğimizi bir sonraki sayfada inceliyoruz.
Çıkının bir başka satırına daha değinerek ne anlama geldiğini inceleyelim. Dizinin ikinci elemanı bildiğiniz gibi checkNotebookStatus metodunu açıklıyor. Metod adının hemen önünde bulunan string ‘in anlamı metodun string tipinde değer döndüreceğini ifade ediyor. Parantez içi ise string tipinde değer istediğini ifade ediyor.
..
$allTypes = $client->__getTypes();
Bir önceki sayfada web servisi üzerindeki fonksiyonları listeleyen metodu anlatmıştır ve bu metod kullanıldığında sunucudan aldığımız yanıt bize web servisi üzerindeki fonksiyonlar ve fonksiyonların kullandıkları tipleri (giriş/çıkış parametreleri) veriyordu.
Şimdi ise bu tiplerin (web servisi için özel tanımlanmış) detaylarını nasıl öğreneceğimize bakacağız. Bir çok arkadaşımı bu kadar yazıyı okumak yerine deneme yanılma yoluyla yapmanın daha hızlı olacabileceğini düşünebilir. Hatta bir çok durumda haklıda olabilirler. Ancak çağırdığınız metod veri çeken değil bir işlem gerçekleştiren (sipariş, satış, iptal gibi) metod ise (helede karşı sunucuda test ortamı yoksa) yada onlarca kez denemekten aşırı istek uyarısı alıyorsanız bu yöntemi uygulamanız gerekebilir.
Yukarıdaki metod (__getTypes) array tipinde değer döner ve örnek çıktısı aşağıdaki gibidir. Bu metodu kullanabilmek için trace moduna gerek yoktur.
Array ( [0] => struct Notebook { string code; string brand; } [1] => struct NotebookList { Notebook Notebook; } [2] => struct Book { string ISBN; string author; } [3] => struct BookList { Book Book; } )
..
$notebooks = $client->getAllNotebooks();
Bu satır client.php ‘de anlatığımız gibi web servisinden getAllNotebooks fonksiyonunu çağırır. Fonksiyonun ne tipte bir değer döneceği bir önceki bölüm açıklamasında da yer alan NotebookList dir.
Çıktısı aşağıdaki gibidir:
stdClass Object ( [Notebook] => Array ( [0] => stdClass Object ( [_code] => 123456 [brand] => ASUS )
[1] => stdClass Object ( [_code] => 123457 [brand] => LENOVO )
[2] => stdClass Object ( [_code] => 123458 [brand] => TOSHIBA )
) )
..
echo htmlentities($client->__getLastRequest());
Bu satırdaki __getLastRequest metodu karşı sunucudan web servisi fonksiyonu çağırdığımızda arka planda oluşturulup sunucuya gönderilen XML ‘i gösterir.
Bu metod için trace mode ‘a ihtiyaç vardır. htmlentities kullanma amacımız browser ekranında kodların (xml tagları vb) görünmesi içindir.
Ayrıca bu XML Soap Web Servisine SoapClient kullanmadan bağlanılırken kullanılan istek XML ‘idir. Tabiki mümkündür SoapClient kullanmadan bağlanmak ancak hem hata ayıklaması hemde yazacağınız kod satırı gerçekten çok çok fazla olacaktır. Örneğin client.php dosyası tek başına karşı sunucudan bir fonksiyonu çağırır ve ekrana basar. Bunu SoapClient kullanmadan yapmayı deneyebilirsiniz (zaman bulursak yazı olarakta ekleyeceğiz) ancak çok zamanınızı alacaktır.
Çıktısı aşağıdaki gibidir;
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:ProductsService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:getAllNotebooks/> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
..
echo htmlentities($client->__getLastResponse());
Bu satır ise son yapılan isteğin header kısmını ekrana basar.
Bu metod için trace mode ‘a ihtiyaç vardır. htmlentities kullanma amacımız browser ekranında kodların (xml tagları vb) görünmesi içindir.
Çıktısı :
POST /rpc/productsService.php HTTP/1.1 Host: ws.mustafakirimli.com Connection: Keep-Alive User-Agent: PHP-SOAP/5.3.2-1ubuntu4.5 Content-Type: text/xml; charset=utf-8 SOAPAction: "urn:ProductsService#getAllNotebooks" Content-Length: 394
..
echo htmlentities($client->__getLastResponse());
Bu metod web servisine son yapılan isteğin XML çıktısı halini gösterir.
Bu metod için trace mode ‘a ihtiyaç vardır. htmlentities kullanma amacımız browser ekranında kodların (xml tagları vb) görünmesi içindir.
Çıktısı:
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:ProductsService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:getAllNotebooksResponse> <return xsi:type="ns1:NotebookList"> <Notebook xsi:type="ns1:Notebook"> <code xsi:type="xsd:string">123456</code> <brand xsi:type="xsd:string">ASUS</brand> </Notebook> <Notebook xsi:type="ns1:Notebook"> <code xsi:type="xsd:string">123457</code> <brand xsi:type="xsd:string">LENOVO</brand> </Notebook> <Notebook xsi:type="ns1:Notebook"> <code xsi:type="xsd:string">123458</code> <brand xsi:type="xsd:string">TOSHIBA</brand> </Notebook> </return> </ns1:getAllNotebooksResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
..
echo htmlentities($client->__getLastResponseHeaders());
Bu metod(__getLastResponseHeaders) web servisine yapılan son isteğin yanıt başlıklarını (header) gösterir.
Bu metod için trace mode ‘a ihtiyaç vardır. htmlentities kullanma amacımız browser ekranında kodların (xml tagları vb) görünmesi içindir.
Çıktısı:
HTTP/1.1 200 OK Date: Sun, 24 Oct 2010 12:51:22 GMT Server: Apache/2.2.14 (Ubuntu) X-Powered-By: PHP/5.3.2-1ubuntu4.5 Content-Length: 916 Vary: Accept-Encoding Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/xml; charset=utf-8
..
Sonuç:
Bir önceki yazımızda da bahsettiğimiz gibi web servisleri biraz kapsamlı bir konudur ve biz ancak bu kadarını anlatabildik. Bundan sonrasında bir çok web servisini entegra edebilir veya web servisi oluşturabilir durumda olacaksınız demektir. Bu bilgilerimizin üzerine kendi geliştirmelerinizle ortaya güzel şeyler çıkacaktır.
Son derece başarılı ve yararlı bir çalışma olmuş. Tebrik ederim.
teşekkurler gayet güzel anlatım
Supersin Teşekürler.
Anlatımınız için çok teşekkürler.. Anlatımlarınız sayesinde bir web servis oluştrdum ve işimi çok büyük ölçüde çözdüm. Mümkünse size bir sorum olucak. SoapClient ile SoapServer a bağlanıp bir fonksiyonla kullanıcı adı ve şifre gönderiyorum. Doğruysa şu fonksiyonu çağır diyorum ama o birsonraki fonksiyon birtürlü çalışmadı..
SoapServer da işlemlerimin bulunduğu sınıfın içine auth die bi private değişken yaptım.Loginde auth=true oluyo ama bi altındaki fonksiyona geçtiğinde bu değer siliniyor. Anladığım kadarıyla $client-> diye çağırdığımızda sınıf hep yeniden başlıyor..
Bu konuyu nasıl çözebilirim?
Merhaba Mehmet Ali bey,
Öncelikle ilginize teşekkür ediyorum. Karşılaştığınız sorun sanırım her istek için yeni bir HTTP isteği yapılmasından kaynaklanıyor. Bu sebeple yapılan istekte oluşturulan nesneye ait private değişken bir sonraki istekte nesnenin yeniden oluşturulmaasından dolayı yok oluyor. Bu yüzdendirki bir çok web servisinde auth token kullanılır.
Önerim, private değişken yerine kullanıcı geçerli bir oturum başlattığında bunu memcache, apc, db vb. yerlerde tutup kendisine autoh token (session id gibi) dönün. Bir sonraki istekte client dan auth token ‘i kontrol edip işlemleri buna göre yapmanız yönünde olacaktır.
Başarılı 😉
Merhaba. Güzel makaleniz için teşekkür ederim.Gerçekten çok açıklayıcı olmuş. Sormak istediğim ise:
değerleri register ederken input parametreleri eğer bir diziden oluşuyorsa addComplexType ile tanımlayıp bunu register icinde nasıl kullanabiliriz?
Örnek
// getUyeSorgu metodunu web servisi icin tanimla
$server->register(‘getUyeSorgu’, // metod adi
// array(‘user’ => ‘xsd:string’,’pass’ => ‘xsd:string’ ), // giris parametreleri
array(‘return’ => ‘tns:UyeBilgisi’), // cikis parametreleri
‘urn:uyeSorgu’, // namespace
‘urn:uyeSorgu#getUyeBilgileri’, // soapaction
‘rpc’, // style
‘encoded’, // use
‘uyenin bilgilerini dondurur’ // dokuman
);
Yukarıdaki şekilde input parametrelerini array seklinde girdiğimde çalışıyor. Bunu registerden once tanimlayıp o arrayin ismi ile nasıl kullanirim?
Aşağıdaki gibi denediğim yöntem çalismiyor.
$server->wsdl->addComplexType(
‘UserPass’, // ozel tip adi
‘complexType’, // tip
‘struct’, // compositor
‘all’, // restrictionBase
”, // elements
array(
// ‘ozellikAdi’ => array(‘name’ => ‘ozellikAdi’,
// ‘type’ => ‘ozellikTipi’,
// ‘minOccurs’ => enazKacDefaOlacak,
// maxOccurs => enazFazlaKacDefaOlabilir)
‘user’ => array(‘name’ => ‘user’, ‘type’ => ‘xsd:string’, ‘minOccurs’ => ‘1’,
‘maxOccurs’ => ‘1’),
‘pass’ => array(‘name’ => ‘pass’, ‘type’ => ‘xsd:string’, ‘minOccurs’ => ‘1’,
‘maxOccurs’ => ‘1’)
// , ‘brand’ => array(‘name’ => ‘brand’, ‘type’ => ‘xsd:string’)
)
);
$server->register(‘getUyeSorgu’, // metod adi
array(‘name’ => ‘tns:UserPass’ ), // giris parametreleri
array(‘return’ => ‘tns:UyeBilgisi’), // cikis parametreleri
‘urn:uyeSorgu’, // namespace
‘urn:uyeSorgu#getUyeBilgileri’, // soapaction
‘rpc’, // style
‘encoded’, // use
‘uyenin bilgilerini dondurur’ // dokuman
);
Çok yararlı 2 yazı olmuş elinize sağlık iyi çalışmalar
merhabalar;
bu bilgileri biz direk php dosyasında giriyoruz ama örneğin bir veritabanından almak istesek nasıl yaparız? örneğin elimizde kitap tablosu var. ve kitapno, kitapisim, şeklinde iki de sütün var kendine kitap no verildiğinde kitap ismini döndürecek web servisini nasıl yazarız?
Çok faydalı bir dökünman olmuş, internette soap ile ilgili açıklayıcı bir döküman yok, elinize sağlık.
“ccgenel_sp” isminde bir prosedür hazırladık. Prosedürden dönen sonuç aşağıdaki gibidir. Prosedüre begindate ve enddate parametreleri gönderilmesi gerekmektedir. Tarih formatı GG.AA.YYYY’dır. (Örn: 30.01.2014)
Prosedüre erişmek için hazırladığımız web servise http://xxxxxxx.com.tr/Service1.svc?wsdl adresinden erişebilir ve getAnyProcByParams methodunu çağırabilirsiniz. procName parametresine ccgenel_sp yazmalısınız.
çalıştığımız bir firmadan talep ettiğimiz veri için web servis hizmeti sunuldu yukardaki bilgiler gönderildi fakat tam olarak bağlantı sağlayamadım. ayrıca ne şekilde tarih sorgulatabileceğimizi anlamadım bu konuda yardımcı olabilirmisiniz. tablo ad soyad olarak örnek verebilirseniz bağlantı konusunda çok memnun olurum
Makaleniz çok yararlı olmuş hocam ellerinize sağlık.
Bir sorum olucak size. Aşağıdaki gibi bir dizim var. Bunları sizin orneginizdeki gibi ayrı ayrı almak istiyorum. print_r($products) ile aşağıdaki sonucu alıyorum.
echo $product->stokKodu;
Sizinki gibi ayrı ayrı almak istediğimde Başka bir yolu varmıdır.
[
{
stokKodu: “ALBAGA “,
oem: “x1”,
urun_marka: “GAYD”,
liste_fiyati: 29.65,
adet: 13,
olusturulma_tarihi: “”,
guncellenme_tarihi: “2012-07-05”,
}
Benzer sistemi https://app1.jandarma.tsk.tr//kbs_tesis/webservis/kbsup.asmx?op=GunlukListeGonder2
buraya yapmaya çalıştım ama nasıl yapacagı konusunda fikrim yok nasıl olabilir?
Tebrikler, Gayet güzel ve açıklayıcı. Anlatım da oldukça başarılı. Ve gerçekten direkt işe yarayan bir paylaşım olmuş.
Gerçekten güzel paylaşımlarınız var. Devamının bozulmadan gelmesi dileğiyle.
Emeğinize sağlık.. Güzel anlatım 🙂