Versionsnummern für Dateien erzeugen

| 5 Kommentare

Für verschiedene Anwendungen ist es recht praktisch, wenn man einer oder mehreren Dateien eine Versionsnummer zuordnen kann. Ein einfaches Beispiel wäre eine Versionsnummer in Image-, CSS- oder JS-Links, um neuere Versionen in den Cache zu bekommen.

Die Funktion sucht sich aus den Dateien den neusten Zeitstempel und nimmt diesen Wert als Grundlage für den Versionschlüssel/CacheKey. Als zweiten Parameter kann ein eigener Wert mit verarbeitet werden, falls der Zeitstempel nicht reicht.

Zuletzt kann der Wert mit einer Callbackfunktion bearbeitet werden, um z.B. einen Hashwert zu bilden.

/**
 * Generate a Versionnumber/-key for one or more Files
 *
 * @param  string|array $files
 * @param  integer|string $salt OPTIONAL
 * @param  string $callback OPTIONAL (null)
 * @param  boolean $throwException if a file does not exist OPTIONAL (false)
 * @return integer|string
 * @throws Exception
 */
function getFileVersion($files, $salt = '', $callback = null, $throwException = false)
{
  $version = 0;

  foreach ((array)$files as $file) {
    if (!file_exists($file)) {
      if ($throwException) {
        throw new Exception('File ' . $file . ' does not exist');
      }
      continue;
    }
    $version = max($version, filemtime($file));
  }

  $version .= $salt;
  return null === $callback ? $version : call_user_func($callback, $version);
}

Zur Verwendung gibt es nicht viel zu sagen.

<?php
$version = getFileVersion('/path/to/file');

oder

<?php
$version = getFileVersion(
   array('/path/to/file', '/path/to/another/file'), 'mySalt', 'md5', true);

Einfach, aber vielleicht mal nützlich.

5 Kommentare

  1. Hm, eigentlich eine nette Idee.
    Aber, irgendwie erscheint mir das ganze zu “mühsam”.
    Wieso nicht einfach eine globale Versionsnummer/String benutzen, die man bei jedem Deployment automatisch erhöht bzw beim String ändert?
    Wäre imho viel einfacher und würde keinen Overhead erzeugen (Array erstellen, prüfen ob die Dateie existieren usw.)

    Vorallem scheint mir dein 2. Beispielcode falsch!

    Deine Funktion hat nur 4 Parameter, du rufst sie aber mit 5 auf!;) da fehlt noch ne Klammer zu nach dem 2. Pfad

  2. Stimmt, da fehlte eine Klammer. Habe es korrigiert. Mit einer globalen Versionsnummer wäre es sicher einfacher, aber dann würde sich der Cache auch alle Dateien nochmal holen, auch wenn diese nicht geändert wurden. So kannst du z.B. eine CSS-Datei ändern und alles andere ist davon nicht betroffen.

  3. @raktek: Globale Versionsnummern haben den Nachteil dass sie global sind. Ändere ich also bei einem Deployment nur eine Datei, dann würde ich mit einer globalen Versionsnummer alle Clients dazu bringen, alle statischen Dateien erneut herunterzuladen. Das ist unnötiger Traffic und unnötige Ladezeit für den Besucher, gerade wenn man häufiger (täglich?) deployed.

    Aber auch die Methode von Daniel mit der filemtime() hat Nachteile, die man nicht verschweigen sollte. Wenn ich nämlich mehrere Apache-Server habe, die jeweils lokal die Dateien liegen haben, dann haben diese eventuell unterschiedliche Modifizierungszeiten bei den statischen Dateien, je nachdem auf welchem Apache ein Request landet gibt es also unterschiedliche Versionsnummern, was zu Problemen führen kann.

  4. Hi,

    ich habe da noch eine andere Lösung für das Problem.
    Ich arbeite direkt mit der .htaccess Datei
    und schneide den “Versionsstring” heraus, so dass ich immer eine Datei habe, bei der ich alle Änderungen vornehmen kann und ich trotzdem die Möglichkeit habe dem User eine neue Datei vor zu setzen.

    RewriteRule ^(css|js)/(.*)\.(v_.*)\.(js|css)$ /$1/$2.$4

    Hier ist meine Anleitung dazu:
    http://www.fractalcenter.de/2011/04/die-unvertraglichkeit-von-javascriptcss-dateien-und-browser-cache/

  5. @Michael: Du hast recht, wenn man mehrere Apachen laufen hat, dann kann es passieren, dass man verschiedene Versionsnummern hat. In erster Linie geht es darum, dass Caches wie Squid oder Varnish die neuen Versionen erkennen.

    @MaikL: Die Erkennung mit filetime() hat auch noch einen anderen Grund: Innerhalb der Anwendung können die benötigten Dateinamen gasammelt und zu einer zusammengefasst werden, dann bestimmt die neuste Datei die Versionsnummer. So können dann beliebig viele CSS/JS-Dateien eingebunden werden und es gibt nur einen Request für alles.

Hinterlasse eine Antwort

Pflichtfelder sind mit * markiert.


Schlagwörter: A/B-Test, AbstractType, Adapter, AddOn, Administration, Ajax, Amazon, Animation, Annotations, Anonyme Klasse, Ant, Apache, API, Array, ArrayAccess, Attachment, Auftrag, Ausbildung, Auswertung, Authentifizierung, AutoLoader, AWS, Bedienung, Bedingung, Benchmark, Berechtigung, Berlin, Bildbearbeitung, Bildschirmfoto, Blog, Blogroll, BOM, Bootstrap, Bot, Browser, Bugtracker, Byte Order Mark, Bücher, Cache, CakePHP, Call-Center, Callback, CamelCase, Canvas, Captcha, CDN, Cheatsheet, CLI, Clickout, Closure, Cloud, CodeSniffer, Collection, Community, Comparator, Config, Contest, Controller, Converter, CouchDB, Countable, Cronjob, CRUD, CSS, CSV, CustomLibrary, Custom_Model, Daemon, Data Mapper, Datei, Datenbank, Datenstruktur, Datentypen, Dating, Datum, Debug, Decorator, Dekorierer, Design, Design Patterns, Doctrine, Dokumentation, Dump, Duplikat, each, EC2, Eclipse, Email, Entwicklung, Entwurfsmuster, Enum, Erweiterung, Event, Eventhandling, Exception-Handling, Extension, Facebook, Factory, Fallback, Fehler, Fehlermeldung, Filter, Firefox, Flash, flexigrid, Foreach, Formatierung, Formular, Framework, FTP, Funktion, Futon, ga:pi(), Getter, Google Analytics, Hash, Hash-Bang, Header, htaccess, HTML5, htpasswd, HTTP, HTTPS, IDE, If, Implementierung, InnoDB, Interceptor, Interface, Internet Explorer, isset, Iterator, Java, JavaScript, Job, jQuery, Kommentar, Konfiguration, Konsole, Kontrollstruktur, kopieren, kostenlos, Kundenbetreuung, Late Static Binding, Layout, Links, Linux, Listeners, Lizenz, Logging, Löschen, Magento, Magic Methods, Manual, ManyToMany, Marketing, Methode, Model, Monolog, MVC, MySQL, NetBeans, Network, Nirvanix, Objekt, Observable, Observer, OneToMany, Online Tool, OOP, Open Source, Operator, OR-Mapper, Order, ORM, O’Reilly, Parameter, Partnersuche, Passwort, Performance, PHP, php.ini, PHP hates me, phpMyAdmin, PHPUnit, Plugin, Popup, Proxy, Prüfsumme, Prüfung, QR-Code, Qualitätssicherung, Query, Queue, Redesign, Refactoring, Reflection, Request, Response, Responsive Design, Rest-API, Rockstar, Rollback, Routing, S3, Samba, Scheifen, Schleife, Schutz, Screenshot, Secure Shell, Selbstreferenz, Server, Setter, setTimeout, Shop, Sicherheit, Sicherung, Sichtbarkeit, Singleton Pattern, Skin, SOAP, Social Network, Software, Sortierung, Sourcecode, Spam, Speicherproblem, Spickzettel, SPL, Splittest, SSH, SSL, Stammtisch, Statement, static, Statistik, Status, Stellvertreter, Strategy Pattern, Stream, String, Stuttgart, Stylesheet, Subversion, Sun VirtualBox, Support, SVN, Switch, Symfony, Symfony2, Symfony Live, Tag, Template, Template Method, Ternär Operator, Testing, Theme, Thumbnail, Tool, Tour, Tracking, Twig, Twitter, Type-Cast, Ubuntu, Umwandlung, Underscore, unset, Update, Upload, Url, User Story, Validierung, Vererbung, Versionskontrolle, Versionsnummer, Verzweigung, Video, Videospiel, Virtualisierung, Visitor Pattern, Vorschaubild, walk, Warteschlange, Webserver, Webservice, Weiterleitung, Werkzeug, Windows, WindowsAzure, WordPress, Wrapper, Writer, XML, Youtube, Zeitschleife, Zeitsteuerung, Zend Framework, Zend_Application, Zend_Cloud, Zend_CodeGenerator, Zend_Http_Client, Zend_Reflection, Zend_Service, ZPress, Zugangskontrolle, Zugriffsmethode