WP Offload S3 Lite - Version 2.1

Version Description

= 2.0 = 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+.

= 1.1 = This is a major change, which ensures S3 URLs are no longer saved in post content. Instead, local URLs are filtered on page generation and replaced with the S3 version. If you depend on the S3 URLs being stored in post content you will need to make modifications to support this version.

= 0.6 = This version requires PHP 5.3.3+ and the Amazon Web Services plugin

Download this release

Release Info

Developer deliciousbrains
Plugin Icon 128x128 WP Offload S3 Lite
Version 2.1
Comparing to
See all releases

Code changes from version 2.0.1 to 2.1

Files changed (98) hide show
  1. README.md +20 -10
  2. assets/css/storage-provider.css +1 -1
  3. assets/img/gcp-logo.svg +16 -0
  4. assets/js/script.js +1 -1
  5. assets/js/script.min.js +1 -1
  6. assets/js/storage-provider.js +5 -3
  7. assets/js/storage-provider.min.js +1 -1
  8. assets/sass/storage-provider.scss +25 -6
  9. classes/amazon-s3-and-cloudfront.php +205 -75
  10. classes/as3cf-compatibility-check.php +9 -1
  11. classes/as3cf-plugin-base.php +25 -4
  12. classes/providers/aws-provider.php +34 -15
  13. classes/providers/digitalocean-provider.php +1 -1
  14. classes/providers/gcp-provider.php +671 -0
  15. classes/providers/provider.php +201 -33
  16. classes/providers/streams/gcp-gcs-stream-wrapper.php +70 -0
  17. languages/amazon-s3-and-cloudfront-en.pot +187 -135
  18. readme.txt +20 -10
  19. vendor/Aws3/Aws/Api/ErrorParser/JsonParserTrait.php +1 -1
  20. vendor/Aws3/Aws/Api/ErrorParser/XmlErrorParser.php +1 -1
  21. vendor/Aws3/Aws/Api/Parser/AbstractParser.php +5 -0
  22. vendor/Aws3/Aws/Api/Parser/AbstractRestParser.php +14 -7
  23. vendor/Aws3/Aws/Api/Parser/Crc32ValidatingParser.php +6 -2
  24. vendor/Aws3/Aws/Api/Parser/DecodingEventStreamIterator.php +241 -0
  25. vendor/Aws3/Aws/Api/Parser/EventParsingIterator.php +81 -0
  26. vendor/Aws3/Aws/Api/Parser/Exception/ParserException.php +20 -1
  27. vendor/Aws3/Aws/Api/Parser/JsonParser.php +3 -0
  28. vendor/Aws3/Aws/Api/Parser/JsonRpcParser.php +7 -2
  29. vendor/Aws3/Aws/Api/Parser/PayloadParserTrait.php +5 -4
  30. vendor/Aws3/Aws/Api/Parser/QueryParser.php +10 -5
  31. vendor/Aws3/Aws/Api/Parser/RestJsonParser.php +10 -3
  32. vendor/Aws3/Aws/Api/Parser/RestXmlParser.php +7 -4
  33. vendor/Aws3/Aws/Api/Parser/XmlParser.php +3 -0
  34. vendor/Aws3/Aws/Api/Serializer/JsonBody.php +5 -1
  35. vendor/Aws3/Aws/Api/Serializer/QueryParamBuilder.php +2 -1
  36. vendor/Aws3/Aws/Api/Serializer/RestSerializer.php +8 -3
  37. vendor/Aws3/Aws/Api/Serializer/XmlBody.php +2 -1
  38. vendor/Aws3/Aws/AwsClient.php +24 -0
  39. vendor/Aws3/Aws/ClientResolver.php +1 -1
  40. vendor/Aws3/Aws/ClientSideMonitoring/AbstractMonitoringMiddleware.php +217 -0
  41. vendor/Aws3/Aws/ClientSideMonitoring/ApiCallAttemptMonitoringMiddleware.php +181 -0
  42. vendor/Aws3/Aws/ClientSideMonitoring/ApiCallMonitoringMiddleware.php +126 -0
  43. vendor/Aws3/Aws/ClientSideMonitoring/Configuration.php +55 -0
  44. vendor/Aws3/Aws/ClientSideMonitoring/ConfigurationInterface.php +35 -0
  45. vendor/Aws3/Aws/ClientSideMonitoring/ConfigurationProvider.php +272 -0
  46. vendor/Aws3/Aws/ClientSideMonitoring/Exception/ConfigurationException.php +13 -0
  47. vendor/Aws3/Aws/ClientSideMonitoring/MonitoringMiddlewareInterface.php +30 -0
  48. vendor/Aws3/Aws/Credentials/CredentialProvider.php +5 -1
  49. vendor/Aws3/Aws/Endpoint/PartitionEndpointProvider.php +29 -2
  50. vendor/Aws3/Aws/EndpointParameterMiddleware.php +65 -0
  51. vendor/Aws3/Aws/Exception/AwsException.php +24 -1
  52. vendor/Aws3/Aws/Exception/CouldNotCreateChecksumException.php +4 -1
  53. vendor/Aws3/Aws/Exception/CredentialsException.php +4 -1
  54. vendor/Aws3/Aws/Exception/EventStreamDataException.php +36 -0
  55. vendor/Aws3/Aws/Exception/MultipartUploadException.php +4 -1
  56. vendor/Aws3/Aws/Exception/UnresolvedApiException.php +4 -1
  57. vendor/Aws3/Aws/Exception/UnresolvedEndpointException.php +4 -1
  58. vendor/Aws3/Aws/Exception/UnresolvedSignatureException.php +4 -1
  59. vendor/Aws3/Aws/HandlerList.php +23 -2
  60. vendor/Aws3/Aws/HasMonitoringEventsTrait.php +36 -0
  61. vendor/Aws3/Aws/MockHandler.php +13 -0
  62. vendor/Aws3/Aws/MonitoringEventsInterface.php +29 -0
  63. vendor/Aws3/Aws/ResponseContainerInterface.php +13 -0
  64. vendor/Aws3/Aws/Result.php +2 -1
  65. vendor/Aws3/Aws/RetryMiddleware.php +73 -27
  66. vendor/Aws3/Aws/S3/AmbiguousSuccessParser.php +6 -2
  67. vendor/Aws3/Aws/S3/ApplyChecksumMiddleware.php +1 -1
  68. vendor/Aws3/Aws/S3/Exception/DeleteMultipleObjectsException.php +4 -1
  69. vendor/Aws3/Aws/S3/GetBucketLocationParser.php +6 -2
  70. vendor/Aws3/Aws/S3/RetryableMalformedResponseParser.php +6 -2
  71. vendor/Aws3/Aws/S3/S3Client.php +22 -0
  72. vendor/Aws3/Aws/S3/S3ClientTrait.php +4 -3
  73. vendor/Aws3/Aws/S3/S3MultiRegionClient.php +23 -1
  74. vendor/Aws3/Aws/Sdk.php +53 -1
  75. vendor/Aws3/Aws/Signature/SignatureProvider.php +2 -1
  76. vendor/Aws3/Aws/Signature/SignatureV4.php +41 -9
  77. vendor/Aws3/Aws/TraceMiddleware.php +3 -1
  78. vendor/Aws3/Aws/Waiter.php +1 -6
  79. vendor/Aws3/Aws/WrappedHttpHandler.php +1 -1
  80. vendor/Aws3/Aws/data/acm-pca/2017-08-22/paginators-1.json.php +1 -1
  81. vendor/Aws3/Aws/data/acm-pca/2017-08-22/waiters-2.json.php +4 -0
  82. vendor/Aws3/Aws/data/acm/2015-12-08/waiters-2.json.php +4 -0
  83. vendor/Aws3/Aws/data/alexaforbusiness/2017-11-09/api-2.json.php +1 -1
  84. vendor/Aws3/Aws/data/alexaforbusiness/2017-11-09/paginators-1.json.php +1 -1
  85. vendor/Aws3/Aws/data/amplify/2017-07-25/api-2.json.php +4 -0
  86. vendor/Aws3/Aws/data/amplify/2017-07-25/paginators-1.json.php +4 -0
  87. vendor/Aws3/Aws/data/apigateway/2015-07-09/api-2.json.php +1 -1
  88. vendor/Aws3/Aws/data/apigatewaymanagementapi/2018-11-29/api-2.json.php +4 -0
  89. vendor/Aws3/Aws/data/apigatewaymanagementapi/2018-11-29/paginators-1.json.php +4 -0
  90. vendor/Aws3/Aws/data/apigatewayv2/2018-11-29/api-2.json.php +4 -0
  91. vendor/Aws3/Aws/data/apigatewayv2/2018-11-29/paginators-1.json.php +4 -0
  92. vendor/Aws3/Aws/data/application-autoscaling/2016-02-06/api-2.json.php +1 -1
  93. vendor/Aws3/Aws/data/appmesh/2018-10-01/api-2.json.php +4 -0
  94. vendor/Aws3/Aws/data/appmesh/2018-10-01/paginators-1.json.php +4 -0
  95. vendor/Aws3/Aws/data/appstream/2016-12-01/api-2.json.php +1 -1
  96. vendor/Aws3/Aws/data/appstream/2016-12-01/paginators-1.json.php +1 -1
  97. vendor/Aws3/Aws/data/appsync/2017-07-25/api-2.json.php +1 -1
  98. vendor/Aws3/Aws/data/athena/2017-05-18/api-2.json.php +1 -1
README.md CHANGED
@@ -1,13 +1,13 @@
1
  # WP Offload Media Lite for Amazon S3 and DigitalOcean Spaces #
2
  **Contributors:** bradt, deliciousbrains, ianmjones
3
- **Tags:** uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, mirror, admin, media, cdn, cloudfront
4
  **Requires at least:** 4.7
5
- **Tested up to:** 5.0
6
  **Requires PHP:** 5.5
7
- **Stable tag:** 2.0.1
8
  **License:** GPLv3
9
 
10
- Copies files to Amazon S3 or DigitalOcean Spaces as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
11
 
12
  ## Description ##
13
 
@@ -15,11 +15,11 @@ FORMERLY WP OFFLOAD S3 LITE
15
 
16
  https://www.youtube.com/watch?v=_PVybEGaRXc
17
 
18
- This plugin automatically copies images, videos, documents, and any other media added through WordPress' media uploader to [Amazon S3](http://aws.amazon.com/s3/) or [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces/). It then automatically replaces the URL to each media file with their respective Amazon S3 or DigitalOcean Spaces URL or, if you have configured [Amazon CloudFront](http://aws.amazon.com/cloudfront/) or another CDN with or without a custom domain, that URL instead. Image thumbnails are also copied to the bucket and delivered through the correct remote URL.
19
 
20
- Uploading files *directly* to your Amazon S3 or DigitalOcean Spaces account is not currently supported by this plugin. They are uploaded to your server first, then copied to the bucket. There is an option to automatically remove the files from your server once they are copied to the bucket however.
21
 
22
- If you're adding this plugin to a site that's been around for a while, your existing media files will not be copied to or served from Amazon S3 or DigitalOcean Spaces. Only newly uploaded files will be copied to and served from the bucket. The pro upgrade has an upload tool to handle existing media files.
23
 
24
  **Image Optimization**
25
 
@@ -27,7 +27,7 @@ Although WP Offload Media doesn't include image optimization features, we work c
27
 
28
  **PRO Upgrade with Email Support and More Features**
29
 
30
- * Upload existing Media Library to Amazon S3 or DigitalOcean Spaces
31
  * Control offloaded files from the Media Library
32
  * [Assets Pull addon](https://deliciousbrains.com/wp-offload-media/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting&utm_content=assets%2Baddon#addons) - Serve your CSS, JS and fonts via CloudFront or another CDN
33
  * [WooCommerce integration](https://deliciousbrains.com/wp-offload-media/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting&utm_content=woocommerce%2Baddon#integrations)
@@ -38,7 +38,7 @@ Although WP Offload Media doesn't include image optimization features, we work c
38
 
39
  The video below runs through the pro upgrade features...
40
 
41
- https://www.youtube.com/watch?v=55xNGnbJ_CY
42
 
43
  ## Installation ##
44
 
@@ -86,6 +86,16 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
86
 
87
  ## Changelog ##
88
 
 
 
 
 
 
 
 
 
 
 
89
  ### WP Offload Media Lite 2.0.1 - 2018-12-17 ###
90
  * Improvement: Streamlined UI for setting Storage Provider and Bucket
91
  * Bug fix: On/Off switches in settings look reversed
@@ -95,7 +105,7 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
95
  * Tested: WordPress 5.0
96
 
97
  ### WP Offload Media Lite 2.0 - 2018-09-24 ###
98
- * [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-s3-is-now-wp-offload-media-and-adds-support-for-digitalocean-spaces/)
99
  * New: DigitalOcean Spaces is now supported
100
  * New: Plugin name updated from WP Offload S3 Lite to WP Offload Media Lite
101
  * Improvement: More logical UI layout and better description of each setting
1
  # WP Offload Media Lite for Amazon S3 and DigitalOcean Spaces #
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.7
5
+ **Tested up to:** 5.1
6
  **Requires PHP:** 5.5
7
+ **Stable tag:** 2.1
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.
11
 
12
  ## Description ##
13
 
15
 
16
  https://www.youtube.com/watch?v=_PVybEGaRXc
17
 
18
+ This plugin automatically copies images, videos, documents, and any other media added through WordPress' media uploader to [Amazon S3](http://aws.amazon.com/s3/), [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces/) or [Google Cloud Storage](https://cloud.google.com/storage/). It then automatically replaces the URL to each media file with their respective Amazon S3, DigitalOcean Spaces or Google Cloud Storage URL or, if you have configured [Amazon CloudFront](http://aws.amazon.com/cloudfront/) or another CDN with or without a custom domain, that URL instead. Image thumbnails are also copied to the bucket and delivered through the correct remote URL.
19
 
20
+ Uploading files *directly* to your Amazon S3, DigitalOcean Spaces or Google Cloud Storage account is not currently supported by this plugin. They are uploaded to your server first, then copied to the bucket. There is an option to automatically remove the files from your server once they are copied to the bucket however.
21
 
22
+ If you're adding this plugin to a site that's been around for a while, your existing media files will not be copied to or served from Amazon S3, DigitalOcean Spaces or Google Cloud Storage. Only newly uploaded files will be copied to and served from the bucket. [The pro upgrade](https://deliciousbrains.com/wp-offload-media/upgrade/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting) has an upload tool to handle existing media files.
23
 
24
  **Image Optimization**
25
 
27
 
28
  **PRO Upgrade with Email Support and More Features**
29
 
30
+ * Upload existing Media Library to Amazon S3, DigitalOcean Spaces or Google Cloud Storage
31
  * Control offloaded files from the Media Library
32
  * [Assets Pull addon](https://deliciousbrains.com/wp-offload-media/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting&utm_content=assets%2Baddon#addons) - Serve your CSS, JS and fonts via CloudFront or another CDN
33
  * [WooCommerce integration](https://deliciousbrains.com/wp-offload-media/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting&utm_content=woocommerce%2Baddon#integrations)
38
 
39
  The video below runs through the pro upgrade features...
40
 
41
+ https://www.youtube.com/watch?v=I-wTMXMeFu4
42
 
43
  ## Installation ##
44
 
86
 
87
  ## Changelog ##
88
 
89
+ ### WP Offload Media Lite 2.1 - 2019-03-05 ###
90
+ * [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-media-2-1-released/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
91
+ * New: Google Cloud Storage is now supported
92
+ * Improvement: AWS PHP SDK updated
93
+ * Improvement: Diagnostic Info shows more complete settings information
94
+ * Bug fix: Year/Month path prefix incorrectly set in bucket for non-image media files
95
+ * Bug fix: PHP Fatal error: Class 'XMLWriter' not found
96
+ * Bug fix: PHP Fatal error: Uncaught Error: Call to undefined method ...\Aws3\Aws\S3\Exception\S3Exception::search() in .../classes/providers/aws-provider.php:439
97
+ * Bug fix: PHP Warning: filesize(): stat failed for [file-path] in classes/amazon-s3-and-cloudfront.php on line 1309
98
+
99
  ### WP Offload Media Lite 2.0.1 - 2018-12-17 ###
100
  * Improvement: Streamlined UI for setting Storage Provider and Bucket
101
  * Bug fix: On/Off switches in settings look reversed
105
  * Tested: WordPress 5.0
106
 
107
  ### WP Offload Media Lite 2.0 - 2018-09-24 ###
108
+ * [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-s3-is-now-wp-offload-media-and-adds-support-for-digitalocean-spaces/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
109
  * New: DigitalOcean Spaces is now supported
110
  * New: Plugin name updated from WP Offload S3 Lite to WP Offload Media Lite
111
  * Improvement: More logical UI layout and better description of each setting
assets/css/storage-provider.css CHANGED
@@ -1 +1 @@
1
- .as3cf-provider-select h3{font-size:20px}.as3cf-provider-select table{border-collapse:collapse}.as3cf-provider-select .as3cf-provider-title{margin:0;padding:0;background:#f1f1f1}.as3cf-provider-select .as3cf-provider-title label{position:relative;display:inline-block}.as3cf-provider-select .as3cf-provider-title label:hover{cursor:pointer}.as3cf-provider-select .as3cf-provider-title .as3cf-provider-logo{color:white;padding:1em}.as3cf-provider-select .as3cf-provider-title h3{display:inline-block;position:absolute;top:50%;left:76px;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);font-weight:bold;text-transform:none;padding:0;margin:0 15px;white-space:nowrap}.as3cf-provider-select .as3cf-provider-title.as3cf-provider-selected{cursor:default}.as3cf-provider-select .as3cf-provider-title.as3cf-provider-aws .as3cf-provider-logo{background-color:#f7a80d}.as3cf-provider-select .as3cf-provider-title.as3cf-provider-do .as3cf-provider-logo{background-color:#0080ff}.as3cf-provider-select .as3cf-provider-content td{padding-bottom:10px}.as3cf-provider-select .as3cf-provider-content table{background:#e5e5e5}.as3cf-provider-select .as3cf-provider-content table th{padding:10px 0 10px 10px}.as3cf-provider-select .as3cf-provider-content table td{padding:10px}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-title label{font-weight:bold}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content td{padding-top:0}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content textarea.as3cf-define-snippet.code{width:100%;white-space:pre;overflow:hidden;font-size:11px;padding:10px;margin-top:10px}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content table.as3cf-access-keys{margin-top:10px}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content table.as3cf-access-keys th{padding-left:0}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content table.as3cf-access-keys input{width:100%}
1
+ .as3cf-provider-select h3{font-size:20px}.as3cf-provider-select table{border-collapse:collapse}.as3cf-provider-select .as3cf-provider-title{margin:0;padding:0;background:#f1f1f1}.as3cf-provider-select .as3cf-provider-title label{position:relative;display:inline-block}.as3cf-provider-select .as3cf-provider-title label:hover{cursor:pointer}.as3cf-provider-select .as3cf-provider-title .as3cf-provider-logo{color:white;padding:1em}.as3cf-provider-select .as3cf-provider-title h3{display:inline-block;position:absolute;top:50%;left:76px;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);font-weight:bold;text-transform:none;padding:0;margin:0 15px;white-space:nowrap}.as3cf-provider-select .as3cf-provider-title.as3cf-provider-selected{cursor:default}.as3cf-provider-select .as3cf-provider-title.as3cf-provider-aws .as3cf-provider-logo{background-color:#f7a80d;border:1px solid #f7a80d}.as3cf-provider-select .as3cf-provider-title.as3cf-provider-do .as3cf-provider-logo{background-color:#0080ff;border:1px solid #0080ff}.as3cf-provider-select .as3cf-provider-title.as3cf-provider-gcp .as3cf-provider-logo{background-color:#fff;border-top:1px solid #ea4335;border-right:1px solid #4285f4;border-bottom:1px solid #34a853;border-left:1px solid #fbbc05}.as3cf-provider-select .as3cf-provider-content td{padding-bottom:10px}.as3cf-provider-select .as3cf-provider-content table{background:#e5e5e5}.as3cf-provider-select .as3cf-provider-content table th{padding:10px 0 10px 10px}.as3cf-provider-select .as3cf-provider-content table td{padding:10px}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-title label{font-weight:bold}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content td{padding-top:0}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content textarea{margin-top:10px}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content textarea.clear{width:100%}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content textarea.as3cf-define-snippet.code{white-space:pre;overflow:hidden;font-size:11px;padding:10px}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content table.as3cf-access-keys{margin-top:10px}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content table.as3cf-access-keys th{padding-left:0}.as3cf-provider-select .as3cf-provider-content .asc3f-provider-authmethod-content table.as3cf-access-keys input{width:100%}
assets/img/gcp-logo.svg ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg width="100%" height="100%" viewBox="0 0 33 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
4
+ <g transform="matrix(1,0,0,1,-1.04531,-0.144077)">
5
+ <path d="M21.85,7.41L22.85,7.41L25.7,4.56L25.84,3.35C23.5,1.285 20.484,0.144 17.363,0.144C11.598,0.144 6.51,4.036 5,9.6C5.317,9.47 5.669,9.449 6,9.54L11.7,8.6C11.7,8.6 11.99,8.12 12.14,8.15C14.661,5.381 18.959,5.054 21.87,7.41L21.85,7.41Z" style="fill:rgb(234,67,53);fill-rule:nonzero;"/>
6
+ </g>
7
+ <g transform="matrix(1,0,0,1,-1.04531,-0.144077)">
8
+ <path d="M29.76,9.6C29.105,7.188 27.76,5.019 25.89,3.36L21.89,7.36C23.578,8.739 24.541,10.821 24.5,13L24.5,13.71C26.453,13.71 28.06,15.317 28.06,17.27C28.06,19.223 26.453,20.83 24.5,20.83C24.5,20.83 17.38,20.83 17.38,20.83L16.67,21.55L16.67,25.82L17.38,26.53L24.5,26.53C24.524,26.53 24.548,26.53 24.572,26.53C29.652,26.53 33.832,22.35 33.832,17.27C33.832,14.199 32.304,11.321 29.76,9.6Z" style="fill:rgb(66,133,244);fill-rule:nonzero;"/>
9
+ </g>
10
+ <g transform="matrix(1,0,0,1,-1.04531,-0.144077)">
11
+ <path d="M10.25,26.49L17.37,26.49L17.37,20.79L10.25,20.79C9.743,20.79 9.241,20.681 8.78,20.47L7.78,20.78L4.91,23.63L4.66,24.63C6.269,25.845 8.234,26.499 10.25,26.49Z" style="fill:rgb(52,168,83);fill-rule:nonzero;"/>
12
+ </g>
13
+ <g transform="matrix(1,0,0,1,-1.04531,-0.144077)">
14
+ <path d="M10.25,8C5.191,8.03 1.045,12.201 1.045,17.26C1.045,20.133 2.383,22.848 4.66,24.6L8.79,20.47C7.517,19.895 6.696,18.622 6.696,17.226C6.696,15.273 8.303,13.666 10.256,13.666C11.652,13.666 12.925,14.487 13.5,15.76L17.63,11.63C15.874,9.334 13.14,7.99 10.25,8Z" style="fill:rgb(251,188,5);fill-rule:nonzero;"/>
15
+ </g>
16
+ </svg>
assets/js/script.js CHANGED
@@ -387,7 +387,7 @@
387
  var prefix = $objectPrefix.val();
388
 
389
  if ( '' !== prefix ) {
390
- prefix = as3cf.provider_console_url_param + encodeURIComponent( prefix );
391
  }
392
 
393
  var url = as3cf.provider_console_url + bucket + prefix;
387
  var prefix = $objectPrefix.val();
388
 
389
  if ( '' !== prefix ) {
390
+ prefix = as3cf.provider_console_url_prefix_param + encodeURIComponent( prefix );
391
  }
392
 
393
  var url = as3cf.provider_console_url + bucket + prefix;
assets/js/script.min.js CHANGED
@@ -1 +1 @@
1
- !function(a,b){function c(b){return a("#"+b+" .as3cf-main-settings form").find("input:not(.no-compare)").serialize()}function d(a){var b=l.find("#"+a),c=b.find("input[type=checkbox]");b.toggleClass("on").find("span").toggleClass("checked");var d=b.find("span.on").hasClass("checked");c.prop("checked",d).trigger("change")}function e(b){var c=b.next(".as3cf-validation-error"),d=a("#"+l.attr("id")+' form button[type="submit"]'),e=/[^a-zA-Z0-9\.\-]/;e.test(b.val())?(c.show(),d.prop("disabled",!0)):(c.hide(),d.prop("disabled",!1))}function f(){var c=a("#"+b.prefix+"-bucket").val(),d=l.find('input[name="object-prefix"]'),e=d.val();""!==e&&(e=as3cf.provider_console_url_param+encodeURIComponent(e));var f=as3cf.provider_console_url+c+e;a("#"+b.prefix+"-view-bucket").attr("href",f)}function g(){a("#as3cf-remove-local-file").is(":checked")&&a("#as3cf-serve-from-s3").is(":not(:checked)")?a("#as3cf-lost-files-notice").show():a("#as3cf-lost-files-notice").hide()}function h(){a("#as3cf-remove-local-file").is(":checked")?a("#as3cf-remove-local-notice").show():a("#as3cf-remove-local-notice").hide()}function i(b){!0!==b?a("#as3cf-seo-friendly-url-notice").show():a("#as3cf-seo-friendly-url-notice").hide()}function j(){a(".as3cf-url-preview").html("Generating...");var b={_nonce:as3cf.nonces.get_url_preview};a.each(a("#tab-"+as3cf.tabs.defaultTab+" .as3cf-main-settings form").serializeArray(),function(c,d){var e=d.name,f=d.value;e=e.replace("[]",""),b[e]=void 0===b[e]?f:a.isArray(b[e])?b[e].concat(f):[b[e],f]}),b.action="as3cf-get-url-preview",a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:b,error:function(a,b,c){alert(as3cf.strings.get_url_preview_error+c)},success:function(b,c,d){"undefined"!=typeof b.success?(a(".as3cf-url-preview").html(b.url),i(b.seo_friendly)):alert(as3cf.strings.get_url_preview_error+b.error)}})}function k(){return"#"+as3cf.tabs.defaultTab===location.hash?void(location.hash=""):(as3cf.tabs.toggle(location.hash.replace("#",""),!0),void a(document).trigger("as3cf.tabRendered",[location.hash.replace("#","")]))}var l,m={},n=/[^a-z0-9.-]/,o=a("body"),p=a(".as3cf-tab");a(".as3cf-settings");as3cf.tabs={defaultTab:"media",toggle:function(c,d){c=as3cf.tabs.sanitizeHash(c),p.hide(),l=a("#tab-"+c),l.show(),a(".nav-tab").removeClass("nav-tab-active"),a('a.nav-tab[data-tab="'+c+'"]').addClass("nav-tab-active"),a(".as3cf-main").data("tab",c),l.data("prefix")&&(b.prefix=l.data("prefix")),d||a(".as3cf-updated").removeClass("show"),"support"===c&&as3cf.tabs.getDiagnosticInfo()},getDiagnosticInfo:function(){var b=a(".debug-log-textarea");b.html(as3cf.strings.get_diagnostic_info);var c={action:"as3cf-get-diagnostic-info",_nonce:as3cf.nonces.get_diagnostic_info};a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:c,error:function(a,c,d){b.html(d)},success:function(a,c,d){"undefined"!=typeof a.success?b.html(a.diagnostic_info):(b.html(as3cf.strings.get_diagnostic_info_error),b.append(a.error))}})},sanitizeHash:function(b){var c=a("#tab-"+b);return 0===c.length&&(b=as3cf.tabs.defaultTab),b}},as3cf.buckets={validLength:3,bucketSelectLock:!1,loadList:function(c){"undefined"==typeof c&&(c=!1);var d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-select"),e=d.find(".bucket-select-region"),f=d.find(".as3cf-bucket-list"),g=a("#"+b.prefix+"-bucket").val();if(!1===c&&f.find("li").length>1)return a(".as3cf-bucket-list a").removeClass("selected"),a('.as3cf-bucket-list a[data-bucket="'+g+'"]').addClass("selected"),void this.scrollToSelected();f.html('<li class="loading">'+f.data("working")+"</li>"),this.disabledButtons();var h={action:b.prefix+"-get-buckets",_nonce:window[b.prefix.replace(/-/g,"_")].nonces.get_buckets};e.val()&&(h.region=e.val());var i=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:h,error:function(a,b,c){f.html(""),i.showError(as3cf.strings.get_buckets_error,c,"as3cf-bucket-select")},success:function(b,c,d){f.html(""),"undefined"!=typeof b.success?(a(".as3cf-bucket-error").hide(),0===b.buckets.length?f.html('<li class="loading">'+f.data("nothing-found")+"</li>"):(a(b.buckets).each(function(a,b){var c=b.Name===g?"selected":"";f.append('<li><a class="'+c+'" href="#" data-bucket="'+b.Name+'"><span class="bucket"><span class="dashicons dashicons-portfolio"></span> '+b.Name+'</span><span class="spinner"></span></span></a></li>')}),i.scrollToSelected(),i.disabledButtons())):i.showError(as3cf.strings.get_buckets_error,b.error,"as3cf-bucket-select")}})},scrollToSelected:function(){if(a(".as3cf-bucket-list a.selected").length){var b=a("ul.as3cf-bucket-list li").first().position().top+150;a(".as3cf-bucket-list").animate({scrollTop:a("ul.as3cf-bucket-list li a.selected").position().top-b})}},setSelected:function(c){a(".as3cf-bucket-list a").removeClass("selected"),c.addClass("selected"),a("#"+b.prefix+"-bucket-select-name").val(c.data("bucket"))},disabledButtons:function(){var c=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-create"),d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-manual"),e=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-select");0===c.length&&0===d.length&&0===e.length||(0<c.length&&this.isValidName(c.find(".as3cf-bucket-name").val())?c.find("button[type=submit]").prop("disabled",!1):c.find("button[type=submit]").prop("disabled",!0),0<d.length&&this.isValidName(d.find(".as3cf-bucket-name").val())?d.find("button[type=submit]").prop("disabled",!1):d.find("button[type=submit]").prop("disabled",!0),0<e.length&&1===e.find(".as3cf-bucket-list a.selected").length?e.find("button[type=submit]").prop("disabled",!1):e.find("button[type=submit]").prop("disabled",!0))},showError:function(b,c,d){var e=a(".as3cf-bucket-container").children(":visible"),f=e.find(".as3cf-bucket-error");d="undefined"==typeof d?null:d,d&&!e.hasClass(d)||(f.find("span.title").html(b+" &mdash;"),f.find("span.message").html(c),f.show(),this.bucketSelectLock=!1)},isValidName:function(a){return!(a.length<3||a.length>63)&&!0!==n.test(a)},updateNameNotice:function(b){var c=null;!0===n.test(b)?c=as3cf.strings.create_bucket_invalid_chars:b.length<3?c=as3cf.strings.create_bucket_name_short:b.length>63&&(c=as3cf.strings.create_bucket_name_long),c&&b.length>0?a(".as3cf-invalid-bucket-name").html(c):a(".as3cf-invalid-bucket-name").html("")}},as3cf.reloadUpdated=function(){var a=location.pathname+location.search;location.search.match(/[?&]updated=/)||(a+="&updated=1"),a+=location.hash,location.assign(a)},as3cf.showSettingsSavedNotice=function(){if(!(0<a("#setting-error-settings_updated:visible").length||0<a("#as3cf-settings_updated:visible").length)){var b='<div id="as3cf-settings_updated" class="updated settings-error notice is-dismissible"><p><strong>'+as3cf.strings.settings_saved+"</strong></p></div>";a("h2.nav-tab-wrapper").after(b),a(document).trigger("wp-updates-notice-added")}},a(document).ready(function(){k(),window.onhashchange=function(a){"function"==typeof history.replaceState&&"#"===location.href.slice(-1)&&history.replaceState({},"",location.href.slice(0,-1)),k()};var i=a(".as3cf-main .nav-tab-wrapper");a(".as3cf-compatibility-notice, div.updated, div.error, div.notice").not(".below-h2, .inline").insertAfter(i),p.length&&p.each(function(a,b){m[b.id]=c(b.id)}),a(window).on("beforeunload.as3cf-settings",function(){if(!a.isEmptyObject(m)){var b=l.attr("id");return c(b)!==m[b]?as3cf.strings.save_alert:void 0}}),a(document).on("submit",".as3cf-main-settings form",function(b){a(window).off("beforeunload.as3cf-settings")}),a(".as3cf-switch").on("click",function(b){a(this).hasClass("disabled")||d(a(this).attr("id"))}),p.on("change",".sub-toggle",function(b){var c=a(this).attr("id");a(".as3cf-setting."+c).toggleClass("hide")}),a(".as3cf-domain").on("change",'input[type="radio"]',function(b){var c=a(this).closest('input:radio[name="domain"]:checked'),d=c.val(),e=a(this).parents(".as3cf-domain").find(".as3cf-setting.cloudfront"),f="cloudfront"===d;e.toggleClass("hide",!f)}),a(".url-preview").on("change","input",function(a){j()}),g(),a("#as3cf-serve-from-s3,#as3cf-remove-local-file").on("change",function(a){g()}),h(),a("#as3cf-remove-local-file").on("change",function(a){h()}),a('.as3cf-setting input[type="text"]').keypress(function(a){if(13===a.which)return a.preventDefault(),!1}),a('input[name="cloudfront"]').on("keyup",function(b){e(a(this))}),a('input[name="domain"]').on("change",function(b){var c=a(this),d=a("#"+l.attr("id")+' form button[type="submit"]');"cloudfront"!==c.val()?d.prop("disabled",!1):e(c.next(".as3cf-setting").find('input[name="cloudfront"]'))}),a('input[name="object-prefix"]').on("change",function(a){f()}),a("#tab-media > .as3cf-bucket-error").detach().insertAfter(".as3cf-bucket-container h3"),as3cf.buckets.disabledButtons(),o.on("click",".bucket-action-refresh",function(a){a.preventDefault(),as3cf.buckets.loadList(!0)}),o.on("change",".bucket-select-region",function(a){a.preventDefault(),as3cf.buckets.loadList(!0)}),0<a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-select").length&&as3cf.buckets.loadList(!0),o.on("click",".as3cf-bucket-list a",function(b){b.preventDefault(),as3cf.buckets.setSelected(a(this)),as3cf.buckets.disabledButtons()}),a(".as3cf-bucket-container").on("click","a.js-link",function(b){return b.preventDefault(),window.open(a(this).attr("href")),!1}),o.on("input keyup",".as3cf-bucket-create .as3cf-bucket-name",function(b){var c=a(this).val();as3cf.buckets.updateNameNotice(c),as3cf.buckets.disabledButtons()}),o.on("input keyup",".as3cf-bucket-manual .as3cf-bucket-name",function(b){var c=a(this).val();as3cf.buckets.updateNameNotice(c),as3cf.buckets.disabledButtons()}),a('.as3cf-bucket-container input[type="text"]').keypress(function(a){if(13===a.which)return a.preventDefault(),!1})})}(jQuery,as3cfModal);
1
+ !function(a,b){function c(b){return a("#"+b+" .as3cf-main-settings form").find("input:not(.no-compare)").serialize()}function d(a){var b=l.find("#"+a),c=b.find("input[type=checkbox]");b.toggleClass("on").find("span").toggleClass("checked");var d=b.find("span.on").hasClass("checked");c.prop("checked",d).trigger("change")}function e(b){var c=b.next(".as3cf-validation-error"),d=a("#"+l.attr("id")+' form button[type="submit"]'),e=/[^a-zA-Z0-9\.\-]/;e.test(b.val())?(c.show(),d.prop("disabled",!0)):(c.hide(),d.prop("disabled",!1))}function f(){var c=a("#"+b.prefix+"-bucket").val(),d=l.find('input[name="object-prefix"]'),e=d.val();""!==e&&(e=as3cf.provider_console_url_prefix_param+encodeURIComponent(e));var f=as3cf.provider_console_url+c+e;a("#"+b.prefix+"-view-bucket").attr("href",f)}function g(){a("#as3cf-remove-local-file").is(":checked")&&a("#as3cf-serve-from-s3").is(":not(:checked)")?a("#as3cf-lost-files-notice").show():a("#as3cf-lost-files-notice").hide()}function h(){a("#as3cf-remove-local-file").is(":checked")?a("#as3cf-remove-local-notice").show():a("#as3cf-remove-local-notice").hide()}function i(b){!0!==b?a("#as3cf-seo-friendly-url-notice").show():a("#as3cf-seo-friendly-url-notice").hide()}function j(){a(".as3cf-url-preview").html("Generating...");var b={_nonce:as3cf.nonces.get_url_preview};a.each(a("#tab-"+as3cf.tabs.defaultTab+" .as3cf-main-settings form").serializeArray(),function(c,d){var e=d.name,f=d.value;e=e.replace("[]",""),b[e]=void 0===b[e]?f:a.isArray(b[e])?b[e].concat(f):[b[e],f]}),b.action="as3cf-get-url-preview",a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:b,error:function(a,b,c){alert(as3cf.strings.get_url_preview_error+c)},success:function(b,c,d){"undefined"!=typeof b.success?(a(".as3cf-url-preview").html(b.url),i(b.seo_friendly)):alert(as3cf.strings.get_url_preview_error+b.error)}})}function k(){return"#"+as3cf.tabs.defaultTab===location.hash?void(location.hash=""):(as3cf.tabs.toggle(location.hash.replace("#",""),!0),void a(document).trigger("as3cf.tabRendered",[location.hash.replace("#","")]))}var l,m={},n=/[^a-z0-9.-]/,o=a("body"),p=a(".as3cf-tab");a(".as3cf-settings");as3cf.tabs={defaultTab:"media",toggle:function(c,d){c=as3cf.tabs.sanitizeHash(c),p.hide(),l=a("#tab-"+c),l.show(),a(".nav-tab").removeClass("nav-tab-active"),a('a.nav-tab[data-tab="'+c+'"]').addClass("nav-tab-active"),a(".as3cf-main").data("tab",c),l.data("prefix")&&(b.prefix=l.data("prefix")),d||a(".as3cf-updated").removeClass("show"),"support"===c&&as3cf.tabs.getDiagnosticInfo()},getDiagnosticInfo:function(){var b=a(".debug-log-textarea");b.html(as3cf.strings.get_diagnostic_info);var c={action:"as3cf-get-diagnostic-info",_nonce:as3cf.nonces.get_diagnostic_info};a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:c,error:function(a,c,d){b.html(d)},success:function(a,c,d){"undefined"!=typeof a.success?b.html(a.diagnostic_info):(b.html(as3cf.strings.get_diagnostic_info_error),b.append(a.error))}})},sanitizeHash:function(b){var c=a("#tab-"+b);return 0===c.length&&(b=as3cf.tabs.defaultTab),b}},as3cf.buckets={validLength:3,bucketSelectLock:!1,loadList:function(c){"undefined"==typeof c&&(c=!1);var d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-select"),e=d.find(".bucket-select-region"),f=d.find(".as3cf-bucket-list"),g=a("#"+b.prefix+"-bucket").val();if(!1===c&&f.find("li").length>1)return a(".as3cf-bucket-list a").removeClass("selected"),a('.as3cf-bucket-list a[data-bucket="'+g+'"]').addClass("selected"),void this.scrollToSelected();f.html('<li class="loading">'+f.data("working")+"</li>"),this.disabledButtons();var h={action:b.prefix+"-get-buckets",_nonce:window[b.prefix.replace(/-/g,"_")].nonces.get_buckets};e.val()&&(h.region=e.val());var i=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:h,error:function(a,b,c){f.html(""),i.showError(as3cf.strings.get_buckets_error,c,"as3cf-bucket-select")},success:function(b,c,d){f.html(""),"undefined"!=typeof b.success?(a(".as3cf-bucket-error").hide(),0===b.buckets.length?f.html('<li class="loading">'+f.data("nothing-found")+"</li>"):(a(b.buckets).each(function(a,b){var c=b.Name===g?"selected":"";f.append('<li><a class="'+c+'" href="#" data-bucket="'+b.Name+'"><span class="bucket"><span class="dashicons dashicons-portfolio"></span> '+b.Name+'</span><span class="spinner"></span></span></a></li>')}),i.scrollToSelected(),i.disabledButtons())):i.showError(as3cf.strings.get_buckets_error,b.error,"as3cf-bucket-select")}})},scrollToSelected:function(){if(a(".as3cf-bucket-list a.selected").length){var b=a("ul.as3cf-bucket-list li").first().position().top+150;a(".as3cf-bucket-list").animate({scrollTop:a("ul.as3cf-bucket-list li a.selected").position().top-b})}},setSelected:function(c){a(".as3cf-bucket-list a").removeClass("selected"),c.addClass("selected"),a("#"+b.prefix+"-bucket-select-name").val(c.data("bucket"))},disabledButtons:function(){var c=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-create"),d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-manual"),e=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-select");0===c.length&&0===d.length&&0===e.length||(0<c.length&&this.isValidName(c.find(".as3cf-bucket-name").val())?c.find("button[type=submit]").prop("disabled",!1):c.find("button[type=submit]").prop("disabled",!0),0<d.length&&this.isValidName(d.find(".as3cf-bucket-name").val())?d.find("button[type=submit]").prop("disabled",!1):d.find("button[type=submit]").prop("disabled",!0),0<e.length&&1===e.find(".as3cf-bucket-list a.selected").length?e.find("button[type=submit]").prop("disabled",!1):e.find("button[type=submit]").prop("disabled",!0))},showError:function(b,c,d){var e=a(".as3cf-bucket-container").children(":visible"),f=e.find(".as3cf-bucket-error");d="undefined"==typeof d?null:d,d&&!e.hasClass(d)||(f.find("span.title").html(b+" &mdash;"),f.find("span.message").html(c),f.show(),this.bucketSelectLock=!1)},isValidName:function(a){return!(a.length<3||a.length>63)&&!0!==n.test(a)},updateNameNotice:function(b){var c=null;!0===n.test(b)?c=as3cf.strings.create_bucket_invalid_chars:b.length<3?c=as3cf.strings.create_bucket_name_short:b.length>63&&(c=as3cf.strings.create_bucket_name_long),c&&b.length>0?a(".as3cf-invalid-bucket-name").html(c):a(".as3cf-invalid-bucket-name").html("")}},as3cf.reloadUpdated=function(){var a=location.pathname+location.search;location.search.match(/[?&]updated=/)||(a+="&updated=1"),a+=location.hash,location.assign(a)},as3cf.showSettingsSavedNotice=function(){if(!(0<a("#setting-error-settings_updated:visible").length||0<a("#as3cf-settings_updated:visible").length)){var b='<div id="as3cf-settings_updated" class="updated settings-error notice is-dismissible"><p><strong>'+as3cf.strings.settings_saved+"</strong></p></div>";a("h2.nav-tab-wrapper").after(b),a(document).trigger("wp-updates-notice-added")}},a(document).ready(function(){k(),window.onhashchange=function(a){"function"==typeof history.replaceState&&"#"===location.href.slice(-1)&&history.replaceState({},"",location.href.slice(0,-1)),k()};var i=a(".as3cf-main .nav-tab-wrapper");a(".as3cf-compatibility-notice, div.updated, div.error, div.notice").not(".below-h2, .inline").insertAfter(i),p.length&&p.each(function(a,b){m[b.id]=c(b.id)}),a(window).on("beforeunload.as3cf-settings",function(){if(!a.isEmptyObject(m)){var b=l.attr("id");return c(b)!==m[b]?as3cf.strings.save_alert:void 0}}),a(document).on("submit",".as3cf-main-settings form",function(b){a(window).off("beforeunload.as3cf-settings")}),a(".as3cf-switch").on("click",function(b){a(this).hasClass("disabled")||d(a(this).attr("id"))}),p.on("change",".sub-toggle",function(b){var c=a(this).attr("id");a(".as3cf-setting."+c).toggleClass("hide")}),a(".as3cf-domain").on("change",'input[type="radio"]',function(b){var c=a(this).closest('input:radio[name="domain"]:checked'),d=c.val(),e=a(this).parents(".as3cf-domain").find(".as3cf-setting.cloudfront"),f="cloudfront"===d;e.toggleClass("hide",!f)}),a(".url-preview").on("change","input",function(a){j()}),g(),a("#as3cf-serve-from-s3,#as3cf-remove-local-file").on("change",function(a){g()}),h(),a("#as3cf-remove-local-file").on("change",function(a){h()}),a('.as3cf-setting input[type="text"]').keypress(function(a){if(13===a.which)return a.preventDefault(),!1}),a('input[name="cloudfront"]').on("keyup",function(b){e(a(this))}),a('input[name="domain"]').on("change",function(b){var c=a(this),d=a("#"+l.attr("id")+' form button[type="submit"]');"cloudfront"!==c.val()?d.prop("disabled",!1):e(c.next(".as3cf-setting").find('input[name="cloudfront"]'))}),a('input[name="object-prefix"]').on("change",function(a){f()}),a("#tab-media > .as3cf-bucket-error").detach().insertAfter(".as3cf-bucket-container h3"),as3cf.buckets.disabledButtons(),o.on("click",".bucket-action-refresh",function(a){a.preventDefault(),as3cf.buckets.loadList(!0)}),o.on("change",".bucket-select-region",function(a){a.preventDefault(),as3cf.buckets.loadList(!0)}),0<a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-select").length&&as3cf.buckets.loadList(!0),o.on("click",".as3cf-bucket-list a",function(b){b.preventDefault(),as3cf.buckets.setSelected(a(this)),as3cf.buckets.disabledButtons()}),a(".as3cf-bucket-container").on("click","a.js-link",function(b){return b.preventDefault(),window.open(a(this).attr("href")),!1}),o.on("input keyup",".as3cf-bucket-create .as3cf-bucket-name",function(b){var c=a(this).val();as3cf.buckets.updateNameNotice(c),as3cf.buckets.disabledButtons()}),o.on("input keyup",".as3cf-bucket-manual .as3cf-bucket-name",function(b){var c=a(this).val();as3cf.buckets.updateNameNotice(c),as3cf.buckets.disabledButtons()}),a('.as3cf-bucket-container input[type="text"]').keypress(function(a){if(13===a.which)return a.preventDefault(),!1})})}(jQuery,as3cfModal);
assets/js/storage-provider.js CHANGED
@@ -1,4 +1,4 @@
1
- ( function( $ ) {
2
  var $body = $( 'body' );
3
 
4
  var as3cf = as3cf || {};
@@ -25,10 +25,12 @@
25
  $( element ).hide();
26
  $( element ).removeClass( 'as3cf-provider-selected' );
27
  $( element ).find( 'input' ).prop( 'disabled', true );
 
28
  },
29
 
30
  enableContent: function( element ) {
31
  $( element ).find( 'input:not( [data-as3cf-disabled="true"] )' ).prop( 'disabled', false );
 
32
  $( element ).addClass( 'as3cf-provider-selected' );
33
  $( element ).show( 'fast', function() {
34
  as3cf.storageProvider.setSelectedAuthMethod( this );
@@ -42,7 +44,7 @@
42
  var checkedCount = $( element ).find( 'input[name="authmethod"]:checked' ).length;
43
 
44
  if ( 1 !== checkedCount ) {
45
- $( element ).find( 'input[name="authmethod"]' ).first().prop( 'checked', true ).change();
46
  }
47
  },
48
 
@@ -82,4 +84,4 @@
82
  } );
83
  } );
84
 
85
- } )( jQuery );
1
+ (function( $ ) {
2
  var $body = $( 'body' );
3
 
4
  var as3cf = as3cf || {};
25
  $( element ).hide();
26
  $( element ).removeClass( 'as3cf-provider-selected' );
27
  $( element ).find( 'input' ).prop( 'disabled', true );
28
+ $( element ).find( 'textarea.as3cf-large-input' ).prop( 'disabled', true );
29
  },
30
 
31
  enableContent: function( element ) {
32
  $( element ).find( 'input:not( [data-as3cf-disabled="true"] )' ).prop( 'disabled', false );
33
+ $( element ).find( 'textarea.as3cf-large-input' ).prop( 'disabled', false );
34
  $( element ).addClass( 'as3cf-provider-selected' );
35
  $( element ).show( 'fast', function() {
36
  as3cf.storageProvider.setSelectedAuthMethod( this );
44
  var checkedCount = $( element ).find( 'input[name="authmethod"]:checked' ).length;
45
 
46
  if ( 1 !== checkedCount ) {
47
+ $( element ).find( 'input[name="authmethod"]:not( [data-as3cf-disabled="true"] )' ).first().prop( 'checked', true ).change();
48
  }
49
  },
50
 
84
  } );
85
  } );
86
 
87
+ })( jQuery );
assets/js/storage-provider.min.js CHANGED
@@ -1 +1 @@
1
- !function(a){var b=a("body"),c=c||{};c.storageProvider={changed:function(){var b=a('input[name="provider"]:checked').val();a(".as3cf-provider-content").each(function(){c.storageProvider.disableContent(this)}),a('.as3cf-provider-content[data-provider="'+b+'"]').each(function(){c.storageProvider.enableContent(this)})},disableContent:function(b){a(b).hide(),a(b).removeClass("as3cf-provider-selected"),a(b).find("input").prop("disabled",!0)},enableContent:function(b){a(b).find('input:not( [data-as3cf-disabled="true"] )').prop("disabled",!1),a(b).addClass("as3cf-provider-selected"),a(b).show("fast",function(){c.storageProvider.setSelectedAuthMethod(this)})},setSelectedAuthMethod:function(b){a(b).find('input[name="authmethod"]:checked').prop("checked",!0).change();var c=a(b).find('input[name="authmethod"]:checked').length;1!==c&&a(b).find('input[name="authmethod"]').first().prop("checked",!0).change()},authMethodChanged:function(){var b=a('input[name="authmethod"]:checked').val();a(".asc3f-provider-authmethod-content").each(function(){c.storageProvider.disableAuthMethodContent(this)}),a('.asc3f-provider-authmethod-content[data-provider-authmethod="'+b+'"]').each(function(){c.storageProvider.enableAuthMethodContent(this)})},disableAuthMethodContent:function(b){a(b).hide()},enableAuthMethodContent:function(b){a(b).show()}},a(document).ready(function(){b.on("change",'input[name="provider"]',function(a){a.preventDefault(),c.storageProvider.changed()}),b.on("change",'input[name="authmethod"]',function(a){a.preventDefault(),c.storageProvider.authMethodChanged()})})}(jQuery);
1
+ !function(a){var b=a("body"),c=c||{};c.storageProvider={changed:function(){var b=a('input[name="provider"]:checked').val();a(".as3cf-provider-content").each(function(){c.storageProvider.disableContent(this)}),a('.as3cf-provider-content[data-provider="'+b+'"]').each(function(){c.storageProvider.enableContent(this)})},disableContent:function(b){a(b).hide(),a(b).removeClass("as3cf-provider-selected"),a(b).find("input").prop("disabled",!0),a(b).find("textarea.as3cf-large-input").prop("disabled",!0)},enableContent:function(b){a(b).find('input:not( [data-as3cf-disabled="true"] )').prop("disabled",!1),a(b).find("textarea.as3cf-large-input").prop("disabled",!1),a(b).addClass("as3cf-provider-selected"),a(b).show("fast",function(){c.storageProvider.setSelectedAuthMethod(this)})},setSelectedAuthMethod:function(b){a(b).find('input[name="authmethod"]:checked').prop("checked",!0).change();var c=a(b).find('input[name="authmethod"]:checked').length;1!==c&&a(b).find('input[name="authmethod"]:not( [data-as3cf-disabled="true"] )').first().prop("checked",!0).change()},authMethodChanged:function(){var b=a('input[name="authmethod"]:checked').val();a(".asc3f-provider-authmethod-content").each(function(){c.storageProvider.disableAuthMethodContent(this)}),a('.asc3f-provider-authmethod-content[data-provider-authmethod="'+b+'"]').each(function(){c.storageProvider.enableAuthMethodContent(this)})},disableAuthMethodContent:function(b){a(b).hide()},enableAuthMethodContent:function(b){a(b).show()}},a(document).ready(function(){b.on("change",'input[name="provider"]',function(a){a.preventDefault(),c.storageProvider.changed()}),b.on("change",'input[name="authmethod"]',function(a){a.preventDefault(),c.storageProvider.authMethodChanged()})})}(jQuery);
assets/sass/storage-provider.scss CHANGED
@@ -1,5 +1,6 @@
1
- $aws_orange: #f7a80d;
2
- $do_blue: #0080ff;
 
3
 
4
  .as3cf-provider-select {
5
  h3 {
@@ -48,13 +49,25 @@ $do_blue: #0080ff;
48
 
49
  &.as3cf-provider-aws {
50
  .as3cf-provider-logo {
51
- background-color: $aws_orange;
 
52
  }
53
  }
54
 
55
  &.as3cf-provider-do {
56
  .as3cf-provider-logo {
57
- background-color: $do_blue;
 
 
 
 
 
 
 
 
 
 
 
58
  }
59
  }
60
  }
@@ -87,13 +100,19 @@ $do_blue: #0080ff;
87
  padding-top: 0;
88
  }
89
 
90
- textarea.as3cf-define-snippet.code {
 
 
 
 
91
  width: 100%;
 
 
 
92
  white-space: pre;
93
  overflow: hidden;
94
  font-size: 11px;
95
  padding: 10px;
96
- margin-top: 10px;
97
  }
98
 
99
  table.as3cf-access-keys {
1
+ $aws_background: #f7a80d;
2
+ $do_background: #0080ff;
3
+ $gcp_background: #ffffff;
4
 
5
  .as3cf-provider-select {
6
  h3 {
49
 
50
  &.as3cf-provider-aws {
51
  .as3cf-provider-logo {
52
+ background-color: $aws_background;
53
+ border: 1px solid $aws_background;
54
  }
55
  }
56
 
57
  &.as3cf-provider-do {
58
  .as3cf-provider-logo {
59
+ background-color: $do_background;
60
+ border: 1px solid $do_background;
61
+ }
62
+ }
63
+
64
+ &.as3cf-provider-gcp {
65
+ .as3cf-provider-logo {
66
+ background-color: $gcp_background;
67
+ border-top: 1px solid #ea4335;
68
+ border-right: 1px solid #4285f4;
69
+ border-bottom: 1px solid #34a853;
70
+ border-left: 1px solid #fbbc05;
71
  }
72
  }
73
  }
100
  padding-top: 0;
101
  }
102
 
103
+ textarea {
104
+ margin-top: 10px;
105
+ }
106
+
107
+ textarea.clear {
108
  width: 100%;
109
+ }
110
+
111
+ textarea.as3cf-define-snippet.code {
112
  white-space: pre;
113
  overflow: hidden;
114
  font-size: 11px;
115
  padding: 10px;
 
116
  }
117
 
118
  table.as3cf-access-keys {
classes/amazon-s3-and-cloudfront.php CHANGED
@@ -2,6 +2,7 @@
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\Null_Provider;
6
  use DeliciousBrains\WP_Offload_Media\Providers\Provider;
7
  use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Content_Replace_URLs;
@@ -138,6 +139,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
138
  static::$provider_classes = array(
139
  AWS_Provider::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\AWS_Provider',
140
  DigitalOcean_Provider::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\DigitalOcean_Provider',
 
141
  );
142
 
143
  $this->set_provider();
@@ -1127,13 +1129,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
1127
  $region = isset( $old_provider_object['region'] ) ? $old_provider_object['region'] : '';
1128
  } else {
1129
  // derive prefix from various settings
1130
- if ( isset( $data['file'] ) ) {
1131
- $time = $this->get_folder_time_from_url( $data['file'] );
1132
- } else {
1133
- $time = $this->get_attachment_folder_time( $post_id );
1134
- $time = date( 'Y/m', $time );
1135
- }
1136
-
1137
  $prefix = $this->get_file_prefix( $time );
1138
 
1139
  // use bucket from settings
@@ -1157,6 +1153,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
1157
  'Expires' => date( 'D, d M Y H:i:s O', time() + 31536000 ),
1158
  );
1159
 
 
1160
  // Handle gzip on supported items
1161
  if ( $this->should_gzip_file( $file_path, $type ) && false !== ( $gzip_body = gzencode( file_get_contents( $file_path ) ) ) ) {
1162
  unset( $args['SourceFile'] );
@@ -1451,31 +1448,42 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
1451
  }
1452
 
1453
  /**
1454
- * Get the time of attachment upload.
1455
  *
1456
- * Use post datetime if attached.
1457
  *
1458
- * @param int $post_id
 
1459
  *
1460
- * @return int|string
1461
  */
1462
- function get_attachment_folder_time( $post_id ) {
1463
- $time = current_time( 'timestamp' );
1464
-
1465
- if ( ! ( $attach = get_post( $post_id ) ) ) {
1466
- return $time;
1467
  }
1468
 
1469
- if ( ! $attach->post_parent ) {
1470
- return $time;
1471
  }
1472
 
1473
- if ( ! ( $post = get_post( $attach->post_parent ) ) ) {
1474
- return $time;
1475
- }
 
 
 
 
 
 
 
 
 
 
 
1476
 
1477
- if ( substr( $post->post_date_gmt, 0, 4 ) > 0 ) {
1478
- return strtotime( $post->post_date_gmt . ' +0000' );
 
1479
  }
1480
 
1481
  return $time;
@@ -1903,8 +1911,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
1903
  * @return mixed|WP_Error
1904
  */
1905
  public function get_attachment_provider_url( $post_id, $provider_object, $expires = null, $size = null, $meta = null, $headers = array() ) {
1906
- $scheme = $this->get_url_scheme();
1907
-
1908
  // We don't use $this->get_provider_object_region() here because we don't want
1909
  // to make an AWS API call and slow down page loading
1910
  if ( isset( $provider_object['region'] ) && ( $this->get_provider()->region_required() || $this->get_provider()->get_default_region() !== $provider_object['region'] ) ) {
@@ -1945,8 +1951,16 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
1945
  }
1946
  }
1947
 
 
 
 
 
1948
  if ( ! is_null( $expires ) && $this->is_plugin_setup( true ) ) {
1949
  try {
 
 
 
 
1950
  $expires = time() + apply_filters( 'as3cf_expires', $expires );
1951
  $secure_url = $this->get_provider_client( $region )
1952
  ->get_object_url( $provider_object['bucket'], $provider_object['key'], $expires, $headers );
@@ -1959,9 +1973,8 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
1959
 
1960
  $provider_object['key'] = $this->maybe_update_cloudfront_path( $provider_object['key'] );
1961
 
1962
- $domain_bucket = $this->get_provider()->get_url_domain( $provider_object['bucket'], $region, $expires );
1963
- $file = $this->encode_filename_in_path( $provider_object['key'] );
1964
- $url = $scheme . '://' . $domain_bucket . '/' . $file;
1965
 
1966
  return apply_filters( 'as3cf_get_attachment_url', $url, $provider_object, $post_id, $expires, $headers );
1967
  }
@@ -2726,7 +2739,11 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2726
  return new WP_Error( 'exception', $e->getMessage() );
2727
  }
2728
 
2729
- return $result['Buckets'];
 
 
 
 
2730
  }
2731
 
2732
  /**
@@ -2770,7 +2787,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2770
  }
2771
 
2772
  $key = $this->get_file_prefix() . 'as3cf-permission-check.txt';
2773
- $file_contents = __( 'This is a test file to check if the user has write permission to S3. Delete me if found.', 'amazon-s3-and-cloudfront' );
2774
 
2775
  $can_write = $this->get_provider_client( $region, true )->can_write( $bucket, $key, $file_contents );
2776
 
@@ -2857,7 +2874,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2857
  wp_localize_script( 'as3cf-script',
2858
  'as3cf',
2859
  array(
2860
- 'strings' => array(
2861
  'create_bucket_error' => __( 'Error creating bucket', 'amazon-s3-and-cloudfront' ),
2862
  'create_bucket_name_short' => __( 'Bucket name too short.', 'amazon-s3-and-cloudfront' ),
2863
  'create_bucket_name_long' => __( 'Bucket name too long.', 'amazon-s3-and-cloudfront' ),
@@ -2872,7 +2889,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2872
  // Mimic WP Core's notice text, therefore no translation needed here.
2873
  'settings_saved' => __( 'Settings saved.' ),
2874
  ),
2875
- 'nonces' => array(
2876
  'create_bucket' => wp_create_nonce( 'as3cf-create-bucket' ),
2877
  'manual_bucket' => wp_create_nonce( 'as3cf-manual-save-bucket' ),
2878
  'get_buckets' => wp_create_nonce( 'as3cf-get-buckets' ),
@@ -2882,9 +2899,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2882
  'aws_keys_set' => wp_create_nonce( 'as3cf-aws-keys-set' ),
2883
  'aws_keys_remove' => wp_create_nonce( 'as3cf-aws-keys-remove' ),
2884
  ),
2885
- 'is_pro' => $this->is_pro(),
2886
- 'provider_console_url' => $this->get_provider()->get_console_url(),
2887
- 'provider_console_url_param' => $this->get_provider()->get_console_url_param(),
2888
  )
2889
  );
2890
 
@@ -2905,6 +2922,8 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2905
  'provider',
2906
  'access-key-id',
2907
  'secret-access-key',
 
 
2908
  'bucket',
2909
  'region',
2910
  'domain',
@@ -2941,7 +2960,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2941
  * @return array
2942
  */
2943
  function get_skip_sanitize_settings() {
2944
- return array();
2945
  }
2946
 
2947
  /**
@@ -2960,6 +2979,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2960
  die( __( "Cheatin' eh?", 'amazon-s3-and-cloudfront' ) );
2961
  }
2962
 
 
 
 
2963
  if ( $this->get_provider()->needs_access_keys() || ( ! empty( $_GET['action'] ) && 'change-provider' === $_GET['action'] ) ) {
2964
  // Changing Provider currently doesn't need anything special over saving settings,
2965
  // but if not already set needs to be handled rather than change-bucket raising its hand.
@@ -2988,7 +3010,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
2988
  // If anything about the Provider has changed then we need to verify the bucket selection.
2989
  // Otherwise we can let the filter decide whether there is an action to take.
2990
  // Last implementer will win, but the above handlers take care of grouping things appropriately.
2991
- if ( in_array( $key, array( 'provider', 'access-key-id', 'secret-access-key' ) ) && ! $this->get_defined_setting( 'bucket', false ) ) {
2992
  $action = 'change-bucket';
2993
  break;
2994
  } else {
@@ -3012,10 +3034,14 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3012
 
3013
  if ( ! empty( $action ) ) {
3014
  $url_args['action'] = $action;
3015
- }
3016
 
3017
- if ( ! empty( $prev_action ) ) {
3018
- $url_args['prev_action'] = $prev_action;
 
 
 
 
 
3019
  }
3020
 
3021
  $url = $this->get_plugin_page_url( $url_args );
@@ -3043,7 +3069,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3043
  $bucket = $this->check_bucket( $bucket );
3044
 
3045
  if ( false === $bucket ) {
3046
- $this->notices->add_notice( __( 'No bucket name not valid.', 'amazon-s3-and-cloudfront' ), array( 'type' => 'error', 'only_show_in_settings' => true, 'only_show_on_tab' => 'media' ) );
3047
 
3048
  return false;
3049
  }
@@ -3121,9 +3147,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3121
  /**
3122
  * Handle saving settings submitted by user.
3123
  *
3124
- * @return array
3125
  */
3126
- private function handle_save_settings() {
3127
  $changed_keys = array();
3128
 
3129
  do_action( 'as3cf_pre_save_settings' );
@@ -3145,6 +3171,23 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3145
 
3146
  $value = $this->sanitize_setting( $var, $_POST[ $var ] );
3147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3148
  $this->set_setting( $var, $value );
3149
 
3150
  // Some setting changes might have knock-on effects that require confirmation of secondary settings.
@@ -3357,6 +3400,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3357
  * @param string $acl
3358
  *
3359
  * @return array|bool|WP_Error
 
3360
  */
3361
  public function set_attachment_acl_on_provider( $post_id, $provider_object, $acl ) {
3362
  // Return early if already set to the desired ACL
@@ -3466,6 +3510,10 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3466
  global $table_prefix;
3467
  global $wpdb;
3468
 
 
 
 
 
3469
  $output = 'site_url(): ';
3470
  $output .= esc_html( site_url() );
3471
  $output .= "\r\n";
@@ -3660,6 +3708,10 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3660
  }
3661
  $output .= "\r\n\r\n";
3662
 
 
 
 
 
3663
  $media_counts = $this->diagnostic_media_counts();
3664
 
3665
  $output .= 'Media Files: ';
@@ -3681,6 +3733,10 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3681
  $output .= $size_details;
3682
  $output .= "\r\n";
3683
 
 
 
 
 
3684
  $output .= 'WP_CONTENT_DIR: ';
3685
  $output .= esc_html( ( defined( 'WP_CONTENT_DIR' ) ) ? WP_CONTENT_DIR : 'Not defined' );
3686
  $output .= "\r\n";
@@ -3701,10 +3757,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3701
  $output .= esc_html( ( defined( 'WP_PLUGIN_URL' ) ) ? WP_PLUGIN_URL : 'Not defined' );
3702
  $output .= "\r\n\r\n";
3703
 
3704
- $output .= 'AWS_USE_EC2_IAM_ROLE: ';
3705
- $output .= esc_html( ( defined( 'AWS_USE_EC2_IAM_ROLE' ) ) ? AWS_USE_EC2_IAM_ROLE : 'Not defined' );
3706
- $output .= "\r\n";
3707
-
3708
  $output .= 'AS3CF_PROVIDER: ';
3709
  $output .= esc_html( ( defined( 'AS3CF_PROVIDER' ) ) ? AS3CF_PROVIDER : 'Not defined' );
3710
  $output .= "\r\n";
@@ -3715,53 +3767,130 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3715
 
3716
  $output .= 'AS3CF_REGION: ';
3717
  $output .= esc_html( ( defined( 'AS3CF_REGION' ) ) ? AS3CF_REGION : 'Not defined' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3718
  $output .= "\r\n\r\n";
3719
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3720
  $output .= 'Bucket: ';
3721
- $output .= $this->get_setting( 'bucket' );
3722
  $output .= "\r\n";
3723
  $output .= 'Region: ';
3724
- $region = $this->get_setting( 'region' );
3725
  if ( ! is_wp_error( $region ) ) {
3726
  $output .= $region;
3727
  }
3728
  $output .= "\r\n";
 
 
3729
  $output .= 'Copy Files to Bucket: ';
3730
  $output .= $this->on_off( 'copy-to-s3' );
3731
  $output .= "\r\n";
3732
- $output .= 'Rewrite File URLs: ';
3733
- $output .= $this->on_off( 'serve-from-s3' );
3734
  $output .= "\r\n";
 
 
3735
  $output .= "\r\n";
3736
-
3737
- $output .= "Local URL:\r\n";
3738
- $output .= $this->get_local_url_preview( $escape );
3739
  $output .= "\r\n";
3740
- $output .= "Offload URL:\r\n";
3741
- $output .= $this->get_url_preview( $escape );
3742
  $output .= "\r\n";
3743
  $output .= "\r\n";
3744
 
3745
- $output .= 'Domain: ';
3746
- $output .= $this->get_setting( 'domain' );
3747
- $output .= "\r\n";
3748
- $output .= 'Enable Path: ';
3749
- $output .= $this->on_off( 'enable-object-prefix' );
3750
  $output .= "\r\n";
3751
- $output .= 'Custom Path: ';
3752
- $output .= $this->get_setting( 'object-prefix' );
3753
  $output .= "\r\n";
3754
- $output .= 'Use Year/Month: ';
3755
- $output .= $this->on_off( 'use-yearmonth-folders' );
3756
  $output .= "\r\n";
3757
  $output .= 'Force HTTPS: ';
3758
  $output .= $this->on_off( 'force-https' );
3759
  $output .= "\r\n";
 
 
3760
  $output .= 'Remove Files From Server: ';
3761
  $output .= $this->on_off( 'remove-local-file' );
3762
- $output .= "\r\n";
3763
- $output .= 'Object Versioning: ';
3764
- $output .= $this->on_off( 'object-versioning' );
3765
  $output .= "\r\n\r\n";
3766
 
3767
  $output = apply_filters( 'as3cf_diagnostic_info', $output );
@@ -3879,14 +4008,15 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
3879
  /**
3880
  * Helper to remove the plugin directory from the plugin path
3881
  *
3882
- * @param string $path
3883
  *
3884
  * @return string
3885
  */
3886
- function remove_wp_plugin_dir( $path ) {
3887
- $plugin = str_replace( WP_PLUGIN_DIR, '', $path );
 
3888
 
3889
- return substr( $plugin, 1 );
3890
  }
3891
 
3892
  /**
@@ -4057,9 +4187,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
4057
 
4058
  $quick_start = sprintf( '<a class="js-link" href="%s">%s</a>', $url, __( 'Quick Start Guide', 'amazon-s3-and-cloudfront' ) );
4059
 
4060
- $message = sprintf( __( "Looks like we don't have write access to this bucket. It's likely that the user you've provided access keys for hasn't been granted the correct permissions. Please see our %s for instructions on setting up permissions correctly.", 'amazon-s3-and-cloudfront' ), $quick_start );
4061
  if ( ! $single ) {
4062
- $message = sprintf( __( "Looks like we don't have access to the buckets. It's likely that the user you've provided access keys for hasn't been granted the correct permissions. Please see our %s for instructions on setting up permissions correctly.", 'amazon-s3-and-cloudfront' ), $quick_start );
4063
  }
4064
 
4065
  return $message;
@@ -4568,7 +4698,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
4568
  *
4569
  * @return array
4570
  */
4571
- function add_media_row_actions( $actions = array(), $post ) {
4572
  return $actions;
4573
  }
4574
 
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;
6
  use DeliciousBrains\WP_Offload_Media\Providers\Null_Provider;
7
  use DeliciousBrains\WP_Offload_Media\Providers\Provider;
8
  use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Content_Replace_URLs;
139
  static::$provider_classes = array(
140
  AWS_Provider::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\AWS_Provider',
141
  DigitalOcean_Provider::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\DigitalOcean_Provider',
142
+ GCP_Provider::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\GCP_Provider',
143
  );
144
 
145
  $this->set_provider();
1129
  $region = isset( $old_provider_object['region'] ) ? $old_provider_object['region'] : '';
1130
  } else {
1131
  // derive prefix from various settings
1132
+ $time = $this->get_attachment_folder_year_month( $post_id, $data );
 
 
 
 
 
 
1133
  $prefix = $this->get_file_prefix( $time );
1134
 
1135
  // use bucket from settings
1153
  'Expires' => date( 'D, d M Y H:i:s O', time() + 31536000 ),
1154
  );
1155
 
1156
+ // TODO: Remove GZIP functionality.
1157
  // Handle gzip on supported items
1158
  if ( $this->should_gzip_file( $file_path, $type ) && false !== ( $gzip_body = gzencode( file_get_contents( $file_path ) ) ) ) {
1159
  unset( $args['SourceFile'] );
1448
  }
1449
 
1450
  /**
1451
+ * Get the year/month string for attachment's upload.
1452
  *
1453
+ * Fall back to post date if attached, otherwise current date.
1454
  *
1455
+ * @param int $post_id Attachment's ID
1456
+ * @param array $data Attachment's metadata
1457
  *
1458
+ * @return string
1459
  */
1460
+ function get_attachment_folder_year_month( $post_id, $data = null ) {
1461
+ if ( isset( $data['file'] ) ) {
1462
+ $time = $this->get_folder_time_from_url( $data['file'] );
 
 
1463
  }
1464
 
1465
+ if ( empty( $time ) && ( $local_url = wp_get_attachment_url( $post_id ) ) ) {
1466
+ $time = $this->get_folder_time_from_url( $local_url );
1467
  }
1468
 
1469
+ if ( empty( $time ) ) {
1470
+ $time = date( 'Y/m' );
1471
+
1472
+ if ( ! ( $attach = get_post( $post_id ) ) ) {
1473
+ return $time;
1474
+ }
1475
+
1476
+ if ( ! $attach->post_parent ) {
1477
+ return $time;
1478
+ }
1479
+
1480
+ if ( ! ( $post = get_post( $attach->post_parent ) ) ) {
1481
+ return $time;
1482
+ }
1483
 
1484
+ if ( substr( $post->post_date_gmt, 0, 4 ) > 0 ) {
1485
+ return date( 'Y/m', strtotime( $post->post_date_gmt . ' +0000' ) );
1486
+ }
1487
  }
1488
 
1489
  return $time;
1911
  * @return mixed|WP_Error
1912
  */
1913
  public function get_attachment_provider_url( $post_id, $provider_object, $expires = null, $size = null, $meta = null, $headers = array() ) {
 
 
1914
  // We don't use $this->get_provider_object_region() here because we don't want
1915
  // to make an AWS API call and slow down page loading
1916
  if ( isset( $provider_object['region'] ) && ( $this->get_provider()->region_required() || $this->get_provider()->get_default_region() !== $provider_object['region'] ) ) {
1951
  }
1952
  }
1953
 
1954
+ $scheme = $this->get_url_scheme();
1955
+ $domain = $this->get_provider()->get_url_domain( $provider_object['bucket'], $region, $expires );
1956
+ $base_url = $scheme . '://' . $domain;
1957
+
1958
  if ( ! is_null( $expires ) && $this->is_plugin_setup( true ) ) {
1959
  try {
1960
+ if ( $this->get_provider()->get_domain() !== $domain ) {
1961
+ $headers['BaseURL'] = $base_url;
1962
+ }
1963
+
1964
  $expires = time() + apply_filters( 'as3cf_expires', $expires );
1965
  $secure_url = $this->get_provider_client( $region )
1966
  ->get_object_url( $provider_object['bucket'], $provider_object['key'], $expires, $headers );
1973
 
1974
  $provider_object['key'] = $this->maybe_update_cloudfront_path( $provider_object['key'] );
1975
 
1976
+ $file = $this->encode_filename_in_path( $provider_object['key'] );
1977
+ $url = $base_url . '/' . $file;
 
1978
 
1979
  return apply_filters( 'as3cf_get_attachment_url', $url, $provider_object, $post_id, $expires, $headers );
1980
  }
2739
  return new WP_Error( 'exception', $e->getMessage() );
2740
  }
2741
 
2742
+ if ( empty( $result['Buckets'] ) ) {
2743
+ return array();
2744
+ } else {
2745
+ return $result['Buckets'];
2746
+ }
2747
  }
2748
 
2749
  /**
2787
  }
2788
 
2789
  $key = $this->get_file_prefix() . 'as3cf-permission-check.txt';
2790
+ $file_contents = __( 'This is a test file to check if the user has write permission to the bucket. Delete me if found.', 'amazon-s3-and-cloudfront' );
2791
 
2792
  $can_write = $this->get_provider_client( $region, true )->can_write( $bucket, $key, $file_contents );
2793
 
2874
  wp_localize_script( 'as3cf-script',
2875
  'as3cf',
2876
  array(
2877
+ 'strings' => array(
2878
  'create_bucket_error' => __( 'Error creating bucket', 'amazon-s3-and-cloudfront' ),
2879
  'create_bucket_name_short' => __( 'Bucket name too short.', 'amazon-s3-and-cloudfront' ),
2880
  'create_bucket_name_long' => __( 'Bucket name too long.', 'amazon-s3-and-cloudfront' ),
2889
  // Mimic WP Core's notice text, therefore no translation needed here.
2890
  'settings_saved' => __( 'Settings saved.' ),
2891
  ),
2892
+ 'nonces' => array(
2893
  'create_bucket' => wp_create_nonce( 'as3cf-create-bucket' ),
2894
  'manual_bucket' => wp_create_nonce( 'as3cf-manual-save-bucket' ),
2895
  'get_buckets' => wp_create_nonce( 'as3cf-get-buckets' ),
2899
  'aws_keys_set' => wp_create_nonce( 'as3cf-aws-keys-set' ),
2900
  'aws_keys_remove' => wp_create_nonce( 'as3cf-aws-keys-remove' ),
2901
  ),
2902
+ 'is_pro' => $this->is_pro(),
2903
+ 'provider_console_url' => $this->get_provider()->get_console_url(),
2904
+ 'provider_console_url_prefix_param' => $this->get_provider()->get_console_url_prefix_param(),
2905
  )
2906
  );
2907
 
2922
  'provider',
2923
  'access-key-id',
2924
  'secret-access-key',
2925
+ 'key-file-path',
2926
+ 'key-file',
2927
  'bucket',
2928
  'region',
2929
  'domain',
2960
  * @return array
2961
  */
2962
  function get_skip_sanitize_settings() {
2963
+ return array( 'key-file' );
2964
  }
2965
 
2966
  /**
2979
  die( __( "Cheatin' eh?", 'amazon-s3-and-cloudfront' ) );
2980
  }
2981
 
2982
+ // Keep track of original provider at start of settings change flow.
2983
+ $orig_provider = empty( $_GET['orig_provider'] ) ? $this->get_setting( 'provider', false ) : $_GET['orig_provider'];
2984
+
2985
  if ( $this->get_provider()->needs_access_keys() || ( ! empty( $_GET['action'] ) && 'change-provider' === $_GET['action'] ) ) {
2986
  // Changing Provider currently doesn't need anything special over saving settings,
2987
  // but if not already set needs to be handled rather than change-bucket raising its hand.
3010
  // If anything about the Provider has changed then we need to verify the bucket selection.
3011
  // Otherwise we can let the filter decide whether there is an action to take.
3012
  // Last implementer will win, but the above handlers take care of grouping things appropriately.
3013
+ if ( in_array( $key, array( 'provider', 'access-key-id', 'secret-access-key', 'key-file' ) ) && ! $this->get_defined_setting( 'bucket', false ) ) {
3014
  $action = 'change-bucket';
3015
  break;
3016
  } else {
3034
 
3035
  if ( ! empty( $action ) ) {
3036
  $url_args['action'] = $action;
 
3037
 
3038
+ if ( ! empty( $prev_action ) ) {
3039
+ $url_args['prev_action'] = $prev_action;
3040
+ }
3041
+
3042
+ if ( ! empty( $orig_provider ) ) {
3043
+ $url_args['orig_provider'] = $orig_provider;
3044
+ }
3045
  }
3046
 
3047
  $url = $this->get_plugin_page_url( $url_args );
3069
  $bucket = $this->check_bucket( $bucket );
3070
 
3071
  if ( false === $bucket ) {
3072
+ $this->notices->add_notice( __( 'Bucket name not valid.', 'amazon-s3-and-cloudfront' ), array( 'type' => 'error', 'only_show_in_settings' => true, 'only_show_on_tab' => 'media' ) );
3073
 
3074
  return false;
3075
  }
3147
  /**
3148
  * Handle saving settings submitted by user.
3149
  *
3150
+ * @return array|bool
3151
  */
3152
+ protected function handle_save_settings() {
3153
  $changed_keys = array();
3154
 
3155
  do_action( 'as3cf_pre_save_settings' );
3171
 
3172
  $value = $this->sanitize_setting( $var, $_POST[ $var ] );
3173
 
3174
+ if ( 'key-file' === $var && is_string( $value ) && ! empty( $value ) ) {
3175
+ $value = stripslashes( $value );
3176
+
3177
+ // Guard against empty JSON.
3178
+ if ( '""' === $value ) {
3179
+ continue;
3180
+ }
3181
+
3182
+ $value = json_decode( $value, true );
3183
+
3184
+ if ( empty( $value ) ) {
3185
+ $this->notices->add_notice( __( 'Key File not valid JSON.', 'amazon-s3-and-cloudfront' ), array( 'type' => 'error', 'only_show_in_settings' => true, 'only_show_on_tab' => 'media' ) );
3186
+
3187
+ return false;
3188
+ }
3189
+ }
3190
+
3191
  $this->set_setting( $var, $value );
3192
 
3193
  // Some setting changes might have knock-on effects that require confirmation of secondary settings.
3400
  * @param string $acl
3401
  *
3402
  * @return array|bool|WP_Error
3403
+ * @throws Exception
3404
  */
3405
  public function set_attachment_acl_on_provider( $post_id, $provider_object, $acl ) {
3406
  // Return early if already set to the desired ACL
3510
  global $table_prefix;
3511
  global $wpdb;
3512
 
3513
+ /*
3514
+ * WordPress & Server Environment
3515
+ */
3516
+
3517
  $output = 'site_url(): ';
3518
  $output .= esc_html( site_url() );
3519
  $output .= "\r\n";
3708
  }
3709
  $output .= "\r\n\r\n";
3710
 
3711
+ /*
3712
+ * Media
3713
+ */
3714
+
3715
  $media_counts = $this->diagnostic_media_counts();
3716
 
3717
  $output .= 'Media Files: ';
3733
  $output .= $size_details;
3734
  $output .= "\r\n";
3735
 
3736
+ /*
3737
+ * Defines
3738
+ */
3739
+
3740
  $output .= 'WP_CONTENT_DIR: ';
3741
  $output .= esc_html( ( defined( 'WP_CONTENT_DIR' ) ) ? WP_CONTENT_DIR : 'Not defined' );
3742
  $output .= "\r\n";
3757
  $output .= esc_html( ( defined( 'WP_PLUGIN_URL' ) ) ? WP_PLUGIN_URL : 'Not defined' );
3758
  $output .= "\r\n\r\n";
3759
 
 
 
 
 
3760
  $output .= 'AS3CF_PROVIDER: ';
3761
  $output .= esc_html( ( defined( 'AS3CF_PROVIDER' ) ) ? AS3CF_PROVIDER : 'Not defined' );
3762
  $output .= "\r\n";
3767
 
3768
  $output .= 'AS3CF_REGION: ';
3769
  $output .= esc_html( ( defined( 'AS3CF_REGION' ) ) ? AS3CF_REGION : 'Not defined' );
3770
+ $output .= "\r\n";
3771
+
3772
+ $output .= 'AS3CF_SETTINGS: ';
3773
+
3774
+ $settings_constant = $this::settings_constant();
3775
+
3776
+ if ( $settings_constant ) {
3777
+ $output .= 'Defined';
3778
+
3779
+ if ( 'AS3CF_SETTINGS' !== $settings_constant ) {
3780
+ $output .= ' (using ' . $settings_constant . ')';
3781
+ }
3782
+
3783
+ $defined_settings = $this::get_defined_settings();
3784
+ if ( empty( $defined_settings ) ) {
3785
+ $output .= ' - *EMPTY*';
3786
+ } else {
3787
+ $output .= "\r\n";
3788
+ $output .= 'AS3CF_SETTINGS Keys: ' . implode( ', ', array_keys( $defined_settings ) );
3789
+ }
3790
+ } else {
3791
+ $output .= 'Not defined';
3792
+ }
3793
  $output .= "\r\n\r\n";
3794
 
3795
+ /*
3796
+ * Settings
3797
+ */
3798
+
3799
+ $output .= "Local URL:\r\n";
3800
+ $output .= $this->get_local_url_preview( $escape );
3801
+ $output .= "\r\n";
3802
+ $output .= "Offload URL:\r\n";
3803
+ $output .= $this->get_url_preview( $escape );
3804
+ $output .= "\r\n";
3805
+ $output .= "\r\n";
3806
+
3807
+ $provider = $this->get_provider();
3808
+
3809
+ if ( empty( $provider ) ) {
3810
+ $output .= 'Provider: Not configured';
3811
+ $output .= "\r\n";
3812
+ } else {
3813
+ $output .= 'Provider: ' . $provider::get_provider_name();
3814
+ $output .= "\r\n";
3815
+
3816
+ if ( $provider::use_server_roles_allowed() ) {
3817
+ $output .= 'Use Server Role: ' . $this->on_off( $provider::use_server_roles() );
3818
+ } else {
3819
+ $output .= 'Use Server Role: N/A';
3820
+ }
3821
+ $output .= "\r\n";
3822
+
3823
+ if ( $provider::use_key_file_allowed() ) {
3824
+ $output .= 'Key File Path: ';
3825
+ $output .= empty( $provider->get_key_file_path() ) ? 'None' : esc_html( $provider->get_key_file_path() );
3826
+ $output .= "\r\n";
3827
+ $output .= 'Key File Path Define: ';
3828
+ $output .= $provider::key_file_path_constant() ? $provider::key_file_path_constant() : 'Not defined';
3829
+ } else {
3830
+ $output .= 'Key File Path: N/A';
3831
+ }
3832
+ $output .= "\r\n";
3833
+
3834
+ if ( $provider::use_access_keys_allowed() ) {
3835
+ $output .= 'Access Keys Set: ';
3836
+ $output .= $provider->are_access_keys_set() ? 'Yes' : 'No';
3837
+ $output .= "\r\n";
3838
+ $output .= 'Access Key ID Define: ';
3839
+ $output .= $provider::access_key_id_constant() ? $provider::access_key_id_constant() : 'Not defined';
3840
+ $output .= "\r\n";
3841
+ $output .= 'Secret Access Key Define: ';
3842
+ $output .= $provider::secret_access_key_constant() ? $provider::secret_access_key_constant() : 'Not defined';
3843
+ } else {
3844
+ $output .= 'Access Keys Set: N/A';
3845
+ }
3846
+ $output .= "\r\n";
3847
+ }
3848
+ $output .= "\r\n";
3849
+
3850
  $output .= 'Bucket: ';
3851
+ $output .= esc_html( $this->get_setting( 'bucket' ) );
3852
  $output .= "\r\n";
3853
  $output .= 'Region: ';
3854
+ $region = esc_html( $this->get_setting( 'region' ) );
3855
  if ( ! is_wp_error( $region ) ) {
3856
  $output .= $region;
3857
  }
3858
  $output .= "\r\n";
3859
+ $output .= "\r\n";
3860
+
3861
  $output .= 'Copy Files to Bucket: ';
3862
  $output .= $this->on_off( 'copy-to-s3' );
3863
  $output .= "\r\n";
3864
+ $output .= 'Enable Path: ';
3865
+ $output .= $this->on_off( 'enable-object-prefix' );
3866
  $output .= "\r\n";
3867
+ $output .= 'Custom Path: ';
3868
+ $output .= esc_html( $this->get_setting( 'object-prefix' ) );
3869
  $output .= "\r\n";
3870
+ $output .= 'Use Year/Month: ';
3871
+ $output .= $this->on_off( 'use-yearmonth-folders' );
 
3872
  $output .= "\r\n";
3873
+ $output .= 'Object Versioning: ';
3874
+ $output .= $this->on_off( 'object-versioning' );
3875
  $output .= "\r\n";
3876
  $output .= "\r\n";
3877
 
3878
+ $output .= 'Rewrite Media URLs: ';
3879
+ $output .= $this->on_off( 'serve-from-s3' );
 
 
 
3880
  $output .= "\r\n";
3881
+ $output .= 'Enable Custom Domain (CDN): ';
3882
+ $output .= 'cloudfront' === $this->get_setting( 'domain' ) ? 'On' : 'Off';
3883
  $output .= "\r\n";
3884
+ $output .= 'Custom Domain (CDN): ';
3885
+ $output .= esc_html( $this->get_setting( 'cloudfront' ) );
3886
  $output .= "\r\n";
3887
  $output .= 'Force HTTPS: ';
3888
  $output .= $this->on_off( 'force-https' );
3889
  $output .= "\r\n";
3890
+ $output .= "\r\n";
3891
+
3892
  $output .= 'Remove Files From Server: ';
3893
  $output .= $this->on_off( 'remove-local-file' );
 
 
 
3894
  $output .= "\r\n\r\n";
3895
 
3896
  $output = apply_filters( 'as3cf_diagnostic_info', $output );
4008
  /**
4009
  * Helper to remove the plugin directory from the plugin path
4010
  *
4011
+ * @param string $path Absolute plugin file path
4012
  *
4013
  * @return string
4014
  */
4015
+ public function remove_wp_plugin_dir( $path ) {
4016
+ $plugin_dir = trailingslashit( WP_PLUGIN_DIR );
4017
+ $plugin = str_replace( $plugin_dir, '', $path );
4018
 
4019
+ return $plugin;
4020
  }
4021
 
4022
  /**
4187
 
4188
  $quick_start = sprintf( '<a class="js-link" href="%s">%s</a>', $url, __( 'Quick Start Guide', 'amazon-s3-and-cloudfront' ) );
4189
 
4190
+ $message = sprintf( __( "Looks like we don't have write access to this bucket. It's likely that the user you've provided credentials for hasn't been granted the correct permissions. Please see our %s for instructions on setting up permissions correctly.", 'amazon-s3-and-cloudfront' ), $quick_start );
4191
  if ( ! $single ) {
4192
+ $message = sprintf( __( "Looks like we don't have access to the buckets. It's likely that the user you've provided credentials for hasn't been granted the correct permissions. Please see our %s for instructions on setting up permissions correctly.", 'amazon-s3-and-cloudfront' ), $quick_start );
4193
  }
4194
 
4195
  return $message;
4698
  *
4699
  * @return array
4700
  */
4701
+ function add_media_row_actions( Array $actions, $post ) {
4702
  return $actions;
4703
  }
4704
 
classes/as3cf-compatibility-check.php CHANGED
@@ -620,6 +620,14 @@ if ( ! class_exists( 'AS3CF_Compatibility_Check' ) ) {
620
  $errors[] = __( 'a PHP version less than 5.5', 'amazon-s3-and-cloudfront' );
621
  }
622
 
 
 
 
 
 
 
 
 
623
  if ( ! function_exists( 'curl_version' ) ) {
624
  $errors[] = __( 'no PHP cURL library activated', 'amazon-s3-and-cloudfront' );
625
 
@@ -665,7 +673,7 @@ if ( ! class_exists( 'AS3CF_Compatibility_Check' ) ) {
665
  return '';
666
  }
667
 
668
- $msg = __( 'The official Amazon&nbsp;Web&nbsp;Services SDK requires PHP 5.5+ and cURL 7.16.2+ compiled with OpenSSL and zlib. Your server currently has', 'amazon-s3-and-cloudfront' );
669
 
670
  if ( count( $errors ) > 1 ) {
671
  $last_one = ' and ' . array_pop( $errors );
620
  $errors[] = __( 'a PHP version less than 5.5', 'amazon-s3-and-cloudfront' );
621
  }
622
 
623
+ if ( ! class_exists( 'SimpleXMLElement' ) ) {
624
+ $errors[] = __( 'no SimpleXML PHP module', 'amazon-s3-and-cloudfront' );
625
+ }
626
+
627
+ if ( ! class_exists( 'XMLWriter' ) ) {
628
+ $errors[] = __( 'no XMLWriter PHP module', 'amazon-s3-and-cloudfront' );
629
+ }
630
+
631
  if ( ! function_exists( 'curl_version' ) ) {
632
  $errors[] = __( 'no PHP cURL library activated', 'amazon-s3-and-cloudfront' );
633
 
673
  return '';
674
  }
675
 
676
+ $msg = __( 'The official Amazon&nbsp;Web&nbsp;Services SDK requires PHP 5.5+ with SimpleXML and XMLWriter modules, and cURL 7.16.2+ compiled with OpenSSL and zlib. Your server currently has', 'amazon-s3-and-cloudfront' );
677
 
678
  if ( count( $errors ) > 1 ) {
679
  $last_one = ' and ' . array_pop( $errors );
classes/as3cf-plugin-base.php CHANGED
@@ -126,6 +126,19 @@ abstract class AS3CF_Plugin_Base {
126
  return $this->settings;
127
  }
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  /**
130
  * Get the constant used to define the settings.
131
  *
@@ -309,16 +322,24 @@ abstract class AS3CF_Plugin_Base {
309
  /**
310
  * Sanitize a setting value, maybe.
311
  *
312
- * @param $key
313
- * @param $value
314
  *
315
- * @return string
316
  */
317
  function sanitize_setting( $key, $value ) {
318
  $skip_sanitize = $this->get_skip_sanitize_settings();
319
 
320
  if ( in_array( $key, $skip_sanitize ) ) {
321
- $value = wp_strip_all_tags( $value );
 
 
 
 
 
 
 
 
322
  } else {
323
  $value = sanitize_text_field( $value );
324
  }
126
  return $this->settings;
127
  }
128
 
129
+ /**
130
+ * Returns first (preferred) settings constant that can be defined, otherwise blank.
131
+ *
132
+ * @return string
133
+ */
134
+ public static function preferred_settings_constant() {
135
+ if ( ! empty( static::$settings_constants ) ) {
136
+ return static::$settings_constants[0];
137
+ } else {
138
+ return '';
139
+ }
140
+ }
141
+
142
  /**
143
  * Get the constant used to define the settings.
144
  *
322
  /**
323
  * Sanitize a setting value, maybe.
324
  *
325
+ * @param string $key
326
+ * @param mixed $value
327
  *
328
+ * @return mixed
329
  */
330
  function sanitize_setting( $key, $value ) {
331
  $skip_sanitize = $this->get_skip_sanitize_settings();
332
 
333
  if ( in_array( $key, $skip_sanitize ) ) {
334
+ if ( is_array( $value ) ) {
335
+ $result = array();
336
+ foreach ( $value as $k => $v ) {
337
+ $result[ $k ] = wp_strip_all_tags( $v );
338
+ }
339
+ $value = $result;
340
+ } else {
341
+ $value = wp_strip_all_tags( $value );
342
+ }
343
  } else {
344
  $value = sanitize_text_field( $value );
345
  }
classes/providers/aws-provider.php CHANGED
@@ -139,7 +139,7 @@ class AWS_Provider extends Provider {
139
  /**
140
  * @var string
141
  */
142
- protected $console_url_param = '&prefix=';
143
 
144
  const API_VERSION = '2006-03-01';
145
  const SIGNATURE_VERSION = 'v4';
@@ -265,7 +265,7 @@ class AWS_Provider extends Provider {
265
  /**
266
  * Check whether bucket exists.
267
  *
268
- * @param $bucket
269
  *
270
  * @return bool
271
  */
@@ -301,9 +301,9 @@ class AWS_Provider extends Provider {
301
  /**
302
  * Check whether key exists in bucket.
303
  *
304
- * @param $bucket
305
- * @param $key
306
- * @param array $options
307
  *
308
  * @return bool
309
  */
@@ -343,10 +343,10 @@ class AWS_Provider extends Provider {
343
  /**
344
  * Get object's URL.
345
  *
346
- * @param $bucket
347
- * @param $key
348
- * @param $expires
349
- * @param array $args
350
  *
351
  * @return string
352
  */
@@ -359,7 +359,7 @@ class AWS_Provider extends Provider {
359
 
360
  $command = $this->s3_client->getCommand( 'GetObject', $commandArgs );
361
 
362
- if ( empty( $expires ) ) {
363
  return (string) \DeliciousBrains\WP_Offload_Media\Aws3\Aws\serialize( $command )->getUri();
364
  } else {
365
  return (string) $this->s3_client->createPresignedRequest( $command, $expires )->getUri();
@@ -436,10 +436,17 @@ class AWS_Provider extends Provider {
436
 
437
  /* @var ResultInterface $result */
438
  foreach ( $results as $attachment_id => $result ) {
439
- $found_keys = $result->search( 'Contents[].Key' );
 
440
 
441
- if ( ! empty( $found_keys ) ) {
442
- $keys[ $attachment_id ] = $found_keys;
 
 
 
 
 
 
443
  }
444
  }
445
 
@@ -524,7 +531,7 @@ class AWS_Provider extends Provider {
524
  'Bucket' => $bucket,
525
  'Key' => $key,
526
  'Body' => $file_contents,
527
- 'ACL' => 'public-read',
528
  ) );
529
 
530
  // delete it straight away if created
@@ -536,7 +543,7 @@ class AWS_Provider extends Provider {
536
  return true;
537
  } catch ( \Exception $e ) {
538
  // If we encounter an error that isn't access denied, throw that error.
539
- if ( ! $e instanceof S3Exception || 'AccessDenied' !== $e->getAwsErrorCode() ) {
540
  return $e->getMessage();
541
  }
542
  }
@@ -599,4 +606,16 @@ class AWS_Provider extends Provider {
599
 
600
  return $domain;
601
  }
 
 
 
 
 
 
 
 
 
 
 
 
602
  }
139
  /**
140
  * @var string
141
  */
142
+ protected $console_url_prefix_param = '&prefix=';
143
 
144
  const API_VERSION = '2006-03-01';
145
  const SIGNATURE_VERSION = 'v4';
265
  /**
266
  * Check whether bucket exists.
267
  *
268
+ * @param string $bucket
269
  *
270
  * @return bool
271
  */
301
  /**
302
  * Check whether key exists in bucket.
303
  *
304
+ * @param string $bucket
305
+ * @param string $key
306
+ * @param array $options
307
  *
308
  * @return bool
309
  */
343
  /**
344
  * Get object's URL.
345
  *
346
+ * @param string $bucket
347
+ * @param string $key
348
+ * @param int $expires
349
+ * @param array $args
350
  *
351
  * @return string
352
  */
359
 
360
  $command = $this->s3_client->getCommand( 'GetObject', $commandArgs );
361
 
362
+ if ( empty( $expires ) || ! is_int( $expires ) || $expires < 0 ) {
363
  return (string) \DeliciousBrains\WP_Offload_Media\Aws3\Aws\serialize( $command )->getUri();
364
  } else {
365
  return (string) $this->s3_client->createPresignedRequest( $command, $expires )->getUri();
436
 
437
  /* @var ResultInterface $result */
438
  foreach ( $results as $attachment_id => $result ) {
439
+ if ( is_a( $result, 'DeliciousBrains\WP_Offload_Media\Aws3\Aws\ResultInterface' ) ) {
440
+ $found_keys = $result->search( 'Contents[].Key' );
441
 
442
+ if ( ! empty( $found_keys ) ) {
443
+ $keys[ $attachment_id ] = $found_keys;
444
+ }
445
+ } elseif ( is_a( $result, 'DeliciousBrains\WP_Offload_Media\Aws3\Aws\S3\Exception\S3Exception' ) ) {
446
+ /* @var S3Exception $result */
447
+ \AS3CF_Error::log( __FUNCTION__ . ' - ' . $result->getAwsErrorMessage() . ' - Attachment ID: ' . $attachment_id );
448
+ } else {
449
+ \AS3CF_Error::log( __FUNCTION__ . ' - Unrecognised class returned from CommandPool::batch - Attachment ID: ' . $attachment_id );
450
  }
451
  }
452
 
531
  'Bucket' => $bucket,
532
  'Key' => $key,
533
  'Body' => $file_contents,
534
+ 'ACL' => self::DEFAULT_ACL,
535
  ) );
536
 
537
  // delete it straight away if created
543
  return true;
544
  } catch ( \Exception $e ) {
545
  // If we encounter an error that isn't access denied, throw that error.
546
+ if ( ! $e instanceof S3Exception || ! in_array( $e->getAwsErrorCode(), array( 'AccessDenied', 'NoSuchBucket' ) ) ) {
547
  return $e->getMessage();
548
  }
549
  }
606
 
607
  return $domain;
608
  }
609
+
610
+ /**
611
+ * Get the suffix param to append to the link to the bucket on the provider's console.
612
+ *
613
+ * @param string $bucket
614
+ * @param string $prefix
615
+ *
616
+ * @return string
617
+ */
618
+ protected function get_console_url_suffix_param( $bucket = '', $prefix = '' ) {
619
+ return '';
620
+ }
621
  }
classes/providers/digitalocean-provider.php CHANGED
@@ -104,7 +104,7 @@ class DigitalOcean_Provider extends AWS_Provider {
104
  /**
105
  * @var string
106
  */
107
- protected $console_url_param = '?path=';
108
 
109
  /**
110
  * @var array
104
  /**
105
  * @var string
106
  */
107
+ protected $console_url_prefix_param = '?path=';
108
 
109
  /**
110
  * @var array
classes/providers/gcp-provider.php ADDED
@@ -0,0 +1,671 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace DeliciousBrains\WP_Offload_Media\Providers;
4
+
5
+ use AS3CF_Utils;
6
+ use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\Exception\GoogleException;
7
+ use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Core\ServiceBuilder;
8
+ use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\Bucket;
9
+ use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\StorageClient;
10
+ use DeliciousBrains\WP_Offload_Media\Gcp\Google\Cloud\Storage\StorageObject;
11
+ use DeliciousBrains\WP_Offload_Media\Providers\Streams\GCP_GCS_Stream_Wrapper;
12
+
13
+ class GCP_Provider extends Provider {
14
+
15
+ /**
16
+ * @var ServiceBuilder
17
+ */
18
+ private $cloud;
19
+
20
+ /**
21
+ * @var StorageClient
22
+ */
23
+ private $storage;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ protected static $provider_name = 'Google Cloud Platform';
29
+
30
+ /**
31
+ * @var string
32
+ */
33
+ protected static $provider_short_name = 'GCP';
34
+
35
+ /**
36
+ * Used in filters and settings.
37
+ *
38
+ * @var string
39
+ */
40
+ protected static $provider_key_name = 'gcp';
41
+
42
+ /**
43
+ * @var string
44
+ */
45
+ protected static $service_name = 'Google Cloud Storage';
46
+
47
+ /**
48
+ * @var string
49
+ */
50
+ protected static $service_short_name = 'GCS';
51
+
52
+ /**
53
+ * Used in filters and settings.
54
+ *
55
+ * @var string
56
+ */
57
+ protected static $service_key_name = 'gcs';
58
+
59
+ /**
60
+ * Optional override of "Provider Name" + "Service Name" for friendly name for service.
61
+ *
62
+ * @var string
63
+ */
64
+ protected static $provider_service_name = 'Google Cloud Storage';
65
+
66
+ /**
67
+ * The slug for the service's quick start guide doc.
68
+ *
69
+ * @var string
70
+ */
71
+ protected static $provider_service_quick_start_slug = 'google-cloud-storage-quick-start-guide';
72
+
73
+ /**
74
+ * @var array
75
+ */
76
+ protected static $use_server_roles_constants = array(
77
+ 'AS3CF_GCP_USE_GCE_IAM_ROLE',
78
+ );
79
+
80
+ /**
81
+ * @var array
82
+ */
83
+ protected static $key_file_path_constants = array(
84
+ 'AS3CF_GCP_KEY_FILE_PATH',
85
+ );
86
+
87
+ /**
88
+ * @var array
89
+ */
90
+ protected $regions = array(
91
+ 'asia' => 'Asia (Multi-Regional)',
92
+ 'eu' => 'European Union (Multi-Regional)',
93
+ 'us' => 'United States (Multi-Regional)',
94
+ 'northamerica-northeast1' => 'Montréal',
95
+ 'us-central1' => 'Iowa',
96
+ 'us-east1' => 'South Carolina',
97
+ 'us-east4' => 'Northern Virginia',
98
+ 'us-west1' => 'Oregon',
99
+ 'us-west2' => 'Los Angeles',
100
+ 'southamerica-east1' => 'São Paulo',
101
+ 'europe-north1' => 'Finland',
102
+ 'europe-west1' => 'Belgium',
103
+ 'europe-west2' => 'London',
104
+ 'europe-west3' => 'Frankfurt',
105
+ 'europe-west4' => 'Netherlands',
106
+ 'asia-east1' => 'Taiwan',
107
+ 'asia-east2' => 'Hong Kong',
108
+ 'asia-northeast1' => 'Tokyo',
109
+ 'asia-south1' => 'Mumbai',
110
+ 'asia-southeast1' => 'Singapore',
111
+ 'australia-southeast1' => 'Sydney',
112
+ );
113
+
114
+ /**
115
+ * @var string
116
+ */
117
+ protected $default_region = 'us';
118
+
119
+ /**
120
+ * @var string
121
+ */
122
+ protected $default_domain = 'storage.googleapis.com';
123
+
124
+ /**
125
+ * @var string
126
+ */
127
+ protected $console_url = 'https://console.cloud.google.com/storage/browser/';
128
+
129
+ /**
130
+ * @var string
131
+ */
132
+ protected $console_url_prefix_param = '/';
133
+
134
+ const DEFAULT_ACL = 'publicRead';
135
+ const PRIVATE_ACL = 'projectPrivate';
136
+
137
+ /**
138
+ * GCP_Provider constructor.
139
+ *
140
+ * @param \AS3CF_Plugin_Base $as3cf
141
+ */
142
+ public function __construct( \AS3CF_Plugin_Base $as3cf ) {
143
+ parent::__construct( $as3cf );
144
+
145
+ // Autoloader.
146
+ require_once $as3cf->get_plugin_sdks_dir_path() . '/Gcp/autoload.php';
147
+ }
148
+
149
+ /**
150
+ * Returns default args array for the client.
151
+ *
152
+ * @return array
153
+ */
154
+ protected function default_client_args() {
155
+ return array();
156
+ }
157
+
158
+ /**
159
+ * Process the args before instantiating a new client for the provider's SDK.
160
+ *
161
+ * @param array $args
162
+ *
163
+ * @return array
164
+ */
165
+ protected function init_client_args( Array $args ) {
166
+ return $args;
167
+ }
168
+
169
+ /**
170
+ * Instantiate a new client for the provider's SDK.
171
+ *
172
+ * @param array $args
173
+ */
174
+ protected function init_client( Array $args ) {
175
+ $this->cloud = new ServiceBuilder( $args );
176
+ }
177
+
178
+ /**
179
+ * Process the args before instantiating a new service specific client.
180
+ *
181
+ * @param array $args
182
+ *
183
+ * @return array
184
+ */
185
+ protected function init_service_client_args( Array $args ) {
186
+ return $args;
187
+ }
188
+
189
+ /**
190
+ * Instantiate a new service specific client.
191
+ *
192
+ * @param array $args
193
+ *
194
+ * @return StorageClient
195
+ */
196
+ protected function init_service_client( Array $args ) {
197
+ $this->storage = $this->cloud->storage( $args );
198
+
199
+ return $this->storage;
200
+ }
201
+
202
+ /**
203
+ * Make sure region "slug" fits expected format.
204
+ *
205
+ * @param string $region
206
+ *
207
+ * @return string
208
+ */
209
+ public function sanitize_region( $region ) {
210