%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home1/lightco1/luminero.com.au/libraries/compojoom/minifier/
Upload File :
Create Path :
Current File : //home1/lightco1/luminero.com.au/libraries/compojoom/minifier/minifier.php

<?php
/**
 * @package    Lib_Compojoom
 * @author     DanielDimitrov <daniel@compojoom.com>
 * @date       20.08.14
 *
 * @copyright  Copyright (C) 2008 - 2013 compojoom.com . All rights reserved.
 * @license    GNU General Public License version 2 or later; see LICENSE
 */

defined('_JEXEC') or die('Restricted access');

/**
 * This file is part of the JShrink package.
 *
 * @link     https://github.com/tedious/JShrink
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
 *
 * (c) Robert Hafner <tedivm@tedivm.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * Copyright (c) 2009, Robert Hafner
 * All rights reserved.
 *
 * 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.
 *       * Neither the name of the Stash Project nor the
 *           names of its contributors may be used to endorse or promote products
 *           derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 Robert Hafner 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.
 */

/**
 * JShrink
 *
 *
 * @package    JShrink
 * @author     Robert Hafner <tedivm@tedivm.com>
 */

/**
 * This is the original Minifier class. I've renamed it to CompojoomMinifier in order for it
 * to be autoloaded with our library. Other than that all functions from jshrink are the same
 *
 * Usage - CompojoomMinifier::minify($js);
 * Usage - CompojoomMinifier::minify($js, $options);
 * Usage - CompojoomMinifier::minify($js, array('flaggedComments' => false));
 *
 * @since  4.0
 */
class CompojoomMinifier
{
	/**
	 * The input javascript to be minified.
	 *
	 * @var string
	 */
	protected $input;

	/**
	 * The location of the character (in the input string) that is next to be
	 * processed.
	 *
	 * @var int
	 */
	protected $index = 0;

	/**
	 * The first of the characters currently being looked at.
	 *
	 * @var string
	 */
	protected $a = '';

	/**
	 * The next character being looked at (after a);
	 *
	 * @var string
	 */
	protected $b = '';

	/**
	 * This character is only active when certain look ahead actions take place.
	 *
	 * @var string
	 */
	protected $c;

	/**
	 * Contains the options for the current minification process.
	 *
	 * @var array
	 */
	protected $options;

	/**
	 * Contains the default options for minification. This array is merged with
	 * the one passed in by the user to create the request specific set of
	 * options (stored in the $options attribute).
	 *
	 * @var array
	 */
	protected static $defaultOptions = array('flaggedComments' => true);

	/**
	 * Contains lock ids which are used to replace certain code patterns and
	 * prevent them from being minified
	 *
	 * @var array
	 */
	protected $locks = array();

	/**
	 * Takes a string containing javascript and removes unneeded characters in
	 * order to shrink the code without altering it's functionality.
	 *
	 * @param   string  $js       The raw javascript to be minified
	 * @param   array   $options  Various runtime options in an associative array
	 *
	 * @throws \Exception
	 * @return bool|string
	 */
	public static function minify($js, $options = array())
	{
		try
		{
			ob_start();

			$jshrink = new CompojoomMinifier;
			$js = $jshrink->lock($js);
			$jshrink->minifyDirectToOutput($js, $options);

			// Sometimes there's a leading new line, so we trim that out here.
			$js = ltrim(ob_get_clean());
			$js = $jshrink->unlock($js);
			unset($jshrink);

			return $js;
		}
		catch (\Exception $e)
		{

			if (isset($jshrink))
			{
				// Since the breakdownScript function probably wasn't finished
				// we clean it out before discarding it.
				$jshrink->clean();
				unset($jshrink);
			}

			// Without this call things get weird, with partially outputted js.
			ob_end_clean();
			throw $e;
		}
	}

	/**
	 * Processes a javascript string and outputs only the required characters,
	 * stripping out all unneeded characters.
	 *
	 * @param   string  $js       The raw javascript to be minified
	 * @param   array   $options  Various runtime options in an associative array
	 *
	 * @return void
	 */
	protected function minifyDirectToOutput($js, $options)
	{
		$this->initialize($js, $options);
		$this->loop();
		$this->clean();
	}

	/**
	 *  Initializes internal variables, normalizes new lines,
	 *
	 * @param   string  $js       The raw javascript to be minified
	 * @param   array   $options  Various runtime options in an associative array
	 *
	 * @return void
	 */
	protected function initialize($js, $options)
	{
		$this->options = array_merge(static::$defaultOptions, $options);
		$js = str_replace("\r\n", "\n", $js);
		$this->input = str_replace("\r", "\n", $js);

		/**
		 * We add a newline to the end of the script to make it easier to deal
		 * with comments at the bottom of the script- this prevents the unclosed
		 * comment error that can otherwise occur.
		 */
		$this->input .= PHP_EOL;

		// Populate "a" with a new line, "b" with the first character, before entering the loop
		$this->a = "\n";
		$this->b = $this->getReal();
	}

	/**
	 * The primary action occurs here. This function loops through the input string,
	 * outputting anything that's relevant and discarding anything that is not.
	 *
	 * @return void
	 */
	protected function loop()
	{
		while ($this->a !== false && !is_null($this->a) && $this->a !== '')
		{
			switch ($this->a)
			{
				// New lines
				case "\n":
					// If the next line is something that can't stand alone preserve the newline
					if (strpos('(-+{[@', $this->b) !== false)
					{
						echo $this->a;
						$this->saveString();
						break;
					}

					// If B is a space we skip the rest of the switch block and go down to the
					// String/regex check below, resetting $this->b with getReal
					if ($this->b === ' ')
					{
						break;
					}

				// Otherwise we treat the newline like a space
				case ' ':
					if (static::isAlphaNumeric($this->b))
					{
						echo $this->a;
					}

					$this->saveString();
					break;

				default:
					switch ($this->b)
					{
						case "\n":
							if (strpos('}])+-"\'', $this->a) !== false)
							{
								echo $this->a;
								$this->saveString();
								break;
							}
							else
							{
								if (static::isAlphaNumeric($this->a))
								{
									echo $this->a;
									$this->saveString();
								}
							}
							break;

						case ' ':
							if (!static::isAlphaNumeric($this->a))
							{
								break;
							}

						default:
							// Check for some regex that breaks stuff
							if ($this->a == '/' && ($this->b == '\'' || $this->b == '"'))
							{
								$this->saveRegex();
								continue;
							}

							echo $this->a;
							$this->saveString();
							break;
					}
			}

			// Do reg check of doom
			$this->b = $this->getReal();

			if (($this->b == '/' && strpos('(,=:[!&|?', $this->a) !== false))
			{
				$this->saveRegex();
			}
		}
	}

	/**
	 * Resets attributes that do not need to be stored between requests so that
	 * the next request is ready to go. Another reason for this is to make sure
	 * the variables are cleared and are not taking up memory.
	 *
	 * @return void
	 */
	protected function clean()
	{
		unset($this->input);
		$this->index = 0;
		$this->a = $this->b = '';
		unset($this->c);
		unset($this->options);
	}

	/**
	 * Returns the next string for processing based off of the current index.
	 *
	 * @return string
	 */
	protected function getChar()
	{
		// Check to see if we had anything in the look ahead buffer and use that.
		if (isset($this->c))
		{
			$char = $this->c;
			unset($this->c);

			// Otherwise we start pulling from the input.
		}
		else
		{
			$char = substr($this->input, $this->index, 1);

			// If the next character doesn't exist return false.
			if (isset($char) && $char === false)
			{
				return false;
			}

			// Otherwise increment the pointer and use this char.
			$this->index++;
		}

		// Normalize all whitespace except for the newline character into a standard space.
		if ($char !== "\n" && ord($char) < 32)
		{
			return ' ';
		}

		return $char;
	}

	/**
	 * This function gets the next "real" character. It is essentially a wrapper
	 * around the getChar function that skips comments. This has significant
	 * performance benefits as the skipping is done using native functions (ie,
	 * c code) rather than in script php.
	 *
	 * @return   string   Next 'real' character to be processed.
	 *
	 * @throws   \RuntimeException
	 */
	protected function getReal()
	{
		$startIndex = $this->index;
		$char = $this->getChar();

		// Check to see if we're potentially in a comment
		if ($char !== '/')
		{
			return $char;
		}

		$this->c = $this->getChar();

		if ($this->c == '/')
		{
			return $this->processOneLineComments($startIndex);
		}
		elseif ($this->c == '*')
		{
			return $this->processMultiLineComments($startIndex);
		}

		return $char;
	}

	/**
	 * Removed one line comments, with the exception of some very specific types of
	 * conditional comments.
	 *
	 * @param   int  $startIndex  The index point where "getReal" function started
	 *
	 * @return string
	 */
	protected function processOneLineComments($startIndex)
	{
		$thirdCommentString = substr($this->input, $this->index, 1);

		// Kill rest of line
		$this->getNext("\n");

		if ($thirdCommentString == '@')
		{
			$endPoint = ($this->index) - $startIndex;
			unset($this->c);
			$char = "\n" . substr($this->input, $startIndex, $endPoint);
		}
		else
		{
			// First one is contents of $this->c
			$this->getChar();
			$char = $this->getChar();
		}

		return $char;
	}

	/**
	 * Skips multiline comments where appropriate, and includes them where needed.
	 * Conditional comments and "license" style blocks are preserved.
	 *
	 * @param   int  $startIndex  The index point where "getReal" function started
	 *
	 * @return bool|string       False if there's no character#
	 *
	 * @throws \RuntimeException Unclosed comments will throw an error
	 */
	protected function processMultiLineComments($startIndex)
	{
		// Current C
		$this->getChar();
		$thirdCommentString = $this->getChar();

		// Kill everything up to the next */ if it's there
		if ($this->getNext('*/'))
		{
			// Get *
			$this->getChar();

			// Get /
			$this->getChar();

			// Get next real character
			$char = $this->getChar();

			// Now we reinsert conditional comments and YUI-style licensing comments
			if (($this->options['flaggedComments'] && $thirdCommentString == '!')
				|| ($thirdCommentString == '@'))
			{
				// If conditional comments or flagged comments are not the first thing in the script
				// we need to echo a and fill it with a space before moving on.
				if ($startIndex > 0)
				{
					echo $this->a;
					$this->a = " ";

					// If the comment started on a new line we let it stay on the new line
					if ($this->input[($startIndex - 1)] == "\n")
					{
						echo "\n";
					}
				}

				$endPoint = ($this->index - 1) - $startIndex;
				echo substr($this->input, $startIndex, $endPoint);

				return $char;
			}
		}
		else
		{
			$char = false;
		}

		if ($char === false)
		{
			throw new \RuntimeException('Unclosed multiline comment at position: ' . ($this->index - 2));
		}

		// If we're here c is part of the comment and therefore tossed
		if (isset($this->c))
		{
			unset($this->c);
		}

		return $char;
	}

	/**
	 * Pushes the index ahead to the next instance of the supplied string. If it
	 * is found the first character of the string is returned and the index is set
	 * to it's position.
	 *
	 * @param   string  $string  - the string
	 *
	 * @return string|false Returns the first character of the string or false.
	 */
	protected function getNext($string)
	{
		// Find the next occurrence of "string" after the current position.
		$pos = strpos($this->input, $string, $this->index);

		// If it's not there return false.
		if ($pos === false)
		{
			return false;
		}

		// Adjust position of index to jump ahead to the asked for string
		$this->index = $pos;

		// Return the first character of that string.
		return substr($this->input, $this->index, 1);
	}

	/**
	 * When a javascript string is detected this function crawls for the end of
	 * it and saves the whole string.
	 *
	 * @throws \RuntimeException Unclosed strings will throw an error
	 *
	 * @return void
	 */
	protected function saveString()
	{
		$startpos = $this->index;

		// SaveString is always called after a gets cleared, so we push b into that spot.
		$this->a = $this->b;

		// If this isn't a string we don't need to do anything.
		if ($this->a != "'" && $this->a != '"')
		{
			return;
		}

		// String type is the quote used, " or '
		$stringType = $this->a;

		// Echo out that starting quote
		echo $this->a;

		// Loop until the string is done
		while (1)
		{
			// Grab the very next character and load it into a
			$this->a = $this->getChar();

			switch ($this->a)
			{
				/**
				 * If the string opener (single or double quote) is used
				 * output it and break out of the while loop-
				 * The string is finished!
				 */
				case $stringType:
					break 2;

				/**
				 * New lines in strings without line delimiters are bad- actual
				 * new lines will be represented by the string \n and not the actual
				 * character, so those will be treated just fine using the switch
				 * block below.
				 */
				case "\n":
					throw new \RuntimeException('Unclosed string at position: ' . $startpos);
					break;

				// Escaped characters get picked up here. If it's an escaped new line it's not really needed
				case '\\':
					/**
					 * a is a slash. We want to keep it, and the next character,
					 * unless it's a new line. New lines as actual strings will be
					 * preserved, but escaped new lines should be reduced.
					 */
					$this->b = $this->getChar();

					// If b is a new line we discard a and b and restart the loop.
					if ($this->b == "\n")
					{
						break;
					}

					// Echo out the escaped character and restart the loop.
					echo $this->a . $this->b;
					break;

				// Since we're not dealing with any special cases we simply
				// output the character and continue our loop.
				default:
					echo $this->a;
			}
		}
	}

	/**
	 * When a regular expression is detected this function crawls for the end of
	 * it and saves the whole regex.
	 *
	 * @throws \RuntimeException Unclosed regex will throw an error
	 *
	 * @return void
	 */
	protected function saveRegex()
	{
		echo $this->a . $this->b;

		while (($this->a = $this->getChar()) !== false)
		{
			if ($this->a == '/')
			{
				break;
			}

			if ($this->a == '\\')
			{
				echo $this->a;
				$this->a = $this->getChar();
			}

			if ($this->a == "\n")
			{
				throw new \RuntimeException('Unclosed regex pattern at position: ' . $this->index);
			}

			echo $this->a;
		}

		$this->b = $this->getReal();
	}

	/**
	 * Checks to see if a character is alphanumeric.
	 *
	 * @param   string  $char  Just one character
	 *
	 * @return bool
	 */
	protected static function isAlphaNumeric($char)
	{
		return preg_match('/^[\w\$]$/', $char) === 1 || $char == '/';
	}

	/**
	 * Replace patterns in the given string and store the replacement
	 *
	 * @param   string  $js  The string to lock
	 *
	 * @return bool
	 */
	protected function lock($js)
	{
		/* lock things like <code>"asd" + ++x;</code> */
		$lock = '"LOCK---' . crc32(time()) . '"';

		$matches = array();
		preg_match('/([+-])(\s+)([+-])/', $js, $matches);

		if (empty($matches))
		{
			return $js;
		}

		$this->locks[$lock] = $matches[2];

		$js = preg_replace('/([+-])\s+([+-])/', "$1{$lock}$2", $js);
		/* -- */

		return $js;
	}

	/**
	 * Replace "locks" with the original characters
	 *
	 * @param   string  $js  The string to unlock
	 *
	 * @return bool
	 */
	protected function unlock($js)
	{
		if (!count($this->locks))
		{
			return $js;
		}

		foreach ($this->locks as $lock => $replacement)
		{
			$js = str_replace($lock, $replacement, $js);
		}

		return $js;
	}
}

Zerion Mini Shell 1.0