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