PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 2.25
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v2.25
3.37 3.36 3.35 3.34 3.33 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.40 2.41 2.42 2.43 All 142 releases
photonic / extensions / Photonic_Zenfolio_Processor.php

Photonic_Zenfolio_Processor.php in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 2.25, at extensions/Photonic_Zenfolio_Processor.php

1,234 lines 44.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Processor for Zenfolio photos. This extends the Photonic_Processor class and defines methods local to Zenfolio.
4 *
5 * @package Photonic
6 * @subpackage Extensions
7 */
8
9 class Photonic_Zenfolio_Processor extends Photonic_Processor {
10 var $user_name, $user_agent, $token, $service_url, $secure_url, $unlocked_realms;
11 function __construct() {
12 parent::__construct();
13 global $photonic_zenfolio_disable_title_link;
14 $this->provider = 'zenfolio';
15 $this->user_agent = "Photonic for ".get_home_url();
16 $this->link_lightbox_title = empty($photonic_zenfolio_disable_title_link);
17 $this->service_url = 'https://api.zenfolio.com/api/1.8/zfapi.asmx';
18 $this->secure_url = 'https://api.zenfolio.com/api/1.8/zfapi.asmx';
19 $this->unlocked_realms = array();
20
21 $this->doc_links = array(
22 'general' => 'https://aquoid.com/plugins/photonic/zenfolio/',
23 'photos' => 'https://aquoid.com/plugins/photonic/zenfolio/photos/',
24 'photosets' => 'https://aquoid.com/plugins/photonic/zenfolio/photosets/',
25 'groups' => 'https://aquoid.com/plugins/photonic/zenfolio/group/',
26 'hierarchies' => 'https://aquoid.com/plugins/photonic/zenfolio/group-hierarchy/',
27 );
28 $this->perform_back_end_authentication();
29 }
30
31 /**
32 * Main function that fetches the images associated with the shortcode.
33 *
34 * @param array $attr
35 * @return string
36 */
37 public function get_gallery_images($attr = array()) {
38 global $photonic_zenfolio_thumb_size, $photonic_zenfolio_main_size, $photonic_zenfolio_tile_size, $photonic_zenfolio_title_caption, $photonic_zenfolio_video_size, $photonic_zenfolio_media, $photonic_zenfolio_default_user;
39 $this->gallery_index++;
40 $this->push_to_stack('Get Gallery Images');
41
42 $attr = array_merge(
43 $this->common_parameters,
44 array(
45 'caption' => $photonic_zenfolio_title_caption,
46 'thumb_size' => $photonic_zenfolio_thumb_size,
47 'main_size' => $photonic_zenfolio_main_size,
48 'video_size' => $photonic_zenfolio_video_size,
49 'tile_size' => $photonic_zenfolio_tile_size,
50
51 'count' => 500,
52 'offset' => 0,
53 'media' => $photonic_zenfolio_media,
54 'structure' => 'nested',
55 'login_name' => $photonic_zenfolio_default_user,
56 ), $attr);
57 $attr = array_map('trim', $attr);
58
59 $attr['limit'] = empty($attr['limit']) ? $attr['count'] : $attr['limit'];
60 $attr['photo_count'] = empty($attr['photo_count']) ? $attr['limit'] : $attr['photo_count'];
61
62 $attr['overlay_size'] = empty($attr['overlay_size']) ? $attr['thumb_size'] : $attr['overlay_size'];
63 $attr['overlay_video_size'] = empty($attr['overlay_video_size']) ? $attr['video_size'] : $attr['overlay_video_size'];
64
65 extract($attr);
66
67 if (isset($_COOKIE['photonic-zf-keyring'])) {
68 $realms = $this->make_call('KeyringGetUnlockedRealms', array('keyring' => $_COOKIE['photonic-zf-keyring']));
69 if (!empty($realms) && !empty($realms->result)) {
70 $this->unlocked_realms = $realms->result;
71 }
72 }
73
74 $chained_methods = array();
75 $zenfolio_params = array();
76 $attr['headers_already_called'] = true;
77 if (!empty($attr['view'])) {
78 switch ($attr['view']) {
79 case 'photos':
80 if (!empty($object_id)) {
81 $chained_methods[] = 'LoadPhoto';
82 if(($h = stripos($object_id, 'h')) !== false) {
83 $object_id = substr($object_id, $h + 1);
84 $object_id = hexdec($object_id);
85 }
86 else if (($p = stripos($object_id, 'p')) !== false) {
87 $object_id = substr($object_id, $p + 1);
88 }
89 else if (strlen($object_id) == 7) {
90 $object_id = hexdec($object_id);
91 }
92
93 $zenfolio_params['photoId'] = $object_id;
94 $zenfolio_params['level'] = 'Full';
95 }
96 else if (!empty($text)) {
97 $zenfolio_params['searchId'] = '';
98 if (!empty($sort_order)) {
99 $zenfolio_params['sortOrder'] = $sort_order; // Popularity | Date | Rank
100 }
101 else {
102 $zenfolio_params['sortOrder'] = 'Date';
103 }
104 $zenfolio_params['query'] = $text;
105 $zenfolio_params['offset'] = $attr['offset'];
106 $zenfolio_params['limit'] = $attr['limit'];
107 $chained_methods[] = 'SearchPhotoByText';
108 }
109 else if (!empty($category_code)) {
110 $zenfolio_params['searchId'] = '';
111 if (!empty($sort_order)) {
112 $zenfolio_params['sortOrder'] = $sort_order; // Popularity | Date
113 }
114 else {
115 $zenfolio_params['sortOrder'] = 'Date';
116 }
117 $zenfolio_params['categoryCode'] = $category_code;
118 $zenfolio_params['offset'] = $attr['offset'];
119 $zenfolio_params['limit'] = $attr['limit'];
120 $chained_methods[] = 'SearchPhotoByCategory';
121 }
122 else if (!empty($kind)) {
123 $zenfolio_params['offset'] = $attr['offset'];
124 $zenfolio_params['limit'] = $attr['limit'];
125 switch ($kind) {
126 case 'popular':
127 $chained_methods[] = 'GetPopularPhotos';
128 break;
129
130 case 'recent':
131 $chained_methods[] = 'GetRecentPhotos';
132 break;
133
134 default:
135 $this->pop_from_stack();
136 return $this->error(sprintf(esc_html__('Invalid %s parameter.', 'photonic'), '<code>kind</code>').
137 Photonic::doc_link($this->doc_links['photos']));
138 }
139 }
140 else {
141 $this->pop_from_stack();
142 return $this->error(sprintf(esc_html__('The %1$s parameter is required if %2$s is not specified.', 'photonic'), '<code>kind</code>', '<code>object_id</code>').
143 Photonic::doc_link($this->doc_links['photos']));
144 }
145 break;
146
147 case 'photosets':
148 if (!empty($object_id)) {
149 if(($p = stripos($object_id, 'p')) !== false) {
150 $object_id = substr($object_id, $p + 1);
151 }
152
153 $zenfolio_params['photosetId'] = $object_id;
154 $zenfolio_params['level'] = 'Level1';
155 $zenfolio_params['includePhotos'] = false;
156
157 if (!empty($password) && empty($realm_id)) {
158 $first_call = $this->make_call('LoadPhotoSet', $zenfolio_params);
159 if (isset($first_call->result) && !empty($first_call->result)) {
160 $photoset = $first_call->result;
161 if (isset($photoset->AccessDescriptor)) {
162 $realm_id = $photoset->AccessDescriptor->Id;
163 }
164 }
165 }
166
167 if (!empty($password) && !empty($realm_id)) {
168 if (!in_array($realm_id, $this->unlocked_realms)) {
169 $attr['headers_already_called'] = empty($attr['panel']); //false;
170 $chained_methods[] = 'KeyringAddKeyPlain';
171 $zenfolio_params['keyring'] = empty($_COOKIE['photonic-zf-keyring']) ? '' : $_COOKIE['photonic-zf-keyring'];
172 $zenfolio_params['realmId'] = $realm_id;
173 $zenfolio_params['password'] = $password;
174 }
175 }
176
177 $chained_methods[] = 'LoadPhotoSet';
178 $zenfolio_params['startingIndex'] = $attr['offset'];
179 $zenfolio_params['numberOfPhotos'] = $attr['limit'];
180 $chained_methods[] = 'LoadPhotoSetPhotos';
181 }
182 else if (!empty($login_name)) {
183 $chained_methods[] = 'LoadGroupHierarchy';
184 $attr['structure'] = 'flat';
185 $zenfolio_params['loginName'] = $login_name;
186 }
187 else if (!empty($text) && !empty($photoset_type)) {
188 $zenfolio_params['searchId'] = '';
189 if (strtolower($photoset_type) == 'gallery' || strtolower($photoset_type) == 'galleries') {
190 $zenfolio_params['type'] = 'Gallery';
191 }
192 else if (strtolower($photoset_type) == 'collection' || strtolower($photoset_type) == 'collections') {
193 $zenfolio_params['type'] = 'Collection';
194 }
195 else {
196 $this->pop_from_stack();
197 return $this->error(sprintf(esc_html__('Invalid %1$s parameter. Permissible values are %2$s or %3$s.', 'photonic'), '<code>photoset_type</code>', '<code>Gallery</code>', '<code>Collection</code>').
198 Photonic::doc_link($this->doc_links['photosets']));
199 }
200
201 if (!empty($sort_order)) {
202 $zenfolio_params['sortOrder'] = $sort_order; // Popularity | Date | Rank
203 }
204 else {
205 $zenfolio_params['sortOrder'] = 'Rank';
206 }
207 $zenfolio_params['query'] = $text;
208 $zenfolio_params['offset'] = $attr['offset'];
209 $zenfolio_params['limit'] = $attr['limit'];
210 $chained_methods[] = 'SearchSetByText';
211 }
212 else if (!empty($category_code) && !empty($photoset_type)) {
213 $zenfolio_params['searchId'] = '';
214 if (strtolower($photoset_type) == 'gallery' || strtolower($photoset_type) == 'galleries') {
215 $zenfolio_params['type'] = 'Gallery';
216 }
217 else if (strtolower($photoset_type) == 'collection' || strtolower($photoset_type) == 'collections') {
218 $zenfolio_params['type'] = 'Collection';
219 }
220 else {
221 $this->pop_from_stack();
222 return $this->error(sprintf(esc_html__('Invalid %1$s parameter. Permissible values are %2$s or %3$s.', 'photonic'), '<code>photoset_type</code>', '<code>Gallery</code>', '<code>Collection</code>').
223 Photonic::doc_link($this->doc_links['photosets']));
224 }
225
226 if (!empty($sort_order)) {
227 $zenfolio_params['sortOrder'] = $sort_order; // Popularity | Date
228 }
229 else {
230 $zenfolio_params['sortOrder'] = 'Date';
231 }
232 $zenfolio_params['categoryCode'] = $category_code;
233 $zenfolio_params['offset'] = $attr['offset'];
234 $zenfolio_params['limit'] = $attr['limit'];
235 $chained_methods[] = 'SearchSetByCategory';
236 }
237 else if (!empty($kind) && !empty($photoset_type)) {
238 switch ($kind) {
239 case 'popular':
240 $chained_methods[] = 'GetPopularSets';
241 break;
242
243 case 'recent':
244 $chained_methods[] = 'GetRecentSets';
245 break;
246
247 default:
248 $this->pop_from_stack();
249 return $this->error(sprintf(esc_html__('Invalid %s parameter.', 'photonic'), '<code>kind</code>').
250 Photonic::doc_link($this->doc_links['photosets']));
251 }
252 if (strtolower($photoset_type) == 'gallery' || strtolower($photoset_type) == 'galleries') {
253 $zenfolio_params['type'] = 'Gallery';
254 }
255 else if (strtolower($photoset_type) == 'collection' || strtolower($photoset_type) == 'collections') {
256 $zenfolio_params['type'] = 'Collection';
257 }
258 else {
259 $this->pop_from_stack();
260 return $this->error(sprintf(esc_html__('Invalid %1$s parameter. Permissible values are %2$s or %3$s.', 'photonic'), '<code>photoset_type</code>', '<code>Gallery</code>', '<code>Collection</code>').
261 Photonic::doc_link($this->doc_links['photosets']));
262 }
263
264 // These have to be after the $params['type'] assignment
265 $zenfolio_params['offset'] = $attr['offset'];
266 $zenfolio_params['limit'] = $attr['limit'];
267 }
268 else if (!empty($filter) && empty($login_name)) {
269 $this->pop_from_stack();
270 return $this->error(sprintf(esc_html__('The %1$s parameter is required if %2$s is specified.', 'photonic'), '<code>login_name</code>', '<code>filter</code>').
271 Photonic::doc_link($this->doc_links['photosets']));
272 }
273 else if (empty($kind)) {
274 $this->pop_from_stack();
275 return $this->error(sprintf(esc_html__('The %1$s parameter is required if %2$s or %3$s is not specified.', 'photonic'), '<code>kind</code>', '<code>object_id</code>', '<code>login_name</code>').
276 Photonic::doc_link($this->doc_links['photosets']));
277 }
278 else if (empty($photoset_type)) {
279 $this->pop_from_stack();
280 return $this->error(sprintf(esc_html__('The %1$s parameter is required if %2$s or %3$s is not specified.', 'photonic'), '<code>photoset_type</code>', '<code>object_id</code>', '<code>login_name</code>').
281 Photonic::doc_link($this->doc_links['photosets']));
282 }
283
284 if (!empty($login_name) && !empty($category_code)) {
285 $attr['user_specific_category'] = true;
286 }
287
288 if (!empty($login_name) && !empty($text)) {
289 $attr['user_specific_text'] = true;
290 }
291 break;
292
293 case 'hierarchy':
294 if (empty($login_name)) {
295 $this->pop_from_stack();
296 return $this->error(sprintf(esc_html__('The %s parameter is required.', 'photonic'), '<code>login_name</code>').
297 Photonic::doc_link($this->doc_links['hierarchies']));
298 }
299 $chained_methods[] = 'LoadGroupHierarchy';
300 $zenfolio_params['loginName'] = $login_name;
301 break;
302
303 case 'group':
304 if (empty($object_id)) {
305 $this->pop_from_stack();
306 return $this->error(sprintf(esc_html__('The %s parameter is required.', 'photonic'), '<code>object_id</code>').
307 Photonic::doc_link($this->doc_links['groups']));
308 }
309 $chained_methods[] = 'LoadGroup';
310 if(($f = stripos($object_id, 'f')) !== false) {
311 $object_id = substr($object_id, $f + 1);
312 }
313 $zenfolio_params['groupId'] = $object_id;
314 $zenfolio_params['level'] = 'Full';
315 $zenfolio_params['includeChildren'] = true;
316 break;
317 }
318 }
319
320 if (!empty($attr['panel'])) {
321 $attr['display'] = 'popup';
322 }
323 else {
324 $attr['display'] = 'in-page';
325 }
326
327 $header_display = $this->get_header_display($attr);
328 $attr['header_display'] = $header_display;
329
330 $level_2_meta = array(
331 'start' => $attr['offset'],
332 'per-page' => $attr['limit'],
333 );
334 $attr['level_2_meta'] = $level_2_meta;
335
336 $call_return = $this->make_chained_calls($chained_methods, $zenfolio_params, $attr);
337
338 if ($call_return == $this->password_protected) {
339 $this->pop_from_stack();
340 return $call_return;
341 }
342 else if (empty($call_return)) {
343 $this->pop_from_stack();
344 return '';
345 }
346
347 $ret = $this->finalize_markup($call_return, $attr);
348 $this->pop_from_stack();
349
350 return $ret.$this->get_stack_markup();
351 }
352
353 /**
354 * Calls a Zenfolio method with the passed parameters. The method is called using JSON-RPC. WP's wp_remote_request
355 * method doesn't work here because of specific CURL parameter requirements.
356 *
357 * @param $method
358 * @param $params
359 * @param null $keyring
360 * @return array|mixed
361 */
362 function make_call($method, $params, $keyring = null) {
363 $request = array();
364 $request['method'] = $method;
365 $request['params'] = array_values($params);
366 $request['id'] = 1;
367 $bodyString = json_encode($request);
368 $bodyLength = strlen($bodyString);
369
370 $headers = array();
371 $headers[] = 'Host: api.zenfolio.com';
372 $headers[] = 'User-Agent: '.$this->user_agent;
373 if ($this->token && $method !== 'GetChallenge' && $method !== 'Authenticate') {
374 $headers[] = 'X-Zenfolio-Token: '.$this->token;
375 }
376 if (isset($_COOKIE['photonic-zf-keyring'])) {
377 $headers[] = 'X-Zenfolio-Keyring: '.$_COOKIE['photonic-zf-keyring'];
378 }
379 else if (!empty($keyring)) {
380 $headers[] = 'X-Zenfolio-Keyring: '.$keyring;
381 }
382 $headers[] = 'Content-Type: application/json';
383 $headers[] = 'Content-Length: '.$bodyLength."\r\n";
384 $headers[] = $bodyString;
385
386 $ch = curl_init($this->secure_url);
387 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, PHOTONIC_SSL_VERIFY);
388 curl_setopt($ch, CURLOPT_USERAGENT, $this->user_agent);
389 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
390 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
391 curl_setopt($ch, CURLOPT_POST, true);
392 curl_setopt($ch, CURLOPT_HEADER, FALSE);
393 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
394 // curl_setopt($ch, CURLINFO_HEADER_OUT, true);
395
396 $response = curl_exec($ch);
397
398 curl_close($ch);
399
400 //PHP/WP's json_decode() function really messes up the "long" ids returned by Zenfolio. The following takes care of this.
401 // Can't pass the 4th argument as outlined here: https://php.net/manual/en/function.json-decode.php, since it only came into existence in PHP 5.4
402 $response = preg_replace('/"Id":(\d+)/', '"Id":"$1"', $response);
403 $response = preg_replace('/"RealmId":(\d+)/', '"Id":"$1"', $response);
404 if ($method == 'KeyringGetUnlockedRealms') {
405 $realm_ids = array();
406 preg_match('/([\[^,\d]+\])/', $response, $realm_ids);
407 if (!empty($realm_ids)) {
408 $realm_ids = $realm_ids[0];
409 $replace = $realm_ids;
410 $replace = str_replace('[', '["', $replace);
411 $replace = str_replace(']', '"]', $replace);
412 $replace = str_replace(',', '","', $replace);
413 $response = str_replace($realm_ids, $replace, $response);
414 }
415 }
416
417 $response = json_decode($response);
418 return $response;
419 }
420
421 /**
422 * @param $method
423 * @param null $params
424 * @param bool $ssl_verify_peer
425 * @param null $keyring
426 * @return array|mixed|null|object|string|string[]|WP_Error
427 */
428 function make_wp_call($method, $params = null, $ssl_verify_peer = PHOTONIC_SSL_VERIFY, $keyring = null) {
429 $request = $this->prepare_request($method, $params, $keyring);
430 $response = $this->make_wp_request($method, $ssl_verify_peer, $request);
431 return $response;
432 }
433
434 /**
435 * Makes a sequence of calls to different Zenfolio methods. This is particularly useful in case of authenticated calls, where
436 * first the authentication happens, then the content is displayed, all in the same call.
437 *
438 * @param array $methods
439 * @param array $zenfolio_args
440 * @param array $short_code
441 * @return string
442 */
443 function make_chained_calls($methods, $zenfolio_args, &$short_code = array()) {
444 $this->push_to_stack('Make chained calls');
445 $ret = '';
446 $keyring = null;
447 $original_params = array();
448 foreach ($zenfolio_args as $param => $value) {
449 $original_params[$param] = $value;
450 }
451
452 foreach ($methods as $method) {
453 $this->push_to_stack("Making call for $method");
454 $keyring_params = array();
455 if ($method == 'KeyringGetUnlockedRealms') {
456 $keyring_params['keyring'] = $zenfolio_args['keyring'];
457 $response = $this->make_call($method, $keyring_params);
458 if (isset($response->result)) {
459 $this->unlocked_realms = $response->result;
460 }
461 }
462 else if ($method == 'KeyringAddKeyPlain') {
463 if (in_array($zenfolio_args['realmId'], $this->unlocked_realms)) {
464 continue;
465 }
466 $keyring_params['keyring'] = $zenfolio_args['keyring'];
467 $keyring_params['realmId'] = $zenfolio_args['realmId'];
468 $keyring_params['password'] = $zenfolio_args['password'];
469 $response = $this->make_call($method, $keyring_params);
470
471 if (!empty($response->result)) {
472 // Sometimes the cookie isn't set by the setcookie command (happens when the password is passed as a shortcode parameter
473 // instead of the password prompt)
474 $keyring = $response->result;
475 if (!in_array($keyring_params['realmId'], $this->unlocked_realms)) {
476 $this->unlocked_realms[] = $keyring_params['realmId'];
477 }
478
479 if (!$short_code['headers_already_called']) {
480 setcookie('photonic-zf-keyring', $response->result, time() + 60 * 60 * 24, COOKIEPATH);
481 }
482 }
483 else {
484 $ret = $this->password_protected;
485 break;
486 }
487 }
488 else {
489 foreach ($original_params as $param => $value) {
490 $zenfolio_args[$param] = $value;
491 }
492
493 $keyring_fields = array('keyring', 'realmId', 'password');
494 foreach ($zenfolio_args as $param => $value) {
495 if (in_array($param, $keyring_fields)) {
496 unset($zenfolio_args[$param]);
497 }
498 }
499
500 if ($method === 'LoadPhotoSetPhotos') {
501 unset($zenfolio_args['level']);
502 unset($zenfolio_args['includePhotos']);
503 }
504 else if ($method === 'LoadPhotoSet') {
505 unset($zenfolio_args['startingIndex']);
506 unset($zenfolio_args['numberOfPhotos']);
507 }
508
509 $response = $this->make_call($method, $zenfolio_args, $keyring);
510 $this->pop_from_stack();
511 $this->push_to_stack('Processing response');
512 $ret .= $this->process_response($method, $response, $short_code);
513 $this->pop_from_stack();
514 }
515 }
516 $this->pop_from_stack();
517 return $ret;
518 }
519
520 /**
521 * Routing function that takes the response and redirects it to the appropriate processing function.
522 *
523 * @param $method
524 * @param $response
525 * @param array $short_code
526 * @return string
527 */
528 function process_response($method, $response, &$short_code = array()) {
529 $header_display = $short_code['header_display'];
530 $level_2_meta = $short_code['level_2_meta'];
531
532 if (!empty($response->result)) {
533 $result = $response->result;
534 $ret = '';
535
536 switch ($method) {
537 case 'GetPopularPhotos':
538 case 'GetRecentPhotos':
539 case 'SearchPhotoByText':
540 case 'SearchPhotoByCategory':
541 $level_2_meta['total'] = $result->TotalCount;
542 $short_code['level_2_meta'] = $level_2_meta;
543 $ret = $this->process_photos($result, 'stream', $short_code);
544 break;
545
546 case 'LoadPhoto':
547 $ret = $this->process_photo($result, $short_code);
548 break;
549
550 case 'GetPopularSets':
551 case 'GetRecentSets':
552 case 'SearchSetByText':
553 case 'SearchSetByCategory':
554 $ret = $this->process_sets($result, $short_code);
555 break;
556
557 case 'LoadPhotoSet':
558 case 'LoadPhotoSetPhotos':
559 if (isset($result->ImageCount)) {
560 $level_2_meta['total'] = $result->ImageCount;
561 $short_code['level_2_meta'] = $level_2_meta;
562 }
563 $ret = $this->process_set($result, array('header_display' => $header_display), $short_code);
564 break;
565
566 case 'LoadGroupHierarchy':
567 $ret = $this->process_group_hierarchy($result, array('header_display' => $header_display), $short_code);
568 break;
569
570 case 'LoadGroup':
571 $ret = $this->process_group($result, array('header_display' => $header_display), $short_code, 0);
572 break;
573 }
574 return $ret;
575 }
576 else if ($response == $this->password_protected) {
577 return $response;
578 }
579 else if (!empty($response->error)) {
580 if (!empty($response->error->message)) {
581 return $this->error(esc_html__('Zenfolio returned an error:', 'photonic')."<br/>\n".$response->error->message);
582 }
583 else {
584 return $this->error(esc_html__('Unknown error', 'photonic'));
585 }
586 }
587 else {
588 return $this->error(esc_html__('Unknown error', 'photonic'));
589 }
590 }
591
592 /**
593 * Takes an array of photos and displays each as a thumbnail. Each thumbnail, upon clicking launches a lightbox.
594 *
595 * @param $response
596 * @param string $parent
597 * @param array $short_code
598 * @return string
599 */
600 function process_photos($response, $parent, $short_code = array()) {
601 if (!is_array($response)) {
602 if (empty($response->Photos) || !is_array($response->Photos)) {
603 return $this->error(esc_html__('Response is not an array', 'photonic'));
604 }
605 $response = $response->Photos;
606 }
607
608 global $photonic_zenfolio_photos_per_row_constraint, $photonic_zenfolio_photo_title_display, $photonic_zenfolio_photos_constrain_by_padding, $photonic_zenfolio_photos_constrain_by_count;
609 $ret = '';
610 $row_constraints = array('constraint-type' => $photonic_zenfolio_photos_per_row_constraint, 'padding' => $photonic_zenfolio_photos_constrain_by_padding, 'count' => $photonic_zenfolio_photos_constrain_by_count);
611 $photo_objects = $this->build_level_1_objects($response, $short_code);
612
613 $level_2_meta = $short_code['level_2_meta'];
614 $level_2_meta['end'] = $level_2_meta['start'] + count($response);
615
616 $ret .= $this->display_level_1_gallery($photo_objects,
617 array(
618 'title_position' => $photonic_zenfolio_photo_title_display,
619 'row_constraints' => $row_constraints,
620 'parent' => $parent,
621 'level_2_meta' => $level_2_meta,
622 ),
623 $short_code
624 );
625
626 return $ret;
627 }
628
629 function build_level_1_objects($response, $short_code = array()) {
630 if (!is_array($response)) {
631 if (empty($response->Photos) || !is_array($response->Photos)) {
632 return array();
633 }
634 $response = $response->Photos;
635 }
636
637 $tile_size = (empty($short_code['tile_size']) || $short_code['tile_size'] == 'same') ? $short_code['main_size'] : $short_code['tile_size'];
638
639 $type = '$type';
640 $photo_objects = array();
641
642 $media = explode(',', $short_code['media']);
643 $videos_ok = in_array('videos', $media) || in_array('all', $media);
644 $photos_ok = in_array('photos', $media) || in_array('all', $media);
645 foreach ($response as $photo) {
646 if (empty($photo->$type) || $photo->$type != 'Photo' || ($photo->IsVideo && !$videos_ok) || (!$photo->IsVideo && !$photos_ok)) {
647 continue;
648 }
649 $appendage = array();
650 if (isset($photo->Sequence)) {
651 $appendage[] = 'sn='.$photo->Sequence;
652 }
653 if (isset($photo->UrlToken)) {
654 $appendage[] = 'tk='.$photo->UrlToken;
655 }
656
657 $photo_object = array();
658 $photo_object['thumbnail'] = 'https://'.$photo->UrlHost.$photo->UrlCore.'-'.$short_code['thumb_size'].'.jpg';
659 $photo_object['main_image'] = 'https://'.$photo->UrlHost.$photo->UrlCore.'-'.$short_code['main_size'].'.jpg';
660 $photo_object['tile_image'] = 'https://'.$photo->UrlHost.$photo->UrlCore.'-'.$tile_size.'.jpg';
661 if ($photo->IsVideo) {
662 $photo_object['video'] = substr($photo->OriginalUrl, 0, strlen($photo->OriginalUrl) - 7).$short_code['video_size'].'.mp4';
663 }
664 $photo_object['download'] = $photo_object['main_image'].'?'.implode('&', $appendage);
665 $photo_object['title'] = $photo->Title;
666 $photo_object['alt_title'] = $photo->Title;
667 $photo_object['description'] = $photo->Caption;
668 $photo_object['main_page'] = $photo->PageUrl;
669 $photo_object['id'] = $photo->Id;
670
671 $photo_object['provider'] = $this->provider;
672 $photo_object['gallery_index'] = $this->gallery_index;
673
674 $photo_objects[] = $photo_object;
675 }
676
677 return $photo_objects;
678 }
679
680 function build_level_2_objects($response, $short_code = array()) {
681 global $photonic_zenfolio_hide_password_protected_thumbnail;
682 $tile_size = (empty($short_code['tile_size']) || $short_code['tile_size'] == 'same') ? $short_code['main_size'] : $short_code['tile_size'];
683
684 $filter_list = array();
685 if (!empty($short_code['filter'])) {
686 $filter_list = explode(',', $short_code['filter']);
687 }
688
689 $objects = array();
690 foreach ($response as $photoset) {
691 if (empty($photoset->TitlePhoto)) {
692 continue;
693 }
694 if (!empty($photoset->AccessDescriptor) && !empty($photoset->AccessDescriptor->AccessType) && $photoset->AccessDescriptor->AccessType == 'Password' && !empty($photonic_zenfolio_hide_password_protected_thumbnail)) {
695 continue;
696 }
697
698 $object = array();
699
700 $photo = $photoset->TitlePhoto;
701 $object['id_1'] = $photoset->Id;
702 $object['thumbnail'] = 'https://'.$photo->UrlHost.$photo->UrlCore.'-'.$short_code['thumb_size'].'.jpg';
703 $object['tile_image'] = 'https://'.$photo->UrlHost.$photo->UrlCore.'-'.$tile_size.'.jpg';
704 $object['main_page'] = $photoset->PageUrl;
705 $object['title'] = esc_attr($photoset->Title);
706 $object['counter'] = $photoset->PhotoCount;
707 $object['data_attributes'] = array(
708 'thumb-size' => $short_code['thumb_size'],
709 'photo-count' => $short_code['photo_count'],
710 'photo-more' => empty($short_code['photo_more']) ? '' : $short_code['photo_more'],
711 'overlay-size' => $short_code['overlay_size'],
712 'overlay-video-size' => $short_code['overlay_video_size'],
713 );
714
715 if (!empty($photoset->AccessDescriptor) && !empty($photoset->AccessDescriptor->AccessType) && $photoset->AccessDescriptor->AccessType == 'Password') {
716 if (!in_array($photoset->AccessDescriptor->Id, $this->unlocked_realms)) {
717 $object['classes'] = array('photonic-zenfolio-passworded');
718 $object['passworded'] = 1;
719 $object['realm_id'] = $photoset->AccessDescriptor->Id;
720 $object['data_attributes']['realm'] = $photoset->AccessDescriptor->Id;
721 }
722 }
723
724 $page_url = parse_url($photoset->PageUrl);
725 $page_url = $page_url['path'];
726 $page_url = explode('/', $page_url);
727 if (count($page_url) > 1) {
728 $page_url = $page_url[1];
729 }
730
731 if (!is_array($page_url) && (count($filter_list) === 0 || (count($filter_list) > 0 && in_array($page_url, $filter_list) && strtolower($short_code['filter_type']) !== 'exclude') ||
732 (count($filter_list) > 0 && !in_array($page_url, $filter_list) && strtolower($short_code['filter_type']) === 'exclude'))) {
733 $objects[] = $object;
734 }
735 else if (is_array($page_url)) { // Something went wrong. Let's be safe and add the object.
736 $objects[] = $object;
737 }
738 }
739 return $objects;
740 }
741
742 /**
743 * Prints a single photo with the title as an <h3> and the caption as the image caption.
744 *
745 * @param $photo
746 * @param $short_code
747 * @return string
748 */
749 function process_photo($photo, $short_code) {
750 $type = '$type';
751 if (empty($photo->$type) || $photo->$type != 'Photo') {
752 return '';
753 }
754
755 return $this->generate_single_photo_markup('zenfolio', array(
756 'src' => 'https://'.$photo->UrlHost.$photo->UrlCore.'-'.$short_code['main_size'].'.jpg',
757 'href' => $photo->PageUrl,
758 'title' => $photo->Title,
759 'caption' => $photo->Caption,
760 )
761 );
762 }
763
764 /**
765 * Takes an array of photosets and displays a thumbnail for each of them. Password-protected thumbnails might be excluded via the options.
766 *
767 * @param $response
768 * @param array $short_code
769 * @return string
770 */
771 function process_sets($response, $short_code = array()) {
772 if (!is_array($response)) {
773 if (empty($response->PhotoSets) || !is_array($response->PhotoSets)) {
774 return $this->error(esc_html__('Response is not an array', 'photonic'));
775 }
776 $response = $response->PhotoSets;
777 }
778
779 global $photonic_zenfolio_sets_per_row_constraint, $photonic_zenfolio_sets_constrain_by_count, $photonic_zenfolio_sets_constrain_by_padding,
780 $photonic_zenfolio_set_title_display, $photonic_zenfolio_hide_set_photos_count_display;
781 $row_constraints = array('constraint-type' => $photonic_zenfolio_sets_per_row_constraint, 'padding' => $photonic_zenfolio_sets_constrain_by_padding, 'count' => $photonic_zenfolio_sets_constrain_by_count);
782 $objects = $this->build_level_2_objects($response, $short_code);
783 $ret = $this->display_level_2_gallery($objects,
784 array(
785 'row_constraints' => $row_constraints,
786 'type' => 'photosets',
787 'singular_type' => 'set',
788 'title_position' => $photonic_zenfolio_set_title_display,
789 'level_1_count_display' => $photonic_zenfolio_hide_set_photos_count_display,
790 ),
791 $short_code
792 );
793 return $ret;
794 }
795
796 /**
797 * Displays a header with a basic summary for a photoset, along with thumbnails for all associated photos.
798 *
799 * @param $response
800 * @param array $options
801 * @param array $short_code
802 * @return string
803 */
804 function process_set($response, $options = array(), &$short_code = array()) {
805 $ret = '';
806 $level_2_meta = $short_code['level_2_meta'];
807
808 $media = explode(',', $short_code['media']);
809 $videos_ok = in_array('videos', $media) || in_array('all', $media);
810 $photos_ok = in_array('photos', $media) || in_array('all', $media);
811
812 if (!is_array($response)) {
813 global $photonic_zenfolio_link_set_page, $photonic_zenfolio_hide_set_thumbnail, $photonic_zenfolio_hide_set_title, $photonic_zenfolio_hide_set_photo_count;
814
815 $header = $this->get_header_object($response, $short_code['thumb_size']);
816 $hidden = array('thumbnail' => !empty($photonic_zenfolio_hide_set_thumbnail), 'title' => !empty($photonic_zenfolio_hide_set_title), 'counter' => !empty($photonic_zenfolio_hide_set_photo_count));
817 $counters = array();
818 if ($photos_ok) $counters['photos'] = $response->ImageCount;
819 if ($videos_ok) $counters['videos'] = $response->VideoCount;
820
821 $level_2_meta['total'] = ($photos_ok ? $response->ImageCount : 0) + ($videos_ok ? $response->VideoCount : 0);
822 $short_code['level_2_meta'] = $level_2_meta;
823 $ret .= $this->process_object_header($header,
824 array(
825 'type' => 'set',
826 'hidden' => $this->get_hidden_headers($options['header_display'], $hidden),
827 'counters' => $counters,
828 'link' => empty($photonic_zenfolio_link_set_page),
829 'display' => $short_code['display'],
830 )
831 );
832 }
833 else {
834 $ret .= $this->process_photos($response, 'set', $short_code);
835 }
836 return $ret;
837 }
838
839 /**
840 * Takes a Zenfolio response object and converts it into an associative array with a title, a thumbnail URL and a link URL.
841 *
842 * @param $object
843 * @param $thumb_size
844 * @return array
845 */
846 public function get_header_object($object, $thumb_size) {
847 $header = array();
848
849 if (!empty($object->Title)) {
850 $header['title'] = $object->Title;
851 if (!empty($object->TitlePhoto)) {
852 $photo = $object->TitlePhoto;
853 $header['thumb_url'] = 'https://' . $photo->UrlHost . $photo->UrlCore . '-' . $thumb_size . '.jpg';
854 }
855 $header['link_url'] = $object->PageUrl;
856 }
857
858 return $header;
859 }
860
861 /**
862 * For a given user this prints out the group hierarchy. This starts with the root level and first prints all immediate
863 * children photosets. It then goes into each child group and recursively displays the photosets for each of them in separate sections.
864 *
865 * @param $response
866 * @param array $options
867 * @param array $short_code
868 * @return string
869 */
870 function process_group_hierarchy($response, $options = array(), $short_code = array()) {
871 if (empty($response->Elements)) {
872 return $this->error(esc_html__('No galleries, collections or groups defined for this user', 'photonic'));
873 }
874
875 $filters = array();
876 if (!empty($short_code['kind']) && in_array(strtolower($short_code['kind']), array('popular', 'recent')) && !empty($short_code['login_name']) && empty($short_code['filter'])) {
877 $pr_response = $this->make_wp_call('LoadPublicProfile', array('login_name' => $short_code['login_name']));
878 if (!empty($pr_response->result)) {
879 $pr_response = $pr_response->result;
880 if (strtolower($short_code['kind']) == 'popular' && !empty($pr_response->FeaturedPhotoSets)) {
881 foreach ($pr_response->FeaturedPhotoSets as $photoset) {
882 $filters[] = $photoset->Id;
883 }
884 }
885 else if (strtolower($short_code['kind']) == 'recent' && !empty($pr_response->RecentPhotoSets)) {
886 foreach ($pr_response->RecentPhotoSets as $photoset) {
887 $filters[] = $photoset->Id;
888 }
889 }
890 if (empty($filters)) {
891 return '';
892 }
893 }
894 }
895
896 $all_photosets = array();
897 $ret = $this->process_group($response, $options, $short_code, 0, $all_photosets, $filters);
898 return $ret;
899 }
900
901 /**
902 * For a given group this displays the immediate children photosets and then recursively displays all children groups.
903 *
904 * @param $group
905 * @param array $options
906 * @param array $short_code
907 * @param $level
908 * @param array $all_photosets
909 * @param array $recent_popular
910 * @return string
911 */
912 function process_group($group, $options, $short_code, $level, &$all_photosets = array(), $recent_popular = array()) {
913 $ret = '';
914 $type = '$type';
915 if (!isset($group->Elements)) {
916 $object_id = $group->Id;
917 $method = 'LoadGroup';
918 if(($f = stripos($object_id, 'f')) !== false) {
919 $object_id = substr($object_id, $f + 1);
920 }
921 $params = array();
922 $params['groupId'] = $object_id;
923 $params['level'] = 'Full';
924 $params['includeChildren'] = true;
925 $response = $this->make_call($method, $params);
926 if (!empty($response->result)) {
927 $group = $response->result;
928 }
929 }
930
931 if (empty($group->Elements)) {
932 return '';
933 }
934
935 $elements = $group->Elements;
936 $photosets = array();
937 $groups = array();
938 global $photonic_zenfolio_hide_password_protected_thumbnail;
939 $image_count = 0;
940 $requests = array();
941
942 foreach ($elements as $element) {
943 if ($element->$type == 'PhotoSet') {
944 if (!empty($short_code['photoset_type']) && in_array(strtolower($short_code['photoset_type']), array('gallery', 'collection')) && $short_code['photoset_type'] !== $element->Type) {
945 continue;
946 }
947
948 if (!empty($element->AccessDescriptor) && !empty($element->AccessDescriptor->AccessType) && $element->AccessDescriptor->AccessType == 'Password' && !empty($photonic_zenfolio_hide_password_protected_thumbnail)) {
949 continue;
950 }
951
952 if (!empty($short_code['user_specific_category']) || !empty($short_code['user_specific_text'])) {
953 // Need an extra call here, since the LoadGroup doesn't return Level2 attributes for the children
954 // Calls are slow, so we make all of them together at the end of this instead of calling the API individually
955 $params = array();
956 $params['photosetId'] = $element->Id;
957 $params['level'] = 'Level2';
958 $params['includePhotos'] = false;
959 $method = 'LoadPhotoSet';
960
961 $request = $this->prepare_request($method, $params);
962 $requests[] = array(
963 'url' => $this->secure_url,
964 'type' => 'POST',
965 'headers' => $request['headers'],
966 'data' => $request['body'],
967 );
968 }
969 $photosets[$element->Id] = $element;
970 $image_count += $element->ImageCount;
971 }
972 else if ($element->$type == 'Group') {
973 $groups[] = $element;
974 }
975 }
976
977 if (!empty($requests)) {
978 $responses = Requests::request_multiple($requests);
979 foreach ($responses as $ps_response) {
980 if (is_a($ps_response, 'Requests_Response')) {
981 $found = false;
982 $ps_response = json_decode($ps_response->body);
983 if (!empty($ps_response->result)) {
984 $ps_response = $ps_response->result;
985 if (empty($ps_response->Categories) && !empty($short_code['user_specific_category'])) {
986 $found = false;
987 }
988 else if (!empty($short_code['user_specific_category'])) {
989 $categories = $ps_response->Categories;
990 foreach ($categories as $category) {
991 if ($category == $short_code['category_code']) {
992 $found = true;
993 }
994 }
995 }
996
997 if (!$found) {
998 if (!empty($short_code['user_specific_text'])) {
999 // Check Title, Caption, Keywords
1000 $text = $short_code['text'];
1001 $text = explode(',', $text);
1002 $text = array_map('trim', $text);
1003 $to_match = array();
1004 foreach ($text as $item) {
1005 $to_match[] = '\b'.$item.'\b';
1006 }
1007 $to_match = '/('.implode('|', $to_match).')/i';
1008 $keywords = implode(',', $ps_response->Keywords);
1009 $found = preg_match($to_match, $ps_response->Title) || preg_match($to_match, $ps_response->Caption) || preg_match($to_match, $keywords);
1010 }
1011 }
1012
1013 if (!$found) {
1014 unset($photosets[$ps_response->Id]);
1015 }
1016 }
1017 }
1018 }
1019 }
1020
1021 if (!empty($recent_popular)) {
1022 foreach ($photosets as $id => $set) {
1023 if (!in_array($id, $recent_popular)) {
1024 unset($photosets[$id]);
1025 }
1026 }
1027 }
1028
1029 $all_photosets = array_merge($all_photosets, array_values($photosets));
1030
1031 global $photonic_zenfolio_hide_empty_groups;
1032 global $photonic_zenfolio_link_group_page, $photonic_zenfolio_hide_group_title, $photonic_zenfolio_hide_group_photo_count, $photonic_zenfolio_hide_group_group_count, $photonic_zenfolio_hide_group_set_count;
1033
1034 $hidden = array(
1035 'thumbnail' => true,
1036 'title' => !empty($photonic_zenfolio_hide_group_title),
1037 'counter' => !(empty($photonic_zenfolio_hide_group_photo_count) || empty($photonic_zenfolio_hide_group_group_count) || empty($photonic_zenfolio_hide_group_set_count)),
1038 );
1039
1040 if (!empty($group->Title) && ($image_count > 0 || empty($photonic_zenfolio_hide_empty_groups))) {
1041 $header = $this->get_header_object($group, $short_code['thumb_size']);
1042
1043 $counters = array(
1044 'sets' => empty($photonic_zenfolio_hide_group_set_count) ? count($photosets) : 0,
1045 'groups' => empty($photonic_zenfolio_hide_group_group_count) ? count($groups) : 0,
1046 'photos' => empty($photonic_zenfolio_hide_group_photo_count)? $image_count : 0,
1047 );
1048
1049 if ($short_code['structure'] !== 'flat') {
1050 $ret .= $this->process_object_header($header,
1051 array(
1052 'type' => 'set',
1053 'hidden' => $this->get_hidden_headers($options['header_display'], $hidden),
1054 'counters' => $counters,
1055 'link' => empty($photonic_zenfolio_link_group_page),
1056 'display' => $short_code['display'],
1057 )
1058 );
1059 }
1060 }
1061
1062 if ($short_code['structure'] !== 'flat') {
1063 $ret .= $this->process_sets($photosets, $short_code);
1064 }
1065
1066 foreach ($groups as $group) {
1067 $out = $this->process_group($group, $options, $short_code, $level + 1, $all_photosets, $recent_popular);
1068 if ($short_code['structure'] !== 'flat') {
1069 $ret .= $out;
1070 }
1071 }
1072
1073 if ($short_code['structure'] === 'flat' && $level === 0) {
1074 if (!empty($header)) {
1075 $counters = array(
1076 'sets' => empty($photonic_zenfolio_hide_group_set_count) ? count($all_photosets) : 0,
1077 );
1078
1079 $ret .= $this->process_object_header($header,
1080 array(
1081 'type' => 'set',
1082 'hidden' => $this->get_hidden_headers($options['header_display'], $hidden),
1083 'counters' => $counters,
1084 'link' => empty($photonic_zenfolio_link_group_page),
1085 'display' => $short_code['display'],
1086 )
1087 );
1088 }
1089 $ret .= $this->process_sets($all_photosets, $short_code);
1090 }
1091 return $ret;
1092 }
1093
1094 function authenticate($password) {
1095 global $photonic_zenfolio_default_user;
1096 $photonic_authentication = get_option('photonic_authentication');
1097 if (!isset($photonic_authentication['zenfolio'])) {
1098 $photonic_authentication['zenfolio'] = array();
1099 }
1100 $ret = array();
1101 if (!empty($photonic_zenfolio_default_user)) {
1102 $challenge_response = $this->make_call('GetChallenge', array('loginName' => $photonic_zenfolio_default_user));
1103
1104 if (!empty($challenge_response)) {
1105 $salt = $challenge_response->result->PasswordSalt;
1106 $salt = call_user_func_array('pack', array_merge(array('C*'), $salt));
1107 $pass_hash = hash('sha256', $salt.utf8_encode($password), true);
1108
1109 $challenge = $challenge_response->result->Challenge;
1110
1111 $this->perform_back_end_authentication($pass_hash, $challenge);
1112 if (empty($this->token)) {
1113 $ret['error'] = esc_html__('Authentication failed.', 'photonic');
1114 unset($photonic_authentication['zenfolio']['pass_hash']);
1115 }
1116 else {
1117 $photonic_authentication['zenfolio']['pass_hash'] = unpack('C*', $pass_hash);
1118 $ret['success'] = $this->token;
1119 }
1120 }
1121 else {
1122 $ret['error'] = esc_html__('Failed to get challenge.', 'photonic');
1123 }
1124 }
1125 else {
1126 unset($photonic_authentication['zenfolio']['pass_hash']);
1127 $ret['error'] = sprintf(esc_html__('Default user not defined. Please define one under %s', 'photonic'), '<em>Photonic &rarr; Settings &rarr; Zenfolio &rarr; Zenfolio Photo Settings &rarr; Default User</em>');
1128 }
1129 update_option('photonic_authentication', $photonic_authentication);
1130 return $ret;
1131 }
1132
1133 function perform_back_end_authentication($pass_hash = '', $challenge = false) {
1134 global $photonic_zenfolio_default_user;
1135 if (!empty($photonic_zenfolio_default_user)) {
1136 $photonic_authentication = get_option('photonic_authentication');
1137 $auth_done = !empty($photonic_authentication) && !empty($photonic_authentication['zenfolio']) && !empty($photonic_authentication['zenfolio']['pass_hash']);
1138 if ($auth_done || !empty($pass_hash)) {
1139 if (empty($pass_hash)) {
1140 $pass_hash = $photonic_authentication['zenfolio']['pass_hash'];
1141 $pass_hash = call_user_func_array('pack', array_merge(array('C*'), $pass_hash));
1142 }
1143
1144 if (empty($challenge)) {
1145 $challenge_response = $this->make_call('GetChallenge', array('loginName' => $photonic_zenfolio_default_user));
1146 $challenge = $challenge_response->result->Challenge;
1147 }
1148
1149 $challenge_pack = call_user_func_array('pack', array_merge(array('C*'), $challenge));
1150 $challenge_hash = hash('sha256', $challenge_pack.$pass_hash, true);
1151 $proof = array_values(unpack('C*', $challenge_hash));
1152
1153 $auth_response = $this->make_call('Authenticate', array('challenge' => $challenge, 'proof' => $proof));
1154 if (!empty($auth_response->result)) {
1155 $this->token = $auth_response->result;
1156 return;
1157 }
1158 }
1159 }
1160 $this->token = false;
1161 }
1162
1163 /**
1164 * @param $method
1165 * @param $params
1166 * @param $keyring
1167 * @return array
1168 */
1169 function prepare_request($method, $params, $keyring = null) {
1170 $request = array();
1171 $request['method'] = $method;
1172 $request['params'] = array_values($params);
1173 $request['id'] = 1;
1174 $bodyString = json_encode($request);
1175 $bodyLength = strlen($bodyString);
1176
1177 $headers = array();
1178 $headers['Host'] = 'api.zenfolio.com';
1179 $headers['User-Agent'] = $this->user_agent;
1180 if ($this->token && $method !== 'GetChallenge' && $method !== 'Authenticate') {
1181 $headers['X-Zenfolio-Token'] = $this->token;
1182 }
1183 if (isset($_COOKIE['photonic-zf-keyring'])) {
1184 $headers['X-Zenfolio-Token'] = $_COOKIE['photonic-zf-keyring'];
1185 }
1186 else if (!empty($keyring)) {
1187 $headers['X-Zenfolio-Keyring'] = $keyring;
1188 }
1189 $headers['Content-Type'] = 'application/json';
1190 $headers['Content-Length'] = $bodyLength;
1191 return array('headers' => $headers, 'body' => $bodyString);
1192 }
1193
1194 /**
1195 * @param $method
1196 * @param $ssl_verify_peer
1197 * @param $request
1198 * @return array|mixed|null|object|string|string[]|WP_Error
1199 */
1200 public function make_wp_request($method, $ssl_verify_peer, $request) {
1201 $curl_args = array(
1202 'user-agent' => $this->user_agent,
1203 'sslverify' => $ssl_verify_peer,
1204 'timeout' => 30,
1205 'headers' => $request['headers'],
1206 'method' => 'POST',
1207 'body' => $request['body'],
1208 );
1209
1210 $response = wp_remote_request($this->secure_url, $curl_args);
1211 $response = wp_remote_retrieve_body($response);
1212
1213 //PHP/WP's json_decode() function really messes up the "long" ids returned by Zenfolio. The following takes care of this.
1214 // Can't pass the 4th argument as outlined here: https://php.net/manual/en/function.json-decode.php, since it only came into existence in PHP 5.4
1215 $response = preg_replace('/"Id":(\d+)/', '"Id":"$1"', $response);
1216 $response = preg_replace('/"RealmId":(\d+)/', '"Id":"$1"', $response);
1217 if ($method == 'KeyringGetUnlockedRealms') {
1218 $realm_ids = array();
1219 preg_match('/([\[^,\d]+\])/', $response, $realm_ids);
1220 if (!empty($realm_ids)) {
1221 $realm_ids = $realm_ids[0];
1222 $replace = $realm_ids;
1223 $replace = str_replace('[', '["', $replace);
1224 $replace = str_replace(']', '"]', $replace);
1225 $replace = str_replace(',', '","', $replace);
1226 $response = str_replace($realm_ids, $replace, $response);
1227 }
1228 }
1229
1230 $response = json_decode($response);
1231 return $response;
1232 }
1233 }
1234