PluginProbe
Datafeedr API / 1.0.27
Datafeedr API v1.0.27
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.27, at libraries/datafeedr.php

1,145 lines 30.7 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.7242
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.7242';
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 * @return array
297 *
298 **/
299 public function apiCall($action, $request = NULL) {
300 if(!$request) {
301 $request = array();
302 }
303
304 $request['aid'] = $this->_accessId;
305 $request['timestamp'] = gmdate('Y-m-d H:i:s');
306
307 $message = $request['aid'] .$action . $request['timestamp'];
308 $request['signature'] = hash_hmac('sha256', $message, $this->_secretKey, FALSE);
309
310 $postdata = json_encode($request);
311 $url = $this->_url . '/' . $action;
312 $headers = array(
313 'Content-Type: application/json',
314 'Accept: application/json',
315 'Content-Length: '. strlen($postdata),
316 'Connection: close',
317 'User-Agent: datafeedr.php.' . self::VERSION
318 );
319 list($status, $response) = call_user_func($this->_transport, $url, $headers, $postdata);
320 if(strlen($response)) {
321 $response = json_decode($response, !$this->_returnObjects);
322 }
323
324 $error = $this->_get($response, 'error');
325 if($error) {
326 $type = $this->_get($response, 'type');
327 $cls = isset($this->_errors[$type]) ? $this->_errors[$type] : 'DatafeedrError';
328 throw new $cls($this->_get($response, 'message'), $error);
329 }
330
331 if($status != 200) {
332 throw new DatafeedrHTTPError("Status $status");
333 }
334
335 $this->_status = $this->_get($response, 'status');
336 return $response;
337 }
338
339 protected function _intarray($id_or_ids) {
340 if(is_numeric($id_or_ids)) {
341 return array($id_or_ids);
342 }
343 if(is_array($id_or_ids)) {
344 return $id_or_ids;
345 }
346 return array();
347 }
348
349 protected function _get($obj, $prop, $default=NULL) {
350 if(is_array($obj) && isset($obj[$prop])) {
351 return $obj[$prop];
352 }
353 if(is_object($obj) && isset($obj->$prop)) {
354 return $obj->$prop;
355 }
356 return $default;
357 }
358
359
360 /**
361 * Perform a HTTP post request by the means of the curl library.
362 *
363 * @param string $url Request url.
364 * @param array $headers Array of headers.
365 * @param string $postdata Post data.
366 * @return array (int http status, string response body)
367 *
368 **/
369 protected function _transportCurl($url, $headers, $postdata) {
370 $ch = curl_init();
371 curl_setopt($ch, CURLOPT_URL, $url);
372 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->_timeout);
373 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
374 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
375 curl_setopt($ch, CURLOPT_POST, 1);
376 curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
377
378 $response = curl_exec($ch);
379 $status = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
380 $errno = curl_errno($ch);
381 $errmsg = curl_error($ch);
382
383 curl_close($ch);
384
385 if($errno) {
386 throw new DatafeedrHTTPError($errmsg, $errno);
387 }
388
389 return array($status, $response);
390 }
391
392 /**
393 * Perform a HTTP post request using file functions.
394 *
395 * @param string $url Request url.
396 * @param array $headers Array of headers.
397 * @param string $postdata Post data.
398 * @return array (int http status, string response body)
399 *
400 **/
401 protected function _transportFile($url, $headers, $postdata) {
402 $options = array('http' => array(
403 'method' => 'POST',
404 'content' => $postdata,
405 'header' => implode("\r\n", $headers),
406 'ignore_errors' => TRUE,
407 'timeout' => $this->_timeout,
408 ));
409 $context = stream_context_create($options);
410 $response = file_get_contents($url, false, $context);
411
412 $status = 200;
413 if(isset($http_response_header) && isset($http_response_header[0])) {
414 if(preg_match('/HTTP.+?(\d\d\d)/', $http_response_header[0], $match)) {
415 $status = intval($match[1]);
416 }
417 } else if($response === false) {
418 throw new DatafeedrHTTPError("HTTP error: invalid response");
419 }
420 return array($status, $response);
421 }
422
423 /**
424 * Perform a HTTP post request using sockets.
425 *
426 * @param string $url Request url.
427 * @param array $headers Array of headers.
428 * @param string $postdata Post data.
429 * @return array (int http status, string response body)
430 *
431 **/
432 protected function _transportSocket($url, $headers, $postdata) {
433 $parts = parse_url($url);
434 $errno = 0;
435 $errmsg = '';
436
437 $fp = fsockopen($parts['host'], 80, $errno, $errmsg, $this->_timeout);
438 if(!$fp) {
439 throw new DatafeedrHTTPError($errmsg, $errno);
440 }
441
442 fwrite($fp, "POST " . $parts['path'] . " HTTP/1.1\r\n");
443 fwrite($fp, implode("\r\n", $headers) . "\r\n\r\n");
444 fwrite($fp, $postdata);
445
446 $buf = '';
447 while(!feof($fp)) {
448 $buf .= fgets($fp, 1024);
449 }
450 fclose($fp);
451
452 $buf = explode("\r\n\r\n", $buf, 2);
453 if(count($buf) != 2) {
454 throw new DatafeedrHTTPError("Invalid response");
455 }
456 if(preg_match('/HTTP.+?(\d\d\d)/', $buf[0], $match)) {
457 $status = intval($match[1]);
458 } else {
459 throw new DatafeedrHTTPError("Invalid status");
460 }
461 return array($status, $buf[1]);
462 }
463 }
464 }
465
466 if(!class_exists('DatafeedrSearchRequestBase', false)) {
467 /**
468 * Generic Datafeedr API search request.
469 **/
470 class DatafeedrSearchRequestBase
471 {
472 protected $_api;
473 protected $_lastResponse;
474
475 /**
476 * Constructor.
477 *
478 * @param object $api DatafeedrApi object.
479 *
480 **/
481 public function __construct($api) {
482 $this->_api = $api;
483 }
484
485 /**
486 * Get the number of found products.
487 *
488 * @return int
489 *
490 **/
491 public function getFoundCount() {
492 return $this->_responseItem('found_count', 0);
493 }
494
495 /**
496 * Get the number of products that can be retrieved from the server.
497 *
498 * @return int
499 *
500 **/
501 public function getResultCount() {
502 return $this->_responseItem('result_count', 0);
503 }
504
505 /**
506 * Return the response from the last search.
507 *
508 * @return array
509 *
510 **/
511 public function getResponse() {
512 return $this->_lastResponse;
513 }
514
515 protected function _responseItem($prop, $default) {
516 if(is_null($this->_lastResponse)) {
517 throw new DatafeedrError("Reading from an empty request");
518 }
519 if(is_object($this->_lastResponse) && isset($this->_lastResponse->$prop)) {
520 return $this->_lastResponse->$prop;
521 }
522 if(is_array($this->_lastResponse) && isset($this->_lastResponse[$prop])) {
523 return $this->_lastResponse[$prop];
524 }
525 return $default;
526 }
527
528 function _apiCall($action, $request = NULL) {
529 $this->_lastResponse = $this->_api->apiCall($action, $request);
530 }
531
532 }
533 }
534
535 if(!class_exists('DatafeedrSearchRequest', false)) {
536 /**
537 * Search request for Datafeedr API.
538 **/
539 class DatafeedrSearchRequest extends DatafeedrSearchRequestBase
540 {
541 /**
542 * Constructor.
543 *
544 * @param object $api DatafeedrApi object.
545 *
546 **/
547 public function __construct($api) {
548 parent::__construct($api);
549
550 $this->_query = array();
551 $this->_sort = array();
552 $this->_fields = array();
553 $this->_limit = 0;
554 $this->_offset = 0;
555 $this->_priceGroups = 0;
556 $this->_excludeDuplicates = "";
557 }
558
559 /**
560 * Add a query filter.
561 *
562 * @param string $filter Query filter.
563 * @return $this
564 *
565 **/
566 public function addFilter($filter) {
567 $this->_query []= $filter;
568 return $this;
569 }
570
571 /**
572 * Add a sort field.
573 *
574 * @param string $field Field name.
575 * @param int $order One of DatafeedrApi::SORT_ASCENDING or DatafeedrApi::SORT_DESCENDING
576 * @return $this
577 *
578 **/
579 public function addSort($field, $order = DatafeedrApi::SORT_ASCENDING) {
580 if(strlen($field) && ($field[0] == '+' || $field[0] == '-')) {
581 $this->_sort []= $field;
582 } else if($order == DatafeedrApi::SORT_ASCENDING) {
583 $this->_sort []= '+' . $field;
584 } else if($order == DatafeedrApi::SORT_DESCENDING) {
585 $this->_sort []= '-' . $field;
586 } else {
587 throw new DatafeedrError("Invalid sort order");
588 }
589 return $this;
590 }
591
592 /**
593 * Set which fields to retrieve.
594 *
595 * @param array $fields List of field names.
596 * @return $this
597 *
598 **/
599 public function setFields($fields) {
600 $this->_fields = $fields;
601 return $this;
602 }
603
604 /**
605 * Exclude duplicate results.
606 *
607 * @param string $filter Equality filter in form "field1 field2 | field3".
608 * @return $this
609 *
610 **/
611 public function excludeDuplicates($filter) {
612 if(is_array($filter)) {
613 $filter = implode(' ', $filter);
614 }
615 $this->_excludeDuplicates = $filter;
616 return $this;
617 }
618
619 /**
620 * Set a limit.
621 *
622 * @param int $limit The limit.
623 * @return $this
624 *
625 **/
626 public function setLimit($limit) {
627 $this->_limit = $limit;
628 return $this;
629 }
630
631 /**
632 * Set an offset.
633 *
634 * @param int $offset The offset.
635 * @return $this
636 *
637 **/
638 public function setOffset($offset) {
639 $this->_offset = $offset;
640 return $this;
641 }
642
643 /**
644 * Set a price group count.
645 *
646 * @param int $groups Group count.
647 * @return $this
648 *
649 **/
650 public function setPriceGroups($groups) {
651 $this->_priceGroups = $groups;
652 return $this;
653 }
654
655 /**
656 * Get found networks.
657 *
658 * @return array
659 *
660 **/
661 public function getNetworks() {
662 return $this->_responseItem('networks', array());
663 }
664
665 /**
666 * Get found merchants.
667 *
668 * @return array
669 *
670 **/
671 public function getMerchants() {
672 return $this->_responseItem('merchants', array());
673 }
674
675 /**
676 * Get found price groups.
677 *
678 * @return array
679 *
680 **/
681 public function getPriceGroups() {
682 return $this->_responseItem('price_groups', array());
683 }
684
685 /**
686 * Create a request object to use with the API.
687 *
688 * @return array
689 *
690 **/
691 public function getParams() {
692 $request = array();
693 if($this->_query) {
694 $request['query'] = $this->_query;
695 }
696 if($this->_sort) {
697 $request['sort'] = $this->_sort;
698 }
699 if($this->_fields) {
700 $request['fields'] = $this->_fields;
701 }
702 if($this->_limit) {
703 $request['limit'] = $this->_limit;
704 }
705 if($this->_offset) {
706 $request['offset'] = $this->_offset;
707 }
708 if($this->_priceGroups) {
709 $request['price_groups'] = $this->_priceGroups;
710 }
711 if($this->_excludeDuplicates) {
712 $request['exclude_duplicates'] = $this->_excludeDuplicates;
713 }
714 $request['string_ids'] = 1;
715 return $request;
716 }
717
718 /**
719 * Run search and return a list of products.
720 *
721 * @return array
722 *
723 **/
724 public function execute() {
725 $params = $this->getParams();
726 if(!isset($params['query'])) {
727 throw new DatafeedrError("Query can't be empty");
728 }
729 $this->_apiCall('search', $params);
730 return $this->_responseItem('products', array());
731 }
732
733 }
734 }
735
736 if(!class_exists('DatafeedrMerchantSearchRequest', false)) {
737 /**
738 * Search request for Datafeedr Merchants.
739 **/
740 class DatafeedrMerchantSearchRequest extends DatafeedrSearchRequestBase
741 {
742 /**
743 * Constructor.
744 *
745 * @param object $api DatafeedrApi object.
746 *
747 **/
748 public function __construct($api) {
749 parent::__construct($api);
750
751 $this->_query = array();
752 $this->_sort = array();
753 $this->_fields = array();
754 $this->_limit = 0;
755 $this->_offset = 0;
756 }
757
758 /**
759 * Add a query filter.
760 *
761 * @param string $filter Query filter.
762 * @return $this
763 *
764 **/
765 public function addFilter($filter) {
766 $this->_query []= $filter;
767 return $this;
768 }
769
770 /**
771 * Add a sort field.
772 *
773 * @param string $field Field name.
774 * @param int $order One of DatafeedrApi::SORT_ASCENDING or DatafeedrApi::SORT_DESCENDING
775 * @throws DatafeedrError
776 * @return $this
777 *
778 **/
779 public function addSort($field, $order = DatafeedrApi::SORT_ASCENDING) {
780 if(strlen($field) && ($field[0] == '+' || $field[0] == '-')) {
781 $this->_sort []= $field;
782 } else if($order == DatafeedrApi::SORT_ASCENDING) {
783 $this->_sort []= '+' . $field;
784 } else if($order == DatafeedrApi::SORT_DESCENDING) {
785 $this->_sort []= '-' . $field;
786 } else {
787 throw new DatafeedrError("Invalid sort order");
788 }
789 return $this;
790 }
791
792 /**
793 * Set which fields to retrieve.
794 *
795 * @param array $fields List of field names.
796 * @return $this
797 *
798 **/
799 public function setFields($fields) {
800 $this->_fields = $fields;
801 return $this;
802 }
803
804 /**
805 * Set a limit.
806 *
807 * @param int $limit The limit.
808 * @return $this
809 *
810 **/
811 public function setLimit($limit) {
812 $this->_limit = $limit;
813 return $this;
814 }
815
816 /**
817 * Set an offset.
818 *
819 * @param int $offset The offset.
820 * @return $this
821 *
822 **/
823 public function setOffset($offset) {
824 $this->_offset = $offset;
825 return $this;
826 }
827
828 /**
829 * Get found networks.
830 *
831 * @return array
832 *
833 **/
834 public function getNetworks() {
835 return $this->_responseItem('networks', array());
836 }
837
838 /**
839 * Get found merchants.
840 *
841 * @return array
842 *
843 **/
844 public function getMerchants() {
845 return $this->_responseItem('merchants', array());
846 }
847
848 /**
849 * Run search and return a list of merchants.
850 *
851 * @throws DatafeedrError
852 * @return array
853 *
854 **/
855 public function execute() {
856 $params = $this->getParams();
857 if(!isset($params['query'])) {
858 throw new DatafeedrError("Query can't be empty");
859 }
860 $this->_apiCall('merchant_search', $params);
861 return $this->_responseItem('merchants', array());
862 }
863
864 /**
865 * Create a request object to use with the API.
866 *
867 * @return array
868 *
869 **/
870 public function getParams() {
871 $request = array();
872 if($this->_query) {
873 $request['query'] = $this->_query;
874 }
875 if($this->_sort) {
876 $request['sort'] = $this->_sort;
877 }
878 if($this->_fields) {
879 $request['fields'] = $this->_fields;
880 }
881 if($this->_limit) {
882 $request['limit'] = $this->_limit;
883 }
884 if($this->_offset) {
885 $request['offset'] = $this->_offset;
886 }
887 return $request;
888 }
889 }
890 }
891
892 if(!class_exists('DatafeedrAmazonRequest', false)) {
893 /**
894 * Generic Amazon request.
895 **/
896 class DatafeedrAmazonRequest extends DatafeedrSearchRequestBase
897 {
898 protected $_found = -1;
899
900 const AWS_VERSION = "2011-08-01";
901
902 /**
903 * Constructor
904 *
905 * @param object $api DatafeedrApi object.
906 * @param string $awsAccessKeyId Amazon access key.
907 * @param string $awsSecretKey Amazon secret key.
908 * @param string $awsAssociateTag Amazon associate tag.
909 * @param string $locale Amazon locale (two-letter code).
910 */
911 public function __construct($api, $awsAccessKeyId, $awsSecretKey, $awsAssociateTag, $locale="US") {
912 parent::__construct($api);
913 $this->_hosts = array(
914 "CA" => "webservices.amazon.ca",
915 "CN" => "webservices.amazon.cn",
916 "DE" => "webservices.amazon.de",
917 "ES" => "webservices.amazon.es",
918 "FR" => "webservices.amazon.fr",
919 "IT" => "webservices.amazon.it",
920 "JP" => "webservices.amazon.co.jp",
921 "UK" => "webservices.amazon.co.uk",
922 "US" => "webservices.amazon.com",
923 );
924
925 $this->_params = array();
926 $this->_locale = strtoupper($locale);
927
928 if(!isset($this->_hosts[$this->_locale])) {
929 throw new DatafeedrError("Invalid Amazon locale");
930 }
931
932 $this->_awsAccessKeyId = $awsAccessKeyId;
933 $this->_awsSecretKey = $awsSecretKey;
934 $this->_awsAssociateTag = $awsAssociateTag;
935 }
936
937 /**
938 * Returns all parameters.
939 *
940 * @return array
941 *
942 **/
943 public function getParams() {
944 return $this->_params;
945 }
946
947 protected function _amazonUrl($operation, $params, $defaults=NULL) {
948 $params = array_filter($params);
949
950 if(!is_null($defaults)) {
951 foreach($defaults as $k => $v) {
952 if(!isset($params[$k])) {
953 $params[$k] = $v;
954 }
955 }
956 }
957
958 $params["Operation"] = $operation;
959 $params["Service"] = "AWSECommerceService";
960 $params["AWSAccessKeyId"] = $this->_awsAccessKeyId;
961 $params["AssociateTag"] = $this->_awsAssociateTag;
962 $params["Version"] = self::AWS_VERSION;
963 $params["Timestamp"] = gmdate("Y-m-d\\TH:i:s\\Z");
964
965 ksort($params);
966 $query = array();
967 foreach($params as $k => $v) {
968 if(is_array($v)) {
969 $v = implode(',', $v);
970 }
971 $query []= $k . '=' . rawurlencode($v);
972 }
973 $query = implode('&', $query);
974 $host = $this->_hosts[$this->_locale];
975 $path = "/onca/xml";
976 $subj = sprintf("GET\n%s\n%s\n%s", $host, $path, $query);
977 $sign = rawurlencode(base64_encode(hash_hmac("sha256", $subj, $this->_awsSecretKey, TRUE)));
978 return "http://{$host}{$path}?{$query}&Signature={$sign}";
979 }
980 }
981 }
982
983 if(!class_exists('DatafeedrAmazonSearchRequest', false)) {
984 /**
985 * Amazon search request.
986 **/
987 class DatafeedrAmazonSearchRequest extends DatafeedrAmazonRequest
988 {
989 /**
990 * Add a parameter.
991 *
992 * @param string $name Parameter name.
993 * @param string $value Parameter value.
994 * @return $this
995 *
996 * @see http://docs.aws.amazon.com/AWSECommerceService/latest/DG/ItemSearch.html
997 *
998 **/
999 public function addParam($name, $value) {
1000 $this->_params[$name] = $value;
1001 return $this;
1002 }
1003
1004 /**
1005 * Run search and return a list of products.
1006 *
1007 * @return array
1008 *
1009 **/
1010 public function execute() {
1011 $defaults = array(
1012 'ResponseGroup' => 'ItemAttributes,Images,OfferFull,BrowseNodes,EditorialReview,VariationSummary',
1013 'SearchIndex' => 'All',
1014 );
1015 $url = $this->_amazonUrl('ItemSearch', $this->_params, $defaults);
1016 $this->_apiCall('amazon_search', array('url' => $url));
1017 return $this->_responseItem('products', array());
1018 }
1019 }
1020 }
1021
1022 if(!class_exists('DatafeedrAmazonLookupRequest', false)) {
1023 /**
1024 * Amazon lookup request.
1025 **/
1026 class DatafeedrAmazonLookupRequest extends DatafeedrAmazonRequest
1027 {
1028 /**
1029 * Add a parameter.
1030 *
1031 * @param string $name Parameter name - one of 'ASIN', 'SKU', 'UPC', 'EAN', 'ISBN'
1032 * @param string|array $value Parameter value or an array of values (up to 10).
1033 * @return $this
1034 *
1035 * @see http://docs.aws.amazon.com/AWSECommerceService/latest/DG/ItemLookup.html
1036 *
1037 **/
1038 public function addParam($name, $value) {
1039 $this->_params[$name] = $value;
1040 return $this;
1041 }
1042
1043 /**
1044 * Run search and return a list of products.
1045 *
1046 * @return array
1047 *
1048 **/
1049 public function execute() {
1050 $params = array_filter($this->_params);
1051 $types = array('ASIN', 'SKU', 'UPC', 'EAN', 'ISBN', 'asin', 'sku', 'upc', 'ean', 'isbn');
1052 foreach($types as $type) {
1053 if(isset($params[$type])) {
1054 $params['IdType'] = strtoupper($type);
1055 $params['ItemId'] = $params[$type];
1056 unset($params[$type]);
1057 }
1058 }
1059
1060 $defaults = array(
1061 'ResponseGroup' => 'ItemAttributes,Images,OfferFull,BrowseNodes,EditorialReview,VariationSummary',
1062 );
1063 if(isset($params['IdType']) && $params['IdType'] != 'ASIN') {
1064 $defaults['SearchIndex'] = 'All';
1065 }
1066 $url = $this->_amazonUrl('ItemLookup', $params, $defaults);
1067 $this->_apiCall('amazon_search', array('url' => $url));
1068 return $this->_responseItem('products', array());
1069 }
1070 }
1071 }
1072
1073 if(!class_exists('DatafeedrError', false)) {
1074 /**
1075 * Generic Api error.
1076 **/
1077 class DatafeedrError extends Exception
1078 {
1079 }
1080 }
1081
1082 if(!class_exists('DatafeedrBadRequestError', false)) {
1083 /**
1084 * API error: Invalid Request.
1085 **/
1086 class DatafeedrBadRequestError extends DatafeedrError
1087 {
1088 }
1089 }
1090
1091 if(!class_exists('DatafeedrAuthenticationError', false)) {
1092 /**
1093 * API error: Authentication failed.
1094 **/
1095 class DatafeedrAuthenticationError extends DatafeedrError
1096 {
1097 }
1098 }
1099
1100 if(!class_exists('DatafeedrLimitExceededError', false)) {
1101 /**
1102 * API error: Query limit exceeded.
1103 **/
1104 class DatafeedrLimitExceededError extends DatafeedrError
1105 {
1106 }
1107 }
1108
1109 if(!class_exists('DatafeedrHTTPError', false)) {
1110 /**
1111 * API error: Unspecified HTTP error.
1112 **/
1113 class DatafeedrHTTPError extends DatafeedrError
1114 {
1115 }
1116 }
1117
1118 if(!class_exists('DatafeedrQueryError', false)) {
1119 /**
1120 * API error: Error in the search query.
1121 **/
1122 class DatafeedrQueryError extends DatafeedrError
1123 {
1124 }
1125 }
1126
1127 if(!class_exists('DatafeedrExternalError', false)) {
1128 /**
1129 * API error: External service error.
1130 **/
1131 class DatafeedrExternalError extends DatafeedrError
1132 {
1133 }
1134 }
1135
1136 if(!class_exists('DatafeedrServerError', false)) {
1137 /**
1138 * API error: Internal server error.
1139 **/
1140 class DatafeedrServerError extends DatafeedrError
1141 {
1142 }
1143 }
1144
1145 ?>