includes/js-compressor.php
changeset 1227 bdac73ed481e
parent 1081 745200a9cc2a
child 1290 27ab1b13a783
equal deleted inserted replaced
1226:de56132c008d 1227:bdac73ed481e
    82  */
    82  */
    83 class JavaScriptCompressor {
    83 class JavaScriptCompressor {
    84 
    84 
    85 	/**
    85 	/**
    86 	 * public variables
    86 	 * public variables
    87          * 	stats:string		after every compression has some informations
    87  				* 	stats:string		after every compression has some informations
    88          *      version:string		version of this class
    88  				*      version:string		version of this class
    89 	 */
    89 	 */
    90 	var	$stats = '',
    90 	var	$stats = '',
    91 		$version = '0.8';
    91 		$version = '0.8';
    92 
    92 
    93 	/** 'private' variables, any comment sorry */
    93 	/** 'private' variables, any comment sorry */
   102 		$__BC = null,
   102 		$__BC = null,
   103 		$__SourceMap = null;
   103 		$__SourceMap = null;
   104 
   104 
   105 	/**
   105 	/**
   106 	 * public constructor
   106 	 * public constructor
   107          * 	creates a new BaseConvert class variable (base 36)
   107  				* 	creates a new BaseConvert class variable (base 36)
   108 	 */
   108 	 */
   109 	function __construct() {
   109 	function __construct() {
   110 		$this->__SourceMap = new SourceMap();
   110 		$this->__SourceMap = new SourceMap();
   111 		$this->__BC = new BaseConvert('0123456789abcdefghijklmnopqrstuvwxyz');
   111 		$this->__BC = new BaseConvert('0123456789abcdefghijklmnopqrstuvwxyz');
   112 		$this->__delimeter = array(
   112 		$this->__delimeter = array(
   118 		);
   118 		);
   119 	}
   119 	}
   120 
   120 
   121 	/**
   121 	/**
   122 	 * public method
   122 	 * public method
   123          * 	getClean(mixed [, bool]):string
   123  				* 	getClean(mixed [, bool]):string
   124          *      compress JavaScript removing comments and somespaces (on by default)
   124  				*      compress JavaScript removing comments and somespaces (on by default)
   125          * @param	mixed		view example and notes on class comments
   125  				* @param	mixed		view example and notes on class comments
   126 	 */
   126 	 */
   127 	function getClean($jsSource) {
   127 	function getClean($jsSource) {
   128 		return $this->__commonInitMethods($jsSource, false);
   128 		return $this->__commonInitMethods($jsSource, false);
   129 	}
   129 	}
   130 	
   130 	
   131 	/**
   131 	/**
   132 	 * public method
   132 	 * public method
   133          * 	getPacked(mixed):string
   133  				* 	getPacked(mixed):string
   134          *      compress JavaScript replaceing words and removing comments and some spaces
   134  				*      compress JavaScript replaceing words and removing comments and some spaces
   135          * @param	mixed		view example and notes on class comments
   135  				* @param	mixed		view example and notes on class comments
   136 	 */
   136 	 */
   137 	function getPacked($jsSource) {
   137 	function getPacked($jsSource) {
   138 		return $this->__commonInitMethods($jsSource, true);
   138 		return $this->__commonInitMethods($jsSource, true);
   139 	}
   139 	}
   140 	
   140 	
   371 * @LastMOd        2006/08/01
   371 * @LastMOd        2006/08/01
   372 * @Version        0.1
   372 * @Version        0.1
   373 * @Application        Last version of JavaScriptCompressor class use this one to map source code.
   373 * @Application        Last version of JavaScriptCompressor class use this one to map source code.
   374 */
   374 */
   375 class SourceMap {
   375 class SourceMap {
   376     
   376 		
   377     /**
   377 		/**
   378      * public method
   378  		* public method
   379          *     getMap(&$source:string, &$delimeters:array):array
   379  				*     getMap(&$source:string, &$delimeters:array):array
   380      * Maps the source code using $delimeters rules and returns map as an array
   380  		* Maps the source code using $delimeters rules and returns map as an array
   381          * NOTE: read comments to know more about map and delimeter
   381  				* NOTE: read comments to know more about map and delimeter
   382          *
   382  				*
   383          * @param    string        generic source code
   383  				* @param    string        generic source code
   384          * @param    array        array with nested array with code rules
   384  				* @param    array        array with nested array with code rules
   385      */
   385  		*/
   386     function getMap(&$source, &$delimeters) {
   386 		function getMap(&$source, &$delimeters) {
   387         
   387 				
   388         # "unsigned" integer variables
   388 				# "unsigned" integer variables
   389         $sourcePosition = 0;
   389 				$sourcePosition = 0;
   390         $delimetersPosition = 0;
   390 				$delimetersPosition = 0;
   391         $findLength = 0;
   391 				$findLength = 0;
   392         $len = 0;
   392 				$len = 0;
   393         $tempIndex = 0;
   393 				$tempIndex = 0;
   394         $sourceLength = strlen($source);
   394 				$sourceLength = strlen($source);
   395         $delimetersLength = count($delimeters);
   395 				$delimetersLength = count($delimeters);
   396         
   396 				
   397         # integer variables
   397 				# integer variables
   398         $tempPosition = -1;
   398 				$tempPosition = -1;
   399         $endPosition = -1;
   399 				$endPosition = -1;
   400         
   400 				
   401         # array variables
   401 				# array variables
   402         $map = array();
   402 				$map = array();
   403         $tempMap = array();
   403 				$tempMap = array();
   404         $tempDelimeter = array();
   404 				$tempDelimeter = array();
   405         
   405 				
   406         while($sourcePosition < $sourceLength) {
   406 				while($sourcePosition < $sourceLength) {
   407             $endPosition = -1;
   407 						$endPosition = -1;
   408             for($delimetersPosition = 0; $delimetersPosition < $delimetersLength; $delimetersPosition++) {
   408 						for($delimetersPosition = 0; $delimetersPosition < $delimetersLength; $delimetersPosition++) {
   409                 $tempPosition = strpos($source, $delimeters[$delimetersPosition]['start'], $sourcePosition);
   409 								$tempPosition = strpos($source, $delimeters[$delimetersPosition]['start'], $sourcePosition);
   410                 if($tempPosition !== false && ($tempPosition < $endPosition || $endPosition === -1)) {
   410 								if($tempPosition !== false && ($tempPosition < $endPosition || $endPosition === -1)) {
   411                     $endPosition = $tempPosition;
   411 										$endPosition = $tempPosition;
   412                     $tempIndex = $delimetersPosition;
   412 										$tempIndex = $delimetersPosition;
   413                 }
   413 								}
   414             }
   414 						}
   415             if($endPosition !== -1) {
   415 						if($endPosition !== -1) {
   416                 $sourcePosition = $endPosition;
   416 								$sourcePosition = $endPosition;
   417                 $tempDelimeter = &$delimeters[$tempIndex];
   417 								$tempDelimeter = &$delimeters[$tempIndex];
   418                 $findLength = strlen($tempDelimeter['start']);
   418 								$findLength = strlen($tempDelimeter['start']);
   419                 if(is_array($tempDelimeter['end'])) {
   419 								if(is_array($tempDelimeter['end'])) {
   420                     $delimetersPosition = 0;
   420 										$delimetersPosition = 0;
   421                     $endPosition = -1;
   421 										$endPosition = -1;
   422                     for($len = count($tempDelimeter['end']); $delimetersPosition < $len; $delimetersPosition++) {
   422 										for($len = count($tempDelimeter['end']); $delimetersPosition < $len; $delimetersPosition++) {
   423                         $tempPosition = strpos($source, $tempDelimeter['end'][$delimetersPosition], $sourcePosition + $findLength);
   423 												$tempPosition = strpos($source, $tempDelimeter['end'][$delimetersPosition], $sourcePosition + $findLength);
   424                         if($tempPosition !== false && ($tempPosition < $endPosition || $endPosition === -1)) {
   424 												if($tempPosition !== false && ($tempPosition < $endPosition || $endPosition === -1)) {
   425                             $endPosition = $tempPosition;
   425 														$endPosition = $tempPosition;
   426                             $tempIndex = $delimetersPosition;
   426 														$tempIndex = $delimetersPosition;
   427                         }    
   427 												}    
   428                     }
   428 										}
   429                     if($endPosition !== -1)
   429 										if($endPosition !== -1)
   430                         $endPosition = $endPosition + strlen($tempDelimeter['end'][$tempIndex]);
   430 												$endPosition = $endPosition + strlen($tempDelimeter['end'][$tempIndex]);
   431                     else
   431 										else
   432                         $endPosition = $sourceLength;
   432 												$endPosition = $sourceLength;
   433                     array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
   433 										array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
   434                     $sourcePosition = $endPosition - 1;
   434 										$sourcePosition = $endPosition - 1;
   435                 }
   435 								}
   436                 elseif(isset($tempDelimeter['match'])) {
   436 								elseif(isset($tempDelimeter['match'])) {
   437                     $tempPosition = strpos($source, $tempDelimeter['end'], $sourcePosition + $findLength);
   437 										$tempPosition = strpos($source, $tempDelimeter['end'], $sourcePosition + $findLength);
   438                     $len = strlen($tempDelimeter['end']);
   438 										$len = strlen($tempDelimeter['end']);
   439                     if($tempPosition !== false && preg_match($tempDelimeter['match'], substr($source, $sourcePosition, $tempPosition - $sourcePosition + $len))) {
   439 										if($tempPosition !== false && preg_match($tempDelimeter['match'], substr($source, $sourcePosition, $tempPosition - $sourcePosition + $len))) {
   440                         $endPosition = isset($tempDelimeter['noslash']) ? $this->__endCharNoSlash($source, $sourcePosition, $tempDelimeter['end'], $sourceLength) : $tempPosition + $len;
   440 												$endPosition = isset($tempDelimeter['noslash']) ? $this->__endCharNoSlash($source, $sourcePosition, $tempDelimeter['end'], $sourceLength) : $tempPosition + $len;
   441                         array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
   441 												array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
   442                         $sourcePosition = $endPosition - 1;
   442 												$sourcePosition = $endPosition - 1;
   443                     }
   443 										}
   444                 }
   444 								}
   445                 else {
   445 								else {
   446                     if(isset($tempDelimeter['noslash']))
   446 										if(isset($tempDelimeter['noslash']))
   447                         $endPosition = $this->__endCharNoSlash($source, $sourcePosition, $tempDelimeter['end'], $sourceLength);
   447 												$endPosition = $this->__endCharNoSlash($source, $sourcePosition, $tempDelimeter['end'], $sourceLength);
   448                     else {
   448 										else {
   449                         $tempPosition = strpos($source, $tempDelimeter['end'], $sourcePosition + $findLength);
   449 												$tempPosition = strpos($source, $tempDelimeter['end'], $sourcePosition + $findLength);
   450                         if($tempPosition !== false)
   450 												if($tempPosition !== false)
   451                             $endPosition = $tempPosition + strlen($tempDelimeter['end']);
   451 														$endPosition = $tempPosition + strlen($tempDelimeter['end']);
   452                         else
   452 												else
   453                             $endPosition = $sourceLength;
   453 														$endPosition = $sourceLength;
   454                     }
   454 										}
   455                     array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
   455 										array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
   456                     $sourcePosition = $endPosition - 1;
   456 										$sourcePosition = $endPosition - 1;
   457                 }
   457 								}
   458             }
   458 						}
   459             else
   459 						else
   460                 $sourcePosition = $sourceLength - 1;
   460 								$sourcePosition = $sourceLength - 1;
   461             ++$sourcePosition;
   461 						++$sourcePosition;
   462         }
   462 				}
   463         $len = count($map);
   463 				$len = count($map);
   464         if($len === 0)
   464 				if($len === 0)
   465             array_push($tempMap, array('name'=>'code', 'start'=>0, 'end'=>$sourceLength));
   465 						array_push($tempMap, array('name'=>'code', 'start'=>0, 'end'=>$sourceLength));
   466         else {
   466 				else {
   467             for($tempIndex = 0; $tempIndex < $len; $tempIndex++) {
   467 						for($tempIndex = 0; $tempIndex < $len; $tempIndex++) {
   468                 if($tempIndex === 0 && $map[$tempIndex]['start'] > 0)
   468 								if($tempIndex === 0 && $map[$tempIndex]['start'] > 0)
   469                     array_push($tempMap, array('name'=>'code', 'start'=>0, 'end'=>$map[$tempIndex]['start']));
   469 										array_push($tempMap, array('name'=>'code', 'start'=>0, 'end'=>$map[$tempIndex]['start']));
   470                 elseif($tempIndex > 0 && $map[$tempIndex]['start'] > $map[$tempIndex-1]['end'])
   470 								elseif($tempIndex > 0 && $map[$tempIndex]['start'] > $map[$tempIndex-1]['end'])
   471                     array_push($tempMap, array('name'=>'code', 'start'=>$map[$tempIndex-1]['end'], 'end'=>$map[$tempIndex]['start']));
   471 										array_push($tempMap, array('name'=>'code', 'start'=>$map[$tempIndex-1]['end'], 'end'=>$map[$tempIndex]['start']));
   472                 array_push($tempMap, array('name'=>$map[$tempIndex]['name'], 'start'=>$map[$tempIndex]['start'], 'end'=>$map[$tempIndex]['end']));
   472 								array_push($tempMap, array('name'=>$map[$tempIndex]['name'], 'start'=>$map[$tempIndex]['start'], 'end'=>$map[$tempIndex]['end']));
   473                 if($tempIndex + 1 === $len && $map[$tempIndex]['end'] < $sourceLength)
   473 								if($tempIndex + 1 === $len && $map[$tempIndex]['end'] < $sourceLength)
   474                     array_push($tempMap, array('name'=>'code', 'start'=>$map[$tempIndex]['end'], 'end'=>$sourceLength));
   474 										array_push($tempMap, array('name'=>'code', 'start'=>$map[$tempIndex]['end'], 'end'=>$sourceLength));
   475             }
   475 						}
   476         }
   476 				}
   477         return $tempMap;
   477 				return $tempMap;
   478     }
   478 		}
   479     
   479 		
   480     function __endCharNoSlash(&$source, $position, &$find, &$len) {
   480 		function __endCharNoSlash(&$source, $position, &$find, &$len) {
   481         $temp = strlen($find);
   481 				$temp = strlen($find);
   482         do {
   482 				do {
   483             $position = strpos($source, $find, $position + 1);
   483 						$position = strpos($source, $find, $position + 1);
   484         }while($position !== false && !$this->__charNoSlash($source, $position));
   484 				}while($position !== false && !$this->__charNoSlash($source, $position));
   485         if($position === false) $position = $len - $temp;
   485 				if($position === false) $position = $len - $temp;
   486         return $position + $temp;
   486 				return $position + $temp;
   487     }
   487 		}
   488     
   488 		
   489     function __charNoSlash(&$source, &$position) {
   489 		function __charNoSlash(&$source, &$position) {
   490         $next = 1; $len = $position - $next;
   490 				$next = 1; $len = $position - $next;
   491         while($len > 0 && $source{$len} === '\\') $len = $position - (++$next);
   491 				while($len > 0 && $source{$len} === '\\') $len = $position - (++$next);
   492         return (($next - 1) % 2 === 0);
   492 				return (($next - 1) % 2 === 0);
   493     }
   493 		}
   494 }
   494 }
   495 
   495 
   496 /**
   496 /**
   497  * Wrapper for the JavaScriptCompressor class.
   497  * Wrapper for the JavaScriptCompressor class.
   498  * @param string Javascript code to compact. If this doesn't contain any newline characters, will be treated as a filename.
   498  * @param string Javascript code to compact. If this doesn't contain any newline characters, will be treated as a filename.
   500  * @return string Compressed JS
   500  * @return string Compressed JS
   501  */
   501  */
   502 
   502 
   503 function perform_js_compress($text_or_file, $aggressive = false)
   503 function perform_js_compress($text_or_file, $aggressive = false)
   504 {
   504 {
   505   static $compressor = false;
   505 	static $compressor = false;
   506   
   506 	
   507   if ( !is_object($compressor) )
   507 	if ( !is_object($compressor) )
   508     $compressor = new JavaScriptCompressor();
   508 		$compressor = new JavaScriptCompressor();
   509   
   509 	
   510   if ( strpos($text_or_file, "\n") )
   510 	if ( strpos($text_or_file, "\n") )
   511   {
   511 	{
   512     $text =& $text_or_file;
   512 		$text =& $text_or_file;
   513   }
   513 	}
   514   else if ( file_exists($text_or_file) )
   514 	else if ( file_exists($text_or_file) )
   515   {
   515 	{
   516     $text = file_get_contents($text_or_file);
   516 		$text = file_get_contents($text_or_file);
   517   }
   517 	}
   518   else
   518 	else
   519   {
   519 	{
   520     $text =& $text_or_file;
   520 		$text =& $text_or_file;
   521   }
   521 	}
   522   
   522 	
   523   return ( $aggressive ) ? $compressor->getPacked($text) : $compressor->getClean($text);
   523 	return ( $aggressive ) ? $compressor->getPacked($text) : $compressor->getClean($text);
   524 }
   524 }
   525 
   525 
   526 ?>
   526 ?>