PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/wp-minify/wp-minify.php

https://github.com/gregoryo/nycga2
PHP | 932 lines | 718 code | 135 blank | 79 comment | 148 complexity | 02903eb5673232f8ea883cf60e98914e MD5 | raw file
Possible License(s): AGPL-1.0, GPL-3.0, GPL-2.0, LGPL-2.1
  1. <?php
  2. /*
  3. Plugin Name: WP Minify
  4. Plugin URI: http://omninoggin.com/wordpress-plugins/wp-minify-wordpress-plugin/
  5. Description: This plugin uses the Minify engine to combine and compress JS and CSS files to improve page load time.
  6. Version: 1.1.8
  7. Author: Thaya Kareeson
  8. Author URI: http://omninoggin.com
  9. */
  10. /*
  11. Copyright 2009-2011 Thaya Kareeson (email : thaya.kareeson@gmail.com)
  12. This program is free software: you can redistribute it and/or modify
  13. it under the terms of the GNU General Public License as published by
  14. the Free Software Foundation, either version 3 of the License, or
  15. (at your option) any later version.
  16. This program is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. GNU General Public License for more details.
  20. You should have received a copy of the GNU General Public License
  21. along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. class WPMinify {
  24. var $author_homepage = 'http://omninoggin.com/';
  25. var $homepage = 'http://omninoggin.com/wordpress-plugins/wp-minify-wordpress-plugin/';
  26. var $name = 'wp_minify';
  27. var $name_dashed = 'wp-minify';
  28. var $name_proper = 'WP Minify';
  29. var $required_wp_version = '2.7';
  30. var $version = '1.1.8';
  31. var $c = null;
  32. var $debug = false;
  33. var $cache_location = 'wp-content/plugins/wp-minify/cache/';
  34. var $url_len_limit = 2000;
  35. var $minify_limit = 50;
  36. var $buffer_started = false;
  37. var $default_exclude = array();
  38. function WPMinify() {
  39. // initialize common functions
  40. $this->c = new WPMinifyCommon($this);
  41. // load translation
  42. $this->c->load_text_domain();
  43. // register admin scripts
  44. add_action('admin_init', array($this->c, 'a_register_scripts'));
  45. add_action('admin_init', array($this->c, 'a_register_styles'));
  46. // check wp version
  47. add_action('admin_head', array($this->c, 'a_check_version'));
  48. // load admin menu
  49. add_action('admin_menu', array($this, 'a_menu'));
  50. // register ajax handler
  51. add_action('wp_ajax_wpm', array($this, 'a_ajax_handler'));
  52. // No need to minify admin stuff
  53. if (!is_admin() && !is_feed() && !defined('XMLRPC_REQUEST')) {
  54. // Don't minify if if user passes wp-minify-off=1 in GET parameter
  55. if (!(isset($_GET['wp-minify-off']) && $_GET['wp-minify-off'])) {
  56. add_action('init', array($this, 'pre_content'), 99999);
  57. add_action('wp_footer', array($this, 'post_content'));
  58. }
  59. // advertise hook
  60. add_action('wp_footer', array($this, 'advertise'));
  61. }
  62. }
  63. // admin functions
  64. function a_default_options() {
  65. return array(
  66. 'cache_external' => false,
  67. 'cache_interval' => 900,
  68. 'css_exclude' => array(),
  69. 'css_include' => array(),
  70. 'debug_nominify' => false,
  71. 'debug_firephp' => false,
  72. 'enable_css' => true,
  73. 'enable_js' => true,
  74. 'enable_html' => true,
  75. 'auto_base' => true,
  76. 'extra_minify_options' => '',
  77. 'js_exclude' => array(),
  78. 'js_include' => array(),
  79. 'js_in_footer' => false,
  80. 'force_https' => false,
  81. 'pretty_url' => false,
  82. 'show_link' => true,
  83. 'show_advanced' => false,
  84. 'uri_exclude' => array(),
  85. 'version' => $this->version,
  86. 'deprecated' => array(
  87. 'wp_path', 'debug', 'debug_noprettyurl'
  88. )
  89. );
  90. }
  91. function a_update_options() {
  92. // new options
  93. $wpm_new_options = stripslashes_deep($_POST['wpm_options_update']);
  94. // current options
  95. $wpm_current_options = get_option($this->name);
  96. // convert "on" to true and "off" to false for checkbox fields
  97. // and set defaults for fields that are left blank
  98. if (isset($wpm_new_options['show_link']) && $wpm_new_options['show_link'] == "on")
  99. $wpm_new_options['show_link'] = true;
  100. else
  101. $wpm_new_options['show_link'] = false;
  102. if (isset($wpm_new_options['enable_js']))
  103. $wpm_new_options['enable_js'] = true;
  104. else
  105. $wpm_new_options['enable_js'] = false;
  106. if (isset($wpm_new_options['enable_css']))
  107. $wpm_new_options['enable_css'] = true;
  108. else
  109. $wpm_new_options['enable_css'] = false;
  110. if (isset($wpm_new_options['enable_html']))
  111. $wpm_new_options['enable_html'] = true;
  112. else
  113. $wpm_new_options['enable_html'] = false;
  114. if (isset($wpm_new_options['auto_base']))
  115. $wpm_new_options['auto_base'] = true;
  116. else
  117. $wpm_new_options['auto_base'] = false;
  118. if (isset($wpm_new_options['cache_external']))
  119. $wpm_new_options['cache_external'] = true;
  120. else
  121. $wpm_new_options['cache_external'] = false;
  122. if (isset($wpm_new_options['js_in_footer']))
  123. $wpm_new_options['js_in_footer'] = true;
  124. else
  125. $wpm_new_options['js_in_footer'] = false;
  126. if (isset($wpm_new_options['pretty_url']))
  127. $wpm_new_options['pretty_url'] = true;
  128. else
  129. $wpm_new_options['pretty_url'] = false;
  130. if (isset($wpm_new_options['debug_nominify']))
  131. $wpm_new_options['debug_nominify'] = true;
  132. else
  133. $wpm_new_options['debug_nominify'] = false;
  134. if (isset($wpm_new_options['debug_firephp']))
  135. $wpm_new_options['debug_firephp'] = true;
  136. else
  137. $wpm_new_options['debug_firephp'] = false;
  138. $this->a_set_minify_config($wpm_new_options['debug_nominify'], $wpm_new_options['debug_firephp']);
  139. if ( isset($wpm_new_options['force_https']) )
  140. $wpm_new_options['force_https'] = true;
  141. else
  142. $wpm_new_options['force_https'] = false;
  143. if (strlen(trim($wpm_new_options['js_include'])) > 0)
  144. $wpm_new_options['js_include'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['js_include'])));
  145. else
  146. $wpm_new_options['js_include'] = array();
  147. if (strlen(trim($wpm_new_options['js_exclude'])) > 0)
  148. $wpm_new_options['js_exclude'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['js_exclude'])));
  149. else
  150. $wpm_new_options['js_exclude'] = array();
  151. if (strlen(trim($wpm_new_options['css_include'])) > 0)
  152. $wpm_new_options['css_include'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['css_include'])));
  153. else
  154. $wpm_new_options['css_include'] = array();
  155. if (strlen(trim($wpm_new_options['css_exclude'])) > 0)
  156. $wpm_new_options['css_exclude'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['css_exclude'])));
  157. else
  158. $wpm_new_options['css_exclude'] = array();
  159. if ( strlen(trim($wpm_new_options['uri_exclude'])) > 0 )
  160. $wpm_new_options['uri_exclude'] = $this->array_trim(split(chr(10), str_replace(chr(13), '', $wpm_new_options['uri_exclude'])));
  161. else
  162. $wpm_new_options['uri_exclude'] = array();
  163. // Update options
  164. foreach ($wpm_new_options as $key => $value) {
  165. $wpm_current_options[$key] = $value;
  166. }
  167. update_option($this->name, $wpm_current_options);
  168. }
  169. function a_set_advanced_options($val) {
  170. $wpm_options = get_option($this->name);
  171. $wpm_options['show_advanced'] = $val;
  172. update_option($this->name, $wpm_options);
  173. }
  174. function a_ajax_handler() {
  175. check_ajax_referer($this->name);
  176. if (isset($_POST['wpm_action'])) {
  177. if (strtolower($_POST['wpm_action']) == 'show_advanced') {
  178. $this->a_set_advanced_options(true);
  179. }
  180. elseif (strtolower($_POST['wpm_action']) == 'hide_advanced') {
  181. $this->a_set_advanced_options(false);
  182. }
  183. else {
  184. echo 'Invalid wpm_action.';
  185. }
  186. }
  187. exit();
  188. }
  189. function a_request_handler() {
  190. if (isset($_POST['wpm_options_update_submit'])) {
  191. check_admin_referer($this->name);
  192. $this->a_update_options();
  193. add_action('admin_notices', array($this->c, 'a_notify_updated'));
  194. }
  195. elseif (isset($_POST['wpm_options_clear_cache_submit'])) {
  196. // if user wants to regenerate nonce
  197. check_admin_referer($this->name);
  198. $this->c->a_clear_cache();
  199. add_action('admin_notices', array($this->c, 'a_notify_cache_cleared'));
  200. }
  201. elseif (isset($_POST['wpm_options_upgrade_submit'])) {
  202. // if user wants to upgrade options (for new options on version upgrades)
  203. check_admin_referer($this->name);
  204. $this->c->a_upgrade_options();
  205. add_action('admin_notices', array($this->c, 'a_notify_upgraded'));
  206. }
  207. elseif (isset($_POST['wpm_options_reset_submit'])) {
  208. // if user wants to reset all options
  209. check_admin_referer($this->name);
  210. $this->c->a_reset_options();
  211. add_action('admin_notices', array($this->c, 'a_notify_reset'));
  212. }
  213. // only check these on plugin settings page
  214. $this->c->a_check_dir_writable($this->c->get_plugin_dir().'cache/', array($this, 'a_notify_cache_not_writable'));
  215. $this->c->a_check_orphan_options(array($this, 'a_notify_orphan_options'));
  216. if ($this->c->a_check_dir_writable($this->c->get_plugin_dir().'min/config.php', array($this, 'a_notify_config_not_writable'))) {
  217. $this->a_check_minify_config();
  218. }
  219. }
  220. function a_check_minify_config() {
  221. $fname = $this->c->get_plugin_dir().'min/config.php';
  222. $fhandle = fopen($fname,'r');
  223. $content = fread($fhandle,filesize($fname));
  224. $config_modified = false;
  225. preg_match('/\/\/###WPM-CACHE-PATH-BEFORE###(.*)\/\/###WPM-CACHE-PATH-AFTER###/s', $content, $matches);
  226. $cache_path_code = $matches[1];
  227. if (!preg_match('/\$min_cachePath.*?/', $cache_path_code)) {
  228. $content = preg_replace(
  229. '/\/\/###WPM-CACHE-PATH-BEFORE###(.*)\/\/###WPM-CACHE-PATH-AFTER###/s',
  230. "//###WPM-CACHE-PATH-BEFORE###\n".'$min_cachePath = \''.$this->c->get_plugin_dir()."cache/';\n//###WPM-CACHE-PATH-AFTER###",
  231. $content);
  232. $config_modified = true;
  233. }
  234. preg_match('/\/\/###WPM-CACHE-AGE-BEFORE###(.*)\/\/###WPM-CACHE-AGE-AFTER###/s', $content, $matches);
  235. $cache_age_code = $matches[1];
  236. if (!preg_match('/\$min_serveOptions\[\'maxAge\'].*?/', $cache_age_code)) {
  237. $content = preg_replace(
  238. '/\/\/###WPM-CACHE-AGE-BEFORE###(.*)\/\/###WPM-CACHE-AGE-AFTER###/s',
  239. "//###WPM-CACHE-AGE-BEFORE###\n".'$min_serveOptions[\'maxAge\'] = 2592000;'."\n//###WPM-CACHE-AGE-AFTER###",
  240. $content);
  241. $config_modified = true;
  242. }
  243. if ($config_modified) {
  244. $this->a_notify_modified_minify_config();
  245. }
  246. $fhandle = fopen($fname,"w");
  247. fwrite($fhandle,$content);
  248. fclose($fhandle);
  249. }
  250. function a_set_minify_config($nominify = false, $firephp = false) {
  251. if ($nominify) {
  252. $nominify = 'true';
  253. } else {
  254. $nominify = 'false';
  255. }
  256. if ($firephp) {
  257. $firephp = 'true';
  258. } else {
  259. $firephp = 'false';
  260. }
  261. $fname = $this->c->get_plugin_dir().'min/config.php';
  262. $fhandle = fopen($fname,'r');
  263. $content = fread($fhandle,filesize($fname));
  264. $content = preg_replace(
  265. '/\/\/###WPM-DEBUG-FLAG-BEFORE###(.*)\/\/###WPM-DEBUG-FLAG-AFTER###/s',
  266. "//###WPM-DEBUG-FLAG-BEFORE###\n".'$min_allowDebugFlag = '.$nominify.";\n//###WPM-DEBUG-FLAG-AFTER###",
  267. $content);
  268. $content = preg_replace(
  269. '/\/\/###WPM-ERROR-LOGGER-BEFORE###(.*)\/\/###WPM-ERROR-LOGGER-AFTER###/s',
  270. "//###WPM-ERROR-LOGGER-BEFORE###\n".'$min_errorLogger = '.$firephp.";\n//###WPM-ERROR-LOGGER-AFTER###",
  271. $content);
  272. $fhandle = fopen($fname,"w");
  273. fwrite($fhandle,$content);
  274. fclose($fhandle);
  275. }
  276. function a_notify_cache_not_writable() {
  277. $this->c->a_notify(
  278. sprintf('%s: %s',
  279. __('Cache directory is not writable. Please grant your server write permissions to the directory', $this->name),
  280. $this->c->get_plugin_dir().'cache/'),
  281. true);
  282. }
  283. function a_notify_config_not_writable() {
  284. $this->c->a_notify(
  285. sprintf('%s: %s',
  286. __('Minify Engine config.php is not writable. Please grant your server write permissions to file', $this->name),
  287. $this->c->get_plugin_dir().'min/config.php'));
  288. }
  289. function a_notify_orphan_options() {
  290. $this->c->a_notify(
  291. sprintf('%s',
  292. __('Some option settings are missing (possibly from plugin upgrade).', $this->name)));
  293. }
  294. function a_notify_modified_minify_config() {
  295. $this->c->a_notify(__('Minify Engine config.php was configured automatically.', $this->name));
  296. }
  297. function a_menu() {
  298. $options_page = add_options_page($this->name_proper, $this->name_proper, 'manage_options', 'wp-minify', array($this, 'a_page'));
  299. add_action('admin_head-'.$options_page, array($this, 'a_request_handler'));
  300. add_action('admin_print_scripts-'.$options_page, array($this->c, 'a_enqueue_scripts'));
  301. add_action('admin_print_styles-'.$options_page, array($this->c, 'a_enqueue_styles'));
  302. }
  303. function a_page() {
  304. $wpm_options = get_option($this->name);
  305. printf('
  306. <div class="wrap omni_admin_content">
  307. <h2>%s</h2>
  308. <div>
  309. <a href="'.preg_replace('/&wpm-page=[^&]*/', '', $_SERVER['REQUEST_URI']).'">%s</a>&nbsp;|&nbsp;
  310. <a href="'.$this->homepage.'">%s</a>
  311. </div>',
  312. __('WP Minify Options', $this->name),
  313. __('General Configuration', $this->name),
  314. __('Documentation', $this->name)
  315. );
  316. printf('<div class="omni_admin_main">');
  317. if (isset($_GET['wpm-page'])) {
  318. if ($_GET['wpm-page'] || !$_GET['wpm-page']) {
  319. require_once('options-generic.php');
  320. }
  321. }
  322. else {
  323. require_once('options-generic.php');
  324. }
  325. printf('</div>'); // omni_admin_main
  326. require_once('options-sidebar.php');
  327. printf('</div>'); // wrap
  328. } // admin_page()
  329. // other functions
  330. function fetch_and_cache($url, $cache_file) {
  331. $ch = curl_init();
  332. $timeout = 5; // set to zero for no timeout
  333. curl_setopt ($ch, CURLOPT_URL, $url);
  334. curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
  335. curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  336. curl_setopt ($ch, CURLOPT_USERAGENT, 'WP-Minify');
  337. $content = curl_exec($ch);
  338. curl_close($ch);
  339. if ($content) {
  340. if (is_array($content)) {
  341. $content = implode($content);
  342. }
  343. // save cache file
  344. $fh = fopen($cache_file, 'w');
  345. if ($fh) {
  346. fwrite($fh, $content);
  347. fclose($fh);
  348. }
  349. else {
  350. // cannot open for write. no error b/c something else is probably writing to the file.
  351. }
  352. return $content;
  353. }
  354. else {
  355. printf(
  356. '%s: '.$url.'. %s<br/>',
  357. __('Error: Could not fetch and cache URL'),
  358. __('You might need to exclude this file in WP Minify options.')
  359. );
  360. return '';
  361. }
  362. }
  363. function refetch_cache_if_expired($url, $cache_file) {
  364. $wpm_options = get_option($this->name);
  365. $cache_file_mtime = filemtime($cache_file);
  366. if ((time() - $cache_file_mtime) > $wpm_options['cache_interval']) {
  367. $this->fetch_and_cache($url, $cache_file);
  368. }
  369. }
  370. function tiny_filename($str) {
  371. $f = __FILE__;
  372. // no fancy shortening for Windows
  373. return ('/' === $f[0]) ? strtr(base64_encode(md5($str, true)), '+/=', '-_(') : md5($str);
  374. }
  375. function array_trim($arr, $charlist=null) {
  376. foreach ($arr as $key => $value) {
  377. if (is_array($value)) $result[$key] = array_trim($value, $charlist);
  378. else $result[$key] = trim($value, $charlist);
  379. }
  380. return $result;
  381. }
  382. function check_and_split_url($url, $latest_modified = 0) {
  383. $url_chunk = explode('?f=', $url);
  384. $base_url = array_shift($url_chunk);
  385. $files = explode(',', array_shift($url_chunk));
  386. $num_files = sizeof($files);
  387. if ($this->url_needs_splitting($url, $files)) {
  388. $first_half = $this->check_and_split_url($base_url . '?f=' . implode(',', array_slice($files, 0, $num_files/2)), $latest_modified);
  389. $second_half = $this->check_and_split_url($base_url . '?f=' . implode(',', array_slice($files, $num_files/2)), $latest_modified);
  390. return $first_half + $second_half;
  391. }
  392. else {
  393. $wpm_options = get_option($this->name);
  394. // append &debug if we need to
  395. if ($wpm_options['debug_nominify']) {
  396. $debug_string = '&amp;debug=true';
  397. } else {
  398. $debug_string = '';
  399. }
  400. // append base directory if needed
  401. $base = $this->get_base();
  402. if ($base != '') {
  403. $base_string = '&amp;b='.$base;
  404. } else {
  405. $base_string = '';
  406. }
  407. // get rid of any base directory specification in extra options
  408. $extra_minify_options = preg_replace('/(&|&amp;|\b)b=[^&]*/', '', trim($wpm_options['extra_minify_options']));
  409. if (trim($extra_minify_options) != '') {
  410. $extra_string = '&amp;'.$extra_minify_options;
  411. } else {
  412. $extra_string = '';
  413. }
  414. // append last modified time
  415. $latest_modified_string = '&amp;m='.$latest_modified;
  416. return array($base_url . '?f=' . implode(',', $files) . $debug_string . $base_string . $extra_string . $latest_modified_string);
  417. }
  418. }
  419. function fetch_content($url, $type = '') {
  420. $cache_file = $this->c->get_plugin_dir().'cache/'.md5($url).$type;
  421. $content = '';
  422. if (file_exists($cache_file)) {
  423. // check cache expiration
  424. $this->refetch_cache_if_expired($url, $cache_file);
  425. $fh = fopen($cache_file, 'r');
  426. if ($fh && filesize($cache_file) > 0) {
  427. $content = fread($fh, filesize($cache_file));
  428. fclose($fh);
  429. }
  430. else {
  431. // cannot open cache file so fetch it
  432. $content = $this->fetch_and_cache($url, $cache_file);
  433. }
  434. }
  435. else {
  436. // no cache file. fetch from internet and save to local cache
  437. $content = $this->fetch_and_cache($url, $cache_file);
  438. }
  439. return $content;
  440. }
  441. function local_version($url) {
  442. $site_url = trailingslashit(get_option('siteurl'));
  443. $url = str_replace($site_url, '', $url); // relative paths only for local urls
  444. $url = preg_replace('/^\//', '', $url); // strip front / if any
  445. $url = preg_replace('/\?.*/i', '', $url); // throws away parameters, if any
  446. return $url;
  447. }
  448. function is_external($url, $localize=true) {
  449. if ($localize) {
  450. $url = $this->local_version($url);
  451. }
  452. if (substr($url, 0, 4) != 'http'
  453. && (substr($url, -3, 3) == '.js' || substr($url, -4, 4) == '.css')) {
  454. return false;
  455. } else {
  456. return true;
  457. }
  458. }
  459. function get_js_location($src) {
  460. if ($this->debug)
  461. echo 'Script URL:'.$src."<br/>\n";
  462. $script_path = $this->local_version($src);
  463. if ($this->is_external($script_path, false)) {
  464. // fetch scripts if necessary
  465. $this->fetch_content($src, '.js');
  466. $location = $this->cache_location . md5($src) . '.js';
  467. if ($this->debug)
  468. echo 'External script detected, cached as:'. md5($src) . "<br/>\n";
  469. } else {
  470. // if script is local to server
  471. $location = $script_path;
  472. if ($this->debug)
  473. echo 'Local script detected:'.$script_path."<br/>\n";
  474. }
  475. return $location;
  476. }
  477. function get_css_location($src) {
  478. if ($this->debug)
  479. echo 'Style URL:'.$src."<br/>\n";
  480. $css_path = $this->local_version($src);
  481. if ($this->is_external($css_path, false)) {
  482. // fetch scripts if necessary
  483. $this->fetch_content($src, '.css');
  484. $location = $this->cache_location . md5($src) . '.css';
  485. if ($this->debug)
  486. echo 'External css detected, cached as:'. md5($src) . "<br/>\n";
  487. } else {
  488. $location = $css_path;
  489. // if css is local to server
  490. if ($this->debug)
  491. echo 'Local css detected:'.$css_path."<br/>\n";
  492. }
  493. return $location;
  494. }
  495. function url_needs_splitting($url, $locations) {
  496. if ($url > $this->url_len_limit || count($locations) > $this->minify_limit) {
  497. return true;
  498. } else {
  499. return false;
  500. }
  501. }
  502. function build_minify_urls($locations, $type) {
  503. $wpm_options = get_option($this->name);
  504. $minify_url = $this->c->get_plugin_url().'min/?f=';
  505. if ($wpm_options['force_https'] && $_SERVER["HTTPS"] == "on") {
  506. $minify_url = preg_replace('/^http:\/\//', 'https://', $minify_url);
  507. }
  508. $minify_url .= implode(',', $locations);
  509. $latest_modified = $this->get_latest_modified_time($locations);
  510. $minify_urls = $this->check_and_split_url($minify_url, $latest_modified);
  511. if ($wpm_options['pretty_url']) {
  512. return $this->get_cached_minify_urls($minify_urls, $type);
  513. } else {
  514. return $minify_urls;
  515. }
  516. }
  517. function get_cached_minify_urls($urls, $type) {
  518. $wpm_options = get_option($this->name);
  519. $cached_urls = array();
  520. foreach ($urls as $url) {
  521. $cache_file = $this->c->get_plugin_dir().'cache/'.md5($url).$type;
  522. if (file_exists($cache_file)) {
  523. // check cache expiration
  524. $this->refetch_cache_if_expired($url, $cache_file);
  525. $fh = fopen($cache_file, 'r');
  526. if ($fh && filesize($cache_file) > 0) {
  527. $content = fread($fh, filesize($cache_file));
  528. fclose($fh);
  529. } else {
  530. // cannot open cache file so fetch it
  531. $this->fetch_and_cache($url, $cache_file);
  532. }
  533. } else {
  534. // no cache file. fetch it
  535. $this->fetch_and_cache($url, $cache_file);
  536. }
  537. $cache_url = $this->c->get_plugin_url().'cache/'.md5($url).$type.'?m='.filemtime($cache_file);
  538. $cached_urls[] = $cache_url;
  539. }
  540. return $cached_urls;
  541. }
  542. function get_base_from_minify_args() {
  543. $wpm_options = get_option($this->name);
  544. if (!empty($wpm_options['extra_minify_options'])) {
  545. if (preg_match('/\bb=([^&]*?)(&|$)/', trim($wpm_options['extra_minify_options']), $matches)) {
  546. return rtrim(trim($matches[1]), '\\/');
  547. }
  548. }
  549. return '';
  550. }
  551. function get_base_from_siteurl() {
  552. $site_url = trailingslashit(get_option('siteurl'));
  553. return rtrim(preg_replace('/^https?:\/\/.*?\//', '', $site_url), '\\/');
  554. }
  555. function get_base() {
  556. $base_from_min_args = $this->get_base_from_minify_args();
  557. if ($base_from_min_args != '') {
  558. return $base_from_min_args;
  559. }
  560. $wpm_options = get_option($this->name);
  561. if ($wpm_options['auto_base']) {
  562. return $this->get_base_from_siteurl();
  563. } else {
  564. return '';
  565. }
  566. }
  567. function get_latest_modified_time($locations = array()) {
  568. $latest_modified = 0;
  569. if (!empty($locations)) {
  570. $base_path = trailingslashit($_SERVER['DOCUMENT_ROOT']);
  571. $base_path .= trailingslashit($this->get_base());
  572. foreach ($locations as $location) {
  573. $path = $base_path.$location;
  574. $mtime = filemtime($path);
  575. if ($latest_modified < $mtime) {
  576. $latest_modified = $mtime;
  577. }
  578. }
  579. }
  580. return $latest_modified;
  581. }
  582. function extract_css($content) {
  583. $wpm_options = get_option($this->name);
  584. $css_locations = array();
  585. preg_match_all('/<link([^>]*?)>/i', $content, $link_tags_match);
  586. foreach ($link_tags_match[0] as $link_tag) {
  587. if (strpos(strtolower($link_tag), 'stylesheet')) {
  588. // check CSS media type
  589. if (!strpos(strtolower($link_tag), 'media=')
  590. || preg_match('/media=["\'](?:["\']|[^"\']*?(all|screen)[^"\']*?["\'])/', $link_tag)
  591. ) {
  592. preg_match('/href=[\'"]([^\'"]+)/', $link_tag, $href_match);
  593. if ($href_match[1]) {
  594. // include it if it is in the include list
  595. $include = false;
  596. $inclusions = $wpm_options['css_include'];
  597. foreach ($inclusions as $include_pat) {
  598. $include_pat = trim($include_pat);
  599. if (strlen($include_pat) > 0 && strpos($src_match[1], $include_pat) !== false) {
  600. $include = true;
  601. break;
  602. }
  603. }
  604. if (!$include) {
  605. // support external files?
  606. if (!$wpm_options['cache_external'] && $this->is_external($href_match[1])) {
  607. continue; // skip if we don't cache externals and this file is external
  608. }
  609. // do not include anything in excluded list
  610. $skip = false;
  611. $exclusions = array_merge($this->default_exclude, $wpm_options['css_exclude']);
  612. foreach ($exclusions as $exclude_pat) {
  613. $exclude_pat = trim($exclude_pat);
  614. if (strlen($exclude_pat) > 0 && strpos($href_match[1], $exclude_pat) !== false) {
  615. $skip = true;
  616. break;
  617. }
  618. }
  619. if ($skip) continue;
  620. }
  621. $content = str_replace($link_tag . '</link>', '', $content);
  622. $content = str_replace($link_tag, '', $content);
  623. $css_locations[] = $this->get_css_location($href_match[1]);
  624. }
  625. }
  626. }
  627. }
  628. $css_locations = array_unique($css_locations);
  629. return array($content, $css_locations);
  630. }
  631. function inject_css($content, $css_locations) {
  632. if (count($css_locations) > 0) {
  633. $wpm_options = get_option($this->name);
  634. // build minify URLS
  635. $css_tags = '';
  636. $minify_urls = $this->build_minify_urls($css_locations, '.css');
  637. foreach ($minify_urls as $minify_url) {
  638. $minify_url = apply_filters('wp_minify_css_url', $minify_url); // Allow plugins to modify final minify URL
  639. $css_tags .= "<link rel='stylesheet' href='$minify_url' type='text/css' media='screen' />";
  640. }
  641. $matches = preg_match('/<!-- WP-Minify CSS -->/', $content);
  642. if ($matches) {
  643. $content = preg_replace('/<!-- WP-Minify CSS -->/', "$css_tags", $content, 1); // limit 1 replacement
  644. } else {
  645. // HTML5 has <header> tags so account for those in regex
  646. $content = preg_replace('/<head(>|\s[^>]*?>)/', "\\0\n$css_tags", $content, 1); // limit 1 replacement
  647. }
  648. }
  649. return $content;
  650. }
  651. function extract_conditionals($content) {
  652. preg_match_all('/<!--\[if[^\]]*?\]>.*?<!\[endif\]-->/is', $content, $conditionals_match);
  653. $content = preg_replace('/<!--\[if[^\]]*?\]>.*?<!\[endif\]-->/is', '###WPM-CSS-CONDITIONAL###', $content);
  654. $conditionals = array();
  655. foreach ($conditionals_match[0] as $conditional) {
  656. $conditionals[] = $conditional;
  657. }
  658. return array($content, $conditionals);
  659. }
  660. function inject_conditionals($content, $conditionals) {
  661. while (count($conditionals) > 0 && strpos($content, '###WPM-CSS-CONDITIONAL###')) {
  662. $conditional = array_shift($conditionals);
  663. $content = preg_replace('/###WPM-CSS-CONDITIONAL###/', $conditional, $content, 1);
  664. }
  665. return $content;
  666. }
  667. function extract_js($content) {
  668. $wpm_options = get_option($this->name);
  669. $js_locations = array();
  670. preg_match_all('/<script([^>]*?)><\/script>/i', $content, $script_tags_match);
  671. foreach ($script_tags_match[0] as $script_tag) {
  672. if (strpos(strtolower($script_tag), 'text/javascript') !== false) {
  673. preg_match('/src=[\'"]([^\'"]+)/', $script_tag, $src_match);
  674. if ($src_match[1]) {
  675. // include it if it is in the include list
  676. $include = false;
  677. $inclusions = $wpm_options['js_include'];
  678. foreach ($inclusions as $include_pat) {
  679. $include_pat = trim($include_pat);
  680. if (strlen($include_pat) > 0 && strpos($src_match[1], $include_pat) !== false) {
  681. $include = true;
  682. break;
  683. }
  684. }
  685. if (!$include) {
  686. // support external files?
  687. if (!$wpm_options['cache_external'] && $this->is_external($src_match[1])) {
  688. continue; // skip if we don't cache externals and this file is external
  689. }
  690. // do not include anything in excluded list
  691. $skip = false;
  692. $exclusions = array_merge($this->default_exclude, $wpm_options['js_exclude']);
  693. foreach ($exclusions as $exclude_pat) {
  694. $exclude_pat = trim($exclude_pat);
  695. if (strlen($exclude_pat) > 0 && strpos($src_match[1], $exclude_pat) !== false) {
  696. $skip = true;
  697. break;
  698. }
  699. }
  700. if ($skip) continue;
  701. }
  702. $content = str_replace($script_tag, '', $content);
  703. $js_locations[] = $this->get_js_location($src_match[1]);
  704. }
  705. }
  706. }
  707. $js_locations = array_unique($js_locations);
  708. return array($content, $js_locations);
  709. }
  710. function inject_js($content, $js_locations) {
  711. if (count($js_locations) > 0) {
  712. // build minify URLS
  713. $js_tags = '';
  714. $minify_urls = $this->build_minify_urls($js_locations, '.js');
  715. foreach ($minify_urls as $minify_url) {
  716. $minify_url = apply_filters('wp_minify_js_url', $minify_url); // Allow plugins to modify final minify URL
  717. $js_tags .= "<script type='text/javascript' src='$minify_url'></script>";
  718. }
  719. $matches = preg_match('/<!-- WP-Minify JS -->/', $content);
  720. if ($matches) {
  721. $content = preg_replace('/<!-- WP-Minify JS -->/', "$js_tags", $content, 1); // limit 1 replacement
  722. } else {
  723. $wpm_options = get_option($this->name);
  724. if ($wpm_options['js_in_footer']) {
  725. $content = preg_replace('/<\/body>/', "$js_tags\n</body>", $content, 1); // limit 1 replacement
  726. } else {
  727. // HTML5 has <header> tags so account for those in regex
  728. $content = preg_replace('/<head(>|\s[^>]*?>)/', "\\0\n$js_tags", $content, 1); // limit 1 replacement
  729. }
  730. }
  731. }
  732. return $content;
  733. }
  734. function pre_content() {
  735. $wpm_options = get_option($this->name);
  736. if ($wpm_options['uri_exclude'] && count($wpm_options['uri_exclude'])) {
  737. foreach ($wpm_options['uri_exclude'] as $exclude_pat) {
  738. $exclude_pat = trim($exclude_pat);
  739. if (strlen($exclude_pat) > 0 && strpos($_SERVER['REQUEST_URI'], $exclude_pat) !== false) {
  740. return;
  741. }
  742. }
  743. }
  744. ob_start(array($this, 'modify_buffer'));
  745. // variable for sanity checking
  746. $this->buffer_started = true;
  747. }
  748. function modify_buffer($buffer) {
  749. $wpm_options = get_option($this->name);
  750. // if we do not want to force http to https then we need to exclude https
  751. if (!($wpm_options['force_https'] && $_SERVER["HTTPS"] == "on")) {
  752. $this->default_exclude[] = 'https://';
  753. }
  754. // minify JS
  755. if ($wpm_options['enable_js']) {
  756. list($buffer, $js_locations) = $this->extract_js($buffer);
  757. $buffer= $this->inject_js($buffer, $js_locations);
  758. }
  759. // minify CSS (make sure to exclude CSS conditionals)
  760. if ($wpm_options['enable_css']) {
  761. list($buffer, $conditionals) = $this->extract_conditionals($buffer);
  762. list($buffer, $css_locations) = $this->extract_css($buffer);
  763. $buffer = $this->inject_css($buffer, $css_locations);
  764. $buffer = $this->inject_conditionals($buffer, $conditionals);
  765. }
  766. // get rid of empty lines
  767. $buffer = preg_replace('/\s*(\r?\n)(\r?\n)*/', '$1', $buffer);
  768. // minify HTML
  769. if ($wpm_options['enable_html']) {
  770. if (!class_exists('Minify_HTML')) {
  771. require_once('min/lib/Minify/HTML.php');
  772. }
  773. $buffer = Minify_HTML::minify($buffer);
  774. }
  775. $buffer = apply_filters('wp_minify_content', $buffer); // allow plugins to modify buffer
  776. return $buffer;
  777. }
  778. function post_content() {
  779. // sanity checking
  780. if ($this->buffer_started) {
  781. ob_end_flush();
  782. }
  783. }
  784. function advertise() {
  785. $wpm_options = get_option($this->name);
  786. if ($wpm_options['show_link']) {
  787. printf("<p align='center'><small>Page optimized by <a href='$this->homepage' title='$this->name_proper WordPress Plugin' style='text-decoration:none;'>$this->name_proper</a> <a href='$this->author_homepage' title='WordPress Plugin' style='text-decoration:none;'>WordPress Plugin</a></small></p>");
  788. }
  789. }
  790. } // class WPMinify
  791. require_once('common.php');
  792. require_once('http_build_url.php');
  793. $wp_minify = new WPMinify();
  794. ?>