File indexing completed on 2024-12-22 05:37:06

0001 <?php
0002 
0003 /**
0004  * Zend Framework
0005  *
0006  * LICENSE
0007  *
0008  * This source file is subject to the new BSD license that is bundled
0009  * with this package in the file LICENSE.txt.
0010  * It is also available through the world-wide-web at this URL:
0011  * http://framework.zend.com/license/new-bsd
0012  * If you did not receive a copy of the license and are unable to
0013  * obtain it through the world-wide-web, please send an email
0014  * to license@zend.com so we can send you a copy immediately.
0015  *
0016  * @category   Zend
0017  * @package    Zend_Service
0018  * @subpackage Amazon
0019  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0020  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0021  * @version    $Id$
0022  */
0023 
0024 /**
0025  * @see Zend_Rest_Client
0026  */
0027 // require_once 'Zend/Rest/Client.php';
0028 
0029 /** @see Zend_Xml_Security */
0030 // require_once 'Zend/Xml/Security.php';
0031 
0032 /**
0033  * @category   Zend
0034  * @package    Zend_Service
0035  * @subpackage Amazon
0036  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0037  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0038  */
0039 class Zend_Service_Amazon
0040 {
0041     /**
0042      * Amazon Web Services Access Key ID
0043      *
0044      * @var string
0045      */
0046     public $appId;
0047 
0048     /**
0049      * @var string
0050      */
0051     protected $_secretKey = null;
0052 
0053     /**
0054      * @var string
0055      */
0056     protected $_baseUri = null;
0057 
0058     /**
0059      * List of Amazon Web Service base URLs, indexed by country code
0060      *
0061      * @var array
0062      */
0063     protected $_baseUriList = array('US' => 'http://webservices.amazon.com',
0064                                     'UK' => 'http://webservices.amazon.co.uk',
0065                                     'DE' => 'http://webservices.amazon.de',
0066                                     'JP' => 'http://webservices.amazon.co.jp',
0067                                     'FR' => 'http://webservices.amazon.fr',
0068                                     'CA' => 'http://webservices.amazon.ca');
0069 
0070     /**
0071      * Reference to REST client object
0072      *
0073      * @var Zend_Rest_Client
0074      */
0075     protected $_rest = null;
0076 
0077 
0078     /**
0079      * Constructs a new Amazon Web Services Client
0080      *
0081      * @param  string $appId       Developer's Amazon appid
0082      * @param  string $countryCode Country code for Amazon service; may be US, UK, DE, JP, FR, CA
0083      * @throws Zend_Service_Exception
0084      * @return Zend_Service_Amazon
0085      */
0086     public function __construct($appId, $countryCode = 'US', $secretKey = null)
0087     {
0088         $this->appId = (string) $appId;
0089         $this->_secretKey = $secretKey;
0090 
0091         $countryCode = (string) $countryCode;
0092         if (!isset($this->_baseUriList[$countryCode])) {
0093             /**
0094              * @see Zend_Service_Exception
0095              */
0096             // require_once 'Zend/Service/Exception.php';
0097             throw new Zend_Service_Exception("Unknown country code: $countryCode");
0098         }
0099 
0100         $this->_baseUri = $this->_baseUriList[$countryCode];
0101     }
0102 
0103 
0104     /**
0105      * Search for Items
0106      *
0107      * @param  array $options Options to use for the Search Query
0108      * @throws Zend_Service_Exception
0109      * @return Zend_Service_Amazon_ResultSet
0110      * @see http://www.amazon.com/gp/aws/sdk/main.html/102-9041115-9057709?s=AWSEcommerceService&v=2011-08-01&p=ApiReference/ItemSearchOperation
0111      */
0112     public function itemSearch(array $options)
0113     {
0114         $client = $this->getRestClient();
0115         $client->setUri($this->_baseUri);
0116 
0117         $defaultOptions = array('ResponseGroup' => 'Small');
0118         $options = $this->_prepareOptions('ItemSearch', $options, $defaultOptions);
0119         $client->getHttpClient()->resetParameters();
0120         $response = $client->restGet('/onca/xml', $options);
0121 
0122         if ($response->isError()) {
0123             /**
0124              * @see Zend_Service_Exception
0125              */
0126             // require_once 'Zend/Service/Exception.php';
0127             throw new Zend_Service_Exception('An error occurred sending request. Status code: '
0128                                            . $response->getStatus());
0129         }
0130 
0131         $dom = new DOMDocument();
0132         $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
0133         self::_checkErrors($dom);
0134 
0135         /**
0136          * @see Zend_Service_Amazon_ResultSet
0137          */
0138         // require_once 'Zend/Service/Amazon/ResultSet.php';
0139         return new Zend_Service_Amazon_ResultSet($dom);
0140     }
0141 
0142 
0143     /**
0144      * Look up item(s) by ASIN
0145      *
0146      * @param  string $asin    Amazon ASIN ID
0147      * @param  array  $options Query Options
0148      * @see http://www.amazon.com/gp/aws/sdk/main.html/102-9041115-9057709?s=AWSEcommerceService&v=2011-08-01&p=ApiReference/ItemLookupOperation
0149      * @throws Zend_Service_Exception
0150      * @return Zend_Service_Amazon_Item|Zend_Service_Amazon_ResultSet
0151      */
0152     public function itemLookup($asin, array $options = array())
0153     {
0154         $client = $this->getRestClient();
0155         $client->setUri($this->_baseUri);
0156         $client->getHttpClient()->resetParameters();
0157 
0158         $defaultOptions = array('ResponseGroup' => 'Small');
0159         $options['ItemId'] = (string) $asin;
0160         $options = $this->_prepareOptions('ItemLookup', $options, $defaultOptions);
0161         $response = $client->restGet('/onca/xml', $options);
0162 
0163         if ($response->isError()) {
0164             /**
0165              * @see Zend_Service_Exception
0166              */
0167             // require_once 'Zend/Service/Exception.php';
0168             throw new Zend_Service_Exception(
0169                 'An error occurred sending request. Status code: ' . $response->getStatus()
0170             );
0171         }
0172 
0173         $dom = new DOMDocument();
0174         $dom = Zend_Xml_Security::scan($response->getBody(), $dom);
0175         self::_checkErrors($dom);
0176         $xpath = new DOMXPath($dom);
0177         $xpath->registerNamespace('az', 'http://webservices.amazon.com/AWSECommerceService/2011-08-01');
0178         $items = $xpath->query('//az:Items/az:Item');
0179 
0180         if ($items->length == 1) {
0181             /**
0182              * @see Zend_Service_Amazon_Item
0183              */
0184             // require_once 'Zend/Service/Amazon/Item.php';
0185             return new Zend_Service_Amazon_Item($items->item(0));
0186         }
0187 
0188         /**
0189          * @see Zend_Service_Amazon_ResultSet
0190          */
0191         // require_once 'Zend/Service/Amazon/ResultSet.php';
0192         return new Zend_Service_Amazon_ResultSet($dom);
0193     }
0194 
0195 
0196     /**
0197      * Returns a reference to the REST client
0198      *
0199      * @return Zend_Rest_Client
0200      */
0201     public function getRestClient()
0202     {
0203         if($this->_rest === null) {
0204             $this->_rest = new Zend_Rest_Client();
0205         }
0206         return $this->_rest;
0207     }
0208 
0209     /**
0210      * Set REST client
0211      *
0212      * @param Zend_Rest_Client
0213      * @return Zend_Service_Amazon
0214      */
0215     public function setRestClient(Zend_Rest_Client $client)
0216     {
0217         $this->_rest = $client;
0218         return $this;
0219     }
0220 
0221 
0222     /**
0223      * Prepare options for request
0224      *
0225      * @param  string $query          Action to perform
0226      * @param  array  $options        User supplied options
0227      * @param  array  $defaultOptions Default options
0228      * @return array
0229      */
0230     protected function _prepareOptions($query, array $options, array $defaultOptions)
0231     {
0232         $options['AWSAccessKeyId'] = $this->appId;
0233         $options['Service']        = 'AWSECommerceService';
0234         $options['Operation']      = (string) $query;
0235         $options['Version']        = '2011-08-01';
0236 
0237         // de-canonicalize out sort key
0238         if (isset($options['ResponseGroup'])) {
0239             $responseGroup = explode(',', $options['ResponseGroup']);
0240 
0241             if (!in_array('Request', $responseGroup)) {
0242                 $responseGroup[] = 'Request';
0243                 $options['ResponseGroup'] = implode(',', $responseGroup);
0244             }
0245         }
0246 
0247         $options = array_merge($defaultOptions, $options);
0248 
0249         if($this->_secretKey !== null) {
0250             $options['Timestamp'] = gmdate("Y-m-d\TH:i:s\Z");;
0251             ksort($options);
0252             $options['Signature'] = self::computeSignature($this->_baseUri, $this->_secretKey, $options);
0253         }
0254 
0255         return $options;
0256     }
0257 
0258     /**
0259      * Compute Signature for Authentication with Amazon Product Advertising Webservices
0260      *
0261      * @param  string $baseUri
0262      * @param  string $secretKey
0263      * @param  array $options
0264      * @return string
0265      */
0266     static public function computeSignature($baseUri, $secretKey, array $options)
0267     {
0268         // require_once "Zend/Crypt/Hmac.php";
0269 
0270         $signature = self::buildRawSignature($baseUri, $options);
0271         return base64_encode(
0272             Zend_Crypt_Hmac::compute($secretKey, 'sha256', $signature, Zend_Crypt_Hmac::BINARY)
0273         );
0274     }
0275 
0276     /**
0277      * Build the Raw Signature Text
0278      *
0279      * @param  string $baseUri
0280      * @param  array $options
0281      * @return string
0282      */
0283     static public function buildRawSignature($baseUri, $options)
0284     {
0285         ksort($options);
0286         $params = array();
0287         foreach($options AS $k => $v) {
0288             $params[] = $k."=".rawurlencode($v);
0289         }
0290 
0291         return sprintf("GET\n%s\n/onca/xml\n%s",
0292             str_replace('http://', '', $baseUri),
0293             implode("&", $params)
0294         );
0295     }
0296 
0297 
0298     /**
0299      * Check result for errors
0300      *
0301      * @param  DOMDocument $dom
0302      * @throws Zend_Service_Exception
0303      * @return void
0304      */
0305     protected static function _checkErrors(DOMDocument $dom)
0306     {
0307         $xpath = new DOMXPath($dom);
0308         $xpath->registerNamespace('az', 'http://webservices.amazon.com/AWSECommerceService/2011-08-01');
0309 
0310         if ($xpath->query('//az:Error')->length >= 1) {
0311             $code = $xpath->query('//az:Error/az:Code/text()')->item(0)->data;
0312             $message = $xpath->query('//az:Error/az:Message/text()')->item(0)->data;
0313 
0314             switch($code) {
0315                 case 'AWS.ECommerceService.NoExactMatches':
0316                     break;
0317                 default:
0318                     /**
0319                      * @see Zend_Service_Exception
0320                      */
0321                     // require_once 'Zend/Service/Exception.php';
0322                     throw new Zend_Service_Exception("$message ($code)");
0323             }
0324         }
0325     }
0326 }