116
THE STATE OF SOAP IN PHP

The State of SOAP in PHP (ZC10 2010-11-02)

Embed Size (px)

DESCRIPTION

Presentation given at ZendCon 2010.

Citation preview

Page 1: The State of SOAP in PHP (ZC10 2010-11-02)

THE STATE OF SOAP IN PHP

Page 2: The State of SOAP in PHP (ZC10 2010-11-02)

David Zülke

Page 3: The State of SOAP in PHP (ZC10 2010-11-02)

David Zuelke

Page 4: The State of SOAP in PHP (ZC10 2010-11-02)
Page 5: The State of SOAP in PHP (ZC10 2010-11-02)
Page 7: The State of SOAP in PHP (ZC10 2010-11-02)

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

Page 8: The State of SOAP in PHP (ZC10 2010-11-02)

Founder

Page 10: The State of SOAP in PHP (ZC10 2010-11-02)

Lead Developer

Page 13: The State of SOAP in PHP (ZC10 2010-11-02)

WHAT IS SOAP?And How Did It All Start?

Page 14: The State of SOAP in PHP (ZC10 2010-11-02)

original plan

Page 15: The State of SOAP in PHP (ZC10 2010-11-02)

talk

Page 16: The State of SOAP in PHP (ZC10 2010-11-02)
Page 17: The State of SOAP in PHP (ZC10 2010-11-02)

make

Page 19: The State of SOAP in PHP (ZC10 2010-11-02)
Page 20: The State of SOAP in PHP (ZC10 2010-11-02)

however

Page 21: The State of SOAP in PHP (ZC10 2010-11-02)

Page 23: The State of SOAP in PHP (ZC10 2010-11-02)

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

Page 25: The State of SOAP in PHP (ZC10 2010-11-02)
Page 26: The State of SOAP in PHP (ZC10 2010-11-02)

NEIN NEIN NEIN NEIN

DAS IST VERBOTEN

Page 27: The State of SOAP in PHP (ZC10 2010-11-02)

Page 28: The State of SOAP in PHP (ZC10 2010-11-02)
Page 29: The State of SOAP in PHP (ZC10 2010-11-02)

WHAT IS SOAP?And How Did It All Start?

Page 30: The State of SOAP in PHP (ZC10 2010-11-02)

Data Exchange Protocol

Page 31: The State of SOAP in PHP (ZC10 2010-11-02)

XML-based

Page 32: The State of SOAP in PHP (ZC10 2010-11-02)

language independent

Page 33: The State of SOAP in PHP (ZC10 2010-11-02)

platform independent

Page 34: The State of SOAP in PHP (ZC10 2010-11-02)

typically used for RPC-style Web Services

Page 35: The State of SOAP in PHP (ZC10 2010-11-02)

zomg lol

Page 36: The State of SOAP in PHP (ZC10 2010-11-02)

ORIGINSA Brief (and Wildly Inaccurate) History Lesson

Page 37: The State of SOAP in PHP (ZC10 2010-11-02)

< 1998

Page 38: The State of SOAP in PHP (ZC10 2010-11-02)

XML-RPC

Page 39: The State of SOAP in PHP (ZC10 2010-11-02)

XML-RPC sucks

Page 40: The State of SOAP in PHP (ZC10 2010-11-02)

1998

Page 41: The State of SOAP in PHP (ZC10 2010-11-02)

Simple Object Access Protocol 1.0

Page 42: The State of SOAP in PHP (ZC10 2010-11-02)

2003

Page 43: The State of SOAP in PHP (ZC10 2010-11-02)

not really simple

Page 44: The State of SOAP in PHP (ZC10 2010-11-02)

renamed

Page 45: The State of SOAP in PHP (ZC10 2010-11-02)

Simple Object Access Protocol

Page 46: The State of SOAP in PHP (ZC10 2010-11-02)

SOAP

Page 47: The State of SOAP in PHP (ZC10 2010-11-02)

SOAP 1.2

Page 48: The State of SOAP in PHP (ZC10 2010-11-02)

GLOSSARYTransports, Messages and WSDL

Page 49: The State of SOAP in PHP (ZC10 2010-11-02)

SOAP TRANSPORTS

• Transports are used for message transmission

• Most important ones:

• HTTP/HTTPS

• SMTP

Page 50: The State of SOAP in PHP (ZC10 2010-11-02)

Amazon

Page 51: The State of SOAP in PHP (ZC10 2010-11-02)

100.000.000.000 SOAP requests

Page 52: The State of SOAP in PHP (ZC10 2010-11-02)

(per second)

Page 53: The State of SOAP in PHP (ZC10 2010-11-02)

Sharks

Page 54: The State of SOAP in PHP (ZC10 2010-11-02)

(with friggin’ laser beams attached to their heads)

Page 55: The State of SOAP in PHP (ZC10 2010-11-02)

Custom Socket Transport and Serialization!

Page 56: The State of SOAP in PHP (ZC10 2010-11-02)

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 57: The State of SOAP in PHP (ZC10 2010-11-02)

but worry not

Page 58: The State of SOAP in PHP (ZC10 2010-11-02)

that’s the entire point of SOAP

Page 59: The State of SOAP in PHP (ZC10 2010-11-02)

WSDL document

Page 60: The State of SOAP in PHP (ZC10 2010-11-02)

describes

Page 61: The State of SOAP in PHP (ZC10 2010-11-02)

• the service

• the operations

• the data types

Page 62: The State of SOAP in PHP (ZC10 2010-11-02)

<?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 63: The State of SOAP in PHP (ZC10 2010-11-02)

AN EXAMPLESo We Are All on the Same Page

Page 64: The State of SOAP in PHP (ZC10 2010-11-02)

$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 65: The State of SOAP in PHP (ZC10 2010-11-02)

by the way

Page 66: The State of SOAP in PHP (ZC10 2010-11-02)

I will not talk about non-WSDL modes

Page 67: The State of SOAP in PHP (ZC10 2010-11-02)

I'd rather stab myself than use SOAP without WSDL

Page 68: The State of SOAP in PHP (ZC10 2010-11-02)

SOAP CLIENTSIf You Want To Consume Services

OMNOMNOM SERVICE

Page 69: The State of SOAP in PHP (ZC10 2010-11-02)

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 70: The State of SOAP in PHP (ZC10 2010-11-02)

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 71: The State of SOAP in PHP (ZC10 2010-11-02)

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 72: The State of SOAP in PHP (ZC10 2010-11-02)

ADVANCED CONCEPTSFaults, Headers and Mappings

Page 73: The State of SOAP in PHP (ZC10 2010-11-02)

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 74: The State of SOAP in PHP (ZC10 2010-11-02)

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 75: The State of SOAP in PHP (ZC10 2010-11-02)

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 76: The State of SOAP in PHP (ZC10 2010-11-02)

ext/soap cannot distinguish between identically namedtypes from different namespaces

Page 77: The State of SOAP in PHP (ZC10 2010-11-02)

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 78: The State of SOAP in PHP (ZC10 2010-11-02)

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 79: The State of SOAP in PHP (ZC10 2010-11-02)

SOAP SERVERSSlightly More Complicated

Page 80: The State of SOAP in PHP (ZC10 2010-11-02)

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 81: The State of SOAP in PHP (ZC10 2010-11-02)

you can also register functions instead of class methods

Page 82: The State of SOAP in PHP (ZC10 2010-11-02)

wanna know how?

Page 83: The State of SOAP in PHP (ZC10 2010-11-02)

RTFM :X

Page 84: The State of SOAP in PHP (ZC10 2010-11-02)

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 85: The State of SOAP in PHP (ZC10 2010-11-02)

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

Page 86: The State of SOAP in PHP (ZC10 2010-11-02)

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 87: The State of SOAP in PHP (ZC10 2010-11-02)

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 88: The State of SOAP in PHP (ZC10 2010-11-02)

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

Page 89: The State of SOAP in PHP (ZC10 2010-11-02)

<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 90: The State of SOAP in PHP (ZC10 2010-11-02)

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 91: The State of SOAP in PHP (ZC10 2010-11-02)

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 92: The State of SOAP in PHP (ZC10 2010-11-02)

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

Page 93: The State of SOAP in PHP (ZC10 2010-11-02)

DateTime objects

Page 94: The State of SOAP in PHP (ZC10 2010-11-02)

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

Page 95: The State of SOAP in PHP (ZC10 2010-11-02)

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 96: The State of SOAP in PHP (ZC10 2010-11-02)

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 97: The State of SOAP in PHP (ZC10 2010-11-02)

DOS AND DON’TSKeep This in Mind

Page 98: The State of SOAP in PHP (ZC10 2010-11-02)

enable the SOAP_SINGLE_ELEMENT_ARRAYS feature

Page 99: The State of SOAP in PHP (ZC10 2010-11-02)

don’t use SoapServer::fault()

Page 100: The State of SOAP in PHP (ZC10 2010-11-02)

use the exceptions option

Page 101: The State of SOAP in PHP (ZC10 2010-11-02)

double-check soap_use_error_handler()

Page 102: The State of SOAP in PHP (ZC10 2010-11-02)

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

Page 103: The State of SOAP in PHP (ZC10 2010-11-02)

FRAMEWORK HIGHLIGHTSZend Framework & Agavi

Page 104: The State of SOAP in PHP (ZC10 2010-11-02)

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 105: The State of SOAP in PHP (ZC10 2010-11-02)

Zend_Soap_Autodiscover generates WSDLs for you!

Page 106: The State of SOAP in PHP (ZC10 2010-11-02)

using PHPDoc comments

Page 107: The State of SOAP in PHP (ZC10 2010-11-02)

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 108: The State of SOAP in PHP (ZC10 2010-11-02)

also very nice for prototyping

Page 109: The State of SOAP in PHP (ZC10 2010-11-02)

but might get difficult with complex stuff

Page 110: The State of SOAP in PHP (ZC10 2010-11-02)

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

Page 111: The State of SOAP in PHP (ZC10 2010-11-02)

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 112: The State of SOAP in PHP (ZC10 2010-11-02)

Demo

Page 113: The State of SOAP in PHP (ZC10 2010-11-02)

SOAP VERSUS RESTA Short Monologue

Page 114: The State of SOAP in PHP (ZC10 2010-11-02)

!e End

Page 115: The State of SOAP in PHP (ZC10 2010-11-02)

Questions?

Page 116: The State of SOAP in PHP (ZC10 2010-11-02)

THANK YOU!This was

http://joind.in/2231by

@dzuelke