/wp-content/plugins/w3-total-cache/lib/W3/Cdn/S3.php

https://github.com/sharpmachine/wakeupmedia.com · PHP · 410 lines · 328 code · 31 blank · 51 comment · 14 complexity · 324294e9673737a594ec380cde374ec0 MD5 · raw file

  1. <?php
  2. /**
  3. * Amazon S3 CDN engine
  4. */
  5. if (!defined('ABSPATH')) {
  6. die();
  7. }
  8. if (!class_exists('S3')) {
  9. require_once W3TC_LIB_DIR . '/S3.php';
  10. }
  11. require_once W3TC_LIB_W3_DIR . '/Cdn/Base.php';
  12. /**
  13. * Class W3_Cdn_S3
  14. */
  15. class W3_Cdn_S3 extends W3_Cdn_Base {
  16. /**
  17. * S3 object
  18. *
  19. * @var S3
  20. */
  21. var $_s3 = null;
  22. /**
  23. * PHP5 Constructor
  24. *
  25. * @param array $config
  26. */
  27. function __construct($config = array()) {
  28. $config = array_merge(array(
  29. 'key' => '',
  30. 'secret' => '',
  31. 'bucket' => '',
  32. 'cname' => array(),
  33. ), $config);
  34. parent::__construct($config);
  35. }
  36. /**
  37. * PHP4 Constructor
  38. *
  39. * @param array $config
  40. */
  41. function W3_Cdn_S3($config = array()) {
  42. $this->__construct($config);
  43. }
  44. /**
  45. * Inits S3 object
  46. *
  47. * @param string $error
  48. * @return boolean
  49. */
  50. function _init(&$error) {
  51. if (empty($this->_config['key'])) {
  52. $error = 'Empty access key.';
  53. return false;
  54. }
  55. if (empty($this->_config['secret'])) {
  56. $error = 'Empty secret key.';
  57. return false;
  58. }
  59. if (empty($this->_config['bucket'])) {
  60. $error = 'Empty bucket.';
  61. return false;
  62. }
  63. @$this->_s3 = & new S3($this->_config['key'], $this->_config['secret'], false);
  64. return true;
  65. }
  66. /**
  67. * Uploads files to S3
  68. *
  69. * @param array $files
  70. * @param array $results
  71. * @param boolean $force_rewrite
  72. * @return boolean
  73. */
  74. function upload($files, &$results, $force_rewrite = false) {
  75. $error = null;
  76. if (!$this->_init($error)) {
  77. $results = $this->_get_results($files, W3TC_CDN_RESULT_HALT, $error);
  78. return false;
  79. }
  80. foreach ($files as $local_path => $remote_path) {
  81. $results[] = $this->_upload($local_path, $remote_path, $force_rewrite);
  82. if ($this->_config['compression'] && $this->_may_gzip($remote_path)) {
  83. $remote_path_gzip = $remote_path . $this->_gzip_extension;
  84. $results[] = $this->_upload_gzip($local_path, $remote_path_gzip, $force_rewrite);
  85. }
  86. }
  87. return !$this->_is_error($results);
  88. }
  89. /**
  90. * Uploads single file to S3
  91. *
  92. * @param string $local_path
  93. * @param string $remote_path
  94. * @param boolean $force_rewrite
  95. * @return array
  96. */
  97. function _upload($local_path, $remote_path, $force_rewrite = false) {
  98. if (!file_exists($local_path)) {
  99. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, 'Source file not found.');
  100. }
  101. if (!$force_rewrite) {
  102. $this->_set_error_handler();
  103. $info = @$this->_s3->getObjectInfo($this->_config['bucket'], $remote_path);
  104. $this->_restore_error_handler();
  105. if ($info) {
  106. $hash = @md5_file($local_path);
  107. $s3_hash = (isset($info['hash']) ? $info['hash'] : '');
  108. if ($hash === $s3_hash) {
  109. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_OK, 'Object up-to-date.');
  110. }
  111. }
  112. }
  113. $headers = $this->_get_headers($local_path);
  114. $this->_set_error_handler();
  115. $result = @$this->_s3->putObjectFile($local_path, $this->_config['bucket'], $remote_path, S3::ACL_PUBLIC_READ, array(), $headers);
  116. $this->_restore_error_handler();
  117. if ($result) {
  118. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_OK, 'OK');
  119. }
  120. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, sprintf('Unable to put object (%s).', $this->_get_last_error()));
  121. }
  122. /**
  123. * Uploads gzip version of file
  124. *
  125. * @param string $local_path
  126. * @param string $remote_path
  127. * @param boolean $force_rewrite
  128. * @return array
  129. */
  130. function _upload_gzip($local_path, $remote_path, $force_rewrite = false) {
  131. if (!function_exists('gzencode')) {
  132. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, "GZIP library doesn't exist.");
  133. }
  134. if (!file_exists($local_path)) {
  135. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, 'Source file not found.');
  136. }
  137. $contents = @file_get_contents($local_path);
  138. if ($contents === false) {
  139. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, 'Unable to read file.');
  140. }
  141. $data = gzencode($contents);
  142. if (!$force_rewrite) {
  143. $this->_set_error_handler();
  144. $info = @$this->_s3->getObjectInfo($this->_config['bucket'], $remote_path);
  145. $this->_restore_error_handler();
  146. if ($info) {
  147. $hash = md5($data);
  148. $s3_hash = (isset($info['hash']) ? $info['hash'] : '');
  149. if ($hash === $s3_hash) {
  150. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_OK, 'Object up-to-date.');
  151. }
  152. }
  153. }
  154. $headers = $this->_get_headers($local_path);
  155. $headers = array_merge($headers, array(
  156. 'Vary' => 'Accept-Encoding',
  157. 'Content-Encoding' => 'gzip'
  158. ));
  159. $this->_set_error_handler();
  160. $result = @$this->_s3->putObjectString($data, $this->_config['bucket'], $remote_path, S3::ACL_PUBLIC_READ, array(), $headers);
  161. $this->_restore_error_handler();
  162. if ($result) {
  163. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_OK, 'OK');
  164. }
  165. return $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, sprintf('Unable to put object (%s).', $this->_get_last_error()));
  166. }
  167. /**
  168. * Deletes files from S3
  169. *
  170. * @param array $files
  171. * @param array $results
  172. * @return boolean
  173. */
  174. function delete($files, &$results) {
  175. $error = null;
  176. if (!$this->_init($error)) {
  177. $results = $this->_get_results($files, W3TC_CDN_RESULT_HALT, $error);
  178. return false;
  179. }
  180. foreach ($files as $local_path => $remote_path) {
  181. $this->_set_error_handler();
  182. $result = @$this->_s3->deleteObject($this->_config['bucket'], $remote_path);
  183. $this->_restore_error_handler();
  184. if ($result) {
  185. $results[] = $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_OK, 'OK');
  186. } else {
  187. $results[] = $this->_get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, sprintf('Unable to delete object (%s).', $this->_get_last_error()));
  188. }
  189. if ($this->_config['compression']) {
  190. $remote_path_gzip = $remote_path . $this->_gzip_extension;
  191. $this->_set_error_handler();
  192. $result = @$this->_s3->deleteObject($this->_config['bucket'], $remote_path_gzip);
  193. $this->_restore_error_handler();
  194. if ($result) {
  195. $results[] = $this->_get_result($local_path, $remote_path_gzip, W3TC_CDN_RESULT_OK, 'OK');
  196. } else {
  197. $results[] = $this->_get_result($local_path, $remote_path_gzip, W3TC_CDN_RESULT_ERROR, sprintf('Unable to delete object (%s).', $this->_get_last_error()));
  198. }
  199. }
  200. }
  201. return !$this->_is_error($results);
  202. }
  203. /**
  204. * Tests S3
  205. *
  206. * @param string $error
  207. * @return boolean
  208. */
  209. function test(&$error) {
  210. if (!parent::test($error)) {
  211. return false;
  212. }
  213. $string = 'test_s3_' . md5(time());
  214. if (!$this->_init($error)) {
  215. return false;
  216. }
  217. $this->_set_error_handler();
  218. $buckets = @$this->_s3->listBuckets();
  219. if ($buckets === false) {
  220. $error = sprintf('Unable to list buckets (%s).', $this->_get_last_error());
  221. $this->_restore_error_handler();
  222. return false;
  223. }
  224. if (!in_array($this->_config['bucket'], (array) $buckets)) {
  225. $error = sprintf('Bucket doesn\'t exist: %s.', $this->_config['bucket']);
  226. $this->_restore_error_handler();
  227. return false;
  228. }
  229. if (!@$this->_s3->putObjectString($string, $this->_config['bucket'], $string, S3::ACL_PUBLIC_READ)) {
  230. $error = sprintf('Unable to put object (%s).', $this->_get_last_error());
  231. $this->_restore_error_handler();
  232. return false;
  233. }
  234. if (!($object = @$this->_s3->getObject($this->_config['bucket'], $string))) {
  235. $error = sprintf('Unable to get object (%s).', $this->_get_last_error());
  236. $this->_restore_error_handler();
  237. return false;
  238. }
  239. if ($object->body != $string) {
  240. $error = 'Objects are not equal.';
  241. @$this->_s3->deleteObject($this->_config['bucket'], $string);
  242. $this->_restore_error_handler();
  243. return false;
  244. }
  245. if (!@$this->_s3->deleteObject($this->_config['bucket'], $string)) {
  246. $error = sprintf('Unable to delete object (%s).', $this->_get_last_error());
  247. $this->_restore_error_handler();
  248. return false;
  249. }
  250. $this->_restore_error_handler();
  251. return true;
  252. }
  253. /**
  254. * Returns CDN domain
  255. *
  256. * @return array
  257. */
  258. function get_domains() {
  259. if (!empty($this->_config['cname'])) {
  260. return (array) $this->_config['cname'];
  261. } elseif (!empty($this->_config['bucket'])) {
  262. $domain = sprintf('%s.s3.amazonaws.com', $this->_config['bucket']);
  263. return array(
  264. $domain
  265. );
  266. }
  267. return array();
  268. }
  269. /**
  270. * Returns via string
  271. *
  272. * @return string
  273. */
  274. function get_via() {
  275. return sprintf('Amazon Web Services: S3: %s', parent::get_via());
  276. }
  277. /**
  278. * Creates bucket
  279. *
  280. * @param string $container_id
  281. * @param string $error
  282. * @return boolean
  283. */
  284. function create_container(&$container_id, &$error) {
  285. if (!$this->_init($error)) {
  286. return false;
  287. }
  288. $this->_set_error_handler();
  289. $buckets = @$this->_s3->listBuckets();
  290. if ($buckets === false) {
  291. $error = sprintf('Unable to list buckets (%s).', $this->_get_last_error());
  292. $this->_restore_error_handler();
  293. return false;
  294. }
  295. if (in_array($this->_config['bucket'], (array) $buckets)) {
  296. $error = sprintf('Bucket already exists: %s.', $this->_config['bucket']);
  297. $this->_restore_error_handler();
  298. return false;
  299. }
  300. if (empty($this->_config['bucket_acl'])) {
  301. $this->_config['bucket_acl'] = S3::ACL_PUBLIC_READ;
  302. }
  303. if (!isset($this->_config['bucket_location'])) {
  304. $this->_config['bucket_location'] = S3::LOCATION_US;
  305. }
  306. if (!@$this->_s3->putBucket($this->_config['bucket'], $this->_config['bucket_acl'], $this->_config['bucket_location'])) {
  307. $error = sprintf('Unable to create bucket: %s (%s).', $this->_config['bucket'], $this->_get_last_error());
  308. $this->_restore_error_handler();
  309. return false;
  310. }
  311. $this->_restore_error_handler();
  312. return true;
  313. }
  314. }