PluginProbe
WP-Stateless – Google Cloud Storage / trunk
WP-Stateless – Google Cloud Storage vtrunk
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
wp-stateless / lib / classes / class-db.php

class-db.php in WP-Stateless – Google Cloud Storage trunk, at lib/classes/class-db.php

1,059 lines 29.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * DB
5 *
6 * @since 4.0.0
7 */
8
9 namespace wpCloud\StatelessMedia {
10
11
12 if (!class_exists('wpCloud\StatelessMedia\DB')) {
13
14 class DB {
15 use Singleton;
16
17 const DB_VERSION_KEY = 'sm_db_version';
18 const DB_VERSION = '1.2';
19 const FULL_SIZE = '__full';
20
21 /**
22 * @var \WPDB
23 */
24 private $wpdb;
25
26 /**
27 * Bucket link
28 */
29 private $bucket_link = '';
30
31 /**
32 * Files table name
33 */
34 private $files = '';
35
36 /**
37 * File sizes table name
38 */
39 private $file_sizes = '';
40
41 /**
42 * File meta table name
43 */
44 private $file_meta = '';
45
46 /**
47 * Cache group name
48 */
49 private $cache_group = 'stateless_media';
50
51 /**
52 * Files table fields mapping, used for backward compatibility with old postmeta
53 */
54 private $file_mapping = [
55 'id' => 'id',
56 'post_id' => 'post_id',
57 'bucket' => 'bucket',
58 'name' => 'name',
59 'generation' => 'generation',
60 'cacheControl' => 'cache_control',
61 'contentType' => 'content_type',
62 'contentDisposition' => 'content_disposition',
63 'filesize' => 'file_size',
64 'width' => 'width',
65 'height' => 'height',
66 'stateless_version' => 'stateless_version',
67 'storageClass' => 'storage_class',
68 'fileLink' => 'file_link',
69 'selfLink' => 'self_link',
70 ];
71
72 /**
73 * Files sizes table fields mapping, used for backward compatibility with old postmeta
74 */
75 private $file_sizes_mapping = [
76 'id' => 'id',
77 'post_id' => 'post_id',
78 'size_name' => 'size_name',
79 'name' => 'name',
80 'generation' => 'generation',
81 'filesize' => 'file_size',
82 'width' => 'width',
83 'height' => 'height',
84 'fileLink' => 'file_link',
85 'selfLink' => 'self_link',
86 ];
87
88 protected function __construct() {
89 global $wpdb;
90 $this->wpdb = $wpdb;
91
92 $this->files = $this->wpdb->prefix . 'stateless_files';
93 $this->file_sizes = $this->wpdb->prefix . 'stateless_file_sizes';
94 $this->file_meta = $this->wpdb->prefix . 'stateless_file_meta';
95
96 $image_host = ud_get_stateless_media()->get_gs_host();
97 $this->bucket_link = apply_filters('wp_stateless_bucket_link', $image_host);
98
99 if ( is_multisite() ) {
100 $this->cache_group = implode('_', [
101 $this->cache_group,
102 get_current_blog_id(),
103 ]);
104 }
105
106 $this->_init();
107 }
108
109 /**
110 * Init hooks
111 */
112 private function _init() {
113 add_filter('wp_stateless_generate_cloud_meta', [$this, 'process_cloud_meta'], 10, 5);
114 add_action('deleted_post', [$this, 'delete_post'], 10, 2);
115
116 add_filter('wp_stateless_get_file', [$this, 'get_file'], 10, 3);
117 add_filter('wp_stateless_get_file_sizes', [$this, 'get_file_sizes'], 10, 2);
118 add_filter('wp_stateless_get_file_meta', [$this, 'get_file_meta'], 10, 2);
119 add_filter('wp_stateless_get_file_meta_value', [$this, 'get_file_meta_value'], 10, 4);
120 add_action('wp_stateless_set_file', [$this, 'set_file'], 10, 2);
121 add_action('wp_stateless_set_file_size', [$this, 'set_file_size'], 10, 3);
122 add_action('wp_stateless_set_file_meta', [$this, 'update_file_meta'], 10, 3);
123 add_action('wp_stateless_get_non_library_files', [$this, 'get_non_library_files'], 10, 2);
124 }
125
126 /**
127 * Getters
128 */
129 public function __get($property) {
130 if ( in_array($property, ['files', 'file_sizes', 'file_meta']) ) {
131 return $this->$property;
132 }
133 }
134
135 /**
136 * Creates or updates DB structure
137 */
138 public function create_db() {
139 $version = get_option(self::DB_VERSION_KEY, '');
140
141 if ($version === self::DB_VERSION) {
142 return;
143 }
144
145 try {
146 Upgrader::upgrade_db(self::DB_VERSION, $version);
147
148 $charset_collate = $this->wpdb->get_charset_collate();
149
150 /**
151 * Indexes for varchar(255) columns are limited for backward compatibility.
152 * Based on wp-admin/includes/schema.php (wp_get_db_schema function)
153 */
154
155 $sql = "CREATE TABLE $this->files (
156 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
157 `post_id` bigint(20) unsigned NULL DEFAULT NULL,
158 `bucket` varchar(255) NOT NULL,
159 `name` varchar(255) NOT NULL,
160 `generation` bigint(16) NOT NULL,
161 `cache_control` varchar(255) NULL DEFAULT NULL,
162 `content_type` varchar(255) NULL DEFAULT NULL,
163 `content_disposition` varchar(100) NULL DEFAULT NULL,
164 `file_size` bigint(20) unsigned NULL DEFAULT NULL,
165 `width` int unsigned NULL DEFAULT NULL,
166 `height` int unsigned NULL DEFAULT NULL,
167 `stateless_version` varchar(20) NOT NULL,
168 `storage_class` varchar(50) NULL DEFAULT NULL,
169 `file_link` text NOT NULL,
170 `self_link` text NOT NULL,
171 `source` varchar(50) NULL DEFAULT NULL,
172 `source_version` varchar(50) NULL DEFAULT NULL,
173 `status` varchar(10) NULL DEFAULT NULL,
174 PRIMARY KEY (`id`),
175 KEY post_id (post_id),
176 KEY `name` (`name`(191)),
177 UNIQUE KEY post_id_name (post_id, `name`(150))
178 ) $charset_collate;
179
180 CREATE TABLE $this->file_sizes (
181 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
182 `post_id` bigint(20) unsigned NULL DEFAULT NULL,
183 `size_name` varchar(255) NOT NULL,
184 `name` varchar(255) NOT NULL,
185 `generation` bigint(16) NOT NULL,
186 `file_size` bigint(20) unsigned NULL DEFAULT NULL,
187 `width` int unsigned NULL DEFAULT NULL,
188 `height` int unsigned NULL DEFAULT NULL,
189 `file_link` text NOT NULL,
190 `self_link` text NOT NULL,
191 PRIMARY KEY (`id`),
192 KEY post_id (post_id),
193 UNIQUE KEY post_id_size (post_id, size_name(150))
194 ) $charset_collate;
195
196 CREATE TABLE $this->file_meta (
197 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
198 `post_id` bigint(20) unsigned NULL DEFAULT NULL,
199 `meta_key` varchar(255) NOT NULL,
200 `meta_value` longtext NOT NULL,
201 PRIMARY KEY (`id`),
202 KEY post_id (post_id),
203 UNIQUE KEY post_id_key (post_id, meta_key(150))
204 ) $charset_collate;";
205
206 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
207 dbDelta($sql);
208
209 update_option(self::DB_VERSION_KEY, self::DB_VERSION);
210 } catch (\Throwable $e) {
211 Helper::log($e->getMessage());
212 }
213 }
214
215 /**
216 * Remove custom DB table on plugin uninstall
217 *
218 * @param int $site_id
219 */
220 public function clear_db($site_id) {
221 switch_to_blog($site_id);
222
223 $tables = array(
224 $this->wpdb->prefix . 'files',
225 $this->wpdb->prefix . 'files_sizes',
226 $this->wpdb->prefix . 'file_meta',
227 );
228
229 $tables = implode(', ', $tables);
230
231 $sql = "DROP TABLE IF EXISTS $tables;";
232 $this->wpdb->query($sql);
233
234 restore_current_blog();
235 }
236
237 /**
238 * Get file link
239 *
240 * @param string $name
241 * @return string
242 */
243 public function get_file_link($name) {
244 return trailingslashit($this->bucket_link) . $name;
245 }
246
247 /**
248 * Get file row ID by post ID
249 *
250 * @param int $post_id
251 * @return int | null
252 */
253 public function get_file_id($post_id) {
254 $sql = "SELECT id FROM $this->files WHERE post_id = %d AND post_id IS NOT NULL";
255 $id = $this->wpdb->get_var( $this->wpdb->prepare($sql, $post_id) );
256
257 return $id ? (int) $id : null;
258 }
259
260 /**
261 * Get ID of the non-library file by file name and status
262 *
263 * @param string $name
264 * @param string $status
265 * @return int | null
266 */
267 public function get_non_library_file_id($name, $status = '') {
268 $sql = "SELECT id FROM $this->files WHERE name = %s AND post_id IS NULL";
269 $args = [$name];
270
271 if ( !empty($status) ) {
272 $sql .= " AND status = %s";
273 $args[] = $status;
274 }
275
276 $id = $this->wpdb->get_var( $this->wpdb->prepare($sql, ...$args) );
277
278 return $id ? (int) $id : null;
279 }
280
281 /**
282 * Get name of the non-library file by part of the name
283 *
284 * @param string $name
285 * @return string | null
286 */
287 public function get_non_library_file_name($name) {
288 $sql = "SELECT name FROM $this->files WHERE name like '%%%s' AND post_id IS NULL";
289
290 return $this->wpdb->get_var( $this->wpdb->prepare($sql, $name) );
291 }
292
293 /**
294 * Get file size row ID by post ID and size name
295 *
296 * @param int $post_id
297 * @param string $size
298 * @return int | null
299 */
300 public function get_file_size_id($post_id, $size) {
301 $sql = "SELECT id FROM $this->file_sizes WHERE post_id = %d AND size_name = %s";
302 $id = $this->wpdb->get_var( $this->wpdb->prepare($sql, $post_id, $size) );
303
304 return $id ? (int) $id : null;
305 }
306
307 /**
308 * Get file meta row ID by post ID and meta key
309 *
310 * @param int $post_id
311 * @param string $key
312 * @return int | null
313 */
314 public function get_file_meta_id($post_id, $key) {
315 $key = sanitize_key($key);
316
317 $sql = "SELECT id FROM $this->file_meta WHERE post_id = %d AND meta_key = %s";
318 $id = $this->wpdb->get_var( $this->wpdb->prepare($sql, $post_id, $key) );
319
320 return $id ? (int) $id : null;
321 }
322
323 /**
324 * Add file data to DB
325 *
326 * @param array $cloud_meta - generated WP postmeta
327 * @param array $media - GCS media object
328 * @param string $image_size - image size name
329 * @param array $img - image (or image size) data for upload
330 * @param string $bucketLink - bucket link
331 * @return mixed
332 */
333 public function process_cloud_meta($cloud_meta, $media, $image_size, $img, $bucketLink) {
334 $this->update_data($media);
335
336 return $cloud_meta;
337 }
338
339 /**
340 * Determine which data to update and run updates
341 *
342 * @param array $media - GCS media object
343 */
344 public function update_data($media) {
345 $error = false;
346
347 if ( !isset($media['name']) || !isset($media['metadata']) || !isset($media['metadata']['size']) ) {
348 $error = 'Metadata missing or incorrect for GCS media object';
349 } else {
350 $size = $media['metadata']['size'];
351
352 if ( $size == self::FULL_SIZE ) {
353 $attachment_id = isset($media['metadata']['object-id']) ? $media['metadata']['object-id'] : null;
354
355 if ( !$attachment_id ) {
356 $error = 'Unable to get attachment ID for GCS media object';
357 } else {
358 $this->_update_file(
359 $attachment_id,
360 $this->_get_file_from_media($media),
361 );
362 }
363 } else {
364 $attachment_id = isset($media['metadata']['child-of']) ? $media['metadata']['child-of'] : null;
365
366 if ( !$attachment_id ) {
367 $error = 'Unable to get parent attachment ID for GCS media object';
368 } else {
369 $this->_update_file_size(
370 $attachment_id,
371 $size,
372 $this->_get_file_size_from_media($media),
373 );
374 }
375 }
376 }
377
378 if ( $error ) {
379 Helper::log($error);
380 Helper::log($media, true);
381 }
382 }
383
384 /**
385 * Update file data, based on the mapping received from the media object
386 *
387 * @param int $attachment_id
388 * @param array $data
389 * @return int | null
390 */
391 public function set_file($attachment_id, $data) {
392 $result = [];
393
394 foreach ($this->file_mapping as $key => $mapping) {
395 if ( isset($data[$key]) ) {
396 $result[$mapping] = $data[$key];
397
398 continue;
399 }
400
401 if ( isset($data[$mapping]) ) {
402 $result[$mapping] = $data[$mapping];
403
404 continue;
405 }
406 }
407
408 unset($result['id']);
409
410 return $this->_update_file($attachment_id, $result);
411 }
412
413 /**
414 * Update file size data
415 *
416 * @param int $attachment_id
417 * @param string $size_name
418 * @param array $data
419 * @return int | null
420 */
421 public function set_file_size($attachment_id, $size_name, $data) {
422 $result = [];
423
424 foreach ($this->file_sizes_mapping as $key => $mapping) {
425 if ( isset($data[$key]) ) {
426 $result[$mapping] = $data[$key];
427
428 continue;
429 }
430
431 if ( isset($data[$mapping]) ) {
432 $result[$mapping] = $data[$mapping];
433
434 continue;
435 }
436 }
437
438 unset($result['id']);
439
440 return $this->_update_file_size($attachment_id, $size_name, $result);
441 }
442
443 /**
444 * Convert GSC media object into stateless file data
445 *
446 * @param array $media
447 * @return array
448 */
449 private function _get_file_from_media($media, $status = '') {
450 $name = $media['name'];
451
452 $data =[
453 'bucket' => $media['bucket'] ?? '',
454 'name' => $name,
455 'generation' => $media['generation'] ?? '',
456 'cache_control' => $media['cacheControl'] ?? null,
457 'content_type' => $media['contentType'] ?? null,
458 'content_disposition' => $media['contentDisposition'] ?? null,
459 'file_size' => $media['size'] ?? null,
460 'width' => $media['metadata']['width'] ?? null,
461 'height' => $media['metadata']['height'] ?? null,
462 'stateless_version' => get_option('wp_sm_version', false),
463 'storage_class' => $media['storageClass'] ?? null,
464 'file_link' => $this->get_file_link($name),
465 'self_link' => $media['selfLink'] ?? '',
466 'status' => $status,
467 'source' => $media['metadata']['source'] ?? '',
468 'source_version' => $media['metadata']['sourceVersion'] ?? '',
469 ];
470
471 return $data;
472 }
473
474 /**
475 * Update non Media Library file (compatibility files)
476 *
477 * @param array $media - GCS media object
478 * @param string $source - source of the file
479 * @param string $status - status of the file
480 */
481 public function update_non_library_file($media, $status = '') {
482 if ( !is_array($media) || empty($media) || !isset($media['name']) ) {
483 Helper::log('Media object is not valid or empty. Unable to update non-library file.');
484
485 return;
486 }
487
488 $data = $this->_get_file_from_media($media, $status);
489 $file_id = $this->get_non_library_file_id($data['name'], $status);
490
491 if ( $file_id ) {
492 $this->wpdb->update(
493 $this->files,
494 $data,
495 ['id' => $file_id]
496 );
497 } else {
498 $this->wpdb->insert( $this->files, $data );
499
500 $file_id = $this->wpdb->insert_id;
501 }
502
503 return $file_id;
504 }
505
506 /**
507 * Update file data
508 *
509 * @param int $attachment_id
510 * @param array $data
511 * @return int | null
512 */
513 private function _update_file($attachment_id, $data) {
514 $file_id = $this->get_file_id($attachment_id);
515
516 if ( $file_id ) {
517 $this->wpdb->update(
518 $this->files,
519 $data,
520 ['id' => $file_id]
521 );
522 } else {
523 $data['post_id'] = $attachment_id;
524
525 $this->wpdb->insert( $this->files, $data );
526
527 $file_id = $this->wpdb->insert_id;
528 }
529
530 $this->_delete_file_cache($attachment_id);
531
532 return $file_id;
533 }
534
535 /**
536 * Convert GSC media object into stateless file size data
537 *
538 * @param array $media
539 * @return array
540 */
541 private function _get_file_size_from_media($media) {
542 $name = $media['name'];
543
544 $data =[
545 'name' => $name,
546 'generation' => $media['generation'] ?? '',
547 'file_size' => $media['size'] ?? null,
548 'width' => $media['metadata']['width'] ?? null,
549 'height' => $media['metadata']['height'] ?? null,
550 'file_link' => $this->get_file_link($name),
551 'self_link' => $media['selfLink'] ?? '',
552 ];
553
554 return $data;
555 }
556
557 /**
558 * Update file size data
559 *
560 * @param int $attachment_id
561 * @param string $size_name
562 * @param array $media
563 * @return int | null
564 */
565 private function _update_file_size($attachment_id, $size_name, $data) {
566 $file_size_id = $this->get_file_size_id($attachment_id, $size_name);
567
568 if ( $file_size_id ) {
569 $this->wpdb->update(
570 $this->file_sizes,
571 $data,
572 ['id' => $file_size_id]
573 );
574 } else {
575 $data['post_id'] = $attachment_id;
576 $data['size_name'] = $size_name;
577
578 $this->wpdb->insert( $this->file_sizes, $data );
579
580 $file_size_id = $this->wpdb->insert_id;
581 }
582
583 $this->_delete_file_sizes_cache($attachment_id);
584
585 return $file_size_id;
586 }
587
588 /**
589 * Delete file data when attachment is deleted
590 *
591 * @param int $post_id
592 * @param \WP_Post $post
593 */
594 public function delete_post($post_id, $post) {
595 $file_id = $this->get_file_id($post_id);
596
597 if ( !$file_id ) {
598 return;
599 }
600
601 $this->wpdb->delete(
602 $this->files,
603 ['post_id' => $post_id]
604 );
605
606 $this->wpdb->delete(
607 $this->file_sizes,
608 ['post_id' => $post_id]
609 );
610
611 $this->wpdb->delete(
612 $this->file_meta,
613 ['post_id' => $post_id]
614 );
615
616 $this->_delete_attachment_cache($post_id);
617 }
618
619 /**
620 * Map requested fields into database query< compatible with the old post meta structure
621 *
622 * @param array $fields
623 * @param array $fields_mapping
624 * @return string
625 */
626 private function _map_fields($fields, $fields_mapping) {
627 $mapped = [];
628 $result = [];
629
630 if ( !is_array($fields) ) {
631 $fields = [$fields];
632 }
633
634 if (empty($fields)) {
635 $fields = array_keys($fields_mapping);
636 }
637
638 foreach ($fields as $key) {
639 if ( isset($fields_mapping[$key]) ) {
640 $mapped[$key] = $fields_mapping[$key];
641 }
642 }
643
644 foreach ($mapped as $key => $value) {
645 $result[] = "$value AS $key";
646 }
647
648 return implode(', ', $result);
649 }
650
651 /**
652 * Get cache key for file data
653 *
654 * @param int $post_id
655 * @return string
656 */
657 private function _get_file_cache_key($post_id) {
658 return implode('_', ['file', $post_id]);
659 }
660
661 /**
662 * Get cache key for file sizes data
663 *
664 * @param int $post_id
665 * @return string
666 */
667 private function _get_file_sizes_cache_key($post_id) {
668 return implode('_', ['file_sizes', $post_id]);
669 }
670
671 /**
672 * Get cache group for file meta data
673 *
674 * @param int $post_id
675 * @return string
676 */
677 private function _get_file_meta_cache_group($post_id) {
678 return implode('_', [$this->cache_group, 'meta', $post_id]);
679 }
680
681 /**
682 * Get cache key for file meta data
683 *
684 * @param int $post_id
685 * @param string $key
686 * @return string
687 */
688 private function _get_file_meta_cache_key($post_id, $key) {
689 return implode('_', [$key, $post_id]);
690 }
691
692 /**
693 * Get cache for file meta
694 *
695 * @param int $post_id
696 * @param string $key
697 * @param bool $found
698 * @return mixed
699 */
700 private function _get_file_meta_cache($post_id, $key, &$found) {
701 return wp_cache_get(
702 $this->_get_file_meta_cache_key($post_id, $key),
703 $this->_get_file_meta_cache_group($post_id),
704 false,
705 $found
706 );
707 }
708
709 /**
710 * Set cache for file meta
711 *
712 * @param int $post_id
713 * @param string $key
714 * @param mixed $value
715 * @return bool
716 */
717 private function _set_file_meta_cache($post_id, $key, $value) {
718 return wp_cache_set(
719 $this->_get_file_meta_cache_key($post_id, $key),
720 $value,
721 $this->_get_file_meta_cache_group($post_id)
722 );
723 }
724
725 /**
726 * Delete file cache
727 *
728 * @param int $attachment_id
729 */
730 private function _delete_file_cache($attachment_id) {
731 wp_cache_delete( $this->_get_file_cache_key($attachment_id), $this->cache_group );
732 }
733
734 /**
735 * Delete file sizes cache
736 *
737 * @param int $attachment_id
738 */
739 private function _delete_file_sizes_cache($attachment_id) {
740 wp_cache_delete( $this->_get_file_sizes_cache_key($attachment_id), $this->cache_group );
741 }
742
743 /**
744 * Delete file meta cache for single key
745 *
746 * @param int $attachment_id
747 * @param string $key
748 */
749 private function _delete_file_meta_key_cache($attachment_id, $key) {
750 wp_cache_delete(
751 $this->_get_file_meta_cache_key($attachment_id, $key),
752 $this->_get_file_meta_cache_group($attachment_id)
753 );
754 }
755
756 /**
757 * Delete all file meta cache
758 *
759 * @param int $attachment_id
760 */
761 private function _delete_file_meta_cache($attachment_id) {
762 wp_cache_flush_group( $this->_get_file_meta_cache_group($attachment_id) );
763 }
764
765 /**
766 * Delete all attachment cache
767 *
768 * @param int $attachment_id
769 */
770 private function _delete_attachment_cache($attachment_id) {
771 $this->_delete_file_cache($attachment_id);
772 $this->_delete_file_sizes_cache($attachment_id);
773 $this->_delete_file_meta_cache($attachment_id);
774 }
775
776 /**
777 * Get the total files count known to WP-Stateless
778 *
779 * @return int
780 */
781 public function get_total_files() {
782 global $wpdb;
783
784 try {
785 $query = "SELECT COUNT(id) FROM $this->files";
786
787 return $wpdb->get_var($query);
788 } catch (\Throwable $e) {
789 return 0;
790 }
791 }
792
793 /**
794 * Get the total file sizes count known to WP-Stateless
795 *
796 * @return int
797 */
798 public function get_total_file_sizes() {
799 global $wpdb;
800
801 try {
802 $query = "SELECT COUNT(id) FROM $this->file_sizes";
803
804 return $wpdb->get_var($query);
805 } catch (\Throwable $e) {
806 return 0;
807 }
808 }
809
810 /**
811 * Get the total non-media file sizes count known to WP-Stateless
812 *
813 * @return int
814 */
815 public function get_total_non_media_files() {
816 global $wpdb;
817
818 try {
819 $query = "SELECT COUNT(id) FROM $this->files WHERE post_id IS NULL";
820
821 return $wpdb->get_var($query);
822 } catch (\Throwable $e) {
823 return 0;
824 }
825 }
826
827 /**
828 * Get file data. If $with_sizes is set to true, all sizes will be included
829 *
830 * @param array $meta
831 * @param int $attachment_id
832 * @param bool $with_sizes
833 * @return array
834 */
835 public function get_file($meta, $attachment_id, $with_sizes = false) {
836 if ( ud_get_stateless_media()->get('sm.use_postmeta') ) {
837 $meta = get_post_meta($attachment_id, 'sm_cloud', true);
838
839 if ( !empty($meta) ) {
840 return $meta;
841 }
842 }
843
844 // Get values from the cache
845 $cache_key = $this->_get_file_cache_key($attachment_id);
846
847 $meta = wp_cache_get($cache_key, $this->cache_group, false, $found);
848
849 if ( $found ) {
850 return $meta;
851 }
852
853 // Get values from the DB
854 $fields = $this->_map_fields([], $this->file_mapping);
855
856 $sql = "SELECT $fields FROM $this->files WHERE post_id = %d";
857
858 $meta = $this->wpdb->get_row( $this->wpdb->prepare($sql, $attachment_id), ARRAY_A );
859
860 if ( empty($meta) ) {
861 return get_post_meta($attachment_id, 'sm_cloud', true);
862 }
863
864 wp_cache_set($cache_key, $meta, $this->cache_group);
865
866 // Get file size meta data
867 if ( $with_sizes ) {
868 $meta['sizes'] = apply_filters('wp_stateless_get_file_sizes', [], $attachment_id);
869 }
870
871 return $meta;
872 }
873
874 /**
875 * Get file sizes data
876 *
877 * @param array $sizes
878 * @param int $attachment_id
879 * @return array
880 */
881 public function get_file_sizes($sizes, $attachment_id) {
882 if ( ud_get_stateless_media()->get('sm.use_postmeta') ) {
883 $meta = get_post_meta($attachment_id, 'sm_cloud', true);
884 return isset($meta['sizes']) ? $meta['sizes'] : [];
885 }
886
887 // Get values from the cache
888 $cache_key = $this->_get_file_sizes_cache_key($attachment_id);
889
890 $sizes = wp_cache_get($cache_key, $this->cache_group, false, $found);
891
892 if ( $found ) {
893 return $sizes;
894 }
895
896 // Get values from the DB
897 $fields = $this->_map_fields([], $this->file_sizes_mapping);
898
899 $sql = "SELECT $fields FROM $this->file_sizes WHERE post_id = %d";
900 $sql = $this->wpdb->prepare($sql, $attachment_id);
901
902 $result = $this->wpdb->get_results( $this->wpdb->prepare($sql, $attachment_id), ARRAY_A );
903 $sizes = [];
904
905 if ( !empty($result) ) {
906 foreach ($result as $size) {
907 $size_name = $size['size_name'];
908 unset($size['size_name']);
909 $sizes[$size_name] = $size;
910 }
911 }
912
913 wp_cache_set($cache_key, $sizes, $this->cache_group);
914
915 return $sizes;
916 }
917
918 /**
919 * Get file meta
920 *
921 * @param int $post_id
922 * @param string $key
923 * @param mixed $default
924 * @return mixed
925 */
926 public function get_file_meta_value($value, $post_id, $key, $default = null) {
927 if ( ud_get_stateless_media()->get('sm.use_postmeta') ) {
928 $meta = get_post_meta($post_id, 'sm_cloud', []);
929
930 return isset($meta[$key]) ? $meta[$key] : $default;
931 }
932
933 // Get values from the cache
934 $key = sanitize_key($key);
935
936 $value = $this->_get_file_meta_cache($post_id, $key, $found);
937
938 if ( $found ) {
939 return $value;
940 }
941
942 // Get values from the DB
943 $sql = "SELECT meta_value FROM $this->file_meta WHERE post_id = %d AND meta_key = %s";
944 $data = $this->wpdb->get_var( $this->wpdb->prepare($sql, $post_id, $key) );
945
946 $value = null;
947
948 if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
949 $value = @unserialize( trim( $data ) );
950 } else {
951 $value = $data;
952 }
953
954 $this->_set_file_meta_cache($post_id, $key, $value);
955
956 return $value;
957 }
958
959 /**
960 * Update file meta
961 *
962 * @param int $post_id
963 * @param string $key
964 * @param mixed $value
965 * @return int
966 */
967 public function update_file_meta($post_id, $key, $value) {
968 $key = sanitize_key($key);
969
970 // Update value in the DB
971 $value = maybe_serialize( $value );
972
973 $file_meta_id = $this->get_file_meta_id($post_id, $key);
974
975 if ( $file_meta_id ) {
976 $this->wpdb->update(
977 $this->file_meta,
978 ['meta_value' => $value],
979 ['id' => $file_meta_id],
980 );
981 } else {
982 $this->wpdb->insert( $this->file_meta, [
983 'meta_key' => $key,
984 'meta_value' => $value,
985 'post_id' => $post_id,
986 ]);
987
988 $file_meta_id = $this->wpdb->insert_id;
989 }
990
991 $this->_delete_file_meta_key_cache($post_id, $key);
992
993 return $file_meta_id;
994 }
995
996 /**
997 * Get all the meta for the file
998 *
999 * @param mixed $meta
1000 * @param int $post_id
1001 * @return mixed
1002 */
1003 public function get_file_meta($meta, $post_id) {
1004 $sql = "SELECT meta_key, meta_value FROM $this->file_meta WHERE post_id = %d";
1005
1006 $result = $this->wpdb->get_results( $this->wpdb->prepare($sql, $post_id), ARRAY_A );
1007
1008 $data = [];
1009
1010 foreach ($result as $row) {
1011 $key = $row['meta_key'];
1012 $value = $row['meta_value'];
1013
1014 if ( is_serialized( $value ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
1015 $value = @unserialize( trim( $value ) );
1016 }
1017
1018 $data[$key] = $value;
1019 }
1020
1021 return $data;
1022 }
1023
1024 /**
1025 * Get file row ID by file name
1026 *
1027 * @param string $name
1028 * @return int | null
1029 */
1030 public function remove_non_library_file($name) {
1031 return $this->wpdb->delete(
1032 $this->files,
1033 [
1034 'name' => $name,
1035 'post_id' => null,
1036 ]
1037 );
1038 }
1039
1040 /**
1041 * Get all non-library files
1042 *
1043 * @param array $files
1044 * @param string $prefix
1045 * @return array | null
1046 */
1047 public function get_non_library_files($files, $prefix = '') {
1048 if ( !empty($prefix) ) {
1049 $sql = $this->wpdb->prepare("SELECT name FROM $this->files WHERE post_id IS NULL AND name LIKE '%s'", $this->wpdb->esc_like($prefix) . '%');
1050 } else {
1051 $sql = "SELECT name FROM $this->files WHERE post_id IS NULL";
1052 }
1053
1054 return $this->wpdb->get_col($sql);
1055 }
1056 }
1057 }
1058 }
1059