Version Description
This is a major upgrade that switches to using a custom table for storing data about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
Download this release
Release Info
Developer | deliciousbrains |
Plugin | WP Offload S3 Lite |
Version | 2.3 |
Comparing to | |
See all releases |
Code changes from version 2.2.1 to 2.3
- README.md +17 -2
- classes/amazon-s3-and-cloudfront.php +434 -356
- classes/as3cf-filter.php +5 -5
- classes/as3cf-notices.php +1 -1
- classes/as3cf-plugin-compatibility.php +129 -116
- classes/as3cf-utils.php +87 -6
- classes/filters/as3cf-local-to-s3.php +27 -27
- classes/filters/as3cf-s3-to-local.php +8 -60
- classes/items/item.php +794 -0
- classes/items/media-library-item.php +450 -0
- classes/upgrades/upgrade-file-sizes.php +9 -3
- classes/upgrades/upgrade-items-table.php +174 -0
- classes/upgrades/upgrade-region-meta.php +19 -4
- classes/upgrades/upgrade.php +15 -12
- languages/amazon-s3-and-cloudfront-en.pot +95 -83
- readme.txt +17 -2
- wordpress-s3.php +2 -2
README.md
CHANGED
@@ -2,9 +2,9 @@
|
|
2 |
**Contributors:** bradt, deliciousbrains, ianmjones
|
3 |
**Tags:** uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google cloud storage, gcs, mirror, admin, media, cdn, cloudfront
|
4 |
**Requires at least:** 4.9
|
5 |
-
**Tested up to:** 5.
|
6 |
**Requires PHP:** 5.5
|
7 |
-
**Stable tag:** 2.
|
8 |
**License:** GPLv3
|
9 |
|
10 |
Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
|
@@ -75,6 +75,9 @@ If you upgrade to the pro version of [WP Offload Media](https://deliciousbrains.
|
|
75 |
|
76 |
## Upgrade Notice ##
|
77 |
|
|
|
|
|
|
|
78 |
### 2.0 ###
|
79 |
This is a major upgrade that introduces support for DigitalOcean Spaces, renames the plugin to WP Offload Media Lite, and coincidentally upgrades some of its database settings. You may not be able to downgrade to WP Offload S3 Lite 1.x after upgrading to WP Offload Media Lite 2.0+.
|
80 |
|
@@ -86,6 +89,18 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
|
86 |
|
87 |
## Changelog ##
|
88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
### WP Offload Media Lite 2.2.1 - 2019-07-18 ###
|
90 |
* Improvement: Menu option and settings page title now include "Lite"
|
91 |
* Improvement: Remove Files From Server option now warns about media backups when switched on
|
2 |
**Contributors:** bradt, deliciousbrains, ianmjones
|
3 |
**Tags:** uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google cloud storage, gcs, mirror, admin, media, cdn, cloudfront
|
4 |
**Requires at least:** 4.9
|
5 |
+
**Tested up to:** 5.3
|
6 |
**Requires PHP:** 5.5
|
7 |
+
**Stable tag:** 2.3
|
8 |
**License:** GPLv3
|
9 |
|
10 |
Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
|
75 |
|
76 |
## Upgrade Notice ##
|
77 |
|
78 |
+
### 2.3 ###
|
79 |
+
This is a major upgrade that switches to using a custom table for storing data about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
|
80 |
+
|
81 |
### 2.0 ###
|
82 |
This is a major upgrade that introduces support for DigitalOcean Spaces, renames the plugin to WP Offload Media Lite, and coincidentally upgrades some of its database settings. You may not be able to downgrade to WP Offload S3 Lite 1.x after upgrading to WP Offload Media Lite 2.0+.
|
83 |
|
89 |
|
90 |
## Changelog ##
|
91 |
|
92 |
+
### WP Offload Media Lite 2.3 - 2019-11-12 ###
|
93 |
+
* [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-media-2-3-released/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
|
94 |
+
* New: Upgrade routine to migrate offload data to custom table
|
95 |
+
* New: Support for changed Media Library upload process introduced with WordPress 5.3
|
96 |
+
* New: Support for new "-scaled" and "-rotated" images introduced with WordPress 5.3
|
97 |
+
* New: Support for customizer changes introduced with WordPress 5.3
|
98 |
+
* New: Offload new "original_image" file introduced with WordPress 5.3
|
99 |
+
* Improvement: Performance boost during both page display and save
|
100 |
+
* Improvement: Better detection of offloaded media URLs during page display
|
101 |
+
* Bug fix: New Media Library upload given same local file name as offloaded and removed file after Remove Files From Server turned off
|
102 |
+
* Bug fix: PHP message: PHP Deprecated: strpos(): Non-string needles will be interpreted as strings in the future
|
103 |
+
|
104 |
### WP Offload Media Lite 2.2.1 - 2019-07-18 ###
|
105 |
* Improvement: Menu option and settings page title now include "Lite"
|
106 |
* Improvement: Remove Files From Server option now warns about media backups when switched on
|
classes/amazon-s3-and-cloudfront.php
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
<?php
|
2 |
|
|
|
3 |
use DeliciousBrains\WP_Offload_Media\Providers\AWS_Provider;
|
4 |
use DeliciousBrains\WP_Offload_Media\Providers\DigitalOcean_Provider;
|
5 |
use DeliciousBrains\WP_Offload_Media\Providers\GCP_Provider;
|
@@ -9,6 +10,7 @@ use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Content_Replace_URLs;
|
|
9 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_EDD_Replace_URLs;
|
10 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_File_Sizes;
|
11 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Filter_Post_Excerpt;
|
|
|
12 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Meta_WP_Error;
|
13 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Region_Meta;
|
14 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_WPOS3_To_AS3CF;
|
@@ -107,7 +109,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
107 |
'WPOS3_SETTINGS',
|
108 |
);
|
109 |
|
110 |
-
const LATEST_UPGRADE_ROUTINE =
|
111 |
|
112 |
/**
|
113 |
* @param string $plugin_file_path
|
@@ -142,6 +144,8 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
142 |
GCP_Provider::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\GCP_Provider',
|
143 |
);
|
144 |
|
|
|
|
|
145 |
$this->set_provider();
|
146 |
|
147 |
// Bundled SDK may require AWS setup before data migrations.
|
@@ -154,6 +158,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
154 |
new Upgrade_EDD_Replace_URLs( $this );
|
155 |
new Upgrade_Filter_Post_Excerpt( $this );
|
156 |
new Upgrade_WPOS3_To_AS3CF( $this );
|
|
|
157 |
|
158 |
// Plugin setup
|
159 |
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
@@ -306,13 +311,22 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
306 |
return apply_filters( 'as3cf_settings_menu_title', $this->plugin_menu_title );
|
307 |
}
|
308 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
/**
|
310 |
* Get the plugin prefix in slug format, ie. replace underscores with hyphens
|
311 |
*
|
312 |
* @return string
|
313 |
*/
|
314 |
-
function get_plugin_prefix_slug() {
|
315 |
-
return str_replace( '_', '-', $this->
|
316 |
}
|
317 |
|
318 |
/**
|
@@ -338,7 +352,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
338 |
'key' => $key,
|
339 |
'disabled' => false,
|
340 |
'disabled_attr' => '',
|
341 |
-
'tr_class' => str_replace( '_', '-', $this->
|
342 |
'setting_msg' => '',
|
343 |
'is_defined' => false,
|
344 |
);
|
@@ -959,23 +973,38 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
959 |
/**
|
960 |
* Removes an attachment's files from provider.
|
961 |
*
|
962 |
-
* @param int
|
963 |
-
* @param
|
964 |
-
* @param bool
|
965 |
-
* @param bool
|
966 |
-
* @param bool
|
967 |
-
* @param bool
|
968 |
-
*
|
969 |
-
*/
|
970 |
-
function remove_attachment_files_from_provider( $post_id, $
|
971 |
-
$prefix = $
|
972 |
-
$
|
973 |
-
$
|
974 |
-
$paths = AS3CF_Utils::get_attachment_file_paths( $post_id, false, false, $remove_backup_sizes );
|
975 |
-
$paths = apply_filters( 'as3cf_remove_attachment_paths', $paths, $post_id, $provider_object, $remove_backup_sizes );
|
976 |
|
977 |
-
|
978 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
979 |
}
|
980 |
|
981 |
$objects_to_remove = array();
|
@@ -987,7 +1016,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
987 |
}
|
988 |
|
989 |
// finally delete the objects from provider
|
990 |
-
$this->delete_objects( $region, $bucket, $objects_to_remove, $log_error, $return_on_error, $force_new_provider_client );
|
991 |
}
|
992 |
|
993 |
/**
|
@@ -1002,7 +1031,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1002 |
return;
|
1003 |
}
|
1004 |
|
1005 |
-
|
|
|
|
|
1006 |
return;
|
1007 |
}
|
1008 |
|
@@ -1010,9 +1041,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1010 |
return;
|
1011 |
}
|
1012 |
|
1013 |
-
$this->remove_attachment_files_from_provider( $post_id, $
|
1014 |
|
1015 |
-
|
1016 |
}
|
1017 |
|
1018 |
/**
|
@@ -1030,25 +1061,36 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1030 |
return $data;
|
1031 |
}
|
1032 |
|
1033 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1034 |
// abort if not already uploaded to provider and the copy setting is off
|
1035 |
return $data;
|
1036 |
}
|
1037 |
|
|
|
|
|
|
|
|
|
1038 |
// allow provider upload to be cancelled for any reason
|
1039 |
-
$pre = apply_filters( 'as3cf_pre_update_attachment_metadata', false, $data, $post_id, $
|
1040 |
if ( false !== $pre ) {
|
1041 |
return $data;
|
1042 |
}
|
1043 |
|
1044 |
// upload attachment to provider
|
1045 |
-
$
|
1046 |
|
1047 |
-
if ( is_wp_error( $
|
1048 |
return $data;
|
1049 |
}
|
1050 |
|
1051 |
-
return $
|
1052 |
}
|
1053 |
|
1054 |
/**
|
@@ -1061,10 +1103,12 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1061 |
* to cope with possible different regions
|
1062 |
* @param bool $remove_local_files
|
1063 |
*
|
1064 |
-
* @return array|WP_Error
|
1065 |
* @throws Exception
|
1066 |
*/
|
1067 |
public function upload_attachment( $post_id, $data = null, $file_path = null, $force_new_provider_client = false, $remove_local_files = true ) {
|
|
|
|
|
1068 |
$return_metadata = null;
|
1069 |
if ( is_null( $data ) ) {
|
1070 |
$data = wp_get_attachment_metadata( $post_id, true );
|
@@ -1092,15 +1136,82 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1092 |
$file_path = get_attached_file( $post_id, true );
|
1093 |
}
|
1094 |
|
1095 |
-
// Check file
|
1096 |
-
if (
|
1097 |
-
$error_msg = sprintf( __( '
|
1098 |
|
1099 |
return $this->return_upload_error( $error_msg, $return_metadata );
|
1100 |
}
|
1101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1102 |
// Get original file's stats.
|
1103 |
-
$filesize = filesize( $file_path );
|
1104 |
$file_name = wp_basename( $file_path );
|
1105 |
$type = get_post_mime_type( $post_id );
|
1106 |
$allowed_types = $this->get_allowed_mime_types();
|
@@ -1115,23 +1226,25 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1115 |
$acl = $this->get_provider()->get_default_acl();
|
1116 |
|
1117 |
// check the attachment already exists in provider, eg. edit or restore image
|
1118 |
-
if (
|
1119 |
// Must be offloaded to same provider as currently configured.
|
1120 |
if ( ! $this->is_attachment_served_by_provider( $post_id, true ) ) {
|
1121 |
return $this->return_upload_error( __( 'Already offloaded to a different provider', 'amazon-s3-and-cloudfront' ), $return_metadata );
|
1122 |
}
|
1123 |
|
1124 |
-
//
|
1125 |
-
if (
|
1126 |
-
$acl = $
|
1127 |
}
|
1128 |
|
1129 |
// use existing prefix
|
1130 |
-
$prefix = $
|
1131 |
// use existing bucket
|
1132 |
-
$bucket = $
|
1133 |
// get existing region
|
1134 |
-
$region =
|
|
|
|
|
1135 |
} else {
|
1136 |
// derive prefix from various settings
|
1137 |
$time = $this->get_attachment_folder_year_month( $post_id, $data );
|
@@ -1143,6 +1256,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1143 |
if ( is_wp_error( $region ) ) {
|
1144 |
$region = '';
|
1145 |
}
|
|
|
|
|
|
|
1146 |
}
|
1147 |
|
1148 |
$acl = apply_filters( 'wps3_upload_acl', $acl, $type, $data, $post_id, $this ); // Old naming convention, will be deprecated soon
|
@@ -1167,43 +1283,43 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1167 |
$args['ContentEncoding'] = 'gzip';
|
1168 |
}
|
1169 |
|
1170 |
-
$image_size
|
1171 |
-
$args
|
1172 |
-
$provider_object = array(
|
1173 |
-
'provider' => $this->get_provider()->get_provider_key_name(),
|
1174 |
-
'region' => $bucket !== $args['Bucket'] ? $this->get_bucket_region( $args['Bucket'], true ) : $region,
|
1175 |
-
'bucket' => $args['Bucket'],
|
1176 |
-
'key' => $args['Key'],
|
1177 |
-
'acl' => $args['ACL'],
|
1178 |
-
);
|
1179 |
|
1180 |
-
|
1181 |
-
|
1182 |
-
|
1183 |
-
|
|
|
|
|
|
|
1184 |
|
1185 |
-
do_action( 'as3cf_upload_attachment_pre_remove', $post_id, $
|
1186 |
|
|
|
1187 |
$files_to_remove = array();
|
1188 |
|
1189 |
-
$provider_client = $this->get_provider_client( $
|
1190 |
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
$error_msg = sprintf( __( 'Error offloading %s to provider: %s', 'amazon-s3-and-cloudfront' ), $file_path, $e->getMessage() );
|
1196 |
|
1197 |
-
|
1198 |
-
|
1199 |
|
1200 |
-
|
|
|
|
|
|
|
1201 |
|
1202 |
-
|
|
|
|
|
1203 |
|
1204 |
-
$
|
1205 |
-
$
|
1206 |
-
$provider_object_sizes = array();
|
1207 |
|
1208 |
foreach ( $file_paths as $size => $file_path ) {
|
1209 |
if ( ! in_array( $file_path, $files_to_remove ) ) {
|
@@ -1216,8 +1332,8 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1216 |
'ContentType' => $this->get_mime_type( $file_path ),
|
1217 |
);
|
1218 |
|
1219 |
-
if ( $this->get_provider()->
|
1220 |
-
$
|
1221 |
}
|
1222 |
}
|
1223 |
}
|
@@ -1225,42 +1341,72 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1225 |
$upload_errors = array();
|
1226 |
|
1227 |
foreach ( $additional_images as $size => $image ) {
|
|
|
|
|
|
|
|
|
|
|
1228 |
$args = apply_filters( 'as3cf_object_meta', array_merge( $args, $image ), $post_id, $size, false );
|
1229 |
|
1230 |
if ( ! file_exists( $args['SourceFile'] ) ) {
|
1231 |
-
|
|
|
|
|
1232 |
continue;
|
1233 |
}
|
1234 |
|
1235 |
try {
|
|
|
1236 |
$provider_client->upload_object( $args );
|
1237 |
-
$files_to_remove[] = $image['SourceFile'];
|
|
|
|
|
|
|
1238 |
} catch ( Exception $e ) {
|
1239 |
$upload_errors[] = $this->return_upload_error( sprintf( __( 'Error offloading %s to provider: %s', 'amazon-s3-and-cloudfront' ), $args['SourceFile'], $e->getMessage() ) );
|
1240 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1241 |
}
|
1242 |
|
1243 |
$remove_local_files_setting = $this->get_setting( 'remove-local-file' );
|
1244 |
|
1245 |
-
if ( $remove_local_files ) {
|
1246 |
-
|
1247 |
-
|
1248 |
-
$files_to_remove = apply_filters( 'as3cf_upload_attachment_local_files_to_remove', $files_to_remove, $post_id, $file_path );
|
1249 |
|
1250 |
-
|
1251 |
-
|
1252 |
|
1253 |
-
|
1254 |
-
|
|
|
|
|
|
|
|
|
1255 |
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
|
1260 |
-
|
1261 |
-
|
1262 |
-
|
1263 |
-
}
|
1264 |
}
|
1265 |
}
|
1266 |
}
|
@@ -1270,16 +1416,36 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1270 |
$data = $this->maybe_cleanup_filesize_metadata( $post_id, $data, empty( $return_metadata ) );
|
1271 |
}
|
1272 |
|
1273 |
-
|
1274 |
-
|
1275 |
-
$
|
1276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1277 |
}
|
1278 |
|
1279 |
// Keep track of attachments uploaded by this instance.
|
1280 |
$this->uploaded_post_ids[] = $post_id;
|
1281 |
|
1282 |
-
do_action( 'as3cf_post_upload_attachment', $post_id, $
|
1283 |
|
1284 |
if ( $upload_errors ) {
|
1285 |
return $this->consolidate_upload_errors( $upload_errors );
|
@@ -1290,7 +1456,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1290 |
return $data;
|
1291 |
}
|
1292 |
|
1293 |
-
return $
|
1294 |
}
|
1295 |
|
1296 |
/**
|
@@ -1373,11 +1539,14 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1373 |
/**
|
1374 |
* Remove files from the local site, recording total filesize in meta if attachment ID given.
|
1375 |
*
|
1376 |
-
* @param array $file_paths
|
1377 |
-
* @param int $attachment_id
|
|
|
1378 |
*/
|
1379 |
-
function remove_local_files( $file_paths, $attachment_id = 0 ) {
|
1380 |
-
$filesize_total
|
|
|
|
|
1381 |
|
1382 |
foreach ( $file_paths as $index => $path ) {
|
1383 |
if ( ! empty( $attachment_id ) && is_int( $attachment_id ) ) {
|
@@ -1405,7 +1574,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1405 |
}
|
1406 |
|
1407 |
// If we were able to sum up file sizes for an attachment, record it.
|
1408 |
-
if ( $filesize_total > 0 ) {
|
1409 |
update_post_meta( $attachment_id, 'as3cf_filesize_total', $filesize_total );
|
1410 |
}
|
1411 |
}
|
@@ -1526,7 +1695,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1526 |
* @return string
|
1527 |
*/
|
1528 |
public function filter_unique_filename( $filename, $ext, $dir, $post_id = null ) {
|
1529 |
-
if ( ! $this->
|
1530 |
return $filename;
|
1531 |
}
|
1532 |
|
@@ -1619,6 +1788,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1619 |
}
|
1620 |
$file = $path . $filename;
|
1621 |
|
|
|
1622 |
$sql = $wpdb->prepare( "
|
1623 |
SELECT COUNT(*)
|
1624 |
FROM $wpdb->postmeta
|
@@ -1626,7 +1796,16 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1626 |
AND meta_value = %s
|
1627 |
", '_wp_attached_file', $file );
|
1628 |
|
1629 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1630 |
}
|
1631 |
|
1632 |
/**
|
@@ -1664,44 +1843,24 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1664 |
*/
|
1665 |
function generate_unique_filename( $name, $ext, $time ) {
|
1666 |
$count = 1;
|
1667 |
-
$filename = $name . $count . $ext;
|
1668 |
|
1669 |
while ( $this->does_file_exist( $filename, $time ) ) {
|
1670 |
$count++;
|
1671 |
-
$filename = $name . $count . $ext;
|
1672 |
}
|
1673 |
|
1674 |
return $filename;
|
1675 |
}
|
1676 |
|
1677 |
-
/**
|
1678 |
-
* Get attachment provider info
|
1679 |
-
*
|
1680 |
-
* @param int $post_id
|
1681 |
-
*
|
1682 |
-
* @return mixed
|
1683 |
-
*/
|
1684 |
-
public function get_attachment_provider_info( $post_id ) {
|
1685 |
-
$provider_object = get_post_meta( $post_id, 'amazonS3_info', true );
|
1686 |
-
|
1687 |
-
if ( is_array( $provider_object ) ) {
|
1688 |
-
$provider_object = array_merge( array(
|
1689 |
-
'provider' => static::$default_provider,
|
1690 |
-
'region' => null,
|
1691 |
-
), $provider_object );
|
1692 |
-
}
|
1693 |
-
|
1694 |
-
$provider_object = apply_filters( 'as3cf_get_attachment_s3_info', $provider_object, $post_id ); // Backwards compatibility
|
1695 |
-
|
1696 |
-
return apply_filters( 'as3cf_get_attachment_provider_info', $provider_object, $post_id );
|
1697 |
-
}
|
1698 |
-
|
1699 |
/**
|
1700 |
* Check the plugin is correctly setup
|
1701 |
*
|
1702 |
* @param bool $with_credentials Do provider credentials need to be set up too? Defaults to false.
|
1703 |
*
|
1704 |
* @return bool
|
|
|
|
|
1705 |
*/
|
1706 |
function is_plugin_setup( $with_credentials = false ) {
|
1707 |
if ( $with_credentials && $this->get_provider()->needs_access_keys() ) {
|
@@ -1831,11 +1990,11 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1831 |
* @return bool|mixed|WP_Error
|
1832 |
*/
|
1833 |
public function get_attachment_url( $post_id, $expires = null, $size = null, $meta = null, $headers = array(), $skip_rewrite_check = false ) {
|
1834 |
-
if ( ! ( $
|
1835 |
return false;
|
1836 |
}
|
1837 |
|
1838 |
-
$url = $this->get_attachment_provider_url( $post_id, $
|
1839 |
|
1840 |
return apply_filters( 'as3cf_wp_get_attachment_url', $url, $post_id );
|
1841 |
}
|
@@ -1908,20 +2067,20 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1908 |
/**
|
1909 |
* Get the provider URL for an attachment
|
1910 |
*
|
1911 |
-
* @param int
|
1912 |
-
* @param
|
1913 |
-
* @param null|int
|
1914 |
-
* @param null|string|array
|
1915 |
-
* @param null|array
|
1916 |
-
* @param array
|
1917 |
*
|
1918 |
-
* @return
|
1919 |
*/
|
1920 |
-
public function get_attachment_provider_url( $post_id, $
|
1921 |
-
|
1922 |
-
|
1923 |
-
if (
|
1924 |
-
$region = $this->get_provider()->sanitize_region( $
|
1925 |
} else {
|
1926 |
$region = '';
|
1927 |
}
|
@@ -1930,12 +2089,12 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1930 |
|
1931 |
// Force use of secured URL when ACL has been set to private
|
1932 |
if ( is_null( $expires ) ) {
|
1933 |
-
if ( is_null( $size ) &&
|
1934 |
// Full size URL private
|
1935 |
$expires = self::DEFAULT_EXPIRES;
|
1936 |
}
|
1937 |
|
1938 |
-
if ( ! is_null( $size ) &&
|
1939 |
// Alternative size URL private
|
1940 |
$expires = self::DEFAULT_EXPIRES;
|
1941 |
}
|
@@ -1951,15 +2110,15 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1951 |
}
|
1952 |
|
1953 |
if ( ! empty( $meta ) && isset( $meta['sizes'][ $size ]['file'] ) ) {
|
1954 |
-
$size_prefix = dirname( $
|
1955 |
$size_file_prefix = ( '.' === $size_prefix ) ? '' : $size_prefix . '/';
|
1956 |
|
1957 |
-
$
|
1958 |
}
|
1959 |
}
|
1960 |
|
1961 |
$scheme = $this->get_url_scheme();
|
1962 |
-
$domain = $this->get_provider()->get_url_domain( $
|
1963 |
$base_url = $scheme . '://' . $domain;
|
1964 |
|
1965 |
if ( ! is_null( $expires ) && $this->is_plugin_setup( true ) ) {
|
@@ -1970,20 +2129,20 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1970 |
|
1971 |
$expires = time() + apply_filters( 'as3cf_expires', $expires );
|
1972 |
$secure_url = $this->get_provider_client( $region )
|
1973 |
-
->get_object_url( $
|
1974 |
|
1975 |
-
return apply_filters( 'as3cf_get_attachment_secure_url', $secure_url, $
|
1976 |
} catch ( Exception $e ) {
|
1977 |
return new WP_Error( 'exception', $e->getMessage() );
|
1978 |
}
|
1979 |
}
|
1980 |
|
1981 |
-
$
|
1982 |
|
1983 |
-
$file = $this->encode_filename_in_path( $
|
1984 |
$url = $base_url . '/' . $file;
|
1985 |
|
1986 |
-
return apply_filters( 'as3cf_get_attachment_url', $url, $
|
1987 |
}
|
1988 |
|
1989 |
/**
|
@@ -1995,6 +2154,10 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1995 |
* @return bool|mixed|WP_Error
|
1996 |
*/
|
1997 |
public function wp_get_attachment_url( $url, $post_id ) {
|
|
|
|
|
|
|
|
|
1998 |
$new_url = $this->get_attachment_url( $post_id );
|
1999 |
|
2000 |
if ( false === $new_url ) {
|
@@ -2020,7 +2183,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2020 |
* @return string
|
2021 |
*/
|
2022 |
public function maybe_encode_get_image_tag( $html, $id, $alt, $title, $align, $size ) {
|
2023 |
-
if ( ! ( $
|
2024 |
// Not served by provider, return
|
2025 |
return $html;
|
2026 |
}
|
@@ -2037,7 +2200,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2037 |
}
|
2038 |
|
2039 |
$img_src = $matches[1];
|
2040 |
-
$new_img_src = $this->maybe_sign_intermediate_size( $img_src, $id, $size, $
|
2041 |
$new_img_src = $this->encode_filename_in_path( $new_img_src );
|
2042 |
|
2043 |
return str_replace( $img_src, $new_img_src, $html );
|
@@ -2054,13 +2217,13 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2054 |
* @return array
|
2055 |
*/
|
2056 |
public function maybe_encode_wp_get_attachment_image_src( $image, $attachment_id, $size, $icon ) {
|
2057 |
-
if ( ! ( $
|
2058 |
// Not served by provider, return
|
2059 |
return $image;
|
2060 |
}
|
2061 |
|
2062 |
if ( isset( $image[0] ) ) {
|
2063 |
-
$url = $this->maybe_sign_intermediate_size( $image[0], $attachment_id, $size, $
|
2064 |
$url = $this->encode_filename_in_path( $url );
|
2065 |
|
2066 |
$image[0] = $url;
|
@@ -2079,7 +2242,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2079 |
* @return array
|
2080 |
*/
|
2081 |
public function maybe_encode_wp_prepare_attachment_for_js( $response, $attachment, $meta ) {
|
2082 |
-
if ( ! ( $
|
2083 |
// Not served by provider, return
|
2084 |
return $response;
|
2085 |
}
|
@@ -2090,7 +2253,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2090 |
|
2091 |
if ( isset( $response['sizes'] ) && is_array( $response['sizes'] ) ) {
|
2092 |
foreach ( $response['sizes'] as $size => $value ) {
|
2093 |
-
$url = $this->maybe_sign_intermediate_size( $value['url'], $attachment->ID, $size, $
|
2094 |
$url = $this->encode_filename_in_path( $url );
|
2095 |
|
2096 |
$response['sizes'][ $size ]['url'] = $url;
|
@@ -2110,13 +2273,13 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2110 |
* @return array
|
2111 |
*/
|
2112 |
public function maybe_encode_image_get_intermediate_size( $data, $post_id, $size ) {
|
2113 |
-
if ( ! ( $
|
2114 |
// Not served by provider, return
|
2115 |
return $data;
|
2116 |
}
|
2117 |
|
2118 |
if ( isset( $data['url'] ) ) {
|
2119 |
-
$url = $this->maybe_sign_intermediate_size( $data['url'], $post_id, $size, $
|
2120 |
$url = $this->encode_filename_in_path( $url );
|
2121 |
|
2122 |
$data['url'] = $url;
|
@@ -2128,23 +2291,23 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2128 |
/**
|
2129 |
* Sign intermediate size.
|
2130 |
*
|
2131 |
-
* @param string
|
2132 |
-
* @param int
|
2133 |
-
* @param string|array
|
2134 |
-
* @param bool|
|
2135 |
*
|
2136 |
-
* @return
|
2137 |
*/
|
2138 |
-
protected function maybe_sign_intermediate_size( $url, $attachment_id, $size, $
|
2139 |
-
if ( ! $
|
2140 |
-
$
|
2141 |
}
|
2142 |
|
2143 |
$size = $this->maybe_convert_size_to_string( $attachment_id, $size );
|
2144 |
|
2145 |
-
if (
|
2146 |
// Private file, add AWS signature if required
|
2147 |
-
return $this->get_attachment_provider_url( $attachment_id, $
|
2148 |
}
|
2149 |
|
2150 |
return $url;
|
@@ -2222,7 +2385,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2222 |
* @param bool $skip_current_provider_check Skip checking if offloaded to current provider. Default: false, negated if $provider supplied
|
2223 |
* @param Provider|null $provider Provider where attachment expected to be offloaded to. Default: currently configured provider
|
2224 |
*
|
2225 |
-
* @return bool|
|
2226 |
*/
|
2227 |
public function is_attachment_served_by_provider( $attachment_id, $skip_rewrite_check = false, $skip_current_provider_check = false, Provider $provider = null ) {
|
2228 |
if ( ! $skip_rewrite_check && ! $this->get_setting( 'serve-from-s3' ) ) {
|
@@ -2230,7 +2393,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2230 |
return false;
|
2231 |
}
|
2232 |
|
2233 |
-
|
|
|
|
|
2234 |
// File not uploaded to a provider
|
2235 |
return false;
|
2236 |
}
|
@@ -2239,12 +2404,12 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2239 |
$provider = $this->get_provider();
|
2240 |
}
|
2241 |
|
2242 |
-
if ( ! empty( $provider ) && $provider::get_provider_key_name() !== $
|
2243 |
// File not uploaded to required provider
|
2244 |
return false;
|
2245 |
}
|
2246 |
|
2247 |
-
return $
|
2248 |
}
|
2249 |
|
2250 |
/**
|
@@ -2285,33 +2450,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2285 |
return str_replace( $file_name, $encoded_file_name, $file );
|
2286 |
}
|
2287 |
|
2288 |
-
/**
|
2289 |
-
* Decode file name.
|
2290 |
-
*
|
2291 |
-
* @param string $file
|
2292 |
-
*
|
2293 |
-
* @return string
|
2294 |
-
*/
|
2295 |
-
public function decode_filename_in_path( $file ) {
|
2296 |
-
$url = parse_url( $file );
|
2297 |
-
|
2298 |
-
if ( ! isset( $url['path'] ) ) {
|
2299 |
-
// Can't determine path, return original
|
2300 |
-
return $file;
|
2301 |
-
}
|
2302 |
-
|
2303 |
-
$file_name = wp_basename( $url['path'] );
|
2304 |
-
|
2305 |
-
if ( false === strpos( $file_name, '%' ) ) {
|
2306 |
-
// File name not encoded, return original
|
2307 |
-
return $file;
|
2308 |
-
}
|
2309 |
-
|
2310 |
-
$decoded_file_name = rawurldecode( $file_name );
|
2311 |
-
|
2312 |
-
return str_replace( $file_name, $decoded_file_name, $file );
|
2313 |
-
}
|
2314 |
-
|
2315 |
/**
|
2316 |
* Allow processes to update the file on provider via update_attached_file()
|
2317 |
*
|
@@ -2325,11 +2463,13 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2325 |
return $file;
|
2326 |
}
|
2327 |
|
2328 |
-
|
|
|
|
|
2329 |
return $file;
|
2330 |
}
|
2331 |
|
2332 |
-
$file = apply_filters( 'as3cf_update_attached_file', $file, $attachment_id, $
|
2333 |
|
2334 |
return $file;
|
2335 |
}
|
@@ -2345,14 +2485,14 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2345 |
* @return string
|
2346 |
*/
|
2347 |
function get_attached_file( $file, $attachment_id ) {
|
2348 |
-
if ( file_exists( $file ) || ! ( $
|
2349 |
return $file;
|
2350 |
}
|
2351 |
|
2352 |
$url = $this->get_attachment_url( $attachment_id );
|
2353 |
|
2354 |
// return the URL by default
|
2355 |
-
$file = apply_filters( 'as3cf_get_attached_file', $url, $file, $attachment_id, $
|
2356 |
|
2357 |
return $file;
|
2358 |
}
|
@@ -2580,6 +2720,15 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2580 |
);
|
2581 |
}
|
2582 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2583 |
/**
|
2584 |
* Returns the Provider's default region slug.
|
2585 |
*
|
@@ -2679,34 +2828,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2679 |
return $region;
|
2680 |
}
|
2681 |
|
2682 |
-
/**
|
2683 |
-
* Get the region of the bucket stored in the provider metadata.
|
2684 |
-
*
|
2685 |
-
*
|
2686 |
-
* @param array $provider_object
|
2687 |
-
* @param int $post_id - if supplied will update the provider meta if no region found
|
2688 |
-
*
|
2689 |
-
* @return string|WP_Error - region name
|
2690 |
-
*/
|
2691 |
-
function get_provider_object_region( $provider_object, $post_id = null ) {
|
2692 |
-
if ( ! isset( $provider_object['region'] ) ) {
|
2693 |
-
// if region hasn't been stored in the provider metadata retrieve using the bucket
|
2694 |
-
$region = $this->get_bucket_region( $provider_object['bucket'], true );
|
2695 |
-
if ( is_wp_error( $region ) ) {
|
2696 |
-
return $region;
|
2697 |
-
}
|
2698 |
-
|
2699 |
-
$provider_object['region'] = $region;
|
2700 |
-
|
2701 |
-
if ( ! is_null( $post_id ) ) {
|
2702 |
-
// retrospectively update provider metadata with region
|
2703 |
-
update_post_meta( $post_id, 'amazonS3_info', $provider_object );
|
2704 |
-
}
|
2705 |
-
}
|
2706 |
-
|
2707 |
-
return $provider_object['region'];
|
2708 |
-
}
|
2709 |
-
|
2710 |
/**
|
2711 |
* AJAX handler for get_buckets()
|
2712 |
*/
|
@@ -3407,56 +3528,63 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
3407 |
/**
|
3408 |
* Apply ACL to an attachment and associated files
|
3409 |
*
|
3410 |
-
* @param int
|
3411 |
-
* @param
|
3412 |
-
* @param
|
3413 |
*
|
3414 |
-
* @return
|
3415 |
-
* @throws Exception
|
3416 |
*/
|
3417 |
-
public function set_attachment_acl_on_provider( $post_id, $
|
3418 |
// Return early if already set to the desired ACL
|
3419 |
-
if (
|
3420 |
return false;
|
3421 |
}
|
3422 |
|
|
|
|
|
3423 |
$args = array(
|
3424 |
'ACL' => $acl,
|
3425 |
-
'Bucket' => $
|
3426 |
-
'Key' => $
|
3427 |
);
|
3428 |
|
3429 |
-
$region
|
3430 |
-
$provider_client = $this->get_provider_client( $region, true );
|
3431 |
|
3432 |
try {
|
|
|
3433 |
$provider_client->update_object_acl( $args );
|
3434 |
-
$provider_object['acl'] = $acl;
|
3435 |
-
|
3436 |
-
// update S3 meta data
|
3437 |
-
if ( $acl == $this->get_provider()->get_default_acl() ) {
|
3438 |
-
unset( $provider_object['acl'] );
|
3439 |
-
}
|
3440 |
|
3441 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3442 |
} catch ( Exception $e ) {
|
3443 |
-
$msg = 'Error setting ACL to ' . $acl . ' for ' . $
|
3444 |
AS3CF_Error::log( $msg );
|
3445 |
|
3446 |
return new WP_Error( 'acl_exception', $msg );
|
3447 |
}
|
3448 |
|
3449 |
-
return $
|
3450 |
}
|
3451 |
|
3452 |
/**
|
3453 |
* Make admin notice for when object ACL has changed
|
3454 |
*
|
3455 |
-
* @param
|
3456 |
*/
|
3457 |
-
function make_acl_admin_notice( $
|
3458 |
-
$filename = wp_basename( $
|
3459 |
-
$acl = (
|
3460 |
$acl_name = $this->get_acl_display_name( $acl );
|
3461 |
$text = sprintf( __( '<strong>WP Offload Media</strong> — The file %s has been given %s permissions in the bucket.', 'amazon-s3-and-cloudfront' ), "<strong>{$filename}</strong>", "<strong>{$acl_name}</strong>" );
|
3462 |
|
@@ -3727,13 +3855,19 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
3727 |
$media_counts = $this->media_counts();
|
3728 |
|
3729 |
$output .= 'Media Files: ';
|
3730 |
-
$output .= number_format_i18n( $media_counts['total'] );
|
3731 |
$output .= "\r\n";
|
3732 |
|
3733 |
$output .= 'Offloaded Media Files: ';
|
3734 |
-
$output .= number_format_i18n( $media_counts['offloaded'] );
|
3735 |
$output .= "\r\n";
|
3736 |
|
|
|
|
|
|
|
|
|
|
|
|
|
3737 |
$output .= 'Number of Image Sizes: ';
|
3738 |
$sizes = count( get_intermediate_image_sizes() );
|
3739 |
$output .= number_format_i18n( $sizes );
|
@@ -4283,55 +4417,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
4283 |
return intval( $memory_limit ) * 1024 * 1024;
|
4284 |
}
|
4285 |
|
4286 |
-
/**
|
4287 |
-
* Count attachments on a site.
|
4288 |
-
*
|
4289 |
-
* @param string $prefix
|
4290 |
-
* @param bool $skip_transient Whether to force database query and skip transient, default false
|
4291 |
-
* @param bool $force Whether to force database query and skip static cache, implies $skip_transient, default false
|
4292 |
-
*
|
4293 |
-
* @return array Keys:
|
4294 |
-
* total: Total media count for site (prefix)
|
4295 |
-
* offloaded: Count of offloaded media for site (prefix)
|
4296 |
-
* not_offloaded: Difference between total and offloaded
|
4297 |
-
*/
|
4298 |
-
public function count_attachments( $prefix, $skip_transient = false, $force = false ) {
|
4299 |
-
global $wpdb;
|
4300 |
-
|
4301 |
-
static $counts;
|
4302 |
-
static $skips;
|
4303 |
-
|
4304 |
-
$transient_key = 'as3cf_' . $prefix . '_attachment_counts';
|
4305 |
-
|
4306 |
-
// Been here, done it, won't do it again!
|
4307 |
-
// Well, unless this is the first transient skip for the prefix, then we need to do it.
|
4308 |
-
if ( ! $force && ! empty( $counts[ $transient_key ] ) && ( false === $skip_transient || ! empty( $skips[ $transient_key ] ) ) ) {
|
4309 |
-
return $counts[ $transient_key ];
|
4310 |
-
}
|
4311 |
-
|
4312 |
-
if ( $force || $skip_transient || false === ( $attachment_counts = get_site_transient( $transient_key ) ) ) {
|
4313 |
-
$sql = "
|
4314 |
-
SELECT COUNT(DISTINCT p.`ID`) total, COUNT(DISTINCT pm.`post_id`) offloaded
|
4315 |
-
FROM `{$prefix}posts` p
|
4316 |
-
LEFT OUTER JOIN `{$prefix}postmeta` pm ON p.`ID` = pm.`post_id` AND pm.`meta_key` = 'amazonS3_info'
|
4317 |
-
WHERE p.`post_type` = 'attachment'
|
4318 |
-
";
|
4319 |
-
|
4320 |
-
$attachment_counts = $wpdb->get_row( $sql, ARRAY_A );
|
4321 |
-
|
4322 |
-
$attachment_counts['not_offloaded'] = $attachment_counts['total'] - $attachment_counts['offloaded'];
|
4323 |
-
|
4324 |
-
set_site_transient( $transient_key, $attachment_counts, 2 * MINUTE_IN_SECONDS );
|
4325 |
-
|
4326 |
-
// One way or another we've skipped the transient.
|
4327 |
-
$skips[ $transient_key ] = true;
|
4328 |
-
}
|
4329 |
-
|
4330 |
-
$counts[ $transient_key ] = $attachment_counts;
|
4331 |
-
|
4332 |
-
return $attachment_counts;
|
4333 |
-
}
|
4334 |
-
|
4335 |
/**
|
4336 |
* Get the total attachment and total offloaded/not offloaded attachment counts
|
4337 |
*
|
@@ -4342,22 +4427,35 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
4342 |
*/
|
4343 |
public function media_counts( $skip_transient = false, $force = false ) {
|
4344 |
if ( $skip_transient || false === ( $attachment_counts = get_site_transient( 'as3cf_attachment_counts' ) ) ) {
|
4345 |
-
$table_prefixes
|
4346 |
-
$total
|
4347 |
-
$
|
4348 |
-
$
|
|
|
|
|
|
|
4349 |
|
4350 |
foreach ( $table_prefixes as $blog_id => $table_prefix ) {
|
4351 |
-
$
|
4352 |
-
|
4353 |
-
$
|
4354 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4355 |
}
|
4356 |
|
4357 |
$attachment_counts = array(
|
4358 |
-
'total'
|
4359 |
-
'
|
4360 |
-
'
|
|
|
|
|
|
|
4361 |
);
|
4362 |
|
4363 |
set_site_transient( 'as3cf_attachment_counts', $attachment_counts, 2 * MINUTE_IN_SECONDS );
|
@@ -4615,42 +4713,39 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
4615 |
}
|
4616 |
|
4617 |
/**
|
4618 |
-
* Return a formatted
|
4619 |
*
|
4620 |
-
* @param int
|
4621 |
-
* @param array|null $provider_object
|
4622 |
*
|
4623 |
-
* @return array
|
4624 |
*/
|
4625 |
-
public function get_formatted_provider_info( $id
|
4626 |
-
|
4627 |
-
|
4628 |
-
|
4629 |
-
|
4630 |
}
|
4631 |
|
4632 |
-
$provider_object
|
|
|
|
|
|
|
|
|
4633 |
|
4634 |
-
$acl = (
|
4635 |
$acl_info = array(
|
4636 |
'acl' => $acl,
|
4637 |
'name' => $this->get_acl_display_name( $acl ),
|
4638 |
'title' => $this->get_media_action_strings( 'change_to_private' ),
|
4639 |
);
|
4640 |
|
4641 |
-
if ( $
|
4642 |
$acl_info['title'] = $this->get_media_action_strings( 'change_to_public' );
|
4643 |
}
|
4644 |
|
4645 |
-
$provider_object['acl']
|
4646 |
-
|
4647 |
-
|
4648 |
-
$provider_object['region'] = $this->get_provider()->get_region_name( $provider_object['region'] );
|
4649 |
-
}
|
4650 |
-
|
4651 |
-
if ( ! empty( $provider_object['provider'] ) ) {
|
4652 |
-
$provider_object['provider_name'] = $this->get_provider_service_name( $provider_object['provider'] );
|
4653 |
-
}
|
4654 |
|
4655 |
return $provider_object;
|
4656 |
}
|
@@ -4764,19 +4859,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
4764 |
return reset( $parts );
|
4765 |
}
|
4766 |
|
4767 |
-
/**
|
4768 |
-
* Normalize object prefix.
|
4769 |
-
*
|
4770 |
-
* @param string $prefix
|
4771 |
-
*
|
4772 |
-
* @return string
|
4773 |
-
*/
|
4774 |
-
protected function normalize_object_prefix( $prefix ) {
|
4775 |
-
$directory = dirname( $prefix );
|
4776 |
-
|
4777 |
-
return ( '.' === $directory ) ? '' : $directory . '/';
|
4778 |
-
}
|
4779 |
-
|
4780 |
/**
|
4781 |
* Has the given attachment been uploaded by this instance?
|
4782 |
*
|
@@ -4839,14 +4921,10 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
4839 |
* @return string
|
4840 |
*/
|
4841 |
public function get_acl_for_intermediate_size( $attachment_id, $size ) {
|
4842 |
-
$
|
4843 |
-
|
4844 |
-
if ( 'original' === $size || empty( $size ) ) {
|
4845 |
-
return isset( $provider_info['acl'] ) ? $provider_info['acl'] : $this->get_provider()->get_default_acl();
|
4846 |
-
}
|
4847 |
|
4848 |
-
if ( ! empty( $
|
4849 |
-
return $
|
4850 |
}
|
4851 |
|
4852 |
return $this->get_provider()->get_default_acl();
|
1 |
<?php
|
2 |
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
4 |
use DeliciousBrains\WP_Offload_Media\Providers\AWS_Provider;
|
5 |
use DeliciousBrains\WP_Offload_Media\Providers\DigitalOcean_Provider;
|
6 |
use DeliciousBrains\WP_Offload_Media\Providers\GCP_Provider;
|
10 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_EDD_Replace_URLs;
|
11 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_File_Sizes;
|
12 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Filter_Post_Excerpt;
|
13 |
+
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Items_Table;
|
14 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Meta_WP_Error;
|
15 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Region_Meta;
|
16 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_WPOS3_To_AS3CF;
|
109 |
'WPOS3_SETTINGS',
|
110 |
);
|
111 |
|
112 |
+
const LATEST_UPGRADE_ROUTINE = 8;
|
113 |
|
114 |
/**
|
115 |
* @param string $plugin_file_path
|
144 |
GCP_Provider::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\GCP_Provider',
|
145 |
);
|
146 |
|
147 |
+
Media_Library_Item::init_cache();
|
148 |
+
|
149 |
$this->set_provider();
|
150 |
|
151 |
// Bundled SDK may require AWS setup before data migrations.
|
158 |
new Upgrade_EDD_Replace_URLs( $this );
|
159 |
new Upgrade_Filter_Post_Excerpt( $this );
|
160 |
new Upgrade_WPOS3_To_AS3CF( $this );
|
161 |
+
new Upgrade_Items_Table( $this );
|
162 |
|
163 |
// Plugin setup
|
164 |
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
311 |
return apply_filters( 'as3cf_settings_menu_title', $this->plugin_menu_title );
|
312 |
}
|
313 |
|
314 |
+
/**
|
315 |
+
* Get the plugin prefix.
|
316 |
+
*
|
317 |
+
* @return string
|
318 |
+
*/
|
319 |
+
public function get_plugin_prefix() {
|
320 |
+
return $this->plugin_prefix;
|
321 |
+
}
|
322 |
+
|
323 |
/**
|
324 |
* Get the plugin prefix in slug format, ie. replace underscores with hyphens
|
325 |
*
|
326 |
* @return string
|
327 |
*/
|
328 |
+
public function get_plugin_prefix_slug() {
|
329 |
+
return str_replace( '_', '-', $this->get_plugin_prefix() );
|
330 |
}
|
331 |
|
332 |
/**
|
352 |
'key' => $key,
|
353 |
'disabled' => false,
|
354 |
'disabled_attr' => '',
|
355 |
+
'tr_class' => str_replace( '_', '-', $this->get_plugin_prefix() . '-' . $key . '-container' ),
|
356 |
'setting_msg' => '',
|
357 |
'is_defined' => false,
|
358 |
);
|
973 |
/**
|
974 |
* Removes an attachment's files from provider.
|
975 |
*
|
976 |
+
* @param int $post_id
|
977 |
+
* @param Media_Library_Item $as3cf_item
|
978 |
+
* @param bool $include_backups remove previous edited image versions
|
979 |
+
* @param bool $log_error
|
980 |
+
* @param bool $return_on_error
|
981 |
+
* @param bool $force_new_provider_client if we are deleting in bulk, force new provider client
|
982 |
+
* to cope with possible different regions
|
983 |
+
*/
|
984 |
+
function remove_attachment_files_from_provider( $post_id, Media_Library_Item $as3cf_item, $include_backups = true, $log_error = false, $return_on_error = false, $force_new_provider_client = false ) {
|
985 |
+
$prefix = $as3cf_item->normalized_path_dir();
|
986 |
+
$paths = AS3CF_Utils::get_attachment_file_paths( $post_id, false, false, $include_backups );
|
987 |
+
$paths = apply_filters( 'as3cf_remove_attachment_paths', $paths, $post_id, $as3cf_item, $include_backups );
|
|
|
|
|
988 |
|
989 |
+
// If another item in current site shares full size *local* paths, only remove remote files not referenced by duplicates.
|
990 |
+
// We reference local paths as they should be reflected one way or another remotely, including backups.
|
991 |
+
$fullsize_paths = AS3CF_Utils::fullsize_paths( $paths );
|
992 |
+
$as3cf_items_with_paths = Media_Library_Item::get_by_source_path( $fullsize_paths, array( $post_id ), false );
|
993 |
+
|
994 |
+
$duplicate_paths = array();
|
995 |
+
|
996 |
+
foreach ( $as3cf_items_with_paths as $as3cf_item_with_path ) {
|
997 |
+
/* @var Media_Library_Item $as3cf_item_with_path */
|
998 |
+
$duplicate_paths += array_values( AS3CF_Utils::get_attachment_file_paths( $as3cf_item_with_path->source_id(), false, false, $include_backups ) );
|
999 |
+
}
|
1000 |
+
|
1001 |
+
if ( ! empty( $duplicate_paths ) ) {
|
1002 |
+
$paths = array_diff( $paths, $duplicate_paths );
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
// Nothing to do, shortcut out.
|
1006 |
+
if ( empty( $paths ) ) {
|
1007 |
+
return;
|
1008 |
}
|
1009 |
|
1010 |
$objects_to_remove = array();
|
1016 |
}
|
1017 |
|
1018 |
// finally delete the objects from provider
|
1019 |
+
$this->delete_objects( $as3cf_item->region(), $as3cf_item->bucket(), $objects_to_remove, $log_error, $return_on_error, $force_new_provider_client );
|
1020 |
}
|
1021 |
|
1022 |
/**
|
1031 |
return;
|
1032 |
}
|
1033 |
|
1034 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
1035 |
+
|
1036 |
+
if ( ! $as3cf_item ) {
|
1037 |
return;
|
1038 |
}
|
1039 |
|
1041 |
return;
|
1042 |
}
|
1043 |
|
1044 |
+
$this->remove_attachment_files_from_provider( $post_id, $as3cf_item, true, true, true, $force_new_provider_client );
|
1045 |
|
1046 |
+
$as3cf_item->delete();
|
1047 |
}
|
1048 |
|
1049 |
/**
|
1061 |
return $data;
|
1062 |
}
|
1063 |
|
1064 |
+
// Protect against updates of partially formed metadata.
|
1065 |
+
if ( wp_attachment_is_image( $post_id ) && empty( $data['sizes'] ) ) {
|
1066 |
+
return $data;
|
1067 |
+
}
|
1068 |
+
|
1069 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
1070 |
+
|
1071 |
+
if ( ! $as3cf_item && ! $this->get_setting( 'copy-to-s3' ) ) {
|
1072 |
// abort if not already uploaded to provider and the copy setting is off
|
1073 |
return $data;
|
1074 |
}
|
1075 |
|
1076 |
+
if ( empty( $as3cf_item ) ) {
|
1077 |
+
$as3cf_item = null;
|
1078 |
+
}
|
1079 |
+
|
1080 |
// allow provider upload to be cancelled for any reason
|
1081 |
+
$pre = apply_filters( 'as3cf_pre_update_attachment_metadata', false, $data, $post_id, $as3cf_item );
|
1082 |
if ( false !== $pre ) {
|
1083 |
return $data;
|
1084 |
}
|
1085 |
|
1086 |
// upload attachment to provider
|
1087 |
+
$attachment_metadata = $this->upload_attachment( $post_id, $data );
|
1088 |
|
1089 |
+
if ( is_wp_error( $attachment_metadata ) ) {
|
1090 |
return $data;
|
1091 |
}
|
1092 |
|
1093 |
+
return $attachment_metadata;
|
1094 |
}
|
1095 |
|
1096 |
/**
|
1103 |
* to cope with possible different regions
|
1104 |
* @param bool $remove_local_files
|
1105 |
*
|
1106 |
+
* @return array|Media_Library_Item|WP_Error
|
1107 |
* @throws Exception
|
1108 |
*/
|
1109 |
public function upload_attachment( $post_id, $data = null, $file_path = null, $force_new_provider_client = false, $remove_local_files = true ) {
|
1110 |
+
static $offloaded = array();
|
1111 |
+
|
1112 |
$return_metadata = null;
|
1113 |
if ( is_null( $data ) ) {
|
1114 |
$data = wp_get_attachment_metadata( $post_id, true );
|
1136 |
$file_path = get_attached_file( $post_id, true );
|
1137 |
}
|
1138 |
|
1139 |
+
// Check for valid "full" file path before attempting upload
|
1140 |
+
if ( empty( $file_path ) ) {
|
1141 |
+
$error_msg = sprintf( __( 'Media Library item with ID %d does not have a valid file path', 'amazon-s3-and-cloudfront' ), $post_id );
|
1142 |
|
1143 |
return $this->return_upload_error( $error_msg, $return_metadata );
|
1144 |
}
|
1145 |
|
1146 |
+
$offload_full = true;
|
1147 |
+
$old_item = Media_Library_Item::get_by_source_id( $post_id );
|
1148 |
+
|
1149 |
+
// If item not already offloaded, is it a duplicate?
|
1150 |
+
$duplicate = false;
|
1151 |
+
if ( empty( $old_item ) ) {
|
1152 |
+
$old_items = Media_Library_Item::get_by_source_path( $file_path, $post_id, true, true );
|
1153 |
+
|
1154 |
+
if ( ! empty( $old_items[0] ) ) {
|
1155 |
+
$duplicate = true;
|
1156 |
+
|
1157 |
+
/** @var Media_Library_Item $duplicate_item */
|
1158 |
+
$duplicate_item = $old_items[0];
|
1159 |
+
|
1160 |
+
$old_item = new Media_Library_Item(
|
1161 |
+
$duplicate_item->provider(),
|
1162 |
+
$duplicate_item->region(),
|
1163 |
+
$duplicate_item->bucket(),
|
1164 |
+
$duplicate_item->path(),
|
1165 |
+
$duplicate_item->is_private(),
|
1166 |
+
$post_id,
|
1167 |
+
$duplicate_item->source_path(),
|
1168 |
+
wp_basename( $duplicate_item->original_source_path() ),
|
1169 |
+
$duplicate_item->private_sizes()
|
1170 |
+
);
|
1171 |
+
|
1172 |
+
$old_item->save();
|
1173 |
+
|
1174 |
+
// If original offloaded in same process, skip offloading anything it's already processed.
|
1175 |
+
// Otherwise, do not need to offload full file if duplicate and file missing.
|
1176 |
+
if ( ! empty( $offloaded[ $duplicate_item->id() ] ) ) {
|
1177 |
+
$offloaded[ $old_item->id() ] = $offloaded[ $duplicate_item->id() ];
|
1178 |
+
} elseif ( ! file_exists( $file_path ) ) {
|
1179 |
+
$offload_full = false;
|
1180 |
+
}
|
1181 |
+
|
1182 |
+
unset( $old_items, $duplicate_item );
|
1183 |
+
}
|
1184 |
+
}
|
1185 |
+
|
1186 |
+
// If not already offloaded in request, check full file exists locally before attempting offload.
|
1187 |
+
if ( $offload_full ) {
|
1188 |
+
if ( $old_item && ! empty( $offloaded[ $old_item->id() ][ $file_path ] ) ) {
|
1189 |
+
$offload_full = false;
|
1190 |
+
} elseif ( ! file_exists( $file_path ) ) {
|
1191 |
+
$error_msg = sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $file_path );
|
1192 |
+
|
1193 |
+
return $this->return_upload_error( $error_msg, $return_metadata );
|
1194 |
+
}
|
1195 |
+
}
|
1196 |
+
|
1197 |
+
$file_paths = AS3CF_Utils::get_attachment_file_paths( $post_id, false, $data );
|
1198 |
+
$file_paths = array_diff( $file_paths, array( $file_path ) );
|
1199 |
+
|
1200 |
+
// Are there any files not already offloaded if full already offloaded in this request?
|
1201 |
+
if ( false === $offload_full ) {
|
1202 |
+
if ( empty( $file_paths ) ) {
|
1203 |
+
return $return_metadata;
|
1204 |
+
}
|
1205 |
+
|
1206 |
+
$offloaded_file_paths = empty( $offloaded[ $old_item->id() ] ) ? array() : $offloaded[ $old_item->id() ];
|
1207 |
+
unset( $offloaded_file_paths[ $file_path ] );
|
1208 |
+
|
1209 |
+
if ( ! empty( $offloaded_file_paths ) && empty( array_diff( $file_paths, array_keys( $offloaded_file_paths ) ) ) ) {
|
1210 |
+
return $return_metadata;
|
1211 |
+
}
|
1212 |
+
}
|
1213 |
+
|
1214 |
// Get original file's stats.
|
|
|
1215 |
$file_name = wp_basename( $file_path );
|
1216 |
$type = get_post_mime_type( $post_id );
|
1217 |
$allowed_types = $this->get_allowed_mime_types();
|
1226 |
$acl = $this->get_provider()->get_default_acl();
|
1227 |
|
1228 |
// check the attachment already exists in provider, eg. edit or restore image
|
1229 |
+
if ( $old_item ) {
|
1230 |
// Must be offloaded to same provider as currently configured.
|
1231 |
if ( ! $this->is_attachment_served_by_provider( $post_id, true ) ) {
|
1232 |
return $this->return_upload_error( __( 'Already offloaded to a different provider', 'amazon-s3-and-cloudfront' ), $return_metadata );
|
1233 |
}
|
1234 |
|
1235 |
+
// Use private ACL if existing offload is already private.
|
1236 |
+
if ( $old_item->is_private() ) {
|
1237 |
+
$acl = $this->get_provider()->get_private_acl();
|
1238 |
}
|
1239 |
|
1240 |
// use existing prefix
|
1241 |
+
$prefix = $old_item->normalized_path_dir();
|
1242 |
// use existing bucket
|
1243 |
+
$bucket = $old_item->bucket();
|
1244 |
// get existing region
|
1245 |
+
$region = $old_item->region();
|
1246 |
+
// Get existing original filename.
|
1247 |
+
$original_filename = wp_basename( $old_item->original_source_path() );
|
1248 |
} else {
|
1249 |
// derive prefix from various settings
|
1250 |
$time = $this->get_attachment_folder_year_month( $post_id, $data );
|
1256 |
if ( is_wp_error( $region ) ) {
|
1257 |
$region = '';
|
1258 |
}
|
1259 |
+
|
1260 |
+
// There may be an original image that can override the default original filename.
|
1261 |
+
$original_filename = empty( $data['original_image'] ) ? null : $data['original_image'];
|
1262 |
}
|
1263 |
|
1264 |
$acl = apply_filters( 'wps3_upload_acl', $acl, $type, $data, $post_id, $this ); // Old naming convention, will be deprecated soon
|
1283 |
$args['ContentEncoding'] = 'gzip';
|
1284 |
}
|
1285 |
|
1286 |
+
$image_size = wp_attachment_is_image( $post_id ) ? 'full' : '';
|
1287 |
+
$args = apply_filters( 'as3cf_object_meta', $args, $post_id, $image_size, false );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1288 |
|
1289 |
+
$provider = $this->get_provider()->get_provider_key_name();
|
1290 |
+
$region = $bucket !== $args['Bucket'] ? $this->get_bucket_region( $args['Bucket'], true ) : $region;
|
1291 |
+
$is_private = $this->get_provider()->get_private_acl() === $args['ACL'] ? true : false;
|
1292 |
+
$private_sizes = empty( $old_item ) ? array() : $old_item->private_sizes();
|
1293 |
+
$item_id = empty( $old_item ) ? null : $old_item->id();
|
1294 |
+
|
1295 |
+
$as3cf_item = new Media_Library_Item( $provider, $region, $args['Bucket'], $args['Key'], $is_private, $post_id, $file_path, $original_filename, $private_sizes, $item_id );
|
1296 |
|
1297 |
+
do_action( 'as3cf_upload_attachment_pre_remove', $post_id, $as3cf_item, $prefix, $args );
|
1298 |
|
1299 |
+
$new_offloads = array();
|
1300 |
$files_to_remove = array();
|
1301 |
|
1302 |
+
$provider_client = $this->get_provider_client( $as3cf_item->region(), $force_new_provider_client );
|
1303 |
|
1304 |
+
if ( $offload_full ) {
|
1305 |
+
try {
|
1306 |
+
// May raise exception, so don't offload anything else if there's an error.
|
1307 |
+
$filesize = (int) filesize( $file_path );
|
|
|
1308 |
|
1309 |
+
// May raise exception, so don't offload anything else if there's an error.
|
1310 |
+
$provider_client->upload_object( $args );
|
1311 |
|
1312 |
+
$new_offloads[ $file_path ] = $filesize; // Note: pre `as3cf_object_meta` filter value.
|
1313 |
+
$files_to_remove[] = $file_path; // Note: pre `as3cf_object_meta` filter value.
|
1314 |
+
} catch ( Exception $e ) {
|
1315 |
+
$error_msg = sprintf( __( 'Error offloading %s to provider: %s', 'amazon-s3-and-cloudfront' ), $file_path, $e->getMessage() );
|
1316 |
|
1317 |
+
return $this->return_upload_error( $error_msg, $return_metadata );
|
1318 |
+
}
|
1319 |
+
}
|
1320 |
|
1321 |
+
$additional_images = array();
|
1322 |
+
$private_sizes = array(); // Reset private sizes to be as expected at time of (re)upload.
|
|
|
1323 |
|
1324 |
foreach ( $file_paths as $size => $file_path ) {
|
1325 |
if ( ! in_array( $file_path, $files_to_remove ) ) {
|
1332 |
'ContentType' => $this->get_mime_type( $file_path ),
|
1333 |
);
|
1334 |
|
1335 |
+
if ( $this->get_provider()->get_private_acl() === $acl ) {
|
1336 |
+
$private_sizes[] = $size;
|
1337 |
}
|
1338 |
}
|
1339 |
}
|
1341 |
$upload_errors = array();
|
1342 |
|
1343 |
foreach ( $additional_images as $size => $image ) {
|
1344 |
+
// If this file has already been offloaded during this request, skip actual offload.
|
1345 |
+
if ( $old_item && ! empty( $offloaded[ $old_item->id() ][ $image['SourceFile'] ] ) ) {
|
1346 |
+
continue;
|
1347 |
+
}
|
1348 |
+
|
1349 |
$args = apply_filters( 'as3cf_object_meta', array_merge( $args, $image ), $post_id, $size, false );
|
1350 |
|
1351 |
if ( ! file_exists( $args['SourceFile'] ) ) {
|
1352 |
+
if ( ! $duplicate ) {
|
1353 |
+
$upload_errors[] = $this->return_upload_error( sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $args['SourceFile'] ) );
|
1354 |
+
}
|
1355 |
continue;
|
1356 |
}
|
1357 |
|
1358 |
try {
|
1359 |
+
// May raise exception, but for sizes we'll just log it and maybe try again later if called.
|
1360 |
$provider_client->upload_object( $args );
|
1361 |
+
$files_to_remove[] = $image['SourceFile']; // Note: pre `as3cf_object_meta` filter value.
|
1362 |
+
|
1363 |
+
// May raise exception, we'll log that, and carry on anyway.
|
1364 |
+
$new_offloads[ $image['SourceFile'] ] = (int) filesize( $image['SourceFile'] ); // Note: pre `as3cf_object_meta` filter value.
|
1365 |
} catch ( Exception $e ) {
|
1366 |
$upload_errors[] = $this->return_upload_error( sprintf( __( 'Error offloading %s to provider: %s', 'amazon-s3-and-cloudfront' ), $args['SourceFile'], $e->getMessage() ) );
|
1367 |
}
|
1368 |
+
|
1369 |
+
// Edge Case: If previously uploaded and a different original_image wasn't picked up but is now, record it.
|
1370 |
+
// This is most likely to happen if older version of plugin was used with WP5.3 and large or rotated image auto-created.
|
1371 |
+
if ( 'original_image' === $size && wp_basename( $as3cf_item->original_source_path() ) !== wp_basename( $image['SourceFile'] ) ) {
|
1372 |
+
$as3cf_item = new Media_Library_Item(
|
1373 |
+
$as3cf_item->provider(),
|
1374 |
+
$as3cf_item->region(),
|
1375 |
+
$as3cf_item->bucket(),
|
1376 |
+
$as3cf_item->path(),
|
1377 |
+
$as3cf_item->is_private(),
|
1378 |
+
$as3cf_item->source_id(),
|
1379 |
+
$as3cf_item->source_path(),
|
1380 |
+
wp_basename( $image['SourceFile'] ),
|
1381 |
+
$as3cf_item->private_sizes(),
|
1382 |
+
$as3cf_item->id()
|
1383 |
+
);
|
1384 |
+
}
|
1385 |
}
|
1386 |
|
1387 |
$remove_local_files_setting = $this->get_setting( 'remove-local-file' );
|
1388 |
|
1389 |
+
if ( $remove_local_files && $remove_local_files_setting ) {
|
1390 |
+
// Allow other functions to remove files after they have processed
|
1391 |
+
$files_to_remove = apply_filters( 'as3cf_upload_attachment_local_files_to_remove', $files_to_remove, $post_id, $file_path );
|
|
|
1392 |
|
1393 |
+
// Remove duplicates
|
1394 |
+
$files_to_remove = array_unique( $files_to_remove );
|
1395 |
|
1396 |
+
$filesize_total = 0;
|
1397 |
+
if ( ! empty( $old_item ) && ! empty( $offloaded[ $old_item->id() ] ) ) {
|
1398 |
+
$filesize_total = array_sum( $offloaded[ $old_item->id() ] );
|
1399 |
+
}
|
1400 |
+
// Delete the files and record original file's size before removal.
|
1401 |
+
$this->remove_local_files( $files_to_remove, $post_id, $filesize_total );
|
1402 |
|
1403 |
+
// Store filesize in the attachment meta data for use by WP if we've just offloaded the full size file.
|
1404 |
+
if ( ! empty( $filesize ) ) {
|
1405 |
+
$data['filesize'] = $filesize;
|
1406 |
|
1407 |
+
if ( is_null( $return_metadata ) ) {
|
1408 |
+
// Update metadata with filesize
|
1409 |
+
update_post_meta( $post_id, '_wp_attachment_metadata', $data );
|
|
|
1410 |
}
|
1411 |
}
|
1412 |
}
|
1416 |
$data = $this->maybe_cleanup_filesize_metadata( $post_id, $data, empty( $return_metadata ) );
|
1417 |
}
|
1418 |
|
1419 |
+
// Additional image sizes have custom ACLs, record them.
|
1420 |
+
if ( ! empty( $private_sizes ) ) {
|
1421 |
+
$as3cf_item = new Media_Library_Item(
|
1422 |
+
$as3cf_item->provider(),
|
1423 |
+
$as3cf_item->region(),
|
1424 |
+
$as3cf_item->bucket(),
|
1425 |
+
$as3cf_item->path(),
|
1426 |
+
$as3cf_item->is_private(),
|
1427 |
+
$as3cf_item->source_id(),
|
1428 |
+
$as3cf_item->source_path(),
|
1429 |
+
wp_basename( $as3cf_item->original_source_path() ),
|
1430 |
+
$private_sizes,
|
1431 |
+
$as3cf_item->id()
|
1432 |
+
);
|
1433 |
+
}
|
1434 |
+
|
1435 |
+
// All done, save record of offloaded item.
|
1436 |
+
$as3cf_item->save();
|
1437 |
+
|
1438 |
+
// Keep track of individual files offloaded during this request.
|
1439 |
+
if ( empty( $offloaded[ $as3cf_item->id() ] ) ) {
|
1440 |
+
$offloaded[ $as3cf_item->id() ] = $new_offloads;
|
1441 |
+
} else {
|
1442 |
+
$offloaded[ $as3cf_item->id() ] += $new_offloads;
|
1443 |
}
|
1444 |
|
1445 |
// Keep track of attachments uploaded by this instance.
|
1446 |
$this->uploaded_post_ids[] = $post_id;
|
1447 |
|
1448 |
+
do_action( 'as3cf_post_upload_attachment', $post_id, $as3cf_item );
|
1449 |
|
1450 |
if ( $upload_errors ) {
|
1451 |
return $this->consolidate_upload_errors( $upload_errors );
|
1456 |
return $data;
|
1457 |
}
|
1458 |
|
1459 |
+
return $as3cf_item;
|
1460 |
}
|
1461 |
|
1462 |
/**
|
1539 |
/**
|
1540 |
* Remove files from the local site, recording total filesize in meta if attachment ID given.
|
1541 |
*
|
1542 |
+
* @param array $file_paths Files to remove.
|
1543 |
+
* @param int $attachment_id Optional, if supplied filesize metadata recorded.
|
1544 |
+
* @param int $filesize_total Optional, if removing partial set of an attachment's files, pass in previously removed total.
|
1545 |
*/
|
1546 |
+
function remove_local_files( $file_paths, $attachment_id = 0, $filesize_total = 0 ) {
|
1547 |
+
if ( empty( $filesize_total ) ) {
|
1548 |
+
$filesize_total = 0;
|
1549 |
+
}
|
1550 |
|
1551 |
foreach ( $file_paths as $index => $path ) {
|
1552 |
if ( ! empty( $attachment_id ) && is_int( $attachment_id ) ) {
|
1574 |
}
|
1575 |
|
1576 |
// If we were able to sum up file sizes for an attachment, record it.
|
1577 |
+
if ( ! empty( $attachment_id ) && is_int( $attachment_id ) && $filesize_total > 0 ) {
|
1578 |
update_post_meta( $attachment_id, 'as3cf_filesize_total', $filesize_total );
|
1579 |
}
|
1580 |
}
|
1695 |
* @return string
|
1696 |
*/
|
1697 |
public function filter_unique_filename( $filename, $ext, $dir, $post_id = null ) {
|
1698 |
+
if ( ! $this->is_plugin_setup( true ) ) {
|
1699 |
return $filename;
|
1700 |
}
|
1701 |
|
1788 |
}
|
1789 |
$file = $path . $filename;
|
1790 |
|
1791 |
+
// WordPress doesn't check its own basic record, so we will.
|
1792 |
$sql = $wpdb->prepare( "
|
1793 |
SELECT COUNT(*)
|
1794 |
FROM $wpdb->postmeta
|
1796 |
AND meta_value = %s
|
1797 |
", '_wp_attached_file', $file );
|
1798 |
|
1799 |
+
if ( (bool) $wpdb->get_var( $sql ) ) {
|
1800 |
+
return true;
|
1801 |
+
}
|
1802 |
+
|
1803 |
+
// Check our records of local source path as it also covers original_image.
|
1804 |
+
if ( ! empty( Media_Library_Item::get_by_source_path( array( $file ), array(), true, true ) ) ) {
|
1805 |
+
return true;
|
1806 |
+
}
|
1807 |
+
|
1808 |
+
return false;
|
1809 |
}
|
1810 |
|
1811 |
/**
|
1843 |
*/
|
1844 |
function generate_unique_filename( $name, $ext, $time ) {
|
1845 |
$count = 1;
|
1846 |
+
$filename = $name . '-' . $count . $ext;
|
1847 |
|
1848 |
while ( $this->does_file_exist( $filename, $time ) ) {
|
1849 |
$count++;
|
1850 |
+
$filename = $name . '-' . $count . $ext;
|
1851 |
}
|
1852 |
|
1853 |
return $filename;
|
1854 |
}
|
1855 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1856 |
/**
|
1857 |
* Check the plugin is correctly setup
|
1858 |
*
|
1859 |
* @param bool $with_credentials Do provider credentials need to be set up too? Defaults to false.
|
1860 |
*
|
1861 |
* @return bool
|
1862 |
+
*
|
1863 |
+
* TODO: Performance - cache / static var by param.
|
1864 |
*/
|
1865 |
function is_plugin_setup( $with_credentials = false ) {
|
1866 |
if ( $with_credentials && $this->get_provider()->needs_access_keys() ) {
|
1990 |
* @return bool|mixed|WP_Error
|
1991 |
*/
|
1992 |
public function get_attachment_url( $post_id, $expires = null, $size = null, $meta = null, $headers = array(), $skip_rewrite_check = false ) {
|
1993 |
+
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $post_id, $skip_rewrite_check ) ) ) {
|
1994 |
return false;
|
1995 |
}
|
1996 |
|
1997 |
+
$url = $this->get_attachment_provider_url( $post_id, $as3cf_item, $expires, $size, $meta, $headers );
|
1998 |
|
1999 |
return apply_filters( 'as3cf_wp_get_attachment_url', $url, $post_id );
|
2000 |
}
|
2067 |
/**
|
2068 |
* Get the provider URL for an attachment
|
2069 |
*
|
2070 |
+
* @param int $post_id
|
2071 |
+
* @param Media_Library_Item $as3cf_item
|
2072 |
+
* @param null|int $expires
|
2073 |
+
* @param null|string|array $size
|
2074 |
+
* @param null|array $meta
|
2075 |
+
* @param array $headers
|
2076 |
*
|
2077 |
+
* @return string|WP_Error
|
2078 |
*/
|
2079 |
+
public function get_attachment_provider_url( $post_id, Media_Library_Item $as3cf_item, $expires = null, $size = null, $meta = null, $headers = array() ) {
|
2080 |
+
$item_path = $as3cf_item->path();
|
2081 |
+
|
2082 |
+
if ( ! empty( $as3cf_item->region() ) && ( $this->get_provider()->region_required() || $this->get_provider()->get_default_region() !== $as3cf_item->region() ) ) {
|
2083 |
+
$region = $this->get_provider()->sanitize_region( $as3cf_item->region() );
|
2084 |
} else {
|
2085 |
$region = '';
|
2086 |
}
|
2089 |
|
2090 |
// Force use of secured URL when ACL has been set to private
|
2091 |
if ( is_null( $expires ) ) {
|
2092 |
+
if ( is_null( $size ) && $as3cf_item->is_private() ) {
|
2093 |
// Full size URL private
|
2094 |
$expires = self::DEFAULT_EXPIRES;
|
2095 |
}
|
2096 |
|
2097 |
+
if ( ! is_null( $size ) && $as3cf_item->is_private_size( $size ) ) {
|
2098 |
// Alternative size URL private
|
2099 |
$expires = self::DEFAULT_EXPIRES;
|
2100 |
}
|
2110 |
}
|
2111 |
|
2112 |
if ( ! empty( $meta ) && isset( $meta['sizes'][ $size ]['file'] ) ) {
|
2113 |
+
$size_prefix = dirname( $item_path );
|
2114 |
$size_file_prefix = ( '.' === $size_prefix ) ? '' : $size_prefix . '/';
|
2115 |
|
2116 |
+
$item_path = $size_file_prefix . $meta['sizes'][ $size ]['file'];
|
2117 |
}
|
2118 |
}
|
2119 |
|
2120 |
$scheme = $this->get_url_scheme();
|
2121 |
+
$domain = $this->get_provider()->get_url_domain( $as3cf_item->bucket(), $region, $expires );
|
2122 |
$base_url = $scheme . '://' . $domain;
|
2123 |
|
2124 |
if ( ! is_null( $expires ) && $this->is_plugin_setup( true ) ) {
|
2129 |
|
2130 |
$expires = time() + apply_filters( 'as3cf_expires', $expires );
|
2131 |
$secure_url = $this->get_provider_client( $region )
|
2132 |
+
->get_object_url( $as3cf_item->bucket(), $item_path, $expires, $headers );
|
2133 |
|
2134 |
+
return apply_filters( 'as3cf_get_attachment_secure_url', $secure_url, $as3cf_item, $post_id, $expires, $headers );
|
2135 |
} catch ( Exception $e ) {
|
2136 |
return new WP_Error( 'exception', $e->getMessage() );
|
2137 |
}
|
2138 |
}
|
2139 |
|
2140 |
+
$item_path = $this->maybe_update_cloudfront_path( $item_path );
|
2141 |
|
2142 |
+
$file = $this->encode_filename_in_path( $item_path );
|
2143 |
$url = $base_url . '/' . $file;
|
2144 |
|
2145 |
+
return apply_filters( 'as3cf_get_attachment_url', $url, $as3cf_item, $post_id, $expires, $headers );
|
2146 |
}
|
2147 |
|
2148 |
/**
|
2154 |
* @return bool|mixed|WP_Error
|
2155 |
*/
|
2156 |
public function wp_get_attachment_url( $url, $post_id ) {
|
2157 |
+
if ( $this->plugin_compat->is_customizer_crop_action() ) {
|
2158 |
+
return $url;
|
2159 |
+
}
|
2160 |
+
|
2161 |
$new_url = $this->get_attachment_url( $post_id );
|
2162 |
|
2163 |
if ( false === $new_url ) {
|
2183 |
* @return string
|
2184 |
*/
|
2185 |
public function maybe_encode_get_image_tag( $html, $id, $alt, $title, $align, $size ) {
|
2186 |
+
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $id ) ) ) {
|
2187 |
// Not served by provider, return
|
2188 |
return $html;
|
2189 |
}
|
2200 |
}
|
2201 |
|
2202 |
$img_src = $matches[1];
|
2203 |
+
$new_img_src = $this->maybe_sign_intermediate_size( $img_src, $id, $size, $as3cf_item );
|
2204 |
$new_img_src = $this->encode_filename_in_path( $new_img_src );
|
2205 |
|
2206 |
return str_replace( $img_src, $new_img_src, $html );
|
2217 |
* @return array
|
2218 |
*/
|
2219 |
public function maybe_encode_wp_get_attachment_image_src( $image, $attachment_id, $size, $icon ) {
|
2220 |
+
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $attachment_id ) ) ) {
|
2221 |
// Not served by provider, return
|
2222 |
return $image;
|
2223 |
}
|
2224 |
|
2225 |
if ( isset( $image[0] ) ) {
|
2226 |
+
$url = $this->maybe_sign_intermediate_size( $image[0], $attachment_id, $size, $as3cf_item );
|
2227 |
$url = $this->encode_filename_in_path( $url );
|
2228 |
|
2229 |
$image[0] = $url;
|
2242 |
* @return array
|
2243 |
*/
|
2244 |
public function maybe_encode_wp_prepare_attachment_for_js( $response, $attachment, $meta ) {
|
2245 |
+
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $attachment->ID ) ) ) {
|
2246 |
// Not served by provider, return
|
2247 |
return $response;
|
2248 |
}
|
2253 |
|
2254 |
if ( isset( $response['sizes'] ) && is_array( $response['sizes'] ) ) {
|
2255 |
foreach ( $response['sizes'] as $size => $value ) {
|
2256 |
+
$url = $this->maybe_sign_intermediate_size( $value['url'], $attachment->ID, $size, $as3cf_item );
|
2257 |
$url = $this->encode_filename_in_path( $url );
|
2258 |
|
2259 |
$response['sizes'][ $size ]['url'] = $url;
|
2273 |
* @return array
|
2274 |
*/
|
2275 |
public function maybe_encode_image_get_intermediate_size( $data, $post_id, $size ) {
|
2276 |
+
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $post_id ) ) ) {
|
2277 |
// Not served by provider, return
|
2278 |
return $data;
|
2279 |
}
|
2280 |
|
2281 |
if ( isset( $data['url'] ) ) {
|
2282 |
+
$url = $this->maybe_sign_intermediate_size( $data['url'], $post_id, $size, $as3cf_item );
|
2283 |
$url = $this->encode_filename_in_path( $url );
|
2284 |
|
2285 |
$data['url'] = $url;
|
2291 |
/**
|
2292 |
* Sign intermediate size.
|
2293 |
*
|
2294 |
+
* @param string $url
|
2295 |
+
* @param int $attachment_id
|
2296 |
+
* @param string|array $size
|
2297 |
+
* @param bool|Media_Library_Item $as3cf_item
|
2298 |
*
|
2299 |
+
* @return string|WP_Error
|
2300 |
*/
|
2301 |
+
protected function maybe_sign_intermediate_size( $url, $attachment_id, $size, $as3cf_item = false ) {
|
2302 |
+
if ( ! $as3cf_item ) {
|
2303 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
2304 |
}
|
2305 |
|
2306 |
$size = $this->maybe_convert_size_to_string( $attachment_id, $size );
|
2307 |
|
2308 |
+
if ( $as3cf_item->is_private_size( $size ) ) {
|
2309 |
// Private file, add AWS signature if required
|
2310 |
+
return $this->get_attachment_provider_url( $attachment_id, $as3cf_item, null, $size );
|
2311 |
}
|
2312 |
|
2313 |
return $url;
|
2385 |
* @param bool $skip_current_provider_check Skip checking if offloaded to current provider. Default: false, negated if $provider supplied
|
2386 |
* @param Provider|null $provider Provider where attachment expected to be offloaded to. Default: currently configured provider
|
2387 |
*
|
2388 |
+
* @return bool|Media_Library_Item
|
2389 |
*/
|
2390 |
public function is_attachment_served_by_provider( $attachment_id, $skip_rewrite_check = false, $skip_current_provider_check = false, Provider $provider = null ) {
|
2391 |
if ( ! $skip_rewrite_check && ! $this->get_setting( 'serve-from-s3' ) ) {
|
2393 |
return false;
|
2394 |
}
|
2395 |
|
2396 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
2397 |
+
|
2398 |
+
if ( ! $as3cf_item ) {
|
2399 |
// File not uploaded to a provider
|
2400 |
return false;
|
2401 |
}
|
2404 |
$provider = $this->get_provider();
|
2405 |
}
|
2406 |
|
2407 |
+
if ( ! empty( $provider ) && $provider::get_provider_key_name() !== $as3cf_item->provider() ) {
|
2408 |
// File not uploaded to required provider
|
2409 |
return false;
|
2410 |
}
|
2411 |
|
2412 |
+
return $as3cf_item;
|
2413 |
}
|
2414 |
|
2415 |
/**
|
2450 |
return str_replace( $file_name, $encoded_file_name, $file );
|
2451 |
}
|
2452 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2453 |
/**
|
2454 |
* Allow processes to update the file on provider via update_attached_file()
|
2455 |
*
|
2463 |
return $file;
|
2464 |
}
|
2465 |
|
2466 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
2467 |
+
|
2468 |
+
if ( ! $as3cf_item ) {
|
2469 |
return $file;
|
2470 |
}
|
2471 |
|
2472 |
+
$file = apply_filters( 'as3cf_update_attached_file', $file, $attachment_id, $as3cf_item );
|
2473 |
|
2474 |
return $file;
|
2475 |
}
|
2485 |
* @return string
|
2486 |
*/
|
2487 |
function get_attached_file( $file, $attachment_id ) {
|
2488 |
+
if ( file_exists( $file ) || ! ( $as3cf_item = $this->is_attachment_served_by_provider( $attachment_id ) ) ) {
|
2489 |
return $file;
|
2490 |
}
|
2491 |
|
2492 |
$url = $this->get_attachment_url( $attachment_id );
|
2493 |
|
2494 |
// return the URL by default
|
2495 |
+
$file = apply_filters( 'as3cf_get_attached_file', $url, $file, $attachment_id, $as3cf_item );
|
2496 |
|
2497 |
return $file;
|
2498 |
}
|
2720 |
);
|
2721 |
}
|
2722 |
|
2723 |
+
/**
|
2724 |
+
* What is the default provider for legacy data?
|
2725 |
+
*
|
2726 |
+
* @return string
|
2727 |
+
*/
|
2728 |
+
public static function get_default_provider() {
|
2729 |
+
return static::$default_provider;
|
2730 |
+
}
|
2731 |
+
|
2732 |
/**
|
2733 |
* Returns the Provider's default region slug.
|
2734 |
*
|
2828 |
return $region;
|
2829 |
}
|
2830 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2831 |
/**
|
2832 |
* AJAX handler for get_buckets()
|
2833 |
*/
|
3528 |
/**
|
3529 |
* Apply ACL to an attachment and associated files
|
3530 |
*
|
3531 |
+
* @param int $post_id
|
3532 |
+
* @param Media_Library_Item $as3cf_item
|
3533 |
+
* @param bool $private
|
3534 |
*
|
3535 |
+
* @return Media_Library_Item|bool|WP_Error
|
|
|
3536 |
*/
|
3537 |
+
public function set_attachment_acl_on_provider( $post_id, Media_Library_Item $as3cf_item, $private ) {
|
3538 |
// Return early if already set to the desired ACL
|
3539 |
+
if ( $as3cf_item->is_private() === $private ) {
|
3540 |
return false;
|
3541 |
}
|
3542 |
|
3543 |
+
$acl = $private ? $this->get_provider()->get_private_acl() : $this->get_provider()->get_default_acl();
|
3544 |
+
|
3545 |
$args = array(
|
3546 |
'ACL' => $acl,
|
3547 |
+
'Bucket' => $as3cf_item->bucket(),
|
3548 |
+
'Key' => $as3cf_item->path(),
|
3549 |
);
|
3550 |
|
3551 |
+
$region = empty( $as3cf_item->region() ) ? false : $as3cf_item->region();
|
|
|
3552 |
|
3553 |
try {
|
3554 |
+
$provider_client = $this->get_provider_client( $region, true );
|
3555 |
$provider_client->update_object_acl( $args );
|
|
|
|
|
|
|
|
|
|
|
|
|
3556 |
|
3557 |
+
$as3cf_item = new Media_Library_Item(
|
3558 |
+
$as3cf_item->provider(),
|
3559 |
+
$as3cf_item->region(),
|
3560 |
+
$as3cf_item->bucket(),
|
3561 |
+
$as3cf_item->path(),
|
3562 |
+
$private,
|
3563 |
+
$as3cf_item->source_id(),
|
3564 |
+
$as3cf_item->source_path(),
|
3565 |
+
wp_basename( $as3cf_item->original_source_path() ),
|
3566 |
+
$as3cf_item->private_sizes(),
|
3567 |
+
$as3cf_item->id()
|
3568 |
+
);
|
3569 |
+
$as3cf_item->save();
|
3570 |
} catch ( Exception $e ) {
|
3571 |
+
$msg = 'Error setting ACL to ' . $acl . ' for ' . $as3cf_item->path() . ': ' . $e->getMessage();
|
3572 |
AS3CF_Error::log( $msg );
|
3573 |
|
3574 |
return new WP_Error( 'acl_exception', $msg );
|
3575 |
}
|
3576 |
|
3577 |
+
return $as3cf_item;
|
3578 |
}
|
3579 |
|
3580 |
/**
|
3581 |
* Make admin notice for when object ACL has changed
|
3582 |
*
|
3583 |
+
* @param Media_Library_Item $as3cf_item
|
3584 |
*/
|
3585 |
+
function make_acl_admin_notice( Media_Library_Item $as3cf_item ) {
|
3586 |
+
$filename = wp_basename( $as3cf_item->path() );
|
3587 |
+
$acl = $as3cf_item->is_private() ? $this->get_provider()->get_private_acl() : $this->get_provider()->get_default_acl();
|
3588 |
$acl_name = $this->get_acl_display_name( $acl );
|
3589 |
$text = sprintf( __( '<strong>WP Offload Media</strong> — The file %s has been given %s permissions in the bucket.', 'amazon-s3-and-cloudfront' ), "<strong>{$filename}</strong>", "<strong>{$acl_name}</strong>" );
|
3590 |
|
3855 |
$media_counts = $this->media_counts();
|
3856 |
|
3857 |
$output .= 'Media Files: ';
|
3858 |
+
$output .= number_format_i18n( $media_counts['total'] ) . ' (paths ' . number_format_i18n( $media_counts['total_paths'] ) . ')';
|
3859 |
$output .= "\r\n";
|
3860 |
|
3861 |
$output .= 'Offloaded Media Files: ';
|
3862 |
+
$output .= number_format_i18n( $media_counts['offloaded'] ) . ' (paths ' . number_format_i18n( $media_counts['offloaded_paths'] ) . ')';
|
3863 |
$output .= "\r\n";
|
3864 |
|
3865 |
+
$output .= 'Not Offloaded Media Files: ';
|
3866 |
+
$output .= number_format_i18n( $media_counts['not_offloaded'] ) . ' (paths ' . number_format_i18n( $media_counts['not_offloaded_paths'] ) . ')';
|
3867 |
+
$output .= "\r\n";
|
3868 |
+
$output .= 'Note: Approximate values, paths *try* and discard duplicates.';
|
3869 |
+
$output .= "\r\n\r\n";
|
3870 |
+
|
3871 |
$output .= 'Number of Image Sizes: ';
|
3872 |
$sizes = count( get_intermediate_image_sizes() );
|
3873 |
$output .= number_format_i18n( $sizes );
|
4417 |
return intval( $memory_limit ) * 1024 * 1024;
|
4418 |
}
|
4419 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4420 |
/**
|
4421 |
* Get the total attachment and total offloaded/not offloaded attachment counts
|
4422 |
*
|
4427 |
*/
|
4428 |
public function media_counts( $skip_transient = false, $force = false ) {
|
4429 |
if ( $skip_transient || false === ( $attachment_counts = get_site_transient( 'as3cf_attachment_counts' ) ) ) {
|
4430 |
+
$table_prefixes = $this->get_all_blog_table_prefixes();
|
4431 |
+
$total = 0;
|
4432 |
+
$total_paths = 0;
|
4433 |
+
$offloaded = 0;
|
4434 |
+
$offloaded_paths = 0;
|
4435 |
+
$not_offloaded = 0;
|
4436 |
+
$not_offloaded_paths = 0;
|
4437 |
|
4438 |
foreach ( $table_prefixes as $blog_id => $table_prefix ) {
|
4439 |
+
$this->switch_to_blog( $blog_id );
|
4440 |
+
|
4441 |
+
$counts = Media_Library_Item::count_attachments( $skip_transient, $force );
|
4442 |
+
$total += $counts['total'];
|
4443 |
+
$total_paths += $counts['total_paths'];
|
4444 |
+
$offloaded += $counts['offloaded'];
|
4445 |
+
$offloaded_paths += $counts['offloaded_paths'];
|
4446 |
+
$not_offloaded += $counts['not_offloaded'];
|
4447 |
+
$not_offloaded_paths += $counts['not_offloaded_paths'];
|
4448 |
+
|
4449 |
+
$this->restore_current_blog();
|
4450 |
}
|
4451 |
|
4452 |
$attachment_counts = array(
|
4453 |
+
'total' => $total,
|
4454 |
+
'total_paths' => $total_paths,
|
4455 |
+
'offloaded' => $offloaded,
|
4456 |
+
'offloaded_paths' => $offloaded_paths,
|
4457 |
+
'not_offloaded' => $not_offloaded,
|
4458 |
+
'not_offloaded_paths' => $not_offloaded_paths,
|
4459 |
);
|
4460 |
|
4461 |
set_site_transient( 'as3cf_attachment_counts', $attachment_counts, 2 * MINUTE_IN_SECONDS );
|
4713 |
}
|
4714 |
|
4715 |
/**
|
4716 |
+
* Return a formatted provider info array with display friendly defaults
|
4717 |
*
|
4718 |
+
* @param int $id
|
|
|
4719 |
*
|
4720 |
+
* @return bool|array
|
4721 |
*/
|
4722 |
+
public function get_formatted_provider_info( $id ) {
|
4723 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $id );
|
4724 |
+
|
4725 |
+
if ( ! $as3cf_item ) {
|
4726 |
+
return false;
|
4727 |
}
|
4728 |
|
4729 |
+
$provider_object = $as3cf_item->key_values();
|
4730 |
+
|
4731 |
+
// Backwards compatibility.
|
4732 |
+
$provider_object['key'] = $provider_object['path'];
|
4733 |
+
$provider_object['url'] = $this->get_attachment_provider_url( $id, $as3cf_item );
|
4734 |
|
4735 |
+
$acl = $as3cf_item->is_private() ? $this->get_provider()->get_private_acl() : $this->get_provider()->get_default_acl();
|
4736 |
$acl_info = array(
|
4737 |
'acl' => $acl,
|
4738 |
'name' => $this->get_acl_display_name( $acl ),
|
4739 |
'title' => $this->get_media_action_strings( 'change_to_private' ),
|
4740 |
);
|
4741 |
|
4742 |
+
if ( $as3cf_item->is_private() ) {
|
4743 |
$acl_info['title'] = $this->get_media_action_strings( 'change_to_public' );
|
4744 |
}
|
4745 |
|
4746 |
+
$provider_object['acl'] = $acl_info;
|
4747 |
+
$provider_object['region'] = $this->get_provider()->get_region_name( $provider_object['region'] );
|
4748 |
+
$provider_object['provider_name'] = $this->get_provider_service_name( $provider_object['provider'] );
|
|
|
|
|
|
|
|
|
|
|
|
|
4749 |
|
4750 |
return $provider_object;
|
4751 |
}
|
4859 |
return reset( $parts );
|
4860 |
}
|
4861 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4862 |
/**
|
4863 |
* Has the given attachment been uploaded by this instance?
|
4864 |
*
|
4921 |
* @return string
|
4922 |
*/
|
4923 |
public function get_acl_for_intermediate_size( $attachment_id, $size ) {
|
4924 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
|
|
|
|
|
|
|
|
4925 |
|
4926 |
+
if ( ! empty( $as3cf_item ) ) {
|
4927 |
+
return $as3cf_item->is_private_size( $size ) ? $this->get_provider()->get_private_acl() : $this->get_provider()->get_default_acl();
|
4928 |
}
|
4929 |
|
4930 |
return $this->get_provider()->get_default_acl();
|
classes/as3cf-filter.php
CHANGED
@@ -330,6 +330,11 @@ abstract class AS3CF_Filter {
|
|
330 |
$attachment_ids = array();
|
331 |
|
332 |
foreach ( $matches as $image ) {
|
|
|
|
|
|
|
|
|
|
|
333 |
if ( ! preg_match( '/src=\\\?["\']+([^"\'\\\]+)/', $image, $src ) || ! isset( $src[1] ) ) {
|
334 |
// Can't determine URL, skip
|
335 |
continue;
|
@@ -344,11 +349,6 @@ abstract class AS3CF_Filter {
|
|
344 |
|
345 |
$url = AS3CF_Utils::reduce_url( $url );
|
346 |
|
347 |
-
if ( ! preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) || ! isset( $class_id[1] ) ) {
|
348 |
-
// Can't determine ID from class, skip
|
349 |
-
continue;
|
350 |
-
}
|
351 |
-
|
352 |
$attachment_ids[ $url ] = absint( $class_id[1] );
|
353 |
}
|
354 |
|
330 |
$attachment_ids = array();
|
331 |
|
332 |
foreach ( $matches as $image ) {
|
333 |
+
if ( ! preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) || ! isset( $class_id[1] ) ) {
|
334 |
+
// Can't determine ID from class, skip
|
335 |
+
continue;
|
336 |
+
}
|
337 |
+
|
338 |
if ( ! preg_match( '/src=\\\?["\']+([^"\'\\\]+)/', $image, $src ) || ! isset( $src[1] ) ) {
|
339 |
// Can't determine URL, skip
|
340 |
continue;
|
349 |
|
350 |
$url = AS3CF_Utils::reduce_url( $url );
|
351 |
|
|
|
|
|
|
|
|
|
|
|
352 |
$attachment_ids[ $url ] = absint( $class_id[1] );
|
353 |
}
|
354 |
|
classes/as3cf-notices.php
CHANGED
@@ -351,7 +351,7 @@ class AS3CF_Notices {
|
|
351 |
*/
|
352 |
protected function maybe_show_notice( $notice, $dismissed_notices, $tab ) {
|
353 |
$screen = get_current_screen();
|
354 |
-
if ( $notice['only_show_in_settings'] && false === strpos( $screen->id, $this->as3cf->hook_suffix ) ) {
|
355 |
return;
|
356 |
}
|
357 |
|
351 |
*/
|
352 |
protected function maybe_show_notice( $notice, $dismissed_notices, $tab ) {
|
353 |
$screen = get_current_screen();
|
354 |
+
if ( $notice['only_show_in_settings'] && false === strpos( strval( $screen->id ), $this->as3cf->hook_suffix ) ) {
|
355 |
return;
|
356 |
}
|
357 |
|
classes/as3cf-plugin-compatibility.php
CHANGED
@@ -9,6 +9,7 @@
|
|
9 |
* @since 0.8.3
|
10 |
*/
|
11 |
|
|
|
12 |
use DeliciousBrains\WP_Offload_Media\Providers\Provider;
|
13 |
|
14 |
// Exit if accessed directly
|
@@ -129,21 +130,21 @@ class AS3CF_Plugin_Compatibility {
|
|
129 |
* Allow any process to trigger the copy back to local with
|
130 |
* the filter 'as3cf_get_attached_file_copy_back_to_local'
|
131 |
*
|
132 |
-
* @param string
|
133 |
-
* @param string
|
134 |
-
* @param int
|
135 |
-
* @param
|
136 |
*
|
137 |
* @return string
|
138 |
*/
|
139 |
-
function legacy_copy_back_to_local( $url, $file, $attachment_id, $
|
140 |
-
$copy_back_to_local = apply_filters( 'as3cf_get_attached_file_copy_back_to_local', false, $file, $attachment_id, $
|
141 |
if ( false === $copy_back_to_local ) {
|
142 |
// Not copying back file
|
143 |
return $url;
|
144 |
}
|
145 |
|
146 |
-
if ( ( $file = $this->copy_provider_file_to_server( $
|
147 |
// Return the file if successfully downloaded from S3
|
148 |
return $file;
|
149 |
};
|
@@ -189,14 +190,14 @@ class AS3CF_Plugin_Compatibility {
|
|
189 |
/**
|
190 |
* Prevent subsequent attempts to copy back after upload and remove.
|
191 |
*
|
192 |
-
* @param bool
|
193 |
-
* @param string
|
194 |
-
* @param integer
|
195 |
-
* @param
|
196 |
*
|
197 |
* @return bool
|
198 |
*/
|
199 |
-
public function prevent_copy_back_to_local_after_remove( $copy_back_to_local, $file, $attachment_id, $
|
200 |
if ( $copy_back_to_local && in_array( $file, $this->removed_files ) ) {
|
201 |
$copy_back_to_local = false;
|
202 |
}
|
@@ -261,20 +262,20 @@ class AS3CF_Plugin_Compatibility {
|
|
261 |
/**
|
262 |
* Generic method for copying back an S3 file to the server on a specific AJAX action
|
263 |
*
|
264 |
-
* @param string
|
265 |
-
* @param bool
|
266 |
-
* @param string
|
267 |
-
* @param string
|
268 |
-
* @param
|
269 |
*
|
270 |
* @return string
|
271 |
*/
|
272 |
-
function copy_image_to_server_on_action( $action_key, $ajax, $url, $file, $
|
273 |
if ( false === $this->maybe_process_on_action( $action_key, $ajax ) ) {
|
274 |
return $url;
|
275 |
}
|
276 |
|
277 |
-
if ( ( $file = $this->copy_provider_file_to_server( $
|
278 |
// Return the file if successfully downloaded from S3
|
279 |
return $file;
|
280 |
};
|
@@ -320,14 +321,33 @@ class AS3CF_Plugin_Compatibility {
|
|
320 |
return $pre;
|
321 |
}
|
322 |
|
323 |
-
$
|
324 |
-
|
|
|
|
|
|
|
|
|
|
|
325 |
|
326 |
// Update object key with original filename
|
327 |
-
$restored_filename
|
328 |
-
$old_filename
|
329 |
-
$
|
330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
331 |
|
332 |
return true;
|
333 |
}
|
@@ -335,55 +355,63 @@ class AS3CF_Plugin_Compatibility {
|
|
335 |
/**
|
336 |
* Remove edited image files from S3.
|
337 |
*
|
338 |
-
* @param int
|
339 |
-
* @param
|
340 |
*/
|
341 |
-
protected function remove_edited_image_files( $attachment_id, $
|
342 |
-
$
|
343 |
-
$region = $this->as3cf->get_provider_object_region( $provider_object );
|
344 |
-
$keys = AS3CF_Utils::get_attachment_edited_keys( $attachment_id, $provider_object );
|
345 |
|
346 |
if ( empty( $keys ) ) {
|
347 |
return;
|
348 |
}
|
349 |
|
350 |
-
$this->as3cf->delete_objects( $region, $bucket, $keys );
|
351 |
}
|
352 |
|
353 |
/**
|
354 |
* Allow the WordPress Image Editor to edit files that have been copied to S3
|
355 |
* but removed from the local server, by copying them back temporarily
|
356 |
*
|
357 |
-
* @param string
|
358 |
-
* @param string
|
359 |
-
* @param int
|
360 |
-
* @param
|
361 |
*
|
362 |
* @return string
|
363 |
*/
|
364 |
-
function image_editor_download_file( $url, $file, $attachment_id, $
|
365 |
if ( ! $this->is_ajax() ) {
|
366 |
return $url;
|
367 |
}
|
368 |
|
369 |
// When the image-editor restores the original it requests the edited image,
|
370 |
// but we actually need to copy back the original image at this point
|
371 |
-
// for the restore to be successful and edited images to be deleted from
|
372 |
// via image_editor_remove_files()
|
373 |
if ( isset( $_POST['do'] ) && 'restore' == $_POST['do'] ) {
|
374 |
$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
|
375 |
$original_filename = $backup_sizes['full-orig']['file'];
|
376 |
|
377 |
-
$
|
378 |
-
|
379 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
380 |
|
381 |
// Copy the original file back to the server for the restore process
|
382 |
-
$this->copy_provider_file_to_server( $
|
383 |
|
384 |
// Copy the edited file back to the server as well, it will be cleaned up later
|
385 |
-
if ( $provider_file = $this->copy_provider_file_to_server( $
|
386 |
-
// Return the file if successfully downloaded from
|
387 |
return $provider_file;
|
388 |
};
|
389 |
}
|
@@ -394,8 +422,8 @@ class AS3CF_Plugin_Compatibility {
|
|
394 |
foreach ( debug_backtrace() as $caller ) {
|
395 |
if ( isset( $caller['function'] ) && '_load_image_to_edit_path' == $caller['function'] ) {
|
396 |
// check this has been called by '_load_image_to_edit_path' so as only to copy back once
|
397 |
-
if ( $provider_file = $this->copy_provider_file_to_server( $
|
398 |
-
// Return the file if successfully downloaded from
|
399 |
return $provider_file;
|
400 |
};
|
401 |
}
|
@@ -435,7 +463,7 @@ class AS3CF_Plugin_Compatibility {
|
|
435 |
*
|
436 |
* @return bool
|
437 |
*/
|
438 |
-
|
439 |
$header_crop = $this->maybe_process_on_action( 'custom-header-crop', true );
|
440 |
|
441 |
$context = array( 'site-icon', 'custom_logo' );
|
@@ -450,17 +478,17 @@ class AS3CF_Plugin_Compatibility {
|
|
450 |
}
|
451 |
|
452 |
/**
|
453 |
-
* Allow the WordPress Customizer to crop images that have been copied to
|
454 |
-
* but removed from the local server, by copying them back temporarily
|
455 |
*
|
456 |
-
* @param string
|
457 |
-
* @param string
|
458 |
-
* @param int
|
459 |
-
* @param
|
460 |
*
|
461 |
* @return string
|
462 |
*/
|
463 |
-
public function customizer_crop_download_file( $url, $file, $attachment_id, $
|
464 |
if ( false === $this->is_customizer_crop_action() ) {
|
465 |
return $url;
|
466 |
}
|
@@ -469,8 +497,8 @@ class AS3CF_Plugin_Compatibility {
|
|
469 |
return $url;
|
470 |
}
|
471 |
|
472 |
-
if ( ( $file = $this->copy_provider_file_to_server( $
|
473 |
-
// Return the file if successfully downloaded from
|
474 |
return $file;
|
475 |
};
|
476 |
|
@@ -512,84 +540,69 @@ class AS3CF_Plugin_Compatibility {
|
|
512 |
if ( ! is_null( $post_id ) ) {
|
513 |
return $post_id;
|
514 |
}
|
515 |
-
$url = parse_url( $url );
|
516 |
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
$key1 = ltrim( $url['path'], '/' );
|
522 |
-
$length1 = strlen( $key1 );
|
523 |
-
|
524 |
-
// URLs may contain the bucket name within the path, therefore we must
|
525 |
-
// also perform the search with the first path segment removed
|
526 |
-
$parts = explode( '/', $key1 );
|
527 |
-
unset( $parts[0] );
|
528 |
-
|
529 |
-
$key2 = implode( '/', $parts );
|
530 |
-
$length2 = strlen( $key2 );
|
531 |
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
OR `{$wpdb->prefix}postmeta`.`meta_value` LIKE %s )
|
539 |
-
",
|
540 |
-
"%s:3:\"key\";s:{$length1}:\"{$key1}\";%",
|
541 |
-
"%s:3:\"key\";s:{$length2}:\"{$key2}\";%"
|
542 |
-
);
|
543 |
-
|
544 |
-
if ( $id = $wpdb->get_var( $sql ) ) {
|
545 |
-
return $id;
|
546 |
}
|
547 |
|
548 |
-
return
|
|
|
|
|
|
|
|
|
|
|
549 |
}
|
550 |
|
551 |
/**
|
552 |
-
* Allow the Regenerate Thumbnails plugin to copy the
|
553 |
-
* server when the file is missing on the server via get_attached_file
|
554 |
*
|
555 |
-
* @param string
|
556 |
-
* @param string
|
557 |
-
* @param int
|
558 |
-
* @param
|
559 |
*
|
560 |
* @return string
|
561 |
*/
|
562 |
-
function regenerate_thumbnails_download_file( $url, $file, $attachment_id, $
|
563 |
-
return $this->copy_image_to_server_on_action( 'regeneratethumbnail', true, $url, $file, $
|
564 |
}
|
565 |
|
566 |
/**
|
567 |
-
* Download a file from
|
568 |
* the attachment's file should be.
|
569 |
*
|
570 |
-
* @param
|
571 |
-
* @param string
|
572 |
*
|
573 |
* @return string|bool File if downloaded, false on failure
|
574 |
*/
|
575 |
-
public function copy_provider_file_to_server( $
|
576 |
// Make sure the directory exists
|
577 |
$dir = dirname( $file );
|
578 |
if ( ! wp_mkdir_p( $dir ) ) {
|
579 |
$error_message = sprintf( __( 'The local directory %s does not exist and could not be created.', 'amazon-s3-and-cloudfront' ), $dir );
|
580 |
-
AS3CF_Error::log( sprintf( __( 'There was an error attempting to download the file %s from the bucket: %s', 'amazon-s3-and-cloudfront' ), $
|
581 |
|
582 |
return false;
|
583 |
}
|
584 |
|
585 |
try {
|
586 |
-
$this->as3cf->get_provider_client( $
|
587 |
-
'Bucket' => $
|
588 |
-
'Key' => $
|
589 |
'SaveAs' => $file,
|
590 |
) );
|
591 |
} catch ( Exception $e ) {
|
592 |
-
AS3CF_Error::log( sprintf( __( 'There was an error attempting to download the file %s from the bucket: %s', 'amazon-s3-and-cloudfront' ), $
|
593 |
|
594 |
return false;
|
595 |
}
|
@@ -627,25 +640,25 @@ class AS3CF_Plugin_Compatibility {
|
|
627 |
* Allow access to the remote file via the stream wrapper.
|
628 |
* This is useful for compatibility with plugins when attachments are removed from the local server after upload.
|
629 |
*
|
630 |
-
* @param string
|
631 |
-
* @param string
|
632 |
-
* @param int
|
633 |
-
* @param
|
634 |
*
|
635 |
* @return string
|
636 |
* @throws Exception
|
637 |
*/
|
638 |
-
public function get_stream_wrapper_file( $url, $file, $attachment_id, $
|
639 |
if ( $url === $file ) {
|
640 |
// Abort if an earlier hook to get the file has been called and it has been copied back.
|
641 |
return $file;
|
642 |
}
|
643 |
|
644 |
// Make sure the region stream wrapper is registered.
|
645 |
-
$client = $this->register_stream_wrapper( $
|
646 |
|
647 |
if ( ! empty( $client ) ) {
|
648 |
-
return $client->prepare_stream_wrapper_file( $
|
649 |
}
|
650 |
|
651 |
return $url;
|
@@ -775,7 +788,7 @@ class AS3CF_Plugin_Compatibility {
|
|
775 |
}
|
776 |
|
777 |
/**
|
778 |
-
* Alter the image meta data to add srcset support for object versioned
|
779 |
*
|
780 |
* @param array $image_meta
|
781 |
* @param array $size_array
|
@@ -795,14 +808,14 @@ class AS3CF_Plugin_Compatibility {
|
|
795 |
return $image_meta;
|
796 |
}
|
797 |
|
798 |
-
if ( ! ( $
|
799 |
// Attachment not uploaded to S3, abort
|
800 |
return $image_meta;
|
801 |
}
|
802 |
|
803 |
$image_basename = $this->as3cf->encode_filename_in_path( wp_basename( $image_meta['file'] ) );
|
804 |
|
805 |
-
if ( false === strpos( $this->as3cf->encode_filename_in_path( $
|
806 |
// Not the correct attachment, abort
|
807 |
return $image_meta;
|
808 |
}
|
@@ -825,7 +838,7 @@ class AS3CF_Plugin_Compatibility {
|
|
825 |
}
|
826 |
|
827 |
/**
|
828 |
-
* Replace local URLs with
|
829 |
*
|
830 |
* @param array $sources
|
831 |
* @param array $size_array
|
@@ -841,7 +854,7 @@ class AS3CF_Plugin_Compatibility {
|
|
841 |
return $sources;
|
842 |
}
|
843 |
|
844 |
-
if ( ! ( $
|
845 |
// Attachment not uploaded to S3, abort
|
846 |
return $sources;
|
847 |
}
|
@@ -849,7 +862,7 @@ class AS3CF_Plugin_Compatibility {
|
|
849 |
foreach ( $sources as $width => $source ) {
|
850 |
$filename = wp_basename( $source['url'] );
|
851 |
$size = $this->find_image_size_from_width( $image_meta['sizes'], $width, $filename );
|
852 |
-
$provider_url = $this->as3cf->get_attachment_provider_url( $attachment_id, $
|
853 |
|
854 |
if ( false === $provider_url || is_wp_error( $provider_url ) ) {
|
855 |
// Skip URLs not offloaded to S3
|
9 |
* @since 0.8.3
|
10 |
*/
|
11 |
|
12 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
13 |
use DeliciousBrains\WP_Offload_Media\Providers\Provider;
|
14 |
|
15 |
// Exit if accessed directly
|
130 |
* Allow any process to trigger the copy back to local with
|
131 |
* the filter 'as3cf_get_attached_file_copy_back_to_local'
|
132 |
*
|
133 |
+
* @param string $url
|
134 |
+
* @param string $file
|
135 |
+
* @param int $attachment_id
|
136 |
+
* @param Media_Library_Item $as3cf_item
|
137 |
*
|
138 |
* @return string
|
139 |
*/
|
140 |
+
function legacy_copy_back_to_local( $url, $file, $attachment_id, Media_Library_Item $as3cf_item ) {
|
141 |
+
$copy_back_to_local = apply_filters( 'as3cf_get_attached_file_copy_back_to_local', false, $file, $attachment_id, $as3cf_item );
|
142 |
if ( false === $copy_back_to_local ) {
|
143 |
// Not copying back file
|
144 |
return $url;
|
145 |
}
|
146 |
|
147 |
+
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
148 |
// Return the file if successfully downloaded from S3
|
149 |
return $file;
|
150 |
};
|
190 |
/**
|
191 |
* Prevent subsequent attempts to copy back after upload and remove.
|
192 |
*
|
193 |
+
* @param bool $copy_back_to_local
|
194 |
+
* @param string $file
|
195 |
+
* @param integer $attachment_id
|
196 |
+
* @param Media_Library_Item $as3cf_item
|
197 |
*
|
198 |
* @return bool
|
199 |
*/
|
200 |
+
public function prevent_copy_back_to_local_after_remove( $copy_back_to_local, $file, $attachment_id, Media_Library_Item $as3cf_item ) {
|
201 |
if ( $copy_back_to_local && in_array( $file, $this->removed_files ) ) {
|
202 |
$copy_back_to_local = false;
|
203 |
}
|
262 |
/**
|
263 |
* Generic method for copying back an S3 file to the server on a specific AJAX action
|
264 |
*
|
265 |
+
* @param string $action_key Action that must be in process
|
266 |
+
* @param bool $ajax Must the process be an AJAX one?
|
267 |
+
* @param string $url S3 URL
|
268 |
+
* @param string $file Local file path of image
|
269 |
+
* @param Media_Library_Item $as3cf_item S3 meta data
|
270 |
*
|
271 |
* @return string
|
272 |
*/
|
273 |
+
function copy_image_to_server_on_action( $action_key, $ajax, $url, $file, Media_Library_Item $as3cf_item ) {
|
274 |
if ( false === $this->maybe_process_on_action( $action_key, $ajax ) ) {
|
275 |
return $url;
|
276 |
}
|
277 |
|
278 |
+
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
279 |
// Return the file if successfully downloaded from S3
|
280 |
return $file;
|
281 |
};
|
321 |
return $pre;
|
322 |
}
|
323 |
|
324 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
325 |
+
|
326 |
+
if ( ! $as3cf_item ) {
|
327 |
+
return $pre;
|
328 |
+
}
|
329 |
+
|
330 |
+
$this->remove_edited_image_files( $post_id, $as3cf_item );
|
331 |
|
332 |
// Update object key with original filename
|
333 |
+
$restored_filename = wp_basename( $data['file'] );
|
334 |
+
$old_filename = wp_basename( $as3cf_item->path() );
|
335 |
+
$item_path = str_replace( $old_filename, $restored_filename, $as3cf_item->path() );
|
336 |
+
|
337 |
+
$as3cf_item = new Media_Library_Item(
|
338 |
+
$as3cf_item->provider(),
|
339 |
+
$as3cf_item->region(),
|
340 |
+
$as3cf_item->bucket(),
|
341 |
+
$item_path,
|
342 |
+
$as3cf_item->is_private(),
|
343 |
+
$as3cf_item->source_id(),
|
344 |
+
$as3cf_item->source_path(),
|
345 |
+
wp_basename( $as3cf_item->original_source_path() ),
|
346 |
+
$as3cf_item->private_sizes(),
|
347 |
+
$as3cf_item->id()
|
348 |
+
);
|
349 |
+
|
350 |
+
$as3cf_item->save();
|
351 |
|
352 |
return true;
|
353 |
}
|
355 |
/**
|
356 |
* Remove edited image files from S3.
|
357 |
*
|
358 |
+
* @param int $attachment_id
|
359 |
+
* @param Media_Library_Item $as3cf_item
|
360 |
*/
|
361 |
+
protected function remove_edited_image_files( $attachment_id, Media_Library_Item $as3cf_item ) {
|
362 |
+
$keys = AS3CF_Utils::get_attachment_edited_keys( $attachment_id, $as3cf_item );
|
|
|
|
|
363 |
|
364 |
if ( empty( $keys ) ) {
|
365 |
return;
|
366 |
}
|
367 |
|
368 |
+
$this->as3cf->delete_objects( $as3cf_item->region(), $as3cf_item->bucket(), $keys );
|
369 |
}
|
370 |
|
371 |
/**
|
372 |
* Allow the WordPress Image Editor to edit files that have been copied to S3
|
373 |
* but removed from the local server, by copying them back temporarily
|
374 |
*
|
375 |
+
* @param string $url
|
376 |
+
* @param string $file
|
377 |
+
* @param int $attachment_id
|
378 |
+
* @param Media_Library_Item $as3cf_item
|
379 |
*
|
380 |
* @return string
|
381 |
*/
|
382 |
+
function image_editor_download_file( $url, $file, $attachment_id, Media_Library_Item $as3cf_item ) {
|
383 |
if ( ! $this->is_ajax() ) {
|
384 |
return $url;
|
385 |
}
|
386 |
|
387 |
// When the image-editor restores the original it requests the edited image,
|
388 |
// but we actually need to copy back the original image at this point
|
389 |
+
// for the restore to be successful and edited images to be deleted from the bucket
|
390 |
// via image_editor_remove_files()
|
391 |
if ( isset( $_POST['do'] ) && 'restore' == $_POST['do'] ) {
|
392 |
$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
|
393 |
$original_filename = $backup_sizes['full-orig']['file'];
|
394 |
|
395 |
+
$as3cf_item_orig = new Media_Library_Item(
|
396 |
+
$as3cf_item->provider(),
|
397 |
+
$as3cf_item->region(),
|
398 |
+
$as3cf_item->bucket(),
|
399 |
+
dirname( $as3cf_item->path() ) . '/' . $original_filename,
|
400 |
+
$as3cf_item->is_private(),
|
401 |
+
$as3cf_item->source_id(),
|
402 |
+
$as3cf_item->source_path(),
|
403 |
+
wp_basename( $as3cf_item->original_source_path() ),
|
404 |
+
$as3cf_item->private_sizes(),
|
405 |
+
$as3cf_item->id()
|
406 |
+
);
|
407 |
+
$orig_file = dirname( $file ) . '/' . $original_filename;
|
408 |
|
409 |
// Copy the original file back to the server for the restore process
|
410 |
+
$this->copy_provider_file_to_server( $as3cf_item_orig, $orig_file );
|
411 |
|
412 |
// Copy the edited file back to the server as well, it will be cleaned up later
|
413 |
+
if ( $provider_file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) {
|
414 |
+
// Return the file if successfully downloaded from bucket.
|
415 |
return $provider_file;
|
416 |
};
|
417 |
}
|
422 |
foreach ( debug_backtrace() as $caller ) {
|
423 |
if ( isset( $caller['function'] ) && '_load_image_to_edit_path' == $caller['function'] ) {
|
424 |
// check this has been called by '_load_image_to_edit_path' so as only to copy back once
|
425 |
+
if ( $provider_file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) {
|
426 |
+
// Return the file if successfully downloaded from bucket.
|
427 |
return $provider_file;
|
428 |
};
|
429 |
}
|
463 |
*
|
464 |
* @return bool
|
465 |
*/
|
466 |
+
public function is_customizer_crop_action() {
|
467 |
$header_crop = $this->maybe_process_on_action( 'custom-header-crop', true );
|
468 |
|
469 |
$context = array( 'site-icon', 'custom_logo' );
|
478 |
}
|
479 |
|
480 |
/**
|
481 |
+
* Allow the WordPress Customizer to crop images that have been copied to bucket
|
482 |
+
* but removed from the local server, by copying them back temporarily.
|
483 |
*
|
484 |
+
* @param string $url
|
485 |
+
* @param string $file
|
486 |
+
* @param int $attachment_id
|
487 |
+
* @param Media_Library_Item $as3cf_item
|
488 |
*
|
489 |
* @return string
|
490 |
*/
|
491 |
+
public function customizer_crop_download_file( $url, $file, $attachment_id, Media_Library_Item $as3cf_item ) {
|
492 |
if ( false === $this->is_customizer_crop_action() ) {
|
493 |
return $url;
|
494 |
}
|
497 |
return $url;
|
498 |
}
|
499 |
|
500 |
+
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
501 |
+
// Return the file if successfully downloaded from bucket.
|
502 |
return $file;
|
503 |
};
|
504 |
|
540 |
if ( ! is_null( $post_id ) ) {
|
541 |
return $post_id;
|
542 |
}
|
|
|
543 |
|
544 |
+
// There seems to be a bug in the WP Customizer whereby sometimes it puts the attachment ID on the URL.
|
545 |
+
if ( is_numeric( $url ) ) {
|
546 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $url );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
547 |
|
548 |
+
// If we found an offloaded Media Library item for that ID, job's a good'n'.
|
549 |
+
if ( $as3cf_item ) {
|
550 |
+
$post_id = $url;
|
551 |
+
}
|
552 |
+
} else {
|
553 |
+
$post_id = $this->as3cf->filter_provider->get_attachment_id_from_url( $url );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
554 |
}
|
555 |
|
556 |
+
// Must return null if not found.
|
557 |
+
if ( empty( $post_id ) ) {
|
558 |
+
return null;
|
559 |
+
} else {
|
560 |
+
return $post_id;
|
561 |
+
}
|
562 |
}
|
563 |
|
564 |
/**
|
565 |
+
* Allow the Regenerate Thumbnails plugin to copy the bucket file back to the local
|
566 |
+
* server when the file is missing on the server via get_attached_file.
|
567 |
*
|
568 |
+
* @param string $url
|
569 |
+
* @param string $file
|
570 |
+
* @param int $attachment_id
|
571 |
+
* @param Media_Library_Item $as3cf_item
|
572 |
*
|
573 |
* @return string
|
574 |
*/
|
575 |
+
function regenerate_thumbnails_download_file( $url, $file, $attachment_id, Media_Library_Item $as3cf_item ) {
|
576 |
+
return $this->copy_image_to_server_on_action( 'regeneratethumbnail', true, $url, $file, $as3cf_item );
|
577 |
}
|
578 |
|
579 |
/**
|
580 |
+
* Download a file from bucket if the file does not exist locally and places it where
|
581 |
* the attachment's file should be.
|
582 |
*
|
583 |
+
* @param Media_Library_Item $as3cf_item
|
584 |
+
* @param string $file
|
585 |
*
|
586 |
* @return string|bool File if downloaded, false on failure
|
587 |
*/
|
588 |
+
public function copy_provider_file_to_server( Media_Library_Item $as3cf_item, $file ) {
|
589 |
// Make sure the directory exists
|
590 |
$dir = dirname( $file );
|
591 |
if ( ! wp_mkdir_p( $dir ) ) {
|
592 |
$error_message = sprintf( __( 'The local directory %s does not exist and could not be created.', 'amazon-s3-and-cloudfront' ), $dir );
|
593 |
+
AS3CF_Error::log( sprintf( __( 'There was an error attempting to download the file %s from the bucket: %s', 'amazon-s3-and-cloudfront' ), $as3cf_item->path(), $error_message ) );
|
594 |
|
595 |
return false;
|
596 |
}
|
597 |
|
598 |
try {
|
599 |
+
$this->as3cf->get_provider_client( $as3cf_item->region(), true )->get_object( array(
|
600 |
+
'Bucket' => $as3cf_item->bucket(),
|
601 |
+
'Key' => $as3cf_item->path(),
|
602 |
'SaveAs' => $file,
|
603 |
) );
|
604 |
} catch ( Exception $e ) {
|
605 |
+
AS3CF_Error::log( sprintf( __( 'There was an error attempting to download the file %s from the bucket: %s', 'amazon-s3-and-cloudfront' ), $as3cf_item->path(), $e->getMessage() ) );
|
606 |
|
607 |
return false;
|
608 |
}
|
640 |
* Allow access to the remote file via the stream wrapper.
|
641 |
* This is useful for compatibility with plugins when attachments are removed from the local server after upload.
|
642 |
*
|
643 |
+
* @param string $url
|
644 |
+
* @param string $file
|
645 |
+
* @param int $attachment_id
|
646 |
+
* @param Media_Library_Item $as3cf_item
|
647 |
*
|
648 |
* @return string
|
649 |
* @throws Exception
|
650 |
*/
|
651 |
+
public function get_stream_wrapper_file( $url, $file, $attachment_id, Media_Library_Item $as3cf_item ) {
|
652 |
if ( $url === $file ) {
|
653 |
// Abort if an earlier hook to get the file has been called and it has been copied back.
|
654 |
return $file;
|
655 |
}
|
656 |
|
657 |
// Make sure the region stream wrapper is registered.
|
658 |
+
$client = $this->register_stream_wrapper( $as3cf_item->region() );
|
659 |
|
660 |
if ( ! empty( $client ) ) {
|
661 |
+
return $client->prepare_stream_wrapper_file( $as3cf_item->region(), $as3cf_item->bucket(), $as3cf_item->path() );
|
662 |
}
|
663 |
|
664 |
return $url;
|
788 |
}
|
789 |
|
790 |
/**
|
791 |
+
* Alter the image meta data to add srcset support for object versioned provider URLs.
|
792 |
*
|
793 |
* @param array $image_meta
|
794 |
* @param array $size_array
|
808 |
return $image_meta;
|
809 |
}
|
810 |
|
811 |
+
if ( ! ( $as3cf_item = $this->as3cf->is_attachment_served_by_provider( $attachment_id ) ) ) {
|
812 |
// Attachment not uploaded to S3, abort
|
813 |
return $image_meta;
|
814 |
}
|
815 |
|
816 |
$image_basename = $this->as3cf->encode_filename_in_path( wp_basename( $image_meta['file'] ) );
|
817 |
|
818 |
+
if ( false === strpos( $this->as3cf->encode_filename_in_path( $as3cf_item->path() ), $image_basename ) ) {
|
819 |
// Not the correct attachment, abort
|
820 |
return $image_meta;
|
821 |
}
|
838 |
}
|
839 |
|
840 |
/**
|
841 |
+
* Replace local URLs with provider ones for srcset image sources.
|
842 |
*
|
843 |
* @param array $sources
|
844 |
* @param array $size_array
|
854 |
return $sources;
|
855 |
}
|
856 |
|
857 |
+
if ( ! ( $as3cf_item = $this->as3cf->is_attachment_served_by_provider( $attachment_id ) ) ) {
|
858 |
// Attachment not uploaded to S3, abort
|
859 |
return $sources;
|
860 |
}
|
862 |
foreach ( $sources as $width => $source ) {
|
863 |
$filename = wp_basename( $source['url'] );
|
864 |
$size = $this->find_image_size_from_width( $image_meta['sizes'], $width, $filename );
|
865 |
+
$provider_url = $this->as3cf->get_attachment_provider_url( $attachment_id, $as3cf_item, null, $size, $image_meta );
|
866 |
|
867 |
if ( false === $provider_url || is_wp_error( $provider_url ) ) {
|
868 |
// Skip URLs not offloaded to S3
|
classes/as3cf-utils.php
CHANGED
@@ -9,6 +9,8 @@
|
|
9 |
*/
|
10 |
|
11 |
// Exit if accessed directly
|
|
|
|
|
12 |
if ( ! defined( 'ABSPATH' ) ) {
|
13 |
exit;
|
14 |
}
|
@@ -98,9 +100,9 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
98 |
/**
|
99 |
* Parses a URL into its components. Compatible with PHP < 5.4.7.
|
100 |
*
|
101 |
-
* @param
|
102 |
*
|
103 |
-
* @param int
|
104 |
*
|
105 |
* @return mixed An array of the parsed components, mixed for a requested component, or false on error.
|
106 |
*/
|
@@ -197,6 +199,11 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
197 |
$paths['thumb'] = str_replace( $file_name, $meta['thumb'], $file_path );
|
198 |
}
|
199 |
|
|
|
|
|
|
|
|
|
|
|
200 |
// Sizes
|
201 |
if ( isset( $meta['sizes'] ) ) {
|
202 |
foreach ( $meta['sizes'] as $size => $file ) {
|
@@ -254,13 +261,13 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
254 |
/**
|
255 |
* Get an attachment's edited S3 keys.
|
256 |
*
|
257 |
-
* @param int
|
258 |
-
* @param
|
259 |
*
|
260 |
* @return array
|
261 |
*/
|
262 |
-
public static function get_attachment_edited_keys( $attachment_id, $
|
263 |
-
$prefix = trailingslashit(
|
264 |
$paths = self::get_attachment_edited_file_paths( $attachment_id );
|
265 |
$paths = array_map( function ( $path ) use ( $prefix ) {
|
266 |
return array( 'Key' => $prefix . wp_basename( $path ) );
|
@@ -493,5 +500,79 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
493 |
|
494 |
return $domain;
|
495 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
496 |
}
|
497 |
}
|
9 |
*/
|
10 |
|
11 |
// Exit if accessed directly
|
12 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
13 |
+
|
14 |
if ( ! defined( 'ABSPATH' ) ) {
|
15 |
exit;
|
16 |
}
|
100 |
/**
|
101 |
* Parses a URL into its components. Compatible with PHP < 5.4.7.
|
102 |
*
|
103 |
+
* @param string $url The URL to parse.
|
104 |
*
|
105 |
+
* @param int $component PHP_URL_ constant for URL component to return.
|
106 |
*
|
107 |
* @return mixed An array of the parsed components, mixed for a requested component, or false on error.
|
108 |
*/
|
199 |
$paths['thumb'] = str_replace( $file_name, $meta['thumb'], $file_path );
|
200 |
}
|
201 |
|
202 |
+
// Original Image (when large image scaled down to threshold size and used as "full").
|
203 |
+
if ( isset( $meta['original_image'] ) ) {
|
204 |
+
$paths['original_image'] = str_replace( $file_name, $meta['original_image'], $file_path );
|
205 |
+
}
|
206 |
+
|
207 |
// Sizes
|
208 |
if ( isset( $meta['sizes'] ) ) {
|
209 |
foreach ( $meta['sizes'] as $size => $file ) {
|
261 |
/**
|
262 |
* Get an attachment's edited S3 keys.
|
263 |
*
|
264 |
+
* @param int $attachment_id
|
265 |
+
* @param Media_Library_Item $as3cf_item
|
266 |
*
|
267 |
* @return array
|
268 |
*/
|
269 |
+
public static function get_attachment_edited_keys( $attachment_id, Media_Library_Item $as3cf_item ) {
|
270 |
+
$prefix = trailingslashit( $as3cf_item->normalized_path_dir() );
|
271 |
$paths = self::get_attachment_edited_file_paths( $attachment_id );
|
272 |
$paths = array_map( function ( $path ) use ( $prefix ) {
|
273 |
return array( 'Key' => $prefix . wp_basename( $path ) );
|
500 |
|
501 |
return $domain;
|
502 |
}
|
503 |
+
|
504 |
+
/**
|
505 |
+
* Decode file name in potentially URL encoded URL path.
|
506 |
+
*
|
507 |
+
* @param string $file
|
508 |
+
*
|
509 |
+
* @return string
|
510 |
+
*/
|
511 |
+
public static function decode_filename_in_path( $file ) {
|
512 |
+
$url = parse_url( $file );
|
513 |
+
|
514 |
+
if ( ! isset( $url['path'] ) ) {
|
515 |
+
// Can't determine path, return original
|
516 |
+
return $file;
|
517 |
+
}
|
518 |
+
|
519 |
+
$file_name = wp_basename( $url['path'] );
|
520 |
+
|
521 |
+
if ( false === strpos( $file_name, '%' ) ) {
|
522 |
+
// File name not encoded, return original
|
523 |
+
return $file;
|
524 |
+
}
|
525 |
+
|
526 |
+
$decoded_file_name = rawurldecode( $file_name );
|
527 |
+
|
528 |
+
return str_replace( $file_name, $decoded_file_name, $file );
|
529 |
+
}
|
530 |
+
|
531 |
+
/**
|
532 |
+
* Returns indexed array of full size paths, e.g. orig and edited.
|
533 |
+
*
|
534 |
+
* @param array $paths Associative array of sizes and relative paths
|
535 |
+
*
|
536 |
+
* @return array
|
537 |
+
*
|
538 |
+
* @see get_attachment_file_paths
|
539 |
+
*/
|
540 |
+
public static function fullsize_paths( $paths ) {
|
541 |
+
if ( is_array( $paths ) && ! empty( $paths ) ) {
|
542 |
+
return array_values( array_unique( array_intersect_key( $paths, array_flip( array( 'original', 'file', 'full-orig', 'original_image' ) ) ) ) );
|
543 |
+
} else {
|
544 |
+
return array();
|
545 |
+
}
|
546 |
+
}
|
547 |
+
|
548 |
+
/**
|
549 |
+
* Converts an array of upload file paths to all be relative paths.
|
550 |
+
* If any path is not absolute or does begin with current uploads base dir it will not be altered.
|
551 |
+
*
|
552 |
+
* @param array $paths Array of upload file paths, absolute or relative.
|
553 |
+
*
|
554 |
+
* @return array Input array with values switched to relative upload file paths.
|
555 |
+
*/
|
556 |
+
public static function make_upload_file_paths_relative( $paths ) {
|
557 |
+
if ( empty( $paths ) ) {
|
558 |
+
return array();
|
559 |
+
}
|
560 |
+
|
561 |
+
if ( ! is_array( $paths ) ) {
|
562 |
+
$paths = array( $paths );
|
563 |
+
}
|
564 |
+
|
565 |
+
$uploads = wp_upload_dir();
|
566 |
+
$basedir = trailingslashit( $uploads['basedir'] );
|
567 |
+
$offset = strlen( $basedir );
|
568 |
+
|
569 |
+
foreach ( $paths as $key => $path ) {
|
570 |
+
if ( 0 === strpos( $path, $basedir ) ) {
|
571 |
+
$paths[ $key ] = substr( $path, $offset );
|
572 |
+
}
|
573 |
+
}
|
574 |
+
|
575 |
+
return $paths;
|
576 |
+
}
|
577 |
}
|
578 |
}
|
classes/filters/as3cf-local-to-s3.php
CHANGED
@@ -1,5 +1,7 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
3 |
class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
4 |
|
5 |
/**
|
@@ -207,7 +209,7 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
207 |
return $this->query_cache[ $full_url ];
|
208 |
}
|
209 |
|
210 |
-
$path =
|
211 |
|
212 |
$sql = $wpdb->prepare( "
|
213 |
SELECT post_id FROM {$wpdb->postmeta}
|
@@ -237,8 +239,6 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
237 |
* @return array url => attachment ID (or false)
|
238 |
*/
|
239 |
protected function get_attachment_ids_from_urls( $urls ) {
|
240 |
-
global $wpdb;
|
241 |
-
|
242 |
$results = array();
|
243 |
|
244 |
if ( empty( $urls ) ) {
|
@@ -262,35 +262,35 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
262 |
continue;
|
263 |
}
|
264 |
|
265 |
-
$path =
|
266 |
|
267 |
$paths[ $path ] = $full_url;
|
268 |
$full_urls[ $full_url ][] = $url;
|
269 |
-
$meta_values[] = "'" . esc_sql( $path ) . "'";
|
270 |
}
|
271 |
|
272 |
-
if ( ! empty( $
|
273 |
-
$
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
|
|
|
|
292 |
}
|
293 |
-
unset( $full_urls[ $full_url ] );
|
294 |
}
|
295 |
}
|
296 |
}
|
@@ -319,7 +319,7 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
319 |
* @return string
|
320 |
*/
|
321 |
protected function normalize_find_value( $url ) {
|
322 |
-
return
|
323 |
}
|
324 |
|
325 |
/**
|
1 |
<?php
|
2 |
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
4 |
+
|
5 |
class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
6 |
|
7 |
/**
|
209 |
return $this->query_cache[ $full_url ];
|
210 |
}
|
211 |
|
212 |
+
$path = AS3CF_Utils::decode_filename_in_path( ltrim( str_replace( $this->get_bare_upload_base_urls(), '', $full_url ), '/' ) );
|
213 |
|
214 |
$sql = $wpdb->prepare( "
|
215 |
SELECT post_id FROM {$wpdb->postmeta}
|
239 |
* @return array url => attachment ID (or false)
|
240 |
*/
|
241 |
protected function get_attachment_ids_from_urls( $urls ) {
|
|
|
|
|
242 |
$results = array();
|
243 |
|
244 |
if ( empty( $urls ) ) {
|
262 |
continue;
|
263 |
}
|
264 |
|
265 |
+
$path = AS3CF_Utils::decode_filename_in_path( ltrim( str_replace( $this->get_bare_upload_base_urls(), '', $full_url ), '/' ) );
|
266 |
|
267 |
$paths[ $path ] = $full_url;
|
268 |
$full_urls[ $full_url ][] = $url;
|
|
|
269 |
}
|
270 |
|
271 |
+
if ( ! empty( $paths ) ) {
|
272 |
+
$as3cf_items = Media_Library_Item::get_by_source_path( array_keys( $paths ) );
|
273 |
+
|
274 |
+
if ( ! empty( $as3cf_items ) ) {
|
275 |
+
/* @var Media_Library_Item $as3cf_item */
|
276 |
+
foreach ( $as3cf_items as $as3cf_item ) {
|
277 |
+
// Each returned item may have matched on either the source_path or original_source_path.
|
278 |
+
// Because the base image file name of a thumbnail might match the original rather scaled or rotated full image
|
279 |
+
// it's possible that both source paths are used by separate URLs.
|
280 |
+
foreach ( array( $as3cf_item->source_path(), $as3cf_item->original_source_path() ) as $source_path ) {
|
281 |
+
if ( ! empty( $paths[ $source_path ] ) ) {
|
282 |
+
$matched_full_url = $paths[ $source_path ];
|
283 |
+
|
284 |
+
if ( ! empty( $full_urls[ $matched_full_url ] ) ) {
|
285 |
+
$attachment_id = $as3cf_item->source_id();
|
286 |
+
$this->query_cache[ $matched_full_url ] = $attachment_id;
|
287 |
+
|
288 |
+
foreach ( $full_urls[ $matched_full_url ] as $url ) {
|
289 |
+
$results[ $url ] = $attachment_id;
|
290 |
+
}
|
291 |
+
unset( $full_urls[ $matched_full_url ] );
|
292 |
+
}
|
293 |
}
|
|
|
294 |
}
|
295 |
}
|
296 |
}
|
319 |
* @return string
|
320 |
*/
|
321 |
protected function normalize_find_value( $url ) {
|
322 |
+
return AS3CF_Utils::decode_filename_in_path( $url );
|
323 |
}
|
324 |
|
325 |
/**
|
classes/filters/as3cf-s3-to-local.php
CHANGED
@@ -1,5 +1,7 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
3 |
class AS3CF_S3_To_Local extends AS3CF_Filter {
|
4 |
|
5 |
/**
|
@@ -110,73 +112,19 @@ class AS3CF_S3_To_Local extends AS3CF_Filter {
|
|
110 |
*
|
111 |
* @return bool|int
|
112 |
*/
|
113 |
-
|
114 |
-
global $wpdb;
|
115 |
-
|
116 |
$full_url = AS3CF_Utils::remove_size_from_filename( $url );
|
117 |
|
|
|
118 |
if ( isset( $this->query_cache[ $full_url ] ) ) {
|
119 |
-
// ID already cached, return
|
120 |
return $this->query_cache[ $full_url ];
|
121 |
}
|
122 |
|
123 |
-
$
|
124 |
-
$path = $this->as3cf->decode_filename_in_path( ltrim( $parts['path'], '/' ) );
|
125 |
-
|
126 |
-
if ( false !== strpos( $path, '/' ) ) {
|
127 |
-
// Remove the first directory to cater for bucket in path domain settings
|
128 |
-
$path = explode( '/', $path );
|
129 |
-
array_shift( $path );
|
130 |
-
$path = implode( '/', $path );
|
131 |
-
}
|
132 |
-
|
133 |
-
$sql = $wpdb->prepare( "
|
134 |
-
SELECT * FROM {$wpdb->postmeta}
|
135 |
-
WHERE meta_key = %s
|
136 |
-
AND meta_value LIKE %s;
|
137 |
-
", 'amazonS3_info', '%' . $path . '%' );
|
138 |
-
|
139 |
-
$results = $wpdb->get_results( $sql );
|
140 |
-
|
141 |
-
if ( empty( $results ) ) {
|
142 |
-
// No attachment found, return false
|
143 |
-
return false;
|
144 |
-
}
|
145 |
-
|
146 |
-
if ( 1 === count( $results ) ) {
|
147 |
-
// Attachment matched, return ID
|
148 |
-
$this->query_cache[ $full_url ] = $results[0]->post_id;
|
149 |
-
|
150 |
-
return $results[0]->post_id;
|
151 |
-
}
|
152 |
-
|
153 |
-
$path = ltrim( $parts['path'], '/' );
|
154 |
-
|
155 |
-
foreach ( $results as $result ) {
|
156 |
-
$meta = maybe_unserialize( $result->meta_value );
|
157 |
-
|
158 |
-
if ( ! isset( $meta['bucket'] ) || ! isset( $meta['key'] ) ) {
|
159 |
-
// Can't determine S3 bucket or key, continue
|
160 |
-
continue;
|
161 |
-
}
|
162 |
-
|
163 |
-
if ( false !== strpos( $path, $meta['bucket'] ) ) {
|
164 |
-
// Bucket in path, remove
|
165 |
-
$path = ltrim( str_replace( $meta['bucket'], '', $path ), '/' );
|
166 |
-
}
|
167 |
-
|
168 |
-
if ( $path === $meta['key'] ) {
|
169 |
-
// Exact match, return ID
|
170 |
-
$this->query_cache[ $full_url ] = $results[0]->post_id;
|
171 |
-
|
172 |
-
return $result->post_id;
|
173 |
-
}
|
174 |
-
}
|
175 |
|
176 |
-
|
177 |
-
$this->query_cache[ $full_url ] = false;
|
178 |
|
179 |
-
return
|
180 |
}
|
181 |
|
182 |
/**
|
@@ -223,7 +171,7 @@ class AS3CF_S3_To_Local extends AS3CF_Filter {
|
|
223 |
* @return string
|
224 |
*/
|
225 |
protected function normalize_replace_value( $url ) {
|
226 |
-
return
|
227 |
}
|
228 |
|
229 |
/**
|
1 |
<?php
|
2 |
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
4 |
+
|
5 |
class AS3CF_S3_To_Local extends AS3CF_Filter {
|
6 |
|
7 |
/**
|
112 |
*
|
113 |
* @return bool|int
|
114 |
*/
|
115 |
+
public function get_attachment_id_from_url( $url ) {
|
|
|
|
|
116 |
$full_url = AS3CF_Utils::remove_size_from_filename( $url );
|
117 |
|
118 |
+
// Result for URL already cached in request whether found or not, return it.
|
119 |
if ( isset( $this->query_cache[ $full_url ] ) ) {
|
|
|
120 |
return $this->query_cache[ $full_url ];
|
121 |
}
|
122 |
|
123 |
+
$post_id = Media_Library_Item::get_source_id_by_remote_url( $full_url );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
125 |
+
$this->query_cache[ $full_url ] = $post_id;
|
|
|
126 |
|
127 |
+
return $post_id;
|
128 |
}
|
129 |
|
130 |
/**
|
171 |
* @return string
|
172 |
*/
|
173 |
protected function normalize_replace_value( $url ) {
|
174 |
+
return AS3CF_Utils::decode_filename_in_path( $url );
|
175 |
}
|
176 |
|
177 |
/**
|
classes/items/item.php
ADDED
@@ -0,0 +1,794 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
+
|
5 |
+
use Amazon_S3_And_CloudFront;
|
6 |
+
use AS3CF_Utils;
|
7 |
+
use WP_Error;
|
8 |
+
|
9 |
+
abstract class Item {
|
10 |
+
const ITEMS_TABLE = 'as3cf_items';
|
11 |
+
|
12 |
+
protected static $source_type = 'media-library';
|
13 |
+
protected static $source_table = 'posts';
|
14 |
+
protected static $source_fk = 'id';
|
15 |
+
|
16 |
+
private static $checked_table_exists = array();
|
17 |
+
|
18 |
+
protected static $items_cache_by_id = array();
|
19 |
+
protected static $items_cache_by_source_id = array();
|
20 |
+
protected static $items_cache_by_path = array();
|
21 |
+
protected static $items_cache_by_source_path = array();
|
22 |
+
|
23 |
+
private $id;
|
24 |
+
private $provider;
|
25 |
+
private $region;
|
26 |
+
private $bucket;
|
27 |
+
private $path;
|
28 |
+
private $original_path;
|
29 |
+
private $is_private;
|
30 |
+
private $source_id;
|
31 |
+
private $source_path;
|
32 |
+
private $original_source_path;
|
33 |
+
private $extra_info;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Item constructor.
|
37 |
+
*
|
38 |
+
* @param string $provider Storage provider key name, e.g. "aws".
|
39 |
+
* @param string $region Region for item's bucket.
|
40 |
+
* @param string $bucket Bucket for item.
|
41 |
+
* @param string $path Key path for item (full sized if type has thumbnails etc).
|
42 |
+
* @param bool $is_private Is the object private in the bucket.
|
43 |
+
* @param int $source_id ID that source has.
|
44 |
+
* @param string $source_path Path that source uses, could be relative or absolute depending on source.
|
45 |
+
* @param string $original_filename An optional filename with no path that was previously used for the item.
|
46 |
+
* @param array $extra_info An optional array of extra data specific to the source type.
|
47 |
+
* @param null $id Optional Item record ID.
|
48 |
+
*/
|
49 |
+
public function __construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename = null, $extra_info = array(), $id = null ) {
|
50 |
+
$this->provider = $provider;
|
51 |
+
$this->region = $region;
|
52 |
+
$this->bucket = $bucket;
|
53 |
+
$this->path = $path;
|
54 |
+
$this->is_private = $is_private;
|
55 |
+
$this->source_id = $source_id;
|
56 |
+
$this->source_path = $source_path;
|
57 |
+
$this->extra_info = serialize( $extra_info );
|
58 |
+
|
59 |
+
if ( empty( $original_filename ) ) {
|
60 |
+
$this->original_path = $path;
|
61 |
+
$this->original_source_path = $source_path;
|
62 |
+
} else {
|
63 |
+
$this->original_path = str_replace( wp_basename( $path ), $original_filename, $path );
|
64 |
+
$this->original_source_path = str_replace( wp_basename( $source_path ), $original_filename, $source_path );
|
65 |
+
}
|
66 |
+
|
67 |
+
if ( ! empty( $id ) ) {
|
68 |
+
$this->id = $id;
|
69 |
+
}
|
70 |
+
|
71 |
+
static::add_to_items_cache( $this );
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* (Re)initialize the static cache used for speeding up queries.
|
76 |
+
*/
|
77 |
+
public static function init_cache() {
|
78 |
+
self::$checked_table_exists = array();
|
79 |
+
|
80 |
+
static::$items_cache_by_id = array();
|
81 |
+
static::$items_cache_by_source_id = array();
|
82 |
+
static::$items_cache_by_path = array();
|
83 |
+
static::$items_cache_by_source_path = array();
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Add an item to the static cache to allow fast retrieval via get_from_items_cache_by_* functions.
|
88 |
+
*
|
89 |
+
* @param Item $item
|
90 |
+
*/
|
91 |
+
protected static function add_to_items_cache( $item ) {
|
92 |
+
$blog_id = get_current_blog_id();
|
93 |
+
|
94 |
+
if ( ! empty( $item->id() ) ) {
|
95 |
+
static::$items_cache_by_id[ $blog_id ][ $item->id() ] = $item;
|
96 |
+
}
|
97 |
+
|
98 |
+
if ( ! empty( $item->source_id() ) ) {
|
99 |
+
static::$items_cache_by_source_id[ $blog_id ][ static::$source_type ][ $item->source_id() ] = $item;
|
100 |
+
}
|
101 |
+
|
102 |
+
if ( ! empty( $item->path() ) ) {
|
103 |
+
static::$items_cache_by_path[ $blog_id ][ static::$source_type ][ $item->original_path() ] = $item;
|
104 |
+
static::$items_cache_by_path[ $blog_id ][ static::$source_type ][ $item->path() ] = $item;
|
105 |
+
}
|
106 |
+
|
107 |
+
if ( ! empty( $item->source_path() ) ) {
|
108 |
+
static::$items_cache_by_source_path[ $blog_id ][ static::$source_type ][ $item->original_source_path() ] = $item;
|
109 |
+
static::$items_cache_by_source_path[ $blog_id ][ static::$source_type ][ $item->source_path() ] = $item;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Add an item to the static cache to allow fast retrieval via get_from_items_cache_by_* functions.
|
115 |
+
*
|
116 |
+
* @param Item $item
|
117 |
+
*/
|
118 |
+
protected static function remove_from_items_cache( $item ) {
|
119 |
+
$blog_id = get_current_blog_id();
|
120 |
+
|
121 |
+
if ( ! empty( $item->id() ) ) {
|
122 |
+
unset( static::$items_cache_by_id[ $blog_id ][ $item->id() ] );
|
123 |
+
}
|
124 |
+
|
125 |
+
if ( ! empty( $item->source_id() ) ) {
|
126 |
+
unset( static::$items_cache_by_source_id[ $blog_id ][ static::$source_type ][ $item->source_id() ] );
|
127 |
+
}
|
128 |
+
|
129 |
+
if ( ! empty( $item->path() ) ) {
|
130 |
+
unset( static::$items_cache_by_path[ $blog_id ][ static::$source_type ][ $item->original_path() ] );
|
131 |
+
unset( static::$items_cache_by_path[ $blog_id ][ static::$source_type ][ $item->path() ] );
|
132 |
+
}
|
133 |
+
|
134 |
+
if ( ! empty( $item->source_path() ) ) {
|
135 |
+
unset( static::$items_cache_by_source_path[ $blog_id ][ static::$source_type ][ $item->original_source_path() ] );
|
136 |
+
unset( static::$items_cache_by_source_path[ $blog_id ][ static::$source_type ][ $item->source_path() ] );
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Try and get Item from cache by known id.
|
142 |
+
*
|
143 |
+
* @param int $id
|
144 |
+
*
|
145 |
+
* @return bool|Item
|
146 |
+
*/
|
147 |
+
private static function get_from_items_cache_by_id( $id ) {
|
148 |
+
$blog_id = get_current_blog_id();
|
149 |
+
|
150 |
+
if ( ! empty( static::$items_cache_by_id[ $blog_id ][ $id ] ) ) {
|
151 |
+
return static::$items_cache_by_id[ $blog_id ][ $id ];
|
152 |
+
}
|
153 |
+
|
154 |
+
return false;
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Try and get Item from cache by known source_id.
|
159 |
+
*
|
160 |
+
* @param int $source_id
|
161 |
+
*
|
162 |
+
* @return bool|Item
|
163 |
+
*/
|
164 |
+
private static function get_from_items_cache_by_source_id( $source_id ) {
|
165 |
+
$blog_id = get_current_blog_id();
|
166 |
+
|
167 |
+
if ( ! empty( static::$items_cache_by_source_id[ $blog_id ][ static::$source_type ][ $source_id ] ) ) {
|
168 |
+
return static::$items_cache_by_source_id[ $blog_id ][ static::$source_type ][ $source_id ];
|
169 |
+
}
|
170 |
+
|
171 |
+
return false;
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Try and get Item from cache by known bucket and path.
|
176 |
+
*
|
177 |
+
* @param string $bucket
|
178 |
+
* @param string $path
|
179 |
+
*
|
180 |
+
* @return bool|Item
|
181 |
+
*/
|
182 |
+
private static function get_from_items_cache_by_bucket_and_path( $bucket, $path ) {
|
183 |
+
$blog_id = get_current_blog_id();
|
184 |
+
|
185 |
+
if ( ! empty( static::$items_cache_by_path[ $blog_id ][ static::$source_type ][ $path ] ) ) {
|
186 |
+
/** @var Item $item */
|
187 |
+
$item = static::$items_cache_by_path[ $blog_id ][ static::$source_type ][ $path ];
|
188 |
+
|
189 |
+
if ( $item->bucket() === $bucket ) {
|
190 |
+
return $item;
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
return false;
|
195 |
+
}
|
196 |
+
|
197 |
+
/**
|
198 |
+
* The full items table name for current blog.
|
199 |
+
*
|
200 |
+
* @return string
|
201 |
+
*/
|
202 |
+
protected static function items_table() {
|
203 |
+
global $wpdb;
|
204 |
+
|
205 |
+
/* @var Amazon_S3_And_CloudFront $as3cf */
|
206 |
+
global $as3cf;
|
207 |
+
|
208 |
+
$table_name = $wpdb->get_blog_prefix() . static::ITEMS_TABLE;
|
209 |
+
|
210 |
+
if ( empty( self::$checked_table_exists[ $table_name ] ) ) {
|
211 |
+
self::$checked_table_exists[ $table_name ] = true;
|
212 |
+
|
213 |
+
$schema_version = get_option( $as3cf->get_plugin_prefix() . '_schema_version', '0.0.0' );
|
214 |
+
|
215 |
+
if ( version_compare( $schema_version, $as3cf->get_plugin_version(), '<' ) ) {
|
216 |
+
self::install_table( $table_name );
|
217 |
+
|
218 |
+
update_option( $as3cf->get_plugin_prefix() . '_schema_version', $as3cf->get_plugin_version() );
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
return $table_name;
|
223 |
+
}
|
224 |
+
|
225 |
+
/**
|
226 |
+
* Create the table needed by this class with given name (for current site).
|
227 |
+
*
|
228 |
+
* @param string $table_name
|
229 |
+
*/
|
230 |
+
private static function install_table( $table_name ) {
|
231 |
+
global $wpdb;
|
232 |
+
|
233 |
+
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
|
234 |
+
|
235 |
+
$wpdb->hide_errors();
|
236 |
+
|
237 |
+
$charset_collate = $wpdb->get_charset_collate();
|
238 |
+
|
239 |
+
$sql = "
|
240 |
+
CREATE TABLE {$table_name} (
|
241 |
+
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
242 |
+
provider VARCHAR(18) NOT NULL,
|
243 |
+
region VARCHAR(255) NOT NULL,
|
244 |
+
bucket VARCHAR(255) NOT NULL,
|
245 |
+
path VARCHAR(1024) NOT NULL,
|
246 |
+
original_path VARCHAR(1024) NOT NULL,
|
247 |
+
is_private BOOLEAN NOT NULL DEFAULT 0,
|
248 |
+
source_type VARCHAR(18) NOT NULL,
|
249 |
+
source_id BIGINT(20) NOT NULL,
|
250 |
+
source_path VARCHAR(1024) NOT NULL,
|
251 |
+
original_source_path VARCHAR(1024) NOT NULL,
|
252 |
+
extra_info LONGTEXT,
|
253 |
+
PRIMARY KEY (id),
|
254 |
+
UNIQUE KEY uidx_path (path(190), id),
|
255 |
+
UNIQUE KEY uidx_original_path (original_path(190), id),
|
256 |
+
UNIQUE KEY uidx_source_path (source_path(190), id),
|
257 |
+
UNIQUE KEY uidx_original_source_path (original_source_path(190), id),
|
258 |
+
UNIQUE KEY uidx_source (source_type, source_id),
|
259 |
+
UNIQUE KEY uidx_provider_bucket (provider, bucket(190), id)
|
260 |
+
) $charset_collate;
|
261 |
+
";
|
262 |
+
dbDelta( $sql );
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Get item's data as an array, optionally with id if available.
|
267 |
+
*
|
268 |
+
* @param bool $include_id Default false.
|
269 |
+
*
|
270 |
+
* @return array
|
271 |
+
*/
|
272 |
+
public function key_values( $include_id = false ) {
|
273 |
+
$key_values = array(
|
274 |
+
'provider' => $this->provider,
|
275 |
+
'region' => $this->region,
|
276 |
+
'bucket' => $this->bucket,
|
277 |
+
'path' => $this->path,
|
278 |
+
'original_path' => $this->original_path,
|
279 |
+
'is_private' => $this->is_private,
|
280 |
+
'source_type' => static::$source_type,
|
281 |
+
'source_id' => $this->source_id,
|
282 |
+
'source_path' => $this->source_path,
|
283 |
+
'original_source_path' => $this->original_source_path,
|
284 |
+
'extra_info' => $this->extra_info,
|
285 |
+
);
|
286 |
+
|
287 |
+
if ( $include_id && ! empty( $this->id ) ) {
|
288 |
+
$key_values['id'] = $this->id;
|
289 |
+
}
|
290 |
+
|
291 |
+
ksort( $key_values );
|
292 |
+
|
293 |
+
return $key_values;
|
294 |
+
}
|
295 |
+
|
296 |
+
/**
|
297 |
+
* All the item's property names in an array, optionally with id if available.
|
298 |
+
*
|
299 |
+
* @param bool $include_id Default false.
|
300 |
+
*
|
301 |
+
* @return array
|
302 |
+
*/
|
303 |
+
private function keys( $include_id = false ) {
|
304 |
+
return array_keys( $this->key_values( $include_id ) );
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* All the item's property values in an array, optionally with id if available.
|
309 |
+
*
|
310 |
+
* @param bool $include_id Default false.
|
311 |
+
*
|
312 |
+
* @return array
|
313 |
+
*/
|
314 |
+
private function values( $include_id = false ) {
|
315 |
+
return array_values( $this->key_values( $include_id ) );
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Get item's column formats as an associative array, optionally with id if available.
|
320 |
+
*
|
321 |
+
* @param bool $include_id Default false.
|
322 |
+
*
|
323 |
+
* @return array
|
324 |
+
*/
|
325 |
+
private function key_formats( $include_id = false ) {
|
326 |
+
$key_values = array(
|
327 |
+
'provider' => '%s',
|
328 |
+
'region' => '%s',
|
329 |
+
'bucket' => '%s',
|
330 |
+
'path' => '%s',
|
331 |
+
'original_path' => '%s',
|
332 |
+
'is_private' => '%s',
|
333 |
+
'source_type' => '%s',
|
334 |
+
'source_id' => '%d',
|
335 |
+
'source_path' => '%s',
|
336 |
+
'original_source_path' => '%s',
|
337 |
+
'extra_info' => '%s',
|
338 |
+
);
|
339 |
+
|
340 |
+
if ( $include_id && ! empty( $this->id ) ) {
|
341 |
+
$key_values['id'] = '%d';
|
342 |
+
}
|
343 |
+
|
344 |
+
ksort( $key_values );
|
345 |
+
|
346 |
+
return $key_values;
|
347 |
+
}
|
348 |
+
|
349 |
+
/**
|
350 |
+
* All the item's column formats in an indexed array, optionally with id if available.
|
351 |
+
*
|
352 |
+
* @param bool $include_id Default false.
|
353 |
+
*
|
354 |
+
* @return array
|
355 |
+
*/
|
356 |
+
private function formats( $include_id = false ) {
|
357 |
+
return array_values( $this->key_formats( $include_id ) );
|
358 |
+
}
|
359 |
+
|
360 |
+
/**
|
361 |
+
* Save the item's current data.
|
362 |
+
*
|
363 |
+
* @return int|WP_Error
|
364 |
+
*/
|
365 |
+
public function save() {
|
366 |
+
global $wpdb;
|
367 |
+
|
368 |
+
if ( empty( $this->id ) ) {
|
369 |
+
$result = $wpdb->insert( static::items_table(), $this->key_values(), $this->formats() );
|
370 |
+
|
371 |
+
if ( $result ) {
|
372 |
+
$this->id = $wpdb->insert_id;
|
373 |
+
|
374 |
+
// Now that the item has an ID it should be (re)cached.
|
375 |
+
self::add_to_items_cache( $this );
|
376 |
+
}
|
377 |
+
} else {
|
378 |
+
$result = $wpdb->update( static::items_table(), $this->key_values(), array( 'id' => $this->id ), $this->formats(), array( '%d' ) );
|
379 |
+
}
|
380 |
+
|
381 |
+
if ( false === $result ) {
|
382 |
+
self::remove_from_items_cache( $this );
|
383 |
+
|
384 |
+
return new WP_Error( 'item_save', 'Error saving item:- ' . $wpdb->last_error );
|
385 |
+
}
|
386 |
+
|
387 |
+
return $this->id;
|
388 |
+
}
|
389 |
+
|
390 |
+
/**
|
391 |
+
* Delete the current item.
|
392 |
+
*
|
393 |
+
* @return bool|WP_Error
|
394 |
+
*/
|
395 |
+
public function delete() {
|
396 |
+
global $wpdb;
|
397 |
+
|
398 |
+
static::remove_from_items_cache( $this );
|
399 |
+
|
400 |
+
if ( empty( $this->id ) ) {
|
401 |
+
return new WP_Error( 'item_delete', 'Error trying to delete item with no id.' );
|
402 |
+
} else {
|
403 |
+
$result = $wpdb->delete( static::items_table(), array( 'id' => $this->id ), array( '%d' ) );
|
404 |
+
}
|
405 |
+
|
406 |
+
if ( ! $result ) {
|
407 |
+
return new WP_Error( 'item_delete', 'Error deleting item:- ' . $wpdb->last_error );
|
408 |
+
}
|
409 |
+
|
410 |
+
return true;
|
411 |
+
}
|
412 |
+
|
413 |
+
/**
|
414 |
+
* Creates an item based on object from database.
|
415 |
+
*
|
416 |
+
* @param object $object
|
417 |
+
*
|
418 |
+
* @return Item
|
419 |
+
*/
|
420 |
+
protected static function create( $object ) {
|
421 |
+
$extra_info = array();
|
422 |
+
|
423 |
+
if ( ! empty( $object->extra_info ) ) {
|
424 |
+
$extra_info = unserialize( $object->extra_info );
|
425 |
+
}
|
426 |
+
|
427 |
+
return new static(
|
428 |
+
$object->provider,
|
429 |
+
$object->region,
|
430 |
+
$object->bucket,
|
431 |
+
$object->path,
|
432 |
+
$object->is_private,
|
433 |
+
$object->source_id,
|
434 |
+
$object->source_path,
|
435 |
+
wp_basename( $object->original_source_path ),
|
436 |
+
$extra_info,
|
437 |
+
$object->id
|
438 |
+
);
|
439 |
+
}
|
440 |
+
|
441 |
+
/**
|
442 |
+
* Get an item by its id.
|
443 |
+
*
|
444 |
+
* @param integer $id
|
445 |
+
*
|
446 |
+
* @return bool|Item
|
447 |
+
*/
|
448 |
+
public static function get_by_id( $id ) {
|
449 |
+
global $wpdb;
|
450 |
+
|
451 |
+
if ( empty( $id ) ) {
|
452 |
+
return false;
|
453 |
+
}
|
454 |
+
|
455 |
+
$item = static::get_from_items_cache_by_id( $id );
|
456 |
+
|
457 |
+
if ( ! empty( $item ) ) {
|
458 |
+
return $item;
|
459 |
+
}
|
460 |
+
|
461 |
+
$sql = $wpdb->prepare( "SELECT * FROM " . static::items_table() . " WHERE source_type = %s AND id = %d", static::$source_type, $id );
|
462 |
+
|
463 |
+
$object = $wpdb->get_row( $sql );
|
464 |
+
|
465 |
+
if ( empty( $object ) ) {
|
466 |
+
return false;
|
467 |
+
}
|
468 |
+
|
469 |
+
return static::create( $object );
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Get an item by its source id.
|
474 |
+
*
|
475 |
+
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
476 |
+
*
|
477 |
+
* @param integer $source_id
|
478 |
+
*
|
479 |
+
* @return bool|Item
|
480 |
+
*/
|
481 |
+
public static function get_by_source_id( $source_id ) {
|
482 |
+
global $wpdb;
|
483 |
+
|
484 |
+
if ( ! is_numeric( $source_id ) ) {
|
485 |
+
return false;
|
486 |
+
}
|
487 |
+
|
488 |
+
$source_id = (int) $source_id;
|
489 |
+
|
490 |
+
if ( empty( $source_id ) ) {
|
491 |
+
return false;
|
492 |
+
}
|
493 |
+
|
494 |
+
$item = static::get_from_items_cache_by_source_id( $source_id );
|
495 |
+
|
496 |
+
if ( ! empty( $item ) ) {
|
497 |
+
return $item;
|
498 |
+
}
|
499 |
+
|
500 |
+
$sql = $wpdb->prepare( "SELECT * FROM " . static::items_table() . " WHERE source_id = %d AND source_type = %s", $source_id, static::$source_type );
|
501 |
+
|
502 |
+
$object = $wpdb->get_row( $sql );
|
503 |
+
|
504 |
+
if ( empty( $object ) ) {
|
505 |
+
return false;
|
506 |
+
}
|
507 |
+
|
508 |
+
return static::create( $object );
|
509 |
+
}
|
510 |
+
|
511 |
+
/**
|
512 |
+
* Getter for item's id value.
|
513 |
+
*
|
514 |
+
* @return integer
|
515 |
+
*/
|
516 |
+
public function id() {
|
517 |
+
return $this->id;
|
518 |
+
}
|
519 |
+
|
520 |
+
/**
|
521 |
+
* Getter for item's provider value.
|
522 |
+
*
|
523 |
+
* @return string
|
524 |
+
*/
|
525 |
+
public function provider() {
|
526 |
+
return $this->provider;
|
527 |
+
}
|
528 |
+
|
529 |
+
/**
|
530 |
+
* Getter for item's region value.
|
531 |
+
*
|
532 |
+
* @return string
|
533 |
+
*/
|
534 |
+
public function region() {
|
535 |
+
return $this->region;
|
536 |
+
}
|
537 |
+
|
538 |
+
/**
|
539 |
+
* Getter for item's bucket value.
|
540 |
+
*
|
541 |
+
* @return string
|
542 |
+
*/
|
543 |
+
public function bucket() {
|
544 |
+
return $this->bucket;
|
545 |
+
}
|
546 |
+
|
547 |
+
/**
|
548 |
+
* Getter for item's path value.
|
549 |
+
*
|
550 |
+
* @return string
|
551 |
+
*/
|
552 |
+
public function path() {
|
553 |
+
return $this->path;
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* Getter for item's original_path value.
|
558 |
+
*
|
559 |
+
* @return string
|
560 |
+
*/
|
561 |
+
public function original_path() {
|
562 |
+
return $this->original_path;
|
563 |
+
}
|
564 |
+
|
565 |
+
/**
|
566 |
+
* Getter for item's is_private value.
|
567 |
+
*
|
568 |
+
* @return bool
|
569 |
+
*/
|
570 |
+
public function is_private() {
|
571 |
+
return (bool) $this->is_private;
|
572 |
+
}
|
573 |
+
|
574 |
+
/**
|
575 |
+
* Getter for item's source_id value.
|
576 |
+
*
|
577 |
+
* @return integer
|
578 |
+
*/
|
579 |
+
public function source_id() {
|
580 |
+
return $this->source_id;
|
581 |
+
}
|
582 |
+
|
583 |
+
/**
|
584 |
+
* Getter for item's source_path value.
|
585 |
+
*
|
586 |
+
* @return string
|
587 |
+
*/
|
588 |
+
public function source_path() {
|
589 |
+
return $this->source_path;
|
590 |
+
}
|
591 |
+
|
592 |
+
/**
|
593 |
+
* Getter for item's original_source_path value.
|
594 |
+
*
|
595 |
+
* @return string
|
596 |
+
*/
|
597 |
+
public function original_source_path() {
|
598 |
+
return $this->original_source_path;
|
599 |
+
}
|
600 |
+
|
601 |
+
/**
|
602 |
+
* Getter for item's extra_info value.
|
603 |
+
*
|
604 |
+
* @return array
|
605 |
+
*/
|
606 |
+
protected function extra_info() {
|
607 |
+
return unserialize( $this->extra_info );
|
608 |
+
}
|
609 |
+
|
610 |
+
/**
|
611 |
+
* Get normalized object path dir.
|
612 |
+
*
|
613 |
+
* @return string
|
614 |
+
*/
|
615 |
+
public function normalized_path_dir() {
|
616 |
+
$directory = dirname( $this->path );
|
617 |
+
|
618 |
+
return ( '.' === $directory ) ? '' : trailingslashit( $directory );
|
619 |
+
}
|
620 |
+
|
621 |
+
/**
|
622 |
+
* Get the first source id for a bucket and path.
|
623 |
+
*
|
624 |
+
* @param string $bucket
|
625 |
+
* @param string $path
|
626 |
+
*
|
627 |
+
* @return int|bool
|
628 |
+
*/
|
629 |
+
public static function get_source_id_by_bucket_and_path( $bucket, $path ) {
|
630 |
+
global $wpdb;
|
631 |
+
|
632 |
+
if ( empty( $bucket ) || empty( $path ) ) {
|
633 |
+
return false;
|
634 |
+
}
|
635 |
+
|
636 |
+
$item = static::get_from_items_cache_by_bucket_and_path( $bucket, $path );
|
637 |
+
|
638 |
+
if ( ! empty( $item ) ) {
|
639 |
+
return $item->source_id();
|
640 |
+
}
|
641 |
+
|
642 |
+
$sql = $wpdb->prepare(
|
643 |
+
"
|
644 |
+
SELECT source_id FROM " . static::items_table() . "
|
645 |
+
WHERE source_type = %s
|
646 |
+
AND bucket = %s
|
647 |
+
AND (path = %s OR original_path = %s)
|
648 |
+
ORDER BY source_id LIMIT 1
|
649 |
+
",
|
650 |
+
static::$source_type,
|
651 |
+
$bucket,
|
652 |
+
$path,
|
653 |
+
$path
|
654 |
+
);
|
655 |
+
|
656 |
+
$result = $wpdb->get_var( $sql );
|
657 |
+
|
658 |
+
return empty( $result ) ? false : (int) $result;
|
659 |
+
}
|
660 |
+
|
661 |
+
/**
|
662 |
+
* Get the source id for a given remote URL.
|
663 |
+
*
|
664 |
+
* @param string $url
|
665 |
+
*
|
666 |
+
* @return int|bool
|
667 |
+
*/
|
668 |
+
public static function get_source_id_by_remote_url( $url ) {
|
669 |
+
global $wpdb;
|
670 |
+
|
671 |
+
$parts = AS3CF_Utils::parse_url( $url );
|
672 |
+
$path = AS3CF_Utils::decode_filename_in_path( ltrim( $parts['path'], '/' ) );
|
673 |
+
|
674 |
+
// Remove the first directory to cater for bucket in path domain settings.
|
675 |
+
if ( false !== strpos( $path, '/' ) ) {
|
676 |
+
$path = explode( '/', $path );
|
677 |
+
array_shift( $path );
|
678 |
+
$path = implode( '/', $path );
|
679 |
+
}
|
680 |
+
|
681 |
+
$sql = $wpdb->prepare(
|
682 |
+
"SELECT * FROM " . static::items_table() . " WHERE source_type = %s AND (path LIKE %s OR original_path LIKE %s);"
|
683 |
+
, static::$source_type
|
684 |
+
, '%' . $path
|
685 |
+
, '%' . $path
|
686 |
+
);
|
687 |
+
|
688 |
+
$results = $wpdb->get_results( $sql );
|
689 |
+
|
690 |
+
// Nothing found, shortcut out.
|
691 |
+
if ( 0 === count( $results ) ) {
|
692 |
+
// TODO: If upgrade in progress, fallback to 'amazonS3_info' in Media_Library_Item override of this function.
|
693 |
+
return false;
|
694 |
+
}
|
695 |
+
|
696 |
+
// Only one attachment matched, return ID.
|
697 |
+
if ( 1 === count( $results ) ) {
|
698 |
+
return $results[0]->source_id;
|
699 |
+
}
|
700 |
+
|
701 |
+
$path = ltrim( $parts['path'], '/' );
|
702 |
+
|
703 |
+
foreach ( $results as $result ) {
|
704 |
+
$as3cf_item = static::create( $result );
|
705 |
+
|
706 |
+
// If item's bucket matches first segment of URL path, remove it from URL path before checking match.
|
707 |
+
if ( 0 === strpos( $path, trailingslashit( $as3cf_item->bucket() ) ) ) {
|
708 |
+
$match_path = ltrim( substr_replace( $path, '', 0, strlen( $as3cf_item->bucket() ) ), '/' );
|
709 |
+
} else {
|
710 |
+
$match_path = $path;
|
711 |
+
}
|
712 |
+
|
713 |
+
// Exact match, return ID.
|
714 |
+
if ( $as3cf_item->path() === $match_path || $as3cf_item->original_path() === $match_path ) {
|
715 |
+
return $as3cf_item->source_id();
|
716 |
+
}
|
717 |
+
}
|
718 |
+
|
719 |
+
return false;
|
720 |
+
}
|
721 |
+
|
722 |
+
/**
|
723 |
+
* Get an array of managed source_ids in descending order.
|
724 |
+
*
|
725 |
+
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
726 |
+
*
|
727 |
+
* @param integer $upper_bound Returned source_ids should be lower than this, use null/0 for no upper bound.
|
728 |
+
* @param integer $limit Maximum number of source_ids to return. Required if not counting.
|
729 |
+
* @param bool $count Just return a count of matching source_ids? Negates $limit, default false.
|
730 |
+
*
|
731 |
+
* @return array|int
|
732 |
+
*/
|
733 |
+
public static function get_source_ids( $upper_bound, $limit, $count = false ) {
|
734 |
+
global $wpdb;
|
735 |
+
|
736 |
+
$args = array( static::$source_type );
|
737 |
+
|
738 |
+
if ( $count ) {
|
739 |
+
$sql = 'SELECT COUNT(DISTINCT source_id)';
|
740 |
+
} else {
|
741 |
+
$sql = 'SELECT DISTINCT source_id';
|
742 |
+
}
|
743 |
+
|
744 |
+
$sql .= ' FROM ' . static::items_table() . ' WHERE source_type = %s';
|
745 |
+
|
746 |
+
if ( ! empty( $upper_bound ) ) {
|
747 |
+
$sql .= ' AND source_id < %d';
|
748 |
+
$args[] = $upper_bound;
|
749 |
+
}
|
750 |
+
|
751 |
+
if ( ! $count ) {
|
752 |
+
$sql .= ' ORDER BY source_id DESC LIMIT %d';
|
753 |
+
$args[] = $limit;
|
754 |
+
}
|
755 |
+
|
756 |
+
$sql = $wpdb->prepare( $sql, $args );
|
757 |
+
|
758 |
+
if ( $count ) {
|
759 |
+
return $wpdb->get_var( $sql );
|
760 |
+
} else {
|
761 |
+
return array_map( 'intval', $wpdb->get_col( $sql ) );
|
762 |
+
}
|
763 |
+
}
|
764 |
+
|
765 |
+
/**
|
766 |
+
* Get an array of un-managed source_ids in descending order.
|
767 |
+
*
|
768 |
+
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
769 |
+
*
|
770 |
+
* @param integer $upper_bound Returned source_ids should be lower than this, use null/0 for no upper bound.
|
771 |
+
* @param integer $limit Maximum number of source_ids to return. Required if not counting.
|
772 |
+
* @param bool $count Just return a count of matching source_ids? Negates $limit, default false.
|
773 |
+
*
|
774 |
+
* @return array|int
|
775 |
+
*
|
776 |
+
* NOTE: Must be overridden by subclass, only reason this is not abstract is because static is preferred.
|
777 |
+
*/
|
778 |
+
public static function get_missing_source_ids( $upper_bound, $limit, $count = false ) {
|
779 |
+
if ( $count ) {
|
780 |
+
return 0;
|
781 |
+
} else {
|
782 |
+
return array();
|
783 |
+
}
|
784 |
+
}
|
785 |
+
|
786 |
+
/**
|
787 |
+
* Get absolute file paths associated with source item.
|
788 |
+
*
|
789 |
+
* @param integer $id
|
790 |
+
*
|
791 |
+
* @return array
|
792 |
+
*/
|
793 |
+
abstract protected function source_paths( $id );
|
794 |
+
}
|
classes/items/media-library-item.php
ADDED
@@ -0,0 +1,450 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
+
|
5 |
+
use Amazon_S3_And_CloudFront;
|
6 |
+
use WP_Error;
|
7 |
+
|
8 |
+
class Media_Library_Item extends Item {
|
9 |
+
private static $attachment_counts = array();
|
10 |
+
private static $attachment_count_skips = array();
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Item constructor.
|
14 |
+
*
|
15 |
+
* @param string $provider Storage provider key name, e.g. "aws".
|
16 |
+
* @param string $region Region for item's bucket.
|
17 |
+
* @param string $bucket Bucket for item.
|
18 |
+
* @param string $path Key path for item (full sized if type has thumbnails etc).
|
19 |
+
* @param bool $is_private Is the object private in the bucket.
|
20 |
+
* @param int $source_id ID that source has.
|
21 |
+
* @param string $source_path Path that source uses, could be relative or absolute depending on source.
|
22 |
+
* @param string $original_filename An optional filename with no path that was previously used for the item.
|
23 |
+
* @param array $private_sizes An optional array of thumbnail sizes that should be private objects in the bucket.
|
24 |
+
* @param null $id Optional Item record ID.
|
25 |
+
*/
|
26 |
+
public function __construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename = null, $private_sizes = array(), $id = null ) {
|
27 |
+
// For Media Library items, the source path should be relative to the Media Library's uploads directory.
|
28 |
+
$uploads = wp_upload_dir();
|
29 |
+
|
30 |
+
if ( false === $uploads['error'] && 0 === strpos( $source_path, $uploads['basedir'] ) ) {
|
31 |
+
$source_path = ltrim( substr( $source_path, strlen( $uploads['basedir'] ) ), DIRECTORY_SEPARATOR );
|
32 |
+
}
|
33 |
+
|
34 |
+
/*
|
35 |
+
* We only need private sizes info at the moment, but just in case we add a bit more extra info...
|
36 |
+
*/
|
37 |
+
|
38 |
+
// Ensure re-hydration is clean.
|
39 |
+
if ( ! empty( $private_sizes['private_sizes'] ) ) {
|
40 |
+
$private_sizes = $private_sizes['private_sizes'];
|
41 |
+
}
|
42 |
+
|
43 |
+
if ( empty( $private_sizes ) || ! is_array( $private_sizes ) ) {
|
44 |
+
$private_sizes = array();
|
45 |
+
}
|
46 |
+
|
47 |
+
$extra_info = array(
|
48 |
+
'private_sizes' => $private_sizes,
|
49 |
+
);
|
50 |
+
|
51 |
+
parent::__construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename, $extra_info, $id );
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* (Re)initialize the static cache used for speeding up queries.
|
56 |
+
*/
|
57 |
+
public static function init_cache() {
|
58 |
+
parent::init_cache();
|
59 |
+
|
60 |
+
self::$attachment_counts = array();
|
61 |
+
self::$attachment_count_skips = array();
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Get the item based on source id.
|
66 |
+
*
|
67 |
+
* @param integer $source_id
|
68 |
+
*
|
69 |
+
* @return bool|Media_Library_Item
|
70 |
+
*/
|
71 |
+
public static function get_by_source_id( $source_id ) {
|
72 |
+
$as3cf_item = parent::get_by_source_id( $source_id );
|
73 |
+
|
74 |
+
if ( ! $as3cf_item ) {
|
75 |
+
$provider_object = static::_legacy_get_attachment_provider_info( $source_id );
|
76 |
+
|
77 |
+
if ( is_array( $provider_object ) ) {
|
78 |
+
$as3cf_item = static::_legacy_provider_info_to_item( $source_id, $provider_object );
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
return $as3cf_item;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Get absolute file paths associated with source item.
|
87 |
+
*
|
88 |
+
* @param integer $id
|
89 |
+
*
|
90 |
+
* @return array
|
91 |
+
*/
|
92 |
+
protected function source_paths( $id ) {
|
93 |
+
$paths = array();
|
94 |
+
|
95 |
+
return $paths;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Get the array of thumbnail sizes that are private in the bucket.
|
100 |
+
*
|
101 |
+
* @return array
|
102 |
+
*/
|
103 |
+
public function private_sizes() {
|
104 |
+
$extra_info = $this->extra_info();
|
105 |
+
|
106 |
+
if ( ! empty( $extra_info['private_sizes'] ) ) {
|
107 |
+
return $extra_info['private_sizes'];
|
108 |
+
}
|
109 |
+
|
110 |
+
return array();
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Get the private status for a specific size.
|
115 |
+
*
|
116 |
+
* @param string $size
|
117 |
+
*
|
118 |
+
* @return bool
|
119 |
+
*/
|
120 |
+
public function is_private_size( $size ) {
|
121 |
+
if ( ( 'original' === $size || empty( $size ) ) ) {
|
122 |
+
return $this->is_private();
|
123 |
+
}
|
124 |
+
|
125 |
+
return in_array( $size, $this->private_sizes() );
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Count attachments on current site.
|
130 |
+
*
|
131 |
+
* @param bool $skip_transient Whether to force database query and skip transient, default false
|
132 |
+
* @param bool $force Whether to force database query and skip static cache, implies $skip_transient, default false
|
133 |
+
*
|
134 |
+
* @return array Keys:
|
135 |
+
* total: Total media count for site (current blog id)
|
136 |
+
* offloaded: Count of offloaded media for site (current blog id)
|
137 |
+
* not_offloaded: Difference between total and offloaded
|
138 |
+
*/
|
139 |
+
public static function count_attachments( $skip_transient = false, $force = false ) {
|
140 |
+
global $wpdb;
|
141 |
+
|
142 |
+
$transient_key = 'as3cf_' . get_current_blog_id() . '_attachment_counts';
|
143 |
+
|
144 |
+
// Been here, done it, won't do it again!
|
145 |
+
// Well, unless this is the first transient skip for the prefix, then we need to do it.
|
146 |
+
if ( ! $force && ! empty( self::$attachment_counts[ $transient_key ] ) && ( false === $skip_transient || ! empty( self::$attachment_count_skips[ $transient_key ] ) ) ) {
|
147 |
+
return self::$attachment_counts[ $transient_key ];
|
148 |
+
}
|
149 |
+
|
150 |
+
if ( $force || $skip_transient || false === ( $result = get_site_transient( $transient_key ) ) ) {
|
151 |
+
// We want to count distinct relative Media Library paths
|
152 |
+
// and ensure type is also attachment as other post types can use the same _wp_attached_file postmeta key.
|
153 |
+
$sql = "
|
154 |
+
SELECT COUNT(DISTINCT p.`ID`) total, COUNT(DISTINCT i.`id`) offloaded, COUNT(DISTINCT m.`meta_value`) total_paths, COUNT(DISTINCT i.`source_path`) offloaded_paths
|
155 |
+
FROM " . $wpdb->postmeta . " AS m
|
156 |
+
LEFT JOIN " . $wpdb->posts . " AS p ON m.post_id = p.ID AND p.`post_type` = 'attachment'
|
157 |
+
LEFT OUTER JOIN " . static::items_table() . " AS i ON p.`ID` = i.`source_id` AND i.`source_type` = 'media-library'
|
158 |
+
WHERE m.`meta_key` = '_wp_attached_file'
|
159 |
+
";
|
160 |
+
|
161 |
+
$result = $wpdb->get_row( $sql, ARRAY_A );
|
162 |
+
|
163 |
+
$result['not_offloaded'] = $result['total'] - $result['offloaded'];
|
164 |
+
$result['not_offloaded_paths'] = max( 0, $result['total_paths'] - $result['offloaded_paths'] );
|
165 |
+
|
166 |
+
ksort( $result );
|
167 |
+
|
168 |
+
set_site_transient( $transient_key, $result, 2 * MINUTE_IN_SECONDS );
|
169 |
+
|
170 |
+
// One way or another we've skipped the transient.
|
171 |
+
self::$attachment_count_skips[ $transient_key ] = true;
|
172 |
+
}
|
173 |
+
|
174 |
+
self::$attachment_counts[ $transient_key ] = $result;
|
175 |
+
|
176 |
+
return $result;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Get an array of un-managed source_ids in descending order.
|
181 |
+
*
|
182 |
+
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
183 |
+
*
|
184 |
+
* @param integer $upper_bound Returned source_ids should be lower than this, use null/0 for no upper bound.
|
185 |
+
* @param integer $limit Maximum number of source_ids to return. Required if not counting.
|
186 |
+
* @param bool $count Just return a count of matching source_ids? Negates $limit, default false.
|
187 |
+
*
|
188 |
+
* @return array|int
|
189 |
+
*/
|
190 |
+
public static function get_missing_source_ids( $upper_bound, $limit, $count = false ) {
|
191 |
+
global $wpdb;
|
192 |
+
|
193 |
+
$args = array( static::$source_type );
|
194 |
+
|
195 |
+
if ( $count ) {
|
196 |
+
$sql = 'SELECT COUNT(DISTINCT posts.ID)';
|
197 |
+
} else {
|
198 |
+
$sql = 'SELECT DISTINCT posts.ID';
|
199 |
+
}
|
200 |
+
|
201 |
+
$sql .= "
|
202 |
+
FROM {$wpdb->prefix}posts AS posts
|
203 |
+
WHERE posts.post_type = 'attachment'
|
204 |
+
AND posts.ID NOT IN (
|
205 |
+
SELECT items.source_id
|
206 |
+
FROM " . static::items_table() . " AS items
|
207 |
+
WHERE items.source_type = %s
|
208 |
+
AND items.source_id = posts.ID
|
209 |
+
)
|
210 |
+
";
|
211 |
+
|
212 |
+
if ( ! empty( $upper_bound ) ) {
|
213 |
+
$sql .= ' AND posts.ID < %d';
|
214 |
+
$args[] = $upper_bound;
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Allow users to exclude certain MIME types from attachments to upload.
|
219 |
+
*
|
220 |
+
* @param array
|
221 |
+
*/
|
222 |
+
$ignored_mime_types = apply_filters( 'as3cf_ignored_mime_types', array() );
|
223 |
+
if ( is_array( $ignored_mime_types ) && ! empty( $ignored_mime_types ) ) {
|
224 |
+
$ignored_mime_types = array_map( 'sanitize_text_field', $ignored_mime_types );
|
225 |
+
$sql .= ' AND posts.post_mime_type NOT IN ("' . implode( '", "', $ignored_mime_types ) . '")';
|
226 |
+
}
|
227 |
+
|
228 |
+
if ( ! $count ) {
|
229 |
+
$sql .= ' ORDER BY posts.ID DESC LIMIT %d';
|
230 |
+
$args[] = $limit;
|
231 |
+
}
|
232 |
+
|
233 |
+
$sql = $wpdb->prepare( $sql, $args );
|
234 |
+
|
235 |
+
if ( $count ) {
|
236 |
+
return $wpdb->get_var( $sql );
|
237 |
+
} else {
|
238 |
+
return array_map( 'intval', $wpdb->get_col( $sql ) );
|
239 |
+
}
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* Search for all items that have the source path(s).
|
244 |
+
*
|
245 |
+
* @param array|string $paths Array of relative source paths.
|
246 |
+
* @param array|int $exclude_source_ids Array of source_ids to exclude from search. Default, none.
|
247 |
+
* @param bool $exact_match Use paths as supplied (true, default), or greedy match on path without extension (e.g. find edited too).
|
248 |
+
* @param bool $first_only Only return first matched item sorted by source_id. Default false.
|
249 |
+
*
|
250 |
+
* @return array
|
251 |
+
*/
|
252 |
+
public static function get_by_source_path( $paths, $exclude_source_ids = array(), $exact_match = true, $first_only = false ) {
|
253 |
+
global $wpdb;
|
254 |
+
|
255 |
+
if ( ! is_array( $paths ) && is_string( $paths ) && ! empty( $paths ) ) {
|
256 |
+
$paths = array( $paths );
|
257 |
+
}
|
258 |
+
|
259 |
+
if ( ! is_array( $paths ) || empty( $paths ) ) {
|
260 |
+
return array();
|
261 |
+
}
|
262 |
+
|
263 |
+
$paths = \AS3CF_Utils::make_upload_file_paths_relative( $paths );
|
264 |
+
|
265 |
+
$args = array( static::$source_type );
|
266 |
+
|
267 |
+
$sql = '
|
268 |
+
SELECT DISTINCT items.*
|
269 |
+
FROM ' . static::items_table() . ' AS items
|
270 |
+
WHERE items.source_type = %s
|
271 |
+
';
|
272 |
+
|
273 |
+
if ( ! empty( $exclude_source_ids ) ) {
|
274 |
+
if ( ! is_array( $exclude_source_ids ) ) {
|
275 |
+
$exclude_source_ids = array( $exclude_source_ids );
|
276 |
+
}
|
277 |
+
|
278 |
+
$sql .= ' AND items.source_id NOT IN (' . join( ',', $exclude_source_ids ) . ')';
|
279 |
+
}
|
280 |
+
|
281 |
+
if ( $exact_match ) {
|
282 |
+
$sql .= ' AND (items.source_path IN ("' . join( '","', $paths ) . '")';
|
283 |
+
$sql .= ' OR items.original_source_path IN ("' . join( '","', $paths ) . '"))';
|
284 |
+
} else {
|
285 |
+
$likes = array_map( function ( $path ) {
|
286 |
+
$ext = '.' . pathinfo( $path, PATHINFO_EXTENSION );
|
287 |
+
$path = substr_replace( $path, '%', -strlen( $ext ) );
|
288 |
+
|
289 |
+
return 'items.source_path LIKE "' . $path . '" OR items.original_source_path LIKE "' . $path . '"';
|
290 |
+
}, $paths );
|
291 |
+
|
292 |
+
$sql .= ' AND (' . join( ' OR ', $likes ) . ')';
|
293 |
+
}
|
294 |
+
|
295 |
+
if ( $first_only ) {
|
296 |
+
$sql .= ' ORDER BY items.source_id LIMIT 1';
|
297 |
+
}
|
298 |
+
|
299 |
+
$sql = $wpdb->prepare( $sql, $args );
|
300 |
+
|
301 |
+
return array_map( 'static::create', $wpdb->get_results( $sql ) );
|
302 |
+
}
|
303 |
+
|
304 |
+
/**
|
305 |
+
* Finds Media Library items with same source_path and sets them as offloaded.
|
306 |
+
*/
|
307 |
+
public function offload_duplicate_items() {
|
308 |
+
global $wpdb;
|
309 |
+
|
310 |
+
$sql = $wpdb->prepare(
|
311 |
+
"
|
312 |
+
SELECT m.post_id
|
313 |
+
FROM " . $wpdb->postmeta . " AS m
|
314 |
+
LEFT JOIN " . $wpdb->posts . " AS p ON m.post_id = p.ID AND p.`post_type` = 'attachment'
|
315 |
+
WHERE m.meta_key = '_wp_attached_file'
|
316 |
+
AND m.meta_value = %s
|
317 |
+
AND m.post_id != %d
|
318 |
+
AND m.post_id NOT IN (
|
319 |
+
SELECT i.source_id
|
320 |
+
FROM " . static::items_table() . " AS i
|
321 |
+
WHERE i.source_type = %s
|
322 |
+
AND i.source_id = m.post_id
|
323 |
+
)
|
324 |
+
;
|
325 |
+
"
|
326 |
+
, $this->source_path()
|
327 |
+
, $this->source_id()
|
328 |
+
, static::$source_type
|
329 |
+
);
|
330 |
+
|
331 |
+
$results = $wpdb->get_results( $sql );
|
332 |
+
|
333 |
+
// Nothing found, shortcut out.
|
334 |
+
if ( 0 === count( $results ) ) {
|
335 |
+
return;
|
336 |
+
}
|
337 |
+
|
338 |
+
foreach ( $results as $result ) {
|
339 |
+
$as3cf_item = new Media_Library_Item(
|
340 |
+
$this->provider(),
|
341 |
+
$this->region(),
|
342 |
+
$this->bucket(),
|
343 |
+
$this->path(),
|
344 |
+
$this->is_private(),
|
345 |
+
$result->post_id,
|
346 |
+
$this->source_path(),
|
347 |
+
wp_basename( $this->original_source_path() ),
|
348 |
+
$this->private_sizes()
|
349 |
+
);
|
350 |
+
$as3cf_item->save();
|
351 |
+
}
|
352 |
+
}
|
353 |
+
|
354 |
+
/*
|
355 |
+
* >>> LEGACY ROUTINES BEGIN >>>
|
356 |
+
*/
|
357 |
+
|
358 |
+
/**
|
359 |
+
* Convert the provider info array for an attachment to item object.
|
360 |
+
*
|
361 |
+
* @param integer $source_id
|
362 |
+
* @param array $provider_info
|
363 |
+
*
|
364 |
+
* @return bool|Media_Library_Item
|
365 |
+
*/
|
366 |
+
private static function _legacy_provider_info_to_item( $source_id, $provider_info ) {
|
367 |
+
$attached_file = get_post_meta( $source_id, '_wp_attached_file', true );
|
368 |
+
|
369 |
+
if ( is_string( $attached_file ) && ! empty( $attached_file ) ) {
|
370 |
+
$private_sizes = array();
|
371 |
+
|
372 |
+
if ( ! empty( $provider_info['sizes'] ) && is_array( $provider_info['sizes'] ) ) {
|
373 |
+
$private_sizes = array_keys( $provider_info['sizes'] );
|
374 |
+
}
|
375 |
+
|
376 |
+
return new static(
|
377 |
+
$provider_info['provider'],
|
378 |
+
$provider_info['region'],
|
379 |
+
$provider_info['bucket'],
|
380 |
+
$provider_info['key'],
|
381 |
+
isset( $provider_info['acl'] ) && false !== strpos( $provider_info['acl'], 'private' ) ? true : false,
|
382 |
+
$source_id,
|
383 |
+
$attached_file,
|
384 |
+
wp_basename( $attached_file ),
|
385 |
+
$private_sizes
|
386 |
+
);
|
387 |
+
}
|
388 |
+
|
389 |
+
return false;
|
390 |
+
}
|
391 |
+
|
392 |
+
/**
|
393 |
+
* Get attachment provider info
|
394 |
+
*
|
395 |
+
* @param int $post_id
|
396 |
+
*
|
397 |
+
* @return bool|array
|
398 |
+
*/
|
399 |
+
private static function _legacy_get_attachment_provider_info( $post_id ) {
|
400 |
+
$provider_object = get_post_meta( $post_id, 'amazonS3_info', true );
|
401 |
+
|
402 |
+
if ( ! empty( $provider_object ) && is_array( $provider_object ) && ! empty( $provider_object['bucket'] ) && ! empty( $provider_object['key'] ) ) {
|
403 |
+
$provider_object = array_merge( array(
|
404 |
+
'provider' => Amazon_S3_And_CloudFront::get_default_provider(),
|
405 |
+
), $provider_object );
|
406 |
+
} else {
|
407 |
+
return false;
|
408 |
+
}
|
409 |
+
|
410 |
+
$provider_object['region'] = static::_legacy_get_provider_object_region( $provider_object );
|
411 |
+
|
412 |
+
if ( is_wp_error( $provider_object['region'] ) ) {
|
413 |
+
return false;
|
414 |
+
}
|
415 |
+
|
416 |
+
$provider_object = apply_filters( 'as3cf_get_attachment_s3_info', $provider_object, $post_id ); // Backwards compatibility
|
417 |
+
|
418 |
+
return apply_filters( 'as3cf_get_attachment_provider_info', $provider_object, $post_id );
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Get the region of the bucket stored in the provider metadata.
|
423 |
+
*
|
424 |
+
* @param array $provider_object
|
425 |
+
*
|
426 |
+
* @return string|WP_Error - region name
|
427 |
+
*/
|
428 |
+
private static function _legacy_get_provider_object_region( $provider_object ) {
|
429 |
+
if ( ! isset( $provider_object['region'] ) ) {
|
430 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
431 |
+
global $as3cf;
|
432 |
+
|
433 |
+
// If region hasn't been stored in the provider metadata retrieve using the bucket.
|
434 |
+
$region = $as3cf->get_bucket_region( $provider_object['bucket'], true );
|
435 |
+
|
436 |
+
// Could just return $region here regardless, but this format is good for debug during legacy migration.
|
437 |
+
if ( is_wp_error( $region ) ) {
|
438 |
+
return $region;
|
439 |
+
}
|
440 |
+
|
441 |
+
$provider_object['region'] = $region;
|
442 |
+
}
|
443 |
+
|
444 |
+
return $provider_object['region'];
|
445 |
+
}
|
446 |
+
|
447 |
+
/*
|
448 |
+
* <<< LEGACY ROUTINES END <<<
|
449 |
+
*/
|
450 |
+
}
|
classes/upgrades/upgrade-file-sizes.php
CHANGED
@@ -12,6 +12,7 @@
|
|
12 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
|
14 |
use AS3CF_Error;
|
|
|
15 |
use Exception;
|
16 |
|
17 |
/**
|
@@ -64,14 +65,19 @@ class Upgrade_File_Sizes extends Upgrade {
|
|
64 |
return false;
|
65 |
}
|
66 |
|
67 |
-
|
68 |
-
|
69 |
-
|
|
|
|
|
70 |
$this->error_count++;
|
71 |
|
72 |
return false;
|
73 |
}
|
74 |
|
|
|
|
|
|
|
75 |
$provider_client = $this->as3cf->get_provider_client( $region, true );
|
76 |
$main_file = $provider_object['key'];
|
77 |
|
12 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
|
14 |
use AS3CF_Error;
|
15 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
16 |
use Exception;
|
17 |
|
18 |
/**
|
65 |
return false;
|
66 |
}
|
67 |
|
68 |
+
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
69 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment->ID );
|
70 |
+
|
71 |
+
if ( ! $as3cf_item ) {
|
72 |
+
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $attachment->ID . ' from legacy offload metadata.' );
|
73 |
$this->error_count++;
|
74 |
|
75 |
return false;
|
76 |
}
|
77 |
|
78 |
+
// $as3cf_item can't exist without a region value, so we can just use it here.
|
79 |
+
$region = $as3cf_item->region();
|
80 |
+
|
81 |
$provider_client = $this->as3cf->get_provider_client( $region, true );
|
82 |
$main_file = $provider_object['key'];
|
83 |
|
classes/upgrades/upgrade-items-table.php
ADDED
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Upgrade Metadata to use custom objects table.
|
4 |
+
*
|
5 |
+
* @package amazon-s3-and-cloudfront
|
6 |
+
* @subpackage Classes/Upgrades/Upgrade_Items_Table
|
7 |
+
* @copyright Copyright (c) 2014, Delicious Brains
|
8 |
+
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
9 |
+
* @since 2.3.0
|
10 |
+
*/
|
11 |
+
|
12 |
+
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
+
|
14 |
+
use AS3CF_Error;
|
15 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
16 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Upgrade_Items_Table Class
|
20 |
+
*
|
21 |
+
* This class handles updating the offload metadata for attachments to use a custom table.
|
22 |
+
*
|
23 |
+
* @since 2.3.0
|
24 |
+
*/
|
25 |
+
class Upgrade_Items_Table extends Upgrade {
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @var int
|
29 |
+
*/
|
30 |
+
protected $upgrade_id = 8;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @var string
|
34 |
+
*/
|
35 |
+
protected $upgrade_name = 'as3cf_items_table';
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @var string 'metadata', 'attachment'
|
39 |
+
*/
|
40 |
+
protected $upgrade_type = 'metadata';
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Get running update text.
|
44 |
+
*
|
45 |
+
* @return string
|
46 |
+
*/
|
47 |
+
protected function get_running_update_text() {
|
48 |
+
return __( 'and updating the plugin\'s metadata to use a faster storage method. During the update the site\'s total offloaded media count may be inaccurate but will settle down shortly after completing.', 'amazon-s3-and-cloudfront' );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Move an attachment's provider object data from the postmeta table to the custom as3cf_objects table.
|
53 |
+
*
|
54 |
+
* @param mixed $attachment
|
55 |
+
*
|
56 |
+
* @return bool
|
57 |
+
*/
|
58 |
+
protected function upgrade_item( $attachment ) {
|
59 |
+
// Make sure legacy metadata isn't broken.
|
60 |
+
$provider_object = unserialize( $attachment->provider_object );
|
61 |
+
|
62 |
+
if ( false === $provider_object ) {
|
63 |
+
AS3CF_Error::log( 'Failed to unserialize legacy offload metadata for attachment ' . $attachment->ID . ': ' . $attachment->provider_object );
|
64 |
+
$this->error_count++;
|
65 |
+
|
66 |
+
return false;
|
67 |
+
}
|
68 |
+
|
69 |
+
if ( empty( $attachment->source_path ) ) {
|
70 |
+
AS3CF_Error::log( 'Attachment with ID ' . $attachment->ID . ' with legacy offload metadata has no local file path.' );
|
71 |
+
$this->error_count++;
|
72 |
+
|
73 |
+
return false;
|
74 |
+
}
|
75 |
+
|
76 |
+
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
77 |
+
// If we're here we already know there's legacy metadata and that there isn't a new items table record yet,
|
78 |
+
// or there's legacy metadata and an existing items table record that we can just re-save without issue before deleting legacy metadata.
|
79 |
+
// An existing items table entry takes precedence over legacy metadata to avoid accidental overrides from migrations, custom code or other plugins.
|
80 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment->ID );
|
81 |
+
|
82 |
+
if ( ! $as3cf_item ) {
|
83 |
+
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $attachment->ID . ' from legacy offload metadata.' );
|
84 |
+
$this->error_count++;
|
85 |
+
|
86 |
+
return false;
|
87 |
+
}
|
88 |
+
|
89 |
+
$result = $as3cf_item->save();
|
90 |
+
|
91 |
+
if ( is_wp_error( $result ) ) {
|
92 |
+
AS3CF_Error::log( 'Error saving item: ' . $result->get_error_message() );
|
93 |
+
$this->error_count++;
|
94 |
+
|
95 |
+
return false;
|
96 |
+
}
|
97 |
+
|
98 |
+
// Delete old metadata.
|
99 |
+
return delete_post_meta( $attachment->ID, 'amazonS3_info' );
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Get a count of all attachments to be processed.
|
104 |
+
* for the whole site
|
105 |
+
*
|
106 |
+
* @return int
|
107 |
+
*/
|
108 |
+
protected function count_items_to_process() {
|
109 |
+
return $this->count_attachments_with_legacy_metadata( $this->blog_prefix );
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Get all attachments to be processed.
|
114 |
+
*
|
115 |
+
* @param string $prefix Table prefix for blog.
|
116 |
+
* @param int $limit
|
117 |
+
* @param bool|mixed $offset
|
118 |
+
*
|
119 |
+
* @return array
|
120 |
+
*/
|
121 |
+
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
122 |
+
$attachments = $this->get_attachments_with_legacy_metadata( $prefix, false, $limit );
|
123 |
+
|
124 |
+
return $attachments;
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Get a count of attachments that have legacy metadata.
|
129 |
+
*
|
130 |
+
* @param string $prefix Table prefix for blog.
|
131 |
+
*
|
132 |
+
* @return int
|
133 |
+
*/
|
134 |
+
protected function count_attachments_with_legacy_metadata( $prefix ) {
|
135 |
+
$count = $this->get_attachments_with_legacy_metadata( $prefix, true );
|
136 |
+
|
137 |
+
return $count;
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Wrapper for database call to get attachments with legacy metadata.
|
142 |
+
*
|
143 |
+
* @param string $prefix Table prefix for blog.
|
144 |
+
* @param bool $count return count of attachments
|
145 |
+
* @param null|int $limit
|
146 |
+
*
|
147 |
+
* @return mixed
|
148 |
+
*/
|
149 |
+
protected function get_attachments_with_legacy_metadata( $prefix, $count = false, $limit = null ) {
|
150 |
+
global $wpdb;
|
151 |
+
|
152 |
+
$sql = "
|
153 |
+
FROM {$prefix}postmeta AS a, {$prefix}postmeta AS p
|
154 |
+
WHERE a.meta_key = '_wp_attached_file'
|
155 |
+
AND p.meta_key = 'amazonS3_info'
|
156 |
+
AND a.post_id = p.post_id
|
157 |
+
";
|
158 |
+
|
159 |
+
if ( $count ) {
|
160 |
+
$sql = 'SELECT COUNT(DISTINCT p.post_id)' . $sql;
|
161 |
+
|
162 |
+
return $wpdb->get_var( $sql );
|
163 |
+
}
|
164 |
+
|
165 |
+
$sql = 'SELECT DISTINCT a.post_id AS ID, a.meta_value AS source_path, p.meta_value AS provider_object' . $sql;
|
166 |
+
$sql .= ' ORDER BY p.post_id, p.meta_id';
|
167 |
+
|
168 |
+
if ( $limit && $limit > 0 ) {
|
169 |
+
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
170 |
+
}
|
171 |
+
|
172 |
+
return $wpdb->get_results( $sql, OBJECT );
|
173 |
+
}
|
174 |
+
}
|
classes/upgrades/upgrade-region-meta.php
CHANGED
@@ -12,6 +12,7 @@
|
|
12 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
|
14 |
use AS3CF_Error;
|
|
|
15 |
|
16 |
/**
|
17 |
* Upgrade_Region_Meta Class
|
@@ -61,10 +62,24 @@ class Upgrade_Region_Meta extends Upgrade {
|
|
61 |
|
62 |
return false;
|
63 |
}
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
$this->error_count++;
|
69 |
|
70 |
return false;
|
12 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
|
14 |
use AS3CF_Error;
|
15 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
16 |
|
17 |
/**
|
18 |
* Upgrade_Region_Meta Class
|
62 |
|
63 |
return false;
|
64 |
}
|
65 |
+
|
66 |
+
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
67 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment->ID );
|
68 |
+
|
69 |
+
if ( ! $as3cf_item ) {
|
70 |
+
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $attachment->ID . ' from legacy offload metadata.' );
|
71 |
+
$this->error_count++;
|
72 |
+
|
73 |
+
return false;
|
74 |
+
}
|
75 |
+
|
76 |
+
// Update legacy amazonS3_info record with region required for subsequent upgrades.
|
77 |
+
$provider_object['region'] = $as3cf_item->region();
|
78 |
+
|
79 |
+
$result = update_post_meta( $attachment->ID, 'amazonS3_info', $provider_object );
|
80 |
+
|
81 |
+
if ( false === $result ) {
|
82 |
+
AS3CF_Error::log( 'Error updating region in legacy offload metadata for attachment ' . $attachment->ID );
|
83 |
$this->error_count++;
|
84 |
|
85 |
return false;
|
classes/upgrades/upgrade.php
CHANGED
@@ -12,6 +12,7 @@
|
|
12 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
|
14 |
use Amazon_S3_And_CloudFront;
|
|
|
15 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\No_More_Blogs_Exception;
|
16 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Batch_Limits_Exceeded_Exception;
|
17 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Too_Many_Errors_Exception;
|
@@ -84,7 +85,7 @@ abstract class Upgrade {
|
|
84 |
/**
|
85 |
* @var string
|
86 |
*/
|
87 |
-
|
88 |
|
89 |
/**
|
90 |
* @var int Time limit in seconds.
|
@@ -208,6 +209,9 @@ abstract class Upgrade {
|
|
208 |
if ( $this->is_running() ) {
|
209 |
// Make sure cron job is persisted in case it has dropped
|
210 |
$this->schedule();
|
|
|
|
|
|
|
211 |
}
|
212 |
|
213 |
return false;
|
@@ -412,7 +416,7 @@ abstract class Upgrade {
|
|
412 |
break;
|
413 |
case self::STATUS_ERROR:
|
414 |
$msg = $this->get_error_message();
|
415 |
-
$action_text = __( 'Try Run It Again', 'amazon-s3-and-cloudfront' );
|
416 |
$msg_type = 'error';
|
417 |
break;
|
418 |
default:
|
@@ -503,7 +507,7 @@ abstract class Upgrade {
|
|
503 |
} else {
|
504 |
// Set up any per-site state
|
505 |
$this->switch_to_blog( get_current_blog_id() );
|
506 |
-
$counts =
|
507 |
|
508 |
// If there are no attachments, disable progress calculation
|
509 |
// and protect against division by zero.
|
@@ -565,8 +569,7 @@ abstract class Upgrade {
|
|
565 |
* Restart upgrade
|
566 |
*/
|
567 |
protected function action_restart_update() {
|
568 |
-
$this->
|
569 |
-
$this->change_status_request( self::STATUS_RUNNING );
|
570 |
}
|
571 |
|
572 |
/**
|
@@ -646,7 +649,7 @@ abstract class Upgrade {
|
|
646 |
* @return array
|
647 |
*/
|
648 |
protected function get_session() {
|
649 |
-
return get_site_option( '
|
650 |
}
|
651 |
|
652 |
/**
|
@@ -655,7 +658,7 @@ abstract class Upgrade {
|
|
655 |
* @param array $session session data to store
|
656 |
*/
|
657 |
protected function save_session( $session ) {
|
658 |
-
update_site_option( '
|
659 |
}
|
660 |
|
661 |
/**
|
@@ -663,7 +666,7 @@ abstract class Upgrade {
|
|
663 |
*
|
664 |
*/
|
665 |
protected function clear_session() {
|
666 |
-
delete_site_option( '
|
667 |
}
|
668 |
|
669 |
/**
|
@@ -703,7 +706,7 @@ abstract class Upgrade {
|
|
703 |
* Lock upgrade.
|
704 |
*/
|
705 |
protected function lock_upgrade() {
|
706 |
-
set_site_transient(
|
707 |
}
|
708 |
|
709 |
/**
|
@@ -712,7 +715,7 @@ abstract class Upgrade {
|
|
712 |
* Voids the lock after 1 second rather than deleting to avoid a race condition.
|
713 |
*/
|
714 |
protected function unlock_upgrade() {
|
715 |
-
set_site_transient(
|
716 |
}
|
717 |
|
718 |
/**
|
@@ -720,8 +723,8 @@ abstract class Upgrade {
|
|
720 |
*
|
721 |
* @return bool
|
722 |
*/
|
723 |
-
|
724 |
-
return false !== get_site_transient(
|
725 |
}
|
726 |
|
727 |
/**
|
12 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
|
14 |
use Amazon_S3_And_CloudFront;
|
15 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
16 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\No_More_Blogs_Exception;
|
17 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Batch_Limits_Exceeded_Exception;
|
18 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Too_Many_Errors_Exception;
|
85 |
/**
|
86 |
* @var string
|
87 |
*/
|
88 |
+
public static $lock_key = 'as3cf_upgrade_lock';
|
89 |
|
90 |
/**
|
91 |
* @var int Time limit in seconds.
|
209 |
if ( $this->is_running() ) {
|
210 |
// Make sure cron job is persisted in case it has dropped
|
211 |
$this->schedule();
|
212 |
+
} else {
|
213 |
+
// Refresh the lock to stop anything from interfering while paused.
|
214 |
+
$this->lock_upgrade();
|
215 |
}
|
216 |
|
217 |
return false;
|
416 |
break;
|
417 |
case self::STATUS_ERROR:
|
418 |
$msg = $this->get_error_message();
|
419 |
+
$action_text = __( 'Try To Run It Again', 'amazon-s3-and-cloudfront' );
|
420 |
$msg_type = 'error';
|
421 |
break;
|
422 |
default:
|
507 |
} else {
|
508 |
// Set up any per-site state
|
509 |
$this->switch_to_blog( get_current_blog_id() );
|
510 |
+
$counts = Media_Library_Item::count_attachments();
|
511 |
|
512 |
// If there are no attachments, disable progress calculation
|
513 |
// and protect against division by zero.
|
569 |
* Restart upgrade
|
570 |
*/
|
571 |
protected function action_restart_update() {
|
572 |
+
$this->init();
|
|
|
573 |
}
|
574 |
|
575 |
/**
|
649 |
* @return array
|
650 |
*/
|
651 |
protected function get_session() {
|
652 |
+
return get_site_option( 'as3cf_update_' . $this->upgrade_name . '_session', array() );
|
653 |
}
|
654 |
|
655 |
/**
|
658 |
* @param array $session session data to store
|
659 |
*/
|
660 |
protected function save_session( $session ) {
|
661 |
+
update_site_option( 'as3cf_update_' . $this->upgrade_name . '_session', $session );
|
662 |
}
|
663 |
|
664 |
/**
|
666 |
*
|
667 |
*/
|
668 |
protected function clear_session() {
|
669 |
+
delete_site_option( 'as3cf_update_' . $this->upgrade_name . '_session' );
|
670 |
}
|
671 |
|
672 |
/**
|
706 |
* Lock upgrade.
|
707 |
*/
|
708 |
protected function lock_upgrade() {
|
709 |
+
set_site_transient( static::$lock_key, $this->upgrade_id, MINUTE_IN_SECONDS * 3 );
|
710 |
}
|
711 |
|
712 |
/**
|
715 |
* Voids the lock after 1 second rather than deleting to avoid a race condition.
|
716 |
*/
|
717 |
protected function unlock_upgrade() {
|
718 |
+
set_site_transient( static::$lock_key, $this->upgrade_id, 1 );
|
719 |
}
|
720 |
|
721 |
/**
|
723 |
*
|
724 |
* @return bool
|
725 |
*/
|
726 |
+
public static function is_locked() {
|
727 |
+
return false !== get_site_transient( static::$lock_key );
|
728 |
}
|
729 |
|
730 |
/**
|
languages/amazon-s3-and-cloudfront-en.pot
CHANGED
@@ -8,7 +8,7 @@ msgid ""
|
|
8 |
msgstr ""
|
9 |
"Project-Id-Version: amazon-s3-and-cloudfront\n"
|
10 |
"Report-Msgid-Bugs-To: nom@deliciousbrains.com\n"
|
11 |
-
"POT-Creation-Date: 2019-
|
12 |
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
@@ -17,177 +17,182 @@ msgstr ""
|
|
17 |
"Content-Type: text/plain; charset=UTF-8\n"
|
18 |
"Content-Transfer-Encoding: 8bit\n"
|
19 |
|
20 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
21 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
22 |
msgid "Offload Media Lite"
|
23 |
msgstr ""
|
24 |
|
25 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
26 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
27 |
msgid "Unknown"
|
28 |
msgstr ""
|
29 |
|
30 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
31 |
#: view/bucket-setting.php:17
|
32 |
#: view/provider-select.php:122
|
33 |
msgid "defined in wp-config.php"
|
34 |
msgstr ""
|
35 |
|
36 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
38 |
#, php-format
|
39 |
msgid "File %s does not exist"
|
40 |
msgstr ""
|
41 |
|
42 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
43 |
#, php-format
|
44 |
msgid "Mime type %s is not allowed"
|
45 |
msgstr ""
|
46 |
|
47 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
48 |
msgid "Already offloaded to a different provider"
|
49 |
msgstr ""
|
50 |
|
51 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
52 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
53 |
#, php-format
|
54 |
msgid "Error offloading %s to provider: %s"
|
55 |
msgstr ""
|
56 |
|
57 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
58 |
msgid "This action can only be performed through an admin screen."
|
59 |
msgstr ""
|
60 |
|
61 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
62 |
msgid "Cheatin’ eh?"
|
63 |
msgstr ""
|
64 |
|
65 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
66 |
msgid "You do not have sufficient permissions to access this page."
|
67 |
msgstr ""
|
68 |
|
69 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
70 |
msgid "Error Getting Bucket Region"
|
71 |
msgstr ""
|
72 |
|
73 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
74 |
#, php-format
|
75 |
msgid "There was an error attempting to get the region of the bucket %s: %s"
|
76 |
msgstr ""
|
77 |
|
78 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
79 |
msgid ""
|
80 |
"This is a test file to check if the user has write permission to the bucket. "
|
81 |
"Delete me if found."
|
82 |
msgstr ""
|
83 |
|
84 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
85 |
#, php-format
|
86 |
msgid ""
|
87 |
"There was an error attempting to check the permissions of the bucket %s: %s"
|
88 |
msgstr ""
|
89 |
|
90 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
91 |
msgid "Error creating bucket"
|
92 |
msgstr ""
|
93 |
|
94 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
95 |
msgid "Bucket name too short."
|
96 |
msgstr ""
|
97 |
|
98 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
99 |
msgid "Bucket name too long."
|
100 |
msgstr ""
|
101 |
|
102 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
103 |
msgid ""
|
104 |
"Invalid character. Bucket names can contain lowercase letters, numbers, "
|
105 |
"periods and hyphens."
|
106 |
msgstr ""
|
107 |
|
108 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
109 |
msgid "Error saving bucket"
|
110 |
msgstr ""
|
111 |
|
112 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
113 |
msgid "Error fetching buckets"
|
114 |
msgstr ""
|
115 |
|
116 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
117 |
msgid "Error getting URL preview: "
|
118 |
msgstr ""
|
119 |
|
120 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
121 |
msgid "The changes you made will be lost if you navigate away from this page"
|
122 |
msgstr ""
|
123 |
|
124 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
125 |
msgid "Getting diagnostic info..."
|
126 |
msgstr ""
|
127 |
|
128 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
129 |
msgid "Error getting diagnostic info: "
|
130 |
msgstr ""
|
131 |
|
132 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
133 |
msgctxt "placeholder for hidden access key, 39 char max"
|
134 |
msgid "-- not shown --"
|
135 |
msgstr ""
|
136 |
|
137 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
138 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
139 |
msgid "Settings saved."
|
140 |
msgstr ""
|
141 |
|
142 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
143 |
msgid "Cheatin' eh?"
|
144 |
msgstr ""
|
145 |
|
146 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
147 |
msgid "No bucket name provided."
|
148 |
msgstr ""
|
149 |
|
150 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
151 |
msgid "Bucket name not valid."
|
152 |
msgstr ""
|
153 |
|
154 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
155 |
msgid "No region provided."
|
156 |
msgstr ""
|
157 |
|
158 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
159 |
#: view/provider-select.php:329
|
160 |
msgctxt "placeholder for hidden secret access key, 39 char max"
|
161 |
msgid "-- not shown --"
|
162 |
msgstr ""
|
163 |
|
164 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
165 |
msgid "Key File not valid JSON."
|
166 |
msgstr ""
|
167 |
|
168 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
169 |
msgctxt "Show the media library tab"
|
170 |
msgid "Media Library"
|
171 |
msgstr ""
|
172 |
|
173 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
174 |
msgctxt "Show the addons tab"
|
175 |
msgid "Addons"
|
176 |
msgstr ""
|
177 |
|
178 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
179 |
msgctxt "Show the support tab"
|
180 |
msgid "Support"
|
181 |
msgstr ""
|
182 |
|
183 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
184 |
#, php-format
|
185 |
msgid ""
|
186 |
"<strong>WP Offload Media</strong> — The file %s has been given %s "
|
187 |
"permissions in the bucket."
|
188 |
msgstr ""
|
189 |
|
190 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
191 |
msgid ""
|
192 |
"<strong>WP Offload Media Requirement Missing</strong> — Looks like you "
|
193 |
"don't have an image manipulation library installed on this server and "
|
@@ -195,18 +200,18 @@ msgid ""
|
|
195 |
"Please setup GD or ImageMagick."
|
196 |
msgstr ""
|
197 |
|
198 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
199 |
#, php-format
|
200 |
msgid ""
|
201 |
"<a href=\"%s\">Define your access keys</a> to enable write access to the "
|
202 |
"bucket"
|
203 |
msgstr ""
|
204 |
|
205 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
206 |
msgid "Quick Start Guide"
|
207 |
msgstr ""
|
208 |
|
209 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
210 |
#, php-format
|
211 |
msgid ""
|
212 |
"Looks like we don't have write access to this bucket. It's likely that the "
|
@@ -215,7 +220,7 @@ msgid ""
|
|
215 |
"correctly."
|
216 |
msgstr ""
|
217 |
|
218 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
219 |
#, php-format
|
220 |
msgid ""
|
221 |
"Looks like we don't have access to the buckets. It's likely that the user "
|
@@ -223,39 +228,39 @@ msgid ""
|
|
223 |
"Please see our %s for instructions on setting up permissions correctly."
|
224 |
msgstr ""
|
225 |
|
226 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
227 |
msgid "WP Offload Media Activation"
|
228 |
msgstr ""
|
229 |
|
230 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
231 |
msgid ""
|
232 |
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
|
233 |
"automatically deactivated WP Offload Media Lite."
|
234 |
msgstr ""
|
235 |
|
236 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
237 |
msgid "WP Offload Media Lite Activation"
|
238 |
msgstr ""
|
239 |
|
240 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
241 |
msgid ""
|
242 |
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
|
243 |
"automatically deactivated WP Offload Media."
|
244 |
msgstr ""
|
245 |
|
246 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
247 |
msgid "More info »"
|
248 |
msgstr ""
|
249 |
|
250 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
251 |
msgid "this doc"
|
252 |
msgstr ""
|
253 |
|
254 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
255 |
msgid "WP Offload Media Feature Removed"
|
256 |
msgstr ""
|
257 |
|
258 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
259 |
#, php-format
|
260 |
msgid ""
|
261 |
"You had the \"Always non-SSL\" option selected in your settings, but we've "
|
@@ -266,59 +271,59 @@ msgid ""
|
|
266 |
"to the old behavior."
|
267 |
msgstr ""
|
268 |
|
269 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
270 |
msgid "Offload"
|
271 |
msgstr ""
|
272 |
|
273 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
274 |
msgctxt "Storage provider key name"
|
275 |
msgid "Storage Provider"
|
276 |
msgstr ""
|
277 |
|
278 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
279 |
msgctxt "Storage provider name"
|
280 |
msgid "Storage Provider"
|
281 |
msgstr ""
|
282 |
|
283 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
284 |
msgctxt "Bucket name"
|
285 |
msgid "Bucket"
|
286 |
msgstr ""
|
287 |
|
288 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
289 |
msgctxt "Path to file in bucket"
|
290 |
msgid "Path"
|
291 |
msgstr ""
|
292 |
|
293 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
294 |
msgctxt "Location of bucket"
|
295 |
msgid "Region"
|
296 |
msgstr ""
|
297 |
|
298 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
299 |
msgctxt "Access control list of the file in bucket"
|
300 |
msgid "Access"
|
301 |
msgstr ""
|
302 |
|
303 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
304 |
msgid "URL"
|
305 |
msgstr ""
|
306 |
|
307 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
308 |
msgid "Assets Pull"
|
309 |
msgstr ""
|
310 |
|
311 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
312 |
msgid ""
|
313 |
"An addon for WP Offload Media to serve your site's JS, CSS, and other "
|
314 |
"enqueued assets from Amazon CloudFront or another CDN."
|
315 |
msgstr ""
|
316 |
|
317 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
318 |
msgid "Feature"
|
319 |
msgstr ""
|
320 |
|
321 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
322 |
#, php-format
|
323 |
msgid ""
|
324 |
"<strong>Amazon Web Services Plugin No Longer Required</strong> — As of "
|
@@ -329,7 +334,7 @@ msgid ""
|
|
329 |
"plugin, it should be safe to deactivate and delete it. %2$s"
|
330 |
msgstr ""
|
331 |
|
332 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
333 |
#, php-format
|
334 |
msgid ""
|
335 |
"<strong>WP Offload Media Settings Moved</strong> — You now define your "
|
@@ -462,20 +467,20 @@ msgstr ""
|
|
462 |
msgid "Settings"
|
463 |
msgstr ""
|
464 |
|
465 |
-
#: classes/as3cf-plugin-compatibility.php:
|
466 |
#, php-format
|
467 |
msgid "The local directory %s does not exist and could not be created."
|
468 |
msgstr ""
|
469 |
|
470 |
-
#: classes/as3cf-plugin-compatibility.php:
|
471 |
-
#: classes/as3cf-plugin-compatibility.php:
|
472 |
#: classes/upgrades/upgrade-meta-wp-error.php:81
|
473 |
#, php-format
|
474 |
msgid ""
|
475 |
"There was an error attempting to download the file %s from the bucket: %s"
|
476 |
msgstr ""
|
477 |
|
478 |
-
#: classes/as3cf-plugin-compatibility.php:
|
479 |
#, php-format
|
480 |
msgid ""
|
481 |
"<strong>Warning:</strong> This site is using PHP %1$s, in a future update WP "
|
@@ -515,7 +520,7 @@ msgstr ""
|
|
515 |
msgid "and ensuring that only the local URL exists in EDD post meta."
|
516 |
msgstr ""
|
517 |
|
518 |
-
#: classes/upgrades/upgrade-file-sizes.php:
|
519 |
msgid ""
|
520 |
"and updating the metadata with the sizes of files that have been removed "
|
521 |
"from the server. This will allow us to serve the correct size for media "
|
@@ -551,12 +556,19 @@ msgid ""
|
|
551 |
"make it run faster."
|
552 |
msgstr ""
|
553 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
554 |
#: classes/upgrades/upgrade-meta-wp-error.php:49
|
555 |
msgid ""
|
556 |
"and rebuilding the metadata for attachments that may have been corrupted."
|
557 |
msgstr ""
|
558 |
|
559 |
-
#: classes/upgrades/upgrade-region-meta.php:
|
560 |
msgid ""
|
561 |
"and updating the metadata with the bucket region it is served from. This "
|
562 |
"will allow us to serve your files from the proper region subdomain <span "
|
@@ -569,19 +581,19 @@ msgid ""
|
|
569 |
"version."
|
570 |
msgstr ""
|
571 |
|
572 |
-
#: classes/upgrades/upgrade.php:
|
573 |
msgid "Pause Update"
|
574 |
msgstr ""
|
575 |
|
576 |
-
#: classes/upgrades/upgrade.php:
|
577 |
msgid "Restart Update"
|
578 |
msgstr ""
|
579 |
|
580 |
-
#: classes/upgrades/upgrade.php:
|
581 |
-
msgid "Try Run It Again"
|
582 |
msgstr ""
|
583 |
|
584 |
-
#: classes/upgrades/upgrade.php:
|
585 |
#, php-format
|
586 |
msgid ""
|
587 |
"<strong>Running %1$s Update%2$s</strong> — We’re going through "
|
@@ -591,14 +603,14 @@ msgid ""
|
|
591 |
"performance."
|
592 |
msgstr ""
|
593 |
|
594 |
-
#: classes/upgrades/upgrade.php:
|
595 |
#, php-format
|
596 |
msgid ""
|
597 |
"<strong>%1$s Update Paused%2$s</strong> — Updating Media Library %3$s "
|
598 |
"has been paused."
|
599 |
msgstr ""
|
600 |
|
601 |
-
#: classes/upgrades/upgrade.php:
|
602 |
#, php-format
|
603 |
msgid ""
|
604 |
"<strong>Error Updating %1$s</strong> — We ran into some errors "
|
@@ -606,12 +618,12 @@ msgid ""
|
|
606 |
"been offloaded. Please check your error log for details. (#%3$d)"
|
607 |
msgstr ""
|
608 |
|
609 |
-
#: classes/upgrades/upgrade.php:
|
610 |
#, php-format
|
611 |
msgid " (%s%% Complete)"
|
612 |
msgstr ""
|
613 |
|
614 |
-
#: classes/upgrades/upgrade.php:
|
615 |
#, php-format
|
616 |
msgid "Every %d Minutes"
|
617 |
msgstr ""
|
8 |
msgstr ""
|
9 |
"Project-Id-Version: amazon-s3-and-cloudfront\n"
|
10 |
"Report-Msgid-Bugs-To: nom@deliciousbrains.com\n"
|
11 |
+
"POT-Creation-Date: 2019-11-12 10:09+0000\n"
|
12 |
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
17 |
"Content-Type: text/plain; charset=UTF-8\n"
|
18 |
"Content-Transfer-Encoding: 8bit\n"
|
19 |
|
20 |
+
#: classes/amazon-s3-and-cloudfront.php:138
|
21 |
+
#: classes/amazon-s3-and-cloudfront.php:139
|
22 |
msgid "Offload Media Lite"
|
23 |
msgstr ""
|
24 |
|
25 |
+
#: classes/amazon-s3-and-cloudfront.php:279
|
26 |
+
#: classes/amazon-s3-and-cloudfront.php:293
|
27 |
msgid "Unknown"
|
28 |
msgstr ""
|
29 |
|
30 |
+
#: classes/amazon-s3-and-cloudfront.php:365
|
31 |
#: view/bucket-setting.php:17
|
32 |
#: view/provider-select.php:122
|
33 |
msgid "defined in wp-config.php"
|
34 |
msgstr ""
|
35 |
|
36 |
+
#: classes/amazon-s3-and-cloudfront.php:1141
|
37 |
+
#, php-format
|
38 |
+
msgid "Media Library item with ID %d does not have a valid file path"
|
39 |
+
msgstr ""
|
40 |
+
|
41 |
+
#: classes/amazon-s3-and-cloudfront.php:1191
|
42 |
+
#: classes/amazon-s3-and-cloudfront.php:1353
|
43 |
#, php-format
|
44 |
msgid "File %s does not exist"
|
45 |
msgstr ""
|
46 |
|
47 |
+
#: classes/amazon-s3-and-cloudfront.php:1221
|
48 |
#, php-format
|
49 |
msgid "Mime type %s is not allowed"
|
50 |
msgstr ""
|
51 |
|
52 |
+
#: classes/amazon-s3-and-cloudfront.php:1232
|
53 |
msgid "Already offloaded to a different provider"
|
54 |
msgstr ""
|
55 |
|
56 |
+
#: classes/amazon-s3-and-cloudfront.php:1315
|
57 |
+
#: classes/amazon-s3-and-cloudfront.php:1366
|
58 |
#, php-format
|
59 |
msgid "Error offloading %s to provider: %s"
|
60 |
msgstr ""
|
61 |
|
62 |
+
#: classes/amazon-s3-and-cloudfront.php:2521
|
63 |
msgid "This action can only be performed through an admin screen."
|
64 |
msgstr ""
|
65 |
|
66 |
+
#: classes/amazon-s3-and-cloudfront.php:2523
|
67 |
msgid "Cheatin’ eh?"
|
68 |
msgstr ""
|
69 |
|
70 |
+
#: classes/amazon-s3-and-cloudfront.php:2525
|
71 |
msgid "You do not have sufficient permissions to access this page."
|
72 |
msgstr ""
|
73 |
|
74 |
+
#: classes/amazon-s3-and-cloudfront.php:2814
|
75 |
msgid "Error Getting Bucket Region"
|
76 |
msgstr ""
|
77 |
|
78 |
+
#: classes/amazon-s3-and-cloudfront.php:2815
|
79 |
#, php-format
|
80 |
msgid "There was an error attempting to get the region of the bucket %s: %s"
|
81 |
msgstr ""
|
82 |
|
83 |
+
#: classes/amazon-s3-and-cloudfront.php:2918
|
84 |
msgid ""
|
85 |
"This is a test file to check if the user has write permission to the bucket. "
|
86 |
"Delete me if found."
|
87 |
msgstr ""
|
88 |
|
89 |
+
#: classes/amazon-s3-and-cloudfront.php:2924
|
90 |
#, php-format
|
91 |
msgid ""
|
92 |
"There was an error attempting to check the permissions of the bucket %s: %s"
|
93 |
msgstr ""
|
94 |
|
95 |
+
#: classes/amazon-s3-and-cloudfront.php:3006
|
96 |
msgid "Error creating bucket"
|
97 |
msgstr ""
|
98 |
|
99 |
+
#: classes/amazon-s3-and-cloudfront.php:3007
|
100 |
msgid "Bucket name too short."
|
101 |
msgstr ""
|
102 |
|
103 |
+
#: classes/amazon-s3-and-cloudfront.php:3008
|
104 |
msgid "Bucket name too long."
|
105 |
msgstr ""
|
106 |
|
107 |
+
#: classes/amazon-s3-and-cloudfront.php:3009
|
108 |
msgid ""
|
109 |
"Invalid character. Bucket names can contain lowercase letters, numbers, "
|
110 |
"periods and hyphens."
|
111 |
msgstr ""
|
112 |
|
113 |
+
#: classes/amazon-s3-and-cloudfront.php:3010
|
114 |
msgid "Error saving bucket"
|
115 |
msgstr ""
|
116 |
|
117 |
+
#: classes/amazon-s3-and-cloudfront.php:3011
|
118 |
msgid "Error fetching buckets"
|
119 |
msgstr ""
|
120 |
|
121 |
+
#: classes/amazon-s3-and-cloudfront.php:3012
|
122 |
msgid "Error getting URL preview: "
|
123 |
msgstr ""
|
124 |
|
125 |
+
#: classes/amazon-s3-and-cloudfront.php:3013
|
126 |
msgid "The changes you made will be lost if you navigate away from this page"
|
127 |
msgstr ""
|
128 |
|
129 |
+
#: classes/amazon-s3-and-cloudfront.php:3014
|
130 |
msgid "Getting diagnostic info..."
|
131 |
msgstr ""
|
132 |
|
133 |
+
#: classes/amazon-s3-and-cloudfront.php:3015
|
134 |
msgid "Error getting diagnostic info: "
|
135 |
msgstr ""
|
136 |
|
137 |
+
#: classes/amazon-s3-and-cloudfront.php:3016
|
138 |
msgctxt "placeholder for hidden access key, 39 char max"
|
139 |
msgid "-- not shown --"
|
140 |
msgstr ""
|
141 |
|
142 |
+
#: classes/amazon-s3-and-cloudfront.php:3018
|
143 |
+
#: classes/amazon-s3-and-cloudfront.php:5012
|
144 |
msgid "Settings saved."
|
145 |
msgstr ""
|
146 |
|
147 |
+
#: classes/amazon-s3-and-cloudfront.php:3108
|
148 |
msgid "Cheatin' eh?"
|
149 |
msgstr ""
|
150 |
|
151 |
+
#: classes/amazon-s3-and-cloudfront.php:3192
|
152 |
msgid "No bucket name provided."
|
153 |
msgstr ""
|
154 |
|
155 |
+
#: classes/amazon-s3-and-cloudfront.php:3201
|
156 |
msgid "Bucket name not valid."
|
157 |
msgstr ""
|
158 |
|
159 |
+
#: classes/amazon-s3-and-cloudfront.php:3214
|
160 |
msgid "No region provided."
|
161 |
msgstr ""
|
162 |
|
163 |
+
#: classes/amazon-s3-and-cloudfront.php:3291
|
164 |
#: view/provider-select.php:329
|
165 |
msgctxt "placeholder for hidden secret access key, 39 char max"
|
166 |
msgid "-- not shown --"
|
167 |
msgstr ""
|
168 |
|
169 |
+
#: classes/amazon-s3-and-cloudfront.php:3314
|
170 |
msgid "Key File not valid JSON."
|
171 |
msgstr ""
|
172 |
|
173 |
+
#: classes/amazon-s3-and-cloudfront.php:3360
|
174 |
msgctxt "Show the media library tab"
|
175 |
msgid "Media Library"
|
176 |
msgstr ""
|
177 |
|
178 |
+
#: classes/amazon-s3-and-cloudfront.php:3361
|
179 |
msgctxt "Show the addons tab"
|
180 |
msgid "Addons"
|
181 |
msgstr ""
|
182 |
|
183 |
+
#: classes/amazon-s3-and-cloudfront.php:3362
|
184 |
msgctxt "Show the support tab"
|
185 |
msgid "Support"
|
186 |
msgstr ""
|
187 |
|
188 |
+
#: classes/amazon-s3-and-cloudfront.php:3589
|
189 |
#, php-format
|
190 |
msgid ""
|
191 |
"<strong>WP Offload Media</strong> — The file %s has been given %s "
|
192 |
"permissions in the bucket."
|
193 |
msgstr ""
|
194 |
|
195 |
+
#: classes/amazon-s3-and-cloudfront.php:3608
|
196 |
msgid ""
|
197 |
"<strong>WP Offload Media Requirement Missing</strong> — Looks like you "
|
198 |
"don't have an image manipulation library installed on this server and "
|
200 |
"Please setup GD or ImageMagick."
|
201 |
msgstr ""
|
202 |
|
203 |
+
#: classes/amazon-s3-and-cloudfront.php:4327
|
204 |
#, php-format
|
205 |
msgid ""
|
206 |
"<a href=\"%s\">Define your access keys</a> to enable write access to the "
|
207 |
"bucket"
|
208 |
msgstr ""
|
209 |
|
210 |
+
#: classes/amazon-s3-and-cloudfront.php:4334
|
211 |
msgid "Quick Start Guide"
|
212 |
msgstr ""
|
213 |
|
214 |
+
#: classes/amazon-s3-and-cloudfront.php:4336
|
215 |
#, php-format
|
216 |
msgid ""
|
217 |
"Looks like we don't have write access to this bucket. It's likely that the "
|
220 |
"correctly."
|
221 |
msgstr ""
|
222 |
|
223 |
+
#: classes/amazon-s3-and-cloudfront.php:4338
|
224 |
#, php-format
|
225 |
msgid ""
|
226 |
"Looks like we don't have access to the buckets. It's likely that the user "
|
228 |
"Please see our %s for instructions on setting up permissions correctly."
|
229 |
msgstr ""
|
230 |
|
231 |
+
#: classes/amazon-s3-and-cloudfront.php:4473
|
232 |
msgid "WP Offload Media Activation"
|
233 |
msgstr ""
|
234 |
|
235 |
+
#: classes/amazon-s3-and-cloudfront.php:4474
|
236 |
msgid ""
|
237 |
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
|
238 |
"automatically deactivated WP Offload Media Lite."
|
239 |
msgstr ""
|
240 |
|
241 |
+
#: classes/amazon-s3-and-cloudfront.php:4476
|
242 |
msgid "WP Offload Media Lite Activation"
|
243 |
msgstr ""
|
244 |
|
245 |
+
#: classes/amazon-s3-and-cloudfront.php:4477
|
246 |
msgid ""
|
247 |
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
|
248 |
"automatically deactivated WP Offload Media."
|
249 |
msgstr ""
|
250 |
|
251 |
+
#: classes/amazon-s3-and-cloudfront.php:4529
|
252 |
msgid "More info »"
|
253 |
msgstr ""
|
254 |
|
255 |
+
#: classes/amazon-s3-and-cloudfront.php:4624
|
256 |
msgid "this doc"
|
257 |
msgstr ""
|
258 |
|
259 |
+
#: classes/amazon-s3-and-cloudfront.php:4626
|
260 |
msgid "WP Offload Media Feature Removed"
|
261 |
msgstr ""
|
262 |
|
263 |
+
#: classes/amazon-s3-and-cloudfront.php:4627
|
264 |
#, php-format
|
265 |
msgid ""
|
266 |
"You had the \"Always non-SSL\" option selected in your settings, but we've "
|
271 |
"to the old behavior."
|
272 |
msgstr ""
|
273 |
|
274 |
+
#: classes/amazon-s3-and-cloudfront.php:4657
|
275 |
msgid "Offload"
|
276 |
msgstr ""
|
277 |
|
278 |
+
#: classes/amazon-s3-and-cloudfront.php:4762
|
279 |
msgctxt "Storage provider key name"
|
280 |
msgid "Storage Provider"
|
281 |
msgstr ""
|
282 |
|
283 |
+
#: classes/amazon-s3-and-cloudfront.php:4763
|
284 |
msgctxt "Storage provider name"
|
285 |
msgid "Storage Provider"
|
286 |
msgstr ""
|
287 |
|
288 |
+
#: classes/amazon-s3-and-cloudfront.php:4764
|
289 |
msgctxt "Bucket name"
|
290 |
msgid "Bucket"
|
291 |
msgstr ""
|
292 |
|
293 |
+
#: classes/amazon-s3-and-cloudfront.php:4765
|
294 |
msgctxt "Path to file in bucket"
|
295 |
msgid "Path"
|
296 |
msgstr ""
|
297 |
|
298 |
+
#: classes/amazon-s3-and-cloudfront.php:4766
|
299 |
msgctxt "Location of bucket"
|
300 |
msgid "Region"
|
301 |
msgstr ""
|
302 |
|
303 |
+
#: classes/amazon-s3-and-cloudfront.php:4767
|
304 |
msgctxt "Access control list of the file in bucket"
|
305 |
msgid "Access"
|
306 |
msgstr ""
|
307 |
|
308 |
+
#: classes/amazon-s3-and-cloudfront.php:4768
|
309 |
msgid "URL"
|
310 |
msgstr ""
|
311 |
|
312 |
+
#: classes/amazon-s3-and-cloudfront.php:4975
|
313 |
msgid "Assets Pull"
|
314 |
msgstr ""
|
315 |
|
316 |
+
#: classes/amazon-s3-and-cloudfront.php:4976
|
317 |
msgid ""
|
318 |
"An addon for WP Offload Media to serve your site's JS, CSS, and other "
|
319 |
"enqueued assets from Amazon CloudFront or another CDN."
|
320 |
msgstr ""
|
321 |
|
322 |
+
#: classes/amazon-s3-and-cloudfront.php:4980
|
323 |
msgid "Feature"
|
324 |
msgstr ""
|
325 |
|
326 |
+
#: classes/amazon-s3-and-cloudfront.php:5026
|
327 |
#, php-format
|
328 |
msgid ""
|
329 |
"<strong>Amazon Web Services Plugin No Longer Required</strong> — As of "
|
334 |
"plugin, it should be safe to deactivate and delete it. %2$s"
|
335 |
msgstr ""
|
336 |
|
337 |
+
#: classes/amazon-s3-and-cloudfront.php:5058
|
338 |
#, php-format
|
339 |
msgid ""
|
340 |
"<strong>WP Offload Media Settings Moved</strong> — You now define your "
|
467 |
msgid "Settings"
|
468 |
msgstr ""
|
469 |
|
470 |
+
#: classes/as3cf-plugin-compatibility.php:592
|
471 |
#, php-format
|
472 |
msgid "The local directory %s does not exist and could not be created."
|
473 |
msgstr ""
|
474 |
|
475 |
+
#: classes/as3cf-plugin-compatibility.php:593
|
476 |
+
#: classes/as3cf-plugin-compatibility.php:605
|
477 |
#: classes/upgrades/upgrade-meta-wp-error.php:81
|
478 |
#, php-format
|
479 |
msgid ""
|
480 |
"There was an error attempting to download the file %s from the bucket: %s"
|
481 |
msgstr ""
|
482 |
|
483 |
+
#: classes/as3cf-plugin-compatibility.php:930
|
484 |
#, php-format
|
485 |
msgid ""
|
486 |
"<strong>Warning:</strong> This site is using PHP %1$s, in a future update WP "
|
520 |
msgid "and ensuring that only the local URL exists in EDD post meta."
|
521 |
msgstr ""
|
522 |
|
523 |
+
#: classes/upgrades/upgrade-file-sizes.php:49
|
524 |
msgid ""
|
525 |
"and updating the metadata with the sizes of files that have been removed "
|
526 |
"from the server. This will allow us to serve the correct size for media "
|
556 |
"make it run faster."
|
557 |
msgstr ""
|
558 |
|
559 |
+
#: classes/upgrades/upgrade-items-table.php:48
|
560 |
+
msgid ""
|
561 |
+
"and updating the plugin's metadata to use a faster storage method. During "
|
562 |
+
"the update the site's total offloaded media count may be inaccurate but will "
|
563 |
+
"settle down shortly after completing."
|
564 |
+
msgstr ""
|
565 |
+
|
566 |
#: classes/upgrades/upgrade-meta-wp-error.php:49
|
567 |
msgid ""
|
568 |
"and rebuilding the metadata for attachments that may have been corrupted."
|
569 |
msgstr ""
|
570 |
|
571 |
+
#: classes/upgrades/upgrade-region-meta.php:47
|
572 |
msgid ""
|
573 |
"and updating the metadata with the bucket region it is served from. This "
|
574 |
"will allow us to serve your files from the proper region subdomain <span "
|
581 |
"version."
|
582 |
msgstr ""
|
583 |
|
584 |
+
#: classes/upgrades/upgrade.php:407
|
585 |
msgid "Pause Update"
|
586 |
msgstr ""
|
587 |
|
588 |
+
#: classes/upgrades/upgrade.php:415
|
589 |
msgid "Restart Update"
|
590 |
msgstr ""
|
591 |
|
592 |
+
#: classes/upgrades/upgrade.php:419
|
593 |
+
msgid "Try To Run It Again"
|
594 |
msgstr ""
|
595 |
|
596 |
+
#: classes/upgrades/upgrade.php:442
|
597 |
#, php-format
|
598 |
msgid ""
|
599 |
"<strong>Running %1$s Update%2$s</strong> — We’re going through "
|
603 |
"performance."
|
604 |
msgstr ""
|
605 |
|
606 |
+
#: classes/upgrades/upgrade.php:456
|
607 |
#, php-format
|
608 |
msgid ""
|
609 |
"<strong>%1$s Update Paused%2$s</strong> — Updating Media Library %3$s "
|
610 |
"has been paused."
|
611 |
msgstr ""
|
612 |
|
613 |
+
#: classes/upgrades/upgrade.php:469
|
614 |
#, php-format
|
615 |
msgid ""
|
616 |
"<strong>Error Updating %1$s</strong> — We ran into some errors "
|
618 |
"been offloaded. Please check your error log for details. (#%3$d)"
|
619 |
msgstr ""
|
620 |
|
621 |
+
#: classes/upgrades/upgrade.php:493
|
622 |
#, php-format
|
623 |
msgid " (%s%% Complete)"
|
624 |
msgstr ""
|
625 |
|
626 |
+
#: classes/upgrades/upgrade.php:626
|
627 |
#, php-format
|
628 |
msgid "Every %d Minutes"
|
629 |
msgstr ""
|
readme.txt
CHANGED
@@ -2,9 +2,9 @@
|
|
2 |
Contributors: bradt, deliciousbrains, ianmjones
|
3 |
Tags: uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google cloud storage, gcs, mirror, admin, media, cdn, cloudfront
|
4 |
Requires at least: 4.9
|
5 |
-
Tested up to: 5.
|
6 |
Requires PHP: 5.5
|
7 |
-
Stable tag: 2.
|
8 |
License: GPLv3
|
9 |
|
10 |
Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
|
@@ -67,6 +67,9 @@ If you upgrade to the pro version of [WP Offload Media](https://deliciousbrains.
|
|
67 |
|
68 |
== Upgrade Notice ==
|
69 |
|
|
|
|
|
|
|
70 |
= 2.0 =
|
71 |
This is a major upgrade that introduces support for DigitalOcean Spaces, renames the plugin to WP Offload Media Lite, and coincidentally upgrades some of its database settings. You may not be able to downgrade to WP Offload S3 Lite 1.x after upgrading to WP Offload Media Lite 2.0+.
|
72 |
|
@@ -78,6 +81,18 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
|
78 |
|
79 |
== Changelog ==
|
80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
= WP Offload Media Lite 2.2.1 - 2019-07-18 =
|
82 |
* Improvement: Menu option and settings page title now include "Lite"
|
83 |
* Improvement: Remove Files From Server option now warns about media backups when switched on
|
2 |
Contributors: bradt, deliciousbrains, ianmjones
|
3 |
Tags: uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google cloud storage, gcs, mirror, admin, media, cdn, cloudfront
|
4 |
Requires at least: 4.9
|
5 |
+
Tested up to: 5.3
|
6 |
Requires PHP: 5.5
|
7 |
+
Stable tag: 2.3
|
8 |
License: GPLv3
|
9 |
|
10 |
Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
|
67 |
|
68 |
== Upgrade Notice ==
|
69 |
|
70 |
+
= 2.3 =
|
71 |
+
This is a major upgrade that switches to using a custom table for storing data about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
|
72 |
+
|
73 |
= 2.0 =
|
74 |
This is a major upgrade that introduces support for DigitalOcean Spaces, renames the plugin to WP Offload Media Lite, and coincidentally upgrades some of its database settings. You may not be able to downgrade to WP Offload S3 Lite 1.x after upgrading to WP Offload Media Lite 2.0+.
|
75 |
|
81 |
|
82 |
== Changelog ==
|
83 |
|
84 |
+
= WP Offload Media Lite 2.3 - 2019-11-12 =
|
85 |
+
* [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-media-2-3-released/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
|
86 |
+
* New: Upgrade routine to migrate offload data to custom table
|
87 |
+
* New: Support for changed Media Library upload process introduced with WordPress 5.3
|
88 |
+
* New: Support for new "-scaled" and "-rotated" images introduced with WordPress 5.3
|
89 |
+
* New: Support for customizer changes introduced with WordPress 5.3
|
90 |
+
* New: Offload new "original_image" file introduced with WordPress 5.3
|
91 |
+
* Improvement: Performance boost during both page display and save
|
92 |
+
* Improvement: Better detection of offloaded media URLs during page display
|
93 |
+
* Bug fix: New Media Library upload given same local file name as offloaded and removed file after Remove Files From Server turned off
|
94 |
+
* Bug fix: PHP message: PHP Deprecated: strpos(): Non-string needles will be interpreted as strings in the future
|
95 |
+
|
96 |
= WP Offload Media Lite 2.2.1 - 2019-07-18 =
|
97 |
* Improvement: Menu option and settings page title now include "Lite"
|
98 |
* Improvement: Remove Files From Server option now warns about media backups when switched on
|
wordpress-s3.php
CHANGED
@@ -4,7 +4,7 @@ Plugin Name: WP Offload Media Lite
|
|
4 |
Plugin URI: http://wordpress.org/extend/plugins/amazon-s3-and-cloudfront/
|
5 |
Description: Automatically copies media uploads to Amazon S3, DigitalOcean Spaces or Google Cloud Storage for storage and delivery. Optionally configure Amazon CloudFront or another CDN for even faster delivery.
|
6 |
Author: Delicious Brains
|
7 |
-
Version: 2.
|
8 |
Author URI: https://deliciousbrains.com/
|
9 |
Network: True
|
10 |
Text Domain: amazon-s3-and-cloudfront
|
@@ -26,7 +26,7 @@ Domain Path: /languages/
|
|
26 |
// Then completely rewritten.
|
27 |
*/
|
28 |
|
29 |
-
$GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] = '2.
|
30 |
|
31 |
require_once dirname( __FILE__ ) . '/classes/as3cf-compatibility-check.php';
|
32 |
|
4 |
Plugin URI: http://wordpress.org/extend/plugins/amazon-s3-and-cloudfront/
|
5 |
Description: Automatically copies media uploads to Amazon S3, DigitalOcean Spaces or Google Cloud Storage for storage and delivery. Optionally configure Amazon CloudFront or another CDN for even faster delivery.
|
6 |
Author: Delicious Brains
|
7 |
+
Version: 2.3
|
8 |
Author URI: https://deliciousbrains.com/
|
9 |
Network: True
|
10 |
Text Domain: amazon-s3-and-cloudfront
|
26 |
// Then completely rewritten.
|
27 |
*/
|
28 |
|
29 |
+
$GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] = '2.3';
|
30 |
|
31 |
require_once dirname( __FILE__ ) . '/classes/as3cf-compatibility-check.php';
|
32 |
|