├── .gitignore ├── src └── AmazonWishlistExporter │ ├── Command │ ├── CommandInterface.php │ └── ExportCommand.php │ └── Logger │ ├── LoggerInterface.php │ └── StandardOutputLogger.php ├── .travis.yml ├── test └── AmazonWishlistExporter │ └── Test │ ├── Logger │ └── StandardOutputLoggerTest.php │ └── Command │ └── ExportCommandTest.php ├── phpunit.dist.xml ├── composer.json ├── README.md ├── awx └── composer.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.csv 3 | vendor 4 | phpunit.xml -------------------------------------------------------------------------------- /src/AmazonWishlistExporter/Command/CommandInterface.php: -------------------------------------------------------------------------------- 1 | expectOutputString("$messageFixture\n"); 13 | $logger = new StandardOutputLogger(); 14 | $logger->log($messageFixture); 15 | } 16 | } -------------------------------------------------------------------------------- /phpunit.dist.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | test 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yuriteixeira/amazon-wishlist-exporter", 3 | "description": "Simple script that parses a public amazon wishlist and export the items to a CSV file.", 4 | "keywords": [ 5 | "amazon", 6 | "wishlist", 7 | "export", 8 | "csv" 9 | ], 10 | "bin": [ 11 | "awx" 12 | ], 13 | "config": { 14 | "bin-dir": "bin" 15 | }, 16 | "autoload": { 17 | "psr-0": { 18 | "AmazonWishlistExporter": "src/", 19 | "AmazonWishlistExporter\\Test": "test/" 20 | } 21 | }, 22 | "require": { 23 | "guzzlehttp/guzzle": "*", 24 | "symfony/dom-crawler": "*", 25 | "symfony/css-selector": "*" 26 | }, 27 | "require-dev": { 28 | "phpunit/phpunit": "3.7.*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Amazon Wishlist Exporter 2 | 3 | [![Build Status](https://travis-ci.org/yuriteixeira/amazon-wishlist-exporter.svg?branch=master)](https://travis-ci.org/yuriteixeira/amazon-wishlist-exporter) 4 | 5 | Simple script that parses a public amazon wishlist and export the items to a CSV file. 6 | 7 | ## Requirements 8 | 9 | - PHP 5.4 10 | 11 | ## Installing 12 | 13 | - Clone this repository 14 | - Go to the cloned repo directory 15 | - Download composer: `php -r "readfile('https://getcomposer.org/installer');" | php` 16 | - Run `php composer.phar install` 17 | 18 | ## Running 19 | 20 | - Just type inside the cloned repo directory: `./awx ` (you can get the id visiting your wishlist, it's part of the URL). 21 | 22 | 23 | ## Next steps 24 | 25 | - Export to Google Docs (with images of the products, options to convert the price into any other currency) 26 | - Access private lists 27 | -------------------------------------------------------------------------------- /awx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | execute(); 35 | 36 | // Saving each item row to the file 37 | $fh = fopen($pathToSave, 'w'); 38 | 39 | foreach ($items as $item) { 40 | fputcsv($fh, $item); 41 | } 42 | 43 | fclose($fh); -------------------------------------------------------------------------------- /src/AmazonWishlistExporter/Command/ExportCommand.php: -------------------------------------------------------------------------------- 1 | countryCode = $countryCode; 38 | $this->whishlistId = $wishlistId; 39 | $this->client = $client; 40 | $this->logger = $logger; 41 | } 42 | 43 | public function execute() 44 | { 45 | $page = 1; 46 | $lastItemsContent = null; 47 | $rows = []; 48 | $baseUrl = $this->getBaseUrlForCountry($this->countryCode); 49 | $wishlistBaseUrl = "{$baseUrl}/registry/wishlist/{$this->whishlistId}?layout=standard"; 50 | 51 | if (!$baseUrl) { 52 | throw new \InvalidArgumentException("Country code {$this->countryCode} is not supported."); 53 | } 54 | 55 | $this->logger->log("Exporting: {$wishlistBaseUrl}"); 56 | 57 | while (true) { 58 | $url = "{$wishlistBaseUrl}&page={$page}"; 59 | $response = $this->client->get($url); 60 | $responseContent = (string) $response->getBody(); 61 | $crawler = new Crawler($responseContent); 62 | $items = $crawler->filter('[id^=item_]'); 63 | 64 | if ($response->getStatusCode() != 200 || !$items->count()) { 65 | $this->logger->log('Empty content (are you sure that you set your list as public?)'); 66 | break; 67 | } 68 | 69 | if ($items->text() == $lastItemsContent) { 70 | $this->logger->log('Current content is repeating last content'); 71 | break; 72 | } 73 | 74 | $items->each(function (Crawler $item) use (&$rows, $baseUrl) { 75 | $name = trim($item->filter('[id^=itemName_]')->text()); 76 | $price = (float) str_replace('$', '', trim($item->filter('[id^=itemPrice_]')->text())); 77 | 78 | $url = 79 | $item->filter('[id^=itemName_]')->attr('href') ? 80 | $baseUrl . $item->filter('[id^=itemName_]')->attr('href') : 81 | $item->filter('[id^=itemInfo_] .a-link-normal')->attr('href'); 82 | 83 | $image = trim($item->filter('[id^=itemImage_] img')->attr('src')); 84 | $rows[] = array($name, $price, $url, $image); 85 | }); 86 | 87 | $this->logger->log("Parsed page {$page} - Url: {$url}"); 88 | 89 | $lastItemsContent = $items->text(); 90 | ++$page; 91 | } 92 | 93 | $this->logger->log("Finished"); 94 | 95 | return $rows; 96 | } 97 | 98 | /** 99 | * @param $countryCode 100 | * @return string|null 101 | */ 102 | private function getBaseUrlForCountry($countryCode) 103 | { 104 | $baseUrlsByCountry = [ 105 | 'US' => 'http://www.amazon.com', 106 | 'UK' => 'http://www.amazon.co.uk', 107 | ]; 108 | 109 | $baseUrl = !empty($baseUrlsByCountry[$countryCode]) ? $baseUrlsByCountry[$countryCode] : null; 110 | 111 | return $baseUrl; 112 | } 113 | } -------------------------------------------------------------------------------- /test/AmazonWishlistExporter/Test/Command/ExportCommandTest.php: -------------------------------------------------------------------------------- 1 | clientMock = $this->getMock('\\GuzzleHttp\\ClientInterface'); 37 | $this->loggerMock = $this->getMock('\\AmazonWishlistExporter\\Logger\\LoggerInterface'); 38 | 39 | $this->responseContentPage1Fixture = << 41 | Product 1 42 |
$ 1.99
43 |
44 | 45 |
46 | Product 2 47 |
$ 2.99
48 |
49 |
50 |
51 | Product 3 52 |
$ 3.99
53 |
54 |
55 | RESPONSE; 56 | 57 | $this->responseContentPage2Fixture = << 59 | Product 4 60 |
$ 4.99
61 |
62 | 63 |
64 | Product 5 65 |
$ 5.99
66 |
67 |
68 |
69 | Product 6 70 |
$ 6.99
71 |
72 |
73 | RESPONSE; 74 | 75 | $this->responseContentPage3Fixture = << 77 | Product 7 78 |
$ 7.99
79 |
80 | 81 |
82 | Product 8 83 |
$ 8.99
84 |
85 |
86 |
87 | Product 9 88 |
$ 9.99
89 |
90 |
91 | RESPONSE; 92 | 93 | $this->unexpectedResponse = << 95 |

No donut for you...

96 | 97 | RESPONSE; 98 | } 99 | 100 | public function testExecuteWithInvalidArguments() 101 | { 102 | $this->setExpectedException('\\InvalidArgumentException'); 103 | $command = new ExportCommand('XX', 'ABC123', $this->clientMock, $this->loggerMock); 104 | $command->execute(); 105 | } 106 | 107 | public function testExecuteWithInvalidWishlistId() 108 | { 109 | $responseMock = $this->getMock('\\GuzzleHttp\\Message\\ResponseInterface'); 110 | $responseMock 111 | ->expects($this->once()) 112 | ->method('getStatusCode') 113 | ->will($this->returnValue(404)) 114 | ; 115 | 116 | $this->clientMock 117 | ->expects($this->once()) 118 | ->method('get') 119 | ->will($this->returnValue($responseMock)) 120 | ; 121 | 122 | // TODO: Check how to check multiple calls with different parameters 123 | $this->loggerMock 124 | ->expects($this->exactly(3)) 125 | ->method('log') 126 | ->withAnyParameters() 127 | ; 128 | 129 | $command = new ExportCommand('US', 'ABC123', $this->clientMock, $this->loggerMock); 130 | $rows = $command->execute(); 131 | $this->assertEmpty($rows); 132 | } 133 | 134 | public function testExecuteWithNotPublicWishlistOrUnexpectedContent() 135 | { 136 | $responseMock = $this->getMock('\\GuzzleHttp\\Message\\ResponseInterface'); 137 | $responseMock 138 | ->expects($this->once()) 139 | ->method('getStatusCode') 140 | ->will($this->returnValue(200)) 141 | ; 142 | 143 | $responseMock 144 | ->expects($this->exactly(1)) 145 | ->method('getBody') 146 | ->will($this->returnValue($this->unexpectedResponse)) 147 | ; 148 | 149 | $this->clientMock 150 | ->expects($this->once()) 151 | ->method('get') 152 | ->will($this->returnValue($responseMock)) 153 | ; 154 | 155 | // TODO: Check how to check multiple calls with different parameters 156 | $this->loggerMock 157 | ->expects($this->exactly(3)) 158 | ->method('log') 159 | ->withAnyParameters() 160 | ; 161 | 162 | $command = new ExportCommand('US', 'ABC123', $this->clientMock, $this->loggerMock); 163 | $rows = $command->execute(); 164 | $this->assertEmpty($rows); 165 | } 166 | 167 | public function testExecuteOnUsWithSinglePageOfItems() 168 | { 169 | $responseMock = $this->getMock('\\GuzzleHttp\\Message\\ResponseInterface'); 170 | $responseMock 171 | ->expects($this->exactly(2)) 172 | ->method('getStatusCode') 173 | ->will($this->returnValue(200)) 174 | ; 175 | 176 | $responseMock 177 | ->expects($this->exactly(2)) 178 | ->method('getBody') 179 | ->will($this->returnValue($this->responseContentPage1Fixture)) 180 | ; 181 | 182 | $this->clientMock 183 | ->expects($this->exactly(2)) 184 | ->method('get') 185 | ->will($this->returnValue($responseMock)) 186 | ; 187 | 188 | $this->loggerMock 189 | ->expects($this->exactly(4)) 190 | ->method('log') 191 | ->withAnyParameters() 192 | ; 193 | 194 | $command = new ExportCommand('US', 'ABC123', $this->clientMock, $this->loggerMock); 195 | $result = $command->execute(); 196 | 197 | $expectedResult = [ 198 | ['Product 1', 1.99, 'http://www.amazon.com/product-1', 'test://product-1.png'], 199 | ['Product 2', 2.99, 'http://www.amazon.com/product-2', 'test://product-2.png'], 200 | ['Product 3', 3.99, 'http://www.amazon.com/product-3', 'test://product-3.png'], 201 | ]; 202 | 203 | $this->assertEquals($expectedResult, $result); 204 | } 205 | 206 | public function testExecuteOnUkWithSinglePageOfItems() 207 | { 208 | $responseMock = $this->getMock('\\GuzzleHttp\\Message\\ResponseInterface'); 209 | $responseMock 210 | ->expects($this->exactly(2)) 211 | ->method('getStatusCode') 212 | ->will($this->returnValue(200)) 213 | ; 214 | 215 | $responseMock 216 | ->expects($this->exactly(2)) 217 | ->method('getBody') 218 | ->will($this->returnValue($this->responseContentPage1Fixture)) 219 | ; 220 | 221 | $this->clientMock 222 | ->expects($this->exactly(2)) 223 | ->method('get') 224 | ->will($this->returnValue($responseMock)) 225 | ; 226 | 227 | $this->loggerMock 228 | ->expects($this->exactly(4)) 229 | ->method('log') 230 | ->withAnyParameters() 231 | ; 232 | 233 | $command = new ExportCommand('UK', 'ABC123', $this->clientMock, $this->loggerMock); 234 | $result = $command->execute(); 235 | 236 | $expectedResult = [ 237 | ['Product 1', 1.99, 'http://www.amazon.co.uk/product-1', 'test://product-1.png'], 238 | ['Product 2', 2.99, 'http://www.amazon.co.uk/product-2', 'test://product-2.png'], 239 | ['Product 3', 3.99, 'http://www.amazon.co.uk/product-3', 'test://product-3.png'], 240 | ]; 241 | 242 | $this->assertEquals($expectedResult, $result); 243 | } 244 | 245 | public function testExecuteOnUsWithMultiplePagesOfItems() 246 | { 247 | $responseMock = $this->getMock('\\GuzzleHttp\\Message\\ResponseInterface'); 248 | $responseMock 249 | ->expects($this->exactly(4)) 250 | ->method('getStatusCode') 251 | ->will($this->returnValue(200)) 252 | ; 253 | 254 | $responseMock 255 | ->expects($this->exactly(4)) 256 | ->method('getBody') 257 | ->will($this->onConsecutiveCalls( 258 | $this->responseContentPage1Fixture, 259 | $this->responseContentPage2Fixture, 260 | $this->responseContentPage3Fixture, 261 | $this->responseContentPage3Fixture 262 | )) 263 | ; 264 | 265 | $this->clientMock 266 | ->expects($this->exactly(4)) 267 | ->method('get') 268 | ->will($this->returnValue($responseMock)) 269 | ; 270 | 271 | $this->loggerMock 272 | ->expects($this->exactly(6)) 273 | ->method('log') 274 | ->withAnyParameters() 275 | ; 276 | 277 | $command = new ExportCommand('US', 'ABC123', $this->clientMock, $this->loggerMock); 278 | $result = $command->execute(); 279 | 280 | $expectedResult = [ 281 | ['Product 1', 1.99, 'http://www.amazon.com/product-1', 'test://product-1.png'], 282 | ['Product 2', 2.99, 'http://www.amazon.com/product-2', 'test://product-2.png'], 283 | ['Product 3', 3.99, 'http://www.amazon.com/product-3', 'test://product-3.png'], 284 | ['Product 4', 4.99, 'http://www.amazon.com/product-4', 'test://product-4.png'], 285 | ['Product 5', 5.99, 'http://www.amazon.com/product-5', 'test://product-5.png'], 286 | ['Product 6', 6.99, 'http://www.amazon.com/product-6', 'test://product-6.png'], 287 | ['Product 7', 7.99, 'http://www.amazon.com/product-7', 'test://product-7.png'], 288 | ['Product 8', 8.99, 'http://www.amazon.com/product-8', 'test://product-8.png'], 289 | ['Product 9', 9.99, 'http://www.amazon.com/product-9', 'test://product-9.png'], 290 | ]; 291 | 292 | $this->assertEquals($expectedResult, $result); 293 | } 294 | 295 | public function testExecuteOnUkWithMultiplePagesOfItems() 296 | { 297 | $responseMock = $this->getMock('\\GuzzleHttp\\Message\\ResponseInterface'); 298 | $responseMock 299 | ->expects($this->exactly(4)) 300 | ->method('getStatusCode') 301 | ->will($this->returnValue(200)) 302 | ; 303 | 304 | $responseMock 305 | ->expects($this->exactly(4)) 306 | ->method('getBody') 307 | ->will($this->onConsecutiveCalls( 308 | $this->responseContentPage1Fixture, 309 | $this->responseContentPage2Fixture, 310 | $this->responseContentPage3Fixture, 311 | $this->responseContentPage3Fixture 312 | )) 313 | ; 314 | 315 | $this->clientMock 316 | ->expects($this->exactly(4)) 317 | ->method('get') 318 | ->will($this->returnValue($responseMock)) 319 | ; 320 | 321 | $this->loggerMock 322 | ->expects($this->exactly(6)) 323 | ->method('log') 324 | ->withAnyParameters() 325 | ; 326 | 327 | $command = new ExportCommand('UK', 'ABC123', $this->clientMock, $this->loggerMock); 328 | $result = $command->execute(); 329 | 330 | $expectedResult = [ 331 | ['Product 1', 1.99, 'http://www.amazon.co.uk/product-1', 'test://product-1.png'], 332 | ['Product 2', 2.99, 'http://www.amazon.co.uk/product-2', 'test://product-2.png'], 333 | ['Product 3', 3.99, 'http://www.amazon.co.uk/product-3', 'test://product-3.png'], 334 | ['Product 4', 4.99, 'http://www.amazon.co.uk/product-4', 'test://product-4.png'], 335 | ['Product 5', 5.99, 'http://www.amazon.co.uk/product-5', 'test://product-5.png'], 336 | ['Product 6', 6.99, 'http://www.amazon.co.uk/product-6', 'test://product-6.png'], 337 | ['Product 7', 7.99, 'http://www.amazon.co.uk/product-7', 'test://product-7.png'], 338 | ['Product 8', 8.99, 'http://www.amazon.co.uk/product-8', 'test://product-8.png'], 339 | ['Product 9', 9.99, 'http://www.amazon.co.uk/product-9', 'test://product-9.png'], 340 | ]; 341 | 342 | $this->assertEquals($expectedResult, $result); 343 | } 344 | } -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" 5 | ], 6 | "hash": "7d630595ac7ff7ee12c4fd84013cbb9c", 7 | "packages": [ 8 | { 9 | "name": "guzzlehttp/guzzle", 10 | "version": "4.0.2", 11 | "source": { 12 | "type": "git", 13 | "url": "https://github.com/guzzle/guzzle.git", 14 | "reference": "40db53833aaea528347994acd4578d7b9b2211ee" 15 | }, 16 | "dist": { 17 | "type": "zip", 18 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/40db53833aaea528347994acd4578d7b9b2211ee", 19 | "reference": "40db53833aaea528347994acd4578d7b9b2211ee", 20 | "shasum": "" 21 | }, 22 | "require": { 23 | "guzzlehttp/streams": "~1.0", 24 | "php": ">=5.4.0" 25 | }, 26 | "require-dev": { 27 | "ext-curl": "*", 28 | "phpunit/phpunit": "~4.0", 29 | "psr/log": "~1.0" 30 | }, 31 | "type": "library", 32 | "extra": { 33 | "branch-alias": { 34 | "dev-master": "4.0.x-dev" 35 | } 36 | }, 37 | "autoload": { 38 | "psr-4": { 39 | "GuzzleHttp\\": "src/" 40 | }, 41 | "files": [ 42 | "src/functions.php" 43 | ] 44 | }, 45 | "notification-url": "https://packagist.org/downloads/", 46 | "license": [ 47 | "MIT" 48 | ], 49 | "authors": [ 50 | { 51 | "name": "Michael Dowling", 52 | "email": "mtdowling@gmail.com", 53 | "homepage": "https://github.com/mtdowling" 54 | } 55 | ], 56 | "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", 57 | "homepage": "http://guzzlephp.org/", 58 | "keywords": [ 59 | "client", 60 | "curl", 61 | "framework", 62 | "http", 63 | "http client", 64 | "rest", 65 | "web service" 66 | ], 67 | "time": "2014-04-16 17:33:22" 68 | }, 69 | { 70 | "name": "guzzlehttp/streams", 71 | "version": "1.1.0", 72 | "source": { 73 | "type": "git", 74 | "url": "https://github.com/guzzle/streams.git", 75 | "reference": "cf0c8c33ca95cc147efba4c714f630ee44767180" 76 | }, 77 | "dist": { 78 | "type": "zip", 79 | "url": "https://api.github.com/repos/guzzle/streams/zipball/cf0c8c33ca95cc147efba4c714f630ee44767180", 80 | "reference": "cf0c8c33ca95cc147efba4c714f630ee44767180", 81 | "shasum": "" 82 | }, 83 | "require": { 84 | "php": ">=5.4.0" 85 | }, 86 | "require-dev": { 87 | "phpunit/phpunit": "~4.0" 88 | }, 89 | "type": "library", 90 | "extra": { 91 | "branch-alias": { 92 | "dev-master": "1.0.x-dev" 93 | } 94 | }, 95 | "autoload": { 96 | "psr-4": { 97 | "GuzzleHttp\\Stream\\": "src/" 98 | }, 99 | "files": [ 100 | "src/functions.php" 101 | ] 102 | }, 103 | "notification-url": "https://packagist.org/downloads/", 104 | "license": [ 105 | "MIT" 106 | ], 107 | "authors": [ 108 | { 109 | "name": "Michael Dowling", 110 | "email": "mtdowling@gmail.com", 111 | "homepage": "https://github.com/mtdowling" 112 | } 113 | ], 114 | "description": "Provides a simple abstraction over streams of data (Guzzle 4+)", 115 | "homepage": "http://guzzlephp.org/", 116 | "keywords": [ 117 | "Guzzle", 118 | "stream" 119 | ], 120 | "time": "2014-04-03 04:48:24" 121 | }, 122 | { 123 | "name": "symfony/css-selector", 124 | "version": "v2.4.4", 125 | "target-dir": "Symfony/Component/CssSelector", 126 | "source": { 127 | "type": "git", 128 | "url": "https://github.com/symfony/CssSelector.git", 129 | "reference": "479a5b409723f596ffc3b5178034e4d76ce615b3" 130 | }, 131 | "dist": { 132 | "type": "zip", 133 | "url": "https://api.github.com/repos/symfony/CssSelector/zipball/479a5b409723f596ffc3b5178034e4d76ce615b3", 134 | "reference": "479a5b409723f596ffc3b5178034e4d76ce615b3", 135 | "shasum": "" 136 | }, 137 | "require": { 138 | "php": ">=5.3.3" 139 | }, 140 | "type": "library", 141 | "extra": { 142 | "branch-alias": { 143 | "dev-master": "2.4-dev" 144 | } 145 | }, 146 | "autoload": { 147 | "psr-0": { 148 | "Symfony\\Component\\CssSelector\\": "" 149 | } 150 | }, 151 | "notification-url": "https://packagist.org/downloads/", 152 | "license": [ 153 | "MIT" 154 | ], 155 | "authors": [ 156 | { 157 | "name": "Fabien Potencier", 158 | "email": "fabien@symfony.com", 159 | "homepage": "http://fabien.potencier.org", 160 | "role": "Lead Developer" 161 | }, 162 | { 163 | "name": "Symfony Community", 164 | "homepage": "http://symfony.com/contributors" 165 | }, 166 | { 167 | "name": "Jean-François Simon", 168 | "email": "jeanfrancois.simon@sensiolabs.com" 169 | } 170 | ], 171 | "description": "Symfony CssSelector Component", 172 | "homepage": "http://symfony.com", 173 | "time": "2014-04-18 20:37:09" 174 | }, 175 | { 176 | "name": "symfony/dom-crawler", 177 | "version": "v2.4.4", 178 | "target-dir": "Symfony/Component/DomCrawler", 179 | "source": { 180 | "type": "git", 181 | "url": "https://github.com/symfony/DomCrawler.git", 182 | "reference": "e94b29c7cac964e58c406408d238ceeaa3604e78" 183 | }, 184 | "dist": { 185 | "type": "zip", 186 | "url": "https://api.github.com/repos/symfony/DomCrawler/zipball/e94b29c7cac964e58c406408d238ceeaa3604e78", 187 | "reference": "e94b29c7cac964e58c406408d238ceeaa3604e78", 188 | "shasum": "" 189 | }, 190 | "require": { 191 | "php": ">=5.3.3" 192 | }, 193 | "require-dev": { 194 | "symfony/css-selector": "~2.0" 195 | }, 196 | "suggest": { 197 | "symfony/css-selector": "" 198 | }, 199 | "type": "library", 200 | "extra": { 201 | "branch-alias": { 202 | "dev-master": "2.4-dev" 203 | } 204 | }, 205 | "autoload": { 206 | "psr-0": { 207 | "Symfony\\Component\\DomCrawler\\": "" 208 | } 209 | }, 210 | "notification-url": "https://packagist.org/downloads/", 211 | "license": [ 212 | "MIT" 213 | ], 214 | "authors": [ 215 | { 216 | "name": "Fabien Potencier", 217 | "email": "fabien@symfony.com", 218 | "homepage": "http://fabien.potencier.org", 219 | "role": "Lead Developer" 220 | }, 221 | { 222 | "name": "Symfony Community", 223 | "homepage": "http://symfony.com/contributors" 224 | } 225 | ], 226 | "description": "Symfony DomCrawler Component", 227 | "homepage": "http://symfony.com", 228 | "time": "2014-04-18 20:37:09" 229 | } 230 | ], 231 | "packages-dev": [ 232 | { 233 | "name": "phpunit/php-code-coverage", 234 | "version": "1.2.17", 235 | "source": { 236 | "type": "git", 237 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 238 | "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34" 239 | }, 240 | "dist": { 241 | "type": "zip", 242 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", 243 | "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", 244 | "shasum": "" 245 | }, 246 | "require": { 247 | "php": ">=5.3.3", 248 | "phpunit/php-file-iterator": ">=1.3.0@stable", 249 | "phpunit/php-text-template": ">=1.2.0@stable", 250 | "phpunit/php-token-stream": ">=1.1.3@stable" 251 | }, 252 | "require-dev": { 253 | "phpunit/phpunit": "3.7.*@dev" 254 | }, 255 | "suggest": { 256 | "ext-dom": "*", 257 | "ext-xdebug": ">=2.0.5" 258 | }, 259 | "type": "library", 260 | "extra": { 261 | "branch-alias": { 262 | "dev-master": "1.2.x-dev" 263 | } 264 | }, 265 | "autoload": { 266 | "classmap": [ 267 | "PHP/" 268 | ] 269 | }, 270 | "notification-url": "https://packagist.org/downloads/", 271 | "include-path": [ 272 | "" 273 | ], 274 | "license": [ 275 | "BSD-3-Clause" 276 | ], 277 | "authors": [ 278 | { 279 | "name": "Sebastian Bergmann", 280 | "email": "sb@sebastian-bergmann.de", 281 | "role": "lead" 282 | } 283 | ], 284 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 285 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 286 | "keywords": [ 287 | "coverage", 288 | "testing", 289 | "xunit" 290 | ], 291 | "time": "2014-03-28 10:53:45" 292 | }, 293 | { 294 | "name": "phpunit/php-file-iterator", 295 | "version": "1.3.4", 296 | "source": { 297 | "type": "git", 298 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 299 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" 300 | }, 301 | "dist": { 302 | "type": "zip", 303 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", 304 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", 305 | "shasum": "" 306 | }, 307 | "require": { 308 | "php": ">=5.3.3" 309 | }, 310 | "type": "library", 311 | "autoload": { 312 | "classmap": [ 313 | "File/" 314 | ] 315 | }, 316 | "notification-url": "https://packagist.org/downloads/", 317 | "include-path": [ 318 | "" 319 | ], 320 | "license": [ 321 | "BSD-3-Clause" 322 | ], 323 | "authors": [ 324 | { 325 | "name": "Sebastian Bergmann", 326 | "email": "sb@sebastian-bergmann.de", 327 | "role": "lead" 328 | } 329 | ], 330 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 331 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 332 | "keywords": [ 333 | "filesystem", 334 | "iterator" 335 | ], 336 | "time": "2013-10-10 15:34:57" 337 | }, 338 | { 339 | "name": "phpunit/php-text-template", 340 | "version": "1.2.0", 341 | "source": { 342 | "type": "git", 343 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 344 | "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" 345 | }, 346 | "dist": { 347 | "type": "zip", 348 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", 349 | "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", 350 | "shasum": "" 351 | }, 352 | "require": { 353 | "php": ">=5.3.3" 354 | }, 355 | "type": "library", 356 | "autoload": { 357 | "classmap": [ 358 | "Text/" 359 | ] 360 | }, 361 | "notification-url": "https://packagist.org/downloads/", 362 | "include-path": [ 363 | "" 364 | ], 365 | "license": [ 366 | "BSD-3-Clause" 367 | ], 368 | "authors": [ 369 | { 370 | "name": "Sebastian Bergmann", 371 | "email": "sb@sebastian-bergmann.de", 372 | "role": "lead" 373 | } 374 | ], 375 | "description": "Simple template engine.", 376 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 377 | "keywords": [ 378 | "template" 379 | ], 380 | "time": "2014-01-30 17:20:04" 381 | }, 382 | { 383 | "name": "phpunit/php-timer", 384 | "version": "1.0.5", 385 | "source": { 386 | "type": "git", 387 | "url": "https://github.com/sebastianbergmann/php-timer.git", 388 | "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" 389 | }, 390 | "dist": { 391 | "type": "zip", 392 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", 393 | "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", 394 | "shasum": "" 395 | }, 396 | "require": { 397 | "php": ">=5.3.3" 398 | }, 399 | "type": "library", 400 | "autoload": { 401 | "classmap": [ 402 | "PHP/" 403 | ] 404 | }, 405 | "notification-url": "https://packagist.org/downloads/", 406 | "include-path": [ 407 | "" 408 | ], 409 | "license": [ 410 | "BSD-3-Clause" 411 | ], 412 | "authors": [ 413 | { 414 | "name": "Sebastian Bergmann", 415 | "email": "sb@sebastian-bergmann.de", 416 | "role": "lead" 417 | } 418 | ], 419 | "description": "Utility class for timing", 420 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 421 | "keywords": [ 422 | "timer" 423 | ], 424 | "time": "2013-08-02 07:42:54" 425 | }, 426 | { 427 | "name": "phpunit/php-token-stream", 428 | "version": "1.2.2", 429 | "source": { 430 | "type": "git", 431 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 432 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" 433 | }, 434 | "dist": { 435 | "type": "zip", 436 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", 437 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", 438 | "shasum": "" 439 | }, 440 | "require": { 441 | "ext-tokenizer": "*", 442 | "php": ">=5.3.3" 443 | }, 444 | "type": "library", 445 | "extra": { 446 | "branch-alias": { 447 | "dev-master": "1.2-dev" 448 | } 449 | }, 450 | "autoload": { 451 | "classmap": [ 452 | "PHP/" 453 | ] 454 | }, 455 | "notification-url": "https://packagist.org/downloads/", 456 | "include-path": [ 457 | "" 458 | ], 459 | "license": [ 460 | "BSD-3-Clause" 461 | ], 462 | "authors": [ 463 | { 464 | "name": "Sebastian Bergmann", 465 | "email": "sb@sebastian-bergmann.de", 466 | "role": "lead" 467 | } 468 | ], 469 | "description": "Wrapper around PHP's tokenizer extension.", 470 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 471 | "keywords": [ 472 | "tokenizer" 473 | ], 474 | "time": "2014-03-03 05:10:30" 475 | }, 476 | { 477 | "name": "phpunit/phpunit", 478 | "version": "3.7.37", 479 | "source": { 480 | "type": "git", 481 | "url": "https://github.com/sebastianbergmann/phpunit.git", 482 | "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc" 483 | }, 484 | "dist": { 485 | "type": "zip", 486 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", 487 | "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", 488 | "shasum": "" 489 | }, 490 | "require": { 491 | "ext-ctype": "*", 492 | "ext-dom": "*", 493 | "ext-json": "*", 494 | "ext-pcre": "*", 495 | "ext-reflection": "*", 496 | "ext-spl": "*", 497 | "php": ">=5.3.3", 498 | "phpunit/php-code-coverage": "~1.2", 499 | "phpunit/php-file-iterator": "~1.3", 500 | "phpunit/php-text-template": "~1.1", 501 | "phpunit/php-timer": "~1.0", 502 | "phpunit/phpunit-mock-objects": "~1.2", 503 | "symfony/yaml": "~2.0" 504 | }, 505 | "require-dev": { 506 | "pear-pear.php.net/pear": "1.9.4" 507 | }, 508 | "suggest": { 509 | "phpunit/php-invoker": "~1.1" 510 | }, 511 | "bin": [ 512 | "composer/bin/phpunit" 513 | ], 514 | "type": "library", 515 | "extra": { 516 | "branch-alias": { 517 | "dev-master": "3.7.x-dev" 518 | } 519 | }, 520 | "autoload": { 521 | "classmap": [ 522 | "PHPUnit/" 523 | ] 524 | }, 525 | "notification-url": "https://packagist.org/downloads/", 526 | "include-path": [ 527 | "", 528 | "../../symfony/yaml/" 529 | ], 530 | "license": [ 531 | "BSD-3-Clause" 532 | ], 533 | "authors": [ 534 | { 535 | "name": "Sebastian Bergmann", 536 | "email": "sebastian@phpunit.de", 537 | "role": "lead" 538 | } 539 | ], 540 | "description": "The PHP Unit Testing framework.", 541 | "homepage": "http://www.phpunit.de/", 542 | "keywords": [ 543 | "phpunit", 544 | "testing", 545 | "xunit" 546 | ], 547 | "time": "2014-04-30 12:24:19" 548 | }, 549 | { 550 | "name": "phpunit/phpunit-mock-objects", 551 | "version": "1.2.3", 552 | "source": { 553 | "type": "git", 554 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 555 | "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" 556 | }, 557 | "dist": { 558 | "type": "zip", 559 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", 560 | "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", 561 | "shasum": "" 562 | }, 563 | "require": { 564 | "php": ">=5.3.3", 565 | "phpunit/php-text-template": ">=1.1.1@stable" 566 | }, 567 | "suggest": { 568 | "ext-soap": "*" 569 | }, 570 | "type": "library", 571 | "autoload": { 572 | "classmap": [ 573 | "PHPUnit/" 574 | ] 575 | }, 576 | "notification-url": "https://packagist.org/downloads/", 577 | "include-path": [ 578 | "" 579 | ], 580 | "license": [ 581 | "BSD-3-Clause" 582 | ], 583 | "authors": [ 584 | { 585 | "name": "Sebastian Bergmann", 586 | "email": "sb@sebastian-bergmann.de", 587 | "role": "lead" 588 | } 589 | ], 590 | "description": "Mock Object library for PHPUnit", 591 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 592 | "keywords": [ 593 | "mock", 594 | "xunit" 595 | ], 596 | "time": "2013-01-13 10:24:48" 597 | }, 598 | { 599 | "name": "symfony/yaml", 600 | "version": "v2.4.4", 601 | "target-dir": "Symfony/Component/Yaml", 602 | "source": { 603 | "type": "git", 604 | "url": "https://github.com/symfony/Yaml.git", 605 | "reference": "65539ecde838f9c0d18b006b2101e3deb4b5c9ff" 606 | }, 607 | "dist": { 608 | "type": "zip", 609 | "url": "https://api.github.com/repos/symfony/Yaml/zipball/65539ecde838f9c0d18b006b2101e3deb4b5c9ff", 610 | "reference": "65539ecde838f9c0d18b006b2101e3deb4b5c9ff", 611 | "shasum": "" 612 | }, 613 | "require": { 614 | "php": ">=5.3.3" 615 | }, 616 | "type": "library", 617 | "extra": { 618 | "branch-alias": { 619 | "dev-master": "2.4-dev" 620 | } 621 | }, 622 | "autoload": { 623 | "psr-0": { 624 | "Symfony\\Component\\Yaml\\": "" 625 | } 626 | }, 627 | "notification-url": "https://packagist.org/downloads/", 628 | "license": [ 629 | "MIT" 630 | ], 631 | "authors": [ 632 | { 633 | "name": "Fabien Potencier", 634 | "email": "fabien@symfony.com", 635 | "homepage": "http://fabien.potencier.org", 636 | "role": "Lead Developer" 637 | }, 638 | { 639 | "name": "Symfony Community", 640 | "homepage": "http://symfony.com/contributors" 641 | } 642 | ], 643 | "description": "Symfony Yaml Component", 644 | "homepage": "http://symfony.com", 645 | "time": "2014-04-18 20:37:09" 646 | } 647 | ], 648 | "aliases": [ 649 | 650 | ], 651 | "minimum-stability": "stable", 652 | "stability-flags": [ 653 | 654 | ], 655 | "platform": [ 656 | 657 | ], 658 | "platform-dev": [ 659 | 660 | ] 661 | } 662 | --------------------------------------------------------------------------------