• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
The State of SOAP in PHP
 

The State of SOAP in PHP

on

  • 9,051 views

Presentation given at International PHP Conference 2009 in Karlsruhe, Germany

Presentation given at International PHP Conference 2009 in Karlsruhe, Germany

Statistics

Views

Total Views
9,051
Views on SlideShare
9,017
Embed Views
34

Actions

Likes
6
Downloads
111
Comments
3

1 Embed 34

http://www.slideshare.net 34

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

13 of 3 previous next Post a comment

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    The State of SOAP in PHP The State of SOAP in PHP Presentation Transcript

    • THE STATE OF SOAP IN PHP
    • David Zülke
    • David Zuelke
    • http://en.wikipedia.org/wiki/File:München_Panorama.JPG
    • Founder
    • awesome
    • Lead Developer
    • @dzuelke
    • WHAT IS SOAP? And How Did It All Start?
    • original plan
    • talk
    •  dis is srs bsns
    • make
    • Kit tY Inc No lu t de d http://flic.kr/kevinsteele/230997861/
    • however
    • http://en.wikipedia.org/wiki/File:Flughafenkontrolle.jpg
    • or else
    • SHOOT ME IN THE FACE
    • WHAT IS SOAP? And How Did It All Start?
    • Data Exchange Protocol
    • XML-based
    • language independent
    • platform independent
    • typically used for RPC-style Web Services
    •  zomg lol
    • ORIGINS A Brief (and Wildly Inaccurate) History Lesson
    • < 1998
    • XML-RPC
    • XML-RPC sucks
    • 1998
    • Simple Object Access Protocol 1.0
    • 2003
    • not really simple
    • renamed
    • Simple Object Access Protocol
    • SOAP
    • SOAP 1.2
    • GLOSSARY Transports, Messages and WSDL
    • SOAP TRANSPORTS • Transports are used for message transmission • Most important ones: • HTTP/HTTPS • SMTP
    • Amazon
    • 100.000.000.000 SOAP requests
    • (per second)
    • Sharks
    • (with friggin’ laser beams attached to their heads)
    • Custom Socket Transport and Serialization!
    • MESSAGES <?xml version="1.0" encoding="UTF‐8"?> <SOAP‐ENV:Envelope   xmlns:SOAP‐ENV="http:// schemas.xmlsoap.org/soap/envelope/" • Wrapped in <Envelope>   xmlns:ns1="http://agavi.org/ sampleapp" > • <Header>s and a <Body>   <SOAP‐ENV:Body>     <ns1:getProductResponse>       <product>         <id>123456</id> • Structure is identical for         <name>Red Stapler</name>         <price>3.14</price> Request and Response       </product>     </ns1:getProductResponse>   </SOAP‐ENV:Body> </SOAP‐ENV:Envelope>
    • but worry not
    • that’s the entire point of SOAP
    • WSDL document
    • describes
    • • the service • the operations • the data types
    • <?xml version="1.0" encoding="utf‐8"?> <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"  xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http:// schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/ encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://agavi.org/ sampleapp/types" xmlns:asa="http://agavi.org/sampleapp"  name="AgaviSampleApplication" targetNamespace="http://agavi.org/sampleapp">   <wsdl:types>     <xsd:schema xmlns:soap‐enc="http://schemas.xmlsoap.org/soap/encoding/"  targetNamespace="http://agavi.org/sampleapp/types">       <xsd:complexType name="Product">         <xsd:sequence>           <xsd:element name="id" type="xsd:int"/>           <xsd:element name="name" type="xsd:string"/>           <xsd:element name="price" type="xsd:float"/>         </xsd:sequence>       </xsd:complexType>       <xsd:complexType name="ArrayOfProducts">         <xsd:complexContent>           <xsd:extension base="soap‐enc:Array">             <xsd:attribute ref="soap‐enc:arrayType"  wsdl:arrayType="tns:Product[]"/>           </xsd:extension>         </xsd:complexContent>       </xsd:complexType>     </xsd:schema>   </wsdl:types>   <wsdl:portType name="AgaviSampleApplicationPortType">     <wsdl:operation name="getProduct">       <wsdl:input message="asa:getProductRequest"/>       <wsdl:output message="asa:getProductResponse"/>
    • AN EXAMPLE So We Are All on the Same Page
    • $client = new SoapClient('http://acme.com/product.wsdl', array(   'exceptions' => true,   'trace' => true, )); try {   var_dump($client‐>listProducts()); } catch(SoapFault $e) {   // here be dragons } array   0 =>      object(stdClass)[3]       public 'id' => int 8172401       public 'name' => string 'TPS Report Cover Sheet' (length=22)       public 'price' => float 0.89   1 =>      object(stdClass)[4]       public 'id' => int 917246       public 'name' => string 'Weighted Companion Cube' (length=23)       public 'price' => float 129.99
    • by the way
    • I will not talk about non-WSDL modes
    • using SOAP without a WSDL is a very bad idea
    • SOAP CLIENTS If You Want To Consume Services OMNOMNOM SERVICE
    • BASICS $client = new SoapClient(   'http://acme.com/product.wsdl', // URL to WSDL describing the service   array( // array of additional options for the client     'exceptions' => true, // throw SoapFault exceptions on errors     'trace' => true, // allow use of SoapClient::__getLast…()   ) ); $allProducts = $client‐>listProducts(); // $allProducts contains return value
    • GETTING AVAILABLE FUNCS $client = new SoapClient('http://acme.com/product.wsdl', array(   'exceptions' => true,   'trace' => true, )); var_dump($client‐>__getFunctions()); array   0 => string 'Product getProduct(int $id)' (length=27)   1 => string 'ArrayOfProducts listProducts()' (length=30)
    • GETTING AVAILABLE TYPES $client = new SoapClient('http://acme.com/product.wsdl', array(   'exceptions' => true,   'trace' => true, )); var_dump($client‐>__getTypes()); array   0 => string 'struct Product {  int id;  string name;  float price; }' (length=55)   1 => string 'Product ArrayOfProducts[]' (length=25)
    • ADVANCED CONCEPTS Faults, Headers and Mappings
    • FAULT HANDLING $client = new SoapClient('http://acme.com/product.wsdl', array(   'exceptions' => true,   'trace' => true, )); try {   $newThing = $client‐>createProduct(new stdClass()); } catch(SoapFault $e) {   // could be a client‐side fault e.g. if fields are missing   // or a server‐side fault if the server had any objections :) }
    • SOAP HEADERS $client = new SoapClient('http://acme.com/product.wsdl', array(   'exceptions' => true,   'trace' => true, )); $client‐>setSoapHeader(   new SoapHeader('http://acme.com/soap/products', 'username', 'Chuck Norris') ); $client‐>setSoapHeader(   new SoapHeader('http://acme.com/soap/products', 'password', 'r0undh0usek!ck') ); // headers will be sent along with the request $allProducts = $client‐>listProducts();
    • CLASSMAPS class Product {   protected $id, $name, $price;   // imagine getters and setters here } $client = new SoapClient('http://acme.com/product.wsdl', array(   'exceptions' => true,   'trace' => true,   'classmap' => array(     'Product' => 'Product', // no XML namespace here, which can be problematic…   ), )); var_dump($client‐>getProduct(123456)); object(Product)[2]   protected 'id' => int 123456   protected 'name' => string 'Red Stapler' (length=11)   protected 'price' => float 3.14
    • TYPEMAPS • Used for custom serialization and unserialization in rare cases • Example: • xsd:long is mapped to PHP int, overflows on 32bit archs • Needs two callbacks: • one for XML->PHP conversion • one for PHP->XML conversion
    • TYPEMAP EXAMPLE: XS:LONG you can use any name for this wrapper tag function to_long_xml($longVal) {   return '<long>' . $longVal . '</long>'; } function from_long_xml($xmlFragmentString) {   return (string)strip_tags($xmlFragmentString); } $client = new SoapClient('http://acme.com/products.wsdl', array(   'typemap' => array(     array(       'type_ns' => 'http://www.w3.org/2001/XMLSchema',       'type_name' => 'long',       'to_xml' => 'to_long_xml',       'from_xml' => 'from_long_xml',     ),   ), ));
    • SOAP SERVERS Slightly More Complicated
    • A BASIC SERVER class ProductService {   public function getProduct($id) {     // witchcraft here     return $product;   }   public function listProducts() {     // more witchcraft here     return $products;   } } $server = new SoapServer('/path/to/local/products.wsdl', array(/* options… */)); // register a class to instantiate that has all the methods $server‐>setClass('ProductService'); // alternative: use an existing instance $server‐>setObject(new ProductService()); // rock and roll $server‐>handle();
    • you can also register functions instead of class methods
    • wanna know how?
    • RTFM :X
    • DEALING WITH HEADERS class ProductService {   public function getProduct($id) {     // witchcraft here     return $product;   }   public function listProducts() {     // more witchcraft here     return $products;   }   public function username($value) {     // check if it's really chuck norris   }   public function password($value) {     // check if he did a roundhouse kick   } } $server = new SoapServer('/path/to/local/products.wsdl', array(/* options… */)); // register a class to instantiate that has all the methods $server‐>setClass('ProductService'); // rock and roll $server‐>handle();
    • again, it can’t tell headers from different namespaces apart
    • PRODUCING FAULTS class ProductService {   public function getProduct($id) {     if($product = ProductFinder::retrieveById($id)) {       return $product;     } else {       return new SoapFault('Server', 'No such product');     }   }   public function listProducts() {     // more witchcraft here     return $products;   } }
    • MULTI-PART RETURN VALUES <wsdl:message name="getTwoThingsRequest">   <wsdl:part name="id1" type="xsd:int"/>   <wsdl:part name="id2" type="xsd:int"/> </wsdl:message> <wsdl:message name="getTwoThingsResponse">   <wsdl:part name="firstThing" type="tns:Product"/>   <wsdl:part name="secondThing" type="tns:Product"/> </wsdl:message> class ProductService {   public function getTwoThings() {     // rocket science here     return array($product1, $product2);   } } list($p1, $p2) = $client‐>getTwoThings($id1, $id2));
    • LITTLE SECRETS Did You Know That ext/soap Supports...
    • XML SCHEMA ARRAYS <complexType name="ArrayOfProducts">   <element name="products" type="foo:Product" maxOccurs="unbounded" /> </complexType> = <xsd:complexType name="ArrayOfProducts">   <xsd:complexContent>     <xsd:extension base="soap‐enc:Array">       <xsd:attribute ref="soap‐enc:arrayType" wsdl:arrayType="tns:Product[]"/>     </xsd:extension>   </xsd:complexContent> </xsd:complexType>
    • HASHMAPS (W/ STRING KEYS) • Custom Apache Axis encoding style <xsd:schema • be aware that it won’t   xmlns:apache‐enc="http:// xml.apache.org/xml‐soap"> offer good interoperability   <xsd:complexType name="MyHashmap">     <xsd:element       name="parameters" • Use any type for values,       type="apache‐enc:Map" />   </xsd:complexType> scalars for keys </xsd:schema> • Keys and values will use RPC encoding in the message
    • ONE-WAY CALLS • SOAP Operations may have only a request, without a response declared • BothSoapClient and SoapServer will close the connection as soon as they can when calling such a method http://flic.kr/99996581@N00/1122331674/
    • LITTLE DISAPPOINTMENTS Things That ext/soap Does Not Support...
    • DateTime objects
    • but you can use type maps until there is support! o/
    • XSD:DATETIME TYPE MAP function to_datetime_xml(DateTime $dateTime) {   return '<dateTime>'.$dateTime‐>format('Y‐m‐dTH:i:sP').'</dateTime>'; } function from_datetime_xml($xmlFragmentString) {   return new DateTime(strip_tags($xmlFragmentString)); } $client = new SoapClient('http://acme.com/products.wsdl', array(   'typemap' => array(     array(       'type_ns' => 'http://www.w3.org/2001/XMLSchema',       'type_name' => 'dateTime',       'to_xml' => 'to_datetime_xml',       'from_xml' => 'from_datetime_xml',     ),   ), ));
    • DOCUMENT/LITERAL WRAPPED • Document style services yield messages that can be validated against the WSDL’s XML Schema • Unlike with RPC style services, such messages won’t contain the name of the called method anymore • Solution: wrap the message payload in an element that has the same name as the procedure you want to call • Not a problem in PHP, but you need to wrap/unwrap yourself
    • DOS AND DON’TS Keep This in Mind
    • enable the SOAP_SINGLE_ELEMENT_ARRAYS feature
    • don’t use SoapServer::fault()
    • use the exceptions option
    • double-check soap_use_error_handler()
    • don’t use cookies or other forms of state, ever
    • FRAMEWORK HIGHLIGHTS Zend Framework & Agavi
    • ZEND FRAMEWORK • Zend_Soap_Client as a wrapper for SOAPClient • Zend_Soap_Server as a wrapper for SOAPServer • Zend_Soap_Wsdl for constructing WSDL documents • Zend_Soap_Autodiscover for auto WSDL generation
    • Zend_Soap_Autodiscover generates WSDLs for you!
    • using PHPDoc comments
    • class AcmeProductService {   /**    * @param      int     The ID of the product.    *    * @return     Product The product object.    *    * @deprecated Call Joe from sales if you want to know details about a product…    */   public function getProduct($id) {     // witchcraft goes here     return $product;   } } $autodiscover = new Zend_Soap_AutoDiscover(); $autodiscover‐>setClass('AcmeProductService'); $autodiscover‐>handle(); // only dumps a WSDL, does not start a server!
    • also very nice for prototyping
    • but might get difficult with complex stuff
    • e.g. multi-dimensional arrays, can’t do those in PHPDoc
    • AGAVI • Re-use existing Actions for SOAP Services • Needs some information about the service in WSDL format • WSDL auto-generated by the Routing • Requires basic knowledge of XML Schema and WSDL • Supports Document/Literal Wrapped for Servers
    • Demo
    • SOAP VERSUS REST Your Thoughts Please
    • !e End
    • Questions?
    • THANK YOU! • Shoot me an E-Mail: david.zuelke@bitextender.com • Follow @dzuelke on Twitter • Slides will be on SlideShare