WP Offload S3 Lite - Version 0.5

Version Description

  • 2013-01-29 =
  • Forked Amazon S3 for WordPress with CloudFront
  • Cleaned up the UI to fit with today's WP UI
  • Fixed issues causing error messages when WP_DEBUG is on
  • Delete files on S3 when deleting WP attachment
  • Added filter to the get_attachment_url function
  • Added function to get a temporary, secure download URL for private files
Download this release

Release Info

Developer bradt
Plugin Icon 128x128 WP Offload S3 Lite
Version 0.5
Comparing to
See all releases

Version 0.5

Files changed (41) hide show
  1. lib/curl.php +211 -0
  2. readme.txt +44 -0
  3. screenshot-1.gif +0 -0
  4. screenshot-2.jpg +0 -0
  5. wordpress-s3.php +48 -0
  6. wordpress-s3/admin-options.html +218 -0
  7. wordpress-s3/admin-tab-head.html +32 -0
  8. wordpress-s3/admin-tab.html +98 -0
  9. wordpress-s3/admin-tab.js +59 -0
  10. wordpress-s3/admin-version-error.html +58 -0
  11. wordpress-s3/class-plugin-public.php +94 -0
  12. wordpress-s3/class-plugin.php +496 -0
  13. wordpress-s3/config-sample.php +15 -0
  14. wordpress-s3/database.png +0 -0
  15. wordpress-s3/index.php +1 -0
  16. wordpress-s3/lib.s3.php +397 -0
  17. wordpress-s3/styles/add.png +0 -0
  18. wordpress-s3/styles/arrow_left.png +0 -0
  19. wordpress-s3/styles/arrow_refresh.png +0 -0
  20. wordpress-s3/styles/arrow_right.png +0 -0
  21. wordpress-s3/styles/cancel.png +0 -0
  22. wordpress-s3/styles/compress.png +0 -0
  23. wordpress-s3/styles/film.png +0 -0
  24. wordpress-s3/styles/folder.gif +0 -0
  25. wordpress-s3/styles/folder_add.png +0 -0
  26. wordpress-s3/styles/page.png +0 -0
  27. wordpress-s3/styles/page_code.png +0 -0
  28. wordpress-s3/styles/page_excel.png +0 -0
  29. wordpress-s3/styles/page_white.png +0 -0
  30. wordpress-s3/styles/page_white_acrobat.png +0 -0
  31. wordpress-s3/styles/page_white_excel.png +0 -0
  32. wordpress-s3/styles/page_white_php.png +0 -0
  33. wordpress-s3/styles/page_white_powerpoint.png +0 -0
  34. wordpress-s3/styles/page_white_text.png +0 -0
  35. wordpress-s3/styles/page_white_word.png +0 -0
  36. wordpress-s3/styles/page_white_zip.png +0 -0
  37. wordpress-s3/styles/page_word.png +0 -0
  38. wordpress-s3/styles/photo.png +0 -0
  39. wordpress-s3/styles/picture.png +0 -0
  40. wordpress-s3/styles/sound.png +0 -0
  41. wordpress-s3/styles/styles.css +189 -0
lib/curl.php ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ This is a clone of the PEAR HTTP/Request class object. It uses libcurl to do the networking stuff.
4
+ Should also work with the HTTPS protocol
5
+
6
+ Important: Not every method has been ported, just the ones that were needed.
7
+
8
+ $Revision: 66280 $
9
+ $Date: 2008-09-25 15:28:23 +0000 (Thu, 25 Sep 2008) $
10
+ $URL: https://photo-album.googlecode.com/svn/trunk/tantan-flickr/lib/curl.php $
11
+ */
12
+
13
+ class TanTanHTTPRequestCurl {
14
+ var $curl;
15
+ var $postData;
16
+ var $cookies;
17
+ var $raw;
18
+ var $response;
19
+ var $headers;
20
+ var $url;
21
+
22
+ function TanTanHTTPRequestCurl($url = '', $params = array()) {
23
+ $this->curl = curl_init();
24
+ $this->postData = array();
25
+ $this->cookies = array();
26
+ $this->headers = array();
27
+ if (!empty($url)) {
28
+ $this->setURL($url);
29
+ } else {
30
+ $this->setURL(false);
31
+ }
32
+ foreach ($params as $key => $value) {
33
+ $this->{'_' . $key} = $value;
34
+ }
35
+
36
+ $this->addHeader('Connection', 'close');
37
+
38
+ // We don't do keep-alives by default
39
+ $this->addHeader('Connection', 'close');
40
+
41
+ // Basic authentication
42
+ if (!empty($this->_user)) {
43
+ $this->addHeader('Authorization', 'Basic ' . base64_encode($this->_user . ':' . $this->_pass));
44
+ }
45
+
46
+ // Proxy authentication (see bug #5913)
47
+ if (!empty($this->_proxy_user)) {
48
+ $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass));
49
+ }
50
+
51
+ }
52
+
53
+ function addHeader($header, $value) {
54
+ $this->headers[$header] = $value;
55
+ }
56
+
57
+ function setMethod($method) {
58
+
59
+ // setting default values for constants if they're not present
60
+ if ( !defined('HTTP_REQUEST_METHOD_PUT') ) define('HTTP_REQUEST_METHOD_PUT', null);
61
+ if ( !defined('HTTP_REQUEST_METHOD_POST') ) define('HTTP_REQUEST_METHOD_POST', null);
62
+
63
+ switch ($method) {
64
+ case 'DELETE':
65
+ curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
66
+ break;
67
+ case HTTP_REQUEST_METHOD_PUT:
68
+ case 'PUT':
69
+ curl_setopt($this->curl, CURLOPT_PUT, true);
70
+ //CURLOPT_INFILE CURLOPT_INFILESIZE
71
+ break;
72
+ case HTTP_REQUEST_METHOD_POST:
73
+ case 'POST':
74
+ curl_setopt($this->curl, CURLOPT_POST, true);
75
+ break;
76
+ default:
77
+ case 'GET':
78
+ curl_setopt($this->curl, CURLOPT_HTTPGET, true);
79
+ break;
80
+ case 'HEAD':
81
+ curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
82
+ break;
83
+ }
84
+ }
85
+ function setURL($url) {
86
+ $this->url = $url;
87
+ }
88
+ function addPostData($name, $value) {
89
+ $this->postData[$name] = $value;
90
+ }
91
+ function addCookie($name, $value) {
92
+ $this->cookies[$name] = array('name' => $name, 'value' => $value);
93
+ }
94
+ function sendRequest() {
95
+ $headers = array(
96
+ "Accept: *.*",
97
+ );
98
+
99
+ foreach ($this->headers as $k=>$h) {
100
+ $headers[] = "$k: $h";
101
+ }
102
+
103
+ if (count($this->cookies) > 0) {
104
+ $cookieVars = '';
105
+ foreach ($this->cookies as $cookie) {
106
+ //$headers[] = "Cookie: ".$cookie['name'].'='.$cookie['value'];
107
+ $cookieVars .= ''.$cookie['name'].'='.$cookie['value'].'; ';
108
+ }
109
+ curl_setopt($this->curl, CURLOPT_COOKIE, $cookieVars);
110
+ //print_r($cookieVars);
111
+ }
112
+
113
+ if (count($this->postData) > 0) { // if a POST
114
+ $postVars = '';
115
+ foreach ($this->postData as $key=>$value) {
116
+ $postVars .= $key.'='.urlencode($value).'&';
117
+ }
118
+ // *** TODO ***
119
+ // weird, libcurl doesnt seem to POST correctly
120
+ curl_setopt($this->curl, CURLOPT_POST, true);
121
+ curl_setopt($this->curl, CURLOPT_POSTFIELDS, $postVars);
122
+
123
+ //curl_setopt($this->curl, CURLOPT_HTTPGET, true);
124
+ //$this->url .= '?'.$postVars;
125
+
126
+
127
+ } else {
128
+ curl_setopt($this->curl, CURLOPT_HTTPGET, true);
129
+ }
130
+ curl_setopt($this->curl, CURLOPT_URL, $this->url);
131
+ curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, false);
132
+ curl_setopt($this->curl, CURLOPT_HEADER, true);
133
+ curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers);
134
+ curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
135
+ curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false);
136
+ $this->raw = curl_exec($this->curl);
137
+ $this->response = $this->_parseResponse($this->raw);
138
+ return true; // hmm no error checking for now
139
+ }
140
+
141
+ function getResponseHeader($header=false) {
142
+ if ($header) {
143
+ return $this->response['header'][$header];
144
+ } else {
145
+ return $this->response['header'];
146
+ }
147
+ }
148
+ function getResponseCookies() {
149
+ $hdrCookies = array();
150
+ foreach ($this->response['header'] as $key => $value) {
151
+ if (strtolower($key) == 'set-cookie') {
152
+ $hdrCookies = array_merge($hdrCookies, explode("\n", $value));
153
+ }
154
+ }
155
+ //$hdrCookies = explode("\n", $this->response['header']['Set-Cookie']);
156
+ $cookies = array();
157
+
158
+ foreach ($hdrCookies as $cookie) {
159
+ if ($cookie) {
160
+ list($name, $value) = explode('=', $cookie, 2);
161
+ list($value, $domain, $path, $expires) = explode(';', $value);
162
+ $cookies[$name] = array('name' => $name, 'value' => $value);
163
+ }
164
+ }
165
+ return $cookies;
166
+ }
167
+ function getResponseBody() {
168
+ return $this->response['body'];
169
+ }
170
+ function getResponseCode() {
171
+ return $this->response['code'];
172
+ }
173
+ function getResponseRaw() {
174
+ return $this->raw;
175
+ }
176
+ function clearPostData($var=false) {
177
+ if (!$var) {
178
+ $this->postData = array();
179
+ } else {
180
+ unset($this->postData[$var]);
181
+ }
182
+ }
183
+
184
+ function _parseResponse($this_response) {
185
+ if (substr_count($this_response, 'HTTP/1.') > 1) { // yet another weird bug. CURL seems to be appending response bodies together
186
+ $chunks = preg_split('@(HTTP/[0-9]\.[0-9] [0-9]{3}.*\n)@', $this_response, -1, PREG_SPLIT_DELIM_CAPTURE);
187
+ $this_response = array_pop($chunks);
188
+ $this_response = array_pop($chunks) . $this_response;
189
+
190
+ }
191
+
192
+ list($response_headers, $response_body) = explode("\r\n\r\n", $this_response, 2);
193
+ $response_header_lines = explode("\r\n", $response_headers);
194
+
195
+ $http_response_line = array_shift($response_header_lines);
196
+ if (preg_match('@^HTTP/[0-9]\.[0-9] 100@',$http_response_line, $matches)) {
197
+ return $this->_parseResponse($response_body);
198
+ } else if(preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@',$http_response_line, $matches)) {
199
+ $response_code = $matches[1];
200
+ }
201
+ $response_header_array = array();
202
+ foreach($response_header_lines as $header_line) {
203
+ list($header,$value) = explode(': ', $header_line, 2);
204
+ if ( isset( $response_header_array[$header] ) ) {
205
+ $response_header_array[$header] .= $value."\n";
206
+ }
207
+ }
208
+ return array("code" => $response_code, "header" => $response_header_array, "body" => $response_body);
209
+ }
210
+ }
211
+ ?>
readme.txt ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Amazon S3 and Cloudfront ===
2
+ 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: 2.3
6
+ Tested up to: 3.5.1
7
+ Stable tag: 0.5
8
+ License: GPLv3
9
+
10
+ Automatically copies media uploads to Amazon S3 for storage and delivery. Optionally configure Amazon CloudFront for even faster delivery.
11
+
12
+ == Description ==
13
+
14
+ This plugin automatically copies images, videos, documents, and any other media added through WordPress' media uploader to [Amazon Simple Storage Service](http://aws.amazon.com/s3/) (S3). It then automatically replaces the URL to each media file with their respective S3 URL or, if you have configured [Amazon CloudFront](http://aws.amazon.com/cloudfront/), the respective CloudFront URL. Image thumbnails are also copied to S3 and delivered through S3/CloudFront.
15
+
16
+ Uploading files *directly* to your S3 account is not currently supported by this plugin. Also, 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.
17
+
18
+ You'll also find a new icon next to the "Add Media" button when editing a post. This allows you to easily browse and manage files in S3.
19
+
20
+ **Request features, report bugs, and submit pull requests on [Github](https://github.com/bradt/wp-tantan-s3/)**
21
+
22
+ *This plugin is a fork of
23
+ [Amazon S3 for WordPress with CloudFront](http://wordpress.org/extend/plugins/tantan-s3-cloudfront/)
24
+ which is a fork of [Amazon S3 for WordPress](http://wordpress.org/extend/plugins/tantan-s3/), also known as tantan-s3. See the Change Log to see what has been done so far.*
25
+
26
+ == Installation ==
27
+
28
+ 1. Use WordPress' built-in installer
29
+ 2. Access the Amazon S3 option under Settings and configure your Amazon details
30
+
31
+ == Screenshots ==
32
+
33
+ 1. The settings screen for the plugin
34
+ 2. Browse files in a Amazon S3 bucket
35
+
36
+ == Changelog ==
37
+
38
+ = 0.5 - 2013-01-29 =
39
+ * Forked [Amazon S3 for WordPress with CloudFront](http://wordpress.org/extend/plugins/tantan-s3-cloudfront/)
40
+ * Cleaned up the UI to fit with today's WP UI
41
+ * Fixed issues causing error messages when WP_DEBUG is on
42
+ * [Delete files on S3 when deleting WP attachment](https://github.com/bradt/wp-tantan-s3/commit/e777cd49a4b6999f999bd969241fb24cbbcece60)
43
+ * [Added filter to the get_attachment_url function](https://github.com/bradt/wp-tantan-s3/commit/bbe1aed5c2ae900e9ba1b16ba6806c28ab8e2f1c)
44
+ * [Added function to get a temporary, secure download URL for private files](https://github.com/bradt/wp-tantan-s3/commit/11f46ec2714d34907009e37ad3b97f4421aefed3)
screenshot-1.gif ADDED
Binary file
screenshot-2.jpg ADDED
Binary file
wordpress-s3.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Amazon S3 and CloudFront
4
+ Plugin URI: https://github.com/bradt/wp-tantan-s3
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.5
8
+ Author URI: http://bradt.ca
9
+
10
+ // Copyright (c) 2013 Brad Touesnard. All rights reserved.
11
+ //
12
+ // Released under the GPL license
13
+ // http://www.opensource.org/licenses/gpl-license.php
14
+ //
15
+ // **********************************************************************
16
+ // This program is distributed in the hope that it will be useful, but
17
+ // WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
+ // **********************************************************************
20
+ //
21
+ // Forked Amazon S3 for WordPress with CloudFront (http://wordpress.org/extend/plugins/tantan-s3-cloudfront/)
22
+ // which is a fork of Amazon S3 for WordPress (http://wordpress.org/extend/plugins/tantan-s3/).
23
+
24
+ */
25
+ if (class_exists('TanTanWordPressS3Plugin')) return;
26
+
27
+ // s3 lib requires php5
28
+ if (strpos($_SERVER['REQUEST_URI'], '/wp-admin/') >= 0) { // just load in admin
29
+ $ver = get_bloginfo('version');
30
+ if (version_compare(phpversion(), '5.0', '>=') && version_compare($ver, '2.1', '>=')) {
31
+ require_once(dirname(__FILE__).'/wordpress-s3/class-plugin.php');
32
+ $TanTanWordPressS3Plugin = new TanTanWordPressS3Plugin();
33
+ } elseif (ereg('wordpress-mu-', $ver)) {
34
+ require_once(dirname(__FILE__).'/wordpress-s3/class-plugin.php');
35
+ $TanTanWordPressS3Plugin = new TanTanWordPressS3Plugin();
36
+ } else {
37
+ class TanTanWordPressS3Error {
38
+ function TanTanWordPressS3Error() {add_action('admin_menu', array(&$this, 'addhooks'));}
39
+ function addhooks() {add_options_page('Amazon S3', 'Amazon S3', 10, __FILE__, array(&$this, 'admin'));}
40
+ function admin(){include(dirname(__FILE__).'/wordpress-s3/admin-version-error.html');}
41
+ }
42
+ $error = new TanTanWordPressS3Error();
43
+ }
44
+ } else {
45
+ require_once(dirname(__FILE__).'/wordpress-s3/class-plugin-public.php');
46
+ $TanTanWordPressS3Plugin = new TanTanWordPressS3PluginPublic();
47
+ }
48
+ ?>
wordpress-s3/admin-options.html ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( isset($error) && $error ):?>
2
+ <div id="message" class="error fade"><p><strong><?php echo $error?></strong></p></div>
3
+ <?php elseif ( isset($message) && $message ):?>
4
+ <div id="message" class="updated fade"><p><strong><?php echo $message?></strong></p></div>
5
+ <?php endif;?>
6
+ <script type="text/javascript">
7
+ function s3_selectBucket(obj) {
8
+ if (obj.options[obj.selectedIndex].value == 'new') {
9
+ var bucket = prompt("Bucket name: ");
10
+ if (bucket) {
11
+ var len = obj.options.length
12
+ obj.options[len] = new Option("New bucket: " + bucket, bucket);
13
+ obj.options[len].selected = true;
14
+ }
15
+ }
16
+ }
17
+ </script>
18
+ <style type="text/css">
19
+ div.album {
20
+ float:left;
21
+ width:200px;
22
+ height:150px;
23
+ margin-right:15px;
24
+ }
25
+ div.album td {
26
+ font-size:0.9em;
27
+ }
28
+ div.album-hidden img {
29
+ opacity:0.5;
30
+ }
31
+ .form-table {
32
+ max-width: 850px;
33
+ float: left;
34
+ clear: none;
35
+ margin: 0 40px 20px 0;
36
+ }
37
+ .form-table th h3 {
38
+ margin: 0;
39
+ }
40
+ .wps3-author {
41
+ width: 250px;
42
+ float: left;
43
+ padding: 20px;
44
+ border: 1px solid #ccc;
45
+ overflow: hidden;
46
+ margin: 0 0 40px 0;
47
+ }
48
+ .wps3-author img {
49
+ float: left;
50
+ margin-right: 20px;
51
+ border-radius: 32px;
52
+ }
53
+ .wps3-author .desc {
54
+ float: left;
55
+ }
56
+ .wps3-author h3 {
57
+ font-size: 12px;
58
+ margin: 0;
59
+ }
60
+ .wps3-author h2 {
61
+ font-size: 18px;
62
+ margin: 0;
63
+ padding: 0;
64
+ }
65
+ .wps3-author h2 a {
66
+ color: #464646;
67
+ text-decoration: none;
68
+ }
69
+ .wps3-author h2 a:hover {
70
+ color: #000;
71
+ }
72
+ .wps3-author p {
73
+ margin: 0;
74
+ }
75
+ .wps3-author .github {
76
+ padding-top: 5px;
77
+ }
78
+ </style>
79
+
80
+
81
+ <div class="wrap">
82
+ <div id="icon-options-general" class="icon32"><br></div>
83
+ <h2 id="write-post">Amazon S3 and CloudFront</h2>
84
+ <?php
85
+ global $TanTanVersionCheck;
86
+ if (is_object($TanTanVersionCheck)):?>
87
+ <div style="width:200px; border:1px solid #ccc;padding:10px; float:right; margin:0 0 10px 10px;">
88
+ <strong>Plugin Updates:</strong><br />
89
+ <a href="plugins.php?page=tantan/version-check.php">Check for updates to this plugin &gt;</a>
90
+ </div>
91
+ <?php endif;?>
92
+
93
+ <table class="form-table">
94
+ <form method="post">
95
+ <input type="hidden" name="action" value="save" />
96
+ <tr valign="top">
97
+ <td colspan="2">
98
+ <h3>AWS Access Credentials</h3>
99
+ <p>
100
+ If you don't have an Amazon S3 account yet, you need to
101
+ <a href="http://aws.amazon.com/s3/">sign up</a>.<br />
102
+
103
+ Once you've signed up, you can retrieve your access credentials from the
104
+ <a href="https://portal.aws.amazon.com/gp/aws/securityCredentials">Security Credentials</a>
105
+ page of your Amazon Web Services account.
106
+ </p>
107
+ </td>
108
+ </tr>
109
+ <tr valign="top">
110
+ <th width="33%" scope="row">Access Key ID:</th>
111
+ <td><input type="text" name="options[key]" value="<?php echo $options['key'];?>" size="50" /></td>
112
+ </tr>
113
+ <tr valign="top">
114
+ <th width="33%" scope="row">Secret Access Key:</th>
115
+ <td><input type="text" name="options[secret]" value="<?php echo ($options['secret'] ? '-- not shown --' : '');?>" size="50" /></td>
116
+ </tr>
117
+ <?php if (!isset($buckets) || !$buckets):?>
118
+ <tr valign="top">
119
+ <td colspan="2">
120
+ <p class="submit">
121
+ <input type="submit" class="button button-primary" value="Next Step" />
122
+ </p>
123
+ </td>
124
+ </tr>
125
+ <?php else:?>
126
+ <tr valign="top">
127
+ <td colspan="2">
128
+ <h3>S3 Settings</h3>
129
+ </td>
130
+ </tr>
131
+ <tr valign="top">
132
+ <th width="33%" scope="row">&nbsp;</th>
133
+ <td>
134
+ <select name="options[bucket]" size="1" onchange="return s3_selectBucket(this)" style="margin-bottom: 5px; width: 380px;">
135
+ <option value="">-- Select an S3 Bucket --</option>
136
+ <?php if (is_array($buckets)) foreach ($buckets as $bucket):?>
137
+ <option value="<?php echo $bucket?>" <?php echo ( isset( $options['bucket'] ) && $bucket == $options['bucket'] ) ? 'selected="selected"' : ''; ?>><?php echo $bucket?></option>
138
+ <?php endforeach;?>
139
+ <option value="new">Create a new bucket...</option>
140
+ </select><br />
141
+
142
+ <input type="checkbox" name="options[virtual-host]" value="1" id="virtual-host" <?php echo ( isset( $options['virtual-host'] ) && $options['virtual-host'] ) ? 'checked="checked" ' : '';?> />
143
+ <label for="virtual-host"> Bucket is setup for virtual hosting</label> (<a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/VirtualHosting.html">more info</a>)
144
+ <br />
145
+
146
+ <input type="checkbox" name="options[expires]" value="315360000" id="expires" <?php echo ( isset( $options['expires'] ) && $options['expires'] ) ? 'checked="checked" ' : ''; ?> />
147
+ <label for="expires"> Set a <a href="http://developer.yahoo.com/performance/rules.html#expires" target="_blank">far future HTTP expiration header</a> for uploaded files <em>(recommended)</em></label>
148
+ <br />
149
+
150
+ <input type="checkbox" name="options[permissions]" value="public" id="permissions" <?php echo ( isset( $options['permissions'] ) && $options['permissions'] == 'public' ) ? 'checked="checked" ' : ''; ?> />
151
+ <label for="permissions"> Force set the permissions on all files in the bucket to public</label>
152
+
153
+ </td>
154
+ </tr>
155
+
156
+ <tr valign="top">
157
+ <td colspan="2">
158
+ <h3>CloudFront Settings</h3>
159
+ </td>
160
+ </tr>
161
+ <tr valign="top">
162
+ <th width="33%" scope="row">Domain Name</th>
163
+ <td>
164
+ <input type="text" name="options[cloudfront]" value="<?php echo isset( $options['cloudfront'] ) ? $options['cloudfront'] : ''; ?>" size="50" />
165
+ <p class="description">Leave blank if you aren't using CloudFront.</p>
166
+ </td>
167
+ </tr>
168
+
169
+ <tr valign="top">
170
+ <td colspan="2">
171
+ <h3>Plugin Settings</h3>
172
+ </td>
173
+ </tr>
174
+
175
+ <tr valign="top">
176
+ <th width="33%" scope="row">&nbsp;</th>
177
+ <td>
178
+ <input type="checkbox" name="options[wp-uploads]" value="1" id="wp-uploads" <?php echo ( isset( $options['wp-uploads'] ) && $options['wp-uploads'] ) ? 'checked="checked" ' : ''; ?> />
179
+ <label for="wp-uploads"> Enable copying of media files to S3 and serving media files from S3/CloudFront</label>
180
+ <p class="description">Uncheck this to revert back to using your own web host for storage and delivery at anytime.</p>
181
+ </td>
182
+ </tr>
183
+
184
+ <tr>
185
+ <td colspan="2">
186
+ <p class="submit">
187
+ <input type="submit" class="button button-primary" value="Save Changes" />
188
+ </p>
189
+ </td>
190
+ </tr>
191
+ <?php endif;?>
192
+
193
+
194
+ </form>
195
+
196
+ </table>
197
+
198
+
199
+
200
+ <div class="wps3-author">
201
+ <img src="http://www.gravatar.com/avatar/e538ca4cb34839d4e5e3ccf20c37c67b?s=128&amp;d" width="64" height="64" />
202
+ <div class="desc">
203
+ <h3>Maintained by</h3>
204
+ <h2>Brad Touesnard</h2>
205
+ <p>
206
+ <a href="http://profiles.wordpress.org/bradt/">Profile</a>
207
+ &nbsp;&nbsp;
208
+ <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=5VPMGLLK94XJC">Donate</a>
209
+ </p>
210
+ <p class="github">
211
+ <a href="https://github.com/bradt/wp-tantan-s3/">Contribute on GitHub</a>
212
+ </p>
213
+ </div>
214
+ </div>
215
+
216
+
217
+
218
+ </div>
wordpress-s3/admin-tab-head.html ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $dir = dirname(__FILE__);
3
+ $pluginRootURL = plugins_url( '', __FILE__ );
4
+ if (!ereg('media-upload.php', $_SERVER['REQUEST_URI'])): // WP < 2.5
5
+ ?>
6
+
7
+ <script type="text/javascript">
8
+ addLoadEvent(function () {
9
+ var div = document.getElementById('upload-menu');
10
+ var as = div.getElementsByTagName('a')
11
+ for (var i=0;i<as.length;i++) {
12
+ var pos = as[i].innerHTML.indexOf('S3');
13
+ if (pos >= 0) {
14
+ as[i].innerHTML = '<span style="padding:0 20px 0 0;background:url(<?php echo $pluginRootURL;?>/database.png) no-repeat right;">' + as[i].innerHTML + '</span>';
15
+ }
16
+ }
17
+ <?php if ($this->options['wp-uploads'] && $this->options['bucket']):?>
18
+ var upload = document.getElementById('upload');
19
+ if (upload && upload.name == 'image') {
20
+ var span = document.createElement('span');
21
+ span.id = 'disable_amazonS3_span';
22
+ span.innerHTML = '<label for="disable_amazonS3"> don\'t upload to amazon s3 </label><input type="checkbox" name="disable_amazonS3" id="disable_amazonS3" value="1" />';
23
+ var btns = document.getElementById('buttons')
24
+ var tds = btns.getElementsByTagName('td')
25
+ tds[0].appendChild(span);
26
+ }
27
+ <?php endif;?>
28
+ });
29
+ </script>
30
+ <?php endif;?>
31
+ <script type="text/javascript" src="<?php echo $pluginRootURL;?>/admin-tab.js"></script>
32
+ <link rel='stylesheet' href='<?php echo $pluginRootURL;?>/styles/styles.css' type='text/css' />
wordpress-s3/admin-tab.html ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function print_file_type($contentType, $file) {
3
+ if (ereg('octet-stream', $contentType)) {
4
+ return ereg_replace('(.*)\.([a-zA-Z0-9]*)$', '\\2', $file);
5
+ } else {
6
+ return ereg_replace('vnd.', '', ereg_replace('/', ' ', $contentType));
7
+ }
8
+ }
9
+ ?>
10
+
11
+ <div id="amazon-s3-wrap">
12
+
13
+ <div class="infobar">
14
+
15
+ <span class="nav-controls">
16
+ <?php if (true || $_SERVER['HTTP_REFERER']):?>
17
+ <a href="javascript:history.back()" onclick="" id="btn-back" title="back">back</a>
18
+ <a href="javascript:history.forward()" onclick="" id="btn-forward" title="forward">forward</a>
19
+ <?php endif; ?>
20
+ <a href="javascript:window.location.reload()" onclick="" id="btn-refresh" title="refresh view">refresh</a>
21
+ <a href="#" onclick="return s3_toggleUpload();" id="btn-upload" title="upload">upload</a>
22
+ <a href="#" onclick="return s3_toggleCreateFolder();" id="btn-folder" title="create new folder">new folder</a>
23
+ </span>
24
+ <span class="path">
25
+ <?php
26
+ $tree = $keys;
27
+ echo '<a href="'.add_query_arg('prefix', urlencode(''), $_SERVER['REQUEST_URI']).'" class="home">home</a> / ';
28
+ $path = '';
29
+ $paths = preg_split('/\//', $prefix, 100, PREG_SPLIT_NO_EMPTY);
30
+ $numPaths = count($paths);
31
+ $i=0;
32
+ foreach ($paths as $name) if ($name) {
33
+ $path .= $name .'/';
34
+ $isLast = (++$i) >= $numPaths;
35
+ echo '<a class="'.( $isLast ? 'last' : '').'" href="'.add_query_arg('prefix', urlencode($path), $_SERVER['REQUEST_URI']).'">'.$name.'</a> '.(!$isLast ? ' / ' : ' ');
36
+ }
37
+ ?>
38
+ </span>
39
+ <span class="options">
40
+ <input type="checkbox" name="useBittorrent" id="useBittorrent" value="1" /><label for="useBittorrent"> create links as torrents</label>
41
+ </span>
42
+ <div id="create-form">
43
+ <form method="post">
44
+ <input type="hidden" name="prefix" value="<?php echo htmlentities($_GET['prefix']);?>">
45
+ <input type="text" name="newfolder" id="newfolder" />
46
+ <input type="submit" value="create" />
47
+ </form>
48
+ </div>
49
+ <div id="upload-form">
50
+ <form method="post" enctype="multipart/form-data">
51
+ <input type="file" name="newfile" />
52
+ <input type="submit" value="upload" />
53
+ </form>
54
+ </div>
55
+
56
+ </div>
57
+ <div class="folders">
58
+ <form method="post">
59
+ <ul id="prefixes">
60
+ <?php
61
+ if (is_array($prefixes)) foreach ($prefixes as $prefix):
62
+ $label = substr($prefix, strrpos(trim($prefix, '/'), '/')+1);
63
+ $label = ($path ? ereg_replace($path, "", '/'.$prefix) : $prefix);
64
+ $label = trim($prefix, '/');
65
+ if (ereg('/', $label)) $label = substr($label, strrpos($label, '/')+1);
66
+ ?>
67
+ <li><a href="<?php echo add_query_arg('prefix', urlencode($prefix), $_SERVER['REQUEST_URI']);?>" title="<?php echo $label;?>"><?php echo $label;?></a></li>
68
+ <?php
69
+ endforeach;
70
+ ?>
71
+ </ul>
72
+ </form>
73
+ </div>
74
+ <div class="files">
75
+ <ul id="keys">
76
+ <?php if (count($keys)): foreach ($keys as $i => $file):
77
+ $file = '/'.$file;
78
+ $url = 'http://'.$accessDomain.$file;
79
+ $label = substr($file, strrpos($file, '/')+1);
80
+ ?>
81
+ <li class="<?php echo print_file_type($meta[$i]['content-type'], $file);?>"><a
82
+ <?php if (ereg("^image/.*", $meta[$i]['content-type'])):?>
83
+ onclick="return s3_insertImage('<?php echo $url;?>', '<?php echo basename($url);?>')"
84
+ <?php else:?>
85
+ onclick="return s3_insertLink('<?php echo addslashes($label);?>', '<?php echo $url;?>')"
86
+ <?php endif;?>
87
+ href="<?php echo $url;?>"
88
+ class="file <?php echo ereg_replace('/', ' ', $meta[$i]['content-type']);?>"
89
+ title="<?php echo $meta[$i]['date'];?> - <?php echo $meta[$i]['content-length'];?> bytes"><?php echo $label;?></a>
90
+ </li>
91
+ <?php endforeach;?>
92
+ <?php else:?>
93
+ <li class="empty">no files in this folder</li>
94
+ <?php endif;?>
95
+ </ul>
96
+ </div>
97
+ </div>
98
+ <br clear="both" />
wordpress-s3/admin-tab.js ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ function s3_insertImage(imgURL, title) {
3
+ if (!title) title = '';
4
+ return s3_insert('<img src="'+imgURL+'" class="s3-img" border="0" alt="'+title+'" /> ');
5
+ }
6
+
7
+ function s3_insertLink(label, url) {
8
+ var useBittorrent = document.getElementById('useBittorrent').checked
9
+ return s3_insert('<a href="'+url+(useBittorrent ? '?torrent' : '')+'" class="s3-link'+(useBittorrent ? ' torrent' : '')+'">' + label + '</a> ');
10
+ }
11
+ function s3_insert(h) {
12
+ var win = window.dialogArguments || opener || parent || top;
13
+
14
+ if (typeof win.send_to_editor == 'function') {
15
+ win.send_to_editor(h);
16
+ if (typeof win.tb_remove == 'function')
17
+ win.tb_remove();
18
+ return false;
19
+ }
20
+ tinyMCE = win.tinyMCE;
21
+ if ( typeof tinyMCE != 'undefined' && tinyMCE.getInstanceById('content') ) {
22
+ tinyMCE.selectedInstance.getWin().focus();
23
+ tinyMCE.execCommand('mceInsertContent', false, h);
24
+ } else win.edInsertContent(win.edCanvas, h);
25
+
26
+ return false;
27
+ }
28
+ function s3_toggleUpload() {
29
+ document.getElementById('create-form').style.display='none';
30
+
31
+ var div = document.getElementById('upload-form');
32
+ if (div.style.display == 'block') {
33
+ div.style.display = 'none';
34
+ } else {
35
+ div.style.display = 'block';
36
+ }
37
+ return false;
38
+ }
39
+ function s3_toggleCreateFolder() {
40
+ document.getElementById('upload-form').style.display='none';
41
+
42
+ var div = document.getElementById('create-form');
43
+ if (div.style.display == 'block') {
44
+ div.style.display = 'none';
45
+ } else {
46
+ div.style.display = 'block';
47
+ document.getElementById('newfolder').focus();
48
+ }
49
+ return false;
50
+
51
+
52
+ var div = document.getElementById('createFolder');
53
+ if (div.className != 'create') {
54
+ div.className = 'create';
55
+ document.getElementById('newfolder').focus();
56
+ } else {
57
+ div.className = '';
58
+ }
59
+ }
wordpress-s3/admin-version-error.html ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($error):?>
2
+ <div id="message" class="error fade"><p><strong><?php echo $error?></strong></p></div>
3
+ <?php elseif ($message):?>
4
+ <div id="message" class="updated fade"><p><strong><?php echo $message?></strong></p></div>
5
+ <?php endif;?>
6
+
7
+ <style>
8
+ fieldset.options {
9
+ clear:both;
10
+ border:1px solid #ccc;
11
+ }
12
+ fieldset.options legend {
13
+ font-family: Georgia,"Times New Roman",Times,serif;
14
+ font-size: 22px;
15
+ }
16
+
17
+ div.album {
18
+ float:left;
19
+ width:200px;
20
+ height:150px;
21
+ margin-right:15px;
22
+ }
23
+ div.album td {
24
+ font-size:0.9em;
25
+ }
26
+ div.album-hidden img {
27
+ opacity:0.5;
28
+ }
29
+ </style>
30
+
31
+
32
+ <div class="wrap">
33
+ <h2 id="write-post">Amazon S3 Plugin for WordPress</h2>
34
+ <div style="width:250px;border:1px solid #ccc;float:right;padding:10px;margin:0 0 10px 10px;">
35
+ <strong><a href="http://www.dreamhost.com/r.cgi?156998" target="_blank">Switch to a better web host!</a></strong><br />
36
+ Use the coupon code
37
+ <b>TANTAN50COUPON</b>
38
+ when you signup to get a $50 discount, and you'll
39
+ help support this plugin in the process.
40
+ That works out to be less than $6.00 per month for the first year.
41
+
42
+ </div>
43
+ <h3>Error</h3>
44
+ <p>
45
+ Sorry, this plugin requires at least PHP <strong>5.0</strong> and WordPress <strong>2.1</strong> in order to work correctly.
46
+ Please contact your systems administrator about getting your version of PHP and/or WordPress upgraded.
47
+ </p>
48
+ <p>
49
+ Your PHP version: <strong style="<?php echo (version_compare(phpversion(), '5.0.0', '<') ? 'color:red;' : '');?>"><?php echo phpversion();?></strong><br />
50
+ Your WordPress version: <strong style="<?php echo (version_compare(get_bloginfo('version'), '2.1', '<') ? 'color:red;' : '');?>"><?php bloginfo('version'); ?></strong>
51
+ <br />
52
+ </p>
53
+
54
+ <p>
55
+ <a href="http://www.php.net/downloads.php">Download PHP</a><br />
56
+ <a href="http://wordpress.org/download/">Download WordPress</a><br />
57
+ </p>
58
+ </div>
wordpress-s3/class-plugin-public.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class TanTanWordPressS3PluginPublic {
3
+ var $options;
4
+ var $s3;
5
+ var $meta;
6
+
7
+ function TanTanWordPressS3PluginPublic() {
8
+ $this->options = array();
9
+ if (file_exists(dirname(__FILE__).'/config.php')) {
10
+ require_once(dirname(__FILE__).'/config.php');
11
+ if ($TanTanWordPressS3Config) $this->options = $TanTanWordPressS3Config;
12
+ }
13
+ add_action('plugins_loaded', array(&$this, 'addhooks'));
14
+ }
15
+ function addhooks() {
16
+ add_filter('wp_get_attachment_url', array(&$this, 'wp_get_attachment_url'), 9, 2);
17
+ }
18
+ function wp_get_attachment_url($url, $postID) {
19
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
20
+
21
+ if ($this->options['wp-uploads'] && ($amazon = get_post_meta($postID, 'amazonS3_info', true))) {
22
+ if ( isset($this->options['cloudfront']) && $this->options['cloudfront'] ) {
23
+ $accessDomain = $this->options['cloudfront'];
24
+ }
25
+ elseif ( isset($this->options['virtual-host']) && $this->options['virtual-host'] ) {
26
+ $accessDomain = $this->options['bucket'];
27
+ }
28
+ else {
29
+ $accessDomain = $amazon['bucket'] . '.s3.amazonaws.com';
30
+ }
31
+
32
+ $url = 'http://'.$accessDomain.'/'.$amazon['key'];
33
+
34
+ $url = apply_filters( 'wps3_get_attachment_url', $url, $postID, $this );
35
+ }
36
+
37
+ return $url;
38
+ }
39
+
40
+
41
+ /**
42
+ * Generate a link to download a file from Amazon S3 using query string
43
+ * authentication. This link is only valid for a limited amount of time.
44
+ *
45
+ * @param $bucket The name of the bucket in which the file is stored.
46
+ * @param $filekey The key of the file, excluding the leading slash.
47
+ * @param $expires The amount of time the link is valid (in seconds).
48
+ * @param $operation The type of HTTP operation. Either GET or HEAD.
49
+ */
50
+ function get_secure_attachment_url($postID, $expires = 900, $operation = 'GET') {
51
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
52
+
53
+ if (
54
+ !$this->options['wp-uploads'] || !$this->options['key'] || !$this->options['secret']
55
+ || !$this->options['bucket'] || !($amazon = get_post_meta($postID, 'amazonS3_info', true))
56
+ ) {
57
+ return false;
58
+ }
59
+
60
+ $accessDomain = $this->options['virtual-host'] ? $amazon['bucket'] : $amazon['bucket'].'.s3.amazonaws.com';
61
+
62
+ $expire_time = time() + $expires;
63
+ $filekey = rawurlencode($amazon['key']);
64
+ $filekey = str_replace('%2F', '/', $filekey);
65
+ $path = $amazon['bucket'] .'/'. $filekey;
66
+
67
+ /**
68
+ * StringToSign = HTTP-VERB + "\n" +
69
+ * Content-MD5 + "\n" +
70
+ * Content-Type + "\n" +
71
+ * Expires + "\n" +
72
+ * CanonicalizedAmzHeaders +
73
+ * CanonicalizedResource;
74
+ */
75
+
76
+ $stringtosign =
77
+ $operation ."\n". // type of HTTP request (GET/HEAD)
78
+ "\n". // Content-MD5 is meaningless for GET
79
+ "\n". // Content-Type is meaningless for GET
80
+ $expire_time ."\n". // set the expire date of this link
81
+ "/$path"; // full path (incl bucket), starting with a /
82
+
83
+ require_once(dirname(__FILE__).'/lib.s3.php');
84
+ $s3 = new TanTanS3($this->options['key'], $this->options['secret']);
85
+ $signature = urlencode($s3->constructSig($stringtosign));
86
+
87
+ return sprintf('http://%s/%s?AWSAccessKeyId=%s&Expires=%u&Signature=%s', $accessDomain, $filekey, $this->options['key'], $expire_time, $signature);
88
+ }
89
+ }
90
+
91
+ function wps3_get_secure_attachment_url($postID, $expires = 900, $operation = 'GET') {
92
+ global $TanTanWordPressS3Plugin;
93
+ return $TanTanWordPressS3Plugin->get_secure_attachment_url($postID, $expires, $operation);
94
+ }
wordpress-s3/class-plugin.php ADDED
@@ -0,0 +1,496 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__).'/class-plugin-public.php');
3
+ class TanTanWordPressS3Plugin extends TanTanWordPressS3PluginPublic {
4
+
5
+ function TanTanWordPressS3Plugin() {
6
+ parent::TanTanWordPressS3PluginPublic();
7
+ if (!file_exists(dirname(__FILE__).'/config.php')) {
8
+ add_action('admin_menu', array(&$this, 'settings'));
9
+ }
10
+ if (!isset($this->options['hideAmazonS3UploadTab']) || !$this->options['hideAmazonS3UploadTab']) {
11
+ add_action('load-upload.php', array(&$this, 'addPhotosTab')); // WP < 2.5
12
+
13
+ // WP >= 2.5
14
+ add_action('media_buttons_context', array(&$this, 'media_buttons'));
15
+ add_action('media_upload_tabs', array(&$this, 'media_upload_tabs'));
16
+ add_action('media_upload_tantan-wordpress-s3', array(&$this, 'media_upload_content'));
17
+ }
18
+ add_action('activate_tantan/wordpress-s3.php', array(&$this, 'activate'));
19
+ if (isset($_GET['tantanActivate']) && $_GET['tantanActivate'] == 'wordpress-s3') {
20
+ $this->showConfigNotice();
21
+ }
22
+ $this->photos = array();
23
+ $this->albums = array();
24
+ $this->perPage = 1000;
25
+
26
+
27
+ }
28
+
29
+ // this should install the javascripts onto the user's s3.amazonaws.com account
30
+
31
+ function installAjax() {
32
+ $js = array('S3Ajax.js');
33
+ }
34
+
35
+ function activate() {
36
+ wp_redirect('plugins.php?tantanActivate=wordpress-s3');
37
+ exit;
38
+ }
39
+ function deactivate() {}
40
+
41
+ function showConfigNotice() {
42
+ add_action('admin_notices', create_function('', 'echo \'<div id="message" class="updated fade"><p>Amazon S3 Plugin for WordPress <strong>activated</strong>. <a href="options-general.php?page=tantan/wordpress-s3/class-plugin.php">Configure the plugin &gt;</a></p></div>\';'));
43
+ }
44
+
45
+ function settings() {
46
+ add_options_page('Amazon S3', 'Amazon S3', 10, __FILE__, array(&$this, 'admin'));
47
+ $this->version_check();
48
+ }
49
+ function addhooks() {
50
+ parent::addhooks();
51
+ if (!isset($_POST['disable_amazonS3']) || !$_POST['disable_amazonS3']) {
52
+ add_filter('wp_update_attachment_metadata', array(&$this, 'wp_update_attachment_metadata'), 9, 2);
53
+ //can't delete mirrored files just yet
54
+ //add_filter('wp_get_attachment_metadata', array(&$this, 'wp_get_attachment_metadata'));
55
+ add_filter('delete_attachment', array(&$this, 'delete_attachment'));
56
+ }
57
+ }
58
+ function version_check() {
59
+ global $TanTanVersionCheck;
60
+ if (is_object($TanTanVersionCheck)) {
61
+ $data = get_plugin_data(dirname(__FILE__).'/../wordpress-s3.php');
62
+ $TanTanVersionCheck->versionCheck(668, $data['Version']);
63
+ }
64
+ }
65
+ function admin() {
66
+ if ( isset( $_POST['action'] ) && $_POST['action'] == 'save' ) {
67
+ if (!is_array($_POST['options'])) $_POST['options'] = array();
68
+ $options = get_option('tantan_wordpress_s3');
69
+
70
+ $_POST['options']['key'] = trim($_POST['options']['key']);
71
+ $_POST['options']['secret'] = trim($_POST['options']['secret']);
72
+
73
+ if (!$_POST['options']['secret'] || ereg('not shown', $_POST['options']['secret'])) {
74
+ $_POST['options']['secret'] = $options['secret'];
75
+ }
76
+
77
+ update_option('tantan_wordpress_s3', $_POST['options']);
78
+
79
+ if (isset($_POST['options']['bucket']) && $_POST['options']['bucket']) {
80
+ $options = get_option('tantan_wordpress_s3');
81
+ require_once(dirname(__FILE__).'/lib.s3.php');
82
+ $s3 = new TanTanS3($options['key'], $options['secret']);
83
+
84
+ if (!in_array($_POST['options']['bucket'], $s3->listBuckets())) {
85
+ if ($s3->createBucket($_POST['options']['bucket'],'public-read')) {
86
+ $message = "Saved settings and created a new bucket: ".$_POST['options']['bucket'];
87
+ } else {
88
+ $error = "There was an error creating the bucket: ".$_POST['options']['bucket'];
89
+ }
90
+ } else {
91
+ $message = "Saved settings.";
92
+ }
93
+ } else {
94
+ $message = "Saved Amazon S3 authentication information. ";
95
+ }
96
+ if (function_exists('dns_get_record') && isset( $_POST['options']['virtual-host'] ) && $_POST['options']['virtual-host'] ) {
97
+ $record = dns_get_record($_POST['options']['bucket']);
98
+ if (($record[0]['type'] != 'CNAME') || ($record[0]['target'] != $_POST['options']['bucket'].'s3.amazonaws.com')) {
99
+ $error = "Warning: Your DNS doesn't seem to be setup correctly to virtually host the domain <em>".$_POST['options']['bucket']."</em>. ".
100
+ "Double check and make sure the following entry is added to your DNS. ".
101
+ "<a href='http://docs.amazonwebservices.com/AmazonS3/2006-03-01/VirtualHosting.html'>More info &gt;</a>".
102
+ "<br /><br />".
103
+ "<code>".$_POST['options']['bucket']." CNAME ".$_POST['options']['bucket'].".s3.amazonaws.com.</code>".
104
+ "<br /><br />".
105
+ "<small>You can ignore this message if you're sure everything is setup correctly.</small>";
106
+ }
107
+ }
108
+ }
109
+ $options = get_option('tantan_wordpress_s3');
110
+ if ($options['key'] && $options['secret']) {
111
+ require_once(dirname(__FILE__).'/lib.s3.php');
112
+ $s3 = new TanTanS3($options['key'], $options['secret']);
113
+ if (!($buckets = $s3->listBuckets())) {
114
+ $error = $this->getErrorMessage($s3->parsed_xml, $s3->responseCode);
115
+ }
116
+
117
+ $s3->initCacheTables();
118
+
119
+ } elseif ($options['key']) {
120
+ $error = "Please enter your Secret Access Key.";
121
+ } elseif ($options['secret']) {
122
+ $error = "Please enter your Access Key ID.";
123
+ }
124
+
125
+
126
+ include(dirname(__FILE__).'/admin-options.html');
127
+ }
128
+
129
+
130
+ /*
131
+ Delete corresponding files from Amazon S3
132
+ */
133
+ function delete_attachment( $post_id ) {
134
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
135
+
136
+ if (!$this->options['wp-uploads'] || !$this->options['bucket'] || !$this->options['secret']) {
137
+ return;
138
+ }
139
+
140
+ $backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
141
+
142
+ $intermediate_sizes = array();
143
+ foreach ( get_intermediate_image_sizes() as $size ) {
144
+ if ( $intermediate = image_get_intermediate_size( $post_id, $size ) )
145
+ $intermediate_sizes[] = $intermediate;
146
+ }
147
+
148
+ if ( !( $amazon = get_post_meta( $post_id, 'amazonS3_info', true ) ) ) {
149
+ return;
150
+ }
151
+
152
+ $amazon_path = dirname( $amazon['key'] );
153
+
154
+ require_once(dirname(__FILE__).'/lib.s3.php');
155
+ $this->s3 = new TanTanS3($this->options['key'], $this->options['secret']);
156
+ $this->s3->setOptions($this->options);
157
+
158
+ // remove intermediate and backup images if there are any
159
+ foreach ( $intermediate_sizes as $intermediate ) {
160
+ $this->s3->deleteObject( $amazon['bucket'], path_join( $amazon_path, $intermediate['file'] ) );
161
+ }
162
+
163
+ if ( is_array($backup_sizes) ) {
164
+ foreach ( $backup_sizes as $size ) {
165
+ $this->s3->deleteObject( $amazon['bucket'], path_join( $amazon_path, $del_file ) );
166
+ }
167
+ }
168
+
169
+ $this->s3->deleteObject( $amazon['bucket'], $amazon['key'] );
170
+ }
171
+
172
+ function wp_get_attachment_metadata($data=false, $postID=false) {
173
+ if (is_numeric($postID)) $this->meta = get_post_meta($postID, 'amazonS3_info', true);
174
+ return $data;
175
+ }
176
+ /*
177
+ Handle uploads through default WordPress upload handler
178
+ */
179
+ function wp_update_attachment_metadata($data, $postID) {
180
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
181
+
182
+ if (!$this->options['wp-uploads'] || !$this->options['bucket'] || !$this->options['secret']) {
183
+ return $data;
184
+ }
185
+
186
+ add_filter('option_siteurl', array(&$this, 'upload_path'));
187
+ $uploadDir = wp_upload_dir();
188
+ remove_filter('option_siteurl', array(&$this, 'upload_path'));
189
+ $parts = parse_url($uploadDir['url']);
190
+
191
+ $prefix = substr($parts['path'], 1) .'/';
192
+ $type = get_post_mime_type($postID);
193
+
194
+ $data['file'] = get_attached_file($postID, true);
195
+
196
+ $acl = apply_filters( 'wps3_upload_acl', 'public-read', $type, $data, $postID, $this );
197
+
198
+ if (file_exists($data['file'])) {
199
+ $file = array(
200
+ 'name' => basename($data['file']),
201
+ 'type' => $type,
202
+ 'tmp_name' => $data['file'],
203
+ 'error' => 0,
204
+ 'size' => filesize($data['file']),
205
+ );
206
+
207
+ require_once(dirname(__FILE__).'/lib.s3.php');
208
+ $this->s3 = new TanTanS3($this->options['key'], $this->options['secret']);
209
+ $this->s3->setOptions($this->options);
210
+
211
+ if ($this->s3->putObjectStream($this->options['bucket'], $prefix.$file['name'], $file, $acl)) {
212
+
213
+ if ($data['thumb']) {
214
+ $thumbpath = str_replace( basename( $data['file'] ), $data['thumb'], $data['file'] );
215
+ $filethumb = array(
216
+ 'name' => $data['thumb'],
217
+ 'type' => $type,
218
+ 'tmp_name' => $thumbpath,
219
+ 'size' => filesize($thumbpath),
220
+ );
221
+
222
+ $this->s3->putObjectStream($this->options['bucket'], $prefix.$filethumb['name'], $filethumb);
223
+ } elseif (count($data['sizes'])) foreach ($data['sizes'] as $altName => $altSize) {
224
+ $altPath = str_replace( basename( $data['file'] ), $altSize['file'], $data['file'] );
225
+ $altMeta = array(
226
+ 'name' => $altSize['file'],
227
+ 'type' => $type,
228
+ 'tmp_name' => $altPath,
229
+ 'size' => filesize($altPath),
230
+ );
231
+ $this->s3->putObjectStream($this->options['bucket'], $prefix.$altMeta['name'], $altMeta);
232
+
233
+ }
234
+
235
+
236
+ delete_post_meta($postID, 'amazonS3_info');
237
+ add_post_meta($postID, 'amazonS3_info', array(
238
+ 'bucket' => $this->options['bucket'],
239
+ 'key' => $prefix.$file['name']
240
+ ));
241
+ } else {
242
+
243
+ }
244
+ }
245
+ return $data;
246
+ }
247
+ function wp_handle_upload($info) {
248
+ return $info;
249
+ }
250
+
251
+ // figure out the correct path to upload to, for wordpress mu installs
252
+ function upload_path($path='') {
253
+ global $current_blog;
254
+ if (!$current_blog) return $path;
255
+ if ($current_blog->path == '/' && ($current_blog->blog_id != 1)) {
256
+ $dir = substr($current_blog->domain, 0, strpos($current_blog->domain, '.'));
257
+ } else {
258
+ // prepend a directory onto the path for vhosted blogs
259
+ if (constant("VHOST") != 'yes') {
260
+ $dir = '';
261
+ } else {
262
+ $dir = $current_blog->path;
263
+ }
264
+ }
265
+ //echo trim($path.'/'.$dir, '/');
266
+ if ($path == '') {
267
+ $path = $current_blog->path;
268
+ }
269
+ return trim($path.'/'.$dir, '/');
270
+ }
271
+ function media_buttons($context) {
272
+ global $post_ID, $temp_ID;
273
+ $pluginRootURL = plugins_url( '', __FILE__ );
274
+ $image_btn = $pluginRootURL.'/database.png';
275
+ $image_title = 'Amazon S3';
276
+
277
+ $uploading_iframe_ID = (int) (0 == $post_ID ? $temp_ID : $post_ID);
278
+
279
+ $media_upload_iframe_src = "media-upload.php?post_id=$uploading_iframe_ID";
280
+ $out = ' <a href="'.$media_upload_iframe_src.'&tab=tantan-wordpress-s3&TB_iframe=true&height=500&width=640" class="thickbox" title="'.$image_title.'"><img src="'.$image_btn.'" alt="'.$image_title.'" /></a>';
281
+ return $context.$out;
282
+ }
283
+ function media_upload_tabs( $tabs ) {
284
+ $tabs['tantan-wordpress-s3'] = 'Amazon S3';
285
+ return $tabs;
286
+ }
287
+ function media_upload_content() {
288
+ $this->upload_files_tantan_amazons3(); // process any uploaded files or new folders
289
+
290
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
291
+ //if (!is_object($this->s3)) {
292
+ require_once(dirname(__FILE__).'/lib.s3.php');
293
+ $this->s3 = new TanTanS3($this->options['key'], $this->options['secret']);
294
+ $this->s3->setOptions($this->options);
295
+ //}
296
+
297
+ add_action('admin_print_scripts', array(&$this, 'upload_tabs_scripts'));
298
+ wp_iframe(array(&$this, 'tab'));
299
+ }
300
+ /*
301
+ Display tabs
302
+ */
303
+ function addPhotosTab() {
304
+ add_filter('wp_upload_tabs', array(&$this, 'wp_upload_tabs'));
305
+ add_action('upload_files_tantan_amazons3', array(&$this, 'upload_files_tantan_amazons3'));
306
+ add_action('upload_files_upload', array(&$this, 'upload_files_upload'));
307
+ add_action('admin_print_scripts', array(&$this, 'upload_tabs_scripts'));
308
+ }
309
+ function wp_upload_tabs ($array) {
310
+ /*
311
+ 0 => tab display name,
312
+ 1 => required cap,
313
+ 2 => function that produces tab content,
314
+ 3 => total number objects OR array(total, objects per page),
315
+ 4 => add_query_args
316
+ */
317
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
318
+ require_once(dirname(__FILE__).'/lib.s3.php');
319
+ $this->s3 = new TanTanS3($this->options['key'], $this->options['secret']);
320
+
321
+
322
+ if ($this->options['key'] && $this->options['secret'] && $this->options['bucket']) {
323
+ $paged = array();
324
+ $args = array('prefix' => ''); // this doesn't do anything in WP 2.1.2
325
+ $tab = array(
326
+ 'tantan_amazons3' => array('Amazon S3', 'upload_files', array(&$this, 'tab'), $paged, $args),
327
+ //'tantan_amazons3_upload' => array('Upload S3', 'upload_files', array(&$this, 'upload'), $paged, $args),
328
+ );
329
+
330
+ return array_merge($array, $tab);
331
+ } else {
332
+ return $array;
333
+ }
334
+ }
335
+
336
+ function get_access_domain() {
337
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
338
+
339
+ if ( isset($this->options['cloudfront']) && $this->options['cloudfront'] ) {
340
+ return $this->options['cloudfront'];
341
+ }
342
+ elseif ( isset($this->options['virtual-host']) && $this->options['virtual-host'] ) {
343
+ return $this->options['bucket'];
344
+ }
345
+ else {
346
+ return $this->options['bucket'].'.s3.amazonaws.com';
347
+ }
348
+ }
349
+
350
+ function upload_tabs_scripts() {
351
+ //wp_enqueue_script('prototype');
352
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
353
+
354
+ $accessDomain = $this->get_access_domain();
355
+
356
+ include(dirname(__FILE__).'/admin-tab-head.html');
357
+ }
358
+ function upload_files_upload() {
359
+ // javascript here to inject javascript and allow the upload from to post to amazon s3 instead
360
+ }
361
+ function upload_files_tantan_amazons3() {
362
+ global $current_blog;
363
+ $restrictPrefix = ''; // restrict to a selected prefix in current bucket
364
+ if ($current_blog) { // if wordpress mu
365
+ $restrictPrefix = ltrim($this->upload_path().'/files/', '/');
366
+ }
367
+
368
+ if (is_array($_FILES['newfile'])) {
369
+ $file = $_FILES['newfile'];
370
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
371
+ require_once(dirname(__FILE__).'/lib.s3.php');
372
+ $this->s3 = new TanTanS3($this->options['key'], $this->options['secret']);
373
+ $this->s3->setOptions($this->options);
374
+ $this->s3->putObjectStream($this->options['bucket'], $restrictPrefix.$_GET['prefix'].$file['name'], $file);
375
+ }
376
+ if ($_POST['newfolder']) {
377
+ if (!$this->options) $this->options = get_option('tantan_wordpress_s3');
378
+ require_once(dirname(__FILE__).'/lib.s3.php');
379
+ $this->s3 = new TanTanS3($this->options['key'], $this->options['secret']);
380
+
381
+ $this->s3->putPrefix($this->options['bucket'], $restrictPrefix.$_POST['prefix'].$_POST['newfolder']);
382
+ }
383
+ }
384
+ function tab() {
385
+ global $current_blog;
386
+ $restrictPrefix = ''; // restrict to a selected prefix in current bucket
387
+ if ($current_blog) { // if wordpress mu
388
+ $restrictPrefix = ltrim($this->upload_path().'/files/', '/');
389
+ }
390
+
391
+ $offsetpage = (int) $_GET['paged'];
392
+ if (!$offsetpage) $offsetpage = 1;
393
+
394
+ if (!$this->options['key'] || !$this->options['secret']) {
395
+ return;
396
+ }
397
+ $bucket = $this->options['bucket'];
398
+ $accessDomain = $this->get_access_domain();
399
+
400
+ $prefix = $_GET['prefix'] ? $_GET['prefix'] : '';
401
+ list($prefixes, $keys, $meta, $privateKeys) = $this->getKeys($restrictPrefix.$prefix);
402
+ if ($restrictPrefix) {
403
+ foreach ($prefixes as $k=>$v) {
404
+ $prefixes[$k] = str_replace($restrictPrefix, '', $v);
405
+ }
406
+ }
407
+ include(dirname(__FILE__).'/admin-tab.html');
408
+ }
409