Martin Lantzsch
Software Entwickler
18. August 2010

einfaches PHP Plugin System

18. August 2010 - Geschrieben von Martin - 6 Kommentare

Plugin Systeme, sie sind viel gefragt in der heutigen Zeit, jeder will seinen Code schön erweiterbar haben, doch viele haben entweder gar keinen Schimmer wie sie das am besten machen oder sie setzten es teils auf unglaubliche Weise um. Ich habe schon die verrücktesten Kostruktionen gesehen, die Code aus Datenbanken lesen oder wie die phpBB Jungs, die einen ganzen Parser geschrieben haben, der Core Dateien Modifiziert, um an bestimmten Stellen eigenen Code ausführen zu können. Für mich ist das alles Humbug, ein Plugin System muss flexibel und performant sein und nicht zuletzt sollte das ganze so umgesetzt werden, dass vom Benutzer selbst keinerlei Änderung am Code durchgeführt werden muss um ein Plugin einzubauen/zu laden.

Dem habe ich mir angenomen, und zwar habe ein an meinem SimpleLD Framework angelehntes Plugin System (bzw. eine Klasse) geschrieben, die alle aufgezählten Punkte vereint. Folgende Funktionen hat das ganze:

  • Überall einsetzbar – Es ist lediglich eine Klasse, welche in jedem PHP Projekt verwendet werde kann
  • Sie erlaubt es Code an vorher definierten Stellen im eigenem Programm einzuhängen und auszuführen. (mittels Hooks dt. Haken)
  • Die Plugins können ohne Programmier Kentnisse vom Benutzer einfach „installiert“ werden. Denn dazu muss lediglich eine Klasse in ein vordefiniertes Verzeichnis kopiert werden.

(Für die Ungeduldigen, hier gehts zum Github Repo: PHP-Plugin-System @ Github)
Durch die geringe Anzahl an Code Zeilen (rund 100 mit Kommentaren) arbeitet das ganze System Performant. Allerdings wird es je nach Anzahl installierter Plugins langsamer, das kann aber durch einen Cache (siehe SimpleLD Framework) umgangen werden.

Wie funktioniert das ganze?
Die Funktionsweise ist ganz simpel. Plugins bestehen aus ganz normalen Klassen mit public Methoden, welche sich alle in einem von ihnen bestimmten Verzeichnis befinden. Von dort liest das Plugin System alle Klassen ein und speichert Methoden als sogenannte Hooks (dt. Haken) in einem Array. Falls im Code ein solcher Hook aufgerufen wird, werden alle Plugins mit einer passenden Methode herausgesucht und aufgerufen.

Praktisches Beispiel
Plugin Klasse (sample.php)

class sample {
  public function helloWorld() {
    echo "Hello World!";
  }
}

Wichtig: Die Klasse muss exakt so wie die Datei benannt werden! Alle Methoden ohne beginnendes _ werden als Hooks verwendet!

Datei in der das Plugin verwendet wird (index.php)

// laden des Plugin Systems
include('plugins.class.php');
// starten des Systems mit Übergabe des Plugin Verzeichnisses
plugins::start('plugin/ordner/');
// nun können wir einen Hook aufrufen
plugins::call('helloWorld');
// dann noch einen anderen 
plugins::call('foo');

Mit Parametern
Natürlich kann an Hooks auch Parameter übergeben werden. Dies geschieht in Form eines Arrays:

plugins::call('foo', array('Parameter 1', 'Parameter 2', 'Parameter 3'));

Die Methode des Plugin sieht dann folgendermaßen aus:

public function foo($parameter1, $parameter2, $parameter3) {
  // was auch immer wir tun möchten ...
}

Dabei muss allerdings beachtet werden, dass die übergeben Parameter alle von der Methode entgegen genommen werden müssen, ansonsten bricht PHP mit einem Fehler ab.

Nimmt man Änderungen an der Parametern innerhalb des Hooks vor und will diese an den Orginal Code wieder „zurückgeben“, bzw mitteilen, setzt man einfach & vor die Variable:

$var = "foo";
plugins::call('foo', array(&$var));
// Inhalt nach Änderung durch den Hook foo
echo $var;

Die Methode des Plugin sieht dann folgendermaßen aus:

public function foo(&$blub) {
  // hier können wir nun $blub ändern
}

Source Code beziehen
Der Code kann hier mit Beispielen in meinem Git Repo heruntergeladen werden:
http://github.com/LinuxDoku/PHP-Plugin-System/
oder für die faulen unter uns der Direktlink
… ich bin der Direktlink zur Zip Datei …

Tipps’n Tricks

  • Der Verzeichnis Parser liest die Plugins nach altbekannten Regeln des Alphabets (dem ABC ;-)) ein, demzufolge werden Hooks, deren Plugin Namen z.B. mit A beginnen vor Hooks, deren Plugin Namen mit M beginnen ausgeführt. Sollte dies nicht gewünscht sein, kann man sich an der Methode „load“ des System zu schaffen gemacht werden.
  • Beim Starten des System muss dem Plugin Ordnername immer ein Endendes / (Slash) mitgegeben werden!
  • Es empfiehlt sich das System in einer Global verwendeten Datei zu Starten, da ansonsten ziemlich viele Ressourcen benötigt werden. Und ein mehrfacher Start unnötig ist.
15. August 2010

PHP Timestamp heute?

15. August 2010 - Geschrieben von Martin - Keine Kommentare

Eben habe ich eine kleine Funktion geschrieben um zu Prüfen ob ein gegebener Timestamp heute ist, nichts gewaltiges aber nützlich.

function isToday($time)
{
  $begin = mktime(0, 0, 0);
  $end = mktime(23, 59, 59);
  // check if given time is between begin and end
  if($time >= $begin && $time <= $end)
  {
    return true;
  } else {
    return false;
  }
}

Falls ab 23 Uhr Abends false zurückgegeben wird, sollten Sie mal nach ihrer Server Uhr schauen (Zeitzonen oder Sommer-/Winter- Zeit).

So wird unter anderem in Resigame eine Anzeige gesteuert, die Signalisiert ob ein User heute bereits Online war.

15. August 2010

PHP_FCGI_CHILDREN – spar dir den Ram!

15. August 2010 - Geschrieben von Martin - 3 Kommentare

Mein kleiner Debian Test Server hat die letzten Tage unwahrscheinlich viel Ram gezogen. Von 265MB welche verbaut sind, nutzte er bereits nach einem Neustart ganze 75% – das kann es ja nicht sein, schließlich laufen dort lediglich ein Lighttpd, MySQL, Exim4, Courier und SSH, also nichts weltbewegendes. Zu diesem Zeitpunkt griff ich auch nur mit 2 Rechnern auf meine PHP Anwendungen zu.

Also begann ich die vielen php5-cgi Prozesse genauer unter die Lupe zu nehmen, da diese am meisten Ram brauchten. Nach einigem unnützen hin und herstellen in der PHP.ini wagte ich mich noch an die FastCGI Konfiguration von Lighttpd, dort habe ich nur so zum Test die PHP_FCGI_CHILDREN heraus geschmissen und siehe da, der Server benötigt nach einem Neustart des Webservers Lighttpd nur noch gute 30 bis 50% Ram, wenn das mal kein befriedigendes Ergebnis ist.

Des weiteren habe ich nun anstatt 12 php5-fcgi Prozessen nur noch 4 Stück. Offenbar beendet PHP oder FastCGI die Geforkten Tasks nicht mehr richtig …

Laut PHP Bugtracker existiert dieser Bug schon seit gut 3,5 Jahren: http://bugs.php.net/40286

4. August 2010

jQuery idTabs bei Seitenwechsel speichern

4. August 2010 - Geschrieben von Martin - 2 Kommentare

In letzter Zeit beschäftige ich mich wieder verstärkt mit JavaScript, bzw. jQuery. Heute habe ich auf Basis von idTabs (@BissyDesign – Danke für den Tipp ;-)) ein Horizontales Menü beflügelt, dessen Untermenüpunkte nun bei klick auf einen Obermenüpunkt ohne Seitenreload wechseln. Lange Rede kurzer Sinn:

und so sieht es nach dem klick auf „Nachrichten“ aus:

Leider hat die Sache mit idTabs einen Haken, und zwar springt das Menü nach einem Seitenreload wieder zum ersten Tab zurück und bleibt nicht beim gewählten. Doch dafür habe ich eine ganz einfache Lösung gefunden.

Als erstes müssen wir das jQuery Cookie Plugin einbinden: http://plugins.jquery.com/project/cookie
Nächster Schritt ist die Modifikation des idTabs Plugins, man suche folgende Stelle im Code (im Unkomprimierten Zeile 95):

$(id).show();
return s.change; //Option for changing url

und ändere dies zu:

$(id).show();
// write to cookie
$.cookie('PAGENAME_menu', id.split('#')[1], { expires: 1 });
return s.change; //Option for changing url

(PAGENAME_menu ist der Cookie Name, welcher an die Gegebenheiten angepasst werden muss).

Anschließend muss noch der Funktionsaufruf von idTabs Modifiziert werden:

$("#menu ul").idTabs();

zu

id = $.cookie("PAGENAME_menu");
if(id == null) { id = 0; } // failback if no cookie is availible
$("#menu ul").idTabs(id);

Nun wird bei jedem Tabwelchsel der aktuelle Tab in einen Cookie geschrieben. Beim neu laden der Seite wird dieser ausgelesen und dessen Wert (der letzte Tab) an idTabs als default Tab übergeben. Es muss lediglich beachtet werden, das keiner der Tabs das Attribut „class=’selected'“ hat, da unser Hack Trick sonst nicht funktioniert.

3. August 2010

jQuery Element Blinken lassen

3. August 2010 - Geschrieben von Martin - 4 Kommentare

Blinkende Gifs, man sieht sie nicht mehr allzu oft, aber dennoch sind sie manchmal brauchbar, um dem Benutzer etwas zu signalisieren. Leider kann man diese schlecht handhaben, denn ein mal erstellt, müsste man bei einer Änderung wieder von vorne beginnen.

Warum also nicht JavaScript dazu verwenden? Mit dieser kleinen Funktion kann man ein Element blinken lassen. Und zwar wird es erst versteckt und dann wieder eingeblendet (jQuery muss natürlich vorhanden sein):

function blink(elm, msec, speed) {
  $(elm).hide();
  $(elm).fadeIn(speed);
  window.setTimeout("blink('" + elm + "', " + msec + ", '" + speed + "')", msec);
}

elm – sagt welches Element blinken soll, z.B. „#messageIcon“
msec – die Anzahl der Milisekunden, bis die Funktion erneut aufgerufen wird. Hier sollte allerdings beachtet werden, das der Effekt auch eine gewisse Zeit benötigt, und der Nutzer durch schnelle Zeiten gestört werden könnte.
speed – gibt die Geschwindigkeit an, entweder „fast“ oder „slow“.

28. Juli 2010

Brickfilm: Was siehst du?

28. Juli 2010 - Geschrieben von Martin - Keine Kommentare

Heute habe ich im Brickboard ein echtes Meisterwerk gefunden, und zwar der Steinerei 2010 (Publikumspreis-)Gewinner – „Was siehst du?“. An dieser Stelle möchte ich den beiden „Machern“ für diesen super Film Danken. Einen Brickfilm mit solch Grandioser Qualität, gefühlvoller Story und Sprechern, die ihre Rollen überzeugend sprechen sieht man selten.

Die Geschichte handelt von einem kleinem Mädchen und einem Blinden Mann. Diesem erzählt das das Mädchen was sie sieht (deshalb auch der Titel ;)). Eine wunderschöne Welt, spielende Kinder, ein verliebtes paar und Menschen denen der Alltag Spaß bereitet. Am Ende des Films gibt es jedoch eine dramatische Wendung, offenbar wurde die schöne Welt in der alles in Ordnung ist durch einen Anschlag, Krieg oder ähnliches zerstört (wird im Film nicht erwähnt) und das Kind „spielt“ dem älterem Herr etwas vor, indem sie eine Kassette mit Geräuschen „von früher“ in ihrem Kassettenrekorder laufen lässt. Offenbar will sie dem Blinden die Wirklichkeit ersparen und ihr eine schöne – heile Welt vor Augen bringen.

Alles in allem Sehr gut Umgesetzt, sowohl die Kamera, als auch die überzeugende Synchronisation. Das ist wirklich großes Kino.

14. Juli 2010

FAT32 das alt bekannte Leid Lied

14. Juli 2010 - Geschrieben von Martin - Keine Kommentare

Soeben musste ich auf meinen 8GB USB Stick von meinem Windows Notebook aus einen Film kopieren, welcher nach dem export aus Adobe Premiere ganze 4,36GB umfasst. Eigentlich nicht weiter tragisch, wäre da nicht die Meldung „Das Zieldateisystem ist voll!“ (oder so ähnlich ;)) obwohl der USB Stick leer ist.

Was nun? Nach mehrmaligen probieren, sowie ein und ausstecken ist mir dann eingefallen, das die Maximale Dateigröße von FAT32 4GB ist. Kurz um, ich habe den USB Stick über den Arbeitsplatz zu NTFS umformatiert und schon klappt alles reibungslos … bis auf den Zugriff von Linux und Mac OS X aus, aber das ist eine andere Geschichte.

Randbemerkung: Warum kein Linux filesystem verwenden? Ganz einfach, auf dem Zielrechner, der mit für die Präsentation gestellt wird, habe ich keinen Admin Zugriff und kann somit keinen ext3 Treiber installieren.

9. Juli 2010

Netcup Gutscheine für Alle!

9. Juli 2010 - Geschrieben von Martin - 7 Kommentare

So ihr lieben heute habe ich ein paar Gutscheine für euch im Gepäck :-)

Es handelt sich hierbei um 10 Gutscheine des Webhosters Netcup im Wert von je 5€. Bei Netcup gibt es vom Einsteiger Webspace (ab 0,19€ / Monat) über vServer bis hin zu Managed vServer alles, was man für einen Gelungenen Webauftritt benötigt. Der Gutschein Code kann einfach beim bestellen mit Angegeben werden und schon hat man 5€ gespart.

Hier die Gutscheincodes:

36nc12786822950
36nc12786822951
36nc12786822952
36nc12786822953
36nc12786822954
36nc12786822955
36nc12786822956
36nc12786822957
36nc12786822958
36nc12786822959

(falls alle Gutscheine aufgebracht sind, schreibt einen Kommentar, dann bekommt ihr neue)

Ein sonniges Wochenende euch allen.