The State of SOAP in PHP

117
THE STATE OF SOAP IN PHP

description

Presentation on SOAP at the PHPBenelux Conference 2010

Transcript of The State of SOAP in PHP

Page 1: The State of SOAP in PHP

THE STATE OF SOAP IN PHP

Page 2: The State of SOAP in PHP

David Zülke

Page 3: The State of SOAP in PHP

David Zuelke

Page 4: The State of SOAP in PHP
Page 5: The State of SOAP in PHP

http://en.wikipedia.org/wiki/File:München_Panorama.JPG

Page 6: The State of SOAP in PHP

Founder

Page 8: The State of SOAP in PHP

Lead Developer

Page 10: The State of SOAP in PHP

@dzuelke

Page 11: The State of SOAP in PHP

WHAT IS SOAP?And How Did It All Start?

Page 12: The State of SOAP in PHP

original plan

Page 13: The State of SOAP in PHP

talk

Page 14: The State of SOAP in PHP
Page 15: The State of SOAP in PHP

make

Page 16: The State of SOAP in PHP

http://flic.kr/kevinsteele/230997861/

KittY NotIncluded

Page 17: The State of SOAP in PHP
Page 18: The State of SOAP in PHP

however

Page 19: The State of SOAP in PHP

Page 21: The State of SOAP in PHP

last week

Page 22: The State of SOAP in PHP

dis is srs bsns

Page 23: The State of SOAP in PHP

( )( )( )

Page 24: The State of SOAP in PHP

http://en.wikipedia.org/wiki/File:Flughafenkontrolle.jpg

Page 25: The State of SOAP in PHP

let him run away

Page 26: The State of SOAP in PHP
Page 28: The State of SOAP in PHP
Page 29: The State of SOAP in PHP

Page 30: The State of SOAP in PHP

NEIN NEIN NEIN NEIN

DAS IST VERBOTEN

Page 31: The State of SOAP in PHP

WHAT IS SOAP?And How Did It All Start?

Page 32: The State of SOAP in PHP

Data Exchange Protocol

Page 33: The State of SOAP in PHP

XML-based

Page 34: The State of SOAP in PHP

language independent

Page 35: The State of SOAP in PHP

platform independent

Page 36: The State of SOAP in PHP

typically used for RPC-style Web Services

Page 37: The State of SOAP in PHP

zomg lol

Page 38: The State of SOAP in PHP

ORIGINSA Brief (and Wildly Inaccurate) History Lesson

Page 39: The State of SOAP in PHP

< 1998

Page 40: The State of SOAP in PHP

XML-RPC

Page 41: The State of SOAP in PHP

XML-RPC sucks

Page 42: The State of SOAP in PHP

1998

Page 43: The State of SOAP in PHP

Simple Object Access Protocol 1.0

Page 44: The State of SOAP in PHP

2003

Page 45: The State of SOAP in PHP

not really simple

Page 46: The State of SOAP in PHP

renamed

Page 47: The State of SOAP in PHP

Simple Object Access Protocol

Page 48: The State of SOAP in PHP

SOAP

Page 49: The State of SOAP in PHP

SOAP 1.2

Page 50: The State of SOAP in PHP

GLOSSARYTransports, Messages and WSDL

Page 51: The State of SOAP in PHP

SOAP TRANSPORTS

• Transports are used for message transmission

• Most important ones:

• HTTP/HTTPS

• SMTP

Page 52: The State of SOAP in PHP

Amazon

Page 53: The State of SOAP in PHP

100.000.000.000 SOAP requests

Page 54: The State of SOAP in PHP

(per second)

Page 55: The State of SOAP in PHP

Sharks

Page 56: The State of SOAP in PHP

(with friggin’ laser beams attached to their heads)

Page 57: The State of SOAP in PHP

Custom Socket Transport and Serialization!

Page 58: The State of SOAP in PHP

MESSAGES

• Wrapped in <Envelope>

• <Header>s and a <Body>

• Structure is identical for Request and Response

<?xml version="1.0" encoding="UTF‐8"?><SOAP‐ENV:Envelope  xmlns:SOAP‐ENV="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:ns1="http://agavi.org/sampleapp">  <SOAP‐ENV:Body>    <ns1:getProductResponse>      <product>        <id>123456</id>        <name>Red Stapler</name>        <price>3.14</price>      </product>    </ns1:getProductResponse>  </SOAP‐ENV:Body></SOAP‐ENV:Envelope>

Page 59: The State of SOAP in PHP

but worry not

Page 60: The State of SOAP in PHP

that’s the entire point of SOAP

Page 61: The State of SOAP in PHP

WSDL document

Page 62: The State of SOAP in PHP

describes

Page 63: The State of SOAP in PHP

• the service

• the operations

• the data types

Page 64: The State of SOAP in PHP

<?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"/>    </wsdl:operation>    <wsdl:operation name="listProducts">      <wsdl:output message="asa:listProductsResponse"/>    </wsdl:operation>  </wsdl:portType>  <binding name="AgaviSampleApplicationBinding" type="asa:AgaviSampleApplicationPortType">    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>    <wsdl:operation name="getProduct">      <soap:operation soapAction="http://agavi.org/sampleapp#getProduct"/>      <wsdl:input>        <soap:body namespace="http://agavi.org/sampleapp" use="literal"/>      </wsdl:input>      <wsdl:output>        <soap:body namespace="http://agavi.org/sampleapp" use="literal"/>      </wsdl:output>    </wsdl:operation>    <wsdl:operation name="listProducts">      <soap:operation soapAction="http://agavi.org/sampleapp#listProducts"/>      <wsdl:output>        <soap:body namespace="http://agavi.org/sampleapp" use="literal"/>      </wsdl:output>    </wsdl:operation>  </binding>  <service name="AgaviSampleApplicationService">    <port name="AgaviSampleApplicationPort" binding="asa:AgaviSampleApplicationBinding">      <soap:address location="http://services.acme.com/soap.php"/>    </port>  </service>  <wsdl:message name="getProductRequest">    <wsdl:part name="id" type="xsd:int"/>  </wsdl:message>  <wsdl:message name="getProductResponse">    <wsdl:part name="product" type="tns:Product"/>  </wsdl:message>  <wsdl:message name="listProductsResponse">    <wsdl:part name="products" type="tns:ArrayOfProducts"/>  </wsdl:message></wsdl:definitions>

Page 65: The State of SOAP in PHP

AN EXAMPLESo We Are All on the Same Page

Page 66: The State of SOAP in PHP

$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

Page 67: The State of SOAP in PHP

by the way

Page 68: The State of SOAP in PHP

I will not talk about non-WSDL modes

Page 69: The State of SOAP in PHP

using SOAP without a WSDL is a very bad idea

Page 70: The State of SOAP in PHP

SOAP CLIENTSIf You Want To Consume Services

OMNOMNOM SERVICE

Page 71: The State of SOAP in PHP

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

Page 72: The State of SOAP in PHP

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)

Page 73: The State of SOAP in PHP

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)

Page 74: The State of SOAP in PHP

ADVANCED CONCEPTSFaults, Headers and Mappings

Page 75: The State of SOAP in PHP

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 :)}

Page 76: The State of SOAP in PHP

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

Page 77: The State of SOAP in PHP

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

Page 78: The State of SOAP in PHP

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

Page 79: The State of SOAP in PHP

TYPEMAP EXAMPLE: XS:LONG

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

you can use any name for this wrapper tag

Page 80: The State of SOAP in PHP

SOAP SERVERSSlightly More Complicated

Page 81: The State of SOAP in PHP

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

A BASIC SERVER

Page 82: The State of SOAP in PHP

you can also register functions instead of class methods

Page 83: The State of SOAP in PHP

wanna know how?

Page 84: The State of SOAP in PHP

RTFM :X

Page 85: The State of SOAP in PHP

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

DEALING WITH HEADERS

Page 86: The State of SOAP in PHP

again, it can’t tell headers from different namespaces apart

Page 87: The State of SOAP in PHP

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

PRODUCING FAULTS

Page 88: The State of SOAP in PHP

class ProductService {  public function getTwoThings() {    // rocket science here    return array($product1, $product2);  }}

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>

list($p1, $p2) = $client‐>getTwoThings($id1, $id2));

Page 89: The State of SOAP in PHP

LITTLE SECRETSDid You Know That ext/soap Supports...

Page 90: The State of SOAP in PHP

<complexType name="ArrayOfProducts">  <element name="products" type="foo:Product" maxOccurs="unbounded" /></complexType>

XML SCHEMA ARRAYS

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

=

Page 91: The State of SOAP in PHP

HASHMAPS (W/ STRING KEYS)

<xsd:schema  xmlns:apache‐enc="http://xml.apache.org/xml‐soap">  <xsd:complexType name="MyHashmap">    <xsd:element      name="parameters"      type="apache‐enc:Map" />  </xsd:complexType></xsd:schema>

• Custom Apache Axis encoding style

• be aware that it won’t offer good interoperability

• Use any type for values, scalars for keys

• Keys and values will use RPC encoding in the message

Page 92: The State of SOAP in PHP

ONE-WAY CALLS

• SOAP Operations may have only a request, without a response declared

• Both SoapClient and SoapServer will close the connection as soon as they can when calling such a method

http://flic.kr/99996581@N00/1122331674/

Page 93: The State of SOAP in PHP

LITTLE DISAPPOINTMENTSThings That ext/soap Does Not Support...

Page 94: The State of SOAP in PHP

DateTime objects

Page 95: The State of SOAP in PHP

but you can use type maps until there is support!\o/

Page 96: The State of SOAP in PHP

XSD:DATETIME TYPE MAP

function to_datetime_xml(DateTime $dateTime) {  return '<dateTime>'.$dateTime‐>format('Y‐m‐d\TH: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',    ),  ),));

Page 97: The State of SOAP in PHP

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

Page 98: The State of SOAP in PHP

DOS AND DON’TSKeep This in Mind

Page 99: The State of SOAP in PHP

enable the SOAP_SINGLE_ELEMENT_ARRAYS feature

Page 100: The State of SOAP in PHP

don’t use SoapServer::fault()

Page 101: The State of SOAP in PHP

use the exceptions option

Page 102: The State of SOAP in PHP

double-check soap_use_error_handler()

Page 103: The State of SOAP in PHP

don’t use cookies or other forms of state, ever

Page 104: The State of SOAP in PHP

FRAMEWORK HIGHLIGHTSZend Framework & Agavi

Page 105: The State of SOAP in PHP

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

Page 106: The State of SOAP in PHP

Zend_Soap_Autodiscover generates WSDLs for you!

Page 107: The State of SOAP in PHP

using PHPDoc comments

Page 108: The State of SOAP in PHP

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!

Page 109: The State of SOAP in PHP

also very nice for prototyping

Page 110: The State of SOAP in PHP

but might get difficult with complex stuff

Page 111: The State of SOAP in PHP

e.g. multi-dimensional arrays, can’t do those in PHPDoc

Page 112: The State of SOAP in PHP

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

Page 113: The State of SOAP in PHP

Demo

Page 114: The State of SOAP in PHP

SOAP VERSUS RESTYour Thoughts Please

Page 115: The State of SOAP in PHP

!e End

Page 116: The State of SOAP in PHP

Questions?

Page 117: The State of SOAP in PHP

THANK YOU!This was

http://joind.in/1243by

@dzuelke