<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>webcodr</title>
    <link>https://webcodr.io/topics/php/</link>
    <description>Recent content on webcodr</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sat, 06 Apr 2013 22:29:53 +0100</lastBuildDate>
    <atom:link href="https://webcodr.io/topics/php/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Say Hello to Mango</title>
      <link>https://webcodr.io/2013/04/say-hello-to-mango/</link>
      <pubDate>Sat, 06 Apr 2013 22:29:53 +0100</pubDate>
      <guid>https://webcodr.io/2013/04/say-hello-to-mango/</guid>
      <description>Was’n das? Finger weg! Diese Mango schmeckt nicht.
Mango ist ein Object Document Mapper für MongoDB und PHP.
Und MongoAppKit? MongoAppKit hat ein Problem, denn es ist nicht nur ein ODM und kann noch so einiges mehr. Theoretisch kann man zwar die ODM-Komponente auch ohne den ganzen anderen Krempel nutzen, aber es bleibt eine große Abhängigkeit zu Silex, die man auch nicht so einfach wieder los wird.
Dies und das im Vergleich schlechte Handling bzw. der geringe Komfort von MongoAppKit, haben mich dazu bewogen mit Mango einen universell einsatzbaren und leicht handzuhabenden ODM zu entwickeln.
</description>
      <content:encoded><![CDATA[<h2 id="wasn-das"><a href="#wasn-das" class="heading-anchor">Was&rsquo;n das?</a></h2>
<p>Finger weg! Diese Mango schmeckt nicht.</p>
<p>Mango ist ein Object Document Mapper für MongoDB und PHP.</p>
<h3 id="und-mongoappkit"><a href="#und-mongoappkit" class="heading-anchor">Und MongoAppKit?</a></h3>
<p>MongoAppKit hat ein Problem, denn es ist nicht nur ein ODM und kann noch so einiges mehr. Theoretisch kann man zwar die ODM-Komponente auch ohne den ganzen anderen Krempel nutzen, aber es bleibt eine große Abhängigkeit zu Silex, die man auch nicht so einfach wieder los wird.</p>
<p>Dies und das im Vergleich schlechte Handling bzw. der geringe Komfort von MongoAppKit, haben mich dazu bewogen mit Mango einen universell einsatzbaren und leicht handzuhabenden ODM zu entwickeln.</p>
<p>Mango wurde stark von Mongoid für Ruby inspiriert und soll dessen Funktionalität zumindest teilweise in PHP abbilden. Das ist einfacher gesagt als getan, denn Ruby bietet wesentlich elegantere Möglichkeiten diverse Probleme zu lösen, als es mit PHP derzeit machbar ist.</p>
<h2 id="los-gehts-"><a href="#los-gehts-" class="heading-anchor">Los geht&rsquo;s …</a></h2>
<h3 id="installation-via-composer"><a href="#installation-via-composer" class="heading-anchor">Installation via Composer</a></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">php composer.phar require webcodr/mango:*
</span></span></code></pre></div><h3 id="ein-dokument-anzulegen-ist-ein-kinderspiel"><a href="#ein-dokument-anzulegen-ist-ein-kinderspiel" class="heading-anchor">Ein Dokument anzulegen ist ein Kinderspiel</a></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">MyProject\Model</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Mango\Document</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Mango\DocumentInterface</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span> <span class="k">implements</span> <span class="nx">DocumentInterface</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">use</span> <span class="nx">Document</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">private</span> <span class="k">function</span> <span class="nf">addFields</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">addField</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;type&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;String&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">addField</span><span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;type&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;String&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">addField</span><span class="p">(</span><span class="s1">&#39;created_at&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;type&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;DateTime&#39;</span><span class="p">,</span> <span class="s1">&#39;index&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">,</span> <span class="s1">&#39;default&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;now&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">addField</span><span class="p">(</span><span class="s1">&#39;updated_at&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;type&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;DateTime&#39;</span><span class="p">,</span> <span class="s1">&#39;index&#39;</span> <span class="o">=&gt;</span> <span class="k">true</span><span class="p">,</span> <span class="s1">&#39;default&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;now&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Es ist lediglich nötig, dass die Model-Klasse das Interface <code>DocumentInterface</code> implementiert und den Trait <code>Document</code> einbindet. In der Hook-Methode <code>addFields()</code> werden anschließend noch die Felder des Dokuments deklariert.</p>
<p>Mango nutzt etwas Magic: Der Klassenname des Models ist gleichzeitig auch der Name der Collection (klein geschrieben). Soll die Collection anders heißen bzw. das Model eine vorhandene nutzen, muss lediglich die Methode <code>getCollectionName()</code> überschrieben werden.</p>
<h3 id="go-mango-go"><a href="#go-mango-go" class="heading-anchor">Go, Mango, go</a></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Mango\Mango</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Mango\DocumentManager</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Document\User</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$mango</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Mango</span><span class="p">(</span><span class="s1">&#39;mongodb://localhost/galactica&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$dm</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DocumentManager</span><span class="p">(</span><span class="nv">$mango</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">User</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">name</span> <span class="o">=</span> <span class="s1">&#39;William Adama&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">email</span> <span class="o">=</span> <span class="s1">&#39;william.adama@bsg-75.mil&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">store</span><span class="p">();</span>
</span></span></code></pre></div><p>Das Mango-Object erwartet eine gültige MongoDB URI, falls notwendig inkl. Benutzer, Passwort, Port usw.</p>
<p>Dem Document Manager kommt eine vergleichbare Aufgabe zu, wie dem Entity Manager in Doctrine2.</p>
<p>Für mehr Komfort holt sich eine Model-Klasse den Document Manager über eine statische Methode ab. Daher können Methoden wie <code>store()</code> direkt über die Model-Klasse abgewickelt werden.</p>
<h3 id="dokumente-abfragen"><a href="#dokumente-abfragen" class="heading-anchor">Dokumente abfragen</a></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$user</span> <span class="o">=</span> <span class="nx">User</span><span class="o">::</span><span class="na">where</span><span class="p">([</span><span class="s1">&#39;name&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;William Adama&#39;</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$user</span><span class="o">-&gt;</span><span class="na">count</span><span class="p">();</span> <span class="c1">// = 1
</span></span></span><span class="line"><span class="cl"><span class="k">echo</span> <span class="nv">$user</span><span class="o">-&gt;</span><span class="na">first</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">email</span><span class="p">;</span> <span class="c1">// = william.adama@bsg-75.mil
</span></span></span></code></pre></div><p>Eine Abfrage kann einfach über die statische Methode <code>where()</code> ausgeführt werden. Die Syntax der Abfragen entspricht derzeit noch der normalen MongoDB Query API. Für die Zukunft plane ich aber eine Abstraktionsebene für die Abfragen, vergleichbar mit Mongoid.</p>
<p>Eine Abfrage mit <code>where()</code> oder <code>find()</code> gibt immer ein Cursor-Objekt zurück, das anhand der aufgerufenen Methode entscheiden kann, ob der Zugriff auf den MongoCursor oder das Abfrageergebnis in Form einer Instanz von MutableMap erfolgt.</p>
<p>In obigem Beispiel ist <code>count()</code> eine Methode des Cursors, während <code>first()</code> schon auf das Ergebnis zugreift. Wie MongoCursor kann auch die Cursor-Klasse von Mango einfach über das Ergebnis iterieren.</p>
<p>Durch die dynamische Unterscheidung zwischen MongoCursor- und Datenzugriff, können auf eine Instanz der Cursor-Klasse auch alle Methoden von MutableMap angewandt werden.</p>
<p>Beispielsweise:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">User</span><span class="o">::</span><span class="na">where</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">reverse</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">each</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="nv">$document</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="nv">$document</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Natürlich macht dieser Code wenig Sinn, da man das wesentlich effizienter über die Cursor-Methoden erledigen kann. Das Beispiel soll lediglich zeigen, was möglich wäre.</p>
<h3 id="hydration"><a href="#hydration" class="heading-anchor">Hydration</a></h3>
<p>Mango sorgt automatisch dafür, dass die Dokumente im Ergebnis immer Instanzen ihrer jeweiligen Model-Klasse sind.</p>
<p>Die Hydration-Automatik sorgt außerdem dafür, dass die Daten intern als jeweilige Typ-Klasse von Mango gehalten werden.</p>
<p>Typ-Klassen halten die Daten und können sie in zwei Formaten zurückgeben. Konfiguriert man ein Feld als <code>DateTime</code> bekommt Mango intern beim Speichern automatisch ein MongoDate-Objekt. Greift man hingegen außerhalb von Mango auf den Wert zu, bekäme man in diesem Fall eine Instanz der Klasse DateTime zurück.</p>
<p>Soweit zum aktuellen Funktionsumfang von Mango. Es ist bei weitem noch nicht fertig, kann aber für kleine Projekte schon eingesetzt werden. Ich verwende es selbst in der aktuellsten Version von CodrPress und es macht wesentlich mehr Spaß als MongoAppKit, ohne ein monströses Schlachtschiff wie Doctrine zu sein.</p>
<p>Natürlich gibt&rsquo;s Mango auch bei <a href="https://github.com/WebCodr/Mango">GitHub</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Array almighty</title>
      <link>https://webcodr.io/2013/02/array-almighty/</link>
      <pubDate>Sat, 02 Feb 2013 22:28:05 +0100</pubDate>
      <guid>https://webcodr.io/2013/02/array-almighty/</guid>
      <description>Wenn man sich zu lange nur mit PHP beschäftigt vergisst man schnell, dass man oft Dinge tut, die kaum in andere Sprachen übertragbar sind.
Letztens habe ich mir Scala etwas näher angesehen. Kurz am Rande: eine schöne Sprache, wenn auch die verschiedenen Syntax-Modi etwas verwirrend oder zumindest recht gewöhnungsbedürftig sind.
Vorteil PHP Scala bietet wie fast jede andere typisierte Sprache verschiedene Listen-Klassen für diverse Nutzungsfälle. In PHP gibt es das nicht. Man hat sein Array, das jederzeit veränderlich ist, jede noch so wilde Mischung von Datentypen akzeptiert und assoziative Schlüssel erlaubt. Es ist einfach ungemein praktisch.
</description>
      <content:encoded><![CDATA[<p>Wenn man sich zu lange nur mit PHP beschäftigt vergisst man schnell, dass man oft Dinge tut, die kaum in andere Sprachen übertragbar sind.</p>
<p>Letztens habe ich mir Scala etwas näher angesehen. Kurz am Rande: eine schöne Sprache, wenn auch die verschiedenen Syntax-Modi etwas verwirrend oder zumindest recht gewöhnungsbedürftig sind.</p>
<h2 id="vorteil-php"><a href="#vorteil-php" class="heading-anchor">Vorteil PHP</a></h2>
<p>Scala bietet wie fast jede andere typisierte Sprache verschiedene Listen-Klassen für diverse Nutzungsfälle. In PHP gibt es das nicht. Man hat sein Array, das jederzeit veränderlich ist, jede noch so wilde Mischung von Datentypen akzeptiert und assoziative Schlüssel erlaubt. Es ist einfach ungemein praktisch.</p>
<h2 id="vorteil-scala"><a href="#vorteil-scala" class="heading-anchor">Vorteil Scala</a></h2>
<p>Da PHP leider weit davon entfernt ist vollständig objekt-orientiert zu sein und darum ein Array leider kein Objekt ist, kann man Arrays nur mit diversen Funktionen bearbeiten.</p>
<p>Zwar funktioniert das einwandfrei, ist aber umständlich. Ein Array-Objekt, das entsprechende Methoden bietet, die sich am besten auch noch verkettet aufrufen lassen, wäre doch toll.</p>
<h2 id="php-goes-scalajavaobjective-c"><a href="#php-goes-scalajavaobjective-c" class="heading-anchor">PHP goes Scala/Java/Objective-C</a></h2>
<p>Daher habe ich mich ans Werk gemacht und die bereits existierende Klasse <code>IterateableList</code> in MongoAppKit in drei neue Klassen des Namespaces <code>\MongoAppKit\Collection</code> aufgeteilt: <code>MutableMap</code> und <code>ArrayMap</code>.</p>
<p>Die Namen orientieren sich an ihren Pendants in Scala, Java oder auch Objective-C. Während alle die SPL-Interfaces <code>Countable</code> und <code>IteratorAggregate</code> implementieren, verwendet <code>ArrayMap</code> zusätzlich das Interface <code>ArrayAccess</code> und kann damit wie ein PHP-Array verwendet werden.</p>
<p>Außerdem implementieren alle drei die Magic Methods <code>__get()</code>, <code>__set()</code>, <code>__isset()</code> und <code>__unset</code>. Das erleichtert z.B. die Verwendung einer Liste in Twig, in dem keine Methode mehr angesprochen werden muss, um innerhalb eines Templates auf die Inhalte zuzugreifen.</p>
<p>Um diverse Array-Funktionen von PHP abzubilden implementieren alle drei die Methoden:</p>
<ul>
<li><code>first()</code>: gibt das erste Element der Liste zurück</li>
<li><code>last()</code>: gibt das letzte Element der Liste zurück</li>
<li><code>reverse()</code>: dreht die Reihenfolge der Elemente innerhalb der Liste um</li>
<li><code>each()</code>: wendet eine Callback-Funktion mittels <code>array_walk</code> auf alle Elemente an, in der auch auf die Schlüssel zugegriffen werden kann</li>
<li><code>map()</code>: wendet eine Callback-Funktion mittels <code>array_map</code> auf alle Elemente an</li>
<li><code>slice()</code>: schneidet einen Teil der Elemente heraus und gibt sie in einem neuen Listen-Objekt zurück</li>
<li><code>filter()</code>: filtert die Elemente einer Liste anhand einer Callback-Funktion und gibt das Ergebnis in einem neuen Listen-Objekt zurück</li>
</ul>
<h2 id="fluent-interface"><a href="#fluent-interface" class="heading-anchor">Fluent Interface</a></h2>
<p>Um eine Verkettung von Methodenaufrufen zu ermöglichen gibt jede Methode, die sonst keinen Rückgabewert hätte, eine Referenz auf ihre Klasse zurück. Nur <code>slice()</code> und <code>filter()</code> geben eine neue Liste mit den herausgeschnittenen bzw. gefilterten Werten zurück.</p>
<p>Hier ein kleines Beispiel aus CodrPress, was man damit alles anstellen kann:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Post</span><span class="o">::</span><span class="na">where</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">each</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="nv">$document</span><span class="p">)</span> <span class="k">use</span> <span class="p">(</span><span class="nv">$app</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$md</span> <span class="o">=</span> <span class="nv">$document</span><span class="o">-&gt;</span><span class="na">getProperty</span><span class="p">(</span><span class="s1">&#39;body&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$html</span> <span class="o">=</span> <span class="nv">$app</span><span class="p">[</span><span class="s1">&#39;markdown&#39;</span><span class="p">]</span><span class="o">-&gt;</span><span class="na">transform</span><span class="p">(</span><span class="nv">$md</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$document</span><span class="o">-&gt;</span><span class="na">set</span><span class="p">(</span><span class="s1">&#39;body_html&#39;</span><span class="p">,</span> <span class="nv">$html</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">save</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Die statische Methode <code>Post::where()</code> liefert ohne Query alle Posts als MutableMap-Objekt zurück. Auf die Rückgabe lässt sich sofort <code>each()</code> anwenden, das alle Elemente der Liste iteriert und die definierte Closure auf jedes Element einzeln anwendet.</p>
<p>In diesem Fall wird das rohe Markdown aus dem Feld <code>body</code> in HTML transformiert und im Feld <code>body_html</code> abgespeichert.</p>
<h2 id="fazit"><a href="#fazit" class="heading-anchor">Fazit</a></h2>
<p><code>MutableMap</code> und seine Sub-Klassen sparen viel Schreibarbeit durch ein simples und komfortables Fluent Interface &ndash; eine Vorgehensweise, der in PHP leider viel zu wenig Beachtung geschenkt wird.</p>
<h2 id="download"><a href="#download" class="heading-anchor">Download</a></h2>
<p>Die drei Klassen sind nicht länger Teil von MongoAppKit. Ich habe sie in ein separates <a href="https://github.com/WebCodr/Collection">GitHub-Repository</a> und <a href="https://packagist.org/packages/webcodr/collection">Composer-Paket</a> ausgelagert, um eine unkomplizierte Nutzung ohne MongoAppKit zu ermöglichen. Viel Spaß!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>CodrPress</title>
      <link>https://webcodr.io/2012/10/codrpress/</link>
      <pubDate>Sun, 21 Oct 2012 22:26:30 +0100</pubDate>
      <guid>https://webcodr.io/2012/10/codrpress/</guid>
      <description>Ich bin mal wieder so wahnsinnig und arbeite an einem Blog-System. Diesmal will ich das Rad aber nicht neu erfinden und ein zweites Wordpress bauen. Stattdessen orientiert sich CodrPress an Schnitzelpress.
Da Schnitzelpress auf Ruby basiert und primär für den Einsatz auf Heroku ausgelegt ist, habe ich mich dazu entschieden mit CodrPress quasi eine PHP-Version von Schnitzelpress zu entwickeln.
Natürlich ist das wieder mal einfacher gesagt als getan, vor allem da es für diverse Ruby Gems, die Schnitzelpress nutzt, in der PHP-Welt kaum brauchbaren Ersatz gibt.
</description>
      <content:encoded><![CDATA[<p>Ich bin mal wieder so wahnsinnig und arbeite an einem Blog-System. Diesmal will ich das Rad aber nicht neu erfinden und ein zweites Wordpress bauen. Stattdessen orientiert sich CodrPress an <a href="https://github.com/hmans/schnitzelpress">Schnitzelpress</a>.</p>
<p>Da Schnitzelpress auf Ruby basiert und primär für den Einsatz auf Heroku ausgelegt ist, habe ich mich dazu entschieden mit <a href="https://web.archive.org/web/20131210084517/https://github.com/MadCatme/CodrPress">CodrPress</a> quasi eine PHP-Version von Schnitzelpress zu entwickeln.</p>
<p>Natürlich ist das wieder mal einfacher gesagt als getan, vor allem da es für diverse Ruby Gems, die Schnitzelpress nutzt, in der PHP-Welt kaum brauchbaren Ersatz gibt.</p>
<p>Mit <a href="https://github.com/vmg/redcarpet">Redcarpet</a> und <a href="https://github.com/rubychan/coderay">CodeRay</a> hat Ruby zwei wundervolle Gems, die sich um Markdown-Rendering bzw. Syntax-Highlighting kümmern.</p>
<p>CodrPress basiert auf meinem Projekt <a href="https://web.archive.org/web/20131210082258/https://github.com/MadCatme/mongoappkit">MongoAppKit</a>, das wiederum auf <a href="https://github.com/silexphp/Silex">Silex</a> sowie <a href="https://twig.symfony.com/">Twig</a> setzt und seine Abhängigkeiten mit <a href="http://getcomposer.org/">Composer</a> regelt. Keine der PHP-basierten Lösungen, um diese zwei Ruby Gems zu ersetzen, bietet Composer-Unterstützung an und die Strukturen sind z.T. auch nicht <a href="/2012/06/php-autoloader-nach-dem-psr-0-standard/">PSR-0-kompatibel</a>, so dass ein Autoloading der Klassen nicht möglich ist.</p>
<p>Daher habe ich zwei neue Projekte aus der Taufe gehoben, die genau diesen Mangel beseitigen:</p>
<h3 id="silexmarkdown"><a href="#silexmarkdown" class="heading-anchor">SilexMarkdown</a></h3>
<p>Da ich keine Lust und Zeit habe, selbst einen Markdown-Renderer zu schreiben, basiert <a href="https://web.archive.org/web/20131210084926/https://github.com/MadCatme/SilexMarkdown">SilexMarkdown</a> auf <a href="https://github.com/michelf/php-markdown/">php-markdown</a> von Michel Fortin.</p>
<p>Ich musste es erstmal in eine brauchbare Struktur bringen, da das Original leider keine Namespaces nutzt und sogar zwei Klassen in einer Datei besitzt.</p>
<p>SilexMarkdown stellt nun eine Service-Provider-Klasse für Silex und eine entsprechende Twig-Extension zur Verfügung. Dazu wurde es noch mit einer Unterstützung für Code-Blöcke angereichert, um Syntax Highlighting wie in GitHub nutzen zu können.</p>
<h3 id="radiant"><a href="#radiant" class="heading-anchor">Radiant</a></h3>
<p>Die Kern-Komponente von <a href="https://web.archive.org/web/20131210083959/https://github.com/MadCatme/Radiant">Radiant</a> ist ebenfalls nicht auf meinem Mist gewachsen und stammt aus dem Projekt <a href="https://github.com/ccampbell/nijikodo">Nijikodo</a> von Clint Campbell.</p>
<p>Immerhin war die Grundlage schon mal PSR-0-kompatibel und damit auch relativ leicht Composer-tauglich zu machen.</p>
<p>Meine Arbeit bestand zum Großteil darin, entsprechende Unit-Tests zu schreiben und einige Fehler zu beseitigen und es in SilexMarkdown einzubinden.</p>
<h2 id="qualität"><a href="#qualit%c3%a4t" class="heading-anchor">Qualität</a></h2>
<p>Alle genannten Projekte, also MongoAppKit, SilexMarkdown, Radiant und CodrPress werden mittels <a href="https://github.com/sebastianbergmann/phpunit/">PHPUnit</a> laufend von mir und automatisiert via <a href="https://travis-ci.org/">Travis CI</a> getestet. Abgesehen von SilexMarkdown beträgt die Code-Coverage zwischen 70 - 90%.</p>
<h2 id="style"><a href="#style" class="heading-anchor">Style</a></h2>
<p>Aktuell ist CodrPress mit dem vollständigen <a href="https://getbootstrap.com/">Twitter Bootstrap</a> versehen, um auch in der Entwicklungsphase ein halbwegs ansehnliches Design zu haben. Später werde ich nur ein paar Komponenten aus Bootstrap nutzen, z.B. das Grid und die responsiven Fähigkeiten.</p>
<p>Für das Syntax-Highlighting habe ich ein Farb-Theme basierend auf meinem Farbschema von PhpStorm geschrieben, das auch Radiant beiliegt. Dank einer recht einfachen Struktur kann man sich auch sehr schnell ein eigenes Theme zusammenstellen.</p>
<h2 id="ausblick"><a href="#ausblick" class="heading-anchor">Ausblick</a></h2>
<p>Die Frontend-Funktionen von CodrPress sind mit einer gefüllten Datenbank (Schnitzelpress-kompatibel) schon nutzbar. Homepage, Einzeldarstellung von Einträgen, eigene Seiten und das Markdown-Rendering mit Syntax-Highlighting funktionieren soweit einwandfrei.</p>
<p>Als nächstes werde ich mich einem Admin-Bereich und anschließend einem ansprechenden Design widmen.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Responsive Bilder mit WordPress</title>
      <link>https://webcodr.io/2012/08/responsive-bilder-mit-wordpress/</link>
      <pubDate>Mon, 13 Aug 2012 22:23:38 +0100</pubDate>
      <guid>https://webcodr.io/2012/08/responsive-bilder-mit-wordpress/</guid>
      <description>Aktuell wage ich erste Gehversuche mit responsiven Layouts in meinem WordPress-Theme. Ziel der Übung ist ein smartphone-taugliches Layout. Leider macht einem WordPress die Arbeit bei Bildern unnötig schwer.
Automatische Bildskalierung mit CSS Bilder müssen in responsiven Layouts automatisch mit der Breite des Anzeigegeräts skalieren. Feste Breiten würden hier zwangsläufig zu Darstellungsproblemen führen. Das klingt nun komplizierter als es ist. Mit drei Zeilen CSS lassen sich Bilder abhängig von der Breite ihres Eltern-Elements automatisch skalieren.
</description>
      <content:encoded><![CDATA[<p>Aktuell wage ich erste Gehversuche mit responsiven Layouts in meinem <a href="https://web.archive.org/web/20131210084100/https://github.com/MadCatme/mcw-blue">WordPress-Theme</a>. Ziel der Übung ist ein smartphone-taugliches Layout. Leider macht einem WordPress die Arbeit bei Bildern unnötig schwer.</p>
<h2 id="automatische-bildskalierung-mit-css"><a href="#automatische-bildskalierung-mit-css" class="heading-anchor">Automatische Bildskalierung mit CSS</a></h2>
<p>Bilder müssen in responsiven Layouts automatisch mit der Breite des Anzeigegeräts skalieren. Feste Breiten würden hier zwangsläufig zu Darstellungsproblemen führen. Das klingt nun komplizierter als es ist. Mit drei Zeilen CSS lassen sich Bilder abhängig von der Breite ihres Eltern-Elements automatisch skalieren.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">img</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">max-width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Ein Bild darf also maximal so breit werden, wie seine vorgesehene Weite. Schrumpft das Eltern-Element durch Verkleinern des Viewports, wird das Bild automatisch mitskaliert. Wir müssen uns also um nichts weiter kümmern, da die Browser den Rest erledigen.</p>
<h2 id="problemfall-wordpress"><a href="#problemfall-wordpress" class="heading-anchor">Problemfall WordPress</a></h2>
<p>Leider klappt die automatische Skalierung in WordPress nicht. Wenn man in einem Beitrag Bilder einfügt, setzt WordPress automatisch das <code>width</code>- bzw. <code>height</code>-Attribut auf das <code>img</code>-Element. Sobald auch nur eines von beiden gesetzt ist, wird eine automatische Größenanpassung verhindert. Die Attribute müssen also weg.</p>
<p>Wie immer, gibt es dafür zig verschiedene Möglichkeiten. Beispielsweise könnte man die überflüssigen Element-Eigenschaften per jQuery-Einzeiler entfernen. Wirklich schön ist das aber nicht. Es wäre doch viel besser, wenn man WordPress dazu bringen könnte, den Quelltext gleich ohne <code>width</code> und <code>height</code> auszuliefern.</p>
<p>Dank des Hook-Systems in WordPress geht das mit ein paar Zeilen Code in der Datei <code>functions.php</code> des Themes:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="nx">add_filter</span><span class="p">(</span><span class="s1">&#39;the_content&#39;</span><span class="p">,</span> <span class="s1">&#39;removeImageDimensions&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">removeImageDimensions</span><span class="p">(</span><span class="nv">$html</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">preg_replace</span><span class="p">(</span><span class="s1">&#39;/(width|height)=\&#34;\d*\&#34;\s/&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nv">$html</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Die Funktion <code>removeImageDimensions()</code> entfernt per regulärem Ausdruck unsere unerwünschten Gäste <code>width</code> und <code>height</code>. Mittels <code>add_filter()</code> wird der WordPress-Funktion <code>the_content()</code> (gibt den Inhalt eines Beitrags aus) unsere neue Funktion als Ausgabefilter zugewiesen. WordPress führt nun bei jedem Aufruf von <code>the_content()</code> unsere neue Funktion <code>removeImageDimensions()</code> aus, die den Rückgabewert von <code>the_content()</code> entsprechend verändert.</p>
<p>Damit steht responsiven Bildbreiten nun nichts mehr im Weg.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>PHP-Autoloader nach dem PSR-0-Standard</title>
      <link>https://webcodr.io/2012/06/php-autoloader-nach-dem-psr-0-standard/</link>
      <pubDate>Sun, 17 Jun 2012 22:20:12 +0100</pubDate>
      <guid>https://webcodr.io/2012/06/php-autoloader-nach-dem-psr-0-standard/</guid>
      <description>Wenn’s um das Schreiben eines Autoloaders in PHP geht, kochen viele Entwickler gern ihr eigenes Süppchen. Sofern nun mehrere gleichzeitig aktiv sind, kann das zu Problemen führen und ggf. sogar dafür sorgen, dass eine Alternative gesucht werden muss.
Die PHP Framework Interoperability Group (kurz FIG) hat sich dieses Problems angenommen und eine Spezifikation für Autoloader entwickelt, die Interoperabilität sicherstellt.
Der PSR-0-Standard besteht aus ein paar recht simplen Regeln, die sich sehr einfach umsetzen lassen und z.T. sicher schon von vielen genutzt wurden:
</description>
      <content:encoded><![CDATA[<p>Wenn&rsquo;s um das Schreiben eines Autoloaders in PHP geht, kochen viele Entwickler gern ihr eigenes Süppchen. Sofern nun mehrere gleichzeitig aktiv sind, kann das zu Problemen führen und ggf. sogar dafür sorgen, dass eine Alternative gesucht werden muss.</p>
<p>Die <a href="https://github.com/php-fig/fig-standards">PHP Framework Interoperability Group</a> (kurz FIG) hat sich dieses Problems angenommen und eine Spezifikation für Autoloader entwickelt, die Interoperabilität sicherstellt.</p>
<p>Der <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md">PSR-0-Standard</a> besteht aus ein paar recht simplen Regeln, die sich sehr einfach umsetzen lassen und z.T. sicher schon von vielen genutzt wurden:</p>
<ul>
<li>Ein qualifizierter Namespace hat folgende Struktur <code>\&lt;Vendor Name&gt;\(&lt;Namespace&gt;\)*&lt;Class Name&gt;</code></li>
<li>Jeder Namespace hat einen Haupt-Namespace (Vendor Name)</li>
<li>Jeder Namespace kann beliebig viele Unter-Namespaces besitzen</li>
<li>Jeder Namespace-Separator wird in einen <code>DIRECTORY_SEPARATOR</code> konvertiert, wenn aus dem Dateisystem geladen wird</li>
<li>Das Zeichen &ldquo;_&rdquo; (Underscore) wird in einen <code>DIRECTORY_SEPARATOR</code> konvertiert und hat keine spezielle Bedeutung.</li>
<li>Der qualifizierte Namespace inkl. Klasse bekommt die Endung &ldquo;.php&rdquo; angehängt, um die Datei zu laden.</li>
<li>Namespaces, Vendor Names und Klassennamen dürfen alphabetische Zeichen in jeder Kombination aus Groß- und Kleinschreibung enthalten.</li>
</ul>
<h2 id="beispiel-implementation"><a href="#beispiel-implementation" class="heading-anchor">Beispiel-Implementation</a></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nx">WebCodr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Loader</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">registerAutoloader</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">spl_autoload_register</span><span class="p">(</span><span class="k">array</span> <span class="p">(</span><span class="s1">&#39;WebCodr\\Loader&#39;</span><span class="p">,</span> <span class="s1">&#39;load&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">load</span><span class="p">(</span><span class="nv">$class</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="nx">substr</span><span class="p">(</span><span class="nv">$class</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span> <span class="o">!==</span> <span class="s1">&#39;WebCodr&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nv">$libraryRoot</span> <span class="o">=</span> <span class="nx">realpath</span><span class="p">(</span><span class="no">__DIR__</span> <span class="o">.</span> <span class="s1">&#39;/../&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$classFileName</span> <span class="o">=</span> <span class="nx">str_replace</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="s1">&#39;\\&#39;</span><span class="p">,</span> <span class="s1">&#39;_&#39;</span><span class="p">),</span> <span class="nx">DIRECTORY_SEPARATOR</span><span class="p">,</span> <span class="nv">$class</span><span class="p">)</span> <span class="o">.</span> <span class="s1">&#39;.php&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$fileName</span> <span class="o">=</span> <span class="nx">realpath</span><span class="p">(</span><span class="nv">$libraryRoot</span> <span class="o">.</span> <span class="nx">DIRECTORY_SEPARATOR</span> <span class="o">.</span> <span class="nv">$classFileName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="nx">is_readable</span><span class="p">(</span><span class="nv">$fileName</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">include_once</span><span class="p">(</span><span class="nv">$fileName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Die Klasse stellt zwei statische Methoden bereit. Mit <code>Loader::registerAutoloader()</code> wird die Methode <code>Loader::load()</code> als SPL-Autoloader registriert.</p>
<p><code>Loader::load()</code> prüft zuerst, ob sich die angeforderte Klasse überhaupt im Namespace WebCodr befindet. Falls dies nicht der Fall ist, wird durch den leeren Rückgabewert signalisiert, dass die Klasse mit diesem Autoloader nicht geladen werden kann und die SPL geht zum nächsten registrierten Autoloader über.</p>
<p>Anschließend wird der Pfad zur Klasse zusammengesetzt und die Datei mittels <code>include_once()</code> eingebunden. Optional könnte man im Fehlerfall natürlich noch eine Exception werfen.</p>
<h2 id="aufruf-des-autoloaders"><a href="#aufruf-des-autoloaders" class="heading-anchor">Aufruf des Autoloaders</a></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">include_once</span><span class="p">(</span><span class="s1">&#39;Loader.php&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">\WebCodr\Loader</span><span class="o">::</span><span class="na">registerAutoloader</span><span class="p">();</span>
</span></span></code></pre></div><h2 id="fazit"><a href="#fazit" class="heading-anchor">Fazit</a></h2>
<p>PSR-0 ist schnell und einfach implementiert. Für neue Projekte gibt es also keinen Grund, sich nicht daran zu halten. In bestehendem Code könnte es recht aufwendig sein, den Standard umzusetzen &ndash; je nachdem, welche Benamungsschemata und Verzeichnisstrukturen bereits verwendet werden.</p>
<p>Man sollte den Aufwand aber nicht scheuen. Was bringt einem schon die tollste Library oder ein cooles Framework, wenn es aufgrund eines schlecht implementierten Autoloaders, kaum eingesetzt werden kann?</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>PHP-Tip: Limonade</title>
      <link>https://webcodr.io/2012/04/php-tip-limonade/</link>
      <pubDate>Wed, 11 Apr 2012 22:17:38 +0100</pubDate>
      <guid>https://webcodr.io/2012/04/php-tip-limonade/</guid>
      <description>Wer sich schon mal mit Symfony oder ähnlichen PHP-Frameworks beschäftigt hat, kam sicher schnell zur Erkenntnis, dass die Dinger zwar viel können und generell eine tolle Sache sind, aber hohe Einstiegshürden haben bzw. viel Einarbeitungszeit benötigen, sowie für viele Projekte einfach überdimensioniert sind.
In Ruby hätte man für solche Fälle z.B. Sinatra: übersichtlich, klein, schnell und flexibel. Mit Limonade gibt es so ein Micro-Framework nun endlich für PHP, mit dem sich auch ähnlich elegant entwickeln lässt.
</description>
      <content:encoded><![CDATA[<p>Wer sich schon mal mit <a href="http://symfony.com/">Symfony</a> oder ähnlichen PHP-Frameworks beschäftigt hat, kam sicher schnell zur Erkenntnis, dass die Dinger zwar viel können und generell eine tolle Sache sind, aber hohe Einstiegshürden haben bzw. viel Einarbeitungszeit benötigen, sowie für viele Projekte einfach überdimensioniert sind.</p>
<p>In Ruby hätte man für solche Fälle z.B. <a href="http://www.sinatrarb.com/">Sinatra</a>: übersichtlich, klein, schnell und flexibel. Mit <a href="https://limonade-php.github.io/">Limonade</a> gibt es so ein Micro-Framework nun endlich für PHP, mit dem sich auch ähnlich elegant entwickeln lässt.</p>
<p>Es reicht eine Datei in ein Script einzubinden, die .htaccess-Datei anzupassen und schon kann man loslegen:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">require_once</span> <span class="s1">&#39;vendors/limonade.php&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// lambda function (&gt;= PHP 5.3)
</span></span></span><span class="line"><span class="cl"><span class="nx">dispatch</span><span class="p">(</span><span class="s1">&#39;/hello/:name&#39;</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$name</span> <span class="o">=</span> <span class="nx">params</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;Hello, </span><span class="si">{</span><span class="nv">$name</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">run</span><span class="p">();</span>
</span></span></code></pre></div><p>Das war es schon. Den ganzen Rest erledigt Limonade und das war noch lange nicht alles, was es kann. Die Routen-Definitionen können beispielsweise auch Wildcards oder reguläre Ausdrücke enthalten. Als Callback lassen sich selbstverständlich auch Objekte bzw. deren Methoden aufrufen (auch statisch) oder man gibt in klassischer Manier einen Funktionsnamen als String an.</p>
<p>Dazu gibt es eine Template Engine mit partiellen Templates, Capture-Möglichkeiten, JSON-Unterstützung, Hooks und Filtern.</p>
<p>Alles davon lässt sich ohne große Einarbeitung sofort nutzen. Natürlich muss man die integrierte Template Engine nicht nutzen und kann auch stattdessen einfach Twig oder Smarty verwenden.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Upload-Probleme mit PHP via FastCGI</title>
      <link>https://webcodr.io/2012/04/upload-probleme-mit-php-via-fastcgi/</link>
      <pubDate>Thu, 05 Apr 2012 22:15:00 +0100</pubDate>
      <guid>https://webcodr.io/2012/04/upload-probleme-mit-php-via-fastcgi/</guid>
      <description>Als ich eben eine neue Galerie in mein privates Weblog hochladen wollte, begrüßte mich bei jedem Versuch ein HTTP 500, besser bekannt als Internal Server Error. Die Meldung ist absolut nichtssagend und es lässt sich nur über Log-Dateien rausfinden, was eigentlich passiert.
Das Problem besteht offenbar seit dem Umzug auf einen virtuellen Server bei Host Europe mit Ubuntu 10.04 LTS und Plesk zur Verwaltung. In Plesk wird PHP standardmäßig via mod_php in den Apache eingebunden. Da das aber u.U. Rechteprobleme zwischen dem Apache-User und dem FTP-User bei von PHP angelegten Dateien geben kann, lasse ich PHP via FastCGI laufen. Das braucht zwar mehr RAM, hat aber den Vorteil, dass der PHP-Prozess und FTP-Zugang über den gleichen Nutzer laufen. Im Gegensatz zu suPHP funktionieren damit auch Opcode Caches wie APC und es muss nicht für jede Anfrage auf ein Script ein neuer PHP-Prozess gestartet werden.
</description>
      <content:encoded><![CDATA[<p>Als ich eben eine neue Galerie in mein privates Weblog hochladen wollte, begrüßte mich bei jedem Versuch ein HTTP 500, besser bekannt als Internal Server Error. Die Meldung ist absolut nichtssagend und es lässt sich nur über Log-Dateien rausfinden, was eigentlich passiert.</p>
<p>Das Problem besteht offenbar seit dem Umzug auf einen virtuellen Server bei <a href="http://www.hosteurope.de/">Host Europe</a> mit Ubuntu 10.04 LTS und Plesk zur Verwaltung. In Plesk wird PHP standardmäßig via mod_php in den Apache eingebunden. Da das aber u.U. Rechteprobleme zwischen dem Apache-User und dem FTP-User bei von PHP angelegten Dateien geben kann, lasse ich PHP via FastCGI laufen. Das braucht zwar mehr RAM, hat aber den Vorteil, dass der PHP-Prozess und FTP-Zugang über den gleichen Nutzer laufen. Im Gegensatz zu suPHP funktionieren damit auch Opcode Caches wie APC und es muss nicht für jede Anfrage auf ein Script ein neuer PHP-Prozess gestartet werden.</p>
<p>Nach etwas Recherche, war die Ursache aber schnell klar. Um mit FastCGI arbeiten zu können, verwendet der Apache das Modul mod_fcgid, das folgenden Fehler auslöst:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">mod_fcgid: HTTP request length 1019250 (so far) exceeds MaxRequestLen
</span></span><span class="line"><span class="cl">(131072)
</span></span></code></pre></div><p>Sprich: sämtliche HTTP-Anfragen, deren Länge mehr als 128 KB beträgt, werden durch FastCGI nicht zugelassen. Wie man sieht, war der Request knapp 1 MB groß, was bei größeren Bildern in ordentlicher Qualität schnell passiert.</p>
<p>Um das Limit zu erhöhen, muss man in die Modul-Konfiguration unter /etc/apache2/mods-available/fcgid.conf eingreifen und folgenden Eintrag hinzufügen bzw. entsprechend verändern:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">MaxRequestLen 2097152
</span></span></code></pre></div><p>Damit wird die Beschränkung auf 2 MB erhöht. Sollte für die meisten Zwecke mehr als ausreichen. Anschließend muss der Apache neu gestartet werden, damit die Änderung wirksam wird.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
