PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/forum/web-optimizer/controller/compressor.php

https://github.com/GreyTeardrop/socionicasys-forum
PHP | 3326 lines | 2813 code | 47 blank | 466 comment | 590 complexity | 65414ab144ec54d59b59a2a52faa2117 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-3.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * File from WEBO Site SpeedUp, WEBO Software (http://www.webogroup.com/)
  4. * Gzips and minifies the JavaScript and CSS within the head tags of a page.
  5. * Can also gzip and minify the page itself
  6. * and 100+ other cool web performance optimization techniques
  7. * Based on Web Optimizer, which was based on PHP Speedy
  8. *
  9. **/
  10. class web_optimizer {
  11. /**
  12. * Constructor
  13. * Sets the options and defines the gzip headers
  14. **/
  15. function web_optimizer ($options = false) {
  16. /* initialize chained optimization */
  17. if(!empty($_GET['web_optimizer_disabled']))
  18. {
  19. $this->options['active'] = 0;
  20. return;
  21. }
  22. $this->web_optimizer_stage = round(empty($_GET['web_optimizer_stage']) ? 0 : $_GET['web_optimizer_stage']);
  23. $this->debug_mode = empty($_GET['web_optimizer_debug']) && empty($_COOKIE['web_optimizer_debug']) ? 0 : 1;
  24. /* get chained optimization params */
  25. if (!empty($this->web_optimizer_stage)) {
  26. $this->username = htmlspecialchars(empty($_GET['username']) ? '' :
  27. $_GET['username']);
  28. $this->password = htmlspecialchars(empty($_GET['password']) ? '' :
  29. $_GET['password']);
  30. $this->auto_rewrite = round(empty($_GET['auto_rewrite']) ? '' :
  31. $_GET['auto_rewrite']);
  32. $this->chained_redirect = 'optimizing.php';
  33. $this->cache_version = round(empty($_GET['cache_version']) ? '' :
  34. $_GET['cache_version']);
  35. /* get major stage number, all stages:
  36. -1 - system, envelope all <script> to try-catch-document.write
  37. 0-9 - inilialization, starts in administrative interface
  38. 10-13 - JS file generation, 1st major stage (common browsers)
  39. 14-19 - CSS Sprites / data:URI generation, 1st major stage
  40. 20-24 - CSS file generation + page parsing, 1st major stage
  41. 25-28 - JS file generation, 2nd major stage (IE 6.0)
  42. 29-34 - CSS Sprites / mhtml generation, 2nd major stage
  43. 35-39 - CSS file generation + page parsing, 2nd major stage
  44. 40-43 - JS file generation, 3rd major stage (IE 7.0)
  45. 44-49 - CSS Sprites / mhtml generation, 2nd major stage
  46. 50-54 - CSS file generation + page parsing, 2nd major stage
  47. 55-58 - JS file generation, 4th major stage (IE 8.0)
  48. 59-64 - CSS Sprites / data:URI generation, 4th major stage
  49. 65-69 - CSS file generation + page parsing, 4th major stage
  50. 70-73 - JS file generation, 5th major stage (IE 7.0 @ Vista)
  51. 74-79 - CSS Sprites generation, 5th major stage
  52. 80-84 - CSS file generation + page parsing, 5th major stage
  53. */
  54. $this->cache_stage = floor(($this->web_optimizer_stage - 10) / 15);
  55. }
  56. /* allow merging of other classes with this one */
  57. foreach ($options as $key => $value) {
  58. $this->$key = $value;
  59. }
  60. $this->options['active'] = $this->debug_mode ? 1 : $this->options['active'];
  61. /* disable any actions if not active */
  62. if (empty($this->options['active'])) {
  63. return;
  64. }
  65. /* define head of the webpage for scripts / styles */
  66. $this->head = '';
  67. /* remember current time */
  68. $this->time = empty($_SERVER['REQUEST_TIME']) ? time() : $_SERVER['REQUEST_TIME'];
  69. $this->host = $_SERVER['HTTP_HOST'];
  70. if (strpos($_SERVER['HTTP_HOST'], "www.") !== false ||
  71. strpos($_SERVER['HTTP_HOST'], "WWW.") !== false) {
  72. $this->host = substr($this->host, 4);
  73. }
  74. /* define PHP version */
  75. $this->php = $this->options['php'];
  76. /* skip buffering (need for integration as plugin) */
  77. $this->buffered = $this->options['buffered'];
  78. /* Sets User Agent to differ IE from non-IE */
  79. $this->ua = empty($_SERVER['HTTP_USER_AGENT']) ? '' : $_SERVER['HTTP_USER_AGENT'];
  80. /* HTTPS or not ? */
  81. $this->https = empty($_SERVER['HTTPS']) ? '' : 's';
  82. /* Set options */
  83. $this->set_options();
  84. /* Include base plugin class */
  85. if (is_array($this->options['plugins'])) {
  86. include_once($this->options['css']['installdir'] . 'libs/php/class.plugin.php');
  87. }
  88. /* Remember current page encoding */
  89. $this->encoding = '';
  90. /* Define the gzip headers */
  91. $this->set_gzip_headers();
  92. /* Deal with flushed content or not? */
  93. $this->flushed = false;
  94. $excluded_html_pages = '';
  95. $included_user_agents = '';
  96. $retricted_cookie = 0;
  97. if (!empty($this->options['page']['cache'])) {
  98. $this->start_cache_engine();
  99. /* HTML cache ? */
  100. if (!empty($this->options['page']['cache_ignore']) ||
  101. !empty($this->options['restricted'])) {
  102. $list = (empty($this->options['page']['cache_ignore']) ? '' : $this->options['page']['cache_ignore']) .
  103. (empty($this->options['restricted']) ? '' : ' ' . $this->options['restricted']);
  104. $excluded_html_pages = preg_replace("/ /", "|", preg_replace("/([\?!\^\$\|\(\)\[\]\{\}])/", "\\\\$1", $list));
  105. }
  106. if (!empty($this->options['page']['allowed_user_agents'])) {
  107. $included_user_agents = preg_replace("/ /", "|", preg_replace("/([\?!\^\$\|\(\)\[\]\{\}])/", "\\\\$1", $this->options['page']['allowed_user_agents']));
  108. }
  109. if (!empty($this->options['page']['exclude_cookies'])) {
  110. $cookies = explode(" ", $this->options['page']['exclude_cookies']);
  111. foreach ($cookies as $cookie) {
  112. if (isset($_COOKIE[$cookie])) {
  113. $retricted_cookie = 1;
  114. }
  115. }
  116. }
  117. }
  118. /* cache if
  119. - option is enabled,
  120. - don't parse excluded pages,
  121. - or parse included USER AGENTS,
  122. - don't parse pages with excluded coockies,
  123. - flush or gzip for HTML are disabled,
  124. - headers have not been sent,
  125. - page is requested by GET,
  126. - no chained optimization,
  127. - no debug mode,
  128. - external cache restriction.
  129. */
  130. $this->cache_me = !empty($this->options['page']['cache']) &&
  131. (empty($this->options['page']['cache_ignore']) ||
  132. !preg_match("!" . $excluded_html_pages . "!is", $_SERVER['REQUEST_URI']) ||
  133. preg_match("!" . $included_user_agents . "!is", $this->ua)) &&
  134. !$retricted_cookie &&
  135. (empty($this->options['page']['gzip']) ||
  136. empty($this->options['page']['flush'])) &&
  137. !headers_sent() &&
  138. (getenv('REQUEST_METHOD') == 'GET') &&
  139. empty($this->web_optimizer_stage) &&
  140. !$this->debug_mode &&
  141. empty($this->no_cache);
  142. /* check if we can get out cached page */
  143. if (!empty($this->cache_me)) {
  144. $this->uri = $this->convert_request_uri();
  145. /* gzip cached content before output? (plugins have onCache) */
  146. $gzip_me = is_array($this->options['plugins']);
  147. $cache_plain_key = $this->view->ensure_trailing_slash($this->uri) . 'index' . $this->ua_mod . '.html';
  148. $cache_key = $cache_plain_key .
  149. ($this->options['page']['flush'] ||
  150. empty($this->encoding_ext) ||
  151. $gzip_me ? '' : $this->encoding_ext);
  152. $timestamp = $this->cache_engine->get_mtime($cache_key);
  153. /* try to get from cache non-gzipped page if gzipped one doesn't exist */
  154. if (!$timestamp && !$this->options['page']['flush'] && !empty($this->encoding_ext) && !$gzip_me) {
  155. $timestamp = $this->cache_engine->get_mtime($cache_plain_key);
  156. $gzip_me = 1;
  157. }
  158. if ($timestamp && $this->time - $timestamp < $this->options['page']['cache_timeout']) {
  159. $content = $this->cache_engine->get_entry($gzip_me ? $cache_plain_key : $cache_key);
  160. if (class_exists('JUtility'))
  161. {
  162. $token = JUtility::getToken();
  163. $content = str_replace('##WSS_JTOKEN_WSS##', $token, $content);
  164. }
  165. /* execute plugin-specific logic */
  166. if (is_array($this->options['plugins'])) {
  167. foreach ($this->options['plugins'] as $plugin) {
  168. $plugin_file =
  169. $this->options['css']['installdir'] .
  170. 'plugins/' . $plugin . '.php';
  171. if (@is_file($plugin_file)) {
  172. include_once($plugin_file);
  173. $web_optimizer_plugin = new $plugin;
  174. $content =
  175. $web_optimizer_plugin->onAfterOptimization($content);
  176. }
  177. }
  178. }
  179. if ($gzip_me) {
  180. $cnt = $this->create_gz_compress($content,
  181. in_array($this->encoding, array('gzip', 'x-gzip')));
  182. if (!empty($cnt)) {
  183. $content = $cnt;
  184. /* skip gzip if we can't compress content */
  185. } else {
  186. $this->options['page']['gzip'] = 0;
  187. $this->encoding = '';
  188. }
  189. }
  190. $hash = crc32($content) .
  191. (empty($this->encoding) ? '' : '-' . str_replace("x-", "", $this->encoding));
  192. /* check for return visits */
  193. if ((isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
  194. stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) == '"' . $hash . '"') ||
  195. (isset($_SERVER['HTTP_IF_MATCH']) &&
  196. stripslashes($_SERVER['HTTP_IF_MATCH']) == '"' . $hash . '"')) {
  197. /* return visit and no modifications, so do not send anything */
  198. header ("HTTP/1.0 304 Not Modified");
  199. header ("Content-Length: 0");
  200. while (@ob_end_clean());
  201. die();
  202. }
  203. /* set ETag, thx to merzmarkus */
  204. header("ETag: \"" . $hash . "\"");
  205. /* set content-type */
  206. if (!empty($this->options['charset'])) {
  207. header("Content-Type: text/html; charset=" . $this->compress_options['charset']);
  208. }
  209. if (empty($this->web_optimizer_stage) &&
  210. $this->options['page']['clientside_cache']) {
  211. /* not really GMT but is valid locally */
  212. $ExpStr = date("D, d M Y H:i:s",
  213. $this->time + $this->options['page']['clientside_timeout']) . " GMT";
  214. header("Cache-Control: " .
  215. ($this->options['page']['gzip'] ? 'private' : 'public') .
  216. ", max-age=" .
  217. $this->options['page']['clientside_timeout']);
  218. header("Expires: " . $ExpStr);
  219. }
  220. /* check if cached content must be gzipped, can't gzip twice via php for flush */
  221. if ($this->options['page']['gzip'] && !$this->options['page']['flush']) {
  222. $this->set_gzip_header();
  223. }
  224. while (@ob_end_clean());
  225. echo $content;
  226. /* content is a head part, flush it after */
  227. if ($this->options['page']['flush']) {
  228. flush();
  229. $this->flushed = true;
  230. } else {
  231. die();
  232. }
  233. }
  234. }
  235. /* change some hosts if HTTPS is used */
  236. if ($this->https && !empty($this->options['page']['parallel_https'])) {
  237. $this->options['javascript']['host'] =
  238. $this->options['css']['host'] =
  239. $this->options['page']['parallel_hosts'] =
  240. $this->options['page']['parallel_https'];
  241. }
  242. /* number of external files calls to process */
  243. $this->initial_files = array();
  244. /* set internal encoding */
  245. $this->charset = empty($wss_encoding) ? 'utf8' : $wss_encoding;
  246. /* prepare escaped host */
  247. $this->host_escaped = str_replace('.', '\.', $this->host);
  248. /* activate application */
  249. $this->options['active'] = 1;
  250. if ($this->buffered) {
  251. /* Start things off */
  252. $this->start();
  253. }
  254. }
  255. /**
  256. * Write installation progress to JavaScript file
  257. *
  258. **/
  259. function write_progress ($progress) {
  260. $this->write_file($this->options['javascript']['cachedir'] . 'progress.html', $progress);
  261. }
  262. /**
  263. * Options are read from config.webo.php
  264. **/
  265. function set_options () {
  266. /* Set paths with new options */
  267. $this->options['document_root'] = empty($this->options['document_root']) ? '' : $this->options['document_root'];
  268. $this->view->set_paths($this->options['document_root']);
  269. /* Set local root if chained optimization */
  270. if (!empty($this->web_optimizer_stage)) {
  271. $this->view->paths['full']['current_directory'] = $this->view->paths['full']['document_root'];
  272. $this->view->paths['relative']['current_directory'] = $this->view->paths['relative']['document_root'];
  273. $_SERVER['REQUEST_URI'] = '/';
  274. /* force User Agent on chained optimization */
  275. $mods = array(
  276. /* all common browsers except IE */
  277. '',
  278. /* IE 6.0, when will it die? */
  279. '.ie6',
  280. /* IE 7.0 */
  281. '.ie7',
  282. /* IE 8.0 */
  283. '.ie8',
  284. /* Mobile Agents */
  285. '.ma'
  286. );
  287. $this->ua_mod = $mods[$this->cache_stage];
  288. }
  289. $this->premium = $this->view->validate_license($this->options['license'], $this->options['html_cachedir'], $this->options['host']);
  290. $this->set_user_agent();
  291. $webo_cachedir = $this->view->unify_dir_separator(realpath(dirname(__FILE__) . '/../') . '/');
  292. /* ensure trailing slashes */
  293. $this->options['html_cachedir'] = $this->view->ensure_trailing_slash($this->options['html_cachedir']);
  294. $this->options['css_cachedir'] = $this->view->ensure_trailing_slash($this->options['css_cachedir']);
  295. $this->options['javascript_cachedir'] = $this->view->ensure_trailing_slash($this->options['javascript_cachedir']);
  296. /* normalize host */
  297. if (!empty($this->options['host'])) {
  298. $this->options['host'] = preg_replace("!^https?://!", "", $this->options['host']);
  299. }
  300. /* Read in options */
  301. $full_options = array(
  302. "javascript" => array(
  303. "cachedir" => $this->options['javascript_cachedir'],
  304. "cachedir_relative" => str_replace($this->options['document_root'], "/", $this->options['javascript_cachedir']),
  305. "installdir" => $webo_cachedir,
  306. "gzip" => $this->options['gzip']['javascript'] &&
  307. ((!$this->options['htaccess']['mod_gzip'] &&
  308. !$this->options['htaccess']['mod_deflate'] &&
  309. (!$this->options['htaccess']['mod_rewrite'] ||
  310. !$this->options['htaccess']['mod_mime'] ||
  311. !$this->options['htaccess']['mod_expires'])) ||
  312. !$this->options['htaccess']['enabled']),
  313. "gzip_level" => round($this->options['gzip']['javascript_level']),
  314. "minify" => $this->options['minify']['javascript'],
  315. "minify_body" => $this->options['minify']['javascript_body'],
  316. "minify_with" => $this->options['minify']['with_jsmin'] ?
  317. 'jsmin' : ($this->options['minify']['with_yui'] ?
  318. 'yui' : ($this->options['minify']['with_packer'] ?
  319. 'packer' : '')),
  320. "minify_try" => $this->options['external_scripts']['include_try'],
  321. "minify_exclude" => $this->options['external_scripts']['minify_exclude'],
  322. "remove_duplicates" => $this->options['external_scripts']['duplicates'],
  323. "far_future_expires" => $this->options['far_future_expires']['javascript'] &&
  324. !$this->options['htaccess']['mod_expires'],
  325. "far_future_expires_php" => $this->options['far_future_expires']['javascript'],
  326. "far_future_expires_rewrite" => $this->options['htaccess']['mod_rewrite'] &&
  327. $this->options['htaccess']['enabled'] &&
  328. $this->options['far_future_expires']['javascript'],
  329. "unobtrusive_body" => $this->options['unobtrusive']['body'] &&
  330. !$this->options['unobtrusive']['all'],
  331. "external_scripts" => $this->options['external_scripts']['on'] &&
  332. $this->options['minify']['javascript'],
  333. "inline_scripts" => $this->options['external_scripts']['inline'] &&
  334. $this->options['minify']['javascript'],
  335. "external_scripts_head_end" => $this->options['external_scripts']['head_end'],
  336. "external_scripts_exclude" => $this->options['external_scripts']['ignore_list'],
  337. "dont_check_file_mtime" => $this->options['performance']['mtime'],
  338. "file" => $this->options['minify']['javascript_file'],
  339. "host" => $this->options['minify']['javascript_host'],
  340. "https" => $this->premium > 1 ? $this->options['parallel']['https'] : ''
  341. ),
  342. "css" => array(
  343. "cachedir" => $this->options['css_cachedir'],
  344. "cachedir_relative" => str_replace($this->options['document_root'], "/", $this->options['css_cachedir']),
  345. "installdir" => $webo_cachedir,
  346. "gzip" => $this->options['gzip']['css'] &&
  347. ((!$this->options['htaccess']['mod_gzip'] &&
  348. !$this->options['htaccess']['mod_deflate'] &&
  349. (!$this->options['htaccess']['mod_rewrite'] ||
  350. !$this->options['htaccess']['mod_mime'] ||
  351. !$this->options['htaccess']['mod_expires'])) ||
  352. !$this->options['htaccess']['enabled']),
  353. "gzip_level" => round($this->options['gzip']['css_level']),
  354. "minify" => $this->options['minify']['css'],
  355. "minify_body" => $this->options['minify']['css_body'],
  356. "minify_with" => $this->options['minify']['css_min'] == 2 ?
  357. 'tidy' : ($this->options['minify']['css_min'] ? 'basic' : ''),
  358. "far_future_expires" => $this->options['far_future_expires']['css'] &&
  359. !$this->options['htaccess']['mod_expires'],
  360. "far_future_expires_php" => $this->options['far_future_expires']['css'],
  361. "far_future_expires_rewrite" => $this->options['htaccess']['mod_rewrite'] &&
  362. $this->options['htaccess']['enabled'] &&
  363. $this->options['far_future_expires']['css'],
  364. "data_uris" => $this->options['data_uris']['on'],
  365. /* disable mhtml for IE7- under HTTPS */
  366. "data_uris_mhtml" => $this->options['data_uris']['mhtml'] &&
  367. (!$this->https || (!strpos($this->ua, 'MSIE 6') && !strpos($this->ua, 'MSIE 7'))),
  368. "data_uris_separate" => $this->options['data_uris']['separate'] &&
  369. ((!empty($this->ua_mod) &&
  370. $this->options['data_uris']['mhtml']) ||
  371. (empty($this->ua_mod) &&
  372. $this->options['data_uris']['on'])),
  373. "data_uris_domloaded" => $this->options['data_uris']['domloaded'],
  374. "data_uris_size" => round($this->options['data_uris']['size']),
  375. "data_uris_mhtml_size" => round($this->options['data_uris']['mhtml_size']),
  376. "data_uris_exclude" => $this->options['data_uris']['ignore_list'],
  377. "data_uris_exclude_mhtml" => $this->options['data_uris']['additional_list'],
  378. "css_sprites" => $this->options['css_sprites']['enabled'],
  379. "css_sprites_expires_rewrite" => (!$this->options['htaccess']['mod_rewrite'] ||
  380. !$this->options['htaccess']['enabled']) &&
  381. $this->options['far_future_expires']['images'],
  382. "css_sprites_ignore" => $this->options['css_sprites']['ignore'],
  383. "css_sprites_exclude" => $this->options['css_sprites']['ignore_list'],
  384. "truecolor_in_jpeg" => $this->options['css_sprites']['truecolor_in_jpeg'],
  385. "aggressive" => $this->options['css_sprites']['aggressive'],
  386. "no_ie6" => $this->options['css_sprites']['no_ie6'],
  387. "dimensions_limited" => round($this->options['css_sprites']['dimensions_limited']),
  388. "css_sprites_extra_space" => $this->options['css_sprites']['extra_space'],
  389. "punypng" => (!empty($this->options['punypng']) ? $this->options['punypng'] : '') &&
  390. ($this->premium > 1),
  391. "css_restore_properties" => $this->options['performance']['restore_properties'] &&
  392. ($this->premium > 1),
  393. "unobtrusive_body" => false,
  394. "parallel" => $this->options['parallel']['enabled'],
  395. "parallel_hosts" => $this->options['parallel']['allowed_list'],
  396. "external_scripts" => $this->options['external_scripts']['css'],
  397. "inline_scripts" => $this->options['external_scripts']['css_inline'],
  398. "external_scripts_exclude" => $this->options['external_scripts']['additional_list'],
  399. "include_code" => $this->options['external_scripts']['include_code'],
  400. "dont_check_file_mtime" => $this->options['performance']['mtime'],
  401. "file" => $this->options['minify']['css_file'],
  402. "host" => $this->options['minify']['css_host'],
  403. "https" => $this->premium > 1 ? $this->options['parallel']['https'] : ''
  404. ),
  405. "page" => array(
  406. "cachedir" => $this->options['html_cachedir'],
  407. "cache_engine" => $this->options['performance']['cache_engine'],
  408. "cache_engine_options" => $this->options['performance']['cache_engine_options'],
  409. "cachedir_relative" => str_replace($this->options['document_root'], "/", $this->options['html_cachedir']),
  410. "installdir" => $webo_cachedir,
  411. "host" => $this->options['host'],
  412. "gzip" => $this->options['gzip']['page'] &&
  413. ((!$this->options['htaccess']['mod_gzip'] &&
  414. !$this->options['htaccess']['mod_deflate']) ||
  415. !$this->options['htaccess']['enabled']),
  416. "gzip_noie" => $this->options['gzip']['noie'],
  417. "gzip_level" => round($this->options['gzip']['page_level']),
  418. "gzip_cookie" => $this->options['gzip']['cookie'],
  419. "minify" => $this->options['minify']['page'],
  420. "minify_aggressive" => $this->options['minify']['html_one_string'],
  421. "remove_comments" => $this->options['minify']['html_comments'],
  422. "dont_check_file_mtime" => $this->options['performance']['mtime'],
  423. "cache_images" => $this->options['far_future_expires']['images'],
  424. "far_future_expires_rewrite" => (!($this->options['htaccess']['mod_rewrite'] ||
  425. $this->options['htaccess']['mod_expires']) ||
  426. !$this->options['htaccess']['enabled']) &&
  427. $this->options['far_future_expires']['images'],
  428. "far_future_expires_external" => $this->options['far_future_expires']['external'],
  429. "clientside_cache" => $this->options['far_future_expires']['html'],
  430. "clientside_timeout" => $this->options['far_future_expires']['html_timeout'],
  431. "cache" => $this->options['html_cache']['enabled'],
  432. "cache_timeout" => $this->options['html_cache']['timeout'],
  433. "flush" => $this->options['html_cache']['flush_only'],
  434. "flush_size" => $this->options['html_cache']['flush_size'],
  435. "cache_ignore" => $this->options['html_cache']['ignore_list'],
  436. "cache_params" => $this->options['html_cache']['params'],
  437. "allowed_user_agents" => $this->options['html_cache']['allowed_list'],
  438. "exclude_cookies" => $this->options['html_cache']['additional_list'],
  439. "parallel" => $this->options['parallel']['enabled'],
  440. "parallel_hosts" => $this->options['parallel']['allowed_list'],
  441. "parallel_satellites" => $this->options['parallel']['additional'],
  442. "parallel_satellites_hosts" => $this->options['parallel']['additional_list'],
  443. "parallel_ignore" => $this->options['parallel']['ignore_list'],
  444. "parallel_css" => $this->options['parallel']['css'],
  445. "parallel_javascript" => $this->options['parallel']['javascript'],
  446. "parallel_ftp" => $this->options['parallel']['ftp'],
  447. "parallel_https" => $this->options['parallel']['https'],
  448. "unobtrusive_informers" => $this->options['unobtrusive']['informers'] &&
  449. ($this->premium > 1),
  450. "unobtrusive_counters" => $this->options['unobtrusive']['counters'] &&
  451. ($this->premium > 1),
  452. "unobtrusive_ads" => $this->options['unobtrusive']['ads'] &&
  453. ($this->premium > 1),
  454. "unobtrusive_all" => $this->options['unobtrusive']['all'] &&
  455. ($this->premium > 1),
  456. "unobtrusive_iframes" => $this->options['unobtrusive']['iframes'] &&
  457. ($this->premium > 1),
  458. "unobtrusive_onload" => $this->options['unobtrusive']['on'] &&
  459. ($this->premium > 1),
  460. "unobtrusive_inline" => $this->options['unobtrusive']['on'] == 2 &&
  461. ($this->premium > 1),
  462. "footer" => $this->premium ? $this->options['footer']['text'] : 1,
  463. "footer_image" => $this->options['footer']['image'],
  464. "footer_text" => $this->options['footer']['link'],
  465. "footer_style" => $this->options['footer']['css_code'],
  466. "spot" => $this->premium ? $this->options['footer']['spot'] : 1,
  467. "counter" => $this->options['footer']['counter'],
  468. "htaccess_username" => $this->options['external_scripts']['user'],
  469. "htaccess_password" => $this->options['external_scripts']['pass'],
  470. "html_tidy" => $this->options['performance']['plain_string'],
  471. "sprites" => $this->options['css_sprites']['html_sprites'],
  472. "dimensions_limited" => round($this->options['css_sprites']['html_limit']),
  473. "per_page" => $this->options['css_sprites']['html_page']
  474. ),
  475. "document_root" => $this->options['document_root'],
  476. "document_root_relative" => str_replace("//", "/", str_replace($this->options['document_root'], "/", $this->options['website_root'])),
  477. "website_root" => $this->options['website_root'],
  478. "cache_version" => round($this->options['performance']['cache_version']),
  479. "uniform_cache" => $this->options['performance']['uniform_cache'],
  480. "plugins" => ($this->premium > 1) &&
  481. !empty($this->options['plugins']) ? explode(" ", $this->options['plugins']) : '',
  482. "restricted" => ($this->premium > 1) &&
  483. !empty($this->options['restricted']) ? $this->options['restricted'] : '',
  484. "days_to_delete" => round($this->options['performance']['delete_old']),
  485. "charset" => $this->options['charset']
  486. );
  487. $this->lc = $this->options['license'];
  488. /* overwrite other options array that we passed in */
  489. $this->options = $full_options;
  490. }
  491. /**
  492. * Start saving the output buffer
  493. *
  494. **/
  495. function start () {
  496. ob_start();
  497. ob_start();
  498. ob_implicit_flush(0);
  499. }
  500. /**
  501. * Compress passes content directly
  502. *
  503. **/
  504. function compress ($content) {
  505. $this->finish($content);
  506. }
  507. /**
  508. * Do work and return output buffer
  509. *
  510. **/
  511. function finish ($content = false) {
  512. /* disable any actions if not active */
  513. if (empty($this->options['active'])) {
  514. return $content;
  515. }
  516. if ($content === false) {
  517. $this->content = ob_get_clean();
  518. /* clear all other buffers */
  519. while (@ob_end_clean());
  520. } else {
  521. $this->content = $content;
  522. }
  523. /* execute plugin-specific logic, BeforeOptimization event */
  524. if (is_array($this->options['plugins'])) {
  525. foreach ($this->options['plugins'] as $plugin) {
  526. $plugin_file =
  527. $this->options['css']['installdir'] .
  528. 'plugins/' . $plugin . '.php';
  529. if (@is_file($plugin_file)) {
  530. include_once($plugin_file);
  531. $web_optimizer_plugin = new $plugin;
  532. $this->content =
  533. $web_optimizer_plugin->onBeforeOptimization($this->content);
  534. }
  535. }
  536. }
  537. $skip = 0;
  538. if (function_exists('get_headers')) {
  539. $headers = headers_list();
  540. /* define if Content-Type is text/html and allow it */
  541. foreach ($headers as $head) {
  542. $header = strtolower($head);
  543. if (strpos($header, 'content-type:') !== false || strpos($header, 'location:') !== false) {
  544. $skip++;
  545. }
  546. if (strpos($header, 'text/html') || strpos($header, 'application/xhtml+xml')) {
  547. $skip--;
  548. }
  549. if (strpos($header, 'content-base') !== false) {
  550. $this->basehref = substr($head, 14);
  551. }
  552. }
  553. }
  554. /* also skip AJAX requests with X-Requested-With: XMLHttpRequest */
  555. if (!$skip &&
  556. !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
  557. $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
  558. $skip = 1;
  559. }
  560. /* also skip some CMS-ralted parameters */
  561. if (!$skip && !empty($_GET['no_html'])) {
  562. $skip = 1;
  563. }
  564. /* skip some extensions */
  565. if (!$skip && !empty($_SERVER['QUERY_STRING'])) {
  566. $query = explode('.', $_SERVER['QUERY_STRING']);
  567. $ext = strtolower($query[count($query) - 1]);
  568. if (in_array($ext, array('pdf', 'doc', 'xls', 'docx', 'xlsx'))) {
  569. $skip = 1;
  570. }
  571. }
  572. /* skip some known cases of non-HTML content */
  573. if (!$skip) {
  574. /* reduce amount of viewing content, accelerate 'fast check' by 1% */
  575. $spot = substr($this->content, 0, 60);
  576. if (strpos($spot, '<methodResponse') !== false ||
  577. strpos($spot, '<rss') !== false ||
  578. strpos($spot, '<feed') !== false ||
  579. strpos($spot, '<urlset') !== false ||
  580. strpos($spot, '<smf') !== false ||
  581. strpos($spot, '{') === 0 ||
  582. strlen($this->content) < 200) {
  583. $skip = 1;
  584. }
  585. }
  586. /* restrict URL from configuration */
  587. if (!$skip &&
  588. !empty($this->options['restricted'])) {
  589. if (preg_match("@" . preg_replace("/ /", "|",
  590. preg_replace("/([\?!\^\$\|\(\)\[\]\{\}])/",
  591. "\\\\$1",
  592. $this->options['restricted'])) . "@",
  593. $_SERVER['REQUEST_URI'])) {
  594. $skip = 1;
  595. }
  596. }
  597. /* skip RSS, SMF xml format */
  598. if (!$skip) {
  599. /* find all files in head to process */
  600. $this->get_script_array();
  601. /* Run the functions specified in options */
  602. if (is_array($this->options)) {
  603. foreach ($this->options as $func => $option) {
  604. if (method_exists($this, $func)) {
  605. if (!empty($option['gzip']) ||
  606. !empty($option['minify']) ||
  607. !empty($option['far_future_expires']) ||
  608. !empty($option['parallel']) ||
  609. !empty($option['unobtrusive_all']) ||
  610. !empty($option['unobtrusive_ads']) ||
  611. !empty($option['unobtrusive_counters']) ||
  612. !empty($option['unobtrusive_informers']) ||
  613. !empty($option['unobtrusive_iframes']) ||
  614. !empty($option['cache']) ||
  615. !empty($option['sprites'])) {
  616. if (!empty($this->web_optimizer_stage)) {
  617. $this->write_progress($this->web_optimizer_stage++);
  618. }
  619. $this->$func($option, $func);
  620. }
  621. }
  622. }
  623. }
  624. if (!empty($this->web_optimizer_stage)) {
  625. $this->write_progress($this->web_optimizer_stage);
  626. /* redirect to installation page if chained optimization if finished */
  627. if ($this->web_optimizer_stage > 85) {
  628. if ($this->chained_redirect === 'optimizing.php') {
  629. $this->write_progress(97);
  630. header('Location: ../index.php?page=install_stage_3&Submit=1&web_optimizer_stage=97&wss__password=' .
  631. $this->password);
  632. }
  633. /* else redirect to the next stage */
  634. } else {
  635. header('Location: ' . $this->chained_redirect . '?web_optimizer_stage=' .
  636. $this->web_optimizer_stage .
  637. '&password=' .
  638. $this->password .
  639. '&web_optimizer_debug=1');
  640. }
  641. while (@ob_end_clean());
  642. die();
  643. }
  644. }
  645. /* remove marker for styles */
  646. $this->content = str_replace('@@@WSSSTYLES@@@', '', $this->content);
  647. /* Return content to requestor */
  648. if ($content) {
  649. return $this->content;
  650. /* or echo content to the browser */
  651. } else {
  652. /* HTTP/1.0 needs Content-Length sometimes. With PHP4 we can't check when exactly. */
  653. if (!empty($this->encoding)) {
  654. header('Content-Length: ' . strlen($this->content));
  655. }
  656. echo $this->content;
  657. /* It's obvious to send anything right after gzipped content */
  658. if (!empty($this->encoding)) {
  659. while (@ob_end_clean());
  660. die();
  661. }
  662. }
  663. }
  664. /**
  665. * GZIP and minify the javascript as required
  666. *
  667. **/
  668. function javascript ($options,$type) {
  669. /* prepare list of files to process */
  670. $script_files = array();
  671. foreach ($this->initial_files as $file) {
  672. if (!empty($file['tag']) && $file['tag'] == 'script') {
  673. $script_files[] = $file;
  674. }
  675. }
  676. if (!empty($options['minify']) && !empty($script_files)) {
  677. $this->content = $this->do_compress(
  678. array(
  679. 'cachedir' => $options['cachedir'],
  680. 'cachedir_relative' => $options['cachedir_relative'],
  681. 'installdir' => $options['installdir'],
  682. 'host' => $options['host'],
  683. 'tag' => 'script',
  684. 'type' => 'text/javascript',
  685. 'ext' => 'js',
  686. 'src' => 'src',
  687. 'self_close' => false,
  688. 'gzip' => $options['gzip'],
  689. 'gzip_level' => $options['gzip_level'],
  690. 'minify' => $options['minify'],
  691. 'minify_body' => $options['minify_body'],
  692. 'minify_with' => $options['minify_with'],
  693. 'minify_try' => $options['minify_try'],
  694. 'minify_exclude' => $options['minify_exclude'],
  695. 'remove_duplicates' => $options['remove_duplicates'],
  696. 'far_future_expires' => $options['far_future_expires'],
  697. 'far_future_expires_php' => $options['far_future_expires_php'],
  698. 'far_future_expires_rewrite' => $options['far_future_expires_rewrite'],
  699. 'header' => $type,
  700. 'css_sprites' => false,
  701. 'css_sprites_exclude' => false,
  702. 'aggressive' => false,
  703. 'no_ie6' => false,
  704. 'dimensions_limited' => false,
  705. 'css_sprites_extra_space' => false,
  706. 'data_uris' => false,
  707. 'mhtml' => false,
  708. 'unobtrusive_body' => $options['unobtrusive_body'],
  709. 'external_scripts' => $options['external_scripts'],
  710. 'inline_scripts' => $options['inline_scripts'],
  711. 'external_scripts_head_end' => $options['external_scripts_head_end'],
  712. 'external_scripts_exclude' => $options['external_scripts_exclude'],
  713. 'dont_check_file_mtime' => $options['dont_check_file_mtime'],
  714. 'file' => $options['file'],
  715. 'https' => $options['https']
  716. ),
  717. $this->content,
  718. $script_files
  719. );
  720. }
  721. }
  722. /**
  723. * GZIP and minify the CSS as required
  724. *
  725. **/
  726. function css ($options, $type) {
  727. /* prepare list of files to process */
  728. $link_files = array();
  729. foreach ($this->initial_files as $file) {
  730. if (!empty($file['tag']) && $file['tag'] == 'link') {
  731. $link_files[] = $file;
  732. }
  733. }
  734. if (!empty($options['minify']) && !empty($link_files)) {
  735. /* Compress separately for each media type*/
  736. $this->content = $this->do_compress(
  737. array(
  738. 'cachedir' => $options['cachedir'],
  739. 'cachedir_relative' => $options['cachedir_relative'],
  740. 'installdir' => $options['installdir'],
  741. 'host' => $options['host'],
  742. 'tag' => 'link',
  743. 'type' => 'text/css',
  744. 'ext' => 'css',
  745. 'src' => 'href',
  746. 'rel' => 'stylesheet',
  747. 'data_uris' => $options['data_uris'],
  748. 'mhtml' => $options['data_uris_mhtml'],
  749. 'data_uris_separate' => $options['data_uris_separate'],
  750. 'data_uris_domloaded' => $options['data_uris_domloaded'],
  751. 'data_uris_size' => $options['data_uris_size'],
  752. 'data_uris_exclude' => $options['data_uris_exclude'],
  753. 'mhtml' => $options['data_uris_mhtml'],
  754. 'mhtml_size' => $options['data_uris_mhtml_size'],
  755. 'mhtml_exclude' => $options['data_uris_exclude_mhtml'],
  756. 'css_sprites' => $options['css_sprites'],
  757. 'css_sprites_ignore' => $options['css_sprites_ignore'],
  758. 'css_sprites_exclude' => $options['css_sprites_exclude'],
  759. 'truecolor_in_jpeg' => $options['truecolor_in_jpeg'],
  760. 'aggressive' => $options['aggressive'],
  761. 'no_ie6' => $options['no_ie6'],
  762. 'dimensions_limited' => $options['dimensions_limited'],
  763. 'css_sprites_extra_space' => $options['css_sprites_extra_space'],
  764. 'css_sprites_expires_rewrite' => $options['css_sprites_expires_rewrite'],
  765. 'punypng' => $options['punypng'],
  766. 'css_restore_properties' => $options['css_restore_properties'],
  767. 'self_close' => true,
  768. 'gzip' => $options['gzip'],
  769. 'gzip_level' => $options['gzip_level'],
  770. 'minify' => $options['minify'],
  771. 'minify_body' => $options['minify_body'],
  772. 'minify_with' => $options['minify_with'],
  773. 'far_future_expires' => $options['far_future_expires'],
  774. 'far_future_expires_php' => $options['far_future_expires_php'],
  775. 'far_future_expires_rewrite' => $options['far_future_expires_rewrite'],
  776. 'header' => $type,
  777. 'unobtrusive_body' => $options['unobtrusive_body'],
  778. 'parallel' => $options['parallel'],
  779. 'parallel_hosts' => $options['parallel_hosts'],
  780. 'external_scripts' => $options['external_scripts'],
  781. 'inline_scripts' => $options['inline_scripts'],
  782. 'external_scripts_exclude' => $options['external_scripts_exclude'],
  783. 'include_code' => $options['include_code'],
  784. 'dont_check_file_mtime' => $options['dont_check_file_mtime'],
  785. 'file' => $options['file'],
  786. 'https' => $options['https']
  787. ),
  788. $this->content,
  789. $link_files
  790. );
  791. }
  792. }
  793. /**
  794. * GZIP and minify the page itself as required
  795. *
  796. **/
  797. function page ($options, $type) {
  798. if (empty($this->web_optimizer_stage) && $options['clientside_cache'] && empty($this->flushed)) {
  799. /* not really GMT but is valid locally */
  800. $ExpStr = date("D, d M Y H:i:s",
  801. $this->time + $this->options['page']['clientside_timeout']) . " GMT";
  802. header("Cache-Control: private, max-age=" .
  803. $this->options['page']['clientside_timeout']);
  804. header("Expires: " . $ExpStr);
  805. }
  806. /* move informers, counters, ads, and iframes before </body> */
  807. $this->replace_informers($options);
  808. /* Minify page itself or parse multiple hosts */
  809. if (!empty($options['minify']) ||
  810. (!empty($options['parallel']) &&
  811. !empty($options['parallel_hosts'])) ||
  812. !empty($options['unobtrusive_all']) ||
  813. !empty($this->options['page']['far_future_expires_rewrite']) ||
  814. !empty($this->options['page']['far_future_expires_external']) ||
  815. !empty($this->options['page']['sprites'])) {
  816. $this->content = $this->trimwhitespace($this->content);
  817. }
  818. /* remove marker for styles and BOM */
  819. $this->content = str_replace(array("@@@WSSSTYLES@@@", "@@@WSSSCRIPT@@@", ""), "", $this->content);
  820. /* Add script to check gzip possibility */
  821. if (!empty($options['gzip_cookie']) && empty($_COOKIE['_wo_gzip_checked']) && empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
  822. $cookie = '<script type="text/javascript" src="' . $options['cachedir_relative'] . 'wo.cookie.php"></script>';
  823. if ($options['html_tidy'] && ($bodypos = strpos($this->content, '</body>'))) {
  824. $this->content = substr_replace($this->content, $cookie, $bodypos, 0);
  825. } elseif ($options['html_tidy'] && ($bodypos = strpos($this->content, '</BODY>'))) {
  826. $this->content = substr_replace($this->content, $cookie, $bodypos, 0);
  827. } else {
  828. $this->content = preg_replace('@(</body>)@is', $cookie . "$1", $this->content);
  829. /* a number of engines doesn't set </body> */
  830. if (!strpos($this->content, "wo.cookie")) {
  831. $this->content .= $cookie;
  832. }
  833. }
  834. }
  835. /* execute plugin-specific logic, AfterOptimization event */
  836. if (is_array($this->options['plugins'])) {
  837. foreach ($this->options['plugins'] as $plugin) {
  838. $plugin_file =
  839. $this->options['css']['installdir'] .
  840. 'plugins/' . $plugin . '.php';
  841. if (@is_file($plugin_file)) {
  842. include_once($plugin_file);
  843. $web_optimizer_plugin = new $plugin;
  844. $this->content =
  845. $web_optimizer_plugin->onAfterOptimization($this->content);
  846. }
  847. }
  848. }
  849. if (!empty($this->web_optimizer_stage)) {
  850. $this->write_progress($this->web_optimizer_stage++);
  851. }
  852. /* check if we need to store cached page */
  853. if (!empty($this->cache_me)) {
  854. /* add client side replacement for WordPress comment fields */
  855. if (defined('WP_CACHE')) {
  856. foreach ($_COOKIE as $key => $value) {
  857. if (strpos($key, 'comment_author') === 0) {
  858. $this->content = str_replace('value="'. urldecode($value) .'"', 'value=""', $this->content);
  859. }
  860. }
  861. $this->content = preg_replace("@(</body>)@is", '<script type="text/javascript">(function(){var a=document.cookie.split(";"),b,c=0,d,e;while(b=a[c++]){if(b.indexOf("comment_author_")!=-1){d=b.split("=");e=document.getElementById(d[0].replace(/(_?[a-f0-9]{32,}|\s?comment_author_)/g,"")||"author");if(e){e.value=unescape(d[1].replace(/\+/g," "))}}}}())</script>$1', $this->content);
  862. }
  863. if (class_exists('JUtility'))
  864. {
  865. $token = JUtility::getToken();
  866. $this->content = str_replace($token, '##WSS_JTOKEN_WSS##', $this->content);
  867. }
  868. /* prepare flushed part of content */
  869. if (!empty($options['flush']) && empty($this->encoding)) {
  870. if (empty($options['flush_size'])) {
  871. if ($this->options['page']['html_tidy'] && ($headpos = strpos($source, '</head>'))) {
  872. $content_to_write = substr($this->content, 0, $headpos + 7);
  873. } elseif ($this->options['page']['html_tidy'] && ($headpos = strpos($source, '</HEAD>'))) {
  874. $content_to_write = substr($this->content, 0, $headpos + 7);
  875. } else {
  876. $content_to_write = preg_replace("!(.*<\/head>).*!is", "$1", $this->content);
  877. }
  878. } else {
  879. $content_to_write =
  880. substr($this->content, 0, $options['flush_size']);
  881. }
  882. }
  883. $ordinary_cache_key = $this->view->ensure_trailing_slash($this->uri) . 'index' . $this->ua_mod . '.html';
  884. $cache_key = $ordinary_cache_key . (empty($this->encoding_ext) ? '' : $this->encoding_ext);
  885. $timestamp = $this->cache_engine->get_mtime($cache_key);
  886. /* set ETag, thx to merzmarkus */
  887. if (empty($options['flush'])) {
  888. header("ETag: \"" .
  889. md5($this->content) .
  890. (empty($this->encoding) ? '' : '-' .
  891. str_replace("x-", "", $this->encoding)) .
  892. "\"");
  893. }
  894. if (empty($timestamp) || $this->time - $timestamp > $options['cache_timeout']) {
  895. if (!empty($options['gzip']) && !empty($this->encoding)) {
  896. $content_to_write = $this->create_gz_compress($this->content,
  897. in_array($this->encoding, array('gzip', 'x-gzip')));
  898. /* or just write full or non-gzipped content */
  899. } elseif (empty($options['flush']) || !empty($this->encoding)) {
  900. $content_to_write = $this->content;
  901. }
  902. /* don't create empty files */
  903. if (!empty($content_to_write)) {
  904. $this->cache_engine->put_entry($cache_key, $content_to_write, $this->time);
  905. }
  906. /* create uncompressed file for plugins */
  907. if (is_array($this->options['plugins']) &&
  908. !empty($this->encoding_ext)) {
  909. $this->cache_engine->put_entry($ordinary_cache_key, $this->content, $this->time);
  910. }
  911. }
  912. }
  913. /* execute plugin-specific logic, Cache event */
  914. if (is_array($this->options['plugins'])) {
  915. foreach ($this->options['plugins'] as $plugin) {
  916. $plugin_file =
  917. $this->options['css']['installdir'] .
  918. 'plugins/' . $plugin . '.php';
  919. if (@is_file($plugin_file)) {
  920. include_once($plugin_file);
  921. $web_optimizer_plugin = new $plugin;
  922. $this->content =
  923. $web_optimizer_plugin->onCache($this->content);
  924. }
  925. }
  926. }
  927. /* strip from content flushed part */
  928. if (!empty($this->flushed)) {
  929. if (empty($options['flush_size'])) {
  930. $options['flush_size'] = strlen($content_to_write);
  931. }
  932. $this->content = substr($this->content, $options['flush_size']);
  933. }
  934. /* Gzip page itself */
  935. if(!empty($options['gzip']) && !empty($this->encoding)) {
  936. $content = $this->create_gz_compress($this->content,
  937. in_array($this->encoding, array('gzip', 'x-gzip')));
  938. if (!empty($content)) {
  939. $this->set_gzip_header();
  940. $this->content = $content;
  941. }
  942. }
  943. }
  944. /**
  945. * Write content to file
  946. *
  947. **/
  948. function write_file ($file, $content, $upload = 0, $mime = '') {
  949. if (@function_exists('file_put_contents')) {
  950. @file_put_contents($file, $content);
  951. } else {
  952. $fp = @fopen($file, "a");
  953. if ($fp) {
  954. /* block file from writing */
  955. @flock($fp, LOCK_EX);
  956. /* erase content and move to the beginning */
  957. @ftruncate($fp, 0);
  958. @fseek($fp, 0);
  959. @fwrite($fp, $content);
  960. @fclose($fp);
  961. }
  962. }
  963. @touch($file, $this->time);
  964. @chmod($file, octdec("0644"));
  965. if ($upload && !empty($this->options['page']['parallel_ftp'])) {
  966. $this->view->upload_cdn($file,
  967. $this->options['document_root'],
  968. $this->options['page']['parallel_ftp'],
  969. $mime,
  970. $this->options['page']['host']);
  971. }
  972. }
  973. /**
  974. * Adds multiple hosts to HTML for images
  975. *
  976. **/
  977. function add_multiple_hosts ($content, $hosts, $satellites, $satellites_hosts) {
  978. /* limit by 4 */
  979. if (count($hosts) > 4) {
  980. $hosts = array($hosts[0], $hosts[1], $hosts[2], $hosts[3]);
  981. }
  982. if (count($satellites_hosts) > 4) {
  983. $satellites_hosts = array($satellites_hosts[0], $satellites_hosts[1], $satellites_hosts[2], $satellites_hosts[3]);
  984. }
  985. $count = count($hosts);
  986. $count_satellites = count($satellites_hosts);
  987. $replaced = array();
  988. $IMG = strpos($content, '<IMG');
  989. if (!empty($this->options['page']['html_tidy']) && !$IMG) {
  990. $_content = $content;
  991. while ($pos = strpos($_content, '<img')) {
  992. $len = strpos(substr($_content, $pos), '>');
  993. /* gets image tag w/o the closing >, it's OK */
  994. $imgs[] = array(substr($_content, $pos, $len));
  995. $_content = substr_replace($_content, '', $pos, $len);
  996. }
  997. } elseif (empty($this->options['page']['html_tidy']) || $IMG) {
  998. preg_match_all("!<img[^>]+>!is", $content, $imgs, PREG_SET_ORDER);
  999. }
  1000. if (!empty($this->options['page']['sprites']) && !empty($imgs)) {
  1001. require($this->options['css']['installdir'] . 'libs/php/html.sprites.php');
  1002. $html_sprites = new html_sprites($imgs, $this->options, $this);
  1003. $content = $html_sprites->process($content);
  1004. }
  1005. if (!empty($imgs)) {
  1006. $ignore_list = explode(" ", $this->options['page']['parallel_ignore']);
  1007. $ignore_sprites = explode(" ", $this->options['css']['css_sprites_exclude']);
  1008. foreach ($imgs as $image) {
  1009. if (!empty($this->options['page']['html_tidy']) && ($pos=strpos($image[0], ' src="'))) {
  1010. $old_src = substr($image[0], $pos+6, strpos(substr($image[0], $pos+6), '"'));
  1011. } elseif (!empty($this->options['page']['html_tidy']) && ($pos=strpos($image[0], " src='"))) {
  1012. $old_src = substr($image[0], $pos+6, strpos(substr($image[0], $pos+6), "'"));
  1013. } else {
  1014. $old_src = preg_replace("!^['\"\s]*(.*?)['\"\s]*$!is", "$1", preg_replace("!.*[\"'\s]src\s*=\s*(\"[^\"]+\"|'[^']+'|[\S]+).*!is", "$1", $image[0]));
  1015. }
  1016. $old_src = $this->convert_basehref($old_src);
  1017. $old_src_param = ($old_src_param_pos = strpos($old_src, '?')) ? substr($old_src, $old_src_param_pos) : '';
  1018. /* image file name to check through ignore list */
  1019. $img = preg_replace("@.*/@", "", $old_src);
  1020. $absolute_src = $this->convert_path_to_absolute($old_src,
  1021. array('file' => $_SERVER['REQUEST_URI']));
  1022. if (empty($replaced[$image[0]])) {
  1023. if (!empty($this->options['page']['sprites']) &&
  1024. ((!in_array($img, $ignore_sprites) && empty($this->options['css']['css_sprites_ignore'])) ||
  1025. (in_array($img, $ignore_sprites) && !empty($this->options['css']['css_sprites_ignore']))) &&
  1026. !empty($html_sprites->css_images[$absolute_src]) && !empty($html_sprites->css_images[$absolute_src][2]) &&
  1027. (empty($this->ua_mod) || $this->ua_mod != '.ie6' || empty($this->options['css']['no_ie6']))) {
  1028. $class = substr($html_sprites->css_images[$absolute_src][8], 1);
  1029. if (!empty($this->options['page']['html_tidy']) &&
  1030. (strpos($image[0], 'class') || strpos($image[0], 'CLASS'))) {
  1031. if ($pos=strpos($image[0], ' class="')) {
  1032. $end = strpos(substr($image[0], $pos + 7), '"');
  1033. $new_image = substr($image[0], 0, $pos + 7 + $end) .
  1034. ' ' . $class . substr($image[0], $pos + 7 + $end);
  1035. } elseif ($pos=strpos($image[0], " class='")) {
  1036. $end = strpos(substr($image[0], $pos + 7), "'");
  1037. $new_image = substr($image[0], 0, $pos + 7 + $end) .
  1038. ' ' . $class . substr($image[0], $end);
  1039. } else {
  1040. $new_image = preg_replace("!(.*['\"\s]class\s*=\s*)([\"'])?([^\"']+)([\"'])?([\s/>])(.*)!is", "$1$2$3 " .
  1041. $class . "$4$5$6", $image[0]);
  1042. }
  1043. } elseif (preg_match("@['\"\s]class\s*=\s*['\"]@is", $image[0])) {
  1044. $new_image = preg_replace("!(.*['\"\s]class\s*=\s*)([\"'])?([^\"']+)([\"'])?([\s/>])(.*)!is", "$1$2$3 " .
  1045. $class . "$4$5$6", $image[0]);
  1046. } elseif (preg_match("@['\"\s]class\s*=\s*@is", $image[0])) {
  1047. $new_image = preg_replace("!(.*['\"\s]class\s*=\s*)([^\s]+)\s!is", "$1\"$2 " .
  1048. $class . "\" ", $image[0]);
  1049. } else {
  1050. $new_image = substr($image[0], 0, 4) . ' class="' .
  1051. $class . '"' . substr($image[0], 4);
  1052. }
  1053. /* add transparent GIF or data:URI chunk */
  1054. $new_src = (empty($this->ua_mod) ||
  1055. substr($this->ua_mod, 3, 1) > 7) &&
  1056. !$this->options['uniform_cache'] ?
  1057. 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==' :
  1058. ((empty($this->options['page']['far_future_expires_rewrite']) ?
  1059. '' : $this->options['page']['cachedir_relative'] . 'wo.static.php?') .
  1060. $this->options['page']['cachedir_relative'] . '0.gif');
  1061. /* are we operating with multiple hosts */
  1062. } elseif (!empty($this->options['page']['parallel']) &&
  1063. !empty($this->options['page']['parallel_hosts']) &&
  1064. (!count($ignore_list) || !in_array(str_replace($old_src_param, '', $img), $ignore_list))) {
  1065. /* skip images on different hosts */
  1066. if (preg_match("!//(www\.)?" . $this->host_escaped . "/+!i", $old_src) || strpos($old_src, '//') === false) {
  1067. /* using secure host */
  1068. if ($this->https && !empty($this->options['page']['parallel_https'])) {
  1069. $new_host = $this->options['page']['parallel_https'];
  1070. } else {
  1071. /* calculating unique sum from image src */
  1072. $sum = 0;
  1073. $i = ceil(strlen($old_src)/2);
  1074. while (isset($old_src{$i++})) {
  1075. $sum += ord($old_src{$i-1});
  1076. }
  1077. $host = $hosts[$sum%$count];
  1078. /* if we have dot in the distribution host - it's a domain name */
  1079. $new_host = $host .
  1080. ((strpos($host, '.') === false) ?
  1081. '.' . $this->host : '');
  1082. }
  1083. $new_src = "//" .
  1084. $new_host .
  1085. $absolute_src .
  1086. preg_replace("!(www\.)?" . $this->host_escaped . "!i",
  1087. $new_host, $old_src_param);
  1088. } elseif ($count_satellites && !empty($satellites_hosts[0]) && empty($replaced[$old_src])) {
  1089. $img_host = preg_replace("@(https?:)?//(www\.)?([^/]+)/.*@", "$3", $old_src);
  1090. /* check if we can distribute this image through satellites' hosts */
  1091. if (in_array($img_host, $satellites)) {
  1092. $new_src = preg_replace("@(https?://)(www\.)?([^/]+)/@", "$1" . $hosts[strlen($old_src)%$count] . ".$3/", $old_src);
  1093. }
  1094. }
  1095. /* or replacing images with rewrite to Expires setter? */
  1096. } elseif (!empty($this->options['page']['far_future_expires_rewrite']) ||
  1097. !empty($this->options['page']['far_future_expires_external'])) {
  1098. /* add static proxy for external images */
  1099. if (!$absolute_src &&
  1100. $this->options['page']['far_future_expires_external']) {
  1101. $absolute_src = $old_src;
  1102. }
  1103. /* do not touch dynamic images / styles / scripts -- how we can handle them? */
  1104. if ($absolute_src &&
  1105. (preg_match("@\.(bmp|gif|png|ico|jpe?g)$@is", $absolute_src) ||
  1106. !empty($this->options['page']['far_future_expires_external']))) {
  1107. $new_src =
  1108. $this->options['page']['cachedir_relative'] .
  1109. 'wo.static.php?' . $absolute_src;
  1110. }
  1111. }
  1112. if (!empty($new_src)) {
  1113. if (empty($new_image)) {
  1114. /* prevent replacing images from oher domains with the same file name */
  1115. $new_src_image = str_replace($old_src, $new_src, $image[0]);
  1116. } else {
  1117. /* replace src in image with new class */
  1118. $new_src_image = str_replace($old_src, $new_src, $new_image);
  1119. }
  1120. $content = str_replace($image[0], $new_src_image, $content);
  1121. $new_src = '';
  1122. $new_image = '';
  1123. }
  1124. $replaced[$image[0]] = 1;
  1125. }
  1126. }
  1127. }
  1128. return $content;
  1129. }
  1130. /**
  1131. * Returns GZIP compressed content string with header
  1132. *
  1133. **/
  1134. function create_gz_compress ($content, $force_gzip = true) {
  1135. if (!empty($this->encoding)) {
  1136. if (!empty($force_gzip) && function_exists('gzcompress')) {
  1137. $size = strlen($content);
  1138. $crc = crc32($content);
  1139. $cnt = "\x1f\x8b\x08\x00\x00\x00\x00\x00";
  1140. $content = gzcompress($content, $this->options['page']['gzip_level']);
  1141. $content = substr($content, 0, -4);
  1142. $cnt .= $content;
  1143. $cnt .= pack('V', $crc);
  1144. $cnt .= pack('V', $size);
  1145. } elseif (empty($force_gzip) && function_exists('gzdeflate')) {
  1146. $cnt = gzdeflate($content, $this->options['page']['gzip_level']);
  1147. }
  1148. return $cnt;
  1149. } else {
  1150. return false;
  1151. }
  1152. }
  1153. /**
  1154. * Sets current encoding for HTML document
  1155. *
  1156. **/
  1157. function set_gzip_encoding () {
  1158. if (!empty($_SERVER["HTTP_ACCEPT_ENCODING"]) && !empty($this->options['page']['gzip'])) {
  1159. $gzip_no_ie = !in_array($this->ua_mod, array('.ie6', '.ie7')) || empty($this->options['page']['gzip_noie']);
  1160. $ae = strtolower($_SERVER["HTTP_ACCEPT_ENCODING"]);
  1161. if (strpos($ae, 'x-gzip') !== false && $gzip_no_ie) {
  1162. $this->encoding = 'x-gzip';
  1163. $this->encoding_ext = '.gz';
  1164. } elseif ((strpos($ae, 'gzip') !== false || !empty($_COOKIE['_wo_gzip'])) && $gzip_no_ie) {
  1165. $this->encoding = 'gzip';
  1166. $this->encoding_ext = '.gz';
  1167. } elseif (strpos($ae, 'x-deflate') !== false) {
  1168. $this->encoding = 'x-deflate';
  1169. $this->encoding_ext = '…

Large files files are truncated, but you can click here to view the full file