PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://github.com/EthanBlast/Glam-Star-Life
PHP | 452 lines | 374 code | 27 blank | 51 comment | 16 complexity | 5527f86d0e3dfd0daab2e05970bd99f2 MD5 | raw file
  1. <?php
  2. /**
  3. * Amazon S3 CDN engine
  4. */
  5. require_once W3TC_LIB_W3_DIR . '/Cdn/Base.php';
  6. if (!class_exists('S3')) {
  7. require_once W3TC_LIB_DIR . '/S3.php';
  8. }
  9. /**
  10. * Class W3_Cdn_S3
  11. */
  12. class W3_Cdn_S3 extends W3_Cdn_Base
  13. {
  14. /**
  15. * S3 object
  16. *
  17. * @var S3
  18. */
  19. var $_s3 = null;
  20. /**
  21. * gzip extension
  22. *
  23. * @var string
  24. */
  25. var $_gzip_extension = '.gzip';
  26. /**
  27. * Last error
  28. *
  29. * @var string
  30. */
  31. var $_last_error = '';
  32. /**
  33. * Inits S3 object
  34. *
  35. * @param string $error
  36. * @return boolean
  37. */
  38. function _init(&$error)
  39. {
  40. if (empty($this->_config['key'])) {
  41. $error = 'Empty access key';
  42. return false;
  43. }
  44. if (empty($this->_config['secret'])) {
  45. $error = 'Empty secret key';
  46. return false;
  47. }
  48. if (empty($this->_config['bucket'])) {
  49. $error = 'Empty bucket';
  50. return false;
  51. }
  52. $this->_s3 = & new S3($this->_config['key'], $this->_config['secret'], false);
  53. return true;
  54. }
  55. /**
  56. * Uploads files to S3
  57. *
  58. * @param array $files
  59. * @param array $results
  60. * @param boolean $force_rewrite
  61. * @return boolean
  62. */
  63. function upload($files, &$results, $force_rewrite = false)
  64. {
  65. $count = 0;
  66. $error = null;
  67. if (!$this->_init($error)) {
  68. $results = $this->get_results($files, W3TC_CDN_RESULT_HALT, $error);
  69. return false;
  70. }
  71. foreach ($files as $local_path => $remote_path) {
  72. $result = $this->_upload($local_path, $remote_path, $force_rewrite);
  73. $results[] = $result;
  74. if ($result['result'] == W3TC_CDN_RESULT_OK) {
  75. $count++;
  76. }
  77. if ($this->_config['compression'] && $this->may_gzip($remote_path)) {
  78. $remote_path_gzip = $remote_path . $this->_gzip_extension;
  79. $result = $this->_upload_gzip($local_path, $remote_path_gzip, $force_rewrite);
  80. $results[] = $result;
  81. if ($result['result'] == W3TC_CDN_RESULT_OK) {
  82. $count++;
  83. }
  84. }
  85. }
  86. return $count;
  87. }
  88. /**
  89. * Uploads single file to S3
  90. *
  91. * @param string $local_path
  92. * @param string $remote_path
  93. * @param boolean $force_rewrite
  94. * @return array
  95. */
  96. function _upload($local_path, $remote_path, $force_rewrite = false)
  97. {
  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. $info = @$this->_s3->getObjectInfo($this->_config['bucket'], $remote_path);
  103. if ($info) {
  104. $hash = @md5_file($local_path);
  105. $s3_hash = (isset($info['hash']) ? $info['hash'] : '');
  106. if ($hash === $s3_hash) {
  107. return $this->get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, 'Object already exists');
  108. }
  109. }
  110. }
  111. $headers = $this->get_headers($local_path);
  112. $result = @$this->_s3->putObjectFile($local_path, $this->_config['bucket'], $remote_path, S3::ACL_PUBLIC_READ, array(), $headers);
  113. return $this->get_result($local_path, $remote_path, ($result ? W3TC_CDN_RESULT_OK : W3TC_CDN_RESULT_ERROR), ($result ? 'OK' : 'Unable to put object'));
  114. }
  115. /**
  116. * Uploads gzip version of file
  117. *
  118. * @param string $local_path
  119. * @param string $remote_path
  120. * @param boolean $force_rewrite
  121. * @return array
  122. */
  123. function _upload_gzip($local_path, $remote_path, $force_rewrite = false)
  124. {
  125. if (!function_exists('gzencode')) {
  126. return $this->get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, "GZIP library doesn't exists");
  127. }
  128. if (!file_exists($local_path)) {
  129. return $this->get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, 'Source file not found');
  130. }
  131. $contents = @file_get_contents($local_path);
  132. if ($contents === false) {
  133. return $this->get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, 'Unable to read file');
  134. }
  135. $data = gzencode($contents);
  136. if (!$force_rewrite) {
  137. $info = @$this->_s3->getObjectInfo($this->_config['bucket'], $remote_path);
  138. if ($info) {
  139. $hash = md5($data);
  140. $s3_hash = (isset($info['hash']) ? $info['hash'] : '');
  141. if ($hash === $s3_hash) {
  142. return $this->get_result($local_path, $remote_path, W3TC_CDN_RESULT_ERROR, 'Object already exists');
  143. }
  144. }
  145. }
  146. $headers = $this->get_headers($local_path);
  147. $headers = array_merge($headers, array(
  148. 'Vary' => 'Accept-Encoding',
  149. 'Content-Encoding' => 'gzip'
  150. ));
  151. $result = @$this->_s3->putObjectString($data, $this->_config['bucket'], $remote_path, S3::ACL_PUBLIC_READ, array(), $headers);
  152. return $this->get_result($local_path, $remote_path, ($result ? W3TC_CDN_RESULT_OK : W3TC_CDN_RESULT_ERROR), ($result ? 'OK' : 'Unable to put object'));
  153. }
  154. /**
  155. * Deletes files from FTP
  156. *
  157. * @param array $files
  158. * @param array $results
  159. * @return boolean
  160. */
  161. function delete($files, &$results)
  162. {
  163. $error = null;
  164. $count = 0;
  165. if (!$this->_init($error)) {
  166. $results = $this->get_results($files, W3TC_CDN_RESULT_HALT, $error);
  167. return false;
  168. }
  169. foreach ($files as $local_path => $remote_path) {
  170. $result = @$this->_s3->deleteObject($this->_config['bucket'], $remote_path);
  171. $results[] = $this->get_result($local_path, $remote_path, ($result ? W3TC_CDN_RESULT_OK : W3TC_CDN_RESULT_ERROR), ($result ? 'OK' : 'Unable to delete object'));
  172. if ($result) {
  173. $count++;
  174. }
  175. if ($this->_config['compression']) {
  176. $remote_path_gzip = $remote_path . $this->_gzip_extension;
  177. $result = @$this->_s3->deleteObject($this->_config['bucket'], $remote_path_gzip);
  178. $results[] = $this->get_result($local_path, $remote_path_gzip, ($result ? W3TC_CDN_RESULT_OK : W3TC_CDN_RESULT_ERROR), ($result ? 'OK' : 'Unable to delete object'));
  179. if ($result) {
  180. $count++;
  181. }
  182. }
  183. }
  184. return $count;
  185. }
  186. /**
  187. * Tests S3
  188. *
  189. * @param string $error
  190. * @return boolean
  191. */
  192. function test(&$error)
  193. {
  194. if (!parent::test($error)) {
  195. return false;
  196. }
  197. $string = 'test_s3_' . md5(time());
  198. if (!$this->_init($error)) {
  199. return false;
  200. }
  201. $this->set_error_handler();
  202. $buckets = @$this->_s3->listBuckets();
  203. if (!$buckets) {
  204. $error = sprintf('Unable to list buckets (%s).', $this->get_last_error());
  205. $this->restore_error_handler();
  206. return false;
  207. }
  208. if (!in_array($this->_config['bucket'], (array) $buckets)) {
  209. $error = sprintf('Bucket doesn\'t exist: %s', $this->_config['bucket']);
  210. $this->restore_error_handler();
  211. return false;
  212. }
  213. if (!@$this->_s3->putObjectString($string, $this->_config['bucket'], $string, S3::ACL_PUBLIC_READ)) {
  214. $error = sprintf('Unable to put object (%s).', $this->get_last_error());
  215. $this->restore_error_handler();
  216. return false;
  217. }
  218. if (!($object = @$this->_s3->getObject($this->_config['bucket'], $string))) {
  219. $error = sprintf('Unable to get object (%s).', $this->get_last_error());
  220. $this->restore_error_handler();
  221. return false;
  222. }
  223. if ($object->body != $string) {
  224. @$this->_s3->deleteObject($this->_config['bucket'], $string);
  225. $error = 'Objects are not equal.';
  226. $this->restore_error_handler();
  227. return false;
  228. }
  229. if (!@$this->_s3->deleteObject($this->_config['bucket'], $string)) {
  230. $error = sprintf('Unable to delete object (%s).', $this->get_last_error());
  231. $this->restore_error_handler();
  232. return false;
  233. }
  234. $this->restore_error_handler();
  235. return true;
  236. }
  237. /**
  238. * Returns CDN domain
  239. *
  240. * @return string
  241. */
  242. function get_domains()
  243. {
  244. if (!empty($this->_config['cname'])) {
  245. return (array) $this->_config['cname'];
  246. } elseif (!empty($this->_config['bucket'])) {
  247. $domain = sprintf('%s.s3.amazonaws.com', $this->_config['bucket']);
  248. return array(
  249. $domain
  250. );
  251. }
  252. return array();
  253. }
  254. /**
  255. * Returns via string
  256. *
  257. * @return string
  258. */
  259. function get_via()
  260. {
  261. return sprintf('Amazon Web Services: S3: %s', parent::get_via());
  262. }
  263. /**
  264. * Creates bucket
  265. *
  266. * @param string $container_id
  267. * @param string $error
  268. * @return boolean
  269. */
  270. function create_container(&$container_id, &$error)
  271. {
  272. if (!$this->_init($error)) {
  273. return false;
  274. }
  275. $this->set_error_handler();
  276. $buckets = @$this->_s3->listBuckets();
  277. if (!$buckets) {
  278. $error = sprintf('Unable to list buckets (%s).', $this->get_last_error());
  279. $this->restore_error_handler();
  280. return false;
  281. }
  282. if (in_array($this->_config['bucket'], (array) $buckets)) {
  283. $error = sprintf('Bucket already exists: %s.', $this->_config['bucket']);
  284. $this->restore_error_handler();
  285. return false;
  286. }
  287. if (!@$this->_s3->putBucket($this->_config['bucket'], S3::ACL_PUBLIC_READ)) {
  288. $error = sprintf('Unable to create bucket: %s (%s).', $this->_config['bucket'], $this->get_last_error());
  289. $this->restore_error_handler();
  290. return false;
  291. }
  292. $this->restore_error_handler();
  293. return true;
  294. }
  295. /**
  296. * Formats URL for object
  297. * @param string $path
  298. * @return string
  299. */
  300. function format_url($path)
  301. {
  302. $url = parent::format_url($path);
  303. if ($this->_config['compression'] && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && stristr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false && $this->may_gzip($path)) {
  304. if (($qpos = strpos($url, '?')) !== false) {
  305. $url = substr_replace($url, $this->_gzip_extension, $qpos, 0);
  306. } else {
  307. $url .= $this->_gzip_extension;
  308. }
  309. return $url;
  310. }
  311. return $url;
  312. }
  313. /**
  314. * Our error handler
  315. *
  316. * @param integer $errno
  317. * @param string $errstr
  318. * @return boolean
  319. */
  320. function error_handler($errno, $errstr)
  321. {
  322. $this->_last_error = $errstr;
  323. return false;
  324. }
  325. /**
  326. * Returns last error
  327. *
  328. * @return string
  329. */
  330. function get_last_error()
  331. {
  332. return $this->_last_error;
  333. }
  334. /**
  335. * Set our error handler
  336. *
  337. * @return void
  338. */
  339. function set_error_handler()
  340. {
  341. set_error_handler(array(
  342. &$this,
  343. 'error_handler'
  344. ));
  345. }
  346. /**
  347. * Restore prev error handler
  348. *
  349. * @return void
  350. */
  351. function restore_error_handler()
  352. {
  353. restore_error_handler();
  354. }
  355. }