<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tobis Blog &#187; Webentwicklung</title>
	<atom:link href="http://blog.aditu.de/category/webentwicklung/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.aditu.de</link>
	<description>Alles rund um Webentwicklung, Fotografie, PHP und das Zend Framework</description>
	<lastBuildDate>Mon, 06 Sep 2010 19:03:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>ServerBridge zwischen PHP und C/C++</title>
		<link>http://blog.aditu.de/2010/05/15/serverbridge-zwischen-php-und-cc/</link>
		<comments>http://blog.aditu.de/2010/05/15/serverbridge-zwischen-php-und-cc/#comments</comments>
		<pubDate>Sat, 15 May 2010 11:11:14 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[mongoose]]></category>
		<category><![CDATA[Zend Server]]></category>

		<guid isPermaLink="false">http://blog.aditu.de/?p=428</guid>
		<description><![CDATA[Jetzt ist es schon wieder einige Zeit her, dass ich hier etwas geschrieben habe und ich denke ich gebe mal ein Lebenszeichen von mir. Natürlich gibt es zahlreiche interessante Themen in meiner Queue zum bloggen, aber wie immer findet man nicht die Zeit oder nötige Ruhe dazu. Die Problemstellung Nun aber zum Thema: für ein [...]]]></description>
			<content:encoded><![CDATA[<p>Jetzt ist es schon wieder einige Zeit her, dass ich hier etwas geschrieben habe und ich denke ich gebe mal ein Lebenszeichen von mir. Natürlich gibt es zahlreiche interessante Themen in meiner Queue zum bloggen, aber wie immer findet man nicht die Zeit oder nötige Ruhe dazu.</p>
<h2>Die Problemstellung</h2>
<p>Nun aber zum Thema: für ein aktuelles Projekt benötige ich, von meiner PHP Webapplikation heraus, den Zugriff auf einige Hardwarekomponenten. Zudem will ich einige Fremdbibliotheken verwenden, die sehr rechenintensive Aufgaben übernehmen und auch nur in C++ zur Verfügung stehen. Die Frage ist also: wie kann ich diese Komponenten an mein PHP Programm ankoppeln?</p>
<p>Für Java gibt es eine ganz gute <a title="PHP Java Bridge" href="http://php-java-bridge.sourceforge.net/pjb/">Server Bridge</a>, die innerhalb der Java Virtual Machine einfach einen kleinen Server startet, der XML Anfragen entgegen nimmt, stellvertretend ausführt und das Ergebnis, auch wieder über eine XML Kommunikationsschnittstelle, zur Verfügung stellt. Die nötige PHP Klasse wird ebenfalls durch den Java Server direkt zur Verfügung gestellt. Eine ähnliche Bridge Lösung bringt auch der <a title="Zend Server Community Edition" href="http://www.zend.com/de/products/server-ce/">Zend Server</a> bereits out of the box mit.</p>
<p>Für C++ habe ich so eine Lösung nicht gefunden und als weiteren Ansatz überlegt, eine PHP Extension zu entwickeln. Sowohl für Linux, als auch für Windows, gibt es hier Tutorials (siehe &#8220;<a title="Extension-Entwicklung unter WAP" href="http://www.phpforum.de/forum/showthread.php?t=244096">Extension-Entwicklung unter WAP</a>&#8220;, &#8220;<a title="Wrapping C++ Classes in a PHP Extension" href="http://devzone.zend.com/article/4486-Wrapping-C-Classes-in-a-PHP-Extension">Wrapping C++ Classes in a PHP Extension</a>&#8221; oder &#8220;<a title="Extension Writing Part I: Introduction to PHP and Zend" href="http://devzone.zend.com/article/1021">Extension Writing Part I: Introduction to PHP and Zend</a>&#8220;). Allerdings ist, neben den Tutorials, der ganze Vorgang nicht gut dokumentiert und scheinbar muss das Kompilat der Extension exakt dem des verwendeten PHP Kompilats entsprechen. Insgesamt also eher eine wackelige Angelegenheit.</p>
<h2>Lösungsansatz</h2>
<p>Meine Lösung ist hingegen pragmatisch und verfolgt eine eher losere Kopplung: Meine C++ Komponenten werden in ein eigenständiges Programm ausgelagert, das selbst, über einen gewöhnlichen HTTP Server, die benötigten Dienste zur Verfügung stellt. Dabei orientiere ich mich an dem REST Architektur Prinzip und binde jeweils eine Teil-Funktionalität an eine feste URL. Die Parameter und Rückgabewerte werden mittels JSON kodiert. Von PHP Seite aus, wird der Aufruf der C++ Komponenten sauber gekapselt, so dass für das PHP Programm der Eindruck entsteht, dass eine gewöhnliche Funktion aufgerufen wird.</p>
<p>Welche Vor- und Nachteile hat das Vorgehen? Zum einen ist die in C++ implementierte Funktionalität sauber gekapselt und von der Webapplikation getrennt. Dadurch wird die Software leichter wartbar. Durch eine saubere Schnittstellendefinition, kann die C++ Serverkomponente auch unabhängig vom Wissen über die PHP Applikation gepflegt werden. Zum anderen entsteht aber ein zusätzlicher Aufwand (mit zusätzlichen Fehlerquellen). Die Schnittstelle muss definiert und implementiert werden, ein Fehlerhandling muss durchgeführt werden und eine zusätzliche Serverapplikation muss gestartet werden, was hinsichtlich der Sicherheit berücksichtigt werden muss. Dennoch halte ich die Lösung für die eleganteste, denn sie nutzt genau die Vorteile der Vernetzung und der losen Kopplung aus. So könnte die C++ Komponente bei höherer Last auch leicht auf einen eigenen Server umgezogen oder unabhängig von der Webapplikation betrieben werden.</p>
<h2>Implementierung</h2>
<p>In der Theorie hört sich natürlich immer alles ganz nett an, aber wie sieht das mit dem HTTP Server aus? Hier gibt es eine hervorragende C++ Bibliothek, mit der sich ohne großen Aufwand eine solcher HTTP Server realisieren lässt. <a title="mongoose" href="http://code.google.com/p/mongoose/">mongoose</a> heißt das Wunderding, steht unter der MIT Lizenz unter <a title="mongoose" href="http://code.google.com/p/mongoose/">Google Code</a> zur Verfügung. Es unterstützt Windows, Linux und Mac OS X, bietet eine CGI Schnittstelle, SSL Verschlüsselung, ACL, eine saubere API und ist nicht größer als 60 kB. Die Dokumentation ist zwar recht knapp, aber dank Beispiele findet man sich schnell zurecht und auch die API Beschreibung ist vollkommen ausreichend.</p>
<p>Will man einen eigenen Server starten, so muss zuerst ein neuer Context erzeugt werden:</p>
<pre class="brush: cpp;">
struct mg_context* ctx;
ctx = mg_start();
</pre>
<p>Mit <em>mg_set_options</em>, werden die Servereinstellungen geändert. Folgende zwei Zeilen deaktivieren das Directory Listing und setzten 8080 als Port.</p>
<pre class="brush: cpp;">
mg_set_option(ctx, &quot;dir_list&quot;, &quot;no&quot;);
mg_set_option(ctx, &quot;ports&quot;, &quot;8080&quot;);
</pre>
<p>Aus Sicherheitsgründen erlaube ich nur einen Zugriff vom selben Rechner aus, also erlaube nur die IP Adresse 127.0.0.1:</p>
<pre class="brush: cpp;">
mg_set_option(ctx, &quot;acl&quot;, &quot;-0.0.0.0,+127.0.0.1&quot;);
</pre>
<p>Mit <em>mg_set_uri_callback</em> kann ein Pointer auf eine eigene Funktion an eine URL gebunden werden. Diese wird aufgerufen, wenn der Client die URL aufruft, wobei die URL auch Wildcards enthalten kann.</p>
<pre class="brush: cpp;">
mg_set_uri_callback(ctx, 'dosomething', &amp;Server::dosomething, NULL);
</pre>
<p>Als dritter Parameter darf ein Pointer (<em>void*</em>) auf ein beliebiges Objekt übergeben werden. Die Callback Methode bekommt dazu alle notwendigen Parameter, wie die aktuelle Verbindung, den aktuellen Request und das zuvor übergebene Objekt (hier <em>NULL</em>) übergeben.</p>
<pre class="brush: cpp;">
void Server::capture(struct mg_connection *conn,
 const struct mg_request_info *request_info,
 void *user_data) {
char* param = mg_get_var(conn, &quot;param&quot;);
mg_printf(conn, &quot;%s&quot;, &quot;HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n&quot;);
}
</pre>
<p>Mit <em>mg_printf</em> kann dann eine Antwort an den Client gesendet werden. Hier als einfaches Beispiel einfach nur ein OK (HTTP 200). In meinem Szenario wird hier der generierte JSON Text zurück gegeben. Mit mg_get_var können übergebene Parameter (POST, GET) ausgelesen werden. Wichtig: um memory leaks zu vermeiden, müssen diese mit <em>mg_free</em> wieder freigegeben werden.</p>
<p>Natürlich ist das nur die eine Hälfte. PHP muss jetzt auch Funktionen, auf dem Server, aufrufen können. Dazu kommt der Zend_Http_Client zum Einsatz. Dieser ist im Zend Framework enthalten, mit etwas Frickelei kann er aber auch aus dem Gesamtpaket heraus gepickt werden. Da ich aber das Zend Framework für die ganze Anwendung nutze, ist das Aufrufen der URL und das Decodieren des JSON Strings in einen Action Helper ausgelagert, der gleichzeitig eine einfache Fehlerbehandlung durchführt:</p>
<pre class="brush: php;">
class JsonHttpHelper extends Zend_Controller_Action_Helper_Abstract {
   public function get($url, $params = array()) {
      try {
         $client = new Zend_Http_Client($url);
         foreach($params as $param=&gt;$value)
            $client-&gt;setParameterPost($param, $value);
            $response = $client-&gt;request('POST');
            $res = Zend_Json::decode($response-&gt;getBody());
            if($response-&gt;isSuccessful()) {
               return $res;
            } else {
               return array(&quot;error&quot; =&gt; &quot;request not successfully: &quot;.$res[&quot;error&quot;]);
            }
      } catch(Exception $e) {
         return array(&quot;error&quot; =&gt; $e-&gt;getMessage());
      }
 }
}
</pre>
<p>Bisher bin ich mit der Lösung sehr zufrieden. Besonders mongoose kann ich nur wärmstens empfehlen. Auch von der Verarbeitungsgeschwindigkeit ist das Ergebnis zufriedenstellend und kann sich sehen lassen. Um den Rahmen nicht zu sprengen, habe ich die serverseitige Generierung und Verarbeitung von JSON außen vor gelassen. Hier gibt es aber auch zahlreiche Bibliotheken, so dass die Suche nicht schwer fallen dürfte.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2010/05/15/serverbridge-zwischen-php-und-cc/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mit Hilfe von phpQuery fremde Seiten verarbeiten</title>
		<link>http://blog.aditu.de/2010/03/18/mit-hilfe-von-phpquery-fremde-seiten-verarbeiten/</link>
		<comments>http://blog.aditu.de/2010/03/18/mit-hilfe-von-phpquery-fremde-seiten-verarbeiten/#comments</comments>
		<pubDate>Thu, 18 Mar 2010 18:21:19 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[phpquery]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://blog.aditu.de/?p=415</guid>
		<description><![CDATA[Ich habe in diesem Blog ja bereits einmal darüber geschrieben, wie man mit Hilfe des Zend Frameworks fremde Seiten verarbeiten kann. Einen zweiten, sehr eleganten Weg, wie man fremde HTML Seiten verarbeiten kann, bietet die Bibliothek phpQuery. Diese greift zwar auch auf das Zend Framework zurück, bringt davon aber nur zwei Teilkomponenten mit und ist [...]]]></description>
			<content:encoded><![CDATA[<p>Ich habe in diesem Blog ja bereits einmal darüber geschrieben, <a title=" Mit Hilfe des Zend Frameworks fremde Seiten verarbeiten" href="http://blog.aditu.de/2008/12/02/mit-hilfe-des-zend-frameworks-fremde-seiten-verarbeiten/">wie man mit Hilfe des Zend Frameworks fremde Seiten verarbeiten kann</a>. Einen zweiten, sehr eleganten Weg, wie man fremde HTML Seiten verarbeiten kann, bietet die Bibliothek <a title="phpQuery" href="http://code.google.com/p/phpquery/">phpQuery</a>. Diese greift zwar auch auf das Zend Framework zurück, bringt davon aber nur zwei Teilkomponenten mit und ist dadurch viel schlanker.</p>
<p>phpQuery greift die Vorgehensweise von <a title="jQuery" href="http://www.jquery.com">jQuery</a> auf und bietet eine zentrale Funktion an, mit deren Hilfe DOM Elemente in einem Dokument selektiert werden können. Beispielsweise liefert die folgende Funktion alle &#8216;ul&#8217; Elemente.</p>
<pre class="brush: php;">
$uls = pq('ul');
</pre>
<p>Mit phpQuery hat man natürlich auch die Möglichkeit, wie bei jQuery auch DOM Elemente zu manipulieren, zu löschen oder neue einzufügen.</p>
<p>Will man also beispielsweise alle Suchergebnisse von Google abgreifen, so reicht folgender Code aus, der dann alle gefundenen URLs ausgibt:</p>
<pre class="brush: php;">
require('phpQuery/phpQuery.php');
$q = &quot;phpquery&quot;;
$doc = phpQuery::newDocument(
	file_get_contents('http://www.google.com/search?q='.urlencode($q))
);
foreach(pq('.g', $doc) as $entry) {
	$url = pq($entry)-&gt;find('.r a')-&gt;attr('href');
	$title = pq($entry)-&gt;find('.r a')-&gt;html();
	echo '&lt;a href=&quot;'.$url.'&quot;&gt;'.$title.'&lt;/a&gt;&lt;br /&gt;';
}
</pre>
<p>Mir gefällt der Ansatz, die Funktionalität von jQuery teilweise in die Welt von PHP zu übertragen. Jeder, der in irgendeiner Form HTML in PHP verarbeiten muss, sollte sich diese Bibliothek auf jeden Fall genauer ansehen.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2010/03/18/mit-hilfe-von-phpquery-fremde-seiten-verarbeiten/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>phphatesme.de in neuem Gewand</title>
		<link>http://blog.aditu.de/2010/02/22/phphatesme-de-in-neuem-gewand/</link>
		<comments>http://blog.aditu.de/2010/02/22/phphatesme-de-in-neuem-gewand/#comments</comments>
		<pubDate>Mon, 22 Feb 2010 19:07:03 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[phphatesme]]></category>
		<category><![CDATA[rsslounge]]></category>

		<guid isPermaLink="false">http://blog.aditu.de/?p=386</guid>
		<description><![CDATA[Heute feiert der populäre phphatesme Blog seinen 500. Beitrag und präsentiert sich im Zuge des Jubiläums in einem neuen Design. Mir gefällt das neue Layout sehr gut, es ist schlicht und übersichtlich. Natürlich gibt es auch ein Gewinnspiel mit interessanten Bücher, Eintrittskarten und Zeitungsabos als Preise. Wer meinen Blog liest, kennt phphatesme bereits von meinem [...]]]></description>
			<content:encoded><![CDATA[<p>Heute feiert der populäre <a title="phphatesme" href="http://www.phphatesme.com">phphatesme Blog</a> seinen 500. Beitrag und präsentiert sich im Zuge des Jubiläums in einem neuen Design. Mir gefällt das neue Layout sehr gut, es ist schlicht und übersichtlich. Natürlich gibt es auch ein Gewinnspiel mit interessanten Bücher, Eintrittskarten und Zeitungsabos als Preise.</p>
<p>Wer meinen Blog liest, kennt phphatesme bereits von meinem <a title="Gastbeitrag rsslounge auf phphatesme" href="http://blog.aditu.de/2010/01/19/gastbeitrag-auf-phphatesme/">Gastbeitrag über rsslounge</a>. Jedem anderen empfehle ich einen Blick auf den Blog zu werfen, der täglich interessante Themen aus der Softwareentwicklung mit PHP aufgreift.</p>
<p><a title="phphatesme Gewinnspiel" href="http://www.phphatesme.com/blog/allgemein/das-gewinnspiel-geht-los/"><img class="alignnone size-full wp-image-387" title="phphatesme" src="http://blog.aditu.de/wp-content/uploads/2010/02/phphatesme.png" alt="" width="518" height="310" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2010/02/22/phphatesme-de-in-neuem-gewand/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>jQuery simple carousel</title>
		<link>http://blog.aditu.de/2010/02/10/jquery-simple-carousel/</link>
		<comments>http://blog.aditu.de/2010/02/10/jquery-simple-carousel/#comments</comments>
		<pubDate>Wed, 10 Feb 2010 19:05:13 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[carousel]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://blog.aditu.de/?p=369</guid>
		<description><![CDATA[Eine einfache und ansprechende Möglichkeit mehrere Informationen auf Webseiten zu präsentieren, bietet ein &#8220;carousel&#8221; Effekt. Besonders wenn eine Liste von Eigenschaften veranschaulicht, Screenshots oder Features oder Fotografien präsentiert werden sollen, bietet es sich an, die einzelnen Bilder nacheinander einzuschieben und wieder verschwinden zu lassen (Beispiel: rsslounge). Neben einer sehr guten Nutzung des zur Verfügung stehenden [...]]]></description>
			<content:encoded><![CDATA[<p>Eine einfache und ansprechende Möglichkeit mehrere Informationen auf Webseiten zu präsentieren, bietet ein &#8220;carousel&#8221; Effekt. Besonders wenn eine Liste von Eigenschaften veranschaulicht, Screenshots oder Features oder Fotografien präsentiert werden sollen, bietet es sich an, die einzelnen Bilder nacheinander einzuschieben und wieder verschwinden zu lassen (Beispiel: <a title="rsslounge slider demo" href="http://rsslounge.aditu.de">rsslounge</a>). Neben einer sehr guten Nutzung des zur Verfügung stehenden Platzes, fällt durch die Bewegung die Information auf und lenkt die Aufmerksamkeit auf wichtige Kernbotschaften.</p>
<p>Slide Effekte und Carousel Skripte gibt es im Internet viele, überzeugen konnte mich keines. Meistens sind sie zu umfangreich oder es ist spezielles CSS notwendig, das dann unüberschaubar eingebunden bzw. die eigene Struktur daran angepasst werden muss. Nachdem jQuery sehr komfortabel ist und ich die meisten meiner Projekte auf jQuery aufbauen, habe ich mich entschlossen selbst ein einfaches jQuery Plugin zu schreiben. Dieses kommt ohne spezielles CSS aus und ist mit 1,8 kB auch schön kompakt.</p>
<p>Das Skript erwartet folgende HTML Struktur:</p>
<pre class="brush: xml;">
&lt;ul id=&quot;carousel&quot;&gt;
 &lt;li&gt;erster Frame (z.B. ein Bild)&lt;/li&gt;
 &lt;li&gt;zweiter Frame (z.B. ein Bild)&lt;/li&gt;
 &lt;li&gt;dritter Frame (z.B. ein Bild)&lt;/li&gt;
 &lt;li&gt;vierter Frame (z.B. ein Bild)&lt;/li&gt;
 ...
&lt;/ul&gt;
</pre>
<p>Um nun aus der Liste ein carousel zu machen, reicht beispielsweise folgender Aufruf aus:</p>
<pre class="brush: jscript;">
$(&quot;#carousel&quot;).simplecarousel({
 slidespeed: 700,
 auto: 5000,
 width: 480,
 height: 280
});
</pre>
<p>In obigen Fall ist das carousel 480&#215;280 Pixel groß, wechselt automatisch alle 5 Sekunden zum nächsten Frame und der Wechsel (Geschwindigkeit des slide Effektes) dauert 0,7 Sekunden.</p>
<h2>Es werden folgende Parameter unterstützt:</h2>
<ul>
<li><strong>width</strong>: (int) Breite</li>
<li><strong>height</strong>: (int) Höhe</li>
<li><strong>next</strong>: (jQuery Objekt/Selector) wird auf dieses Objekt geklickt, wird der nächste Frame aufgerufen</li>
<li><strong>prev</strong>: (jQuery Objekt/Selector) wird auf dieses Objekt geklickt, wird der vorhergehende Frame aufgerufen</li>
<li><strong>vertical</strong>: (boolean) <em>true </em>= vertikales carousel; <em>false </em>= horizontales carousel</li>
<li><strong>auto</strong>: (int/boolean) <em>false </em>= kein automatischer Wechsel; <em>Wert in Millisekunden</em> = pause bis automatisch zum nächsten Frame gewechselt wird</li>
<li><strong>slidespeed</strong>: (int) Geschwindigkeit des Wechsels in Millisekunden</li>
<li><strong>visible:</strong> (int) Anzahl an Frames die gleichzeitig sichtbar sein sollen</li>
<li><strong>fade</strong>: (int) wird dieser Wert angegeben, so wird anstatt zu sliden das Frame ausgeblendet und das neue wieder eingeblendet. Die Geschwindigkeit des fade Effektes ist dann dieser Wert (siehe <a title="aditu.de fade statt slide" href="http://www.aditu.de">aditu.de</a>)</li>
</ul>
<h2>Demo:</h2>
<ul>
<li><a title="rsslounge" href="http://rsslounge.aditu.de">rsslounge</a></li>
<li><a title="aditu.de" href="http://www.aditu.de">aditu.de Fotografie (fade Effekt)</a></li>
<li><a title="aditu.de slide" href="http://www.aditu.de/projects">aditu.de Projects (slide Effekt)</a></li>
</ul>
<h2>Download:</h2>
<ul>
<li><a href="http://blog.aditu.de/wp-content/uploads/2010/02/simple.carousel.0.2.zip">simple.carousel.0.2</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2010/02/10/jquery-simple-carousel/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Intrusion Detection mit PHPIDS</title>
		<link>http://blog.aditu.de/2010/01/30/intrusion-detection-mit-phpids/</link>
		<comments>http://blog.aditu.de/2010/01/30/intrusion-detection-mit-phpids/#comments</comments>
		<pubDate>Sat, 30 Jan 2010 12:23:46 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[Intrusion Detection]]></category>
		<category><![CDATA[PHPIDS]]></category>

		<guid isPermaLink="false">http://localhost/aditu.de/blog2/?p=5</guid>
		<description><![CDATA[Eine große Sache bei der Entwicklung von Webapplikationen ist das Thema Sicherheit. Verfolgt man verschiedene Nachrichtendienste zum Thema Sicherheit, dann stellt man sehr schnell fest, dass zahlreiche Applikationen immer wieder kritische Sicherheitslücken aufweisen. Besonders wenn es sich um OpenSource Software handelt stellt das ein Problem dar, da ein Angreifer den Programmcode einer möglichen Opferapplikation kennt. [...]]]></description>
			<content:encoded><![CDATA[<p>Eine große Sache bei der Entwicklung von Webapplikationen ist das Thema Sicherheit. Verfolgt man verschiedene Nachrichtendienste zum Thema Sicherheit, dann stellt man sehr schnell fest, dass zahlreiche Applikationen immer wieder kritische Sicherheitslücken aufweisen. Besonders wenn es sich um OpenSource Software handelt stellt das ein Problem dar, da ein Angreifer den Programmcode einer möglichen Opferapplikation kennt.</p>
<p>Ein Blick in die Literatur offenbart einige grundlegende Bedrohungen, die immer wieder anzutreffen sind:</p>
<ul>
<li><strong>SQL Injection</strong>: fremde SQL Statements werden in die Opferapplikation eingeschleußt und von dieser ausgeführt</li>
<li><strong>Command Injection</strong>: Einschleusen (Injizieren) bösartiger Befehle zur Kompromittierung der Funktionsschicht</li>
<li><strong>Cross-Site Scripting</strong>: Einschleusen (Injizieren) von bösartigen Programmcode</li>
<li><strong>Directory Traversal</strong>: Technik um an nicht öffentliche, aber zugängliche Daten zu kommen</li>
<li><strong>Header Injection</strong>: Manipulation von dynamisch generierten Header</li>
<li><strong>Session Hijacking</strong>: Technik zur Übernahme einer fremden Session</li>
<li><strong>Session Fixation</strong>: Technik zur Session-Manipulation um Session des Angreifers zu privilegieren</li>
<li><strong>Cookie Poisoning</strong>: Manipulation von Cookies</li>
</ul>
<p>Eine sehr schöne Übersicht mit möglichen Gegenmaßnahmen zeigt hier das Buch &#8220;<em>Pro PHP Security</em>&#8221; von Chris Snyder und Michael Southwell auf (apress Verlag, ISBN: 1-59059-508-4).</p>
<h2>PHPIDS</h2>
<p><a title="PHPIDS" href="http://php-ids.org"><img src="wp-content/uploads/2010/01/25/phpids_logo.gif" alt="PHPIDS Logo" width="320" height="66" /></a></p>
<p>Vor einiger Zeit bin ich auf <a title="PHPIDS" href="http://php-ids.org/">PHPIDS</a> gestoßen, einem <a title="Wikipedia: Intrusion Detection System" href="http://de.wikipedia.org/wiki/Intrusion_Detection_System">Intrusion Detection System</a> für PHP. Dabei handelt es sich um ein Skript, das mittels regulären Ausdrücken und einem generischen Ansatz (Zentrifuge-Ansatz) die übergebenen Parameter (GET, POST, COOKIE, REQUEST) überprüft und mögliche Angriffe erkennt.</p>
<p>Ein erkannter Angriff wird mit einem &#8220;Impact&#8221; Wert gekennzeichnet, der angibt, wie schwerwiegend der Angriff ist. Ein Impactwert von 2-5 ist unbedenklich, wobei ein Impact 15 schon sehr hoch ist und eine Reaktion erfordert. Ein sehr hoher Wert (25-50) macht eine Reaktion unbedingt erforderlich. Dabei kommt PHPIDS auch mit exotischen Zeichensätze (UTF-7), JavaScript Unicode, dezimal und hexcode usw. zurecht und erkennt alle gängigen Angriffsmuster wie SQL Injection, Cross-Site Scripting Attacken oder Directory Traversal Zugriffe.</p>
<p>PHPIDS steht unter LGPL und kann unter <a title="PHPIDS" href="http://php-ids.org">http://php-ids.org</a> frei heruntergeladen werden.</p>
<h2>Arbeitsweise</h2>
<p>PHPIDS besitzt eine Liste von Filterregeln. Diese definieren reguläre Ausdrücke, welche gängige Angriffmuster erkennen. Dazu wird der Angriff mit einem Tag und einem Impactwert gekennzeichnet. Greifen mehrere Filterregeln, dann werden die einzelnen Impactwerte aufkummuliert. Um neue, unbekannte Angriffe zu erkennen, wird ein Zentrifuge-Ansatz verwendet, d.h. ist ein Parameter ein String von der Mindestlänge von 40 Zeichen, dann wird dieser String durch geschickte Zeichenersetzung auf eine repräsentative, kurze Zeichenkombination reduziert. Hierbei werden:</p>
<ol>
<li>alle Wortzeichen sowie Whitespace (berücksichtigt Unicode) entfernt</li>
<li>mehrfach vorkommende Zeichen werden gestrippt</li>
<li>bestimmte Zeichengruppen durch festgelegte Zeichen ersetzt (Ziel: Anzahl unterschiedliche Zeichen gering halten)</li>
<li>unerwünschte Zeichen (z.B. Backslash aus Magic-Quotes-Funktion) entfernt</li>
</ol>
<p>Das Ergebnis ist ein String aus 4 bis 6 Zeichen. Cross Site oder Code Injection Angriffe führen dabei erstaunlicherweise immer wieder auf ein ähnliches Muster. Taucht ein solches Muster (z.B. &#8220;((+::&#8221;) auf, so schlägt PHPIDS Alarm.</p>
<h2>Installation</h2>
<p>Die Installation ist denkbar einfach. In der zentralen Bootstrap Datei einer Applikation werden die PHPIDS Klassen geladen, alle Parameter als Array übergeben und das Ergebnis ausgewertet. Die Reaktion kann selbst ausgestalltet werden und kann von einfachen Logging (PHPIDS bringt hier bereits eine Hilfsklasse mit) bis hin zum Sperren der IP Adresse reichen.</p>
<p>Einbinden und Starten von PHPIDS:</p>
<pre class="brush: php;">
$request = array(
'REQUEST' =&gt; $_REQUEST,
'GET' =&gt; $_GET,
'POST' =&gt; $_POST,
'COOKIE' =&gt; $_COOKIE
);

require_once 'IDS/Init.php';
$init = IDS_Init::init('/IDS/Config/Config.ini.php');
$ids = new IDS_Monitor($request, $init);
$result = $ids-&gt;run();

// Angriff erkannt? Loggen und Abbruch
if (!$result-&gt;isEmpty()) {
	require_once 'IDS/Log/File.php';
	require_once 'IDS/Log/Composite.php';

	$compositeLog = new IDS_Log_Composite();
	$compositeLog-&gt;addLogger(IDS_Log_File::getInstance($init));
	$compositeLog-&gt;execute($result);

	die(&quot;ids error &quot;.$result-&gt;getImpact());
}
</pre>
<p>Hat die eigene Applikation keine Bootstrap Datei, so kann mit Hilfe der PHP Option &#8220;auto_prepend_file&#8221; eine Datei angegeben werden, die immer vor der eigentlichen PHP Datei geparst wird. Diese kann unter Apache auch in der .htaccess gesetzt werden:</p>
<pre class="brush: php;">
php_value auto_prepend_file phpids.php
</pre>
<p>phpids.php muss dann den oben stehenden Programmcode enthalten und PHPIDS ausführen.</p>
<p>Hat man beispielsweise einen Blog, wo tatsächlich HTML eingegeben und übertragen wird (z.B. in der Administrationsoberfläche beim Erstellen neuer Blogeinträge), so muss das PHPIDS hier bescheid wissen, da es sonst Alarm schlägt. Hierzu können in der Konfiguration Parameter festgelegt werden, die HTML enthalten dürfen. Ebenso schlägt PHPIDS bei der Verwendung von Google Analytics Alarm. Dieses ist zwar schon vorkonfiguriert, ich musste es aber immer nochmal für REQUEST und COOKIE konfigurieren:</p>
<pre class="brush: php;">
exceptions[]    = REQUEST.__utmz
exceptions[]    = REQUEST.__utmc
exceptions[]    = COOKIE.__utmz
exceptions[]    = COOKIE.__utmc
</pre>
<h2>Performance</h2>
<p>Natürlich hat PHPIDS auch eine Auswirkung auf die Performance der Applikation. Hier haben die Entwickler verschiedene Szenarien getestet und es hat sich gezeigt, dass PHPIDS lediglich 0,5 % der gesamten Rechenzeit benötigt, wenn z.B. von einer CakePHP Applikation ausgegangen wird. Selbst wenn man davon ausgeht, dass die Zahlen geschönt sind, ergibt sich aus meiner Sicht hier trotzdem kein Problem. Nimmt man beispielsweise einen privaten Weblog, der auf WordPress basiert, dann dürften sich hier die Besucherzahlen in Grenzen halten und das IDS nicht ins Gewicht fallen.</p>
<p>PHPIDS berücksichtigt das Performanceproblem bereits und verzichtet darauf z.B. den Zentrifuge-Ansatz auf kurze Strings anzuwenden. Zudem beschränkt es sich auf Strings: Integer Werte werden beispielsweise nicht geprüft. Wer trotzdem noch optimieren will, dem bietet PHPIDS ein Caching Mechanismus, so dass die Liste mit den Filterregeln nicht jedes mal neu geparst werden muss. Zudem liegen die Filterlisten nicht nur als XML Datei vor, sondern auch im JSON Format, welches bedeutend schneller geparst wird.</p>
<h2>Literatur und Links</h2>
<ul>
<li>c&#8217;t magazin 2009 Heft 10: Alarmanlage – Angriffe auf Webanwendungen mit PHPIDS erkennen, Christian Matthies, 27.04.2009</li>
<li>PHPIDS Webseite: <a title="PHPIDS" href="http://php-ids.org/">http://php-ids.org/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2010/01/30/intrusion-detection-mit-phpids/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Einmalpasswörter mit PHP und OpenKubus</title>
		<link>http://blog.aditu.de/2009/12/24/einmalpasswoerter-mit-php-und-openkubus/</link>
		<comments>http://blog.aditu.de/2009/12/24/einmalpasswoerter-mit-php-und-openkubus/#comments</comments>
		<pubDate>Thu, 24 Dec 2009 14:10:05 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programme]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[AES]]></category>
		<category><![CDATA[mcrypt]]></category>
		<category><![CDATA[OpenKubus]]></category>
		<category><![CDATA[Sicherheit]]></category>
		<category><![CDATA[Verschlüsselung]]></category>

		<guid isPermaLink="false">http://localhost/aditu.de/blog2/?p=266</guid>
		<description><![CDATA[Schon vor einiger Zeit bin ich auf eine sehr schöne Lösung gestoßen, mit der sich ein sicherer Login mit Einmalpassworte realisieren lässt. Dabei wird ein Hardware USB Dongle verwendet, welcher nach einem Druck auf einen Taster ein Einmalpasswort generiert. Die serverseitige Prüfung kann aus einer beliebigen Sprache heraus passieren. Für mich bietet sich hier natürlich [...]]]></description>
			<content:encoded><![CDATA[<p>Schon vor einiger Zeit bin ich auf eine sehr schöne Lösung gestoßen, mit der sich ein sicherer Login mit Einmalpassworte realisieren lässt. Dabei wird ein Hardware USB Dongle verwendet, welcher nach einem Druck auf einen Taster ein Einmalpasswort generiert. Die serverseitige Prüfung kann aus einer beliebigen Sprache heraus passieren. Für mich bietet sich hier natürlich PHP an. In meinem Fall verwende ich für die Applikation das Zend Framework, aber die hier vorgestellte Lösung ist allgemein verwendbar und unabhängig vom restlichen Backend.</p>
<h2>Was ist ein Einmalpasswort?</h2>
<p>Wie der Name bereits sagt, kann ein Einmalpasswort nur für einen Login verwendet werden. Dann erlischt die Gültigkeit und ein neues Einmalpasswort wird benötigt. Ein solches Passwort wird durch eine spezielle Hardware (hier OpenKubus Stick) erzeugt. Eine genaue Definition findet ihr auch in <a title="Einmalpasswörter auf Wikipedia" href="http://de.wikipedia.org/wiki/Einmalpasswort">Wikipedia</a>, wo auch verschiedene Algorithmen vorgestellt werden. Der englischsprachige Begriff ist One Time Passwort und hierzu findet man auch auf dem <a title="One Time Password auf Wikipedia" href="http://en.wikipedia.org/wiki/One_Time_Password">internationalen Wikipedia</a> eine interessante Beschreibung.</p>
<h2>Vorteile Einmalpasswörter</h2>
<p>Zu Beginn stellt sich die Frage, welche Vorteile ein Login mit Einmalpasswörter mit sich bringt. Hier macht es Sinn, sich der Problemstellung von Seite der Bedrohungen aus zu nähern und zu analysieren, ob ein solches System für den eigenen Anwendungsfall eine sinnvolle Maßnahme ist oder nicht. Mögliche Bedrohungen, gegen die ein Einmalpasswort eine risikominimierende Wirkung hat sind:</p>
<ul>
<li>an erster Stelle natürlich eine sichere Authentifikation: nur wer den Stick besitzt kann sich auch in das System einloggen</li>
<li>ungeeigneter Umgang mit Passwörter: es kann nicht sichergestellt werden, dass Benutzer unsichere Passwörter verwenden</li>
<li>Abhören von Leitungen/Ausspähen des Passwortes: es kann passieren, dass in einer unsicheren Umgebung die eigenen Zugangsdaten abgehört werden. Hier wäre auch eine verschlüsselte Verbindung eine empfehlenswerte Gegenmaßnahme, aber auch ein Einmalpasswort bietet hier einen geeigneten Schutz, da dieses nur für einen Login gültig ist.</li>
<li> systematisches Ausprobieren von Passwörter: es kann passieren, dass ein Brute Force Angriff auf das System durchgeführt wird. Ein Einmalpasswort ist in der Regel sehr lange und somit schwerer zu knacken</li>
<li>Trojanische Pferde: am Clientrechner könnte ein Schadprogramm installiert sein, welches die Zugangsdaten ausspäht</li>
</ul>
<p>Natürlich ist ein Einmalpasswort kein Allheilmittel. So schützt es nicht vor Pishing Angriffen, oder Man in the Middle Attacken, wo die Logindaten abgefangen und erst garnicht an den Server gesendet werden.</p>
<h2>Komponenten</h2>
<p>An dieser Stelle will ich zuerst die verschiedenen Komponenten vorstellen, die für die Lösung verwendet wurden. Natürlich ist alles OpenSource und frei verfügbar. Auch der Hardwaredongle ist frei und recht günstig zu erstehen.</p>
<p><strong>OpenKubus</strong></p>
<p><a title="Openkubus auf Google Code" href="http://code.google.com/p/openkubus/"><img src="wp-content/uploads/2009/12/24/openkubus.jpg" alt="OpenKubus" width="200" height="73" /></a></p>
<p>Der OpenKubus ist ein kleiner, handlicher USB Stick (der Problemlos an den Schlüsselbund passt), dessen Hardwarelayout frei verfügbar ist und der frei programmiert werden kann. Wird der Stick an einem Rechner angesteckt, so wird er als Tastatur erkannt. Ein Druck auf einen Taster führt dazu, dass der Stick ein neues Einmalpasswort generiert und als Tastatureingabe an den Rechner sendet. Es reicht also, den Cursor auf das Eingabefeld im Login Formular zu setzen und der Stick schießt sein Passwort hinein. Dabei ist der Stick kompatibel zu nahezu allen Systemen, weil er als einfache Tastatur arbeitet.</p>
<p>Der Stick kostet 24,95 Euro und kann im <a title="Embedded projects shop" href="http://shop.embedded-projects.net/product_info.php/info/p176_Open-Kubus-USB-Stick.html">embedded projects Shop</a> bestellt werden. Beispielprogramme und die nötige Software um den Stick zu programmieren (was unter Linux recht leicht möglich ist), sind auf der <a title="Google Code OpenKubus" href="http://code.google.com/p/openkubus/">google code Projektseite</a> zu finden. Dort gibt es auch Anleitungen und ein Beispielserver in Perl. Der OpenKubus kann auch für einen sicheren Linux Login (PAM) verwendet werden.</p>
<p><strong>phpseclib</strong></p>
<p><a title="phpseclib" href="http://phpseclib.sourceforge.net/"><img src="wp-content/uploads/2009/12/24/phpseclib.jpg" alt="phpseclib" width="275" height="67" /></a></p>
<p>Um das Passwort zu entschlüsseln (AES), benötigt man eine passende Bibliothek. <a title="phpseclib" href="http://phpseclib.sourceforge.net/">phpseclib</a> bietet eine komfortable und objektorientierte Lösung, die auf keine PHP Extensions oder ähnliches angewiesen ist. Diese Bibliothek ist in PHP geschrieben, entwickelt man in einer anderen Sprache, so benötigt man irgendwie eine Möglichkeit mit AES Verschlüsselung zu arbeiten.</p>
<p>phpseclib ist aus meiner Sicht für Verschlüsselung allgemein ein Tipp. Es stehen Klassen für die verschiedensten Algorithmen zur Verfügung (z.B. RSA, SSH, DES, 3DES, AES uvm.). Die Bibliothek ist OpenSource und steht unter der LGPL Lizenz.</p>
<h2>Ablauf</h2>
<p>Um die unten stehende Implementierung zu verstehen, muss man zuerst den gesamten Ablauf kennen. Dieser ist recht simpel. Zuerst muss der Stick einmalig vorbereitet werden. Der Authentifizierungsprozess kann dann beliebig oft durchgeführt werden.</p>
<p><strong>Initialisierung</strong></p>
<p>Der Stick muss mit dem AES Schlüssel und einem zufälligen Datenblock beschrieben werden. Dies funktioniert recht einfach unter Linux:</p>
<pre class="brush: bash;">
sudo ./stick-write -p AESKeyundDatenblock
</pre>
<p>Wobei <em>AESKeyundDatenblock</em> ein 46 Byte langer String ist, der zuerst aus dem AES Key (32 Bytes lang) und dann dem Datenblock (14 Bytes lang) besteht. Der AES Schlüssel und der Datenblock müssen auch dem Server bekannt sein. Zudem muss auf dem Server der Zähler auf 0 gesetzt werden (=das nächste Einmalpasswort ist das erste).</p>
<p><strong>Authentifizierung</strong></p>
<p>Client:</p>
<ol>
<li>Der Stick wird am Client eingesteckt und das Loginformular wird aufgerufen. Nun gibt der Benutzer seinen Benutzernamen ein, setzt den Cursor auf das Einmalpasswort-Feld und drückt auf den Taster am Stick.</li>
<li>Der Stick erzeugt nun das Einmalpasswort: Ein interner Zählwert wird mit dem Datenblock verknüpft und mit dem angegebenen Schlüssel (key) AES verschlüsselt. Anschließend erhöht der Stick seinen internen Zähler um eins.</li>
<li>Das so generierte Einmalpasswort wird base64 kodiert, so dass es durch gewöhnliche (ASCII) Zeichen darstellbar ist.</li>
<li>Der Stick sendet das so generierte, base64 kodierte Einmalpasswort als Tasteneingabe und befüllt so das selektierte Feld. Ein Klick auf &#8220;Login&#8221; sendet das HTML Formular wie bei einem gewöhnlichen Login an den Server.</li>
</ol>
<p>Server:</p>
<ol>
<li>Der Server nimmt die Anfrage entgegen und lädt seinen eigenen, zum Stick passenden AES Schlüssel und Datenblock.</li>
<li>Dann wird der durch den Client übermittelte base64 String erst einmal korrigiert: ein z am Anfang kennzeichnet ob ein amerikanisches Tastaturlayout vorliegt (entsprechend müssen alle z durch y und alle y durch z ersetzt werden). Zudem werden einige Sonderzeichen ersetzt.</li>
<li>Anschließend wird das noch verschlüsselte Einmalpasswort von base64 wieder in einen Bytevektor dekodiert.</li>
<li>Nun wird das Einmalpasswort mit AES entschlüsselt.</li>
<li>der Zählstand wird ausgelesen und der Datenblock entnommen.</li>
<li>Der Login ist erfolgreich wenn der gegebene Zählstand größer dem Zählstand am Server ist <span style="text-decoration: underline;">und</span> der gegebene Datenblock mit dem intern gespeicherten übereinstimmt.</li>
<li>War der Login erfolgreich, so wird am Server der Zählstand des Sticks übernommen: es werden nur Einmalpasswörter akzeptiert, die einen höheren Zählstand haben (alte funktionieren also nicht mehr).</li>
</ol>
<p>Auch wenn sich alles nun nach einer Menge Arbeit anhört, ist die Implementierung übersichtlich. Ich habe dazu in meiner Applikation einen Action Helper verwendet (in Zend Framework Applikationen eine Hilfsklasse, die in allen Controller zur Verfügung steht). An dieser Stelle eine PHP Funktion, welche nur von phpseclib abhängt und alle Schritte durchführt, die oben unter Server gelistet sind. Jeder Schritt wird nochmal als Kommentar erklärt.</p>
<pre class="brush: php;">

/**
 * @param string $givenOtp Einmalpasswort, dass geprueft werden soll
 * @param string $aesKey der AES Schluessel und Datenteil
 * @param int $number aktueller Zaehlstand des Servers
 */
function otp($givenOtp, $aesKey, $number) {
	// AES Schluessel besteht aus
	// erste 32 Byte: AES Key
	// restliche 14 Byte: Datenblock
	$key  = substr($aesKey, 0, 32);
	$data = substr($aesKey, 32, 14);

	// base64 Kodierung des Sticks korrigieren
	$givenOtp = rtrim($givenOtp);

	// Sonderzeichen in korrekte Sonderzeichen umwandeln
	// (diese werden vom Stick anders vorgegeben, um von
	// unterschiedl. Tastaturlayouts unabhängig zu werden)
	for($i = 0; $i &lt; strlen($givenOtp); $i++) {
		if($givenOtp[$i] == &quot; &quot;) { $givenOtp[$i] = &quot;/&quot;; }
		elseif($givenOtp[$i] == &quot;.&quot;) { $givenOtp[$i] = &quot;=&quot;; }
		elseif($givenOtp[$i] == &quot;-&quot;) { $givenOtp[$i] = &quot;+&quot;; }
	}

	// erstes Zeichen pruefen ob z oder y
	// abhaengig davon alle y durch z ersetzen und umgekehrt
	$z = $givenOtp[0];
	$crypted = substr($givenOtp, 1);

	if($z == &quot;y&quot; or $z == &quot;Y&quot;) {
		for($i = 0; $i &lt; strlen($crypted); $i++) {
		  if	($crypted[$i] == 'y') { $crypted[$i] = &quot;z&quot;; }
		  elseif($crypted[$i] == 'Y') { $crypted[$i] = &quot;Z&quot;; }
		  elseif($crypted[$i] == 'z') { $crypted[$i] = &quot;y&quot;; }
		  elseif($crypted[$i] == 'Z') { $crypted[$i] = &quot;Y&quot;; }
		}
	}

	if($z == &quot;Y&quot; or $z == &quot;Z&quot;) {
		for($i = 0; $i &lt; strlen($crypted); $i++) {
			if(ctype_upper($crypted[$i])) {
				$crypted[$i] = strtolower($crypted[$i]);
			} else {
				$crypted[$i] = strtoupper($crypted[$i]);
			}
		}
	}

	// base64 String nun in binary dekodieren
	$crypted = base64_decode($crypted);

	// gegebenes One Time Passwort mit AES entschluesseln
	$aes = new Crypt_AES();
	$aes-&gt;disablePadding();
	$aes-&gt;setKey($key);
	$plain = $aes-&gt;decrypt($crypted);

	// entschluesseltes Passwort aufteilen in

	// aktueller Zaehlstand
	$i	 = substr($plain, 0,1);
	$j	 = substr($plain, 1,1);
	$n	 = ord($i) + (ord($j) &lt;&lt; 8);

	// und Datenblock
	$plain = substr($plain, 2, strlen($plain)-2);

	// wenn Datenblock korrekt und Laufnummer nach aktueller Nummer:
	// aktuelle Nummer zurueckgeben (Login korrekt)
	if(($plain == $data) and ($n &gt; $number)) {
		return $n;
	} else {
		return false;
	}
}
</pre>
<p>Natürlich kann das Entschlüsseln auch mit der <a title="mcrypt manual" href="http://de.php.net/manual/en/book.mcrypt.php">mcrypt Erweiterung</a> von PHP durchgeführt werden. So benötigt man keine zusätzliche Bibliothek wie phpseclib. Um das Passwort mit mcrypt zu entschlüsseln, muss der Codeteil</p>
<pre class="brush: php;">

$aes = new Crypt_AES();
$aes-&gt;disablePadding();
$aes-&gt;setKey($key);
$plain = $aes-&gt;decrypt($crypted);
</pre>
<p>durch die entsprechenden mcrypt Aufrufe ersetzt werden:</p>
<pre class="brush: php;">

$td = mcrypt_module_open(&quot;rijndael-128&quot;, &quot;&quot;, &quot;ecb&quot;, &quot;&quot;);
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_RANDOM);
mcrypt_generic_init($td, $key, $iv);
$plain = mdecrypt_generic($td, $crypted);
</pre>
<h2>Fazit</h2>
<p>Ich bin mit der Lösung sehr zufrieden. Die AES Schlüssel/Datenblöcke lassen sich komfortabel in der Datenbank ablegen und auch leicht ändern, falls der Stick verloren geht. Besonders wenn man oft in unsicheren Netzen unterwegs ist (z.B. in der Firma oder an der Uni, in Internet Cafes usw.) ist die Lösung praktisch. Es müssen keine langen Einmalpasswörter von einem Display abgeschrieben werden und der Stick läuft gleichermaßen unter Linux und Windows. Die Integration in die eigene Applikation ist denkbar einfach.</p>
<p>Einziger Nachteil: der Stick hat keine Zeitkomponente, d.h. jemand könnte das Passwort abgreifen und dann die Netzverbindung kappen. Erst wenn sich der Besitzer einloggt, wird das zuvor abgepishte Passwort ungültig. Ebenso lassen sich mehrere Passwörter auslesen: so lange der Besitzer sich nicht einloggt, bleiben sie alle gültig.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2009/12/24/einmalpasswoerter-mit-php-und-openkubus/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Pluginschnittstelle mittels PHP Reflection realisieren</title>
		<link>http://blog.aditu.de/2009/12/06/pluginschnittstelle-mittels-php-reflection-realisieren/</link>
		<comments>http://blog.aditu.de/2009/12/06/pluginschnittstelle-mittels-php-reflection-realisieren/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 12:47:06 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[Reflection]]></category>
		<category><![CDATA[rsslounge]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://localhost/aditu.de/blog2/?p=263</guid>
		<description><![CDATA[Erweiterbarkeit ist eine zentrale Anforderung an nahezu jede Applikation. Dabei stellt man relativ schnell fest, dass dies auf verschiedenen Ebenen einer Anwendung passieren kann. Auf einer elementaren Ebene spiegelt sich die Erweiterbarkeit in der grundlegenden Architektur wieder, kann aber auch sehr hoch angesiedelt werden. Beispielsweise in einer Pluginschnittstelle für externe Programmierer. Ralf beschreibt in seinem [...]]]></description>
			<content:encoded><![CDATA[<p>Erweiterbarkeit ist eine zentrale Anforderung an nahezu jede Applikation. Dabei stellt man relativ schnell fest, dass dies auf verschiedenen Ebenen einer Anwendung passieren kann. Auf einer elementaren Ebene spiegelt sich die Erweiterbarkeit in der grundlegenden Architektur wieder, kann aber auch sehr hoch angesiedelt werden. Beispielsweise in einer Pluginschnittstelle für externe Programmierer.</p>
<p>Ralf beschreibt in <a title="Ralf Egger Das Zend Framework" href="2009/04/05/Neues-Buch-Ralf-Eggert:-Das-Zend-Framework">seinem Buch</a> eine gute Möglichkeit eine auf dem Zend Framework basierende Applikation modular zu strukturieren (mit Teilmodule, die nach belieben eingefügt oder ausgehängt werden können). Häufig ist aber auch das zu weit gefasst und eine viel klarere und schmalere Schnittstelle reicht vollkommen aus. Gesucht ist also ein Mechanismus, der Teilfunktionen dynamisch nachlädt und in die Gesamtapplikation einbindet.</p>
<p>Ein Beispiel: mein webbasierter RSS Reader <a title="rsslounge RSS Reader" href="http://rsslounge.aditu.de/">rsslounge</a> kann verschiedene Quellen verfolgen und verarbeiten. So liest er gewöhnliche RSS Feeds. Aber weiterführend kann er auch RSS Feeds als Quelle für Bilder verarbeiten (und extrahiert aus diesen RSS Feeds nur die Bilder). Möglich ist aber auch deviantArt als Datenquelle. Sprich jede mögliche Datenquelle ist denkbar. Nicht nur RSS Feeds, sondern auch normale HTML Seiten (die in irgend einer Weise geparst werden) oder auch der Zugriff auf einen Email Account wäre denkbar. Es macht also Sinn hier eine Abstraktionsebene einzubauen und die Möglichkeit zu schaffen einfach neue Datenquellen hinzuzufügen.</p>
<p>Die Vorgehensweise, welche ich für rsslounge gewählt habe ist simpel: jede Datenquelle ist eine Klasse, welche eine fest vorgegebene abstrakte Basisklasse (rsslounge_source) implementieren muss. Diese abstrakte Basisklasse gibt die Methoden vor, die unbedingt angeboten werden müssen (z.B. load() um die Datenquelle abzurufen).</p>
<pre class="brush: php;">
abstract class rsslounge_source {
	abstract public function load($url);
	abstract public function getHtmlUrl();
	abstract public function getId();
	//...
}
</pre>
<p>Alle Datenquellen, welche die abstrakte Basisklasse implementieren, werden in einem festen Verzeichnis abgelegt. Die Gesamtapplikation durchsucht diesen Pfad nach verfügbare Datenquellen, prüft, ob sie die nötige Basisklasse implementieren und verwendet sie dann im Programm. Soll beispielsweise ein neues Feed hinzugefügt werden, so werden alle verfügbaren Datenquellen gesucht und im Dialog gelistet:</p>
<p><img src="wp-content/uploads/2009/12/06/feedhinzufuegen.jpg" alt="Feed hinzufügen" width="518" height="266" /></p>
<p>Angenommen ich entschließe mich ein Jahr später eine neue Datenquelle für die API von Google Analytics zu realisieren, so muss ich lediglich eine neue Klasse von rssloung_source ableiten, die entsprechenden Methoden implementieren und diese dann in das Verzeichnis ablegen.</p>
<p>Dieses Prinzip wird auch Hollywood Prinzip genannt: &#8220;Don&#8217;t call us, we call you&#8221;. Die Datenquelle Klasse bietet Methoden an, welche von der Gesamtapplikation im Bedarfsfall aufgerufen werden. Das Plugin muss von der Gesamtapplikation nichts wissen und ausschließlich ihre eigene Funktionalität und damit die Schnittstelle realisieren.</p>
<p>Die Implementierung basiert auf den <a title="PHP Manual Reflection" href="http://de.php.net/manual/de/book.reflection.php">Reflection Mechanismus</a> der seit PHP 5 zur Verfügung steht. Mit Hilfe der Reflection Klassen können zur Laufzeit Klassen geladen und deren Eigenschaften ausgelesen werden. Zudem kann über diesen Weg die Klasse dann auch instanziiert werden:</p>
<pre class="brush: php;">
$class = new ReflectionClass(&quot;plugin_rss_feed&quot;);
$baseClass = new ReflectionClass(&quot;rsslounge_source&quot;);
$class-&gt;isSubclassOf($baseClass); // true wenn plugin_rss_feed die Klasse rsslounge_source implementiert
$obj = $class-&gt;newInstance();
</pre>
<p>Sollen, wie im obigen Beispiel, alle verfügbaren Datenquellen gelistet werden, so wird das Verzeichnis mit den Datenquellen nach PHP Dateien durchsucht, geprüft ob diese von rsslounge_source abgeleitet sind und falls dies zutrifft instanziiert. Alle Objekte der so gefundenen Klassen werden in ein Array gespeichert und dann für die weitere Verarbeitung an die Gesamtapplikation übergeben (die diese Klassen dann auflistet):</p>
<pre class="brush: php;">
$pluginLocation = &quot;/plugins&quot;;
$pluginPrefix = &quot;plugins_&quot;;
$plugins = array();
foreach(scandir($pluginLocation) as $file) {
	if(is_file($pluginLocation . &quot;/&quot; . $file)
	&amp;&amp; substr($file,0,1)!=&quot;.&quot;
	&amp;&amp; strpos($file,&quot;.php&quot;)!==false) {

		$classname = str_replace(&quot;.php&quot;,&quot;&quot;,$file);
		$class = new ReflectionClass($pluginPrefix.$classname);

		if($class-&gt;isSubclassOf(new ReflectionClass(&quot;base_plugin&quot;)))
			$plugins[$pluginPrefix.$classname] = $class-&gt;newInstance();
	}
}
</pre>
<p>Natürlich macht es hier Sinn einen Cache einzubauen, da sich die verfügbaren Klassen nicht oft ändern. Zend_Cache bietet hier eine einfache Möglichkeit so ein Array dateibasiert oder mittels memcached zu cachen.</p>
<p>Für meinen RSS Reader habe ich diesen Mechanismus zum Laden der Datenquellen in einen <a title="Action Helper Zend Manual" href="http://framework.zend.com/manual/de/zend.controller.actionhelpers.html">Action Helper</a> ausgelagert. So steht diese Funktionalität in der gesamten Applikation zur Verfügung. Wer an Details interessiert ist, sei an dieser Stelle auf <a title="rsslounge Google Code Projekt Page" href="http://code.google.com/p/rsslounge/">Google Code</a> verwiesen, wo der Quellcode von rsslounge zu finden ist.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2009/12/06/pluginschnittstelle-mittels-php-reflection-realisieren/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Bibliotheken und jQuery Plugins von rsslounge</title>
		<link>http://blog.aditu.de/2009/09/04/bibliotheken-und-jquery-plugins-von-rsslounge/</link>
		<comments>http://blog.aditu.de/2009/09/04/bibliotheken-und-jquery-plugins-von-rsslounge/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 16:41:30 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[rsslounge]]></category>
		<category><![CDATA[Date Picker]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[SimplePie]]></category>
		<category><![CDATA[Skripte]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://localhost/aditu.de/blog2/?p=248</guid>
		<description><![CDATA[Frameworks und Bibliotheken zu verwenden hat viele Vorteile. Vor allem spart es aber Zeit, weil viele Funktionen so schon out of the box zur Verfügung stehen und wozu auch für jedes Projekt das Rad neu erfinden. In diesem Blogeintrag will ich alle Bibliotheken und Frameworks vorstellen, die ich für meinen aktuellen Feed Reader rsslounge verwendet [...]]]></description>
			<content:encoded><![CDATA[<p>Frameworks und Bibliotheken zu verwenden hat <a title="10 Gründe gegen den Einsatz von Frameworks" href="http://www.phphatesme.com/blog/wtf/10-grunde-gegen-den-einsatz-von-php-frameworks/">viele Vorteile</a>. Vor allem spart es aber Zeit, weil viele Funktionen so schon out of the box zur Verfügung stehen und wozu auch für jedes Projekt das Rad neu erfinden. In diesem Blogeintrag will ich alle Bibliotheken und Frameworks vorstellen, die ich für meinen aktuellen Feed Reader <a title="rsslounge" href="http://rsslounge.aditu.de">rsslounge</a> verwendet habe. Die Liste ist als kleine Empfehlung zu verstehen und soll gleichzeitig einen kleinen Einblick in rsslounge geben.</p>
<h2><a title="Zend Framework" href="http://framework.zend.com/">Zend Framework</a></h2>
<p><a title="Zend Framework" href="http://framework.zend.com/"><img src="wp-content/uploads/2009/09/04/zend_framework.jpg" alt="Zend Framework" width="520" height="100" /></a></p>
<p>Das Zend Framework ist ein objektorientiertes PHP Framework, das auf dem MVC Pattern basiert und viele viele Funktionen bietet. Das Zend Framework ist in diesem Blog ja ohnehin ein Thema und deshalb will ich an dieser Stelle dazu nicht schreiben. Einen ersten Überblick gebe ich <a title="Zend Framework ein Überblick" href="2008/09/30/Zend-Framework-ein-Ueberblick">hier</a>, wobei natürlich innerhalb des letzten Jahres einiges hinzu gekommen ist.</p>
<h2><a title="jQuery" href="http://jquery.com/">jQuery</a></h2>
<p><a title="jQuery" href="http://jquery.com/"><img src="wp-content/uploads/2009/09/04/jquery.jpg" alt="jQuery" width="520" height="100" /></a></p>
<p>Auch jQuery ist mittlerweile kein Geheimtipp mehr und wie eine <a title="jQuery dominiert bei den javascript frameworks - Webstandard Blog" href="http://webstandard.kulando.de/post/2009/07/21/jquery-dominiert-bei-den-javascript-frameworks">Umfrage des Webstandard Blogs</a> zeigt, auch das beliebteste JavaScript Framework. Ich kann das gut verstehen, nachdem ich bisher auf <a title="Prototype JavaScript Framework" href="http://www.prototypejs.org/">prototype</a> und <a title="script.aculo.us" href="http://script.aculo.us/">script.aculo.us</a> gesetzt habe, hat mich jQuery sofort überzeugt.</p>
<p>Alle weiteren JavaScript Bibliotheken basieren auf jQuery. Die Auswahl an Plugins ist schier unendlich und es gibt eine große Zahl an hervorragenden Projekten, die auf jQuery aufsetzen.</p>
<h2><a title="jQuery UI" href="http://jqueryui.com/">jQuery UI</a></h2>
<p><a title="jQuery UI" href="http://jqueryui.com/"><img src="wp-content/uploads/2009/09/04/jqueryui.jpg" alt="jQuery UI" width="520" height="100" /></a></p>
<p>Aufbauend auf jQuery gibt es jQuery UI, eine Bibliothek, die verschiedene Widgets und Funktionen bietet. Neben Widgets deckt jQuery UI das ab, was bei prototype durch script.aculo.us ergänzt wird: Drag n Drop, sortierbare Listen und animierte Effekte. In rsslounge basiert der Slider für die Priorität, das Drag n Drop der Feeds und Kategorien, sowie die Processbar für den ajaxbasierten Update auf dieser Bibliothek.</p>
<h2><a title="Impromptu" href="http://trentrichardson.com/Impromptu/index.php">Impromptu</a></h2>
<p><a title="Impromptu" href="http://trentrichardson.com/Impromptu/index.php"><img src="wp-content/uploads/2009/09/04/impromtu.jpg" alt="Impromptu" width="520" height="100" /></a></p>
<p>Es gibt ja eine <a title="15 JavaScript LightBox Skripte" href="2008/11/22/15-JavaScript-LightBox-Skripte/">ganze Reihe guter Lightbox Skripte</a>. Für rsslounge habe ich aber ein LightBox Skript gesucht, das sich besonders gut für Dialoge eignet. Impromptu bietet hier eine einfache Möglichkeit Buttons zu setzen und eigene Funktionen an die verschiedenen Aktionen der Popup-Box zu binden. Lediglich bei der Positionierung der Box, die pauschal auf top:15% gesetzt ist, war ich nicht zufrieden. Allerdings hat man hier vollen Einfluss auf das CSS, so dass auch das kein echtes Problem ist. Eine sehr gute Alternative wäre die <a title="ModalBox" href="http://okonet.ru/projects/modalbox/">ModalBox</a> gewesen. Diese basiert allerdings auf prototype.</p>
<h2><a title="Date Picker" href="http://www.eyecon.ro/datepicker/">Date Picker</a></h2>
<p><a title="Date Picker" href="http://www.eyecon.ro/datepicker/"><img src="wp-content/uploads/2009/09/04/datepicker.jpg" alt="Date Picker" width="520" height="100" /></a></p>
<p>Ein hervorragendes Skript für die Auswahl eines Datumbereichs ist der Date Picker von <a title="Stefan Petre" href="http://www.eyecon.ro">Stefan Petre</a>. Date Picker für die Auswahl eines einzelnen Datums gibt es ja viele, so bietet jQuery UI hier auch ein grundsolides Widget. Aber wenn es darum geht einen Bereich zu wählen, wird die Auswahl plötzlich sehr klein. Der Date Picker hat ein schickes Design und kann sehr genau konfiguriert und mittels CSS gestaltet werden.</p>
<h2><a title="jGrowl" href="http://www.stanlemon.net/projects/jgrowl.html">jgrowl</a></h2>
<p><a title="jGrowl" href="http://www.stanlemon.net/projects/jgrowl.html"><img src="wp-content/uploads/2009/09/04/jgrowl.jpg" alt="jGrowl" width="520" height="100" /></a></p>
<p>jgrowl orientiert sich an dem Benachrichtigungssystem von <a title="Growl Wikipedia" href="http://de.wikipedia.org/wiki/Growl_%28Software%29">Growl</a>, welches für Mac OS X verfügbar ist. Es zeigt Benachrichtigungen in einer kleinen Box am Bildschirmrand an. rsslounge nutzt dieses Skript nur recht selten, für Fehlermeldungen und wichtige Informationen ist es aber hervorragend geeignet.</p>
<h2><a title="Ajax Upload" href="http://valums.com/ajax-upload/">Ajax Upload</a></h2>
<p><a title="Ajax Upload" href="http://valums.com/ajax-upload/"><img src="wp-content/uploads/2009/09/04/ajaxupload.jpg" alt="Ajax Upload" width="520" height="100" /></a></p>
<p>Mit Hilfe dieses jQuery Plugins können bei rsslounge OPML Dateien importiert werden. So lässt sich der Dateiupload mit einem Klick auf den entsprechenden Menüpunkt starten, ohne das explizit ein neu Laden der Seite oder das Datei Eingabefeld nötig ist.</p>
<h2><a title="Tipsy" href="http://onehackoranother.com/projects/jquery/tipsy/">Tipsy</a></h2>
<p><a title="Tipsy" href="http://onehackoranother.com/projects/jquery/tipsy/"><img src="wp-content/uploads/2009/09/04/tipsy.jpg" alt="tipsy" width="520" height="100" /></a></p>
<p>Das Plugin Tipsy ermöglicht beliebige ToolTipps zu erstellen. Diese verwende ich für den Eingabedialog von neuen Feeds. Manchmal bleiben die ToolTipps noch hängen, hier muss ich also nochmal genauer testen. Der erste Eindruck ist aber sehr gut und die zusätzlichen Informationen sind für Neulinge dann doch eine gute Hilfe.</p>
<h2><a title="SimplePie" href="http://simplepie.org/">SimplePie</a></h2>
<p><a title="SimplePie" href="http://simplepie.org/"><img src="wp-content/uploads/2009/09/04/simplepie.jpg" alt="SimplePie" width="520" height="100" /></a></p>
<p>Das Herzstück von rsslounge ist die Bibliothek SimplePie. Diese PHP Bibliothek ermöglicht es sehr einfach RSS Feeds zu lesen und zu verarbeiten. Ich habe mich für SimplePie und nicht für Zend_Feed entschlossen, da es um einiges ausgereifter ist, mit keinem Feed Probleme hat und sich bereits in vielen Applikationen bewährt hat. Ein erster Test hat dann auch gleich gezeigt das SimplePie schwer zu toppen ist. rsslounge selbst ist so aufgebaut, dass sich problemlos SimplePie durch eine andere Bibliothek ersetzen lässt (oder eine zweite Bibliothek optional gewählt werden kann), bisher gab es aber keinen Grund dafür. SimplePie besteht lediglich aus einer Datei und einer Hand voll Klassen.</p>
<h2><a title="WideImage" href="http://wideimage.sourceforge.net/">WideImage</a></h2>
<p><a title="WideImage" href="http://wideimage.sourceforge.net/"><img src="wp-content/uploads/2009/09/04/wideimage.jpg" alt="WideImage" width="520" height="100" /></a></p>
<p>Für das Erzeugen der Thumbnails verwende ich die Bibliothek WideImage, welche sich zwar noch in Beta befindet, aber im Test super funktioniert. WideImage basiert auf der GD2 Erweiterung und kapselt alle Funktionen in eine Klasse und erlaubt es komfortabel Bilder zu laden, zu verkleinern oder anderweitig zu verändern. Ein Beispiel wie das dann aussehen kann:</p>
<pre class="brush: php;">

wiImage::load('image.png')-&gt;resize(50, 30)-&gt;saveToFile('new-image.jpg');
</pre>
<h2>Icons</h2>
<p>An der Stelle will ich auch nicht die Icons vergessen. Diese stammen von <a title="DryIcons" href="http://dryicons.com/free-icons/preview/stickers-icon-set/">DryIcons</a>, welche die Sticker Icons unter einer Free Lizenz anbieten, sowie vom <a title="Smashing Magazine" href="http://www.smashingmagazine.com/2009/03/16/new-smashing-freebies-for-designers-and-bloggers/">Smashing Magazine</a>. Letztere erlauben eine freie Verwendung der Icons (auch für kommerzielle Zwecke, ohne Einschränkungen).</p>
<p>Die Liste ist ganz schön lange, aber bestätigt mich darin laufend gute Skripte zu sammeln. Besonders Funktionalitäten, die sich gut kapseln lassen, oder kompliziert zu entwickeln sind, sind für eigene Projekte eine wahre Bereicherung.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2009/09/04/bibliotheken-und-jquery-plugins-von-rsslounge/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mehr Performance mit mod_deflate und mod_expires</title>
		<link>http://blog.aditu.de/2009/08/22/mehr-performance-mit-mod_deflate-und-mod_expires/</link>
		<comments>http://blog.aditu.de/2009/08/22/mehr-performance-mit-mod_deflate-und-mod_expires/#comments</comments>
		<pubDate>Sat, 22 Aug 2009 12:08:11 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Page Speed]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[YSlow]]></category>

		<guid isPermaLink="false">http://localhost/aditu.de/blog2/?p=230</guid>
		<description><![CDATA[Mit der Firefox Erweiterung Page Speed, welche von Google vor kurzem veröffentlicht wurde, sowie dem Addon YSlow von Yahoo stößt man immer wieder auf die zwei gleichen Meldungen: Leverage browser caching Enable gzip compression Zwei Apache Module, welche per default auch meist verfügbar sind, schaffen hier Abhilfe. Die Rede ist von mod_deflate und mod_expires. Beide [...]]]></description>
			<content:encoded><![CDATA[<p>Mit der Firefox Erweiterung <a title="Google Page Speed" href="http://code.google.com/intl/de-DE/speed/page-speed/">Page Speed</a>, welche von Google vor kurzem veröffentlicht wurde, sowie dem Addon <a title="YSlow" href="http://developer.yahoo.com/yslow/">YSlow </a>von Yahoo stößt man immer wieder auf die zwei gleichen Meldungen:</p>
<ul>
<li>Leverage browser caching</li>
<li>Enable gzip compression</li>
</ul>
<p>Zwei Apache Module, welche per default auch meist verfügbar sind, schaffen hier Abhilfe. Die Rede ist von mod_deflate und mod_expires. Beide sind im Handumdrehen konfiguriert und bringen einen guten Performanceschub.</p>
<p><a title="mod_deflate Apache Manual" href="http://httpd.apache.org/docs/2.0/mod/mod_deflate.html">mod_deflate</a> sorgt dafür, dass die Inhalte, welche vom Apache Webserver zum Client gesendet werden, zuvor komprimiert werden. Die Konfiguration ist denkbar einfach und kann in der .htaccess Konfigurationsdatei hinterlegt werden. Folgende Konfiguration ist dem Apache Manual entnommen und so auch bei mir im Einsatz:</p>
<pre class="brush: xml;">
&lt;IfModule mod_deflate.c&gt;
	# Insert filter
	SetOutputFilter DEFLATE

	# Netscape 4.x has some problems...
	BrowserMatch ^Mozilla/4 gzip-only-text/html

	# Netscape 4.06-4.08 have some more problems
	BrowserMatch ^Mozilla/4.0[678] no-gzip

	# MSIE masquerades as Netscape, but it is fine
	# BrowserMatch bMSIE !no-gzip !gzip-only-text/html

	# NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
	# the above regex won't work. You can use the following
	# workaround to get the desired effect:
	BrowserMatch bMSI[E] !no-gzip !gzip-only-text/html

	# Don't compress images
	SetEnvIfNoCase Request_URI
	.(?:gif|jpe?g|png)$ no-gzip dont-vary

	# Make sure proxies don't deliver the wrong content
	Header append Vary User-Agent env=!dont-vary
&lt;/IfModule&gt;
</pre>
<p><a title="mod_expires Apache Manual" href="http://httpd.apache.org/docs/2.0/mod/mod_expires.html">mod_expires</a> erlaubt es ein Verfallsdatum für den Cache zu setzen. Folgende Konfiguration habe ich <a title="Jörns Blog" href="http://www.allmers.de/blog/archives/147-Schneller-durch-mod_deflate-und-mod_expires.html">Jörns Blog</a> entnommen (der mich zu diesem Eintrag inspiriert hat):</p>
<pre class="brush: xml;">
&lt;IfModule mod_expires.c&gt;
	ExpiresActive On
	ExpiresByType text/html &quot;access plus 2 houres &quot;
	ExpiresByType text/xml &quot;access plus 2 houres&quot;
	ExpiresByType image/gif &quot;access plus 3 weeks&quot;
	ExpiresByType image/jpg &quot;access plus 2 weeks&quot;
	ExpiresByType image/png &quot;access plus 3 weeks&quot;
	ExpiresByType video/quicktime &quot;access plus 2 months&quot;
	ExpiresByType audio/mpeg &quot;access plus 2 months&quot;
	ExpiresByType application/pdf &quot;access plus 2 weeks&quot;
	ExpiresByType application/ps &quot;access plus 2 weeks&quot;
	ExpiresByType application/xml &quot;modification plus 2 weeks&quot;
&lt;/IfModule&gt;
</pre>
<p>Durch die IfModule Direktiven ist auch sichergestellt, dass auf die Konfiguration verzichtet wird, wenn die Module nicht vorhanden sind.</p>
<p>Viel weiter habe ich mich zu dem Thema nicht eingelesen, bin mir aber sicher, dass man hier noch einiges mehr herausholen und machen kann. Auf meiner Wunschliste steht zu dem Thema noch das Buch <a title="High Performance Websites" href="http://www.oreilly.de/catalog/hpwebsitesger/">High Performance Websites</a>. Ein erstes Durchblättern hat gezeigt, dass hier noch einiges im Verborgenen liegt. Meistens so unkompliziert wie diese beiden Konfigurationen in die eigene .htaccess hinein zu kopieren. Kommentare zu diesem Thema sind also erwünscht. Wer hier bereits Erfahrung gesammelt hat und etwas empfehlen kann einfach diesen Beitrag kommentieren.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2009/08/22/mehr-performance-mit-mod_deflate-und-mod_expires/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ein Reader für alle Fälle&#8230;</title>
		<link>http://blog.aditu.de/2009/08/06/ein-reader-fuer-alle-faelle/</link>
		<comments>http://blog.aditu.de/2009/08/06/ein-reader-fuer-alle-faelle/#comments</comments>
		<pubDate>Thu, 06 Aug 2009 17:37:17 +0000</pubDate>
		<dc:creator>Tobi</dc:creator>
				<category><![CDATA[Webentwicklung]]></category>
		<category><![CDATA[rsslounge]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[RSS]]></category>
		<category><![CDATA[RSS Reader]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://localhost/aditu.de/blog2/?p=225</guid>
		<description><![CDATA[Jetzt habe ich schon lange nicht mehr gebloggt und hoffe ich bin noch nicht bei allen aus der RSS Reader Liste geflogen. Aber in diesem Fall habe ich eine ganz gute Ausrede. Momentan programmiere ich flei&#223;ig an einem neuen webbasierten RSS Reader. Auch nach vielen Stunden Suche habe ich keinen guten RSS Reader gefunden, den [...]]]></description>
			<content:encoded><![CDATA[<p>Jetzt habe ich schon lange nicht mehr gebloggt und hoffe ich bin noch nicht bei allen aus der RSS Reader Liste geflogen. Aber in diesem Fall habe ich eine ganz gute Ausrede. Momentan programmiere ich flei&szlig;ig an einem neuen webbasierten RSS Reader.</p>
<p>Auch nach vielen Stunden Suche habe ich keinen guten RSS Reader gefunden, den man auch auf dem eigenen Webspace installieren kann und der dabei einfach und praktisch zu bedienen ist. Bisher nutze ich <a href="http://gregarius.net/" title="Gregarius">Gregarius</a>, der leider nicht mehr weiter entwickelt wird. Der <a href="http://reader.google.de" title="Google Reader">Google Reader</a> konnte auch &uuml;berzeugen, aber hier mache ich mir aus Sicht des Datenschutzes sorgen, da die eigene Feedauswahl doch so einige R&uuml;ckschl&uuml;sse auf Interessen und Hobbys zul&auml;sst. Ein weiterer interessanter Reader ist <a href="http://feedafever.com/" title="Fever">Fever</a>, dieser kostet aber $30. Das w&auml;re ich schon bereit zu zahlen, wenn die Software dann auch gut ist. Aber mit einer domainbezogenen Lizenz wollte ich mich dann einfach nicht herumschlagen. <a href="http://tt-rss.org/trac/" title="tiny tiny RSS">tiny tiny RSS</a> scheint auch solide zu funktionieren, ist mir aber zu &uuml;berladen und irgendwie unpraktisch.</p>
<p>Da Meckern nicht hilft habe ich mich also selbst ans Werk gemacht. Dazu habe ich mir aus bestehenden Reader die Features herausgepickt, die mir besonders gefallen, oder die ich bereits in Gregarius regelm&auml;&szlig;ig benutze.</p>
<p>Mein Wunsch-RSS-Reader muss dar&uuml;ber hinaus folgende Features haben (und hat sie auch schon):</p>
<ul>
<li>Neben normalen Feeds soll der Reader auch Medien lesen k&ouml;nnen. Ich verfolge viele Fotoblogs und Communitys und die sollen komfortabel als Thumbnail&uuml;bersicht angezeigt werden (und nicht wie gew&ouml;hnliche Textnachrichten).</li>
<li> Der Reader soll Priorit&auml;ten unterst&uuml;tzen. Jedes Feed soll dabei eine Priorit&auml;t bekommen und je nach gew&auml;hlten Priorit&auml;tsbereich wird nur eine Teilmenge (oder alle) Feeds angezeigt. In stressigen Lebensphasen lassen sich so gezielt Feeds ausblenden und man kann sich auf das Wesentliche konzentrieren. Am Wochenende kann dann der Priorit&auml;tsbereich erh&ouml;ht und der Rest gelesen werden.</li>
<li> Es soll ein offenes Pluginsystem f&uuml;r die Datenquellen vorhanden sein. Neben gew&ouml;hnlichen RSS Feeds soll man auch die M&ouml;glichkeit haben sp&auml;ter neue Quellen zu definieren. So kann z.B. dann eine Seite manuell geparsed, verarbeitet und verfolgt werden, auch wenn diese kein RSS Feed anbietet (hierzu braucht man dann nat&uuml;rlich Programmierkenntnisse).</li>
<li> Eine komfortable ajaxbasierte Oberfl&auml;che, die schlicht und &uuml;bersichtlich sein soll. Zudem soll sich alles intuitiv mit Drag n Drop bedienen lassen (z.B. die Feeds zwischen den Kategorien verschieben, oder die Reihenfolge der Kategorien ver&auml;ndern).</li>
<li> Es soll die M&ouml;glichkeit bestehen einen bestimmten Zeitraum vorzugeben, um nur Eintr&auml;ge dieser Periode zu sehen.</li>
<li> Feeds sollen wahlweise mit Cronjob oder ohne (also via Ajax Aufruf) aktualisiert werden k&ouml;nnen.</li>
</ul>
<p>Als Namen habe ich <strong>rsslounge aggregator</strong> gew&auml;hlt. Ich finde das ziemlich passend, denn ich lese immer abends oder morgens ganz gechillt, bei einer Tasse Tee meine Feeds. Zudem soll das Priorit&auml;tsfeature dabei helfen Stress zu vermeiden und immer nur die Menge an Feeds zu zeigen, f&uuml;r die man auch Zeit hat. Der Rest kann ruhig bis zum Wochenende warten (oder wird nur grob &uuml;berflogen).</p>
<p>Was nun auf der Agenda steht, ist ein ausf&uuml;hrlicher Test. Dazu werde ich den Reader erst selbst einige Monate testen und anschlie&szlig;end einen geschlossenen Betatest unterziehen. Erst dann werde ich den Reader unter GPL in Deutsch und Englisch jedem frei zur Verf&uuml;gung stellen. Hinzu kommt dann nat&uuml;rlich auch eine Anleitung, wie man selbst Plugins schreiben kann.</p>
<p>Als ersten Einblick gibts erst einmal ein paar Screenshots. Ich hoffe, dass ich bei einigen Interesse wecken kann. Mal sehen was daraus wird.</p>
<p><a href="wp-content/uploads/2009/08/06/rsslounge_aggregator_1.png" title="rsslounge Screenshot"><img src="wp-content/uploads/2009/08/06/rsslounge_aggregator_1.jpg" alt="rsslounge Screenshot" /></a></p>
<p><a href="wp-content/uploads/2009/08/06/rsslounge_aggregator_2.png" title="rsslounge Screenshot"><img src="wp-content/uploads/2009/08/06/rsslounge_aggregator_2.jpg" alt="rsslounge Screenshot" /></a></p>
<p><a href="wp-content/uploads/2009/08/06/rsslounge_aggregator_3.png" title="rsslounge Screenshot"><img src="wp-content/uploads/2009/08/06/rsslounge_aggregator_3.jpg" alt="rsslounge Screenshot" /></a></p>
<p><a href="wp-content/uploads/2009/08/06/rsslounge_aggregator_4.png" title="rsslounge Screenshot"><img src="wp-content/uploads/2009/08/06/rsslounge_aggregator_4.jpg" alt="rsslounge Screenshot" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.aditu.de/2009/08/06/ein-reader-fuer-alle-faelle/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>
