dolibarr 21.0.0-alpha
PSWebServiceLibrary.class.php
1<?php
2/*
3* 2007-2022 PrestaShop SA and Contributors
4*
5* NOTICE OF LICENSE
6*
7* This source file is subject to the Open Software License (OSL 3.0)
8* that is bundled with this package in the file LICENSE.txt.
9* It is also available through the world-wide-web at this URL:
10* https://opensource.org/licenses/osl-3.0.php
11* If you did not receive a copy of the license and are unable to
12* obtain it through the world-wide-web, please send an email
13* to license@prestashop.com so we can send you a copy immediately.
14*
15* DISCLAIMER
16*
17* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
18* versions in the future. If you wish to customize PrestaShop for your
19* needs please refer to https://www.prestashop.com for more information.
20*
21* @author PrestaShop SA <contact@prestashop.com>
22* @copyright 2007-2022 PrestaShop SA
23* @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
24* International Registered Trademark & Property of PrestaShop SA
25* PrestaShop Webservice Library
26* @package PrestaShopWebservice
27*/
28
33{
34
36 protected $url;
37
39 protected $key;
40
42 protected $debug;
43
45 protected $version;
46
48 const PS_COMPATIBLE_VERSIONS_MIN = '1.4.0.0';
50 const PS_COMPATIBLE_VERSIONS_MAX = '8.1.1';
51
75 public function __construct($url, $key, $debug = true)
76 {
77 if (!extension_loaded('curl')) {
79 'Please activate the PHP extension \'curl\' to allow use of PrestaShop webservice library'
80 );
81 }
82 $this->url = $url;
83 $this->key = $key;
84 $this->debug = $debug;
85 $this->version = 'unknown';
86 }
87
100 protected function checkStatusCode($request)
101 {
102 switch ($request['status_code']) {
103 case 200:
104 case 201:
105 break;
106 case 204:
107 $error_message = 'No content';
108 break;
109 case 400:
110 $error_message = 'Bad Request';
111 break;
112 case 401:
113 $error_message = 'Unauthorized';
114 break;
115 case 404:
116 $error_message = 'Not Found';
117 break;
118 case 405:
119 $error_message = 'Method Not Allowed';
120 break;
121 case 500:
122 $error_message = 'Internal Server Error';
123 break;
124 default:
126 'This call to PrestaShop Web Services returned an unexpected HTTP status of:' . $request['status_code']
127 );
128 }
129
130 if (!empty($error_message)) {
131 $response = $this->parseXML($request['response']);
132 $errors = $response->children()->children();
133 if ($errors && count($errors) > 0) {
134 foreach ($errors as $error) {
135 $error_message.= ' - (Code ' . $error->code . '): ' . $error->message;
136 }
137 }
138 $error_label = 'This call to PrestaShop Web Services failed and returned an HTTP status of %d. That means: %s.';
139 throw new PrestaShopWebserviceException(sprintf($error_label, $request['status_code'], $error_message));
140 }
141 }
142
147 protected function getCurlDefaultParams()
148 {
149 $defaultParams = array(
150 CURLOPT_HEADER => true,
151 CURLOPT_RETURNTRANSFER => true,
152 CURLINFO_HEADER_OUT => true,
153 CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
154 CURLOPT_USERPWD => $this->key . ':',
155 CURLOPT_HTTPHEADER => array('Expect:'),
156 //CURLOPT_SSL_VERIFYPEER => false, // reminder, in dev environment sometimes self-signed certificates are used
157 //CURLOPT_CAINFO => "PATH2CAINFO", // ssl certificate chain checking
158 //CURLOPT_CAPATH => "PATH2CAPATH",
159 );
160 return $defaultParams;
161 }
162
173 public function executeRequest($url, $curl_params = array())
174 {
175 $defaultParams = $this->getCurlDefaultParams();
176
177 dol_syslog("curl_init url=".$url);
178 $session = curl_init($url);
179
180 $curl_options = array();
181 foreach ($defaultParams as $defkey => $defval) {
182 if (isset($curl_params[$defkey])) {
183 $curl_options[$defkey] = $curl_params[$defkey];
184 } else {
185 $curl_options[$defkey] = $defaultParams[$defkey];
186 }
187 }
188 foreach ($curl_params as $defkey => $defval) {
189 if (!isset($curl_options[$defkey])) {
190 $curl_options[$defkey] = $curl_params[$defkey];
191 }
192 }
193
194 dol_syslog("curl curl_options = ".var_export($curl_options, true));
195 curl_setopt_array($session, $curl_options);
196 $response = curl_exec($session);
197
198 $index = strpos($response, "\r\n\r\n");
199 if ($index === false && $curl_params[CURLOPT_CUSTOMREQUEST] != 'HEAD') {
200 throw new PrestaShopWebserviceException('Bad HTTP response ' . $response . curl_error($session));
201 }
202
203 $header = substr($response, 0, $index);
204 $body = substr($response, $index + 4);
205
206 $headerArrayTmp = explode("\n", $header);
207
208 $headerArray = array();
209 foreach ($headerArrayTmp as &$headerItem) {
210 $tmp = explode(':', $headerItem);
211 $tmp = array_map('trim', $tmp);
212 if (count($tmp) == 2) {
213 $headerArray[$tmp[0]] = $tmp[1];
214 }
215 }
216
217 if (array_key_exists('PSWS-Version', $headerArray)) {
218 $this->version = $headerArray['PSWS-Version'];
219 if (
220 version_compare(PrestaShopWebservice::PS_COMPATIBLE_VERSIONS_MIN, $headerArray['PSWS-Version']) == 1 ||
221 version_compare(PrestaShopWebservice::PS_COMPATIBLE_VERSIONS_MAX, $headerArray['PSWS-Version']) == -1
222 ) {
224 'This library is not compatible with this version of PrestaShop. Please upgrade/downgrade this library'
225 );
226 }
227 }
228
229 if ($this->debug) {
230 $this->printDebug('HTTP REQUEST HEADER', curl_getinfo($session, CURLINFO_HEADER_OUT));
231 $this->printDebug('HTTP RESPONSE HEADER', $header);
232 }
233 $status_code = curl_getinfo($session, CURLINFO_HTTP_CODE);
234 if ($status_code === 0) {
235 throw new PrestaShopWebserviceException('CURL Error: ' . curl_error($session));
236 }
237 curl_close($session);
238 if ($this->debug) {
239 if ($curl_params[CURLOPT_CUSTOMREQUEST] == 'PUT' || $curl_params[CURLOPT_CUSTOMREQUEST] == 'POST') {
240 $this->printDebug('XML SENT', urldecode($curl_params[CURLOPT_POSTFIELDS]));
241 }
242 if ($curl_params[CURLOPT_CUSTOMREQUEST] != 'DELETE' && $curl_params[CURLOPT_CUSTOMREQUEST] != 'HEAD') {
243 $this->printDebug('RETURN HTTP BODY', $body);
244 }
245 }
246 return array('status_code' => $status_code, 'response' => $body, 'header' => $header);
247 }
248
256 public function printDebug($title, $content)
257 {
258 if (php_sapi_name() == 'cli') {
259 echo $title . PHP_EOL . $content;
260 } else {
261 echo '<div style="display:table;background:#CCC;font-size:8pt;padding:7px"><h6 style="font-size:9pt;margin:0">'
262 . $title
263 . '</h6><pre>'
264 . htmlentities($content)
265 . '</pre></div>';
266 }
267 }
268
274 public function getVersion()
275 {
276 return $this->version;
277 }
278
287 protected function parseXML($response)
288 {
289 if ($response != '') {
290 libxml_clear_errors();
291 libxml_use_internal_errors(true);
292 if (LIBXML_VERSION < 20900) {
293 // Avoid load of external entities (security problem).
294 // Required only if LIBXML_VERSION < 20900
295 // @phan-suppress-next-line PhanDeprecatedFunctionInternal
296 libxml_disable_entity_loader(true);
297 }
298
299 $xml = simplexml_load_string(trim($response), 'SimpleXMLElement', LIBXML_NOCDATA|LIBXML_NONET);
300 if (libxml_get_errors()) {
301 $msg = var_export(libxml_get_errors(), true);
302 libxml_clear_errors();
303 throw new PrestaShopWebserviceException('HTTP XML response is not parsable: ' . $msg);
304 }
305 return $xml;
306 } else {
307 throw new PrestaShopWebserviceException('HTTP response is empty');
308 }
309 }
310
323 public function add($options)
324 {
325 $xml = '';
326
327 if (isset($options['resource'], $options['postXml']) || isset($options['url'], $options['postXml'])) {
328 $url = (isset($options['resource']) ? $this->url . '/api/' . $options['resource'] : $options['url']);
329 $xml = $options['postXml'];
330 if (isset($options['id_shop'])) {
331 $url .= '&id_shop=' . $options['id_shop'];
332 }
333 if (isset($options['id_group_shop'])) {
334 $url .= '&id_group_shop=' . $options['id_group_shop'];
335 }
336 } else {
337 throw new PrestaShopWebserviceException('Bad parameters given');
338 }
339 $request = $this->executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => $xml));
340
341 $this->checkStatusCode($request);
342 return $this->parseXML($request['response']);
343 }
344
376 public function get($options)
377 {
378 if (isset($options['url'])) {
379 $url = $options['url'];
380 } elseif (isset($options['resource'])) {
381 $url = $this->url . '/api/' . $options['resource'];
382 $url_params = array();
383 if (isset($options['id'])) {
384 $url .= '/' . $options['id'];
385 }
386
387 $params = array('filter', 'display', 'sort', 'limit', 'id_shop', 'id_group_shop', 'schema', 'language', 'date', 'price');
388 foreach ($params as $p) {
389 foreach ($options as $k => $o) {
390 if (strpos($k, $p) !== false) {
391 $url_params[$k] = $options[$k];
392 }
393 }
394 }
395 if (count($url_params) > 0) {
396 $url .= '?' . http_build_query($url_params);
397 }
398 } else {
399 throw new PrestaShopWebserviceException('Bad parameters given');
400 }
401
402 $request = $this->executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'GET'));
403
404 $this->checkStatusCode($request);// check the response validity
405
406 return $this->parseXML($request['response']);
407 }
408
417 public function head($options)
418 {
419 if (isset($options['url'])) {
420 $url = $options['url'];
421 } elseif (isset($options['resource'])) {
422 $url = $this->url . '/api/' . $options['resource'];
423 $url_params = array();
424 if (isset($options['id'])) {
425 $url .= '/' . $options['id'];
426 }
427
428 $params = array('filter', 'display', 'sort', 'limit');
429 foreach ($params as $p) {
430 foreach ($options as $k => $o) {
431 if (strpos($k, $p) !== false) {
432 $url_params[$k] = $options[$k];
433 }
434 }
435 }
436 if (count($url_params) > 0) {
437 $url .= '?' . http_build_query($url_params);
438 }
439 } else {
440 throw new PrestaShopWebserviceException('Bad parameters given');
441 }
442 $request = $this->executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'HEAD', CURLOPT_NOBODY => true));
443 $this->checkStatusCode($request);// check the response validity
444 return $request['header'];
445 }
446
460 public function edit($options)
461 {
462 $xml = '';
463 if (isset($options['url'])) {
464 $url = $options['url'];
465 } elseif ((isset($options['resource'], $options['id']) || isset($options['url'])) && $options['putXml']) {
466 $url = (isset($options['url']) ? $options['url'] :
467 $this->url . '/api/' . $options['resource'] . '/' . $options['id']);
468 $xml = $options['putXml'];
469 if (isset($options['id_shop'])) {
470 $url .= '&id_shop=' . $options['id_shop'];
471 }
472 if (isset($options['id_group_shop'])) {
473 $url .= '&id_group_shop=' . $options['id_group_shop'];
474 }
475 } else {
476 throw new PrestaShopWebserviceException('Bad parameters given');
477 }
478
479 $request = $this->executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_POSTFIELDS => $xml));
480 $this->checkStatusCode($request);// check the response validity
481 return $this->parseXML($request['response']);
482 }
483
511 public function delete($options)
512 {
513 if (isset($options['url'])) {
514 $url = $options['url'];
515 } elseif (isset($options['resource']) && isset($options['id'])) {
516 $url = (is_array($options['id']))
517 ? $this->url . '/api/' . $options['resource'] . '/?id=[' . implode(',', $options['id']) . ']'
518 : $this->url . '/api/' . $options['resource'] . '/' . $options['id'];
519 } else {
520 throw new PrestaShopWebserviceException('Bad parameters given');
521 }
522
523 if (isset($options['id_shop'])) {
524 $url .= '&id_shop=' . $options['id_shop'];
525 }
526 if (isset($options['id_group_shop'])) {
527 $url .= '&id_group_shop=' . $options['id_group_shop'];
528 }
529
530 $request = $this->executeRequest($url, array(CURLOPT_CUSTOMREQUEST => 'DELETE'));
531 $this->checkStatusCode($request);// check the response validity
532 return true;
533 }
534}
535
add($options)
Add (POST) a resource.
printDebug($title, $content)
Output debug info.
edit($options)
Edit (PUT) a resource.
parseXML($response)
Load XML from string.
checkStatusCode($request)
Take the status code and throw an exception if the server didn't return 200 or 201 code.
getCurlDefaultParams()
Provides default parameters for the curl connection(s)
head($options)
Head method (HEAD) a resource.
__construct($url, $key, $debug=true)
PrestaShopWebservice constructor.
executeRequest($url, $curl_params=array())
Handles a CURL request to PrestaShop Webservice.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.