PHP-Applikationen und Caching – I

Einige Web-Hosting-Anbieter – u.a. 1&1 – haben mit ihren aktuellen Webhosting-Angeboten eine Politik verbunden, die die Performance eines angebotenen Web-Hosting-Leistungspakets von dessen Preis abhängig macht. Dies wirkt sich vor allem bei Web-Seiten aus, die dynamisch mittels PHP, Perl oder anderen serverbasierten Scriptsprachen auf der Basis von Datenbankdaten generiert werden.

Einige preisbewusste Kunden diskutieren deshalb immer häufiger mit uns, was man tun kann, um die Performance von serverbasierten Web-Applikationen zu verbessern. In unserem Fall sind dies vor allem PHP5-Applikationen. Wir meinen, dass in vielen Fällen ein systematischer und situationsgerechter Einsatz von verschiedenen “Caching”-Verfahren zu einer substanziellen Verbesserung der Situation führen kann.

Ich stelle deshalb in diesem und in nachfolgenden Artikeln einige Caching-Ansätze für PHP-Applikationen zusammen, die in unserer praktischen Entwicklungsarbeit eine Rolle spielen.

Im vorliegenden Teil I der Beitragsserie gehe ich zuerst auf generelle Faktoren ein, die die Performance von Web-Applikationen beeinflussen. Caching-Verfahren wirken sich auf verschiedene dieser Faktoren aus.

Ich beschreibe danach die Grund-Prinzipien einiger gängiger Caching-Verfahren für PHP-Anwendungen. Ziel ist es aufzuzeigen, wie man den Interaktionsaufwand mit dem Web-Server durch die Kombination dieser Cache-Methoden sukzessive reduzieren kann.

Zudem betrachte ich auch ein paar fachliche und technische Voraussetzungen für Caching. Dabei ergibt sich, dass und warum ein konservativer Ansatz für bestimmte Caching-Verfahren oder deren Kombination sich sowohl an zeitbasierten Regeln als auch an Merkmalen für Änderungen der Datenbestände des Servers orientieren sollte.

Dieser erste Teil ist als Einführung also am ehesten für Leute gedacht, die sich erstmalig mit der Thematik des Cachens im Zusammenhang mit PHP-Applikationen befassen.

In den nachfolgenden Teilen der Beitragsserie widme ich mich dann dem Coding einzelner, spezifischer Caching-Lösungen unter PHP.

Performance von PHP-basierten Webseiten aus Sicht des Nutzers

Der Betrachter von Webseiten servergestützter Webapplikationen begreift die Performance der Applikationen und ihrer einzelnen Seiten hauptsächlich unter dem Aspekt, wie lange es dauert, bis der Browser nach einer Benutzerinteraktion mit einer bereits dargestellten Seite das gewünschte Resultat – in der Regel eine Webseite oder Teile davon – darstellt. Diese “Antwortzeit” ist natürlich ganz entscheidend davon abhängig, ob überhaupt ein Datentransfer zum oder vom Server und ein Seitenaufbau auf dem Server stattfinden:

In vielen modernen Applikationen werden kleinere lokale Zwischenschritte am Browser von einer lokalen Javascript-/JQuery-Logik übernommen, die per DOM Seiteninhalte manipuliert. Oftmals werden auch nicht ganze Webseiten neu generiert, sondern per AJAX/DOM nur Teile einer geöffneten Seite mittels der Ergebnisse einer asynchronen Serveranfrage im Hintergrund modifiziert. Von der Interaktion der Webseite mit dem Server bekommt der Anwender am Browser dabei bei einem asynchronen Datenaustausch im Hintergrund nur bedingt etwas mit.

Kritisch mit der Performance wird es in der Regel immer dann,

wenn vor der nächsten Userinteraktion eine (synchrone) Interaktion mit dem Server stattfindet oder stattfinden muss. Hier addieren sich Datentransferzeiten zwischen Browser/Client und Web-/Datenbank-Servern zu den erforderlichen Zeiten, um das jeweilige Programm am Server durchzuführen.

Wann erfolgt ein solcher Neu-Aufbau von Webseiten durch den Server ? Eine typische, einfache, aber regelmäßig auftretende Situation während der Benutzerinteraktion hierfür ergibt sich ggf. bereits durch den Seitenwechsel eines Nutzers am Browser zu Web-Seiten, die PHP-
basiert sind.

Nicht ist störender als beim Hin- und Herwechseln zwischen Webseiten als bei denjenigen Seiten, die am Server durch PHP-Programme generiert werden, unverhältnismäßig lang warten zu müssen ! Und das, obwohl sich ggf. seit dem letzten Besuch der PHP-basierten Seite vielleicht gar nichts an deren Inhalt geändert hat.

Serverbasierte Applikationen wie PHP-Applikationen trifft die Seiten-Neugenerierung am Server besonders, weil die meisten Browser den Output von serverbasierten Script-Programmen nicht ohne Zusatzmaßnahmen cachen oder dies nur gemäß einer eigenen Heuristik tun. Die Webserver der meisten Hoster sind zudem praktisch nie so eingestellt, dass für PHP-Seiten defaultmäßig ein Caching angewiesen wird. Um diesen Punkt muss man sich der Entwickler schon selbst kümmern !

Bei ein wenig Nachdenken wird man feststellen, dass Caching in Kombination mit “Ajax/PHP” oder gar “PHP/SOAP/REST/Webservices” ein komplexeres Thema ist als Caching im Falle des Abrufes ganzer PHP-Seiten. Wir klammern Ajax und Web-Services aus den Betrachtungen dieser Beitragsserie weitgehend aus.

Hingewiesen sei auch darauf, dass bestimmte Caching-Verfahren natürlich nicht nur in Bezug auf Browser sondern auch gegenüber anderen Clients (Apps, andere serverbasierte Applikationen) interessant sind. Ob und inwieweit der Client explizite HTTP-Header-Anweisungen zum Cachen tatsächlich in ähnlicher Form wie ein Browser nutzen kann, lassen wir mal dahingestellt.

Performance-limitierende Faktoren für serverbasierte Web-Applikationen und für dynamisch generierte Webseiten

Die Performance von Webseiten, deren Inhalte z.B. vollständig oder teilweise durch PHP-Programme auf dem Webserver generiert werden, wird durch eine Vielzahl von Faktoren beeinflusst. Zu nennen sind u.a.:

  1. Die Auslastung des Servers und dessen Puffer-Mechanismen
  2. die benötigte Zeit zum aktiven Laden der dynamisch eingesetzten Script-Module des Webservers,
  3. die Ladezeit von benötigten Include-Dateien am Web-Server,
  4. die benötigte Zeit für die Interpretation und Durchführung des Server-Skript-Codes,
  5. die Zeit für den Verbindungsaufbau vom Webserver zu Datenbankservern und die evtl. Nutzung eines Verbindungspoolings,
  6. die benötigte Zeit für Datenbanktransaktionen und die Zeit für Datentransfers zwischen Webserver und Datenbankserver und umgekehrt,
  7. das Caching-Verhalten des Web-Servers bzgl. der PHP-Module und bzgl. des Ladens der Include-Dateien,
  8. die Effizienz von Sessionspeichern und zugehörigen Technologien (RAM, Filesystem, Datenbank),
  9. das Caching von Provider- und Proxy-Servern,
  10. die Geschwindigkeit der Internetanbindung und Datentransferzeiten zwischen Browser und Webserver,
  11. das Caching am Browser selbst (Nutzung des Browser-Caches).

Die Performance-Politik von Providern beeinflusst praktisch alle Punkte bis auf die letzten zwei.

Wie stark ist nun die Abhängigkeit der Performance von unterschiedlichen Hosting-Paketen und deren Preis? Wir haben je nach Vertrag unserer Kunden Unterschiede in der Größenordnung bis zu einem Faktor 5 für das gleiche Programm unter verschiedenen Hosting-Paketen registriert:

Ein Programm, das in einem lokalen Netzwerk mit Gigabit-Netzwerk, nicht ausgelastetem Web- und Datenbankserver ca. 70 bis 80 Millisekunden (ohne das Nutzen von Caching-Mechanismen) benötigt, erforderte typischerweise ca. 120 – 220 Millisekunden unter besten Bedingungen beim Provider. Je nach Vertrag und auch Auslastung der Server
des Providers kamen jedoch auch Zeiten deutlich oberhalb von 500 Millisekunden oder gar 1,5 Sekunden vor.

Bei preismäßig “günstigen” Verträgen bewegt man sich also u.U. in einem vom Kunden deutlich wahrnehmbaren Reaktionsbereich der Webserver-Leistung. Eine Optimierung von Web-Applikationen durch den Entwickler ist also angesagt, wenn der Kunde “preisgünstige” Angebote wahrnehmen will oder muss. Optimierung kann grundsätzlich an vielen Punkten ansetzen – doch nicht immer kann ein Entwickler auf einfache Weise spürbare Effekte erzielen:

Etliche der genannten Punkte sind partiell natürlich abhängig von dem, was der Provider an Netz- und Server-Technik nutzt und anbietet. Dennoch kann der Entwickler einiges tun:

Optimierungsmaßnahmen bzgl. des obigen Punktes 3) benötigen z.B. eine intelligente Klassen- und Programm-Politik auf der PHP-Seite. Unter besten Bedingungen kann das Laden von Klassenbibliothek-Files bei umfangreichen Systemen durchaus ein performance-limitierender Faktor sein. Hat man den Webserver selbst unter Kontrolle, so mag sich hier ein Griff zu Tools wie APC lohnen.

Unter Punkt 4 ist natürlich nicht nur eine performante Server-Hard- und Software gefragt. Selbstverständlich lassen sich auch PHP-Programme durch intelligente Maßnahmen des Entwicklers optimieren. Dies kann jedoch sehr aufwändig werden – und Kosten/Nutzen-Betrachtungen sind wichtig. Und welcher Entwickler geht schon ohne echte Not an die Grundfesten von Applikationen heran, die seit Jahren im Einsatz sind ?

Um eine optimale SQL-Performance muss sich der Entwickler zu einem essentiellen Anteil in jedem Falle selbst kümmern. Die Wahl geeigneter Tabellen-Varianten des RDBMS, die Wahl der Aufgabe angemessener Sperrmechanismen, Performance-Optimierung des Datenmodells, wo sinnvoll auch Einsatz von Denormalisierung und optimierte Indizierung sind hier erste Stichworte.

Man sollte sich als Kunde jedoch darüber im Klaren sein, dass der Aufwand für eine nachträgliche Performance-Optimierung von Web-Applikationen beträchtliche Ausmaße annehmen kann. Für die entsprechenden Kosten kann man sich dann ggf. auch ein besseres Hosting-Paket oder einen eigene Root-Server leisten.

Will man als Entwickler in der Kooperation mit dem Kunden schnell und effizient positive Effekte hinsichtlich der Performance erzielen, lohnt es sich daher durchaus, Caching-Methoden zu untersuchen und diese über klar abgegrenzte, überschaubare Funktionen oder Klassen-Methoden in die PHP-Applikationen zu implementieren. Der Aufwand dafür hält sich nämlich in Grenzen.

Ziele von Caching-Verfahren

Das grundlegende Ziel des Einsatzes von Caching-Verfahren macht sich an folgender Frage fest:

Wie kann ich die Interaktionsdauer mit dem Web-Server durch das Ausnutzen von Pufferspeichern – also Caches – und die Analyse von Änderungsinformationen zur Datenbasis der Webseiten so weit als möglich reduzieren ?

Strategien in diesem Zusammenhang können sein:

  • bereits erzielte Ergebnisse – sprich Webseiten – in direkt verwertbarer Form zwischenzuspeichern und aus entsprechenden Pufferspeichern zu laden, statt den Server zu einer Seitengenerierung aufzufordern,
  • den Kommunikationsaufwand und Datenaustausch zwischen Browsern und Servern auf das notwendige Maß zu reduzieren

und vor allem:

  • die Vermeidung von ressoucenintensiven Programmabläufen und Datenbanktransaktionen auf den Servern des Providers, soweit das unter dem Aspekt einer dynamischen Änderung der Datenbasis vertretbar ist.

Pufferspeicher – zeitbasierte Regeln – Änderung der Datenbasis von Webseiten

Um die eben genannten
Ziele zu erreichen, ist es zum einen notwendig, Pufferspeicher und Caches zu nutzen. Hierfür kommen Browser-Caches, Server-Session-Speicher oder auch selbst-verwaltete “Datei-Caches” am Server in Betracht. Intelligentes Daten- und Datei-Caching kann PHP-seitig teilweise auch im PHP-Code-Ablauf realisiert werden. Aber natürlich muss man primär die “Public-” bzw. “Private-” Caches im Sinne von Proxy- und Browser-Caches für die generierten Webseiten und deren Elemente ausnutzen.

Neben der Notwendigkeit der Nutzung von “Pufferspeichern” ist es aber auch erforderlich, den Bedarf nach einer Aktualisierung von Webseiten und deren Inhalten

  • anhand von Regeln – z.B. für Zeitintervalle – zu steuern
  • und aufgrund der Analyse von definierten Änderungsmerkmalen der Datenbasis am Server festzustellen.

Beide Aspekte sind auszutarieren: Ein zu langes Zeitintervall für die Nutzung von Pufferspeichern steht ggf. in Konflikt mit dem Anspruch, aktuelle Informationen auch dann zu liefern, wenn sich die Datenbasis einer Webseite geändert hat.

Fachliche Voraussetzungen für Caching

Der Aspekt der Änderung der Datenbasis für den Inhalt einer Webseite oder generell von serverbasiertem Output führt uns zu den fachlichen Voraussetzungen für den Einsatz von Caching-Verfahren. Aus meiner Sicht gilt ganz allgemein:

Voraussetzung für den Einsatz von Caching-Verfahren ist, dass sich der Inhalt einer generierten Webseite aus Client- bzw. Kundensicht nicht laufend und zeitnah ändern muss, sondern über einen definierbaren Zeitraum konstant bleiben darf.
 
Auf der Client- oder Kundenseite darf kein Schaden entstehen, wenn eine Änderung erst nach einem definierten Zeitintervall am Client oder Browser bekannt wird.

Wie groß das zu wählende Zeitintervall ist, hängt natürlich vom Einsatzzweck der Website ab. Caching-Zeitintervalle können sich zwischen Sekunden und Wochen bewegen. Bei einem Newsticker wird das Zeitintervall konstanter Information natürlich viel kleiner sein als bei einer Informationsseite, deren Inhalt sich bekanntermaßen nur zu Beginn eines jeden Monats ändert.

Macht man sich jedoch klar, dass die typische Interaktionsdauer eines Kunden mit Web-Informationsseiten vielleicht zwischen 1 und 15 Minuten liegt, so wird klar, dass bereits das Ausnutzen von Caching-Zeiten im Bereich weniger Minuten bis zu einer Viertelstunde einen großen Effekt auf den subjektiven Performance-Eindruck eines Kunden haben können.

Wir erkennen hier übrigens, dass Ajax tatsächlich ein schwieriges Thema im Zshg. mit Caching ist:
Wann setze ich denn Ajax ein? Meist doch dann,

  • wenn eine Benutzereingabe zu einer direkten “Aktualisierung” von Datenbeständen auf dem Server und nachgelagert auch von bestimmten Inhalten der aktuell am Browser geöffneten Webseite führen soll (synchron oder asynchron). Caching ist hier in der Regel kontraproduktiv. Man steuert vielmehr aktionsgerecht selbst, was zwischen Server und Browser transferiert werden soll.
  • wenn eine Abfrage von listenartigen Vorschlägen aufgrund von Benutzereingaben gestartet wird. Das Problem ist hier, dass das Ergebnis solcher Abfragen noch während der Benutzereingabe Modifikationen erfahren soll – z.B. im Sinne von sich laufend modifzierenden Filtern. Hier hängt der Sinn eines möglichen Cachings vor allem davon ab, ob man die Filterung am Server oder am Client vornimmt und davon, wie vorhersagbar und wohldefiniert bestimmte Benutzerabfragen absehbar sind.
  • generell wenn Abfragen asynchron im Hintergund vorgenommen werden sollen, ohne die Webseite zu verlassen. Hier stellt sich die Frage, ob und wie das Ergebnis – oft ein XML-formatierter Datenstrom oder per JSON sequentialisierter
    Datenstrom – wo und wie gecached werden könnte.

Einige Caching-Verfahren

Kommen Browser- und Proxy-Caches zum Einsatz werden statische Webseiten ohne besondere Vorkehrungen nur einmal oder periodisch vom Server geladen, danach kommen ihre Inhalte für definierte Zeitintervalle aus dem Cache des Browsers oder eben eines Proxys. Bei dynamisch generierten Webseiten – wie PHP-Seiten – hängt die Caching-Politik vom Browserhersteller und von Einstellungen der Proxys wie des Webservers selbst ab – falls keine besonderen Vorkehrungen getroffen werden.

Gezieltes, anweisungsgesteuertes Caching im Cache des Browsers macht ggf. den Unterschied zwischen einigen zehn Millisekunden für den Seitenaufbau im Gegensatz zu einer Sekunde aus – pro Seite ! Das ist ziemlich durchschlagend. Unter bestimmten Bedingungen kann es aber auch interessant sein, Webseiten aus einem selbst verwalteten File-Cache aus dem Webserver zu ziehen.

In einer “HTTP 1.1”-Umgebung sind für normale PHP-Applikationen vor allem folgende vier Verfahren zur Ausnutzung von Caching-Mechanismen interessant, wobei alle Methoden explizit die Unterstützung des jeweiligen PHP-Programms (und des Webservers) erfordern. Wir ordnen die Verfahren nach dem Grad der Reduktion der Interaktion mit einem Web/Datenbank-Server und der Vermeidung von unnötigen Prozessen auf dem Server an :

  1. Methode 1 – Explizite Caching-Anweisung an “Public” und “Private” Caches mit einem limitierenden Zeitintervall:
    Der Browser oder ein chache-gestütztes Client-System erhalten den Hinweis, den Server über ein definiertes Zeitintervall hinweg nicht abzufragen, sondern explizit ihren Cache zu benutzen. Erst nach Ablauf des vorgegebenen Zeitintervalls wird der Server erneut kontaktiert: die geforderte Seite wird dann über das angesprochene PHP-Programm vollständig neu generiert (oder ggf. aus einem serverseitigen Filecache geladen) und auf dem aktuellen Stand zum Browser, in dessen Cache und die Caches von Proxy-Systemen etc. übertragen.
  2. Methode 2 – Check auf Änderungen von Webseiten und “Not Modified”-Rückmeldung im HTTP-Header an den Browser:
    Die auf dem Server angesprochenen PHP-Programme überprüfen anhand bestimmter Merkmale als allererstes, ob sich die Datenbasis der dynamisch zu generierenden Website seit der letzten Serveranfrage geändert hat. Ist dies nicht der Fall, erhalten der Browser und andere Cache-Systeme per HTTP-Header einen expliziten Hinweis (Code 304-Meldung), ihren Inhalt weiter zu verwenden, aber bei der nächsten Seitenabfrage den Server erneut bzgl. möglicher Änderungen abzufragen. Nur falls in der Zwischenzeit Änderungen aufgetreten waren, wird der geänderte Webseitencode entweder neu aus Datenbankinhalten erzeugt oder aus einem intermediären Datei-Puffer (s. Punkt 4) des Webserver geladen und zum Client übertragen.
  3. Methode 3 – Kombination der Methoden 1 und 2:
    Methode 3 kombiniert die erste und die zweite Methode: Grundsätzlich wird ein zeitlimitiertes Caching zugelassen. Nach Ablauf des Zeitintervalls überprüft das angesprochen PHP-Programm aber zunächst, ob sich die Datenbasis seit der letzten Seitenauslieferung überhaupt geändert hat. Wenn nicht, wird erneut ein clientseitiges Caching für ein definiertes Zeritintervall erlaubt – wobei die Seite nicht (!) neu generiert oder geladen wird. Im Falle einer Änderung der Datenbasis wird die Seite dagegen neu auf dem Server erzeugt und in die Caches übertragen – das Caching-Zeitintervall auf der Kunden- oder Proxy-Seite beginnt erneut.
  4. Methode 4 – PHP-gesteuertes File-Caching am Server:
    Wohldefinierte Ereignisse auf dem Server werden genutzt, um den HTML/XHTML/XML-Code der benötigten Webseiten oder Informationen auf der Basis von erkannten
    Änderungen der Datenbasis neu zu generieren. Der durch das PHP-Programm generierte HTML/XHTML- oder auch XML-Code wird dann für ein definiertes Zeitintervall oder aber bis zum nächsten wohldefinierten Änderungs-Event als “Datei” auf dem Server in einem selbstverwalteten “Cache”-Verzeichnis abgelegt. Bei der nächsten Browserabfrage wird vom PHP-Programm direkt der Datei-Inhalt aus dem Verzeichnis-Cache geladen und zum Browser übertragen, falls keine sonstige Änderung der Datenbasis erfolgt ist. Ressourcenintensive Prozesse zur Webseitengenerierung werden so nur periodisch oder aber aufgrund definierter Änderungsereignisse fällig.
  5. Methode 5 – Kombination der Methoden 3 und 4:
    Grundsätzlich wird ein zeitlimitiertes Caching zugelassen. Nach Ablauf des Zeitintervalls überprüft das angesprochen PHP-Programm aber zunächst, ob sich die Datenbasis geändert hat. Ist ein aktuelles HTML/XHTML/XML-File zur geänderten Datenbasis vorhanden, wird dieses gezogen. Ist das nicht der Fall, wird die Seite neu generiert, en passant am Server als File abgelegt und zudem zum Client übertragen.

Einschränkungen, Vor- und Nachteile der Verfahren

Die einzelnen Verfahren weisen Vor- und nachteiel auf, die ich nachfolgend kurz diskutiere:

Einschränkungen für den Einsatz der ersten Methode – Caching während eines definierten Zeitintervalls

Beim Einsatz der ersten Methode, versucht man, eine Interaktion mit dem Server über definierte Zeitintervalle hinweg zu vermeiden. Diese Methode hat den Vorteil eines schnellen Seitenaufbaus auf der Basis lokaler Informationen und Objekte im Cache des Browsers. Das wirkt sich am Browser vor allem beim Wechsel zu und zwischen (eigentlich PHP-basierten) Webseiten sehr vorteilhaft auf die Performance aus. Durch die Nutzung des Browser-Caches wird nicht zuletzt auch der Server spürbar entlastet.

Der Nachteil der Methode 1 besteht jedoch darin, dass während des vorgegebenen Zeitintervalls eben auch keinerlei Serverinteraktion mehr stattfindet (soweit der Browser/Proxy die Caching-Vorgaben des Servers respektiert). Das cachende System – i.d.R. der Browser – erfährt (bei normaler Bedienung) innerhalb des vorgegebenen Zeitintervalls nichts (!) mehr über eventuelle Änderungen der Datenbasis des Webseiten-Inhalts. Die aus dem Cache gezogene Information ist also möglicherweise schon veraltet. Und selbst wenn der Browser die Seite neu anfordern würde, kämen ggf. veraltete Inhalte aus Proxy-Caches zurück.

Eine kluge, dem Einsatzzweck der Web-Applikation angemessene Vorgabe des Caching-Zeitintervalls an beteiligte Systeme ist also eine wichtige Voraussetzung der Anwendung der Methode 1.

Die zweite Voraussetzung für den Einsatz dieser Methode ist die, dass die Benutzerinteraktion nicht selbst zu einer Datenbestandsänderung führt und dass für den Aufbau der geforderten Webseite nicht unmittelbar eine komplette Neukalkulation und Neu-Generierung der Seite auf dem Server erforderlich ist. (Gezielt gesteuerte Ajax-Prozesse können den Cache natürlich immer umgehen. Ich lasse das aber mal außer Acht).

Man erkennt deshalb,

dass diese erste Methode des Cachings  nicht  für Previews und Voransichten von Webseiten geeignet ist , die mit Hilfe von CM-Systemen oder anderen Pflegemodulen aus Datenbankinhalten generiert werden.

Will man den Effekt von Datenbankänderungen sofort sehen, muss das Caching der zugehörigen Webseiten durch bestimmte PHP-Übergabe-Parameter, die bei den normalen Web-Adressen nicht auftauchen, umgangen bzw. explizit abgestellt werden.

Dies ist jedoch leicht realisierbar, da sich das Browser-Caching immer auf eine vollständige URL-Adresse – also
inkl. aller GET-Parametern – bezieht. Bei der Übergabe von POST-Parametern muss eben ein bestimmter Zusatz-Parameter zur Situationsanalyse eingesetzt werden und die Namen für die Previewer-Programme sollten sich dann auch von denen der normalen Web-Generator-Programme unterscheiden.

Vor-und Nachteile der zweiten Methode – Prüfung der Änderung der Datenbasis vor einer Neugenerierung oder Cache-Nutzung

Die zweite Methode für sich erspart einem nicht eine Kommunikation zum und vom Server. Aber sie stellt ein Schlüsselelement dar, um den Aufwand auf dem Server zu begrenzen:

Sie erspart u.U. die Durchführung ressourcenintensiver PHP-Programmschritte und von RDBMS-Prozessen auf dem Web- und den Datenbank-Servern.

Die Latenz der PHP-Applikation hängt dann hauptsächlich von der Internetanbindung und im wesentlichen einer Datei- oder Datenbankabfrage auf Änderungen ab. Beides kann aber erheblich (!) schneller sein, als eine vollständige Neugenerierung der Seiteninformation durch komplexe Programme und Datenbanktransaktionen – wenn sich der Datenbestand nicht geändert haben sollte.

Der Einsatz der zweiten Methode ist aus meiner Sicht grundsätzlich sinnvoll. Hier muss man sich allerdings überlegen, wie und was man auf Änderungen prüft. In meinen Programmen sind das

  • erstens Datenbankänderungen
  • zweitens Änderungen von Files
  • drittens ggf. Änderungen von speziellen Files für die Caching-Methode 4
  • viertens Änderungen der Inhalte von Session-Speichern

Änderungen an anderen Datenbestände, die hier nicht genannt wurden, sind denkbar.

Datenbankänderungen bekommt man grundsätzlich über die Analyse von Timestamps in Tabellen mit. Hierbei muss man aber die Zusammenhänge der Daten – sprich das Datenmodell beachten ! Das Ergebnis des PHP-Programms wird ja i.d.R. von einer Kombination von Tabellen abhängen. Man muss sich also darüber klar werden, welche Timestamps eigentlich für den gewünschten Output relevant sind. Ggf. lohnt es sich, für die einfache Abfrage relevanter Änderungen im Rahmen von Caching-Verfahren spezielle Einträge in selbst verwalteten Timestamp-Tabellen explizit zu setzen oder z.B. über Datenbank-Trigger setzen zu lassen.

Es zeigt sich also, dass die Möglichkeit zum einfachen Erkennen der Änderungen von Datenbeständen für ein späteres Caching schon frühzeitig beim Design einer Applikation berücksichtigt werden muss.

Analoge Argumente gelten für andere Datenbestände, die in Kombination zur Erzeugung eines aktuellen Seiteninhalts wichtig sein mögen.

Ein weiterer Nachteil dieser Methode besteht übrigens ggf. darin, dass man die Verbindung zur Datenbank in einem PHP-Programm sehr frühzeitig aufbauen muss. Dies kann vor allem in sicherheitsrelevanten Applikationen eine Rolle spielen.

Vorteile der dritten Methode – Kombination aus zeitgesteuertem Caching und Prüfung der Datenbasis

Sind die Voraussetzungen für den Einsatz der Methoden 1 und 2 gegeben, bringt deren Kombination aus meiner Sicht nur Vorteile mit sich. Man cached lokal solange, wie das eben vertretbar ist. Erst danach wendet sich der Client/Browser wieder an den Server. Aber dort wird nur wirklich etwas getan, wenn dies aufgrund eingetretener Änderungen notwendig ist. Ansonsten wird erneut auf den am Client vorhanden Cache-Inhalt zurückgegriffen. Besser kann es kaum kommen – deswegen setze ich diese Kombination auch in vielen Applikationen ein.

Vor-und Nachteile der vierten und fünften Methode – Einsatz eines selbstverwalteten File-Cache für PHP-Output

nGrundsätzlich ist es gut, einen selbstverwalteten File-Cache zu realisieren. Sein Einsatz lohnt sich vor allem unter der Voraussetzung, dass sich die Generierung der Webseite zeitlich und logisch weitgehend von der konkreten Nutzer- und Abfragesituation am Client abkoppeln lässt:

  • Eine durch Ereignisse oder Pflegepersonen ausgelöste Datenbestandsänderung führt für sich alleine und unabhängig von der aktuellen Benutzerinteraktion bereits zu einem wohldefinierten Aufbau der betroffenen Webseiten. Diese können im Prinzip also unmittelbar nach der Datenänderung als Files am Server erzeugt werden.
  • Der Inhalt der Seiten ist relativ unabhängig von dynamischen Parameterkonstellationen, die situationsspezifisch erst durch den Anwender der Web-Applikation definiert werden.

Sind diese Voraussetzungen gegeben, so gilt zusätzlich Folgendes:

Sollen oder müssen die generierten Files im selbst verwalteten Cache-Verzeichnis alle möglichen Abfragesituationen abdecken, so erkennt an schnell ein potentielles Mengenproblem. Bei komplexen Applikationen mit großen Datenbeständen kann dies durchaus ein Thema werden. Man muss sich also genau überlegen, welchen Output von PHP-Applikationen man in Puffer-Files überführen will. Für den einen oder anderen mag zudem der technisch erforderliche Einsatz des sog. Output-Bufferings unter PHP5 zur Erzeugung der Files ein unbekanntes Terrain darstellen.

Ein weiteres mögliches Problem ist, dass man den eigenen File-Cache natürlich auch im Rahmen seiner Applikationen selbst verwalten muss. Wie bei jedem anderen Cache wird man hier Zeitregeln und eine Mengenbegrenzung einführen. Dies führt dann zu FIFO-Mechanismen oder ähnlichem.

Insgesamt lohnt sich der Einsatz von selbstverwalteten Filecaches vor allem dann, wenn

  • die Generierung des HTML/XHTML/XML-Outputs substanzielle Ressourcen beansprucht,
  • die Änderung der Datenbasis von der aktuellen Benutzerinteraktion weitgehend entkoppelt ist,
  • die im File hinterlegte Information eine langfristige Gültigkeit hat.

Solche Voraussetzungen sind oft in CM- oder Pflege-Systemen gegeben, in denen Seiten erzeugt werden, deren Inhalt nicht dynamisch durch viele Parameter gesteuert wird und über relativ lange Zeitintervalle hinweg konstant bleibt.

Ein Beispiel hierfür wäre etwa eine Webseite, die einen CV darstellt. Der HTML-Code der Webseite kann unmittelbar nach Änderung der Datenbankinhalte zum CV erzeugt werden und bleibt dann lange konstant, also statisch. Hier lohnt sich die Ablage in Dateiform unmittelbar nach Durchführung der Datenänderung. Das PHP-Programm, das für eine Anfrage des Kunden zu dieser CV-Webseite verantwortlich ist, prüft auf Änderungen der Datei durch andere Pflegeprogramme ab und schickt den vorab generierten und hinterlegten Datei-Inhalt direkt weiter, wenn keine Änderungen vorliegen.

Ein Gegenbeispiel wäre etwa eine Projekt- oder Produktliste, auf die der Anwender interaktiv viele verschiedene Filter anwenden kann und deren Inhalt sich aufgrund äußerer Umstände in kurzen, unperiodischen Zeitabständen ändert. Gegenbeispeile stellen auch Seiten zu sehr vielen unterschiedlichen Items dar, die sich erratisch ändern.

Genannt sei ein weiterer Einsatzbereich des vierten Verfahrens – nämlich Ajax-Transaktionen: Es gibt bestimmte Ajax-Abfragen (z.B. die Generierung von relativ statischen Listen), deren Ergebnis sich nicht immer auf dem alleraktuellsten Status befinden muss. Dann lohnt es sich durchaus, XML- oder JSON-Daten nicht immer neu erzeugen zu lassen, sondern direkt Cache-Files zu entnehmen.

Insgesamt meine ich, dass man vor dem Einsatz der Methoden 4 und 5 zunächst Methode 3 ausprobieren sollte. Methode 3 ist – wie wir sehen werden – auch einfacher zu implementieren als ein selbst verwalteter File-Cache.
Natürlich kann man die Methode 4 auch mit der Methode 3 kombinieren:

Wenn Änderungen am Datenbestand festgestellt werden, kann man zunächst überprüfen, ob seit der letzten Änderung bereits ein neueres File erzeugt wurde und dessen Inhalt dann als Output an den Browser weiterreichen. Ist kein hinreichend junges File gegeben, so kann man ein solches “en passant” anlegen.

Server-Entlastung

Caching ist auch interessant und wichtig für Leute, die ihre eigenen Webserver betreiben. Es liegt nach dem bisher Gesagten auf der Hand, dass ein vernünftiges Caching auf Basis der oben genannten Methoden insgesamt die Auslastung der Web-Server reduziert. Alle genannten Verfahren haben ja gerade zum Ziel, die Interaktion mit dem Server zu verringern. Im zeitlichen Mittel bleiben bei Einsatz von Caching-Verfahren mehr Serverressourcen übrig.

Nun haben wir das notwendige Rüstzeug beieinander, um uns den einzelnen Methoden zuzuwenden. Dies geschieht in einem weiteren Beitrag dieser Reihe unter der Rubrick “Lamp / Webentwicklung”. Bis dann !

Opensuse 12.2 – mysql, logrotate error

Vor einigen Tagen habe ich den Mysql-Community-Server über das entsprechende Opensuse “Database”-Repository upgedated. Seitdem erhalte ich beim Systemstart Meldungen der Art

Nov 15 18:30:04 myserver logrotate: ALERT exited abnormally with [1]
Nov 15 18:30:04 myserver logrotate: #007/usr/bin/mysqladmin: refresh failed; error: ‘Unknown error’
Nov 15 18:30:04 myserver logrotate: /logrotate.d/mysql failed, probably because
Nov 15 18:30:04 myserver logrotate: the root acount is protected by password.
Nov 15 18:30:04 myserver logrotate: See comments in /logrotate.d/mysql on how to fix this
Nov 15 18:30:04 myserver logrotate: error: error running non-shared postrotate script for /var/log/mysql/mysqld.log of ‘/var/log/mysql/mysqld.log ‘

Diese Meldung erhalte ich, obwohl es unter dem “/root”-Verzeichnis die notwendige “/root/.my.cnf”-Datei mit den Account-/Passwort-Daten für den MySQL-Admin (MySQL root-Account) gibt. Die Fehlermeldung führt einen daher in die Irre.

Der Fehler liegt wohl eher im Startup-Skript “/etc/init.d/mysql” für den MySQL-Server.

Das habe nicht ich herausgefunden sondern Archie Cobbs, der das bei Novell als Bug eingestellt hat.

Siehe :
http://lists.opensuse.org/opensuse-bugs/2012-11/msg01186.html
und
https://bugzilla.novell.com/show_bug.cgi?id=789263

Dort findet man auch den notwendigen Hinweis, wie man das Startup-Skript abändern muss, damit Logrotate wieder funktioniert:

The bug is in the line “chmod 660 $log_dir”.
That should be “chmod 770 $log_dir”.

Scheint rechtemäßig logisch zu sein und hat bei mir funktioniert.

Eclipse, SVN, kopierte .svn-Verzeichnisse (beseitigen)

Der Mensch ist ein Gewohnheitstier. Leider auch im Machen von Fehlern. Ein Beispiel für eine solche Fehl-Leistung hat mich gestern wieder im Zusammenhang mit Eclipse und der SVN-Verwaltung neu angelegter, kundenspezifischer PHP-Projekte ereilt. Für die PHP-Entwicklungsarbeit nutze ich primär Eclipse unter Linux.

Beim Zusammenstellen der Verzeichnisse und Dateien für neue PHP-Projekte unter Eclipse kopiere ich manchmal ganze Verzeichnisstrukturen aus anderen, früheren PHP-Projekten. Wenn ich dabei zu bequem vorgehe, erwische ich beim Datentransfer auch alle vorhandenen “.svn”-Verzeichnisse innerhalb der kopierten Verzeichnishierarchie.

Vergesse ich nun (wie gestern geschehen), diese “.svn”-Verzeichnisse zu löschen, bevor ich eine Zuordnung des neuen kundenspezifischen PHP-Projekts zu einem SVN-Repository vornehme, so führt dies zwangsläufig zu Problemen mit der Versionsverwaltung der kopierten Dateien im neuen PHP-Projekt. Je nach Projekt-Setup

  • wundert man sich anschließend ggf. über unabgeschlossene SVN-“Commit”-Vorgänge bzgl. der (kopierten) Verzeichnisse in das eben zugeordnete SVN-Repository
  • oder aber man erkennt an der grafischen Darstellung des PHP-Explorers, dass es zugrunde liegende SVN-Links zwischen dem neuen und den alten Projekten gibt, die man im neuen, kundenspezifischen Projekt aber nicht haben will und auch nicht beabsichtigt hatte.

Um die durch die Kopiererei verkorkste SVN-Situation unter Eclipse zu bereinigen, muss man das neu angelegte Projekt mit den kopierten Verzeichnissen wieder von SVN lösen, die kopierten “.svn”-Verzeichnisse rekursiv beseitigen – also löschen – und dann erneut die Zuordnung des neuen Projektes zu einem SVN-Repository durchführen.

Aber der Reihe nach.

2 Arten der Nutzung vorhandener Arbeitsergebnisse und Dateien in neuen PHP-Projekten unter Eclipse

Beim Anlegen von bestimmten neuen PHP-Projekten unter Eclipse stelle ich mir als Ausgangspunkt meiner Arbeit Verzeichnisstrukturen zusammen, bei denen ich die Früchte bisheriger Arbeit nutze. Hierbei gibt es u.a. zwei Hauptvarianten:

Zugriff auf Dateien zentraler Bibliotheken

Dabei spielt zum einen der Zugriff auf Verzeichnisstrukturen zentraler Klassen- und Funktions-Bibliotheken eine Rolle. Diese Bibliotheken und deren Dateien werden bei mir über eigene spezielle Projekte gepflegt. Sie stellen das Fundament dar, auf dem kundenspezifische Projekte aufbauen können.

Die Dateien der zentralen kunden-unspezifischen Bibliotheken (und ihre dort definierten Klassen/Funktionen) können und sollen von anderen Projekten genutzt werden. Den Zugriff auf solche Ressourcen von einem kundenspezifischen PHP-Projekt aus erreiche ich unter Eclipse durch Ordner-Verlinkung und ein entsprechendes Setup der PHP-Build-Pfade.

Man legt den neuen Ordner im Projekt einfach als Verweis auf ein vorhandenes Verzeichnis an.

Eclipse Verzeichnis Link

(Man ignoriere die Fehleranzeige bei den Projekten – so schlimm wie das erscheint, ist die Situation in meinen Projekten wahrlich nicht 🙂 . Der Fehler vererbt sich durch regelmäßige Referenz auf bestimmte phpmyadmin-Dateien.

Je nach Rechte-Setup kann ich danach von einem spezifischen Kunden-Projekt aus die zentralen Ressourcen bei Bedarf auch modifizieren. Das Ergebnis steht dann automatisch auch allen anderen kundenspezifischen Projekten zur Verfügung. Für die Unterstützung der “Content-Assist”-Funktionalität (Vorschläge beim Coding – Variablen, Klassen etc.) muss man im PHP-Projekt ggf. die Build-Pfade richtig setzen.

Die SVN-Versions-Verwaltung der zentralen Bibliotheken erfolgt in
meinem Fall natürlich getrennt von der SVN-Verwaltung des spezifischen neuen Kunden-Projektes. Die SVN-Verwaltung der zentralen Klassenbibliotheken führe ich über deren eigene Projektumgebung und gemäß des zugehörigen SVN-Setups durch und nicht über die Kundenprojekte.

Die Eclipse SVN-Plugins erkennen die verlinkte Verzeichnis-Struktur der Kundenprojekte und reagieren adäquat:

Die per Link eingebundenen Verzeichnisse und Dateien werden beim Ein- und Auschecken in das spezifische SVN-Repository des neuen kundenspezifischen PHP-Projektes ignoriert. Das ist vernünftig, weil ressourcenschonend und so auch von mir gewünscht. Die Projekte für die zentralen Bibliotheken habe ihr eigene SVN-Repository-Verwaltung – unabhängig von meinem kundenspezifischen Projekt. So weit, so gut.

Kopierte Verzeichnisse und Dateien, die projektspezifisch verändert werden

Zum anderen “kopiere” ich mir aber auch etliche Verzeichnisse mit spezifischen Klassendefinitionen und PHP-Programmen in mein PHP-Projekt. Dabei verlinke ich die entsprechenden Ordner nicht wie bei der Benutzung echter, zentral gepflegter Bibliotheken:

Ich kopiere, weil die entsprechenden Files (Programme, Funktionen, Klassen) projektspezifisch verändert werden sollen.

Die kopierten Verzeichnisse können dabei durchaus eine komplexe Subverzeichnisstruktur aufweisen. Einen Teil der Verzeichnisstrukturen richte ich dabei zudem auf Samba-Verzeichnissen ein, so dass die entsprechenden Dateien unter (virtuellen) Windows-Maschinen parallel auch in Dreamweaver-Projekte eingebunden werden können. (Wie man einen entsrpechenden durchgehenden Arbeitsfluss gestaltet, beschreibe ich vielleicht mal in einem gesonderten Beitrag). Aus Hygienegründen trenne ich das Samba-Verzeichnis vom Eclipse-Workspace-Verzeichnis ab. Unter Eclipse führe ich alle Ressourcen aber wieder durch geeignete Projekt-Setups zusammen.

Dabei schließe ich Dreamweaver-spezifische “_notes”-Verzeichnisse und “*.LCK”-Dateien, aber auch “.svn”-Verzeichnisse aus der Projektstruktur- und Build-Verwaltung über das Setzen von rekursiven “Ressource-Filtern” aus.

Eclipse Resource Filter

Im PHP-Explorer erscheinen die entsprechenden Verzeichnisse und Dateien dann nicht mehr ! (SVN geht natürlich trotzdem).

Die erforderlichen initialen Kopiervorgänge führe ich der Bequemlichkeit halber oft außerhalb von Eclipse auf Kommandozeilenebene oder mit einem Dateimanager durch. Manchmal benutze ich aber auch die Exportfunktionalität innerhalb von Eclipse.

Ein klassisches SVN-Problem entsteht anschließend, wenn ich aus Unachtsamkeit oder Bequemlichkeit die aus den älteren Projekten vorhandenen “.svn”-Verzeichnisse in das neue Projekt mit hinein kopiert habe. Und das können je nach Tiefe der Verzeichnisstruktur sehr, sehr viele “.svn”-Ordner sein (pro vorhandenem Subverzeichnis nämlich ein “.svn”-Ordner!).

Manchmal vergesse ich leider die kopierten “.svn”-Verzeichnisse einfach aufgrund anderer Themen, die mir dazwischenkommen (ja das Alter!), und wegen der gesetzten Ressource-Filter fallen mir die kopierten “.svn”-Ordner anschließend auch nicht mehr ins Auge.

SVN übernimmt die Verwaltung der kopierten Verzeichnisse und Dateien nicht wie gewünscht

Nach den ersten Schritten im Projekt erreicht man dann schnell ein Stadium, in dem man seine Ergebnisse der Versionsverwaltung SVN anvertrauen möchte.

Mein SVN-Plugin stellt unter dem Menüpunkt “SVN >> Share Projects …” eine menügeführte Möglichkeit zur Zuordnung eines Projekts zu einem Repository bzw. einem Unterbereich davon zur Verfügung. Ich “share” also mein
neu angelegtes Projekt und platziere es in einem eigenen SVN-Repository oder einem eigenen Zweig eines vorhandenen Repositories.

Natürlich möchte ich nun, dass bei der Anlage dieses projektspezifischen Repository-Bereichs eine initiale Erfassung auch derjenigen Verzeichnisse und Dateien erfolgt, die in mein kundenspezifisches Projekt kopiert wurden. Genau das funktioniert aber leider nicht wie erwartet, wenn in den Verzeichnissen bereits gültige “.svn”-Ordner existieren!

SVN meint dann, dass diese Verzeichnisse ja schon einer SVN-Verwaltung unterliegen würden und nutzt SVN-interne Links auf die bereits verwalteten SVN-Ressourcen.

Das ist natürlich nicht im Interesse meines neuen Projekts – ich bewege mich da ja in einem völlig anderen Kontext und was dort mit den kopierten Dateien geschieht, hat mit den in den Änderungen, die in der Versionsverwaltung eines anderen Projektes erfasst werden, nichts zu tun. Die SVN-interne Verlinkung ist im vorliegenden Fall sogar schädlich bis gefährlich. (In anderen Fällen als dem beschriebenen mag eine SVN-Verkettung aber durchaus sinnvoll sein).

Leider weiß SVN aber nichts von meiner stumpfsinnigen Kopiererei und meinen Intentionen. Es nimmt die Hinweise in den entdeckten (kopierten) “.svn”-Verzeichnissen ernst.

Man merkt die Verkopplung des neuen Projektes mit älteren auf SVN-Ebene u.a. durch einen roten Pfeil in der rechten unteren Ecke der Dateisymbole im PHP-Explorer.

Eclipse SVN Link

Der Pfeil zeigt die Referenz auf SVN-Ebene zu einem anderen Repository-Container eines anderen Projektes an. Commit-Vorgänge auf dem aktuellen Projekt werden ggf. nicht als abgeschlossen angezeigt, wenn im anderen Projekt durchgeführte Dateiänderungen noch nicht “committed” wurden. Auch sonst kann es zu erheblichen Verwirrungen kommen

Bereinigung des SVN-Problems – Rekursives Entfernen der kopierten “.svn”-Ordner

Was ist in dieser Situation zu tun? Es ist notwendig, das neu angelegte Projekt vom kopierten Ballast anderer Projekt zu befreien und erst danach – also im aufgeräumten Zustand – einem SVN-Repository zuzuordnen. Vorher lösen wir das Projekt aber von der schon vorgenommenen Versionsverwaltung. Folgende Schritte sind somit durchzuführen:

  • Schritt 1: Man muss das neu angelegte PHP-Projekt zunächst vom SVN-Repository “disconnecten”.
  • Schritt 2: Man muss nun alle kopierten “.svn”-Ordner löschen.
  • Schritt 3: Erneute Zuweisung des Projektes an SVN und an ein neu anzulegendes SVN-Repository oder einen neuen Zweig eines vorhandenen Repositories

Das hört sich einfach an. Schritt 2 kann sich ohne Shell-Einsatz aber als aufwändig erweisen.

Hinweis zu Schritt 1:
Die Durchführung von Schritt 1 ermöglicht ein Menüpunkt im verzeichnisspezifischen Kontext-Menü: “Team” >> “Disconnect”.

Eclipse SVN Disconnect

Dabei lässt man im nächsten Schritt auf Rückfrage auch die projektspezifischen “.svn”-Einträge löschen. Dabei bleiben allerdings – wie ein anschließender Blick auf die Verzeichnisstruktur zeigt – die ins Projekt kopierten “.svn”-Ordner unangetastet! Das musste man eigentlich erwarten.

Hinweis zu Schritt 2:
Schritt 2 ist wegen der Vielzahl der “.svn”-Verzeichnisse u.U. sehr zeitaufwändig. Ein rekursives Löschen der “.svn”-Verzeichnisse auf allen (!) Verzeichnisebenen der kopierten Ordner ist erforderlich.

Bei einer hinreichend komplexen und umfangreichen Ordner-Struktur braucht man dann gar nicht anfangen, mit “Dolphin” oder anderen grafischen Dateimanagern
herumzuwurschteln. Ich nutze in einer solchen Situation lieber die Kommandozeile.

Dort gibt es dann im Hauptverzeichnis der kopierten Ordnerstruktur (hier: “/projekte/dw/ntcomp” ) folgende Möglichkeit für die Vorsichtigen:

tux@my:/projekte/dw/ntcomp> find . -name “.svn” -exec rm -r {} \;
rm: reguläre Datei (schreibgeschützt) ?./ntc/scripts/_notes/.svn/prop-base/dwsync.xml.svn-base? entfernen? yes

Hierbei muss man allerdings das Entfernen jeder einzelnen Datei unterhalb der gefundenen “.svn”-Verzeichnisse bestätigen! Auch das ist aufwändig – wenn auch vielleicht schneller als die Arbeit mit grafischen Dateimanagern.

Für die weniger Vorsichtigen tut es auch ein

tux@my:/projekte/dw/ntcomp> find . -name “.svn” -exec rm -fR {} \;

oder ein

tux@my:/projekte/dw/ntcomp> find . -type d -name .svn | xargs -i rm -r {};

In den beiden letzten Fällen muss man die Löschaktion nicht bestätigen und das rekursive Löschen braucht nur Millisekunden. Also Vorsicht: Doppelt und dreifach checken, dass man das Richtige im richtigen Verzeichnis tut – und vorher lieber mal alles sichern! Lieber auch nur den “.” als “./” angeben. Vergisst man bei “./” durch Fehler den “.” hat dies je nach Rechtesituation evtl. gravierende Auswirkungen!

Wenn ich alles richtig gemacht habe, ist mein neues PHP-Projekt schließlich von allem ungewollten SVN-Ballast alter Projekte, aus denen ich Verzeichnisse kopiert habe, befreit.

Und dann funktioniert auch die SVN-Verwaltung des neuen Projektes mit den sich spezifisch entwickelnden Klassen und Programmen wieder wie gewünscht – nämlich vollständig und unabhängig von alten Projekten !

Schritt 3 braucht für diejenigen, die SVN unter Eclipse einsetzen, keine besondere Erläuterung. Man “shared” das Projekt erneut (Menüpunkt “SVN” >> “Share Projects …” ) und hangelt sich durch die menügeführte SVN-Einrichtung für das Projekt.

Viel Spaß weiterhin mit Eclipse, SVN und PHP.