first commit
This commit is contained in:
397
components/com_jce/editor/libraries/classes/packer.php
Normal file
397
components/com_jce/editor/libraries/classes/packer.php
Normal file
@@ -0,0 +1,397 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2009-2022 Ryan Demmer. All rights reserved
|
||||
* @license GNU/GPL 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* JCE is free software. This version may have been modified pursuant
|
||||
* to the GNU General Public License, and as distributed it includes or
|
||||
* is derivative of works licensed under the GNU General Public License or
|
||||
* other free or open source software licenses
|
||||
*/
|
||||
defined('JPATH_PLATFORM') or die;
|
||||
|
||||
class WFPacker extends JObject
|
||||
{
|
||||
const IMPORT_RX = '#@import.*?(?:\(([^\)]+)\);|(?:[\'"]([^\'"]+)[\'"]);)#i'; // match @import url('...'); or @import '...'; or @import "...";
|
||||
|
||||
protected $files = array();
|
||||
protected $type = 'javascript';
|
||||
protected $text = '';
|
||||
protected $start = '';
|
||||
protected $end = '';
|
||||
protected static $imports = array();
|
||||
|
||||
/**
|
||||
* Constructor activating the default information of the class.
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
$this->setProperties($config);
|
||||
}
|
||||
|
||||
public function setFiles($files = array())
|
||||
{
|
||||
$this->files = $files;
|
||||
}
|
||||
|
||||
public function getFiles()
|
||||
{
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
public function setText($text = '')
|
||||
{
|
||||
$this->text = $text;
|
||||
}
|
||||
|
||||
public function setContentStart($start = '')
|
||||
{
|
||||
$this->start = $start;
|
||||
}
|
||||
|
||||
public function getContentStart()
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
public function setContentEnd($end = '')
|
||||
{
|
||||
$this->end = $end;
|
||||
}
|
||||
|
||||
public function getContentEnd()
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get encoding.
|
||||
*
|
||||
* @copyright Copyright (C) 2005 - 2010 Open Source Matters. All rights reserved
|
||||
*/
|
||||
private static function getEncoding()
|
||||
{
|
||||
if (!isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$encoding = false;
|
||||
|
||||
if (false !== strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
|
||||
$encoding = 'gzip';
|
||||
}
|
||||
|
||||
if (false !== strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip')) {
|
||||
$encoding = 'x-gzip';
|
||||
}
|
||||
|
||||
return $encoding;
|
||||
}
|
||||
|
||||
private function getEtag($hash)
|
||||
{
|
||||
if (strpos($hash, '"') !== 0) {
|
||||
$hash = '"' . $hash . '"';
|
||||
}
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack and output content based on type.
|
||||
*
|
||||
* @param bool|true $minify
|
||||
* @param bool|true $cache
|
||||
* @param bool|false $gzip
|
||||
* Contains some code from libraries/joomla/cache/controller/page.php - Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved
|
||||
*/
|
||||
public function pack($minify = true, $cache_validation = true, $gzip = false)
|
||||
{
|
||||
$type = $this->getType();
|
||||
|
||||
ob_start();
|
||||
|
||||
// Headers
|
||||
if ($type == 'javascript') {
|
||||
header('Content-type: application/javascript; charset: UTF-8');
|
||||
}
|
||||
|
||||
if ($type == 'css') {
|
||||
header('Content-type: text/css; charset: UTF-8');
|
||||
}
|
||||
|
||||
// encoding
|
||||
header('Vary: Accept-Encoding');
|
||||
|
||||
// cache control
|
||||
header('Cache-Control: max-age=0,no-cache');
|
||||
|
||||
$files = $this->getFiles();
|
||||
|
||||
$content = $this->getContentStart();
|
||||
|
||||
if (empty($files)) {
|
||||
$content .= $this->getText();
|
||||
} else {
|
||||
foreach ($files as $file) {
|
||||
$content .= $this->getText($file, $minify);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->getType() == 'css') {
|
||||
// move external import rules to top
|
||||
foreach (array_unique(self::$imports) as $import) {
|
||||
if (strpos($import, '//') !== false) {
|
||||
$content = '@import url("' . $import . '");' . $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$content .= $this->getContentEnd();
|
||||
|
||||
// trim content
|
||||
$content = trim($content);
|
||||
|
||||
// force browser caching using an E-tag
|
||||
if ($cache_validation) {
|
||||
// get content hash
|
||||
$hash = md5(implode(' ', array_map('basename', $files)) . $content);
|
||||
// create E-tag
|
||||
$etag = $this->getEtag($hash);
|
||||
// set etag header
|
||||
header('ETag: ' . $etag);
|
||||
|
||||
// check for sent etag against hash
|
||||
if (!headers_sent() && isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
||||
$_etag = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
|
||||
|
||||
if ($_etag && $_etag === $etag) {
|
||||
header('HTTP/1.x 304 Not Modified', true);
|
||||
exit(ob_get_clean());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate GZIP'd content
|
||||
if ($gzip) {
|
||||
$encoding = self::getEncoding();
|
||||
|
||||
$zlib = function_exists('ini_get') && extension_loaded('zlib') && ini_get('zlib.output_compression');
|
||||
|
||||
if (!empty($encoding) && !$zlib && function_exists('gzencode')) {
|
||||
header('Content-Encoding: ' . $encoding);
|
||||
$content = gzencode($content, 4, FORCE_GZIP);
|
||||
}
|
||||
}
|
||||
|
||||
// stream to client
|
||||
echo $content;
|
||||
|
||||
exit(ob_get_clean());
|
||||
}
|
||||
|
||||
protected function jsmin($data)
|
||||
{
|
||||
// remove header comments
|
||||
return preg_replace('#^\/\*[\s\S]+?\*\/#', '', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple CSS Minifier
|
||||
* https://github.com/GaryJones/Simple-PHP-CSS-Minification.
|
||||
*
|
||||
* @param $data Data string to minify
|
||||
*/
|
||||
protected function cssmin($css)
|
||||
{
|
||||
// Normalize whitespace
|
||||
//$css = preg_replace('/\s+/', ' ', $css);
|
||||
// Remove comment blocks, everything between /* and */, unless
|
||||
// preserved with /*! ... */
|
||||
//$css = preg_replace('/\/\*[^\!](.*?)\*\//', '', $css);
|
||||
// Remove space after , : ; { }
|
||||
//$css = preg_replace('/(,|:|;|\{|}) /', '$1', $css);
|
||||
// Remove space before , ; { }
|
||||
//$css = preg_replace('/ (,|;|\{|})/', '$1', $css);
|
||||
// Strips leading 0 on decimal values (converts 0.5px into .5px)
|
||||
//$css = preg_replace('/(:| )0\.([0-9]+)(%|em|ex|px|in|cm|mm|pt|pc)/i', '${1}.${2}${3}', $css);
|
||||
// Strips units if value is 0 (converts 0px to 0)
|
||||
//$css = preg_replace('/(:| )(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/i', '${1}0', $css);
|
||||
// Converts all zeros value into short-hand
|
||||
//$css = preg_replace('/0 0 0 0/', '0', $css);
|
||||
// Shortern 6-character hex color codes to 3-character where possible
|
||||
//$css = preg_replace('/#([a-f0-9])\\1([a-f0-9])\\2([a-f0-9])\\3/i', '#\1\2\3', $css);
|
||||
|
||||
require_once __DIR__ . '/vendor/cssmin/cssmin.php';
|
||||
|
||||
try {
|
||||
$css = CssMin::minify($css);
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
return trim($css);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import CSS from a file.
|
||||
*
|
||||
* @param file File path where data comes from
|
||||
* @param $data Data from file
|
||||
*/
|
||||
protected function importCss($data, $file)
|
||||
{
|
||||
if (preg_match_all(self::IMPORT_RX, $data, $matches)) {
|
||||
$data = '';
|
||||
|
||||
foreach ($matches[1] as $match) {
|
||||
// clean up url
|
||||
$match = str_replace(array('url', '"', "'", '(', ')'), '', $match);
|
||||
// trim
|
||||
$match = trim($match);
|
||||
|
||||
if ($match) {
|
||||
// external url, skip it
|
||||
if (strpos($match, '//') !== false) {
|
||||
// add to imports list
|
||||
self::$imports[] = $match;
|
||||
continue;
|
||||
}
|
||||
|
||||
// url has a query, remove
|
||||
if (strpos($match, '?') !== false) {
|
||||
$match = substr($match, 0, strpos($match, '?'));
|
||||
}
|
||||
|
||||
if (strpos($match, '&') !== false) {
|
||||
$match = substr($match, 0, strpos($match, '&'));
|
||||
}
|
||||
|
||||
// get full path
|
||||
$path = realpath($this->get('_cssbase') . '/' . $match);
|
||||
|
||||
// already import, don't repeat!
|
||||
if (in_array($path, self::$imports)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get data
|
||||
$data .= $this->getText($path);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function compileLess($string, $path)
|
||||
{
|
||||
$less = new lessc();
|
||||
// add file directory
|
||||
$less->addImportDir($path);
|
||||
// add joomla media folder
|
||||
$less->addImportDir(JPATH_SITE . '/media');
|
||||
|
||||
try {
|
||||
return $less->compile($string);
|
||||
} catch (Exception $e) {
|
||||
return '/* LESS file could not be compiled due to error - ' . $e->getMessage() . ' */';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getText($file = null, $minify = true)
|
||||
{
|
||||
if ($file && is_file($file)) {
|
||||
$text = file_get_contents($file);
|
||||
|
||||
if ($text) {
|
||||
// process css files
|
||||
if ($this->getType() == 'css') {
|
||||
// compile less files
|
||||
if (preg_match('#\.less$#', $file)) {
|
||||
$text = $this->compileLess($text, dirname($file));
|
||||
}
|
||||
|
||||
if ($minify) {
|
||||
// minify
|
||||
$text = $this->cssmin($text, $file);
|
||||
}
|
||||
|
||||
// add to imports list
|
||||
self::$imports[] = $file;
|
||||
|
||||
if (strpos($text, '@import') !== false) {
|
||||
// store the base path of the current file
|
||||
$this->set('_cssbase', dirname($file));
|
||||
|
||||
// process import rules
|
||||
$text = $this->importCss($text, $file) . preg_replace(self::IMPORT_RX, '', $text);
|
||||
}
|
||||
|
||||
// store the base path of the current file
|
||||
$this->set('_imgbase', dirname($file));
|
||||
|
||||
// process urls
|
||||
$text = preg_replace_callback('#url\s?\([\'"]?([^\'"\))]+)[\'"]?\)#', array('WFPacker', 'processPaths'), $text);
|
||||
}
|
||||
// make sure text ends in a semi-colon;
|
||||
if ($this->getType() == 'javascript') {
|
||||
$text = rtrim(trim($text), ';') . ';';
|
||||
|
||||
if ($minify) {
|
||||
$text = $this->jsmin($text);
|
||||
}
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
protected function processPaths($data)
|
||||
{
|
||||
if (isset($data[1])) {
|
||||
if (strpos($data[1], '//') === false) {
|
||||
$path = parse_url($data[1], PHP_URL_PATH);
|
||||
|
||||
if (empty($path)) {
|
||||
$path = $data[1];
|
||||
}
|
||||
|
||||
// get query, if any, eg: ?v=273
|
||||
$query = parse_url($data[1], PHP_URL_QUERY);
|
||||
|
||||
if (empty($query)) {
|
||||
$query = "";
|
||||
} else {
|
||||
$query = "?" . $query;
|
||||
}
|
||||
|
||||
$path = str_replace(JPATH_SITE, '', realpath($this->get('_imgbase') . '/' . $path));
|
||||
|
||||
if ($path) {
|
||||
return "url('" . JURI::root(true) . str_replace('\\', '/', $path) . $query . "')";
|
||||
}
|
||||
|
||||
return "url('" . $data[1] . "')";
|
||||
}
|
||||
|
||||
return $data[1];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user