initial commit

This commit is contained in:
2024-04-29 13:12:44 +05:45
commit 34887303c5
19300 changed files with 5268802 additions and 0 deletions

View File

@ -0,0 +1,156 @@
<?php
namespace LiteSpeed\Lib\CSS_MIN ;
defined( 'WPINC' ) || exit ;
class Colors
{
public static function getHexToNamedMap()
{
// Hex colors longer than named counterpart
return array(
'#f0ffff' => 'azure',
'#f5f5dc' => 'beige',
'#ffe4c4' => 'bisque',
'#a52a2a' => 'brown',
'#ff7f50' => 'coral',
'#ffd700' => 'gold',
'#808080' => 'gray',
'#008000' => 'green',
'#4b0082' => 'indigo',
'#fffff0' => 'ivory',
'#f0e68c' => 'khaki',
'#faf0e6' => 'linen',
'#800000' => 'maroon',
'#000080' => 'navy',
'#fdf5e6' => 'oldlace',
'#808000' => 'olive',
'#ffa500' => 'orange',
'#da70d6' => 'orchid',
'#cd853f' => 'peru',
'#ffc0cb' => 'pink',
'#dda0dd' => 'plum',
'#800080' => 'purple',
'#f00' => 'red',
'#fa8072' => 'salmon',
'#a0522d' => 'sienna',
'#c0c0c0' => 'silver',
'#fffafa' => 'snow',
'#d2b48c' => 'tan',
'#008080' => 'teal',
'#ff6347' => 'tomato',
'#ee82ee' => 'violet',
'#f5deb3' => 'wheat'
);
}
public static function getNamedToHexMap()
{
// Named colors longer than hex counterpart
return array(
'aliceblue' => '#f0f8ff',
'antiquewhite' => '#faebd7',
'aquamarine' => '#7fffd4',
'black' => '#000',
'blanchedalmond' => '#ffebcd',
'blueviolet' => '#8a2be2',
'burlywood' => '#deb887',
'cadetblue' => '#5f9ea0',
'chartreuse' => '#7fff00',
'chocolate' => '#d2691e',
'cornflowerblue' => '#6495ed',
'cornsilk' => '#fff8dc',
'darkblue' => '#00008b',
'darkcyan' => '#008b8b',
'darkgoldenrod' => '#b8860b',
'darkgray' => '#a9a9a9',
'darkgreen' => '#006400',
'darkgrey' => '#a9a9a9',
'darkkhaki' => '#bdb76b',
'darkmagenta' => '#8b008b',
'darkolivegreen' => '#556b2f',
'darkorange' => '#ff8c00',
'darkorchid' => '#9932cc',
'darksalmon' => '#e9967a',
'darkseagreen' => '#8fbc8f',
'darkslateblue' => '#483d8b',
'darkslategray' => '#2f4f4f',
'darkslategrey' => '#2f4f4f',
'darkturquoise' => '#00ced1',
'darkviolet' => '#9400d3',
'deeppink' => '#ff1493',
'deepskyblue' => '#00bfff',
'dodgerblue' => '#1e90ff',
'firebrick' => '#b22222',
'floralwhite' => '#fffaf0',
'forestgreen' => '#228b22',
'fuchsia' => '#f0f',
'gainsboro' => '#dcdcdc',
'ghostwhite' => '#f8f8ff',
'goldenrod' => '#daa520',
'greenyellow' => '#adff2f',
'honeydew' => '#f0fff0',
'indianred' => '#cd5c5c',
'lavender' => '#e6e6fa',
'lavenderblush' => '#fff0f5',
'lawngreen' => '#7cfc00',
'lemonchiffon' => '#fffacd',
'lightblue' => '#add8e6',
'lightcoral' => '#f08080',
'lightcyan' => '#e0ffff',
'lightgoldenrodyellow' => '#fafad2',
'lightgray' => '#d3d3d3',
'lightgreen' => '#90ee90',
'lightgrey' => '#d3d3d3',
'lightpink' => '#ffb6c1',
'lightsalmon' => '#ffa07a',
'lightseagreen' => '#20b2aa',
'lightskyblue' => '#87cefa',
'lightslategray' => '#778899',
'lightslategrey' => '#778899',
'lightsteelblue' => '#b0c4de',
'lightyellow' => '#ffffe0',
'limegreen' => '#32cd32',
'mediumaquamarine' => '#66cdaa',
'mediumblue' => '#0000cd',
'mediumorchid' => '#ba55d3',
'mediumpurple' => '#9370db',
'mediumseagreen' => '#3cb371',
'mediumslateblue' => '#7b68ee',
'mediumspringgreen' => '#00fa9a',
'mediumturquoise' => '#48d1cc',
'mediumvioletred' => '#c71585',
'midnightblue' => '#191970',
'mintcream' => '#f5fffa',
'mistyrose' => '#ffe4e1',
'moccasin' => '#ffe4b5',
'navajowhite' => '#ffdead',
'olivedrab' => '#6b8e23',
'orangered' => '#ff4500',
'palegoldenrod' => '#eee8aa',
'palegreen' => '#98fb98',
'paleturquoise' => '#afeeee',
'palevioletred' => '#db7093',
'papayawhip' => '#ffefd5',
'peachpuff' => '#ffdab9',
'powderblue' => '#b0e0e6',
'rebeccapurple' => '#663399',
'rosybrown' => '#bc8f8f',
'royalblue' => '#4169e1',
'saddlebrown' => '#8b4513',
'sandybrown' => '#f4a460',
'seagreen' => '#2e8b57',
'seashell' => '#fff5ee',
'slateblue' => '#6a5acd',
'slategray' => '#708090',
'slategrey' => '#708090',
'springgreen' => '#00ff7f',
'steelblue' => '#4682b4',
'turquoise' => '#40e0d0',
'white' => '#fff',
'whitesmoke' => '#f5f5f5',
'yellow' => '#ff0',
'yellowgreen' => '#9acd32'
);
}
}

View File

@ -0,0 +1,866 @@
<?php
/*!
* CssMin
* Author: Tubal Martin - http://tubalmartin.me/
* Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
*
* This is a PHP port of the CSS minification tool distributed with YUICompressor,
* itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
* Permission is hereby granted to use the PHP version under the same
* conditions as the YUICompressor.
*/
/*!
* YUI Compressor
* http://developer.yahoo.com/yui/compressor/
* Author: Julien Lecomte - http://www.julienlecomte.net/
* Copyright (c) 2013 Yahoo! Inc. All rights reserved.
* The copyrights embodied in the content of this file are licensed
* by Yahoo! Inc. under the BSD (revised) open source license.
*/
namespace LiteSpeed\Lib\CSS_MIN ;
defined( 'WPINC' ) || exit ;
class Minifier
{
const QUERY_FRACTION = '_CSSMIN_QF_';
const COMMENT_TOKEN = '_CSSMIN_CMT_%d_';
const COMMENT_TOKEN_START = '_CSSMIN_CMT_';
const RULE_BODY_TOKEN = '_CSSMIN_RBT_%d_';
const PRESERVED_TOKEN = '_CSSMIN_PTK_%d_';
// Token lists
private $comments = array();
private $ruleBodies = array();
private $preservedTokens = array();
// Output options
private $keepImportantComments = true;
private $keepSourceMapComment = false;
private $linebreakPosition = 0;
// PHP ini limits
private $raisePhpLimits;
private $memoryLimit;
private $maxExecutionTime = 60; // 1 min
private $pcreBacktrackLimit;
private $pcreRecursionLimit;
// Color maps
private $hexToNamedColorsMap;
private $namedToHexColorsMap;
// Regexes
private $numRegex;
private $charsetRegex = '/@charset [^;]+;/Si';
private $importRegex = '/@import [^;]+;/Si';
private $namespaceRegex = '/@namespace [^;]+;/Si';
private $namedToHexColorsRegex;
private $shortenOneZeroesRegex;
private $shortenTwoZeroesRegex;
private $shortenThreeZeroesRegex;
private $shortenFourZeroesRegex;
private $unitsGroupRegex = '(?:ch|cm|em|ex|gd|in|mm|px|pt|pc|q|rem|vh|vmax|vmin|vw|%)';
/**
* @param bool|int $raisePhpLimits If true, PHP settings will be raised if needed
*/
public function __construct($raisePhpLimits = true)
{
$this->raisePhpLimits = (bool) $raisePhpLimits;
$this->memoryLimit = 128 * 1048576; // 128MB in bytes
$this->pcreBacktrackLimit = 1000 * 1000;
$this->pcreRecursionLimit = 500 * 1000;
$this->hexToNamedColorsMap = Colors::getHexToNamedMap();
$this->namedToHexColorsMap = Colors::getNamedToHexMap();
$this->namedToHexColorsRegex = sprintf(
'/([:,( ])(%s)( |,|\)|;|$)/Si',
implode('|', array_keys($this->namedToHexColorsMap))
);
$this->numRegex = sprintf('-?\d*\.?\d+%s?', $this->unitsGroupRegex);
$this->setShortenZeroValuesRegexes();
}
/**
* Parses & minifies the given input CSS string
* @param string $css
* @return string
*/
public function run($css = '')
{
if (empty($css) || !is_string($css)) {
return '';
}
$this->resetRunProperties();
if ($this->raisePhpLimits) {
$this->doRaisePhpLimits();
}
return $this->minify($css);
}
/**
* Sets whether to keep or remove sourcemap special comment.
* Sourcemap comments are removed by default.
* @param bool $keepSourceMapComment
*/
public function keepSourceMapComment($keepSourceMapComment = true)
{
$this->keepSourceMapComment = (bool) $keepSourceMapComment;
}
/**
* Sets whether to keep or remove important comments.
* Important comments outside of a declaration block are kept by default.
* @param bool $removeImportantComments
*/
public function removeImportantComments($removeImportantComments = true)
{
$this->keepImportantComments = !(bool) $removeImportantComments;
}
/**
* Sets the approximate column after which long lines will be splitted in the output
* with a linebreak.
* @param int $position
*/
public function setLineBreakPosition($position)
{
$this->linebreakPosition = (int) $position;
}
/**
* Sets the memory limit for this script
* @param int|string $limit
*/
public function setMemoryLimit($limit)
{
$this->memoryLimit = Utils::normalizeInt($limit);
}
/**
* Sets the maximum execution time for this script
* @param int|string $seconds
*/
public function setMaxExecutionTime($seconds)
{
$this->maxExecutionTime = (int) $seconds;
}
/**
* Sets the PCRE backtrack limit for this script
* @param int $limit
*/
public function setPcreBacktrackLimit($limit)
{
$this->pcreBacktrackLimit = (int) $limit;
}
/**
* Sets the PCRE recursion limit for this script
* @param int $limit
*/
public function setPcreRecursionLimit($limit)
{
$this->pcreRecursionLimit = (int) $limit;
}
/**
* Builds regular expressions needed for shortening zero values
*/
private function setShortenZeroValuesRegexes()
{
$zeroRegex = '0'. $this->unitsGroupRegex;
$numOrPosRegex = '('. $this->numRegex .'|top|left|bottom|right|center) ';
$oneZeroSafeProperties = array(
'(?:line-)?height',
'(?:(?:min|max)-)?width',
'top',
'left',
'background-position',
'bottom',
'right',
'border(?:-(?:top|left|bottom|right))?(?:-width)?',
'border-(?:(?:top|bottom)-(?:left|right)-)?radius',
'column-(?:gap|width)',
'margin(?:-(?:top|left|bottom|right))?',
'outline-width',
'padding(?:-(?:top|left|bottom|right))?'
);
// First zero regex
$regex = '/(^|;)('. implode('|', $oneZeroSafeProperties) .'):%s/Si';
$this->shortenOneZeroesRegex = sprintf($regex, $zeroRegex);
// Multiple zeroes regexes
$regex = '/(^|;)(margin|padding|border-(?:width|radius)|background-position):%s/Si';
$this->shortenTwoZeroesRegex = sprintf($regex, $numOrPosRegex . $zeroRegex);
$this->shortenThreeZeroesRegex = sprintf($regex, $numOrPosRegex . $numOrPosRegex . $zeroRegex);
$this->shortenFourZeroesRegex = sprintf($regex, $numOrPosRegex . $numOrPosRegex . $numOrPosRegex . $zeroRegex);
}
/**
* Resets properties whose value may change between runs
*/
private function resetRunProperties()
{
$this->comments = array();
$this->ruleBodies = array();
$this->preservedTokens = array();
}
/**
* Tries to configure PHP to use at least the suggested minimum settings
* @return void
*/
private function doRaisePhpLimits()
{
$phpLimits = array(
'memory_limit' => $this->memoryLimit,
'max_execution_time' => $this->maxExecutionTime,
'pcre.backtrack_limit' => $this->pcreBacktrackLimit,
'pcre.recursion_limit' => $this->pcreRecursionLimit
);
// If current settings are higher respect them.
foreach ($phpLimits as $name => $suggested) {
$current = Utils::normalizeInt(ini_get($name));
if ($current >= $suggested) {
continue;
}
// memoryLimit exception: allow -1 for "no memory limit".
if ($name === 'memory_limit' && $current === -1) {
continue;
}
// maxExecutionTime exception: allow 0 for "no memory limit".
if ($name === 'max_execution_time' && $current === 0) {
continue;
}
ini_set($name, $suggested);
}
}
/**
* Registers a preserved token
* @param string $token
* @return string The token ID string
*/
private function registerPreservedToken($token)
{
$tokenId = sprintf(self::PRESERVED_TOKEN, count($this->preservedTokens));
$this->preservedTokens[$tokenId] = $token;
return $tokenId;
}
/**
* Registers a candidate comment token
* @param string $comment
* @return string The comment token ID string
*/
private function registerCommentToken($comment)
{
$tokenId = sprintf(self::COMMENT_TOKEN, count($this->comments));
$this->comments[$tokenId] = $comment;
return $tokenId;
}
/**
* Registers a rule body token
* @param string $body the minified rule body
* @return string The rule body token ID string
*/
private function registerRuleBodyToken($body)
{
if (empty($body)) {
return '';
}
$tokenId = sprintf(self::RULE_BODY_TOKEN, count($this->ruleBodies));
$this->ruleBodies[$tokenId] = $body;
return $tokenId;
}
/**
* Parses & minifies the given input CSS string
* @param string $css
* @return string
*/
private function minify($css)
{
// Process data urls
$css = $this->processDataUrls($css);
// Process comments
$css = preg_replace_callback(
'/(?<!\\\\)\/\*(.*?)\*(?<!\\\\)\//Ss',
array($this, 'processCommentsCallback'),
$css
);
// IE7: Process Microsoft matrix filters (whitespaces between Matrix parameters). Can contain strings inside.
$css = preg_replace_callback(
'/filter:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^)]+)\)/Ss',
array($this, 'processOldIeSpecificMatrixDefinitionCallback'),
$css
);
// Process quoted unquotable attribute selectors to unquote them. Covers most common cases.
// Likelyhood of a quoted attribute selector being a substring in a string: Very very low.
$css = preg_replace(
'/\[\s*([a-z][a-z-]+)\s*([\*\|\^\$~]?=)\s*[\'"](-?[a-z_][a-z0-9-_]+)[\'"]\s*\]/Ssi',
'[$1$2$3]',
$css
);
// Process strings so their content doesn't get accidentally minified
$double_quoted = '"(?:[^"\\\\]|\\\\.)*"';
$single_quoted = "'(?:[^'\\\\]|\\\\.)*'";
$css = preg_replace_callback(
"/(?<!\\\\)(?:$double_quoted|$single_quoted)/S",
array($this, 'processStringsCallback'),
$css
);
// Normalize all whitespace strings to single spaces. Easier to work with that way.
$css = preg_replace('/\s+/S', ' ', $css);
// Process comments
$css = $this->processComments($css);
// Process rule bodies
$css = $this->processRuleBodies($css);
// Process at-rules and selectors
$css = $this->processAtRulesAndSelectors($css);
// Restore preserved rule bodies before splitting
$css = strtr($css, $this->ruleBodies);
// Some source control tools don't like it when files containing lines longer
// than, say 8000 characters, are checked in. The linebreak option is used in
// that case to split long lines after a specific column.
if ($this->linebreakPosition > 0) {
$l = strlen($css);
$offset = $this->linebreakPosition;
while (preg_match('/(?<!\\\\)\}(?!\n)/S', $css, $matches, PREG_OFFSET_CAPTURE, $offset)) {
$matchIndex = $matches[0][1];
$css = substr_replace($css, "\n", $matchIndex + 1, 0);
$offset = $matchIndex + 2 + $this->linebreakPosition;
$l += 1;
if ($offset > $l) {
break;
}
}
}
// Restore preserved comments and strings
$css = strtr($css, $this->preservedTokens);
return trim($css);
}
/**
* Searches & replaces all data urls with tokens before we start compressing,
* to avoid performance issues running some of the subsequent regexes against large string chunks.
* @param string $css
* @return string
*/
private function processDataUrls($css)
{
$ret = '';
$searchOffset = $substrOffset = 0;
// Since we need to account for non-base64 data urls, we need to handle
// ' and ) being part of the data string.
while (preg_match('/url\(\s*(["\']?)data:/Si', $css, $m, PREG_OFFSET_CAPTURE, $searchOffset)) {
$matchStartIndex = $m[0][1];
$dataStartIndex = $matchStartIndex + 4; // url( length
$searchOffset = $matchStartIndex + strlen($m[0][0]);
$terminator = $m[1][0]; // ', " or empty (not quoted)
$terminatorRegex = '/(?<!\\\\)'. (strlen($terminator) === 0 ? '' : $terminator.'\s*') .'(\))/S';
$ret .= substr($css, $substrOffset, $matchStartIndex - $substrOffset);
// Terminator found
if (preg_match($terminatorRegex, $css, $matches, PREG_OFFSET_CAPTURE, $searchOffset)) {
$matchEndIndex = $matches[1][1];
$searchOffset = $matchEndIndex + 1;
$token = substr($css, $dataStartIndex, $matchEndIndex - $dataStartIndex);
// Remove all spaces only for base64 encoded URLs.
if (stripos($token, 'base64,') !== false) {
$token = preg_replace('/\s+/S', '', $token);
}
$ret .= 'url('. $this->registerPreservedToken(trim($token)) .')';
// No end terminator found, re-add the whole match. Should we throw/warn here?
} else {
$ret .= substr($css, $matchStartIndex, $searchOffset - $matchStartIndex);
}
$substrOffset = $searchOffset;
}
$ret .= substr($css, $substrOffset);
return $ret;
}
/**
* Registers all comments found as candidates to be preserved.
* @param array $matches
* @return string
*/
private function processCommentsCallback($matches)
{
return '/*'. $this->registerCommentToken($matches[1]) .'*/';
}
/**
* Preserves old IE Matrix string definition
* @param array $matches
* @return string
*/
private function processOldIeSpecificMatrixDefinitionCallback($matches)
{
return 'filter:progid:DXImageTransform.Microsoft.Matrix('. $this->registerPreservedToken($matches[1]) .')';
}
/**
* Preserves strings found
* @param array $matches
* @return string
*/
private function processStringsCallback($matches)
{
$match = $matches[0];
$quote = substr($match, 0, 1);
$match = substr($match, 1, -1);
// maybe the string contains a comment-like substring?
// one, maybe more? put'em back then
if (strpos($match, self::COMMENT_TOKEN_START) !== false) {
$match = strtr($match, $this->comments);
}
// minify alpha opacity in filter strings
$match = str_ireplace('progid:DXImageTransform.Microsoft.Alpha(Opacity=', 'alpha(opacity=', $match);
return $quote . $this->registerPreservedToken($match) . $quote;
}
/**
* Preserves or removes comments found.
* @param string $css
* @return string
*/
private function processComments($css)
{
foreach ($this->comments as $commentId => $comment) {
$commentIdString = '/*'. $commentId .'*/';
// ! in the first position of the comment means preserve
// so push to the preserved tokens keeping the !
if ($this->keepImportantComments && strpos($comment, '!') === 0) {
$preservedTokenId = $this->registerPreservedToken($comment);
// Put new lines before and after /*! important comments
$css = str_replace($commentIdString, "\n/*$preservedTokenId*/\n", $css);
continue;
}
// # sourceMappingURL= in the first position of the comment means sourcemap
// so push to the preserved tokens if {$this->keepSourceMapComment} is truthy.
if ($this->keepSourceMapComment && strpos($comment, '# sourceMappingURL=') === 0) {
$preservedTokenId = $this->registerPreservedToken($comment);
// Add new line before the sourcemap comment
$css = str_replace($commentIdString, "\n/*$preservedTokenId*/", $css);
continue;
}
// Keep empty comments after child selectors (IE7 hack)
// e.g. html >/**/ body
if (strlen($comment) === 0 && strpos($css, '>/*'.$commentId) !== false) {
$css = str_replace($commentId, $this->registerPreservedToken(''), $css);
continue;
}
// in all other cases kill the comment
$css = str_replace($commentIdString, '', $css);
}
// Normalize whitespace again
$css = preg_replace('/ +/S', ' ', $css);
return $css;
}
/**
* Finds, minifies & preserves all rule bodies.
* @param string $css the whole stylesheet.
* @return string
*/
private function processRuleBodies($css)
{
$ret = '';
$searchOffset = $substrOffset = 0;
while (($blockStartPos = strpos($css, '{', $searchOffset)) !== false) {
$blockEndPos = strpos($css, '}', $blockStartPos);
if ( ! $blockEndPos ) throw new \Exception( 'CSS parse error' ) ;
$nextBlockStartPos = strpos($css, '{', $blockStartPos + 1);
$ret .= substr($css, $substrOffset, $blockStartPos - $substrOffset);
if ($nextBlockStartPos !== false && $nextBlockStartPos < $blockEndPos) {
$ret .= substr($css, $blockStartPos, $nextBlockStartPos - $blockStartPos);
$searchOffset = $nextBlockStartPos;
} else {
$ruleBody = substr($css, $blockStartPos + 1, $blockEndPos - $blockStartPos - 1);
$ruleBodyToken = $this->registerRuleBodyToken($this->processRuleBody($ruleBody));
$ret .= '{'. $ruleBodyToken .'}';
$searchOffset = $blockEndPos + 1;
}
$substrOffset = $searchOffset;
}
$ret .= substr($css, $substrOffset);
return $ret;
}
/**
* Compresses non-group rule bodies.
* @param string $body The rule body without curly braces
* @return string
*/
private function processRuleBody($body)
{
$body = trim($body);
// Remove spaces before the things that should not have spaces before them.
$body = preg_replace('/ ([:=,)*\/;\n])/S', '$1', $body);
// Remove the spaces after the things that should not have spaces after them.
$body = preg_replace('/([:=,(*\/!;\n]) /S', '$1', $body);
// Replace multiple semi-colons in a row by a single one
$body = preg_replace('/;;+/S', ';', $body);
// Remove semicolon before closing brace except when:
// - The last property is prefixed with a `*` (lte IE7 hack) to avoid issues on Symbian S60 3.x browsers.
if (!preg_match('/\*[a-z0-9-]+:[^;]+;$/Si', $body)) {
$body = rtrim($body, ';');
}
// Remove important comments inside a rule body (because they make no sense here).
if (strpos($body, '/*') !== false) {
$body = preg_replace('/\n?\/\*[A-Z0-9_]+\*\/\n?/S', '', $body);
}
// Empty rule body? Exit :)
if (empty($body)) {
return '';
}
// Shorten font-weight values
$body = preg_replace(
array('/(font-weight:)bold\b/Si', '/(font-weight:)normal\b/Si'),
array('${1}700', '${1}400'),
$body
);
// Shorten background property
$body = preg_replace('/(background:)(?:none|transparent)( !|;|$)/Si', '${1}0 0$2', $body);
// Shorten opacity IE filter
$body = str_ireplace('progid:DXImageTransform.Microsoft.Alpha(Opacity=', 'alpha(opacity=', $body);
// Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
// Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
// This makes it more likely that it'll get further compressed in the next step.
$body = preg_replace_callback(
'/(rgb|hsl)\(([0-9,.% -]+)\)(.|$)/Si',
array($this, 'shortenHslAndRgbToHexCallback'),
$body
);
// Shorten colors from #AABBCC to #ABC or shorter color name:
// - Look for hex colors which don't have a "=" in front of them (to avoid MSIE filters)
$body = preg_replace_callback(
'/(?<!=)#([0-9a-f]{3,6})( |,|\)|;|$)/Si',
array($this, 'shortenHexColorsCallback'),
$body
);
// Shorten long named colors with a shorter HEX counterpart: white -> #fff.
// Run at least 2 times to cover most cases
$body = preg_replace_callback(
array($this->namedToHexColorsRegex, $this->namedToHexColorsRegex),
array($this, 'shortenNamedColorsCallback'),
$body
);
// Replace positive sign from numbers before the leading space is removed.
// +1.2em to 1.2em, +.8px to .8px, +2% to 2%
$body = preg_replace('/([ :,(])\+(\.?\d+)/S', '$1$2', $body);
// shorten ms to s
$body = preg_replace_callback('/([ :,(])(-?)(\d{3,})ms/Si', function ($matches) {
return $matches[1] . $matches[2] . ((int) $matches[3] / 1000) .'s';
}, $body);
// Remove leading zeros from integer and float numbers.
// 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
$body = preg_replace('/([ :,(])(-?)0+([1-9]?\.?\d+)/S', '$1$2$3', $body);
// Remove trailing zeros from float numbers.
// -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
$body = preg_replace('/([ :,(])(-?\d?\.\d+?)0+([^\d])/S', '$1$2$3', $body);
// Remove trailing .0 -> -9.0 to -9
$body = preg_replace('/([ :,(])(-?\d+)\.0([^\d])/S', '$1$2$3', $body);
// Replace 0 length numbers with 0
$body = preg_replace('/([ :,(])-?\.?0+([^\d])/S', '${1}0$2', $body);
// Shorten zero values for safe properties only
$body = preg_replace(
array(
$this->shortenOneZeroesRegex,
$this->shortenTwoZeroesRegex,
$this->shortenThreeZeroesRegex,
$this->shortenFourZeroesRegex
),
array(
'$1$2:0',
'$1$2:$3 0',
'$1$2:$3 $4 0',
'$1$2:$3 $4 $5 0'
),
$body
);
// Replace 0 0 0; or 0 0 0 0; with 0 0 for background-position property.
$body = preg_replace('/(background-position):0(?: 0){2,3}( !|;|$)/Si', '$1:0 0$2', $body);
// Shorten suitable shorthand properties with repeated values
$body = preg_replace(
array(
'/(margin|padding|border-(?:width|radius)):('.$this->numRegex.')(?: \2)+( !|;|$)/Si',
'/(border-(?:style|color)):([#a-z0-9]+)(?: \2)+( !|;|$)/Si'
),
'$1:$2$3',
$body
);
$body = preg_replace(
array(
'/(margin|padding|border-(?:width|radius)):'.
'('.$this->numRegex.') ('.$this->numRegex.') \2 \3( !|;|$)/Si',
'/(border-(?:style|color)):([#a-z0-9]+) ([#a-z0-9]+) \2 \3( !|;|$)/Si'
),
'$1:$2 $3$4',
$body
);
$body = preg_replace(
array(
'/(margin|padding|border-(?:width|radius)):'.
'('.$this->numRegex.') ('.$this->numRegex.') ('.$this->numRegex.') \3( !|;|$)/Si',
'/(border-(?:style|color)):([#a-z0-9]+) ([#a-z0-9]+) ([#a-z0-9]+) \3( !|;|$)/Si'
),
'$1:$2 $3 $4$5',
$body
);
// Lowercase some common functions that can be values
$body = preg_replace_callback(
'/(?:attr|blur|brightness|circle|contrast|cubic-bezier|drop-shadow|ellipse|from|grayscale|'.
'hsla?|hue-rotate|inset|invert|local|minmax|opacity|perspective|polygon|rgba?|rect|repeat|saturate|sepia|'.
'steps|to|url|var|-webkit-gradient|'.
'(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|(?:repeating-)?(?:linear|radial)-gradient))\(/Si',
array($this, 'strtolowerCallback'),
$body
);
// Lowercase all uppercase properties
$body = preg_replace_callback('/(?:^|;)[A-Z-]+:/S', array($this, 'strtolowerCallback'), $body);
return $body;
}
/**
* Compresses At-rules and selectors.
* @param string $css the whole stylesheet with rule bodies tokenized.
* @return string
*/
private function processAtRulesAndSelectors($css)
{
$charset = '';
$imports = '';
$namespaces = '';
// Remove spaces before the things that should not have spaces before them.
$css = preg_replace('/ ([@{};>+)\]~=,\/\n])/S', '$1', $css);
// Remove the spaces after the things that should not have spaces after them.
$css = preg_replace('/([{}:;>+(\[~=,\/\n]) /S', '$1', $css);
// Shorten shortable double colon (CSS3) pseudo-elements to single colon (CSS2)
$css = preg_replace('/::(before|after|first-(?:line|letter))(\{|,)/Si', ':$1$2', $css);
// Retain space for special IE6 cases
$css = preg_replace_callback('/:first-(line|letter)(\{|,)/Si', function ($matches) {
return ':first-'. strtolower($matches[1]) .' '. $matches[2];
}, $css);
// Find a fraction that may used in some @media queries such as: (min-aspect-ratio: 1/1)
// Add token to add the "/" back in later
$css = preg_replace('/\(([a-z-]+):([0-9]+)\/([0-9]+)\)/Si', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
// Remove empty rule blocks up to 2 levels deep.
$css = preg_replace(array_fill(0, 2, '/(\{)[^{};\/\n]+\{\}/S'), '$1', $css);
$css = preg_replace('/[^{};\/\n]+\{\}/S', '', $css);
// Two important comments next to each other? Remove extra newline.
if ($this->keepImportantComments) {
$css = str_replace("\n\n", "\n", $css);
}
// Restore fraction
$css = str_replace(self::QUERY_FRACTION, '/', $css);
// Lowercase some popular @directives
$css = preg_replace_callback(
'/(?<!\\\\)@(?:charset|document|font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframes|media|'.
'namespace|page|supports|viewport)/Si',
array($this, 'strtolowerCallback'),
$css
);
// Lowercase some popular media types
$css = preg_replace_callback(
'/[ ,](?:all|aural|braille|handheld|print|projection|screen|tty|tv|embossed|speech)[ ,;{]/Si',
array($this, 'strtolowerCallback'),
$css
);
// Lowercase some common pseudo-classes & pseudo-elements
$css = preg_replace_callback(
'/(?<!\\\\):(?:active|after|before|checked|default|disabled|empty|enabled|first-(?:child|of-type)|'.
'focus(?:-within)?|hover|indeterminate|in-range|invalid|lang\(|last-(?:child|of-type)|left|link|not\(|'.
'nth-(?:child|of-type)\(|nth-last-(?:child|of-type)\(|only-(?:child|of-type)|optional|out-of-range|'.
'read-(?:only|write)|required|right|root|:selection|target|valid|visited)/Si',
array($this, 'strtolowerCallback'),
$css
);
// @charset handling
if (preg_match($this->charsetRegex, $css, $matches)) {
// Keep the first @charset at-rule found
$charset = $matches[0];
// Delete all @charset at-rules
$css = preg_replace($this->charsetRegex, '', $css);
}
// @import handling
$css = preg_replace_callback($this->importRegex, function ($matches) use (&$imports) {
// Keep all @import at-rules found for later
$imports .= $matches[0];
// Delete all @import at-rules
return '';
}, $css);
// @namespace handling
$css = preg_replace_callback($this->namespaceRegex, function ($matches) use (&$namespaces) {
// Keep all @namespace at-rules found for later
$namespaces .= $matches[0];
// Delete all @namespace at-rules
return '';
}, $css);
// Order critical at-rules:
// 1. @charset first
// 2. @imports below @charset
// 3. @namespaces below @imports
$css = $charset . $imports . $namespaces . $css;
return $css;
}
/**
* Converts hsl() & rgb() colors to HEX format.
* @param $matches
* @return string
*/
private function shortenHslAndRgbToHexCallback($matches)
{
$type = $matches[1];
$values = explode(',', $matches[2]);
$terminator = $matches[3];
if ($type === 'hsl') {
$values = Utils::hslToRgb($values);
}
$hexColors = Utils::rgbToHex($values);
// Restore space after rgb() or hsl() function in some cases such as:
// background-image: linear-gradient(to bottom, rgb(210,180,140) 10%, rgb(255,0,0) 90%);
if (!empty($terminator) && !preg_match('/[ ,);]/S', $terminator)) {
$terminator = ' '. $terminator;
}
return '#'. implode('', $hexColors) . $terminator;
}
/**
* Compresses HEX color values of the form #AABBCC to #ABC or short color name.
* @param $matches
* @return string
*/
private function shortenHexColorsCallback($matches)
{
$hex = $matches[1];
// Shorten suitable 6 chars HEX colors
if (strlen($hex) === 6 && preg_match('/^([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3$/Si', $hex, $m)) {
$hex = $m[1] . $m[2] . $m[3];
}
// Lowercase
$hex = '#'. strtolower($hex);
// Replace Hex colors with shorter color names
$color = array_key_exists($hex, $this->hexToNamedColorsMap) ? $this->hexToNamedColorsMap[$hex] : $hex;
return $color . $matches[2];
}
/**
* Shortens all named colors with a shorter HEX counterpart for a set of safe properties
* e.g. white -> #fff
* @param array $matches
* @return string
*/
private function shortenNamedColorsCallback($matches)
{
return $matches[1] . $this->namedToHexColorsMap[strtolower($matches[2])] . $matches[3];
}
/**
* Makes a string lowercase
* @param array $matches
* @return string
*/
private function strtolowerCallback($matches)
{
return strtolower($matches[0]);
}
}

View File

@ -0,0 +1,350 @@
<?php
/**
* Rewrite file-relative URIs as root-relative in CSS files
*
* @package Minify
* @author Stephen Clay <steve@mrclay.org>
*/
namespace LiteSpeed\Lib\CSS_MIN ;
defined( 'WPINC' ) || exit ;
class UriRewriter
{
/**
* rewrite() and rewriteRelative() append debugging information here
*
* @var string
*/
public static $debugText = '';
/**
* In CSS content, rewrite file relative URIs as root relative
*
* @param string $css
*
* @param string $currentDir The directory of the current CSS file.
*
* @param string $docRoot The document root of the web site in which
* the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']).
*
* @param array $symlinks (default = array()) If the CSS file is stored in
* a symlink-ed directory, provide an array of link paths to
* target paths, where the link paths are within the document root. Because
* paths need to be normalized for this to work, use "//" to substitute
* the doc root in the link paths (the array keys). E.g.:
* <code>
* array('//symlink' => '/real/target/path') // unix
* array('//static' => 'D:\\staticStorage') // Windows
* </code>
*
* @return string
*/
public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array())
{
self::$_docRoot = self::_realpath(
$docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT']
);
self::$_currentDir = self::_realpath($currentDir);
self::$_symlinks = array();
// normalize symlinks in order to map to link
foreach ($symlinks as $link => $target) {
$link = ($link === '//') ? self::$_docRoot : str_replace('//', self::$_docRoot . '/', $link);
$link = strtr($link, '/', DIRECTORY_SEPARATOR);
self::$_symlinks[$link] = self::_realpath($target);
}
self::$debugText .= "docRoot : " . self::$_docRoot . "\n"
. "currentDir : " . self::$_currentDir . "\n";
if (self::$_symlinks) {
self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n";
}
self::$debugText .= "\n";
$css = self::_trimUrls($css);
$css = self::_owlifySvgPaths($css);
// rewrite
$pattern = '/@import\\s+([\'"])(.*?)[\'"]/';
$css = preg_replace_callback($pattern, __CLASS__ . '::_processUriCB', $css);
$pattern = '/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/';
$css = preg_replace_callback($pattern, __CLASS__ . '::_processUriCB', $css);
$css = self::_unOwlify($css);
return $css;
}
/**
* In CSS content, prepend a path to relative URIs
*
* @param string $css
*
* @param string $path The path to prepend.
*
* @return string
*/
public static function prepend($css, $path)
{
self::$_prependPath = $path;
$css = self::_trimUrls($css);
$css = self::_owlifySvgPaths($css);
// append
$pattern = '/@import\\s+([\'"])(.*?)[\'"]/';
$css = preg_replace_callback($pattern, __CLASS__ . '::_processUriCB', $css);
$pattern = '/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/';
$css = preg_replace_callback($pattern, __CLASS__ . '::_processUriCB', $css);
$css = self::_unOwlify($css);
self::$_prependPath = null;
return $css;
}
/**
* Get a root relative URI from a file relative URI
*
* <code>
* UriRewriter::rewriteRelative(
* '../img/hello.gif'
* , '/home/user/www/css' // path of CSS file
* , '/home/user/www' // doc root
* );
* // returns '/img/hello.gif'
*
* // example where static files are stored in a symlinked directory
* UriRewriter::rewriteRelative(
* 'hello.gif'
* , '/var/staticFiles/theme'
* , '/home/user/www'
* , array('/home/user/www/static' => '/var/staticFiles')
* );
* // returns '/static/theme/hello.gif'
* </code>
*
* @param string $uri file relative URI
*
* @param string $realCurrentDir realpath of the current file's directory.
*
* @param string $realDocRoot realpath of the site document root.
*
* @param array $symlinks (default = array()) If the file is stored in
* a symlink-ed directory, provide an array of link paths to
* real target paths, where the link paths "appear" to be within the document
* root. E.g.:
* <code>
* array('/home/foo/www/not/real/path' => '/real/target/path') // unix
* array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path') // Windows
* </code>
*
* @return string
*/
public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array())
{
// prepend path with current dir separator (OS-independent)
$path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR);
$path .= DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
self::$debugText .= "file-relative URI : {$uri}\n"
. "path prepended : {$path}\n";
// "unresolve" a symlink back to doc root
foreach ($symlinks as $link => $target) {
if (0 === strpos($path, $target)) {
// replace $target with $link
$path = $link . substr($path, strlen($target));
self::$debugText .= "symlink unresolved : {$path}\n";
break;
}
}
// strip doc root
$path = substr($path, strlen($realDocRoot));
self::$debugText .= "docroot stripped : {$path}\n";
// fix to root-relative URI
$uri = strtr($path, '/\\', '//');
$uri = self::removeDots($uri);
self::$debugText .= "traversals removed : {$uri}\n\n";
return $uri;
}
/**
* Remove instances of "./" and "../" where possible from a root-relative URI
*
* @param string $uri
*
* @return string
*/
public static function removeDots($uri)
{
$uri = str_replace('/./', '/', $uri);
// inspired by patch from Oleg Cherniy
do {
$uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
} while ($changed);
return $uri;
}
/**
* Get realpath with any trailing slash removed. If realpath() fails,
* just remove the trailing slash.
*
* @param string $path
*
* @return mixed path with no trailing slash
*/
protected static function _realpath($path)
{
$realPath = realpath($path);
if ($realPath !== false) {
$path = $realPath;
}
return rtrim($path, '/\\');
}
/**
* Directory of this stylesheet
*
* @var string
*/
private static $_currentDir = '';
/**
* DOC_ROOT
*
* @var string
*/
private static $_docRoot = '';
/**
* directory replacements to map symlink targets back to their
* source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
*
* @var array
*/
private static $_symlinks = array();
/**
* Path to prepend
*
* @var string
*/
private static $_prependPath = null;
/**
* @param string $css
*
* @return string
*/
private static function _trimUrls($css)
{
$pattern = '/
url\\( # url(
\\s*
([^\\)]+?) # 1 = URI (assuming does not contain ")")
\\s*
\\) # )
/x';
return preg_replace($pattern, 'url($1)', $css);
}
/**
* @param array $m
*
* @return string
*/
private static function _processUriCB($m)
{
// $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
$isImport = ($m[0][0] === '@');
// determine URI and the quote character (if any)
if ($isImport) {
$quoteChar = $m[1];
$uri = $m[2];
} else {
// $m[1] is either quoted or not
$quoteChar = ($m[1][0] === "'" || $m[1][0] === '"') ? $m[1][0] : '';
$uri = ($quoteChar === '') ? $m[1] : substr($m[1], 1, strlen($m[1]) - 2);
}
if ($uri === '') {
return $m[0];
}
// if not anchor id, not root/scheme relative, and not starts with scheme
if (!preg_match('~^(#|/|[a-z]+\:)~', $uri)) {
// URI is file-relative: rewrite depending on options
if (self::$_prependPath === null) {
$uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
} else {
$uri = self::$_prependPath . $uri;
if ($uri[0] === '/') {
$root = '';
$rootRelative = $uri;
$uri = $root . self::removeDots($rootRelative);
} elseif (preg_match('@^((https?\:)?//([^/]+))/@', $uri, $m) && (false !== strpos($m[3], '.'))) {
$root = $m[1];
$rootRelative = substr($uri, strlen($root));
$uri = $root . self::removeDots($rootRelative);
}
}
}
if ($isImport) {
return "@import {$quoteChar}{$uri}{$quoteChar}";
} else {
return "url({$quoteChar}{$uri}{$quoteChar})";
}
}
/**
* Mungs some inline SVG URL declarations so they won't be touched
*
* @link https://github.com/mrclay/minify/issues/517
* @see _unOwlify
*
* @param string $css
* @return string
*/
private static function _owlifySvgPaths($css)
{
$pattern = '~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)url(\(\s*#\w+\s*\))~';
return preg_replace($pattern, '$1owl$2', $css);
}
/**
* Undo work of _owlify
*
* @see _owlifySvgPaths
*
* @param string $css
* @return string
*/
private static function _unOwlify($css)
{
$pattern = '~\b((?:clip-path|mask|-webkit-mask)\s*\:\s*)owl~';
return preg_replace($pattern, '$1url', $css);
}
}

View File

@ -0,0 +1,150 @@
<?php
namespace LiteSpeed\Lib\CSS_MIN ;
defined( 'WPINC' ) || exit ;
class Utils
{
/**
* Clamps a number between a minimum and a maximum value.
* @param int|float $n the number to clamp
* @param int|float $min the lower end number allowed
* @param int|float $max the higher end number allowed
* @return int|float
*/
public static function clampNumber($n, $min, $max)
{
return min(max($n, $min), $max);
}
/**
* Clamps a RGB color number outside the sRGB color space
* @param int|float $n the number to clamp
* @return int|float
*/
public static function clampNumberSrgb($n)
{
return self::clampNumber($n, 0, 255);
}
/**
* Converts a HSL color into a RGB color
* @param array $hslValues
* @return array
*/
public static function hslToRgb($hslValues)
{
$h = floatval($hslValues[0]);
$s = floatval(str_replace('%', '', $hslValues[1]));
$l = floatval(str_replace('%', '', $hslValues[2]));
// Wrap and clamp, then fraction!
$h = ((($h % 360) + 360) % 360) / 360;
$s = self::clampNumber($s, 0, 100) / 100;
$l = self::clampNumber($l, 0, 100) / 100;
if ($s == 0) {
$r = $g = $b = self::roundNumber(255 * $l);
} else {
$v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
$v1 = (2 * $l) - $v2;
$r = self::roundNumber(255 * self::hueToRgb($v1, $v2, $h + (1/3)));
$g = self::roundNumber(255 * self::hueToRgb($v1, $v2, $h));
$b = self::roundNumber(255 * self::hueToRgb($v1, $v2, $h - (1/3)));
}
return array($r, $g, $b);
}
/**
* Tests and selects the correct formula for each RGB color channel
* @param $v1
* @param $v2
* @param $vh
* @return mixed
*/
public static function hueToRgb($v1, $v2, $vh)
{
$vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
if ($vh * 6 < 1) {
return $v1 + ($v2 - $v1) * 6 * $vh;
}
if ($vh * 2 < 1) {
return $v2;
}
if ($vh * 3 < 2) {
return $v1 + ($v2 - $v1) * ((2 / 3) - $vh) * 6;
}
return $v1;
}
/**
* Convert strings like "64M" or "30" to int values
* @param mixed $size
* @return int
*/
public static function normalizeInt($size)
{
if (is_string($size)) {
$letter = substr($size, -1);
$size = intval($size);
switch ($letter) {
case 'M':
case 'm':
return (int) $size * 1048576;
case 'K':
case 'k':
return (int) $size * 1024;
case 'G':
case 'g':
return (int) $size * 1073741824;
}
}
return (int) $size;
}
/**
* Converts a string containing and RGB percentage value into a RGB integer value i.e. '90%' -> 229.5
* @param $rgbPercentage
* @return int
*/
public static function rgbPercentageToRgbInteger($rgbPercentage)
{
if (strpos($rgbPercentage, '%') !== false) {
$rgbPercentage = self::roundNumber(floatval(str_replace('%', '', $rgbPercentage)) * 2.55);
}
return intval($rgbPercentage, 10);
}
/**
* Converts a RGB color into a HEX color
* @param array $rgbColors
* @return array
*/
public static function rgbToHex($rgbColors)
{
$hexColors = array();
// Values outside the sRGB color space should be clipped (0-255)
for ($i = 0, $l = count($rgbColors); $i < $l; $i++) {
$hexColors[$i] = sprintf("%02x", self::clampNumberSrgb(self::rgbPercentageToRgbInteger($rgbColors[$i])));
}
return $hexColors;
}
/**
* Rounds a number to its closest integer
* @param $n
* @return int
*/
public static function roundNumber($n)
{
return intval(round(floatval($n)), 10);
}
}

View File

@ -0,0 +1,198 @@
<?php
namespace LiteSpeed\Lib;
/**
* Update guest vary
*
* @since 4.1
*/
class Guest
{
const CONF_FILE = '.litespeed_conf.dat';
const HASH = 'hash'; // Not set-able
const O_CACHE_LOGIN_COOKIE = 'cache-login_cookie';
const O_DEBUG = 'debug';
const O_DEBUG_IPS = 'debug-ips';
const O_UTIL_NO_HTTPS_VARY = 'util-no_https_vary';
const O_GUEST_UAS = 'guest_uas';
const O_GUEST_IPS = 'guest_ips';
private static $_ip;
private static $_vary_name = '_lscache_vary'; // this default vary cookie is used for logged in status check
private $_conf = false;
/**
* Construtor
*
* @since 4.1
*/
public function __construct()
{
!defined('LSCWP_CONTENT_FOLDER') && define('LSCWP_CONTENT_FOLDER', dirname(dirname(dirname(__DIR__))));
// Load config
$this->_conf = file_get_contents(LSCWP_CONTENT_FOLDER . '/' . self::CONF_FILE);
if ($this->_conf) {
$this->_conf = json_decode($this->_conf, true);
}
if (!empty($this->_conf[self::O_CACHE_LOGIN_COOKIE])) {
self::$_vary_name = $this->_conf[self::O_CACHE_LOGIN_COOKIE];
}
}
/**
* Update Guest vary
*
* @since 4.0
*/
public function update_guest_vary()
{
// This process must not be cached
/**
* @reference https://wordpress.org/support/topic/soft-404-from-google-search-on-litespeed-cache-guest-vary-php/#post-16838583
*/
header('X-Robots-Tag: noindex');
header('X-LiteSpeed-Cache-Control: no-cache');
if ($this->always_guest()) {
echo '[]';
exit;
}
// If contains vary already, don't reload to avoid infinite loop when parent page having browser cache
if ($this->_conf && self::has_vary()) {
echo '[]';
exit;
}
// Send vary cookie
$vary = 'guest_mode:1';
if ($this->_conf && empty($this->_conf[self::O_DEBUG])) {
$vary = md5($this->_conf[self::HASH] . $vary);
}
$expire = time() + 2 * 86400;
$is_ssl = !empty($this->_conf[self::O_UTIL_NO_HTTPS_VARY]) ? false : $this->is_ssl();
setcookie(self::$_vary_name, $vary, $expire, '/', false, $is_ssl, true);
// return json
echo json_encode(array('reload' => 'yes'));
exit;
}
/**
* WP's is_ssl() func
*
* @since 4.1
*/
private function is_ssl()
{
if (isset($_SERVER['HTTPS'])) {
if ('on' === strtolower($_SERVER['HTTPS'])) {
return true;
}
if ('1' == $_SERVER['HTTPS']) {
return true;
}
} elseif (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) {
return true;
}
return false;
}
/**
* Check if default vary has a value
*
* @since 1.1.3
* @access public
*/
public static function has_vary()
{
if (empty($_COOKIE[self::$_vary_name])) {
return false;
}
return $_COOKIE[self::$_vary_name];
}
/**
* Detect if is a guest visitor or not
*
* @since 4.0
*/
public function always_guest()
{
if (empty($_SERVER['HTTP_USER_AGENT'])) {
return false;
}
if ($this->_conf[self::O_GUEST_UAS]) {
$quoted_uas = array();
foreach ($this->_conf[self::O_GUEST_UAS] as $v) {
$quoted_uas[] = preg_quote($v, '#');
}
$match = preg_match('#' . implode('|', $quoted_uas) . '#i', $_SERVER['HTTP_USER_AGENT']);
if ($match) {
return true;
}
}
if ($this->ip_access($this->_conf[self::O_GUEST_IPS])) {
return true;
}
return false;
}
/**
* Check if the ip is in the range
*
* @since 1.1.0
* @access public
*/
public function ip_access($ip_list)
{
if (!$ip_list) {
return false;
}
if (!isset(self::$_ip)) {
self::$_ip = self::get_ip();
}
// $uip = explode('.', $_ip);
// if(empty($uip) || count($uip) != 4) Return false;
// foreach($ip_list as $key => $ip) $ip_list[$key] = explode('.', trim($ip));
// foreach($ip_list as $key => $ip) {
// if(count($ip) != 4) continue;
// for($i = 0; $i <= 3; $i++) if($ip[$i] == '*') $ip_list[$key][$i] = $uip[$i];
// }
return in_array(self::$_ip, $ip_list);
}
/**
* Get client ip
*
* @since 1.1.0
* @since 1.6.5 changed to public
* @access public
* @return string
*/
public static function get_ip()
{
$_ip = '';
if (function_exists('apache_request_headers')) {
$apache_headers = apache_request_headers();
$_ip = !empty($apache_headers['True-Client-IP']) ? $apache_headers['True-Client-IP'] : false;
if (!$_ip) {
$_ip = !empty($apache_headers['X-Forwarded-For']) ? $apache_headers['X-Forwarded-For'] : false;
$_ip = explode(',', $_ip);
$_ip = $_ip[0];
}
}
if (!$_ip) {
$_ip = !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false;
}
return $_ip;
}
}

View File

@ -0,0 +1,269 @@
<?php
/**
* Compress HTML
*
* This is a heavy regex-based removal of whitespace, unnecessary comments and
* tokens. IE conditional comments are preserved. There are also options to have
* STYLE and SCRIPT blocks compressed by callback functions.
*
* A test suite is available.
*
* @package Minify
* @author Stephen Clay <steve@mrclay.org>
*/
namespace LiteSpeed\Lib ;
defined( 'WPINC' ) || exit ;
class HTML_MIN
{
/**
* @var string
*/
protected $_html = '';
/**
* @var boolean
*/
protected $_jsCleanComments = true;
/**
* "Minify" an HTML page
*
* @param string $html
*
* @param array $options
*
* 'cssMinifier' : (optional) callback function to process content of STYLE
* elements.
*
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
* elements. Note: the type attribute is ignored.
*
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
* unset, minify will sniff for an XHTML doctype.
*
* @return string
*/
public static function minify($html, $options = array())
{
$min = new self($html, $options);
return $min->process();
}
/**
* Create a minifier object
*
* @param string $html
*
* @param array $options
*
* 'cssMinifier' : (optional) callback function to process content of STYLE
* elements.
*
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
* elements. Note: the type attribute is ignored.
*
* 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block
*
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
* unset, minify will sniff for an XHTML doctype.
*/
public function __construct($html, $options = array())
{
$this->_html = str_replace("\r\n", "\n", trim($html));
if (isset($options['xhtml'])) {
$this->_isXhtml = (bool)$options['xhtml'];
}
if (isset($options['cssMinifier'])) {
$this->_cssMinifier = $options['cssMinifier'];
}
if (isset($options['jsMinifier'])) {
$this->_jsMinifier = $options['jsMinifier'];
}
if (isset($options['jsCleanComments'])) {
$this->_jsCleanComments = (bool)$options['jsCleanComments'];
}
}
/**
* Minify the markeup given in the constructor
*
* @return string
*/
public function process()
{
if ($this->_isXhtml === null) {
$this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
}
$this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
$this->_placeholders = array();
// replace SCRIPTs (and minify) with placeholders
$this->_html = preg_replace_callback(
'/(\\s*)<script(\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
,array($this, '_removeScriptCB')
,$this->_html);
// replace STYLEs (and minify) with placeholders
$this->_html = preg_replace_callback(
'/\\s*<style(\\b[^>]*>)([\\s\\S]*?)<\\/style>\\s*/i'
,array($this, '_removeStyleCB')
,$this->_html);
// remove HTML comments (not containing IE conditional comments).
$this->_html = preg_replace_callback(
'/<!--([\\s\\S]*?)-->/'
,array($this, '_commentCB')
,$this->_html);
// replace PREs with placeholders
$this->_html = preg_replace_callback('/\\s*<pre(\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
,array($this, '_removePreCB')
,$this->_html);
// replace TEXTAREAs with placeholders
$this->_html = preg_replace_callback(
'/\\s*<textarea(\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
,array($this, '_removeTextareaCB')
,$this->_html);
// trim each line.
// @todo take into account attribute values that span multiple lines.
$this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
// remove ws around block/undisplayed elements
$this->_html = preg_replace('/\\s+(<\\/?(?:area|article|aside|base(?:font)?|blockquote|body'
.'|canvas|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|figcaption|figure|footer|form'
.'|frame(?:set)?|h[1-6]|head|header|hgroup|hr|html|legend|li|link|main|map|menu|meta|nav'
.'|ol|opt(?:group|ion)|output|p|param|section|t(?:able|body|head|d|h||r|foot|itle)'
.'|ul|video)\\b[^>]*>)/i', '$1', $this->_html);
// remove ws outside of all elements
$this->_html = preg_replace(
'/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?</'
,'>$1$2$3<'
,$this->_html);
// use newlines before 1st attribute in open tags (to limit line lengths)
// $this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
// fill placeholders
$this->_html = str_replace(
array_keys($this->_placeholders)
,array_values($this->_placeholders)
,$this->_html
);
// issue 229: multi-pass to catch scripts that didn't get replaced in textareas
$this->_html = str_replace(
array_keys($this->_placeholders)
,array_values($this->_placeholders)
,$this->_html
);
return $this->_html;
}
protected function _commentCB($m)
{
return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))
? $m[0]
: '';
}
protected function _reservePlace($content)
{
$placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
$this->_placeholders[$placeholder] = $content;
return $placeholder;
}
protected $_isXhtml = null;
protected $_replacementHash = null;
protected $_placeholders = array();
protected $_cssMinifier = null;
protected $_jsMinifier = null;
protected function _removePreCB($m)
{
return $this->_reservePlace("<pre{$m[1]}");
}
protected function _removeTextareaCB($m)
{
return $this->_reservePlace("<textarea{$m[1]}");
}
protected function _removeStyleCB($m)
{
$openStyle = "<style{$m[1]}";
$css = $m[2];
// remove HTML comments
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
// remove CDATA section markers
$css = $this->_removeCdata($css);
// minify
$minifier = $this->_cssMinifier
? $this->_cssMinifier
: 'trim';
$css = call_user_func($minifier, $css);
return $this->_reservePlace($this->_needsCdata($css)
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
: "{$openStyle}{$css}</style>"
);
}
protected function _removeScriptCB($m)
{
$openScript = "<script{$m[2]}";
$js = $m[3];
// whitespace surrounding? preserve at least one space
$ws1 = ($m[1] === '') ? '' : ' ';
$ws2 = ($m[4] === '') ? '' : ' ';
// remove HTML comments (and ending "//" if present)
if ($this->_jsCleanComments) {
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
}
// remove CDATA section markers
$js = $this->_removeCdata($js);
// minify
/**
* Added 2nd param by LiteSpeed
*
* @since 2.2.3
*/
if ( $this->_jsMinifier ) {
$js = call_user_func( $this->_jsMinifier, $js, trim( $m[ 2 ] ) ) ;
}
else {
$js = trim( $js ) ;
}
return $this->_reservePlace($this->_needsCdata($js)
? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
: "{$ws1}{$openScript}{$js}</script>{$ws2}"
);
}
protected function _removeCdata($str)
{
return (false !== strpos($str, '<![CDATA['))
? str_replace(array('<![CDATA[', ']]>'), '', $str)
: $str;
}
protected function _needsCdata($str)
{
return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
in
public
extends
private
protected
implements
instanceof

View File

@ -0,0 +1,26 @@
do
in
let
new
var
case
else
enum
void
with
class
const
yield
delete
export
import
public
static
typeof
extends
package
private
function
protected
implements
instanceof

View File

@ -0,0 +1,63 @@
do
if
in
for
let
new
try
var
case
else
enum
eval
null
this
true
void
with
break
catch
class
const
false
super
throw
while
yield
delete
export
import
public
return
static
switch
typeof
default
extends
finally
package
private
continue
debugger
function
arguments
interface
protected
implements
instanceof
abstract
boolean
byte
char
double
final
float
goto
int
long
native
short
synchronized
throws
transient
volatile

View File

@ -0,0 +1,46 @@
+
-
*
/
%
=
+=
-=
*=
/=
%=
<<=
>>=
>>>=
&=
^=
|=
&
|
^
~
<<
>>
>>>
==
===
!=
!==
>
<
>=
<=
&&
||
!
.
[
]
?
:
,
;
(
)
{
}

View File

@ -0,0 +1,43 @@
+
-
*
/
%
=
+=
-=
*=
/=
%=
<<=
>>=
>>>=
&=
^=
|=
&
|
^
<<
>>
>>>
==
===
!=
!==
>
<
>=
<=
&&
||
.
[
]
?
:
,
;
(
)
}

View File

@ -0,0 +1,43 @@
+
-
*
/
%
=
+=
-=
*=
/=
%=
<<=
>>=
>>>=
&=
^=
|=
&
|
^
~
<<
>>
>>>
==
===
!=
!==
>
<
>=
<=
&&
||
!
.
[
?
:
,
;
(
{

View File

@ -0,0 +1,46 @@
<?php
defined( 'WPINC' ) || exit;
/**
* LiteSpeed Object Cache
*
* @since 1.8
*/
! defined( 'LSCWP_OBJECT_CACHE' ) && define( 'LSCWP_OBJECT_CACHE', true );
// Initialize const `LSCWP_DIR` and locate LSCWP plugin foder
$lscwp_dir = ( defined( 'WP_PLUGIN_DIR' ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins' ) . '/litespeed-cache/';
// Use plugin as higher priority than MU plugin
if ( ! file_exists( $lscwp_dir . 'litespeed-cache.php' ) ) {
// Check if is mu plugin or not
$lscwp_dir = ( defined( 'WPMU_PLUGIN_DIR' ) ? WPMU_PLUGIN_DIR : WP_CONTENT_DIR . '/mu-plugins' ) . '/litespeed-cache/';
if ( ! file_exists( $lscwp_dir . 'litespeed-cache.php' ) ) {
$lscwp_dir = '';
}
}
$data_file = WP_CONTENT_DIR . '/.litespeed_conf.dat';
$lib_file = $lscwp_dir . 'src/object.lib.php';
// Can't find LSCWP location, terminate object cache process
if ( ! $lscwp_dir || ! file_exists( $data_file ) || ( ! file_exists( $lib_file ) ) ) {
if ( ! is_admin() ) { // Bypass object cache for frontend
require_once ABSPATH . WPINC . '/cache.php';
}
else {
$err = 'Can NOT find LSCWP path for object cache initialization in ' . __FILE__;
error_log( $err );
add_action( is_network_admin() ? 'network_admin_notices' : 'admin_notices', function() use ( &$err ) {
echo $err;
} );
}
}
else {
if ( ! LSCWP_OBJECT_CACHE ) { // Disable cache
wp_using_ext_object_cache(false);
}
// Init object cache & LSCWP
else if ( file_exists( $lib_file ) ) {
require_once $lib_file;
}
}

View File

@ -0,0 +1,137 @@
<?php
/**
* LiteSpeed PHP compatibility functions for lower PHP version
*
* @since 1.1.3
* @package LiteSpeed_Cache
* @subpackage LiteSpeed_Cache/lib
* @author LiteSpeed Technologies <info@litespeedtech.com>
*/
defined( 'WPINC' ) || exit ;
/**
* http_build_url() compatibility
*
*/
if ( ! function_exists('http_build_url') ) {
if ( ! defined( 'HTTP_URL_REPLACE' ) ) define('HTTP_URL_REPLACE', 1); // Replace every part of the first URL when there's one of the second URL
if ( ! defined( 'HTTP_URL_JOIN_PATH' ) ) define('HTTP_URL_JOIN_PATH', 2); // Join relative paths
if ( ! defined( 'HTTP_URL_JOIN_QUERY' ) ) define('HTTP_URL_JOIN_QUERY', 4); // Join query strings
if ( ! defined( 'HTTP_URL_STRIP_USER' ) ) define('HTTP_URL_STRIP_USER', 8); // Strip any user authentication information
if ( ! defined( 'HTTP_URL_STRIP_PASS' ) ) define('HTTP_URL_STRIP_PASS', 16); // Strip any password authentication information
if ( ! defined( 'HTTP_URL_STRIP_AUTH' ) ) define('HTTP_URL_STRIP_AUTH', 32); // Strip any authentication information
if ( ! defined( 'HTTP_URL_STRIP_PORT' ) ) define('HTTP_URL_STRIP_PORT', 64); // Strip explicit port numbers
if ( ! defined( 'HTTP_URL_STRIP_PATH' ) ) define('HTTP_URL_STRIP_PATH', 128); // Strip complete path
if ( ! defined( 'HTTP_URL_STRIP_QUERY' ) ) define('HTTP_URL_STRIP_QUERY', 256); // Strip query string
if ( ! defined( 'HTTP_URL_STRIP_FRAGMENT' ) ) define('HTTP_URL_STRIP_FRAGMENT', 512); // Strip any fragments (#identifier)
if ( ! defined( 'HTTP_URL_STRIP_ALL' ) ) define('HTTP_URL_STRIP_ALL', 1024); // Strip anything but scheme and host
// Build an URL
// The parts of the second URL will be merged into the first according to the flags argument.
//
// @param mixed (Part(s) of) an URL in form of a string or associative array like parse_url() returns
// @param mixed Same as the first argument
// @param int A bitmask of binary or'ed HTTP_URL constants (Optional)HTTP_URL_REPLACE is the default
// @param array If set, it will be filled with the parts of the composed url like parse_url() would return
function http_build_url($url, $parts = array(), $flags = HTTP_URL_REPLACE, &$new_url = false)
{
$keys = array('user','pass','port','path','query','fragment');
// HTTP_URL_STRIP_ALL becomes all the HTTP_URL_STRIP_Xs
if ( $flags & HTTP_URL_STRIP_ALL ) {
$flags |= HTTP_URL_STRIP_USER;
$flags |= HTTP_URL_STRIP_PASS;
$flags |= HTTP_URL_STRIP_PORT;
$flags |= HTTP_URL_STRIP_PATH;
$flags |= HTTP_URL_STRIP_QUERY;
$flags |= HTTP_URL_STRIP_FRAGMENT;
}
// HTTP_URL_STRIP_AUTH becomes HTTP_URL_STRIP_USER and HTTP_URL_STRIP_PASS
else if ( $flags & HTTP_URL_STRIP_AUTH ) {
$flags |= HTTP_URL_STRIP_USER;
$flags |= HTTP_URL_STRIP_PASS;
}
// Parse the original URL
// - Suggestion by Sayed Ahad Abbas
// In case you send a parse_url array as input
$parse_url = !is_array($url) ? parse_url($url) : $url;
// Scheme and Host are always replaced
if ( isset($parts['scheme']) ) {
$parse_url['scheme'] = $parts['scheme'];
}
if ( isset($parts['host']) ) {
$parse_url['host'] = $parts['host'];
}
// (If applicable) Replace the original URL with it's new parts
if ( $flags & HTTP_URL_REPLACE ) {
foreach ($keys as $key) {
if ( isset($parts[$key]) ) {
$parse_url[$key] = $parts[$key];
}
}
}
else {
// Join the original URL path with the new path
if (isset($parts['path']) && ($flags & HTTP_URL_JOIN_PATH)) {
if ( isset($parse_url['path']) ) {
$parse_url['path'] = rtrim(str_replace(basename($parse_url['path']), '', $parse_url['path']), '/') . '/' . ltrim($parts['path'], '/');
}
else {
$parse_url['path'] = $parts['path'];
}
}
// Join the original query string with the new query string
if ( isset($parts['query']) && ($flags & HTTP_URL_JOIN_QUERY) ) {
if ( isset($parse_url['query']) ) {
$parse_url['query'] .= '&' . $parts['query'];
}
else {
$parse_url['query'] = $parts['query'];
}
}
}
// Strips all the applicable sections of the URL
// Note: Scheme and Host are never stripped
foreach ($keys as $key) {
if ( $flags & (int)constant('HTTP_URL_STRIP_' . strtoupper($key)) ) {
unset($parse_url[$key]);
}
}
$new_url = $parse_url;
return
(isset($parse_url['scheme']) ? $parse_url['scheme'] . '://' : '')
.(isset($parse_url['user']) ? $parse_url['user'] . (isset($parse_url['pass']) ? ':' . $parse_url['pass'] : '') .'@' : '')
.(isset($parse_url['host']) ? $parse_url['host'] : '')
.(isset($parse_url['port']) ? ':' . $parse_url['port'] : '')
.(isset($parse_url['path']) ? $parse_url['path'] : '')
.(isset($parse_url['query']) ? '?' . $parse_url['query'] : '')
.(isset($parse_url['fragment']) ? '#' . $parse_url['fragment'] : '')
;
}
}
if ( ! function_exists( 'array_key_first' ) ) {
function array_key_first( array $arr ) {
foreach( $arr as $k => $unused ) {
return $k ;
}
return NULL ;
}
}
if ( ! function_exists( 'array_column' ) ) {
function array_column( $array, $column_name )
{
return array_map( function( $element ) use( $column_name ) { return $element[ $column_name ]; }, $array );
}
}