diff --git a/AmazonAPI.php b/AmazonAPI.php deleted file mode 100644 index 63626fc..0000000 --- a/AmazonAPI.php +++ /dev/null @@ -1,467 +0,0 @@ - 'webservices.amazon.ca/onca/xml', - 'cn' => 'webservices.amazon.cn/onca/xml', - 'de' => 'webservices.amazon.de/onca/xml', - 'es' => 'webservices.amazon.es/onca/xml', - 'fr' => 'webservices.amazon.fr/onca/xml', - 'it' => 'webservices.amazon.it/onca/xml', - 'jp' => 'webservices.amazon.jp/onca/xml', - 'uk' => 'webservices.amazon.co.uk/onca/xml', - 'us' => 'webservices.amazon.com/onca/xml', - ); - - // API key ID - private $m_keyId = NULL; - - // API Secret Key - private $m_secretKey = NULL; - - // AWS associate tag - private $m_associateTag = NULL; - - // Valid names that can be used for search - private $mValidSearchNames = array( - 'All', - 'Apparel', - 'Appliances', - 'Automotive', - 'Baby', - 'Beauty', - 'Blended', - 'Books', - 'Classical', - 'DVD', - 'Electronics', - 'Grocery', - 'HealthPersonalCare', - 'HomeGarden', - 'HomeImprovement', - 'Jewelry', - 'KindleStore', - 'Kitchen', - 'Lighting', - 'Marketplace', - 'MP3Downloads', - 'Music', - 'MusicTracks', - 'MusicalInstruments', - 'OfficeProducts', - 'OutdoorLiving', - 'Outlet', - 'PetSupplies', - 'PCHardware', - 'Shoes', - 'Software', - 'SoftwareVideoGames', - 'SportingGoods', - 'Tools', - 'Toys', - 'VHS', - 'Video', - 'VideoGames', - 'Watches' - ); - - private $mErrors = array(); - - public function __construct( $keyId, $secretKey, $associateTag ) - { - // Setup the AWS credentials - $this->m_keyId = $keyId; - $this->m_secretKey = $secretKey; - $this->m_associateTag = $associateTag; - - // Set UK as locale by default - $this->SetLocale( 'uk' ); - } - - /** - * Enable or disable SSL endpoints - * - * @param useSSL True if using SSL, false otherwise - * - * @return None - */ - public function SetSSL( $useSSL = true ) - { - $this->m_useSSL = $useSSL; - } - - /** - * Enable or disable retrieving items array rather than XML - * - * @param retrieveArray True if retrieving as array, false otherwise. - * - * @return None - */ - public function SetRetrieveAsArray( $retrieveArray = true ) - { - $this->m_retrieveArray = $retrieveArray; - } - - /** - * Sets the locale for the endpoints - * - * @param locale Set to a valid AWS locale - see link below. - * @link http://docs.aws.amazon.com/AWSECommerceService/latest/DG/Locales.html - * - * @return None - */ - public function SetLocale( $locale ) - { - // Check we have a locale in our table - if ( !array_key_exists( $locale, $this->m_localeTable ) ) - { - // If not then just assume it's US - $locale = 'us'; - } - - // Set the URL for this locale - $this->m_locale = $locale; - - // Check for SSL - if ( $this->m_useSSL ) - $this->m_amazonUrl = 'https://' . $this->m_localeTable[$locale]; - else - $this->m_amazonUrl = 'http://' . $this->m_localeTable[$locale]; - } - - /** - * Return valid search names - * - * @param None - * - * @return Array Array of valid string names - */ - public function GetValidSearchNames() - { - return( $this->mValidSearchNames ); - } - - /** - * Return data from AWS - * - * @param url URL request - * - * @return mixed SimpleXML object or false if failure. - */ - private function MakeRequest( $url ) - { - // Check if curl is installed - if ( !function_exists( 'curl_init' ) ) - { - $this->AddError( "Curl not available" ); - return( false ); - } - - // Use curl to retrieve data from Amazon - $session = curl_init( $url ); - curl_setopt( $session, CURLOPT_HEADER, false ); - curl_setopt( $session, CURLOPT_RETURNTRANSFER, true ); - $response = curl_exec( $session ); - - $error = NULL; - if ( $response === false ) - $error = curl_error( $session ); - - curl_close( $session ); - - // Have we had an error? - if ( !empty( $error ) ) - { - $this->AddError( "Error downloading data : $url : " . $error ); - return( false ); - } - - // Interpret data as XML - $parsedXml = simplexml_load_string( $response ); - - return( $parsedXml ); - } - - /** - * Search for items - * - * @param keywords Keywords which we're requesting - * @param searchIndex Name of search index (category) requested. NULL if searching all. - * @param sortBy Category to sort by, only used if searchIndex is not 'All' - * @param condition Condition of item. Valid conditions : Used, Collectible, Refurbished, All - * - * @return mixed SimpleXML object, array of data or false if failure. - */ - public function ItemSearch( $keywords, $searchIndex = NULL, $sortBy = NULL, $condition = 'New' ) - { - // Set the values for some of the parameters. - $operation = "ItemSearch"; - $responseGroup = "ItemAttributes,Offers,Images"; - - //Define the request - $request= $this->GetBaseUrl() - . "&Operation=" . $operation - . "&Keywords=" . $keywords - . "&ResponseGroup=" . $responseGroup - . "&Condition=" . $condition; - - // Assume we're searching in all if an index isn't passed - if ( empty( $searchIndex ) ) - { - // Search for all - $request .= "&SearchIndex=All"; - } - else - { - // Searching for specific index - $request .= "&SearchIndex=" . $searchIndex; - - // Set sort category - if ( $sortBy && ( $searchIndex != 'All' ) ) - $request .= "&Sort=" . $sortBy; - } - - // Need to sign the request now - $signedUrl = $this->GetSignedRequest( $this->m_secretKey, $request ); - - // Get the response from the signed URL - $parsedXml = $this->MakeRequest( $signedUrl ); - if ( $parsedXml === false ) - return( false ); - - if ( $this->m_retrieveArray ) - { - $items = $this->RetrieveItems( $parsedXml ); - } - else - { - $items = $parsedXml; - } - - return( $items ); - } - - /** - * Lookup items from ASINs - * - * @param asinList Either a single ASIN or an array of ASINs - * @param onlyFromAmazon True if only requesting items from Amazon and not 3rd party vendors - * - * @return mixed SimpleXML object, array of data or false if failure. - */ - public function ItemLookup( $asinList, $onlyFromAmazon = false ) - { - // Check if it's an array - if ( is_array( $asinList ) ) - { - $asinList = implode( ',', $asinList ); - } - - // Set the values for some of the parameters. - $operation = "ItemLookup"; - $responseGroup = "ItemAttributes,Offers,Reviews,Images,EditorialReview"; - - // Determine whether we just want Amazon results only or not - $merchantId = ( $onlyFromAmazon == true ) ? 'Amazon' : 'All'; - - $reviewSort = '-OverallRating'; - //Define the request - $request = $this->GetBaseUrl() - . "&ItemId=" . $asinList - . "&Operation=" . $operation - . "&ResponseGroup=" . $responseGroup - . "&ReviewSort=" . $reviewSort - . "&MerchantId=" . $merchantId; - - // Need to sign the request now - $signedUrl = $this->GetSignedRequest( $this->m_secretKey, $request ); - - // Get the response from the signed URL - $parsedXml = $this->MakeRequest( $signedUrl ); - if ( $parsedXml === false ) - return( false ); - - if ( $this->m_retrieveArray ) - { - $items = $this->RetrieveItems( $parsedXml ); - } - else - { - $items = $parsedXml; - } - return( $items ); - } - - /** - * Basic method to retrieve only requested item data as an array - * - * @param responseXML XML data to be passed - * - * @return Array Array of item data. Empty array if not found - */ - private function RetrieveItems( $responseXml ) - { - $items = array(); - if ( empty( $responseXml ) ) - { - $this->AddError( "No XML response found from AWS." ); - return( $items ); - } - - if ( empty( $responseXml->Items ) ) - { - $this->AddError( "No items found." ); - return( $items ); - } - - if ( $responseXml->Items->Request->IsValid != 'True' ) - { - $errorCode = $responseXml->Items->Request->Errors->Error->Code; - $errorMessage = $responseXml->Items->Request->Errors->Error->Message; - $error = "API ERROR ($errorCode) : $errorMessage"; - $this->AddError( $error ); - return( $items ); - } - - // Get each item - foreach( $responseXml->Items->Item as $responseItem ) - { - $item = array(); - $item['asin'] = (string) $responseItem->ASIN; - $item['url'] = (string) $responseItem->DetailPageURL; - $item['rrp'] = ( (float) $responseItem->ItemAttributes->ListPrice->Amount ) / 100.0; - $item['title'] = (string) $responseItem->ItemAttributes->Title; - - if ( $responseItem->OfferSummary ) - { - $item['lowestPrice'] = ( (float) $responseItem->OfferSummary->LowestNewPrice->Amount ) / 100.0; - } - else - { - $item['lowestPrice'] = 0.0; - } - - // Images - $item['largeImage'] = (string) $responseItem->LargeImage->URL; - $item['mediumImage'] = (string) $responseItem->MediumImage->URL; - $item['smallImage'] = (string) $responseItem->SmallImage->URL; - - array_push( $items, $item ); - } - - return( $items ); - } - - /** - * Determines the base address of the request - * - * @param None - * - * @return string Base URL of AWS request - */ - private function GetBaseUrl() - { - //Define the request - $request= - $this->m_amazonUrl - . "?Service=AWSECommerceService" - . "&AssociateTag=" . $this->m_associateTag - . "&AWSAccessKeyId=" . $this->m_keyId; - - return( $request ); - } - - /** - * This function will take an existing Amazon request and change it so that it will be usable - * with the new authentication. - * - * @param string $secret_key - your Amazon AWS secret key - * @param string $request - your existing request URI - * @param string $access_key - your Amazon AWS access key - * @param string $version - (optional) the version of the service you are using - * - * @link http://www.ilovebonnie.net/2009/07/27/amazon-aws-api-rest-authentication-for-php-5/ - */ - private function GetSignedRequest( $secret_key, $request, $access_key = false, $version = '2011-08-01') - { - // Get a nice array of elements to work with - $uri_elements = parse_url($request); - - // Grab our request elements - $request = $uri_elements['query']; - - // Throw them into an array - parse_str($request, $parameters); - - // Add the new required paramters - $parameters['Timestamp'] = gmdate( "Y-m-d\TH:i:s\Z" ); - $parameters['Version'] = $version; - if ( strlen($access_key) > 0 ) - { - $parameters['AWSAccessKeyId'] = $access_key; - } - - // The new authentication requirements need the keys to be sorted - ksort( $parameters ); - - // Create our new request - foreach ( $parameters as $parameter => $value ) - { - // We need to be sure we properly encode the value of our parameter - $parameter = str_replace( "%7E", "~", rawurlencode( $parameter ) ); - $value = str_replace( "%7E", "~", rawurlencode( $value ) ); - $request_array[] = $parameter . '=' . $value; - } - - // Put our & symbol at the beginning of each of our request variables and put it in a string - $new_request = implode( '&', $request_array ); - - // Create our signature string - $signature_string = "GET\n{$uri_elements['host']}\n{$uri_elements['path']}\n{$new_request}"; - - // Create our signature using hash_hmac - $signature = urlencode( base64_encode( hash_hmac( 'sha256', $signature_string, $secret_key, true ) ) ); - - // Return our new request - return "http://{$uri_elements['host']}{$uri_elements['path']}?{$new_request}&Signature={$signature}"; - } - - /** - * Adds error to an error array - * - * @param error Error string - * - * @return None - */ - private function AddError( $error ) - { - array_push( $this->mErrors, $error ); - } - - /** - * Returns array of errors - * - * @param None - * - * @return Array Array of errors. Empty array if none found - */ - public function GetErrors() - { - return( $this->mErrors ); - } -} -?> diff --git a/README.md b/README.md index 6bbb9d4..732044f 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,19 @@ # AmazonProductAPI PHP library to perform product lookup and searches using the Amazon Product API. -## Dependencies -Requires the [SimpleXML](http://php.net/manual/en/book.simplexml.php) PHP and [Curl](http://php.net/manual/en/book.curl.php) extensions to be installed. -It also assumes that you have some knowledge of Amazon's Product API and have set up an Amazon Associate and [Amazon Web Services](http://docs.amazonwebservices.com/AWSECommerceService/2011-08-01/GSG/GettingSetUp.html) account in order to retrieve your access keys. - ## Installation -Clone the git repository: + +This library requires the [SimpleXML](http://php.net/manual/en/book.simplexml.php) and [Curl](http://php.net/manual/en/book.curl.php) extensions to be installed and uses PHP 7+ . Installation is simple using [Composer](https://composer.io): ```shell -git clone https://github.com/MarcL/AmazonProductAPI.git +composer require marcl\amazonproductapi ``` +### Amazon Product API +It also assumes that you have some basic knowledge of Amazon's Product API and have set up an Amazon Associate account see: [Amazon Product API Set Up](http://docs.amazonwebservices.com/AWSECommerceService/2011-08-01/GSG/GettingSetUp.html). + +You'll need an AWS key, secret key, and associate tag. Ensure that you keep these safe! + ## Examples I've added some simple examples in `examples.php`. To run them create a file called `secretKeys.php` containing your secret keys: @@ -30,35 +32,41 @@ and then run the examples with: php examples.php ``` -## Usage -Include the library in your code: +## Quick Start + +Include the library in your code using the Composer autoloader and create an AmazonUrlBuilder with your credentials ```php -include_once('./AmazonAPI.php'); -``` +require('vendor/autoload.php'); -Instantiate the class using your secret keys: +use MarcL\AmazonAPI; +use MarcL\AmazonUrlBuilder; -```php // Keep these safe $keyId = 'YOUR-AWS-KEY'; $secretKey = 'YOUR-AWS-SECRET-KEY'; $associateId = 'YOUR-AMAZON-ASSOCIATE-ID'; -$amazonAPI = new AmazonAPI($keyId, $secretKey, $associateId); +// Setup a new instance of the AmazonUrlBuilder with your keys +$urlBuilder = new AmazonUrlBuilder( + $keyId, + $secretKey, + $associateId, + 'uk' +); + +// Setup a new instance of the AmazonAPI and define the type of response +$amazonAPI = new AmazonAPI($urlBuilder, 'simple'); + +$items = $amazonAPI->ItemSearch('harry potter', 'Books', 'price'); + ``` **Note:** Keep your Amazon keys safe. Either use environment variables or include from a file that you don't check into GitHub. ### Locale -This library supports all [Product Advertising API locales](http://docs.aws.amazon.com/AWSECommerceService/latest/DG/Locales.html) and you can set them using `SetLocale`: - -It defaults to UK but to set the locale call `SetLocale()` __before__ calling the product methods. E.g. - -```php -$amazonAPI->SetLocale('uk'); -``` +This library supports all [Product Advertising API locales](http://docs.aws.amazon.com/AWSECommerceService/latest/DG/Locales.html) and you can set it as you construct the AmazonUrlBuilder class with your keys. At this time, these are the current supported locales: @@ -75,16 +83,6 @@ At this time, these are the current supported locales: * United Kingdom ('uk') * United States ('us') -### SSL - -By default it will use HTTPS, but if you don't want to use SSL then call the following before using the product methods and it will connect to the HTTP endpoints: - -```php -$amazonAPI->SetSSL(false); -``` - -**Note:** I have no idea why I originally had this method. Perhaps the Amazon Product API didn't use SSL at one point. I've enabled HTTPS as default now but you can turn it off if you need to. I assume you won't need to but I've left it in the API. - ### Item Search To search for an item use the `ItemSearch()` method: @@ -127,12 +125,12 @@ $asinIds = array('B003U6I396', 'B003U6I397', 'B003U6I398'); $items = $amazonAPI->ItemLookUp($asinIds); ``` -### Returned data -By default the data will be returned as SimpleXML nodes. However if you call `SetRetrieveAsArray()` then a simplified array of items will be returned. For example: +### Data Transformation +By default the data will be returned as SimpleXML nodes. However, you can ask for the data to be transformed differently, depending on your use case for the API. Pass a type when instantiating the AmazonAPI class as follows: ```php -// Return XML data -$amazonAPI = new AmazonAPI($keyId, $secretKey, $associateId); +// Default return type is XML +$amazonAPI = new AmazonAPI($amazonUrlBuilder); $items = $amazonAPI->ItemSearch('harry potter'); var_dump($items); ``` @@ -154,13 +152,12 @@ class SimpleXMLElement#2 (2) { ```php // Return simplified data -$amazonAPI = new AmazonAPI($keyId, $secretKey, $associateId); -$amazonAPI->SetRetrieveAsArray(); +$amazonAPI = new AmazonAPI($amazonUrlBuilder, 'simple'); $items = $amazonAPI->ItemSearch('harry potter'); var_dump($items); ``` -Returning simplified data gives a PHP array +This will return a simplified version of each item with minimal data but enough for simple use cases. ``` array(10) { @@ -196,16 +193,21 @@ array(10) { … ``` +The different data transformation types are defined as follows. Feel free to raise an issue if you'd like the data transforming to a new type. + +* **xml** - (Default) returns data as SimpleXML nodes. +* **array** - Returns data as PHP arrays and objects. +* **simple** - Returns data as simplified arrays and doesn't contain all API data. Use this if you just need prices, title and images. +* **json** - Returns data as a JSON string. Use this for returning from a server API endpoint. + ## TODO * Need to make the simplified data less hardcoded! -* Make this a Composer package -* Add unit tests ## Thanks -This library uses code based on [AWS API authentication For PHP](http://randomdrake.com/2009/07/27/amazon-aws-api-rest-authentication-for-php-5/) by [David Drake](https://github.com/randomdrake). +This library uses code based on [AWS API authentication For PHP](http://randomdrake.com/2009/07/27/amazon-aws-api-rest-authentication-for-php-5/) by [David Drake](https://github.com/randomdrake) but has been mostly rewritten. ## LICENSE -See [LICENSE](LICENSE) +See [LICENSE](LICENSE) \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..a28e5db --- /dev/null +++ b/composer.json @@ -0,0 +1,34 @@ +{ + "name": "marcl/amazonproductapi", + "description": "PHP library to perform product lookup and searches using the Amazon Product API.", + "version": "3.0.0", + "type": "library", + "keywords": ["amazon", "product", "api"], + "homepage": "https://github.com/MarcL/AmazonProductAPI/", + "license": "MIT", + "authors": [ + { + "name": "Marc Littlemore", + "email": "marc@marclittlemore.com", + "homepage": "http://www.marclittlemore.com", + "role": "Developer" + } + ], + "support": { + "source": "https://github.com/MarcL/AmazonProductAPI/", + "issues": "https://github.com/MarcL/AmazonProductAPI/issues" + }, + "require-dev": { + "phpunit/phpunit": "6.1.*" + }, + "autoload": { + "psr-4": { + "MarcL\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "MarcL\\": "src/", + "tests\\": "tests/" + } + }} \ No newline at end of file diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..950cd5b --- /dev/null +++ b/composer.lock @@ -0,0 +1,1467 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "677407d26dd1e9c0fcf31bd69cd2698c", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/8e6e04167378abf1ddb4d3522d8755c5fd90d102", + "reference": "8e6e04167378abf1ddb4d3522d8755c5fd90d102", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-04-12T18:52:22+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2017-03-05T17:38:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27T11:43:31+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-09-30T07:12:33+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-11-25T06:54:22+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1|^2.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8 || ^5.6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2017-03-02T20:05:34+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "5.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "dc421f9ca5082a0c0cb04afb171c765f79add85b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/dc421f9ca5082a0c0cb04afb171c765f79add85b", + "reference": "dc421f9ca5082a0c0cb04afb171c765f79add85b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.0", + "phpunit/php-file-iterator": "^1.3", + "phpunit/php-text-template": "^1.2", + "phpunit/php-token-stream": "^1.4.11 || ^2.0", + "sebastian/code-unit-reverse-lookup": "^1.0", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "ext-xdebug": "^2.5", + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-xdebug": "^2.5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2017-04-21T08:03:57+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2016-10-03T07:40:28+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.11", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-02-27T10:12:30+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "6.1.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "42b7f394a8e009516582331b1e03a1aba40175d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/42b7f394a8e009516582331b1e03a1aba40175d1", + "reference": "42b7f394a8e009516582331b1e03a1aba40175d1", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.3", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.0", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^5.2", + "phpunit/php-file-iterator": "^1.4", + "phpunit/php-text-template": "^1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^4.0", + "sebastian/comparator": "^2.0", + "sebastian/diff": "^1.4.3 || ^2.0", + "sebastian/environment": "^3.0.2", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^1.1 || ^2.0", + "sebastian/object-enumerator": "^3.0.2", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2", + "phpunit/dbunit": "<3.0" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "^1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-05-22T07:45:30+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4", + "reference": "d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^3.0" + }, + "conflict": { + "phpunit/phpunit": "<6.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2017-06-30T08:15:21+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "20f84f468cb67efee293246e6a09619b891f55f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/20f84f468cb67efee293246e6a09619b891f55f0", + "reference": "20f84f468cb67efee293246e6a09619b891f55f0", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/diff": "^1.2", + "sebastian/exporter": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-03-03T06:26:08+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2017-05-22T07:24:03+00:00" + }, + { + "name": "sebastian/environment", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2017-07-01T08:51:00+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2017-04-03T13:19:02+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/31dd3379d16446c5d86dec32ab1ad1f378581ad8", + "reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-03-12T15:17:29+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2016-11-23T20:04:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/examples.php b/examples.php index 4be40e3..d140e52 100644 --- a/examples.php +++ b/examples.php @@ -1,16 +1,26 @@ SetLocale('uk'); -$amazonAPI->SetSSL(true); -$amazonAPI->SetRetrieveAsArray(); +$amazonAPI = new AmazonAPI($urlBuilder, 'simple'); + +// Need to avoid triggering Amazon API throttling +$sleepTime = 1.5; // Item Search: // Harry Potter in Books, sort by featured @@ -18,13 +28,24 @@ print('>> Harry Potter in Books, sort by featured'); var_dump($items); +sleep($sleepTime); + // Harry Potter in Books, sort by price low to high $items = $amazonAPI->ItemSearch('harry potter', 'Books', 'price'); print('>> Harry Potter in Books, sort by price low to high'); var_dump($items); +sleep($sleepTime); + // Harry Potter in Books, sort by price high to low $items = $amazonAPI->ItemSearch('harry potter', 'Books', '-price'); print('>> Harry Potter in Books, sort by price high to low'); var_dump($items); + +sleep($sleepTime); + +// Amazon echo, lookup only with Amazon as a seller +$items = $amazonAPI->ItemLookUp('B01GAGVIE4', true); +print('>> Look up specific ASIN\n'); +var_dump($items); ?> \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..2067b6e --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,8 @@ + + + + + ./tests/ + + + \ No newline at end of file diff --git a/src/AmazonAPI.php b/src/AmazonAPI.php new file mode 100644 index 0000000..96b4901 --- /dev/null +++ b/src/AmazonAPI.php @@ -0,0 +1,151 @@ +urlBuilder = $urlBuilder; + $this->dataTransformer = DataTransformerFactory::create($outputType); + } + + public function GetValidSearchNames() { + return $this->mValidSearchNames; + } + + /** + * Search for items + * + * @param keywords Keywords which we're requesting + * @param searchIndex Name of search index (category) requested. NULL if searching all. + * @param sortBy Category to sort by, only used if searchIndex is not 'All' + * @param condition Condition of item. Valid conditions : Used, Collectible, Refurbished, All + * + * @return mixed SimpleXML object, array of data or false if failure. + */ + public function ItemSearch($keywords, $searchIndex = NULL, $sortBy = NULL, $condition = 'New') { + $params = array( + 'Operation' => 'ItemSearch', + 'ResponseGroup' => 'ItemAttributes,Offers,Images', + 'Keywords' => $keywords, + 'Condition' => $condition, + 'SearchIndex' => empty($searchIndex) ? 'All' : $searchIndex, + 'Sort' => $sortBy && ($searchIndex != 'All') ? $sortBy : NULL + ); + + return $this->MakeAndParseRequest($params); + } + + /** + * Lookup items from ASINs + * + * @param asinList Either a single ASIN or an array of ASINs + * @param onlyFromAmazon True if only requesting items from Amazon and not 3rd party vendors + * + * @return mixed SimpleXML object, array of data or false if failure. + */ + public function ItemLookup($asinList, $onlyFromAmazon = false) { + if (is_array($asinList)) { + $asinList = implode(',', $asinList); + } + + $params = array( + 'Operation' => 'ItemLookup', + 'ResponseGroup' => 'ItemAttributes,Offers,Reviews,Images,EditorialReview', + 'ReviewSort' => '-OverallRating', + 'ItemId' => $asinList, + 'MerchantId' => ($onlyFromAmazon == true) ? 'Amazon' : 'All' + ); + + return $this->MakeAndParseRequest($params); + } + + public function GetErrors() { + return $this->mErrors; + } + + private function AddError($error) { + array_push($this->mErrors, $error); + } + + private function MakeAndParseRequest($params) { + $signedUrl = $this->urlBuilder->generate($params); + + try { + $request = new CurlHttpRequest(); + $response = $request->execute($signedUrl); + + $parsedXml = simplexml_load_string($response); + + return($parsedXml); + } catch(\Exception $error) { + $this->AddError("Error downloading data : $signedUrl : " . $error->getMessage()); + } + + if ($parsedXml === false) { + return false; + } + + return $this->dataTransformer->execute($parsedXml); + } +} +?> diff --git a/src/AmazonUrlBuilder.php b/src/AmazonUrlBuilder.php new file mode 100644 index 0000000..04627a1 --- /dev/null +++ b/src/AmazonUrlBuilder.php @@ -0,0 +1,133 @@ + 'webservices.amazon.br/onca/xml', + 'ca' => 'webservices.amazon.ca/onca/xml', + 'cn' => 'webservices.amazon.cn/onca/xml', + 'fr' => 'webservices.amazon.fr/onca/xml', + 'de' => 'webservices.amazon.de/onca/xml', + 'in' => 'webservices.amazon.in/onca/xml', + 'it' => 'webservices.amazon.it/onca/xml', + 'jp' => 'webservices.amazon.co.jp/onca/xml', + 'mx' => 'webservices.amazon.com.mx/onca/xml', + 'es' => 'webservices.amazon.es/onca/xml', + 'uk' => 'webservices.amazon.co.uk/onca/xml', + 'us' => 'webservices.amazon.com/onca/xml' + ); + + private function throwIfNull($parameterValue, $parameterName) { + if ($parameterValue == NULL) { + throw new \Exception($parameterName . ' should be defined'); + } + } + + public function __construct($keyId, $secretKey, $associateTag, $locale = 'us') { + $this->throwIfNull($keyId, 'Amazon key ID'); + $this->throwIfNull($secretKey, 'Amazon secret key'); + $this->throwIfNull($associateTag, 'Amazon associate tag'); + + $this->secretKey = $secretKey; + $this->amazonEndpoint = $this->GetAmazonApiEndpoint($locale); + $this->associateTag = $associateTag; + $this->keyId = $keyId; + } + + private function GetAmazonApiEndpoint($locale) { + if (!array_key_exists($locale, $this->localeTable)) { + $locale = 'us'; + } + + return('https://' . $this->localeTable[$locale]); + } + + private function CreateUnsignedAmazonUrl($params) { + $baseParams = array( + 'Service' => 'AWSECommerceService', + 'AssociateTag' => $this->associateTag, + 'AWSAccessKeyId' => $this->keyId + ); + + $buildParams = array_merge($baseParams, $params); + + $request = $this->amazonEndpoint . '?' .http_build_query($buildParams); + + return($request); + } + + private function createSignature($signatureString) { + return urlencode( + base64_encode( + hash_hmac( + 'sha256', + $signatureString, + $this->secretKey, + true + ) + ) + ); + } + + /** + * This function will take an existing Amazon request and change it so that it will be usable + * with the new authentication. + * + * @param string $request - your existing request URI + * @param string $version - (optional) the version of the service you are using + * + * @link http://www.ilovebonnie.net/2009/07/27/amazon-aws-api-rest-authentication-for-php-5/ + */ + private function CreateSignedAwsRequest($request, $version = '2011-08-01') { + // Get a nice array of elements to work with + $uri_elements = parse_url($request); + + // Grab our request elements + $request = $uri_elements['query']; + + // Throw them into an array + parse_str($request, $parameters); + + // Add the new required paramters + $parameters['Timestamp'] = gmdate("Y-m-d\TH:i:s\Z"); + $parameters['Version'] = $version; + + // The new authentication requirements need the keys to be sorted + ksort($parameters); + + // Create our new request + foreach ($parameters as $parameter => $value) { + // We need to be sure we properly encode the value of our parameter + $parameter = str_replace("%7E", "~", rawurlencode($parameter)); + $value = str_replace("%7E", "~", rawurlencode($value)); + $requestArray[] = $parameter . '=' . $value; + } + + // Put our & symbol at the beginning of each of our request variables and put it in a string + $requestParameters = implode('&', $requestArray); + + // Create our signature string + $signatureString = "GET\n{$uri_elements['host']}\n{$uri_elements['path']}\n{$requestParameters}"; + $signature = $this->createSignature($signatureString); + + // Return our new request + $newUrl = "http://{$uri_elements['host']}{$uri_elements['path']}?{$requestParameters}&Signature={$signature}"; + return $newUrl; + } + + public function generate($params) { + $unsignedRequest = $this->CreateUnsignedAmazonUrl($params); + + return $this->CreateSignedAwsRequest($unsignedRequest); + } +} + +?> \ No newline at end of file diff --git a/src/CurlHttpRequest.php b/src/CurlHttpRequest.php new file mode 100644 index 0000000..6f4a876 --- /dev/null +++ b/src/CurlHttpRequest.php @@ -0,0 +1,41 @@ +error = curl_error($session); + } + + curl_close($session); + + if (!empty($error)) { + throw new \Exception($error); + } + + return($response); + } +} + +?> \ No newline at end of file diff --git a/src/Transformers/ArrayTransformer.php b/src/Transformers/ArrayTransformer.php new file mode 100644 index 0000000..797f038 --- /dev/null +++ b/src/Transformers/ArrayTransformer.php @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/src/Transformers/DataTransformerFactory.php b/src/Transformers/DataTransformerFactory.php new file mode 100644 index 0000000..751adc1 --- /dev/null +++ b/src/Transformers/DataTransformerFactory.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/src/Transformers/IDataTransformer.php b/src/Transformers/IDataTransformer.php new file mode 100644 index 0000000..45db901 --- /dev/null +++ b/src/Transformers/IDataTransformer.php @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/src/Transformers/JsonTransformer.php b/src/Transformers/JsonTransformer.php new file mode 100644 index 0000000..1c3e981 --- /dev/null +++ b/src/Transformers/JsonTransformer.php @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/src/Transformers/SimpleArrayTransformer.php b/src/Transformers/SimpleArrayTransformer.php new file mode 100644 index 0000000..1494dee --- /dev/null +++ b/src/Transformers/SimpleArrayTransformer.php @@ -0,0 +1,54 @@ +AddError("No XML response found from AWS."); + return($items); + } + + if (empty($xmlData->Items)) { + $this->AddError("No items found."); + return($items); + } + + if ($xmlData->Items->Request->IsValid != 'True') { + $errorCode = $xmlData->Items->Request->Errors->Error->Code; + $errorMessage = $xmlData->Items->Request->Errors->Error->Message; + $error = "API ERROR ($errorCode) : $errorMessage"; + $this->AddError($error); + return($items); + } + + // Get each item + foreach($xmlData->Items->Item as $responseItem) { + $item = array(); + $item['asin'] = (string) $responseItem->ASIN; + $item['url'] = (string) $responseItem->DetailPageURL; + $item['rrp'] = ((float) $responseItem->ItemAttributes->ListPrice->Amount) / 100.0; + $item['title'] = (string) $responseItem->ItemAttributes->Title; + + if ($responseItem->OfferSummary) { + $item['lowestPrice'] = ((float) $responseItem->OfferSummary->LowestNewPrice->Amount) / 100.0; + } + else { + $item['lowestPrice'] = 0.0; + } + + // Images + $item['largeImage'] = (string) $responseItem->LargeImage->URL; + $item['mediumImage'] = (string) $responseItem->MediumImage->URL; + $item['smallImage'] = (string) $responseItem->SmallImage->URL; + + array_push($items, $item); + } + + return($items); } +} + +?> \ No newline at end of file diff --git a/src/Transformers/XmlTransformer.php b/src/Transformers/XmlTransformer.php new file mode 100644 index 0000000..5a42f9d --- /dev/null +++ b/src/Transformers/XmlTransformer.php @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/tests/AmazonApiTest.php b/tests/AmazonApiTest.php new file mode 100644 index 0000000..da9ba0f --- /dev/null +++ b/tests/AmazonApiTest.php @@ -0,0 +1,11 @@ +assertEquals(true, true); + } +} +?> \ No newline at end of file diff --git a/tests/AmazonUrlBuilderTest.php b/tests/AmazonUrlBuilderTest.php new file mode 100644 index 0000000..9e850c4 --- /dev/null +++ b/tests/AmazonUrlBuilderTest.php @@ -0,0 +1,178 @@ +expectExceptionMessage('Amazon key ID should be defined'); + + $amazonUrlBuilder = new AmazonUrlBuilder(NULL, NULL, NULL); + } + + public function testShouldThrowExceptionIfMissingSecretKey() { + $this->expectExceptionMessage('Amazon secret key should be defined'); + + $amazonUrlBuilder = new AmazonUrlBuilder($this->defaultKeyId, NULL, NULL); + } + + public function testShouldThrowExceptionIfMissingAssociateTag() { + $this->expectExceptionMessage('Amazon associate tag should be defined'); + + $amazonUrlBuilder = new AmazonUrlBuilder($this->defaultKeyId, $this->defaultSecretKey, NULL); + } + + private function createDefaultUrlBuilder($locale = 'us') { + return new AmazonUrlBuilder( + $this->defaultKeyId, + $this->defaultSecretKey, + $this->defaultAssociateTag, + $locale + ); + } + + private function getUrlQueryParameterArray($url) { + $uriElements = parse_url($url); + $query = $uriElements['query']; + + parse_str($query, $parameters); + + return($parameters); + } + + public function testShouldBuildUrlWithExpectedDefaultTld() { + $amazonUrlBuilder = new AmazonUrlBuilder( + $this->defaultKeyId, + $this->defaultSecretKey, + $this->defaultAssociateTag + ); + $expectedTld = 'amazon.com'; + + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains($expectedTld, $url); + } + + public function testShouldBuildUrlWithExpectedGivenUKLocale() { + $amazonUrlBuilder = $this->createDefaultUrlBuilder('uk'); + $expectedTld = 'amazon.co.uk'; + + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains($expectedTld, $url); + } + + public function testShouldBuildUrlWithExpectedGivenJapaneseLocale() { + $amazonUrlBuilder = $this->createDefaultUrlBuilder('jp'); + $expectedTld = 'amazon.co.jp'; + + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains($expectedTld, $url); + } + + public function testShouldBuildUrlWithExpectedGivenMexicanLocale() { + $amazonUrlBuilder = $this->createDefaultUrlBuilder('mx'); + $expectedTld = 'amazon.com.mx'; + + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains($expectedTld, $url); + } + + public function testShouldBuildUrlWithExpectedGivenValidLocale() { + $amazonUrlBuilder = $this->createDefaultUrlBuilder('de'); + $expectedTld = 'amazon.de'; + + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains($expectedTld, $url); + } + + public function testShouldBuildUrlWithDefaultUSLocaleIfGivenLocaleIsUnknown() { + $amazonUrlBuilder = $this->createDefaultUrlBuilder('unknown'); + $expectedTld = 'amazon.com'; + + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains($expectedTld, $url); + } + + public function testShouldContainExpectedService() { + $amazonUrlBuilder = $this->createDefaultUrlBuilder(); + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains('Service=AWSECommerceService', $url); + } + + public function testShouldContainExpectedAssociateTag() { + $givenAssociateTag = 'given-associate-tag'; + $amazonUrlBuilder = new AmazonUrlBuilder( + $this->defaultKeyId, + $this->defaultSecretKey, + $givenAssociateTag + ); + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains('AssociateTag=' . $givenAssociateTag, $url); + } + + public function testShouldContainExpectedAwsAccessKeyId() { + $givenAwsAccessKeyId = 'givenAwsAccessKeyId'; + $amazonUrlBuilder = new AmazonUrlBuilder( + $givenAwsAccessKeyId, + $this->defaultSecretKey, + $this->defaultAssociateTag + ); + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains('AWSAccessKeyId=' . $givenAwsAccessKeyId, $url); + } + + public function testShouldContainExpectedVersion() { + $amazonUrlBuilder = $this->createDefaultUrlBuilder(); + $url = $amazonUrlBuilder->generate(array()); + + $this->assertContains('Version=2011-08-01', $url); + } + + public function testShouldContainValidTimestamp() { + $amazonUrlBuilder = $this->createDefaultUrlBuilder(); + $url = $amazonUrlBuilder->generate(array()); + + $parameters = $this->getUrlQueryParameterArray($url); + + $this->assertStringMatchesFormat('%d-%d-%dT%d:%d:%dZ', $parameters['Timestamp']); + } + + public function testShouldContainPassedParameter() { + $givenParameters = array( + 'Operation' => 'ItemLookup' + ); + $amazonUrlBuilder = $this->createDefaultUrlBuilder(); + $url = $amazonUrlBuilder->generate($givenParameters); + + $parameters = $this->getUrlQueryParameterArray($url); + + $this->assertContains('Operation=' . $givenParameters['Operation'], $url); + } + + public function testShouldContainPassedParameterWithCorrectEncoding() { + $givenParameters = array( + 'ResponseGroup' => 'ItemAttributes,Offers,Reviews,Images,EditorialReview', + ); + $amazonUrlBuilder = $this->createDefaultUrlBuilder(); + $url = $amazonUrlBuilder->generate($givenParameters); + + $expectedParameter = 'ResponseGroup=' . rawurlencode($givenParameters['ResponseGroup']); + + $parameters = $this->getUrlQueryParameterArray($url); + + $this->assertContains($expectedParameter, $url); + } +} +?> \ No newline at end of file