einfaches PHP Plugin System


No Comments

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.

PHP Timestamp heute?


No Comments

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.

PHP_FCGI_CHILDREN – spar dir den Ram!


2 Comments

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

jQuery idTabs bei Seitenwechsel speichern


2 Comments

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.

jQuery Element Blinken lassen


1 Comment

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”.

Older Entries