Skip to content

Commit 3cf407f

Browse files
committed
Updated config::__construct() to only recursively merge the config when a custom config has been supplied.
Reworked script::minify() and style::minify() to implement caching which is controlled by a config. Restructured the custom config for style and script to make it simpler. Updated performance.php to specify a cache location for javascript and css.
1 parent ce3484d commit 3cf407f

File tree

5 files changed

+162
-109
lines changed

5 files changed

+162
-109
lines changed

index.php

+70-68
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
require(__DIR__.'/vendor/autoload.php');
33

44
$error = null;
5-
set_error_handler(function (int $type, string $msg) use (&$error) {
6-
if (in_array($type, [E_USER_WARNING, E_USER_NOTICE])) {
5+
\set_error_handler(function (int $type, string $msg) use (&$error) {
6+
if (\in_array($type, [E_USER_WARNING, E_USER_NOTICE])) {
77
$error = $msg;
88
} else {
99
return false;
@@ -15,10 +15,10 @@
1515
$output = '';
1616
$minify = Array();
1717
$timing = Array(
18-
'start' => microtime(true)
18+
'start' => \microtime(true)
1919
);
2020
$mem = Array(
21-
'start' => memory_get_peak_usage()
21+
'start' => \memory_get_peak_usage()
2222
);
2323

2424
// create object and retrieve config
@@ -33,15 +33,15 @@
3333

3434
// parse the URL
3535
if (($url = parse_url($_POST['url'])) === false) {
36-
trigger_error('Could not parse URL: The URL is not valid', E_USER_WARNING);
36+
\trigger_error('Could not parse URL: The URL is not valid', E_USER_WARNING);
3737

3838
// check the host name
3939
} elseif (!isset($url['host'])) {
40-
trigger_error('Could not parse URL: No host was supplied', E_USER_WARNING);
40+
\trigger_error('Could not parse URL: No host was supplied', E_USER_WARNING);
4141

4242
// open the document manually so we can time it
43-
} elseif (($input = file_get_contents($_POST['url'])) === false) {
44-
trigger_error('Could not load HTML: The file could not be accessed'.$error, E_USER_WARNING);
43+
} elseif (($input = \file_get_contents($_POST['url'])) === false) {
44+
\trigger_error('Could not load HTML: The file could not be accessed'.$error, E_USER_WARNING);
4545

4646
// save base URL
4747
} else {
@@ -50,33 +50,33 @@
5050

5151
// handle directly entered source code
5252
} elseif (empty($_POST['source'])) {
53-
trigger_error('No URL or HTML source was posted', E_USER_WARNING);
53+
\trigger_error('No URL or HTML source was posted', E_USER_WARNING);
5454

5555
// record the HTML
5656
} else {
5757
$input = $_POST['source'];
5858
}
59-
$timing['fetch'] = microtime(true);
60-
$mem['fetch'] = memory_get_peak_usage();
59+
$timing['fetch'] = \microtime(true);
60+
$mem['fetch'] = \memory_get_peak_usage();
6161

6262
// load the source code
6363
if ($input) {
6464
if (!$doc->load($input, null, $error)) {
65-
trigger_error('Could not parse HTML: '.$error, E_USER_WARNING);
65+
\trigger_error('Could not parse HTML: '.$error, E_USER_WARNING);
6666

6767
// minify the output
6868
} else {
69-
$timing['parse'] = microtime(true);
70-
$mem['parse'] = memory_get_peak_usage();
69+
$timing['parse'] = \microtime(true);
70+
$mem['parse'] = \memory_get_peak_usage();
7171

7272
// retrieve the user posted options
73-
$isset = isset($_POST['minify']) && is_array($_POST['minify']);
73+
$isset = isset($_POST['minify']) && \is_array($_POST['minify']);
7474
foreach ($options AS $key => $item) {
7575
if ($key != 'elements') {
76-
$minify[$key] = $isset && in_array($key, $_POST['minify']) ? (is_array($item) ? [] : (is_bool($options[$key]) ? true : $options[$key])) : false;
77-
if (is_array($item)) {
76+
$minify[$key] = $isset && \in_array($key, $_POST['minify']) ? (\is_array($item) ? [] : (\is_bool($options[$key]) ? true : $options[$key])) : false;
77+
if (\is_array($item)) {
7878
foreach ($item AS $sub => $value) {
79-
if ($minify[$key] !== false && isset($_POST['minify'][$key]) && is_array($_POST['minify'][$key]) && in_array($sub, $_POST['minify'][$key])) {
79+
if ($minify[$key] !== false && isset($_POST['minify'][$key]) && \is_array($_POST['minify'][$key]) && \in_array($sub, $_POST['minify'][$key])) {
8080
$minify[$key][$sub] = true;
8181
} elseif ($minify[$key]) {
8282
$minify[$key][$sub] = false;
@@ -94,11 +94,11 @@
9494
}
9595

9696
// record timings
97-
$timing['minify'] = microtime(true);
98-
$mem['minify'] = memory_get_peak_usage();
97+
$timing['minify'] = \microtime(true);
98+
$mem['minify'] = \memory_get_peak_usage();
9999
$output = $doc->save();
100-
$timing['output'] = microtime(true);
101-
$mem['output'] = memory_get_peak_usage();
100+
$timing['output'] = \microtime(true);
101+
$mem['output'] = \memory_get_peak_usage();
102102
}
103103
}
104104
} else {
@@ -187,15 +187,15 @@
187187
</style>
188188
</head>
189189
<body>
190-
<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']); ?>" method="post" accept-charset="<?= mb_internal_encoding(); ?>" class="minify__form">
190+
<form action="<?= \htmlspecialchars($_SERVER['PHP_SELF']); ?>" method="post" accept-charset="<?= \htmlspecialchars(\mb_internal_encoding()); ?>" class="minify__form">
191191
<div class="minify__form-wrap">
192192
<h1 class="minify__form-heading">HTML Minifier</h1>
193193
<?php if ($error) { ?>
194-
<div class="minify__form-error"><?= htmlspecialchars($error); ?></div>
194+
<div class="minify__form-error"><?= \htmlspecialchars($error); ?></div>
195195
<?php } ?>
196196
<div class="minify__form-input">
197197
<label for="source">Paste HTML:</label>
198-
<textarea name="source" id="source" class="minify__form-input-box"><?= htmlspecialchars($input); ?></textarea>
198+
<textarea name="source" id="source" class="minify__form-input-box"><?= \htmlspecialchars($input); ?></textarea>
199199
</div>
200200
<div class="minify__form-url">
201201
<label for="url">or External URL:</label>
@@ -205,7 +205,7 @@
205205
<?php if ($output) { ?>
206206
<div class="minify__form-input">
207207
<label for="output">Output HTML:</label>
208-
<textarea id="output" class="minify__form-input-box"><?= htmlspecialchars($output); ?></textarea>
208+
<textarea id="output" class="minify__form-input-box"><?= \htmlspecialchars($output); ?></textarea>
209209
</div>
210210
<table class="minify__table">
211211
<thead>
@@ -225,66 +225,68 @@
225225
</thead>
226226
<tbody>
227227
<?php
228-
$ilen = strlen($input);
229-
$olen = strlen($output);
230-
$gilen = strlen(gzencode($input));
231-
$golen = strlen(gzencode($output));
228+
$ilen = \strlen($input);
229+
$olen = \strlen($output);
230+
$gilen = \strlen(\gzencode($input));
231+
$golen = \strlen(\gzencode($output));
232232
?>
233233
<tr>
234234
<td>Uncompressed</td>
235-
<td><?= htmlspecialchars(number_format($ilen)); ?></td>
236-
<td><?= htmlspecialchars(number_format($olen)); ?></td>
237-
<td><?= htmlspecialchars(number_format($ilen - $olen)); ?></td>
238-
<td><?= htmlspecialchars(number_format((100 / $ilen) * $olen)); ?>%</td>
235+
<td><?= \htmlspecialchars(\number_format($ilen)); ?></td>
236+
<td><?= \htmlspecialchars(\number_format($olen)); ?></td>
237+
<td><?= \htmlspecialchars(\number_format($ilen - $olen)); ?></td>
238+
<td><?= \htmlspecialchars(\number_format((100 / $ilen) * $olen)); ?>%</td>
239239
<td style="font-weight:bold;">Time (sec)</td>
240-
<td><?= htmlspecialchars(number_format($timing['fetch'] - $timing['start'], 4)); ?>s</td>
241-
<td><?= htmlspecialchars(number_format($timing['parse'] - $timing['fetch'], 4)); ?>s</td>
242-
<td><?= htmlspecialchars(number_format($timing['minify'] - $timing['parse'], 4)); ?>s</td>
243-
<td><?= htmlspecialchars(number_format($timing['output'] - $timing['minify'], 4)); ?>s</td>
244-
<td><?= htmlspecialchars(number_format($timing['output'] - $timing['fetch'], 4)); ?>s</td>
240+
<td><?= \htmlspecialchars(\number_format($timing['fetch'] - $timing['start'], 4)); ?>s</td>
241+
<td><?= \htmlspecialchars(\number_format($timing['parse'] - $timing['fetch'], 4)); ?>s</td>
242+
<td><?= \htmlspecialchars(\number_format($timing['minify'] - $timing['parse'], 4)); ?>s</td>
243+
<td><?= \htmlspecialchars(\number_format($timing['output'] - $timing['minify'], 4)); ?>s</td>
244+
<td><?= \htmlspecialchars(\number_format($timing['output'] - $timing['fetch'], 4)); ?>s</td>
245245
</tr>
246246
<tr>
247247
<td>Compressed</td>
248-
<td><?= htmlspecialchars(number_format($gilen)); ?></td>
249-
<td><?= htmlspecialchars(number_format($golen)); ?></td>
250-
<td><?= htmlspecialchars(number_format($gilen - $golen)); ?></td>
251-
<td><?= htmlspecialchars(number_format((100 / $gilen) * $golen)); ?>%</td>
248+
<td><?= \htmlspecialchars(\number_format($gilen)); ?></td>
249+
<td><?= \htmlspecialchars(\number_format($golen)); ?></td>
250+
<td><?= \htmlspecialchars(\number_format($gilen - $golen)); ?></td>
251+
<td><?= \htmlspecialchars(\number_format((100 / $gilen) * $golen)); ?>%</td>
252252
<td style="font-weight:bold;">Peak (kb)</td>
253-
<td><?= htmlspecialchars(number_format($mem['fetch'] / 1024, 0)); ?>kb</td>
254-
<td><?= htmlspecialchars(number_format($mem['parse'] / 1024, 0)); ?>kb</td>
255-
<td><?= htmlspecialchars(number_format($mem['minify'] / 1024, 0)); ?>kb</td>
256-
<td><?= htmlspecialchars(number_format($mem['output'] / 1024, 0)); ?>kb</td>
257-
<td><?= htmlspecialchars(number_format(memory_get_peak_usage() / 1024, 0)); ?>kb</td>
253+
<td><?= \htmlspecialchars(\number_format($mem['fetch'] / 1024, 0)); ?>kb</td>
254+
<td><?= \htmlspecialchars(\number_format($mem['parse'] / 1024, 0)); ?>kb</td>
255+
<td><?= \htmlspecialchars(\number_format($mem['minify'] / 1024, 0)); ?>kb</td>
256+
<td><?= \htmlspecialchars(\number_format($mem['output'] / 1024, 0)); ?>kb</td>
257+
<td><?= \htmlspecialchars(\number_format(\memory_get_peak_usage() / 1024, 0)); ?>kb</td>
258258
</tr>
259259
</tbody>
260260
</table>
261261
<?php } ?>
262262
</div>
263263
<?php if ($output) { ?>
264-
<input type="hidden" name="base" value="<?= htmlspecialchars($base); ?>" />
265-
<iframe class="minify__preview" srcdoc="<?= htmlspecialchars(preg_replace('/<head[^>]*>/i', '$0<base href="'.htmlspecialchars($base).'">', $output)); ?>"></iframe>
264+
<input type="hidden" name="base" value="<?= \htmlspecialchars($base); ?>" />
265+
<iframe class="minify__preview" srcdoc="<?= \htmlspecialchars(\preg_replace('/<head[^>]*>/i', '$0<base href="'.\htmlspecialchars($base).'">', $output)); ?>"></iframe>
266266
<?php } ?>
267267
<div class="minify__options">
268268
<h3>Options</h3>
269269
<ul class="minify__options-list">
270-
<?php foreach ($options AS $key => $item) { ?>
271-
<li>
272-
<label>
273-
<input type="checkbox" name="minify[]" value="<?= $key; ?>"<?= !isset($minify[$key]) || $minify[$key] === false ? '' : ' checked="checked"'; ?> /><?= htmlspecialchars(ucfirst($key)); ?>
274-
</label>
275-
<?php if (is_array($item)) { ?>
276-
<ul class="minify__options-list">
277-
<?php foreach ($item AS $sub => $value) { ?>
278-
<li>
279-
<label>
280-
<input type="checkbox" name="minify[<?= $key; ?>][]" value="<?= $sub; ?>"<?= !isset($minify[$key][$sub]) || $minify[$key][$sub] === false ? '' : ' checked="checked"'; ?> /><?= htmlspecialchars(ucfirst($sub)); ?>
281-
</label>
282-
</li>
283-
<?php } ?>
284-
</ul>
285-
<?php } ?>
286-
</li>
287-
<?php } ?>
270+
<?php foreach ($options AS $key => $item) {
271+
if (\is_bool($item) || \is_array($item)) { ?>
272+
<li>
273+
<label>
274+
<input type="checkbox" name="minify[]" value="<?= $key; ?>"<?= !isset($minify[$key]) || $minify[$key] === false ? '' : ' checked="checked"'; ?> /><?= \htmlspecialchars(ucfirst($key)); ?>
275+
</label>
276+
<?php if (\is_array($item)) { ?>
277+
<ul class="minify__options-list">
278+
<?php foreach ($item AS $sub => $value) { ?>
279+
<li>
280+
<label>
281+
<input type="checkbox" name="minify[<?= $key; ?>][]" value="<?= $sub; ?>"<?= !isset($minify[$key][$sub]) || $minify[$key][$sub] === false ? '' : ' checked="checked"'; ?> /><?= \htmlspecialchars(\ucfirst($sub)); ?>
282+
</label>
283+
</li>
284+
<?php } ?>
285+
</ul>
286+
<?php } ?>
287+
</li>
288+
<?php }
289+
} ?>
288290
</ul>
289291
</div>
290292
</form>

src/config.php

+23-23
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class config {
1515
* @param array $config An array of configuration parameters that is recursively merged with the default config
1616
*/
1717
public function __construct(array $config = []) {
18-
$this->config = \array_replace_recursive($this->config, [
18+
$default = [
1919
'elements' => [
2020
'inline' => [
2121
'b', 'u', 'big', 'i', 'small', 'ttspan', 'em', 'a', 'strong', 'sub', 'sup', 'abbr', 'acronym', 'cite', 'code', 'dfn', 'em', 'kbd', 'strong', 'samp', 'var', 'span'
@@ -65,31 +65,29 @@ public function __construct(array $config = []) {
6565
// default to CSSdoc if available
6666
'style' => [
6767
'class' => '\\hexydec\\html\\style',
68-
'config' => [
69-
'minifier' => \class_exists('\\hexydec\\css\\cssdoc') ? function (string $css, array $minify) {
70-
$obj = new \hexydec\css\cssdoc();
71-
if ($obj->load($css)) {
72-
$obj->minify($minify);
73-
return $obj->compile();
74-
}
75-
return $css;
76-
} : null
77-
]
68+
'cache' => null, // a file path pattern containing %s to replace the generated file key, e.g. dirname(__DIR__).'/cache/%s.css'
69+
'minifier' => \class_exists('\\hexydec\\css\\cssdoc') ? function (string $css, array $minify) {
70+
$obj = new \hexydec\css\cssdoc();
71+
if ($obj->load($css)) {
72+
$obj->minify($minify);
73+
return $obj->compile();
74+
}
75+
return false;
76+
} : null
7877
],
7978

8079
// default to JSLite if available
8180
'script' => [
8281
'class' => '\\hexydec\\html\\script',
83-
'config' => [
84-
'minifier' => \class_exists('\\hexydec\\jslite\\jslite') ? function (string $css, array $minify) {
85-
$obj = new \hexydec\jslite\jslite();
86-
if ($obj->load($css)) {
87-
$obj->minify($minify);
88-
return $obj->compile();
89-
}
90-
return $css;
91-
} : null
92-
]
82+
'cache' => null, // a file path pattern containing %s to replace the generated file key, e.g. dirname(__DIR__).'/cache/%s.js'
83+
'minifier' => \class_exists('\\hexydec\\jslite\\jslite') ? function (string $css, array $minify) {
84+
$obj = new \hexydec\jslite\jslite();
85+
if ($obj->load($css)) {
86+
$obj->minify($minify);
87+
return $obj->compile();
88+
}
89+
return false;
90+
} : null
9391
]
9492
],
9593
'minify' => [
@@ -136,7 +134,8 @@ public function __construct(array $config = []) {
136134
'close' => true, // don't write close tags where possible
137135
'email' => false, // sets the minification presets to email safe options
138136
'style' => [], // specify CSS minifier options
139-
'script' => [] // specify CSS javascript options
137+
'script' => [], // specify CSS javascript options
138+
'cache' => null // for style and scipt tags, the folder to cache the minified code in (Assuming you are using the default callback)
140139
],
141140
'output' => [
142141
'charset' => null, // set the output charset
@@ -153,7 +152,8 @@ public function __construct(array $config = []) {
153152
]
154153
]
155154
]
156-
], $config);
155+
];
156+
$this->config = $config ? \array_replace_recursive($default, $config) : $default;
157157
}
158158

159159
/**

src/tokens/script.php

+28-9
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
class script implements token {
77

88
/**
9-
* @var htmldoc The parent htmldoc object
9+
* @var array The style configuration
1010
*/
11-
protected $root;
11+
protected $config = [];
1212

1313
/**
1414
* @var string A string containing javascript
@@ -21,7 +21,7 @@ class script implements token {
2121
* @param htmldoc $root The parent htmldoc object
2222
*/
2323
public function __construct(htmldoc $root) {
24-
$this->root = $root;
24+
$this->config = $root->config['custom']['script'];
2525
}
2626

2727
/**
@@ -32,7 +32,6 @@ public function __construct(htmldoc $root) {
3232
* @return void
3333
*/
3434
public function parse(tokenise $tokens) : void {
35-
// $pattern = '/\G(?:"(?:\\\\[^\\n\\r]|[^\\\\"\\n\\r])*+"|\'(?:\\\\[^\\n\\r]|[^\\\\\'\\n\\r])*+\'|`(?:\\\\.|[^\\\\`])*+`|[^"\'`]*)*(?=<\\/script>)/iU';
3635
$pattern = '/[\\S\\s]*(?=<\\/script>)/iU';
3736
if (($token = $tokens->next($pattern)) !== null && $token[0]) {
3837
$this->content = $token[0];
@@ -47,11 +46,31 @@ public function parse(tokenise $tokens) : void {
4746
*/
4847
public function minify(array $minify) : void {
4948
if (!isset($minify['script']) || $minify['script'] !== false) {
50-
$this->content = \trim($this->content);
51-
if ($this->content) {
52-
$func = $this->root->getConfig('custom', 'script', 'config', 'minifier');
53-
if ($func) {
54-
$this->content = \call_user_func($func, $this->content, $minify['script']);
49+
$config = $this->config;
50+
$content = \trim($this->content);
51+
52+
// minify?
53+
if ($content && $config['minifier']) {
54+
55+
// cache the output?
56+
if (empty($config['cache'])) {
57+
$file = null;
58+
} else {
59+
$file = sprintf($config['cache'], md5($content));
60+
if (\file_exists($file) && ($output = \file_get_contents($file)) !== false) {
61+
$this->content = $output;
62+
return;
63+
}
64+
}
65+
66+
// minify the CSS
67+
if (($content = \call_user_func($config['minifier'], $content, $minify['script'])) !== false) {
68+
69+
// cache the minified code
70+
if ($file) {
71+
\file_put_contents($file, $content);
72+
}
73+
$this->content = $content;
5574
}
5675
}
5776
}

0 commit comments

Comments
 (0)