<?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>// der php hacker &#187; Entwicklung</title>
	<atom:link href="http://phphacker.net/category/entwicklung/feed/" rel="self" type="application/rss+xml" />
	<link>http://phphacker.net</link>
	<description>ein php blog</description>
	<lastBuildDate>Wed, 27 Jan 2010 12:06:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>XINGs Recruiting Methoden</title>
		<link>http://phphacker.net/2010/01/27/xings-recruiting-methoden/</link>
		<comments>http://phphacker.net/2010/01/27/xings-recruiting-methoden/#comments</comments>
		<pubDate>Wed, 27 Jan 2010 12:06:22 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=1064</guid>
		<description><![CDATA[Eine sehr nette Idee, um sich fähige Entwickler an Bord zu holen hat XING:

Auf der anderen Seite: Haben sie derzeit aber auch dringen nötig =)
]]></description>
			<content:encoded><![CDATA[<p>Eine sehr nette Idee, um sich fähige Entwickler an Bord zu holen hat XING:</p>
<p><a href="http://phphacker.net/wp-content/uploads/2010/01/Bildschirmfoto-2010-01-27-um-13.02.25.png"><img class="aligncenter size-full wp-image-1065" title="Bildschirmfoto 2010-01-27 um 13.02.25" src="http://phphacker.net/wp-content/uploads/2010/01/Bildschirmfoto-2010-01-27-um-13.02.25.png" alt="Bildschirmfoto 2010-01-27 um 13.02.25" width="560" /></a></p>
<p>Auf der anderen Seite: Haben sie derzeit aber auch dringen nötig =)</p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2010/01/27/xings-recruiting-methoden/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Wusstest du schon …</title>
		<link>http://phphacker.net/2009/12/31/wusstest-du-schon-4/</link>
		<comments>http://phphacker.net/2009/12/31/wusstest-du-schon-4/#comments</comments>
		<pubDate>Thu, 31 Dec 2009 07:30:49 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Hintergrund]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=1040</guid>
		<description><![CDATA[… dass PHP jonglieren kann? Und zwar mit Typen. Type juggling nennt man das, was passiert, wenn man einen String mit dem Inhalt &#8220;1&#8243; versucht mit einem Integer zu addieren. Oder wenn man den String &#8220;Foo&#8221; mit dem Booleschen Wert &#8220;true&#8221; vergleicht: PHP würfelt die Typen einmal kräftig durch. Das sieht manchmal willkürlich aus, ist [...]]]></description>
			<content:encoded><![CDATA[<p>… dass PHP jonglieren kann? Und zwar mit Typen. Type juggling nennt man das, was passiert, wenn man einen String mit dem Inhalt &#8220;1&#8243; versucht mit einem Integer zu addieren. Oder wenn man den String &#8220;Foo&#8221; mit dem Booleschen Wert &#8220;true&#8221; vergleicht: PHP würfelt die Typen einmal kräftig durch. Das sieht manchmal willkürlich aus, ist es meist aber nicht. Damit man keine bösen Überraschungen erlebt, sollte man sich mal diese <a href="http://php.net/manual/de/types.comparisons.php">Comparison Tables</a> zu Gemüte führen.</p>
<p>Das wird dann auch mein letzter Post für dieses Jahr gewesen sein. Ich denke ich werde dann und wann noch einmal ein paar &#8220;wusstest du schon&#8221;-Beiträge raushauen. Ich hoffe ich konnte euch die Brückentage etwas verkürzen und vielleicht das ein oder andere neue erzählen. Ich wünsche euch allen einen guten Rutsch ins neue Jahr (… nen Fünfer ins Phrasenschwein – oh Mist. Schon wieder <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ) und wir sehen uns dann 2010 in alter Frische wieder! Und als kleines Silvestergeschenk noch dieses tolle Video. Über den Song kann man streiten, aber die Performance ist toll. Also dann: Ciao!</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="560" height="340" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/yjbpwlqp5Qw&amp;hl=de_DE&amp;fs=1&amp;" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="560" height="340" src="http://www.youtube.com/v/yjbpwlqp5Qw&amp;hl=de_DE&amp;fs=1&amp;" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/31/wusstest-du-schon-4/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wusstest du schon …</title>
		<link>http://phphacker.net/2009/12/30/wusstest-du-schon-%e2%80%a6/</link>
		<comments>http://phphacker.net/2009/12/30/wusstest-du-schon-%e2%80%a6/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 13:52:30 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=1033</guid>
		<description><![CDATA[… dass man mit strtotime wesentlich einfacher und korrekter Zeitenräume addieren oder abziehen kann, als es von Hand überhaupt möglich ist? Denn nicht jeder Tag hat 86400 Sekunden. Außerdem umgeht man auch noch das Antipattern der Magic Numbers.


$nextWeek = strtotime(&#039;+1 week&#039;);
$twoMonth = strtotime(&#039;+2 month&#039;);
$reallyScrewed = strtotime(&#039;+2 years +1 month +1 day +4 hours +7 minutes&#039;);


Sieht [...]]]></description>
			<content:encoded><![CDATA[<p>… dass man mit <a href="http://php.net/manual/en/function.strtotime.php">strtotime</a> wesentlich einfacher und korrekter Zeitenräume addieren oder abziehen kann, als es von Hand überhaupt möglich ist? Denn nicht jeder Tag hat 86400 Sekunden. Außerdem umgeht man auch noch das Antipattern der <a href="http://en.wikipedia.org/wiki/Magic_number_(programming)#Unnamed_numerical_constants">Magic Numbers</a>.</p>
<pre>
<pre class="brush: php">
$nextWeek = strtotime(&#039;+1 week&#039;);
$twoMonth = strtotime(&#039;+2 month&#039;);
$reallyScrewed = strtotime(&#039;+2 years +1 month +1 day +4 hours +7 minutes&#039;);
</pre>
</pre>
<p>Sieht doch wesentlich besser aus, oder? Und man weiß genau, was hier passiert. Als zweiten Parameter kann man übrigens einen UNIX-Timestamp angeben, der als Ausgangszeitpunkt verwendet wird.<span id="more-1033"></span></p>
<p><em>Während den Tagen bis zum neuen Jahr werde ich immer mal wieder ein bisschen aus dem Trick- und Nähkästchen plaudern. Die arbeiten an Brawler stagnieren derzeit ob des Fresskomas unter dem ich grade leide, aber da mich mein gähnend Leerer Feedreader annervt, will ich wenigstens dazu beitragen, dass ein wenig passiert.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/30/wusstest-du-schon-%e2%80%a6/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Wusstest du schon &#8230;</title>
		<link>http://phphacker.net/2009/12/29/wusstest-du-schon-2/</link>
		<comments>http://phphacker.net/2009/12/29/wusstest-du-schon-2/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 11:29:45 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=1016</guid>
		<description><![CDATA[&#8230; dass Type Hints auf Arrays gemacht werden können? Im Gegensatz zu Primitiven Datentypen wie Strings, Integer oder Boolean kann man also in Methoden- und Funktionssignaturen  auch Arrays verlangen.
Type Hints sind eine bequeme und robuste Möglichkeit, die erwarteten Datentypen zu prüfen, bzw von PHP prüfen zu lassen. Dazu wird der Datentyp (bzw. die zu erwartete [...]]]></description>
			<content:encoded><![CDATA[<p>&#8230; dass Type Hints auf Arrays gemacht werden können? Im Gegensatz zu Primitiven Datentypen wie Strings, Integer oder Boolean kann man also in Methoden- und Funktionssignaturen  auch Arrays verlangen.</p>
<p>Type Hints sind eine bequeme und robuste Möglichkeit, die erwarteten Datentypen zu prüfen, bzw von PHP prüfen zu lassen. Dazu wird der Datentyp (bzw. die zu erwartete Klasse) einfach vor den Parameter in die Signatur geschrieben. Verwende ich beispielsweise eine Signatur wie folgende &#8230;</p>
<pre>
<pre class="brush: php">

     function foo(Array $bar, Foo_Bar $buzz)
</pre>
</pre>
<p>&#8230; weise ich PHP so an, dass der erste Parameter &#8220;bar&#8221; vom Typ Array sein muss. Der zweite &#8220;buzz&#8221; allerdings kann vom Typ &#8220;Foo_Bar&#8221; sein &#8211; oder von diesem abgeleitet sein. Man kann hier also auch jede Kindklasse übergeben.</p>
<p><em>Während den Tagen bis zum neuen Jahr werde ich immer mal wieder ein bisschen aus dem Trick- und Nähkästchen plaudern. Die arbeiten an Brawler stagnieren derzeit ob des Fresskomas unter dem ich grade leide, aber da mich mein gähnend Leerer Feedreader annervt, will ich wenigstens dazu beitragen, dass ein wenig passiert.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/29/wusstest-du-schon-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wusstest du schon &#8230;</title>
		<link>http://phphacker.net/2009/12/28/wusstest-du-schon/</link>
		<comments>http://phphacker.net/2009/12/28/wusstest-du-schon/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 17:10:30 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Hintergrund]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=1013</guid>
		<description><![CDATA[&#8230; dass das schließende PHP Tag nicht zwingen notwendig ist? Im ZF findet man es kaum, PDT lässt es seit ein paar Versionen auch weg und meine Wenigkeit ebenfalls.
Aber warum macht man das? Zwei Gründe: Der erste ist mit Sicherheit eine gewisse Faulheit. Der zweite jedoch hat Hand und Fuß: Man stell sich vor, hinter [...]]]></description>
			<content:encoded><![CDATA[<p>&#8230; dass das schließende PHP Tag nicht zwingen notwendig ist? Im ZF findet man es kaum, PDT lässt es seit ein paar Versionen auch weg und meine Wenigkeit ebenfalls.</p>
<p>Aber warum macht man das? Zwei Gründe: Der erste ist mit Sicherheit eine gewisse Faulheit. Der zweite jedoch hat Hand und Fuß: Man stell sich vor, hinter dem schließenden PHP-Tag befindet sich ein Zeilenumbruch oder Whitespace. Wird nun kein Output-Buffering benutzt, wird man keine Cookies oder Customized Header mehr setzen können. Das wäre natürlich blöd.</p>
<p><em>Während den Tagen bis zum neuen Jahr werde ich immer mal wieder ein bisschen aus dem Trick- und Nähkästchen plaudern. Die arbeiten an Brawler stagnieren derzeit ob des Fresskomas unter dem ich grade leide, aber da mich mein gähnend Leerer Feedreader annervt, will ich wenigstens dazu beitragen, dass ein wenig passiert.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/28/wusstest-du-schon/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Von Eastereggs und wie man sie verstecken kann</title>
		<link>http://phphacker.net/2009/12/16/von-eastereggs-und-wie-man-sie-verstecken-kann/</link>
		<comments>http://phphacker.net/2009/12/16/von-eastereggs-und-wie-man-sie-verstecken-kann/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 14:07:21 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Kurioses]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=981</guid>
		<description><![CDATA[                                Uns  Entwicklern                     [...]]]></description>
			<content:encoded><![CDATA[                                <p>Uns  Entwicklern                              
                           wird  oftmals  abgesprochen,                          
                        dass  wir  Kreativ  sind.  Das                           
                      erkennt  man  leider  schon  oft                           
                     daran,  dass  in  den  meisten  Agenturen                   
                    zwischen  „Kreativen“  und  „Entwicklern“            
                   unterschieden              wird.  Dabei                       
                   ist  das                      alles  andere                   
                   als  Gerechtfertigt.           So  verstehen                  
                   wir  unser                      Handwerk                      
                   ebenfalls                       als  eine                     
                    „Kunstform“,              erkennen                       
                     in  schönem                Code  Ästhetik,                
                       wo  das                 ungeschulte                       
                    Auge  nur  wirre  Zeichenfolgen  sieht.  Investieren         
                    wir  doch  viel  Liebe  und  Herz  in  den  Aufbau  und      
                    die  Gestaltung  unserer  Applikationen  ist  es  letztlich  
                    am  Ende  für  den  Anwender  doch  nur  ein  Werkzeug.     
                    Mich  persönlich  stimmt  es  dann  und  wann  traurig,     
                           wenn  der  Betrachter  das  Kunstwerk,                
                        das  man  geschaffen  hat  nicht                         
                      würdigt  –  oder  würdigen  kann.                      
                    Aber  daran  wird  man  wohl  auch  nie                      
                   etwas  ändern  können:  Das  was  für                      
                   die  meisten  an  Software  „schön“                      
                   ist,  ist                                                     
                   in  der                                                       
                   Regel                                                         
                   nicht  einmal                                                 
                    die  Software                                                
                      selbst                                                     
                      sondern  eben                                              
      das,  was  die  „Kreativen“  dazu  beigetragen                         
      haben.</p><p>All  das  soll  mich  aber  nicht  daran                      
      hindern,  meine  Signatur  unter  das  zu  setzen,                         
      was  ich  schaffe.  Damit  meine  ich  nicht  meinen                       
      Namen  in  den  Kommentaren,  damit  meine  ich  auch                      
                              nicht,  dass  ich                                  
                          ans  Dokumentende  ein  pubertäres                    
                       „hacked  together  by  Cem  Derin“                    
                      klatsche.  Oftmals  ist  das  ja                           
                     auch  gar  nicht  möglich.  Nein,                          
                    ich  meine,  dass    ich  meine  Handschrift                 
                   so  hinterlasse,             dass  Sie                        
                   zwar  Sichtbar                 ist  –                       
                   aber  trotzdem                  auch  Unsichtbar.             
                   Dazu  bediene                   ich  mich                     
                    dem,  was                      gemeinhin                     
                    als  „Easteregg“          bekannt                        
                      ist.  So                   stelle                          
                       ich  sicher,          dass  meine                         
                    Software  von  den  Leuten  gewürdigt  werden  kann,        
                    die  dazu  auch  in  der  Lage  sind.</p><p>Viele  Seiten    
                    beinhalten  einen  kleinen  Scherz,  einen  Kommentar,       
                    einen  Witz  oder  ähnliches,  wenn  man  bestimmte         
                    Tastenkombinationen  auf  einer  Seite  betätigt.  Das      
             hat  den  Nachteil,                                                 
           das  ein  gewisser                                                    
         Anteil  JavaScript  nachgeladen                                         
        werden  muss  und  man  ggf.                                             
       auch  Resourcen  einbettet,                                               
      die  kein  Mensch  freigegeben                                             
      hat.  Da             man  sowas  natürlich  auch  nicht                   
      mit  seinem            Gewissen  vereinbaren  kann,                        
      hatte  dies             zur  Folge,       dass  meine                      
      Eastereggs                so  versteckt   waren,  dass                     
      sie  keiner                 Gefunden      hat.</p><p>Irgendwie             
      hat  auch                                                                  
       das  geschlaucht.                                                         
       Da  gab  es  dann                                                         
         aber  noch  eine                                                        
          andere  Möglichkeit,                                                  
             wie  man                                                            
                 ein                                                             
                   Easteregg                      unterbringen                   
                   kann:  ASCII-Art.             Obwohl,                         
                    nicht  direkt.              Im  Grunde                       
                     meine  ich                 nur  das                         
                      hinzufügen              von  zusätzlichem                
                      Whitespace.             Man  verändert                    
                       den  Inhalt           nicht,  sondern                     
                        lediglich            die  Formatierung,                  
                         so  dass           dem  Betrachter                      
                         eine  Botschaft   ohne  jegliche                        
                          Nebenwirkungen   übermitteln                          
                           kann.</p><p>Dazu  habe                                
                            ich  ein     kleines                                 
                             Programm   geschrieben,                             
                             dass  zwar  noch  alles                             
                              andere  als  ausgereift                            
                               ist,  aber  seinen                                
                                Zweck  trotzdem                                  
                                schon  erfüllt.                                 
                                 Zu  finden                                      
                                  ist  es  <a                                    

href="http://phphacker.net/embed/" >hier</a>. Und wer sich nun fragt, was das Ding macht – der schaue sich den Quelltext dieses Beitrags an =)</p><p>Übrigens: Die Textbasis ist derzeit die, die ihr hier grade lest. Das wird sich aber bald ändern. Außerdem stehen die Einstellungsmöglichkeiten noch nicht zur Verfügung – denn um ein halbwegs zufrieden stellendes Ergebnis zu erzielen, muss man ganz schön den Parametern rumjustieren.</p>]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/16/von-eastereggs-und-wie-man-sie-verstecken-kann/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Workshop: Brawler – Host scannen, Teil 5</title>
		<link>http://phphacker.net/2009/12/15/workshop-brawler-host-scannen-teil-5/</link>
		<comments>http://phphacker.net/2009/12/15/workshop-brawler-host-scannen-teil-5/#comments</comments>
		<pubDate>Tue, 15 Dec 2009 16:31:24 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Brawler]]></category>
		<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=979</guid>
		<description><![CDATA[Zuvor:

Workshop: Brawler – The Web Application Security Scanner, Teil 0
Workshop: Brawler – Eine Frage der Lizenz, Teil 1
Workshop: Brawler – Alles im Rahmen, Teil 2
Workshop: Brawler – Not unplugged, Teil 3
Workshop: Brawler – Der Rutengänger, Teil 4
Workshop: Brawler – Code Review, Teil 5

Heute beginne ich mit einer der Kernfunktionen von Brawler: Das scannen eines Hosts bzw. eine Seite. [...]]]></description>
			<content:encoded><![CDATA[<p>Zuvor:</p>
<ol>
<li><a href="http://phphacker.net/2009/12/04/workshop-brawler-the-web-application-security-scanner-teil-0/">Workshop: Brawler – The Web Application Security Scanner, Teil 0</a></li>
<li><a href="http://phphacker.net/2009/12/06/workshop-brawler-eine-frage-der-lizenz-teil-1/">Workshop: Brawler – Eine Frage der Lizenz, Teil 1</a></li>
<li><a href="http://phphacker.net/2009/12/07/workshop-brawler-alles-im-rahmen-teil-2/">Workshop: Brawler – Alles im Rahmen, Teil 2</a></li>
<li><a href="http://phphacker.net/2009/12/08/workshop-brawler-not-unplugged-teil-3/">Workshop: Brawler – Not unplugged, Teil 3</a></li>
<li><a href="http://phphacker.net/2009/12/09/workshop-brawler-der-rutenganger-teil-4/">Workshop: Brawler – Der Rutengänger, Teil 4</a></li>
<li><a href="http://phphacker.net/2009/12/11/workshop-brawler-code-review-teil-5/">Workshop: Brawler – Code Review, Teil 5</a></li>
</ol>
<p>Heute beginne ich mit einer der Kernfunktionen von Brawler: Das scannen eines Hosts bzw. eine Seite. Außerdem werde ich heute die Plugin-Schnittstelle implementieren, damit man Brawler direkt mit neuen Funktionen versehen werden kann. Für heute wird das lediglich das setzen eines eigenen User-Agents sein.</p>
<h2><span id="more-979"></span>Das Scannen</h2>
<p>Bevor wir einen Host scannen können, brauchen wir Klassen, die mehr oder minder einen Client simuliert. Dazu habe ich ein simples Interface geschrieben, die konkrete Klasse dann mit cURL. Interessant ist, dass die Klasse direkt ein Response-Objekt zurück gibt, das wir uns mal etwas näher anschauen:</p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * A URL request response
	 *
	 * @package     Brawler
	 * @subpackage  Client
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Client_Response {
		/**
		 * The raw result
		 *
		 * @var String
		 */
		protected $_rawResult;

		/**
		 * The raw curl info array
		 *
		 * @var Array
		 */
		protected $_rawInfo;

		/**
		 * Ctor
		 *
		 * @param String $dom
		 * @param Array $info
		 * @return void
		 */
		public function __construct($dom, $info) {
			$this-&gt;_rawResult = $dom;
			$this-&gt;_rawInfo = $info;
		}

		/**
		 * Returns a DOM representation of the returned document
		 * @return Brawler_Dom
		 */
		public function getDom() {
			if(strstr($this-&gt;getContentType(), &#039;html&#039;)) {
				return new Brawler_Dom($this-&gt;getRawContent(), $this-&gt;_rawInfo[&#039;url&#039;]);
			} else {
				throw new Brawler_Client_Response_Exception(&#039;Invalid content type&#039;);
			}
		}

		/**
		 * Returns the content type
		 *
		 * @return String
		 */
		public function getContentType() {
			$return = split(&#039;;&#039;, $this-&gt;_rawInfo[&#039;content_type&#039;]);
			return trim($return[0]);
		}

		/**
		 * Returns the raw content (wo header)
		 *
		 * @return String
		 */
		public function getRawContent() {
			return substr($this-&gt;_rawResult, $this-&gt;_rawInfo[&#039;header_size&#039;]);
		}

		/**
		 * Returns fetched urls
		 *
		 * @return Array
		 */
		public function getUrls() {
			$return = array();

			$nodeList = $this-&gt;getDom()-&gt;getUrls();
			foreach($nodeList as $node) {
				$return[] = $node-&gt;attributes-&gt;getNamedItem(&#039;href&#039;)-&gt;value;
			}

			return $return;
		}
	}
?&gt;</pre>
</pre>
<p>Diese Klasse soll einfachen Zugriff auf die Rückgabe ermöglich, ohne das man sich von außen viel Gedanken um die komplexe Struktur dahinter machen muss. Für das reine scannen wird die Methode getUrls am interessantesten sein. Derzeit ermittelt diese lediglich Ziele von Verweisen und gibt diese zurück.</p>
<p>Desweiteren habe ich einen neuen Controller geschrieben: Brawler_Controller_Scan. Dieser wird mit dem Argument r aufgerufen, dem eine URL zugewiesen sein muss. Was dieser Controller macht, ist im Grunde selbsterklärend: Scannen <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * Scanner controller
	 *
	 * @package     Brawler
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Controller_Scan extends Brawler_Controller {
		/**
		 * Holds an array with the fetched urls
		 *
		 * @var Array
		 */
		protected $_urls = array();

		/**
		 * Holds the client
		 *
		 * @var Brawler_Client
		 */
		protected $_client;

		/**
		 * Index Action
		 *
		 * @return void
		 */
		public function indexAction() {
			$this-&gt;_client = new Brawler_Client();

			$url = Brawler_Console::getArgument(&#039;r&#039;)-&gt;getValue();

			$this-&gt;_scanRecursively($url, 0, 5);

			$grid = new Brawler_View_Grid();
			$grid-&gt;setRows(new ArrayObject($this-&gt;_urls));
			$this-&gt;setView($grid);
		}

		/**
		 * Recursive method
		 *
		 * @param String $url
		 * @param Int $level
		 * @param Int $maxlevel
		 * @return void
		 */
		protected function _scanRecursively($url, $level, $maxlevel) {
			$urls = $this-&gt;_client-&gt;request($url)-&gt;getUrls();

			$urls = array_unique($urls);
			$urls = $this-&gt;_filterKnownUrls($urls);
			$urls = $this-&gt;_filterForeignHostUrls($urls);

			$this-&gt;_urls = array_merge($urls, $this-&gt;_urls);

			if($level &lt; $maxlevel) { 				foreach($urls as $newUrl) { 					$this-&gt;_scanRecursively($newUrl, $level+1, $maxlevel);
				}
			}
		}

		/**
		 * Filters already known urls
		 *
		 * @param Array $urls
		 * @return Array
		 */
		protected function _filterKnownUrls($urls) {
			$return = array();

			foreach($urls as $url) {
				if(!in_array($url, $this-&gt;_urls)) {
					$return[] = $url;
				}
			}

			return $return;
		}

		/**
		 * Filters foreign host urls
		 *
		 * @param Array $urls
		 * @return Array
		 */
		protected function _filterForeignHostUrls($urls) {
			$return = array();
			$curl = Brawler_Console::getArgument(&#039;r&#039;)-&gt;getValue();
			foreach($urls as $url) {
				if(parse_url($url, PHP_URL_HOST) == parse_url($curl, PHP_URL_HOST)) {
					$return[] = $url;
				}
			}

			return $return;
		}
	}
?&gt;</pre>
</pre>
<p>Dafür hat der Controller eine Methode, die rekursiv aufgerufen wird. Dieser wird eine URL sowie die aktuelle und die maximal gewünschte Ebene übergeben. Dann macht die Methode nichts weiter als die URL aufzurufen und dort alle Links auszulesen. Diese werden noch gefiltert – bereits bekannte und URLs zu einem Fremden Host werden entfernt – und dann wird, sofern die maximale Ebene noch nicht erreicht ist, die Methode mit den gefundenen URLs aufgerufen. Rekursiv eben. Am Ende gibt der Controller alle URLs aus, die er gefunden hat.</p>
<p>Die Grundfunktionalität wäre damit gelegt. Aber die ist auch alles andere als ausreichen. Spontan fallen mir eine Reihe Dinge ein, die hier noch zu tun sind:</p>
<p>URLs müssen auch aus Grafiken, Formularen, Frames, etc ausgelesen werden können<br />
Nicht absolute URLs müssen umgewandelt werden<br />
Anker müssen ignoriert werden<br />
Die gewünschte Tiefe muss per Argument eingestellt werden können<br />
Der User-Agent muss per Argument eingestellt werden können<br />
und einiges mehr …</p>
<p>Auf das Problem mit dem User-Agent gehe ich direkt ein, und damit komme ich dann auch zu der Plugin-Schnittstelle.</p>
<h2>Das erste echte Plugin</h2>
<p>Damit die Basisklassen durch Plugins erweitert werden können, müssen sie sich in irgend einer Ableitung der Pluggable-Klasse befinden. Diese stellt ein paar Methoden bereit, mit denen man schnell und einfach jede Methode erweiterbar machen kann.</p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * Abstract Pluggable class
	 *
	 * @package     Brawler
	 * @subpackage  Plugin
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	abstract class Brawler_Plugin_Pluggable_Abstract {
		/**
		 * Holds the plugins
		 *
		 * @var Brawler_Array_Object
		 */
		protected $_plugins;

		/**
		 * Ctor –Â loads the plugins
		 *
		 * @return void
		 */
		public function __construct() {
			$this-&gt;_plugins = new Brawler_Array_Object();

			// fetching plugins
			foreach(Brawler_Plugin_Loader::getPlugins() as $plugin) {
				// get plug name
				$pluginClass = $this-&gt;getPluginClassName($plugin);
				if(class_exists($pluginClass)) {
					$this-&gt;registerPlugin(new $pluginClass);
				}
			}
		}

		/**
		 * Registers a plugin
		 *
		 * @param Brawler_Plugin_Plugin $plugin
		 * @return void
		 */
		public function registerPlugin(Brawler_Plugin_Plug_Abstract $plugin) {
			$this-&gt;_plugins-&gt;append($plugin);
		}

		/**
		 * Notifies the Plugins before method starts to act
		 *
		 * @param String $method
		 * @param Array $arguments
		 * @return void
		 */
		public function preCallNotify($method, $arguments) {
			$notification = new Brawler_Plugin_Notification_Pre($method, $arguments);
			return $this-&gt;_notify($notification);
		}

		/**
		 * Notifies the Plugins after a method has acted
		 *
		 * @param String $method
		 * @param Array $arguments
		 * @param mixed $return
		 * @return mixed
		 */
		public function postCallNotify($method, $arguments, $return) {
			$notification = new Brawler_Plugin_Notification_Post($method, $arguments, $return);
			return $this-&gt;_notify($notification);
		}

		/**
		 * General notofication
		 *
		 * @param Brawler_Plugin_Notification $notification
		 * @return unknown_type
		 */
		protected function _notify(Brawler_Plugin_Notification $notification) {
			$i = $this-&gt;_plugins-&gt;getIterator();
			while($i-&gt;valid()) {
				$i-&gt;current()-&gt;notify($notification);
				$i-&gt;next();
			}

			return $notification;
		}

		/**
		 * Returns the name of the plugin class depending on a given plugin
		 *
		 * @param Brawler_Plugin $plugin
		 * @return String
		 */
		public function getPluginClassName($plugin) {
			$return = split(&#039;_&#039;, get_class($this));
			array_shift($return);
			return $plugin-&gt;getBaseName(). &#039;_&#039;. implode(&#039;_&#039;, $return);
		}
	}
?&gt;</pre>
</pre>
<p>Wir sehen, in den Ableitungen darf nicht vergessen werden, den Konstruktur der Eltern-Klasse aufzurufen – aber das sollte ja ohnehin immer gemacht werden. Dort werden nämlich die Plugins geladen und registriert. Wird also der Eltern-Konstruktor nicht aufgerufen, existieren zum einen keine Plugins, zum anderen kommt es aber auch zu einem Fehler, weil das Array Objekt gar nicht existiert (und später abgefrat wird).</p>
<p>Die nächsten Methoden machen klar, es gibt zwei Arten von Benachrichtigungen: Pre und Post. Die Namen sind denke ich selbsterklärend: Die eine wird vor dem durchführen der zu erweiternden Methode verschickt, und die anderen eben danach. Allerdings hat letztere noch die bereits prozessierte Rückgabe im Gepäck, woran sich die Plugins nun auch noch einmal vergreifen dürfen.</p>
<p>Die Plugins selbst müssen sich von der Plug-Klasse ableiten:</p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * Abstract Plug class
	 *
	 * @package     Brawler
	 * @subpackage  Plugin
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Plugin_Plug_Abstract {
		/**
		 * Reveives the notification
		 *
		 * @param Brawler_Plugin_Notification $notification
		 * @return Brawler_Plugin_Notification
		 */
		public function notify(Brawler_Plugin_Notification $notification) {
			if(method_exists($this, $notification-&gt;getMethod())) {
				call_user_func(array($this, $notification-&gt;getMethod()), $notification);
			}
		}
	}
?&gt;</pre>
</pre>
<p>Die ist (noch?) angenehm übersichtlich. Beim Notify wird geschaut, ob die entsprechende Methode überhaupt erweitert werden soll und wenn ja, wird diese aufgerufen.</p>
<p>So wird das Notification-Objekt einmal durch die ganze Bagage gereicht. Derzeit wird noch nichts damit gemacht (weil wir in unserem konkreten Fall lediglich an die cURL-Resource wollen), geplant ist aber, dass die Parameter im PreCall-Notify und die Rückgabe im PostCall-Notify modifiziert werden können, welche dann in der zu erweiternden Methode ausgewertet bzw. ausgegeben werden.</p>
<p>Dazu kommt später auch noch eine kleine Gewichtung der Plugins (,low‘, ,med‘, ,high‘), mit denen diese die Reihenfolge ein wenig beeinflussen können, denn – was auch noch geplant ist – ist die Möglichkeit für ein Plugin zu sagen, dass jede weitere Notification unterbunden werden soll. Das bedeutet im Umkehrschluss zwar, dass bestimmte Plugins in bestimmten Konstellationen sich gegenseitig unbrauchbar machen, bzw. stören, aber so weit muss es ja auch erst mal kommen <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Das konkrete Plugin zum ändern des User Agents sieht dann übrigens so aus <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * Just a template plugin
	 *
	 * @package     Brawler
	 * @subpackage  Plugin_UserAgent
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Plugin_UserAgent_UserAgent extends Brawler_Plugin {
		/**
		 * (non-PHPdoc)
		 * @see trunk/src/Brawler/Brawler_Plugin#getArguments()
		 */
		public function getArguments() {
			$list = new Brawler_Plugin_Argument_List();

			$list-&gt;append(new Brawler_Plugin_Argument(
				&#039;a&#039;,
				&#039;Sets the submitted user agent&#039;,
				true
			));

			return $list;
		}
	}
?&gt;</pre>
</pre>
<p>beziehungsweise</p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * Client plugin to make user agent settable
	 *
	 * @package     Brawler
	 * @subpackage  Plugin_UserAgent
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Plugin_UserAgent_Client extends Brawler_Plugin_Plug_Abstract {
		public function _initCurl($notification) {
			if($notification instanceof Brawler_Plugin_Notification_Post) {
				if(Brawler_Console::getArgument(&#039;a&#039;)-&gt;getValue()) {
					curl_setopt(
						$notification-&gt;getReturn(),
						CURLOPT_USERAGENT,
						Brawler_Console::getArgument(&#039;a&#039;)-&gt;getValue()
					);
				}
			}
		}
	}
?&gt;</pre>
</pre>
<p>Eigentlich also ganz einfach <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Sehen sie demnächst …</p>
<p>Beim nächsten mal werde ich mich dem auslesen von weiteren Adresse aus einem Dokument widmen bzw. die ermittelten Adressen robuster gestalten um auch die Host-Erkennung zu optimieren. Das wird glaube ich auch noch ein bisschen kniffelig …</p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/15/workshop-brawler-host-scannen-teil-5/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Workshop: Brawler – Code Review, Teil 5</title>
		<link>http://phphacker.net/2009/12/11/workshop-brawler-code-review-teil-5/</link>
		<comments>http://phphacker.net/2009/12/11/workshop-brawler-code-review-teil-5/#comments</comments>
		<pubDate>Fri, 11 Dec 2009 07:30:22 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Brawler]]></category>
		<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=970</guid>
		<description><![CDATA[Zuvor:

Workshop: Brawler – The Web Application Security Scanner, Teil 0
Workshop: Brawler – Eine Frage der Lizenz, Teil 1
Workshop: Brawler – Alles im Rahmen, Teil 2
Workshop: Brawler – Not unplugged, Teil 3
Workshop: Brawler – Der Rutengänger, Teil 4

Ich hab zwar beim letzten mal gesagt, dass ich die Plugin-Schnittstelle implementieren werde sowie die ersten Zeilen für das Scanning schreibe, doch [...]]]></description>
			<content:encoded><![CDATA[<p>Zuvor:</p>
<ol>
<li><a href="http://phphacker.net/2009/12/04/workshop-brawler-the-web-application-security-scanner-teil-0/">Workshop: Brawler – The Web Application Security Scanner, Teil 0</a></li>
<li><a href="http://phphacker.net/2009/12/06/workshop-brawler-eine-frage-der-lizenz-teil-1/">Workshop: Brawler – Eine Frage der Lizenz, Teil 1</a></li>
<li><a href="http://phphacker.net/2009/12/07/workshop-brawler-alles-im-rahmen-teil-2/">Workshop: Brawler – Alles im Rahmen, Teil 2</a></li>
<li><a href="http://phphacker.net/2009/12/08/workshop-brawler-not-unplugged-teil-3/">Workshop: Brawler – Not unplugged, Teil 3</a></li>
<li><a href="http://phphacker.net/2009/12/09/workshop-brawler-der-rutenganger-teil-4/">Workshop: Brawler – Der Rutengänger, Teil 4</a></li>
</ol>
<p>Ich hab zwar beim letzten mal gesagt, dass ich die Plugin-Schnittstelle implementieren werde sowie die ersten Zeilen für das Scanning schreibe, doch beim durchsehen des Codes fielen mir schon so viele Stellen ins Auge, die ein Code Review mit einhergehendem Refactoring unumgänglich machen. Einige davon kamen sogar von Lesern. Vielen Dank an dieser Stelle.</p>
<p>Ein paar Worte zum Vorgehen: Ich gehe Datei für Datei und Zeile für Zeile durch. Ich werde hier allerdings nur Änderungen kommentieren.</p>
<p><span id="more-970"></span></p>
<p>Die erste Stelle, die mir unangenehm ins Auge stach (und auch schon beim schreiben irgendwie unbehaglich war) ist die _checkRoute-Funktion des Routers. Diese sieht derzeit so aus:</p>
<pre>
<pre class="brush: php">
		/**
		 * Checks a route for matching conditions
		 *
		 * @param Brawler_Router_Route $route
		 * @return Bool
		 */
		protected static function _checkRoute(Brawler_Router_Route $route) {
			// check arguments
			$argumentIterator = $route-&gt;getArguments()-&gt;getIterator();
			$match = true;
			while($argumentIterator-&gt;valid()) {
				if(!Brawler_Console::getArgument($argumentIterator-&gt;current()-&gt;getFlag())) {
					// flag is missing break;
					$match = false;
					break;
				}

				if($argumentIterator-&gt;current()-&gt;getOnValue()) {
					if(!Brawler_Console::getArgument($argumentIterator-&gt;current()-&gt;getFlag())-&gt;getValue()) {
						// value is missing, break
						$match = false;
						break;
					}

					if($argumentIterator-&gt;current()-&gt;getSpecificValue()) {
						$specValue = $argumentIterator-&gt;current()-&gt;getSpecificValue();
						if(Brawler_Console::getArgument($argumentIterator-&gt;current()-&gt;getFlag())-&gt;getValue() != $specValue) {
							// value does not match, break
							$match = false;
							break;
						}
					}
				}
				$argumentIterator-&gt;next();
			}

			// dispatch
			if($match) {
				$route-&gt;getController()-&gt;dispatch($route-&gt;getAction());
			} else {
				return true;
			}

			// check chain
			return $route-&gt;getChain();
		}
</pre>
</pre>
<p>Ich finde, hier wird ein bisschen zu viel abgehandelt. Das wirkt zwar alles so, als gehöre es auch zusammen, es tut aber zum einen nicht weh, das aufzutrennen, und zum anderen bleibe ich so schön flexibel! Daher werden wir zwei neue Methoden einführen: _checkFlag, _checkValue und _checkSpecificValue. Die _checkRoute Methode sieht danach so aus:</p>
<pre>
<pre class="brush: php">
		/**
		 * Checks a route for matching conditions
		 *
		 * @param Brawler_Router_Route $route
		 * @return Bool
		 */
		protected static function _checkRoute(Brawler_Router_Route $route) {
			// check arguments
			$argumentIterator = $route-&gt;getArguments()-&gt;getIterator();
			$match = true;

			while($argumentIterator-&gt;valid()) {
				$match = self::_checkFlag($argumentIterator-&gt;current());
					if(!$match) break;

				$match = self::_checkValue($argumentIterator-&gt;current());
					if(!$match) break;

				$match = self::_checkSpecificValue($argumentIterator-&gt;current());
					if(!$match) break;

				$argumentIterator-&gt;next();
			}

			// dispatch
			if($match) {
				$route-&gt;getController()-&gt;dispatch($route-&gt;getAction());
			} else {
				return true;
			}

			// check chain
			return $route-&gt;getChain();
		}
</pre>
</pre>
<p>Eine ganze Ecke schlanker also. Dazu kommen die drei neuen Methoden:</p>
<pre>
<pre class="brush: php">
		/**
		 * Checks whether a route argument is present in call request
		 *
		 * @param Brawler_Router_Argument $routeArgument
		 * @return Bool
		 */
		protected static function _checkFlag($routeArgument) {
			return Brawler_Console::getArgument($routeArgument-&gt;getFlag());
		}

		/**
		 * Checks whether a route arguments value is present
		 *
		 * @param Brawler_Router_Argument $routeArgument
		 * @return Bool
		 */
		protected static function _checkValue($routeArgument) {
			if($routeArgument-&gt;getOnValue()) {
				$argument = Brawler_Console::getArgument($routeArgument-&gt;getFlag());
				if(!$argument OR !$argument-&gt;getValue()) {
					return false;
				}
			}

			return true;
		}

		/**
		 * Checks whether a route arguments vakue matches to the required
		 *
		 * @param Brawler_Router_Argument $routeArgument
		 * @return Bool
		 */
		protected static function _checkSpecificValue($routeArgument) {
			if($routeArgument-&gt;getSpecificValue()) {
				if(self::_checkValue($routeArgument)) {
					$argument = Brawler_Console::getArgument($routeArgument-&gt;getFlag());
					return ($argument-&gt;getValue() == $routeArgument-&gt;getSpecificValue());
				}
			}

			return true;
		}
</pre>
</pre>
<p>Ebenfalls alle schön schlank. Besser. Weiter zu den nächsten Verbesserungsbedürftigen Stellen. Und lange suchen muss ich auch nicht. In der forward-Methode der Controller-Klasse hat sich der Copy-Paste-Teufel eingeschlichen. Ich rufe derzeit eine Methode über call_user_func auf, obwohl ich genau weiß wie selbige heißt. Da hätte ich mal besser aufpassen sollen. Danke an onemorenerd für diesen Hinweis!</p>
<p>Als nächstes habe ich das etwas unschöne Parsen von Argumenten in der Console-Klasse. Das Gewirr sieht derzeit so aus:</p>
<pre>
<pre class="brush: php">
		/**
		 * Parses a single argument
		 *
		 * @param $argument
		 * @return void
		 */
		protected static function _parseArgument($argument) {
			if(strstr($argument, &#039;=&#039;)) {
				// definition
				$name = substr($argument, 1, 1);

				$parts = split(&#039;=&#039;, $argument);
				if(substr($parts[1], 0, 1) == &#039;&quot;&#039;) {
					$value = substr($parts[1], 1, strlen($parts[1] - 2));
				} else {
					$value = $parts[1];
				}

				self::$_arguments-&gt;append(new Brawler_Console_Argument($name, $value));
			} else {
				// option or optiongroup
				for($i = 1; $i &lt; strlen($argument); $i++) {&lt;/pre&gt;
&lt;pre&gt; 					self::$_arguments-&gt;append(new Brawler_Console_Argument(substr($argument, $i, 1)));
				}
			}
		}
</pre>
</pre>
<p>Das geht wesentlich schöner: Hier muss gekapselt werden. Alleine schon, weil ich Plane, in naher Zukunft auch Argumente mit Doppel-Minus anzunehmen, die keine Gruppen darstellen. Die Prüfung hier einzubauen würde in noch mehr Gestrüpp enden. Also frisch ans Werk und einmal mit der Sense durch! Zwei neue Methoden: _parseNonValuedArgument und _parseValuedArgument – außerdem bedienen wir uns statt Zeichenketten-Methoden einfach Regulären Ausdrücken:</p>
<pre>
<pre class="brush: php">
		/**
		 * Parses a single argument
		 *
		 * @param $argument
		 * @return void
		 */
		protected static function _parseArgument($argument) {
			$return = self::_parseNonValuedArgument($argument);
				if($return) return;

			$return = self::_parseValuedArgument($argument);
				if($return) return;
		}

		/**
		 * Parses an non valued argument or an argument group
		 *
		 * @param String $argument
		 * @return Bool
		 */
		protected static function _parseNonValuedArgument($argument) {
			if(preg_match(&#039;#-([a-zA-Z0-9]+)$#&#039;, $argument, $return)) {
				for($i = 0; $i &lt; strlen($return[1]); $i++) { 					$newArgument = new Brawler_Console_Argument($return[1][$i]); 					self::$_arguments-&gt;append($newArgument);
				}
				return true;
			}
			return false;
		}

		/**
		 * Parses a valued argument
		 *
		 * @param String $argument
		 * @return Bool
		 */
		protected static function _parseValuedArgument($argument) {
			if(preg_match(&#039;#-([a-zA-Z0-9]{1})=(.+)#&#039;, $argument, $return)) {
				if(preg_match(&#039;#^&quot;(.+)&quot;$#&#039;, $return[2], $vReturn)) {
					$value = $vReturn[1];
				} else {
					$value = $return[2];
				}

				$newArgument = new Brawler_Console_Argument($return[1], $value);
				self::$_arguments-&gt;append($newArgument);

				return true;
			}

			return false;
		}
</pre>
</pre>
<p>Wesentlich schicker, oder? Übrigens seht ihr da auch direkt einen kleinen Tipp: Man kann auf einen String wie auf ein Array zugreifen, wenn man an einzelne Zeichen will. Das ist in dem Fall wahrscheinlich die schnellste Methode.</p>
<p>Kommen wir nun zu einer Stelle, die ich bereits im Code hervorgehoben habe. Es geht um das mergen zweiter ArrayObject-Instanzen. Dieses scheinbar so einfach klingende Problem habe ich mit folgendem Konstrukt erschlagen:</p>
<pre>
<pre class="brush: php">
			// Argument List
			$list = new Brawler_Plugin_Argument_List();

			// Plugin arguments
			// @TODO find a better way to merge ArrayObjects
			$plugins = Brawler_Plugin_Loader::getPlugins();
			$i = $plugins-&gt;getIterator();
			while($i-&gt;valid()) {
				$pluginArguments = $i-&gt;current()-&gt;getArguments();
				$k = $pluginArguments-&gt;getIterator();
				while($k-&gt;valid()) {
					$list-&gt;append($k-&gt;current());
					$k-&gt;next();
				}
				$i-&gt;next();
			}
</pre>
</pre>
<p>Für Array gibt es array_merge(). Für ArrayObject-Instanzen … nicht. Eine solche Methode ist allerdings schnell geschrieben. Eine neue Klasse angelegt, ArrayObject abgeleitet und eine Methode merge rein:</p>
<pre>
<pre class="brush: php">
	/**
	 * Array Object WITH merge method
	 *
	 * @package     Brawler
	 * @subpackage  Array
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Array_Object extends ArrayObject {
		/**
		 * Merges an Array Object in this one
		 *
		 * @param ArrayObject $array
		 * @return void
		 */
		public function merge(ArrayObject $array) {
			$i = $array-&gt;getIterator();
			while($i-&gt;valid()) {
				$this-&gt;append($i-&gt;current());
				$i-&gt;next();
			}
		}
	}
</pre>
</pre>
<p>Das war einfach. Nur noch statt von ArrayObject von dieser Klasse ableiten und gut ist. Denkste! Das Ding Merged nämlich nicht wirklich, sondern ergänzt die eine Liste um die andere – und berücksichtigt somit nur eine Ebene. Ein Array als Element erkennt unser Freund nicht. Ist aber derzeit auch gar nicht notwendig.</p>
<p>Das war es auch schon. Phew. Ich habe zwar hier und dort noch ein paar kleinere Anpassungen vorgenommen, das waren aber maximal Formatierungsänderungen (die mache ich übrigens bei Quellcode lesen oft schon unbewusst – und das kann Kollegen manchmal in den Wahnsinn treiben <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ).</p>
<p>Auf Martin‘s Anmerkung, statt Klassen Objektinstanzen zu verwenden, will ich aber noch kurz eingehen: Kommt. Das würde nämlich doch etwas mehr Arbeit bedeuten, die ich heute nicht auf mich nehmen will <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/11/workshop-brawler-code-review-teil-5/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Tiefe Verschachtelung – A common Code Smell</title>
		<link>http://phphacker.net/2009/12/10/tiefe-verschachtelung-%e2%80%93-a-common-code-smell/</link>
		<comments>http://phphacker.net/2009/12/10/tiefe-verschachtelung-%e2%80%93-a-common-code-smell/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 08:00:15 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=962</guid>
		<description><![CDATA[Ich habe es schon getwittert: Heute habe ich keinen Bock auf mein Brawler-Projekt. Stattdessen gibt es mal wieder einen kleinen Praxis-Tipp von mir. Dabei geht es um etwas, das sicher jeder von uns kennt: Unverhältnismäßig tiefe Verschachtelung von Code. If-Condition in If-Condition, unnötige Else-Statements, dick vermantelte Methodenaufrufe.
Für mich persönlich ein Code-Smell. Zumindest ekele ich mich, [...]]]></description>
			<content:encoded><![CDATA[<p>Ich habe es schon getwittert: Heute habe ich keinen Bock auf mein Brawler-Projekt. Stattdessen gibt es mal wieder einen kleinen Praxis-Tipp von mir. Dabei geht es um etwas, das sicher jeder von uns kennt: Unverhältnismäßig tiefe Verschachtelung von Code. If-Condition in If-Condition, unnötige Else-Statements, dick vermantelte Methodenaufrufe.<span id="more-962"></span></p>
<p>Für mich persönlich ein Code-Smell. Zumindest ekele ich mich, wenn ich soetwas sehe:</p>
<pre>
<pre class="brush: php">&lt;?php

	if(isset($_POST[&#039;username&#039;])) {
		if(trim($_POST[&#039;username&#039;]) != &#039;&#039;) {
			if(isset($_POST[&#039;password&#039;])) {
				if(trim($_POST[&#039;password&#039;]) != &#039;&#039;) {
					// … und so weiter
				}
			}
		}
	}

?&gt;</pre>
</pre>
<p>Natürich ist das ein Extrembeispiel. In der Realität sind zumindest die Prüfungen auf ein Feld in einer If-Condition zusammengefasst. Trotzdem: Werden mehr als 2 übergebene Werte geprüft, wird das ganze zu einem unübersichtlichen Haufen Mist. Das mag nun für manche Hart ausgedrückt sein, aber es ist leider so. Und spätestens wenn man so etwas warten oder ergänzen muss, wird mir jeder zustimmen.</p>
<p>Trotzdem ist das nur die schlimmste Erscheinungsform des von mir gemeinten Problems. Eine andere sind zum Beispiel Wahnwitzige Switch-Case-Konstrukte, bei denen jeder Case dutzende bis hunderte Zeilen Code hat. Oder Funktionsaufrufe wie dieser hier:</p>
<pre>
<pre class="brush: php">&lt;?php

	addtoquery($query, mysql_real_escape(myCustomCheckFunc(ucfirst(strtolower($value)))));

?&gt;</pre>
</pre>
<p>Sicher, auch wieder ein eher merkwürdiges Szenario, aber ein definitv real auftauchendes Problem. Und keineswegs lediglich in ermangelung von OOP auftretend. Das hier habe ich auch schon gesehen:</p>
<pre>
<pre class="brush: php">&lt;?php

	$table-&gt;select($table-&gt;statement()-&gt;where($user-&gt;username)-&gt;where($user-&gt;password()))-&gt;getBuddies()-&gt;count();
?&gt;</pre>
</pre>
<p>Ein Wahnsinniges Konstrukt und jeder außer der Autor wird sich fragen: Was zum Geier passiert hier?</p>
<p>Ich könnte noch viele weitere Beispiele bringen: Merkwürdig und in scheinbar sinnloser Reihe aufeinanderfolgende Zeichenkettenverknüpfungen und Funktionsaufrufe; Tief in Klammern gefasste und sich über mehrere Bildschirme erstreckende Berechnungen; und, und, und. Wer solche Dinge noch nicht gesehen hat, der ist entweder ein Meister seines Fachs oder lügt! Spätestens wenn man an Uralten Legacy-Code muss, wird einem soetwas üder den Weg laufen.</p>
<p>Aber ich beruhige mich ja schon wieder. Meckern kann jeder. Konstruktibe Kritik ist gefragt. Daher hier ein paar meiner persönlichen Richtlinien für möglichst gut lesbaren Code!</p>
<h2>Keep it Short – 80-chars-short!</h2>
<p>Als ich meine ersten Scriptzeilen schrieb, für die ich Geld bekommen habe, habe ich mir möglichst gute Software besorgen wollen. Ich hab mir vom damals besten Entwickler den ich kannte (und das ist er im übrigen Heute noch. Er weiß schon, dass er gemeint ist) Tipps geholt. Damals empfahl er mir Crimson Editor für Windows. Das Ding gibt‘s heute AFAIK gar nicht mehr. Trotzdem bin ich damit Ewigkeiten rumgehampelt. Jedenfalls: Dieser Editor hatte eine feine Linie im Textbereich. Und zwar genau nach dem 80. Zeichen. Damals hatte ich keine Ahnung, warum die da war. Wenn ich ehrlich bin: Ich hab es heute auch nicht. Trotzdem habe ich mich unterbewusst an dieser Linie orientiert, und Zeilen möglichst nicht über diese Linie hinausgeschrieben. Und nun dürft ihr einen Blick auf meinen derzeit geöffneten Editor werfen:</p>
<p>￼<a href="http://phphacker.net/wp-content/uploads/2009/12/Bild-3.png"><img class="aligncenter size-full wp-image-963" title="Bild 3" src="http://phphacker.net/wp-content/uploads/2009/12/Bild-3.png" alt="Bild 3" width="540" /></a></p>
<p>Ihr seht: Ich habe diese Linie immer noch. Und ich versuche immer noch, sie möglichst nicht zu überschreiten. Das sich das nicht immer machen lässt, ist klar. Vor allem wenn – wie man auch im Screenshot sieht – die Linie lediglich um eine Handvoll Zeichen überschritten wird, nehme ich mir die Freiheit heraus, das zu ignorieren. Trotzdem: Allein die Tatsache, dass ich eine räumliche (gibt es eigentlich das Wort „breitliche“?) Begrenzung habe (jetzt fällt mir das richtige Wort ein: horizontale <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ), bin ich gezwungen, öfter mal die Enter-Taste zu schlagen. Und das wiederum führt alleine schon dazu, dass ich keine Ewig langen ineinander Verschachtelten Calls mache.</p>
<p>Randanekdote: Ich habe mal in einem Tochterunternehmen eines großen deutschen Hosting-Anbieters gearbeitet. Man hat sich Gegenseitig öfter mal mit Code-Base ausgeholfen. Damals habe ich nur auf einem Monitor gearbeitet. Eines Tages brauchte ich eine gute Mailklasse (warum freie nicht gingen, weiß ich nicht mehr) und bekam eine vom Kollegen der Mutterfirma. Absolut unlesbar, die Person nutzte 10(!) Spaces als Tabs, hat zwischen allem eben solche plaziert ($this	-	&gt;	method	(	$var	)	; – und das ist kein Witz!) und darüberhinaus auch noch Ellenlange Methoden- und Variablennamen benutzt. Warum er trotzdem damit arbeiten konnte war klar, als ich ihm einen Besuch abstattete: Sein Editor erstreckte sich über beide Monitore …</p>
<h2>JSON! – hä?</h2>
<p>Ja, wie komme ich nun auf JSON? Ganz einfach: Als ich JSON das erste mal bewusst wahr genommen habe, war ich fasziniert von der Schlanken Art und Weise, Informationen zu verpacken, dabei fast immer gut 30% weniger Overhead zu brauchen als mit XML und das ganze dabei noch für das menschliche Auge lesbar zu halten.</p>
<p>Mir fiel auch sehr schnell auf, dass man das im Grunde auch auf PHP-Code anwenden kann. Daher sehen Arrays bei mir nicht mehr so aus:</p>
<pre>
<pre class="brush: php">&lt;?php
	$a = array(&#039;name&#039; =&gt; &#039;Cem&#039;, &#039;url&#039; =&gt; &#039;http://phphacker.net/&#039;, &#039;likes&#039;
				=&gt; array(&#039;beer&#039;, &#039;music&#039;, &#039;tattoos&#039;), &#039;dislikes&#039; =&gt; array(&#039;ignorance&#039;
				, &#039;spam&#039;, &#039;fish&#039;));
?&gt;</pre>
</pre>
<p>Sondern so:</p>
<pre>
<pre class="brush: php">&lt;?php
	$a = array(
			&#039;name&#039; 	=&gt; &#039;Cem&#039;,
			&#039;url&#039; 	=&gt; &#039;http://phphacker.net/&#039;,
			&#039;likes&#039; =&gt; array(
				&#039;beer&#039;,
				&#039;music&#039;,
				&#039;tattoos&#039;
			),
			&#039;dislikes&#039; =&gt; array(
				&#039;ignorance&#039;,
				&#039;spam&#039;,
				&#039;fish&#039;
			)
	);
?&gt;</pre>
</pre>
<p>Wesentlich leserlicher, oder? Das Konzept lässt sich im Grunde auf alles Anwenden: Methoden und Funktionen mir vielen Parametern, Fluid-Interfaces, Zeichenkettenverknüpfungen. Und selbst wenn man mal anfängt wild zu verschachteln: Es ist zumindest noch ersichtlich, was passiert.</p>
<h2>Ein Tab ist 4 Spaces lang und darf nur viermal hintereinander vorkommen</h2>
<p>Ok, das was jetzt kommt, ist eine Regel, die ich meist eher halbherzig befolge. Das liegt daran, dass diese Gewohnheit im Gegensatz zu den anderen beiden aktives mitdenken erfordert – und das kommt mir, wenn ich ein kniffeliges Problem löse, eher ungelegen. Trotzdem will ich kurz erläutern, um was es geht.</p>
<p>Man Strafe mich nun Lügen, aber ich bin mir fast sicher, dass ich diese Regel (nicht in diesem Wortlaut) bei den offiziellen Coding-Guidelines des Linux-Kernel gelesen habe. Dort wird empfohlen, die Tab-Breite auf 4 Spaces einzustellen. DAS mache ich definitiv nicht – bei mir sind es nur 2. Und ich finde auch, das sollte jedem selbst überlassen sein (wenn man weiß, wie man „tabbt“, so dass es bei allen gleich ausschaut <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ). Interessant fand ich aber, dass man nach Möglichkeit nur maximal 4 Ebenen einrücken soll. Begründet wurde das mit besserer Lesbarkeit und nicht so schnell auftretenden Ermüdungserscheinungen.</p>
<p>Randanekdote: Dabei stand auch, dass man nicht mehr als 2 Stunden am Stückprogrammieren sollte, um keinen schlechten Code durch Müdigkeit zu erzeugen. Das lässt sich im Berufsleben ja leider eher schwer umsetzen. Allerdings rührt das sicherlich nicht auch zuletzt daher, dass man in der Regel nach Feierabend (und das bedeutet bei den meisten nach 8 Stunden und Mehr, die man schon programmiert hat) an Open Source Projekten arbeitet.</p>
<h2>Lieber einmal mehr als einmal zu wenig zuweisen</h2>
<p>Ich persönlich finde Parameter, die aus direkten Rückgaben von anderen Methoden oder Funktionen übergeben werden, immer irgendwie … nervig. Es ist nicht falsch (und pauschal kann man das sowieso nicht festlegen), aber oftmals erschwert es mir die Leserlichkeit. Falls ihr nicht nachvollziehen könnte, was ich meine:</p>
<pre>
<pre class="brush: php">&lt;?php
	$this-&gt;transform($this-&gt;getValue($request-&gt;getName()));
?&gt;</pre>
</pre>
<p>Hier könnte man durch oben erwähnte Einrückung schon einiges an Übersichtlichkeit herausholen, aber es tut auch nicht weh, wenn man es so macht:</p>
<pre>
<pre class="brush: php">&lt;?php
	$value = $this-&gt;getValue($request-&gt;getName());
	$this-&gt;transform($value);
?&gt;</pre>
</pre>
<p>Man darf nie vergessen, das Code gewartet werden muss, damit er nicht verottet. Oder das Funktionalitäten ergänzt oder geändert werden müssen. Dann ist es hilfreich, wenn der Entwickler, der diese Stelle überarbeitet nicht erst den Call auseinandernehmen muss (evtl. auch nur, um ihn zu verstehen), um am Ende einzelne Werte nochmal zuweisen zu müssen, weil diese noch woanders hingeschickt werden – und dann dabei evtl. auch noch Gefahr läuft Namen zu vergeben, die schon vergeben wurde. Sicher, in der Regel sollte die IDE meckern, muss aber nicht sein. Und sicher, spätestens PHP wird meckern … muss aber auch nicht sein, wenn es eine Stelle ist, die beim schnellen hacken nicht geprüft und somit durchlaufen wird.</p>
<h2>Skizzen nutzen</h2>
<p>Wenn ich einen Komplexen Ablauf programmiere, erstelle ich die Methode inkl. Signatur und erstelle mit Kommentaren eine Beschreibung dessen, was ich gleich Programmieren werde. Beispiel:</p>
<pre>
<pre class="brush: php">&lt;?php
	// determine class name
	// init instance of class
	// call requested method
	// return result
?&gt;</pre>
</pre>
<p>Und ihr werdet nun auch alle wissen, dass man seinen Code kommentieren sollte, daher wird euch das nicht komisch vorkommen. Allerdings: Wenn es dann an konkrete Befehle geht, passiert bei mir folgendes:</p>
<pre>
<pre class="brush: php">&lt;?php
	// determine class name
	$className = $this-&gt;determineClassName();
	// init instance of class
	$instance = $this-&gt;getInstanceOfClass($instance);
	// call requested method
	$return = $this-&gt;callMethod($instance, $method);
	// return result
	return $return;
?&gt;</pre>
</pre>
<p>Ich deligiere den Krempel in weitere Methoden. Und das mache ich in der Regel so lange, bis Methoden nicht länger als eine halbe Seite sind (also so um die 30-50 Zeilen). Das hat en angenehmen Nebeneffekt, dass man so wiederverwertbare Methoden baut, auch wenn man jetzt noch gar nicht weiß, dass man genau das Stück Code bald noch einmal braucht.</p>
<p>So, ich hoffe ich konnte euch ein paar nützliche Sachen mit auf den Weg geben. Feedback ist wie immer willkommen!</p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/10/tiefe-verschachtelung-%e2%80%93-a-common-code-smell/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Workshop: Brawler – Der Rutengänger, Teil 4</title>
		<link>http://phphacker.net/2009/12/09/workshop-brawler-der-rutenganger-teil-4/</link>
		<comments>http://phphacker.net/2009/12/09/workshop-brawler-der-rutenganger-teil-4/#comments</comments>
		<pubDate>Wed, 09 Dec 2009 08:00:20 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Brawler]]></category>
		<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=948</guid>
		<description><![CDATA[Zuvor:

Workshop: Brawler – The Web Application Security Scanner, Teil 0
Workshop: Brawler – Eine Frage der Lizenz, Teil 1
Workshop: Brawler – Alles im Rahmen, Teil 2
Workshop: Brawler – Not unplugged, Teil 3

Nachdem ich mir eine kleine MVC-Architektur sowie diverse Tools zum ahandeln der Konsole geschrieben habe und im letzten Teil auch noch die Grundlegende Plugin-Funktionalität implementieren konnte, werde ich [...]]]></description>
			<content:encoded><![CDATA[<p>Zuvor:</p>
<ol>
<li><a href="http://phphacker.net/2009/12/04/workshop-brawler-the-web-application-security-scanner-teil-0/">Workshop: Brawler – The Web Application Security Scanner, Teil 0</a></li>
<li><a href="http://phphacker.net/2009/12/06/workshop-brawler-eine-frage-der-lizenz-teil-1/">Workshop: Brawler – Eine Frage der Lizenz, Teil 1</a></li>
<li><a href="http://phphacker.net/2009/12/07/workshop-brawler-alles-im-rahmen-teil-2/">Workshop: Brawler – Alles im Rahmen, Teil 2</a></li>
<li><a href="http://phphacker.net/2009/12/08/workshop-brawler-not-unplugged-teil-3/">Workshop: Brawler – Not unplugged, Teil 3</a></li>
</ol>
<p>Nachdem ich mir eine kleine MVC-Architektur sowie diverse Tools zum ahandeln der Konsole geschrieben habe und im letzten Teil auch noch die Grundlegende Plugin-Funktionalität implementieren konnte, werde ich heute einen Router in den MVC-Part einbauen – der auch direkt die Plugins berücksichtigt. Ganz zum Schluss gibt es dann auch noch mal einen flüchtigen Blick auf das Chaos das ich „Arbeitsweise und Stil“ nenne <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><span id="more-948"></span></p>
<h2>Wie wird geroutet?</h2>
<p>In der schönen und heilen Webapplikationswelt, gestalten sich Routen recht „einfach“. Die Route und der Call sind im Grunde so gut wie immer identisch bzw. die Ableitung ist ersichtlich. Zum Beispiel ist so gut wie klar, dass der Call „http://example.com/user/list“ auf den User-Controller und die List-Action routet.</p>
<p>Auf der Kommandozeile sieht das ein bisschen anders aus. Hier übergibt man mehr oder weniger nur Flags bzw. Flag-Wert-Paare und die Applikation muss mit diesen Informationen routen.</p>
<p>Also, wie habe ich das angestellt. Schauen wir uns die Router-Klasse an:</p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * Router class
	 *
	 * @package     Brawler
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Router {
		/**
		 * Holds the registered routes
		 *
		 * @var Brawler_Router_Route_List
		 */
		protected static $_routes = null;

		/**
		 * Registers a given route
		 *
		 * @param Brawler_Router_Route $route
		 * @return void
		 */
		public static function registerRoute(Brawler_Router_Route $route) {
			if(!self::$_routes) {
				self::_initRouteArray();
			}

			self::$_routes-&gt;append($route);
		}

		/**
		 * Inits the Route List
		 *
		 * @return void
		 */
		protected static function _initRouteArray() {
			self::$_routes = new ArrayObject();
		}

		/**
		 * More or less the dispatcher <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />
		 *
		 * @return void
		 */
		public static function route() {
			$i = self::$_routes-&gt;getIterator();
			while($i-&gt;valid()) {
				if(!self::_checkRoute($i-&gt;current())) {
					break;
				}
				$i-&gt;next();
			}
		}

		/**
		 * Checks a route for matching conditions
		 *
		 * @param Brawler_Router_Route $route
		 * @return Bool
		 */
		protected static function _checkRoute(Brawler_Router_Route $route) {
			// check arguments
			$argumentIterator = $route-&gt;getArguments()-&gt;getIterator();
			$match = true;
			while($argumentIterator-&gt;valid()) {
				if(!Brawler_Console::getArgument($argumentIterator-&gt;current()-&gt;getFlag())) {
					// flag is missing break;
					$match = false;
					break;
				}

				if($argumentIterator-&gt;current()-&gt;getOnValue()) {
					if(!Brawler_Console::getArgument($argumentIterator-&gt;current()-&gt;getFlag())-&gt;getValue()) {
						// value is missing, break
						$match = false;
						break;
					}

					if($argumentIterator-&gt;current()-&gt;getSpecificValue()) {
						$specValue = $argumentIterator-&gt;current()-&gt;getSpecificValue();
						if(Brawler_Console::getArgument($argumentIterator-&gt;current()-&gt;getFlag())-&gt;getValue() != $specValue) {
							// value does not match, break
							$match = false;
							break;
						}
					}
				}
				$argumentIterator-&gt;next();
			}

			// dispatch
			if($match) {
				$route-&gt;getController()-&gt;dispatch($route-&gt;getAction());
			} else {
				return true;
			}

			// check chain
			return $route-&gt;getChain();
		}
	}
</pre>
</pre>
<p>An Properties hält der Router nicht viel vor – lediglich eine Liste der Routen die man über die Methode registerRoute registrieren kann. Anhand dieser Routen wird der Router später dispatchen können (und ich habe ihn damit mehr oder weniger in den Stand eines Dispatcher erhoben).</p>
<p>Wird der Router angewiesen, seiner eigentlichen Arbeit nachzugehen, so durchläuft er alle Routen, und wenn die gewünschten Parameter oder Parameter-Wert-Paare passen, wird der hinterlegte Controller mit der hinterlegten Action aufgerufen. Da man Routen auch in Reihe schalten kann, gibt es das Attribut chain. Damit kann die Route bestimmten, ob nach ihr noch weitere Routen nachgegangen werden darf, die auf den Call passen.</p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * Represents a single route
	 *
	 * @package     Brawler
	 * @subpackage  Router
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Router_Route {
		/**
		 * Name of this route
		 *
		 * @var String
		 */
		protected $_name = null;

		/**
		 * Arguments for this route
		 *
		 * @var Brawler_Router_Argument_List
		 */
		protected $_arguments = null;

		/**
		 * Controller to call
		 *
		 * @var Brawler_Controller
		 */
		protected $_controller = null;

		/**
		 * Action to call
		 *
		 * @var String
		 */
		protected $_action = &#039;index&#039;;

		/**
		 * Defines whether the route can dispatch in chain
		 *
		 * @var Bool
		 */
		protected $_chain = null;

		/**
		 * Ctor
		 *
		 * @param String $name
		 * @param Brawler_Router_Argument_List $arguments
		 * @param Brawler_Controller $controller
		 * @param String $action
		 * @return void
		 */
		public function __construct($name, Brawler_Router_Argument_List $arguments, Brawler_Controller $controller = null, $action = null, $chain = true) {
			$this-&gt;_name = $name;
			$this-&gt;_arguments = $arguments;

			if($controller) {
				$this-&gt;_controller = $controller;
			} else {
				$this-&gt;_controller = new Brawler_Controller_Index();
			}

			if($action) {
				$this-&gt;_action = $action;
			}

			$this-&gt;_chain = $chain;
		}

		/**
		 * Returns the arguments attached to this route
		 *
		 * @return Brawler_Router_Argument_List
		 */
		public function getArguments() {
			return $this-&gt;_arguments;
		}

		public function getChain() {
			return $this-&gt;_chain;
		}

		public function getController() {
			return $this-&gt;_controller;
		}

		public function getAction() {
			return $this-&gt;_action;
		}
	}
</pre>
</pre>
<p>Eine Route baut sich aus einem Namen (den brauchen wir eigentlich noch nicht, aber man weiß ja nie), einer Liste von Argumenten, einem Controller, eine Action und der Angabe ob die Route in Reihe geschaltet werden darf auf. Bis auf die Argument-Liste und den Namen ist alles optional … wobei es natürlich wenig sinnvoll ist, wenn alle Routen auf den Index-Controller zeigen <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Eine kleine Besonderheit an dieser Stelle ist, dass direkt eine Instanz des Controller übergeben wird. Man könnte stattdessen auch den Klassennamen übergeben, aber irgendwie erschien mir das an dieser Stelle unpassend.</p>
<p>Die Argumente, die eine Route braucht, unterscheiden sich ein wenig von denen, die Plugins nennen, wenn sie gefragt werden, welche sie überhaupt auswerten. Das liegt zum einen daran, dass hier gar nicht genau diese auftauchen müssen, zum anderen, dass völlig andere Informationen notwendig sind. Schauen wir uns die Klasse an:</p>
<pre>
<pre class="brush: php">&lt;?php
	/**
	 * Represents an argument for routes
	 *
	 * @package     Brawler
	 * @subpackage  Router
	 * @author      Cem Derin,
	 * @copyright   2009 Cem Derin,
	 */
	class Brawler_Router_Argument {
		/**
		 * The flag this route is for
		 *
		 * @var String
		 */
		protected $_flag = null;

		/**
		 * Defines whether this route only is for vakued flags
		 *
		 * @var Bool
		 */
		protected $_onValue = null;

		/**
		 * Defines whether this route is only for a valued flag with a specific value
		 *
		 * @var String
		 */
		protected $_specificValue = null;

		public function __construct($flag, $onValue = false, $specificValue = null) {
			$this-&gt;_flag = $flag;
			$this-&gt;_onValue = $onValue;
			$this-&gt;_specificValue = $specificValue;
		}

		/**
		 * Returns the setted flag
		 *
		 * @return String
		 */
		public function getFlag() {
			return $this-&gt;_flag;
		}

		/**
		 * Returns whether this argument needs a value
		 *
		 * @return Boolean
		 */
		public function getOnValue() {
			return $this-&gt;_onValue;
		}

		/**
		 * Returns whether a specific value is needed
		 *
		 * @return String
		 */
		public function getSpecificValue() {
			return $this-&gt;_specificValue;
		}
	}
</pre>
</pre>
<p>Auch nichts wildes! Der Konstruktor will das Flag, auf das die Route reagieren soll, fragt noch, ob es einen Inhalt haben muss und wenn ja, ob dieser einem bestimmten Wert entsprechen soll (für so Sachen wie „m=low/m=med/m=hi“ und so). Das war es auch schon.</p>
<p>Der Router wertet den Krempel aus, ob alle Faktoren der Route auf den Call matchen und – wenn ja – dispatcht die Klasse. Aus die Maus. Eigentlich ganz einfach, oder?</p>
<p>Und da mir von vorne herein klar war, dass ich diesmal länger am Code als an der Erläuterung sitze, gibt es heute noch die Eingangs erwähnte Einführung in meine kleine Hacker-Welt</p>
<h2>Sauber, schlank, schnell, robust</h2>
<p>Das sollte Code sein. Meistens kann man ihn auch vom Kopf in die Tastatur bekommen, und er entspricht genau den Kriterien. Manchmal – aus Faulheit, aus Unwissen oder weil dort ein Hund mit hochstehendem Schwanz lang läuft) prügelt man aber auch eine solche Grütze in den Rechner, dass man sich beim nächsten mal ernsthaft fragt, ob nicht doch LSD im Trinkwasser ist.</p>
<p>Bei mir setzt dieses Phänomen mit steigender Müdigkeit ein (übrigens ein Grund, warum nächtelanges durchhacken eher ein romantisches Nerd-Klischee ist und in den seltensten Fällen dabei Code entsteht, der obigen Ansprüchen genügt), und da ich das Zeug hier vorwiegend Abends schreibe und ohnehin schon den ganzen Tag programmiert habe, ist dieses Projekt hier besonders anfällig!</p>
<p>Nichtsdestotrotz möchte ich meine Ansprüche nicht herunterschrauben. Daher werde ich meinen eigenen Code in kurzen Abständen einem Review unterziehen, und jedes Fragment kritisch beurteilen sowie im Bedarf einem Refactoring unterziehen. Das wird dann auch Teil meines Workshops werden (und glaubt mir, umfangreiches Refactoring macht mit PHP keinen Spaß <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ).</p>
<h2>Dokumentation ist alles</h2>
<p>Ich persönlich hasse es, wenn Code undokumentiert ist. Daher nutze ich die Doc-Syntax. In der Regel finde ich, dass jede Klasse (bzw. jede Datei) einen Kopf braucht, in dem Angegeben wird, wer den Mist verbrochen hat, wer dannach daran rumgepfuscht hat. Für Methoden halte ich das etwas laxer. Da gilt: Steht da nix, war es der Klassen(haupt)autor.</p>
<p>Die Angabe von Packages und Subpackages lässt die Dokumentation später aufgeräumt erscheinen. Und eine Erklärung sowie eine Typvorgabe bei Parametern und Rückhaben ist unerlässlich!</p>
<h2>Danke für das erste Feedback</h2>
<p>Bedanken möchte ich mich im 4. (eigentlich ja 5.) Teil des Workshops bei Uli und Martin, die mich auf zwei kleine Unschönheiten hingewiesen haben. Mehr davon, bitte! <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<h2>Und jetze?</h2>
<p>Im nächsten Teil werde ich die Hooks für die Plugins integrieren sowie den ersten spannenden Teil bauen: Das scannen eines Hosts. Und da kommen dann auch schon die ersten Fallstricke <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/12/09/workshop-brawler-der-rutenganger-teil-4/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
