PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/thirdparty/tinymce/tiny_mce_gzip.php

http://github.com/silverstripe/sapphire
PHP | 387 lines | 201 code | 63 blank | 123 comment | 43 complexity | 5a84c576b47b7536f9dd8ab137c208df MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, CC-BY-3.0, GPL-2.0, AGPL-1.0, LGPL-2.1
  1. <?php
  2. /**
  3. * tinymce.gzip.php
  4. *
  5. * Copyright, Moxiecode Systems AB
  6. * Released under LGPL License.
  7. *
  8. * License: http://tinymce.moxiecode.com/license
  9. * Contributing: http://tinymce.moxiecode.com/contributing
  10. */
  11. $frameworkPath = rtrim(dirname(dirname(dirname(__FILE__))), DIRECTORY_SEPARATOR);
  12. $basePath = rtrim(dirname($frameworkPath), DIRECTORY_SEPARATOR);
  13. // require composers autoloader
  14. if(file_exists($basePath . '/vendor/autoload.php')) {
  15. require_once $basePath . '/vendor/autoload.php';
  16. }
  17. else {
  18. if (!headers_sent()) {
  19. header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error");
  20. header('Content-Type: text/plain');
  21. }
  22. echo "Failed to include composer's autoloader, unable to continue\n";
  23. exit(1);
  24. }
  25. // Handle incoming request if it's a script call
  26. if (TinyMCE_Compressor::getParam("js")) {
  27. // Default settings
  28. $tinyMCECompressor = new TinyMCE_Compressor(array(
  29. /*
  30. * Add any site-specific defaults here that you may wish to implement. For example:
  31. *
  32. * "languages" => "en",
  33. * "cache_dir" => realpath(dirname(__FILE__) . "/../../_cache"),
  34. * "files" => "somescript,anotherscript",
  35. * "expires" => "1m",
  36. */
  37. // CUSTOM SilverStripe
  38. 'cache_dir' => TEMP_FOLDER
  39. // CUSTOM END
  40. ));
  41. // Handle request, compress and stream to client
  42. $tinyMCECompressor->handleRequest();
  43. }
  44. /**
  45. * This class combines and compresses the TinyMCE core, plugins, themes and
  46. * language packs into one disk cached gzipped request. It improves the loading speed of TinyMCE dramatically but
  47. * still provides dynamic initialization.
  48. *
  49. * Example of direct usage:
  50. * require_once("../js/tinymce/tinymce.gzip.php");
  51. *
  52. * // Renders script tag with compressed scripts
  53. * TinyMCE_Compressor::renderTag(array(
  54. * "url" => "../js/tinymce/tinymce.gzip.php",
  55. * "plugins" => "pagebreak,style",
  56. * "themes" => "advanced",
  57. * "languages" => "en"
  58. * ));
  59. */
  60. class TinyMCE_Compressor {
  61. private $files, $settings;
  62. private static $defaultSettings = array(
  63. "plugins" => "",
  64. "themes" => "",
  65. "languages" => "",
  66. // CUSTOM SilverStripe
  67. "disk_cache" => true,
  68. // END CUSTOM
  69. "expires" => "30d",
  70. "cache_dir" => "",
  71. "compress" => true,
  72. "files" => "",
  73. "source" => true,
  74. );
  75. /**
  76. * Constructs a new compressor instance.
  77. *
  78. * @param Array $settings Name/value array with non-default settings for the compressor instance.
  79. */
  80. public function __construct($settings = array()) {
  81. $this->settings = array_merge(self::$defaultSettings, $settings);
  82. if (empty($this->settings["cache_dir"])) {
  83. $this->settings["cache_dir"] = dirname(__FILE__);
  84. }
  85. }
  86. /**
  87. * Adds a file to the concatenation/compression process.
  88. *
  89. * @param String $path Path to the file to include in the compressed package/output.
  90. */
  91. public function &addFile($file) {
  92. $this->files .= ($this->files ? "," : "") . $file;
  93. return $this;
  94. }
  95. /**
  96. * Handles the incoming HTTP request and sends back a compressed script depending on settings and client support.
  97. */
  98. public function handleRequest() {
  99. $files = array();
  100. $supportsGzip = false;
  101. $expiresOffset = $this->parseTime($this->settings["expires"]);
  102. $tinymceDir = dirname(__FILE__);
  103. // Plugins
  104. $plugins = self::getParam("plugins");
  105. if ($plugins) {
  106. $this->settings["plugins"] = $plugins;
  107. }
  108. $plugins = array_unique(preg_split('/,/', $this->settings["plugins"], -1, PREG_SPLIT_NO_EMPTY));
  109. // Themes
  110. $themes = self::getParam("themes");
  111. if ($themes) {
  112. $this->settings["themes"] = $themes;
  113. }
  114. $themes = array_unique(preg_split('/,/', $this->settings["themes"], -1, PREG_SPLIT_NO_EMPTY));
  115. // Languages
  116. $languages = self::getParam("languages");
  117. if ($languages) {
  118. $this->settings["languages"] = $languages;
  119. }
  120. $languages = array_unique(preg_split('/,/', $this->settings["languages"], -1, PREG_SPLIT_NO_EMPTY));
  121. // Files
  122. $tagFiles = self::getParam("files");
  123. if ($tagFiles) {
  124. $this->settings["files"] = $tagFiles;
  125. }
  126. // Diskcache option
  127. $diskCache = self::getParam("diskcache");
  128. if ($diskCache) {
  129. $this->settings["disk_cache"] = ($diskCache === "true");
  130. }
  131. // Source or minified version
  132. $src = self::getParam("src");
  133. if ($src) {
  134. $this->settings["source"] = ($src === "true");
  135. }
  136. // Add core js
  137. if (self::getParam("core", "true") === "true") {
  138. $files[] = "tinymce";
  139. }
  140. // Add core languages
  141. foreach ($languages as $language) {
  142. $files[] = "langs/" . $language;
  143. }
  144. // Add plugins
  145. foreach ($plugins as $plugin) {
  146. $files[] = "plugins/" . $plugin . "/plugin";
  147. foreach ($languages as $language) {
  148. $files[] = "plugins/" . $plugin . "/langs/" . $language;
  149. }
  150. }
  151. // Add themes
  152. foreach ($themes as $theme) {
  153. $files[] = "themes/" . $theme . "/theme";
  154. foreach ($languages as $language) {
  155. $files[] = "themes/" . $theme . "/langs/" . $language;
  156. }
  157. }
  158. // Add any specified files.
  159. $allFiles = array_merge($files, array_unique(preg_split('/,/', $this->settings['files'], -1, PREG_SPLIT_NO_EMPTY)));
  160. // Process source files
  161. for ($i = 0; $i < count($allFiles); $i++) {
  162. $file = $allFiles[$i];
  163. if ($this->settings["source"] && file_exists($file . ".js")) {
  164. $file .= ".js";
  165. } else if (file_exists($file . ".min.js")) {
  166. $file .= ".min.js";
  167. } else {
  168. $file = "";
  169. }
  170. $allFiles[$i] = $file;
  171. }
  172. // Generate hash for all files
  173. // CUSTOM SilverStripe Webroot-specific caches
  174. $hash = md5(implode('', $allFiles) . $_SERVER['SCRIPT_NAME']);
  175. // CUSTOM END
  176. // Check if it supports gzip
  177. $zlibOn = ini_get('zlib.output_compression') || (ini_set('zlib.output_compression', 0) === false);
  178. $encodings = (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) ? strtolower($_SERVER['HTTP_ACCEPT_ENCODING']) : "";
  179. $encoding = preg_match( '/\b(x-gzip|gzip)\b/', $encodings, $match) ? $match[1] : "";
  180. // Is northon antivirus header
  181. if (isset($_SERVER['---------------'])) {
  182. $encoding = "x-gzip";
  183. }
  184. $supportsGzip = $this->settings['compress'] && !empty($encoding) && !$zlibOn && function_exists('gzencode');
  185. // Set cache file name
  186. $cacheFile = $this->settings["cache_dir"] . "/tinymce.gzip-" . $hash . ($supportsGzip ? ".gz" : ".js");
  187. // Set headers
  188. header("Content-type: text/javascript");
  189. header("Vary: Accept-Encoding"); // Handle proxies
  190. header("Expires: " . gmdate("D, d M Y H:i:s", time() + $expiresOffset) . " GMT");
  191. header("Cache-Control: public, max-age=" . $expiresOffset);
  192. if ($supportsGzip) {
  193. header("Content-Encoding: " . $encoding);
  194. }
  195. // Use cached file
  196. if ($this->settings['disk_cache'] && file_exists($cacheFile)) {
  197. readfile($cacheFile);
  198. return;
  199. }
  200. // Set base URL for where tinymce is loaded from
  201. $buffer = "var tinyMCEPreInit={base:'" . dirname($_SERVER["SCRIPT_NAME"]) . "',suffix:'.min'};";
  202. // Load all tinymce script files into buffer
  203. foreach ($allFiles as $file) {
  204. if ($file) {
  205. $fileContents = $this->getFileContents($tinymceDir . "/" . $file);
  206. // $buffer .= "\n//-FILE-$tinymceDir/$file (". strlen($fileContents) . " bytes)\n";
  207. $buffer .= $fileContents;
  208. }
  209. }
  210. // Mark all themes, plugins and languages as done
  211. $buffer .= 'tinymce.each("' . implode(',', $files) . '".split(","),function(f){tinymce.ScriptLoader.markDone(tinyMCE.baseURL+"/"+f+".js");});';
  212. // Compress data
  213. if ($supportsGzip) {
  214. $buffer = gzencode($buffer, 9, FORCE_GZIP);
  215. }
  216. // Write cached file
  217. if ($this->settings["disk_cache"]) {
  218. @file_put_contents($cacheFile, $buffer);
  219. }
  220. // Stream contents to client
  221. echo $buffer;
  222. }
  223. /**
  224. * Renders a script tag that loads the TinyMCE script.
  225. *
  226. * @param Array $settings Name/value array with settings for the script tag.
  227. * @param Bool $return The script tag is return instead of being output if true
  228. * @return String the tag is returned if $return is true
  229. */
  230. public static function renderTag($tagSettings, $return = false) {
  231. $settings = array_merge(self::$defaultSettings, $tagSettings);
  232. if (empty($settings["cache_dir"])) {
  233. $settings["cache_dir"] = dirname(__FILE__);
  234. }
  235. $scriptSrc = $settings["url"] . "?js=1";
  236. // Add plugins
  237. if (isset($settings["plugins"])) {
  238. $scriptSrc .= "&plugins=" . (is_array($settings["plugins"]) ? implode(',', $settings["plugins"]) : $settings["plugins"]);
  239. }
  240. // Add themes
  241. if (isset($settings["themes"])) {
  242. $scriptSrc .= "&themes=" . (is_array($settings["themes"]) ? implode(',', $settings["themes"]) : $settings["themes"]);
  243. }
  244. // Add languages
  245. if (isset($settings["languages"])) {
  246. $scriptSrc .= "&languages=" . (is_array($settings["languages"]) ? implode(',', $settings["languages"]) : $settings["languages"]);
  247. }
  248. // Add disk_cache
  249. if (isset($settings["disk_cache"])) {
  250. $scriptSrc .= "&diskcache=" . ($settings["disk_cache"] === true ? "true" : "false");
  251. }
  252. // Add any explicitly specified files if the default settings have been overriden by the tag ones
  253. /*
  254. * Specifying tag files will override (rather than merge with) any site-specific ones set in the
  255. * TinyMCE_Compressor object creation. Note that since the parameter parser limits content to alphanumeric
  256. * only base filenames can be specified. The file extension is assumed to be ".js" and the directory is
  257. * the TinyMCE root directory. A typical use of this is to include a script which initiates the TinyMCE object.
  258. */
  259. if (isset($tagSettings["files"])) {
  260. $scriptSrc .= "&files=" .(is_array($settings["files"]) ? implode(',', $settings["files"]) : $settings["files"]);
  261. }
  262. // Add src flag
  263. if (isset($settings["source"])) {
  264. $scriptSrc .= "&src=" . ($settings["source"] === true ? "true" : "false");
  265. }
  266. $scriptTag = '<script src="' . htmlspecialchars($scriptSrc) . '"></script>';
  267. if ($return) {
  268. return $scriptTag;
  269. } else {
  270. echo $scriptTag;
  271. }
  272. }
  273. /**
  274. * Returns a sanitized query string parameter.
  275. *
  276. * @param String $name Name of the query string param to get.
  277. * @param String $default Default value if the query string item shouldn't exist.
  278. * @return String Sanitized query string parameter value.
  279. */
  280. public static function getParam($name, $default = "") {
  281. if (!isset($_GET[$name])) {
  282. return $default;
  283. }
  284. return preg_replace("/[^0-9a-z\-_,]+/i", "", $_GET[$name]); // Sanatize for security, remove anything but 0-9,a-z,-_,
  285. }
  286. /**
  287. * Parses the specified time format into seconds. Supports formats like 10h, 10d, 10m.
  288. *
  289. * @param String $time Time format to convert into seconds.
  290. * @return Int Number of seconds for the specified format.
  291. */
  292. private function parseTime($time) {
  293. $multipel = 1;
  294. // Hours
  295. if (strpos($time, "h") > 0) {
  296. $multipel = 3600;
  297. }
  298. // Days
  299. if (strpos($time, "d") > 0) {
  300. $multipel = 86400;
  301. }
  302. // Months
  303. if (strpos($time, "m") > 0) {
  304. $multipel = 2592000;
  305. }
  306. // Trim string
  307. return intval($time) * $multipel;
  308. }
  309. /**
  310. * Returns the contents of the script file if it exists and removes the UTF-8 BOM header if it exists.
  311. *
  312. * @param String $file File to load.
  313. * @return String File contents or empty string if it doesn't exist.
  314. */
  315. private function getFileContents($file) {
  316. $content = file_get_contents($file);
  317. // Remove UTF-8 BOM
  318. if (substr($content, 0, 3) === pack("CCC", 0xef, 0xbb, 0xbf)) {
  319. $content = substr($content, 3);
  320. }
  321. return $content;
  322. }
  323. }