MD5 Hash and Timestamp Based File Naming Convention for Minified Assets in OpenMage

The openmage-cssjs-minify module generates minified asset filenames by combining an MD5 hash of the original file path with the Unix timestamp of the last modification, producing unique cache-busting names like d41d8cd98f00b204e9800998ecf8427e-1709254321.js.

The MD5 hash and timestamp based file naming convention for minified assets ensures that every compressed JavaScript or CSS file in OpenMage has a unique, deterministic identifier that automatically invalidates browser caches when source files change. This article examines the implementation in the fballiano/openmage-cssjs-minify repository, specifically within the observer model that intercepts HTTP responses and manages asset compression.

How the Naming Convention Works

The filename generation relies on three discrete components concatenated into a single string.

MD5 Hash of the Relative Path

In app/code/community/Fballiano/CssjsMinify/Model/Observer.php, the module calculates md5($path) where $path represents the asset's relative path on disk. This operation occurs at line 45 for JavaScript files and line 75 for CSS stylesheets, producing a 32-character hexadecimal hash that guarantees uniqueness across different source files.

File Modification Timestamp

Immediately after computing the hash, the module retrieves the source file's Unix modification time using filemtime($baseDir . $path) at line 46 for JS and line 76 for CSS. This timestamp serves as the cache-busting mechanism, ensuring that any modification to the source immediately generates a new filename.

Original Extension Preservation

The final component appends the original file extension—.js or .css—to complete the pattern: <md5-hash>-<timestamp>.extension.

Implementation in the Observer Model

The httpResponseSendBefore observer method handles the filename construction dynamically during the page rendering process.

For JavaScript assets (lines 44-48):

$time = filemtime($baseDir . $path);
$hash = md5($path) . "-$time.js";

For CSS assets (lines 75-78):

$time = filemtime($baseDir . $path);
$hash = md5($path) . "-$time.css";

Benefits of the MD5-Timestamp Pattern

This dual-component approach solves three critical problems in asset management:

  • Deterministic Uniqueness: The MD5 hash ensures that js/app.js and skin/js/app.js produce different filenames even if modified simultaneously, preventing collisions in the media/fbminify/ directory.
  • Automatic Cache Busting: Because the timestamp changes with every file save, browsers treat updated assets as new resources, eliminating stale cache issues without manual version query strings.
  • Simplified Cleanup: The dailyCron method (lines 22-35) parses the hash component to group related files, allowing the system to retain only the newest timestamp for each unique hash while deleting outdated versions.

Working with the Filename Convention

Developers can leverage this pattern both within the module's automated workflow and for custom implementations.

Accessing Minified URLs Programmatically

When the observer processes a response, it constructs the complete URL by combining the media base URL with the generated hash:

$time = filemtime($baseDir . $path);
$hash = md5($path) . "-$time.js";
$minifiedUrl = $mediaUrl . 'fbminify/' . $hash;

Manual Minification Outside the Observer

For custom scripts requiring manual compression:

$srcPath = '/var/www/magento/js/custom/script.js';
$baseDir = Mage::getBaseDir();
$mediaDir = Mage::getBaseDir('media');
$minDir = $mediaDir . '/fbminify/';

$time = filemtime($baseDir . $srcPath);
$hash = md5($srcPath) . "-$time.js";
$target = $minDir . $hash;

$minifier = new \MatthiasMullie\Minify\JS($baseDir . $srcPath);
$minifier->minify($target);

Cron-Based Cleanup Logic

The maintenance routine in dailyCron removes obsolete files by extracting the hash prefix:

$files = scandir($minifiedDir, SCANDIR_SORT_DESCENDING);
foreach ($files as $file) {
    $hash = explode('-', preg_replace('/\.(js|css)$/', '', $file))[0];
    // Retain only the first (newest) file per hash, delete others
}

Summary

  • The MD5 hash and timestamp based file naming convention combines md5($path) with filemtime() to create unique asset identifiers.
  • Filenames follow the pattern <md5>-<timestamp>.js or <md5>-<timestamp>.css as implemented in Observer.php lines 45-48 and 75-78.
  • This approach guarantees cache invalidation when source files change while preventing filename collisions across different asset paths.
  • The dailyCron method uses the hash component to group and clean up outdated minified versions automatically.

Frequently Asked Questions

How does the MD5 hash prevent filename collisions?

The hash is computed from the complete relative path of the source file, meaning js/app.js and skin/frontend/js/app.js produce different MD5 values. This ensures that identically named files in different directories receive unique minified filenames, preventing one asset from overwriting another in the media/fbminify/ storage directory.

What triggers a new timestamp in the filename?

Any modification to the source file updates its Unix modification time, which the filemtime() function captures at processing time. When the observer detects a newer timestamp, it generates a fresh filename with the updated timestamp, forcing browsers to download the updated asset rather than serving a cached version.

How does the module clean up old minified files?

The dailyCron method scans the minified directory and extracts the MD5 hash from each filename by splitting on the hyphen delimiter. Files sharing the same hash are grouped, and all but the newest timestamp version are deleted, preventing disk bloat while maintaining the most recent compressed assets.

Can I manually generate these filenames outside the observer?

Yes. By importing the MatthiasMullie\Minify library and using the same logic found in Observer.php—computing md5($path), appending filemtime(), and adding the extension—you can programmatically create minified files that follow the convention and remain compatible with the module's cleanup routines.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →