1
0
mirror of https://github.com/mrclay/minify.git synced 2025-08-06 14:16:28 +02:00

Fix up web-based tool and correct error byte in JSMin exceptions

This commit is contained in:
Steve Clay
2013-11-27 18:28:39 -05:00
parent f8b62b358b
commit 5560a664e9
4 changed files with 103 additions and 28 deletions

View File

@@ -200,8 +200,9 @@ class JSMin {
break; break;
} }
if ($this->isEOF($this->a)) { if ($this->isEOF($this->a)) {
$byte = $this->inputIndex - 1;
throw new JSMin_UnterminatedStringException( throw new JSMin_UnterminatedStringException(
"JSMin: Unterminated String at byte {$this->inputIndex}: {$str}"); "JSMin: Unterminated String at byte {$byte}: {$str}");
} }
$str .= $this->a; $str .= $this->a;
if ($this->a === '\\') { if ($this->a === '\\') {
@@ -251,8 +252,9 @@ class JSMin {
$this->a = $this->get(); $this->a = $this->get();
$pattern .= $this->a; $pattern .= $this->a;
} elseif ($this->isEOF($this->a)) { } elseif ($this->isEOF($this->a)) {
$byte = $this->inputIndex - 1;
throw new JSMin_UnterminatedRegExpException( throw new JSMin_UnterminatedRegExpException(
"JSMin: Unterminated RegExp at byte {$this->inputIndex}: {$pattern}"); "JSMin: Unterminated RegExp at byte {$byte}: {$pattern}");
} }
$this->output .= $this->a; $this->output .= $this->a;
$this->lastByteOut = $this->a; $this->lastByteOut = $this->a;

View File

@@ -63,8 +63,6 @@ class Minify_HTML {
* *
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
* unset, minify will sniff for an XHTML doctype. * unset, minify will sniff for an XHTML doctype.
*
* @return null
*/ */
public function __construct($html, $options = array()) public function __construct($html, $options = array())
{ {

View File

@@ -6,6 +6,10 @@ function getPost($key) {
: $_POST[$key]; : $_POST[$key];
} }
function h($txt) {
return htmlspecialchars($txt, ENT_QUOTES, 'UTF-8');
}
if (isset($_POST['textIn'])) { if (isset($_POST['textIn'])) {
require '../config.php'; require '../config.php';
$textIn = str_replace("\r\n", "\n", getPost('textIn')); $textIn = str_replace("\r\n", "\n", getPost('textIn'));
@@ -17,7 +21,7 @@ if (isset($_POST['method']) && $_POST['method'] === 'Minify and serve') {
if ($base) { if ($base) {
$textIn = preg_replace( $textIn = preg_replace(
'@(<head\\b[^>]*>)@i' '@(<head\\b[^>]*>)@i'
,'$1<base href="' . htmlspecialchars($base, ENT_QUOTES, 'UTF-8') . '" />' ,'$1<base href="' . h($base) . '" />'
,$textIn ,$textIn
); );
} }
@@ -38,14 +42,15 @@ if (isset($_POST['method']) && $_POST['method'] === 'Minify and serve') {
,'contentType' => Minify::TYPE_HTML ,'contentType' => Minify::TYPE_HTML
)); ));
} catch (Exception $e) { } catch (Exception $e) {
echo htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'); echo h($e->getMessage());
} }
exit(); exit();
} }
$classes = array('Minify_HTML', 'JSMin', 'Minify_CSS', 'Minify_CSSmin', 'JSMinPlus'); $tpl = array();
$tpl['classes'] = array('Minify_HTML', 'JSMin', 'Minify_CSS', 'Minify_CSSmin', 'JSMinPlus');
if (isset($_POST['method']) && in_array($_POST['method'], $classes)) { if (isset($_POST['method']) && in_array($_POST['method'], $tpl['classes'])) {
$args = array($textIn); $args = array($textIn);
if ($_POST['method'] === 'Minify_HTML') { if ($_POST['method'] === 'Minify_HTML') {
@@ -55,40 +60,78 @@ if (isset($_POST['method']) && in_array($_POST['method'], $classes)) {
); );
} }
$func = array($_POST['method'], 'minify'); $func = array($_POST['method'], 'minify');
$inOutBytes[0] = strlen($textIn); $tpl['inBytes'] = strlen($textIn);
$startTime = microtime(true); $startTime = microtime(true);
try { try {
$textOut = call_user_func_array($func, $args); $tpl['output'] = call_user_func_array($func, $args);
} catch (Exception $e) { } catch (Exception $e) {
echo htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'); $tpl['exceptionMsg'] = getExceptionMsg($e, $textIn);
exit; $tpl['output'] = $textIn;
sendPage($tpl);
} }
$elapsedTime = microtime(true) - $startTime; $tpl['time'] = microtime(true) - $startTime;
$inOutBytes[1] = strlen($textOut); $tpl['outBytes'] = strlen($tpl['output']);
} }
header('Content-Type: text/html; charset=utf-8'); sendPage($tpl);
/**
* @param Exception $e
* @param string $input
* @return string HTML
*/
function getExceptionMsg(Exception $e, $input) {
$msg = "<p>" . h($e->getMessage()) . "</p>";
if (0 === strpos(get_class($e), 'JSMin_Unterminated')
&& preg_match('~byte (\d+)~', $e->getMessage(), $m)) {
$msg .= "<pre>";
if ($m[1] > 200) {
$msg .= h(substr($input, ($m[1] - 200), 200));
} else {
$msg .= h(substr($input, 0, $m[1]));
}
$highlighted = isset($input[$m[1]]) ? h($input[$m[1]]) : '&#9220;';
if ($highlighted === "\n") {
$highlighted = "&#9166;\n";
}
$msg .= "<span style='background:#c00;color:#fff'>$highlighted</span>";
$msg .= h(substr($input, $m[1] + 1, 200)) . "</span></pre>";
}
return $msg;
}
/**
* Draw page
*
* @param array $vars
*/
function sendPage($vars) {
header('Content-Type: text/html; charset=utf-8');
?> ?>
<!DOCTYPE html><head><title>minifyTextarea</title></head> <!DOCTYPE html><head><title>minifyTextarea</title></head>
<?php <?php
if (isset($inOutBytes)) { if (isset($vars['exceptionMsg'])) {
echo $vars['exceptionMsg'];
}
if (isset($vars['time'])) {
echo " echo "
<table> <table>
<tr><th>Bytes in</th><td>{$inOutBytes[0]} (after line endings normalized to <code>\\n</code>)</td></tr> <tr><th>Bytes in</th><td>{$vars['inBytes']} (after line endings normalized to <code>\\n</code>)</td></tr>
<tr><th>Bytes out</th><td>{$inOutBytes[1]} (reduced " . round(100 - (100 * $inOutBytes[1] / $inOutBytes[0])) . "%)</td></tr> <tr><th>Bytes out</th><td>{$vars['outBytes']} (reduced " . round(100 - (100 * $vars['outBytes'] / $vars['inBytes'])) . "%)</td></tr>
<tr><th>Time (s)</th><td>" . round($elapsedTime, 5) . "</td></tr> <tr><th>Time (s)</th><td>" . round($vars['time'], 5) . "</td></tr>
</table> </table>
"; ";
} }
?> ?>
<form action="?2" method="post"> <form action="?2" method="post">
<p><label>Content<br><textarea name="textIn" cols="80" rows="35" style="width:99%"><?php <p><label>Content<br><textarea name="textIn" cols="80" rows="35" style="width:99%"><?php
if (isset($textOut)) { if (isset($vars['output'])) {
echo htmlspecialchars($textOut, ENT_QUOTES, 'UTF-8'); echo h($vars['output']);
} }
?></textarea></label></p> ?></textarea></label></p>
<p>Minify with: <p>Minify with:
<?php foreach ($classes as $minClass): ?> <?php foreach ($vars['classes'] as $minClass): ?>
<input type="submit" name="method" value="<?php echo $minClass; ?>"> <input type="submit" name="method" value="<?php echo $minClass; ?>">
<?php endForEach; ?> <?php endForEach; ?>
</p> </p>
@@ -98,3 +141,35 @@ if (isset($textOut)) {
<label>Insert BASE element w/ href: <input type="text" name="base" size="20"></label> <label>Insert BASE element w/ href: <input type="text" name="base" size="20"></label>
</p> </p>
</form> </form>
<?php if (isset($vars['selectByte'])) { ?>
<script>
function selectText(el, begin, end) {
var len = el.value.length;
end = end || len;
if (begin == null) {
el.select();
} else {
if (el.setSelectionRange) {
el.setSelectionRange(begin, end);
} else {
if (el.createTextRange) {
var tr = el.createTextRange()
,c = "character";
tr.moveStart(c, begin);
tr.moveEnd(c, end - len);
tr.select();
} else {
el.select();
}
}
}
el.focus();
}
window.onload = function () {
var ta = document.querySelector('textarea[name="textIn"]');
selectText(ta, <?= $vars['selectByte'] ?>, <?= ($vars['selectByte'] + 1) ?>);
};
</script>
<?php }
exit;
}

View File

@@ -60,29 +60,29 @@ function test_JSMin()
test_JSMin_exception('"Hello' test_JSMin_exception('"Hello'
,'Unterminated String' ,'Unterminated String'
,'JSMin_UnterminatedStringException' ,'JSMin_UnterminatedStringException'
,"JSMin: Unterminated String at byte 6: \"Hello"); ,"JSMin: Unterminated String at byte 5: \"Hello");
test_JSMin_exception("return /regexp\n}" test_JSMin_exception("return /regexp\n}"
,'Unterminated RegExp' ,'Unterminated RegExp'
,'JSMin_UnterminatedRegExpException' ,'JSMin_UnterminatedRegExpException'
,"JSMin: Unterminated RegExp at byte 15: /regexp\n"); ,"JSMin: Unterminated RegExp at byte 14: /regexp\n");
test_JSMin_exception("return/regexp\n}" test_JSMin_exception("return/regexp\n}"
,'Unterminated RegExp' ,'Unterminated RegExp'
,'JSMin_UnterminatedRegExpException' ,'JSMin_UnterminatedRegExpException'
,"JSMin: Unterminated RegExp at byte 14: /regexp\n"); ,"JSMin: Unterminated RegExp at byte 13: /regexp\n");
test_JSMin_exception(";return/regexp\n}" test_JSMin_exception(";return/regexp\n}"
,'Unterminated RegExp' ,'Unterminated RegExp'
,'JSMin_UnterminatedRegExpException' ,'JSMin_UnterminatedRegExpException'
,"JSMin: Unterminated RegExp at byte 15: /regexp\n"); ,"JSMin: Unterminated RegExp at byte 14: /regexp\n");
test_JSMin_exception(";return /regexp\n}" test_JSMin_exception(";return /regexp\n}"
,'Unterminated RegExp' ,'Unterminated RegExp'
,'JSMin_UnterminatedRegExpException' ,'JSMin_UnterminatedRegExpException'
,"JSMin: Unterminated RegExp at byte 16: /regexp\n"); ,"JSMin: Unterminated RegExp at byte 15: /regexp\n");
test_JSMin_exception("typeof/regexp\n}" test_JSMin_exception("typeof/regexp\n}"
,'Unterminated RegExp' ,'Unterminated RegExp'
,'JSMin_UnterminatedRegExpException' ,'JSMin_UnterminatedRegExpException'
,"JSMin: Unterminated RegExp at byte 14: /regexp\n"); ,"JSMin: Unterminated RegExp at byte 13: /regexp\n");
test_JSMin_exception("/* Comment " test_JSMin_exception("/* Comment "
,'Unterminated Comment' ,'Unterminated Comment'