Skip to content

Instantly share code, notes, and snippets.

@Arifursdev
Last active May 27, 2023 19:50
Show Gist options
  • Save Arifursdev/899d0d71ed0ea4e3d62bf27a6b33275b to your computer and use it in GitHub Desktop.
Save Arifursdev/899d0d71ed0ea4e3d62bf27a6b33275b to your computer and use it in GitHub Desktop.
<?php
/*
USAGES
require __DIR__ . '/AssetsManager.php';
$assets = new AssetsManager( 'assets/', 'cache/');
<link rel="stylesheet" href="<?php echo $assets->getAssetUrl('css/style.min.css'); ?>">
<script src="<?php echo $assets->getAssetUrl('js/vendors.min.js', false); ?>" defer></script>
<script src="<?php echo $assets->getAssetUrl('js/app.min.js'); ?>" defer></script>
use at your own risk
*/
class AssetsManager {
private $assetPath;
private $cachePath;
/**
* AssetsManager constructor.
*
* @param string $assetPath The path to the asset files.
* @param string $cachePath The path to the cache folder.
*/
public function __construct( $assetPath, $cachePath ) {
$this->assetPath = $assetPath;
$this->cachePath = $cachePath;
}
/**
* Minify CSS content.
*
* @param string $content The CSS content to be minified.
* @return string The minified CSS content.
*/
private function minifyCSS( $content ) {
// Remove CSS comments (/* ... */)
$content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content);
// Remove leading and trailing whitespace
$content = trim($content);
// Remove whitespace around selectors, properties, and values
$content = preg_replace('/\s*([{}|:;,])\s*/', '$1', $content);
// Remove semicolons before closing braces
$content = preg_replace('/;\s*}/', '}', $content);
// Remove empty rules
$content = preg_replace('/[^{}]+{}/', '', $content);
// Remove trailing semicolons from rules
$content = preg_replace('/;\s*}/', '}', $content);
// Remove leading zeros from decimal values
$content = preg_replace('/(\s|:|,)0+\.(\d+)/', '$1.$2', $content);
// Remove units from zero values
$content = preg_replace('/(\s|:)0+([a-zA-Z]+)/', '$1$2', $content);
return $content;
}
/**
* Minify JS content.
*
* @param string $content The JS content to be minified.
* @return string The minified JS content.
*/
private function minifyJS( $content ) {
// Remove JS comments (// ... and /* ... */)
$content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content);
$content = preg_replace('/\/\/(.+)$/', '', $content);
// Remove leading and trailing whitespace
$content = trim($content);
// Remove line breaks and multiple whitespace
$content = preg_replace('/\s+/', ' ', $content);
// Remove unnecessary whitespace around operators and brackets
$content = preg_replace('/\s*([=!<>+\-*\/%&|^~?:]=|\+\+|--|\+=|-=|\*=|\/=|%=|&&|\|\||<<|>>|>>>)\s*/', '$1', $content);
$content = preg_replace('/\s*([{}()[\],;])\s*/', '$1', $content);
return $content;
}
/**
* Get the URL for the asset file, either from the cache or generate a new minified version.
*
* @param string $filePath The path to the asset file.
* @return string The URL of the asset file.
* @throws Exception If the file extension is invalid.
*/
public function getAssetUrl( $filePath, $minifyAndCache = true ) {
if ( $minifyAndCache === false ) {
return $this->assetPath . $filePath;
}
$extension = pathinfo( $filePath, PATHINFO_EXTENSION );
// Check if the file extension is valid (CSS or JS)
if ( $extension !== 'css' && $extension !== 'js' ) {
// Invalid file extension, throw an exception
throw new Exception( 'Invalid file extension. Only CSS and JS files are supported.' );
}
$cachedFile = $this->getCachedFilePath( $filePath );
// Check if the cached file exists and if the original file has been modified
if ( file_exists( $cachedFile ) && !$this->isFileModified( $filePath, $cachedFile ) ) {
// Retrieve the URL from the cache folder
return $this->getCacheUrl( $cachedFile );
}
// Generate the minified version
$minifiedFile = $this->generateMinifiedFile( $filePath, $extension );
// Move the minified file to the cache folder
$this->moveToCache( $minifiedFile, $cachedFile );
// Retrieve the URL from the cache folder
return $this->getCacheUrl( $cachedFile );
}
/**
* Generate a minified version of the asset file.
*
* @param string $filePath The path to the asset file.
* @param string $extension The file extension.
* @return string The path to the minified file.
*/
private function generateMinifiedFile( $filePath, $extension ) {
$fileContent = file_get_contents( $this->assetPath . $filePath );
$minifiedContent = '';
if ( $extension === 'css' ) {
// Minify CSS
$minifiedContent = $this->minifyCSS( $fileContent, 'css' );
} elseif ( $extension === 'js' ) {
// Minify JS
$minifiedContent = $this->minifyJS( $fileContent, 'js' );
}
// Get the original file name without the extension
$originalFileName = pathinfo( $filePath, PATHINFO_FILENAME );
// Generate the minified file name with the original file name and version
$minifiedFileName = $originalFileName . '.' . filemtime( $this->assetPath . $filePath ) . '.min.' . $extension;
// Get the directory path of the cache file
$cacheDirectory = dirname( $this->cachePath . $minifiedFileName );
// Create the directory if it doesn't exist
if ( !file_exists( $cacheDirectory ) ) {
mkdir( $cacheDirectory, 0777, true );
}
// Write the minified content to a new file
$minifiedFilePath = $this->cachePath . $minifiedFileName;
file_put_contents( $minifiedFilePath, $minifiedContent );
return $minifiedFilePath;
}
/**
* Check if the original asset file has been modified.
*
* @param string $filePath The path to the asset file.
* @param string $cachedFile The path to the cached file.
* @return bool Whether the original file has been modified or not.
*/
private function isFileModified( $filePath, $cachedFile ) {
$originalTimestamp = filemtime( $this->assetPath . $filePath );
$cachedTimestamp = filemtime( $cachedFile );
return $originalTimestamp > $cachedTimestamp;
}
/**
* Get the path to the cached file.
*
* @param string $filePath The path to the asset file.
* @return string The path to the cached file.
*/
private function getCachedFilePath( $filePath ) {
// Get the directory name of the asset file
$directoryName = pathinfo( $filePath, PATHINFO_DIRNAME );
// Get the original file name without the extension
$originalFileName = pathinfo( $filePath, PATHINFO_FILENAME );
// Generate a unique file name for the cached version with the original file name, directory, and version
$cachedFileName = $directoryName . '/' . $originalFileName . '.' . filemtime( $this->assetPath . $filePath ) . '.' . pathinfo( $filePath, PATHINFO_EXTENSION );
return $this->cachePath . $cachedFileName;
}
/**
* Move a file to the cache folder.
*
* @param string $sourceFile The path to the source file.
* @param string $destinationFile The path to the destination file.
* @return void
*/
private function moveToCache( $sourceFile, $destinationFile ) {
// Create the parent directory if it doesn't exist
$parentDirectory = pathinfo( $destinationFile, PATHINFO_DIRNAME );
if ( !file_exists( $parentDirectory ) ) {
mkdir( $parentDirectory, 0777, true );
}
// Move the file to the cache folder
rename( $sourceFile, $destinationFile );
}
/**
* Get the URL of the cached file.
*
* @param string $cachedFile The path to the cached file.
* @return string The URL of the cached file.
*/
private function getCacheUrl( $cachedFile ) {
// Get the relative path to the cached file
$relativePath = str_replace( $this->cachePath, '', $cachedFile );
// Combine the cache folder path with the relative path
$cacheUrl = rtrim( $this->cachePath, '/' ) . '/' . ltrim( $relativePath, '/' );
return $cacheUrl;
}
/**
* Delete all cache files.
*
* @return void
*/
public function deleteCacheFiles() {
foreach (glob($dir) as $file) {
if (is_dir($file)) {
rmrf("$file/*");
rmdir($file);
} else {
unlink($file);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment