PluginProbe
Datafeedr API / 1.0.29
Datafeedr API v1.0.29
1.4.3 1.4.2 1.0.125 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.3 1.0.30 1.0.31 1.0.32 All 182 releases
datafeedr-api / libraries / datafeedr.php

datafeedr.php in Datafeedr API 1.0.29, at libraries/datafeedr.php

1,146 lines 27.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Datafeedr Api Client Library.
5 *
6 * @version 0.1b.7382
7 * @copyright Datafeedr 2007 ~ 2014 - All Rights Reserved
8 *
9 * @mainpage
10 *
11 * Example of use:
12 *
13 * @code
14 * $api = new DatafeedrApi('<access id>', '<secret key>');
15 *
16 * foreach($api->getMerchants() as $merchant)
17 * print $merchant['name'];
18 *
19 * $search = $api->searchRequest();
20 * $search->addFilter("name LIKE shoe");
21 * $search->addFilter("price < 100");
22 * $search->addSort("price", DatafeedrApi::SORT_ASCENDING);
23 * $search->setLimit(25);
24 *
25 * $products = $search->execute();
26 *
27 * foreach($products as $product)
28 * print $product['name'];
29 *
30 * @endcode
31 *
32 *
33 *
34 **/
35
36 if(!class_exists('DatafeedrApi', false)) {
37
38 /**
39 * Datafeedr API core class.
40 **/
41 class DatafeedrApi
42 {
43 protected $_accessId;
44 protected $_secretKey;
45
46 protected $_transport;
47 protected $_timeout;
48 protected $_url;
49 protected $_returnObjects;
50
51 protected $_status;
52
53 const SORT_DESCENDING = -1;
54 const SORT_ASCENDING = +1;
55
56 const DEFAULT_URL = 'http://api.datafeedr.com';
57 const DEFAULT_TIMEOUT = 30;
58
59 const VERSION = '0.1b.7382';
60
61 /**
62 * Constructor.
63 *
64 * @param string $accessId Access ID.
65 * @param object $secretKey Secret key.
66 * @param string|callable $transport (optional) HTTP transport function.
67 * @param int $timeout (optional) HTTP connection timeout, in seconds.
68 * @param bool $returnObjects (optional) if TRUE, responses are objects, otherwise associative arrays.
69 *
70 * The optional $transport parameter tells how HTTP requests should be made.
71 * It can be either a string that describes one of built-in transports ("curl", "file" or "socket"),
72 * or a callable object that should accept an url, an array of headers and a string of post data and
73 * should return an array [int http response status, string response body].
74 *
75 **/
76 public function __construct($accessId, $secretKey, $transport = 'curl', $timeout = 0, $returnObjects = FALSE) {
77 $this->_accessId = $accessId;
78 $this->_secretKey = $secretKey;
79
80 $this->_errors = array(
81 1 => 'DatafeedrBadRequestError',
82 2 => 'DatafeedrAuthenticationError',
83 3 => 'DatafeedrLimitExceededError',
84 4 => 'DatafeedrQueryError',
85 7 => 'DatafeedrExternalError',
86 9 => 'DatafeedrServerError',
87 );
88
89 $this->_url = self::DEFAULT_URL;
90 $this->_timeout = $timeout ? $timeout : self::DEFAULT_TIMEOUT;
91 $this->_returnObjects = $returnObjects;
92
93 switch($transport) {
94 case 'curl':
95 $this->_transport = array($this, '_transportCurl');
96 break;
97 case 'file':
98 $this->_transport = array($this, '_transportFile');
99 break;
100 case 'socket':
101 $this->_transport = array($this, '_transportSocket');
102 break;
103 default:
104 if(!is_callable($transport)) {
105 throw new DatafeedrError("Transport must be a function");
106 }
107 $this->_transport = $transport;
108 }
109 }
110
111 /**
112 * Return status information.
113 *
114 * @return array
115 *
116 **/
117 public function getStatus() {
118 $this->apiCall('status');
119 return $this->_status;
120 }
121
122 /**
123 * Return status information from the last request.
124 *
125 * If no Api request have been made, return NULL
126 *
127 * @return array|null
128 *
129 **/
130 public function lastStatus() {
131 return $this->_status;
132 }
133
134 /**
135 * Return the list of networks.
136 *
137 * @param int|array $networkId (optional) Network id or an array of network ids
138 * @param bool $includeEmpty (optional) If FALSE, omit networks with 0 products
139 * @param array $fields (optional) list of fields to retrieve
140 * @return array
141 *
142 **/
143 public function getNetworks($networkId = NULL, $includeEmpty = FALSE, $fields = NULL) {
144 $request = array();
145 if($networkId) {
146 $request['_ids'] = $this->_intarray($networkId);
147 }
148 $request['skip_empty'] = intval(!$includeEmpty);
149 if($fields) {
150 $request['fields'] = $fields;
151 }
152 $response = $this->apiCall('networks', $request);
153 return $this->_get($response, 'networks');
154 }
155
156 /**
157 * Return the list of merchants.
158 *
159 * @param int|array $networkId (optional) Network id or array of network ids
160 * @param bool $includeEmpty (optional) If FALSE, omit merchants with 0 products
161 * @param array $fields (optional) list of fields to retrieve
162 * @return array
163 *
164 **/
165 public function getMerchants($networkId = NULL, $includeEmpty = FALSE, $fields = NULL) {
166 $request = array();
167 if($networkId) {
168 $request['source_ids'] = $this->_intarray($networkId);
169 }
170 $request['skip_empty'] = intval(!$includeEmpty);
171 if($fields) {
172 $request['fields'] = $fields;
173 }
174 $response = $this->apiCall('merchants', $request);
175 return $this->_get($response, 'merchants');
176 }
177
178 /**
179 * Return the list of merchants by their ids.
180 *
181 * @param int|array $merchantId Merchant id or array of network ids
182 * @param bool $includeEmpty (optional) If FALSE, omit merchants with 0 products
183 * @param array $fields (optional) list of fields to retrieve
184 * @return array
185 *
186 **/
187 public function getMerchantsById($merchantId, $includeEmpty = FALSE, $fields = NULL) {
188 $request = array();
189 $request['_ids'] = $this->_intarray($merchantId);
190 $request['skip_empty'] = intval(!$includeEmpty);
191 if($fields) {
192 $request['fields'] = $fields;
193 }
194 $response = $this->apiCall('merchants', $request);
195 return $this->_get($response, 'merchants');
196 }
197
198 /**
199 * Return the list of searchable fields.
200 *
201 * @param int|array $networkId (optional) Network id or array of network ids
202 * @return array
203 *
204 **/
205 public function getFields($networkId = NULL) {
206 $request = array();
207 if($networkId) {
208 $request['source_ids'] = $this->_intarray($networkId);
209 }
210 $response = $this->apiCall('fields', $request);
211 return $this->_get($response, 'fields');
212 }
213
214 /**
215 * Return the list of products by their ids.
216 *
217 * @param int|array $productId Product id or an array of products ids.
218 * @param array $fields (optional) list of fields to retrieve.
219 * @return array
220 *
221 **/
222 public function getProducts($productId, $fields = NULL) {
223 $request = array();
224 $request['_ids'] = $this->_intarray($productId);
225 $request['string_ids'] = 1;
226 if($fields) {
227 $request['fields'] = $fields;
228 }
229 $response = $this->apiCall('get', $request);
230 return $this->_get($response, 'products');
231 }
232
233 /**
234 * Return the list of Zanox merchant ids ("zmids").
235 *
236 * @param int|array $merchantId Merchant id or an array of merchant ids.
237 * @param int $adspaceId Zanox adspace Id.
238 * @param string $connectId Zanox connection Id.
239 * @return array
240 *
241 **/
242 public function getZanoxMerchantIds($merchantId, $adspaceId, $connectId) {
243 $request = array();
244 $request['merchant_ids'] = $this->_intarray($merchantId);
245 $request['adspace_id'] = $adspaceId;
246 $request['connect_id'] = $connectId;
247 $response = $this->apiCall('zanox_merchant_ids', $request);
248 return $this->_get($response, 'zanox_merchant_ids');
249 }
250
251 /**
252 * Create a new DatafeedrSearchRequest object.
253 *
254 * @return DatafeedrSearchRequest
255 *
256 **/
257 public function searchRequest() {
258 return new DatafeedrSearchRequest($this);
259 }
260
261 /**
262 * Create a new DatafeedrMerchantSearchRequest object.
263 *
264 * @return DatafeedrMerchantSearchRequest
265 *
266 **/
267 public function merchantSearchRequest() {
268 return new DatafeedrMerchantSearchRequest($this);
269 }
270
271 /**
272 * Create a new DatafeedrAmazonSearchRequest object.
273 *
274 * @return DatafeedrAmazonSearchRequest
275 *
276 **/
277 public function amazonSearchRequest($awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale="US") {
278 return new DatafeedrAmazonSearchRequest($this, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale);
279 }
280
281 /**
282 * Create a new DatafeedrAmazonLookupRequest object.
283 *
284 * @return DatafeedrAmazonLookupRequest
285 *
286 **/
287 public function amazonLookupRequest($awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale="US") {
288 return new DatafeedrAmazonLookupRequest($this, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale);
289 }
290
291 /**
292 * Perform the raw Api call.
293 *
294 * @param string $action Api action.
295 * @param array $request (optional) Request data.
296 *
297 * @return array
298 *
299 **/
300 public function apiCall($action, $request = NULL) {
301 if(!$request) {
302 $request = array();
303 }
304
305 $request['aid'] = $this->_accessId;
306 $request['timestamp'] = gmdate('Y-m-d H:i:s');
307
308 $message = $request['aid'] .$action . $request['timestamp'];
309 $request['signature'] = hash_hmac('sha256', $message, $this->_secretKey, FALSE);
310
311 $postdata = json_encode($request);
312 $url = $this->_url . '/' . $action;
313 $headers = array(
314 'Content-Type: application/json',
315 'Accept: application/json',
316 'Content-Length: '. strlen($postdata),
317 'Connection: close',
318 'User-Agent: datafeedr.php.' . self::VERSION
319 );
320 list($status, $response) = call_user_func($this->_transport, $url, $headers, $postdata);
321 if(strlen($response)) {
322 $response = json_decode($response, !$this->_returnObjects);
323 }
324
325 $error = $this->_get($response, 'error');
326 if($error) {
327 $type = $this->_get($response, 'type');
328 $cls = isset($this->_errors[$type]) ? $this->_errors[$type] : 'DatafeedrError';
329 throw new $cls($this->_get($response, 'message'), $error);
330 }
331
332 if($status != 200) {
333 throw new DatafeedrHTTPError("Status $status");
334 }
335
336 $this->_status = $this->_get($response, 'status');
337 return $response;
338 }
339
340 protected function _intarray($id_or_ids) {
341 if(is_numeric($id_or_ids)) {
342 return array($id_or_ids);
343 }
344 if(is_array($id_or_ids)) {
345 return array_values($id_or_ids);
346 }
347 return array();
348 }
349
350 protected function _get($obj, $prop, $default=NULL) {
351 if(is_array($obj) && isset($obj[$prop])) {
352 return $obj[$prop];
353 }
354 if(is_object($obj) && isset($obj->$prop)) {
355 return $obj->$prop;
356 }
357 return $default;
358 }
359
360
361 /**
362 * Perform a HTTP post request by the means of the curl library.
363 *
364 * @param string $url Request url.
365 * @param array $headers Array of headers.
366 * @param string $postdata Post data.
367 * @return array (int http status, string response body)
368 *
369 **/
370 protected function _transportCurl($url, $headers, $postdata) {
371 $ch = curl_init();
372 curl_setopt($ch, CURLOPT_URL, $url);
373 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->_timeout);
374 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
375 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
376 curl_setopt($ch, CURLOPT_POST, 1);
377 curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
378
379 $response = curl_exec($ch);
380 $status = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
381 $errno = curl_errno($ch);
382 $errmsg = curl_error($ch);
383
384 curl_close($ch);
385
386 if($errno) {
387 throw new DatafeedrHTTPError($errmsg, $errno);
388 }
389
390 return array($status, $response);
391 }
392
393 /**
394 * Perform a HTTP post request using file functions.
395 *
396 * @param string $url Request url.
397 * @param array $headers Array of headers.
398 * @param string $postdata Post data.
399 * @return array (int http status, string response body)
400 *
401 **/
402 protected function _transportFile($url, $headers, $postdata) {
403 $options = array('http' => array(
404 'method' => 'POST',
405 'content' => $postdata,
406 'header' => implode("\r\n", $headers),
407 'ignore_errors' => TRUE,
408 'timeout' => $this->_timeout,
409 ));
410 $context = stream_context_create($options);
411 $response = file_get_contents($url, false, $context);
412
413 $status = 200;
414 if(isset($http_response_header) && isset($http_response_header[0])) {
415 if(preg_match('/HTTP.+?(\d\d\d)/', $http_response_header[0], $match)) {
416 $status = intval($match[1]);
417 }
418 } else if($response === false) {
419 throw new DatafeedrHTTPError("HTTP error: invalid response");
420 }
421 return array($status, $response);
422 }
423
424 /**
425 * Perform a HTTP post request using sockets.
426 *
427 * @param string $url Request url.
428 * @param array $headers Array of headers.
429 * @param string $postdata Post data.
430 * @return array (int http status, string response body)
431 *
432 **/
433 protected function _transportSocket($url, $headers, $postdata) {
434 $parts = parse_url($url);
435 $errno = 0;
436 $errmsg = '';
437
438 $fp = fsockopen($parts['host'], 80, $errno, $errmsg, $this->_timeout);
439 if(!$fp) {
440 throw new DatafeedrHTTPError($errmsg, $errno);
441 }
442
443 fwrite($fp, "POST " . $parts['path'] . " HTTP/1.1\r\n");
444 fwrite($fp, implode("\r\n", $headers) . "\r\n\r\n");
445 fwrite($fp, $postdata);
446
447 $buf = '';
448 while(!feof($fp)) {
449 $buf .= fgets($fp, 1024);
450 }
451 fclose($fp);
452
453 $buf = explode("\r\n\r\n", $buf, 2);
454 if(count($buf) != 2) {
455 throw new DatafeedrHTTPError("Invalid response");
456 }
457 if(preg_match('/HTTP.+?(\d\d\d)/', $buf[0], $match)) {
458 $status = intval($match[1]);
459 } else {
460 throw new DatafeedrHTTPError("Invalid status");
461 }
462 return array($status, $buf[1]);
463 }
464 }
465 }
466
467 if(!class_exists('DatafeedrSearchRequestBase', false)) {
468 /**
469 * Generic Datafeedr API search request.
470 **/
471 class DatafeedrSearchRequestBase
472 {
473 protected $_api;
474 protected $_lastResponse;
475
476 /**
477 * Constructor.
478 *
479 * @param object $api DatafeedrApi object.
480 *
481 **/
482 public function __construct($api) {
483 $this->_api = $api;
484 }
485
486 /**
487 * Get the number of found products.
488 *
489 * @return int
490 *
491 **/
492 public function getFoundCount() {
493 return $this->_responseItem('found_count', 0);
494 }
495
496 /**
497 * Get the number of products that can be retrieved from the server.
498 *
499 * @return int
500 *
501 **/
502 public function getResultCount() {
503 return $this->_responseItem('result_count', 0);
504 }
505
506 /**
507 * Return the response from the last search.
508 *
509 * @return array
510 *
511 **/
512 public function getResponse() {
513 return $this->_lastResponse;
514 }
515
516 protected function _responseItem($prop, $default) {
517 if(is_null($this->_lastResponse)) {
518 throw new DatafeedrError("Reading from an empty request");
519 }
520 if(is_object($this->_lastResponse) && isset($this->_lastResponse->$prop)) {
521 return $this->_lastResponse->$prop;
522 }
523 if(is_array($this->_lastResponse) && isset($this->_lastResponse[$prop])) {
524 return $this->_lastResponse[$prop];
525 }
526 return $default;
527 }
528
529 function _apiCall($action, $request = NULL) {
530 $this->_lastResponse = $this->_api->apiCall($action, $request);
531 }
532
533 }
534 }
535
536 if(!class_exists('DatafeedrSearchRequest', false)) {
537 /**
538 * Search request for Datafeedr API.
539 **/
540 class DatafeedrSearchRequest extends DatafeedrSearchRequestBase
541 {
542 /**
543 * Constructor.
544 *
545 * @param object $api DatafeedrApi object.
546 *
547 **/
548 public function __construct($api) {
549 parent::__construct($api);
550
551 $this->_query = array();
552 $this->_sort = array();
553 $this->_fields = array();
554 $this->_limit = 0;
555 $this->_offset = 0;
556 $this->_priceGroups = 0;
557 $this->_excludeDuplicates = "";
558 }
559
560 /**
561 * Add a query filter.
562 *
563 * @param string $filter Query filter.
564 * @return $this
565 *
566 **/
567 public function addFilter($filter) {
568 $this->_query []= $filter;
569 return $this;
570 }
571
572 /**
573 * Add a sort field.
574 *
575 * @param string $field Field name.
576 * @param int $order One of DatafeedrApi::SORT_ASCENDING or DatafeedrApi::SORT_DESCENDING
577 * @return $this
578 *
579 **/
580 public function addSort($field, $order = DatafeedrApi::SORT_ASCENDING) {
581 if(strlen($field) && ($field[0] == '+' || $field[0] == '-')) {
582 $this->_sort []= $field;
583 } else if($order == DatafeedrApi::SORT_ASCENDING) {
584 $this->_sort []= '+' . $field;
585 } else if($order == DatafeedrApi::SORT_DESCENDING) {
586 $this->_sort []= '-' . $field;
587 } else {
588 throw new DatafeedrError("Invalid sort order");
589 }
590 return $this;
591 }
592
593 /**
594 * Set which fields to retrieve.
595 *
596 * @param array $fields List of field names.
597 * @return $this
598 *
599 **/
600 public function setFields($fields) {
601 $this->_fields = $fields;
602 return $this;
603 }
604
605 /**
606 * Exclude duplicate results.
607 *
608 * @param string $filter Equality filter in form "field1 field2 | field3".
609 * @return $this
610 *
611 **/
612 public function excludeDuplicates($filter) {
613 if(is_array($filter)) {
614 $filter = implode(' ', $filter);
615 }
616 $this->_excludeDuplicates = $filter;
617 return $this;
618 }
619
620 /**
621 * Set a limit.
622 *
623 * @param int $limit The limit.
624 * @return $this
625 *
626 **/
627 public function setLimit($limit) {
628 $this->_limit = $limit;
629 return $this;
630 }
631
632 /**
633 * Set an offset.
634 *
635 * @param int $offset The offset.
636 * @return $this
637 *
638 **/
639 public function setOffset($offset) {
640 $this->_offset = $offset;
641 return $this;
642 }
643
644 /**
645 * Set a price group count.
646 *
647 * @param int $groups Group count.
648 * @return $this
649 *
650 **/
651 public function setPriceGroups($groups) {
652 $this->_priceGroups = $groups;
653 return $this;
654 }
655
656 /**
657 * Get found networks.
658 *
659 * @return array
660 *
661 **/
662 public function getNetworks() {
663 return $this->_responseItem('networks', array());
664 }
665
666 /**
667 * Get found merchants.
668 *
669 * @return array
670 *
671 **/
672 public function getMerchants() {
673 return $this->_responseItem('merchants', array());
674 }
675
676 /**
677 * Get found price groups.
678 *
679 * @return array
680 *
681 **/
682 public function getPriceGroups() {
683 return $this->_responseItem('price_groups', array());
684 }
685
686 /**
687 * Create a request object to use with the API.
688 *
689 * @return array
690 *
691 **/
692 public function getParams() {
693 $request = array();
694 if($this->_query) {
695 $request['query'] = $this->_query;
696 }
697 if($this->_sort) {
698 $request['sort'] = $this->_sort;
699 }
700 if($this->_fields) {
701 $request['fields'] = $this->_fields;
702 }
703 if($this->_limit) {
704 $request['limit'] = $this->_limit;
705 }
706 if($this->_offset) {
707 $request['offset'] = $this->_offset;
708 }
709 if($this->_priceGroups) {
710 $request['price_groups'] = $this->_priceGroups;
711 }
712 if($this->_excludeDuplicates) {
713 $request['exclude_duplicates'] = $this->_excludeDuplicates;
714 }
715 $request['string_ids'] = 1;
716 return $request;
717 }
718
719 /**
720 * Run search and return a list of products.
721 *
722 * @return array
723 *
724 **/
725 public function execute() {
726 $params = $this->getParams();
727 if(!isset($params['query'])) {
728 throw new DatafeedrError("Query can't be empty");
729 }
730 $this->_apiCall('search', $params);
731 return $this->_responseItem('products', array());
732 }
733
734 }
735 }
736
737 if(!class_exists('DatafeedrMerchantSearchRequest', false)) {
738 /**
739 * Search request for Datafeedr Merchants.
740 **/
741 class DatafeedrMerchantSearchRequest extends DatafeedrSearchRequestBase
742 {
743 /**
744 * Constructor.
745 *
746 * @param object $api DatafeedrApi object.
747 *
748 **/
749 public function __construct($api) {
750 parent::__construct($api);
751
752 $this->_query = array();
753 $this->_sort = array();
754 $this->_fields = array();
755 $this->_limit = 0;
756 $this->_offset = 0;
757 }
758
759 /**
760 * Add a query filter.
761 *
762 * @param string $filter Query filter.
763 * @return $this
764 *
765 **/
766 public function addFilter($filter) {
767 $this->_query []= $filter;
768 return $this;
769 }
770
771 /**
772 * Add a sort field.
773 *
774 * @param string $field Field name.
775 * @param int $order One of DatafeedrApi::SORT_ASCENDING or DatafeedrApi::SORT_DESCENDING
776 * @throws DatafeedrError
777 * @return $this
778 *
779 **/
780 public function addSort($field, $order = DatafeedrApi::SORT_ASCENDING) {
781 if(strlen($field) && ($field[0] == '+' || $field[0] == '-')) {
782 $this->_sort []= $field;
783 } else if($order == DatafeedrApi::SORT_ASCENDING) {
784 $this->_sort []= '+' . $field;
785 } else if($order == DatafeedrApi::SORT_DESCENDING) {
786 $this->_sort []= '-' . $field;
787 } else {
788 throw new DatafeedrError("Invalid sort order");
789 }
790 return $this;
791 }
792
793 /**
794 * Set which fields to retrieve.
795 *
796 * @param array $fields List of field names.
797 * @return $this
798 *
799 **/
800 public function setFields($fields) {
801 $this->_fields = $fields;
802 return $this;
803 }
804
805 /**
806 * Set a limit.
807 *
808 * @param int $limit The limit.
809 * @return $this
810 *
811 **/
812 public function setLimit($limit) {
813 $this->_limit = $limit;
814 return $this;
815 }
816
817 /**
818 * Set an offset.
819 *
820 * @param int $offset The offset.
821 * @return $this
822 *
823 **/
824 public function setOffset($offset) {
825 $this->_offset = $offset;
826 return $this;
827 }
828
829 /**
830 * Get found networks.
831 *
832 * @return array
833 *
834 **/
835 public function getNetworks() {
836 return $this->_responseItem('networks', array());
837 }
838
839 /**
840 * Get found merchants.
841 *
842 * @return array
843 *
844 **/
845 public function getMerchants() {
846 return $this->_responseItem('merchants', array());
847 }
848
849 /**
850 * Run search and return a list of merchants.
851 *
852 * @throws DatafeedrError
853 * @return array
854 *
855 **/
856 public function execute() {
857 $params = $this->getParams();
858 if(!isset($params['query'])) {
859 throw new DatafeedrError("Query can't be empty");
860 }
861 $this->_apiCall('merchant_search', $params);
862 return $this->_responseItem('merchants', array());
863 }
864
865 /**
866 * Create a request object to use with the API.
867 *
868 * @return array
869 *
870 **/
871 public function getParams() {
872 $request = array();
873 if($this->_query) {
874 $request['query'] = $this->_query;
875 }
876 if($this->_sort) {
877 $request['sort'] = $this->_sort;
878 }
879 if($this->_fields) {
880 $request['fields'] = $this->_fields;
881 }
882 if($this->_limit) {
883 $request['limit'] = $this->_limit;
884 }
885 if($this->_offset) {
886 $request['offset'] = $this->_offset;
887 }
888 return $request;
889 }
890 }
891 }
892
893 if(!class_exists('DatafeedrAmazonRequest', false)) {
894 /**
895 * Generic Amazon request.
896 **/
897 class DatafeedrAmazonRequest extends DatafeedrSearchRequestBase
898 {
899 protected $_found = -1;
900
901 const AWS_VERSION = "2011-08-01";
902
903 /**
904 * Constructor
905 *
906 * @param object $api DatafeedrApi object.
907 * @param string $awsAccessKeyId Amazon access key.
908 * @param string $awsSecretKey Amazon secret key.
909 * @param string $awsAssociateTag Amazon associate tag.
910 * @param string $locale Amazon locale (two-letter code).
911 */
912 public function __construct($api, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale="US") {
913 parent::__construct($api);
914 $this->_hosts = array(
915 "CA" => "webservices.amazon.ca",
916 "CN" => "webservices.amazon.cn",
917 "DE" => "webservices.amazon.de",
918 "ES" => "webservices.amazon.es",
919 "FR" => "webservices.amazon.fr",
920 "IT" => "webservices.amazon.it",
921 "JP" => "webservices.amazon.co.jp",
922 "UK" => "webservices.amazon.co.uk",
923 "US" => "webservices.amazon.com",
924 );
925
926 $this->_params = array();
927 $this->_locale = strtoupper($locale);
928
929 if(!isset($this->_hosts[$this->_locale])) {
930 throw new DatafeedrError("Invalid Amazon locale");
931 }
932
933 $this->_awsAccessKeyId = $awsAccessKeyId;
934 $this->_awsSecretKey = $awsSecretKey;
935 $this->_awsAssociateTag = $awsAssociateTag;
936 }
937
938 /**
939 * Returns all parameters.
940 *
941 * @return array
942 *
943 **/
944 public function getParams() {
945 return $this->_params;
946 }
947
948 protected function _amazonUrl($operation, $params, $defaults=NULL) {
949 $params = array_filter($params);
950
951 if(!is_null($defaults)) {
952 foreach($defaults as $k => $v) {
953 if(!isset($params[$k])) {
954 $params[$k] = $v;
955 }
956 }
957 }
958
959 $params["Operation"] = $operation;
960 $params["Service"] = "AWSECommerceService";
961 $params["AWSAccessKeyId"] = $this->_awsAccessKeyId;
962 $params["AssociateTag"] = $this->_awsAssociateTag;
963 $params["Version"] = self::AWS_VERSION;
964 $params["Timestamp"] = gmdate("Y-m-d\\TH:i:s\\Z");
965
966 ksort($params);
967 $query = array();
968 foreach($params as $k => $v) {
969 if(is_array($v)) {
970 $v = implode(',', $v);
971 }
972 $query []= $k . '=' . rawurlencode($v);
973 }
974 $query = implode('&', $query);
975 $host = $this->_hosts[$this->_locale];
976 $path = "/onca/xml";
977 $subj = sprintf("GET\n%s\n%s\n%s", $host, $path, $query);
978 $sign = rawurlencode(base64_encode(hash_hmac("sha256", $subj, $this->_awsSecretKey, TRUE)));
979 return "http://{$host}{$path}?{$query}&Signature={$sign}";
980 }
981 }
982 }
983
984 if(!class_exists('DatafeedrAmazonSearchRequest', false)) {
985 /**
986 * Amazon search request.
987 **/
988 class DatafeedrAmazonSearchRequest extends DatafeedrAmazonRequest
989 {
990 /**
991 * Add a parameter.
992 *
993 * @param string $name Parameter name.
994 * @param string $value Parameter value.
995 * @return $this
996 *
997 * @see http://docs.aws.amazon.com/AWSECommerceService/latest/DG/ItemSearch.html
998 *
999 **/
1000 public function addParam($name, $value) {
1001 $this->_params[$name] = $value;
1002 return $this;
1003 }
1004
1005 /**
1006 * Run search and return a list of products.
1007 *
1008 * @return array
1009 *
1010 **/
1011 public function execute() {
1012 $defaults = array(
1013 'ResponseGroup' => 'ItemAttributes,Images,OfferFull,BrowseNodes,EditorialReview,VariationSummary',
1014 'SearchIndex' => 'All',
1015 );
1016 $url = $this->_amazonUrl('ItemSearch', $this->_params, $defaults);
1017 $this->_apiCall('amazon_search', array('url' => $url));
1018 return $this->_responseItem('products', array());
1019 }
1020 }
1021 }
1022
1023 if(!class_exists('DatafeedrAmazonLookupRequest', false)) {
1024 /**
1025 * Amazon lookup request.
1026 **/
1027 class DatafeedrAmazonLookupRequest extends DatafeedrAmazonRequest
1028 {
1029 /**
1030 * Add a parameter.
1031 *
1032 * @param string $name Parameter name - one of 'ASIN', 'SKU', 'UPC', 'EAN', 'ISBN'
1033 * @param string|array $value Parameter value or an array of values (up to 10).
1034 * @return $this
1035 *
1036 * @see http://docs.aws.amazon.com/AWSECommerceService/latest/DG/ItemLookup.html
1037 *
1038 **/
1039 public function addParam($name, $value) {
1040 $this->_params[$name] = $value;
1041 return $this;
1042 }
1043
1044 /**
1045 * Run search and return a list of products.
1046 *
1047 * @return array
1048 *
1049 **/
1050 public function execute() {
1051 $params = array_filter($this->_params);
1052 $types = array('ASIN', 'SKU', 'UPC', 'EAN', 'ISBN', 'asin', 'sku', 'upc', 'ean', 'isbn');
1053 foreach($types as $type) {
1054 if(isset($params[$type])) {
1055 $params['IdType'] = strtoupper($type);
1056 $params['ItemId'] = $params[$type];
1057 unset($params[$type]);
1058 }
1059 }
1060
1061 $defaults = array(
1062 'ResponseGroup' => 'ItemAttributes,Images,OfferFull,BrowseNodes,EditorialReview,VariationSummary',
1063 );
1064 if(isset($params['IdType']) && $params['IdType'] != 'ASIN') {
1065 $defaults['SearchIndex'] = 'All';
1066 }
1067 $url = $this->_amazonUrl('ItemLookup', $params, $defaults);
1068 $this->_apiCall('amazon_search', array('url' => $url));
1069 return $this->_responseItem('products', array());
1070 }
1071 }
1072 }
1073
1074 if(!class_exists('DatafeedrError', false)) {
1075 /**
1076 * Generic Api error.
1077 **/
1078 class DatafeedrError extends Exception
1079 {
1080 }
1081 }
1082
1083 if(!class_exists('DatafeedrBadRequestError', false)) {
1084 /**
1085 * API error: Invalid Request.
1086 **/
1087 class DatafeedrBadRequestError extends DatafeedrError
1088 {
1089 }
1090 }
1091
1092 if(!class_exists('DatafeedrAuthenticationError', false)) {
1093 /**
1094 * API error: Authentication failed.
1095 **/
1096 class DatafeedrAuthenticationError extends DatafeedrError
1097 {
1098 }
1099 }
1100
1101 if(!class_exists('DatafeedrLimitExceededError', false)) {
1102 /**
1103 * API error: Query limit exceeded.
1104 **/
1105 class DatafeedrLimitExceededError extends DatafeedrError
1106 {
1107 }
1108 }
1109
1110 if(!class_exists('DatafeedrHTTPError', false)) {
1111 /**
1112 * API error: Unspecified HTTP error.
1113 **/
1114 class DatafeedrHTTPError extends DatafeedrError
1115 {
1116 }
1117 }
1118
1119 if(!class_exists('DatafeedrQueryError', false)) {
1120 /**
1121 * API error: Error in the search query.
1122 **/
1123 class DatafeedrQueryError extends DatafeedrError
1124 {
1125 }
1126 }
1127
1128 if(!class_exists('DatafeedrExternalError', false)) {
1129 /**
1130 * API error: External service error.
1131 **/
1132 class DatafeedrExternalError extends DatafeedrError
1133 {
1134 }
1135 }
1136
1137 if(!class_exists('DatafeedrServerError', false)) {
1138 /**
1139 * API error: Internal server error.
1140 **/
1141 class DatafeedrServerError extends DatafeedrError
1142 {
1143 }
1144 }
1145
1146 ?>