PluginProbe ʕ •ᴥ•ʔ
Responsive Lightbox & Gallery / 2.7.5
Responsive Lightbox & Gallery v2.7.5
2.7.8 trunk 1.0.0 1.0.1 1.0.1.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4.0 1.4.0.1 1.4.1 1.4.11 1.4.12 1.4.13 1.4.14 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3.1 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7
responsive-lightbox / includes / class-remote-library.php
responsive-lightbox / includes Last commit date
galleries 3 months ago providers 3 months ago settings 3 months ago class-fast-image.php 2 years ago class-folders.php 3 months ago class-frontend.php 3 months ago class-galleries.php 3 months ago class-multilang.php 2 years ago class-remote-library-api.php 3 months ago class-remote-library.php 3 months ago class-settings-api.php 3 months ago class-settings-data.php 3 months ago class-settings-pages.php 3 months ago class-settings.php 3 months ago class-tour.php 3 months ago class-welcome.php 3 months ago class-widgets.php 2 years ago functions.php 3 years ago
class-remote-library.php
842 lines
1 <?php
2 // exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) )
4 exit;
5
6 /**
7 * Responsive Lightbox Remote Library class.
8 *
9 * @class Responsive_Lightbox_Remote_Library
10 */
11 class Responsive_Lightbox_Remote_Library {
12
13 public $providers = [];
14 private $image_formats = [
15 'bmp' => 'image/bmp',
16 'gif' => 'image/gif',
17 'jpe' => 'image/jpeg',
18 'jpeg' => 'image/jpeg',
19 'jpg' => 'image/jpeg',
20 'png' => 'image/png',
21 'tif' => 'image/tiff',
22 'tiff' => 'image/tiff',
23 'webp' => 'image/webp'
24 ];
25
26 /**
27 * Class constructor.
28 *
29 * @return void
30 */
31 public function __construct() {
32 // is remote library active?
33 if ( ! Responsive_Lightbox()->options['remote_library']['active'] )
34 return;
35
36 // actions
37 add_action( 'wp_ajax_rl_remote_library_query', [ $this, 'ajax_query_media' ] );
38 add_action( 'wp_ajax_rl_upload_image', [ $this, 'ajax_upload_image' ] );
39 add_action( 'admin_enqueue_scripts', [ $this, 'remote_library_scripts' ] );
40
41 // add filter to send new data to editor
42 add_filter( 'image_send_to_editor', [ $this, 'send_image_to_editor' ], 21, 8 );
43 }
44
45 /**
46 * Hidden field with response data for gallery preview.
47 *
48 * @param array $args Field arguments
49 * @return string
50 */
51 public function remote_library_response_data( $args ) {
52 // get main instance
53 $rl = Responsive_Lightbox();
54
55 // get active providers
56 $providers = $this->get_active_providers();
57
58 // normalize provider value
59 if ( is_array( $args['media_provider'] ) ) {
60 $args['media_provider'] = reset( $args['media_provider'] );
61 }
62 $args['media_provider'] = sanitize_key( (string) $args['media_provider'] );
63 if ( $args['media_provider'] === '' ) {
64 $args['media_provider'] = 'all';
65 }
66 if ( $args['media_provider'] !== 'all' && ! in_array( $args['media_provider'], $providers, true ) ) {
67 $args['media_provider'] = 'all';
68 }
69
70 $html = '';
71
72 // any providers?
73 if ( ! empty( $providers ) ) {
74 foreach ( $providers as $provider ) {
75 // get provider
76 $provider = $rl->providers[$provider];
77
78 // add response data arguments if needed
79 if ( ! empty( $provider['response_args'] ) ) {
80 $response = $provider['instance']->get_response_data();
81
82 foreach ( $provider['response_args'] as $arg ) {
83 if ( array_key_exists( $arg, $response ) ) {
84 $html .= '<span id="' . esc_attr( 'rl_' . $args['tab_id'] . '_' . $args['menu_item'] . '_' . $args['field'] . '_' . $provider['slug'] . '_' . $arg ) . '" class="rl-response-data" data-value="' . esc_attr( base64_encode( wp_json_encode( $response[$arg] ) ) ) . '" data-name="' . esc_attr( $arg ) . '" data-provider="' . esc_attr( $provider['slug'] ) . '"></span>';
85 }
86 }
87 }
88 }
89 }
90
91 return $html;
92 }
93
94 /**
95 * Send updated image data to editor.
96 *
97 * @param string $html The image HTML markup to send
98 * @param int $id The attachment ID
99 * @param string $caption The image caption
100 * @param string $title The image title
101 * @param string $align The image alignment
102 * @param string $url The image source URL
103 * @param string|array $size Size of image
104 * @param string $alt The image alternative text.
105 * @return string
106 */
107 function send_image_to_editor( $html, $id, $caption, $title, $align, $url, $size, $alt ) {
108 if ( $id === Responsive_Lightbox()->galleries->maybe_generate_thumbnail() && isset( $_POST['attachment'] ) && is_array( $_POST['attachment'] ) ) {
109 $attachment = wp_unslash( $_POST['attachment'] );
110
111 if ( isset( $attachment['remote_library_image'], $attachment['width'], $attachment['height'] ) ) {
112 $html = preg_replace( '/src=(\'|")(.*?)(\'|")/', 'src="' . ( ! empty( $attachment['rl_url'] ) ? esc_url( $attachment['rl_url'] ) : $url ) . '"', $html );
113 $html = preg_replace( '/width=(\'|")(.*?)(\'|")/', 'width="' . (int) $attachment['width'] . '"', $html );
114 $html = preg_replace( '/height=(\'|")(.*?)(\'|")/', 'height="' . (int) $attachment['height'] . '"', $html );
115 $html = preg_replace( '/(\s)?id="attachment_' . (int) $id . '"/', '', $html );
116 $html = preg_replace( '/(\s)?wp-image-' . (int) $id . '/', '', $html );
117 }
118 }
119
120 return $html;
121 }
122
123 /**
124 * Get all available providers.
125 *
126 * @return array
127 */
128 public function get_providers() {
129 return (array) apply_filters( 'rl_get_providers', Responsive_Lightbox()->providers );
130 }
131
132 /**
133 * Get all active providers.
134 *
135 * @return array
136 */
137 public function get_active_providers() {
138 $providers = $this->get_providers();
139 $active_providers = [];
140
141 foreach ( $providers as $provider => $data ) {
142 if ( $this->is_provider_enabled( $provider ) )
143 $active_providers[] = $provider;
144 }
145
146 return (array) apply_filters( 'rl_get_active_providers', $active_providers );
147 }
148
149 /**
150 * Check whether provider is active.
151 *
152 * @param string $provider Media provider
153 * @return bool
154 */
155 public function is_active_provider( $provider ) {
156 $is_active = $this->is_provider_enabled( $provider );
157
158 return (bool) apply_filters( 'rl_is_active_provider', $is_active, $provider );
159 }
160
161 /**
162 * Check whether a provider is enabled in settings.
163 *
164 * Supports both legacy key: [provider][active]
165 * and migrated key pattern: [provider][provider_active].
166 *
167 * @param string $provider Provider slug.
168 * @return bool
169 */
170 private function is_provider_enabled( $provider ) {
171 $rl = Responsive_Lightbox();
172 $remote_settings = isset( $rl->options['remote_library'] ) && is_array( $rl->options['remote_library'] )
173 ? $rl->options['remote_library']
174 : [];
175 $alt_key = $provider . '_active';
176
177 if ( array_key_exists( $provider, $remote_settings ) ) {
178 $provider_settings = $remote_settings[$provider];
179
180 // Migrated key ({provider}_active) takes priority over legacy key (active)
181 // to prevent false negatives when both exist with conflicting values.
182 if ( is_array( $provider_settings ) ) {
183 if ( isset( $provider_settings[$alt_key] ) ) {
184 return $this->normalize_bool_value( $provider_settings[$alt_key] );
185 }
186
187 if ( isset( $provider_settings['active'] ) ) {
188 return $this->normalize_bool_value( $provider_settings['active'] );
189 }
190 } else {
191 // Fallback for scalar provider values.
192 return $this->normalize_bool_value( $provider_settings );
193 }
194 }
195
196 // Fallback shape: remote_library[provider_active]
197 if ( isset( $remote_settings[$alt_key] ) ) {
198 return $this->normalize_bool_value( $remote_settings[$alt_key] );
199 }
200
201 // Fallback to plugin defaults when option payload does not carry provider keys.
202 if ( isset( $rl->defaults['remote_library'][$provider] ) && is_array( $rl->defaults['remote_library'][$provider] ) ) {
203 $default_provider = $rl->defaults['remote_library'][$provider];
204 if ( isset( $default_provider['active'] ) ) {
205 return $this->normalize_bool_value( $default_provider['active'] );
206 }
207 if ( isset( $default_provider[$alt_key] ) ) {
208 return $this->normalize_bool_value( $default_provider[$alt_key] );
209 }
210 }
211
212 // Fallback to provider registration defaults.
213 if ( isset( $rl->providers[$provider]['defaults'] ) && is_array( $rl->providers[$provider]['defaults'] ) ) {
214 $provider_defaults = $rl->providers[$provider]['defaults'];
215 if ( isset( $provider_defaults['active'] ) ) {
216 return $this->normalize_bool_value( $provider_defaults['active'] );
217 }
218 if ( isset( $provider_defaults[$alt_key] ) ) {
219 return $this->normalize_bool_value( $provider_defaults[$alt_key] );
220 }
221 }
222
223 return false;
224 }
225
226 /**
227 * Normalize mixed bool-like values from options.
228 *
229 * @param mixed $value Value to normalize.
230 * @return bool
231 */
232 private function normalize_bool_value( $value ) {
233 if ( is_bool( $value ) ) {
234 return $value;
235 }
236
237 if ( is_string( $value ) ) {
238 $value = strtolower( trim( $value ) );
239 if ( $value === '' || $value === 'false' || $value === '0' ) {
240 return false;
241 }
242 if ( $value === 'true' || $value === '1' ) {
243 return true;
244 }
245 }
246
247 return ! empty( $value );
248 }
249
250 /**
251 * Scripts and styles for media frame.
252 *
253 * @global string $wp_version
254 * @global string $pagenow
255 *
256 * @return void
257 */
258 public function remote_library_scripts() {
259 global $wp_version;
260 global $pagenow;
261
262 // display only for post edit pages
263 if ( ! ( ( $pagenow === 'post.php' || $pagenow === 'post-new.php' ) || ( version_compare( $wp_version, '5.8', '>=' ) && ( $pagenow === 'widgets.php' || $pagenow === 'customize.php' ) ) ) )
264 return;
265
266 // get main instance
267 $rl = Responsive_Lightbox();
268
269 wp_enqueue_script( 'responsive-lightbox-remote-library-media', RESPONSIVE_LIGHTBOX_URL . '/js/admin-media.js', [ 'jquery', 'media-models', 'underscore' ], $rl->defaults['version'] );
270
271 // prepare script data
272 $script_data = [
273 'thumbnailID' => $rl->galleries->maybe_generate_thumbnail(),
274 'postID' => get_the_ID(),
275 'providers' => $this->get_providers(),
276 'providersActive' => $this->get_active_providers(),
277 'allProviders' => esc_html__( 'All providers', 'responsive-lightbox' ),
278 'uploadAndInsert' => esc_html__( 'Upload and Insert', 'responsive-lightbox' ),
279 'uploadAndSelect' => esc_html__( 'Upload and Select', 'responsive-lightbox' ),
280 'filterByremoteLibrary' => esc_html__( 'Filter by remote library', 'responsive-lightbox' ),
281 'getUploadNonce' => wp_create_nonce( 'rl-remote-library-upload-image' ),
282 'queryNonce' => wp_create_nonce( 'rl-remote-library-query' )
283 ];
284
285 wp_add_inline_script( 'responsive-lightbox-remote-library-media', 'var rlRemoteLibraryMedia = ' . wp_json_encode( $script_data ) . ";\n", 'before' );
286
287 // enqueue gallery
288 $rl->galleries->enqueue_gallery_scripts_styles();
289 }
290
291 /**
292 * AJAX media query action.
293 *
294 * @return void
295 */
296 public function ajax_query_media() {
297 $data = stripslashes_deep( $_POST );
298
299 // check rate limiting (30 queries per minute to prevent API abuse)
300 if ( ! Responsive_Lightbox()->check_rate_limit( 'rl_ajax_query_media', 30, 60 ) ) {
301 wp_send_json_error( esc_html__( 'Rate limit exceeded. Please try again later.', 'responsive-lightbox' ) );
302 }
303
304 // check user capabilities
305 if ( ! current_user_can( 'upload_files' ) )
306 wp_send_json_error( esc_html__( 'Insufficient permissions.', 'responsive-lightbox' ) );
307
308 // verify nonce
309 if ( ! isset( $data['nonce'] ) || ! wp_verify_nonce( $data['nonce'], 'rl-remote-library-query' ) )
310 wp_send_json_error( esc_html__( 'Invalid nonce.', 'responsive-lightbox' ) );
311
312 $results = [
313 'last' => false,
314 'images' => [],
315 'data' => []
316 ];
317
318 if ( isset( $data['media_provider'], $data['media_search'], $data['media_page'] ) ) {
319 $data['media_provider'] = sanitize_key( $data['media_provider'] );
320
321 if ( $data['media_provider'] === 'all' || $this->is_active_provider( $data['media_provider'] ) ) {
322 $data['preview_page'] = (int) $data['media_page'];
323 $data['preview_per_page'] = 20;
324
325 // get images
326 $results['images'] = $this->get_remote_library_images( $data );
327
328 // get main instance
329 $rl = Responsive_Lightbox();
330
331 // single provider?
332 if ( $data['media_provider'] !== 'all' ) {
333 // get provider
334 $provider = $rl->providers[$data['media_provider']];
335
336 // add response data arguments if needed
337 if ( ! empty( $provider['response_args'] ) ) {
338 $response = $provider['instance']->get_response_data();
339
340 foreach ( $provider['response_args'] as $arg ) {
341 if ( array_key_exists( $arg, $response ) )
342 $results['data'][$provider['slug']][$arg] = base64_encode( wp_json_encode( $response[$arg] ) );
343 }
344 }
345 } else {
346 // get active providers
347 $providers = $this->get_active_providers();
348
349 if ( ! empty( $providers ) ) {
350 foreach ( $providers as $provider ) {
351 // get provider
352 $provider = $rl->providers[$provider];
353
354 // add response data arguments if needed
355 if ( ! empty( $provider['response_args'] ) ) {
356 $response = $provider['instance']->get_response_data();
357
358 foreach ( $provider['response_args'] as $arg ) {
359 if ( array_key_exists( $arg, $response ) )
360 $results['data'][$provider['slug']][$arg] = base64_encode( wp_json_encode( $response[$arg] ) );
361 }
362 }
363 }
364 }
365 }
366
367 if ( ! empty( $results['images'] ) ) {
368 // create WP compatible attachments
369 $results['images'] = $this->create_wp_remote_attachments( $results['images'], $data );
370
371 // handle last page if needed
372 $results['last'] = apply_filters( 'rl_remote_library_query_last_page', false, $results, $data );
373 } else
374 $results['last'] = true;
375 }
376 }
377
378 // send data
379 wp_send_json( $results );
380 }
381
382 /**
383 * AJAX upload image action.
384 *
385 * @return void
386 */
387 public function ajax_upload_image() {
388 // clear post data
389 $data = stripslashes_deep( $_POST );
390
391 // default result
392 $result = [
393 'id' => 0,
394 'full' => [ '', 0, 0, false ],
395 'error' => false,
396 'message' => ''
397 ];
398
399 // verified upload?
400 if ( current_user_can( 'upload_files' ) && isset( $data['rlnonce'], $data['image'], $data['post_id'] ) && wp_verify_nonce( $data['rlnonce'], 'rl-remote-library-upload-image' ) ) {
401 // check rate limiting (10 uploads per minute)
402 if ( ! Responsive_Lightbox()->check_rate_limit( 'rl_upload_image', 10, 60 ) ) {
403 $result['error'] = true;
404 $result['message'] = __( 'Rate limit exceeded. Please try again later.', 'responsive-lightbox' );
405 wp_send_json( $result );
406 }
407
408 // include required files if needed
409 if ( ! function_exists( 'media_handle_upload' ) )
410 require_once( path_join( ABSPATH, 'wp-admin/includes/media.php' ) );
411
412 if ( ! function_exists( 'wp_handle_upload' ) )
413 require_once( path_join( ABSPATH, 'wp-admin/includes/file.php' ) );
414
415 // get media provider
416 $media_provider = ! empty( $data['image']['media_provider'] ) ? sanitize_key( $data['image']['media_provider'] ) : '';
417
418 // get active providers
419 $providers = $this->get_active_providers();
420
421 if ( in_array( $media_provider, $providers, true ) ) {
422 // get image formats
423 $image_formats = $this->get_allowed_image_formats( $media_provider );
424
425 if ( ! empty( $data['image']['url'] ) && ! empty( $data['image']['mime'] ) && ! empty( $data['image']['subtype'] ) && array_key_exists( $data['image']['subtype'], $image_formats ) ) {
426 // get image url
427 $image_url = esc_url_raw( $data['image']['url'] );
428
429 // get allowed hosts
430 $hosts = $this->get_allowed_hosts( $media_provider );
431
432 $valid_host = false;
433
434 if ( ! empty( $hosts ) ) {
435 // get image host
436 $image_host = parse_url( $image_url, PHP_URL_HOST );
437
438 // validate that we got a valid hostname
439 if ( ! is_string( $image_host ) || $image_host === '' ) {
440 $result['error'] = true;
441 $result['message'] = __( 'Invalid image URL.', 'responsive-lightbox' );
442 } else {
443 // normalize hostname to lowercase for case-insensitive comparison
444 $image_host = strtolower( $image_host );
445
446 // check allowed hosts - strict validation to prevent SSRF bypasses
447 foreach ( $hosts as $host ) {
448 $host = strtolower( $host );
449
450 // Validate exact match or valid subdomain (e.g., upload.wikimedia.org matches wikimedia.org)
451 // Prevent substring bypass: evil-wikimedia.org or upload.wikimedia.org.evil.com must NOT match
452 if ( $image_host === $host || substr( $image_host, -( strlen( $host ) + 1 ) ) === '.' . $host ) {
453 $valid_host = true;
454
455 // no need to check rest of the hosts
456 break;
457 }
458 }
459 }
460 } else {
461 $valid_host = true;
462 }
463
464 if ( $valid_host && empty( $result['error'] ) ) {
465 // get max image size (ensure at least 1MB)
466 $max_size = max( 1, absint( Responsive_Lightbox()->options['remote_library']['max_image_size'] ) ) * 1024 * 1024;
467
468 // check image size via HEAD request - use wp_safe_remote_head for SSRF protection
469 $head_response = wp_safe_remote_head( $image_url );
470 $skip_size_check = false;
471
472 if ( is_wp_error( $head_response ) ) {
473 $skip_size_check = true;
474 } else {
475 $content_length = wp_remote_retrieve_header( $head_response, 'content-length' );
476
477 if ( $content_length && (int) $content_length > $max_size ) {
478 $result['error'] = true;
479 $result['message'] = __( 'Image size exceeds maximum allowed size.', 'responsive-lightbox' );
480 }
481 }
482
483 if ( empty( $result['error'] ) ) {
484 // get image as binary data with timeout and size limit to prevent memory exhaustion
485 $response = wp_safe_remote_get( $image_url, [
486 'timeout' => 30,
487 'limit_response_size' => $max_size + 1024, // Add 1KB buffer for headers
488 ] );
489
490 // no errors?
491 if ( ! is_wp_error( $response ) ) {
492 // get image binary data
493 $image_bits = wp_remote_retrieve_body( $response );
494
495 // check body size as validation
496 // Note: limit_response_size prevents memory exhaustion, but we still validate the actual size
497 $body_size = strlen( $image_bits );
498 if ( $body_size > $max_size ) {
499 $result['error'] = true;
500 $result['message'] = __( 'Image size exceeds maximum allowed size.', 'responsive-lightbox' );
501 }
502
503 if ( empty( $result['error'] ) ) {
504 // get sanitized file name
505 $file_name = sanitize_file_name( pathinfo( $data['image']['name'], PATHINFO_BASENAME ) );
506
507 // get file extension
508 $file_ext = pathinfo( $file_name, PATHINFO_EXTENSION );
509
510 // no extension?
511 if ( $file_ext === '' || ! array_key_exists( $file_ext, $image_formats ) ) {
512 $file_name .= '.jpg';
513 $file_ext = 'jpg';
514 }
515
516 // strict file validation using wp_check_filetype with allowed formats whitelist
517 $check = wp_check_filetype( $file_name, $image_formats );
518
519 // validate extension is allowed and mime type matches
520 if ( $check['ext'] && $check['type'] && array_key_exists( $check['ext'], $image_formats ) && $check['type'] === $data['image']['mime'] ) {
521 // upload image
522 $uploaded_image = wp_upload_bits( $file_name, null, $image_bits, current_time( 'Y/m' ) );
523
524 if ( isset( $uploaded_image['error'] ) && $uploaded_image['error'] ) {
525 $result['error'] = true;
526 $result['message'] = $uploaded_image['error'];
527 } else {
528 // get file name
529 $file_name = pathinfo( $uploaded_image['file'], PATHINFO_BASENAME );
530
531 // simulate upload
532 $_FILES['rl-remote-image'] = [
533 'error' => 0,
534 'name' => $file_name,
535 'tmp_name' => $uploaded_image['file'],
536 'size' => filesize( $uploaded_image['file'] )
537 ];
538
539 // get post id
540 $post_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0;
541
542 // more reliable mime type checking
543 $check = wp_check_filetype_and_ext( $uploaded_image['file'], $file_name );
544
545 // correct mime type and extension?
546 if ( strpos( $data['image']['mime'], 'image/' ) === 0 && $check['type'] === $data['image']['mime'] && $check['ext'] !== false && wp_get_image_mime( $uploaded_image['file'] ) === $check['type'] ) {
547 // upload image, wp handle sanitization and validation here
548 $attachment_id = media_handle_upload(
549 'rl-remote-image',
550 $post_id,
551 [
552 'post_title' => empty( $data['image']['title'] ) ? $file_name : $data['image']['title'],
553 'post_content' => empty( $data['image']['description'] ) ? '' : $data['image']['description'],
554 'post_excerpt' => empty( $data['image']['caption'] ) ? '' : $data['image']['caption']
555 ],
556 [
557 'action' => 'rl_remote_library_handle_upload',
558 'test_form' => false
559 ]
560 );
561
562 // upload success?
563 if ( ! is_wp_error( $attachment_id ) ) {
564 add_post_meta( $attachment_id, '_wp_attachment_image_alt', empty( $data['image']['alt'] ) ? '' : $data['image']['alt'] );
565
566 $result['id'] = $attachment_id;
567 $result['full'] = wp_get_attachment_image_src( $attachment_id, 'full' );
568 } else {
569 $result['error'] = true;
570 $result['message'] = $attachment_id->get_error_message();
571 }
572 // file still exists?
573 } elseif ( file_exists( $uploaded_image['file'] ) ) {
574 $result['error'] = true;
575 $result['message'] = __( 'Invalid MIME type', 'responsive-lightbox' );
576
577 // delete file
578 wp_delete_file( $uploaded_image['file'] );
579 }
580 }
581 } else {
582 $result['error'] = true;
583 $result['message'] = __( 'Invalid image type', 'responsive-lightbox' );
584 }
585 } else {
586 $result['error'] = true;
587 $result['message'] = $response->get_error_message();
588 }
589 }
590 }
591 } elseif ( empty( $result['error'] ) ) {
592 // Only set "Invalid host" if no previous error was set (e.g., "Invalid image URL")
593 $result['error'] = true;
594 $result['message'] = __( 'Invalid host', 'responsive-lightbox' );
595 }
596 } else {
597 $result['error'] = true;
598 $result['message'] = __( 'Missing or invalid image data', 'responsive-lightbox' );
599 }
600 } else {
601 $result['error'] = true;
602 $result['message'] = __( 'Invalid media provider', 'responsive-lightbox' );
603 }
604 } else {
605 $result['error'] = true;
606 $result['message'] = __( 'Access denied', 'responsive-lightbox' );
607 }
608
609 // send data
610 wp_send_json( $result );
611 }
612
613 /**
614 * Create WP compatible attachments for JavaScript.
615 *
616 * @param array $results Requested images
617 * @param array $args Additional arguments
618 * @return array
619 */
620 public function create_wp_remote_attachments( $results, $args ) {
621 // get current user
622 $user = wp_get_current_user();
623
624 // copy results
625 $copy = $results;
626
627 // get current time
628 $time = current_time( 'timestamp' );
629
630 // get date format
631 $date_format = get_option( 'date_format' );
632
633 // format date
634 $date = date_i18n( __( 'F j Y' ), $time );
635
636 // $result is already sanitized by specific provider sanitize_result function
637 foreach ( $results as $no => $result ) {
638 // make sure those attributes are strings
639 $copy[$no]['caption'] = (string) $result['caption'];
640 $copy[$no]['description'] = (string) $result['description'];
641 $copy[$no]['title'] = (string) $result['title'];
642 $copy[$no]['filename'] = $copy[$no]['name'] = (string) $result['filename'];
643
644 // rest of attributes
645 $copy[$no]['id'] = 'rl-attachment-' . ( ( $args['preview_page'] - 1 ) * $args['preview_per_page'] + $no ) . '-' . $args['media_provider'];
646 $copy[$no]['remote_library_image'] = true;
647 $copy[$no]['author'] = $user->ID;
648 $copy[$no]['authorName'] = esc_html( $user->user_login );
649 $copy[$no]['can'] = [
650 'save' => true,
651 'remove' => false
652 ];
653 $copy[$no]['compat'] = '';
654 $copy[$no]['date'] = $time;
655 $copy[$no]['dateFormatted'] = $date;
656 $copy[$no]['delete'] = '';
657 $copy[$no]['edit'] = '';
658 $copy[$no]['update'] = '';
659 $copy[$no]['filesizeHumanReadable'] = '';
660 $copy[$no]['filesizeInBytes'] = 0;
661 $copy[$no]['icon'] = '';
662 $copy[$no]['link'] = $result['url'];
663 $copy[$no]['menuOrder'] = 0;
664 $copy[$no]['meta'] = false;
665
666 // check extension
667 $file_ext = pathinfo( $result['url'], PATHINFO_EXTENSION );
668
669 // get image formats
670 $image_formats = $this->get_allowed_image_formats( $args['media_provider'] );
671
672 if ( array_key_exists( $file_ext, $image_formats ) ) {
673 $copy[$no]['mime'] = $image_formats[$file_ext];
674 $copy[$no]['subtype'] = $file_ext;
675 } else {
676 $copy[$no]['mime'] = 'image/jpeg';
677 $copy[$no]['subtype'] = 'jpg';
678 }
679
680 $copy[$no]['modified'] = $time;
681 $copy[$no]['nonces'] = [
682 'delete' => '',
683 'edit' => '',
684 'update' => ''
685 ];
686 $copy[$no]['orientation'] = $result['orientation'];
687 $copy[$no]['status'] = 'inherit';
688 $copy[$no]['type'] = 'image';
689 $copy[$no]['uploadedTo'] = 0;
690 $copy[$no]['uploadedToLink'] = '';
691 $copy[$no]['uploadedToTitle'] = '';
692 $copy[$no]['sizes'] = [
693 'medium' => [
694 'height' => $result['thumbnail_height'],
695 'width' => $result['thumbnail_width'],
696 'orientation' => $result['thumbnail_orientation'],
697 'url' => $result['thumbnail_url']
698 ],
699 'full' => [
700 'height' => $result['height'],
701 'width' => $result['width'],
702 'orientation' => $result['orientation'],
703 'url' => $result['url']
704 ]
705 ];
706 }
707
708 return (array) apply_filters( 'rl_remote_library_wp_attachments', $copy, $args );
709 }
710
711 /**
712 * Remote library media query.
713 *
714 * @param array $args
715 * @return array
716 */
717 public function get_remote_library_images( $args ) {
718 $args = stripslashes_deep( $args );
719
720 // search phrase
721 if ( isset( $args['media_search'] ) )
722 $args['media_search'] = strtolower( trim( $args['media_search'] ) );
723 else
724 $args['media_search'] = '';
725
726 // media provider
727 if ( isset( $args['media_provider'] ) )
728 $args['media_provider'] = trim( $args['media_provider'] );
729 else
730 $args['media_provider'] = 'all';
731
732 // page number
733 if ( isset( $args['preview_page'] ) )
734 $args['preview_page'] = (int) $args['preview_page'];
735 else
736 $args['preview_page'] = 1;
737
738 // number of images per page
739 if ( isset( $args['preview_per_page'] ) )
740 $args['preview_per_page'] = (int) $args['preview_per_page'];
741 else
742 $args['preview_per_page'] = 20;
743
744 // get active providers
745 $providers = $this->get_active_providers();
746
747 // prepare valid providers
748 $valid_providers = [];
749
750 if ( $args['media_provider'] === 'all' )
751 $valid_providers = $providers;
752 elseif ( in_array( $args['media_provider'], $providers, true ) )
753 $valid_providers[] = $args['media_provider'];
754
755 $results = [];
756
757 // any valid providers?
758 if ( ! empty( $valid_providers ) ) {
759 // get main instance
760 $rl = Responsive_Lightbox();
761
762 foreach ( $valid_providers as $provider_name ) {
763 if ( ! empty( $args['response_data'][$provider_name] ) ) {
764 // get provider
765 $provider = $rl->providers[$provider_name];
766
767 if ( ! empty( $provider['response_args'] ) ) {
768 foreach ( $provider['response_args'] as $arg ) {
769 if ( array_key_exists( $arg, $args['response_data'][$provider_name] ) ) {
770 $base64 = base64_decode( $args['response_data'][$provider_name][$arg] );
771
772 if ( ! empty( $base64 ) )
773 $args['response_data'][$provider_name][$arg] = json_decode( $base64, true );
774 }
775 }
776 }
777 }
778
779 // get results
780 $results = apply_filters( 'rl_remote_library_query', $results, $args['media_search'], $provider_name, $args );
781
782 // number of results
783 $nor = count( $results );
784
785 // more than requested images?
786 if ( $nor > $args['preview_per_page'] ) {
787 // get part of images
788 $results = array_slice( $results, 0, $args['preview_per_page'], true );
789
790 break;
791 // same amount of images?
792 } elseif ( $nor === $args['preview_per_page'] )
793 break;
794 }
795 }
796
797 return $results;
798 }
799
800 /**
801 * Get allowed hosts.
802 *
803 * @param string $provider
804 * @return array
805 */
806 public function get_allowed_hosts( $provider ) {
807 // get active providers
808 $providers = $this->get_active_providers();
809
810 if ( in_array( $provider, $providers, true ) ) {
811 // get available provider host
812 $hosts = Responsive_Lightbox()->providers[$provider]['instance']->get_allowed_hosts();
813 } else
814 $hosts = [];
815
816 return $hosts;
817 }
818
819 /**
820 * Get allowed image formats.
821 *
822 * @param string $provider
823 * @return array
824 */
825 public function get_allowed_image_formats( $provider = 'all' ) {
826 if ( $provider === 'all' ) {
827 $image_formats = $this->image_formats;
828 } else {
829 // get active providers
830 $providers = $this->get_active_providers();
831
832 if ( in_array( $provider, $providers, true ) ) {
833 // get available provider image formats
834 $image_formats = Responsive_Lightbox()->providers[$provider]['instance']->get_allowed_formats();
835 } else
836 $image_formats = [];
837 }
838
839 return $image_formats;
840 }
841 }
842