You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by ch...@apache.org on 2008/05/15 14:39:15 UTC

svn commit: r656630 - in /incubator/shindig/trunk/php: ./ src/common/ src/gadgets/ src/gadgets/http/

Author: chabotc
Date: Thu May 15 05:39:15 2008
New Revision: 656630

URL: http://svn.apache.org/viewvc?rev=656630&view=rev
Log:
Take 2 of javascript compression.

This time we're using a php port of jsmin.c, it has a slightly lower compression
ratio then yuicompressort, but the overhead of starting a java app in the background
was way to high. This way it's actually quite functional and speedy.

All the compressed js is cached, so the first time a feature lib is called it will
have a slight delay compared to normal (0.5 seconds on my box), but all subsiquent
calls will be just as fast as before.

Using this method we save nearly 50% on the gadget html size


Added:
    incubator/shindig/trunk/php/src/common/JsMin.php
Modified:
    incubator/shindig/trunk/php/config.php
    incubator/shindig/trunk/php/src/common/HttpServlet.php
    incubator/shindig/trunk/php/src/common/RemoteContentRequest.php
    incubator/shindig/trunk/php/src/gadgets/GadgetContext.php
    incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php
    incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php
    incubator/shindig/trunk/php/src/gadgets/JsLibrary.php
    incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php

Modified: incubator/shindig/trunk/php/config.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/config.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/config.php (original)
+++ incubator/shindig/trunk/php/config.php Thu May 15 05:39:15 2008
@@ -1,5 +1,24 @@
 <?
 /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ * 
+ */
+
+/*
  * I really detest such config files to be honest, why put configuration in a web document! 
  * But since PHP lacks a propper way to set application configurations, and any other method 
  * would be horribly slow (db, xml, ini files etc), so ... here's our config.php
@@ -20,10 +39,14 @@
 	'token_cipher_key' => 'INSECURE_DEFAULT_KEY',
 	'token_hmac_key' => 'INSECURE_DEFAULT_KEY',
 
+	// Compresses features javascript? can save upto 50% page size
+	'compress_javascript' => true,
+
 	// Configurable CSS rules that are injected to the gadget page, 
 	// be careful when adjusting these not to break most gadget's layouts :)
 	'gadget_css' => 'body,td,div,span,p{font-family:arial,sans-serif;} a {color:#0000cc;}a:visited {color:#551a8b;}a:active {color:#ff0000;}body{margin: 0px;padding: 0px;background-color:white;}',
-
+	// 'gadget_css' => 'body,td,div,span,p{font-family:arial,sans-serif;} body {background-color:#ffffff; font-family: arial, sans-serif; padding: 0px; margin: 0px;  font-size: 12px; color: #000000;}a, a:visited {color: #3366CC;text-decoration: none; }a:hover {color: #3366CC; text-decoration: underline;} input, select { border: 1px solid #bdc7d8;font-size: 11px;padding: 3px;}',
+	
 	// The html / javascript samples use a plain text demo token,
 	// set this to false on anything resembling a real site
 	'allow_plaintext_token' => true,
@@ -43,7 +66,7 @@
 
 	// The data handlers for the social data, this is a list of class names
 	// seperated by a , For example:
-	// 'handlers' => 'PartuzaHandler',
+	//'handlers' => 'PartuzaHandler',
 	// if the value is empty, the defaults used in the example above will be used.
 	'handlers' => '',
 
@@ -82,8 +105,7 @@
 
 /**
  * Abstracts how to retrieve configuration values so we can replace the
- * not so pretty $config array some day.
- *
+ * not so pretty $shindigConfig array some day.
  */
 class Config {
 	static function get($key)

Modified: incubator/shindig/trunk/php/src/common/HttpServlet.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/HttpServlet.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/common/HttpServlet.php (original)
+++ incubator/shindig/trunk/php/src/common/HttpServlet.php Thu May 15 05:39:15 2008
@@ -68,8 +68,8 @@
 				header("Expires: " . gmdate("D, d M Y H:i:s", time() + $this->cacheTime) . " GMT");
 				// Obey browsers (or proxy's) request to send a fresh copy if we recieve a no-cache pragma or cache-control request
 				if (! isset($_SERVER['HTTP_PRAGMA']) || ! strstr(strtolower($_SERVER['HTTP_PRAGMA']), 'no-cache') && (! isset($_SERVER['HTTP_CACHE_CONTROL']) || ! strstr(strtolower($_SERVER['HTTP_CACHE_CONTROL']), 'no-cache'))) {
-					// If the browser send us a E-TAG check if it matches (sha1 sum of content), if so send a not modified header instead of content
-					$etag = sha1($content);
+					// If the browser send us a E-TAG check if it matches (md5 sum of content), if so send a not modified header instead of content
+					$etag = md5($content);
 					if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag) {
 						header("ETag: \"$etag\"");
 						if ($this->lastModified) {

Added: incubator/shindig/trunk/php/src/common/JsMin.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/JsMin.php?rev=656630&view=auto
==============================================================================
--- incubator/shindig/trunk/php/src/common/JsMin.php (added)
+++ incubator/shindig/trunk/php/src/common/JsMin.php Thu May 15 05:39:15 2008
@@ -0,0 +1,290 @@
+<?php
+/**
+ * jsmin.php - PHP implementation of Douglas Crockford's JSMin.
+ *
+ * This is pretty much a direct port of jsmin.c to PHP with just a few
+ * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
+ * outputs to stdout, this library accepts a string as input and returns another
+ * string as output.
+ *
+ * PHP 5 or higher is required.
+ *
+ * Permission is hereby granted to use this version of the library under the
+ * same terms as jsmin.c, which has the following license:
+ *
+ * --
+ * Copyright (c) 2002 Douglas Crockford  (www.crockford.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 shall be used for Good, not Evil.
+ *
+ * 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.
+ * --
+ *
+ * @package JSMin
+ * @author Ryan Grove <ry...@wonko.com>
+ * @copyright 2002 Douglas Crockford <do...@crockford.com> (jsmin.c)
+ * @copyright 2008 Ryan Grove <ry...@wonko.com> (PHP port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @version 1.1.1 (2008-03-02)
+ * @link http://code.google.com/p/jsmin-php/
+ */
+
+class JsMinException extends Exception {}
+
+class JsMin {
+  const ORD_LF    = 10;
+  const ORD_SPACE = 32;
+
+  protected $a           = '';
+  protected $b           = '';
+  protected $input       = '';
+  protected $inputIndex  = 0;
+  protected $inputLength = 0;
+  protected $lookAhead   = null;
+  protected $output      = '';
+
+  // -- Public Static Methods --------------------------------------------------
+
+  public static function minify($js) {
+    $jsmin = new JsMin($js);
+    return $jsmin->min();
+  }
+
+  // -- Public Instance Methods ------------------------------------------------
+
+  public function __construct($input) {
+    $this->input       = str_replace("\r\n", "\n", $input);
+    $this->inputLength = strlen($this->input);
+  }
+
+  // -- Protected Instance Methods ---------------------------------------------
+
+  protected function action($d) {
+    switch($d) {
+      case 1:
+        $this->output .= $this->a;
+
+      case 2:
+        $this->a = $this->b;
+
+        if ($this->a === "'" || $this->a === '"') {
+          for (;;) {
+            $this->output .= $this->a;
+            $this->a       = $this->get();
+
+            if ($this->a === $this->b) {
+              break;
+            }
+
+            if (ord($this->a) <= self::ORD_LF) {
+              throw new JsMinException('Unterminated string literal.');
+            }
+
+            if ($this->a === '\\') {
+              $this->output .= $this->a;
+              $this->a       = $this->get();
+            }
+          }
+        }
+
+      case 3:
+        $this->b = $this->next();
+
+        if ($this->b === '/' && (
+            $this->a === '(' || $this->a === ',' || $this->a === '=' ||
+            $this->a === ':' || $this->a === '[' || $this->a === '!' ||
+            $this->a === '&' || $this->a === '|' || $this->a === '?')) {
+
+          $this->output .= $this->a . $this->b;
+
+          for (;;) {
+            $this->a = $this->get();
+
+            if ($this->a === '/') {
+              break;
+            } elseif ($this->a === '\\') {
+              $this->output .= $this->a;
+              $this->a       = $this->get();
+            } elseif (ord($this->a) <= self::ORD_LF) {
+              throw new JsMinException('Unterminated regular expression '.
+                  'literal.');
+            }
+
+            $this->output .= $this->a;
+          }
+
+          $this->b = $this->next();
+        }
+    }
+  }
+
+  protected function get() {
+    $c = $this->lookAhead;
+    $this->lookAhead = null;
+
+    if ($c === null) {
+      if ($this->inputIndex < $this->inputLength) {
+        $c = $this->input[$this->inputIndex];
+        $this->inputIndex += 1;
+      } else {
+        $c = null;
+      }
+    }
+
+    if ($c === "\r") {
+      return "\n";
+    }
+
+    if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
+      return $c;
+    }
+
+    return ' ';
+  }
+
+  protected function isAlphaNum($c) {
+    return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
+  }
+
+  protected function min() {
+    $this->a = "\n";
+    $this->action(3);
+
+    while ($this->a !== null) {
+      switch ($this->a) {
+        case ' ':
+          if ($this->isAlphaNum($this->b)) {
+            $this->action(1);
+          } else {
+            $this->action(2);
+          }
+          break;
+
+        case "\n":
+          switch ($this->b) {
+            case '{':
+            case '[':
+            case '(':
+            case '+':
+            case '-':
+              $this->action(1);
+              break;
+
+            case ' ':
+              $this->action(3);
+              break;
+
+            default:
+              if ($this->isAlphaNum($this->b)) {
+                $this->action(1);
+              }
+              else {
+                $this->action(2);
+              }
+          }
+          break;
+
+        default:
+          switch ($this->b) {
+            case ' ':
+              if ($this->isAlphaNum($this->a)) {
+                $this->action(1);
+                break;
+              }
+
+              $this->action(3);
+              break;
+
+            case "\n":
+              switch ($this->a) {
+                case '}':
+                case ']':
+                case ')':
+                case '+':
+                case '-':
+                case '"':
+                case "'":
+                  $this->action(1);
+                  break;
+
+                default:
+                  if ($this->isAlphaNum($this->a)) {
+                    $this->action(1);
+                  }
+                  else {
+                    $this->action(3);
+                  }
+              }
+              break;
+
+            default:
+              $this->action(1);
+              break;
+          }
+      }
+    }
+
+    return $this->output;
+  }
+
+  protected function next() {
+    $c = $this->get();
+
+    if ($c === '/') {
+      switch($this->peek()) {
+        case '/':
+          for (;;) {
+            $c = $this->get();
+
+            if (ord($c) <= self::ORD_LF) {
+              return $c;
+            }
+          }
+
+        case '*':
+          $this->get();
+
+          for (;;) {
+            switch($this->get()) {
+              case '*':
+                if ($this->peek() === '/') {
+                  $this->get();
+                  return ' ';
+                }
+                break;
+
+              case null:
+                throw new JsMinException('Unterminated comment.');
+            }
+          }
+
+        default:
+          return $c;
+      }
+    }
+
+    return $c;
+  }
+
+  protected function peek() {
+    $this->lookAhead = $this->get();
+    return $this->lookAhead;
+  }
+}
+

Modified: incubator/shindig/trunk/php/src/common/RemoteContentRequest.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/common/RemoteContentRequest.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/common/RemoteContentRequest.php (original)
+++ incubator/shindig/trunk/php/src/common/RemoteContentRequest.php Thu May 15 05:39:15 2008
@@ -39,10 +39,10 @@
 	}
 
 	// returns a hash code which identifies this request, used for caching
-	// takes url and postbody into account for constructing the sha1 checksum
+	// takes url and postbody into account for constructing the md5 checksum
 	public function toHash()
 	{
-		return sha1($this->url . $this->postBody);
+		return md5($this->url . $this->postBody);
 	}
 
 	public function getContentType()

Modified: incubator/shindig/trunk/php/src/gadgets/GadgetContext.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/GadgetContext.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/GadgetContext.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/GadgetContext.php Thu May 15 05:39:15 2008
@@ -149,9 +149,9 @@
 	{
 		// Profiling showed 40% of the processing time was spend in the feature registry
 		// So by caching this and making it a one time initialization, we almost double the performance  
-		if (! ($registry = $this->getCache()->get(sha1(Config::get('features_path'))))) {
+		if (! ($registry = $this->getCache()->get(md5(Config::get('features_path'))))) {
 			$registry = new GadgetFeatureRegistry(Config::get('features_path'));
-			$this->getCache()->set(sha1(Config::get('features_path')), $registry);
+			$this->getCache()->set(md5(Config::get('features_path')), $registry);
 		}
 		return $registry;
 	}

Modified: incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php Thu May 15 05:39:15 2008
@@ -22,11 +22,9 @@
 	private $features = array();
 	private $core = array();
 	private $coreDone = false;
-	private $debug;
 
-	public function __construct($featurePath, $debug = false)
+	public function __construct($featurePath)
 	{
-		$this->debug = $debug;
 		$this->registerFeatures($featurePath);
 	}
 
@@ -36,7 +34,7 @@
 			return;
 		}
 		$coreDeps = array();
-		$loader = new JsFeatureLoader($this->debug);
+		$loader = new JsFeatureLoader();
 		$jsFeatures = $loader->loadFeatures($featurePath, $this);
 		if (! $this->coreDone) {
 			foreach ($jsFeatures as $entry) {

Modified: incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/JsFeatureLoader.php Thu May 15 05:39:15 2008
@@ -19,12 +19,6 @@
  */
 
 class JsFeatureLoader {
-	private $debug;
-
-	public function __construct($debug)
-	{
-		$this->debug = $debug;
-	}
 
 	public function loadFeatures($path, $registry)
 	{

Modified: incubator/shindig/trunk/php/src/gadgets/JsLibrary.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/JsLibrary.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/JsLibrary.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/JsLibrary.php Thu May 15 05:39:15 2008
@@ -36,23 +36,23 @@
 	{
 		return $this->type;
 	}
-	
-	public function readfile()
-	{
-		// hack to bypass having the script in memory and dump it directly to stdout
-		if (!$this->loaded && $this->type == 'FILE') {
-			readfile($this->content);
-			echo "\n";
-		} else {
-			// a call to getContent was already made so we have it in memory, just echo it then
-			echo $this->content;
-		}
-	}
 
 	public function getContent()
 	{
 		if (!$this->loaded && $this->type == 'FILE') {
-			$this->content = JsLibrary::loadData($this->content, $this->type);
+			if (Config::get('compress_javascript')) {
+				$dataCache = Config::get('data_cache');
+				$dataCache = new $dataCache();
+				if (!($content = $dataCache->get(md5($this->content)))) {
+					$content = JSMin::minify(JsLibrary::loadData($this->content, $this->type));
+					$dataCache->set(md5($this->content), $content);
+					$this->content = $content;
+				} else {
+					$this->content = $content;
+				}
+			} else {
+				$this->content = JsLibrary::loadData($this->content, $this->type);
+			}
 			$this->loaded = true;
 		}
 		return $this->content;

Modified: incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php?rev=656630&r1=656629&r2=656630&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php (original)
+++ incubator/shindig/trunk/php/src/gadgets/http/GadgetRenderingServlet.php Thu May 15 05:39:15 2008
@@ -160,11 +160,11 @@
 				// servlet. We should probably inline external JS as well.
 				$externJs .= sprintf($externFmt, $library->getContent()) . "\n";
 			} else if ($type == 'INLINE') {
-				$library->readfile();
+				echo $library->getContent();
 			} else {
 				// FILE or RESOURCE
 				if ($forcedLibs == null) {
-					$library->readfile();
+					echo $library->getContent();
 				}
 				// otherwise it was already included by config.forceJsLibs.
 			}