PHP'de bir sabun web hizmetinin pratik bir örneği. PHP Soap wsdl php örneklerinde SOAP istemci-sunucu uygulaması yazma

  • 20.06.2020

PHP kodu yazmaya alışkınım ama nesne yönelimli kodlamayı pek kullanmıyorum. Şimdi (bir istemci olarak) SOAP ile etkileşime geçmem gerekiyor ve sözdizimini doğru yapamıyorum. SoapClient sınıfını kullanarak yeni bir bağlantı kurmamı sağlayan bir WSDL dosyam var. Ancak, doğru aramayı yapamıyorum ve verileri geri alamıyorum. Aşağıdaki (basitleştirilmiş) verileri göndermem gerekiyor:

  • Kişi Kimliği
  • Kişi adı
  • Genel açıklama
  • toplam

WSDL belgesinde iki işlev vardır, ancak yalnızca birine ihtiyacım var (aşağıda "FirstFunction"). Kullanılabilir işlevler ve türler hakkında bilgi almak için çalıştırdığım komut dosyası:

$ client = new SoapClient ("http://example.com/webservices?wsdl"); var_dump ($ client -> __ getFunctions()); var_dump ($ client -> __ getTypes());

Ve işte ürettiği çıktı:

Array (=> "FirstFunction Function1 (FirstFunction $ parametreleri)", => "SecondFunction Function2 (SecondFunction $ parametreleri)",); dizi (=> struct Contact (id id; name name;) => string "string açıklaması" => string "int miktar")

Verilerle FirstFunction'ı çağırmak istediğimi varsayalım:

  • Kişi Kimliği: 100
  • İrtibat Kişisi: John
  • Genel açıklama: Petrol Varil
  • Tutar: 500

Doğru sözdizimi nedir? Her türlü seçeneği denedim ama sabun yapısı oldukça esnek görünüyor, bu yüzden bunu yapmanın pek çok yolu var. Kılavuzdan anlayamadım...

GÜNCELLEME 1: MMK'den denenmiş örnek:

$ client = new SoapClient ("http://example.com/webservices?wsdl"); $ params = dizi ("id" => 100, "name" => "John", "description" => "Petrol Varil", "tutar" => 500,); $ yanıtı = $ istemci -> __ soapCall ("Fonksiyon1", dizi ($ params));

Ancak şu yanıtı alıyorum: Nesnenin "İletişim" özelliği yok. getTypes() çıktısında da görebileceğiniz gibi, Contact adında bir yapı var, bu yüzden bir şekilde parametrelerimin Contact verilerini içerdiğini açıklamam gerektiğini düşünüyorum, ancak soru şu: nasıl?

GÜNCELLEME 2: Bu yapıları da denedim, aynı hata.

$ params = dizi (dizi ("id" => 100, "name" => "John",), "Petrol Varil", 500,);

Birlikte:

$ params = dizi ("İletişim" => dizi ("id" => 100, "isim" => "John",), "açıklama" => "Petrol Varil", "tutar" => 500,);

Her iki durumda da hata: nesnenin "İletişim" özelliği yok

8 cevap

Yapman gereken bu.

Sadece bilmek için, durumunuzu yeniden yaratmaya çalıştım ...

  • Bu örnekte, Function1 adlı bir WebMethod kullanarak bir .NET web hizmeti oluşturdum ve parametreler şunlardır:

Function1 (pin, string açıklaması, int sayısı)

    Sizin durumunuzda olduğu gibi, Contact'ın yalnızca kimlik ve ad için alıcıları ve ayarlayıcıları olan bir fasulye sınıfı vardır.

    Bu .NET web hizmetini aşağıdakilerle yükleyebilirsiniz:

Kod.

Bu tarafta yapmanız gereken şey PHP:

(Test edildi ve çalışıyor)

kimlik = $ kimlik; $ bu-> isim = $ isim; )) / * WSDL'niz ile web servisini başlatın * / $ client = new SoapClient ("http: // localhost: 10139 / Service1.asmx? Wsdl"); / * Kişi Nesnenizi doldurun * / $ kişi = yeni Kişi (100, "John"); / * İstek için parametrelerinizi ayarlayın * / $ params = array ("İletişim" => $ iletişim, "açıklama" => "Petrol Varil", "miktar" => 500,); / * Bu durumda parametrelerinizle web servisi yöntemini çağırın: Function1 * / $ yanıtı = $ client -> __ soapCall ("Function1", dizi ($ params)); / * Web hizmeti yanıtını yazdır * / var_dump ($ yanıtı); ?>

Bunun çalıştığını nasıl anlarım?

  • print_r ($ params) yaparsanız; , web hizmetinizin beklediği gibi bu çıktıyı göreceksiniz:

Dizi ([İletişim] => Temas nesnesi (=> 100 => John) [açıklama] => Petrol varili [miktar] => 500)

  • .NET web hizmeti örneğinde hata ayıkladığımda şunu anladım:

(Gördüğünüz gibi Contact nesnesi null değildir ve ayrıca diğer parametreler, bu isteğinizin PHP tarafından başarıyla tamamlandığı anlamına gelir).

  • .NET web hizmetinden gelen yanıt bekleniyordu ve PHP tarafında gösterildi:

nesne (stdClass) public "Function1Result" => string "Talebinizle ilgili ayrıntılar! id: 100, ad: John, açıklama: Petrol Varil, miktar: 500" (uzunluk = 98)

Umarım yardımcı olur :-)

SOAP servislerini de kullanabilirsiniz:

"İspanya", "ŞehirAdı" => "Alicante"); $ yanıt = $ soapclient-> getWeather ($ params); var_dump ($ yanıt); // Ülkeye Göre Şehirleri Alın $ param = dizi ("ÜlkeAdı" => "İspanya"); $ yanıt = $ soapclient-> getCitiesByCountry ($ param); var_dump ($ yanıt);

Bu gerçek bir hizmet örneğidir ve işe yarar.

Umarım yardımcı olur.

İlk olarak, web hizmetlerini başlatın:

$ client = new SoapClient ("http://example.com/webservices?wsdl");

Ardından parametreleri ayarlayın ve iletin:

$ params = dizi ("arg0" => $ kişi kimliği, "arg1" => $ desc, "arg2" => $ kişi adı); $ yanıtı = $ istemci -> __ soapCall ("yöntem adı", dizi ($ params));

Yöntem adının WSDL'de işlem adı olarak mevcut olduğunu unutmayın, örneğin:

Web servisimin neden sizinle aynı yapıya sahip olduğunu bilmiyorum, ancak parametre için bir sınıfa ihtiyacı yok, sadece bir diziye ihtiyacı var.

Örneğin: - WSDL'm:

5390a7006cee11e0ae3e0800200c9a66 831f8c1ad25e1dc89cf2d8f23d2af ... fa85155f5c67627 VITS-STAELENS Zoeth seni 0.100 10K24 2012-12-31 Gladys Röldan de Moras

Calle General Oraa 26 (4º izda) 28006 Madrid ES
[e-posta korumalı] es

Var_dump ($ client-> getFunctions()); var_dump ($ client-> getTypes());

İşte sonuç:

Dizi 0 => string "OrderConfirmation createOrder (OrderRequest $ createOrder)" (uzunluk = 56) dizi 0 => string "struct OrderRequest (Kimlik tanımlama; Teslimat teslimatı; Koli paketi; Alıcı alıcı; dize referansı;)" (uzunluk = 130) 1 => string "struct Identification (string gönderici; string hash; string yaratıcısı;)" (uzunluk = 75) 2 => string "struct Teslimat (Düğüm kaynağı; Düğüm;)" (uzunluk = 41) 3 => string " struct Node (string country; string node;) "(uzunluk = 46) 4 => string" struct Parcel (dize açıklaması; ondalık ağırlık; dize orderNumber; date orderDate;) "(uzunluk = 93) 5 => dize" struct Alıcı (string ad; dize soyadı; Adres adresi; dize e-postası; dize dili;) "(uzunluk = 106) 6 => dize" struct Adres (dize satır1; dize satır2; dize postaKodu; dize şehir; dize ülke;) "(uzunluk = 99) 7 => string "struct OrderConfirmation (string izlemeNumarası; string referansı;)" (uzunluk = 71) 8 => string "str uct OrderServiceException (dize kodu; OrderServiceException errorInfo; dize mesajı; ) "(uzunluk = 97)

Yani kodumda:

$ client = new SoapClient ("http://packandship-ws.kiala.com/psws/order?wsdl"); $ params = dizi ("referans" => $ orderId, "identification" => dizi ("sender" => param ("kiala", "sender_id"), "hash" => hash ("sha512", $ orderId. param ("kiala", "sender_id"). param ("kiala", "şifre")), "originator" => null,), "delivery" => array ("from" => array ("country" = > "es", "düğüm" => "",), "to" => dizi ("ülke" => "es", "düğüm" => "0299")), "parsel" => dizi ( "description" => "Description", "weight" => 0.200, "orderNumber" => $ orderId, "orderDate" => tarih ("Ymd"), "alıcı" => dizi ("firstName" => " Müşteri Adı "," soyadı "=>" Müşteri Soyadı "," adres "=> dizi (" satır1 "=>" Satır 1 Adresi "," satır2 "=>" Satır 2 Adresi "," postaKodu "=> 28006, "şehir" => "Madrid", "ülke" => "es",), "e-posta" => " [e-posta korumalı]"," dil "=>" es ")); $ sonuç = $ müşteri-> createOrder ($ params); var_dump ($ sonuç);

ama o başarılı!

Bu, "__call" SABUN işlevi için iyi bir örnektir. Ancak, kullanımdan kaldırılmıştır.

Envio Internacional: "; $ vem = $ cliente -> __ call (" CustoEMSInternacional ", dizi ($ int_zona, $ int_peso)); print $ vem; print"

"; ?>

  • öğretici

Herkese merhaba!
Son zamanlarda web servisleri geliştirmeye başladım. Ama bugün konu benimle ilgili değil, XML Web Servisimizi SOAP 1.2 protokolüne dayalı olarak nasıl yazabileceğimizle ilgili.

Umarım konuyu okuduktan sonra kendiniz yapabilirsiniz:

  • bir web uygulamasının kendi sunucu tarafı uygulamanızı yazın;
  • bir web uygulamasının kendi istemci tarafı uygulamanızı yazın;
  • kendi web hizmeti açıklamanızı (WSDL) yazın;
  • sunucuya aynı tür verinin istemci dizileri tarafından gönderilir.
Tahmin edebileceğiniz gibi, tüm sihir PHP ve yerleşik SoapClient ve SoapServer sınıfları kullanılarak yapılacak. SMS gönderme servisi bir tavşan görevi görecektir.

1 Sorun bildirimi

1.1 Sınırlar

Başlangıçta, konunun sonunda elde edeceğimiz sonuçla ilgilenmeyi öneriyorum. Yukarıda da duyurduğumuz gibi sms mesajları göndermek için bir servis yazacağız ya da daha doğrusu SOAP protokolü üzerinden farklı kaynaklardan mesaj alacağız. Ondan sonra sunucuya hangi formda geldiklerini ele alacağız. Sağlayıcıya daha fazla gönderilmeleri için mesajların sıraya konması süreci, ne yazık ki, birçok nedenden dolayı bu yazının kapsamı dışındadır.

1.2 Hangi verileri değiştireceğiz?

Harika, sınırlara karar verdik! Yapılması gereken bir sonraki adım, sunucu ve istemci arasında hangi verileri değiştireceğimize karar vermektir. Bu konuda uzun süre akıllı olmamayı ve ana soruları hemen kendim için cevaplamayı öneriyorum:
  • Bir aboneye SMS mesajı göndermek için sunucuya gönderilmesi gereken minimum veri miktarı nedir?
  • Müşterinin ihtiyaçlarını karşılamak için sunucudan gönderilmesi gereken minimum veri miktarı nedir?
Bir şey bana bunun aşağıdakileri göndermeyi gerektirdiğini söylüyor:
  • cep telefonu numarası da
  • SMS metni.
Prensip olarak, bu iki özellik göndermek için yeterlidir, ancak sabah saat 3'te veya 4'te size doğum günü tebrik içeren bir SMS geldiğinde hemen bir durum hayal ediyorum! Şu anda, beni unutmadıkları için herkese çok minnettar olacağım! Bu nedenle, sunucuya da göndereceğiz ve
  • sms mesajının gönderilme tarihi.
Sunucuya göndermek istediğim bir sonraki şey
  • Mesajın türü.
Bu parametre isteğe bağlıdır, ancak patrona haberlerimizle kaç müşterimizi "mutlu ettiğimizi" hızlı bir şekilde söylememiz ve bu puanla ilgili bazı güzel istatistikler çizmemiz gerektiğinde bizim için çok yararlı olabilir.

Ve yine de bir şey unuttum! Biraz daha düşünecek olursak, bir istemcinin sunucuya aynı anda hem bir sms mesajı hem de birkaç tane gönderebileceğini belirtmekte fayda var. Başka bir deyişle, bir veri paketi birden sonsuz mesaj içerebilir.

Sonuç olarak, bir SMS mesajı göndermek için aşağıdaki verilere ihtiyacımız olduğunu anlıyoruz:

  • Telefon numarası,
  • SMS metni,
  • bir aboneye SMS mesajı gönderme zamanı,
  • mesaj türü.

İlk soruyu cevapladık, şimdi ikinci soruyu cevaplamak gerekiyor. Ve belki de kendime küçük bir hack izni veririm. Bu nedenle, sunucudan yalnızca değeri şu anlama gelen boole verileri göndereceğiz:

  • DOĞRU - paket sunucuya başarıyla ulaştı, kimliği doğrulandı ve sms sağlayıcısına gönderilmek üzere kuyruğa girdi
  • YANLIŞ - diğer tüm durumlarda

Bu, sorun bildiriminin açıklamasını tamamlar! Ve son olarak, en ilginç şeye geçelim - hadi bu SABUN'un ne kadar tuhaf bir canavar olduğunu anlayalım!

2 SABUN nedir?

Genel olarak, başlangıçta SOAP'ın ne olduğu hakkında hiçbir şey yazmayı planlamadım ve kendimi w3.org sitesine gerekli özelliklere sahip bağlantılarla ve Wikipedia bağlantılarıyla sınırlamak istedim. Ama en sonunda bu protokol hakkında kısa bir referans yazmaya karar verdim.

Ve hikayeme, bu veri alışverişi protokolünün, tam tersi REST (Representational State Transfer) olan RPC (Uzaktan Yordam Çağrısı) paradigmasına dayanan bir protokol alt kümesine ait olduğu gerçeğiyle başlayacağım. Bununla ilgili daha fazla bilgiyi Wikipedia'da okuyabilirsiniz, makalelerin bağlantıları konunun en sonunda bulunur. Bu makalelerden şunu anlamamız gerekiyor: “RPC yaklaşımı, çok sayıda yöntemle ve karmaşık bir protokolle az miktarda ağ kaynağı kullanmanıza olanak tanır. REST yaklaşımıyla, yöntemlerin sayısı ve protokolün karmaşıklığı kesinlikle sınırlıdır, bu da çok sayıda bireysel kaynağa yol açabilir. " Yani, bizimle ilgili olarak, bu, sitedeki RPC yaklaşımı durumunda, hizmete her zaman bir giriş (bağlantı) olacağı ve verilerle birlikte aktardığımız gelen verileri işlemek için hangi prosedürün çağrılması gerektiği anlamına gelir, Sitemizdeki REST yaklaşımı ile her biri yalnızca belirli verileri kabul eden ve işleyen birçok girdi (bağlantı) vardır. Okuyan biri bu yaklaşımlardaki farkı nasıl daha kolay açıklayacağını biliyorsa, yorumları yazdığınızdan emin olun!

SOAP hakkında bilmemiz gereken bir sonraki şey, bu protokolün bir aktarım olarak aynı XML'i kullanmasıdır, bu bir yandan çok iyidir, çünkü hemen, bu biçimlendirme diline dayalı teknoloji yığınının tüm gücü cephaneliğimize girer, yani XML-Schema - bir XML belgesinin yapısını tanımlayan bir dil (Wikipedia sayesinde!), gelen verilerin otomatik olarak doğrulanmasına izin verir. istemcilerden sunucu.

Ve artık SOAP'ın uzaktan prosedür çağrılarını uygulamak için kullanılan bir protokol olduğunu ve aktarım olarak XML kullandığını biliyoruz! Wikipedia'daki makaleyi okursanız, oradan herhangi bir uygulama katmanı protokolünde kullanılabileceğini ve yalnızca HTTP ile eşleştirilmediğini de öğrenebilirsiniz (maalesef bu konuda yalnızca HTTP üzerinden SOAP'ı ele alacağız). Ve tüm bunlar hakkında en çok neyi sevdiğimi biliyor musun? Eğer tahmin yoksa, size bir ipucu vereceğim - SABUN! ... Neyse, tahmin çıkmadı mı? ... Wikipedia'daki makaleyi kesinlikle okudunuz mu? ... Genel olarak, size daha fazla işkence etmeyeceğim. Bu nedenle, doğrudan cevaba gideceğim: “SOAP (İngilizce Basit Nesne Erişim Protokolünden - basit protokol nesnelere erişim; 1.2 spesifikasyonuna kadar)". Bu satırla ilgili en dikkat çekici şey italik yazılmış! Tüm bunlardan hangi sonuçları çıkardığınızı bilmiyorum, ancak aşağıdakileri görüyorum - bu protokol "basit" olarak adlandırılamadığından (ve görünüşe göre w3'te bile buna katılıyorum), o zaman sürüm 1.2'den beri deşifre edilmeyi bıraktı. bir şekilde! Ve SABUN, sadece SABUN dönemi olarak tanındı.

Pekala, tamam, özür dilerim, biraz yana kaydı. Daha önce yazdığım gibi, aktarım olarak XML kullanılır ve istemci ile sunucu arasında katlanan paketlere SOAP zarfları denir. Zarfın genel yapısını düşünürsek, size çok tanıdık gelecektir, çünkü HTML sayfasının yapısına benzer. Bir ana bölümü vardır - Zarf bölümleri içeren başlık ve Vücut veya Arıza... V Vücut veriler aktarılır ve zarfın zorunlu bir bölümüdür, ancak başlıkİsteğe bağlı. V başlık yetkilendirme veya web servis prosedürlerinin giriş verileriyle doğrudan ilgili olmayan diğer veriler iletilebilir. Hakkında Arıza herhangi bir hata olması durumunda sunucudan istemciye gelmesi dışında söylenecek özel bir şey yoktur.

SOAP protokolüyle ilgili genel bakış hikayem burada sona eriyor (daha ayrıntılı olarak, zarfların kendileri ve yapıları, istemcimiz ve sunucumuz nihayet onları birbirine nasıl çalıştıracağını öğrendiğinde ele alacağız) ve yeni bir tane başlıyor - SABUN hakkında refakatçi denir WSDL(Web Hizmetleri Açıklama Dili). Evet, evet, çoğumuzu bu protokolde API'mizi alma ve uygulama girişiminden korkutan şey budur. Sonuç olarak, genellikle tekerleğimizi taşıma olarak JSON ile yeniden icat ederiz. Peki WSDL nedir? WSDL, XML (c) Wikipedia diline dayalı olarak web hizmetlerini tanımlamak ve bunlara erişmek için kullanılan bir dildir. Bu tanımdan bu teknolojinin tüm kutsal anlamını anlamıyorsanız, o zaman onu kendi kelimelerimle açıklamaya çalışacağım!

WSDL, müşterilerimizin sunucuyla normal bir şekilde iletişim kurabilmesi için tasarlanmıştır. Bunun için "* .wsdl" uzantılı dosyada aşağıdaki bilgiler anlatılmaktadır:

  • Hangi ad alanları kullanıldı,
  • Hangi veri şemaları kullanıldı,
  • Web servisinin istemcilerden ne tür mesajlar beklediği,
  • Hangi verilerin web servisinin hangi prosedürlerine ait olduğu,
  • Web servisi hangi prosedürleri içerir,
  • Müşterinin web servis prosedürlerini nasıl çağırması gerektiği,
  • Müşterinin aramaları hangi adrese gönderilmelidir.
Gördüğünüz gibi, bu dosya tüm web servisidir. İstemcide WSDL dosyasının adresini belirterek, herhangi bir web hizmeti hakkında her şeyi bileceğiz! Sonuç olarak, web hizmetinin kendisinin nerede olduğu hakkında kesinlikle hiçbir şey bilmemize gerek yoktur. Sadece WSDL dosyasının konumunu bilmeniz gerekiyor! Yakında SABUN'un (c) Rus atasözlerinde anlatıldığı kadar korkunç olmadığını öğreneceğiz.

3 XML-Şemasına Giriş

Artık SOAP'ın ne olduğu, içinde ne olduğu hakkında çok şey biliyoruz ve onu çevreleyen teknoloji yığınına genel bir bakışa sahibiz. Her şeyden önce SOAP, bir istemci ve bir sunucu arasındaki etkileşimin bir yolu olduğundan ve XML bunun için bir aktarım olarak kullanıldığından, bu bölümde verilerin XML şemaları kullanılarak otomatik olarak nasıl doğrulandığını biraz anlayacağız.

Şemanın ana görevi, işleyeceğimiz verilerin yapısını tanımlamaktır. XML şemalarındaki tüm veriler basit(skaler) ve karmaşık(yapılar) türleri. Basit türler, aşağıdaki türleri içerir:

  • hat,
  • sayı,
  • boole değeri,
  • tarih.
İçinde uzantıları olmayan çok basit bir şey. Karmaşık tipler onların zıttıdır. Herkesin aklına gelebilecek karmaşık bir türün en basit örneği nesnelerdir. Örneğin, bir kitap. Kitap özelliklerden oluşur: yazar, Başlık, fiyat, ISBN numarası vesaire. Ve bu özellikler sırayla hem basit türler hem de karmaşık olanlar olabilir. Ve XML şemasının görevi onu tanımlamaktır.

Uzaklara gitmemenizi ve sms mesajımız için bir XML şeması yazmamanızı öneririm! Aşağıda sms mesajının xml açıklaması yer almaktadır:

71239876543 Deneme mesajı 2013-07-20T12: 00:00 12
Karmaşık tip şemamız şöyle görünecek:


Bu girdi şu şekildedir: bir değişkenimiz var " İleti"Tip" İleti"Ve adında karmaşık bir tür var" İleti", Sıralı bir dizi öğeden oluşan" telefon"Tip sicim, « Metin"Tip sicim, « tarih"Tip tarihSaat, « tip"Tip ondalık... Bu türler basittir ve şema açıklamasında zaten tanımlanmıştır. Tebrikler! Az önce ilk XML Şemamızı yazdık!

Bence elementlerin anlamı " eleman" ve " karmaşık tip"Her şey sizin için az çok netleşti, bu yüzden artık onlara odaklanmayacağız ve hemen besteci unsuruna geçeceğiz" sıra". besteci öğesini kullandığımızda " sıra»İçerdiği öğelerin her zaman şemada belirtilen sırada olması gerektiğini ve hepsinin zorunlu olduğunu bildiririz. Ama umutsuzluğa kapılmayın! XML şemalarında iki besteci öğesi daha vardır: “ tercih" ve " herşey". Besteci tercih"İçinde listelenen öğelerden birinin olması gerektiğini ve besteciyi bildirir" herşey"- listelenen öğelerin herhangi bir kombinasyonu.

Hatırladığınız gibi konunun ilk bölümünde bir pakette birden sonsuz sms mesajının iletilebileceği konusunda anlaşmıştık. Bu nedenle, bu tür verilerin XML şemasında nasıl bildirildiğini anlamayı öneriyorum. Paketin genel yapısı şöyle görünebilir:

71239876543 Test mesajı 1 2013-07-20T12: 00:00 12 71239876543 Test mesajı N 2013-07-20T12: 00:00 12
Böyle karmaşık bir türün şeması şöyle görünecektir:


İlk blok, karmaşık tipteki tanıdık bildirimi içerir “ İleti". Fark ettiyseniz, o zaman dahil edilen her basit tipte " İleti", Yeni nitelikler eklendi" minOccurs" ve " maxOccurs". Adından da tahmin edebileceğiniz gibi, ilk ( minOccurs) bu dizinin en az bir eleman tipi içermesi gerektiğini bildirir. telefon», « Metin», « tarih" ve " tip", Sıradaki ( maxOccurs) özniteliği, dizimizde bu tür en fazla bir öğe olduğunu bize bildirir. Sonuç olarak, herhangi bir veri için şemalarımızı yazdığımızda, özelleştirmelerinde en geniş seçenek bize veriliyor!

Diyagramın ikinci bloğu öğeyi bildirir " mesaj listesi"Tip" Mesaj Listesi". Açıktır ki" Mesaj Listesi"En az bir öğe içeren karmaşık bir türdür" İleti”, Ancak bu tür öğelerin maksimum sayısı sınırlı değildir!

4 Kendi WSDL'nizi yazma

WSDL'nin bizim web hizmetimiz olduğunu hatırlıyor musunuz? Umarım hatırlarsın! Biz yazarken, küçük web hizmetimiz üzerinde yüzecek. Bu nedenle, hile yapmamayı öneriyorum.

Genel olarak her şeyin düzgün çalışması için doğru MIME tipine sahip bir WSDL dosyasını istemciye aktarmamız gerekir. Bunu yapmak için web sunucunuzu buna göre yapılandırmanız, yani "* .wsdl" uzantılı dosyalar için MIME türünü aşağıdaki satıra ayarlamanız gerekir:

Uygulama / wsdl + xml
Ancak pratikte genellikle HTTP başlığını gönderirim “ metin / xml»:

Başlık ("İçerik Türü: metin / xml; karakter kümesi = utf-8");
ve her şey harika çalıştı!

Basit web servisimizin oldukça etkileyici bir açıklaması olacağı konusunda sizi hemen uyarmak istiyorum, bu yüzden paniğe kapılmayın, çünkü metnin çoğu zorunludur ve bir kez yazıldığında, bir web hizmetinden diğerine sürekli olarak kopyalayabilirsiniz!

WSDL XML olduğundan, ilk satırda doğrudan onun hakkında yazmanız gerekir. Dosyanın kök öğesi her zaman " olarak adlandırılmalıdır. tanımlar»:


Tipik olarak, WSDL 4-5 ana bloktan oluşur. İlk blok, web hizmetinin tanımı veya başka bir deyişle giriş noktasıdır.


Burada bir servisimiz olduğu yazıyor - " SMS Hizmeti". Temel olarak, WSDL dosyasındaki tüm adları istediğiniz gibi değiştirebilirsiniz. kesinlikle hiçbir rol oynamazlar.

Bundan sonra web servisimizde duyuruyoruz” SMS Hizmeti"Adı verilen bir giriş noktası ("bağlantı noktası") var" SmsServicePort". İstemcilerden sunucuya gelen tüm istekler bu giriş noktasına gönderilir. Ve biz öğesinde belirtiyoruz " adres»Talepleri kabul edecek işleyici dosyasına bir bağlantı.

Bir web servisi tanımladıktan ve onun için bir giriş noktası belirledikten sonra, desteklenen prosedürleri ona bağlamamız gerekiyor:


Bunun için hangi işlemlerin ve hangi formda çağrılacağı listelenir. Onlar. liman için " SmsServicePort"Adın altında bir bağlama tanımlanır" SmsServiceBağlama", Hangi arama türüne sahip" rpc"Ve HTTP, aktarım protokolü (taşıma) olarak kullanılır. Bu yüzden HTTP üzerinden RPC çağrısı yapacağımızı burada belirtmiş olduk. Bundan sonra, hangi prosedürleri açıklıyoruz ( operasyon) web hizmetinde desteklenir. Yalnızca bir prosedürü destekleyeceğiz - " gönderSms". Bu prosedür sayesinde harika mesajlarımız sunucuya gönderilecek! Prosedür duyurulduktan sonra verilerin hangi biçimde iletileceğinin belirtilmesi gerekmektedir. Bu durumda standart SABUN zarfların kullanılacağı belirtilir.

Bundan sonra, prosedürü mesajlara bağlamamız gerekiyor:


Bunu yapmak için, "bağlayıcımızın" türünde olduğunu belirtiyoruz " SmsServicePortType"Ve elementte" bağlantı noktası türü»Aynı tip isim ile prosedürlerin mesajlara bağlanmasını belirtiyoruz. Ve böylece, gelen mesaj (istemciden sunucuya) olarak adlandırılacaktır. sendSmsRequest", Ve giden (sunucudan istemciye)" sendSmsResponse". WSDL'deki tüm isimler gibi, gelen ve giden mesajların isimleri isteğe bağlıdır.

Şimdi mesajların kendilerini tanımlamamız gerekiyor, yani. giren ve çıkan:


Bunu yapmak için öğeleri ekliyoruz " İleti"İsimleri ile" sendSmsRequest" ve " sendSmsResponse" sırasıyla. Onlarda, yapısı veri türüne karşılık gelen girişe bir zarf gelmesi gerektiğini belirtiyoruz " Rica etmek". Bundan sonra sunucu, veri türünü içeren bir zarf döndürür - " Cevap».

Şimdi en küçük şeyi yapmamız gerekiyor - WSDL dosyamıza bu türlerin bir açıklamasını ekleyin! Ve WSDL'nin gelen ve giden verileri nasıl tanımladığını düşünüyorsunuz? Sanırım her şeyi uzun zaman önce anladınız ve bunu XML şemalarının yardımıyla kendinize söylediniz! Ve kesinlikle haklı olacaksın!


Bizi tebrik edebilirsiniz! İlk WSDL'miz yazıldı! Ve bu hedefe ulaşmaya bir adım daha yaklaştık.
Ardından, kendi dağıtık uygulamalarımızı geliştirmemiz için PHP'nin bize neler sağladığına bakacağız.

5 İlk SOAP sunucumuz

PHP'de bir SOAP sunucusu oluşturmak için yerleşik SoapServer sınıfını kullanacağımızı daha önce yazmıştım. Diğer tüm eylemlerin benimkiyle aynı şekilde gerçekleşmesi için PHP'nizi biraz ayarlamanız gerekecek. Daha kesin olmak gerekirse, "php-soap" uzantısının kurulu olduğundan emin olmanız gerekir. Bunu web sunucunuza nasıl koyacağınız en iyi şekilde resmi PHP sitesinde okunur (referans listesine bakın).

Her şey yüklenip yapılandırıldıktan sonra, hostinginizin kök klasöründe bir dosya oluşturmamız gerekecek " smsservice.php"Aşağıdaki içerikle:

setClass ("SoapSmsGateWay"); // Sunucuyu başlatın $ sunucu-> tanıtıcı ();
Umarım "ini_set" fonksiyonu ile çizginin üstünde ne olduğunu açıklamaya gerek yoktur. Çünkü orada sunucudan istemciye hangi HTTP başlıklarını göndereceğimiz belirlenir ve ortam yapılandırılır. "ini_set" doğrultusunda, WSDL dosyasının önbelleğe alınmasını devre dışı bırakırız, böylece dosyadaki değişikliklerimiz anında istemci üzerinde etkili olur.

Şimdi sunucuya geliyoruz! Gördüğünüz gibi, tüm SOAP sunucusu sadece üç satır uzunluğunda! İlk satırda, SoapServer nesnesinin yeni bir örneğini oluşturuyoruz ve bunu, web hizmetinin WSDL açıklamamızın adresini yapıcıya iletiyoruz. Artık kendi kendini açıklayıcı isimle bir dosyada barındırma kök dizininde bulunacağını biliyoruz. smsservice.wsdl.php". İkinci satırda, istemciden gelen zarfın işlenmesi için SOAP sunucusuna hangi sınıfın çekilmesi gerektiğini söylüyor ve zarfı yanıtla birlikte iade ediyoruz. Tahmin edebileceğiniz gibi, tek yöntemimiz bu sınıfta anlatılacak. gönderSms... Üçüncü satırda sunucuyu başlatıyoruz! İşte bu, sunucumuz hazır! Bununla hepimizi tebrik ediyorum!

Şimdi bir WSDL dosyası oluşturmamız gerekiyor. Bunu yapmak için, içeriğini önceki bölümden kopyalayabilir veya özgürlüğü alıp biraz "şablonlayabilirsiniz":

"; ?> / "xmlns: xs =" http://www.w3.org/2001/XMLSchema "xmlns: soap12 =" http://schemas.xmlsoap.org/wsdl/soap12/ "xmlns: http =" http: // schemas.xmlsoap.org/wsdl/http/ "name =" SmsWsdl "xmlns =" ​​​​http://schemas.xmlsoap.org/wsdl/ "> /"> /smsservice.php "/>
Bu aşamada ortaya çıkan sunucu bize tamamen uymalıdır, çünkü ona gelen zarfları kaydedebilir ve ardından gelen verileri sakince analiz edebiliriz. Sunucuda bir şey alabilmemiz için bir istemciye ihtiyacımız var. O halde başlayalım!

6 SABUN istemcisi yolda

Her şeyden önce, istemciyi yazacağımız bir dosya oluşturmamız gerekiyor. Her zamanki gibi, onu ana bilgisayarın kökünde oluşturacağız ve adını “ istemci.php", Ve içeride aşağıdakileri yazıyoruz:

mesajListesi = yeni MessageList(); $ req-> messageList-> mesaj = yeni Mesaj (); $ req-> messageList-> mesaj-> telefon = "79871234567"; $ req-> messageList-> message-> text = "Test mesajı 1"; $ req-> messageList-> mesaj-> tarih = "2013-07-21T15: 00: 00.26"; $ req-> messageList-> mesaj-> type = 15; $ client = new SoapClient ("http:// ($ _SERVER [" HTTP_HOST "]) / smsservice.wsdl.php", dizi ("soap_version" => SOAP_1_2)); var_dump ($ client-> sendSms ($ req));
Nesnelerimizi tanımlayalım. WSDL'yi yazdığımızda, sunucuya giren zarf için üç varlık tanımladı: Rica etmek, Mesaj Listesi ve İleti... Buna göre sınıflar Rica etmek, Mesaj Listesi ve İleti PHP betiğimizdeki bu varlıkların yansımalarıdır.

Nesneleri tanımladıktan sonra bir nesne oluşturmamız gerekiyor ( $ istek) sunucuya göndereceğiz. Ondan sonra bizim için en çok değer verilen iki satır var! SABUN müşterimiz! İster inanın ister inanmayın, ancak bu, istemciden gelen mesajların sunucumuza akmaya başlaması ve sunucumuzun bunları başarıyla alması ve işlemesi için yeterlidir! Bunlardan ilkinde, SoapClient sınıfının bir örneğini oluşturup WSDL dosyasının bulunduğu yerin adresini yapıcısına iletiyoruz ve SOAP sürüm 1.2 kullanarak çalışacağımızı parametrelerde açıkça belirtiyoruz. Bir sonraki satırda, yöntemi çağırıyoruz gönderSms nesne $ müşteri ve sonucu hemen tarayıcıda görüntüleyin.
Hadi çalıştıralım ve sonunda elimizde ne olduğunu görelim!

Aşağıdaki nesne sunucudan bana döndürüldü:

Nesne (stdClass) genel "durum" => boolean true
Ve bu harika, çünkü Artık sunucumuzun çalıştığından ve sadece çalıştığından değil, aynı zamanda istemciye bazı değerleri de döndürebildiğinden eminiz!

Şimdi sunucu tarafında ihtiyatlı bir şekilde tuttuğumuz loga bir göz atalım! İlk bölümde sunucuya gelen ham verileri görüyoruz:

79871234567 Test mesajı 1 2013-07-21T15: 00: 00.26 15
Bu zarf. Şimdi neye benzediğini biliyorsun! Ancak her zaman hayran olmamız pek ilginç olmayacak, bu yüzden nesneyi günlük dosyasından seri hale getirelim ve her şeyin yolunda olup olmadığına bakalım:

Object (stdClass) public "messageList" => object (stdClass) public "message" => object (stdClass) public "phone" => string "79871234567" (uzunluk = 11) public "text" => string "Test mesajı 1 "(uzunluk = 37) genel" tarih "=> dize" 2013-07-21T15: 00: 00.26 "(uzunluk = 22) genel" tür "=> dize" 15 "(uzunluk = 2)
Gördüğünüz gibi, nesne doğru bir şekilde seri durumdan çıkarıldı, bu da hepimizi tebrik etmek istiyorum! Sonra, daha ilginç bir şey bizi bekliyor! Yani - istemci tarafından sunucuya bir sms mesajı değil, bir sürü (daha doğrusu üç) göndereceğiz!

7 Karmaşık nesneler gönderme

Bir pakette bir sürü mesajı sunucuya nasıl aktarabileceğimizi düşünelim mi? Muhtemelen en kolay yol, diziyi messageList öğesi içinde düzenlemek olacaktır! Bunu yapalım:

// sunucuya gönderilecek bir nesne oluşturun $ req = new Request(); $ req-> messageList = yeni MessageList(); $ msg1 = yeni Mesaj (); $ msg1-> telefon = "79871234567"; $ msg1-> text = "Test Mesajı 1"; $ msg1-> tarih = "2013-07-21T15: 00: 00.26"; $ msg1-> tip = 15; $ msg2 = yeni Mesaj (); $ msg2-> telefon = "79871234567"; $ msg2-> text = "Test Mesajı 2"; $ msg2-> tarih = "2014-08-22T16: 01: 10"; $ msg2-> tip = 16; $ msg3 = yeni Mesaj (); $ msg3-> telefon = "79871234567"; $ msg3-> text = "Test Mesajı 3"; $ msg3-> tarih = "2014-08-22T16: 01: 10"; $ msg3-> tip = 17; $ req-> messageList-> mesaj = $ msg1; $ req-> messageList-> mesaj = $ msg2; $ req-> messageList-> mesaj = $ msg3;
Günlüklerimiz, aşağıdaki paketin bir istemciden geldiğini gösteriyor:

79871234567 Test mesajı 1 2013-07-21T15: 00: 00.26 15 79871234567 Test mesajı 2 2014-08-22T16: 01: 10 16 79871234567 Test mesajı 3 2014-08-22T16: 01: 10 17
Ne saçmalık diyorsunuz? Ve bir anlamda haklı olacaksın, çünkü istemciden hangi nesnenin ayrıldığını öğrendik, sonra kesinlikle aynı biçimde bir zarf şeklinde sunucumuza geldi. Ancak, sms mesajları ihtiyaç duyduğumuz şekilde XML'e serileştirilmedi - öğelere sarılmaları gerekiyordu İleti, değil yapı... Şimdi böyle bir nesnenin yönteme hangi formda geldiğini görelim gönderSms:

Object (stdClass) public "messageList" => object (stdClass) public "message" => object (stdClass) public "Struct" => dizi (size = 3) 0 => nesne (stdClass) public "phone" => string "79871234567" (uzunluk = 11) genel "metin" => dize "Test mesajı 1" (uzunluk = 37) genel "tarih" => dize "2013-07-21T15: 00: 00.26" (uzunluk = 22) genel " type "=> string" 15 "(uzunluk = 2) 1 => nesne (stdClass) public" phone "=> string" 79871234567 "(uzunluk = 11) public" text "=> string" Test mesajı 2 "(uzunluk = 37) public "date" => string "2014-08-22T16: 01: 10" (uzunluk = 19) public "type" => string "16" (uzunluk = 2) 2 => nesne (stdClass) public "phone "=> dize" 79871234567 "(uzunluk = 11) genel" metin "=> dize" Test mesajı 3 "(uzunluk = 37) genel" tarih "=> dize" 2014-08-22T16: 01: 10 "(uzunluk = 19) public "type" => string "17" (uzunluk = 2)
Bu bilgi bize ne veriyor? Sadece seçtiğimiz yol doğru değil ve "Sunucuda doğru veri yapısını nasıl elde edebiliriz?" sorusuna cevap alamadık. Ama umutsuzluğa kapılmamanızı ve dizimizi türe çevirmeyi denemenizi öneririm. bir obje:

$ req-> messageList-> mesaj = (nesne) $ req-> messageList-> mesaj;
Bu durumda, başka bir zarf alacağız:

79871234567 Test mesajı 1 2013-07-21T15: 00: 00.26 15 79871234567 Test mesajı 2 2014-08-22T16: 01: 10 16 79871234567 Test mesajı 3 2014-08-22T16: 01: 10 17
yöntem geldi gönderSms nesne aşağıdaki yapıya sahiptir:

Object (stdClass) public "messageList" => object (stdClass) public "message" => object (stdClass) public "BOGUS" => dizi (size = 3) 0 => nesne (stdClass) public "phone" => string "79871234567" (uzunluk = 11) genel "metin" => dize "Test mesajı 1" (uzunluk = 37) genel "tarih" => dize "2013-07-21T15: 00: 00.26" (uzunluk = 22) genel " type "=> string" 15 "(uzunluk = 2) 1 => nesne (stdClass) public" phone "=> string" 79871234567 "(uzunluk = 11) public" text "=> string" Test mesajı 2 "(uzunluk = 37) public "date" => string "2014-08-22T16: 01: 10" (uzunluk = 19) public "type" => string "16" (uzunluk = 2) 2 => nesne (stdClass) public "phone "=> dize" 79871234567 "(uzunluk = 11) genel" metin "=> dize" Test mesajı 3 "(uzunluk = 37) genel" tarih "=> dize" 2014-08-22T16: 01: 10 "(uzunluk = 19) public "type" => string "17" (uzunluk = 2)
Bana gelince, o zaman “terimlerin yerlerinin değişmesinden toplam değişmez” (c). Ne SAHTE, ne yapı- hedefe henüz bizim tarafımızdan ulaşılmadı! Ve bunu başarmak için, bu anlaşılmaz isimler yerine anadilimizin görüntülendiğinden emin olmalıyız. İleti... Ancak bunun nasıl başarılacağını yazar henüz bilmiyor. Bu nedenle yapabileceğimiz tek şey fazladan konteynırdan kurtulmak. Başka bir deyişle, şimdi öyle yapacağız ki yerine İleti NS SAHTE! Bunu yapmak için nesneyi aşağıdaki gibi değiştirelim:

// sunucuya gönderilecek bir nesne oluşturun $ req = new Request(); $ msg1 = yeni Mesaj (); $ msg1-> telefon = "79871234567"; $ msg1-> text = "Test Mesajı 1"; $ msg1-> tarih = "2013-07-21T15: 00: 00.26"; $ msg1-> tip = 15; $ msg2 = yeni Mesaj (); $ msg2-> telefon = "79871234567"; $ msg2-> text = "Test Mesajı 2"; $ msg2-> tarih = "2014-08-22T16: 01: 10"; $ msg2-> tip = 16; $ msg3 = yeni Mesaj (); $ msg3-> telefon = "79871234567"; $ msg3-> text = "Test Mesajı 3"; $ msg3-> tarih = "2014-08-22T16: 01: 10"; $ msg3-> tip = 17; $ istek-> mesajListesi = $ msg1; $ istek-> mesajListesi = $ msg2; $ istek-> mesajListesi = $ msg3; $ req-> messageList = (nesne) $ req-> messageList;
Ya şanslıysak ve şemadan doğru isim çekilecekse? Bunu yapmak için, alınan zarfa bakalım:

79871234567 Test mesajı 1 2013-07-21T15: 00: 00.26 15 79871234567 Test mesajı 2 2014-08-22T16: 01: 10 16 79871234567 Test mesajı 3 2014-08-22T16: 01: 10 17
Evet, mucize gerçekleşmedi! SAHTE- kazanmayacağız! İçeri gel gönderSms bu durumda nesne şöyle görünecektir:

Nesne (stdClass) public "messageList" => nesne (stdClass) public "BOGUS" => dizi (boyut = 3) 0 => nesne (stdClass) public "phone" => string "79871234567" (uzunluk = 11) public " metin "=> dize" Test mesajı 1 "(uzunluk = 37) genel" tarih "=> dize" 2013-07-21T15: 00: 00.26 "(uzunluk = 22) genel" tür "=> dize" 15 "(uzunluk) = 2) 1 => nesne (stdClass) public "phone" => string "79871234567" (uzunluk = 11) public "text" => string "Test mesajı 2" (uzunluk = 37) public "date" => string " 2014-08-22T16: 01: 10 "(uzunluk = 19) genel" tür "=> dize" 16 "(uzunluk = 2) 2 => nesne (stdSınıf) genel" telefon "=> dize" 79871234567 "(uzunluk = 11) public "text" => string "Test mesajı 3" (uzunluk = 37) public "date" => string "2014-08-22T16: 01: 10" (uzunluk = 19) public "type" => string " 17"(uzunluk = 2)
Dedikleri gibi - "Neredeyse"! Bu (biraz üzücü) notta, yavaş yavaş yuvarlamayı ve kendim için bazı sonuçlar çıkarmayı öneriyorum.

8 Sonuç

Sonunda buraya geldik! Şimdi neler yapabileceğinizi tanımlayalım:
  • web hizmetiniz için gerekli WSDL dosyasını yazabilirsiniz;
  • SOAP protokolünü kullanarak sunucu ile iletişim kurabilen herhangi bir sorun yaşamadan kendi istemcinizi yazabilirsiniz;
  • SABUN üzerinden dış dünya ile iletişim kuran kendi sunucunuzu yazabilirsiniz;
  • istemcinizden sunucuya aynı türde nesne dizileri gönderebilirsiniz (bazı kısıtlamalarla).
Ayrıca, küçük araştırmamız sırasında kendimiz için bazı keşifler yaptık:
  • yerel SoapClient sınıfı, XML'de aynı türdeki veri yapılarını düzgün şekilde serileştiremez;
  • bir diziyi XML'e serileştirirken, adında fazladan bir öğe oluşturur. yapı;
  • bir nesneyi XML'e serileştirirken, adında fazladan bir öğe oluşturur. SAHTE;
  • SAHTE daha az kötülük yapı zarfın daha kompakt olması nedeniyle (zarfın XML başlığına fazladan ad alanı eklenmez);
  • ne yazık ki, SoapServer sınıfı, XML şemamızla zarf verilerini otomatik olarak doğrulamaz (belki diğer sunucular doğrulamaz).

Herkese merhaba!
Son zamanlarda web servisleri geliştirmeye başladım. Ama bugün konu benimle ilgili değil, XML Web Servisimizi SOAP 1.2 protokolüne dayalı olarak nasıl yazabileceğimizle ilgili.

Umarım konuyu okuduktan sonra kendiniz yapabilirsiniz:

  • bir web uygulamasının kendi sunucu tarafı uygulamanızı yazın;
  • bir web uygulamasının kendi istemci tarafı uygulamanızı yazın;
  • kendi web hizmeti açıklamanızı (WSDL) yazın;
  • sunucuya aynı tür verinin istemci dizileri tarafından gönderilir.

Tahmin edebileceğiniz gibi, tüm sihir PHP ve yerleşik SoapClient ve SoapServer sınıfları kullanılarak yapılacak. SMS gönderme servisi bir tavşan görevi görecektir.

1 Sorun bildirimi

1.1 Sınırlar

Başlangıçta, konunun sonunda elde edeceğimiz sonuçla ilgilenmeyi öneriyorum. Yukarıda da duyurduğumuz gibi sms mesajları göndermek için bir servis yazacağız ya da daha doğrusu SOAP protokolü üzerinden farklı kaynaklardan mesaj alacağız. Ondan sonra sunucuya hangi formda geldiklerini ele alacağız. Ne yazık ki, daha sonraki sağlayıcıları için mesajları sıraya koyma süreci, birçok nedenden dolayı bu yazının kapsamı dışındadır.

1.2 Hangi verileri değiştireceğiz?

Harika, sınırlara karar verdik! Yapılması gereken bir sonraki adım, sunucu ve istemci arasında hangi verileri değiştireceğimize karar vermektir. Bu konuda uzun süre akıllı olmamayı ve ana soruları hemen kendim için cevaplamayı öneriyorum:

  • Bir aboneye SMS mesajı göndermek için sunucuya gönderilmesi gereken minimum veri miktarı nedir?
  • Müşterinin ihtiyaçlarını karşılamak için sunucudan gönderilmesi gereken minimum veri miktarı nedir?

Bir şey bana bunun aşağıdakileri göndermeyi gerektirdiğini söylüyor:

  • cep telefonu numarası da
  • SMS metni.

Prensip olarak, bu iki özellik göndermek için yeterlidir, ancak sabah saat 3'te veya 4'te size doğum günü tebrik içeren bir SMS geldiğinde hemen bir durum hayal ediyorum! Şu anda, beni unutmadıkları için herkese çok minnettar olacağım! Bu nedenle, sunucuya da göndereceğiz ve

  • sms mesajının gönderilme tarihi.

Sunucuya göndermek istediğim bir sonraki şey

  • Mesajın türü.

Bu parametre isteğe bağlıdır, ancak patrona haberlerimizle kaç müşterimizi "mutlu ettiğimizi" hızlı bir şekilde söylememiz ve bu puanla ilgili bazı güzel istatistikler çizmemiz gerektiğinde bizim için çok yararlı olabilir.

Ve yine de bir şey unuttum! Biraz daha düşünecek olursak, bir istemcinin sunucuya aynı anda hem bir sms mesajı hem de birkaç tane gönderebileceğini belirtmekte fayda var. Başka bir deyişle, bir veri paketi birden sonsuz mesaj içerebilir.

Sonuç olarak, bir SMS mesajı göndermek için aşağıdaki verilere ihtiyacımız olduğunu anlıyoruz:

  • Telefon numarası,
  • SMS metni,
  • bir aboneye SMS mesajı gönderme zamanı,
  • mesaj türü.

İlk soruyu cevapladık, şimdi ikinci soruyu cevaplamak gerekiyor. Ve belki de kendime küçük bir hack izni veririm. Bu nedenle, sunucudan yalnızca değeri şu anlama gelen boole verileri göndereceğiz:

  • DOĞRU - paket sunucuya başarıyla ulaştı, kimliği doğrulandı ve sms sağlayıcısına gönderilmek üzere kuyruğa girdi
  • YANLIŞ - diğer tüm durumlarda

Bu, sorun bildiriminin açıklamasını tamamlar! Ve son olarak, en ilginç şeye geçelim - hadi bu SABUN'un ne kadar tuhaf bir canavar olduğunu anlayalım!

2 SABUN nedir?

Genel olarak, başlangıçta SOAP'ın ne olduğu hakkında hiçbir şey yazmayı planlamadım ve kendimi w3.org sitesine gerekli özelliklere sahip bağlantılarla ve Wikipedia bağlantılarıyla sınırlamak istedim. Ama en sonunda bu protokol hakkında kısa bir referans yazmaya karar verdim.

Ve hikayeme, bu veri alışverişi protokolünün, tam tersi REST (Representational State Transfer) olan RPC (Uzaktan Yordam Çağrısı) paradigmasına dayanan bir protokol alt kümesine ait olduğu gerçeğiyle başlayacağım. Bununla ilgili daha fazla bilgiyi Wikipedia'da okuyabilirsiniz, makalelerin bağlantıları konunun en sonunda bulunur. Bu makalelerden şunu anlamamız gerekiyor: “RPC yaklaşımı, çok sayıda yöntemle ve karmaşık bir protokolle az miktarda ağ kaynağı kullanmanıza olanak tanır. REST yaklaşımıyla, yöntemlerin sayısı ve protokolün karmaşıklığı kesinlikle sınırlıdır, bu da çok sayıda bireysel kaynağa yol açabilir. " Yani, bizimle ilgili olarak, bu, RPC yaklaşımı durumunda, sitedeki hizmete her zaman bir giriş (bağlantı) olacağı ve verilerle birlikte ilettiğimiz gelen verileri işlemek için hangi prosedürün çağrılması gerektiği anlamına gelir. , REST yaklaşımı ile sitemizde her biri yalnızca belirli verileri kabul eden ve işleyen birçok girdi (bağlantı) bulunur. Okuyan biri bu yaklaşımlardaki farkı nasıl daha kolay açıklayacağını biliyorsa, yorumları yazdığınızdan emin olun!

SOAP hakkında bilmemiz gereken bir sonraki şey, bu protokolün bir aktarım olarak aynı XML'i kullanmasıdır, bu bir yandan çok iyidir, çünkü hemen, bu biçimlendirme diline dayalı teknoloji yığınının tüm gücü cephaneliğimize girer, yani XML-Schema - bir XML belgesinin yapısını tanımlayan bir dil (Wikipedia sayesinde!), gelen verilerin otomatik olarak doğrulanmasına izin verir. istemcilerden sunucu.

Ve artık SOAP'ın uzaktan prosedür çağrılarını uygulamak için kullanılan bir protokol olduğunu ve aktarım olarak XML kullandığını biliyoruz! Wikipedia'daki makaleyi okursanız, oradan herhangi bir uygulama katmanı protokolünde kullanılabileceğini ve yalnızca HTTP ile eşleştirilmediğini de öğrenebilirsiniz (maalesef bu konuda yalnızca HTTP üzerinden SOAP'ı ele alacağız). Ve tüm bunlar hakkında en çok neyi sevdiğimi biliyor musun? Eğer tahmin yoksa, size bir ipucu vereceğim - SABUN! ... Neyse, tahmin çıkmadı mı? ... Wikipedia'daki makaleyi kesinlikle okudunuz mu? ... Genel olarak, size daha fazla işkence etmeyeceğim. Bu nedenle, doğrudan cevaba gideceğim: “SOAP (İngilizce Basit Nesne Erişim Protokolünden - basit protokol nesnelere erişim; 1.2 spesifikasyonuna kadar)". Bu satırla ilgili en dikkat çekici şey italik yazılmış! Tüm bunlardan hangi sonuçları çıkardığınızı bilmiyorum, ancak aşağıdakileri görüyorum - bu protokol "basit" olarak adlandırılamadığından (ve görünüşe göre w3'te bile buna katılıyorum), o zaman sürüm 1.2'den beri deşifre edilmeyi bıraktı. bir şekilde! Ve SABUN, sadece SABUN dönemi olarak tanındı.

Peki tamam pardon biraz kenara çekmişler. Daha önce yazdığım gibi, aktarım olarak XML kullanılır ve istemci ile sunucu arasında katlanan paketlere SOAP zarfları denir. Zarfın genel yapısını düşünürsek, size çok tanıdık gelecektir, çünkü bir HTML sayfasının işaretlemesine benzer. Bir ana bölümü vardır - Zarf bölümleri içeren başlık ve Vücut veya Arıza... V Vücut veriler aktarılır ve zarfın zorunlu bir bölümüdür, ancak başlıkİsteğe bağlı. V başlık yetkilendirme veya web servis prosedürlerinin giriş verileriyle doğrudan ilgili olmayan diğer veriler iletilebilir. Hakkında Arıza herhangi bir hata olması durumunda sunucudan istemciye gelmesi dışında söylenecek özel bir şey yoktur.

SOAP protokolüyle ilgili genel bakış hikayem burada sona eriyor (daha ayrıntılı olarak, zarfların kendileri ve yapıları, istemcimiz ve sunucumuz nihayet onları birbirine nasıl çalıştıracağını öğrendiğinde ele alacağız) ve yeni bir tane başlıyor - SABUN hakkında refakatçi denir WSDL(Web Hizmetleri Açıklama Dili). Evet, evet, çoğumuzu bu protokolde API'mizi alma ve uygulama girişiminden korkutan şey budur. Sonuç olarak, genellikle tekerleğimizi taşıma olarak JSON ile yeniden icat ederiz. Peki WSDL nedir? WSDL, XML (c) Wikipedia diline dayalı olarak web hizmetlerini tanımlamak ve bunlara erişmek için kullanılan bir dildir. Bu tanımdan bu teknolojinin tüm kutsal anlamını anlamıyorsanız, o zaman onu kendi kelimelerimle açıklamaya çalışacağım!

WSDL, müşterilerimizin sunucuyla normal bir şekilde iletişim kurabilmesi için tasarlanmıştır. Bunun için "* .wsdl" uzantılı dosyada aşağıdaki bilgiler anlatılmaktadır:

  • Hangi ad alanları kullanıldı,
  • Hangi veri şemaları kullanıldı,
  • Web servisinin istemcilerden ne tür mesajlar beklediği,
  • Hangi verilerin web servisinin hangi prosedürlerine ait olduğu,
  • Web servisi hangi prosedürleri içerir,
  • Müşterinin web servis prosedürlerini nasıl çağırması gerektiği,
  • Müşterinin aramaları hangi adrese gönderilmelidir.

Gördüğünüz gibi, bu dosya tüm web servisidir. İstemcide WSDL dosyasının adresini belirterek, herhangi bir web hizmeti hakkında her şeyi bileceğiz! Sonuç olarak, web hizmetinin kendisinin nerede olduğu hakkında kesinlikle hiçbir şey bilmemize gerek yoktur. Sadece WSDL dosyasının konumunu bilmeniz gerekiyor! Yakında SABUN'un (c) Rus atasözlerinde anlatıldığı kadar korkunç olmadığını öğreneceğiz.

3 XML-Şemasına Giriş

Artık SOAP'ın ne olduğu, içinde ne olduğu hakkında çok şey biliyoruz ve onu çevreleyen teknoloji yığınına genel bir bakışa sahibiz. Her şeyden önce SOAP, bir istemci ve bir sunucu arasındaki etkileşimin bir yolu olduğundan ve XML bunun için bir aktarım olarak kullanıldığından, bu bölümde verilerin XML şemaları kullanılarak otomatik olarak nasıl doğrulandığını biraz anlayacağız.

Şemanın ana görevi, işleyeceğimiz verilerin yapısını tanımlamaktır. XML şemalarındaki tüm veriler basit(skaler) ve karmaşık(yapılar) türleri. Basit türler, aşağıdaki türleri içerir:

  • hat,
  • sayı,
  • boole değeri,
  • tarih.

İçinde uzantıları olmayan çok basit bir şey. Karmaşık tipler onların zıttıdır. Herkesin aklına gelebilecek karmaşık bir türün en basit örneği nesnelerdir. Örneğin, bir kitap. Kitap özelliklerden oluşur: yazar, Başlık, fiyat, ISBN numarası vesaire. Ve bu özellikler sırayla hem basit türler hem de karmaşık olanlar olabilir. Ve XML şemasının görevi onu tanımlamaktır.

Uzaklara gitmemenizi ve sms mesajımız için bir XML şeması yazmamanızı öneririm! Aşağıda sms mesajının xml açıklaması yer almaktadır:

71239876543 Deneme mesajı 2013-07-20T12: 00:00 12

Karmaşık tip şemamız şöyle görünecek:

Bu girdi şu şekildedir: bir değişkenimiz var " İleti"Tip" İleti"Ve adında karmaşık bir tür var" İleti", Sıralı bir dizi öğeden oluşan" telefon"Tip sicim, « Metin"Tip sicim, « tarih"Tip tarihSaat, « tip"Tip ondalık... Bu türler basittir ve şema açıklamasında zaten tanımlanmıştır. Tebrikler! Az önce ilk XML Şemamızı yazdık!

Bence elementlerin anlamı " eleman" ve " karmaşık tip"Her şey sizin için az çok netleşti, bu yüzden artık onlara odaklanmayacağız ve hemen besteci unsuruna geçeceğiz" sıra". besteci öğesini kullandığımızda " sıra»İçerdiği öğelerin her zaman şemada belirtilen sırada olması gerektiğini ve hepsinin zorunlu olduğunu bildiririz. Ama umutsuzluğa kapılmayın! XML şemalarında iki besteci öğesi daha vardır: “ tercih" ve " herşey". Besteci tercih"İçinde listelenen öğelerden birinin olması gerektiğini ve besteciyi bildirir" herşey"- listelenen öğelerin herhangi bir kombinasyonu.

Hatırladığınız gibi konunun ilk bölümünde bir pakette birden sonsuz sms mesajının iletilebileceği konusunda anlaşmıştık. Bu nedenle, bu tür verilerin XML şemasında nasıl bildirildiğini anlamayı öneriyorum. Paketin genel yapısı şöyle görünebilir:

71239876543 Test mesajı 1 2013-07-20T12: 00:00 12 71239876543 Test mesajı N 2013-07-20T12: 00:00 12

Böyle karmaşık bir türün şeması şöyle görünecektir:

İlk blok, karmaşık tipteki tanıdık bildirimi içerir “ İleti". Fark ettiyseniz, o zaman dahil edilen her basit tipte " İleti", Yeni nitelikler eklendi" minOccurs" ve " maxOccurs". Adından da tahmin edebileceğiniz gibi, ilk ( minOccurs) bu dizinin en az bir eleman tipi içermesi gerektiğini bildirir. telefon», « Metin», « tarih" ve " tip", Sıradaki ( maxOccurs) özniteliği, dizimizde bu tür en fazla bir öğe olduğunu bize bildirir. Sonuç olarak, herhangi bir veri için şemalarımızı yazdığımızda, özelleştirmelerinde en geniş seçenek bize veriliyor!

Diyagramın ikinci bloğu öğeyi bildirir " mesaj listesi"Tip" Mesaj Listesi". Açıktır ki" Mesaj Listesi"En az bir öğe içeren karmaşık bir türdür" İleti”, Ancak bu tür öğelerin maksimum sayısı sınırlı değildir!

4 Kendi WSDL'nizi yazma

WSDL'nin bizim web hizmetimiz olduğunu hatırlıyor musunuz? Umarım hatırlarsın! Biz yazarken, küçük web hizmetimiz üzerinde yüzecek. Bu nedenle, hile yapmamayı öneriyorum.

Genel olarak her şeyin düzgün çalışması için doğru MIME tipine sahip bir WSDL dosyasını istemciye aktarmamız gerekir. Bunu yapmak için web sunucunuzu buna göre yapılandırmanız, yani "* .wsdl" uzantılı dosyalar için MIME türünü aşağıdaki satıra ayarlamanız gerekir:

Uygulama / wsdl + xml

Ancak pratikte genellikle HTTP başlığını gönderirim “ metin / xml»:

Başlık ("İçerik Türü: metin / xml; karakter kümesi = utf-8");

ve her şey harika çalıştı!

Basit web servisimizin oldukça etkileyici bir açıklaması olacağı konusunda sizi hemen uyarmak istiyorum, bu yüzden paniğe kapılmayın, çünkü metnin çoğu zorunludur ve bir kez yazıldığında, bir web hizmetinden diğerine sürekli olarak kopyalayabilirsiniz!

WSDL XML olduğundan, ilk satırda doğrudan onun hakkında yazmanız gerekir. Dosyanın kök öğesi her zaman " olarak adlandırılmalıdır. tanımlar»:

Tipik olarak, WSDL 4-5 ana bloktan oluşur. İlk blok, web hizmetinin tanımı veya başka bir deyişle giriş noktasıdır.

Burada bir servisimiz olduğu yazıyor - " SMS Hizmeti". Temel olarak, WSDL dosyasındaki tüm adları istediğiniz gibi değiştirebilirsiniz. kesinlikle hiçbir rol oynamazlar.

Bundan sonra web servisimizde duyuruyoruz” SMS Hizmeti"Adı verilen bir giriş noktası ("bağlantı noktası") var" SmsServicePort". İstemcilerden sunucuya gelen tüm istekler bu giriş noktasına gönderilir. Ve biz öğesinde belirtiyoruz " adres»Talepleri kabul edecek işleyici dosyasına bir bağlantı.

Bir web servisi tanımladıktan ve onun için bir giriş noktası belirledikten sonra, desteklenen prosedürleri ona bağlamamız gerekiyor:

Bunun için hangi işlemlerin ve hangi formda çağrılacağı listelenir. Onlar. liman için " SmsServicePort"Adın altında bir bağlama tanımlanır" SmsServiceBağlama", Hangi arama türüne sahip" rpc"Ve HTTP, aktarım protokolü (taşıma) olarak kullanılır. Bu yüzden HTTP üzerinden RPC çağrısı yapacağımızı burada belirtmiş olduk. Bundan sonra, hangi prosedürleri açıklıyoruz ( operasyon) web hizmetinde desteklenir. Yalnızca bir prosedürü destekleyeceğiz - " gönderSms". Bu prosedür sayesinde harika mesajlarımız sunucuya gönderilecek! Prosedür duyurulduktan sonra verilerin hangi biçimde iletileceğinin belirtilmesi gerekmektedir. Bu durumda standart SABUN zarfların kullanılacağı belirtilir.

Bundan sonra, prosedürü mesajlara bağlamamız gerekiyor:

Bunu yapmak için, "bağlayıcımızın" türünde olduğunu belirtiyoruz " SmsServicePortType"Ve elementte" bağlantı noktası türü»Aynı tip isim ile prosedürlerin mesajlara bağlanmasını belirtiyoruz. Ve böylece, gelen mesaj (istemciden sunucuya) olarak adlandırılacaktır. sendSmsRequest", Ve giden (sunucudan istemciye)" sendSmsResponse". WSDL'deki tüm isimler gibi, gelen ve giden mesajların isimleri isteğe bağlıdır.

Şimdi mesajların kendilerini tanımlamamız gerekiyor, yani. giren ve çıkan:

Bunu yapmak için öğeleri ekliyoruz " İleti"İsimleri ile" sendSmsRequest" ve " sendSmsResponse" sırasıyla. Onlarda, yapısı veri türüne karşılık gelen girişe bir zarf gelmesi gerektiğini belirtiyoruz " Rica etmek". Bundan sonra sunucu, veri türünü içeren bir zarf döndürür - " Cevap».

Şimdi en küçük şeyi yapmamız gerekiyor - WSDL dosyamıza bu türlerin bir açıklamasını ekleyin! Ve WSDL'nin gelen ve giden verileri nasıl tanımladığını düşünüyorsunuz? Sanırım her şeyi uzun zaman önce anladınız ve bunu XML şemalarının yardımıyla kendinize söylediniz! Ve kesinlikle haklı olacaksın!

Bizi tebrik edebilirsiniz! İlk WSDL'miz yazıldı! Ve bu hedefe ulaşmaya bir adım daha yaklaştık.
Ardından, kendi dağıtık uygulamalarımızı geliştirmemiz için PHP'nin bize neler sağladığına bakacağız.

5 İlk SOAP sunucumuz

PHP'de bir SOAP sunucusu oluşturmak için yerleşik SoapServer sınıfını kullanacağımızı daha önce yazmıştım. Diğer tüm eylemlerin benimkiyle aynı şekilde gerçekleşmesi için PHP'nizi biraz ayarlamanız gerekecek. Daha kesin olmak gerekirse, "php-soap" uzantısının kurulu olduğundan emin olmanız gerekir. Bunu web sunucunuza nasıl koyacağınız en iyi şekilde resmi PHP sitesinde okunur (referans listesine bakın).

Her şey yüklenip yapılandırıldıktan sonra, hostinginizin kök klasöründe bir dosya oluşturmamız gerekecek " smsservice.php"Aşağıdaki içerikle:

setClass ("SoapSmsGateWay"); // Sunucuyu başlatın $ sunucu-> tanıtıcı ();

Umarım "ini_set" fonksiyonu ile satırın üstünde ne olduğunu açıklamaya gerek yoktur. Çünkü orada sunucudan istemciye hangi HTTP başlıklarını göndereceğimiz belirlenir ve ortam yapılandırılır. "ini_set" doğrultusunda, WSDL dosyasının önbelleğe alınmasını devre dışı bırakırız, böylece dosyadaki değişikliklerimiz istemci üzerinde hemen etkili olur.

Şimdi sunucuya geliyoruz! Gördüğünüz gibi, tüm SOAP sunucusu sadece üç satır uzunluğunda! İlk satırda, SoapServer nesnesinin yeni bir örneğini oluşturuyoruz ve bunu, web hizmetinin WSDL açıklamamızın adresini yapıcıya iletiyoruz. Artık kendi kendini açıklayıcı isimle bir dosyada barındırma kök dizininde bulunacağını biliyoruz. smsservice.wsdl.php". İkinci satırda, istemciden gelen zarfın işlenmesi için SOAP sunucusuna hangi sınıfın çekilmesi gerektiğini söylüyor ve zarfı yanıtla birlikte iade ediyoruz. Tahmin edebileceğiniz gibi, tek yöntemimiz bu sınıfta anlatılacak. gönderSms... Üçüncü satırda sunucuyu başlatıyoruz! İşte bu, sunucumuz hazır! Bununla hepimizi tebrik ediyorum!

Şimdi bir WSDL dosyası oluşturmamız gerekiyor. Bunu yapmak için, içeriğini önceki bölümden kopyalayabilir veya özgürlüğü alıp biraz "şablonlayabilirsiniz":

"; ?> / "xmlns: xs =" http://www.w3.org/2001/XMLSchema "xmlns: soap12 =" http://schemas.xmlsoap.org/wsdl/soap12/ "xmlns: http =" http: // schemas.xmlsoap.org/wsdl/http/ "name =" SmsWsdl "xmlns =" ​​​​http://schemas.xmlsoap.org/wsdl/ "> /"> /smsservice.php "/>

Bu aşamada ortaya çıkan sunucu bize tamamen uymalıdır, çünkü ona gelen zarfları kaydedebilir ve ardından gelen verileri sakince analiz edebiliriz. Sunucuda bir şey alabilmemiz için bir istemciye ihtiyacımız var. O halde başlayalım!

6 SABUN istemcisi yolda

Her şeyden önce, istemciyi yazacağımız bir dosya oluşturmamız gerekiyor. Her zamanki gibi, onu ana bilgisayarın kökünde oluşturacağız ve adını “ istemci.php", Ve içeride aşağıdakileri yazıyoruz:

mesajListesi = yeni MessageList(); $ req-> messageList-> mesaj = yeni Mesaj (); $ req-> messageList-> mesaj-> telefon = "79871234567"; $ req-> messageList-> message-> text = "Test mesajı 1"; $ req-> messageList-> mesaj-> tarih = "2013-07-21T15: 00: 00.26"; $ req-> messageList-> mesaj-> type = 15; $ client = new SoapClient ("http:// ($ _SERVER [" HTTP_HOST "]) / smsservice.wsdl.php, dizi (" soap_version "=> SOAP_1_2)); var_dump ($ client-> sendSms ($ req));

Nesnelerimizi tanımlayalım. WSDL'yi yazdığımızda, sunucuya giren zarf için üç varlık tanımladı: Rica etmek, Mesaj Listesi ve İleti... Buna göre sınıflar Rica etmek, Mesaj Listesi ve İleti PHP betiğimizdeki bu varlıkların yansımalarıdır.

Nesneleri tanımladıktan sonra bir nesne oluşturmamız gerekiyor ( $ istek) sunucuya göndereceğiz. Ondan sonra bizim için en çok değer verilen iki satır var! SABUN müşterimiz! İster inanın ister inanmayın, ancak bu, istemciden gelen mesajların sunucumuza akmaya başlaması ve sunucumuzun bunları başarıyla alması ve işlemesi için yeterlidir! Bunlardan ilkinde, SoapClient sınıfının bir örneğini oluşturup WSDL dosyasının bulunduğu yerin adresini yapıcısına iletiyoruz ve SOAP sürüm 1.2 kullanarak çalışacağımızı parametrelerde açıkça belirtiyoruz. Bir sonraki satırda, yöntemi çağırıyoruz gönderSms nesne $ müşteri ve sonucu hemen tarayıcıda görüntüleyin.
Hadi çalıştıralım ve sonunda ne elde ettiğimizi görelim!

Aşağıdaki nesne sunucudan bana döndürüldü:

Nesne (stdClass) genel "durum" => boolean true

Ve bu harika, çünkü Artık sunucumuzun çalıştığından ve sadece çalıştığından değil, aynı zamanda istemciye bazı değerleri de döndürebildiğinden eminiz!

Şimdi sunucu tarafında ihtiyatlı bir şekilde tuttuğumuz loga bir göz atalım! İlk bölümde sunucuya gelen ham verileri görüyoruz:

79871234567 Test mesajı 1 2013-07-21T15: 00: 00.26 15

Bu zarf. Şimdi neye benzediğini biliyorsun! Ancak her zaman hayran olmamız pek ilginç olmayacak, bu yüzden nesneyi günlük dosyasından seri hale getirelim ve her şeyin yolunda olup olmadığına bakalım:

Object (stdClass) public "messageList" => object (stdClass) public "message" => object (stdClass) public "phone" => string "79871234567" (uzunluk = 11) public "text" => string "Test mesajı 1 "(uzunluk = 37) genel" tarih "=> dize" 2013-07-21T15: 00: 00.26 "(uzunluk = 22) genel" tür "=> dize" 15 "(uzunluk = 2)

Gördüğünüz gibi, nesne doğru bir şekilde seri durumdan çıkarıldı, bu da hepimizi tebrik etmek istiyorum! Sonra, daha ilginç bir şey bizi bekliyor! Yani - istemci tarafından sunucuya bir sms mesajı değil, bir sürü (daha doğrusu üç) göndereceğiz!

7 Karmaşık nesneler gönderme

Bir pakette bir sürü mesajı sunucuya nasıl aktarabileceğimizi düşünelim mi? Muhtemelen en kolay yol, diziyi messageList öğesi içinde düzenlemek olacaktır! Bunu yapalım:

// sunucuya gönderilecek bir nesne oluşturun $ req = new Request(); $ req-> messageList = yeni MessageList(); $ msg1 = yeni Mesaj (); $ msg1-> telefon = "79871234567"; $ msg1-> text = "Test Mesajı 1"; $ msg1-> tarih = "2013-07-21T15: 00: 00.26"; $ msg1-> tip = 15; $ msg2 = yeni Mesaj (); $ msg2-> telefon = "79871234567"; $ msg2-> text = "Test Mesajı 2"; $ msg2-> tarih = "2014-08-22T16: 01: 10"; $ msg2-> tip = 16; $ msg3 = yeni Mesaj (); $ msg3-> telefon = "79871234567"; $ msg3-> text = "Test Mesajı 3"; $ msg3-> tarih = "2014-08-22T16: 01: 10"; $ msg3-> tip = 17; $ req-> messageList-> mesaj = $ msg1; $ req-> messageList-> mesaj = $ msg2; $ req-> messageList-> mesaj = $ msg3;

Günlüklerimiz, aşağıdaki paketin bir istemciden geldiğini gösteriyor:

79871234567 Test mesajı 1 2013-07-21T15: 00: 00.26 15 79871234567 Test mesajı 2 2014-08-22T16: 01: 10 16 79871234567 Test mesajı 3 2014-08-22T16: 01: 10 17

Ne saçmalık diyorsunuz? Ve bir anlamda haklı olacaksın, çünkü istemciden hangi nesnenin ayrıldığını öğrendik, sonra kesinlikle aynı biçimde bir zarf şeklinde sunucumuza geldi. Ancak, sms mesajları ihtiyaç duyduğumuz şekilde XML'e serileştirilmedi - öğelere sarılmaları gerekiyordu İleti, değil yapı... Şimdi böyle bir nesnenin yönteme hangi formda geldiğini görelim gönderSms:

Object (stdClass) public "messageList" => object (stdClass) public "message" => object (stdClass) public "Struct" => dizi (size = 3) 0 => nesne (stdClass) public "phone" => string "79871234567" (uzunluk = 11) genel "metin" => dize "Test mesajı 1" (uzunluk = 37) genel "tarih" => dize "2013-07-21T15: 00: 00.26" (uzunluk = 22) genel " type "=> string" 15 "(uzunluk = 2) 1 => nesne (stdClass) public" phone "=> string" 79871234567 "(uzunluk = 11) public" text "=> string" Test mesajı 2 "(uzunluk = 37) public "date" => string "2014-08-22T16: 01: 10" (uzunluk = 19) public "type" => string "16" (uzunluk = 2) 2 => nesne (stdClass) public "phone "=> dize" 79871234567 "(uzunluk = 11) genel" metin "=> dize" Test mesajı 3 "(uzunluk = 37) genel" tarih "=> dize" 2014-08-22T16: 01: 10 "(uzunluk = 19) public "type" => string "17" (uzunluk = 2)

Bu bilgi bize ne veriyor? Sadece seçtiğimiz yol doğru değil ve "Sunucuda doğru veri yapısını nasıl elde edebiliriz?" sorusuna cevap alamadık. Ama umutsuzluğa kapılmamanızı ve dizimizi türe çevirmeyi denemenizi öneririm. bir obje:

$ req-> messageList-> mesaj = (nesne) $ req-> messageList-> mesaj;

Bu durumda, başka bir zarf alacağız:

79871234567 Test mesajı 1 2013-07-21T15: 00: 00.26 15 79871234567 Test mesajı 2 2014-08-22T16: 01: 10 16 79871234567 Test mesajı 3 2014-08-22T16: 01: 10 17

yöntem geldi gönderSms nesne aşağıdaki yapıya sahiptir:

Object (stdClass) public "messageList" => object (stdClass) public "message" => object (stdClass) public "BOGUS" => dizi (size = 3) 0 => nesne (stdClass) public "phone" => string "79871234567" (uzunluk = 11) genel "metin" => dize "Test mesajı 1" (uzunluk = 37) genel "tarih" => dize "2013-07-21T15: 00: 00.26" (uzunluk = 22) genel " type "=> string" 15 "(uzunluk = 2) 1 => nesne (stdClass) public" phone "=> string" 79871234567 "(uzunluk = 11) public" text "=> string" Test mesajı 2 "(uzunluk = 37) public "date" => string "2014-08-22T16: 01: 10" (uzunluk = 19) public "type" => string "16" (uzunluk = 2) 2 => nesne (stdClass) public "phone "=> dize" 79871234567 "(uzunluk = 11) genel" metin "=> dize" Test mesajı 3 "(uzunluk = 37) genel" tarih "=> dize" 2014-08-22T16: 01: 10 "(uzunluk = 19) public "type" => string "17" (uzunluk = 2)

Bana gelince, o zaman “terimlerin yerlerinin değişmesinden toplam değişmez” (c). Ne SAHTE, ne yapı- hedefe henüz bizim tarafımızdan ulaşılmadı! Ve bunu başarmak için, bu anlaşılmaz isimler yerine anadilimizin görüntülendiğinden emin olmalıyız. İleti... Ancak bunun nasıl başarılacağını yazar henüz bilmiyor. Bu nedenle yapabileceğimiz tek şey fazladan konteynırdan kurtulmak. Başka bir deyişle, şimdi öyle yapacağız ki yerine İleti NS SAHTE! Bunu yapmak için nesneyi aşağıdaki gibi değiştirelim:

// sunucuya gönderilecek bir nesne oluşturun $ req = new Request(); $ msg1 = yeni Mesaj (); $ msg1-> telefon = "79871234567"; $ msg1-> text = "Test Mesajı 1"; $ msg1-> tarih = "2013-07-21T15: 00: 00.26"; $ msg1-> tip = 15; $ msg2 = yeni Mesaj (); $ msg2-> telefon = "79871234567"; $ msg2-> text = "Test Mesajı 2"; $ msg2-> tarih = "2014-08-22T16: 01: 10"; $ msg2-> tip = 16; $ msg3 = yeni Mesaj (); $ msg3-> telefon = "79871234567"; $ msg3-> text = "Test Mesajı 3"; $ msg3-> tarih = "2014-08-22T16: 01: 10"; $ msg3-> tip = 17; $ istek-> mesajListesi = $ msg1; $ istek-> mesajListesi = $ msg2; $ istek-> mesajListesi = $ msg3; $ req-> messageList = (nesne) $ req-> messageList;

Ya şanslıysak ve şemadan doğru isim çekilecekse? Bunu yapmak için, alınan zarfa bakalım:

79871234567 Test mesajı 1 2013-07-21T15: 00: 00.26 15 79871234567 Test mesajı 2 2014-08-22T16: 01: 10 16 79871234567 Test mesajı 3 2014-08-22T16: 01: 10 17

Evet, mucize gerçekleşmedi! SAHTE- kazanmayacağız! İçeri gel gönderSms bu durumda nesne şöyle görünecektir:

Nesne (stdClass) public "messageList" => nesne (stdClass) public "BOGUS" => dizi (boyut = 3) 0 => nesne (stdClass) public "phone" => string "79871234567" (uzunluk = 11) public " metin "=> dize" Test mesajı 1 "(uzunluk = 37) genel" tarih "=> dize" 2013-07-21T15: 00: 00.26 "(uzunluk = 22) genel" tür "=> dize" 15 "(uzunluk) = 2) 1 => nesne (stdClass) public "phone" => string "79871234567" (uzunluk = 11) public "text" => string "Test mesajı 2" (uzunluk = 37) public "date" => string " 2014-08-22T16: 01: 10 "(uzunluk = 19) genel" tür "=> dize" 16 "(uzunluk = 2) 2 => nesne (stdSınıf) genel" telefon "=> dize" 79871234567 "(uzunluk = 11) public "text" => string "Test mesajı 3" (uzunluk = 37) public "date" => string "2014-08-22T16: 01: 10" (uzunluk = 19) public "type" => string " 17"(uzunluk = 2)

Dedikleri gibi - "Neredeyse"! Bu (biraz üzücü) notta, yavaş yavaş yuvarlamayı ve kendim için bazı sonuçlar çıkarmayı öneriyorum.

8 Sonuç

Sonunda buraya geldik! Şimdi neler yapabileceğinizi tanımlayalım:

  • web hizmetiniz için gerekli WSDL dosyasını yazabilirsiniz;
  • SOAP protokolünü kullanarak sunucu ile iletişim kurabilen herhangi bir sorun yaşamadan kendi istemcinizi yazabilirsiniz;
  • SABUN üzerinden dış dünya ile iletişim kuran kendi sunucunuzu yazabilirsiniz;
  • istemcinizden sunucuya aynı türde nesne dizileri gönderebilirsiniz (bazı kısıtlamalarla).

Ayrıca, küçük araştırmamız sırasında kendimiz için bazı keşifler yaptık:

  • yerel SoapClient sınıfı, XML'de aynı türdeki veri yapılarını düzgün şekilde serileştiremez;
  • bir diziyi XML'e serileştirirken, adında fazladan bir öğe oluşturur. yapı;
  • bir nesneyi XML'e serileştirirken, adında fazladan bir öğe oluşturur. SAHTE;
  • SAHTE daha az kötülük yapı zarfın daha kompakt olması nedeniyle (zarfın XML başlığına fazladan ad alanları eklenmez);
  • ne yazık ki, SoapServer sınıfı, XML şemamızla zarf verilerini otomatik olarak doğrulamaz (belki diğer sunucular doğrulamaz).

PHP'de bir SOAP web hizmeti oluşturmak için önce PHP ve yerel bir HTTP sunucusunu kurmanız ve yapılandırmanız gerekir. Bu projede, Apache HTTP sunucusunu ve PHP'yi hızlı bir şekilde kurmanızı sağlayan XAMP paketi kullanılmıştır.

Ayrı olarak, Apache ve PHP yapılandırma dosyalarında düzenlemeler yapmanız gerekir.

Apache HTTP sunucusu yapılandırma dosyası httpd.conf'ta aşağıdaki kod parçasını bulmanız gerekir:

PHP komut dosyalarını yerel bir sunucuda çalıştırmak için, bunları Apache sunucusunun kök dizininde, varsayılan olarak kök Apache klasöründeki htdocs klasöründe saklamanız gerekir.

Sitenin kök dizinini değiştirmek için aşağıdaki satırdaki httpd.conf dosyasında değişiklik yapmanız gerekmektedir:

PHP desteğini etkinleştirmek için httpd.conf dosyasına aşağıdaki satırları ekleyin:


Apache HTTP Sunucusunu başlatmak için konsol komutlarını kullanabilir veya Apache'nin durumunu yönetmek ve yapılandırmak için XAMMP kontrol panelini kullanabilirsiniz.

Bu yardımcı programın görünümü Şekil 2'de gösterilmektedir.

Şekil 2. - XAMMP Kontrol Paneli yardımcı programı:


Bir SOAP web hizmeti oluşturmak için, uygulamanın istemci ve sunucu taraflarını uygulayan PHP belgelerinin yanı sıra web hizmetini tanımlamak için bir WSDL sayfası yazmanız gerekir.

İki sayı üzerinde bir aritmetik işlemin sonucunu istemciye döndüren bir web hizmeti sağlayan bir web hizmeti oluşturalım. Girdi öğeleri, istemci tarafından sağlanan iki sayı ve bir aritmetik işlemi tanımlayan sembolik bir değişkendir.

İstemci tarafı iki PHP belgesi tarafından uygulanır. Öğeyi kullanarak form.php dosyasında

kullanıcının verileri girdiği form açıklanır. Form özellikleri, formdan bilgi almak ve onu bir PHP dosyasına aktarmak için kullanılan POST yöntemini içerir. Bu durumda kullanıcı tarafından girilen veriler afqk code.php'ye aktarılır. Elementler veri girişi için metin alanlarını ve basıldığında verileri code.php dosyasına aktaran bir düğmeyi tanımlar.

Form.php dosyasını uygulayan kod parçacığı aşağıda gösterilmiştir:


code.php dosyasında, istemci sınıfının bir örneği oluşturulur ve kullanıcı tarafından girilen veriler alınır ve bir SOAP mesajında ​​sunucuya gönderilir. İstemci sınıfının bir örneğinin oluşturulmasını uygulayan bir kod parçacığı aşağıda gösterilmiştir:

Bu snippet, SOAP mesajını cacl.wsdl yapılandırma dosyasına uygun olarak yürüten SoapClient sınıfının bir $ istemci örneğini oluşturur.

Code.php dosyasında, $ a, $ b, $ action değişkenlerine, form.php'den alınan verileri depolayan $ _POST ilişkisel dizisinin üyelerinin değerleri de atanır.

Bu işlemleri uygulayan bir kod parçası aşağıda gösterilmiştir:

Burada getCalcEntry (), WSDL dosyasında açıklanan işlemdir.

Bu web servisinde calc-server.php dosyası sunucu tarafında rol oynamaktadır.

Bu dosyada getCalcEntry işlevi bildirilir ve çağrılır.

Bu işlev, $ action değişkeninin değerini kontrol eder ve buna göre, $ a ve $ b değişkenleri üzerinde bir işlem gerçekleştirerek sonucu $ c değişkenine yazar. Bu kod parçacığında, addFunction () yöntemi, getCalcentry işlevini uzak istemciye sunar. Handle() yöntemi, SOAP isteğini işleyecek, gerekli işlevleri çağıracak ve SOAP yanıtını gönderecektir. Bu işlevi uygulayan bir kod parçacığı aşağıda gösterilmiştir:


calc.wsdl dağıtım tanımlayıcısı, bu SOAP web hizmetinde önemli bir rol oynar.

Bu dosya, SOAP mesajlarının temel parametrelerini tanımlar. Bunu uygulamaktan sorumlu kod parçacığı aşağıdadır:


Bu pasajda, öğeler getCalcRequest ve getCalcResponse - sırasıyla SABUN isteği ve SABUN yanıtı. iç içe elemanlar, geçirilen değişkenlerin adları ve türleri ile tanımlanır. PHP'de dinamik yazma sayesinde örtük olarak sayılara dönüştürülecek olan dizeleri (string türünden) geçirmenin mümkün olduğuna dikkat edilmelidir. Ayrıca WSDL dosyasının önemli bir öğesi, öğe tarafından yürütülen web hizmeti arabiriminin açıklamasıdır.

Bu parçada, eleman iki eylemden oluşan belirli bir getCalcEntry hizmetini açıklar:

  • - getCalcRequest'in ilk eylemi, mesajın gönderilmesini temsil eder;
  • - getCalcResponse'nin ikinci eylemi bir yanıt almaktır.

Web hizmetinin yerel sunucuda başarılı bir şekilde çalışması için şunları yapmanız gerekir:

  • 1) Apache sunucusunun kök dizininde dağıtılmış uygulama için ayrı bir dizin oluşturun. içine form.php, code.php, calc-server.php ve calc.wsdl dosyalarını yerleştirin;
  • 2) Konsolu veya XAMMP kontrol panelini kullanarak Apache'yi başlatın;
  • 3) Tarayıcının adres çubuğuna web hizmeti istemcisinin adresini girin;
  • 4) Metin alanlarına verileri girin ve Hesapla düğmesini tıklayın;
  • 5) Sonuç olarak, tarayıcı sekmesinde görüntülenen hesaplama sonucunun olduğu bir PHP sayfası açılacaktır.

Şekil 3. - Değiştirilen web servisinin sonucu:


SOAP'ın nasıl çalıştığına daha yakından bakmak için, code.php dosyasının kodunu, en son SOAP mesajlarının listeleri - istek ve yanıt - hesaplama sonucu ile birlikte tarayıcıda görüntülenecek şekilde değiştiriyoruz.

Bu işlevleri gerçekleştiren bir kod parçası aşağıda gösterilmiştir:


web sunucusu programlama

Bu snippet, standart sistem sınıfı yöntemlerini içerir:

SOAP mesajlarının metninin döndürülmesi. Bu şekilde alınan SOAP mesajlarına baktığınızda client ile server arasındaki veri alışverişini net bir şekilde görebilirsiniz. İstenirse, veriler aşağıdaki kod parçacığında bulunur. Bu parça, öğenin yuvalandığı SOAP zarfının gövdesini içerir. web servisini tanımlar.


Geçirilen değişkenlerin değerlerini ve veri türlerini saklayan öğeleri içerir. Sunucu, 5 ve 3 sayılarının değerlerini ve üzerlerinde gerçekleştirilen çıkarma işleminin sembolünü alır.

Cevap için benzer bir kod parçacığı aşağıda verilmiştir:


Bu kod parçasında, istemciye iletilen çıkarma sonucunun değerini görebilirsiniz - 2.

Bir web servisine bağlanmam gerekiyor ve sahip olduğum tek şey bu:

    Çağrı örneği:

    Kullanıcı adı Parola

    Bu işlevin bir dize döndürdüğünü biliyorum;

Şimdiye kadar yaptığım şey bu:

    Yalnızca 1. maddede belirtilen WSDL adresini ekleyerek bir Hizmet Referansı oluşturuldu.

    Bir web hizmeti örneği oluşturdu ve gerekli tüm parametrelere sahip bir işlev çağırdı, ancak başlık için kullanıcı ve şifre değil.

Nasıl devam edebilirim? Şimdiden teşekkür ederim.

1 cevap

Kimlik bilgilerinizi eklemeniz gerekiyorsa, bu iyi bir başlangıç ​​noktası olabilir; Onları bir şekilde aldığına göre, zorunda kalabileceğini düşünüyorum. Kimlik bilgilerinizi eklediğiniz kısım aşağıda listelenmiştir:

KullanıcıAdıToken userToken = yeni KullanıcıAdıToken (kullanıcıAdı, parola, PasswordOption.SendHashed); Hizmet1 hizmetProxy = yeni Hizmet1 (); SoapContext requestContext = serviceProxy.RequestSoapContext; requestContext.Security.Tokens.Add (userToken);

  1. Kimlik bilgilerinizi, türü Microsoft.Web.Services2.Security.Tokens ad alanına ait olan belirli bir simgeye ekleyerek ekleyin
  2. Hizmetiniz için bir proxy oluşturun (yukarıdaki örnek serviceProxy'de)
  3. İstek başlığınıza RequestSoapContext hizmetiniz aracılığıyla erişin
  4. İsteğe jeton ekle

Ayrıca, web hizmeti spesifikasyonu ile ilgili olduğu için URL'nin "? Wsdl" bölümünü atlayabileceğinizi düşünüyorum. Bu yapıldıktan sonra, işlevi çağırmayı deneyebilir ve her şeyin nasıl çalıştığını görebilirsiniz: işlev bir şey döndürürse, ne beklediğinizi kontrol edin.