Version Description
- 2014-12-04 =
- New: Proper S3 region subdomain in URLs for buckets not in the US Standard region (e.g. https://s3-us-west-2.amazonaws.com/...)
- New: Update all existing attachment meta with bucket region (automatically runs in the background)
- New: Get secure URL for different image sizes (iamzozo)
- New: S3 bucket can be set with constant in wp-config.php (dberube)
- New: Filter for allowing/disallowing file types:
as3cf_allowed_mime_types
- New: Filter to cancel upload to S3 for any reason:
as3cf_pre_update_attachment_metadata
- New: Sidebar with email opt-in
- Improvement: Show warning when S3 policy is read-only
- Improvement: Tooltip added to clarify option
- Improvement: Move object versioning option to make it clear it does not require CloudFront
- Improvement: By default only allow file types in
get_allowed_mime_types()
to be uploaded to S3 - Improvement: Compatibility with WPML Media plugin
- Bug Fix: Edited images not removed on S3 when restoring image and IMAGE_EDIT_OVERWRITE true
- Bug Fix: File names with certain characters broken not working
- Bug Fix: Edited image uploaded to incorrect month folder
- Bug Fix: When creating a new bucket the bucket select box appears empty on success
- Bug Fix: SSL not working in regions other than US Standard
- Bug Fix: 'Error uploading' and 'Error removing local file' messages when editing an image
- Bug Fix: Upload and delete failing when bucket is non-US-region and bucket name contains dot
- Bug Fix: S3 file overwritten when file with same name uploaded and local file removed (dataferret)
- Bug Fix: Manually resized images not uploaded (gmauricio)
Download this release
Release Info
Developer | bradt |
Plugin | WP Offload S3 Lite |
Version | 0.7 |
Comparing to | |
See all releases |
Code changes from version 0.6.1 to 0.7
- assets/Gruntfile.js +36 -0
- assets/css/styles.css +1 -1
- assets/img/snail.jpg +0 -0
- assets/img/snail@2x.jpg +0 -0
- assets/js/script.js +1 -1
- assets/js/script.min.js +1 -1
- assets/package.json +10 -0
- assets/sass/styles.scss +253 -1
- classes/amazon-s3-and-cloudfront.php +637 -197
- classes/as3cf-compatibility-check.php +105 -0
- classes/as3cf-upgrade.php +354 -0
- composer.json +11 -0
- composer.lock +107 -0
- include/functions.php +9 -13
- languages/amazon-s3-and-cloudfront.pot +315 -0
- readme.txt +47 -10
- view/error-fatal.php +5 -0
- view/error.php +3 -7
- view/notice.php +3 -0
- view/settings.php +47 -5
- view/sidebar.php +55 -0
- wordpress-s3.php +24 -27
assets/Gruntfile.js
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module.exports = function(grunt) {
|
2 |
+
|
3 |
+
grunt.initConfig({
|
4 |
+
pkg: grunt.file.readJSON('package.json'),
|
5 |
+
uglify: {
|
6 |
+
build: {
|
7 |
+
files: {
|
8 |
+
'js/script.min.js': 'js/script.js'
|
9 |
+
}
|
10 |
+
}
|
11 |
+
},
|
12 |
+
compass: {
|
13 |
+
dist: {
|
14 |
+
options: {
|
15 |
+
}
|
16 |
+
}
|
17 |
+
},
|
18 |
+
watch: {
|
19 |
+
js: {
|
20 |
+
files: ['js/*'],
|
21 |
+
tasks: ['uglify']
|
22 |
+
},
|
23 |
+
sass: {
|
24 |
+
files: ['sass/*'],
|
25 |
+
tasks: ['compass']
|
26 |
+
}
|
27 |
+
}
|
28 |
+
});
|
29 |
+
|
30 |
+
grunt.loadNpmTasks('grunt-contrib-uglify');
|
31 |
+
grunt.loadNpmTasks('grunt-contrib-watch');
|
32 |
+
grunt.loadNpmTasks('grunt-contrib-compass');
|
33 |
+
|
34 |
+
grunt.registerTask('default', ['uglify','compass']);
|
35 |
+
|
36 |
+
};
|
assets/css/styles.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.as3cf-settings select.bucket{margin-bottom:5px;width:380px}
|
1 |
+
.aws-main .error{max-width:835px}.aws-main .error pre{background:#eaeaea;background:rgba(0,0,0,0.07);display:block;padding:10px 15px}.aws-main .error pre code{padding:0;background:none}.aws-main .as3cf-notice{max-width:835px}.as3cf-settings{position:relative;width:550px;min-height:800px}.as3cf-settings select.bucket{margin-bottom:5px;width:380px}.as3cf-settings .form-table td{padding-left:0;padding-right:0}.as3cf-settings .form-table tr:first-child h3{margin-top:0}.as3cf-settings .tooltip{position:relative;z-index:2;cursor:pointer}.as3cf-settings .tooltip:before,.as3cf-settings .tooltip:after{visibility:hidden;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);opacity:0;pointer-events:none}.as3cf-settings .tooltip:before{position:absolute;bottom:150%;left:50%;margin-bottom:5px;margin-left:-250px;padding:10px;width:500px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#000;background-color:rgba(51,51,51,0.9);color:#fff;content:attr(data-tooltip);text-align:center;font-size:14px;line-height:1.3}.as3cf-settings .tooltip:after{position:absolute;bottom:150%;left:50%;margin-left:-5px;width:0;border-top:5px solid #000;border-top:5px solid rgba(51,51,51,0.9);border-right:5px solid transparent;border-left:5px solid transparent;content:" ";font-size:0;line-height:0}.as3cf-settings .tooltip:hover:before,.as3cf-settings .tooltip:hover:after{visibility:visible;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}.as3cf-banner img{display:block}.as3cf-sidebar{position:absolute;top:17px;right:-312px;width:292px}.as3cf-sidebar .block{padding:20px;border:1px solid #ccc}.as3cf-sidebar .subscribe{border-top:none}.as3cf-sidebar .subscribe h2{padding:0;margin:0;margin-bottom:0.5em;color:#666;font-size:20px;line-height:1.2em;float:none}.as3cf-sidebar .subscribe h3{font-size:16px;margin:0}.as3cf-sidebar .subscribe p{margin:0}.as3cf-sidebar .subscribe .intro{margin-bottom:1em;line-height:1.4}.as3cf-sidebar .subscribe ul{margin-left:20px;list-style-type:disc}.as3cf-sidebar .subscribe li{line-height:1.4}.as3cf-sidebar .subscribe .links{margin-bottom:2em}.as3cf-sidebar .subscribe .links a{text-decoration:none}.as3cf-sidebar .subscribe .promise{color:#999;font-size:12px;line-height:1.4em}.as3cf-sidebar .subscribe .field{margin-bottom:0.5em}.as3cf-sidebar .subscribe .field p{margin-bottom:0.3em}.as3cf-sidebar .subscribe .field.submit-button{margin-bottom:1em}.as3cf-sidebar .credits{border-top:0}.as3cf-sidebar .credits h4{font-size:16px;margin-top:0;margin-bottom:10px}.as3cf-sidebar .credits ul{margin:0}.as3cf-sidebar .credits li{overflow:hidden}.as3cf-sidebar .credits li:last-child{margin-bottom:0}.as3cf-sidebar .credits img{float:left;margin-right:10px}.as3cf-sidebar .credits span{float:left;display:block;line-height:32px}.as3cf-sidebar .credits a{display:block;text-decoration:none;color:#444;font-size:16px;text-align:center}.as3cf-sidebar .credits a:hover{color:#888}@media (min--moz-device-pixel-ratio: 1.3), (-o-min-device-pixel-ratio: 2.6 / 2), (-webkit-min-device-pixel-ratio: 1.3), (min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){.as3cf-sidebar .as3cf-banner{background-image:url(../img/snail@2x.jpg);background-size:292px 165px;width:292px;height:165px;display:block}.as3cf-sidebar .as3cf-banner img{display:none}}@media screen and (max-width: 1052px){.as3cf-sidebar{position:relative;top:auto;right:auto;margin-top:50px}}
|
assets/img/snail.jpg
ADDED
Binary file
|
assets/img/snail@2x.jpg
ADDED
Binary file
|
assets/js/script.js
CHANGED
@@ -31,7 +31,7 @@
|
|
31 |
if ($(this).val() == bucket_name) {
|
32 |
return false;
|
33 |
}
|
34 |
-
if ($(this).val() > bucket_name) {
|
35 |
$(opt).insertBefore($(this));
|
36 |
return false;
|
37 |
}
|
31 |
if ($(this).val() == bucket_name) {
|
32 |
return false;
|
33 |
}
|
34 |
+
if ($(this).val() > bucket_name || 'new' == $(this).val() ) {
|
35 |
$(opt).insertBefore($(this));
|
36 |
return false;
|
37 |
}
|
assets/js/script.min.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
(function(e){e(document).ready(function(){e(".as3cf-settings").each(function(){var t=e(this);e("select.bucket",t).change(function(){var t=e(this);if(t.val()!=="new")return
|
1 |
+
(function(e){e(document).ready(function(){e(".as3cf-settings").each(function(){var t=e(this);e("select.bucket",t).change(function(){var t=e(this);if(t.val()!=="new"){return}var n=function(e,n,r){alert(as3cf_i18n.create_bucket_error+r);t[0].selectedIndex=0;console.log(e);console.log(n);console.log(r)};var r=function(n,r,s){if(typeof n["success"]!=="undefined"){var o=document.createElement("option");o.value=o.innerHTML=i;var u=0;e("option",t).each(function(){if(e(this).val()==i){return false}if(e(this).val()>i||"new"==e(this).val()){e(o).insertBefore(e(this));return false}u=u+1});t[0].selectedIndex=u;as3cf_i18n.create_bucket_nonce=n["_nonce"]}else{alert(as3cf_i18n.create_bucket_error+n["error"]);t[0].selectedIndex=0}};var i=window.prompt(as3cf_i18n.create_bucket_prompt);if(!i){t[0].selectedIndex=0;return}var s={action:"as3cf-create-bucket",bucket_name:i,_nonce:as3cf_i18n.create_bucket_nonce};e.ajax({url:ajaxurl,type:"POST",dataType:"JSON",success:r,error:n,data:s})})})})})(jQuery)
|
assets/package.json
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "amazon-s3-and-cloudfront",
|
3 |
+
"version": "0.1.0",
|
4 |
+
"devDependencies": {
|
5 |
+
"grunt": "^0.4.4",
|
6 |
+
"grunt-contrib-uglify": "^0.4.0",
|
7 |
+
"grunt-contrib-watch": "^0.6.0",
|
8 |
+
"grunt-contrib-compass": "^0.7.2"
|
9 |
+
}
|
10 |
+
}
|
assets/sass/styles.scss
CHANGED
@@ -1,6 +1,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
.as3cf-settings {
|
|
|
|
|
|
|
|
|
2 |
select.bucket {
|
3 |
margin-bottom: 5px;
|
4 |
width: 380px;
|
5 |
}
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.aws-main {
|
2 |
+
.error {
|
3 |
+
max-width: 835px;
|
4 |
+
pre {
|
5 |
+
background: #eaeaea;
|
6 |
+
background: rgba(0, 0, 0, 0.07);
|
7 |
+
display: block;
|
8 |
+
padding: 10px 15px;
|
9 |
+
|
10 |
+
code {
|
11 |
+
padding: 0;
|
12 |
+
background: none;
|
13 |
+
}
|
14 |
+
}
|
15 |
+
}
|
16 |
+
|
17 |
+
.as3cf-notice {
|
18 |
+
max-width: 835px;
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
.as3cf-settings {
|
23 |
+
position: relative;
|
24 |
+
width: 550px;
|
25 |
+
min-height: 800px;
|
26 |
+
|
27 |
select.bucket {
|
28 |
margin-bottom: 5px;
|
29 |
width: 380px;
|
30 |
}
|
31 |
+
|
32 |
+
.form-table {
|
33 |
+
td {
|
34 |
+
padding-left: 0;
|
35 |
+
padding-right: 0;
|
36 |
+
}
|
37 |
+
|
38 |
+
tr:first-child {
|
39 |
+
h3 {
|
40 |
+
margin-top: 0;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
.tooltip {
|
46 |
+
position: relative;
|
47 |
+
z-index: 2;
|
48 |
+
cursor: pointer;
|
49 |
+
}
|
50 |
+
|
51 |
+
/* Hide the tooltip content by default */
|
52 |
+
.tooltip:before,
|
53 |
+
.tooltip:after {
|
54 |
+
visibility: hidden;
|
55 |
+
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
56 |
+
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
|
57 |
+
opacity: 0;
|
58 |
+
pointer-events: none;
|
59 |
+
}
|
60 |
+
|
61 |
+
/* Position tooltip above the element */
|
62 |
+
.tooltip:before {
|
63 |
+
position: absolute;
|
64 |
+
bottom: 150%;
|
65 |
+
left: 50%;
|
66 |
+
margin-bottom: 5px;
|
67 |
+
margin-left: -250px;
|
68 |
+
padding: 10px;
|
69 |
+
width: 500px;
|
70 |
+
-webkit-border-radius: 3px;
|
71 |
+
-moz-border-radius: 3px;
|
72 |
+
border-radius: 3px;
|
73 |
+
background-color: #000;
|
74 |
+
background-color: hsla(0, 0%, 20%, 0.9);
|
75 |
+
color: #fff;
|
76 |
+
content: attr(data-tooltip);
|
77 |
+
text-align: center;
|
78 |
+
font-size: 14px;
|
79 |
+
line-height: 1.3;
|
80 |
+
}
|
81 |
+
|
82 |
+
/* Triangle hack to make tooltip look like a speech bubble */
|
83 |
+
.tooltip:after {
|
84 |
+
position: absolute;
|
85 |
+
bottom: 150%;
|
86 |
+
left: 50%;
|
87 |
+
margin-left: -5px;
|
88 |
+
width: 0;
|
89 |
+
border-top: 5px solid #000;
|
90 |
+
border-top: 5px solid hsla(0, 0%, 20%, 0.9);
|
91 |
+
border-right: 5px solid transparent;
|
92 |
+
border-left: 5px solid transparent;
|
93 |
+
content: " ";
|
94 |
+
font-size: 0;
|
95 |
+
line-height: 0;
|
96 |
+
}
|
97 |
+
|
98 |
+
/* Show tooltip content on hover */
|
99 |
+
.tooltip:hover:before,
|
100 |
+
.tooltip:hover:after {
|
101 |
+
visibility: visible;
|
102 |
+
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
|
103 |
+
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
|
104 |
+
opacity: 1;
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
.as3cf-banner {
|
109 |
+
img {
|
110 |
+
display: block;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
.as3cf-sidebar {
|
115 |
+
position: absolute;
|
116 |
+
top: 17px;
|
117 |
+
right: -312px;
|
118 |
+
width: 292px;
|
119 |
+
|
120 |
+
.block {
|
121 |
+
padding: 20px;
|
122 |
+
border: 1px solid #ccc;
|
123 |
+
}
|
124 |
+
|
125 |
+
.subscribe {
|
126 |
+
border-top: none;
|
127 |
+
|
128 |
+
h2 {
|
129 |
+
padding: 0;
|
130 |
+
margin: 0;
|
131 |
+
margin-bottom: 0.5em;
|
132 |
+
color: #666;
|
133 |
+
font-size: 20px;
|
134 |
+
line-height: 1.2em;
|
135 |
+
float: none;
|
136 |
+
}
|
137 |
+
|
138 |
+
h3 {
|
139 |
+
font-size: 16px;
|
140 |
+
margin: 0;
|
141 |
+
}
|
142 |
+
|
143 |
+
p {
|
144 |
+
margin: 0;
|
145 |
+
}
|
146 |
+
|
147 |
+
.intro {
|
148 |
+
margin-bottom: 1em;
|
149 |
+
line-height: 1.4;
|
150 |
+
}
|
151 |
+
|
152 |
+
ul {
|
153 |
+
margin-left: 20px;
|
154 |
+
list-style-type: disc;
|
155 |
+
}
|
156 |
+
|
157 |
+
li {
|
158 |
+
line-height: 1.4;
|
159 |
+
}
|
160 |
+
|
161 |
+
.links {
|
162 |
+
margin-bottom: 2em;
|
163 |
+
|
164 |
+
a {
|
165 |
+
text-decoration: none;
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
.promise {
|
170 |
+
color: #999;
|
171 |
+
font-size: 12px;
|
172 |
+
line-height: 1.4em;
|
173 |
+
}
|
174 |
+
|
175 |
+
.field {
|
176 |
+
margin-bottom: 0.5em;
|
177 |
+
|
178 |
+
p {
|
179 |
+
margin-bottom: 0.3em;
|
180 |
+
}
|
181 |
+
|
182 |
+
&.submit-button {
|
183 |
+
margin-bottom: 1em;
|
184 |
+
}
|
185 |
+
}
|
186 |
+
}
|
187 |
+
|
188 |
+
.credits {
|
189 |
+
border-top: 0;
|
190 |
+
|
191 |
+
h4 {
|
192 |
+
font-size: 16px;
|
193 |
+
margin-top: 0;
|
194 |
+
margin-bottom: 10px;
|
195 |
+
}
|
196 |
+
|
197 |
+
ul {
|
198 |
+
margin: 0;
|
199 |
+
}
|
200 |
+
|
201 |
+
li {
|
202 |
+
overflow: hidden;
|
203 |
+
}
|
204 |
+
|
205 |
+
li:last-child {
|
206 |
+
margin-bottom: 0;
|
207 |
+
}
|
208 |
+
|
209 |
+
img {
|
210 |
+
float: left;
|
211 |
+
margin-right: 10px;
|
212 |
+
}
|
213 |
+
|
214 |
+
span {
|
215 |
+
float: left;
|
216 |
+
display: block;
|
217 |
+
line-height: 32px;
|
218 |
+
}
|
219 |
+
|
220 |
+
a {
|
221 |
+
display: block;
|
222 |
+
text-decoration: none;
|
223 |
+
color: #444;
|
224 |
+
font-size: 16px;
|
225 |
+
text-align: center;
|
226 |
+
|
227 |
+
&:hover {
|
228 |
+
color: #888;
|
229 |
+
}
|
230 |
+
}
|
231 |
+
}
|
232 |
+
|
233 |
+
@media (min--moz-device-pixel-ratio: 1.3),
|
234 |
+
(-o-min-device-pixel-ratio: 2.6/2),
|
235 |
+
(-webkit-min-device-pixel-ratio: 1.3),
|
236 |
+
(min-device-pixel-ratio: 1.3),
|
237 |
+
(min-resolution: 1.3dppx) {
|
238 |
+
|
239 |
+
.as3cf-banner {
|
240 |
+
background-image: url(../img/snail@2x.jpg);
|
241 |
+
background-size: 292px 165px;
|
242 |
+
width: 292px;
|
243 |
+
height: 165px;
|
244 |
+
display: block;
|
245 |
+
|
246 |
+
img {
|
247 |
+
display: none;
|
248 |
+
}
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
@media screen and (max-width: 1052px) {
|
253 |
+
position: relative;
|
254 |
+
top: auto;
|
255 |
+
right: auto;
|
256 |
+
margin-top: 50px;
|
257 |
+
}
|
258 |
+
}
|
classes/amazon-s3-and-cloudfront.php
CHANGED
@@ -4,13 +4,22 @@ use Aws\S3\S3Client;
|
|
4 |
class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
5 |
private $aws, $s3client;
|
6 |
|
|
|
|
|
|
|
|
|
7 |
const SETTINGS_KEY = 'tantan_wordpress_s3';
|
8 |
|
9 |
function __construct( $plugin_file_path, $aws ) {
|
|
|
|
|
10 |
parent::__construct( $plugin_file_path );
|
11 |
|
12 |
$this->aws = $aws;
|
13 |
|
|
|
|
|
|
|
14 |
add_action( 'aws_admin_menu', array( $this, 'admin_menu' ) );
|
15 |
|
16 |
$this->plugin_title = __( 'Amazon S3 and CloudFront', 'as3cf' );
|
@@ -18,12 +27,16 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
18 |
|
19 |
add_action( 'wp_ajax_as3cf-create-bucket', array( $this, 'ajax_create_bucket' ) );
|
20 |
|
21 |
-
add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ),
|
22 |
-
add_filter( '
|
|
|
|
|
23 |
add_filter( 'delete_attachment', array( $this, 'delete_attachment' ), 20 );
|
|
|
|
|
24 |
}
|
25 |
|
26 |
-
function get_setting( $key ) {
|
27 |
$settings = $this->get_settings();
|
28 |
|
29 |
// If legacy setting set, migrate settings
|
@@ -33,217 +46,334 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
33 |
|
34 |
// Default object prefix
|
35 |
if ( 'object-prefix' == $key && !isset( $settings['object-prefix'] ) ) {
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
}
|
40 |
-
|
41 |
-
return parent::get_setting( $key );
|
42 |
-
}
|
43 |
-
|
44 |
-
function delete_attachment( $post_id ) {
|
45 |
-
if ( !$this->is_plugin_setup() ) {
|
46 |
-
return;
|
47 |
-
}
|
48 |
-
|
49 |
-
$backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
|
50 |
-
|
51 |
-
$intermediate_sizes = array();
|
52 |
-
foreach ( get_intermediate_image_sizes() as $size ) {
|
53 |
-
if ( $intermediate = image_get_intermediate_size( $post_id, $size ) )
|
54 |
-
$intermediate_sizes[] = $intermediate;
|
55 |
-
}
|
56 |
-
|
57 |
-
if ( !( $s3object = $this->get_attachment_s3_info( $post_id ) ) ) {
|
58 |
-
return;
|
59 |
-
}
|
60 |
-
|
61 |
-
$amazon_path = dirname( $s3object['key'] );
|
62 |
-
$objects = array();
|
63 |
-
|
64 |
-
// remove intermediate and backup images if there are any
|
65 |
-
foreach ( $intermediate_sizes as $intermediate ) {
|
66 |
-
$objects[] = array(
|
67 |
-
'Key' => path_join( $amazon_path, $intermediate['file'] )
|
68 |
-
);
|
69 |
-
}
|
70 |
-
|
71 |
-
if ( is_array( $backup_sizes ) ) {
|
72 |
-
foreach ( $backup_sizes as $size ) {
|
73 |
-
$objects[] = array(
|
74 |
-
'Key' => path_join( $amazon_path, $del_file )
|
75 |
-
);
|
76 |
-
}
|
77 |
-
}
|
78 |
-
|
79 |
-
// Try removing any @2x images but ignore any errors
|
80 |
-
if ( $objects ) {
|
81 |
-
$hidpi_images = array();
|
82 |
-
foreach ( $objects as $object ) {
|
83 |
-
$hidpi_images[] = array(
|
84 |
-
'Key' => $this->get_hidpi_file_path( $object['Key'] )
|
85 |
-
);
|
86 |
-
}
|
87 |
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
}
|
94 |
-
|
95 |
-
|
96 |
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
try {
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
}
|
107 |
-
|
108 |
-
|
|
|
|
|
109 |
return;
|
110 |
}
|
111 |
|
112 |
-
|
113 |
-
|
|
|
114 |
|
115 |
-
|
116 |
-
if ( !$this->get_setting( 'copy-to-s3' ) || !$this->is_plugin_setup() ) {
|
117 |
-
return $data;
|
118 |
-
}
|
119 |
|
120 |
-
|
121 |
-
$time = date( 'Y/m', $time );
|
122 |
|
123 |
-
$
|
124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
|
126 |
-
|
127 |
-
|
128 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
|
130 |
-
|
|
|
|
|
|
|
|
|
|
|
131 |
|
132 |
-
|
|
|
133 |
|
134 |
-
|
135 |
-
|
136 |
|
137 |
-
|
138 |
-
return $data;
|
139 |
-
}
|
140 |
|
141 |
-
|
142 |
-
|
|
|
|
|
143 |
|
144 |
-
|
|
|
|
|
|
|
145 |
|
146 |
-
|
|
|
|
|
|
|
147 |
|
148 |
-
|
|
|
|
|
|
|
149 |
'Bucket' => $bucket,
|
150 |
'Key' => $prefix . $file_name,
|
151 |
'SourceFile' => $file_path,
|
152 |
'ACL' => $acl
|
153 |
-
|
154 |
|
155 |
-
|
156 |
if ( $this->get_setting( 'expires' ) ) {
|
157 |
$args['Expires'] = date( 'D, d M Y H:i:s O', time()+315360000 );
|
158 |
}
|
159 |
|
160 |
-
|
161 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
}
|
163 |
-
|
164 |
-
|
165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
}
|
167 |
|
168 |
-
|
169 |
|
170 |
-
|
171 |
-
'bucket' => $bucket,
|
172 |
-
'key' => $prefix . $file_name
|
173 |
-
) );
|
174 |
|
175 |
$additional_images = array();
|
176 |
|
177 |
-
|
178 |
$path = str_replace( $file_name, $data['thumb'], $file_path );
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
);
|
183 |
-
$files_to_remove[] = $path;
|
184 |
-
}
|
185 |
-
elseif ( !empty( $data['sizes'] ) ) {
|
186 |
-
foreach ( $data['sizes'] as $size ) {
|
187 |
-
$path = str_replace( $file_name, $size['file'], $file_path );
|
188 |
-
$additional_images[] = array(
|
189 |
-
'Key' => $prefix . $size['file'],
|
190 |
'SourceFile' => $path
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
'Key' => $this->get_hidpi_file_path( $image['Key'] ),
|
206 |
'SourceFile' => $hidpi_path
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
|
212 |
$additional_images = array_merge( $additional_images, $hidpi_images );
|
213 |
}
|
214 |
|
215 |
-
|
216 |
try {
|
217 |
$args = array_merge( $args, $image );
|
|
|
218 |
$s3client->putObject( $args );
|
219 |
}
|
220 |
catch ( Exception $e ) {
|
221 |
error_log( 'Error uploading ' . $args['SourceFile'] . ' to S3: ' . $e->getMessage() );
|
222 |
}
|
223 |
-
|
224 |
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
|
229 |
-
|
230 |
-
|
231 |
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
|
240 |
-
|
241 |
$hidpi_suffix = apply_filters( 'as3cf_hidpi_suffix', '@2x' );
|
242 |
$pathinfo = pathinfo( $orig_path );
|
243 |
return $pathinfo['dirname'] . '/' . $pathinfo['filename'] . $hidpi_suffix . '.' . $pathinfo['extension'];
|
244 |
-
|
245 |
|
246 |
-
|
247 |
if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
|
248 |
$date_format = 'dHis';
|
249 |
}
|
@@ -255,22 +385,22 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
255 |
|
256 |
$object_version = date( $date_format, $time ) . '/';
|
257 |
$object_version = apply_filters( 'as3cf_get_object_version_string', $object_version );
|
258 |
-
|
259 |
return $object_version;
|
260 |
-
|
261 |
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
$time = current_time( 'timestamp' );
|
266 |
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
|
275 |
if ( !( $post = get_post( $attach->post_parent ) ) ) {
|
276 |
return $time;
|
@@ -280,15 +410,77 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
280 |
return strtotime( $post->post_date_gmt . ' +0000' );
|
281 |
}
|
282 |
|
283 |
-
|
284 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
285 |
|
286 |
function wp_get_attachment_url( $url, $post_id ) {
|
287 |
$new_url = $this->get_attachment_url( $post_id );
|
288 |
if ( false === $new_url ) {
|
289 |
return $url;
|
290 |
}
|
291 |
-
|
292 |
$new_url = apply_filters( 'wps3_get_attachment_url', $new_url, $post_id, $this ); // Old naming convention, will be deprecated soon
|
293 |
$new_url = apply_filters( 'as3cf_wp_get_attachment_url', $new_url, $post_id );
|
294 |
|
@@ -307,15 +499,36 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
307 |
* Generate a link to download a file from Amazon S3 using query string
|
308 |
* authentication. This link is only valid for a limited amount of time.
|
309 |
*
|
310 |
-
* @param
|
311 |
-
* @param int
|
|
|
|
|
|
|
312 |
*/
|
313 |
-
function get_secure_attachment_url( $post_id, $expires =
|
314 |
-
|
|
|
|
|
|
|
315 |
}
|
316 |
|
317 |
-
|
318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
return false;
|
320 |
}
|
321 |
|
@@ -326,6 +539,22 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
326 |
$scheme = 'http';
|
327 |
}
|
328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
if ( is_null( $expires ) && $this->get_setting( 'cloudfront' ) ) {
|
330 |
$domain_bucket = $this->get_setting( 'cloudfront' );
|
331 |
}
|
@@ -333,26 +562,103 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
333 |
$domain_bucket = $s3object['bucket'];
|
334 |
}
|
335 |
elseif ( is_ssl() || $this->get_setting( 'force-ssl' ) ) {
|
336 |
-
$domain_bucket = '
|
337 |
}
|
338 |
else {
|
339 |
-
$domain_bucket = $s3object['bucket'] . '.
|
340 |
}
|
341 |
|
342 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
343 |
|
344 |
if ( !is_null( $expires ) ) {
|
345 |
try {
|
346 |
$expires = time() + $expires;
|
347 |
-
|
348 |
-
$url .= substr( $secure_url, strpos( $secure_url, '?' ) );
|
349 |
}
|
350 |
catch ( Exception $e ) {
|
351 |
return new WP_Error( 'exception', $e->getMessage() );
|
352 |
}
|
353 |
}
|
354 |
|
355 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
356 |
}
|
357 |
|
358 |
function verify_ajax_request() {
|
@@ -381,12 +687,12 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
381 |
}
|
382 |
|
383 |
echo json_encode( $out );
|
384 |
-
exit;
|
385 |
}
|
386 |
|
387 |
function create_bucket( $bucket_name ) {
|
388 |
try {
|
389 |
-
|
390 |
}
|
391 |
catch ( Exception $e ) {
|
392 |
return new WP_Error( 'exception', $e->getMessage() );
|
@@ -408,6 +714,59 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
408 |
return $this->s3client;
|
409 |
}
|
410 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
function get_buckets() {
|
412 |
try {
|
413 |
$result = $this->get_s3client()->listBuckets();
|
@@ -419,20 +778,74 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
419 |
return $result['Buckets'];
|
420 |
}
|
421 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
422 |
function plugin_load() {
|
|
|
|
|
423 |
$src = plugins_url( 'assets/css/styles.css', $this->plugin_file_path );
|
424 |
-
wp_enqueue_style( 'as3cf-styles', $src, array(), $
|
425 |
|
426 |
$suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
|
427 |
|
428 |
$src = plugins_url( 'assets/js/script' . $suffix . '.js', $this->plugin_file_path );
|
429 |
-
wp_enqueue_script( 'as3cf-script', $src, array( 'jquery' ), $
|
430 |
-
|
431 |
wp_localize_script( 'as3cf-script', 'as3cf_i18n', array(
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
|
437 |
$this->handle_post_request();
|
438 |
}
|
@@ -446,10 +859,11 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
446 |
die( __( "Cheatin' eh?", 'amazon-web-services' ) );
|
447 |
}
|
448 |
|
449 |
-
$this->set_settings( array() );
|
450 |
-
|
451 |
$post_vars = array( 'bucket', 'virtual-host', 'expires', 'permissions', 'cloudfront', 'object-prefix', 'copy-to-s3', 'serve-from-s3', 'remove-local-file', 'force-ssl', 'hidpi-images', 'object-versioning' );
|
|
|
452 |
foreach ( $post_vars as $var ) {
|
|
|
|
|
453 |
if ( !isset( $_POST[$var] ) ) {
|
454 |
continue;
|
455 |
}
|
@@ -465,26 +879,27 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
465 |
|
466 |
function render_page() {
|
467 |
$this->aws->render_view( 'header', array( 'page_title' => $this->plugin_title ) );
|
468 |
-
|
469 |
$aws_client = $this->aws->get_client();
|
470 |
|
471 |
if ( is_wp_error( $aws_client ) ) {
|
472 |
-
$this->render_view( 'error', array( '
|
473 |
}
|
474 |
else {
|
|
|
475 |
$this->render_view( 'settings' );
|
476 |
}
|
477 |
-
|
478 |
$this->aws->render_view( 'footer' );
|
479 |
}
|
480 |
|
481 |
function get_dynamic_prefix( $time = null ) {
|
482 |
-
|
483 |
-
|
484 |
}
|
485 |
|
486 |
// Without the multisite subdirectory
|
487 |
-
function get_base_upload_path() {
|
488 |
if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
|
489 |
return ABSPATH . UPLOADS;
|
490 |
}
|
@@ -501,4 +916,29 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
|
501 |
}
|
502 |
}
|
503 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
504 |
}
|
4 |
class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
|
5 |
private $aws, $s3client;
|
6 |
|
7 |
+
const DEFAULT_ACL = 'public-read';
|
8 |
+
const PRIVATE_ACL = 'private';
|
9 |
+
const DEFAULT_EXPIRES = 900;
|
10 |
+
|
11 |
const SETTINGS_KEY = 'tantan_wordpress_s3';
|
12 |
|
13 |
function __construct( $plugin_file_path, $aws ) {
|
14 |
+
$this->plugin_slug = 'amazon-s3-and-cloudfront';
|
15 |
+
|
16 |
parent::__construct( $plugin_file_path );
|
17 |
|
18 |
$this->aws = $aws;
|
19 |
|
20 |
+
// fire up the plugin upgrade checker
|
21 |
+
new AS3CF_Upgrade( $this );
|
22 |
+
|
23 |
add_action( 'aws_admin_menu', array( $this, 'admin_menu' ) );
|
24 |
|
25 |
$this->plugin_title = __( 'Amazon S3 and CloudFront', 'as3cf' );
|
27 |
|
28 |
add_action( 'wp_ajax_as3cf-create-bucket', array( $this, 'ajax_create_bucket' ) );
|
29 |
|
30 |
+
add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 99, 2 );
|
31 |
+
add_filter( 'wp_handle_upload_prefilter', array( $this, 'wp_handle_upload_prefilter' ), 1 );
|
32 |
+
add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 100, 2 );
|
33 |
+
add_filter( 'wp_get_attachment_metadata', array( $this, 'wp_get_attachment_metadata' ), 10, 2 );
|
34 |
add_filter( 'delete_attachment', array( $this, 'delete_attachment' ), 20 );
|
35 |
+
|
36 |
+
load_plugin_textdomain( 'as3cf', false, dirname( plugin_basename( $plugin_file_path ) ) . '/languages/' );
|
37 |
}
|
38 |
|
39 |
+
function get_setting( $key, $default = '' ) {
|
40 |
$settings = $this->get_settings();
|
41 |
|
42 |
// If legacy setting set, migrate settings
|
46 |
|
47 |
// Default object prefix
|
48 |
if ( 'object-prefix' == $key && !isset( $settings['object-prefix'] ) ) {
|
49 |
+
$uploads = wp_upload_dir();
|
50 |
+
$parts = parse_url( $uploads['baseurl'] );
|
51 |
+
return substr( $parts['path'], 1 ) . '/';
|
52 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
+
if ( 'bucket' == $key && defined( 'AS3CF_BUCKET' ) ) {
|
55 |
+
$value = AS3CF_BUCKET;
|
56 |
+
}
|
57 |
+
else {
|
58 |
+
$value = parent::get_setting( $key, $default );
|
59 |
+
}
|
60 |
+
|
61 |
+
return apply_filters( 'as3cf_setting_' . $key, $value );
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Allowed mime types array that can be edited for specific S3 uploading
|
66 |
+
*
|
67 |
+
* @return array
|
68 |
+
*/
|
69 |
+
function get_allowed_mime_types() {
|
70 |
+
return apply_filters( 'as3cf_allowed_mime_types', get_allowed_mime_types() );
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Find backup images and add to array for removal
|
75 |
+
*
|
76 |
+
* @param unknown $post_id
|
77 |
+
* @param unknown $objects
|
78 |
+
* @param unknown $path
|
79 |
+
*/
|
80 |
+
function prepare_backup_size_images_to_remove( $post_id, &$objects, $path ) {
|
81 |
+
$backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
|
82 |
+
|
83 |
+
if ( is_array( $backup_sizes ) ) {
|
84 |
+
foreach ( $backup_sizes as $size ) {
|
85 |
+
$objects[] = array(
|
86 |
+
'Key' => path_join( $path, $size['file'] )
|
87 |
+
);
|
88 |
}
|
89 |
+
}
|
90 |
+
}
|
91 |
|
92 |
+
/**
|
93 |
+
* Find intermediate size images and add to array for removal
|
94 |
+
*
|
95 |
+
* @param unknown $post_id
|
96 |
+
* @param unknown $objects
|
97 |
+
* @param unknown $path
|
98 |
+
*/
|
99 |
+
function prepare_intermediate_images_to_remove( $post_id, &$objects, $path ) {
|
100 |
+
$intermediate_images = get_intermediate_image_sizes();
|
101 |
+
|
102 |
+
foreach ( $intermediate_images as $size ) {
|
103 |
+
if ( $intermediate = image_get_intermediate_size( $post_id, $size ) ) {
|
104 |
+
$objects[] = array(
|
105 |
+
'Key' => path_join( $path, $intermediate['file'] )
|
106 |
+
);
|
107 |
+
}
|
108 |
+
}
|
109 |
+
}
|
110 |
|
111 |
+
/**
|
112 |
+
* Delete bulk objects from an S3 bucket
|
113 |
+
*
|
114 |
+
* @param unknown $bucket
|
115 |
+
* @param unknown $objects
|
116 |
+
* @param bool $log_error
|
117 |
+
* @param bool $return_on_error
|
118 |
+
*/
|
119 |
+
function delete_s3_objects( $bucket, $objects, $log_error = false, $return_on_error = false ) {
|
120 |
try {
|
121 |
+
$this->get_s3client()->deleteObjects( array(
|
122 |
+
'Bucket' => $bucket,
|
123 |
+
'Objects' => $objects
|
124 |
+
) );
|
125 |
+
} catch ( Exception $e ) {
|
126 |
+
if ( $log_error ) {
|
127 |
+
error_log( 'Error removing files from S3: ' . $e->getMessage() );
|
128 |
+
}
|
129 |
+
if ( $return_on_error ) {
|
130 |
+
return;
|
131 |
+
}
|
132 |
}
|
133 |
+
}
|
134 |
+
|
135 |
+
function delete_attachment( $post_id ) {
|
136 |
+
if ( !$this->is_plugin_setup() ) {
|
137 |
return;
|
138 |
}
|
139 |
|
140 |
+
if ( !( $s3object = $this->get_attachment_s3_info( $post_id ) ) ) {
|
141 |
+
return;
|
142 |
+
}
|
143 |
|
144 |
+
$bucket = $s3object['bucket'];
|
|
|
|
|
|
|
145 |
|
146 |
+
$this->set_s3client_region( $s3object );
|
|
|
147 |
|
148 |
+
$amazon_path = dirname( $s3object['key'] );
|
149 |
+
$objects = array();
|
150 |
+
|
151 |
+
// remove intermediate images
|
152 |
+
$this->prepare_intermediate_images_to_remove( $post_id, $objects, $amazon_path );
|
153 |
+
// remove backup images
|
154 |
+
$this->prepare_backup_size_images_to_remove( $post_id, $objects, $amazon_path );
|
155 |
+
|
156 |
+
// Try removing any @2x images but ignore any errors
|
157 |
+
if ( $objects ) {
|
158 |
+
$hidpi_images = array();
|
159 |
+
foreach ( $objects as $object ) {
|
160 |
+
$hidpi_images[] = array(
|
161 |
+
'Key' => $this->get_hidpi_file_path( $object['Key'] )
|
162 |
+
);
|
163 |
+
}
|
164 |
+
|
165 |
+
$this->delete_s3_objects( $bucket, $hidpi_images );
|
166 |
+
}
|
167 |
+
|
168 |
+
// add main file to be deleted
|
169 |
+
$objects[] = array(
|
170 |
+
'Key' => $s3object['key']
|
171 |
+
);
|
172 |
+
|
173 |
+
$this->delete_s3_objects( $bucket, $objects, true, true );
|
174 |
+
|
175 |
+
delete_post_meta( $post_id, 'amazonS3_info' );
|
176 |
+
}
|
177 |
+
|
178 |
+
function wp_update_attachment_metadata( $data, $post_id ) {
|
179 |
+
if ( !$this->get_setting( 'copy-to-s3' ) || !$this->is_plugin_setup() ) {
|
180 |
+
return $data;
|
181 |
+
}
|
182 |
+
|
183 |
+
// allow S3 upload to be cancelled for any reason
|
184 |
+
$pre = apply_filters( 'as3cf_pre_update_attachment_metadata', false, $data, $post_id );
|
185 |
+
if ( false !== $pre ) {
|
186 |
+
return $data;
|
187 |
+
}
|
188 |
+
|
189 |
+
$type = get_post_mime_type( $post_id );
|
190 |
+
$allowed_types = $this->get_allowed_mime_types();
|
191 |
+
|
192 |
+
// check mime type of file is in allowed S3 mime types
|
193 |
+
if ( ! in_array( $type, $allowed_types ) ) {
|
194 |
+
return $data;
|
195 |
+
}
|
196 |
+
|
197 |
+
$acl = self::DEFAULT_ACL;
|
198 |
|
199 |
+
// check the attachment already exists in S3, eg. edit or restore image
|
200 |
+
if ( ( $old_s3object = $this->get_attachment_s3_info( $post_id ) ) ) {
|
201 |
+
// use existing non default ACL if attachment already exists
|
202 |
+
if ( isset( $old_s3object['acl'] ) ) {
|
203 |
+
$acl = $old_s3object['acl'];
|
204 |
+
}
|
205 |
+
// use existing prefix
|
206 |
+
$prefix = trailingslashit( dirname( $old_s3object['key'] ) );
|
207 |
+
// use existing bucket
|
208 |
+
$bucket = $old_s3object['bucket'];
|
209 |
+
// get existing region
|
210 |
+
if ( isset( $old_s3object['region'] ) ) {
|
211 |
+
$region = $old_s3object['region'];
|
212 |
+
};
|
213 |
+
} else {
|
214 |
+
// derive prefix from various settings
|
215 |
+
if ( isset( $data['file'] ) ) {
|
216 |
+
$time = untrailingslashit( dirname( $data['file'] ) );
|
217 |
+
} else {
|
218 |
+
$time = $this->get_attachment_folder_time( $post_id );
|
219 |
+
$time = date( 'Y/m', $time );
|
220 |
+
}
|
221 |
+
|
222 |
+
$prefix = ltrim( trailingslashit( $this->get_setting( 'object-prefix' ) ), '/' );
|
223 |
+
$prefix .= ltrim( trailingslashit( $this->get_dynamic_prefix( $time ) ), '/' );
|
224 |
|
225 |
+
if ( $this->get_setting( 'object-versioning' ) ) {
|
226 |
+
$prefix .= $this->get_object_version_string( $post_id );
|
227 |
+
}
|
228 |
+
// use bucket from settings
|
229 |
+
$bucket = $this->get_setting( 'bucket' );
|
230 |
+
}
|
231 |
|
232 |
+
$file_path = get_attached_file( $post_id, true );
|
233 |
+
$file_name = basename( $file_path );
|
234 |
|
235 |
+
$acl = apply_filters( 'wps3_upload_acl', $acl, $type, $data, $post_id, $this ); // Old naming convention, will be deprecated soon
|
236 |
+
$acl = apply_filters( 'as3cf_upload_acl', $acl, $data, $post_id );
|
237 |
|
238 |
+
$s3client = $this->get_s3client();
|
|
|
|
|
239 |
|
240 |
+
$s3object = array(
|
241 |
+
'bucket' => $bucket,
|
242 |
+
'key' => $prefix . $file_name
|
243 |
+
);
|
244 |
|
245 |
+
// store acl if not default
|
246 |
+
if ( $acl != self::DEFAULT_ACL ) {
|
247 |
+
$s3object['acl'] = $acl;
|
248 |
+
}
|
249 |
|
250 |
+
// use existing region
|
251 |
+
if ( isset( $region ) ) {
|
252 |
+
$s3object['region'] = $region;
|
253 |
+
}
|
254 |
|
255 |
+
// retrieve region when necessary and set the region of the s3client
|
256 |
+
$s3object['region'] = $this->set_s3client_region( $s3object );
|
257 |
+
|
258 |
+
$args = array(
|
259 |
'Bucket' => $bucket,
|
260 |
'Key' => $prefix . $file_name,
|
261 |
'SourceFile' => $file_path,
|
262 |
'ACL' => $acl
|
263 |
+
);
|
264 |
|
265 |
+
// If far future expiration checked (10 years)
|
266 |
if ( $this->get_setting( 'expires' ) ) {
|
267 |
$args['Expires'] = date( 'D, d M Y H:i:s O', time()+315360000 );
|
268 |
}
|
269 |
|
270 |
+
// if the original image is being restored and 'IMAGE_EDIT_OVERWRITE' is set
|
271 |
+
// then we need to remove the edited image versions
|
272 |
+
if ( isset( $_POST['do'] ) && 'restore' == $_POST['do'] && defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE ) {
|
273 |
+
$objects_to_remove = array();
|
274 |
+
// edited main file
|
275 |
+
$meta = get_post_meta( $post_id, '_wp_attachment_metadata', true );
|
276 |
+
$objects_to_remove[] = array(
|
277 |
+
'Key' => path_join( $prefix, basename( $meta['file'] ) )
|
278 |
+
);
|
279 |
+
// edited resized image files
|
280 |
+
$this->prepare_intermediate_images_to_remove( $post_id, $objects_to_remove, $prefix );
|
281 |
+
$this->delete_s3_objects( $bucket, $objects_to_remove, true );
|
282 |
}
|
283 |
+
|
284 |
+
$files_to_remove = array();
|
285 |
+
if ( file_exists( $file_path ) ) {
|
286 |
+
$files_to_remove[] = $file_path;
|
287 |
+
try {
|
288 |
+
$s3client->putObject( $args );
|
289 |
+
}
|
290 |
+
catch ( Exception $e ) {
|
291 |
+
error_log( 'Error uploading ' . $file_path . ' to S3: ' . $e->getMessage() );
|
292 |
+
return $data;
|
293 |
+
}
|
294 |
}
|
295 |
|
296 |
+
delete_post_meta( $post_id, 'amazonS3_info' );
|
297 |
|
298 |
+
add_post_meta( $post_id, 'amazonS3_info', $s3object );
|
|
|
|
|
|
|
299 |
|
300 |
$additional_images = array();
|
301 |
|
302 |
+
if ( isset( $data['thumb'] ) && $data['thumb'] ) {
|
303 |
$path = str_replace( $file_name, $data['thumb'], $file_path );
|
304 |
+
if ( file_exists( $path ) ) {
|
305 |
+
$additional_images[] = array(
|
306 |
+
'Key' => $prefix . $data['thumb'],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
307 |
'SourceFile' => $path
|
308 |
+
);
|
309 |
+
$files_to_remove[] = $path;
|
310 |
+
}
|
311 |
+
}
|
312 |
+
elseif ( !empty( $data['sizes'] ) ) {
|
313 |
+
foreach ( $data['sizes'] as $size ) {
|
314 |
+
$path = str_replace( $file_name, $size['file'], $file_path );
|
315 |
+
if ( file_exists( $path ) ) {
|
316 |
+
$additional_images[] = array(
|
317 |
+
'Key' => $prefix . $size['file'],
|
318 |
+
'SourceFile' => $path
|
319 |
+
);
|
320 |
+
$files_to_remove[] = $path;
|
321 |
+
}
|
322 |
+
}
|
323 |
+
}
|
324 |
+
|
325 |
+
// Because we're just looking at the filesystem for files with @2x
|
326 |
+
// this should work with most HiDPI plugins
|
327 |
+
if ( $this->get_setting( 'hidpi-images' ) ) {
|
328 |
+
$hidpi_images = array();
|
329 |
+
|
330 |
+
foreach ( $additional_images as $image ) {
|
331 |
+
$hidpi_path = $this->get_hidpi_file_path( $image['SourceFile'] );
|
332 |
+
if ( file_exists( $hidpi_path ) ) {
|
333 |
+
$hidpi_images[] = array(
|
334 |
'Key' => $this->get_hidpi_file_path( $image['Key'] ),
|
335 |
'SourceFile' => $hidpi_path
|
336 |
+
);
|
337 |
+
$files_to_remove[] = $hidpi_path;
|
338 |
+
}
|
339 |
+
}
|
340 |
|
341 |
$additional_images = array_merge( $additional_images, $hidpi_images );
|
342 |
}
|
343 |
|
344 |
+
foreach ( $additional_images as $image ) {
|
345 |
try {
|
346 |
$args = array_merge( $args, $image );
|
347 |
+
$args['ACL'] = self::DEFAULT_ACL;
|
348 |
$s3client->putObject( $args );
|
349 |
}
|
350 |
catch ( Exception $e ) {
|
351 |
error_log( 'Error uploading ' . $args['SourceFile'] . ' to S3: ' . $e->getMessage() );
|
352 |
}
|
353 |
+
}
|
354 |
|
355 |
+
if ( $this->get_setting( 'remove-local-file' ) ) {
|
356 |
+
$this->remove_local_files( $files_to_remove );
|
357 |
+
}
|
358 |
|
359 |
+
return $data;
|
360 |
+
}
|
361 |
|
362 |
+
function remove_local_files( $file_paths ) {
|
363 |
+
foreach ( $file_paths as $path ) {
|
364 |
+
if ( !@unlink( $path ) ) {
|
365 |
+
error_log( 'Error removing local file ' . $path );
|
366 |
+
}
|
367 |
+
}
|
368 |
+
}
|
369 |
|
370 |
+
function get_hidpi_file_path( $orig_path ) {
|
371 |
$hidpi_suffix = apply_filters( 'as3cf_hidpi_suffix', '@2x' );
|
372 |
$pathinfo = pathinfo( $orig_path );
|
373 |
return $pathinfo['dirname'] . '/' . $pathinfo['filename'] . $hidpi_suffix . '.' . $pathinfo['extension'];
|
374 |
+
}
|
375 |
|
376 |
+
function get_object_version_string( $post_id ) {
|
377 |
if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
|
378 |
$date_format = 'dHis';
|
379 |
}
|
385 |
|
386 |
$object_version = date( $date_format, $time ) . '/';
|
387 |
$object_version = apply_filters( 'as3cf_get_object_version_string', $object_version );
|
388 |
+
|
389 |
return $object_version;
|
390 |
+
}
|
391 |
|
392 |
+
// Media files attached to a post use the post's date
|
393 |
+
// to determine the folder path they are placed in
|
394 |
+
function get_attachment_folder_time( $post_id ) {
|
395 |
$time = current_time( 'timestamp' );
|
396 |
|
397 |
+
if ( !( $attach = get_post( $post_id ) ) ) {
|
398 |
+
return $time;
|
399 |
+
}
|
400 |
|
401 |
+
if ( !$attach->post_parent ) {
|
402 |
+
return $time;
|
403 |
+
}
|
404 |
|
405 |
if ( !( $post = get_post( $attach->post_parent ) ) ) {
|
406 |
return $time;
|
410 |
return strtotime( $post->post_date_gmt . ' +0000' );
|
411 |
}
|
412 |
|
413 |
+
return $time;
|
414 |
+
}
|
415 |
+
|
416 |
+
/**
|
417 |
+
* Create unique names for file to be uploaded to AWS
|
418 |
+
* This only applies when the remove local file option is enabled
|
419 |
+
*
|
420 |
+
* @param array $file An array of data for a single file.
|
421 |
+
*
|
422 |
+
* @return array $file The altered file array with AWS unique filename.
|
423 |
+
*/
|
424 |
+
function wp_handle_upload_prefilter( $file ) {
|
425 |
+
if ( ! $this->get_setting( 'copy-to-s3' ) || ! $this->is_plugin_setup() ) {
|
426 |
+
return $file;
|
427 |
+
}
|
428 |
+
|
429 |
+
// only do this when we are removing local versions of files
|
430 |
+
if ( ! $this->get_setting( 'remove-local-file' ) ) {
|
431 |
+
return $file;
|
432 |
+
}
|
433 |
+
|
434 |
+
$filename = $file['name'];
|
435 |
+
|
436 |
+
// sanitize the file name before we begin processing
|
437 |
+
$filename = sanitize_file_name( $filename );
|
438 |
+
|
439 |
+
// separate the filename into a name and extension
|
440 |
+
$info = pathinfo( $filename );
|
441 |
+
$ext = ! empty( $info['extension'] ) ? '.' . $info['extension'] : '';
|
442 |
+
$name = basename( $filename, $ext );
|
443 |
+
|
444 |
+
// edge case: if file is named '.ext', treat as an empty name
|
445 |
+
if ( $name === $ext ) {
|
446 |
+
$name = '';
|
447 |
+
}
|
448 |
+
|
449 |
+
// rebuild filename with lowercase extension as S3 will have converted extension on upload
|
450 |
+
$ext = strtolower( $ext );
|
451 |
+
$filename = $info['filename'] . $ext;
|
452 |
+
|
453 |
+
$time = current_time( 'timestamp' );
|
454 |
+
$time = date( 'Y/m', $time );
|
455 |
+
|
456 |
+
$prefix = ltrim( trailingslashit( $this->get_setting( 'object-prefix' ) ), '/' );
|
457 |
+
$prefix .= ltrim( trailingslashit( $this->get_dynamic_prefix( $time ) ), '/' );
|
458 |
+
$s3client = $this->get_s3client();
|
459 |
+
|
460 |
+
$bucket = $this->get_setting( 'bucket' );
|
461 |
+
|
462 |
+
$number = '';
|
463 |
+
while ( $s3client->doesObjectExist( $bucket, $prefix . $filename ) !== false ) {
|
464 |
+
$previous = $number;
|
465 |
+
++$number;
|
466 |
+
if ( '' == $previous ) {
|
467 |
+
$filename = $name . $number . $ext;
|
468 |
+
} else {
|
469 |
+
$filename = str_replace( "$previous$ext", $number . $ext, $filename );
|
470 |
+
}
|
471 |
+
}
|
472 |
+
|
473 |
+
$file['name'] = $filename;
|
474 |
+
|
475 |
+
return $file;
|
476 |
+
}
|
477 |
|
478 |
function wp_get_attachment_url( $url, $post_id ) {
|
479 |
$new_url = $this->get_attachment_url( $post_id );
|
480 |
if ( false === $new_url ) {
|
481 |
return $url;
|
482 |
}
|
483 |
+
|
484 |
$new_url = apply_filters( 'wps3_get_attachment_url', $new_url, $post_id, $this ); // Old naming convention, will be deprecated soon
|
485 |
$new_url = apply_filters( 'as3cf_wp_get_attachment_url', $new_url, $post_id );
|
486 |
|
499 |
* Generate a link to download a file from Amazon S3 using query string
|
500 |
* authentication. This link is only valid for a limited amount of time.
|
501 |
*
|
502 |
+
* @param unknown $post_id Post ID of the attachment
|
503 |
+
* @param int $expires Seconds for the link to live
|
504 |
+
* @param null $size Size of the image to get
|
505 |
+
*
|
506 |
+
* @return mixed|void|WP_Error
|
507 |
*/
|
508 |
+
function get_secure_attachment_url( $post_id, $expires = null, $size = null ) {
|
509 |
+
if ( is_null( $expires ) ) {
|
510 |
+
$expires = self::DEFAULT_EXPIRES;
|
511 |
+
}
|
512 |
+
return $this->get_attachment_url( $post_id, $expires, $size );
|
513 |
}
|
514 |
|
515 |
+
/**
|
516 |
+
* Get the url of the file from Amazon S3
|
517 |
+
*
|
518 |
+
* @param unknown $post_id Post ID of the attachment
|
519 |
+
* @param null $expires Seconds for the link to live
|
520 |
+
* @param null $size Size of the image to get
|
521 |
+
* @param null $meta Pre retrieved _wp_attachment_metadata for the attachment
|
522 |
+
*
|
523 |
+
* @return bool|mixed|void|WP_Error
|
524 |
+
*/
|
525 |
+
function get_attachment_url( $post_id, $expires = null, $size = null, $meta = null ) {
|
526 |
+
if ( ! $this->get_setting( 'serve-from-s3' ) ) {
|
527 |
+
return false;
|
528 |
+
}
|
529 |
+
|
530 |
+
// check that the file has been uploaded to S3
|
531 |
+
if ( ! ( $s3object = $this->get_attachment_s3_info( $post_id ) ) ) {
|
532 |
return false;
|
533 |
}
|
534 |
|
539 |
$scheme = 'http';
|
540 |
}
|
541 |
|
542 |
+
// We don't use $this->get_s3object_region() here because we don't want
|
543 |
+
// to make an AWS API call and slow down page loading
|
544 |
+
if ( isset( $s3object['region'] ) ) {
|
545 |
+
$region = $s3object['region'];
|
546 |
+
}
|
547 |
+
else {
|
548 |
+
$region = '';
|
549 |
+
}
|
550 |
+
|
551 |
+
// force use of secured url when ACL has been set to private
|
552 |
+
if ( is_null( $expires ) && isset( $s3object['acl'] ) && self::PRIVATE_ACL == $s3object['acl'] ) {
|
553 |
+
$expires = self::DEFAULT_EXPIRES;
|
554 |
+
}
|
555 |
+
|
556 |
+
$prefix = ( '' == $region ) ? 's3' : 's3-' . $region;
|
557 |
+
|
558 |
if ( is_null( $expires ) && $this->get_setting( 'cloudfront' ) ) {
|
559 |
$domain_bucket = $this->get_setting( 'cloudfront' );
|
560 |
}
|
562 |
$domain_bucket = $s3object['bucket'];
|
563 |
}
|
564 |
elseif ( is_ssl() || $this->get_setting( 'force-ssl' ) ) {
|
565 |
+
$domain_bucket = $prefix . '.amazonaws.com/' . $s3object['bucket'];
|
566 |
}
|
567 |
else {
|
568 |
+
$domain_bucket = $s3object['bucket'] . '.' . $prefix . '.amazonaws.com';
|
569 |
}
|
570 |
|
571 |
+
if ( $size ) {
|
572 |
+
if ( is_null( $meta ) ) {
|
573 |
+
$meta = get_post_meta( $post_id, '_wp_attachment_metadata', true );
|
574 |
+
}
|
575 |
+
if ( isset( $meta['sizes'][$size]['file'] ) ) {
|
576 |
+
$s3object['key'] = dirname( $s3object['key'] ) . '/' . $meta['sizes'][$size]['file'];
|
577 |
+
}
|
578 |
+
}
|
579 |
|
580 |
if ( !is_null( $expires ) ) {
|
581 |
try {
|
582 |
$expires = time() + $expires;
|
583 |
+
$secure_url = $this->get_s3client()->getObjectUrl( $s3object['bucket'], $s3object['key'], $expires );
|
|
|
584 |
}
|
585 |
catch ( Exception $e ) {
|
586 |
return new WP_Error( 'exception', $e->getMessage() );
|
587 |
}
|
588 |
}
|
589 |
|
590 |
+
// encode file
|
591 |
+
$file = $this->encode_filename_in_path( $s3object['key'] );
|
592 |
+
|
593 |
+
$url = $scheme . '://' . $domain_bucket . '/' . $file;
|
594 |
+
if ( isset( $secure_url ) ) {
|
595 |
+
$url .= substr( $secure_url, strpos( $secure_url, '?' ) );
|
596 |
+
}
|
597 |
+
|
598 |
+
return apply_filters( 'as3cf_get_attachment_url', $url, $s3object, $post_id, $expires );
|
599 |
+
}
|
600 |
+
|
601 |
+
/**
|
602 |
+
* Override the attachment metadata
|
603 |
+
*
|
604 |
+
* @param unknown $data
|
605 |
+
* @param unknown $post_id
|
606 |
+
*
|
607 |
+
* @return mixed
|
608 |
+
*/
|
609 |
+
function wp_get_attachment_metadata( $data, $post_id ) {
|
610 |
+
return $this->maybe_encoded_file_of_resized_images( $data, $post_id );
|
611 |
+
}
|
612 |
+
|
613 |
+
/**
|
614 |
+
* Encodes the file names for resized image files for an attachment where necessary
|
615 |
+
*
|
616 |
+
* @param unknown $data
|
617 |
+
* @param unknown $post_id
|
618 |
+
*
|
619 |
+
* @return mixed Attachment meta data
|
620 |
+
*/
|
621 |
+
function maybe_encoded_file_of_resized_images( $data, $post_id ) {
|
622 |
+
if ( ! $this->get_setting( 'serve-from-s3' ) ) {
|
623 |
+
return $data;
|
624 |
+
}
|
625 |
+
|
626 |
+
if ( ! ( $s3object = $this->get_attachment_s3_info( $post_id ) ) ) {
|
627 |
+
return $data;
|
628 |
+
}
|
629 |
+
|
630 |
+
// we only need to encode the file name if url encoding is needed
|
631 |
+
$filename = basename( $s3object['key'] );
|
632 |
+
if ( $filename == rawurlencode( $filename ) ) {
|
633 |
+
return $data;
|
634 |
+
}
|
635 |
+
|
636 |
+
// we only need to encode resized image files
|
637 |
+
if ( ! isset( $data['sizes'] ) ) {
|
638 |
+
return $data;
|
639 |
+
}
|
640 |
+
|
641 |
+
foreach ( $data['sizes'] as $key => $size ) {
|
642 |
+
$data['sizes'][ $key ]['file'] = $this->encode_filename_in_path( $data['sizes'][ $key ]['file'] );
|
643 |
+
}
|
644 |
+
|
645 |
+
return $data;
|
646 |
+
}
|
647 |
+
|
648 |
+
/**
|
649 |
+
* Encode file names according to RFC 3986 when generating urls
|
650 |
+
* As per Amazon https://forums.aws.amazon.com/thread.jspa?threadID=55746#jive-message-244233
|
651 |
+
*
|
652 |
+
* @param unknown $file
|
653 |
+
*
|
654 |
+
* @return string Encoded filename with path prefix untouched
|
655 |
+
*/
|
656 |
+
function encode_filename_in_path( $file ) {
|
657 |
+
$file_path = dirname( $file );
|
658 |
+
$file_path = ( '.' != $file_path ) ? trailingslashit( $file_path ) : '';
|
659 |
+
$file_name = rawurlencode( basename( $file ) );
|
660 |
+
|
661 |
+
return $file_path . $file_name;
|
662 |
}
|
663 |
|
664 |
function verify_ajax_request() {
|
687 |
}
|
688 |
|
689 |
echo json_encode( $out );
|
690 |
+
exit;
|
691 |
}
|
692 |
|
693 |
function create_bucket( $bucket_name ) {
|
694 |
try {
|
695 |
+
$this->get_s3client()->createBucket( array( 'Bucket' => $bucket_name ) );
|
696 |
}
|
697 |
catch ( Exception $e ) {
|
698 |
return new WP_Error( 'exception', $e->getMessage() );
|
714 |
return $this->s3client;
|
715 |
}
|
716 |
|
717 |
+
/**
|
718 |
+
* Get the region of the bucket.
|
719 |
+
*
|
720 |
+
*
|
721 |
+
* @param unknown $s3object
|
722 |
+
* @param unknown $post_id - if supplied will update the s3 meta if no region found
|
723 |
+
*
|
724 |
+
* @return string - region name
|
725 |
+
*/
|
726 |
+
function get_s3object_region( $s3object, $post_id = null ) {
|
727 |
+
if ( ! isset( $s3object['region'] ) ) {
|
728 |
+
// if region hasn't been stored in the s3 metadata retrieve using the bucket
|
729 |
+
try {
|
730 |
+
$region = $this->get_s3client()->getBucketLocation( array( 'Bucket' => $s3object['bucket'] ) );
|
731 |
+
}
|
732 |
+
catch ( Exception $e ) {
|
733 |
+
return new WP_Error( 'exception', $e->getMessage() );
|
734 |
+
}
|
735 |
+
$s3object['region'] = $region['Location'];
|
736 |
+
|
737 |
+
if ( ! is_null( $post_id ) ) {
|
738 |
+
// retrospectively update s3 metadata with region
|
739 |
+
update_post_meta( $post_id, 'amazonS3_info', $s3object );
|
740 |
+
}
|
741 |
+
}
|
742 |
+
|
743 |
+
return $s3object['region'];
|
744 |
+
}
|
745 |
+
|
746 |
+
/**
|
747 |
+
* Set the region of the AWS client based on the bucket.
|
748 |
+
*
|
749 |
+
* This is needed for non US standard buckets to add and delete files.
|
750 |
+
*
|
751 |
+
* @param unknown $s3object
|
752 |
+
* @param unknown $post_id
|
753 |
+
*
|
754 |
+
* @return string - region name
|
755 |
+
*/
|
756 |
+
function set_s3client_region( $s3object, $post_id = null ) {
|
757 |
+
$region = $this->get_s3object_region( $s3object, $post_id );
|
758 |
+
|
759 |
+
if ( is_wp_error( $region ) ) {
|
760 |
+
return '';
|
761 |
+
}
|
762 |
+
|
763 |
+
if ( $region ) {
|
764 |
+
$this->get_s3client()->setRegion( $region );
|
765 |
+
}
|
766 |
+
|
767 |
+
return $region;
|
768 |
+
}
|
769 |
+
|
770 |
function get_buckets() {
|
771 |
try {
|
772 |
$result = $this->get_s3client()->listBuckets();
|
778 |
return $result['Buckets'];
|
779 |
}
|
780 |
|
781 |
+
/**
|
782 |
+
* Checks the user has write permission for S3
|
783 |
+
*
|
784 |
+
* @param string $bucket
|
785 |
+
*
|
786 |
+
* @return bool
|
787 |
+
*/
|
788 |
+
function check_write_permission( $bucket ) {
|
789 |
+
// fire up the filesystem API
|
790 |
+
$filesystem = WP_Filesystem();
|
791 |
+
global $wp_filesystem;
|
792 |
+
if ( false === $filesystem || is_null( $wp_filesystem ) ) {
|
793 |
+
return new WP_Error( 'exception', __( 'There was an error attempting to access the file system', 'as3cf' ) );
|
794 |
+
}
|
795 |
+
|
796 |
+
$uploads = wp_upload_dir();
|
797 |
+
$file_name = 'as3cf-permission-check.txt';
|
798 |
+
$file = trailingslashit( $uploads['basedir'] ) . $file_name;
|
799 |
+
$file_contents = __( 'This is a test file to check if the user has write permission to S3. Delete me if found.', 'as3cf' );
|
800 |
+
// create a temp file to upload
|
801 |
+
$temp_file = $wp_filesystem->put_contents( $file, $file_contents, FS_CHMOD_FILE );
|
802 |
+
if ( false === $temp_file ) {
|
803 |
+
return new WP_Error( 'exception', __( 'It looks like we cannot create a file locally to test the S3 permissions', 'as3cf' ) );
|
804 |
+
}
|
805 |
+
|
806 |
+
$args = array(
|
807 |
+
'Bucket' => $bucket,
|
808 |
+
'Key' => $file_name,
|
809 |
+
'SourceFile' => $file,
|
810 |
+
'ACL' => 'public-read'
|
811 |
+
);
|
812 |
+
|
813 |
+
try {
|
814 |
+
// attempt to create the test file
|
815 |
+
$this->get_s3client()->putObject( $args );
|
816 |
+
// delete it straight away if created
|
817 |
+
$this->get_s3client()->deleteObject( array(
|
818 |
+
'Bucket' => $bucket,
|
819 |
+
'Key' => $file_name
|
820 |
+
) );
|
821 |
+
$can_write = true;
|
822 |
+
} catch ( Exception $e ) {
|
823 |
+
// write permission not found
|
824 |
+
$can_write = false;
|
825 |
+
}
|
826 |
+
|
827 |
+
// delete temp file
|
828 |
+
$wp_filesystem->delete( $file );
|
829 |
+
|
830 |
+
return $can_write;
|
831 |
+
}
|
832 |
+
|
833 |
function plugin_load() {
|
834 |
+
$version = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? time() : $this->plugin_version;
|
835 |
+
|
836 |
$src = plugins_url( 'assets/css/styles.css', $this->plugin_file_path );
|
837 |
+
wp_enqueue_style( 'as3cf-styles', $src, array(), $version );
|
838 |
|
839 |
$suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
|
840 |
|
841 |
$src = plugins_url( 'assets/js/script' . $suffix . '.js', $this->plugin_file_path );
|
842 |
+
wp_enqueue_script( 'as3cf-script', $src, array( 'jquery' ), $version, true );
|
843 |
+
|
844 |
wp_localize_script( 'as3cf-script', 'as3cf_i18n', array(
|
845 |
+
'create_bucket_prompt' => __( 'Bucket Name:', 'as3cf' ),
|
846 |
+
'create_bucket_error' => __( 'Error creating bucket: ', 'as3cf' ),
|
847 |
+
'create_bucket_nonce' => wp_create_nonce( 'as3cf-create-bucket' )
|
848 |
+
) );
|
849 |
|
850 |
$this->handle_post_request();
|
851 |
}
|
859 |
die( __( "Cheatin' eh?", 'amazon-web-services' ) );
|
860 |
}
|
861 |
|
|
|
|
|
862 |
$post_vars = array( 'bucket', 'virtual-host', 'expires', 'permissions', 'cloudfront', 'object-prefix', 'copy-to-s3', 'serve-from-s3', 'remove-local-file', 'force-ssl', 'hidpi-images', 'object-versioning' );
|
863 |
+
|
864 |
foreach ( $post_vars as $var ) {
|
865 |
+
$this->remove_setting( $var );
|
866 |
+
|
867 |
if ( !isset( $_POST[$var] ) ) {
|
868 |
continue;
|
869 |
}
|
879 |
|
880 |
function render_page() {
|
881 |
$this->aws->render_view( 'header', array( 'page_title' => $this->plugin_title ) );
|
882 |
+
|
883 |
$aws_client = $this->aws->get_client();
|
884 |
|
885 |
if ( is_wp_error( $aws_client ) ) {
|
886 |
+
$this->render_view( 'error-fatal', array( 'message' => $aws_client->get_error_message() ) );
|
887 |
}
|
888 |
else {
|
889 |
+
do_action( 'as3cf_pre_settings_render' );
|
890 |
$this->render_view( 'settings' );
|
891 |
}
|
892 |
+
|
893 |
$this->aws->render_view( 'footer' );
|
894 |
}
|
895 |
|
896 |
function get_dynamic_prefix( $time = null ) {
|
897 |
+
$uploads = wp_upload_dir( $time );
|
898 |
+
return str_replace( $this->get_base_upload_path(), '', $uploads['path'] );
|
899 |
}
|
900 |
|
901 |
// Without the multisite subdirectory
|
902 |
+
function get_base_upload_path() {
|
903 |
if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
|
904 |
return ABSPATH . UPLOADS;
|
905 |
}
|
916 |
}
|
917 |
}
|
918 |
|
919 |
+
/**
|
920 |
+
* Get all the blog IDs for the multisite network used for table prefixes
|
921 |
+
*
|
922 |
+
* @return array
|
923 |
+
*/
|
924 |
+
function get_blog_ids() {
|
925 |
+
$args = array(
|
926 |
+
'limit' => false,
|
927 |
+
'spam' => 0,
|
928 |
+
'deleted' => 0,
|
929 |
+
'archived' => 0
|
930 |
+
);
|
931 |
+
$blogs = wp_get_sites( $args );
|
932 |
+
|
933 |
+
$blog_ids = array();
|
934 |
+
foreach ( $blogs as $blog ) {
|
935 |
+
if ( 1 == $blog['blog_id'] ) {
|
936 |
+
// ignore the first blog which doesn't have the ID in the table prefix
|
937 |
+
continue;
|
938 |
+
}
|
939 |
+
$blog_ids[] = $blog['blog_id'];
|
940 |
+
}
|
941 |
+
|
942 |
+
return $blog_ids;
|
943 |
+
}
|
944 |
}
|
classes/as3cf-compatibility-check.php
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class AS3CF_Compatibility_Check {
|
3 |
+
|
4 |
+
private $plugin_file_path, $aws_plugin_version_required;
|
5 |
+
|
6 |
+
function __construct( $plugin_file_path, $aws_plugin_version_required ) {
|
7 |
+
$this->plugin_file_path = $plugin_file_path;
|
8 |
+
$this->aws_plugin_version_required = $aws_plugin_version_required;
|
9 |
+
|
10 |
+
add_action( 'admin_notices', array( $this, 'hook_admin_notices' ) );
|
11 |
+
add_action( 'network_admin_notices', array( $this, 'hook_admin_notices' ) );
|
12 |
+
}
|
13 |
+
|
14 |
+
function is_compatible() {
|
15 |
+
return $this->get_error_msg() ? false : true;
|
16 |
+
}
|
17 |
+
|
18 |
+
function get_error_msg() {
|
19 |
+
static $msg;
|
20 |
+
|
21 |
+
if ( ! is_null( $msg ) ) {
|
22 |
+
return $msg;
|
23 |
+
}
|
24 |
+
|
25 |
+
$hide_notice_msg = '<br>' . __( 'You can deactivate the Amazon S3 and CloudFront plugin to get rid of this notice.', 'as3cf' );
|
26 |
+
|
27 |
+
if ( ! class_exists( 'Amazon_Web_Services' ) ) {
|
28 |
+
$msg = sprintf( __( 'Amazon S3 and CloudFront has been disabled as it requires the <a style="text-decoration:none;" href="%s">Amazon Web Services</a> plugin.', 'as3cf' ), 'http://wordpress.org/extend/plugins/amazon-web-services/' );
|
29 |
+
|
30 |
+
if ( file_exists( WP_PLUGIN_DIR . '/amazon-web-services/amazon-web-services.php' ) ) {
|
31 |
+
$msg .= ' ' . __( 'It appears to be installed already.', 'as3cf' );
|
32 |
+
$activate_url = wp_nonce_url( network_admin_url( 'plugins.php?action=activate&plugin=amazon-web-services/amazon-web-services.php' ), 'activate-plugin_amazon-web-services/amazon-web-services.php' );
|
33 |
+
$msg .= ' <a style="font-weight:bold;text-decoration:none;" href="' . $activate_url . '">' . _x( 'Activate it now', 'Activate plugin', 'as3cf' ) . '</a>';
|
34 |
+
}
|
35 |
+
else {
|
36 |
+
$install_url = wp_nonce_url( network_admin_url( 'update.php?action=install-plugin&plugin=amazon-web-services' ), 'install-plugin_amazon-web-services' );
|
37 |
+
$msg .= ' ' . sprintf( __( '<a href="%s">Install it</a> and activate.', 'as3cf' ), $install_url );
|
38 |
+
}
|
39 |
+
|
40 |
+
$msg .= $hide_notice_msg;
|
41 |
+
|
42 |
+
return $msg;
|
43 |
+
}
|
44 |
+
|
45 |
+
$aws_plugin_version = isset( $GLOBALS['aws_meta']['amazon-web-services']['version'] ) ? $GLOBALS['aws_meta']['amazon-web-services']['version'] : 0;
|
46 |
+
|
47 |
+
if ( ! version_compare( $aws_plugin_version, $this->aws_plugin_version_required, '>=' ) ) {
|
48 |
+
$msg = sprintf( __( 'Amazon S3 and CloudFront has been disabled as it requires version %s or later of the <a style="text-decoration:none;" href="%s">Amazon Web Services</a> plugin.', 'as3cf' ), $this->aws_plugin_version_required, 'http://wordpress.org/extend/plugins/amazon-web-services/' );
|
49 |
+
|
50 |
+
if ( $aws_plugin_version ) {
|
51 |
+
$msg .= ' ' . sprintf( __( 'You currently have version %s installed.', 'as3cf' ), $aws_plugin_version );
|
52 |
+
}
|
53 |
+
|
54 |
+
$update_url = wp_nonce_url( network_admin_url( 'update.php?action=upgrade-plugin&plugin=amazon-web-services/amazon-web-services.php' ), 'upgrade-plugin_amazon-web-services/amazon-web-services.php' );
|
55 |
+
$msg .= ' <a style="font-weight:bold;text-decoration:none;white-space:nowrap;" href="' . $update_url . '">' . __( 'Update to the latest version', 'as3cf' ) . '</a>';
|
56 |
+
|
57 |
+
$msg .= $hide_notice_msg;
|
58 |
+
|
59 |
+
return $msg;
|
60 |
+
}
|
61 |
+
|
62 |
+
$as3cf_plugin_version_required = $GLOBALS['aws_meta']['amazon-web-services']['supported_addon_versions']['amazon-s3-and-cloudfront'];
|
63 |
+
$as3cf_plugin_version = $GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'];
|
64 |
+
|
65 |
+
if ( ! version_compare( $as3cf_plugin_version, $as3cf_plugin_version_required, '>=' ) ) {
|
66 |
+
$msg = sprintf( __( 'Amazon S3 and CloudFront has been disabled because it will not work with the version of the Amazon Web Services plugin installed. Amazon S3 and CloudFront %s or later is required.', 'as3cf' ), $as3cf_plugin_version_required );
|
67 |
+
|
68 |
+
$plugin_basename = plugin_basename( __FILE__ );
|
69 |
+
$update_url = wp_nonce_url( network_admin_url( 'update.php?action=upgrade-plugin&plugin=' . $plugin_basename ), 'upgrade-plugin_' . $plugin_basename );
|
70 |
+
$msg .= ' <a style="font-weight:bold;text-decoration:none;white-space:nowrap;" href="' . $update_url . '">' . __( 'Update Amazon S3 and CloudFront to the latest version', 'as3cf' ) . '</a>';
|
71 |
+
|
72 |
+
$msg .= $hide_notice_msg;
|
73 |
+
|
74 |
+
return $msg;
|
75 |
+
}
|
76 |
+
|
77 |
+
$msg = false;
|
78 |
+
return $msg;
|
79 |
+
}
|
80 |
+
|
81 |
+
function hook_admin_notices() {
|
82 |
+
if ( is_multisite() ) {
|
83 |
+
if ( ! current_user_can( 'manage_network_plugins' ) ) {
|
84 |
+
return; // Don't show notices if the user can't manage network plugins
|
85 |
+
}
|
86 |
+
}
|
87 |
+
else {
|
88 |
+
// Don't show notices if user doesn't have plugin management privileges
|
89 |
+
$caps = array( 'activate_plugins', 'update_plugins', 'install_plugins' );
|
90 |
+
foreach ( $caps as $cap ) {
|
91 |
+
if ( ! current_user_can( $cap ) ) {
|
92 |
+
return;
|
93 |
+
}
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
$error_msg = $this->get_error_msg();
|
98 |
+
|
99 |
+
if ( ! $error_msg ) {
|
100 |
+
return;
|
101 |
+
}
|
102 |
+
|
103 |
+
printf( '<div class="error"><p>%s</p></div>', $error_msg );
|
104 |
+
}
|
105 |
+
}
|
classes/as3cf-upgrade.php
ADDED
@@ -0,0 +1,354 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Upgrade
|
4 |
+
*
|
5 |
+
* @package amazon-s3-and-cloudfront
|
6 |
+
* @subpackage Classes/Upgrade
|
7 |
+
* @copyright Copyright (c) 2014, Delicious Brains
|
8 |
+
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
9 |
+
* @since 0.6.2
|
10 |
+
*/
|
11 |
+
|
12 |
+
// Exit if accessed directly
|
13 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
14 |
+
exit;
|
15 |
+
}
|
16 |
+
|
17 |
+
/**
|
18 |
+
* AS3CF_Upgrade Class
|
19 |
+
*
|
20 |
+
* This class handles data updates and other migrations after a plugin update
|
21 |
+
*
|
22 |
+
* @since 0.6.2
|
23 |
+
*/
|
24 |
+
class AS3CF_Upgrade {
|
25 |
+
|
26 |
+
private $as3cf;
|
27 |
+
private $cron_interval_in_minutes;
|
28 |
+
private $error_threshold;
|
29 |
+
|
30 |
+
const CRON_HOOK = 'as3cf_cron_update_meta_with_region';
|
31 |
+
const CRON_SCHEDULE_KEY = 'as3cf_update_meta_with_region_interval';
|
32 |
+
|
33 |
+
const STATUS_RUNNING = 1;
|
34 |
+
const STATUS_ERROR = 2;
|
35 |
+
const STATUS_PAUSED = 3;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Start it up
|
39 |
+
*
|
40 |
+
* @param unknown $as3cf - the instance of the as3cf class
|
41 |
+
*/
|
42 |
+
function __construct( $as3cf ) {
|
43 |
+
$this->as3cf = $as3cf;
|
44 |
+
|
45 |
+
$this->cron_interval_in_minutes = apply_filters( 'as3cf_update_meta_with_region_interval', 10 );
|
46 |
+
$this->error_threshold = apply_filters( 'as3cf_update_meta_with_region_error_threshold', 20 );
|
47 |
+
|
48 |
+
add_filter( 'cron_schedules', array( $this, 'cron_schedules' ) );
|
49 |
+
add_action( self::CRON_HOOK, array( $this, 'cron_update_meta_with_region' ) );
|
50 |
+
|
51 |
+
add_action( 'as3cf_pre_settings_render', array( $this, 'maybe_display_notices' ) );
|
52 |
+
add_action( 'admin_init', array( $this, 'maybe_handle_action' ) );
|
53 |
+
|
54 |
+
$this->maybe_init_upgrade();
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Maybe initialize the upgrade
|
59 |
+
*/
|
60 |
+
function maybe_init_upgrade() {
|
61 |
+
if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
|
62 |
+
return;
|
63 |
+
}
|
64 |
+
|
65 |
+
// Have we completed the upgrade yet?
|
66 |
+
if ( $this->as3cf->get_setting( 'post_meta_version', 0 ) > 0 ) {
|
67 |
+
return;
|
68 |
+
}
|
69 |
+
|
70 |
+
// If the upgrade status is already set, then we've already initialized the upgrade
|
71 |
+
if ( $this->get_upgrade_status() ) {
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
|
75 |
+
// Initialize the upgrade
|
76 |
+
$this->save_session( array( 'status' => self::STATUS_RUNNING ) );
|
77 |
+
|
78 |
+
$this->schedule_event();
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Adds notices about issues with upgrades allowing user to restart them
|
83 |
+
*/
|
84 |
+
function maybe_display_notices() {
|
85 |
+
$restart_url = self_admin_url( 'admin.php?page=' . $this->as3cf->get_plugin_slug() . '&action=restart_update_meta_with_region' );
|
86 |
+
|
87 |
+
switch ( $this->get_upgrade_status() ) {
|
88 |
+
case self::STATUS_RUNNING :
|
89 |
+
$msg = sprintf( __( '<strong>Running Metadata Update</strong> — We’re going through all the Media Library items uploaded to S3 and updating the metadata with the bucket region it is served from. This will allow us to serve your files from the proper S3 region subdomain <span style="white-space:nowrap;">(e.g. s3-us-west-2.amazonaws.com)</span>. This will be done quietly in the background, processing a small batch of Media Library items every %d minutes. There should be no noticeable impact on your server’s performance.', 'as3cf' ), $this->cron_interval_in_minutes );
|
90 |
+
$msg .= ' <strong><a href="' . self_admin_url( 'admin.php?page=' . $this->as3cf->get_plugin_slug() . '&action=pause_update_meta_with_region' ) . '">' . __( 'Pause Update', 'as3cf' ) . '</a></strong>';
|
91 |
+
$this->as3cf->render_view( 'notice', array( 'message' => $msg ) );
|
92 |
+
break;
|
93 |
+
case self::STATUS_PAUSED :
|
94 |
+
$msg = __( '<strong>Metadata Update Paused</strong> — Updating Media Library metadata has been paused.', 'as3cf' );
|
95 |
+
$msg .= ' <strong><a href="' . $restart_url . '">' . __( 'Restart Update', 'as3cf' ) . '</a></strong>';
|
96 |
+
$this->as3cf->render_view( 'notice', array( 'message' => $msg ) );
|
97 |
+
break;
|
98 |
+
case self::STATUS_ERROR :
|
99 |
+
$msg = __( '<strong>Error Updating Metadata</strong> — We ran into some errors attempting to update the metadata for all your Media Library items that have been uploaded to S3. Please check your error log for details.', 'as3cf' );
|
100 |
+
$msg .= ' <strong><a href="' . $restart_url . '">' . __( 'Try Run It Again', 'as3cf' ) . '</a></strong>';
|
101 |
+
$this->as3cf->render_view( 'error', array( 'message' => $msg ) );
|
102 |
+
break;
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
function maybe_handle_action() {
|
107 |
+
if ( ! isset( $_GET['page'] ) || $_GET['page'] != $this->as3cf->get_plugin_slug() || ! isset( $_GET['action'] ) ) {
|
108 |
+
return;
|
109 |
+
}
|
110 |
+
|
111 |
+
$method_name = 'action_' . $_GET['action'];
|
112 |
+
if ( method_exists( $this, $method_name ) ) {
|
113 |
+
call_user_func( array( $this, $method_name ) );
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Restart upgrade
|
119 |
+
*/
|
120 |
+
function action_restart_update_meta_with_region() {
|
121 |
+
$this->change_status_request( self::STATUS_RUNNING );
|
122 |
+
$this->schedule_event();
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Pause upgrade
|
127 |
+
*/
|
128 |
+
function action_pause_update_meta_with_region() {
|
129 |
+
$this->clear_scheduled_event();
|
130 |
+
$this->change_status_request( self::STATUS_PAUSED );
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Helper for the above action requests
|
135 |
+
*/
|
136 |
+
function change_status_request( $status ) {
|
137 |
+
$session = $this->get_session();
|
138 |
+
$session['status'] = $status;
|
139 |
+
$this->save_session( $session );
|
140 |
+
|
141 |
+
wp_redirect( self_admin_url( 'admin.php?page=' . $this->as3cf->get_plugin_slug() ) );
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Add custom cron interval schedules
|
146 |
+
*
|
147 |
+
* @param array $schedules
|
148 |
+
*
|
149 |
+
* @return array
|
150 |
+
*/
|
151 |
+
function cron_schedules( $schedules ) {
|
152 |
+
// Adds every 10 minutes to the existing schedules.
|
153 |
+
$schedules[ self::CRON_SCHEDULE_KEY ] = array(
|
154 |
+
'interval' => $this->cron_interval_in_minutes * 60,
|
155 |
+
'display' => __( 'Every ' . $this->cron_interval_in_minutes . ' Minutes', 'as3cf' )
|
156 |
+
);
|
157 |
+
|
158 |
+
return $schedules;
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Wrapper for scheduling the cron job
|
163 |
+
*/
|
164 |
+
function schedule_event() {
|
165 |
+
if ( ! wp_next_scheduled( self::CRON_HOOK ) ) {
|
166 |
+
wp_schedule_event( current_time( 'timestamp' ), self::CRON_SCHEDULE_KEY, self::CRON_HOOK );
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Wrapper for clearing scheduled events for a specific cron job
|
172 |
+
*/
|
173 |
+
function clear_scheduled_event() {
|
174 |
+
$timestamp = wp_next_scheduled( self::CRON_HOOK );
|
175 |
+
if ( $timestamp ) {
|
176 |
+
wp_unschedule_event( $timestamp, self::CRON_HOOK );
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Cron jon to update the region of the bucket in s3 metadata
|
182 |
+
*/
|
183 |
+
function cron_update_meta_with_region() {
|
184 |
+
// Check if the cron should even be running
|
185 |
+
if ( $this->as3cf->get_setting( 'post_meta_version', 0 ) > 0 || $this->get_upgrade_status() != self::STATUS_RUNNING ) {
|
186 |
+
$this->clear_scheduled_event();
|
187 |
+
return;
|
188 |
+
}
|
189 |
+
|
190 |
+
global $wpdb;
|
191 |
+
$prefix = $wpdb->prefix;
|
192 |
+
|
193 |
+
// set the batch size limit for the query
|
194 |
+
$limit = apply_filters( 'as3cf_update_meta_with_region_batch_size', 500 );
|
195 |
+
$all_limit = $limit;
|
196 |
+
|
197 |
+
$table_prefixes = array();
|
198 |
+
$session = $this->get_session();
|
199 |
+
|
200 |
+
// find the blog IDs that have been processed so we can skip them
|
201 |
+
$processed_blog_ids = isset( $session['processed_blog_ids'] ) ? $session['processed_blog_ids'] : array();
|
202 |
+
$error_count = isset( $session['error_count'] ) ? $session['error_count'] : 0;
|
203 |
+
|
204 |
+
if ( ! in_array( 1, $processed_blog_ids ) ) {
|
205 |
+
$table_prefixes[1] = $prefix;
|
206 |
+
}
|
207 |
+
|
208 |
+
if ( is_multisite() ) {
|
209 |
+
$blog_ids = $this->as3cf->get_blog_ids();
|
210 |
+
foreach ( $blog_ids as $blog_id ) {
|
211 |
+
if ( in_array( $blog_id, $processed_blog_ids ) ) {
|
212 |
+
continue;
|
213 |
+
}
|
214 |
+
$table_prefixes[ $blog_id ] = $prefix . $blog_id . '_';
|
215 |
+
}
|
216 |
+
}
|
217 |
+
|
218 |
+
$all_attachments = array();
|
219 |
+
$all_count = 0;
|
220 |
+
|
221 |
+
foreach ( $table_prefixes as $blog_id => $table_prefix ) {
|
222 |
+
$attachments = $this->get_attachments_without_region( $table_prefix, $limit );
|
223 |
+
$count = count( $attachments );
|
224 |
+
|
225 |
+
if ( 0 == $count ) {
|
226 |
+
// no more attachments, record the blog ID to skip next time
|
227 |
+
$processed_blog_ids[] = $blog_id;
|
228 |
+
} else {
|
229 |
+
$all_count += $count;
|
230 |
+
$all_attachments[ $blog_id ] = $attachments;
|
231 |
+
}
|
232 |
+
|
233 |
+
if ( $all_count >= $all_limit ) {
|
234 |
+
break;
|
235 |
+
}
|
236 |
+
|
237 |
+
$limit = $limit - $count;
|
238 |
+
}
|
239 |
+
|
240 |
+
if ( 0 == $all_count ) {
|
241 |
+
$this->as3cf->set_setting( 'post_meta_version', 1 );
|
242 |
+
$this->as3cf->remove_setting( 'update_meta_with_region_session' );
|
243 |
+
$this->as3cf->save_settings();
|
244 |
+
$this->clear_scheduled_event();
|
245 |
+
return;
|
246 |
+
}
|
247 |
+
|
248 |
+
// only process the loop for a certain amount of time
|
249 |
+
$minutes = $this->cron_interval_in_minutes * 60;
|
250 |
+
|
251 |
+
// smaller time limit so won't run into another instance of cron
|
252 |
+
$minutes = $minutes * 0.8;
|
253 |
+
|
254 |
+
$finish = time() + $minutes;
|
255 |
+
|
256 |
+
// loop through and update s3 meta with region
|
257 |
+
foreach ( $all_attachments as $blog_id => $attachments ) {
|
258 |
+
if ( 1 != $blog_id && is_multisite() ) {
|
259 |
+
switch_to_blog( $blog_id );
|
260 |
+
}
|
261 |
+
|
262 |
+
foreach ( $attachments as $attachment ) {
|
263 |
+
if ( $error_count >= $this->error_threshold ) {
|
264 |
+
$session['status'] = self::STATUS_ERROR;
|
265 |
+
$this->save_session( $session );
|
266 |
+
$this->clear_scheduled_event();
|
267 |
+
return;
|
268 |
+
}
|
269 |
+
|
270 |
+
if ( time() >= $finish ) {
|
271 |
+
break;
|
272 |
+
}
|
273 |
+
|
274 |
+
$s3object = unserialize( $attachment->s3object );
|
275 |
+
if ( false === $s3object ) {
|
276 |
+
error_log( 'Failed to unserialize S3 meta for attachment ' . $attachment->ID . ': ' . $attachment->s3object );
|
277 |
+
$error_count++;
|
278 |
+
continue;
|
279 |
+
}
|
280 |
+
|
281 |
+
// retrieve region and update the attachment metadata
|
282 |
+
$region = $this->as3cf->get_s3object_region( $s3object, $attachment->ID );
|
283 |
+
if ( is_wp_error( $region ) ) {
|
284 |
+
error_log( 'Error updating region: ' . $region->get_error_message() );
|
285 |
+
$error_count++;
|
286 |
+
}
|
287 |
+
}
|
288 |
+
|
289 |
+
if ( 1 != $blog_id && is_multisite() ) {
|
290 |
+
restore_current_blog();
|
291 |
+
}
|
292 |
+
}
|
293 |
+
|
294 |
+
$session['processed_blog_ids'] = $processed_blog_ids;
|
295 |
+
$session['error_count'] = $error_count;
|
296 |
+
|
297 |
+
$this->save_session( $session );
|
298 |
+
}
|
299 |
+
|
300 |
+
/*
|
301 |
+
* Get the current status of the upgrade
|
302 |
+
* See STATUS_* constants in the class declaration above.
|
303 |
+
*/
|
304 |
+
function get_upgrade_status() {
|
305 |
+
$session = $this->get_session();
|
306 |
+
|
307 |
+
if ( ! isset( $session['status'] ) ) {
|
308 |
+
return '';
|
309 |
+
}
|
310 |
+
|
311 |
+
return $session['status'];
|
312 |
+
}
|
313 |
+
|
314 |
+
/*
|
315 |
+
* Retrieve session data from plugin settings
|
316 |
+
*
|
317 |
+
* @return array
|
318 |
+
*/
|
319 |
+
function get_session() {
|
320 |
+
return $this->as3cf->get_setting( 'update_meta_with_region_session', array() );
|
321 |
+
}
|
322 |
+
|
323 |
+
/*
|
324 |
+
* Store data to be used between requests in plugin settings
|
325 |
+
*
|
326 |
+
* @param $session array of session data to store
|
327 |
+
*/
|
328 |
+
function save_session( $session ) {
|
329 |
+
$this->as3cf->set_setting( 'update_meta_with_region_session', $session );
|
330 |
+
$this->as3cf->save_settings();
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Get all attachments that don't have region in their S3 meta
|
335 |
+
*
|
336 |
+
* @param unknown $prefix
|
337 |
+
* @param unknown $limit
|
338 |
+
*
|
339 |
+
* @return mixed
|
340 |
+
*/
|
341 |
+
function get_attachments_without_region( $prefix, $limit ) {
|
342 |
+
global $wpdb;
|
343 |
+
$sql = $wpdb->prepare(
|
344 |
+
"SELECT `post_id` as `ID`, `meta_value` AS 's3object'
|
345 |
+
FROM `{$prefix}postmeta`
|
346 |
+
WHERE `meta_key` = 'amazonS3_info'
|
347 |
+
AND `meta_value` NOT LIKE '%%\"region\"%%'
|
348 |
+
LIMIT %d",
|
349 |
+
$limit
|
350 |
+
);
|
351 |
+
|
352 |
+
return $wpdb->get_results( $sql, OBJECT );
|
353 |
+
}
|
354 |
+
}
|
composer.json
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "deliciousbrains/wp-amazon-s3-and-cloudfront",
|
3 |
+
"type": "wordpress-plugin",
|
4 |
+
"homepage": "https://github.com/deliciousbrains/wp-amazon-s3-and-cloudfront",
|
5 |
+
"license": "GPLv3",
|
6 |
+
"description": "Automatically copies media uploads to Amazon S3 for delivery. Optionally configure Amazon CloudFront for even faster delivery.",
|
7 |
+
"keywords": ["plugin","amazon-web-services","s3","cloudfront","cdn"],
|
8 |
+
"require": {
|
9 |
+
"composer/installers": "~1.0.6"
|
10 |
+
}
|
11 |
+
}
|
composer.lock
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_readme": [
|
3 |
+
"This file locks the dependencies of your project to a known state",
|
4 |
+
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
5 |
+
"This file is @generated automatically"
|
6 |
+
],
|
7 |
+
"hash": "4b6bce2aaae303cfd3fc478e7cc55366",
|
8 |
+
"packages": [
|
9 |
+
{
|
10 |
+
"name": "composer/installers",
|
11 |
+
"version": "v1.0.18",
|
12 |
+
"source": {
|
13 |
+
"type": "git",
|
14 |
+
"url": "https://github.com/composer/installers.git",
|
15 |
+
"reference": "74fb0a7a1a23696d9c8cc2fba5903f6711cdd067"
|
16 |
+
},
|
17 |
+
"dist": {
|
18 |
+
"type": "zip",
|
19 |
+
"url": "https://api.github.com/repos/composer/installers/zipball/74fb0a7a1a23696d9c8cc2fba5903f6711cdd067",
|
20 |
+
"reference": "74fb0a7a1a23696d9c8cc2fba5903f6711cdd067",
|
21 |
+
"shasum": ""
|
22 |
+
},
|
23 |
+
"replace": {
|
24 |
+
"roundcube/plugin-installer": "*",
|
25 |
+
"shama/baton": "*"
|
26 |
+
},
|
27 |
+
"require-dev": {
|
28 |
+
"composer/composer": "1.0.*@dev",
|
29 |
+
"phpunit/phpunit": "4.1.*"
|
30 |
+
},
|
31 |
+
"type": "composer-installer",
|
32 |
+
"extra": {
|
33 |
+
"class": "Composer\\Installers\\Installer",
|
34 |
+
"branch-alias": {
|
35 |
+
"dev-master": "1.0-dev"
|
36 |
+
}
|
37 |
+
},
|
38 |
+
"autoload": {
|
39 |
+
"psr-0": {
|
40 |
+
"Composer\\Installers\\": "src/"
|
41 |
+
}
|
42 |
+
},
|
43 |
+
"notification-url": "https://packagist.org/downloads/",
|
44 |
+
"license": [
|
45 |
+
"MIT"
|
46 |
+
],
|
47 |
+
"authors": [
|
48 |
+
{
|
49 |
+
"name": "Kyle Robinson Young",
|
50 |
+
"email": "kyle@dontkry.com",
|
51 |
+
"homepage": "https://github.com/shama"
|
52 |
+
}
|
53 |
+
],
|
54 |
+
"description": "A multi-framework Composer library installer",
|
55 |
+
"homepage": "http://composer.github.com/installers/",
|
56 |
+
"keywords": [
|
57 |
+
"Craft",
|
58 |
+
"Dolibarr",
|
59 |
+
"Hurad",
|
60 |
+
"MODX Evo",
|
61 |
+
"OXID",
|
62 |
+
"WolfCMS",
|
63 |
+
"agl",
|
64 |
+
"annotatecms",
|
65 |
+
"bitrix",
|
66 |
+
"cakephp",
|
67 |
+
"chef",
|
68 |
+
"codeigniter",
|
69 |
+
"concrete5",
|
70 |
+
"croogo",
|
71 |
+
"drupal",
|
72 |
+
"elgg",
|
73 |
+
"fuelphp",
|
74 |
+
"installer",
|
75 |
+
"joomla",
|
76 |
+
"kohana",
|
77 |
+
"laravel",
|
78 |
+
"lithium",
|
79 |
+
"magento",
|
80 |
+
"mako",
|
81 |
+
"mediawiki",
|
82 |
+
"modulework",
|
83 |
+
"moodle",
|
84 |
+
"phpbb",
|
85 |
+
"piwik",
|
86 |
+
"ppi",
|
87 |
+
"puppet",
|
88 |
+
"roundcube",
|
89 |
+
"shopware",
|
90 |
+
"silverstripe",
|
91 |
+
"symfony",
|
92 |
+
"typo3",
|
93 |
+
"wordpress",
|
94 |
+
"zend",
|
95 |
+
"zikula"
|
96 |
+
],
|
97 |
+
"time": "2014-08-18 20:00:12"
|
98 |
+
}
|
99 |
+
],
|
100 |
+
"packages-dev": [],
|
101 |
+
"aliases": [],
|
102 |
+
"minimum-stability": "stable",
|
103 |
+
"stability-flags": [],
|
104 |
+
"prefer-stable": false,
|
105 |
+
"platform": [],
|
106 |
+
"platform-dev": []
|
107 |
+
}
|
include/functions.php
CHANGED
@@ -1,18 +1,14 @@
|
|
1 |
<?php
|
2 |
/**
|
3 |
-
*
|
4 |
-
*
|
5 |
*
|
6 |
-
* @
|
7 |
-
* @
|
8 |
-
* @param mixed
|
9 |
-
* @param int $expires Secondes for the link to live
|
10 |
-
* @return array
|
11 |
*/
|
12 |
-
function
|
13 |
-
|
14 |
-
}
|
15 |
-
|
16 |
-
function as3cf_get_secure_attachment_url( $post_id, $expires = 900, $operation = 'GET' ) {
|
17 |
|
18 |
-
|
|
1 |
<?php
|
2 |
/**
|
3 |
+
* API function to generate a link to download a file from Amazon S3 using
|
4 |
+
* query string authentication, expiring after a set amount of time.
|
5 |
*
|
6 |
+
* @param mixed $post_id Post ID of the attachment or null to use the loop
|
7 |
+
* @param int $expires Seconds for the link to live
|
8 |
+
* @param mixed $size Size of the image to get
|
|
|
|
|
9 |
*/
|
10 |
+
function as3cf_get_secure_attachment_url( $post_id, $expires = 900, $size = null ) {
|
11 |
+
global $as3cf;
|
|
|
|
|
|
|
12 |
|
13 |
+
return $as3cf->get_secure_attachment_url( $post_id, $expires, $size );
|
14 |
+
}
|
languages/amazon-s3-and-cloudfront.pot
ADDED
@@ -0,0 +1,315 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
msgid ""
|
2 |
+
msgstr ""
|
3 |
+
"Project-Id-Version: Amazon S3 and CloudFront\n"
|
4 |
+
"POT-Creation-Date: 2014-12-02 16:41-0000\n"
|
5 |
+
"PO-Revision-Date: 2014-12-02 16:44-0000\n"
|
6 |
+
"Last-Translator: Delicious Brains <nom@deliciousbrains.com>\n"
|
7 |
+
"Language-Team: Delicious Brains <nom@deliciousbrains.com>\n"
|
8 |
+
"Language: en\n"
|
9 |
+
"MIME-Version: 1.0\n"
|
10 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
11 |
+
"Content-Transfer-Encoding: 8bit\n"
|
12 |
+
"X-Generator: Poedit 1.6.10\n"
|
13 |
+
"X-Poedit-Basepath: ..\n"
|
14 |
+
"X-Poedit-SourceCharset: UTF-8\n"
|
15 |
+
"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
|
16 |
+
"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
|
17 |
+
"_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
|
18 |
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
19 |
+
"X-Poedit-SearchPath-0: .\n"
|
20 |
+
|
21 |
+
#: classes/amazon-s3-and-cloudfront.php:25
|
22 |
+
msgid "Amazon S3 and CloudFront"
|
23 |
+
msgstr ""
|
24 |
+
|
25 |
+
#: classes/amazon-s3-and-cloudfront.php:26
|
26 |
+
msgid "S3 and CloudFront"
|
27 |
+
msgstr ""
|
28 |
+
|
29 |
+
#: classes/amazon-s3-and-cloudfront.php:666
|
30 |
+
msgid "Cheatin’ eh?"
|
31 |
+
msgstr ""
|
32 |
+
|
33 |
+
#: classes/amazon-s3-and-cloudfront.php:670
|
34 |
+
msgid "You do not have sufficient permissions to access this page."
|
35 |
+
msgstr ""
|
36 |
+
|
37 |
+
#: classes/amazon-s3-and-cloudfront.php:678
|
38 |
+
msgid "No bucket name provided."
|
39 |
+
msgstr ""
|
40 |
+
|
41 |
+
#: classes/amazon-s3-and-cloudfront.php:793
|
42 |
+
msgid "There was an error attempting to access the file system"
|
43 |
+
msgstr ""
|
44 |
+
|
45 |
+
#: classes/amazon-s3-and-cloudfront.php:799
|
46 |
+
msgid ""
|
47 |
+
"This is a test file to check if the user has write permission to S3. Delete "
|
48 |
+
"me if found."
|
49 |
+
msgstr ""
|
50 |
+
|
51 |
+
#: classes/amazon-s3-and-cloudfront.php:803
|
52 |
+
msgid ""
|
53 |
+
"It looks like we cannot create a file locally to test the S3 permissions"
|
54 |
+
msgstr ""
|
55 |
+
|
56 |
+
#: classes/amazon-s3-and-cloudfront.php:845
|
57 |
+
msgid "Bucket Name:"
|
58 |
+
msgstr ""
|
59 |
+
|
60 |
+
#: classes/amazon-s3-and-cloudfront.php:846
|
61 |
+
msgid "Error creating bucket: "
|
62 |
+
msgstr ""
|
63 |
+
|
64 |
+
#: classes/amazon-s3-and-cloudfront.php:859
|
65 |
+
msgid "Cheatin' eh?"
|
66 |
+
msgstr ""
|
67 |
+
|
68 |
+
#: classes/as3cf-compatibility-check.php:25
|
69 |
+
msgid ""
|
70 |
+
"You can deactivate the Amazon S3 and CloudFront plugin to get rid of this "
|
71 |
+
"notice."
|
72 |
+
msgstr ""
|
73 |
+
|
74 |
+
#: classes/as3cf-compatibility-check.php:28
|
75 |
+
#, php-format
|
76 |
+
msgid ""
|
77 |
+
"Amazon S3 and CloudFront has been disabled as it requires the <a style="
|
78 |
+
"\"text-decoration:none;\" href=\"%s\">Amazon Web Services</a> "
|
79 |
+
"plugin."
|
80 |
+
msgstr ""
|
81 |
+
|
82 |
+
#: classes/as3cf-compatibility-check.php:31
|
83 |
+
msgid "It appears to be installed already."
|
84 |
+
msgstr ""
|
85 |
+
|
86 |
+
#: classes/as3cf-compatibility-check.php:33
|
87 |
+
msgctxt "Activate plugin"
|
88 |
+
msgid "Activate it now"
|
89 |
+
msgstr ""
|
90 |
+
|
91 |
+
#: classes/as3cf-compatibility-check.php:37
|
92 |
+
#, php-format
|
93 |
+
msgid "<a href=\"%s\">Install it</a> and activate."
|
94 |
+
msgstr ""
|
95 |
+
|
96 |
+
#: classes/as3cf-compatibility-check.php:48
|
97 |
+
#, php-format
|
98 |
+
msgid ""
|
99 |
+
"Amazon S3 and CloudFront has been disabled as it requires version %s or "
|
100 |
+
"later of the <a style=\"text-decoration:none;\" href=\"%s\">Amazon "
|
101 |
+
"Web Services</a> plugin."
|
102 |
+
msgstr ""
|
103 |
+
|
104 |
+
#: classes/as3cf-compatibility-check.php:51
|
105 |
+
#, php-format
|
106 |
+
msgid "You currently have version %s installed."
|
107 |
+
msgstr ""
|
108 |
+
|
109 |
+
#: classes/as3cf-compatibility-check.php:55
|
110 |
+
msgid "Update to the latest version"
|
111 |
+
msgstr ""
|
112 |
+
|
113 |
+
#: classes/as3cf-compatibility-check.php:66
|
114 |
+
#, php-format
|
115 |
+
msgid ""
|
116 |
+
"Amazon S3 and CloudFront has been disabled because it will not work with the "
|
117 |
+
"version of the Amazon Web Services plugin installed. Amazon "
|
118 |
+
"S3 and CloudFront %s or later is required."
|
119 |
+
msgstr ""
|
120 |
+
|
121 |
+
#: classes/as3cf-compatibility-check.php:70
|
122 |
+
msgid "Update Amazon S3 and CloudFront to the latest version"
|
123 |
+
msgstr ""
|
124 |
+
|
125 |
+
#: classes/as3cf-upgrade.php:89
|
126 |
+
#, php-format
|
127 |
+
msgid ""
|
128 |
+
"<strong>Running Metadata Update</strong> — We’re going through "
|
129 |
+
"all the Media Library items uploaded to S3 and updating the metadata with "
|
130 |
+
"the bucket region it is served from. This will allow us to serve your files "
|
131 |
+
"from the proper S3 region subdomain <span style=\"white-space:nowrap;\">(e."
|
132 |
+
"g. s3-us-west-2.amazonaws.com)</span>. This will be done quietly in the "
|
133 |
+
"background, processing a small batch of Media Library items every %d "
|
134 |
+
"minutes. There should be no noticeable impact on your server’s "
|
135 |
+
"performance."
|
136 |
+
msgstr ""
|
137 |
+
|
138 |
+
#: classes/as3cf-upgrade.php:90
|
139 |
+
msgid "Pause Update"
|
140 |
+
msgstr ""
|
141 |
+
|
142 |
+
#: classes/as3cf-upgrade.php:94
|
143 |
+
msgid ""
|
144 |
+
"<strong>Metadata Update Paused</strong> — Updating Media Library "
|
145 |
+
"metadata has been paused."
|
146 |
+
msgstr ""
|
147 |
+
|
148 |
+
#: classes/as3cf-upgrade.php:95
|
149 |
+
msgid "Restart Update"
|
150 |
+
msgstr ""
|
151 |
+
|
152 |
+
#: classes/as3cf-upgrade.php:99
|
153 |
+
msgid ""
|
154 |
+
"<strong>Error Updating Metadata</strong> — We ran into some errors "
|
155 |
+
"attempting to update the metadata for all your Media Library items that have "
|
156 |
+
"been uploaded to S3. Please check your error log for details."
|
157 |
+
msgstr ""
|
158 |
+
|
159 |
+
#: classes/as3cf-upgrade.php:100
|
160 |
+
msgid "Try Run It Again"
|
161 |
+
msgstr ""
|
162 |
+
|
163 |
+
#: classes/as3cf-upgrade.php:155
|
164 |
+
msgid "Every "
|
165 |
+
msgstr ""
|
166 |
+
|
167 |
+
#: view/settings.php:10
|
168 |
+
msgid "Error retrieving a list of your S3 buckets from AWS:"
|
169 |
+
msgstr ""
|
170 |
+
|
171 |
+
#: view/settings.php:21
|
172 |
+
msgid "Settings saved."
|
173 |
+
msgstr ""
|
174 |
+
|
175 |
+
#: view/settings.php:41
|
176 |
+
msgid "S3 Policy is Read-Only"
|
177 |
+
msgstr ""
|
178 |
+
|
179 |
+
#: view/settings.php:43
|
180 |
+
#, php-format
|
181 |
+
msgid ""
|
182 |
+
"You need to go to <a href=\"%s\">Identity and Access Management</a> in your "
|
183 |
+
"AWS console and manage the policy for the user you're using for this plugin. "
|
184 |
+
"Your policy should look something like the following:"
|
185 |
+
msgstr ""
|
186 |
+
|
187 |
+
#: view/settings.php:69
|
188 |
+
msgid "S3 Settings"
|
189 |
+
msgstr ""
|
190 |
+
|
191 |
+
#: view/settings.php:72
|
192 |
+
msgid "Select an S3 Bucket"
|
193 |
+
msgstr ""
|
194 |
+
|
195 |
+
#: view/settings.php:76
|
196 |
+
msgid "Create a new bucket..."
|
197 |
+
msgstr ""
|
198 |
+
|
199 |
+
#: view/settings.php:80
|
200 |
+
msgid "Bucket is setup for virtual hosting"
|
201 |
+
msgstr ""
|
202 |
+
|
203 |
+
#: view/settings.php:80
|
204 |
+
msgid "more info"
|
205 |
+
msgstr ""
|
206 |
+
|
207 |
+
#: view/settings.php:84
|
208 |
+
#, php-format
|
209 |
+
msgid ""
|
210 |
+
"Set a <a href=\"%s\" target=\"_blank\">far future HTTP expiration header</a> "
|
211 |
+
"for uploaded files <em>(recommended)</em>"
|
212 |
+
msgstr ""
|
213 |
+
|
214 |
+
#: view/settings.php:90
|
215 |
+
msgid "Object Path:"
|
216 |
+
msgstr ""
|
217 |
+
|
218 |
+
#: view/settings.php:98
|
219 |
+
msgid "CloudFront Settings"
|
220 |
+
msgstr ""
|
221 |
+
|
222 |
+
#: view/settings.php:100
|
223 |
+
msgid "Domain Name"
|
224 |
+
msgstr ""
|
225 |
+
|
226 |
+
#: view/settings.php:102
|
227 |
+
msgid "Leave blank if you aren’t using CloudFront."
|
228 |
+
msgstr ""
|
229 |
+
|
230 |
+
#: view/settings.php:109
|
231 |
+
msgid "Plugin Settings"
|
232 |
+
msgstr ""
|
233 |
+
|
234 |
+
#: view/settings.php:112
|
235 |
+
msgid "Copy files to S3 as they are uploaded to the Media Library"
|
236 |
+
msgstr ""
|
237 |
+
|
238 |
+
#: view/settings.php:116
|
239 |
+
msgid "Point file URLs to S3/CloudFront for files that have been copied to S3"
|
240 |
+
msgstr ""
|
241 |
+
|
242 |
+
#: view/settings.php:117
|
243 |
+
msgid ""
|
244 |
+
"When this is option unchecked, your Media Library images and other files "
|
245 |
+
"will be served from your server instead of S3/CloudFront. If any images were "
|
246 |
+
"removed from your server, they will be broken."
|
247 |
+
msgstr ""
|
248 |
+
|
249 |
+
#: view/settings.php:124
|
250 |
+
msgid ""
|
251 |
+
"Remove uploaded file from local filesystem once it has been copied to S3"
|
252 |
+
msgstr ""
|
253 |
+
|
254 |
+
#: view/settings.php:128
|
255 |
+
msgid "Always serve files over https (SSL)"
|
256 |
+
msgstr ""
|
257 |
+
|
258 |
+
#: view/settings.php:132
|
259 |
+
#, php-format
|
260 |
+
msgid ""
|
261 |
+
"Implement <a href=\"%s\">object versioning</a> by appending a timestamp to "
|
262 |
+
"the S3 file path"
|
263 |
+
msgstr ""
|
264 |
+
|
265 |
+
#: view/settings.php:136
|
266 |
+
msgid "Copy any HiDPI (@2x) images to S3 (works with WP Retina 2x plugin)"
|
267 |
+
msgstr ""
|
268 |
+
|
269 |
+
#: view/settings.php:142
|
270 |
+
msgid "Save Changes"
|
271 |
+
msgstr ""
|
272 |
+
|
273 |
+
#: view/sidebar.php:6
|
274 |
+
msgid "Pro Version?"
|
275 |
+
msgstr ""
|
276 |
+
|
277 |
+
#: view/sidebar.php:11
|
278 |
+
msgid ""
|
279 |
+
"We're working on a pro version that will include the following features:"
|
280 |
+
msgstr ""
|
281 |
+
|
282 |
+
#: view/sidebar.php:15
|
283 |
+
msgid "Copy existing Media Library to S3"
|
284 |
+
msgstr ""
|
285 |
+
|
286 |
+
#: view/sidebar.php:16
|
287 |
+
msgid "Serve theme JS & CSS from S3/CloudFront"
|
288 |
+
msgstr ""
|
289 |
+
|
290 |
+
#: view/sidebar.php:17
|
291 |
+
msgid ""
|
292 |
+
"WooCommerce & <abbr title=\"Easy Digital Downloads\">EDD</abbr> integration"
|
293 |
+
msgstr ""
|
294 |
+
|
295 |
+
#: view/sidebar.php:18
|
296 |
+
msgid "Awesome email support"
|
297 |
+
msgstr ""
|
298 |
+
|
299 |
+
#: view/sidebar.php:22
|
300 |
+
msgid "Your Name"
|
301 |
+
msgstr ""
|
302 |
+
|
303 |
+
#: view/sidebar.php:26
|
304 |
+
msgid "Your Email"
|
305 |
+
msgstr ""
|
306 |
+
|
307 |
+
#: view/sidebar.php:30
|
308 |
+
msgid "Send me news about a pro version"
|
309 |
+
msgstr ""
|
310 |
+
|
311 |
+
#: view/sidebar.php:34
|
312 |
+
msgid ""
|
313 |
+
"We promise we will not use your email for anything else and you can "
|
314 |
+
"unsubscribe with 1-click anytime."
|
315 |
+
msgstr ""
|
readme.txt
CHANGED
@@ -3,8 +3,8 @@ Contributors: bradt
|
|
3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5VPMGLLK94XJC
|
4 |
Tags: uploads, amazon, s3, mirror, admin, media, cdn, cloudfront
|
5 |
Requires at least: 3.5
|
6 |
-
Tested up to: 3.
|
7 |
-
Stable tag: 0.
|
8 |
License: GPLv3
|
9 |
|
10 |
Copies files to Amazon S3 as they are uploaded to the Media Library. Optionally configure Amazon CloudFront for faster delivery.
|
@@ -17,15 +17,26 @@ Uploading files *directly* to your S3 account is not currently supported by this
|
|
17 |
|
18 |
If you're adding this plugin to a site that's been around for a while, your existing media files will not be copied or served from S3. Only newly uploaded files will be copied and served from S3.
|
19 |
|
20 |
-
**
|
21 |
|
22 |
-
|
23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
which is a fork of [Amazon S3 for WordPress](http://wordpress.org/extend/plugins/tantan-s3/), also known as tantan-s3.*
|
25 |
|
26 |
== Installation ==
|
27 |
|
28 |
-
1. Install the required [Amazon Web Services plugin](
|
29 |
2. Follow the instructions to setup your AWS access keys
|
30 |
3. Install this plugin using WordPress' built-in installer
|
31 |
4. Access the *S3 and CloudFront* option under *AWS* and configure
|
@@ -42,15 +53,41 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
|
42 |
= 0.6.1 =
|
43 |
This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
44 |
|
|
|
|
|
|
|
45 |
== Changelog ==
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
= 0.6.1 - 2013-09-21 =
|
48 |
* WP.org download of Amazon Web Services plugin is giving a 404 Not Found, so directing people to download from Github instead
|
49 |
|
50 |
= 0.6 - 2013-09-20 =
|
51 |
* Complete rewrite
|
52 |
* Now requires PHP 5.3.3+
|
53 |
-
* Now requires the [Amazon Web Services plugin](
|
54 |
* Now works with multisite
|
55 |
* New Option: Custom S3 object path
|
56 |
* New Option: Always serve files over https (SSL)
|
@@ -62,6 +99,6 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
|
62 |
* Forked [Amazon S3 for WordPress with CloudFront](http://wordpress.org/extend/plugins/tantan-s3-cloudfront/)
|
63 |
* Cleaned up the UI to fit with today's WP UI
|
64 |
* Fixed issues causing error messages when WP_DEBUG is on
|
65 |
-
* [Delete files on S3 when deleting WP attachment](https://github.com/
|
66 |
-
* [Added filter to the get_attachment_url function](https://github.com/
|
67 |
-
* [Added function to get a temporary, secure download URL for private files](https://github.com/
|
3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5VPMGLLK94XJC
|
4 |
Tags: uploads, amazon, s3, mirror, admin, media, cdn, cloudfront
|
5 |
Requires at least: 3.5
|
6 |
+
Tested up to: 3.9
|
7 |
+
Stable tag: 0.7
|
8 |
License: GPLv3
|
9 |
|
10 |
Copies files to Amazon S3 as they are uploaded to the Media Library. Optionally configure Amazon CloudFront for faster delivery.
|
17 |
|
18 |
If you're adding this plugin to a site that's been around for a while, your existing media files will not be copied or served from S3. Only newly uploaded files will be copied and served from S3.
|
19 |
|
20 |
+
**Pro Version**
|
21 |
|
22 |
+
We’re working on a pro version that will include the following features:
|
23 |
+
|
24 |
+
* Copy existing Media Library to S3
|
25 |
+
* Serve theme JS & CSS from S3/CloudFront
|
26 |
+
* WooCommerce & EDD integration
|
27 |
+
* Awesome email support
|
28 |
+
|
29 |
+
[Sign up for news about the pro version](https://confirmsubscription.com/h/t/295CA85AEB94E879)
|
30 |
+
|
31 |
+
[Request features, report bugs, and submit pull requests on Github](https://github.com/deliciousbrains/wp-amazon-s3-and-cloudfront/issues)
|
32 |
+
|
33 |
+
*This plugin has been completely rewritten, but was originally a fork of
|
34 |
+
[Amazon S3 for WordPress with CloudFront](http://wordpress.org/extend/plugins/tantan-s3-cloudfront/)
|
35 |
which is a fork of [Amazon S3 for WordPress](http://wordpress.org/extend/plugins/tantan-s3/), also known as tantan-s3.*
|
36 |
|
37 |
== Installation ==
|
38 |
|
39 |
+
1. Install the required [Amazon Web Services plugin](http://wordpress.org/extend/plugins/amazon-web-services/) using WordPress' built-in installer
|
40 |
2. Follow the instructions to setup your AWS access keys
|
41 |
3. Install this plugin using WordPress' built-in installer
|
42 |
4. Access the *S3 and CloudFront* option under *AWS* and configure
|
53 |
= 0.6.1 =
|
54 |
This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
55 |
|
56 |
+
= 0.6.2 =
|
57 |
+
This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
58 |
+
|
59 |
== Changelog ==
|
60 |
|
61 |
+
= 0.7 - 2014-12-04 =
|
62 |
+
* New: Proper S3 region subdomain in URLs for buckets not in the US Standard region (e.g. https://s3-us-west-2.amazonaws.com/...)
|
63 |
+
* New: Update all existing attachment meta with bucket region (automatically runs in the background)
|
64 |
+
* New: Get secure URL for different image sizes (iamzozo)
|
65 |
+
* New: S3 bucket can be set with constant in wp-config.php (dberube)
|
66 |
+
* New: Filter for allowing/disallowing file types: `as3cf_allowed_mime_types`
|
67 |
+
* New: Filter to cancel upload to S3 for any reason: `as3cf_pre_update_attachment_metadata`
|
68 |
+
* New: Sidebar with email opt-in
|
69 |
+
* Improvement: Show warning when S3 policy is read-only
|
70 |
+
* Improvement: Tooltip added to clarify option
|
71 |
+
* Improvement: Move object versioning option to make it clear it does not require CloudFront
|
72 |
+
* Improvement: By default only allow file types in `get_allowed_mime_types()` to be uploaded to S3
|
73 |
+
* Improvement: Compatibility with WPML Media plugin
|
74 |
+
* Bug Fix: Edited images not removed on S3 when restoring image and IMAGE_EDIT_OVERWRITE true
|
75 |
+
* Bug Fix: File names with certain characters broken not working
|
76 |
+
* Bug Fix: Edited image uploaded to incorrect month folder
|
77 |
+
* Bug Fix: When creating a new bucket the bucket select box appears empty on success
|
78 |
+
* Bug Fix: SSL not working in regions other than US Standard
|
79 |
+
* Bug Fix: 'Error uploading' and 'Error removing local file' messages when editing an image
|
80 |
+
* Bug Fix: Upload and delete failing when bucket is non-US-region and bucket name contains dot
|
81 |
+
* Bug Fix: S3 file overwritten when file with same name uploaded and local file removed (dataferret)
|
82 |
+
* Bug Fix: Manually resized images not uploaded (gmauricio)
|
83 |
+
|
84 |
= 0.6.1 - 2013-09-21 =
|
85 |
* WP.org download of Amazon Web Services plugin is giving a 404 Not Found, so directing people to download from Github instead
|
86 |
|
87 |
= 0.6 - 2013-09-20 =
|
88 |
* Complete rewrite
|
89 |
* Now requires PHP 5.3.3+
|
90 |
+
* Now requires the [Amazon Web Services plugin](http://wordpress.org/extend/plugins/amazon-web-services/) which contains the latest PHP libraries from Amazon
|
91 |
* Now works with multisite
|
92 |
* New Option: Custom S3 object path
|
93 |
* New Option: Always serve files over https (SSL)
|
99 |
* Forked [Amazon S3 for WordPress with CloudFront](http://wordpress.org/extend/plugins/tantan-s3-cloudfront/)
|
100 |
* Cleaned up the UI to fit with today's WP UI
|
101 |
* Fixed issues causing error messages when WP_DEBUG is on
|
102 |
+
* [Delete files on S3 when deleting WP attachment](https://github.com/deliciousbrains/wp-amazon-s3-and-cloudfront/commit/e777cd49a4b6999f999bd969241fb24cbbcece60)
|
103 |
+
* [Added filter to the get_attachment_url function](https://github.com/deliciousbrains/wp-amazon-s3-and-cloudfront/commit/bbe1aed5c2ae900e9ba1b16ba6806c28ab8e2f1c)
|
104 |
+
* [Added function to get a temporary, secure download URL for private files](https://github.com/deliciousbrains/wp-amazon-s3-and-cloudfront/commit/11f46ec2714d34907009e37ad3b97f4421aefed3)
|
view/error-fatal.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="aws-content as3cf-error">
|
2 |
+
|
3 |
+
<?php $this->render_view( 'error', compact( 'message' ) ); ?>
|
4 |
+
|
5 |
+
</div>
|
view/error.php
CHANGED
@@ -1,7 +1,3 @@
|
|
1 |
-
<div class="
|
2 |
-
|
3 |
-
|
4 |
-
<p><?php echo $error->get_error_message(); ?></p>
|
5 |
-
</div>
|
6 |
-
|
7 |
-
</div>
|
1 |
+
<div class="error">
|
2 |
+
<p><?php echo $message; ?></p>
|
3 |
+
</div>
|
|
|
|
|
|
|
|
view/notice.php
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
<div class="updated as3cf-notice">
|
2 |
+
<p><?php echo $message; ?></p>
|
3 |
+
</div>
|
view/settings.php
CHANGED
@@ -23,6 +23,40 @@ if ( isset( $_GET['updated'] ) ) {
|
|
23 |
</div>
|
24 |
<?php
|
25 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
?>
|
27 |
|
28 |
<form method="post">
|
@@ -37,13 +71,13 @@ if ( isset( $_GET['updated'] ) ) {
|
|
37 |
<select name="bucket" class="bucket">
|
38 |
<option value="">-- <?php _e( 'Select an S3 Bucket', 'as3cf' ); ?> --</option>
|
39 |
<?php if ( is_array( $buckets ) ) foreach ( $buckets as $bucket ): ?>
|
40 |
-
|
41 |
<?php endforeach;?>
|
42 |
<option value="new"><?php _e( 'Create a new bucket...', 'as3cf' ); ?></option>
|
43 |
</select><br />
|
44 |
|
45 |
<input type="checkbox" name="virtual-host" value="1" id="virtual-host" <?php echo $this->get_setting( 'virtual-host' ) ? 'checked="checked" ' : '';?> />
|
46 |
-
<label for="virtual-host"> <?php _e( 'Bucket is setup for virtual hosting', 'as3cf' ); ?></label> (<a href="http://docs.
|
47 |
<br />
|
48 |
|
49 |
<input type="checkbox" name="expires" value="1" id="expires" <?php echo $this->get_setting( 'expires' ) ? 'checked="checked" ' : ''; ?> />
|
@@ -67,8 +101,6 @@ if ( isset( $_GET['updated'] ) ) {
|
|
67 |
<input type="text" name="cloudfront" value="<?php echo esc_attr( $this->get_setting( 'cloudfront' ) ); ?>" size="50" />
|
68 |
<p class="description"><?php _e( 'Leave blank if you aren’t using CloudFront.', 'as3cf' ); ?></p>
|
69 |
|
70 |
-
<input type="checkbox" name="object-versioning" value="1" id="object-versioning" <?php echo $this->get_setting( 'object-versioning' ) ? 'checked="checked" ' : ''; ?> />
|
71 |
-
<label for="object-versioning"> <?php printf( __( 'Implement <a href="%s">object versioning</a> by appending a timestamp to the S3 file path', 'as3cf' ), 'http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ReplacingObjects.html' ); ?></label>
|
72 |
</td>
|
73 |
</tr>
|
74 |
|
@@ -81,7 +113,11 @@ if ( isset( $_GET['updated'] ) ) {
|
|
81 |
<br />
|
82 |
|
83 |
<input type="checkbox" name="serve-from-s3" value="1" id="serve-from-s3" <?php echo $this->get_setting( 'serve-from-s3' ) ? 'checked="checked" ' : ''; ?> />
|
84 |
-
<label for="serve-from-s3"> <?php _e( 'Point file URLs to S3/CloudFront for files that have been copied to S3', 'as3cf' );
|
|
|
|
|
|
|
|
|
85 |
<br />
|
86 |
|
87 |
<input type="checkbox" name="remove-local-file" value="1" id="remove-local-file" <?php echo $this->get_setting( 'remove-local-file' ) ? 'checked="checked" ' : ''; ?> />
|
@@ -92,6 +128,10 @@ if ( isset( $_GET['updated'] ) ) {
|
|
92 |
<label for="force-ssl"> <?php _e( 'Always serve files over https (SSL)', 'as3cf' ); ?></label>
|
93 |
<br />
|
94 |
|
|
|
|
|
|
|
|
|
95 |
<input type="checkbox" name="hidpi-images" value="1" id="hidpi-images" <?php echo $this->get_setting( 'hidpi-images' ) ? 'checked="checked" ' : ''; ?> />
|
96 |
<label for="hidpi-images"> <?php _e( 'Copy any HiDPI (@2x) images to S3 (works with WP Retina 2x plugin)', 'as3cf' ); ?></label>
|
97 |
|
@@ -106,4 +146,6 @@ if ( isset( $_GET['updated'] ) ) {
|
|
106 |
|
107 |
</form>
|
108 |
|
|
|
|
|
109 |
</div>
|
23 |
</div>
|
24 |
<?php
|
25 |
}
|
26 |
+
|
27 |
+
$can_write = true;
|
28 |
+
if ( ! is_wp_error( $buckets ) && is_array( $buckets ) ) {
|
29 |
+
$can_write = $this->check_write_permission( $buckets[0]['Name'] );
|
30 |
+
// catch any file system issues
|
31 |
+
if ( is_wp_error( $can_write ) ) {
|
32 |
+
$this->render_view( 'error', array( 'error' => $can_write ) );
|
33 |
+
return;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
// display a error message if the user does not have write permission to S3
|
37 |
+
if ( ! $can_write ) : ?>
|
38 |
+
<div class="error">
|
39 |
+
<p>
|
40 |
+
<strong>
|
41 |
+
<?php _e( 'S3 Policy is Read-Only', 'as3cf' ); ?>
|
42 |
+
</strong>—
|
43 |
+
<?php printf( __( 'You need to go to <a href="%s">Identity and Access Management</a> in your AWS console and manage the policy for the user you\'re using for this plugin. Your policy should look something like the following:', 'as3cf' ), 'https://console.aws.amazon.com/iam/home' ); ?>
|
44 |
+
</p>
|
45 |
+
<pre><code>{
|
46 |
+
"Version": "2012-10-17",
|
47 |
+
"Statement": [
|
48 |
+
{
|
49 |
+
"Effect": "Allow",
|
50 |
+
"Action": "s3:*",
|
51 |
+
"Resource": "*"
|
52 |
+
}
|
53 |
+
]
|
54 |
+
}</code></pre>
|
55 |
+
</div>
|
56 |
+
<?php
|
57 |
+
// don't show the rest of the settings if cannot write
|
58 |
+
return;
|
59 |
+
endif;
|
60 |
?>
|
61 |
|
62 |
<form method="post">
|
71 |
<select name="bucket" class="bucket">
|
72 |
<option value="">-- <?php _e( 'Select an S3 Bucket', 'as3cf' ); ?> --</option>
|
73 |
<?php if ( is_array( $buckets ) ) foreach ( $buckets as $bucket ): ?>
|
74 |
+
<option value="<?php echo esc_attr( $bucket['Name'] ); ?>" <?php echo $bucket['Name'] == $this->get_setting( 'bucket' ) ? 'selected="selected"' : ''; ?>><?php echo esc_html( $bucket['Name'] ); ?></option>
|
75 |
<?php endforeach;?>
|
76 |
<option value="new"><?php _e( 'Create a new bucket...', 'as3cf' ); ?></option>
|
77 |
</select><br />
|
78 |
|
79 |
<input type="checkbox" name="virtual-host" value="1" id="virtual-host" <?php echo $this->get_setting( 'virtual-host' ) ? 'checked="checked" ' : '';?> />
|
80 |
+
<label for="virtual-host"> <?php _e( 'Bucket is setup for virtual hosting', 'as3cf' ); ?></label> (<a href="http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html"><?php _e( 'more info', 'as3cf' ); ?></a>)
|
81 |
<br />
|
82 |
|
83 |
<input type="checkbox" name="expires" value="1" id="expires" <?php echo $this->get_setting( 'expires' ) ? 'checked="checked" ' : ''; ?> />
|
101 |
<input type="text" name="cloudfront" value="<?php echo esc_attr( $this->get_setting( 'cloudfront' ) ); ?>" size="50" />
|
102 |
<p class="description"><?php _e( 'Leave blank if you aren’t using CloudFront.', 'as3cf' ); ?></p>
|
103 |
|
|
|
|
|
104 |
</td>
|
105 |
</tr>
|
106 |
|
113 |
<br />
|
114 |
|
115 |
<input type="checkbox" name="serve-from-s3" value="1" id="serve-from-s3" <?php echo $this->get_setting( 'serve-from-s3' ) ? 'checked="checked" ' : ''; ?> />
|
116 |
+
<label for="serve-from-s3"> <?php _e( 'Point file URLs to S3/CloudFront for files that have been copied to S3', 'as3cf' ); ?>
|
117 |
+
<span class="tooltip" data-tooltip="<?php _e( 'When this is option unchecked, your Media Library images and other files will be served from your server instead of S3/CloudFront. If any images were removed from your server, they will be broken.', 'as3cf' ); ?>">
|
118 |
+
<span class="dashicons dashicons-editor-help"></span>
|
119 |
+
</span>
|
120 |
+
</label>
|
121 |
<br />
|
122 |
|
123 |
<input type="checkbox" name="remove-local-file" value="1" id="remove-local-file" <?php echo $this->get_setting( 'remove-local-file' ) ? 'checked="checked" ' : ''; ?> />
|
128 |
<label for="force-ssl"> <?php _e( 'Always serve files over https (SSL)', 'as3cf' ); ?></label>
|
129 |
<br />
|
130 |
|
131 |
+
<input type="checkbox" name="object-versioning" value="1" id="object-versioning" <?php echo $this->get_setting( 'object-versioning' ) ? 'checked="checked" ' : ''; ?> />
|
132 |
+
<label for="object-versioning"> <?php printf( __( 'Implement <a href="%s">object versioning</a> by appending a timestamp to the S3 file path', 'as3cf' ), 'http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ReplacingObjects.html' ); ?></label>
|
133 |
+
<br />
|
134 |
+
|
135 |
<input type="checkbox" name="hidpi-images" value="1" id="hidpi-images" <?php echo $this->get_setting( 'hidpi-images' ) ? 'checked="checked" ' : ''; ?> />
|
136 |
<label for="hidpi-images"> <?php _e( 'Copy any HiDPI (@2x) images to S3 (works with WP Retina 2x plugin)', 'as3cf' ); ?></label>
|
137 |
|
146 |
|
147 |
</form>
|
148 |
|
149 |
+
<?php $this->render_view( 'sidebar' ); ?>
|
150 |
+
|
151 |
</div>
|
view/sidebar.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="as3cf-sidebar">
|
2 |
+
|
3 |
+
<div class="as3cf-banner"><img src="<?php echo plugins_url( 'assets/img/snail.jpg', $this->plugin_file_path ); ?>" width="292" height="165" alt="" /></div>
|
4 |
+
|
5 |
+
<form method="post" action="https://deliciousbrains.createsend.com/t/t/s/dlihik/" target="_blank" class="subscribe block">
|
6 |
+
<h2><?php _e( 'Pro Version?', 'as3cf' ); ?></h2>
|
7 |
+
|
8 |
+
<?php $user = wp_get_current_user(); ?>
|
9 |
+
|
10 |
+
<p class="intro">
|
11 |
+
<?php echo wptexturize( __( "We're working on a pro version that will include the following features:", 'as3cf' ) ); ?>
|
12 |
+
</p>
|
13 |
+
|
14 |
+
<ul>
|
15 |
+
<li><?php echo wptexturize( __( 'Copy existing Media Library to S3', 'as3cf' ) ); ?></li>
|
16 |
+
<li><?php echo wptexturize( __( 'Serve theme JS & CSS from S3/CloudFront', 'as3cf' ) ); ?></li>
|
17 |
+
<li><?php echo wptexturize( __( 'WooCommerce & <abbr title="Easy Digital Downloads">EDD</abbr> integration', 'as3cf' ) ); ?></li>
|
18 |
+
<li><?php echo wptexturize( __( 'Awesome email support', 'as3cf' ) ); ?></li>
|
19 |
+
</ul>
|
20 |
+
|
21 |
+
<div class="field notify-name">
|
22 |
+
<input type="text" name="cm-name" value="<?php echo trim( esc_attr( $user->first_name ) . ' ' . esc_attr( $user->last_name ) ); ?>" placeholder="<?php _e( 'Your Name', 'as3cf' ); ?>"/>
|
23 |
+
</div>
|
24 |
+
|
25 |
+
<div class="field notify-email">
|
26 |
+
<input type="email" name="cm-dlihik-dlihik" value="<?php echo esc_attr( $user->user_email ); ?>" placeholder="<?php _e( 'Your Email', 'as3cf' ); ?>"/>
|
27 |
+
</div>
|
28 |
+
|
29 |
+
<div class="field submit-button">
|
30 |
+
<input type="submit" class="button" value="<?php _e( 'Send me news about a pro version', 'as3cf' ); ?>"/>
|
31 |
+
</div>
|
32 |
+
|
33 |
+
<p class="promise">
|
34 |
+
<?php _e( 'We promise we will not use your email for anything else and you can unsubscribe with 1-click anytime.', 'as3cf' ); ?>
|
35 |
+
</p>
|
36 |
+
</form>
|
37 |
+
|
38 |
+
<div class="block credits">
|
39 |
+
<h4>Created & maintained by</h4>
|
40 |
+
<ul>
|
41 |
+
<li>
|
42 |
+
<a href="http://profiles.wordpress.org/bradt/">
|
43 |
+
<img src="//www.gravatar.com/avatar/e538ca4cb34839d4e5e3ccf20c37c67b?size=64" alt="" width="32" height="32">
|
44 |
+
<span>Brad Touesnard</span>
|
45 |
+
</a>
|
46 |
+
</li>
|
47 |
+
<li>
|
48 |
+
<a href="https://deliciousbrains.com/?utm_source=insideplugin&utm_medium=web&utm_content=sidebar&utm_campaign=as3cf">
|
49 |
+
<img src="//www.gravatar.com/avatar/e62fc2e9c8d9fc6edd4fea5339036a91?size=64" alt="" width="32" height="32">
|
50 |
+
<span>Delicious Brains Inc.</span>
|
51 |
+
</a>
|
52 |
+
</li>
|
53 |
+
</ul>
|
54 |
+
</div>
|
55 |
+
</div>
|
wordpress-s3.php
CHANGED
@@ -4,8 +4,11 @@ Plugin Name: Amazon S3 and CloudFront
|
|
4 |
Plugin URI: http://wordpress.org/extend/plugins/amazon-s3-and-cloudfront/
|
5 |
Description: Automatically copies media uploads to Amazon S3 for storage and delivery. Optionally configure Amazon CloudFront for even faster delivery.
|
6 |
Author: Brad Touesnard
|
7 |
-
Version: 0.
|
8 |
Author URI: http://bradt.ca
|
|
|
|
|
|
|
9 |
|
10 |
// Copyright (c) 2013 Brad Touesnard. All rights reserved.
|
11 |
//
|
@@ -23,36 +26,30 @@ Author URI: http://bradt.ca
|
|
23 |
// Then completely rewritten.
|
24 |
*/
|
25 |
|
26 |
-
|
27 |
-
if ( class_exists( 'Amazon_Web_Services' ) || !is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
|
28 |
-
return;
|
29 |
-
}
|
30 |
|
31 |
-
|
32 |
-
|
|
|
33 |
|
34 |
-
|
35 |
-
|
36 |
-
if ( file_exists( WP_PLUGIN_DIR . '/amazon-web-services/amazon-web-services.php' ) ) {
|
37 |
-
$activate_url = wp_nonce_url( 'plugins.php?action=activate&plugin=amazon-web-services/amazon-web-services.php', 'activate-plugin_amazon-web-services/amazon-web-services.php' );
|
38 |
-
$msg .= sprintf( __( 'It appears to already be installed. <a href="%s">Click here to activate it.</a>', 'as3cf' ), $activate_url );
|
39 |
-
}
|
40 |
-
else {
|
41 |
-
$download_url = 'https://github.com/deliciousbrains/wp-amazon-web-services/releases/download/v0.1/amazon-web-services-0.1.zip';
|
42 |
-
$msg .= sprintf( __( '<a href="%s">Click here to download a zip of the latest version.</a> Then install and activate it. ', 'as3cf' ), $download_url );
|
43 |
-
}
|
44 |
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
}
|
49 |
-
|
50 |
-
add_action( 'plugins_loaded', 'as3cf_check_required_plugin' );
|
51 |
|
52 |
function as3cf_init( $aws ) {
|
53 |
-
|
54 |
-
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
-
add_action( 'aws_init', 'as3cf_init' );
|
4 |
Plugin URI: http://wordpress.org/extend/plugins/amazon-s3-and-cloudfront/
|
5 |
Description: Automatically copies media uploads to Amazon S3 for storage and delivery. Optionally configure Amazon CloudFront for even faster delivery.
|
6 |
Author: Brad Touesnard
|
7 |
+
Version: 0.7
|
8 |
Author URI: http://bradt.ca
|
9 |
+
Network: True
|
10 |
+
Text Domain: as3cf
|
11 |
+
Domain Path: /languages/
|
12 |
|
13 |
// Copyright (c) 2013 Brad Touesnard. All rights reserved.
|
14 |
//
|
26 |
// Then completely rewritten.
|
27 |
*/
|
28 |
|
29 |
+
$GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] = '0.7';
|
|
|
|
|
|
|
30 |
|
31 |
+
$GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['supported_addon_versions'] = array(
|
32 |
+
'amazon-s3-and-cloudfront-edd' => '1.0',
|
33 |
+
);
|
34 |
|
35 |
+
$aws_plugin_version_required = '0.2';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
+
require dirname( __FILE__ ) . '/classes/as3cf-compatibility-check.php';
|
38 |
+
global $as3cf_compat_check;
|
39 |
+
$as3cf_compat_check = new AS3CF_Compatibility_Check( __FILE__, $aws_plugin_version_required );
|
|
|
|
|
|
|
40 |
|
41 |
function as3cf_init( $aws ) {
|
42 |
+
global $as3cf_compat_check;
|
43 |
+
if ( ! $as3cf_compat_check->is_compatible() ) {
|
44 |
+
return;
|
45 |
+
}
|
46 |
+
|
47 |
+
global $as3cf;
|
48 |
+
$abspath = dirname( __FILE__ );
|
49 |
+
require_once $abspath . '/include/functions.php';
|
50 |
+
require_once $abspath . '/classes/as3cf-upgrade.php';
|
51 |
+
require_once $abspath . '/classes/amazon-s3-and-cloudfront.php';
|
52 |
+
$as3cf = new Amazon_S3_And_CloudFront( __FILE__, $aws );
|
53 |
}
|
54 |
|
55 |
+
add_action( 'aws_init', 'as3cf_init' );
|