ConLite/conlite/classes/class.output_compressor.php

217 Zeilen
8.5 KiB
PHP

<?php
/**
* Project:
* ConLite Content Management System
*
* Description:
* Class for creating and outputing only one compressed file
*
* Requirements:
* @con_php_req 5.0
*
*
* @package ConLite Content Types
* @version 1.0.0
* @author Rene Mansveld
* @copyright ConLite Team <www.conlite.org>
* @license http://www.conlite.org/license/LIZENZ.txt
* @link http://www.conlite.org
* @since file available since ConLite release 2.0.0
*
* {@internal
* created 2012-12-15
*
* $Id$:
* }}
*
*/
/**
* Class for creating and outputing only one compressed file
*/
abstract class Output_Compressor {
/**
* Worker-Function generate()
*
* @param string $sCachePath - Path to the cache folder
* @param array string $asFiles - Files to include in the compressed output file
* @return string - Returns the name of the compressed file in the cache folder
* @access public
*/
public function generate($sCachePath, $asFiles, $sFileExt, $sFrontendPath) {
# Check for input files
if ((!is_array($asFiles)) || (!count($asFiles))) {
return false;
}
$lastCacheTime = 0;
$lastChangeTime = 0;
# Generate a unique filename for the compressed file
$md5 = md5(implode('', $asFiles));
# Check if a file with this name exists in the cache folder
$found = self::findMatchingFilenames($sCachePath, strtolower($sFileExt), $md5);
if ($found !== false) {
# Matching files were found, check which one ist the latest one
for ($i = 0, $n = count($found); $i < $n; $i ++) {
$time = substr($found[$i], strlen($md5), 14);
if ($time > $lastCacheTime) {
$lastCacheTime = $time;
}
}
}
# Get the date and time of the last modified input file
for ($i = 0, $n = count($asFiles); $i < $n; $i ++) {
if (file_exists($asFiles[$i])) {
$time = date('YmdHis', filemtime($asFiles[$i]));
if ($time > $lastChangeTime) {
$lastChangeTime = $time;
}
}
}
if ($lastCacheTime == $lastChangeTime) {
# If the cache file has the date and time of the last changed file, just return it's name
return $md5 . $lastCacheTime . '.' . $sFileExt;
} else {
# Create new cache files
$content = '';
# Read the input files
for ($i = 0, $n = count($asFiles); $i < $n; $i ++) {
if (file_exists($asFiles[$i])) {
$cnt = file_get_contents($asFiles[$i]);
# Remove file include commands (those files were added to the array or HTML head section)
if (strrpos($asFiles[$i], '/') > 0) {
$path = substr($asFiles[$i], 0, (strrpos($asFiles[$i], '/') + 1));
} else {
$path = '';
}
$p1 = strpos(strtolower($cnt), '@import url(');
while ($p1 !== false) {
$p2 = strpos($cnt, ');', $p1);
$cnt = substr($cnt, 0, $p1) . substr($cnt, ($p2 + 2));
$p1 = strpos(strtolower($cnt), '@import url(');
}
$content .= $cnt . "\n";
}
}
# Compress the content
switch ($sFileExt) {
case 'css':
# Remove '/* ... */' comments
$content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content);
# Convert line breaks and tabs to a single space
$content = str_replace(array("\r\n", "\r", "\n", "\t"), ' ', $content);
# Convert multiple spaces to a single space
while (strpos($content, ' ') !== false) {
$content = str_replace(' ', ' ', $content);
}
# Remove preceding and trailing spaces
$content = trim($content);
# Correct paths starting with '../' to start with the client HTML path
$content = str_replace(array('../../', '../'), $sFrontendPath, $content);
break;
case 'js':
# Convert tabs to a single space
$content = str_replace("\t", ' ', $content);
# Convert multiple spaces to a single space
while (strpos($content, ' ') !== false) {
$content = str_replace(' ', ' ', $content);
}
# Remove blank lines
$content = str_replace(array("\r\n\r\n", "\r\r", "\n\n"), "\n", $content);
# Remove preceding and trailing spaces from each line and
$aCnt = explode("\n", $content);
for ($i = 0, $n = count($aCnt); $i < $n; $i ++) {
$aCnt[$i] = trim($aCnt[$i]);
}
$content = implode("\n", $aCnt);
# Remove remaining blank lines
while (strpos($content, "\n\n") !== false) {
$content = str_replace("\n\n", "\n", $content);
}
break;
}
# Save a new uncompressed cache file, use date and time of the last modified file in the filename
$fp = fopen($sCachePath . $md5 . $lastChangeTime . '.' . $sFileExt, 'w');
fwrite($fp, $content);
fclose($fp);
if (extension_loaded('zlib')) {
# Save a new compressed cache file, use date and time of the last modified file in the filename
$fp = fopen($sCachePath . $md5 . $lastChangeTime . '.' . $sFileExt . '.gz', 'w');
fwrite($fp, gzencode($content, 6, FORCE_GZIP));
fclose($fp);
}
# Delete all older versions of the cache file
for ($i = 0, $n = count($found); $i < $n; $i ++) {
@unlink($sCachePath . $found[$i]);
@unlink($sCachePath . $found[$i] . '.gz');
}
# Return the name of the new cache file
return $md5 . $lastChangeTime . '.' . $sFileExt;
}
}
/**
* Worker-Function output()
*
* @param string $sCachePath - Path to the cache folder
* @param string $sFilename - Name of the file to deliver
* @param string $sContentType - Content-Type of the file (eg 'css', 'html' or 'javascript')
*/
public function output($sCachePath, $sFilename, $sContentType) {
header('Content-Type: text/' . $sContentType);
if ((strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) && (extension_loaded('zlib')) && (is_file($sCachePath . $sFilename . '.gz')) && (!ini_get('zlib.output_compression'))) {
header('Content-Length: ' . filesize($sCachePath . $sFilename . '.gz'));
header('Content-Encoding: gzip');
readfile($sCachePath . $sFilename . '.gz');
} else {
header('Content-Length: ' . filesize($sCachePath . $sFilename));
readfile($sCachePath . $sFilename);
}
}
/**
* private helper function findMatchingFilenames()
*
* @param string $sCachePath - Path to the cache folder
* @param string $sFileExt - filename extension (eg css)
* @param string $sFilenamePart - Beginning part of the filename
* @return - Returns an array of the matching files found or false
* @access private
*/
private function findMatchingFilenames($sCachePath, $sFileExt, $sFilenamePart) {
$pattern = '[0123456789]';
# Find only files with 14 numerical characters in the filename (yyyymmddHHiiss)
$files = glob($sCachePath . $sFilenamePart . str_repeat($pattern, 14) . '.' . $sFileExt);
if (empty($files)) {
# No suiting filename was found
return false;
} else {
# Return the filenames of the found files
return array_map('basename', $files);
}
}
}
?>