Sid Gifari File Manager
🏠 Root
/
home2
/
iuywvcmy
/
public_html
/
wp-content
/
plugins
/
beaver-builder-lite-version
/
classes
/
Editing: class-fl-jsmin.php
<?php // @codingStandardsIgnoreFile /* * This file is part of the JShrink package. * * (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. */ /** * JShrink * * * @package JShrink * @author Robert Hafner <tedivm@tedivm.com> */ class FLJSMin { /** * The input javascript to be minified. * * @var string */ protected $input; /** * Length of input javascript. * * @var int */ protected $len = 0; /** * 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; /** * This character is only active when certain look ahead actions take place. * * @var string */ protected $last_char; /** * This character is only active when certain look ahead actions take place. * * @var string */ protected $output; /** * Contains the options for the current minification process. * * @var array */ protected $options; /** * These characters are used to define strings. */ protected $stringDelimiters = [ '\'' => true, '"' => true, '`' => true, ]; /** * 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 = [ 'flaggedComments' => true ]; protected static $keywords = [ 'delete', 'do', 'for', 'in', 'instanceof', 'return', 'typeof', 'yield' ]; protected $max_keyword_len; /** * Contains lock ids which are used to replace certain code patterns and * prevent them from being minified * * @var array */ protected $locks = []; /** * 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 = [] ) { try { $jshrink = new FLJSMin(); $js = $jshrink->lock( $js ); $js = ltrim( $jshrink->minifyToString( $js, $options ) ); $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 ); } 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 */ protected function minifyToString( $js, $options ) { $this->initialize( $js, $options ); $this->loop(); $this->clean(); return $this->output; } /** * 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 */ protected function initialize( $js, $options ) { $this->options = array_merge( static::$defaultOptions, $options ); $this->input = $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; // save input length to skip calculation every time $this->len = strlen( $this->input ); // Populate "a" with a new line, "b" with the first character, before // entering the loop $this->a = "\n"; $this->b = "\n"; $this->last_char = "\n"; $this->output = ''; $this->max_keyword_len = max( array_map( 'strlen', static::$keywords ) ); } /** * Characters that can't stand alone preserve the newline. * * @var array */ protected $noNewLineCharacters = [ '(' => true, '-' => true, '+' => true, '[' => true, '#' => true, '@' => true, ]; protected function echo( $char ) { $this->output .= $char; $this->last_char = $char[-1]; } /** * The primary action occurs here. This function loops through the input string, * outputting anything that's relevant and discarding anything that is not. */ protected function loop() { while ( $this->a !== false && ! is_null( $this->a ) && $this->a !== '' ) { switch ( $this->a ) { // new lines case "\r": case "\n": // if the next line is something that can't stand alone preserve the newline if ( $this->b !== false && isset( $this->noNewLineCharacters[ $this->b ] ) ) { $this->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 // no break case ' ': if ( static::isAlphaNumeric( $this->b ) ) { $this->echo( $this->a ); } $this->saveString(); break; default: switch ( $this->b ) { case "\r": case "\n": if ( strpos( '}])+-"\'', $this->a ) !== false ) { $this->echo( $this->a ); $this->saveString(); break; } else { if ( static::isAlphaNumeric( $this->a ) ) { $this->echo( $this->a ); $this->saveString(); } } break; case ' ': if ( ! static::isAlphaNumeric( $this->a ) ) { break; } // no break default: // check for some regex that breaks stuff if ( $this->a === '/' && ( $this->b === '\'' || $this->b === '"' ) ) { $this->saveRegex(); continue 3; } $this->echo( $this->a ); $this->saveString(); break; } } // do reg check of doom $this->b = $this->getReal(); if ( $this->b == '/' ) { $valid_tokens = "(,=:[!&|?\n"; # Find last "real" token, excluding spaces. $last_token = $this->a; if ( $last_token == ' ' ) { $last_token = $this->last_char; } if ( $last_token && strpos( $valid_tokens, $last_token ) !== false ) { // Regex can appear unquoted after these symbols $this->saveRegex(); } elseif ( $this->endsInKeyword() ) { // This block checks for the "return" token before the slash. $this->saveRegex(); } } // 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. */ protected function clean() { unset( $this->input ); $this->len = 0; $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 ); } else { // Otherwise we start pulling from the input. $char = $this->index < $this->len ? $this->input[ $this->index ] : false; // 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++; } # Convert all line endings to unix standard. # `\r\n` converts to `\n\n` and is minified. if ( $char == "\r" ) { $char = "\n"; } // Normalize all whitespace except for the newline character into a // standard space. if ( $char !== "\n" && $char < "\x20" ) { return ' '; } return $char; } /** * This function returns the next character without moving the index forward. * * * @return string The next character * @throws \RuntimeException */ protected function peek() { if ( $this->index >= $this->len ) { return false; } $char = $this->input[ $this->index ]; # Convert all line endings to unix standard. # `\r\n` converts to `\n\n` and is minified. if ( $char == "\r" ) { $char = "\n"; } // Normalize all whitespace except for the newline character into a // standard space. if ( $char !== "\n" && $char < "\x20" ) { return ' '; } # Return the next character but don't push the index. 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 === '/' ) { $this->processOneLineComments( $startIndex ); return $this->getReal(); } elseif ( $this->c === '*' ) { $this->processMultiLineComments( $startIndex ); return $this->getReal(); } 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 void */ protected function processOneLineComments( $startIndex ) { $thirdCommentString = $this->index < $this->len ? $this->input[ $this->index ] : false; // kill rest of line $this->getNext( "\n" ); unset( $this->c ); if ( $thirdCommentString == '@' ) { $endPoint = $this->index - $startIndex; $this->c = "\n" . substr( $this->input, $startIndex, $endPoint ); } } /** * 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 void * @throws \RuntimeException Unclosed comments will throw an error */ protected function processMultiLineComments( $startIndex ) { $this->getChar(); // current C $thirdCommentString = $this->getChar(); // Detect a completely empty comment, ie `/**/` if ( $thirdCommentString == '*' ) { $peekChar = $this->peek(); if ( $peekChar == '/' ) { $this->index++; return; } } // kill everything up to the next */ if it's there if ( $this->getNext( '*/' ) ) { $this->getChar(); // get * $this->getChar(); // get / $char = $this->getChar(); // get next real character // 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 ) { $this->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" ) { $this->echo( "\n" ); } } $endPoint = ( $this->index - 1 ) - $startIndex; $this->echo( substr( $this->input, $startIndex, $endPoint ) ); $this->c = $char; return; } } 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 $this->c = $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 * @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 $this->index < $this->len ? $this->input[ $this->index ] : false; } /** * 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 */ 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 ( ! isset( $this->stringDelimiters[ $this->a ] ) ) { return; } // String type is the quote used, " or ' $stringType = $this->a; // Echo out that starting quote $this->echo( $this->a ); // Loop until the string is done // Grab the very next character and load it into a while ( ( $this->a = $this->getChar() ) !== false ) { 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": if ( $stringType === '`' ) { $this->echo( $this->a ); } else { 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. $this->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: $this->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 */ protected function saveRegex() { if ( $this->a != ' ' ) { $this->echo( $this->a ); } $this->echo( $this->b ); while ( ( $this->a = $this->getChar() ) !== false ) { if ( $this->a === '/' ) { break; } if ( $this->a === '\\' ) { $this->echo( $this->a ); $this->a = $this->getChar(); } if ( $this->a === "\n" ) { throw new \RuntimeException( 'Unclosed regex pattern at position: ' . $this->index ); } $this->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\$\pL]$/', $char ) === 1 || $char == '/'; } protected function endsInKeyword() { # When this function is called A is not yet assigned to output. # Regular expression only needs to check final part of output for keyword. $testOutput = substr( $this->output . $this->a, -1 * ( $this->max_keyword_len + 10 ) ); foreach ( static::$keywords as $keyword ) { if ( preg_match( '/[^\w]' . $keyword . '[ ]?$/i', $testOutput ) === 1 ) { return true; } } return false; } /** * 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 = []; preg_match( '/([+-])(\s+)([+-])/S', $js, $matches ); if ( empty( $matches ) ) { return $js; } $this->locks[ $lock ] = $matches[2]; $js = preg_replace( '/([+-])\s+([+-])/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 ( empty( $this->locks ) ) { return $js; } foreach ( $this->locks as $lock => $replacement ) { $js = str_replace( $lock, $replacement, $js ); } return $js; } }
Save
Cancel