From afbcadf33cebe8678322c1a8d0c4be4e794d4cb3 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Mon, 7 Mar 2016 16:45:01 -0500 Subject: [PATCH 1/7] Begin prep for 2.3 release --- .gitignore | 2 ++ HISTORY.txt | 34 ++++++++++++++++++++++------------ docs/CookBook.wiki.md | 7 +++---- docs/CustomSource.wiki.md | 2 +- min/lib/DooDigestAuth.php | 2 ++ min/lib/FirePHP.php | 2 ++ min/lib/JSMinPlus.php | 6 +++++- min/lib/Minify/Loader.php | 5 +++++ min/lib/Minify/Logger.php | 2 +- 9 files changed, 43 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 3d403b4..42733c5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ # / /test /.idea/ +/composer.lock .DS_Store /vendor +/.php_cs.cache diff --git a/HISTORY.txt b/HISTORY.txt index 464251c..39b46e4 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,10 +1,20 @@ Minify Release History -(master) - * Builder styled with Bootstrap (thanks to help from acidvertigo) - * Add config option for simply concatenating files +Version 2.3.0 + * Adds `$min_concatOnly` option to just concatenate files + * Deprecates use of Minify_Loader + * Deprecates use of Minify_Logger + * Deprecates use of JSMinPlus + * Deprecates use of FirePHP + * Deprecates use of DooDigestAuth -Version 2.2.0 +Version 2.2.1 (2014-10-30) + * Builder styled with Bootstrap (thanks to help from acidvertigo) + * Update CSSmin to v.2.4.8 + * Added WinCache + * URLs with spaces properly rewritten + +Version 2.2.0 (2014-03-12) * Fix handling of RegEx in certain situations in JSMin * Thanks to Vovan-VE for reporting this * Update composer.json with support info @@ -26,11 +36,11 @@ Version 2.2.0 * Allow far-future expiration and file versioning with the "v" querystirng parameter in addition to existing method * Lots of general code tidy ups -Version 2.1.7 +Version 2.1.7 (2013-07-23) * Fixes arbitrary file inclusion vulnerability on some systems * Thanks to Matt Mecham for reporting this -Version 2.1.6 +Version 2.1.6 (2013-07-19) * JSMin fixes * Prevents some Closure Compiler API failures * Uses autoloading for all class loading @@ -42,7 +52,7 @@ Version 2.1.6 * CLI script more portable * Adds composer.json -Version 2.1.5 +Version 2.1.5 (2012-03-10) * Removed XSS vulnerability * Disabled builder bby default * command line tools to minify and rewrite URIs in CSS @@ -51,7 +61,7 @@ Version 2.1.5 * Closure Compiler uses cURL when allow_url_fopen is off * Missing file notices when using groups -Version 2.1.4 +Version 2.1.4 (2010-07-10) * Option to minify JS with Closure Compiler API w/ JSMin failover * Cookie/bookmarklet-based debug mode. No HTML editing! * Allows 1 file to be missing w/o complete failure @@ -67,7 +77,7 @@ Version 2.1.4 * Removed annoying maxFiles limit * mbstring.func_overload usage is safer -Version 2.1.3 +Version 2.1.3 (2009-06-30) * HTTP fixes * ETag generation now valid (different when gzipped) * Vary header always sent when Accept-Encoding is sniffed @@ -79,7 +89,7 @@ Version 2.1.3 * Allow setting contentType in Minify_Source objects * No more 5.3 deprecation warnings: split() removed -Version 2.1.2 +Version 2.1.2 (2009-03-04) * Javascript fixes * Debug mode no longer confused by "*/*" in strings/RegExps (jQuery) * quote characters inside RegExp literals no longer cause exception @@ -91,14 +101,14 @@ Version 2.1.2 * Builder app doesn't fail on systems without gzdeflate() * APC caching class included -Version 2.1.1 +Version 2.1.1 (2008-10-19) * Bug fix release * Detection and workarounds for zlib.output_compression and non-PHP encoding modules * Zlib not required (mod_rewrite, et.al., can still be used for encoding) * HTML : More IE conditional comments preserved * Minify_groupUri() utility fixed -Version 2.1.0 +Version 2.1.0 (2008-09-18) * "min" default application for quick deployment * Minify URI Builder app & bookmarklet for quickly creating minify URIs * Relative URIs in CSS file are fixed automatically by default diff --git a/docs/CookBook.wiki.md b/docs/CookBook.wiki.md index a68de4d..975ddfc 100644 --- a/docs/CookBook.wiki.md +++ b/docs/CookBook.wiki.md @@ -91,13 +91,12 @@ $min_serveOptions['minifiers']['text/css'] = array('Minify_CSSmin', 'minify'); ## JSMin+ -Minify 2.1.3 comes with Tino Zijdel's [JSMin+](http://crisp.tweakblogs.net/blog/1665/a-new-javascript-minifier-jsmin+.html) 1.1. This is a full parser based on a port of [Narcissus](http://en.wikipedia.org/wiki/Narcissus_(JavaScript_engine)). To try it out: +Tino Zijdel's [JSMin+](http://crisp.tweakblogs.net/blog/6861/jsmin%2B-version-14.html) has resulted in memory usage problems for many users and will be removed from the Minify codebase in 3.0. If you wish to use it, you should download it outside the Minify directory and link to it: + ``` +require '/path/to/jsminplus.php'; $min_serveOptions['minifiers']['application/x-javascript'] = array('JSMinPlus', 'minify'); ``` -This should yield smaller javascript files, but I've tested this only briefly. For production you may want to get the [latest version](http://crisp.tweakblogs.net/blog/cat/716) (you must rename it: `min/lib/JSMinPlus.php`). - -Note: JSMin+ is memory intensive, so be prepared to up your memory limit. Also it has no [comment preservation](http://code.google.com/p/minify/source/browse/tags/release_2.1.3/min/lib/JSMin.php#10) as of 1.3, in case you rely on this. ## Server-specific Options diff --git a/docs/CustomSource.wiki.md b/docs/CustomSource.wiki.md index 1d615cb..c593c32 100644 --- a/docs/CustomSource.wiki.md +++ b/docs/CustomSource.wiki.md @@ -33,7 +33,7 @@ To change minifier, set `minifier` to a [callback](http://php.net/manual/en/lang ``` if (! function_exists('myMin')) { function myMin($js) { - require_once 'JSMinPlus.php'; + require_once '/path/to/jsminplus.php'; return JSMinPlus::minify($js); } } diff --git a/min/lib/DooDigestAuth.php b/min/lib/DooDigestAuth.php index 69bc4ed..5a9b467 100644 --- a/min/lib/DooDigestAuth.php +++ b/min/lib/DooDigestAuth.php @@ -23,6 +23,8 @@ * @version $Id: DooDigestAuth.php 1000 2009-07-7 18:27:22 * @package doo.auth * @since 1.0 + * + * @deprecated 2.3 This will be removed in Minify 3.0 */ class DooDigestAuth{ diff --git a/min/lib/FirePHP.php b/min/lib/FirePHP.php index 8fff783..bf4fb70 100644 --- a/min/lib/FirePHP.php +++ b/min/lib/FirePHP.php @@ -64,6 +64,8 @@ if (!defined('E_USER_DEPRECATED')) { * @author Christoph Dorn * @license [MIT License](http://www.opensource.org/licenses/mit-license.php) * @package FirePHPCore + * + * @deprecated 2.3 This will be removed in Minify 3.0 */ class FirePHP { diff --git a/min/lib/JSMinPlus.php b/min/lib/JSMinPlus.php index 5a3c5bd..1c7463c 100644 --- a/min/lib/JSMinPlus.php +++ b/min/lib/JSMinPlus.php @@ -170,7 +170,9 @@ define('KEYWORD_VOID', 'void'); define('KEYWORD_WHILE', 'while'); define('KEYWORD_WITH', 'with'); - +/** + * @deprecated 2.3 This will be removed in Minify 3.0 + */ class JSMinPlus { private $parser; @@ -197,6 +199,8 @@ class JSMinPlus public static function minify($js, $filename='') { + trigger_error(__CLASS__ . ' is deprecated. This will be removed in Minify 3.0', E_USER_DEPRECATED); + static $instance; // this is a singleton diff --git a/min/lib/Minify/Loader.php b/min/lib/Minify/Loader.php index 0a225c0..ca43192 100644 --- a/min/lib/Minify/Loader.php +++ b/min/lib/Minify/Loader.php @@ -9,6 +9,8 @@ * * @package Minify * @author Stephen Clay + * + * @deprecated 2.3 This will be removed in Minify 3.0 */ class Minify_Loader { public function loadClass($class) @@ -20,6 +22,9 @@ class Minify_Loader { } } + /** + * @deprecated 2.3 This will be removed in Minify 3.0 + */ static public function register() { $inst = new self(); diff --git a/min/lib/Minify/Logger.php b/min/lib/Minify/Logger.php index 8eb72f4..5217441 100644 --- a/min/lib/Minify/Logger.php +++ b/min/lib/Minify/Logger.php @@ -10,7 +10,7 @@ * @package Minify * @author Stephen Clay * - * @todo lose this singleton! pass log object in Minify::serve and distribute to others + * @deprecated 2.3 This will be removed in Minify 3.0 */ class Minify_Logger { From 2d3c417a516750853bc23c6176e900d4efa6bb3d Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Fri, 11 Mar 2016 23:08:29 -0500 Subject: [PATCH 2/7] Update README.md Add news --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index c51b193..356c33b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,11 @@ The stats above are from a [brief walkthrough](http://mrclay.org/index.php/2008/ Relative URLs in CSS files are rewritten to compensate for being served from a different directory. +News +---- + +Version [2.3.0](https://github.com/mrclay/minify/releases/tag/2.3.0) was released, mainly to deprecate some classes that will be removed in 3.0. + Wordpress User? --------------- From 0eb2cfe78d07c2462362c90727c72022a6007195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 13 Mar 2016 14:55:23 +0200 Subject: [PATCH 3/7] Update README.md fixes from googlecode migration --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 356c33b..e896bb5 100644 --- a/README.md +++ b/README.md @@ -81,4 +81,4 @@ Acknowledgments Minify was inspired by [jscsscomp](http://code.google.com/p/jscsscomp/) by Maxim Martynyuk and by the article [Supercharged JavaScript](http://www.hunlock.com/blogs/Supercharged_Javascript) by Patrick Hunlock. -The [JSMin library](http://www.crockford.com/javascript/jsmin.html) used for !JavaScript minification was originally written by Douglas Crockford and was [ported to PHP](https://github.com/mrclay/jsmin-php) by Ryan Grove specifically for use in Minify. +The [JSMin library](http://www.crockford.com/javascript/jsmin.html) used for JavaScript minification was originally written by Douglas Crockford and was [ported to PHP](https://github.com/mrclay/jsmin-php) by Ryan Grove specifically for use in Minify. From cff094781ba46cc3636e9fe546ea0c5b39c670bf Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Wed, 16 Mar 2016 18:32:47 -0400 Subject: [PATCH 4/7] No longer alters inline SVG id URLs Fixes #517 --- min/lib/Minify/CSS/UriRewriter.php | 38 ++++++++++++++++++- .../_test_files/css_uriRewriter/exp.css | 4 ++ .../css_uriRewriter/exp_prepend.css | 4 ++ .../css_uriRewriter/exp_prepend2.css | 4 ++ .../_test_files/css_uriRewriter/in.css | 4 ++ 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/min/lib/Minify/CSS/UriRewriter.php b/min/lib/Minify/CSS/UriRewriter.php index 43cc254..e963fb8 100644 --- a/min/lib/Minify/CSS/UriRewriter.php +++ b/min/lib/Minify/CSS/UriRewriter.php @@ -66,16 +66,20 @@ class Minify_CSS_UriRewriter { self::$debugText .= "\n"; $css = self::_trimUrls($css); - + + $css = self::_owlifySvgPaths($css); + // rewrite $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' ,array(self::$className, '_processUriCB'), $css); $css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/' ,array(self::$className, '_processUriCB'), $css); + $css = self::_unOwlify($css); + return $css; } - + /** * In CSS content, prepend a path to relative URIs * @@ -90,6 +94,8 @@ class Minify_CSS_UriRewriter { self::$_prependPath = $path; $css = self::_trimUrls($css); + + $css = self::_owlifySvgPaths($css); // append $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' @@ -97,6 +103,8 @@ class Minify_CSS_UriRewriter { $css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/' ,array(self::$className, '_processUriCB'), $css); + $css = self::_unOwlify($css); + self::$_prependPath = null; return $css; } @@ -304,4 +312,30 @@ class Minify_CSS_UriRewriter { ? "@import {$quoteChar}{$uri}{$quoteChar}" : "url({$quoteChar}{$uri}{$quoteChar})"; } + + /** + * Mungs some inline SVG URL declarations so they won't be touched + * + * @link https://github.com/mrclay/minify/issues/517 + * @see _unOwlify + * + * @param string $css + * @return string + */ + private static function _owlifySvgPaths($css) { + return preg_replace('~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)url(\(\s*#\w+\s*\))~', '$1owl$2', $css); + + } + + /** + * Undo work of _owlify + * + * @see _owlifySvgPaths + * + * @param string $css + * @return string + */ + private static function _unOwlify($css) { + return preg_replace('~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)owl~', '$1url', $css); + } } diff --git a/min_unit_tests/_test_files/css_uriRewriter/exp.css b/min_unit_tests/_test_files/css_uriRewriter/exp.css index 22c109f..3296c26 100644 --- a/min_unit_tests/_test_files/css_uriRewriter/exp.css +++ b/min_unit_tests/_test_files/css_uriRewriter/exp.css @@ -8,6 +8,10 @@ @import url("/css/foo.css"); /* abs, should not alter */ @import url(/css2/foo.css); /* abs, should not alter */ @import url(foo:bar); /* scheme, should not alter */ +foo {clip-path:url(#c1)} /* inline clip path, should not alter */ +foo {clip-path:url(/_test_files/css_uriRewriter/foo.svg#c1)} +foo {mask: url(#c1)} /* should not alter */ +foo {-webkit-mask: url(#c1)} /* should not alter */ foo {background:url('/_test_files/css_uriRewriter/bar/foo.png')} foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ diff --git a/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css b/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css index ce31df1..bc09c44 100644 --- a/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css +++ b/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css @@ -8,6 +8,10 @@ @import url("/css/foo.css"); /* abs, should not alter */ @import url(/css2/foo.css); /* abs, should not alter */ @import url(foo:bar); /* scheme, should not alter */ +foo {clip-path:url(#c1)} /* inline clip path, should not alter */ +foo {clip-path:url(http://cnd.com/A/B/foo.svg#c1)} +foo {mask: url(#c1)} /* should not alter */ +foo {-webkit-mask: url(#c1)} /* should not alter */ foo {background:url('http://cnd.com/A/B/bar/foo.png')} foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ diff --git a/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css b/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css index 087d94d..c8f7c61 100644 --- a/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css +++ b/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css @@ -8,6 +8,10 @@ @import url("/css/foo.css"); /* abs, should not alter */ @import url(/css2/foo.css); /* abs, should not alter */ @import url(foo:bar); /* scheme, should not alter */ +foo {clip-path:url(#c1)} /* inline clip path, should not alter */ +foo {clip-path:url(//cnd.com/A/B/foo.svg#c1)} +foo {mask: url(#c1)} /* should not alter */ +foo {-webkit-mask: url(#c1)} /* should not alter */ foo {background:url('//cnd.com/A/B/bar/foo.png')} foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ diff --git a/min_unit_tests/_test_files/css_uriRewriter/in.css b/min_unit_tests/_test_files/css_uriRewriter/in.css index 3bdce36..0200450 100644 --- a/min_unit_tests/_test_files/css_uriRewriter/in.css +++ b/min_unit_tests/_test_files/css_uriRewriter/in.css @@ -8,6 +8,10 @@ @import url("/css/foo.css"); /* abs, should not alter */ @import url(/css2/foo.css); /* abs, should not alter */ @import url(foo:bar); /* scheme, should not alter */ +foo {clip-path:url(#c1)} /* inline clip path, should not alter */ +foo {clip-path:url(foo.svg#c1)} +foo {mask: url( #c1 )} /* should not alter */ +foo {-webkit-mask: url( #c1 )} /* should not alter */ foo {background:url('bar/foo.png')} foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ From 28197576c69fedb985e7488bf6d2af5002534f54 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Mon, 18 Apr 2016 21:02:00 -0400 Subject: [PATCH 5/7] Use $min_libPath in examples and move it within config.php Fixes #522 --- docs/CookBook.wiki.md | 4 ++-- min/config.php | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/CookBook.wiki.md b/docs/CookBook.wiki.md index 975ddfc..6229cd2 100644 --- a/docs/CookBook.wiki.md +++ b/docs/CookBook.wiki.md @@ -7,7 +7,7 @@ By default, Minify uses [Minify\_Cache\_File](http://code.google.com/p/minify/so ### APC ``` -require 'lib/Minify/Cache/APC.php'; +require "$min_libPath/Minify/Cache/APC.php"; $min_cachePath = new Minify_Cache_APC(); ``` @@ -15,7 +15,7 @@ $min_cachePath = new Minify_Cache_APC(); You must create and connect your Memcache object then pass it to `Minify_Cache_Memcache`'s constructor. ``` -require 'lib/Minify/Cache/Memcache.php'; +require "$min_libPath/Minify/Cache/Memcache.php"; $memcache = new Memcache; $memcache->connect('localhost', 11211); $min_cachePath = new Minify_Cache_Memcache($memcache); diff --git a/min/config.php b/min/config.php index 3b5fd2b..d5d413d 100644 --- a/min/config.php +++ b/min/config.php @@ -60,11 +60,19 @@ $min_allowDebugFlag = false; //$min_cachePath = '/tmp'; //$min_cachePath = preg_replace('/^\\d+;/', '', session_save_path()); + +/** + * Path to Minify's lib folder. If you happen to move it, change + * this accordingly. + */ +$min_libPath = dirname(__FILE__) . '/lib'; + + /** * To use APC/Memcache/ZendPlatform for cache storage, require the class and * set $min_cachePath to an instance. Example below: */ -//require dirname(__FILE__) . '/lib/Minify/Cache/APC.php'; +//require "$min_libPath/Minify/Cache/APC.php"; //$min_cachePath = new Minify_Cache_APC(); @@ -187,12 +195,5 @@ $min_symlinks = array(); $min_uploaderHoursBehind = 0; -/** - * Path to Minify's lib folder. If you happen to move it, change - * this accordingly. - */ -$min_libPath = dirname(__FILE__) . '/lib'; - - // try to disable output_compression (may not have an effect) ini_set('zlib.output_compression', '0'); From 6a2995f93256a54928f7413bf26971e92ed43d2b Mon Sep 17 00:00:00 2001 From: Evgeny Mazovetskiy Date: Mon, 9 May 2016 17:29:08 +0200 Subject: [PATCH 6/7] list allowDirs in exception to simplify debugging --- min/lib/Minify/Controller/Base.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/min/lib/Minify/Controller/Base.php b/min/lib/Minify/Controller/Base.php index 4e43013..3ed3028 100644 --- a/min/lib/Minify/Controller/Base.php +++ b/min/lib/Minify/Controller/Base.php @@ -126,7 +126,9 @@ abstract class Minify_Controller_Base { return true; } } - throw new Exception("File '$file' is outside \$allowDirs. If the path is" + + $allowDirs = implode(';', array_values($allowDirs)); + throw new Exception("File '$file' is outside \$allowDirs ($allowDirs). If the path is" . " resolved via an alias/symlink, look into the \$min_symlinks option." . " E.g. \$min_symlinks['/" . dirname($uri) . "'] = '" . dirname($file) . "';"); } From 6f94b78135edfc6c2d76a557fa70e9ea6392004e Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Thu, 12 May 2016 11:07:59 -0400 Subject: [PATCH 7/7] Remove stuff accidentally left in merge --- .gitignore | 1 - HISTORY.md | 1 + config.php | 8 +- min/lib/DooDigestAuth.php | 123 -- min/lib/FirePHP.php | 1843 ------------------------ min/lib/JSMinPlus.php | 2090 ---------------------------- min/lib/Minify/Controller/Base.php | 223 --- min/lib/Minify/Loader.php | 33 - min/lib/Minify/Logger.php | 47 - 9 files changed, 2 insertions(+), 4367 deletions(-) delete mode 100644 min/lib/DooDigestAuth.php delete mode 100644 min/lib/FirePHP.php delete mode 100644 min/lib/JSMinPlus.php delete mode 100644 min/lib/Minify/Controller/Base.php delete mode 100644 min/lib/Minify/Loader.php delete mode 100644 min/lib/Minify/Logger.php diff --git a/.gitignore b/.gitignore index e743192..ca2c1a9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ [._]s[a-w][a-z] .DS_Store -/test /.idea/ /composer.lock /vendor diff --git a/HISTORY.md b/HISTORY.md index ead861a..641efe0 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,6 +5,7 @@ * Removes DooDigestAuth * Removes Minify_Loader (uses Composer) * Removes Minify_Logger (uses Monolog) +* Removes `$min_libPath` option * The Minify, source, and controller components have changed APIs * Better CSS minification via Túbal Martín's CSSMin * Add config option for simply concatenating files diff --git a/config.php b/config.php index 098ce41..1c1cd4f 100644 --- a/config.php +++ b/config.php @@ -57,13 +57,6 @@ $min_allowDebugFlag = false; //$min_cachePath = preg_replace('/^\\d+;/', '', session_save_path()); -/** - * Path to Minify's lib folder. If you happen to move it, change - * this accordingly. - */ -$min_libPath = dirname(__FILE__) . '/lib'; - - /** * To use APC/Memcache/ZendPlatform for cache storage, require the class and * set $min_cachePath to an instance. Example below: @@ -199,3 +192,4 @@ $min_uploaderHoursBehind = 0; */ //$min_factories['minify'] = ... a callable accepting a Minify\App object //$min_factories['controller'] = ... a callable accepting a Minify\App object + diff --git a/min/lib/DooDigestAuth.php b/min/lib/DooDigestAuth.php deleted file mode 100644 index 5a9b467..0000000 --- a/min/lib/DooDigestAuth.php +++ /dev/null @@ -1,123 +0,0 @@ - - * @link http://www.doophp.com/ - * @copyright Copyright © 2009 Leng Sheng Hong - * @license http://www.doophp.com/license - */ - -/** - * Handles HTTP digest authentication - * - *

HTTP digest authentication can be used with the URI router. - * HTTP digest is much more recommended over the use of HTTP Basic auth which doesn't provide any encryption. - * If you are running PHP on Apache in CGI/FastCGI mode, you would need to - * add the following line to your .htaccess for digest auth to work correctly.

- * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] - * - *

This class is tested under Apache 2.2 and Cherokee web server. It should work in both mod_php and cgi mode.

- * - * @author Leng Sheng Hong - * @version $Id: DooDigestAuth.php 1000 2009-07-7 18:27:22 - * @package doo.auth - * @since 1.0 - * - * @deprecated 2.3 This will be removed in Minify 3.0 - */ -class DooDigestAuth{ - - /** - * Authenticate against a list of username and passwords. - * - *

HTTP Digest Authentication doesn't work with PHP in CGI mode, - * you have to add this into your .htaccess RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

- * - * @param string $realm Name of the authentication session - * @param array $users An assoc array of username and password: array('uname1'=>'pwd1', 'uname2'=>'pwd2') - * @param string $fail_msg Message to be displayed if the User cancel the login - * @param string $fail_url URL to be redirect if the User cancel the login - * @return string The username if login success. - */ - public static function http_auth($realm, $users, $fail_msg=NULL, $fail_url=NULL){ - $realm = "Restricted area - $realm"; - - //user => password - //$users = array('admin' => '1234', 'guest' => 'guest'); - if(!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && strpos($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 'Digest')===0){ - $_SERVER['PHP_AUTH_DIGEST'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; - } - - if (empty($_SERVER['PHP_AUTH_DIGEST'])) { - header('WWW-Authenticate: Digest realm="'.$realm. - '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); - header('HTTP/1.1 401 Unauthorized'); - if($fail_msg!=NULL) - die($fail_msg); - if($fail_url!=NULL) - die(""); - exit; - } - - // analyze the PHP_AUTH_DIGEST variable - if (!($data = self::http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])){ - header('WWW-Authenticate: Digest realm="'.$realm. - '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); - header('HTTP/1.1 401 Unauthorized'); - if($fail_msg!=NULL) - die($fail_msg); - if($fail_url!=NULL) - die(""); - exit; - } - - // generate the valid response - $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]); - $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); - $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); - - if ($data['response'] != $valid_response){ - header('HTTP/1.1 401 Unauthorized'); - header('WWW-Authenticate: Digest realm="'.$realm. - '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); - if($fail_msg!=NULL) - die($fail_msg); - if($fail_url!=NULL) - die(""); - exit; - } - - // ok, valid username & password - return $data['username']; - } - - /** - * Method to parse the http auth header, works with IE. - * - * Internet Explorer returns a qop="xxxxxxxxxxx" in the header instead of qop=xxxxxxxxxxx as most browsers do. - * - * @param string $txt header string to parse - * @return array An assoc array of the digest auth session - */ - private static function http_digest_parse($txt) - { - $res = preg_match("/username=\"([^\"]+)\"/i", $txt, $match); - $data['username'] = (isset($match[1]))?$match[1]:null; - $res = preg_match('/nonce=\"([^\"]+)\"/i', $txt, $match); - $data['nonce'] = $match[1]; - $res = preg_match('/nc=([0-9]+)/i', $txt, $match); - $data['nc'] = $match[1]; - $res = preg_match('/cnonce=\"([^\"]+)\"/i', $txt, $match); - $data['cnonce'] = $match[1]; - $res = preg_match('/qop=([^,]+)/i', $txt, $match); - $data['qop'] = str_replace('"','',$match[1]); - $res = preg_match('/uri=\"([^\"]+)\"/i', $txt, $match); - $data['uri'] = $match[1]; - $res = preg_match('/response=\"([^\"]+)\"/i', $txt, $match); - $data['response'] = $match[1]; - return $data; - } - - -} diff --git a/min/lib/FirePHP.php b/min/lib/FirePHP.php deleted file mode 100644 index bf4fb70..0000000 --- a/min/lib/FirePHP.php +++ /dev/null @@ -1,1843 +0,0 @@ -, Copyright 2007, New BSD License -// - qbbr, Sokolov Innokenty , Copyright 2011, New BSD License -// - cadorn, Christoph Dorn , Copyright 2011, MIT License - -/** - * *** BEGIN LICENSE BLOCK ***** - * - * [MIT License](http://www.opensource.org/licenses/mit-license.php) - * - * Copyright (c) 2007+ [Christoph Dorn](http://www.christophdorn.com/) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * ***** END LICENSE BLOCK ***** - * - * @copyright Copyright (C) 2007+ Christoph Dorn - * @author Christoph Dorn - * @license [MIT License](http://www.opensource.org/licenses/mit-license.php) - * @package FirePHPCore - */ - -/** - * @see http://code.google.com/p/firephp/issues/detail?id=112 - */ -if (!defined('E_STRICT')) { - define('E_STRICT', 2048); -} -if (!defined('E_RECOVERABLE_ERROR')) { - define('E_RECOVERABLE_ERROR', 4096); -} -if (!defined('E_DEPRECATED')) { - define('E_DEPRECATED', 8192); -} -if (!defined('E_USER_DEPRECATED')) { - define('E_USER_DEPRECATED', 16384); -} - -/** - * Sends the given data to the FirePHP Firefox Extension. - * The data can be displayed in the Firebug Console or in the - * "Server" request tab. - * - * For more information see: http://www.firephp.org/ - * - * @copyright Copyright (C) 2007+ Christoph Dorn - * @author Christoph Dorn - * @license [MIT License](http://www.opensource.org/licenses/mit-license.php) - * @package FirePHPCore - * - * @deprecated 2.3 This will be removed in Minify 3.0 - */ -class FirePHP { - - /** - * FirePHP version - * - * @var string - */ - const VERSION = '0.3'; // @pinf replace '0.3' with '%%VERSION%%' - - /** - * Firebug LOG level - * - * Logs a message to firebug console. - * - * @var string - */ - const LOG = 'LOG'; - - /** - * Firebug INFO level - * - * Logs a message to firebug console and displays an info icon before the message. - * - * @var string - */ - const INFO = 'INFO'; - - /** - * Firebug WARN level - * - * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. - * - * @var string - */ - const WARN = 'WARN'; - - /** - * Firebug ERROR level - * - * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. - * - * @var string - */ - const ERROR = 'ERROR'; - - /** - * Dumps a variable to firebug's server panel - * - * @var string - */ - const DUMP = 'DUMP'; - - /** - * Displays a stack trace in firebug console - * - * @var string - */ - const TRACE = 'TRACE'; - - /** - * Displays an exception in firebug console - * - * Increments the firebug error count. - * - * @var string - */ - const EXCEPTION = 'EXCEPTION'; - - /** - * Displays an table in firebug console - * - * @var string - */ - const TABLE = 'TABLE'; - - /** - * Starts a group in firebug console - * - * @var string - */ - const GROUP_START = 'GROUP_START'; - - /** - * Ends a group in firebug console - * - * @var string - */ - const GROUP_END = 'GROUP_END'; - - /** - * Singleton instance of FirePHP - * - * @var FirePHP - */ - protected static $instance = null; - - /** - * Flag whether we are logging from within the exception handler - * - * @var boolean - */ - protected $inExceptionHandler = false; - - /** - * Flag whether to throw PHP errors that have been converted to ErrorExceptions - * - * @var boolean - */ - protected $throwErrorExceptions = true; - - /** - * Flag whether to convert PHP assertion errors to Exceptions - * - * @var boolean - */ - protected $convertAssertionErrorsToExceptions = true; - - /** - * Flag whether to throw PHP assertion errors that have been converted to Exceptions - * - * @var boolean - */ - protected $throwAssertionExceptions = false; - - /** - * Wildfire protocol message index - * - * @var integer - */ - protected $messageIndex = 1; - - /** - * Options for the library - * - * @var array - */ - protected $options = array('maxDepth' => 10, - 'maxObjectDepth' => 5, - 'maxArrayDepth' => 5, - 'useNativeJsonEncode' => true, - 'includeLineNumbers' => true); - - /** - * Filters used to exclude object members when encoding - * - * @var array - */ - protected $objectFilters = array( - 'firephp' => array('objectStack', 'instance', 'json_objectStack'), - 'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack') - ); - - /** - * A stack of objects used to detect recursion during object encoding - * - * @var object - */ - protected $objectStack = array(); - - /** - * Flag to enable/disable logging - * - * @var boolean - */ - protected $enabled = true; - - /** - * The insight console to log to if applicable - * - * @var object - */ - protected $logToInsightConsole = null; - - /** - * When the object gets serialized only include specific object members. - * - * @return array - */ - public function __sleep() - { - return array('options', 'objectFilters', 'enabled'); - } - - /** - * Gets singleton instance of FirePHP - * - * @param boolean $autoCreate - * @return FirePHP - */ - public static function getInstance($autoCreate = false) - { - if ($autoCreate === true && !self::$instance) { - self::init(); - } - return self::$instance; - } - - /** - * Creates FirePHP object and stores it for singleton access - * - * @return FirePHP - */ - public static function init() - { - return self::setInstance(new self()); - } - - /** - * Set the instance of the FirePHP singleton - * - * @param FirePHP $instance The FirePHP object instance - * @return FirePHP - */ - public static function setInstance($instance) - { - return self::$instance = $instance; - } - - /** - * Set an Insight console to direct all logging calls to - * - * @param object $console The console object to log to - * @return void - */ - public function setLogToInsightConsole($console) - { - if (is_string($console)) { - if (get_class($this) != 'FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) { - throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!'); - } - $this->logToInsightConsole = $this->to('request')->console($console); - } else { - $this->logToInsightConsole = $console; - } - } - - /** - * Enable and disable logging to Firebug - * - * @param boolean $enabled TRUE to enable, FALSE to disable - * @return void - */ - public function setEnabled($enabled) - { - $this->enabled = $enabled; - } - - /** - * Check if logging is enabled - * - * @return boolean TRUE if enabled - */ - public function getEnabled() - { - return $this->enabled; - } - - /** - * Specify a filter to be used when encoding an object - * - * Filters are used to exclude object members. - * - * @param string $class The class name of the object - * @param array $filter An array of members to exclude - * @return void - */ - public function setObjectFilter($class, $filter) - { - $this->objectFilters[strtolower($class)] = $filter; - } - - /** - * Set some options for the library - * - * Options: - * - maxDepth: The maximum depth to traverse (default: 10) - * - maxObjectDepth: The maximum depth to traverse objects (default: 5) - * - maxArrayDepth: The maximum depth to traverse arrays (default: 5) - * - useNativeJsonEncode: If true will use json_encode() (default: true) - * - includeLineNumbers: If true will include line numbers and filenames (default: true) - * - * @param array $options The options to be set - * @return void - */ - public function setOptions($options) - { - $this->options = array_merge($this->options, $options); - } - - /** - * Get options from the library - * - * @return array The currently set options - */ - public function getOptions() - { - return $this->options; - } - - /** - * Set an option for the library - * - * @param string $name - * @param mixed $value - * @return void - * @throws Exception - */ - public function setOption($name, $value) - { - if (!isset($this->options[$name])) { - throw $this->newException('Unknown option: ' . $name); - } - $this->options[$name] = $value; - } - - /** - * Get an option from the library - * - * @param string $name - * @return mixed - * @throws Exception - */ - public function getOption($name) - { - if (!isset($this->options[$name])) { - throw $this->newException('Unknown option: ' . $name); - } - return $this->options[$name]; - } - - /** - * Register FirePHP as your error handler - * - * Will throw exceptions for each php error. - * - * @return mixed Returns a string containing the previously defined error handler (if any) - */ - public function registerErrorHandler($throwErrorExceptions = false) - { - //NOTE: The following errors will not be caught by this error handler: - // E_ERROR, E_PARSE, E_CORE_ERROR, - // E_CORE_WARNING, E_COMPILE_ERROR, - // E_COMPILE_WARNING, E_STRICT - - $this->throwErrorExceptions = $throwErrorExceptions; - - return set_error_handler(array($this, 'errorHandler')); - } - - /** - * FirePHP's error handler - * - * Throws exception for each php error that will occur. - * - * @param integer $errno - * @param string $errstr - * @param string $errfile - * @param integer $errline - * @param array $errcontext - */ - public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) - { - // Don't throw exception if error reporting is switched off - if (error_reporting() == 0) { - return; - } - // Only throw exceptions for errors we are asking for - if (error_reporting() & $errno) { - - $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline); - if ($this->throwErrorExceptions) { - throw $exception; - } else { - $this->fb($exception); - } - } - } - - /** - * Register FirePHP as your exception handler - * - * @return mixed Returns the name of the previously defined exception handler, - * or NULL on error. - * If no previous handler was defined, NULL is also returned. - */ - public function registerExceptionHandler() - { - return set_exception_handler(array($this, 'exceptionHandler')); - } - - /** - * FirePHP's exception handler - * - * Logs all exceptions to your firebug console and then stops the script. - * - * @param Exception $exception - * @throws Exception - */ - function exceptionHandler($exception) - { - $this->inExceptionHandler = true; - - header('HTTP/1.1 500 Internal Server Error'); - - try { - $this->fb($exception); - } catch (Exception $e) { - echo 'We had an exception: ' . $e; - } - - $this->inExceptionHandler = false; - } - - /** - * Register FirePHP driver as your assert callback - * - * @param boolean $convertAssertionErrorsToExceptions - * @param boolean $throwAssertionExceptions - * @return mixed Returns the original setting or FALSE on errors - */ - public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false) - { - $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions; - $this->throwAssertionExceptions = $throwAssertionExceptions; - - if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) { - throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!'); - } - - return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler')); - } - - /** - * FirePHP's assertion handler - * - * Logs all assertions to your firebug console and then stops the script. - * - * @param string $file File source of assertion - * @param integer $line Line source of assertion - * @param mixed $code Assertion code - */ - public function assertionHandler($file, $line, $code) - { - if ($this->convertAssertionErrorsToExceptions) { - - $exception = new ErrorException('Assertion Failed - Code[ ' . $code . ' ]', 0, null, $file, $line); - - if ($this->throwAssertionExceptions) { - throw $exception; - } else { - $this->fb($exception); - } - - } else { - $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File' => $file, 'Line' => $line)); - } - } - - /** - * Start a group for following messages. - * - * Options: - * Collapsed: [true|false] - * Color: [#RRGGBB|ColorName] - * - * @param string $name - * @param array $options OPTIONAL Instructions on how to log the group - * @return true - * @throws Exception - */ - public function group($name, $options = null) - { - - if ( !isset($name) ) { - throw $this->newException('You must specify a label for the group!'); - } - - if ($options) { - if (!is_array($options)) { - throw $this->newException('Options must be defined as an array!'); - } - if (array_key_exists('Collapsed', $options)) { - $options['Collapsed'] = ($options['Collapsed']) ? 'true' : 'false'; - } - } - - return $this->fb(null, $name, FirePHP::GROUP_START, $options); - } - - /** - * Ends a group you have started before - * - * @return true - * @throws Exception - */ - public function groupEnd() - { - return $this->fb(null, null, FirePHP::GROUP_END); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::LOG - * @param mixes $object - * @param string $label - * @return true - * @throws Exception - */ - public function log($object, $label = null, $options = array()) - { - return $this->fb($object, $label, FirePHP::LOG, $options); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::INFO - * @param mixes $object - * @param string $label - * @return true - * @throws Exception - */ - public function info($object, $label = null, $options = array()) - { - return $this->fb($object, $label, FirePHP::INFO, $options); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::WARN - * @param mixes $object - * @param string $label - * @return true - * @throws Exception - */ - public function warn($object, $label = null, $options = array()) - { - return $this->fb($object, $label, FirePHP::WARN, $options); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::ERROR - * @param mixes $object - * @param string $label - * @return true - * @throws Exception - */ - public function error($object, $label = null, $options = array()) - { - return $this->fb($object, $label, FirePHP::ERROR, $options); - } - - /** - * Dumps key and variable to firebug server panel - * - * @see FirePHP::DUMP - * @param string $key - * @param mixed $variable - * @return true - * @throws Exception - */ - public function dump($key, $variable, $options = array()) - { - if (!is_string($key)) { - throw $this->newException('Key passed to dump() is not a string'); - } - if (strlen($key) > 100) { - throw $this->newException('Key passed to dump() is longer than 100 characters'); - } - if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $key, $m)) { - throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]'); - } - return $this->fb($variable, $key, FirePHP::DUMP, $options); - } - - /** - * Log a trace in the firebug console - * - * @see FirePHP::TRACE - * @param string $label - * @return true - * @throws Exception - */ - public function trace($label) - { - return $this->fb($label, FirePHP::TRACE); - } - - /** - * Log a table in the firebug console - * - * @see FirePHP::TABLE - * @param string $label - * @param string $table - * @return true - * @throws Exception - */ - public function table($label, $table, $options = array()) - { - return $this->fb($table, $label, FirePHP::TABLE, $options); - } - - /** - * Insight API wrapper - * - * @see Insight_Helper::to() - */ - public static function to() - { - $instance = self::getInstance(); - if (!method_exists($instance, '_to')) { - throw new Exception('FirePHP::to() implementation not loaded'); - } - $args = func_get_args(); - return call_user_func_array(array($instance, '_to'), $args); - } - - /** - * Insight API wrapper - * - * @see Insight_Helper::plugin() - */ - public static function plugin() - { - $instance = self::getInstance(); - if (!method_exists($instance, '_plugin')) { - throw new Exception('FirePHP::plugin() implementation not loaded'); - } - $args = func_get_args(); - return call_user_func_array(array($instance, '_plugin'), $args); - } - - /** - * Check if FirePHP is installed on client - * - * @return boolean - */ - public function detectClientExtension() - { - // Check if FirePHP is installed on client via User-Agent header - if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si', $this->getUserAgent(), $m) && - version_compare($m[1][0], '0.0.6', '>=')) { - return true; - } else - // Check if FirePHP is installed on client via X-FirePHP-Version header - if (@preg_match_all('/^([\.\d]*)$/si', $this->getRequestHeader('X-FirePHP-Version'), $m) && - version_compare($m[1][0], '0.0.6', '>=')) { - return true; - } - return false; - } - - /** - * Log varible to Firebug - * - * @see http://www.firephp.org/Wiki/Reference/Fb - * @param mixed $object The variable to be logged - * @return boolean Return TRUE if message was added to headers, FALSE otherwise - * @throws Exception - */ - public function fb($object) - { - if ($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) { - if (!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message - $this->_logUpgradeClientMessage(); - } - } - - static $insightGroupStack = array(); - - if (!$this->getEnabled()) { - return false; - } - - if ($this->headersSent($filename, $linenum)) { - // If we are logging from within the exception handler we cannot throw another exception - if ($this->inExceptionHandler) { - // Simply echo the error out to the page - echo '
FirePHP ERROR: Headers already sent in ' . $filename . ' on line ' . $linenum . '. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.
'; - } else { - throw $this->newException('Headers already sent in ' . $filename . ' on line ' . $linenum . '. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.'); - } - } - - $type = null; - $label = null; - $options = array(); - - if (func_num_args() == 1) { - } else if (func_num_args() == 2) { - switch (func_get_arg(1)) { - case self::LOG: - case self::INFO: - case self::WARN: - case self::ERROR: - case self::DUMP: - case self::TRACE: - case self::EXCEPTION: - case self::TABLE: - case self::GROUP_START: - case self::GROUP_END: - $type = func_get_arg(1); - break; - default: - $label = func_get_arg(1); - break; - } - } else if (func_num_args() == 3) { - $type = func_get_arg(2); - $label = func_get_arg(1); - } else if (func_num_args() == 4) { - $type = func_get_arg(2); - $label = func_get_arg(1); - $options = func_get_arg(3); - } else { - throw $this->newException('Wrong number of arguments to fb() function!'); - } - - // Get folder name where firephp is located. - $parentFolder = basename(dirname(__FILE__)); - $parentFolderLength = strlen( $parentFolder ); - $fbLength = 7 + $parentFolderLength; - $fireClassLength = 18 + $parentFolderLength; - - if ($this->logToInsightConsole !== null && (get_class($this) == 'FirePHP_Insight' || is_subclass_of($this, 'FirePHP_Insight'))) { - $trace = debug_backtrace(); - if (!$trace) return false; - for ($i = 0; $i < sizeof($trace); $i++) { - if (isset($trace[$i]['class'])) { - if ($trace[$i]['class'] == 'FirePHP' || $trace[$i]['class'] == 'FB') { - continue; - } - } - if (isset($trace[$i]['file'])) { - $path = $this->_standardizePath($trace[$i]['file']); - if (substr($path, -1*$fbLength, $fbLength) == $parentFolder.'/fb.php' || substr($path, -1*$fireClassLength, $fireClassLength) == $parentFolder.'/FirePHP.class.php') { - continue; - } - } - if (isset($trace[$i]['function']) && $trace[$i]['function'] == 'fb' && - isset($trace[$i - 1]['file']) && substr($this->_standardizePath($trace[$i - 1]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') { - continue; - } - if (isset($trace[$i]['class']) && $trace[$i]['class'] == 'FB' && - isset($trace[$i - 1]['file']) && substr($this->_standardizePath($trace[$i - 1]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') { - continue; - } - break; - } - // adjust trace offset - $msg = $this->logToInsightConsole->option('encoder.trace.offsetAdjustment', $i); - - if ($object instanceof Exception) { - $type = self::EXCEPTION; - } - if ($label && $type != self::TABLE && $type != self::GROUP_START) { - $msg = $msg->label($label); - } - switch ($type) { - case self::DUMP: - case self::LOG: - return $msg->log($object); - case self::INFO: - return $msg->info($object); - case self::WARN: - return $msg->warn($object); - case self::ERROR: - return $msg->error($object); - case self::TRACE: - return $msg->trace($object); - case self::EXCEPTION: - return $this->plugin('error')->handleException($object, $msg); - case self::TABLE: - if (isset($object[0]) && !is_string($object[0]) && $label) { - $object = array($label, $object); - } - return $msg->table($object[0], array_slice($object[1], 1), $object[1][0]); - case self::GROUP_START: - $insightGroupStack[] = $msg->group(md5($label))->open(); - return $msg->log($label); - case self::GROUP_END: - if (count($insightGroupStack) == 0) { - throw new Error('Too many groupEnd() as opposed to group() calls!'); - } - $group = array_pop($insightGroupStack); - return $group->close(); - default: - return $msg->log($object); - } - } - - if (!$this->detectClientExtension()) { - return false; - } - - $meta = array(); - $skipFinalObjectEncode = false; - - if ($object instanceof Exception) { - - $meta['file'] = $this->_escapeTraceFile($object->getFile()); - $meta['line'] = $object->getLine(); - - $trace = $object->getTrace(); - if ($object instanceof ErrorException - && isset($trace[0]['function']) - && $trace[0]['function'] == 'errorHandler' - && isset($trace[0]['class']) - && $trace[0]['class'] == 'FirePHP') { - - $severity = false; - switch ($object->getSeverity()) { - case E_WARNING: - $severity = 'E_WARNING'; - break; - - case E_NOTICE: - $severity = 'E_NOTICE'; - break; - - case E_USER_ERROR: - $severity = 'E_USER_ERROR'; - break; - - case E_USER_WARNING: - $severity = 'E_USER_WARNING'; - break; - - case E_USER_NOTICE: - $severity = 'E_USER_NOTICE'; - break; - - case E_STRICT: - $severity = 'E_STRICT'; - break; - - case E_RECOVERABLE_ERROR: - $severity = 'E_RECOVERABLE_ERROR'; - break; - - case E_DEPRECATED: - $severity = 'E_DEPRECATED'; - break; - - case E_USER_DEPRECATED: - $severity = 'E_USER_DEPRECATED'; - break; - } - - $object = array('Class' => get_class($object), - 'Message' => $severity . ': ' . $object->getMessage(), - 'File' => $this->_escapeTraceFile($object->getFile()), - 'Line' => $object->getLine(), - 'Type' => 'trigger', - 'Trace' => $this->_escapeTrace(array_splice($trace, 2))); - $skipFinalObjectEncode = true; - } else { - $object = array('Class' => get_class($object), - 'Message' => $object->getMessage(), - 'File' => $this->_escapeTraceFile($object->getFile()), - 'Line' => $object->getLine(), - 'Type' => 'throw', - 'Trace' => $this->_escapeTrace($trace)); - $skipFinalObjectEncode = true; - } - $type = self::EXCEPTION; - - } else if ($type == self::TRACE) { - - $trace = debug_backtrace(); - if (!$trace) return false; - for ($i = 0; $i < sizeof($trace); $i++) { - - if (isset($trace[$i]['class']) - && isset($trace[$i]['file']) - && ($trace[$i]['class'] == 'FirePHP' - || $trace[$i]['class'] == 'FB') - && (substr($this->_standardizePath($trace[$i]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php' - || substr($this->_standardizePath($trace[$i]['file']), -1*$fireClassLength, $fireClassLength) == $parentFolder.'/FirePHP.class.php')) { - /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ - } else - if (isset($trace[$i]['class']) - && isset($trace[$i+1]['file']) - && $trace[$i]['class'] == 'FirePHP' - && substr($this->_standardizePath($trace[$i + 1]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') { - /* Skip fb() */ - } else - if ($trace[$i]['function'] == 'fb' - || $trace[$i]['function'] == 'trace' - || $trace[$i]['function'] == 'send') { - - $object = array('Class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : '', - 'Type' => isset($trace[$i]['type']) ? $trace[$i]['type'] : '', - 'Function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : '', - 'Message' => $trace[$i]['args'][0], - 'File' => isset($trace[$i]['file']) ? $this->_escapeTraceFile($trace[$i]['file']) : '', - 'Line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : '', - 'Args' => isset($trace[$i]['args']) ? $this->encodeObject($trace[$i]['args']) : '', - 'Trace' => $this->_escapeTrace(array_splice($trace, $i + 1))); - - $skipFinalObjectEncode = true; - $meta['file'] = isset($trace[$i]['file']) ? $this->_escapeTraceFile($trace[$i]['file']) : ''; - $meta['line'] = isset($trace[$i]['line']) ? $trace[$i]['line'] : ''; - break; - } - } - - } else - if ($type == self::TABLE) { - - if (isset($object[0]) && is_string($object[0])) { - $object[1] = $this->encodeTable($object[1]); - } else { - $object = $this->encodeTable($object); - } - - $skipFinalObjectEncode = true; - - } else if ($type == self::GROUP_START) { - - if (!$label) { - throw $this->newException('You must specify a label for the group!'); - } - - } else { - if ($type === null) { - $type = self::LOG; - } - } - - if ($this->options['includeLineNumbers']) { - if (!isset($meta['file']) || !isset($meta['line'])) { - - $trace = debug_backtrace(); - for ($i = 0; $trace && $i < sizeof($trace); $i++) { - - if (isset($trace[$i]['class']) - && isset($trace[$i]['file']) - && ($trace[$i]['class'] == 'FirePHP' - || $trace[$i]['class'] == 'FB') - && (substr($this->_standardizePath($trace[$i]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php' - || substr($this->_standardizePath($trace[$i]['file']), -1*$fireClassLength, $fireClassLength) == $parentFolder.'/FirePHP.class.php')) { - /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ - } else - if (isset($trace[$i]['class']) - && isset($trace[$i + 1]['file']) - && $trace[$i]['class'] == 'FirePHP' - && substr($this->_standardizePath($trace[$i + 1]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') { - /* Skip fb() */ - } else - if (isset($trace[$i]['file']) - && substr($this->_standardizePath($trace[$i]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') { - /* Skip FB::fb() */ - } else { - $meta['file'] = isset($trace[$i]['file']) ? $this->_escapeTraceFile($trace[$i]['file']) : ''; - $meta['line'] = isset($trace[$i]['line']) ? $trace[$i]['line'] : ''; - break; - } - } - } - } else { - unset($meta['file']); - unset($meta['line']); - } - - $this->setHeader('X-Wf-Protocol-1', 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); - $this->setHeader('X-Wf-1-Plugin-1', 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/' . self::VERSION); - - $structureIndex = 1; - if ($type == self::DUMP) { - $structureIndex = 2; - $this->setHeader('X-Wf-1-Structure-2', 'http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); - } else { - $this->setHeader('X-Wf-1-Structure-1', 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); - } - - if ($type == self::DUMP) { - $msg = '{"' . $label . '":' . $this->jsonEncode($object, $skipFinalObjectEncode) . '}'; - } else { - $msgMeta = $options; - $msgMeta['Type'] = $type; - if ($label !== null) { - $msgMeta['Label'] = $label; - } - if (isset($meta['file']) && !isset($msgMeta['File'])) { - $msgMeta['File'] = $meta['file']; - } - if (isset($meta['line']) && !isset($msgMeta['Line'])) { - $msgMeta['Line'] = $meta['line']; - } - $msg = '[' . $this->jsonEncode($msgMeta) . ',' . $this->jsonEncode($object, $skipFinalObjectEncode) . ']'; - } - - $parts = explode("\n", chunk_split($msg, 5000, "\n")); - - for ($i = 0; $i < count($parts); $i++) { - - $part = $parts[$i]; - if ($part) { - - if (count($parts) > 2) { - // Message needs to be split into multiple parts - $this->setHeader('X-Wf-1-' . $structureIndex . '-' . '1-' . $this->messageIndex, - (($i == 0) ? strlen($msg) : '') - . '|' . $part . '|' - . (($i < count($parts) - 2) ? '\\' : '')); - } else { - $this->setHeader('X-Wf-1-' . $structureIndex . '-' . '1-' . $this->messageIndex, - strlen($part) . '|' . $part . '|'); - } - - $this->messageIndex++; - - if ($this->messageIndex > 99999) { - throw $this->newException('Maximum number (99,999) of messages reached!'); - } - } - } - - $this->setHeader('X-Wf-1-Index', $this->messageIndex - 1); - - return true; - } - - /** - * Standardizes path for windows systems. - * - * @param string $path - * @return string - */ - protected function _standardizePath($path) - { - return preg_replace('/\\\\+/', '/', $path); - } - - /** - * Escape trace path for windows systems - * - * @param array $trace - * @return array - */ - protected function _escapeTrace($trace) - { - if (!$trace) return $trace; - for ($i = 0; $i < sizeof($trace); $i++) { - if (isset($trace[$i]['file'])) { - $trace[$i]['file'] = $this->_escapeTraceFile($trace[$i]['file']); - } - if (isset($trace[$i]['args'])) { - $trace[$i]['args'] = $this->encodeObject($trace[$i]['args']); - } - } - return $trace; - } - - /** - * Escape file information of trace for windows systems - * - * @param string $file - * @return string - */ - protected function _escapeTraceFile($file) - { - /* Check if we have a windows filepath */ - if (strpos($file, '\\')) { - /* First strip down to single \ */ - - $file = preg_replace('/\\\\+/', '\\', $file); - - return $file; - } - return $file; - } - - /** - * Check if headers have already been sent - * - * @param string $filename - * @param integer $linenum - */ - protected function headersSent(&$filename, &$linenum) - { - return headers_sent($filename, $linenum); - } - - /** - * Send header - * - * @param string $name - * @param string $value - */ - protected function setHeader($name, $value) - { - return header($name . ': ' . $value); - } - - /** - * Get user agent - * - * @return string|false - */ - protected function getUserAgent() - { - if (!isset($_SERVER['HTTP_USER_AGENT'])) return false; - return $_SERVER['HTTP_USER_AGENT']; - } - - /** - * Get all request headers - * - * @return array - */ - public static function getAllRequestHeaders() - { - static $_cachedHeaders = false; - if ($_cachedHeaders !== false) { - return $_cachedHeaders; - } - $headers = array(); - if (function_exists('getallheaders')) { - foreach (getallheaders() as $name => $value) { - $headers[strtolower($name)] = $value; - } - } else { - foreach ($_SERVER as $name => $value) { - if (substr($name, 0, 5) == 'HTTP_') { - $headers[strtolower(str_replace(' ', '-', str_replace('_', ' ', substr($name, 5))))] = $value; - } - } - } - return $_cachedHeaders = $headers; - } - - /** - * Get a request header - * - * @return string|false - */ - protected function getRequestHeader($name) - { - $headers = self::getAllRequestHeaders(); - if (isset($headers[strtolower($name)])) { - return $headers[strtolower($name)]; - } - return false; - } - - /** - * Returns a new exception - * - * @param string $message - * @return Exception - */ - protected function newException($message) - { - return new Exception($message); - } - - /** - * Encode an object into a JSON string - * - * Uses PHP's jeson_encode() if available - * - * @param object $object The object to be encoded - * @param boolean $skipObjectEncode - * @return string The JSON string - */ - public function jsonEncode($object, $skipObjectEncode = false) - { - if (!$skipObjectEncode) { - $object = $this->encodeObject($object); - } - - if (function_exists('json_encode') - && $this->options['useNativeJsonEncode'] != false) { - - return json_encode($object); - } else { - return $this->json_encode($object); - } - } - - /** - * Encodes a table by encoding each row and column with encodeObject() - * - * @param array $table The table to be encoded - * @return array - */ - protected function encodeTable($table) - { - if (!$table) return $table; - - $newTable = array(); - foreach ($table as $row) { - - if (is_array($row)) { - $newRow = array(); - - foreach ($row as $item) { - $newRow[] = $this->encodeObject($item); - } - - $newTable[] = $newRow; - } - } - - return $newTable; - } - - /** - * Encodes an object including members with - * protected and private visibility - * - * @param object $object The object to be encoded - * @param integer $Depth The current traversal depth - * @return array All members of the object - */ - protected function encodeObject($object, $objectDepth = 1, $arrayDepth = 1, $maxDepth = 1) - { - if ($maxDepth > $this->options['maxDepth']) { - return '** Max Depth (' . $this->options['maxDepth'] . ') **'; - } - - $return = array(); - - //#2801 is_resource reports false for closed resources https://bugs.php.net/bug.php?id=28016 - if (is_resource($object) || gettype($object) === "unknown type") { - - return '** ' . (string) $object . ' **'; - - } else if (is_object($object)) { - - if ($objectDepth > $this->options['maxObjectDepth']) { - return '** Max Object Depth (' . $this->options['maxObjectDepth'] . ') **'; - } - - foreach ($this->objectStack as $refVal) { - if ($refVal === $object) { - return '** Recursion (' . get_class($object) . ') **'; - } - } - array_push($this->objectStack, $object); - - $return['__className'] = $class = get_class($object); - $classLower = strtolower($class); - - $reflectionClass = new ReflectionClass($class); - $properties = array(); - foreach ($reflectionClass->getProperties() as $property) { - $properties[$property->getName()] = $property; - } - - $members = (array)$object; - - foreach ($properties as $plainName => $property) { - - $name = $rawName = $plainName; - if ($property->isStatic()) { - $name = 'static:' . $name; - } - if ($property->isPublic()) { - $name = 'public:' . $name; - } else if ($property->isPrivate()) { - $name = 'private:' . $name; - $rawName = "\0" . $class . "\0" . $rawName; - } else if ($property->isProtected()) { - $name = 'protected:' . $name; - $rawName = "\0" . '*' . "\0" . $rawName; - } - - if (!(isset($this->objectFilters[$classLower]) - && is_array($this->objectFilters[$classLower]) - && in_array($plainName, $this->objectFilters[$classLower]))) { - - if (array_key_exists($rawName, $members) && !$property->isStatic()) { - $return[$name] = $this->encodeObject($members[$rawName], $objectDepth + 1, 1, $maxDepth + 1); - } else { - if (method_exists($property, 'setAccessible')) { - $property->setAccessible(true); - $return[$name] = $this->encodeObject($property->getValue($object), $objectDepth + 1, 1, $maxDepth + 1); - } else - if ($property->isPublic()) { - $return[$name] = $this->encodeObject($property->getValue($object), $objectDepth + 1, 1, $maxDepth + 1); - } else { - $return[$name] = '** Need PHP 5.3 to get value **'; - } - } - } else { - $return[$name] = '** Excluded by Filter **'; - } - } - - // Include all members that are not defined in the class - // but exist in the object - foreach ($members as $rawName => $value) { - - $name = $rawName; - - if ($name{0} == "\0") { - $parts = explode("\0", $name); - $name = $parts[2]; - } - - $plainName = $name; - - if (!isset($properties[$name])) { - $name = 'undeclared:' . $name; - - if (!(isset($this->objectFilters[$classLower]) - && is_array($this->objectFilters[$classLower]) - && in_array($plainName, $this->objectFilters[$classLower]))) { - - $return[$name] = $this->encodeObject($value, $objectDepth + 1, 1, $maxDepth + 1); - } else { - $return[$name] = '** Excluded by Filter **'; - } - } - } - - array_pop($this->objectStack); - - } elseif (is_array($object)) { - - if ($arrayDepth > $this->options['maxArrayDepth']) { - return '** Max Array Depth (' . $this->options['maxArrayDepth'] . ') **'; - } - - foreach ($object as $key => $val) { - - // Encoding the $GLOBALS PHP array causes an infinite loop - // if the recursion is not reset here as it contains - // a reference to itself. This is the only way I have come up - // with to stop infinite recursion in this case. - if ($key == 'GLOBALS' - && is_array($val) - && array_key_exists('GLOBALS', $val)) { - $val['GLOBALS'] = '** Recursion (GLOBALS) **'; - } - - if (!$this->is_utf8($key)) { - $key = utf8_encode($key); - } - - $return[$key] = $this->encodeObject($val, 1, $arrayDepth + 1, $maxDepth + 1); - } - } elseif ( is_bool($object) ) { - return $object; - } elseif ( is_null($object) ) { - return $object; - } elseif ( is_numeric($object) ) { - return $object; - } else { - if ($this->is_utf8($object)) { - return $object; - } else { - return utf8_encode($object); - } - } - return $return; - } - - /** - * Returns true if $string is valid UTF-8 and false otherwise. - * - * @param mixed $str String to be tested - * @return boolean - */ - protected function is_utf8($str) - { - if (function_exists('mb_detect_encoding')) { - return ( - mb_detect_encoding($str, 'UTF-8', true) == 'UTF-8' && - ($str === null || $this->jsonEncode($str, true) !== 'null') - ); - } - $c = 0; - $b = 0; - $bits = 0; - $len = strlen($str); - for ($i = 0; $i < $len; $i++) { - $c = ord($str[$i]); - if ($c > 128) { - if (($c >= 254)) return false; - elseif ($c >= 252) $bits = 6; - elseif ($c >= 248) $bits = 5; - elseif ($c >= 240) $bits = 4; - elseif ($c >= 224) $bits = 3; - elseif ($c >= 192) $bits = 2; - else return false; - if (($i + $bits) > $len) return false; - while($bits > 1) { - $i++; - $b = ord($str[$i]); - if ($b < 128 || $b > 191) return false; - $bits--; - } - } - } - return ($str === null || $this->jsonEncode($str, true) !== 'null'); - } - - /** - * Converts to and from JSON format. - * - * JSON (JavaScript Object Notation) is a lightweight data-interchange - * format. It is easy for humans to read and write. It is easy for machines - * to parse and generate. It is based on a subset of the JavaScript - * Programming Language, Standard ECMA-262 3rd Edition - December 1999. - * This feature can also be found in Python. JSON is a text format that is - * completely language independent but uses conventions that are familiar - * to programmers of the C-family of languages, including C, C++, C#, Java, - * JavaScript, Perl, TCL, and many others. These properties make JSON an - * ideal data-interchange language. - * - * This package provides a simple encoder and decoder for JSON notation. It - * is intended for use with client-side Javascript applications that make - * use of HTTPRequest to perform server communication functions - data can - * be encoded into JSON notation for use in a client-side javascript, or - * decoded from incoming Javascript requests. JSON format is native to - * Javascript, and can be directly eval()'ed with no further parsing - * overhead - * - * All strings should be in ASCII or UTF-8 format! - * - * LICENSE: Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: Redistributions of source code must retain the - * above copyright notice, this list of conditions and the following - * disclaimer. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * @category - * @package Services_JSON - * @author Michal Migurski - * @author Matt Knapp - * @author Brett Stimmerman - * @author Christoph Dorn - * @copyright 2005 Michal Migurski - * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ - * @license http://www.opensource.org/licenses/bsd-license.php - * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 - */ - - - /** - * Keep a list of objects as we descend into the array so we can detect recursion. - */ - private $json_objectStack = array(); - - - /** - * convert a string from one UTF-8 char to one UTF-16 char - * - * Normally should be handled by mb_convert_encoding, but - * provides a slower PHP-only method for installations - * that lack the multibye string extension. - * - * @param string $utf8 UTF-8 character - * @return string UTF-16 character - * @access private - */ - private function json_utf82utf16($utf8) - { - // oh please oh please oh please oh please oh please - if (function_exists('mb_convert_encoding')) { - return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); - } - - switch (strlen($utf8)) { - case 1: - // this case should never be reached, because we are in ASCII range - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return $utf8; - - case 2: - // return a UTF-16 character from a 2-byte UTF-8 char - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0x07 & (ord($utf8{0}) >> 2)) - . chr((0xC0 & (ord($utf8{0}) << 6)) - | (0x3F & ord($utf8{1}))); - - case 3: - // return a UTF-16 character from a 3-byte UTF-8 char - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr((0xF0 & (ord($utf8{0}) << 4)) - | (0x0F & (ord($utf8{1}) >> 2))) - . chr((0xC0 & (ord($utf8{1}) << 6)) - | (0x7F & ord($utf8{2}))); - } - - // ignoring UTF-32 for now, sorry - return ''; - } - - /** - * encodes an arbitrary variable into JSON format - * - * @param mixed $var any number, boolean, string, array, or object to be encoded. - * see argument 1 to Services_JSON() above for array-parsing behavior. - * if var is a strng, note that encode() always expects it - * to be in ASCII or UTF-8 format! - * - * @return mixed JSON string representation of input var or an error if a problem occurs - * @access public - */ - private function json_encode($var) - { - if (is_object($var)) { - if (in_array($var, $this->json_objectStack)) { - return '"** Recursion **"'; - } - } - - switch (gettype($var)) { - case 'boolean': - return $var ? 'true' : 'false'; - - case 'NULL': - return 'null'; - - case 'integer': - return (int) $var; - - case 'double': - case 'float': - return (float) $var; - - case 'string': - // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT - $ascii = ''; - $strlen_var = strlen($var); - - /* - * Iterate over every character in the string, - * escaping with a slash or encoding to UTF-8 where necessary - */ - for ($c = 0; $c < $strlen_var; ++$c) { - - $ord_var_c = ord($var{$c}); - - switch (true) { - case $ord_var_c == 0x08: - $ascii .= '\b'; - break; - case $ord_var_c == 0x09: - $ascii .= '\t'; - break; - case $ord_var_c == 0x0A: - $ascii .= '\n'; - break; - case $ord_var_c == 0x0C: - $ascii .= '\f'; - break; - case $ord_var_c == 0x0D: - $ascii .= '\r'; - break; - - case $ord_var_c == 0x22: - case $ord_var_c == 0x2F: - case $ord_var_c == 0x5C: - // double quote, slash, slosh - $ascii .= '\\' . $var{$c}; - break; - - case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): - // characters U-00000000 - U-0000007F (same as ASCII) - $ascii .= $var{$c}; - break; - - case (($ord_var_c & 0xE0) == 0xC0): - // characters U-00000080 - U-000007FF, mask 110XXXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, ord($var{$c + 1})); - $c += 1; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF0) == 0xE0): - // characters U-00000800 - U-0000FFFF, mask 1110XXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2})); - $c += 2; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF8) == 0xF0): - // characters U-00010000 - U-001FFFFF, mask 11110XXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3})); - $c += 3; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFC) == 0xF8): - // characters U-00200000 - U-03FFFFFF, mask 111110XX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3}), - ord($var{$c + 4})); - $c += 4; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFE) == 0xFC): - // characters U-04000000 - U-7FFFFFFF, mask 1111110X - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3}), - ord($var{$c + 4}), - ord($var{$c + 5})); - $c += 5; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - } - } - - return '"' . $ascii . '"'; - - case 'array': - /* - * As per JSON spec if any array key is not an integer - * we must treat the the whole array as an object. We - * also try to catch a sparsely populated associative - * array with numeric keys here because some JS engines - * will create an array with empty indexes up to - * max_index which can cause memory issues and because - * the keys, which may be relevant, will be remapped - * otherwise. - * - * As per the ECMA and JSON specification an object may - * have any string as a property. Unfortunately due to - * a hole in the ECMA specification if the key is a - * ECMA reserved word or starts with a digit the - * parameter is only accessible using ECMAScript's - * bracket notation. - */ - - // treat as a JSON object - if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { - - $this->json_objectStack[] = $var; - - $properties = array_map(array($this, 'json_name_value'), - array_keys($var), - array_values($var)); - - array_pop($this->json_objectStack); - - foreach ($properties as $property) { - if ($property instanceof Exception) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - } - - $this->json_objectStack[] = $var; - - // treat it like a regular array - $elements = array_map(array($this, 'json_encode'), $var); - - array_pop($this->json_objectStack); - - foreach ($elements as $element) { - if ($element instanceof Exception) { - return $element; - } - } - - return '[' . join(',', $elements) . ']'; - - case 'object': - $vars = self::encodeObject($var); - - $this->json_objectStack[] = $var; - - $properties = array_map(array($this, 'json_name_value'), - array_keys($vars), - array_values($vars)); - - array_pop($this->json_objectStack); - - foreach ($properties as $property) { - if ($property instanceof Exception) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - - default: - return null; - } - } - - /** - * array-walking function for use in generating JSON-formatted name-value pairs - * - * @param string $name name of key to use - * @param mixed $value reference to an array element to be encoded - * - * @return string JSON-formatted name-value pair, like '"name":value' - * @access private - */ - private function json_name_value($name, $value) - { - // Encoding the $GLOBALS PHP array causes an infinite loop - // if the recursion is not reset here as it contains - // a reference to itself. This is the only way I have come up - // with to stop infinite recursion in this case. - if ($name == 'GLOBALS' - && is_array($value) - && array_key_exists('GLOBALS', $value)) { - $value['GLOBALS'] = '** Recursion **'; - } - - $encodedValue = $this->json_encode($value); - - if ($encodedValue instanceof Exception) { - return $encodedValue; - } - - return $this->json_encode(strval($name)) . ':' . $encodedValue; - } - - /** - * @deprecated - */ - public function setProcessorUrl($URL) - { - trigger_error('The FirePHP::setProcessorUrl() method is no longer supported', E_USER_DEPRECATED); - } - - /** - * @deprecated - */ - public function setRendererUrl($URL) - { - trigger_error('The FirePHP::setRendererUrl() method is no longer supported', E_USER_DEPRECATED); - } -} \ No newline at end of file diff --git a/min/lib/JSMinPlus.php b/min/lib/JSMinPlus.php deleted file mode 100644 index 1c7463c..0000000 --- a/min/lib/JSMinPlus.php +++ /dev/null @@ -1,2090 +0,0 @@ - - * - * Usage: $minified = JSMinPlus::minify($script [, $filename]) - * - * Versionlog (see also changelog.txt): - * 23-07-2011 - remove dynamic creation of OP_* and KEYWORD_* defines and declare them on top - * reduce memory footprint by minifying by block-scope - * some small byte-saving and performance improvements - * 12-05-2009 - fixed hook:colon precedence, fixed empty body in loop and if-constructs - * 18-04-2009 - fixed crashbug in PHP 5.2.9 and several other bugfixes - * 12-04-2009 - some small bugfixes and performance improvements - * 09-04-2009 - initial open sourced version 1.0 - * - * Latest version of this script: http://files.tweakers.net/jsminplus/jsminplus.zip - * - */ - -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Narcissus JavaScript engine. - * - * The Initial Developer of the Original Code is - * Brendan Eich . - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): Tino Zijdel - * PHP port, modifications and minifier routine are (C) 2009-2011 - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -define('TOKEN_END', 1); -define('TOKEN_NUMBER', 2); -define('TOKEN_IDENTIFIER', 3); -define('TOKEN_STRING', 4); -define('TOKEN_REGEXP', 5); -define('TOKEN_NEWLINE', 6); -define('TOKEN_CONDCOMMENT_START', 7); -define('TOKEN_CONDCOMMENT_END', 8); - -define('JS_SCRIPT', 100); -define('JS_BLOCK', 101); -define('JS_LABEL', 102); -define('JS_FOR_IN', 103); -define('JS_CALL', 104); -define('JS_NEW_WITH_ARGS', 105); -define('JS_INDEX', 106); -define('JS_ARRAY_INIT', 107); -define('JS_OBJECT_INIT', 108); -define('JS_PROPERTY_INIT', 109); -define('JS_GETTER', 110); -define('JS_SETTER', 111); -define('JS_GROUP', 112); -define('JS_LIST', 113); - -define('JS_MINIFIED', 999); - -define('DECLARED_FORM', 0); -define('EXPRESSED_FORM', 1); -define('STATEMENT_FORM', 2); - -/* Operators */ -define('OP_SEMICOLON', ';'); -define('OP_COMMA', ','); -define('OP_HOOK', '?'); -define('OP_COLON', ':'); -define('OP_OR', '||'); -define('OP_AND', '&&'); -define('OP_BITWISE_OR', '|'); -define('OP_BITWISE_XOR', '^'); -define('OP_BITWISE_AND', '&'); -define('OP_STRICT_EQ', '==='); -define('OP_EQ', '=='); -define('OP_ASSIGN', '='); -define('OP_STRICT_NE', '!=='); -define('OP_NE', '!='); -define('OP_LSH', '<<'); -define('OP_LE', '<='); -define('OP_LT', '<'); -define('OP_URSH', '>>>'); -define('OP_RSH', '>>'); -define('OP_GE', '>='); -define('OP_GT', '>'); -define('OP_INCREMENT', '++'); -define('OP_DECREMENT', '--'); -define('OP_PLUS', '+'); -define('OP_MINUS', '-'); -define('OP_MUL', '*'); -define('OP_DIV', '/'); -define('OP_MOD', '%'); -define('OP_NOT', '!'); -define('OP_BITWISE_NOT', '~'); -define('OP_DOT', '.'); -define('OP_LEFT_BRACKET', '['); -define('OP_RIGHT_BRACKET', ']'); -define('OP_LEFT_CURLY', '{'); -define('OP_RIGHT_CURLY', '}'); -define('OP_LEFT_PAREN', '('); -define('OP_RIGHT_PAREN', ')'); -define('OP_CONDCOMMENT_END', '@*/'); - -define('OP_UNARY_PLUS', 'U+'); -define('OP_UNARY_MINUS', 'U-'); - -/* Keywords */ -define('KEYWORD_BREAK', 'break'); -define('KEYWORD_CASE', 'case'); -define('KEYWORD_CATCH', 'catch'); -define('KEYWORD_CONST', 'const'); -define('KEYWORD_CONTINUE', 'continue'); -define('KEYWORD_DEBUGGER', 'debugger'); -define('KEYWORD_DEFAULT', 'default'); -define('KEYWORD_DELETE', 'delete'); -define('KEYWORD_DO', 'do'); -define('KEYWORD_ELSE', 'else'); -define('KEYWORD_ENUM', 'enum'); -define('KEYWORD_FALSE', 'false'); -define('KEYWORD_FINALLY', 'finally'); -define('KEYWORD_FOR', 'for'); -define('KEYWORD_FUNCTION', 'function'); -define('KEYWORD_IF', 'if'); -define('KEYWORD_IN', 'in'); -define('KEYWORD_INSTANCEOF', 'instanceof'); -define('KEYWORD_NEW', 'new'); -define('KEYWORD_NULL', 'null'); -define('KEYWORD_RETURN', 'return'); -define('KEYWORD_SWITCH', 'switch'); -define('KEYWORD_THIS', 'this'); -define('KEYWORD_THROW', 'throw'); -define('KEYWORD_TRUE', 'true'); -define('KEYWORD_TRY', 'try'); -define('KEYWORD_TYPEOF', 'typeof'); -define('KEYWORD_VAR', 'var'); -define('KEYWORD_VOID', 'void'); -define('KEYWORD_WHILE', 'while'); -define('KEYWORD_WITH', 'with'); - -/** - * @deprecated 2.3 This will be removed in Minify 3.0 - */ -class JSMinPlus -{ - private $parser; - private $reserved = array( - 'break', 'case', 'catch', 'continue', 'default', 'delete', 'do', - 'else', 'finally', 'for', 'function', 'if', 'in', 'instanceof', - 'new', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'var', - 'void', 'while', 'with', - // Words reserved for future use - 'abstract', 'boolean', 'byte', 'char', 'class', 'const', 'debugger', - 'double', 'enum', 'export', 'extends', 'final', 'float', 'goto', - 'implements', 'import', 'int', 'interface', 'long', 'native', - 'package', 'private', 'protected', 'public', 'short', 'static', - 'super', 'synchronized', 'throws', 'transient', 'volatile', - // These are not reserved, but should be taken into account - // in isValidIdentifier (See jslint source code) - 'arguments', 'eval', 'true', 'false', 'Infinity', 'NaN', 'null', 'undefined' - ); - - private function __construct() - { - $this->parser = new JSParser($this); - } - - public static function minify($js, $filename='') - { - trigger_error(__CLASS__ . ' is deprecated. This will be removed in Minify 3.0', E_USER_DEPRECATED); - - static $instance; - - // this is a singleton - if(!$instance) - $instance = new JSMinPlus(); - - return $instance->min($js, $filename); - } - - private function min($js, $filename) - { - try - { - $n = $this->parser->parse($js, $filename, 1); - return $this->parseTree($n); - } - catch(Exception $e) - { - echo $e->getMessage() . "\n"; - } - - return false; - } - - public function parseTree($n, $noBlockGrouping = false) - { - $s = ''; - - switch ($n->type) - { - case JS_MINIFIED: - $s = $n->value; - break; - - case JS_SCRIPT: - // we do nothing yet with funDecls or varDecls - $noBlockGrouping = true; - // FALL THROUGH - - case JS_BLOCK: - $childs = $n->treeNodes; - $lastType = 0; - for ($c = 0, $i = 0, $j = count($childs); $i < $j; $i++) - { - $type = $childs[$i]->type; - $t = $this->parseTree($childs[$i]); - if (strlen($t)) - { - if ($c) - { - $s = rtrim($s, ';'); - - if ($type == KEYWORD_FUNCTION && $childs[$i]->functionForm == DECLARED_FORM) - { - // put declared functions on a new line - $s .= "\n"; - } - elseif ($type == KEYWORD_VAR && $type == $lastType) - { - // mutiple var-statements can go into one - $t = ',' . substr($t, 4); - } - else - { - // add terminator - $s .= ';'; - } - } - - $s .= $t; - - $c++; - $lastType = $type; - } - } - - if ($c > 1 && !$noBlockGrouping) - { - $s = '{' . $s . '}'; - } - break; - - case KEYWORD_FUNCTION: - $s .= 'function' . ($n->name ? ' ' . $n->name : '') . '('; - $params = $n->params; - for ($i = 0, $j = count($params); $i < $j; $i++) - $s .= ($i ? ',' : '') . $params[$i]; - $s .= '){' . $this->parseTree($n->body, true) . '}'; - break; - - case KEYWORD_IF: - $s = 'if(' . $this->parseTree($n->condition) . ')'; - $thenPart = $this->parseTree($n->thenPart); - $elsePart = $n->elsePart ? $this->parseTree($n->elsePart) : null; - - // empty if-statement - if ($thenPart == '') - $thenPart = ';'; - - if ($elsePart) - { - // be carefull and always make a block out of the thenPart; could be more optimized but is a lot of trouble - if ($thenPart != ';' && $thenPart[0] != '{') - $thenPart = '{' . $thenPart . '}'; - - $s .= $thenPart . 'else'; - - // we could check for more, but that hardly ever applies so go for performance - if ($elsePart[0] != '{') - $s .= ' '; - - $s .= $elsePart; - } - else - { - $s .= $thenPart; - } - break; - - case KEYWORD_SWITCH: - $s = 'switch(' . $this->parseTree($n->discriminant) . '){'; - $cases = $n->cases; - for ($i = 0, $j = count($cases); $i < $j; $i++) - { - $case = $cases[$i]; - if ($case->type == KEYWORD_CASE) - $s .= 'case' . ($case->caseLabel->type != TOKEN_STRING ? ' ' : '') . $this->parseTree($case->caseLabel) . ':'; - else - $s .= 'default:'; - - $statement = $this->parseTree($case->statements, true); - if ($statement) - { - $s .= $statement; - // no terminator for last statement - if ($i + 1 < $j) - $s .= ';'; - } - } - $s .= '}'; - break; - - case KEYWORD_FOR: - $s = 'for(' . ($n->setup ? $this->parseTree($n->setup) : '') - . ';' . ($n->condition ? $this->parseTree($n->condition) : '') - . ';' . ($n->update ? $this->parseTree($n->update) : '') . ')'; - - $body = $this->parseTree($n->body); - if ($body == '') - $body = ';'; - - $s .= $body; - break; - - case KEYWORD_WHILE: - $s = 'while(' . $this->parseTree($n->condition) . ')'; - - $body = $this->parseTree($n->body); - if ($body == '') - $body = ';'; - - $s .= $body; - break; - - case JS_FOR_IN: - $s = 'for(' . ($n->varDecl ? $this->parseTree($n->varDecl) : $this->parseTree($n->iterator)) . ' in ' . $this->parseTree($n->object) . ')'; - - $body = $this->parseTree($n->body); - if ($body == '') - $body = ';'; - - $s .= $body; - break; - - case KEYWORD_DO: - $s = 'do{' . $this->parseTree($n->body, true) . '}while(' . $this->parseTree($n->condition) . ')'; - break; - - case KEYWORD_BREAK: - case KEYWORD_CONTINUE: - $s = $n->value . ($n->label ? ' ' . $n->label : ''); - break; - - case KEYWORD_TRY: - $s = 'try{' . $this->parseTree($n->tryBlock, true) . '}'; - $catchClauses = $n->catchClauses; - for ($i = 0, $j = count($catchClauses); $i < $j; $i++) - { - $t = $catchClauses[$i]; - $s .= 'catch(' . $t->varName . ($t->guard ? ' if ' . $this->parseTree($t->guard) : '') . '){' . $this->parseTree($t->block, true) . '}'; - } - if ($n->finallyBlock) - $s .= 'finally{' . $this->parseTree($n->finallyBlock, true) . '}'; - break; - - case KEYWORD_THROW: - case KEYWORD_RETURN: - $s = $n->type; - if ($n->value) - { - $t = $this->parseTree($n->value); - if (strlen($t)) - { - if ($this->isWordChar($t[0]) || $t[0] == '\\') - $s .= ' '; - - $s .= $t; - } - } - break; - - case KEYWORD_WITH: - $s = 'with(' . $this->parseTree($n->object) . ')' . $this->parseTree($n->body); - break; - - case KEYWORD_VAR: - case KEYWORD_CONST: - $s = $n->value . ' '; - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - { - $t = $childs[$i]; - $s .= ($i ? ',' : '') . $t->name; - $u = $t->initializer; - if ($u) - $s .= '=' . $this->parseTree($u); - } - break; - - case KEYWORD_IN: - case KEYWORD_INSTANCEOF: - $left = $this->parseTree($n->treeNodes[0]); - $right = $this->parseTree($n->treeNodes[1]); - - $s = $left; - - if ($this->isWordChar(substr($left, -1))) - $s .= ' '; - - $s .= $n->type; - - if ($this->isWordChar($right[0]) || $right[0] == '\\') - $s .= ' '; - - $s .= $right; - break; - - case KEYWORD_DELETE: - case KEYWORD_TYPEOF: - $right = $this->parseTree($n->treeNodes[0]); - - $s = $n->type; - - if ($this->isWordChar($right[0]) || $right[0] == '\\') - $s .= ' '; - - $s .= $right; - break; - - case KEYWORD_VOID: - $s = 'void(' . $this->parseTree($n->treeNodes[0]) . ')'; - break; - - case KEYWORD_DEBUGGER: - throw new Exception('NOT IMPLEMENTED: DEBUGGER'); - break; - - case TOKEN_CONDCOMMENT_START: - case TOKEN_CONDCOMMENT_END: - $s = $n->value . ($n->type == TOKEN_CONDCOMMENT_START ? ' ' : ''); - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - $s .= $this->parseTree($childs[$i]); - break; - - case OP_SEMICOLON: - if ($expression = $n->expression) - $s = $this->parseTree($expression); - break; - - case JS_LABEL: - $s = $n->label . ':' . $this->parseTree($n->statement); - break; - - case OP_COMMA: - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); - break; - - case OP_ASSIGN: - $s = $this->parseTree($n->treeNodes[0]) . $n->value . $this->parseTree($n->treeNodes[1]); - break; - - case OP_HOOK: - $s = $this->parseTree($n->treeNodes[0]) . '?' . $this->parseTree($n->treeNodes[1]) . ':' . $this->parseTree($n->treeNodes[2]); - break; - - case OP_OR: case OP_AND: - case OP_BITWISE_OR: case OP_BITWISE_XOR: case OP_BITWISE_AND: - case OP_EQ: case OP_NE: case OP_STRICT_EQ: case OP_STRICT_NE: - case OP_LT: case OP_LE: case OP_GE: case OP_GT: - case OP_LSH: case OP_RSH: case OP_URSH: - case OP_MUL: case OP_DIV: case OP_MOD: - $s = $this->parseTree($n->treeNodes[0]) . $n->type . $this->parseTree($n->treeNodes[1]); - break; - - case OP_PLUS: - case OP_MINUS: - $left = $this->parseTree($n->treeNodes[0]); - $right = $this->parseTree($n->treeNodes[1]); - - switch ($n->treeNodes[1]->type) - { - case OP_PLUS: - case OP_MINUS: - case OP_INCREMENT: - case OP_DECREMENT: - case OP_UNARY_PLUS: - case OP_UNARY_MINUS: - $s = $left . $n->type . ' ' . $right; - break; - - case TOKEN_STRING: - //combine concatted strings with same quotestyle - if ($n->type == OP_PLUS && substr($left, -1) == $right[0]) - { - $s = substr($left, 0, -1) . substr($right, 1); - break; - } - // FALL THROUGH - - default: - $s = $left . $n->type . $right; - } - break; - - case OP_NOT: - case OP_BITWISE_NOT: - case OP_UNARY_PLUS: - case OP_UNARY_MINUS: - $s = $n->value . $this->parseTree($n->treeNodes[0]); - break; - - case OP_INCREMENT: - case OP_DECREMENT: - if ($n->postfix) - $s = $this->parseTree($n->treeNodes[0]) . $n->value; - else - $s = $n->value . $this->parseTree($n->treeNodes[0]); - break; - - case OP_DOT: - $s = $this->parseTree($n->treeNodes[0]) . '.' . $this->parseTree($n->treeNodes[1]); - break; - - case JS_INDEX: - $s = $this->parseTree($n->treeNodes[0]); - // See if we can replace named index with a dot saving 3 bytes - if ( $n->treeNodes[0]->type == TOKEN_IDENTIFIER && - $n->treeNodes[1]->type == TOKEN_STRING && - $this->isValidIdentifier(substr($n->treeNodes[1]->value, 1, -1)) - ) - $s .= '.' . substr($n->treeNodes[1]->value, 1, -1); - else - $s .= '[' . $this->parseTree($n->treeNodes[1]) . ']'; - break; - - case JS_LIST: - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); - break; - - case JS_CALL: - $s = $this->parseTree($n->treeNodes[0]) . '(' . $this->parseTree($n->treeNodes[1]) . ')'; - break; - - case KEYWORD_NEW: - case JS_NEW_WITH_ARGS: - $s = 'new ' . $this->parseTree($n->treeNodes[0]) . '(' . ($n->type == JS_NEW_WITH_ARGS ? $this->parseTree($n->treeNodes[1]) : '') . ')'; - break; - - case JS_ARRAY_INIT: - $s = '['; - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - { - $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); - } - $s .= ']'; - break; - - case JS_OBJECT_INIT: - $s = '{'; - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - { - $t = $childs[$i]; - if ($i) - $s .= ','; - if ($t->type == JS_PROPERTY_INIT) - { - // Ditch the quotes when the index is a valid identifier - if ( $t->treeNodes[0]->type == TOKEN_STRING && - $this->isValidIdentifier(substr($t->treeNodes[0]->value, 1, -1)) - ) - $s .= substr($t->treeNodes[0]->value, 1, -1); - else - $s .= $t->treeNodes[0]->value; - - $s .= ':' . $this->parseTree($t->treeNodes[1]); - } - else - { - $s .= $t->type == JS_GETTER ? 'get' : 'set'; - $s .= ' ' . $t->name . '('; - $params = $t->params; - for ($i = 0, $j = count($params); $i < $j; $i++) - $s .= ($i ? ',' : '') . $params[$i]; - $s .= '){' . $this->parseTree($t->body, true) . '}'; - } - } - $s .= '}'; - break; - - case TOKEN_NUMBER: - $s = $n->value; - if (preg_match('/^([1-9]+)(0{3,})$/', $s, $m)) - $s = $m[1] . 'e' . strlen($m[2]); - break; - - case KEYWORD_NULL: case KEYWORD_THIS: case KEYWORD_TRUE: case KEYWORD_FALSE: - case TOKEN_IDENTIFIER: case TOKEN_STRING: case TOKEN_REGEXP: - $s = $n->value; - break; - - case JS_GROUP: - if (in_array( - $n->treeNodes[0]->type, - array( - JS_ARRAY_INIT, JS_OBJECT_INIT, JS_GROUP, - TOKEN_NUMBER, TOKEN_STRING, TOKEN_REGEXP, TOKEN_IDENTIFIER, - KEYWORD_NULL, KEYWORD_THIS, KEYWORD_TRUE, KEYWORD_FALSE - ) - )) - { - $s = $this->parseTree($n->treeNodes[0]); - } - else - { - $s = '(' . $this->parseTree($n->treeNodes[0]) . ')'; - } - break; - - default: - throw new Exception('UNKNOWN TOKEN TYPE: ' . $n->type); - } - - return $s; - } - - private function isValidIdentifier($string) - { - return preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $string) && !in_array($string, $this->reserved); - } - - private function isWordChar($char) - { - return $char == '_' || $char == '$' || ctype_alnum($char); - } -} - -class JSParser -{ - private $t; - private $minifier; - - private $opPrecedence = array( - ';' => 0, - ',' => 1, - '=' => 2, '?' => 2, ':' => 2, - // The above all have to have the same precedence, see bug 330975 - '||' => 4, - '&&' => 5, - '|' => 6, - '^' => 7, - '&' => 8, - '==' => 9, '!=' => 9, '===' => 9, '!==' => 9, - '<' => 10, '<=' => 10, '>=' => 10, '>' => 10, 'in' => 10, 'instanceof' => 10, - '<<' => 11, '>>' => 11, '>>>' => 11, - '+' => 12, '-' => 12, - '*' => 13, '/' => 13, '%' => 13, - 'delete' => 14, 'void' => 14, 'typeof' => 14, - '!' => 14, '~' => 14, 'U+' => 14, 'U-' => 14, - '++' => 15, '--' => 15, - 'new' => 16, - '.' => 17, - JS_NEW_WITH_ARGS => 0, JS_INDEX => 0, JS_CALL => 0, - JS_ARRAY_INIT => 0, JS_OBJECT_INIT => 0, JS_GROUP => 0 - ); - - private $opArity = array( - ',' => -2, - '=' => 2, - '?' => 3, - '||' => 2, - '&&' => 2, - '|' => 2, - '^' => 2, - '&' => 2, - '==' => 2, '!=' => 2, '===' => 2, '!==' => 2, - '<' => 2, '<=' => 2, '>=' => 2, '>' => 2, 'in' => 2, 'instanceof' => 2, - '<<' => 2, '>>' => 2, '>>>' => 2, - '+' => 2, '-' => 2, - '*' => 2, '/' => 2, '%' => 2, - 'delete' => 1, 'void' => 1, 'typeof' => 1, - '!' => 1, '~' => 1, 'U+' => 1, 'U-' => 1, - '++' => 1, '--' => 1, - 'new' => 1, - '.' => 2, - JS_NEW_WITH_ARGS => 2, JS_INDEX => 2, JS_CALL => 2, - JS_ARRAY_INIT => 1, JS_OBJECT_INIT => 1, JS_GROUP => 1, - TOKEN_CONDCOMMENT_START => 1, TOKEN_CONDCOMMENT_END => 1 - ); - - public function __construct($minifier=null) - { - $this->minifier = $minifier; - $this->t = new JSTokenizer(); - } - - public function parse($s, $f, $l) - { - // initialize tokenizer - $this->t->init($s, $f, $l); - - $x = new JSCompilerContext(false); - $n = $this->Script($x); - if (!$this->t->isDone()) - throw $this->t->newSyntaxError('Syntax error'); - - return $n; - } - - private function Script($x) - { - $n = $this->Statements($x); - $n->type = JS_SCRIPT; - $n->funDecls = $x->funDecls; - $n->varDecls = $x->varDecls; - - // minify by scope - if ($this->minifier) - { - $n->value = $this->minifier->parseTree($n); - - // clear tree from node to save memory - $n->treeNodes = null; - $n->funDecls = null; - $n->varDecls = null; - - $n->type = JS_MINIFIED; - } - - return $n; - } - - private function Statements($x) - { - $n = new JSNode($this->t, JS_BLOCK); - array_push($x->stmtStack, $n); - - while (!$this->t->isDone() && $this->t->peek() != OP_RIGHT_CURLY) - $n->addNode($this->Statement($x)); - - array_pop($x->stmtStack); - - return $n; - } - - private function Block($x) - { - $this->t->mustMatch(OP_LEFT_CURLY); - $n = $this->Statements($x); - $this->t->mustMatch(OP_RIGHT_CURLY); - - return $n; - } - - private function Statement($x) - { - $tt = $this->t->get(); - $n2 = null; - - // Cases for statements ending in a right curly return early, avoiding the - // common semicolon insertion magic after this switch. - switch ($tt) - { - case KEYWORD_FUNCTION: - return $this->FunctionDefinition( - $x, - true, - count($x->stmtStack) > 1 ? STATEMENT_FORM : DECLARED_FORM - ); - break; - - case OP_LEFT_CURLY: - $n = $this->Statements($x); - $this->t->mustMatch(OP_RIGHT_CURLY); - return $n; - - case KEYWORD_IF: - $n = new JSNode($this->t); - $n->condition = $this->ParenExpression($x); - array_push($x->stmtStack, $n); - $n->thenPart = $this->Statement($x); - $n->elsePart = $this->t->match(KEYWORD_ELSE) ? $this->Statement($x) : null; - array_pop($x->stmtStack); - return $n; - - case KEYWORD_SWITCH: - $n = new JSNode($this->t); - $this->t->mustMatch(OP_LEFT_PAREN); - $n->discriminant = $this->Expression($x); - $this->t->mustMatch(OP_RIGHT_PAREN); - $n->cases = array(); - $n->defaultIndex = -1; - - array_push($x->stmtStack, $n); - - $this->t->mustMatch(OP_LEFT_CURLY); - - while (($tt = $this->t->get()) != OP_RIGHT_CURLY) - { - switch ($tt) - { - case KEYWORD_DEFAULT: - if ($n->defaultIndex >= 0) - throw $this->t->newSyntaxError('More than one switch default'); - // FALL THROUGH - case KEYWORD_CASE: - $n2 = new JSNode($this->t); - if ($tt == KEYWORD_DEFAULT) - $n->defaultIndex = count($n->cases); - else - $n2->caseLabel = $this->Expression($x, OP_COLON); - break; - default: - throw $this->t->newSyntaxError('Invalid switch case'); - } - - $this->t->mustMatch(OP_COLON); - $n2->statements = new JSNode($this->t, JS_BLOCK); - while (($tt = $this->t->peek()) != KEYWORD_CASE && $tt != KEYWORD_DEFAULT && $tt != OP_RIGHT_CURLY) - $n2->statements->addNode($this->Statement($x)); - - array_push($n->cases, $n2); - } - - array_pop($x->stmtStack); - return $n; - - case KEYWORD_FOR: - $n = new JSNode($this->t); - $n->isLoop = true; - $this->t->mustMatch(OP_LEFT_PAREN); - - if (($tt = $this->t->peek()) != OP_SEMICOLON) - { - $x->inForLoopInit = true; - if ($tt == KEYWORD_VAR || $tt == KEYWORD_CONST) - { - $this->t->get(); - $n2 = $this->Variables($x); - } - else - { - $n2 = $this->Expression($x); - } - $x->inForLoopInit = false; - } - - if ($n2 && $this->t->match(KEYWORD_IN)) - { - $n->type = JS_FOR_IN; - if ($n2->type == KEYWORD_VAR) - { - if (count($n2->treeNodes) != 1) - { - throw $this->t->SyntaxError( - 'Invalid for..in left-hand side', - $this->t->filename, - $n2->lineno - ); - } - - // NB: n2[0].type == IDENTIFIER and n2[0].value == n2[0].name. - $n->iterator = $n2->treeNodes[0]; - $n->varDecl = $n2; - } - else - { - $n->iterator = $n2; - $n->varDecl = null; - } - - $n->object = $this->Expression($x); - } - else - { - $n->setup = $n2 ? $n2 : null; - $this->t->mustMatch(OP_SEMICOLON); - $n->condition = $this->t->peek() == OP_SEMICOLON ? null : $this->Expression($x); - $this->t->mustMatch(OP_SEMICOLON); - $n->update = $this->t->peek() == OP_RIGHT_PAREN ? null : $this->Expression($x); - } - - $this->t->mustMatch(OP_RIGHT_PAREN); - $n->body = $this->nest($x, $n); - return $n; - - case KEYWORD_WHILE: - $n = new JSNode($this->t); - $n->isLoop = true; - $n->condition = $this->ParenExpression($x); - $n->body = $this->nest($x, $n); - return $n; - - case KEYWORD_DO: - $n = new JSNode($this->t); - $n->isLoop = true; - $n->body = $this->nest($x, $n, KEYWORD_WHILE); - $n->condition = $this->ParenExpression($x); - if (!$x->ecmaStrictMode) - { - //