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