Skip to content

Ekim 28, 2010

PHP İle SOAP Server ‘a Bağlanmak (SOAP Client)

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.

Toplam 13 Yorum Yorum Yaz
  1. Eki 29 2010

    Son derece başarılı ve yararlı bir çalışma olmuş. Tebrik ederim.

    Cevapla
  2. Mehmet Ali
    Kas 8 2010

    teşekkurler gayet güzel anlatım

    Cevapla
  3. Şükrü ÖZLEM
    Oca 26 2012

    Supersin Teşekürler.

    Cevapla
  4. Mehmet Ali Çetin
    Nis 5 2012

    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?

    Cevapla
    • Nis 12 2012

      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.

      Cevapla
  5. Emre
    May 17 2012

    Başarılı ;)

    Cevapla
  6. hasan
    Tem 31 2012

    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
    );

    Cevapla
  7. Fettah KURTULUŞ
    Ağu 6 2012

    Çok yararlı 2 yazı olmuş elinize sağlık iyi çalışmalar

    Cevapla
  8. Can
    Eyl 9 2013

    Çok faydalı bir dökünman olmuş, internette soap ile ilgili açıklayıcı bir döküman yok, elinize sağlık.

    Cevapla

Trackbacks & Pingbacks

  1. PHP ve SOAP ile TC Kimlik Numarası Doğrulama « Göktuğ ÖZTÜRK
  2. webservis kullanımı (ceviz.net)
  3. bu kodları php ile nasıl yazarım (ceviz.net)
  4. PHP ile WS-Security SOAP Servislerine Bağlanmak | Mustafa KIRIMLI

Sizin fikriniz nedir? Lütfen aşağıdaki formu kullanarak yorum yapın.

(gerekli)
(gerekli)