/plugins/system/jsntplframework/libraries/joomlashine/compress/js.php
PHP | 467 lines | 328 code | 63 blank | 76 comment | 48 complexity | 431128405e1f11982936af032e153748 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0, 0BSD, MIT, LGPL-2.1
- <?php
- /**
- * @version $Id$
- * @package JSNExtension
- * @subpackage TPLFramework
- * @author JoomlaShine Team <support@joomlashine.com>
- * @copyright Copyright (C) 2012 JoomlaShine.com. All Rights Reserved.
- * @license GNU/GPL v2 or later http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Websites: http://www.joomlashine.com
- * Technical Support: Feedback - http://www.joomlashine.com/contact-us/get-support.html
- */
- // No direct access to this file
- defined('_JEXEC') or die('Restricted access');
- // Import necessary Joomla libraries
- jimport('joomla.filesystem.folder');
- jimport('joomla.filesystem.file');
- /**
- * Javascript Compression engine
- *
- * @package TPLFramework
- * @subpackage Plugin
- * @since 1.0.0
- */
- abstract class JSNTplCompressJs
- {
- /**
- * Method to parse all link to css files from the html markup
- * and compress it
- *
- * @param string $htmlMarkup HTML Content to response to browser
- *
- * @return void
- */
- public static function compress ($scripts)
- {
- static $compressedFiles;
- // Get object for working with URI
- $uri = JUri::getInstance();
- // Generate link prefix if current scheme is HTTPS
- $prefix = '';
- if ($uri->getScheme() == 'https')
- {
- $prefix = $uri->toString(array('scheme', 'host', 'port'));
- }
- // Initialize variables
- $groupIndex = 0;
- $groupType = 'default';
- $groupFiles = array();
- $compress = array();
- // Sometime, script file need to be stored in the original location and file name
- $document = JFactory::getDocument();
- $leaveAlone = preg_split('/[\r\n]+/', $document->params->get('compressionExclude'));
- // We already know some files must be excluded from compression
- $leaveAlone[] = 'modal.js';
- $leaveAlone[] = 'tiny_mce.js';
- $leaveAlone[] = 'tinymce.min.js';
- // Parse script tags
- foreach ($scripts as $key => $line)
- {
- // Set default group
- $attributes['group'] = 'default';
- $attributes['src'] = $key;
- if (!isset($attributes['src']))
- {
- continue;
- }
- if(isset($attributes['type']) && $attributes['type'] == "application/ld+json"){
- continue;
- }
- // Add to result list if this is external file
- if ( ! ($isInternal = JSNTplCompressHelper::isInternal($attributes['src'])) OR strpos($attributes['src'], '//') === 0)
- {
- // Add collected files to compress list
- if ( ! empty($groupFiles))
- {
- $compress[] = array(
- 'files' => $groupFiles[$groupIndex],
- 'group' => $groupType
- );
- $groupFiles = array();
- }
- $compress[] = array('src' => $attributes['src']);
- continue;
- }
- // Add to result list if this is dynamic generation content
- $questionPos = false;
- if (($questionPos = strpos($attributes['src'], '?')) !== false)
- {
- $isDynamic = (substr($attributes['src'], $questionPos - 4, 4) == '.php');
- $path = JSNTplCompressHelper::getFilePath(substr($attributes['src'], 0, $questionPos));
- // Check if this is a dynamic generation content
- if ( ! $isDynamic AND JSNTplCompressHelper::isInternal($attributes['src']))
- {
- $isDynamic = ! is_file($path);
- }
- if ($isDynamic)
- {
- // Add collected files to compress list
- if ( ! empty($groupFiles))
- {
- $compress[] = array(
- 'files' => $groupFiles[$groupIndex],
- 'group' => $groupType
- );
- $groupFiles = array();
- }
- $compress[] = array('src' => $attributes['src']);
- continue;
- }
- }
- // Check if reserving script file name is required
- $scriptName = basename($questionPos !== false ? $path : $attributes['src']);
- if (in_array($scriptName, $leaveAlone))
- {
- $attributes['group'] = 'reserve|' . $scriptName;
- }
- // Create new compression group if reserving script file name is required
- if ($attributes['group'] != $groupType)
- {
- // Add collected files to compress list
- if (isset($groupFiles[$groupIndex]) AND ! empty($groupFiles[$groupIndex]))
- {
- $compress[] = array(
- 'files' => $groupFiles[$groupIndex],
- 'group' => $groupType
- );
- }
- // Increase index number of the group
- $groupIndex++;
- $groupType = $attributes['group'];
- }
- // Initial group
- if ( ! isset($groupFiles[$groupIndex]))
- {
- $groupFiles[$groupIndex] = array();
- }
- $src = $attributes['src'];
- $queryStringIndex = strpos($src, '?');
- if ($queryStringIndex !== false)
- {
- $src = substr($src, 0, $queryStringIndex);
- }
- // Add file to the group
- $groupFiles[$groupIndex][] = preg_match('/^reserve\|(.+)$/', $groupType) ? $attributes['src'] : $src;
- }
- // Add collected files to result list
- if (isset($groupFiles[$groupIndex]) AND ! empty($groupFiles[$groupIndex]))
- {
- $compress[] = array(
- 'files' => $groupFiles[$groupIndex],
- 'group' => $groupType
- );
- }
- // Initial compress result
- $compressResult = array();
- $fileCompressed = array();
- // Get template details
- $templateName = JFactory::getApplication()->getTemplate();
- // Generate path to store compressed files
- if ( ! preg_match('#^(/|\\|[a-z]:)#i', $document->params->get('cacheDirectory')))
- {
- $compressPath = JPATH_ROOT . '/' . rtrim($document->params->get('cacheDirectory'), '\\/');
- }
- else
- {
- $compressPath = rtrim($document->params->get('cacheDirectory'), '\\/');
- }
- $compressPath = $compressPath . '/' . $templateName . '/';
- // Create directory if not exists
- if ( ! is_dir($compressPath))
- {
- JFolder::create($compressPath);
- }
- // Loop to each compress element to compress file
- $modifiedFlag = false;
- foreach ($compress AS $group)
- {
- // Ignore compress when group is a external file
- if (isset($group['src']))
- {
- $compressResult[] = sprintf('<script src="%s" type="text/javascript"></script>', $group['src']);
- $fileCompressed[] = $group['src'];
- continue;
- }
- // Check if reserving script file name is required
- if (isset($group['group']) AND preg_match('/^reserve\|(.+)$/', $group['group']))
- {
- foreach ($group['files'] as $gFile)
- {
- $compressResult[] = sprintf('<script src="%s" type="text/javascript"></script>', $gFile);
- $fileCompressed[] = $gFile;
- }
- continue;
- }
- // Generate compress file name
- $compressFile = md5(implode('', $group['files'])) . '.js';
- $lastModified = 0;
- $splittedFiles = array();
- // Check last modified time for each file in the group
- foreach ($group['files'] AS $file)
- {
- $path = JSNTplCompressHelper::getFilePath($file);
- $lastModified = (is_file($path) && @filemtime($path) > $lastModified) ? @filemtime($path) : $lastModified;
- }
- if (@filemtime($compressPath . $compressFile) < $lastModified)
- {
- $modifiedFlag = true;
- }
- // Compress group when expired
- if ( ! is_file($compressPath . $compressFile) OR @filemtime($compressPath . $compressFile) < $lastModified)
- {
- // Preset compression buffer
- $buffer = '';
- // Preset some variables to hold compression status
- $processedFiles = array();
- $maxFileSize = 1024 * (int) $document->params->get('maxCompressionSize');
- $currentSize = 0;
- // Read content of each file and write it to the cache file
- foreach ($group['files'] AS $file)
- {
- $filePath = JSNTplCompressHelper::getFilePath($file);
- // Skip when cannot access to file
- if ( ! is_file($filePath) OR ! is_readable($filePath))
- {
- continue;
- }
- // Prepend path to source file
- $source = ($currentSize == 0 ? '' : "\n\n")
- . '/* FILE: ' . str_replace(str_replace('\\', '/', JPATH_ROOT), '', str_replace('\\', '/', $filePath)) . ' */'
- . "\n" . file_get_contents($filePath);
- // Get length of processed content
- $length = strlen($source);
- if ($length > $maxFileSize OR ($currentSize + $length) > $maxFileSize)
- {
- // Write buffer to cache file
- JFile::write($compressPath . $compressFile, $buffer);
- // Rename created cache file
- if ($currentSize > 0)
- {
- $newFileName = md5(implode('', $processedFiles)) . '.js';
- JFile::move($compressPath . $compressFile, $compressPath . $newFileName);
- // Save every compressed file associated with this page for maintenance later
- $compressedFiles[] = str_replace('\\', '/', $compressPath) . $newFileName;
- // Store splitted file URL for later reference
- $splittedFiles[] = $prefix . str_replace(str_replace('\\', '/', JPATH_ROOT), JUri::root(true), str_replace('\\', '/', $compressPath)) . $newFileName;
- }
- // Reset compression buffer
- $buffer = '';
- // Reset current file size
- $currentSize = $length;
- $processedFiles = array($filePath);
- }
- else
- {
- // Update current file size
- $currentSize += $length;
- $processedFiles[] = $filePath;
- }
- // Append processed content to buffer
- $buffer .= $source . ";\n";
- }
- // Write buffer to cache file
- JFile::write($compressPath . $compressFile, $buffer);
- // Save every compressed file associated with this page for maintenance later
- $compressedFiles[] = str_replace('\\', '/', $compressPath) . $compressFile;
- // Prepend splitted compress files into trackable compress file
- if (count($splittedFiles))
- {
- for ($n = count($splittedFiles), $i = $n - 1; $i >= 0; $i--)
- {
- JSNTplCompressHelper::prependIntoFile("// Include: {$splittedFiles[$i]}" . ($i + 1 < $n ? "\n" : "\n\n"), $compressPath . $compressFile);
- }
- }
- }
- else
- {
- // Read compressed file for list of splitted file
- $include = file_get_contents($compressPath . $compressFile);
- $include = substr($include, 0, strpos($include, "\n\n"));
- // Parse splitted compress file
- foreach (explode("\n", $include) AS $line)
- {
- if (strpos($line, '// Include: ') === 0)
- {
- $splittedFiles[] = str_replace('// Include: ', '', $line);
- }
- }
- }
- // Load splitted compress file
- if (count($splittedFiles))
- {
- foreach ($splittedFiles AS $file)
- {
- $compressResult[] = sprintf('<script src="%s" type="text/javascript"></script>', $file);
- $fileCompressed[] = $file;
- }
- }
- // Add compressed file to the compress result list
- $compressUrl = str_replace(str_replace('\\', '/', JPATH_ROOT), JUri::root(true), str_replace('\\', '/', $compressPath)) . $compressFile;
- $compressResult[] = sprintf('<script src="%s" type="text/javascript"></script>', $prefix . $compressUrl);
- $fileCompressed[] = $prefix . $compressUrl;
- }
- // Verify if stylesheets associated with this page has been changed
- if (isset($compressedFiles))
- {
- $trackFile = $compressPath . 'tracking.php';
- $pageLink = JUri::current();
- $cleanUp = array();
- if (file_exists($trackFile))
- {
- if ( ! file_exists("{$trackFile}.lock"))
- {
- // Get tracking data
- include $trackFile;
- if (isset($tracking) && isset($tracking[$pageLink]) && isset($tracking[$pageLink]['js']))
- {
- foreach ($tracking[$pageLink]['js'] as $file)
- {
- if ( ! in_array($file, $compressedFiles))
- {
- // Store obsolete file to be removed
- $cleanUp[] = $file;
- }
- }
- // Remove obsolete file only if not used in another page
- foreach ($cleanUp as $file)
- {
- $removable = true;
- foreach ($tracking as $link => $assets)
- {
- if ($pageLink == $link)
- {
- continue;
- }
- if (in_array($file, $assets['js']))
- {
- $removable = false;
- break;
- }
- }
- if ($removable && !$modifiedFlag)
- {
- JFile::delete($file);
- }
- }
- }
- }
- }
- else
- {
- // Clean all unmaintained compressed files
- if ($files = glob($compressPath . '*.js'))
- {
- foreach ($files as $file)
- {
- $file = str_replace('\\', '/', $file);
- if ( ! in_array($file, $compressedFiles))
- {
- JFile::delete($file);
- }
- }
- }
- }
- // Update tracking file if not locked
- if ( ! file_exists("{$trackFile}.lock"))
- {
- // Create lock file
- $content = 'Updating';
- JFile::write("{$trackFile}.lock", $content);
- // Preset tracking array
- if ( ! isset($tracking))
- {
- $tracking = array($pageLink => array());
- }
- $tracking[$pageLink]['js'] = $compressedFiles;
- // Update tracking data
- $content = "<?php\n\$tracking = json_decode('" . json_encode($tracking) . "', true);\n?>";
- // Update tracking file
- JFile::write($trackFile, $content);
- // Remove lock file
- JFile::delete("{$trackFile}.lock");
- }
- }
- return $fileCompressed;
- }
- }