CSS-Dateien mit PHP zusammenführen und komprimieren

Das Thema ist eigentlich ein alter Hut. Im Internet finden sich zahlreiche Anleitungen, um CSS-Dateien via PHP zu vereinen und zu minimieren. Jedoch ist kaum ein Tutorial vollständig. So manches Script bietet nur rudimentäre Funktionen oder es fehlt die Hälfte. Durch das Redesign meines Blogs habe ich mich dazu entschieden, meine Stylesheets diesmal nicht manuell zu komprimieren und zusammenzuführen. Ich habe da mittlerweile eine gute Struktur reinbekommen, mit der ich wunderbar arbeiten kann. Aber beim Seitenaufruf sollen keine drei Stylesheets laden. Nein, stattdessen nur ein Einziges. Da kam mir natürlich der Gedanke, das per PHP-Script zu erledigen.

Zuerst die Anforderungen bestimmen

Nach ein bisschen Recherche und reindenken in den Code ist ein Script entstanden, das meinen Anforderungen gerecht wird. Doch was muss das Script leisten können? Einerseits müssen sich beliebig viele CSS-Dateien zusammenfügen lassen. Anderseits soll anschließend der Output von überflüssigen Leerzeichen, Leerzeilen, Semikolons etc. befreit werden. Ansonsten geht das zulasten der Ladezeit der Webseite. Für meine Begriffe ist es immer noch ein Unterschied, ob ich 50 KB laden muss oder nur schlanke 30 KB. Gerade mobile Nutzer können davon ein Liedchen singen. Okay, und an dritter Stelle kommen dann noch Optimierungen wie Caching, Komprimierung, Änderungsprüfung und Ablaufdatum.

Ladezeiten minimieren durch CSS Komprimierung
Ladezeiten minimieren durch CSS Komprimierung

Grobe Funktionsweise und das fertige Script

Als Ausgangspunkt diente mir das Minify-Script von Manas Tungare. Dieses macht aber beim Komprimieren einige Fehler. Da habe ich mir selbst Gedanken drum gemacht. Immerhin weiß ich als Webdesigner auch, wo überflüssige Zeichen auftauchen. Mittels der Funktion str_replace lassen sich die meisten Ausdrücke ersetzen. Ganz simple eben. Etwas Kopfzerbrechen bereitete mir die Problematik, dass das PHP-Script beim Seitenaufruf immer wieder neu abgerufen wird. Normalerweise sollte der Status beim erneuten Aufruf von 200 - OK auf 304 - Not Modified wechseln. Das spart Zeit und Ressourcen. Hier half mir die Methode von CastlesBlog.com auf die Sprünge. Man überprüft einfach das Alter der CSS-Dateien und gibt es dem PHP-Script per HTTP-Header mit. Ändert sich etwas an den Files, wird der Status anhand des Änderungsdatums neu erfasst.

Ich stelle das fertige Script hier zur Verfügung. Bitte beachtet die Lizenzangaben. Da Manas Tungare sein Script unter einer Creative Commons Lizenz anbietet, werde ich dies so belassen.

<?php
/**
* On-the-fly CSS Compression
* Copyright (c) 2009 and onwards, Manas Tungare
* Fork/Remix: Copyright (c) 2015 GFX-Stylez.blog
* Creative Commons Attribution, Share-Alike
* 
*/
/* Add your CSS files to this array (THESE ARE ONLY EXAMPLES) */
$cssFiles = array(
"stylesheet.css",
"stylesheet-2.css",
"stylesheet-3.css",
);
/**
* Ideally, you wouldn't need to change any code beyond this point.
*/
$buffer = "";
foreach ($cssFiles as $cssFile) {
$buffer .= file_get_contents($cssFile);
}
    // Remove comments, space after colons, withespaces, unnecessary chars
    $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
    $buffer = str_replace(array("\r\n", "\r", "\n", "\t", '  ', '    ', '    '), '', $buffer);
    $buffer = str_replace(';}', '}', $buffer);
    $buffer = str_replace(', ', ',', $buffer);
    $buffer = str_replace(' ,', ',', $buffer);
    $buffer = str_replace(' ;', ';', $buffer);
    $buffer = str_replace('; ', ';', $buffer);
    $buffer = str_replace(': ', ':', $buffer);
    $buffer = str_replace(' >', '>', $buffer);
    $buffer = str_replace('> ', '>', $buffer);
    $buffer = str_replace(' {', '{', $buffer);
    $buffer = str_replace('{ ', '{', $buffer);
    $buffer = str_replace('} ', '}', $buffer);
    $buffer = str_replace(' }', '}', $buffer);
// Enable GZip encoding
ob_start("ob_gzhandler");
/**
* Set HTTP/1.0 304 Not Modified 
* Source: http://castlesblog.com/2010/august/14/php-javascript-css-minification
*/
$modified = 0;
foreach($cssFiles as $cssFile) {        
    $age = filemtime($cssFile);
    if($age > $modified) {
        $modified = $age;
    }
}
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $modified) {
    header("HTTP/1.0 304 Not Modified");
} else {
    header ("Last-Modified: ".gmdate("D, d M Y H:i:s", $modified )." GMT");}
// Cache for 1 day
$offset = 60 * 60 * 24;
// Enable caching
header('Cache-Control: max-age='.$offset.'');
// Set expire
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $offset) . ' GMT');
// Set the correct MIME type, because Apache won't set it for us
header("Content-type: text/css");
// Write everything out
echo($buffer);
?>

Speichert den Quellcode als PHP-Datei ab und legt diese in euer CSS-Verzeichnis. Das Script bindet ihr entsprechend dem Beispiel in euer HTML-Dokument ein:

<link rel="stylesheet" href="/css/minify.php" type="text/css" media="screen">

.htaccess Anpassung: aus PHP mach CSS

Wer nun gerne sein PHP-Script augenscheinlich in eine CSS-Datei umbenennen will, kann das einfach über die .htaccess erledigen. Nachfolgend ein Beispiel:

<IfModule mod_rewrite.c>
  RewriteRule ^css/stylesheet\.css$ /css/minify.php [QSA,L]
</IfModule>

Jetzt müsst ihr nur noch den neuen Namen in eurem HTML-Dokument ändern.

So einfach kann es gehen. Man behält die Übersicht über seine Stylesheets und gleichzeitig wird der Output deutlich verkleinert. Also eine Win-win-Situation für alle Seiten.


Avatar von reraiseace
Autor: Markus Werner (reraiseace) Twitterreraiseace, Google+reraiseace, Twittercb_werner
Ich bin Redaktionsvolontär bei der COMPUTER BILD in Hamburg, Fernstudent am Deutschen Journalistenkolleg und schreibe auf re{raise}ace privat über Webdesign und Programmierung. Seit 2015 schrieb ich auch regelmäßig für andere Medien.

4 Kommentare – Schreib mir deine Meinung!

Fülle bitte die nachstehenden Felder aus. Angaben mit einem Sternchen sind Pflichtangaben. Deine E-Mail-Adresse wird nicht veröffentlicht.

  1. Kommentar von Breu Michael · · #

    Hallo,

    das Script ist super – besten Dank dafür!!!!!
    einige Fragen habe ich – evtl. gibts Hilfe dazu:

    ich möchte das Script auch für die Einbindung von Javascript-Dateien verwenden – dazu müßte die “Komprimierung” entfernt werden. Da ich leider nicht mit PHP-Kenntnissen gesegnet bin müßte ich wissen – welchen Teil genau von dem Script entfernt werden muss/darf!

    mir ist natürlich bewusst, dass dies kein Support-Forum ist – über einen Tipp wäre ich trotzdem sehr dankbar!

    Grüße Breu

  2. Kommentar von reraiseace · · #

    Gern geschehen. Im Prinzip kannst du das Skript auch für JavaScript verwenden. Entferne bzw. ersetze die Anweisungen für die buffer Variable ab // Remove comments, space after colons, withespaces, unnecessary chars. Als kleine Hilfestellung kannst du dir das Skript bei snippetrepo.com anschauen. Ganz unten solltest du dann noch den MIME-Type von css auf javascript ändern. Ich habe es nicht getestet, sollte aber so funktionieren. An der Komprimierung kann man aber noch schrauben. Kannst mir gern ein Feedback geben, obs geklappt hat.

  3. Kommentar von Sabine · · #

    Hi Markus,

    erstmal danke für deine super Anleitung! Bei mir hat das wunderpar geklappt!

    Ich habe eine Frage zum cache. Wenn ich das php Dokument umbenenne so wie bei dir beschrieben, wird sie dann auch wie eine normale css Datei gecached?

  4. Kommentar von reraiseace · · #

    Hallo Sabine, gern geschehen! Also wenn du die php-Datei via Serverkonfiguration umbenennst und dort auch den entsprechenden Expires header gesetzt hast, dann verfällt sich die php-Datei am Ende wie eine CSS-Datei.