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 | ![]() |
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
|
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
|
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
|
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 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|