├── LICENCE.txt ├── README.md ├── examples ├── code-url.html ├── code-url.php ├── js │ ├── animation.js │ └── color.js ├── post-script.html └── post-script.php └── php-closure.php /LICENCE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010 Daniel Pupius. http://pupius.co.uk 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | 16 | ------------------------------------------------------------------------- 17 | Apache License 18 | Version 2.0, January 2004 19 | http://www.apache.org/licenses/ 20 | 21 | 22 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 23 | 24 | 1. Definitions. 25 | 26 | "License" shall mean the terms and conditions for use, reproduction, 27 | and distribution as defined by Sections 1 through 9 of this document. 28 | 29 | "Licensor" shall mean the copyright owner or entity authorized by 30 | the copyright owner that is granting the License. 31 | 32 | "Legal Entity" shall mean the union of the acting entity and all 33 | other entities that control, are controlled by, or are under common 34 | control with that entity. For the purposes of this definition, 35 | "control" means (i) the power, direct or indirect, to cause the 36 | direction or management of such entity, whether by contract or 37 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 38 | outstanding shares, or (iii) beneficial ownership of such entity. 39 | 40 | "You" (or "Your") shall mean an individual or Legal Entity 41 | exercising permissions granted by this License. 42 | 43 | "Source" form shall mean the preferred form for making modifications, 44 | including but not limited to software source code, documentation 45 | source, and configuration files. 46 | 47 | "Object" form shall mean any form resulting from mechanical 48 | transformation or translation of a Source form, including but 49 | not limited to compiled object code, generated documentation, 50 | and conversions to other media types. 51 | 52 | "Work" shall mean the work of authorship, whether in Source or 53 | Object form, made available under the License, as indicated by a 54 | copyright notice that is included in or attached to the work 55 | (an example is provided in the Appendix below). 56 | 57 | "Derivative Works" shall mean any work, whether in Source or Object 58 | form, that is based on (or derived from) the Work and for which the 59 | editorial revisions, annotations, elaborations, or other modifications 60 | represent, as a whole, an original work of authorship. For the purposes 61 | of this License, Derivative Works shall not include works that remain 62 | separable from, or merely link (or bind by name) to the interfaces of, 63 | the Work and Derivative Works thereof. 64 | 65 | "Contribution" shall mean any work of authorship, including 66 | the original version of the Work and any modifications or additions 67 | to that Work or Derivative Works thereof, that is intentionally 68 | submitted to Licensor for inclusion in the Work by the copyright owner 69 | or by an individual or Legal Entity authorized to submit on behalf of 70 | the copyright owner. For the purposes of this definition, "submitted" 71 | means any form of electronic, verbal, or written communication sent 72 | to the Licensor or its representatives, including but not limited to 73 | communication on electronic mailing lists, source code control systems, 74 | and issue tracking systems that are managed by, or on behalf of, the 75 | Licensor for the purpose of discussing and improving the Work, but 76 | excluding communication that is conspicuously marked or otherwise 77 | designated in writing by the copyright owner as "Not a Contribution." 78 | 79 | "Contributor" shall mean Licensor and any individual or Legal Entity 80 | on behalf of whom a Contribution has been received by Licensor and 81 | subsequently incorporated within the Work. 82 | 83 | 2. Grant of Copyright License. Subject to the terms and conditions of 84 | this License, each Contributor hereby grants to You a perpetual, 85 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 86 | copyright license to reproduce, prepare Derivative Works of, 87 | publicly display, publicly perform, sublicense, and distribute the 88 | Work and such Derivative Works in Source or Object form. 89 | 90 | 3. Grant of Patent License. Subject to the terms and conditions of 91 | this License, each Contributor hereby grants to You a perpetual, 92 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 93 | (except as stated in this section) patent license to make, have made, 94 | use, offer to sell, sell, import, and otherwise transfer the Work, 95 | where such license applies only to those patent claims licensable 96 | by such Contributor that are necessarily infringed by their 97 | Contribution(s) alone or by combination of their Contribution(s) 98 | with the Work to which such Contribution(s) was submitted. If You 99 | institute patent litigation against any entity (including a 100 | cross-claim or counterclaim in a lawsuit) alleging that the Work 101 | or a Contribution incorporated within the Work constitutes direct 102 | or contributory patent infringement, then any patent licenses 103 | granted to You under this License for that Work shall terminate 104 | as of the date such litigation is filed. 105 | 106 | 4. Redistribution. You may reproduce and distribute copies of the 107 | Work or Derivative Works thereof in any medium, with or without 108 | modifications, and in Source or Object form, provided that You 109 | meet the following conditions: 110 | 111 | (a) You must give any other recipients of the Work or 112 | Derivative Works a copy of this License; and 113 | 114 | (b) You must cause any modified files to carry prominent notices 115 | stating that You changed the files; and 116 | 117 | (c) You must retain, in the Source form of any Derivative Works 118 | that You distribute, all copyright, patent, trademark, and 119 | attribution notices from the Source form of the Work, 120 | excluding those notices that do not pertain to any part of 121 | the Derivative Works; and 122 | 123 | (d) If the Work includes a "NOTICE" text file as part of its 124 | distribution, then any Derivative Works that You distribute must 125 | include a readable copy of the attribution notices contained 126 | within such NOTICE file, excluding those notices that do not 127 | pertain to any part of the Derivative Works, in at least one 128 | of the following places: within a NOTICE text file distributed 129 | as part of the Derivative Works; within the Source form or 130 | documentation, if provided along with the Derivative Works; or, 131 | within a display generated by the Derivative Works, if and 132 | wherever such third-party notices normally appear. The contents 133 | of the NOTICE file are for informational purposes only and 134 | do not modify the License. You may add Your own attribution 135 | notices within Derivative Works that You distribute, alongside 136 | or as an addendum to the NOTICE text from the Work, provided 137 | that such additional attribution notices cannot be construed 138 | as modifying the License. 139 | 140 | You may add Your own copyright statement to Your modifications and 141 | may provide additional or different license terms and conditions 142 | for use, reproduction, or distribution of Your modifications, or 143 | for any such Derivative Works as a whole, provided Your use, 144 | reproduction, and distribution of the Work otherwise complies with 145 | the conditions stated in this License. 146 | 147 | 5. Submission of Contributions. Unless You explicitly state otherwise, 148 | any Contribution intentionally submitted for inclusion in the Work 149 | by You to the Licensor shall be under the terms and conditions of 150 | this License, without any additional terms or conditions. 151 | Notwithstanding the above, nothing herein shall supersede or modify 152 | the terms of any separate license agreement you may have executed 153 | with Licensor regarding such Contributions. 154 | 155 | 6. Trademarks. This License does not grant permission to use the trade 156 | names, trademarks, service marks, or product names of the Licensor, 157 | except as required for reasonable and customary use in describing the 158 | origin of the Work and reproducing the content of the NOTICE file. 159 | 160 | 7. Disclaimer of Warranty. Unless required by applicable law or 161 | agreed to in writing, Licensor provides the Work (and each 162 | Contributor provides its Contributions) on an "AS IS" BASIS, 163 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 164 | implied, including, without limitation, any warranties or conditions 165 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 166 | PARTICULAR PURPOSE. You are solely responsible for determining the 167 | appropriateness of using or redistributing the Work and assume any 168 | risks associated with Your exercise of permissions under this License. 169 | 170 | 8. Limitation of Liability. In no event and under no legal theory, 171 | whether in tort (including negligence), contract, or otherwise, 172 | unless required by applicable law (such as deliberate and grossly 173 | negligent acts) or agreed to in writing, shall any Contributor be 174 | liable to You for damages, including any direct, indirect, special, 175 | incidental, or consequential damages of any character arising as a 176 | result of this License or out of the use or inability to use the 177 | Work (including but not limited to damages for loss of goodwill, 178 | work stoppage, computer failure or malfunction, or any and all 179 | other commercial damages or losses), even if such Contributor 180 | has been advised of the possibility of such damages. 181 | 182 | 9. Accepting Warranty or Additional Liability. While redistributing 183 | the Work or Derivative Works thereof, You may choose to offer, 184 | and charge a fee for, acceptance of support, warranty, indemnity, 185 | or other liability obligations and/or rights consistent with this 186 | License. However, in accepting such obligations, You may act only 187 | on Your own behalf and on Your sole responsibility, not on behalf 188 | of any other Contributor, and only if You agree to indemnify, 189 | defend, and hold each Contributor harmless for any liability 190 | incurred by, or claims asserted against, such Contributor by reason 191 | of your accepting any such warranty or additional liability. 192 | 193 | END OF TERMS AND CONDITIONS 194 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Library for the Google Closure Compiler 2 | 3 | A PHP class for optimizing and serving JavaScript sources using Google's 4 | [Closure Compiler web service](http://code.google.com/closure/compiler/docs/gettingstarted_api.html). 5 | The sources will be compiled on demand and cached locally for performance. 6 | 7 | Example usage: 8 | 9 | ```php 10 | include("libs/php-closure.php"); 11 | 12 | $c = new PhpClosure(); 13 | $c->add("my-app.js") 14 | ->add("popup.js") 15 | ->advancedMode() 16 | ->useClosureLibrary() 17 | ->cacheDir("/tmp/js-cache/") 18 | ->write(); 19 | ``` 20 | 21 | This was put together pretty quickly for use on [my website](http://pupius.co.uk). Patches and improvements welcome! 22 | 23 | Author 24 | ------ 25 | 26 | [Dan Pupius](https://github.com/dpup) ([personal website](http://pupius.co.uk)). 27 | 28 | License 29 | ------- 30 | 31 | Copyright 2010 [Daniel Pupius](http://pupius.co.uk/). 32 | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). 33 | -------------------------------------------------------------------------------- /examples/code-url.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PHP-Closure Code URL Example 5 | 10 | 11 | 12 |

This example passes the script URLs to the Closure compiler service which requests the files.

13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/code-url.php: -------------------------------------------------------------------------------- 1 | add("js/animation.js") 6 | ->add("js/color.js") 7 | ->advancedMode() 8 | ->useClosureLibrary() 9 | // TODO : Update URL to match your host. 10 | ->useCodeUrl("http://yourhost.com/php-closure/examples/") 11 | // TODO : Change or make sure path exists and is writable. 12 | ->cacheDir("/tmp/js-cache/") 13 | ->write(); 14 | 15 | ?> -------------------------------------------------------------------------------- /examples/js/animation.js: -------------------------------------------------------------------------------- 1 | 2 | goog.require('goog.dom'); 3 | goog.require('goog.events'); 4 | goog.require('goog.fx.dom'); 5 | 6 | var $d = goog.dom.createDom; 7 | 8 | var el = $d('div', {}, 9 | $d('img', {src: 'http://lh4.ggpht.com/__HC3vBAdElI/S7f7r5-l1tI/AAAAAAAACxc/AYncN9-S2Ps/s400/IMG_2934.jpg' })); 10 | 11 | document.body.appendChild(el); 12 | 13 | fadeout(); 14 | 15 | function fadeout() { 16 | var anim = new goog.fx.dom.FadeOutAndHide(el, 1000); 17 | goog.events.listen(anim, goog.fx.Animation.EventType.END, fadein); 18 | anim.play(); 19 | } 20 | 21 | function fadein() { 22 | var anim = new goog.fx.dom.FadeInAndShow(el, 1000); 23 | goog.events.listen(anim, goog.fx.Animation.EventType.END, fadeout); 24 | anim.play(); 25 | } 26 | -------------------------------------------------------------------------------- /examples/js/color.js: -------------------------------------------------------------------------------- 1 | goog.require('goog.color'); 2 | 3 | document.write('

#efacde in RGB is ' + 4 | goog.color.hexToRgbStyle('#efacde') + '

'); 5 | -------------------------------------------------------------------------------- /examples/post-script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PHP-Closure Post Script Example 5 | 10 | 11 | 12 |

This example posts the script contents to the Closure compiler service.

13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/post-script.php: -------------------------------------------------------------------------------- 1 | add("js/animation.js") 6 | ->add("js/color.js") 7 | ->advancedMode() 8 | ->useClosureLibrary() 9 | // TODO : Change or make sure path exists and is writable. 10 | ->cacheDir("/tmp/js-cache/") 11 | ->write(); 12 | 13 | ?> -------------------------------------------------------------------------------- /php-closure.php: -------------------------------------------------------------------------------- 1 | add("my-app.js") 35 | * ->add("popup.js") 36 | * ->advancedMode() 37 | * ->useClosureLibrary() 38 | * ->cacheDir("/tmp/js-cache/") 39 | * ->write(); 40 | * 41 | * See http://code.google.com/closure/compiler/docs/api-ref.html for more 42 | * details on the compiler options. 43 | */ 44 | class PhpClosure { 45 | 46 | var $_srcs = array(); 47 | var $_mode = "WHITESPACE_ONLY"; 48 | var $_warning_level = "DEFAULT"; 49 | var $_use_closure_library = false; 50 | var $_pretty_print = false; 51 | var $_debug = true; 52 | var $_cache_dir = ""; 53 | var $_code_url_prefix = ""; 54 | 55 | function PhpClosure() { } 56 | 57 | /** 58 | * Adds a source file to the list of files to compile. Files will be 59 | * concatenated in the order they are added. 60 | */ 61 | function add($file) { 62 | $this->_srcs[] = $file; 63 | return $this; 64 | } 65 | 66 | /** 67 | * Sets the directory where the compilation results should be cached, if 68 | * not set then caching will be disabled and the compiler will be invoked 69 | * for every request (NOTE: this will hit ratelimits pretty fast!) 70 | */ 71 | function cacheDir($dir) { 72 | $this->_cache_dir = $dir; 73 | return $this; 74 | } 75 | 76 | /** 77 | * Sets whether to use the Closure Library. i.e. goog.requires will be 78 | * resolved and the library code made available. 79 | */ 80 | function useClosureLibrary() { 81 | $this->_use_closure_library = true; 82 | return $this; 83 | } 84 | 85 | /** 86 | * Sets the URL prefix to use with the Closure Compiler service's code_url 87 | * parameter. 88 | * 89 | * By default PHP-Closure posts the scripts to the compiler service, however, 90 | * this is subject to a 200000-byte size limit for the whole post request. 91 | * 92 | * Using code_url tells the compiler service the URLs of the scripts to 93 | * fetch. The file paths added in add() must therefore be relative to this 94 | * URL. 95 | * 96 | * Example usage: 97 | * 98 | * $c->add("js/my-app.js") 99 | * ->add("js/popup.js") 100 | * ->useCodeUrl('http://www.example.com/app/') 101 | * ->cacheDir("/tmp/js-cache/") 102 | * ->write(); 103 | * 104 | * This assumes your PHP script is in a directory /app/ and that the JS is in 105 | * /app/js/ and accessible via HTTP. 106 | */ 107 | function useCodeUrl($code_url_prefix) { 108 | $this->_code_url_prefix = $code_url_prefix; 109 | return $this; 110 | } 111 | 112 | /** 113 | * Tells the compiler to pretty print the output. 114 | */ 115 | function prettyPrint() { 116 | $this->_pretty_print = true; 117 | return $this; 118 | } 119 | 120 | /** 121 | * Turns of the debug info. 122 | * By default statistics, errors and warnings are logged to the console. 123 | */ 124 | function hideDebugInfo() { 125 | $this->_debug = false; 126 | return $this; 127 | } 128 | 129 | /** 130 | * Sets the compilation mode to optimize whitespace only. 131 | */ 132 | function whitespaceOnly() { 133 | $this->_mode = "WHITESPACE_ONLY"; 134 | return $this; 135 | } 136 | 137 | /** 138 | * Sets the compilation mode to simple optimizations. 139 | */ 140 | function simpleMode() { 141 | $this->_mode = "SIMPLE_OPTIMIZATIONS"; 142 | return $this; 143 | } 144 | 145 | /** 146 | * Sets the compilation mode to advanced optimizations (recommended). 147 | */ 148 | function advancedMode() { 149 | $this->_mode = "ADVANCED_OPTIMIZATIONS"; 150 | return $this; 151 | } 152 | 153 | /** 154 | * Gets the compilation mode from the URL, set the mode param to 155 | * 'w', 's' or 'a'. 156 | */ 157 | function getModeFromUrl() { 158 | if ($_GET['mode'] == 's') $this->simpleMode(); 159 | else if ($_GET['mode'] == 'a') $this->advancedMode(); 160 | else $this->whitespaceOnly(); 161 | return $this; 162 | } 163 | 164 | /** 165 | * Sets the warning level to QUIET. 166 | */ 167 | function quiet() { 168 | $this->_warning_level = "QUIET"; 169 | return $this; 170 | } 171 | 172 | /** 173 | * Sets the default warning level. 174 | */ 175 | function defaultWarnings() { 176 | $this->_warning_level = "DEFAULT"; 177 | return $this; 178 | } 179 | 180 | /** 181 | * Sets the warning level to VERBOSE. 182 | */ 183 | function verbose() { 184 | $this->_warning_level = "VERBOSE"; 185 | return $this; 186 | } 187 | 188 | /** 189 | * Writes the compiled response. Reading from either the cache, or 190 | * invoking a recompile, if necessary. 191 | */ 192 | function write() { 193 | header("Content-Type: text/javascript"); 194 | 195 | // No cache directory so just dump the output. 196 | if ($this->_cache_dir == "") { 197 | echo $this->_compile(); 198 | 199 | } else { 200 | $cache_file = $this->_getCacheFileName(); 201 | if ($this->_isRecompileNeeded($cache_file)) { 202 | $result = $this->_compile(); 203 | file_put_contents($cache_file, $result); 204 | echo $result; 205 | } else { 206 | // No recompile needed, but see if we can send a 304 to the browser. 207 | $cache_mtime = filemtime($cache_file); 208 | $etag = md5_file($cache_file); 209 | header("Last-Modified: ".gmdate("D, d M Y H:i:s", $cache_mtime)." GMT"); 210 | header("Etag: $etag"); 211 | if (@strtotime(@$_SERVER['HTTP_IF_MODIFIED_SINCE']) == $cache_mtime || 212 | @trim(@$_SERVER['HTTP_IF_NONE_MATCH']) == $etag) { 213 | header("HTTP/1.1 304 Not Modified"); 214 | } else { 215 | // Read the cache file and send it to the client. 216 | echo file_get_contents($cache_file); 217 | } 218 | } 219 | } 220 | } 221 | 222 | // ----- Privates ----- 223 | 224 | function _isRecompileNeeded($cache_file) { 225 | // If there is no cache file, we obviously need to recompile. 226 | if (!file_exists($cache_file)) return true; 227 | 228 | $cache_mtime = filemtime($cache_file); 229 | 230 | // If the source files are newer than the cache file, recompile. 231 | foreach ($this->_srcs as $src) { 232 | if (filemtime($src) > $cache_mtime) return true; 233 | } 234 | 235 | // If this script calling the compiler is newer than the cache file, 236 | // recompile. Note, this might not be accurate if the file doing the 237 | // compilation is loaded via an include(). 238 | if (filemtime($_SERVER["SCRIPT_FILENAME"]) > $cache_mtime) return true; 239 | 240 | // Cache is up to date. 241 | return false; 242 | } 243 | 244 | function _compile() { 245 | // Quieten strict notices. 246 | $code = $originalSize = $originalGzipSize = $compressedSize = $compressedGzipSize = $compileTime = ''; 247 | 248 | $tree = $this->_parseXml($this->_makeRequest()); 249 | 250 | $result = $tree; 251 | foreach ($result as $node) { 252 | switch ($node["tag"]) { 253 | case "compiledCode": $code = $node["value"]; break; 254 | case "warnings": $warnings = $node["value"]; break; 255 | case "errors": $errors = $node["value"]; break; 256 | case "statistics": 257 | foreach ($node["value"] as $stat) { 258 | switch ($stat["tag"]) { 259 | case "originalSize": $originalSize = $stat["value"]; break; 260 | case "originalGzipSize": $originalGzipSize = $stat["value"]; break; 261 | case "compressedSize": $compressedSize = $stat["value"]; break; 262 | case "compressedGzipSize": $compressedGzipSize = $stat["value"]; break; 263 | case "compileTime": $compileTime = $stat["value"]; break; 264 | } 265 | } 266 | break; 267 | } 268 | } 269 | 270 | $result = ""; 271 | if ($this->_debug) { 272 | $result = "if(window.console&&window.console.log){\r\n" . 273 | "window.console.log('Closure Compiler Stats:\\n" . 274 | "-----------------------\\n" . 275 | "Original Size: $originalSize\\n" . 276 | "Original Gzip Size: $originalGzipSize\\n" . 277 | "Compressed Size: $compressedSize\\n" . 278 | "Compressed Gzip Size: $compressedGzipSize\\n" . 279 | "Compile Time: $compileTime\\n" . 280 | "Generated: " . Date("Y/m/d H:i:s T") . "');\r\n"; 281 | if (isset($errors)) $result .= $this->_printWarnings($errors, "error"); 282 | if (isset($warnings)) $result .= $this->_printWarnings($warnings, "warn"); 283 | $result .= "}\r\n\r\n"; 284 | } 285 | $result .= "$code \r\n"; 286 | 287 | return $result; 288 | } 289 | 290 | function _printWarnings($warnings, $level="log") { 291 | $result = ""; 292 | foreach ($warnings as $warning) { 293 | $desc = addslashes($warning["value"]); 294 | $type = $warning["attributes"]["type"]; 295 | $lineno = $warning["attributes"]["lineno"]; 296 | $charno = $warning["attributes"]["charno"]; 297 | $line = addslashes($warning["attributes"]["line"]); 298 | $result .= "window.console.$level('$type: $desc\\nLine: $lineno\\nChar: $charno\\nLine: $line');\r\n"; 299 | } 300 | return $result; 301 | } 302 | 303 | function _getCacheFileName() { 304 | return $this->_cache_dir . $this->_getHash() . ".js"; 305 | } 306 | 307 | function _getHash() { 308 | return md5(implode(",", $this->_srcs) . "-" . 309 | $this->_mode . "-" . 310 | $this->_warning_level . "-" . 311 | $this->_use_closure_library . "-" . 312 | $this->_pretty_print . "-" . 313 | $this->_debug); 314 | } 315 | 316 | function _getParams() { 317 | $params = array(); 318 | foreach ($this->_getParamList() as $key => $value) { 319 | $params[] = preg_replace("/_[0-9]$/", "", $key) . "=" . urlencode($value); 320 | } 321 | return implode("&", $params); 322 | } 323 | 324 | function _getParamList() { 325 | $params = array(); 326 | if ($this->_code_url_prefix) { 327 | // Send the URL to each source file instead of the raw source. 328 | $i = 0; 329 | foreach($this->_srcs as $file){ 330 | $params["code_url_$i"] = $this->_code_url_prefix . $file; 331 | $i++; 332 | } 333 | } else { 334 | $params["js_code"] = $this->_readSources(); 335 | } 336 | $params["compilation_level"] = $this->_mode; 337 | $params["output_format"] = "xml"; 338 | $params["warning_level"] = $this->_warning_level; 339 | if ($this->_pretty_print) $params["formatting"] = "pretty_print"; 340 | if ($this->_use_closure_library) $params["use_closure_library"] = "true"; 341 | $params["output_info_1"] = "compiled_code"; 342 | $params["output_info_2"] = "statistics"; 343 | $params["output_info_3"] = "warnings"; 344 | $params["output_info_4"] = "errors"; 345 | return $params; 346 | } 347 | 348 | function _readSources() { 349 | $code = ""; 350 | foreach ($this->_srcs as $src) { 351 | $code .= file_get_contents($src) . "\n\n"; 352 | } 353 | return $code; 354 | } 355 | 356 | function _makeRequest() { 357 | $data = $this->_getParams(); 358 | $referer = @$_SERVER["HTTP_REFERER"] or ""; 359 | 360 | $fp = fsockopen("ssl://closure-compiler.appspot.com", 443) or die("Unable to open socket"); 361 | 362 | if ($fp) { 363 | fputs($fp, "POST /compile HTTP/1.1\r\n"); 364 | fputs($fp, "Host: closure-compiler.appspot.com\r\n"); 365 | fputs($fp, "Referer: $referer\r\n"); 366 | fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n"); 367 | fputs($fp, "Content-length: ". strlen($data) ."\r\n"); 368 | fputs($fp, "Connection: close\r\n\r\n"); 369 | fputs($fp, $data); 370 | 371 | $result = ""; 372 | while (!feof($fp)) { 373 | $result .= fgets($fp, 128); 374 | } 375 | 376 | fclose($fp); 377 | } 378 | 379 | $data = substr($result, (strpos($result, "\r\n\r\n")+4)); 380 | if (strpos(strtolower($result), "transfer-encoding: chunked") !== FALSE) { 381 | $data = $this->_unchunk($data); 382 | } 383 | 384 | return $data; 385 | } 386 | 387 | function _unchunk($data) { 388 | $fp = 0; 389 | $outData = ""; 390 | while ($fp < strlen($data)) { 391 | $rawnum = substr($data, $fp, strpos(substr($data, $fp), "\r\n") + 2); 392 | $num = hexdec(trim($rawnum)); 393 | $fp += strlen($rawnum); 394 | $chunk = substr($data, $fp, $num); 395 | $outData .= $chunk; 396 | $fp += strlen($chunk); 397 | } 398 | return $outData; 399 | } 400 | 401 | function _parseXml($data) { 402 | $xml = new SimpleXMLElement($data); 403 | return $this->_parseXmlHelper($xml); 404 | } 405 | 406 | function _parseXmlHelper($xml) { 407 | $tree = null; 408 | foreach ($xml->children() as $name => $child) { 409 | $value = (string)$child; 410 | $node = array('tag' => $name, 'value' => count($child->children()) == 0 ? $value : $this->_parseXmlHelper($child)); 411 | 412 | foreach ($child->attributes() as $attr => $value) { 413 | $node['attributes'][$attr] = $value[0]; 414 | } 415 | $tree[] = $node; 416 | } 417 | return $tree; 418 | } 419 | } 420 | --------------------------------------------------------------------------------