PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/sharpmachine/wakeupmedia.com
PHP | 775 lines | 472 code | 128 blank | 175 comment | 84 complexity | 869d1f8ad5772c7157346e8d25e4782a MD5 | raw file
  1. <?php
  2. /**
  3. * W3 Total Cache CDN Plugin
  4. */
  5. if (!defined('W3TC')) {
  6. die();
  7. }
  8. require_once W3TC_INC_DIR . '/functions/file.php';
  9. require_once W3TC_LIB_W3_DIR . '/Plugin.php';
  10. /**
  11. * Class W3_Plugin_Cdn
  12. */
  13. class W3_Plugin_Cdn extends W3_Plugin {
  14. /**
  15. * CDN reject reason
  16. *
  17. * @var string
  18. */
  19. var $cdn_reject_reason = '';
  20. /**
  21. * Run plugin
  22. */
  23. function run() {
  24. add_filter('cron_schedules', array(
  25. &$this,
  26. 'cron_schedules'
  27. ));
  28. $cdn_engine = $this->_config->get_string('cdn.engine');
  29. if (!w3_is_cdn_mirror($cdn_engine)) {
  30. add_action('delete_attachment', array(
  31. &$this,
  32. 'delete_attachment'
  33. ));
  34. add_filter('update_attached_file', array(
  35. &$this,
  36. 'update_attached_file'
  37. ));
  38. add_filter('wp_update_attachment_metadata', array(
  39. &$this,
  40. 'update_attachment_metadata'
  41. ));
  42. add_action('w3_cdn_cron_queue_process', array(
  43. &$this,
  44. 'cron_queue_process'
  45. ));
  46. add_action('w3_cdn_cron_upload', array(
  47. &$this,
  48. 'cron_upload'
  49. ));
  50. add_action('switch_theme', array(
  51. &$this,
  52. 'switch_theme'
  53. ));
  54. add_filter('update_feedback', array(
  55. &$this,
  56. 'update_feedback'
  57. ));
  58. }
  59. /**
  60. * Start rewrite engine
  61. */
  62. if ($this->can_cdn()) {
  63. ob_start(array(
  64. &$this,
  65. 'ob_callback'
  66. ));
  67. }
  68. }
  69. /**
  70. * Instantiates worker with admin functionality on demand
  71. *
  72. * @return W3_Plugin_CdnAdmin
  73. */
  74. function &_get_admin() {
  75. return w3_instance('W3_Plugin_CdnAdmin');
  76. }
  77. /**
  78. * Instantiates worker with common functionality on demand
  79. *
  80. * @return W3_Plugin_CdnCommon
  81. */
  82. function &_get_common() {
  83. return w3_instance('W3_Plugin_CdnCommon');
  84. }
  85. /**
  86. * Activate plugin action (called by W3_PluginProxy)
  87. */
  88. function activate() {
  89. $this->_get_admin()->activate();
  90. }
  91. /**
  92. * Deactivate plugin action (called by W3_PluginProxy)
  93. */
  94. function deactivate() {
  95. $this->_get_admin()->deactivate();
  96. }
  97. /**
  98. * Cron queue process event
  99. */
  100. function cron_queue_process() {
  101. $queue_limit = $this->_config->get_integer('cdn.queue.limit');
  102. $this->_get_admin()->queue_process($queue_limit);
  103. }
  104. /**
  105. * Cron upload event
  106. */
  107. function cron_upload() {
  108. $files = $this->get_files();
  109. $document_root = w3_get_document_root();
  110. $upload = array();
  111. $results = array();
  112. foreach ($files as $file) {
  113. $upload[$document_root . '/' . $file] = $file;
  114. }
  115. $this->_get_common()->upload($upload, true, $results);
  116. }
  117. /**
  118. * Update attachment file
  119. *
  120. * Upload _wp_attached_file
  121. *
  122. * @param string $attached_file
  123. * @return string
  124. */
  125. function update_attached_file($attached_file) {
  126. $files = $this->_get_common()->get_files_for_upload($attached_file);
  127. $files = apply_filters('w3tc_cdn_update_attachment', $files);
  128. $results = array();
  129. $this->_get_common()->upload($files, true, $results);
  130. return $attached_file;
  131. }
  132. /**
  133. * On attachment delete action
  134. *
  135. * Delete _wp_attached_file, _wp_attachment_metadata, _wp_attachment_backup_sizes
  136. *
  137. * @param integer $attachment_id
  138. */
  139. function delete_attachment($attachment_id) {
  140. $files = $this->_get_common()->get_attachment_files($attachment_id);
  141. $files = apply_filters('w3tc_cdn_delete_attachment', $files);
  142. $results = array();
  143. $this->_get_common()->delete($files, true, $results);
  144. }
  145. /**
  146. * Update attachment metadata filter
  147. *
  148. * Upload _wp_attachment_metadata
  149. *
  150. * @param array $metadata
  151. * @return array
  152. */
  153. function update_attachment_metadata($metadata) {
  154. $files = $this->_get_common()->get_metadata_files($metadata);
  155. $files = apply_filters('w3tc_cdn_update_attachment_metadata', $files);
  156. $results = array();
  157. $this->_get_common()->upload($files, true, $results);
  158. return $metadata;
  159. }
  160. /**
  161. * Cron schedules filter
  162. *
  163. * @param array $schedules
  164. * @return array
  165. */
  166. function cron_schedules($schedules) {
  167. $queue_interval = $this->_config->get_integer('cdn.queue.interval');
  168. $autoupload_interval = $this->_config->get_integer('cdn.autoupload.interval');
  169. return array_merge($schedules, array(
  170. 'w3_cdn_cron_queue_process' => array(
  171. 'interval' => $queue_interval,
  172. 'display' => sprintf('[W3TC] CDN queue process (every %d seconds)', $queue_interval)
  173. ),
  174. 'w3_cdn_cron_upload' => array(
  175. 'interval' => $autoupload_interval,
  176. 'display' => sprintf('[W3TC] CDN auto upload (every %d seconds)', $autoupload_interval)
  177. )
  178. ));
  179. }
  180. /**
  181. * Switch theme action
  182. */
  183. function switch_theme() {
  184. $this->_config->set('notes.theme_changed', true);
  185. $this->_config->save();
  186. }
  187. /**
  188. * WP Upgrade action hack
  189. *
  190. * @param string $message
  191. */
  192. function update_feedback($message) {
  193. if ($message == __('Upgrading database')) {
  194. $this->_config->set('notes.wp_upgraded', true);
  195. $this->_config->save();
  196. }
  197. }
  198. /**
  199. * OB Callback
  200. *
  201. * @param string $buffer
  202. * @return string
  203. */
  204. function ob_callback(&$buffer) {
  205. if ($buffer != '' && w3_is_xml($buffer)) {
  206. if ($this->can_cdn2($buffer)) {
  207. $regexps = array();
  208. $site_path = w3_get_site_path();
  209. $domain_url_regexp = w3_get_domain_url_regexp();
  210. if ($this->_config->get_boolean('cdn.uploads.enable')) {
  211. require_once W3TC_INC_DIR . '/functions/http.php';
  212. $upload_info = w3_upload_info();
  213. if ($upload_info) {
  214. if (preg_match('~' . $domain_url_regexp . '~i', $upload_info['baseurl'])) {
  215. $regexps[] = '~(["\'])((' . $domain_url_regexp . ')?(' . w3_preg_quote($upload_info['baseurlpath']) . '([^"\'>]+)))~';
  216. } else {
  217. $regexps[] = '~(["\'])((' . w3_preg_quote($upload_info['baseurl']) . ')(([^"\'>]+)))~';
  218. }
  219. }
  220. }
  221. if ($this->_config->get_boolean('cdn.includes.enable')) {
  222. $mask = $this->_config->get_string('cdn.includes.files');
  223. if ($mask != '') {
  224. $regexps[] = '~(["\'])((' . $domain_url_regexp . ')?(' . w3_preg_quote($site_path . WPINC) . '/(' . $this->get_regexp_by_mask($mask) . ')))~';
  225. }
  226. }
  227. if ($this->_config->get_boolean('cdn.theme.enable')) {
  228. $theme_dir = preg_replace('~' . $domain_url_regexp . '~i', '', get_theme_root_uri());
  229. $mask = $this->_config->get_string('cdn.theme.files');
  230. if ($mask != '') {
  231. $regexps[] = '~(["\'])((' . $domain_url_regexp . ')?(' . w3_preg_quote($theme_dir) . '/(' . $this->get_regexp_by_mask($mask) . ')))~';
  232. }
  233. }
  234. if ($this->_config->get_boolean('cdn.minify.enable')) {
  235. if ($this->_config->get_boolean('minify.auto')) {
  236. $regexps[] = '~(["\'])((' . $domain_url_regexp . ')?(' . w3_preg_quote($site_path . W3TC_CONTENT_MINIFY_DIR_NAME) . '/[a-f0-9]+\.[a-f0-9]+\.(css|js)))~U';
  237. } else {
  238. $regexps[] = '~(["\'])((' . $domain_url_regexp . ')?(' . w3_preg_quote($site_path . W3TC_CONTENT_MINIFY_DIR_NAME) . '/[a-f0-9]+/.+\.include(-(footer|body))?(-nb)?\.[a-f0-9]+\.(css|js)))~U';
  239. }
  240. }
  241. if ($this->_config->get_boolean('cdn.custom.enable')) {
  242. $masks = $this->_config->get_array('cdn.custom.files');
  243. $masks = array_map('w3_parse_path', $masks);
  244. if (count($masks)) {
  245. $mask_regexps = array();
  246. foreach ($masks as $mask) {
  247. if ($mask != '') {
  248. $mask = w3_normalize_file($mask);
  249. $mask_regexps[] = $this->get_regexp_by_mask($mask);
  250. }
  251. }
  252. $regexps[] = '~(["\'])((' . $domain_url_regexp . ')?(' . w3_preg_quote($site_path) . '(' . implode('|', $mask_regexps) . ')))~i';
  253. }
  254. }
  255. foreach ($regexps as $regexp) {
  256. $buffer = preg_replace_callback($regexp, array(
  257. &$this,
  258. 'link_replace_callback'
  259. ), $buffer);
  260. }
  261. }
  262. if ($this->_config->get_boolean('cdn.debug')) {
  263. $buffer .= "\r\n\r\n" . $this->get_debug_info();
  264. }
  265. }
  266. return $buffer;
  267. }
  268. /**
  269. * Returns array of files to upload
  270. *
  271. * @return array
  272. */
  273. function get_files() {
  274. $files = array();
  275. if ($this->_config->get_boolean('cdn.includes.enable')) {
  276. $files = array_merge($files, $this->get_files_includes());
  277. }
  278. if ($this->_config->get_boolean('cdn.theme.enable')) {
  279. $files = array_merge($files, $this->get_files_theme());
  280. }
  281. if ($this->_config->get_boolean('cdn.minify.enable')) {
  282. $files = array_merge($files, $this->get_files_minify());
  283. }
  284. if ($this->_config->get_boolean('cdn.custom.enable')) {
  285. $files = array_merge($files, $this->get_files_custom());
  286. }
  287. return $files;
  288. }
  289. /**
  290. * Exports includes to CDN
  291. *
  292. * @return array
  293. */
  294. function get_files_includes() {
  295. $includes_root = w3_path(ABSPATH . WPINC);
  296. $site_root = w3_get_site_root();
  297. $includes_path = ltrim(str_replace($site_root, rtrim(w3_get_site_path(), '/'), $includes_root), '/');
  298. $files = $this->search_files($includes_root, $includes_path, $this->_config->get_string('cdn.includes.files'));
  299. return $files;
  300. }
  301. /**
  302. * Exports theme to CDN
  303. *
  304. * @return array
  305. */
  306. function get_files_theme() {
  307. /**
  308. * If mobile or referrer support enabled
  309. * we should upload whole themes directory
  310. */
  311. if ($this->_config->get_boolean('mobile.enabled') || $this->_config->get_boolean('referrer.enabled')) {
  312. $themes_root = get_theme_root();
  313. } else {
  314. $themes_root = get_stylesheet_directory();
  315. }
  316. $themes_root = w3_path($themes_root);
  317. $site_root = w3_get_site_root();
  318. $themes_path = ltrim(str_replace($site_root, rtrim(w3_get_site_path(), '/'), $themes_root), '/');
  319. $files = $this->search_files($themes_root, $themes_path, $this->_config->get_string('cdn.theme.files'));
  320. return $files;
  321. }
  322. /**
  323. * Exports min files to CDN
  324. *
  325. * @return array
  326. */
  327. function get_files_minify() {
  328. $files = array();
  329. if (W3TC_PHP5 && $this->_config->get_boolean('minify.rewrite') && (!$this->_config->get_boolean('minify.auto') || w3_is_cdn_mirror($this->_config->get_string('cdn.engine')))) {
  330. require_once W3TC_INC_DIR . '/functions/http.php';
  331. $minify = & w3_instance('W3_Plugin_Minify');
  332. $document_root = w3_get_document_root();
  333. $site_root = w3_get_site_root();
  334. $minify_root = w3_path(W3TC_CACHE_FILE_MINIFY_DIR);
  335. $minify_path = ltrim(str_replace($site_root, rtrim(w3_get_site_path(), '/'), $minify_root), '/');
  336. $urls = $minify->get_urls();
  337. if ($this->_config->get_string('minify.engine') == 'file') {
  338. foreach ($urls as $url) {
  339. w3_http_get($url);
  340. }
  341. $files = $this->search_files($minify_root, $minify_path, '*.css;*.js');
  342. } else {
  343. foreach ($urls as $url) {
  344. $file = w3_normalize_file_minify($url);
  345. $file = w3_translate_file($file);
  346. if (!w3_is_url($file)) {
  347. $file = $document_root . '/' . $file;
  348. $file = ltrim(str_replace($minify_root, '', $file), '/');
  349. $dir = dirname($file);
  350. if ($dir) {
  351. w3_mkdir($dir, 0777, $minify_root);
  352. }
  353. if (w3_download($url, $minify_root . '/' . $file) !== false) {
  354. $files[] = $minify_path . '/' . $file;
  355. }
  356. }
  357. }
  358. }
  359. }
  360. return $files;
  361. }
  362. /**
  363. * Exports custom files to CDN
  364. *
  365. * @return array
  366. */
  367. function get_files_custom() {
  368. $files = array();
  369. $document_root = w3_get_document_root();
  370. $custom_files = $this->_config->get_array('cdn.custom.files');
  371. $custom_files = array_map('w3_parse_path', $custom_files);
  372. foreach ($custom_files as $custom_file) {
  373. if ($custom_file != '') {
  374. $custom_file = w3_normalize_file($custom_file);
  375. $dir = trim(dirname($custom_file), '/\\');
  376. if ($dir == '.') {
  377. $dir = '';
  378. }
  379. $mask = basename($custom_file);
  380. $files = array_merge($files, $this->search_files($document_root . '/' . $dir, $dir, $mask));
  381. }
  382. }
  383. return $files;
  384. }
  385. /**
  386. * Link replace callback
  387. *
  388. * @param array $matches
  389. * @return string
  390. */
  391. function link_replace_callback($matches) {
  392. global $wpdb;
  393. static $queue = null, $reject_files = null;
  394. list($match, $quote, $url, , , , $path) = $matches;
  395. $path = ltrim($path, '/');
  396. /**
  397. * Check if URL was already replaced
  398. */
  399. if (isset($this->replaced_urls[$url])) {
  400. return $quote . $this->replaced_urls[$url];
  401. }
  402. /**
  403. * Check URL for rejected files
  404. */
  405. if ($reject_files === null) {
  406. $reject_files = $this->_config->get_array('cdn.reject.files');
  407. }
  408. foreach ($reject_files as $reject_file) {
  409. if ($reject_file != '') {
  410. $reject_file = w3_normalize_file($reject_file);
  411. $reject_file_regexp = '~^(' . $this->get_regexp_by_mask($reject_file) . ')~i';
  412. if (preg_match($reject_file_regexp, $path)) {
  413. return $match;
  414. }
  415. }
  416. }
  417. /**
  418. * Don't replace URL for files that are in the CDN queue
  419. */
  420. if ($queue === null) {
  421. if (!w3_is_cdn_mirror($this->_config->get_string('cdn.engine'))) {
  422. $sql = sprintf('SELECT remote_path FROM %s', $wpdb->prefix . W3TC_CDN_TABLE_QUEUE);
  423. $queue = $wpdb->get_col($sql);
  424. } else {
  425. $queue = false;
  426. }
  427. }
  428. if ($queue && in_array($path, $queue)) {
  429. return $match;
  430. }
  431. /**
  432. * Do replacement
  433. */
  434. $cdn = & $this->_get_common()->get_cdn();
  435. $new_url = $cdn->format_url($path);
  436. if ($new_url) {
  437. $this->replaced_urls[$url] = $new_url;
  438. return $quote . $new_url;
  439. }
  440. return $match;
  441. }
  442. /**
  443. * Search files
  444. *
  445. * @param string $search_dir
  446. * @param string $base_dir
  447. * @param string $mask
  448. * @param boolean $recursive
  449. * @return array
  450. */
  451. function search_files($search_dir, $base_dir, $mask = '*.*', $recursive = true) {
  452. static $stack = array();
  453. $files = array();
  454. $ignore = array(
  455. '.svn',
  456. '.git',
  457. '.DS_Store',
  458. 'CVS',
  459. 'Thumbs.db',
  460. 'desktop.ini'
  461. );
  462. $dir = @opendir($search_dir);
  463. if ($dir) {
  464. while (($entry = @readdir($dir)) !== false) {
  465. if ($entry != '.' && $entry != '..' && !in_array($entry, $ignore)) {
  466. $path = $search_dir . '/' . $entry;
  467. if (@is_dir($path) && $recursive) {
  468. array_push($stack, $entry);
  469. $files = array_merge($files, $this->search_files($path, $base_dir, $mask, $recursive));
  470. array_pop($stack);
  471. } else {
  472. $regexp = '~^(' . $this->get_regexp_by_mask($mask) . ')$~i';
  473. if (preg_match($regexp, $entry)) {
  474. $files[] = ($base_dir != '' ? $base_dir . '/' : '') . (($p = implode('/', $stack)) != '' ? $p . '/' : '') . $entry;
  475. }
  476. }
  477. }
  478. }
  479. @closedir($dir);
  480. }
  481. return $files;
  482. }
  483. /**
  484. * Returns regexp by mask
  485. *
  486. * @param string $mask
  487. * @return string
  488. */
  489. function get_regexp_by_mask($mask) {
  490. $mask = trim($mask);
  491. $mask = w3_preg_quote($mask);
  492. $mask = str_replace(array(
  493. '\*',
  494. '\?',
  495. ';'
  496. ), array(
  497. '@ASTERISK@',
  498. '@QUESTION@',
  499. '|'
  500. ), $mask);
  501. $regexp = str_replace(array(
  502. '@ASTERISK@',
  503. '@QUESTION@'
  504. ), array(
  505. '[^\\?\\*:\\|"<>]*',
  506. '[^\\?\\*:\\|"<>]'
  507. ), $mask);
  508. return $regexp;
  509. }
  510. /**
  511. * Returns debug info
  512. *
  513. * @return string
  514. */
  515. function get_debug_info() {
  516. $debug_info = "<!-- W3 Total Cache: CDN debug info:\r\n";
  517. $debug_info .= sprintf("%s%s\r\n", str_pad('Engine: ', 20), $this->_config->get_string('cdn.engine'));
  518. if ($this->cdn_reject_reason) {
  519. $debug_info .= sprintf("%s%s\r\n", str_pad('Reject reason: ', 20), $this->cdn_reject_reason);
  520. }
  521. if (count($this->replaced_urls)) {
  522. $debug_info .= "\r\nReplaced URLs:\r\n";
  523. foreach ($this->replaced_urls as $old_url => $new_url) {
  524. $debug_info .= sprintf("%s => %s\r\n", w3_escape_comment($old_url), w3_escape_comment($new_url));
  525. }
  526. }
  527. $debug_info .= '-->';
  528. return $debug_info;
  529. }
  530. /**
  531. * Check if we can do CDN logic
  532. * @return boolean
  533. */
  534. function can_cdn() {
  535. /**
  536. * Skip if admin
  537. */
  538. if (defined('WP_ADMIN')) {
  539. $this->cdn_reject_reason = 'wp-admin';
  540. return false;
  541. }
  542. /**
  543. * Check for WPMU's and WP's 3.0 short init
  544. */
  545. if (defined('SHORTINIT') && SHORTINIT) {
  546. $this->cdn_reject_reason = 'Short init';
  547. return false;
  548. }
  549. /**
  550. * Check User agent
  551. */
  552. if (!$this->check_ua()) {
  553. $this->cdn_reject_reason = 'user agent is rejected';
  554. return false;
  555. }
  556. /**
  557. * Check request URI
  558. */
  559. if (!$this->check_request_uri()) {
  560. $this->cdn_reject_reason = 'request URI is rejected';
  561. return false;
  562. }
  563. return true;
  564. }
  565. /**
  566. * Returns true if we can do CDN logic
  567. *
  568. * @param $buffer
  569. * @return string
  570. */
  571. function can_cdn2(&$buffer) {
  572. /**
  573. * Check for database error
  574. */
  575. if (w3_is_database_error($buffer)) {
  576. $this->cdn_reject_reason = 'Database Error occurred';
  577. return false;
  578. }
  579. /**
  580. * Check for DONOTCDN constant
  581. */
  582. if (defined('DONOTCDN') && DONOTCDN) {
  583. $this->cdn_reject_reason = 'DONOTCDN constant is defined';
  584. return false;
  585. }
  586. /**
  587. * Check logged in admin
  588. */
  589. if ($this->_config->get_boolean('cdn.reject.admins') && current_user_can('manage_options')) {
  590. $this->cdn_reject_reason = 'logged in admin is rejected';
  591. return false;
  592. }
  593. return true;
  594. }
  595. /**
  596. * Checks User Agent
  597. *
  598. * @return boolean
  599. */
  600. function check_ua() {
  601. $uas = array_merge($this->_config->get_array('cdn.reject.ua'), array(
  602. W3TC_POWERED_BY
  603. ));
  604. foreach ($uas as $ua) {
  605. if (isset($_SERVER['HTTP_USER_AGENT']) && stristr($_SERVER['HTTP_USER_AGENT'], $ua) !== false) {
  606. return false;
  607. }
  608. }
  609. return true;
  610. }
  611. /**
  612. * Checks request URI
  613. *
  614. * @return boolean
  615. */
  616. function check_request_uri() {
  617. $auto_reject_uri = array(
  618. 'wp-login',
  619. 'wp-register'
  620. );
  621. foreach ($auto_reject_uri as $uri) {
  622. if (strstr($_SERVER['REQUEST_URI'], $uri) !== false) {
  623. return false;
  624. }
  625. }
  626. $reject_uri = $this->_config->get_array('cdn.reject.uri');
  627. $reject_uri = array_map('w3_parse_path', $reject_uri);
  628. foreach ($reject_uri as $expr) {
  629. $expr = trim($expr);
  630. if ($expr != '' && preg_match('~' . $expr . '~i', $_SERVER['REQUEST_URI'])) {
  631. return false;
  632. }
  633. }
  634. return true;
  635. }
  636. }