Archiv

Artikel Tagged ‘plugin’

Ein Pluginsystem mit Paketserver in PHP – Teil 2

19. Januar 2012 Keine Kommentare

Ein Pluginsystem mit Paketserver in PHP – Teil 2

Im letzten Teiles meiner Serie hab ich euch gezeigt, wie man ein Plugin innerhalb einer PHP Anwendung aufruft und, wie man die Plugininformationen effizient in der Datenbank speichert.

Kommen wir heute nun zu einer entscheidenen Frage: Wie ist das Plugin aufgebaut?

Bevor wir zur Datenstruktur kommen, überlegen wir erst einmal, welche Informationen das Plugin immer braucht:

  • Name
  • Typ
  • Installationspfad
  • Beschreibung
  • Version
  • comID (zB com.gvisions.framework)
  • Autorname
  • Autorurl
  • Version
  • Vorraussetzungen -> Unser Installationssystem prüft später, ob die Vorraussetzungen gegeben sind, um ein Plugin zu nutzen.
  • Downloadpfad -> vor der Installation lädt das Script später erst nur eine .xml Datei mit all diesen Infos herunter, damit wir nicht unnötig Daten laden, falls zB die Vorraussetzungen nicht stimmen
  • Lizenzabkommen
  • SQL Query bei Installation
  • SQL Query bei evtl. Upadte
  • SQL Query bei Deinstallation

All diese Infos packen wir in eine xml Datei, welche später auch auf dem UpdateServer liegen wird.
Die XML habe ich logisch strukturiert und sieht wie folgt aus:

<xml>
<type>plugin</type>
<typede>Erweiterung</typede>
<installpath>/apps/</installpath>

<author>solar22</author>
<date>24.11.2011</date>
<url>http://gvisions.de</url>

<zipfile>http://update.gvisions.de/app/gmoonlight.zip</zipfile>
<version>0.2</version>
<comid>com.gvisions.gmoonlight</comid>
<name>gMoon!ight</name>
<desc>Kleine Seitenverwaltung. CMS.</desc>
<requirements>com.gvisions.framework-0.1</requirements>
<license>Stimmst du mir zu?</license>

<updatesql></updatesql>
<installsql></installsql>
<unistallsql></unistallsql>

</xml>

Das Plugin wird also später von http://update.gvisions.de/app/gmoonlight.zip runtergeladen.
In der zip Datei liegen alle Dateien des Plugins, ausgehend vom Ordner $xml->installpath.$xml->comid (zB /apps/com.gvisions.framework).
Jedes Plugin wird also in einem Ordner installiert, welcher gleich der comid ist.

Innerhalb der zip Datei müssen folgende Dateien vorhanden sein:

/ – root der Zip Datei
/cp – Hier liegen später die Dateien für das ControlPanel
/cp/index.php – Diese Datei stellt die Hauptdatei des CPs dar, natürlich kann das Plugin hier andere Dateien aus seinem CP Ordner nachladen
/index.php – Diese Datei stellt die Hauptdatei des Plugins dar, wenn das Frontend das Plugin lädt (s. Teil 1)
/com.x.y.xml – ggf. die XML Datei des Plugins

Die XML Datei kommt bei meinem Verfahren nicht in die ZIP Datei rein, natürlich kann man dies trotzdem so machen, wenn man zB die Installation via “Datei hochladen” realisieren möchte.

Dies ist die Grundstruktur eines Plugins, natürlich kann der Entwickler weitere Ordner und Dateien erstellen, hauptsache ist nur, dass min. die o.g. Dateien und Ordner vorhanden sind.

Dies war Teil 2 meiner Serie, ich hoffe, es hat euch gefallen und Ihr lest auch Teil 3.

Zur Hauptseite

Ein Pluginsystem mit Paketserver in PHP – Teil 1

18. Januar 2012 Keine Kommentare

Ein PHP Plugin- und Paketsystem – Teil 1

Welcher PHP Programmierer möchte das nicht, ein Pluginsystem für seine Anwendung, welches in der Lage ist, Pakete von einem Server nachzuladen und schick zu installieren.
Ich wollte so etwas auch für meine Anwendung gFramework. Zwar hatte ich bereits vor 3 Jahren ein mal einen ähnlichen Code bereits geschrieben, doch toll und performant war dieser gar nicht.
In den folgenden Teilen dieses Tutorials möchte ich euch zeigen, wie Ihr euch so ein Pluginsystem baut und anschließend, wie Ihr ein Paketserver aufsetzt und eine automatische Installationsroutine in eure Anwendung einbaut.
Dafür werde ich das Know-How nutzen, welches ich mir im letzten halben Jahr für gFramework angegeignet habe. Die Gesamtentwicklungszeit des Systemes liegt “nur” bei 6 bis 7 Stunden (für mich als Laie auf diesem Gebiet bis Dato.).
Ihr findet am Ende jedes Teiles den ganzen Code der im Teil behandelten Dateien. Wenn Ihr nicht alle Dateien kopieren wollt, so ladet euch das gFramework herunter. (Zusatz: Erscheinungstermin und weitere Details: s. http://bug.gvisions.de)

Der hier veröffentliche Quellcode kann unter den folgenden Bedingungen genutzt und veröffentlicht werden.

Was soll das System können?

Bevor wir uns um die Erstellung der Klasse kümmern, klären wir erst einmal, was die Klasse am Ende alles können soll:

  • generalle Pluginfunktionalität: d.h. Plugin durch URL Parameter aufrufen, auf Rechte prüfen und sichern, das ganze modular
  • Plugins in Datenbank verwalten
  • Plugin(de)installation
  • Plugin von Paketserver installieren

Fangen wir an mit der Plugindatenbank

Um die Plugins später in der Datenbank zu verwalten, müssen wir eine Tabelle anlegen, nennen wir diese ‘plugins’.
Was für Felder brauchen wir in der Datenbank?

  • id int (99) auto_increment key – Hieran wird das Plugin erkannt
  • name varchar(200) – Dies ist der Name des Plugins
  • activate bool – Hier steht jeweils nur true oder false, jenachdem, ob das Plugin aktiv ist oder nicht
  • desc text – Hier soll der Entwickler eine kurze Beschreibung mitliefern, ggf. mit HilfeURL oder Screenshot
  • com_id varchar(200) – Diese ID setzt sich aus einem Präfix, den Herstellernamen und dem Pluginnamen zusammen (ähnlich wie bei Android), zB com.gvisions.framework oder com.mustermann.faq
  • version varchar(200) – Die aktuell installierte Version
  • path varchar(999) – Dies stellt den relativen Pfad zum Plugin auf dem Server dar
  • updateServer int(10) – Hier steht die ID des UpdateServer drinn, dazu kommen wir später noch.

Hier nun der SQL Code zur Datenbank:

CREATE TABLE IF NOT EXISTS `gframework_plugins` (
`id` int(99) NOT NULL AUTO_INCREMENT,
`name` varchar(200) NOT NULL DEFAULT ”,
`activate` varchar(200) NOT NULL DEFAULT ‘true’,
`desc` text NOT NULL,
`com_id` varchar(200) NOT NULL,
`version` varchar(20) NOT NULL,
`path` varchar(200) NOT NULL COMMENT ‘von root an zB root./apps/…/’,
`updateServer` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=37 ;

Damit wir einheitlich arbeiten, gebe ich euch nun eine Ordnerstruktur vor, mit welcher ich arbeite.
Ihr könnt die gesamte Klasse dann auf eure Struktur anpassen, wenn dies erforderlich ist.

/ – Dies ist der Root des Projektes
/apps – Hier liegen alle Plugins
/apps/com.gvisions.framework – Die Pluginordner sind nach dessen comid benannt, hierdurch wird die Wahrscheinlichkeit = 0, dass ein Pluginordner sich doppelt, denn bei der Installation wird geprüft, ob die comid schon registriert ist.
/core – Hier liegen die Systemdateien
/core/classes – Und hier die Klasse, indem Fall auch die Klasse gPlugin und die Klasse gInstall, welche wir brauchen

Kommen wir zum Aufruf des Plugins…

…bevor wir zum Anfang der Klasse kommen.
Um ein Plugin aufzurufen, übergeben wir den Parameter $_GET['app'] mit der PluginID oder den Parameter $_GET['app_comid'] mit der comID.
Wir schauen dann, mithilfe SQL, ob diese AppID bzw. die comID existent ist und aktiv ist.
Falls beide Abfragen true ergeben binden wir das Plugin ein, ansonten schalten wir eine 404 Seite:
Datei: /index.php


<?php

/**
* gFramework is a little framework for Scripts by gVisions.
*
*
* PHP 5
*
* LICENSE: Creative Commong NC-BY-SA 3.0 with additional legalcode (link above)
*
* @package    com.gvisions.framework
* @author     Alexander Grüßung <me at gvisions dot de>
* @copyright  2011 Alexander Grüßung
* @license    http://gvisions.de/rechte.html CC NC-BY-SA 3.0 with additional legalcode
* @version    0.5
* @link       http://gvisions.de
*/

/*
eine AppID wird immer bevorzugt, falls parralel eine app_comid angeben ist!
*/

$appid = "";
$app_comid = "";
if (isset($_GET['app']) ){
$appid = $_GET['app'];
}
if (isset($_GET['app_comid'])) {
$app_comid = $_GET['app_comid'];
}
if (empty($appid) AND empty($app_comid)) {

/*
Baue DB Verb. auf und schaue, welche App als aller erstes in der DB steht,  laden wir dann einfach diese. Der Nutzer wird darauf per trigger_error(); hingewisen!
*/

$db = new db();
$db->query("SELECT * FROM ".pfw."_".plugins." WHERE `id` != '1' ORDER BY id ASC LIMIT 0,1");
$app = $db->fetch();
if ($app->activate != "true" AND $app->activate != "1") {
require_once("apps/com.gvisions.framework/pluginnotfound.php");
die();
}
require_once($app->path."/index.php");

/*
So, dann hoffen wir mal, es war richtig.
*/

die();

}

/*
Gibt es diese Applikation denn in unserer Datenbank ?
Baue DB Verb. dafür auf:
*/

$db = new db();

/*
Suche nun in der DB nach der Applikation.
Eigentlich sollte ja nur eine Übereinstimmung vorhanden sein.
*/

if (!empty($appid)) {
$db->query("SELECT * FROM ".pfw."_".plugins." WHERE id = ".$appid."");
}
elseif (!empty($app_comid)) {
$db->query("SELECT * FROM ".pfw."_".plugins." WHERE `com_id` = '".$app_comid."'");
}
else
{
trigger_error("Interner Fehler bei appid und app_comid.",E_USER_ERROR);
}
/*
So, dann mal alles in einem array speichern
*/
$row = $db->fetch();

/*
Es gibt eine Übereinstimmung, gut, dann binden wir das Teil mal ein.
Und überlassen wir der Applikation den Rest.
*/

if ($row->activate != "true" AND $row->activate != "1")
{
require_once("apps/com.gvisions.framework/pluginnotfound.php"); //404 Seite im Hauptplugin, Pfad kann natürlich angepasst werden
die();
}
if ($num==1){
require_once($row->path."/index.php");
}

(Ein kurzer Hinweis: Ich arbeite mit einer Datenbankklasse, ihr könnt natürlich die normalen Befehle, wie mysql_connect(); mysql_query(); und andere, nutzen.)

Wie Ihr seht ist das einbinden relativ einfach, sieht mehr aus, als es ist, durch die vielen Kommentare für euch ;)
Auch seht Ihr, dass beim Aufruf keine gPlugin-Klasse aufgerufen wird, wieso? Weil die notwendigen Daten _alle_ In der Datenbank stehen, wieso dann extra Laufzeit erzeugen und über eine Klasse gehen.
Soweit wäre das Tutorial ja eigentlich zu Ende, schließlich können wir nun Plugins laden…nur ist das natürlich nicht alles, was wir wollen.

Wir wir nun die Plugins intern verwalten, das sehen wir im nächsten Teil des Tutorials!
Zur Hauptseite

Über Feedback würde ich mich natürlich freuen.

Ein kleines Pluginsystem in PHP – Teil1

2. April 2010 3 Kommentare

Artikel wurde neu geschrieben und ist hier erreichbar.

OUTDATED: Dieser Text ist veraltet und wird in der Woche vom 16.01.2012 bis zum 22.01.2012 ersetzt.

In den folgenden 3 Teilen werd ich euch zeigen, wie Ihr euch relativ einfach ein PHP Pluginsystem schreibt.
Der hier veröffentliche Quellcode kann unter der Creative Commons 3.0 by-sa mit Namensnennung von “Alexander Grüßung” und Verlinkung auf www.gvisions.de (zB. in den Credits (nicht nur als Kommentar!)) genutzt und veröffentlicht werden.

Teil 1: Vorüberlegung & die Klasse

Nun, wenn man so überlegt, was muss ein Pluginsystem alles mitbringen, damit man mit diesem ordentlich arbeiten kann?

Ich finde ein Pluginsystem sollte leicht zu verstehen sein, modular aufbauend sein und Ressourcen schonen.

Auf die Architektur der Ordner in eurem Projekt gehe ich jetzt nicht ein, da diese für die Pluginklasse, welche ich geschrieben habe nicht relevant ist.
Aber als Information gebe ich hier mal meine Ordnerstruktur preis:

/ – root Verzeichnis des Projektes
/core – hier liegen die ganzen Klassen
/application/plugins – wie der name schon sagt

 

Die anderen Ordner sind irrelevant.
In dem Ordner Plugins bekommt jedes Plugin noch einen Unterordner, die Schwierigkeit besteht darin, das die Pluginentwickler Ihre Plugins unterschiedlich benennen.
Vorerst lasse ich dies aber außer Betracht und widme mich in Teil 3 nochmal dem ganzen.

Kommen wir nun zur Pluginklasse ansich:


<del><!--?php /* gPlugin class to manage plugins (c) Alexander Gruessung 2010 */ class gPlugin { public  $pluginName = ''; public  $pluginClass = ''; public  $sql = ''; public  $content = ''; function __construct($pluginName) { $this--->pluginName = $pluginName;</del>
<del> if ($this->isRegist()==false OR $this->isActive()==false) {</del>
<del> $this->pluginName = 'PluginNotFound';</del>
<del> }</del>
<del> require_once('application/plugins/'.$this->pluginName.'/'.$this->pluginName.'.php');</del>
<del> $this->pluginClass = new $this->pluginName();</del>
<del> }</del>
<del> /*</del>
<del> * public function getContent</del>
<del> * @name getContent</del>
<del> * @version 1.0</del>
<del> * @author Alexander Gruessung</del>
<del> * @parameters pluginname</del>
<del> */</del>
<del> public function getContent() {</del>
<del> $plugin = new $this->pluginName();</del>
<del> $this->content = $plugin->run();</del>
<del> return $this->content;</del>

<del> }</del>

<del> public function getTitel() {</del>
<del> return $this->pluginClass->getTitel();</del>
<del> }</del>

<del> private function isRegist() {</del>
<del> $plugin = $this->pluginName;</del>
<del> $sql = new db();</del>
<del> $sql->query("SELECT * FROM ".prafix."_plugins WHERE `filename` = '".$this->pluginName."'");</del>
<del> $num = $sql->num_rows();</del>
<del> if ($num!="") {</del>
<del> return true;</del>
<del> } else {</del>
<del> return false;</del>
<del> }</del>
<del> }</del>

<del> public function isActive() {</del>
<del> $sql = new db();</del>
<del> $plugin = mysql_real_escape_string($this->pluginName);</del>
<del> $sql->query("SELECT * FROM ".prafix."_plugins WHERE `filename` = '".$plugin."' AND `activate` = 'true'");</del>
<del> $row = $sql->fetch();</del>
<del> $num = $sql->num_rows();</del>
<del> if ($num=="" OR $row->activate=="false") {</del>
<del> return false;</del>
<del> } else {</del>
<del> return true;</del>
<del> }</del>
<del> }</del>

<del>}</del>

Die Klasse ist somit komplett.
Erklärungen, so denke ich, muss ich nicht viele geben.>
Kurz zur Datenbankstruktur:

id (int, primary) | name (varchar 500 [für beschreibung]) | filename (varchar 200 [dateiname des plugins]) | activate (varchar 4 [true oder false])

Die Verwaltung der Plugins ist also relativ einfach.
Jetzt mal ein beispielplugin:

<!--?php class HelloWorld {  public function __constructor() {  }  public function getTitel() {  return "Hello World";  } //hier eventuell Dateien includieren und/doder Funktionen einbinden.  public function run() {   $html = "Hello World";   return $html;  } } ?-->

Wie man also sieht, gibt die Funktion run() in meinem Fall den HTML Quelltext zurück.
Natürlich kann man Pluginintern noch mit Templates arbeiten. Das ist garkein problem und sollte auch für PHP Laien realisierbar sein.
Stichwort: preg_replace, preg_match und so weiter…

Aufgerufen werden Plugins folgendermaßen:

</pre>
&nbsp;

<!--?php $plugin = new gPlugin('HelloWorld');  //die Klasse deklaireren $pluginTitel = $plugin--->getTitel();</del></span>
<span style="color: #000000;"><del>$pluginContent = $plugin->getContent();
?>

 

Nun kann man mit diesen Variablen machen, was man will:)

Im nächsten Teil werde ich auf eine Installationsroutine eingehen.

Rss Feed Tweeter button Facebook button Technorati button Delicious button Flickr button Youtube button