Services_Amazon_S3
[ class tree: Services_Amazon_S3 ] [ index: Services_Amazon_S3 ] [ all elements ]

Source for file S3.php

Documentation is available at S3.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * Services_Amazon_S3, a PHP5 API for accessing the Amazon Simple Storage
  7.  * Service, Amazon S3.
  8.  *
  9.  * PHP version 5
  10.  *
  11.  * LICENSE:
  12.  *
  13.  * Copyright (c) 2008-2009, Peytz & Co. A/S
  14.  * All rights reserved.
  15.  *
  16.  * Redistribution and use in source and binary forms, with or without
  17.  * modification, are permitted provided that the following conditions
  18.  * are met:
  19.  *
  20.  *  * Redistributions of source code must retain the above copyright
  21.  *    notice, this list of conditions and the following disclaimer.
  22.  *  * Redistributions in binary form must reproduce the above copyright
  23.  *    notice, this list of conditions and the following disclaimer in
  24.  *    the documentation and/or other materials provided with the distribution.
  25.  *  * Neither the name of the PHP_LexerGenerator nor the names of its
  26.  *    contributors may be used to endorse or promote products derived
  27.  *    from this software without specific prior written permission.
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  30.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  31.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  32.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  33.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  34.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  35.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  36.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  37.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  38.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  39.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40.  *
  41.  * @category  Services
  42.  * @package   Services_Amazon_S3
  43.  * @author    Christian Schmidt <services.amazon.s3@chsc.dk>
  44.  * @copyright 2008-2009 Peytz & Co. A/S
  45.  * @license   http://www.opensource.org/licenses/bsd-license.php BSD
  46.  * @version   SVN: $Id: S3.php 291670 2009-12-03 21:12:40Z gauthierm $
  47.  * @link      http://pear.php.net/package/Services_Amazon_S3
  48.  * @link      https://s3.amazonaws.com/
  49.  * @link      http://docs.amazonwebservices.com/AmazonS3/2006-03-01/
  50.  */
  51.  
  52. /**
  53.  * Use HTTP_Request2 for connecting to the S3 REST interface.
  54.  */
  55. require_once 'HTTP/Request2.php';
  56.  
  57. /**
  58.  * Use Crypt_HMAC2 for signing REST requests.
  59.  */
  60. require_once 'Crypt/HMAC2.php';
  61.  
  62. require_once 'Services/Amazon/S3/Resource.php';
  63. require_once 'Services/Amazon/S3/Resource/Bucket.php';
  64. require_once 'Services/Amazon/S3/Resource/Object.php';
  65. require_once 'Services/Amazon/S3/Exception.php';
  66. require_once 'Services/Amazon/S3/ServerErrorException.php';
  67.  
  68. /**
  69.  * The main S3 class contains the credentials used for accessing the S3
  70.  * service and is a starting point for accessing the storage service.
  71.  *
  72.  * Sample usage:
  73.  * <code>
  74.  * require_once 'Services/Amazon/S3.php';
  75.  * // Replace with your own credentials
  76.  * $accessKeyId = '0PN5J17HBGZHT7JJ3X82';
  77.  * $secretAccessKey = 'uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o';
  78.  * $s3 = Services_Amazon_S3::getAccount($accessKeyId, $secretAccessKey);
  79.  * </code>
  80.  *
  81.  * The S3 account instance can now be used to list the buckets owned by this
  82.  * account. A bucket is a file container similar to a filesystem directory,
  83.  * except that it cannot contain subdirectories.
  84.  * <code>
  85.  * foreach ($s3->getBuckets() as $bucket) {
  86.  *     print '<li>' . htmlspecialchars($bucket->name) . '</li>';
  87.  * }
  88.  * </code>
  89.  *
  90.  * Get a specific bucket:
  91.  * <code>
  92.  * $bucket = $s3->getBucket('foobar');
  93.  * </code>
  94.  *
  95.  * Iterate over the objects (files) in a bucket:
  96.  * <code>
  97.  * foreach ($bucket->getObjects() as $object) {
  98.  *     print '<li>' . htmlspecialchars($object->key) . '</li>';
  99.  * }
  100.  * </code>
  101.  *
  102.  * Fetch a specific object:
  103.  * <code>
  104.  * $object = $bucket->getObject('foo.gif');
  105.  * $object->load();
  106.  * $img = imagecreatefromstring($object->data);
  107.  * </code>
  108.  *
  109.  * Save an object with public read access:
  110.  * <code>
  111.  * require_once 'Services/Amazon/S3/AccessControlList.php';
  112.  * $object = $bucket->getObject('foo.txt');
  113.  * $object->acl = Services_Amazon_S3_AccessControlList::ACL_PUBLIC_READ;
  114.  * $object->data = 'lorem ipsum dolor sit amet';
  115.  * $object->save();
  116.  * </code>
  117.  *
  118.  * @category  Services
  119.  * @package   Services_Amazon_S3
  120.  * @author    Christian Schmidt <services.amazon.s3@chsc.dk>
  121.  * @copyright 2008-2009 Peytz & Co. A/S
  122.  * @license   http://www.opensource.org/licenses/bsd-license.php BSD
  123.  * @version   Release: @release-version@
  124.  * @link      http://pear.php.net/package/Services_Amazon_S3
  125.  */
  126. {
  127.     // {{{ class constants
  128.  
  129.     /**
  130.      * Namespace URI used in XML.
  131.      */
  132.     const NS_S3 = 'http://s3.amazonaws.com/doc/2006-03-01/';
  133.  
  134.     /**
  135.      * Namespace URI for XML schema instances.
  136.      */
  137.     const NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance';
  138.  
  139.     // }}}
  140.     // {{{ public properties
  141.  
  142.     /**
  143.      * Amazon Web Services Access Key ID.
  144.      * @var string|bool20-character, alphanumeric string, or false if this is
  145.      *                   an anonymous account
  146.      */
  147.     public $accessKeyId;
  148.  
  149.     /**
  150.      * Amazon Web Services Secret Access Key.
  151.      * @var string 40-character string
  152.      */
  153.     public $secretAccessKey;
  154.  
  155.     /**
  156.      * Configuration parameters for HTTP_Request2, e.g. proxy server,
  157.      * timeout etc. NOTE: Some options may interfere with this service.
  158.      * @var array  configuration array for HTTP_Request2.
  159.      * @see HTTP_Request2::HTTP_Request2()
  160.      */
  161.     public $httpConfig = array('follow_redirects' => true);
  162.  
  163.     /**
  164.      * The default method for accessing buckets. This value may be specified
  165.      * per bucket using $bucket->requestStyle.
  166.      * @var string  a Services_Amazon_S3::REQUEST_STYLE_xxx constant
  167.      * @see Services_Amazon_S3_Resource_Bucket::REQUEST_STYLE_VIRTUAL_HOST
  168.      * @see Services_Amazon_S3_Resource_Bucket::REQUEST_STYLE_PATH
  169.      * @see Services_Amazon_S3_Resource_Bucket::REQUEST_STYLE_CNAME
  170.      * @see Services_Amazon_S3_Resource_Bucket::$requestStyle
  171.      * @link http://docs.amazonwebservices.com/AmazonS3/2006-03-01/VirtualHosting.html
  172.      */
  173.     public $requestStyle
  174.         = Services_Amazon_S3_Resource_Bucket::REQUEST_STYLE_VIRTUAL_HOST;
  175.  
  176.     /**
  177.      * The hostname of the endpoint used for requests done by this class and
  178.      * requests for buckets done with REQUEST_STYLE_VIRTUAL_HOST and
  179.      * REQUEST_STYLE_PATH. This value may be specified per bucket using
  180.      * $bucket->endpoint.
  181.      * @see Services_Amazon_S3_Resource_Bucket::$endpoint
  182.      * @see Services_Amazon_S3_Resource_Bucket::REQUEST_STYLE_PATH
  183.      */
  184.     public $endpoint = 's3.amazonaws.com';
  185.  
  186.     /**
  187.      * Whether connections should be made using HTTPS.
  188.      * @var bool 
  189.      */
  190.     public $useSSL = false;
  191.  
  192.     /**
  193.      * Maximum number of keys to fetch per request when iterating over the
  194.      * objects of a bucket. A low value will result in more requests to the
  195.      * serve. This value may be specified on the iterator using
  196.      * <kbd>$iterator->maxKeys</kbd>.
  197.      * @var int|false a positive integer, or false to let the server decide
  198.      *                  the limit
  199.      * @see Services_Amazon_S3_ObjectIterator::$maxKeys
  200.      */
  201.     public $maxKeys = false;
  202.  
  203.     /**
  204.      * Maximum number of retries to make if a request fails with a 500 Internal
  205.      * server error, or if a transport-level error occurs.
  206.      * @var int  a non-negative integer, 0 means do not retry
  207.      */
  208.     public $maxRetries = 2;
  209.  
  210.     // }}}
  211.     // {{{ protected properties
  212.  
  213.     /**
  214.      * Object used to make HTTP requests for the S3 REST API.
  215.      *
  216.      * @var HTTP_Request2 
  217.      *
  218.      * @see Services_Amazon_S3::setRequest()
  219.      */
  220.     protected $request = null;
  221.  
  222.     // }}}
  223.     // {{{ __construct()
  224.  
  225.     /**
  226.      * Private constructor. Use Services_Amazon_S3::getService() or
  227.      * Services_Amazon_S3::getAnonymousService().
  228.      */
  229.     private function __construct()
  230.     {
  231.         $this->request = new HTTP_Request2();
  232.     }
  233.  
  234.     // }}}
  235.     // {{{ setRequest()
  236.  
  237.     /**
  238.      * Sets the HTTP request object to use
  239.      *
  240.      * Can be used to mock requests for testing.
  241.      *
  242.      * @param HTTP_Request2 $request the HTTP request object to use.
  243.      *
  244.      * @return void 
  245.      */
  246.     public function setRequest(HTTP_Request2 $request)
  247.     {
  248.         $this->request = $request;
  249.     }
  250.  
  251.     // }}}
  252.     // {{{ getAccount()
  253.  
  254.     /**
  255.      * Returns an account instance with the specified credentials. This may
  256.      * be used to access resources owned by this account as well as resources
  257.      * owned by other accounts that have permissions granted to this account
  258.      * or to the authenticated users group.
  259.      *
  260.      * @param string $accessKeyId     Amazon Web Services Access Key ID
  261.      *                                 (20-character, alphanumeric string)
  262.      * @param string $secretAccessKey Amazon Web Services Secret Access Key
  263.      *                                 (40-character string)
  264.      *
  265.      * @return Services_Amazon_S3 
  266.      * @see Services_Amazon_S3_AccessControlList::URI_AUTHENTICATED_USERS
  267.      */
  268.     public static function getAccount($accessKeyId$secretAccessKey)
  269.     {
  270.         $s3                  = new Services_Amazon_S3();
  271.         $s3->accessKeyId     = $accessKeyId;
  272.         $s3->secretAccessKey = $secretAccessKey;
  273.         return $s3;
  274.     }
  275.  
  276.     // }}}
  277.     // {{{ getAnonymousAccount()
  278.  
  279.     /**
  280.      * Returns an unauthorized account instance. This can be used to access
  281.      * resources that have permissions granted to anonymous users.
  282.      *
  283.      * @return Services_Amazon_S3 
  284.      * @see Services_Amazon_S3_AccessControlList::URI_ALL_USERS
  285.      */
  286.     public static function getAnonymousAccount()
  287.     {
  288.         $s3              = new Services_Amazon_S3();
  289.         $s3->accessKeyId = false;
  290.         return $s3;
  291.     }
  292.  
  293.     // }}}
  294.     // {{{ getURL()
  295.  
  296.     /**
  297.      * Returns the base URL of this resource.
  298.      *
  299.      * @return string  an absolute URL
  300.      */
  301.     public function getURL()
  302.     {
  303.         return ($this->useSSL ? 'https' 'http''://' $this->endpoint . '/';
  304.     }
  305.  
  306.     // }}}
  307.     // {{{ getBuckets()
  308.  
  309.     /**
  310.      * Returns the buckets owned by the current user.
  311.      *
  312.      * @return Traversable a traversable collection of
  313.      *                      {@link Services_Amazon_S3_Resource_Bucket}
  314.      *                      instances.
  315.      *
  316.      * @throws Services_Amazon_S3_Exception
  317.      */
  318.     public function getBuckets()
  319.     {
  320.         $request $this->sendRequest($this);
  321.         $xPath   = self::getDOMXPath($request);
  322.  
  323.         $buckets = array();
  324.         $query   '/s3:ListAllMyBucketsResult/s3:Buckets/s3:Bucket/s3:Name/text()';
  325.         foreach ($xPath->evaluate($queryas $node{
  326.             $buckets[= new Services_Amazon_S3_Resource_Bucket($this$node->data);
  327.         }
  328.         // Specify Traversable in the documentation to allow us to change to
  329.         // RecursiveIterator in the future without breaking the documented API
  330.         return new ArrayObject($buckets);
  331.     }
  332.  
  333.     // }}}
  334.     // {{{ getBucket()
  335.  
  336.     /**
  337.      * Returns the buckets with the specified name.
  338.      *
  339.      * @param string $name the bucket name (UTF-8)
  340.      *
  341.      * @return Services_Amazon_S3_Resource_Bucket 
  342.      */
  343.     public function getBucket($name)
  344.     {
  345.         return new Services_Amazon_S3_Resource_Bucket($this$name);
  346.     }
  347.  
  348.     // }}}
  349.     // {{{ getRequestSignature()
  350.  
  351.     /**
  352.      * Signs the specified request with the secret key and returns the request
  353.      * signature used by Services_Amazon_S3::sendRequest and
  354.      * Services_Amazon_S3_Resource_Bucket::getSignedUrl().
  355.      *
  356.      * @param string $method      HTTP method - "GET", "PUT", or "DELETE"
  357.      * @param mixed  $resource    an instance of Services_Amazon_S3 or
  358.      *                             Services_Amazon_S3_Resource
  359.      * @param string $subResource e.g. "?acl", "?location", or "?torrent"
  360.      *                             (including the question mark)
  361.      * @param array  $headers     associative array of HTTP request headers -
  362.      *                             the "date" header is mandatory, "content-md5"
  363.      *                             and "content-type" are optional. All keys
  364.      *                             must be in lowercase.
  365.      *
  366.      * @return string 
  367.      *
  368.      * @throws Services_Amazon_S3_Exception
  369.      *
  370.      * @link http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html
  371.      */
  372.     public function getRequestSignature(
  373.         $method,
  374.         $resource,
  375.         $subResource,
  376.         $headers
  377.     {
  378.         $stringToSign $method "\n" .
  379.             (isset($headers['content-md5']$headers['content-md5'''.
  380.             "\n" .
  381.             (isset($headers['content-type']$headers['content-type'''.
  382.             "\n" .
  383.             $headers['date'"\n";
  384.  
  385.         // Generate CanonicalizedAmzHeaders part
  386.         $amzHeaders = array();
  387.         foreach ($headers as $name => $value{
  388.             if (strncmp($name'x-amz-'6=== 0{
  389.                 $amzHeaders[rtrim($name)trim($value);
  390.             }
  391.         }
  392.  
  393.         ksort($amzHeaders);
  394.  
  395.         foreach ($amzHeaders as $name => $value{
  396.             // unfold long headers
  397.             $value preg_replace('/\s*\n\s*/'' '$value);
  398.             // add to string
  399.             $stringToSign .= $name ':' $value "\n";
  400.         }
  401.  
  402.         // Generate CanonicalizedResource part
  403.         if ($resource instanceof Services_Amazon_S3{
  404.             $stringToSign .= '/';
  405.         elseif ($resource instanceof Services_Amazon_S3_Resource_Bucket{
  406.             $stringToSign .= '/' rawurlencode($resource->name'/';
  407.         elseif ($resource instanceof Services_Amazon_S3_Resource_Object{
  408.             $stringToSign .= '/' rawurlencode($resource->bucket->name.
  409.                              '/' rawurlencode($resource->key);
  410.         }
  411.         $stringToSign .= $subResource;
  412.  
  413.         return $this->signString($stringToSign);
  414.  
  415.     }
  416.  
  417.     // }}}
  418.     // {{{ signString()
  419.  
  420.     /**
  421.      * Signs the specified string with the secret key.
  422.      *
  423.      * @param string $stringToSign UTF-8
  424.      *
  425.      * @return string a 28 character string.
  426.      *
  427.      * @throws Services_Amazon_S3_Exception  if this is an anonymous account
  428.      */
  429.     public function signString($stringToSign)
  430.     {
  431.         if (!$this->accessKeyId{
  432.             throw new Services_Amazon_S3_Exception(
  433.                 'Anonymous account cannot sign strings');
  434.         }
  435.  
  436.         // Generate signature
  437.         $hmac = new Crypt_HMAC2($this->secretAccessKey'SHA1');
  438.         $signature $hmac->hash($stringToSignCrypt_HMAC2::BINARY);
  439.  
  440.         // Amazon wants the signature value base64-encoded
  441.         return base64_encode($signature);
  442.     }
  443.  
  444.     // }}}
  445.     // {{{ sendRequest()
  446.  
  447.     /**
  448.      * Sends the specified request to the server. This method is for internal
  449.      * use only.
  450.      *
  451.      * @param mixed  $resource    an instance of Services_Amazon_S3 or
  452.      *                             Services_Amazon_S3_Resource
  453.      * @param string $subResource e.g. "?acl", "?location", or "?torrent"
  454.      *                             (including the question mark)
  455.      * @param array  $query       additional query string parameters
  456.      * @param string $method      HTTP method - "GET", "PUT", or "DELETE"
  457.      * @param array  $headers     associative array of HTTP request headers,
  458.      *                             all keys must be in lowercase
  459.      * @param string $body        HTTP request body for PUT requests
  460.      *
  461.      * @return HTTP_Request2_Response 
  462.      *
  463.      * @throws Services_Amazon_S3_Exception
  464.      */
  465.     public function sendRequest(
  466.         $resource,
  467.         $subResource = false,
  468.         $query = null,
  469.         $method = HTTP_Request2::METHOD_GET,
  470.         array $headers = array(),
  471.         $body = false
  472.     {
  473.         $headers['date'gmdate(DATE_RFC1123);
  474.  
  475.         // Sign request, unless this is an anonymous account
  476.         if ($this->accessKeyId{
  477.             $headers['authorization''AWS ' $this->accessKeyId . ':' .
  478.                 $this->getRequestSignature(
  479.                     $method,
  480.                     $resource,
  481.                     $subResource,
  482.                     $headers
  483.                 );
  484.  
  485.         }
  486.  
  487.         // Generate URL
  488.         $url $resource->getURL();
  489.         if ($subResource{
  490.             $url .= $subResource;
  491.             if ($query{
  492.                 $url .= '&';
  493.             }
  494.         elseif ($query{
  495.             $url .= '?';
  496.         }
  497.         if ($query{
  498.             $url .= http_build_query($query'''&');
  499.         }
  500.  
  501.         // Convert null headers to empty strings so they still get sent with
  502.         // the request. (Bug #16827)
  503.         foreach ($headers as $name => $value{
  504.             if ($value === null{
  505.                 $headers[$name'';
  506.             }
  507.         }
  508.  
  509.         // Send request
  510.         try {
  511.             $request = clone $this->request;
  512.  
  513.             $request->setConfig($this->httpConfig);
  514.             $request->setUrl($url);
  515.             $request->setMethod($method);
  516.  
  517.             if ($method === HTTP_Request2::METHOD_PUT{
  518.                 $request->setBody($body);
  519.             }
  520.  
  521.             $request->setHeader($headers);
  522.  
  523.             for ($i = 0; $i <= $this->maxRetries$i++{
  524.                 $response $request->send();
  525.                 if ($response->getStatus(!= 500{
  526.                     break;
  527.                 }
  528.             }
  529.         catch (HTTP_Request2_Exception $e{
  530.             throw new Services_Amazon_S3_Exception($e->getMessage(),
  531.                                                    $e->getCode());
  532.         }
  533.  
  534.         if ($response->getStatus(>= 300{
  535.             if ($response->getStatus(== 301{
  536.                 // Permanents redirects without a Location header indicates that
  537.                 // the wrong endpoint is being used, e.g. due to DNS problems. A
  538.                 // temporary fix is to change /etc/hosts or similar on the local
  539.                 // machine (or change this method to retry the call on the
  540.                 // specified endpoint).
  541.                 $message $xPath->evaluate(
  542.                     'concat(' .
  543.                     '    string(/Error/Message),' .
  544.                     '    " Endpoint: ",' .
  545.                     '    string(/Error/Endpoint)' .
  546.                     ')'
  547.                 );
  548.  
  549.                 throw new Services_Amazon_S3_Exception(
  550.                     $message $message $response
  551.                 );
  552.             elseif ($response->getStatus(== 403
  553.                       && $method == HTTP_Request2::METHOD_GET
  554.             {
  555.                 // getDOMXPath() may throw a Services_Amazon_S3_ServerErrorException
  556.                 $xPath = self::getDOMXPath($response);
  557.                 $code  $xPath->evaluate('string(/Error/Code)');
  558.  
  559.                 // RequestTimeTooSkewed indicates that local clock is scewed.
  560.                 // SignatureDoesNotMatch indicates a bug in
  561.                 // self::getRequestSignature().
  562.                 if (   $code != 'RequestTimeTooSkewed'
  563.                     && $code != 'SignatureDoesNotMatch'
  564.                 {
  565.                     include_once 'Services/Amazon/S3/AccessDeniedException.php';
  566.                     throw new Services_Amazon_S3_AccessDeniedException($response);
  567.                 else {
  568.                     throw new Services_Amazon_S3_Exception($response);
  569.                 }
  570.             elseif ($response->getStatus(== 404{
  571.                 include_once 'Services/Amazon/S3/NotFoundException.php';
  572.                 throw new Services_Amazon_S3_NotFoundException($response);
  573.             elseif ($response->getStatus(>= 500{
  574.                 throw new Services_Amazon_S3_ServerErrorException($response);
  575.             else {
  576.                 throw new Services_Amazon_S3_Exception($response);
  577.             }
  578.         }
  579.  
  580.         return $response;
  581.     }
  582.  
  583.     // }}}
  584.     // {{{ getDOMXPath()
  585.  
  586.     /**
  587.      * Returns a DOMXPath object for the XML document in the body of the
  588.      * specified HTTP response. This method is for internal use only.
  589.      *
  590.      * @param HTTP_Request2_Response $response the HTTP response.
  591.      *
  592.      * @return DOMXPath 
  593.      * @throws Services_Amazon_S3_ServerErrorException
  594.      */
  595.     public static function getDOMXPath(HTTP_Request2_Response $response)
  596.     {
  597.         if ($response->getHeader('content-type'!= 'application/xml'{
  598.             throw new Services_Amazon_S3_ServerErrorException(
  599.                 'Response was not of type application/xml'$response);
  600.         }
  601.         $prevUseInternalErrors libxml_use_internal_errors(true);
  602.         $doc = new DOMDocument();
  603.         $ok  $doc->loadXML($response->getBody());
  604.         libxml_use_internal_errors($prevUseInternalErrors);
  605.         if (!$ok{
  606.             throw new Services_Amazon_S3_ServerErrorException($response);
  607.         }
  608.  
  609.         $xPath = new DOMXPath($doc);
  610.         $xPath->registerNamespace('s3'self::NS_S3);
  611.         $xPath->registerNamespace('xsi'self::NS_XSI);
  612.         return $xPath;
  613.     }
  614.  
  615.     // }}}
  616. }
  617.  
  618. ?>

Documentation generated on Fri, 08 Jul 2011 17:00:05 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.