SlideShare a Scribd company logo
1 of 30
Download to read offline
Dirty Secrets of
PHP 5’s ext/soap
Adam Trachtenberg
Senior Manager of
Platform Evangelism, eBay
eBay Developers Program
• http://developer.ebay.com
• Free to join
• Make up to 1,500,000 calls/day
• Make money by remixing eBay to help our 203 million
  buyers and sellers use our marketplace in new and
  interesting ways.
SOAP Is A Dirty Business
• SOAP 101
• ext/soap 101
• Debugging
• Headers (Authentication)
• Redefining Endpoints
• Intercepting the PHP Method (Before)
• Intercepting the SOAP Request (After)
• Class Mapping
• Attributes
• Everything Else
• Final Thoughts
SOAP 101
• Language-neutral versions of serialize() and unserialize()
• In theory, specification allows many generalizations
• In reality, data structures formatted to and from XML sent
  and received via HTTP(S) POST
• Quite helpful to use a specialized extension to manage
  the translation and transportation, say ext/soap.
• Thus abstracting out those particular details
• But abstractions are leaky
• And the specification is difficult to understand
• This requires you, brave coder, to stare and stare at the
  messy XML that is SOAP to debug the call.
The Messy XML That is SOAP
POST /wsapi?callname=GetUser&siteid=0&version=467&appid=ADAMMACCABM7F714274W4IE2M27882&Routing=default HTTP/1.1
Host: api.ebay.com
Connection: Keep-Alive
User-Agent: PHP-SOAP/5.2.0-dev
Content-Type: text/xml; charset=utf-8
SOAPAction: ""
Content-Length: 1539

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:ebay:apis:eBLBaseComponents"><SOAP-
ENV:Header><ns1:RequesterCredentials><ns1:eBayAuthToken>AgAAAA**AQAAAA**aAAAAA**/Zl1QQ**nY+sHZ2PrBmdj6wVnY
+sEZ2PrA2dj6wJkYepAZCKoA6dj6x9nY+seQ**4wQAAA**OAMAAA**vWmMixB3j6PEtkJfIRd7YWKP3fhydfNhsRquW7zh6WT5csX7HSq0kjXWg5Rp2nG/
8Uglv6ihMk5LHYzWpmyYUu9Bht5LhlZLF1pvtkFaK3267tmeqcyDU+8mX1eNp+lUslsFJhLaNyZFSyeJSMeDFm243j9RIlLmcNjx8/
rSc0Fsen7A7z3M2K63ya4KJU34tPvyfSSHWCanqgOHTx4dYqTqrFL6sZvORa5tUIt4JPKkKT5jOoWVOmKqyOW
+GEsjcBuIlswhGsjubzlXFmhuszDZzMxbKxIMqCCflXoR1CxXInm4g3o+bFJZNah2/
tadvQXw1nJo2NNaDTc1o9wdE4brr3MXnC8A35E8vitkqdtFsVx4JFs2aXuYAwl/rrM//KT2L7gDG4+V2ZMb+UkvB2eEWJYXOKsFdPJXdOzWoFFe69fxetfKS8
+8MDYVBS2i+TdqwiuBh0NCaqG9jIjT0wE3PYsfSxW1WzTLvk/h7oat8JOxY+71kyrvQirywJCcsG98Wpe/bQGI25zK2YIupTakxTHBCf0R/prjy3ryjoQ/7GaRFK/
80mUYmzG4h5jCW/nQ2ilFC5YJF0+OwhKCW81KpK89r1kQoVJ2ecyD/
UGCwLor8P9Wa8dHOgUdThpLM5LImR1NjPtEmT9V9ysIUn2ALqT5bksPAplDhalgJBLrjmemXNdg9vci0pYxMKVcpxab0KcF03cvyS0YhbLyMWvvc2J5ZeUlL3Oi0O3s
3KUyWdTN6QfeH8jVzodxaRhLPQKC6TDQMGEZud3ED7/cCS/WnKP0Wt2x59hj531HWr8b6iflZF2NvA**</
ns1:eBayAuthToken><ns1:Credentials><ns1:AppId>ADAMMACCABM7F714274W4IE2M27882</
ns1:AppId><ns1:DevId>H47LA7CN65J1E1DRYRDJI61V2238F2</ns1:DevId><ns1:AuthCert>A3G23U95I29$1EEOC9848-OU2VI4BA</ns1:AuthCert></
ns1:Credentials></ns1:RequesterCredentials></SOAP-ENV:Header><SOAP-ENV:Body><ns1:GetUserRequest><ns1:Version>467</
ns1:Version></ns1:GetUserRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>

HTTP/1.1 200 OK
Date: Tue, 25 Jul 2006 04:15:30 GMT
Server: WebSphere Application Server/4.0
Content-Type: text/xml; charset=utf-8
X-EBAY-API-SERVER-NAME: ___dXUucmd3ajUyNCw0NikyNSgxNys3MzA/Pjc7NQ==
Content-Language: en
X-Cache: MISS from propel.sjc.ebay.com, MISS from propel.sjc.ebay.com
Connection: close
Transfer-Encoding: chunked

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
Never Fear
• I have seen the enemy and it is SOAP
• But I have learned all its dirty secrets
• I will show you how to use ext/soap to tame even the most
  unruly of SOAP servers
ext/soap 101: Amazon E-commerce WS
$client = new SoapClient(
  "http://soap.amazon.com/schemas2AmazonWebServices.wsdl");
$params = array(
  'keyword' => 'adam trachtenberg', /* ... */ );
$result = $client->KeywordSearchRequest($params);
foreach ($result->Details as $product) {
    echo $product->ProductName . "n";
}

PHP Cookbook
Upgrading to PHP 5
WSDL and XML Schema
• WSDL file describes the service
• Specifies methods, input arguments, return values, types
• This file can get quite large
• The eBay WSDL is 2.7 megs. That’s 75k+ lines.
• XML Schema describes the data structures
• As a result, variables are typed
• Understanding these specifications can be quite useful
Debugging
• Wrap your code inside a try/catch block
• Find the XML of a working request
• Enable the trace option
• Use the __getLast*() methods
• Read the WSDL
Debugging: Amazon E-commerce WS
try {
  $opts = array('trace' => true);
  $client = new SoapClient(
  "http://soap.amazon.com/schemas2/AmazonWebServices.wsdl",
  $opts);
  $params = array(
    'keyword' => 'adam trachtenberg', /* ... */ );
  $result = $client->KeywordSearchRequest($params);
  foreach ($result->Details as $product) {
    echo $product->ProductName . "n";
  }
} catch (SOAPFault $f) {
  print $f;
}
Debugging: getLast*() Methods
try {
/* ... */
} catch (SOAPFault $f) {
  print $f;
}
print "Request: n".
       $client->__getLastRequestHeaders() ."n";
print "Request: n".
       $client->__getLastRequest() ."n";
print "Response: n".
       $client->__getLastResponseHeaders()."n";
print "Response: n".
       $client->__getLastResponse()."n";
Debugging: getLast*() Methods
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope ...>
  <SOAP-ENV:Body>
    <ns1:KeywordSearchRequest>
      <KeywordSearchRequest xsi:type="ns1:KeywordRequest">
      <keyword xsi:type="xsd:string">adam trachtenberg</
keyword>
      ...
    </ns1:KeywordSearchRequest>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Headers
• SOAP headers go in SOAP’s <Header> block
• Similar in spirit to HTTP headers
• Most often used with authentication credentials
• For all requests: __setSOAPHeaders()
• For individual requests: __soapCall()
• Must create headers by hand using SOAPHeader
Headers: Google AdWords
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope ...
  xmlns:ns1="https://adwords.google.com/api/adwords/v4">
  <SOAP-ENV:Header>
      <ns1:email>adam@trachtenberg.com</ns1:email>
      <ns1:password>Secret Password</ns1:password>
      <ns1:useragent>OSCON AdWords Demo</ns1:useragent>
      <ns1:token>Secret Token</ns1:token>
  </SOAP-ENV:Header>
...
Headers: Google AdWords
$ns         = 'https://adwords.google.com/api/adwords/v4';
$email      = new SOAPHeader($ns, 'email',         $email);
$password   = new SOAPHeader($ns, 'password',   $password);
$useragent = new SOAPHeader($ns, 'useragent', $useragent);
$token      = new SOAPHeader($ns, 'token',         $token);
$headers    = array($email, $password, $useragent, $token);


$client     = new SOAPClient($wsdl);
$client->__setSOAPHeaders($headers);
Headers: eBay
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope ...
  xmlns:ns1=" urn:ebay:apis:eBLBaseComponents">
  <SOAP-ENV:Header>
      <ns1:RequesterCredentials>
          <ns1:eBayAuthToken>My Token</ns1:eBayAuthToken>
      </ns1:RequesterCredentials>
  </SOAP-ENV:Header>
...
Headers: eBay
$eBayAuthToken = ‘My Token’;
$eBayAuth = array(‘eBayAuthToken’ =>
  new SOAPVar($eBayAuthToken, XSD_STRING, null, null,
                                          null, $ns);
$headerBody = new SOAPVar($eBayAuth, SOAP_ENC_OBJECT);
$header = new SOAPHeader($ns, 'RequesterCredentials',
                         $headerBody);
$client->__soapCall($method, $args, array(),
                    array($header));
Redefining Endpoints
• Change the request URL specified in WSDL
• Staging versus Production
• Per-call data (routing, authentication, performance)
• For all requests: __construct(), __setLocation()
• For individual requests: __soapCall()

new SOAPClient($wsdl, array('location' => $location));
$this->__setLocation($location);
$this->__soapCall($function, $args,
   array('location' => $location), $this->headers);
Intercepting the PHP Method (Before)
• Alter the endpoint location, add SOAP headers, etc. on a
  per-call basis without exposing the kludgy __soapCall()
  syntax.
• Subclass SOAPClient and implement a __call() method
Intercepting the PHP Method (Before)
class eBaySOAP extends SoapClient {
    public function __call($function, $args) {
        $query_string = http_build_query(array(
          'callname' => $function, /* ... */);
        $location = "{$this->location}?{$query_string}";
        return $this->__soapCall($function, $args,
          array('location' => $location), $this->headers);
    }
}


$eBay = new eBaySOAP($wsdl);
$eBay->GetUser();
Intercepting the SOAP Request (After)
• Alter the SOAP XML document to implement
  manipulations ext/soap doesn’t support or to wrangle your
  XML into a state compatible with a non-compliant SOAP
  Server
• Subclass SOAPClient and create a __doRequest()
  method
Intercepting the SOAP Request (After)
class SalesforceSOAP extends SOAPClient {
    public function __doRequest($request, $location,
                                    $action, $version) {
        $dom = new DOMDocument(‘1.0’);
        $dom->loadXML($request);
        // ... manipulate XML ...
        $request = $dom->saveXML();
        return parent::__doRequest($request, $location,
                                     $action , $version);
    }
}
Attributes
• When the return data has attributes, ext/soap maps the
  attribute name to object properties.
• The text inside the element gets mapped to “_”

<StartPrice currencyID=”EUR”>85</StartPrice>


[StartPrice] => stdClass Object
  (
      [_] => 85
      [currencyID] => EUR
  )
Class Mapping
• By default, XML Schema complexTypes are mapped to
  StdObjects.
• You can make ext/soap map them to specific PHP classes
• Lets you simplify usability by implementing iterators,
  stringifications, ArrayAccess, etc.
• No ability (currently) to call a method, but plans to add
  support for __sleep() and __wakeUp().
• Use the classmap option in the constructor
Class Mapping
class eBayAmountType {
    public function __toString() {
        return (string) $this->Fee->_;
    }
}
$classmap = array(‘AmountType’ => ‘eBayAmountType’);
$options = array(‘classmap’ => $classmap);
$eBay = new SOAPClient($wsdl, $options);
Class Mapping: eBay Fees
<Fees>
 <Fee>
   <Name>AuctionLengthFee</Name>
   <Fee currencyID="USD">1.0</Fee>
 </Fee>
 <Fee>
  <Name>BoldFee</Name>
  <Fee currencyID="USD">0.0</Fee>
 </Fee>
 ...
</Fees>
Class Mapping
class eBayFeesType implements ArrayAccess {
    public function offsetGet($offset) {
        foreach ($this->Fee as $value) {
            if ($value->Name == $offset) {
                return $value;
            }
        }
    }
    // other interface methods
}


echo "Listing fee: ", $result->Fees['ListingFee'], "n";
Everything Else
• Setting a Custom XML Schema Type: xsi:type attribute
• Google AdWords

<ns1:job xsi:type="ns1:CustomReportJob">...


$data = array(‘name’ => ‘OSCON Test’, /* ... */);
$job = new SOAPVar($data, SOAP_ENC_OBJECT,
                   'CustomReportJob', $ns);
$response = $client->scheduleReportJob(
               array('job' => $job));
Everything Else
• Enabling compressed requests using gzip:
$options = array('compression' => SOAP_COMPRESSION_ACCEPT |
   SOAP_COMPRESSION_GZIP | 9); // 9 is the gzip level
$client = new SoapClient($wsdl, $options);

• XML Security: Ask Rob Richards. :)

http://www.cdatazone.org/index.php?/archives/9-WSSE-and-
extsoap.html
More Information
• http://www.php.net/soap
• Upgrading to PHP 5 (OSCON bookstore today)
• PHP Cookbook, 2ed (Pre-order for August or September)

More Related Content

What's hot

맛만 보자 액터 모델이란
맛만 보자 액터 모델이란 맛만 보자 액터 모델이란
맛만 보자 액터 모델이란 jbugkorea
 
React.js - The Dawn of Virtual DOM
React.js - The Dawn of Virtual DOMReact.js - The Dawn of Virtual DOM
React.js - The Dawn of Virtual DOMJimit Shah
 
NDC11_슈퍼클래스
NDC11_슈퍼클래스NDC11_슈퍼클래스
NDC11_슈퍼클래스noerror
 
Presentation Spring, Spring MVC
Presentation Spring, Spring MVCPresentation Spring, Spring MVC
Presentation Spring, Spring MVCNathaniel Richand
 
Node.js Express
Node.js  ExpressNode.js  Express
Node.js ExpressEyal Vardi
 
진선웅 유저수만큼다양한섬을만들자 공개용
진선웅 유저수만큼다양한섬을만들자 공개용진선웅 유저수만큼다양한섬을만들자 공개용
진선웅 유저수만큼다양한섬을만들자 공개용Sunwung Jin
 
CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationSamuel ROZE
 
[데브루키160409 박민근] UniRx 시작하기
[데브루키160409 박민근] UniRx 시작하기[데브루키160409 박민근] UniRx 시작하기
[데브루키160409 박민근] UniRx 시작하기MinGeun Park
 
[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개MinGeun Park
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드NAVER Engineering
 
Asynchronous programming
Asynchronous programmingAsynchronous programming
Asynchronous programmingFilip Ekberg
 
Building a World in the Clouds: MMO Architecture on AWS (MBL304) | AWS re:Inv...
Building a World in the Clouds: MMO Architecture on AWS (MBL304) | AWS re:Inv...Building a World in the Clouds: MMO Architecture on AWS (MBL304) | AWS re:Inv...
Building a World in the Clouds: MMO Architecture on AWS (MBL304) | AWS re:Inv...Amazon Web Services
 
[2019] 언리얼 엔진을 통해 살펴보는 리플렉션과 가비지 컬렉션
[2019] 언리얼 엔진을 통해 살펴보는 리플렉션과 가비지 컬렉션[2019] 언리얼 엔진을 통해 살펴보는 리플렉션과 가비지 컬렉션
[2019] 언리얼 엔진을 통해 살펴보는 리플렉션과 가비지 컬렉션NHN FORWARD
 
[NDC2017] 뛰는 프로그래머 나는 언리얼 엔진 - 언알못에서 커미터까지
[NDC2017] 뛰는 프로그래머 나는 언리얼 엔진 - 언알못에서 커미터까지[NDC2017] 뛰는 프로그래머 나는 언리얼 엔진 - 언알못에서 커미터까지
[NDC2017] 뛰는 프로그래머 나는 언리얼 엔진 - 언알못에서 커미터까지Minjung Ko
 
The virtual DOM and how react uses it internally
The virtual DOM and how react uses it internallyThe virtual DOM and how react uses it internally
The virtual DOM and how react uses it internallyClóvis Neto
 
Introduction to VueJS & Vuex
Introduction to VueJS & VuexIntroduction to VueJS & Vuex
Introduction to VueJS & VuexBernd Alter
 
Build RESTful API Using Express JS
Build RESTful API Using Express JSBuild RESTful API Using Express JS
Build RESTful API Using Express JSCakra Danu Sedayu
 
Jsf 110530152515-phpapp01
Jsf 110530152515-phpapp01Jsf 110530152515-phpapp01
Jsf 110530152515-phpapp01Eric Bourdet
 

What's hot (20)

Les Servlets et JSP
Les Servlets et JSPLes Servlets et JSP
Les Servlets et JSP
 
맛만 보자 액터 모델이란
맛만 보자 액터 모델이란 맛만 보자 액터 모델이란
맛만 보자 액터 모델이란
 
React.js - The Dawn of Virtual DOM
React.js - The Dawn of Virtual DOMReact.js - The Dawn of Virtual DOM
React.js - The Dawn of Virtual DOM
 
NDC11_슈퍼클래스
NDC11_슈퍼클래스NDC11_슈퍼클래스
NDC11_슈퍼클래스
 
Presentation Spring, Spring MVC
Presentation Spring, Spring MVCPresentation Spring, Spring MVC
Presentation Spring, Spring MVC
 
Node.js Express
Node.js  ExpressNode.js  Express
Node.js Express
 
Workshop React.js
Workshop React.jsWorkshop React.js
Workshop React.js
 
진선웅 유저수만큼다양한섬을만들자 공개용
진선웅 유저수만큼다양한섬을만들자 공개용진선웅 유저수만큼다양한섬을만들자 공개용
진선웅 유저수만큼다양한섬을만들자 공개용
 
CQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony applicationCQRS and Event Sourcing in a Symfony application
CQRS and Event Sourcing in a Symfony application
 
[데브루키160409 박민근] UniRx 시작하기
[데브루키160409 박민근] UniRx 시작하기[데브루키160409 박민근] UniRx 시작하기
[데브루키160409 박민근] UniRx 시작하기
 
[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
 
Asynchronous programming
Asynchronous programmingAsynchronous programming
Asynchronous programming
 
Building a World in the Clouds: MMO Architecture on AWS (MBL304) | AWS re:Inv...
Building a World in the Clouds: MMO Architecture on AWS (MBL304) | AWS re:Inv...Building a World in the Clouds: MMO Architecture on AWS (MBL304) | AWS re:Inv...
Building a World in the Clouds: MMO Architecture on AWS (MBL304) | AWS re:Inv...
 
[2019] 언리얼 엔진을 통해 살펴보는 리플렉션과 가비지 컬렉션
[2019] 언리얼 엔진을 통해 살펴보는 리플렉션과 가비지 컬렉션[2019] 언리얼 엔진을 통해 살펴보는 리플렉션과 가비지 컬렉션
[2019] 언리얼 엔진을 통해 살펴보는 리플렉션과 가비지 컬렉션
 
[NDC2017] 뛰는 프로그래머 나는 언리얼 엔진 - 언알못에서 커미터까지
[NDC2017] 뛰는 프로그래머 나는 언리얼 엔진 - 언알못에서 커미터까지[NDC2017] 뛰는 프로그래머 나는 언리얼 엔진 - 언알못에서 커미터까지
[NDC2017] 뛰는 프로그래머 나는 언리얼 엔진 - 언알못에서 커미터까지
 
The virtual DOM and how react uses it internally
The virtual DOM and how react uses it internallyThe virtual DOM and how react uses it internally
The virtual DOM and how react uses it internally
 
Introduction to VueJS & Vuex
Introduction to VueJS & VuexIntroduction to VueJS & Vuex
Introduction to VueJS & Vuex
 
Build RESTful API Using Express JS
Build RESTful API Using Express JSBuild RESTful API Using Express JS
Build RESTful API Using Express JS
 
Jsf 110530152515-phpapp01
Jsf 110530152515-phpapp01Jsf 110530152515-phpapp01
Jsf 110530152515-phpapp01
 

Similar to Dirty Secrets of the PHP SOAP Extension

PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applicationselliando dias
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Masahiro Nagano
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Kacper Gunia
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Jakub Zalas
 
Node.js for PHP developers
Node.js for PHP developersNode.js for PHP developers
Node.js for PHP developersAndrew Eddie
 
Drupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary EditionDrupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary Editionddiers
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasminePaulo Ragonha
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 

Similar to Dirty Secrets of the PHP SOAP Extension (20)

PHP and Rich Internet Applications
PHP and Rich Internet ApplicationsPHP and Rich Internet Applications
PHP and Rich Internet Applications
 
Fatc
FatcFatc
Fatc
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
 
php2.pptx
php2.pptxphp2.pptx
php2.pptx
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Php summary
Php summaryPhp summary
Php summary
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
 
My shell
My shellMy shell
My shell
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
Node.js for PHP developers
Node.js for PHP developersNode.js for PHP developers
Node.js for PHP developers
 
PHP 5.4
PHP 5.4PHP 5.4
PHP 5.4
 
Web 8 | Introduction to PHP
Web 8 | Introduction to PHPWeb 8 | Introduction to PHP
Web 8 | Introduction to PHP
 
Drupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary EditionDrupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary Edition
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
PHP PPT FILE
PHP PPT FILEPHP PPT FILE
PHP PPT FILE
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 

More from Adam Trachtenberg

More from Adam Trachtenberg (6)

LinkedIn Platform at LeWeb 2010
LinkedIn Platform at LeWeb 2010LinkedIn Platform at LeWeb 2010
LinkedIn Platform at LeWeb 2010
 
PHP 5 Sucks. PHP 5 Rocks.
PHP 5 Sucks. PHP 5 Rocks.PHP 5 Sucks. PHP 5 Rocks.
PHP 5 Sucks. PHP 5 Rocks.
 
PHP 5 + MySQL 5 = A Perfect 10
PHP 5 + MySQL 5 = A Perfect 10PHP 5 + MySQL 5 = A Perfect 10
PHP 5 + MySQL 5 = A Perfect 10
 
ApacheCon 2005
ApacheCon 2005ApacheCon 2005
ApacheCon 2005
 
PHP 5 Boot Camp
PHP 5 Boot CampPHP 5 Boot Camp
PHP 5 Boot Camp
 
XML and PHP 5
XML and PHP 5XML and PHP 5
XML and PHP 5
 

Dirty Secrets of the PHP SOAP Extension

  • 1. Dirty Secrets of PHP 5’s ext/soap Adam Trachtenberg Senior Manager of Platform Evangelism, eBay
  • 2. eBay Developers Program • http://developer.ebay.com • Free to join • Make up to 1,500,000 calls/day • Make money by remixing eBay to help our 203 million buyers and sellers use our marketplace in new and interesting ways.
  • 3. SOAP Is A Dirty Business • SOAP 101 • ext/soap 101 • Debugging • Headers (Authentication) • Redefining Endpoints • Intercepting the PHP Method (Before) • Intercepting the SOAP Request (After) • Class Mapping • Attributes • Everything Else • Final Thoughts
  • 4. SOAP 101 • Language-neutral versions of serialize() and unserialize() • In theory, specification allows many generalizations • In reality, data structures formatted to and from XML sent and received via HTTP(S) POST • Quite helpful to use a specialized extension to manage the translation and transportation, say ext/soap. • Thus abstracting out those particular details • But abstractions are leaky • And the specification is difficult to understand • This requires you, brave coder, to stare and stare at the messy XML that is SOAP to debug the call.
  • 5. The Messy XML That is SOAP POST /wsapi?callname=GetUser&siteid=0&version=467&appid=ADAMMACCABM7F714274W4IE2M27882&Routing=default HTTP/1.1 Host: api.ebay.com Connection: Keep-Alive User-Agent: PHP-SOAP/5.2.0-dev Content-Type: text/xml; charset=utf-8 SOAPAction: "" Content-Length: 1539 <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:ebay:apis:eBLBaseComponents"><SOAP- ENV:Header><ns1:RequesterCredentials><ns1:eBayAuthToken>AgAAAA**AQAAAA**aAAAAA**/Zl1QQ**nY+sHZ2PrBmdj6wVnY +sEZ2PrA2dj6wJkYepAZCKoA6dj6x9nY+seQ**4wQAAA**OAMAAA**vWmMixB3j6PEtkJfIRd7YWKP3fhydfNhsRquW7zh6WT5csX7HSq0kjXWg5Rp2nG/ 8Uglv6ihMk5LHYzWpmyYUu9Bht5LhlZLF1pvtkFaK3267tmeqcyDU+8mX1eNp+lUslsFJhLaNyZFSyeJSMeDFm243j9RIlLmcNjx8/ rSc0Fsen7A7z3M2K63ya4KJU34tPvyfSSHWCanqgOHTx4dYqTqrFL6sZvORa5tUIt4JPKkKT5jOoWVOmKqyOW +GEsjcBuIlswhGsjubzlXFmhuszDZzMxbKxIMqCCflXoR1CxXInm4g3o+bFJZNah2/ tadvQXw1nJo2NNaDTc1o9wdE4brr3MXnC8A35E8vitkqdtFsVx4JFs2aXuYAwl/rrM//KT2L7gDG4+V2ZMb+UkvB2eEWJYXOKsFdPJXdOzWoFFe69fxetfKS8 +8MDYVBS2i+TdqwiuBh0NCaqG9jIjT0wE3PYsfSxW1WzTLvk/h7oat8JOxY+71kyrvQirywJCcsG98Wpe/bQGI25zK2YIupTakxTHBCf0R/prjy3ryjoQ/7GaRFK/ 80mUYmzG4h5jCW/nQ2ilFC5YJF0+OwhKCW81KpK89r1kQoVJ2ecyD/ UGCwLor8P9Wa8dHOgUdThpLM5LImR1NjPtEmT9V9ysIUn2ALqT5bksPAplDhalgJBLrjmemXNdg9vci0pYxMKVcpxab0KcF03cvyS0YhbLyMWvvc2J5ZeUlL3Oi0O3s 3KUyWdTN6QfeH8jVzodxaRhLPQKC6TDQMGEZud3ED7/cCS/WnKP0Wt2x59hj531HWr8b6iflZF2NvA**</ ns1:eBayAuthToken><ns1:Credentials><ns1:AppId>ADAMMACCABM7F714274W4IE2M27882</ ns1:AppId><ns1:DevId>H47LA7CN65J1E1DRYRDJI61V2238F2</ns1:DevId><ns1:AuthCert>A3G23U95I29$1EEOC9848-OU2VI4BA</ns1:AuthCert></ ns1:Credentials></ns1:RequesterCredentials></SOAP-ENV:Header><SOAP-ENV:Body><ns1:GetUserRequest><ns1:Version>467</ ns1:Version></ns1:GetUserRequest></SOAP-ENV:Body></SOAP-ENV:Envelope> HTTP/1.1 200 OK Date: Tue, 25 Jul 2006 04:15:30 GMT Server: WebSphere Application Server/4.0 Content-Type: text/xml; charset=utf-8 X-EBAY-API-SERVER-NAME: ___dXUucmd3ajUyNCw0NikyNSgxNys3MzA/Pjc7NQ== Content-Language: en X-Cache: MISS from propel.sjc.ebay.com, MISS from propel.sjc.ebay.com Connection: close Transfer-Encoding: chunked <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body>
  • 6. Never Fear • I have seen the enemy and it is SOAP • But I have learned all its dirty secrets • I will show you how to use ext/soap to tame even the most unruly of SOAP servers
  • 7. ext/soap 101: Amazon E-commerce WS $client = new SoapClient( "http://soap.amazon.com/schemas2AmazonWebServices.wsdl"); $params = array( 'keyword' => 'adam trachtenberg', /* ... */ ); $result = $client->KeywordSearchRequest($params); foreach ($result->Details as $product) { echo $product->ProductName . "n"; } PHP Cookbook Upgrading to PHP 5
  • 8. WSDL and XML Schema • WSDL file describes the service • Specifies methods, input arguments, return values, types • This file can get quite large • The eBay WSDL is 2.7 megs. That’s 75k+ lines. • XML Schema describes the data structures • As a result, variables are typed • Understanding these specifications can be quite useful
  • 9. Debugging • Wrap your code inside a try/catch block • Find the XML of a working request • Enable the trace option • Use the __getLast*() methods • Read the WSDL
  • 10. Debugging: Amazon E-commerce WS try { $opts = array('trace' => true); $client = new SoapClient( "http://soap.amazon.com/schemas2/AmazonWebServices.wsdl", $opts); $params = array( 'keyword' => 'adam trachtenberg', /* ... */ ); $result = $client->KeywordSearchRequest($params); foreach ($result->Details as $product) { echo $product->ProductName . "n"; } } catch (SOAPFault $f) { print $f; }
  • 11. Debugging: getLast*() Methods try { /* ... */ } catch (SOAPFault $f) { print $f; } print "Request: n". $client->__getLastRequestHeaders() ."n"; print "Request: n". $client->__getLastRequest() ."n"; print "Response: n". $client->__getLastResponseHeaders()."n"; print "Response: n". $client->__getLastResponse()."n";
  • 12. Debugging: getLast*() Methods <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope ...> <SOAP-ENV:Body> <ns1:KeywordSearchRequest> <KeywordSearchRequest xsi:type="ns1:KeywordRequest"> <keyword xsi:type="xsd:string">adam trachtenberg</ keyword> ... </ns1:KeywordSearchRequest> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
  • 13. Headers • SOAP headers go in SOAP’s <Header> block • Similar in spirit to HTTP headers • Most often used with authentication credentials • For all requests: __setSOAPHeaders() • For individual requests: __soapCall() • Must create headers by hand using SOAPHeader
  • 14. Headers: Google AdWords <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope ... xmlns:ns1="https://adwords.google.com/api/adwords/v4"> <SOAP-ENV:Header> <ns1:email>adam@trachtenberg.com</ns1:email> <ns1:password>Secret Password</ns1:password> <ns1:useragent>OSCON AdWords Demo</ns1:useragent> <ns1:token>Secret Token</ns1:token> </SOAP-ENV:Header> ...
  • 15. Headers: Google AdWords $ns = 'https://adwords.google.com/api/adwords/v4'; $email = new SOAPHeader($ns, 'email', $email); $password = new SOAPHeader($ns, 'password', $password); $useragent = new SOAPHeader($ns, 'useragent', $useragent); $token = new SOAPHeader($ns, 'token', $token); $headers = array($email, $password, $useragent, $token); $client = new SOAPClient($wsdl); $client->__setSOAPHeaders($headers);
  • 16. Headers: eBay <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope ... xmlns:ns1=" urn:ebay:apis:eBLBaseComponents"> <SOAP-ENV:Header> <ns1:RequesterCredentials> <ns1:eBayAuthToken>My Token</ns1:eBayAuthToken> </ns1:RequesterCredentials> </SOAP-ENV:Header> ...
  • 17. Headers: eBay $eBayAuthToken = ‘My Token’; $eBayAuth = array(‘eBayAuthToken’ => new SOAPVar($eBayAuthToken, XSD_STRING, null, null, null, $ns); $headerBody = new SOAPVar($eBayAuth, SOAP_ENC_OBJECT); $header = new SOAPHeader($ns, 'RequesterCredentials', $headerBody); $client->__soapCall($method, $args, array(), array($header));
  • 18. Redefining Endpoints • Change the request URL specified in WSDL • Staging versus Production • Per-call data (routing, authentication, performance) • For all requests: __construct(), __setLocation() • For individual requests: __soapCall() new SOAPClient($wsdl, array('location' => $location)); $this->__setLocation($location); $this->__soapCall($function, $args, array('location' => $location), $this->headers);
  • 19. Intercepting the PHP Method (Before) • Alter the endpoint location, add SOAP headers, etc. on a per-call basis without exposing the kludgy __soapCall() syntax. • Subclass SOAPClient and implement a __call() method
  • 20. Intercepting the PHP Method (Before) class eBaySOAP extends SoapClient { public function __call($function, $args) { $query_string = http_build_query(array( 'callname' => $function, /* ... */); $location = "{$this->location}?{$query_string}"; return $this->__soapCall($function, $args, array('location' => $location), $this->headers); } } $eBay = new eBaySOAP($wsdl); $eBay->GetUser();
  • 21. Intercepting the SOAP Request (After) • Alter the SOAP XML document to implement manipulations ext/soap doesn’t support or to wrangle your XML into a state compatible with a non-compliant SOAP Server • Subclass SOAPClient and create a __doRequest() method
  • 22. Intercepting the SOAP Request (After) class SalesforceSOAP extends SOAPClient { public function __doRequest($request, $location, $action, $version) { $dom = new DOMDocument(‘1.0’); $dom->loadXML($request); // ... manipulate XML ... $request = $dom->saveXML(); return parent::__doRequest($request, $location, $action , $version); } }
  • 23. Attributes • When the return data has attributes, ext/soap maps the attribute name to object properties. • The text inside the element gets mapped to “_” <StartPrice currencyID=”EUR”>85</StartPrice> [StartPrice] => stdClass Object ( [_] => 85 [currencyID] => EUR )
  • 24. Class Mapping • By default, XML Schema complexTypes are mapped to StdObjects. • You can make ext/soap map them to specific PHP classes • Lets you simplify usability by implementing iterators, stringifications, ArrayAccess, etc. • No ability (currently) to call a method, but plans to add support for __sleep() and __wakeUp(). • Use the classmap option in the constructor
  • 25. Class Mapping class eBayAmountType { public function __toString() { return (string) $this->Fee->_; } } $classmap = array(‘AmountType’ => ‘eBayAmountType’); $options = array(‘classmap’ => $classmap); $eBay = new SOAPClient($wsdl, $options);
  • 26. Class Mapping: eBay Fees <Fees> <Fee> <Name>AuctionLengthFee</Name> <Fee currencyID="USD">1.0</Fee> </Fee> <Fee> <Name>BoldFee</Name> <Fee currencyID="USD">0.0</Fee> </Fee> ... </Fees>
  • 27. Class Mapping class eBayFeesType implements ArrayAccess { public function offsetGet($offset) { foreach ($this->Fee as $value) { if ($value->Name == $offset) { return $value; } } } // other interface methods } echo "Listing fee: ", $result->Fees['ListingFee'], "n";
  • 28. Everything Else • Setting a Custom XML Schema Type: xsi:type attribute • Google AdWords <ns1:job xsi:type="ns1:CustomReportJob">... $data = array(‘name’ => ‘OSCON Test’, /* ... */); $job = new SOAPVar($data, SOAP_ENC_OBJECT, 'CustomReportJob', $ns); $response = $client->scheduleReportJob( array('job' => $job));
  • 29. Everything Else • Enabling compressed requests using gzip: $options = array('compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP | 9); // 9 is the gzip level $client = new SoapClient($wsdl, $options); • XML Security: Ask Rob Richards. :) http://www.cdatazone.org/index.php?/archives/9-WSSE-and- extsoap.html
  • 30. More Information • http://www.php.net/soap • Upgrading to PHP 5 (OSCON bookstore today) • PHP Cookbook, 2ed (Pre-order for August or September)