Forcing JavaScript to be inserted on the page bottom
authorAlexander Ebert <ebert@woltlab.com>
Sun, 7 Jul 2013 18:48:13 +0000 (20:48 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sun, 7 Jul 2013 18:48:13 +0000 (20:48 +0200)
wcfsetup/install/files/lib/util/HeaderUtil.class.php

index 2b14c96178e17c3629d9ccb5c060de97d6c1079b..f61365be4d707cd0d370da5ef857c7b90bbb8793 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace wcf\util;
 use wcf\system\application\ApplicationHandler;
+use wcf\system\event\EventHandler;
 use wcf\system\request\RouteHandler;
 use wcf\system\WCF;
 
@@ -15,6 +16,12 @@ use wcf\system\WCF;
  * @category   Community Framework
  */
 final class HeaderUtil {
+       /**
+        * output HTML
+        * @var string
+        */
+       public static $output = '';
+       
        /**
         * Alias to php setcookie() function.
         */
@@ -37,10 +44,7 @@ final class HeaderUtil {
                        self::sendNoCacheHeaders();
                }
                
-               // enable gzip compression
-               if (HTTP_ENABLE_GZIP && HTTP_GZIP_LEVEL > 0 && HTTP_GZIP_LEVEL < 10 && !defined('HTTP_DISABLE_GZIP')) {
-                       self::compressOutput();
-               }
+               ob_start(array('wcf\util\HeaderUtil', 'parseOutput'));
                
                // send Internet Explorer compatibility mode
                @header('X-UA-Compatible: IE=edge');
@@ -57,34 +61,52 @@ final class HeaderUtil {
        }
        
        /**
-        * Enables the gzip compression of the page output.
+        * Parses the rendered output.
+        * 
+        * @param       string          $output
+        * @return      string
         */
-       public static function compressOutput() {
-               if (function_exists('gzcompress') && !@ini_get('zlib.output_compression') && !@ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
-                       if (strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip')) {
-                               @header('Content-Encoding: x-gzip');
-                       }
-                       else {
-                               @header('Content-Encoding: gzip');
+       public static function parseOutput($output) {
+               self::$output = $output;
+               
+               // move script tags to the bottom of the page
+               $javascript = array();
+               self::$output = preg_replace_callback('~<script(.*?)</script>~s', function($matches) use (&$javascript) {
+                       $javascript[] = $matches[0];
+                       return '';
+               }, self::$output);
+               
+               self::$output = str_replace(array('</body>', '</html>'), array('', ''), self::$output);
+               self::$output .= "\n".implode("\n", $javascript)."\n</body></html>";
+               
+               // 3rd party plugins may differ the actual output before it is sent to the browser
+               // please be aware, that $eventObj is not available here due to this being a static
+               // class. Use HeaderUtil::$output to modify it.
+               EventHandler::getInstance()->fireAction('wcf\util\HeaderUtil', 'parseOutput');
+               
+               // enable gzip compression
+               if (HTTP_ENABLE_GZIP && HTTP_GZIP_LEVEL > 0 && HTTP_GZIP_LEVEL < 10 && !defined('HTTP_DISABLE_GZIP')) {
+                       if (function_exists('gzcompress') && !@ini_get('zlib.output_compression') && !@ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
+                               if (strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip')) {
+                                       @header('Content-Encoding: x-gzip');
+                               }
+                               else {
+                                       @header('Content-Encoding: gzip');
+                               }
+                               
+                               $size = strlen(self::$output);
+                               $crc = crc32(self::$output);
+                               
+                               $newOutput = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff";
+                               $newOutput .= substr(gzcompress(self::$output, HTTP_GZIP_LEVEL), 2, -4);
+                               $newOutput .= pack('V', $crc);
+                               $newOutput .= pack('V', $size);
+                               
+                               self::$output = $newOutput;
                        }
-                       ob_start(array('wcf\util\HeaderUtil', 'getCompressedOutput'));
                }
-       }
-       
-       /**
-        * Outputs the compressed page content.
-        */
-       public static function getCompressedOutput($output) {
-               $size = strlen($output);
-               $crc = crc32($output);
-               
-               $newOutput = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff";
-               $newOutput .= substr(gzcompress($output, HTTP_GZIP_LEVEL), 2, -4);
-               unset($output);
-               $newOutput .= pack('V', $crc);
-               $newOutput .= pack('V', $size);
                
-               return $newOutput;
+               return self::$output;
        }
        
        /**