<?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>No nix narrets! &#187; Webtechnik</title>
	<atom:link href="http://neunzehn83.de/blog/category/webtechnik/feed/" rel="self" type="application/rss+xml" />
	<link>http://neunzehn83.de/blog</link>
	<description>Ein Mann, ein Blog, kein Plan!</description>
	<lastBuildDate>Sun, 29 Jan 2012 21:19:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Froxlor Bug: maximale Länge von ServerAlias (Apache)</title>
		<link>http://neunzehn83.de/blog/2012/01/08/froxlor-bug-maximale-lange-von-serveralias-apache/</link>
		<comments>http://neunzehn83.de/blog/2012/01/08/froxlor-bug-maximale-lange-von-serveralias-apache/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 21:39:56 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=1002</guid>
		<description><![CDATA[SysCP bzw. dessen Nachfolger Froxlor kümmert sich hier auf diesem Server um das Erstellen diverser Konfigurationsdateien sowie um die Verwaltung der virtuellen User für E-Mail- und FTP-Zugänge. Schon vor einiger Zeit habe ich festgestellt, dass bei Verwendung vieler Alias-Domains die erzeugte Apache-Konfiguration fehlerhaft sein kann. Dann nämlich, wenn die ServerAlias-Direktive mehr als 8000 Zeichen hat. [...]]]></description>
			<content:encoded><![CDATA[<p>SysCP bzw. dessen Nachfolger <a href="http://www.froxlor.org/">Froxlor</a> kümmert sich hier auf diesem Server um das Erstellen diverser Konfigurationsdateien sowie um die Verwaltung der virtuellen User für E-Mail- und FTP-Zugänge.</p>

<p>Schon vor einiger Zeit habe ich festgestellt, dass bei Verwendung vieler Alias-Domains die erzeugte Apache-Konfiguration fehlerhaft sein kann. Dann nämlich, wenn die ServerAlias-Direktive mehr als 8000 Zeichen hat. Scheinbar hat noch keiner zuvor so viele Alias-Domains einer Hauptdomain hinzugefügt. 8000 Zeichen hört sich auch viel an, doch wenn pro Domain jeweils noch die www-Subdomain hinzukommt, reichen bereits ca. 150 Domains um dieses Limit zu erreichen.</p>

<p>Der Apache vHost-Container unterstützt mehrere ServerAlias-Direktiven, so dass bevor die 8000 Zeichen erreicht werden einfach ein neuer ServerAlias-Eintrag erzeugt werden sollte. Die Datei <code>cron_tasks.inc.http.10.apache.php</code> in <code>scripts/jobs</code> ist für das Erstellen der Apache-Konfigurationsdateien verantwortlich und mit wenigen Zeilen auf dieses Verhalten anpassbar (<a href="http://neunzehn83.de/blog/wp-content/uploads/2012/01/ServerAlias.patch">Patch</a>).</p>

<p>Da ich nicht nach jedem Update daran denken möchte, diese Änderung einzuspielen, habe ich bei Froxlor mal ein <a href="http://redmine.froxlor.org/issues/1012">Ticket erstellt</a> und diesen Patch angehängt. Vielleicht schafft er es ja in die 0.9.27 :)</p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2012/01/08/froxlor-bug-maximale-lange-von-serveralias-apache/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP und Y2K38: Werden wir alle sterben?</title>
		<link>http://neunzehn83.de/blog/2011/12/22/php-und-y2k38-werden-wir-alle-sterben/</link>
		<comments>http://neunzehn83.de/blog/2011/12/22/php-und-y2k38-werden-wir-alle-sterben/#comments</comments>
		<pubDate>Thu, 22 Dec 2011 07:58:43 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=527</guid>
		<description><![CDATA[Der 19. Januar 2038 3:14:07 Uhr ist ein besonderer Zeitpunkt. Dann sind nämlich genau 2147483647 Sekunden seit dem 1. Januar 1970 vergangen. PHPs date()-Funktion arbeitet genau auf dieser Grundlage &#8211; auch bekannt als der UNIX-Timestamp. Der Unix-Timestamp ist in PHP sehr populär. Funktionen wie date() oder strtotime() arbeiten mit UNIX Timestamps. Das ist auf den [...]]]></description>
			<content:encoded><![CDATA[<p>Der 19. Januar 2038 3:14:07 Uhr ist ein besonderer Zeitpunkt. Dann sind nämlich genau 2147483647 Sekunden seit dem 1. Januar 1970 vergangen. PHPs <code>date()</code>-Funktion arbeitet genau auf dieser Grundlage &#8211; auch bekannt als der UNIX-Timestamp.</p>

<p>Der Unix-Timestamp ist in PHP sehr populär. Funktionen wie <code>date()</code> oder <code>strtotime()</code> arbeiten mit UNIX Timestamps. Das ist auf den ersten Blick auch unheimlich praktisch, weil sich damit relativ platzsparend Daten (<em>Plural von Datum</em>) speichern lassen. Außerdem lässt es sich mit einem Timestamp leicht rechnen.</p>

<p>Ein PHP signed Integer auf 32bit-Systemen kann Werte zwischen -2147483648 und 2147483647 annehmen. Am 19. Januar 2038 3:14:08 läuft der Int also über und es ist plötzlich der 13. Dezember 1901 20:45:52 Uhr (Freitag der 13.!).</p>

<p>Folgendes Beispiel zeigt das Verhalten auf 32bit-Systemen. Mit einem 64bit-System und 64bit PHP kann PHPs unsinged Int Werte bis 9223372036854775807 annehmen. Dort stellt sich die Y2K38-Frage also garnicht. Hier stellt sich dann die <strong>Jahr 292471210689-Frage</strong> &#8211; aber bis dahin sind 64bit Systeme genau so ausgestorben, wie es 2038 die 32bit-Systeme sein werden.</p>

<pre><code>var_export(strtotime("20 jan 2038")); // false :(
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/12/22/php-und-y2k38-werden-wir-alle-sterben/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP CLI Fortschrittsbalken</title>
		<link>http://neunzehn83.de/blog/2011/12/18/php-cli-fortschrittsbalken/</link>
		<comments>http://neunzehn83.de/blog/2011/12/18/php-cli-fortschrittsbalken/#comments</comments>
		<pubDate>Sun, 18 Dec 2011 07:22:49 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=928</guid>
		<description><![CDATA[Hin und wieder führt man PHP-Skripte direkt auf der Kommandozeile (CLI) aus. Das hat den Vorteil, dass man nicht den Umweg über den Webserver gehen muss, wenn man ihn garnicht braucht. Außerdem lässt sich das Skript leicht mit STRG+C abbrechen, den Webserver hingegen müsste man bei einer Endlosschleife neu starten. Der aktuelle Fortschritt lässt sich [...]]]></description>
			<content:encoded><![CDATA[<p>Hin und wieder führt man PHP-Skripte direkt auf der Kommandozeile (CLI) aus. Das hat den Vorteil, dass man nicht den Umweg über den Webserver gehen muss, wenn man ihn garnicht braucht. Außerdem lässt sich das Skript leicht mit STRG+C abbrechen, den Webserver hingegen müsste man bei einer Endlosschleife neu starten.</p>

<p>Der aktuelle Fortschritt lässt sich auch ganz einfach mit echo ausgeben &#8211; kein (ob_)flush notwendig.</p>

<p>Wenn man mit echo einen Carriage Return (<code>"\r"</code>) ausgibt, wird der Cursor auf den Anfang der Zeile zurückgestellt und man kann eine bereits ausgegebene Zeile überschreiben. Perfekt also für einen Fortschrittsbalken!</p>

<pre><code>$total = 10;
$bar_length = 20;
$spinner = '-\\|/';
for ($i = 1; $i &lt;= $total; $i++) {
    usleep(1000000);

    $spin = $spinner[$i%strlen($spinner)];    
    $cur = sprintf('%'.strlen($total).'.d', $i);
    $percent = $i/$total*100;

    $progress_len = floor($bar_length * $percent / 100);
    $progress = str_repeat('=', $progress_len);
    if ($progress_len &lt; $bar_length) {
        $progress .= '&gt;';
        $progress .= str_repeat('-', $bar_length-$progress_len-1);
    }

    echo " $cur/$total $spin [$progress] $percent%\r";
}
</code></pre>

<p><a href="http://neunzehn83.de/blog/wp-content/uploads/2011/12/php-cli-progress.gif"><img src="http://neunzehn83.de/blog/wp-content/uploads/2011/12/php-cli-progress.gif" alt="" title="php-cli-progress" width="301" height="69" class="alignnone size-full wp-image-960" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/12/18/php-cli-fortschrittsbalken/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP-Security! Heute: path traversal</title>
		<link>http://neunzehn83.de/blog/2011/06/26/php-security-heute-path-traversal/</link>
		<comments>http://neunzehn83.de/blog/2011/06/26/php-security-heute-path-traversal/#comments</comments>
		<pubDate>Sun, 26 Jun 2011 15:21:13 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=884</guid>
		<description><![CDATA[Path traversal bzw. directory traversal ist eine Methode, um aus vorgesehenen Verzeichnissen auszubrechen. In Bezug auf PHP findet diese Sicherheitslücke  Anwendung, da Dateien oftmals anhand des Querystrings eingebunden werden. Beispiel: http://example.org/index.php?site=impressum.php &#60;?php include './includes/sites/' . $_GET['site']; ?&#62; Das ist natürlich fatal. Mittels ../ in $_GET['site'] kann man das vorgegebene Verzeichnis verlassen und je nach Rechten [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-888" title="php-security" src="http://neunzehn83.de/blog/wp-content/uploads/2011/06/php-security.jpg" alt="" width="600" height="200" /></p>

<p>Path traversal bzw. directory traversal ist eine Methode, um aus vorgesehenen Verzeichnissen auszubrechen. In Bezug auf PHP findet diese Sicherheitslücke  Anwendung, da Dateien oftmals anhand des Querystrings eingebunden werden. Beispiel:
<pre>http://example.org/index.php?site=impressum.php</pre>
<pre>&lt;?php
    include './includes/sites/' . $_GET['site'];
?&gt;</pre>
Das ist natürlich fatal. Mittels <code>../</code> in $_GET['site'] kann man das vorgegebene Verzeichnis verlassen und je nach Rechten auch sicherheitsrelevante Dateien ausgeben lassen. Denn: wird eine nicht-PHP-Datei mittels include eingebunden wird deren Inhalt 1:1 an den Browser gesendet.</p>

<p>Oftmals wird das Ausbrechen aus einem Verzeichnis dadurch versucht zu verhindern, indem &#8216;../&#8217; aus $_GET['site'] entfernt wird.
<pre>$save = str_replace('../', '', $_GET['site']);</pre>
Auch ganz schlecht: Aus einem <code>....//</code> würde <code>../</code>, da str_replace bereits ersetzte Teile nicht nochmals ersetzt. Außerdem kommen durch URL-Encoding und unterschiedliche Directory-Separator (Linux/Windows) noch weitere Zeichen in Frage, die es erlauben aus einem Verzeichnis auszubrechen.</p>

<p>Sehr verbreitet ist auch die Dateiendung vorzugeben:
<pre>include './includes/sites/' . $_GET['site'] . '.php';</pre>
Je nach Betriebssystem ist hier mit einem NULL-Byte (Url-Encoded: %00) die vorzeitige Terminierung des Strings möglich:
<pre>http://example.org/index.php?site=../../../../../../../etc/passwd%00</pre>
Hier muss man übrigens nicht die exakte Anzahl der nach oben zu gehenden Verzeichnisse wissen &#8211; ist man im Root-Verzeichnis angelangt, können beliebige <code>../</code> ohne Auswirkungen folgen.</p>

<p>Mit aktiviertem allow_url_fopen gibt es noch weitere Zeichen zu prüfen &#8211; das ist dann aber kein path traversal mehr und somit nicht bestandteil dieses Blog-Beitrages.</p>

<h2>Was tun?</h2>

<p>Statt str_replace sollte man besser preg_replace mit einem Pattern wie <code>#&#92;.+[/&#92;]+#</code> verwenden. Noch besser ist es natürlich von vorne herein eine Whitelist zu führen &#8211; also ein Array mit erlaubten Dateinamen und dann prüfen, ob $_GET['site'] in diesem Array vorkommt. Eine weitere Methode ist, den kanonischen, absoluten Pfad mittels realpath() zu erzeugen und dann den Beginn dieses Pfades mit dem Document-Root (bzw. dem erlaubten Verzeichnis) abzugleichen.</p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/06/26/php-security-heute-path-traversal/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Variablen tauschen ohne Hilfsvariable?</title>
		<link>http://neunzehn83.de/blog/2011/06/24/variablen-tauschen-ohne-hilfsvariable/</link>
		<comments>http://neunzehn83.de/blog/2011/06/24/variablen-tauschen-ohne-hilfsvariable/#comments</comments>
		<pubDate>Fri, 24 Jun 2011 20:28:29 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=899</guid>
		<description><![CDATA[Pah! list($a, $b) = array($b, $a);]]></description>
			<content:encoded><![CDATA[<p>Pah!
<pre>list($a, $b) = array($b, $a);</pre></p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/06/24/variablen-tauschen-ohne-hilfsvariable/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Über Primary-Keys in URLs .. und sonstwo</title>
		<link>http://neunzehn83.de/blog/2011/06/19/uber-primary-keys-in-urls-und-sonstwo/</link>
		<comments>http://neunzehn83.de/blog/2011/06/19/uber-primary-keys-in-urls-und-sonstwo/#comments</comments>
		<pubDate>Sun, 19 Jun 2011 13:58:02 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>
		<category><![CDATA[»Featured]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=576</guid>
		<description><![CDATA[Ein Primary-Key identifiziert eindeutig ein Tupel (Zeile/Reihe/Row) in einer relationalen Datenbank. Im trivialen Fall ist das eine Integer-Spalte mit auto_increment &#8211; wenn wir von MySQL reden, wie so oft hier. Eine fortlaufende Nummer also. Diese Nummer wird in Webanwendungen oft direkt an den User weitergegeben. Zum Beispiel als Teil der URL oder als Datensatznummer (z.B. [...]]]></description>
			<content:encoded><![CDATA[<p>Ein Primary-Key identifiziert eindeutig ein Tupel (Zeile/Reihe/Row) in einer relationalen Datenbank. Im trivialen Fall ist das eine Integer-Spalte mit <em>auto_increment</em> &#8211; wenn wir von MySQL reden, wie so oft hier. Eine fortlaufende Nummer also. Diese Nummer wird in Webanwendungen oft direkt an den User weitergegeben. Zum Beispiel als Teil der URL oder als Datensatznummer (z.B. Bestellnummer in einem Online-Shop).</p>

<h2>Beispiele</h2>

<h3>1. Online-Shop: $kunde erhält seine Bestellbestätigung per E-Mai mit der Bestellnummer 27.</h3>

<p style="padding-left: 30px;">Das wäre mir (als Shop-Betreiber) ein Dorn im Auge, da es Rückschlüsse auf die Anzahl der bisherigen Bestellungen zulässt. Das lässt sich noch relativ leicht beheben, indem man die auto_increment-Spalte nicht bei 1 sondern bei einer höheren Zahl beginnen lässt (<em>ALTER TABLE tbl AUTO_INCREMENT = 1000;</em>). Doch was, wenn der Kunde zwei Wochen später erneut bestellt, und eine nur wenig höhere Bestellnummer erhält? Dies lässt wiederum Rückschlüsse auf die Häufigkeit von Bestellungen im Shop zu. Daran ändert auch der Beginn bei höheren Zahlen nichts.</p>

<h3>2. URL: http://domain.com/user/123</h3>

<p style="padding-left: 30px;">Wir nehmen an, hinter dieser URL verbirgt sich ein öffentliches Benutzerprofil. Auch hier selbes Problem wie oben (Aussage über Quantität). Zudem kann man hier, aufgrund der fortlaufenden Nummer, die &#8220;Umgebung erkunden&#8221;, andere Benutzerprofile erraten oder per Script sämtliche Userprofile crawlen (for i=1; i&lt;999;i++). Hier bräuchte man also im Idealfall eine zufällig fortlaufende Zahlen/Nummernkombination, mit genügend &#8220;Lücken&#8221; um das direkte erraten anderer Profile zu <span style="text-decoration: line-through;">verhindern</span> erschweren. Dennoch sollte die User-ID natürlich so kurz wie möglich sein.</p>

<p>Das dürfte ja alles soweit bekannt sein. In den meisten Szenarien spielt das auch überhaupt keine Rolle. In einem Blog oder Forum z.B. dürfen die Post-IDs gerne den Primary-Keys entsprechen. Was aber, wenn der paranoide Webmaster Rückschlüsse nicht (oder sagen wir besser: nur erschwert) zulassen will?</p>

<h2>Anforderungen an eine ID-Verschleierung</h2>

<ul>
<li>wenig Overhead (nicht länger als nötig)</li>
<li>leicht reversibel (ohne Datenbankabfrage, ohne Speicherung der verschleierten ID in extra DB-Spalte)</li>
<li>Erhöhung des PK um 1 soll große Änderung der verschleierten ID bewirken</li>
<li>kollisionsfrei, zu 100%</li>
<li>optional: Spielraum/Lücken um das Erraten von weiteren IDs zu erschweren</li>
</ul>

<h2>Mögliche Lösungen zum Verbergen der ID</h2>

<h3>GUID</h3>

<p><a href="http://de.wikipedia.org/wiki/Globally_Unique_Identifier">GUID</a>s haben mit Sicherheit Ihre Daseinsberechtigung. In den meisten Fällen sind sie aber einfach nur des Guten zu viel. Von der Performance auf Datenbankseite möchte ich jetzt gar nicht reden. Auch nicht über die Tatsache, dass GUID in URLs schrecklich aussehen. Das Ziel muss sein, so wenig wie möglich Overhead zu erzeugen. GUID: no-go!</p>

<h3>Hashen des PKs</h3>

<p>Ein Hash resultiert immer in einem String mit fester Länge. Selbst bei sehr kleinen Primary-Keys, wäre der Hash immer gleich lang. Welch&#8217; Verschwendung! Außerdem sind Hashs nicht kollisionsfrei*, und sie lassen sich auch nicht zurückrechnen. D.h. man müsste den Hash zusätzlich zum Primary-Key speichern (noch mehr Overhead).</p>

<p>[* zugegeben, in diesem Ganzzahlbereich um den es hier geht wohl schon]</p>

<h3>Basis</h3>

<p>Man kann den Primary-Key einfach in einer anderen Basis darstellen, Base32 od. 64 zum Beispiel. Wenn man darauf besteht, dass die ID nach wie vor aus Zahlen bestehen soll, hat man Pech. Auch doof ist, dass eine Erhöhung des PK um 1 nur eine sehr kleine Änderung der verschleierten ID bewirkt. Beispiel: 12345(base10) = C1P (base32), 12346(base10) = C1Q(base32)).</p>

<h3>Random-ID</h3>

<p>Die Idee dahinter ist, im Vorfeld einen Pool an Random-IDs zu erzeugen (in einer extra DB-Tabelle). Ein UNIQUE-Key verhindert Duplikate. Beim Anlegen eines neuen Datensatzes, wird aus der Kandidaten-Tabelle dann eine Zufallszahl geholt und mit dem PK verknüpft. Das Ganze geht auch ohne vorheriges Erstellen der Kandidaten-Tabelle. Endlos-Schleife und race conditions nicht ausgeschlossen.</p>

<h3>ID Verschleiern</h3>

<p>Alles &#8220;Bekannte&#8221; scheint hier nicht zum Erfolg zu führen. Es gibt unendlich viele Methoden, durch logische Verknüpfung (<a href="http://de.wikipedia.org/wiki/Kontravalenz">XOR</a> in erster Linie) und sonstige mathematische Funktionen, Zahlen zu verschleiern. Eine einfache, auf diese Problematik passende, möchte ich hier vorstellen.</p>

<p>Man nehme <strong>einmalig</strong> eine zufällige Zahl (&#8220;secret&#8221;), die mindestens so groß ist, wie die höchste Primary ID. Der längste PK kann, wenn wir ein MySQL SMALLINT unsigned annehmen, max. 65535 sein. Unsere Zufallszahl: 99565. Diese Zahl ist systemweit immer gleich &#8211; wird also für alle späteren Ver- und Entschleierungen verwendet.</p>

<p>Das eigentliche Prozedere ist einfach: Die binäre Präsentation des PK wird umgekehrt und mit der Zufallszahl mit XOR verknüpft. Von der Zufallszahl verwenden wir nur so viele binäre Stellen, wie unser PK hat. Da durch das Umkehren und XORen führende Nullen entstehen können, stellen wir immer eine binäre 1 dem  umgekehrten Binärstring voran &#8211; sonst kommt es zu Kollisionen. Beispiel:
    PK 12      =  1100
    Flip +1    = 10011
    99565      = _1100[0010011101101] (das ist unser Secret)
    XOR        = 11111 = 31</p>

<pre><code>PK 13      =  1101
Flip +1    = 11011
99565      = _1100[0010011101101] das ist unser Secret)
XOR        = 10111 = 23
</code></pre>

<h2>PHP-Code</h2>

<pre><code>function obfuscateID($pk, $secret, $margin = 5) {
    if ($margin) {
        $pk = base_convert($pk, 10, 10-$margin);
    }

    $pk = bindec(1 . strrev(decbin($pk)));
    $pk ^= bindec(substr(decbin($secret), 0, strlen(decbin($pk))-1));

    return $pk;
}

function deObfuscateID($pk, $secret, $margin = 5) {
    $pk ^= bindec(substr(decbin($secret), 0, strlen(decbin($pk))-1));
    $pk = bindec(substr(strrev(decbin($pk)), 0, -1));

    if ($margin) {
        $pk = base_convert($pk, 10-$margin, 10);
    }

    return $pk;
}
</code></pre>

<p><a href="http://neunzehn83.de/blog/wp-content/uploads/2011/06/obfuscateID.html">Hier mit Highlighting</a>.</p>

<p>Vorsicht mit bindec() und decbin() auf 32bit-Systemen: hier sind max. Umwandlungen bis zu 4,294,967,295 möglich. Wer auf 32bit mehr braucht, muss sich diese Funktionen auf Stringbasis selber basteln. Anregung dazu findet man wie so oft in den Kommentaren des PHP-Manuals.</p>

<h2>Sicherheitsmarge</h2>

<p>Um das Erraten von Nachbarn zu erschweren, können die Lücken zwischen den PKs vergrößert werden. Das passiert mit dem Parameter $margin. Dieser muss ebenso wie das $secret systemweit immer gleich sein. Beim Zurückwandeln muss also das selbe Margin angegeben werden, wie für die Verschleierung. $margin kann ein Wert zwischen 0 und 9 haben und basiert auf einer simplen Basisumwandlung (umgerechnet wird von Basis 10 in Basis 10-$margin).</p>

<h2>Ausgabe</h2>

<p>Bis hierhin war&#8217;s ganz schön trocken. Höchste Zeit für ein wenig Praxis! Der folgende PHP-Schnipsel in Kombination mit den obigen Funktionen..</p>

<pre><code>$secret = 99565;
for ($i = 1; $i &amp;lt; 1000; $i++) {
    $camo = obfuscateID($i, $secret);  
    echo "$i: $camo &lt;br /&gt;";
}
</code></pre>

<p>ergibt folgende Ausgabe:
<pre>[..]
524: 7960
525: 15439
526: 11343
527: 13391
528: 9295
[..]
991: 19678
992: 29406
993: 21214
994: 25310
995: 30430
[..]</pre>
Äußerst nett, wie ich finde!</p>

<h2>Zahlen oder Alphanum?</h2>

<p>Um Platz zu sparen, könnte man die nach wie vor aus Zahlen bestehende, verschleierte ID in eine höhere Basis (32, 64) umwandeln. Auch mit dieser Umwandlung kann man relativ einfach für (weitere) Lücken sorgen. Da dies aber gefühlt ohnehin schon mein längster Blogbeitrag ist (in jedem Fall was die investierte Zeit angeht), lassen wir das mal so offen stehen bzw. überlasse ich es dem Leser als Übung :)</p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/06/19/uber-primary-keys-in-urls-und-sonstwo/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Data URIs vs. CSS-Sprites</title>
		<link>http://neunzehn83.de/blog/2011/06/16/data-uris-vs-css-sprites/</link>
		<comments>http://neunzehn83.de/blog/2011/06/16/data-uris-vs-css-sprites/#comments</comments>
		<pubDate>Thu, 16 Jun 2011 18:46:15 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=789</guid>
		<description><![CDATA[CSS-Sprites sind eine elegante Möglichkeit um GET-Requests zu minimieren und daruch den Seitenaufbau zu beschleunigen. Dabei werden viele kleine Symbole in einer großen Grafik zusammengefasst und via CSS  immer nur der passende Ausschnitt der Grafik gezeigt. Eine andere Möglichkeit, GET-Requests zu sparen, besteht in der Verwendung des Data URI scheme. &#60;img src="data:image/png;base64,iVBORw0KGgoAAAANSU[...]FTkSuQmCC" alt="" /&#62; Statt [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://neunzehn83.de/blog/wp-content/uploads/2011/03/google-sprite.png"><img class="size-full wp-image-793 alignleft" title="google-sprite" src="http://neunzehn83.de/blog/wp-content/uploads/2011/03/google-sprite.png" alt="" width="100" height="160" /></a><a href="http://css-tricks.com/css-sprites/">CSS-Sprites</a> sind eine elegante Möglichkeit um GET-Requests zu minimieren und daruch den Seitenaufbau zu beschleunigen. Dabei werden viele kleine Symbole in einer großen Grafik zusammengefasst und via CSS  immer nur der passende Ausschnitt der Grafik gezeigt. Eine andere Möglichkeit, GET-Requests zu sparen, besteht in der Verwendung des <a href="http://de.wikipedia.org/wiki/Data-URL">Data URI scheme</a>.
<pre style="clear: both;">&lt;img src="data:image/png;base64,iVBORw0KGgoAAAANSU[...]FTkSuQmCC" alt="" /&gt;</pre></p>

<p>Statt einer URL wird  direkt der Dateiinhalt Base64-Kodiert angegeben. Das Bild wird also mit dem HTML-Quelltext mitgeladen. Es ist kein separater GET-Request notwendig. Das funktioniert selbstverständlich analog in CSS-Dateien  und selbstverständlich nicht mit dem IE6/7.
<pre>body { background: url('data:image/png;base64,iVBOR[..]QmCC'); }</pre></p>

<p>Der fehlende IE6/7 Support mag ein Grund für die geringe Verbreitung des Data URI scheme sein. Erschwerend hinzu kommt die Tatsache, dass das Laden des (langen) Base64-Strings das weitere Rendering der Webseite zunächst blockiert. Die Base64-Darstellung ist im übrigen ca. 1/3 größer als die binäre und kann selbstverständlich nicht vom Browser gecached werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/06/16/data-uris-vs-css-sprites/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP-Skript im Hintergrund ausführen #2</title>
		<link>http://neunzehn83.de/blog/2011/05/22/php-skript-im-hintergrund-ausfuhren-2/</link>
		<comments>http://neunzehn83.de/blog/2011/05/22/php-skript-im-hintergrund-ausfuhren-2/#comments</comments>
		<pubDate>Sun, 22 May 2011 10:23:53 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=633</guid>
		<description><![CDATA[Die bereits erwähnte Methode über Content-Length funktioniert zwar etwas hakelig, ist aber in Webspace-Umgebungen oft die einzige Methode ein PHP-Skript im Hintergrund auszuführen. Eine andere Methode (neben dem Cronjob) besteht darin, über exec einen Hintergrundprozess zu starten. Beispiel (Linux only): &#60;?php exec('/usr/bin/php -f /var/www/cron.php &#62; /dev/null &#38;') ?&#62; Mit -f wird die auszuführende Datei angegeben. [...]]]></description>
			<content:encoded><![CDATA[<p>Die <a href="http://neunzehn83.de/blog/2010/12/27/php-skript-im-hintergrund-ausfuhren/">bereits erwähnte Methode</a> über Content-Length funktioniert zwar etwas hakelig, ist aber in Webspace-Umgebungen oft die einzige Methode ein PHP-Skript im Hintergrund auszuführen.</p>

<p>Eine andere Methode (neben dem Cronjob) besteht darin, über <a href="http://de.php.net/manual/de/function.exec.php">exec</a> einen Hintergrundprozess zu starten. Beispiel (Linux only):
<pre>&lt;?php exec('/usr/bin/php -f /var/www/cron.php &gt; /dev/null &amp;') ?&gt;</pre></p>

<p>Mit -f wird die auszuführende Datei angegeben. In Shared-Hosting-Umgebungen wird man keinen Zugriff auf die php-binary haben. Wget hingegen sollte verfügbar oder zumindest installierbar sein. Mit wget kann man prima &#8220;Cronjobs&#8221; über HTTP-GET im Hintergrund anstoßen:
<pre>&lt;?php exec('wget -bq -o /dev/null -O /dev/null -t 1 http://www.example.org/cron.php') ?&gt;</pre></p>

<p>Wget&#8217;s Parameter sind case-sensitive. -b sorgt dafür, dass der wget-Prozess im Hintergrund ausgeführt wird, -q unterdrückt jegliche Ausgabe, -o leitet die heruntergeladene Datei nach /dev/null, -O schreibt das Logfile ebenfalls ins Nirvana und -t 1 unternimmt nur einen Versuch die folgende URL aufzurufen.</p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/05/22/php-skript-im-hintergrund-ausfuhren-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuerys $-Funktion</title>
		<link>http://neunzehn83.de/blog/2011/04/17/jquerys-funktion/</link>
		<comments>http://neunzehn83.de/blog/2011/04/17/jquerys-funktion/#comments</comments>
		<pubDate>Sun, 17 Apr 2011 18:14:49 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=778</guid>
		<description><![CDATA[Wie wir alle wissen, werden Variablen in JavaScript nicht mit einem vorangestellten Dollarzeichen kenntlich gemacht. Insofern ist das Dollarzeichen für Javascript einfach nur das 36. Zeichen der ASCII-Tabelle. Und zudem ein gültiges Zeichen für Funktionsnamen (selbiges gilt neben allen Buchstaben und Zahlen auch für den Unterstrich). function Framework(id) { return document.getElementById(id); }   var $ [...]]]></description>
			<content:encoded><![CDATA[<p>Wie wir alle wissen, werden Variablen in JavaScript nicht mit einem vorangestellten Dollarzeichen kenntlich gemacht. Insofern ist das Dollarzeichen für Javascript einfach nur das 36. Zeichen der ASCII-Tabelle. Und zudem ein gültiges Zeichen für Funktionsnamen (selbiges gilt neben allen Buchstaben und Zahlen auch für den Unterstrich).</p>

<p><pre>
function Framework(id) {
    return document.getElementById(id);
}
 
var $ = Framework;
</pre></p>

<p>Jetzt ist $() ein Alias für die Funktion Framework(). Benutzt werden kann das jetzt schon wie bei jQuery:</p>

<p><pre>var nav = $('nav');</pre></p>

<p>Um es Framework zu nennen, ist es wohl noch etwas dünn. Erweitern wir unser <em>Framework</em> also um eine handliche Datumsfunktion. <a href="http://api.jquery.com/jQuery.now/">Analog zu jQuery</a>, gibt diese Funktion die aktuelle Zeit zurück.</p>

<p><pre>
Framework.now = function() {
    return (new Date).getTime();
}
 
$.now(); // 1301227135 (unix timestamp)
</pre></p>

<p>Das ist immer noch recht lasch! Weiter geht&#8217;s: Mit <a href="http://www.javascriptkit.com/javatutors/proto.shtml">Javascripts Prototype Object</a> ist es möglich einer Klasse eine gewisse Eigenschaft/Methode zu geben, die automatisch alle Instanzen dieses Objektes ebenfalls haben. Damit kann man z.B. jedem JS-Array eine <a href="http://api.jquery.com/each/">each()-Methode</a> verpassen, oder alle HTML-Elemente um Funktionen erweitern. Letzteres nehmen wir mal als Beispiel:</p>

<p><pre>Element.prototype.addClass = function(className) {
    this.className += ' ' + className;
}
$('myDiv').addClass('foo');</pre></p>

<p>Das Chaining von Methoden hat jQuery bekannt gemacht. Nichts leichter als das! Dazu muss die jeweilige Methode nur das Objekt selbst zurückgeben. Wir passen also unsere &#8220;addClass&#8221; Methode an und erstellen eine weitere um das Chaining zu testen.
<pre>Element.prototype.addClass = function(className) {
    this.className += ' ' + className;
    <strong>return this;</strong>
}
Element.prototype.content = function(content) {
    this.innerHTML = content;
    return this;
}
$('myDiv').addClass('foo').content('bar');</pre></p>

<p>Das ist jetzt natürlich alles nicht elegant gelöst und bestimmt auch nicht Cross-Browser tauglich (ich rede mit dir, IE!), verdeutlicht aber was so prinzipiell hinter einen Javascript-Framework steckt. <a href="http://neunzehn83.de/blog/wp-content/uploads/2011/04/jsframework.html.html">Hier</a> nochmal am Stück und mit <span style="text-decoration: line-through;">gehighlightetem</span> hervorgehobenem Syntax.</p>

<p>Merke: jQuery ist nur ein JavaScript-Framework. Mit jQuery kann man also auf keinen Fall mehr Dinge tun, als mit reinem Javascript selbst. Mit jQuery geht das meist nur einfacher und vor allem konsistenter zwischen verschiedenen Browser-Versionen.</p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/04/17/jquerys-funktion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Protocol Relative URLs</title>
		<link>http://neunzehn83.de/blog/2011/03/27/protocol-relative-urls/</link>
		<comments>http://neunzehn83.de/blog/2011/03/27/protocol-relative-urls/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 10:29:05 +0000</pubDate>
		<dc:creator>Nils</dc:creator>
				<category><![CDATA[Webtechnik]]></category>

		<guid isPermaLink="false">http://neunzehn83.de/blog/?p=767</guid>
		<description><![CDATA[Ist eine Webseite per https-Protokoll SSL-verschlüsselt aufrufbar, so müssen alle externen Objekte auf dieser Webseite ebenfalls über HTTPS geladen werden. Ist das nicht der Fall, gibt es im Internet-Explorer eine hässliche Meldung, bei anderen Browsern verschwindet einfach das begehrte Schloss-Icon. Da Objekte (also Bilder, Scripte, CSS-Dateien usw.) meistens mit relativer Pfadangabe geladen werden, ist das [...]]]></description>
			<content:encoded><![CDATA[<p>Ist eine Webseite per https-Protokoll SSL-verschlüsselt aufrufbar, so müssen alle externen Objekte auf dieser Webseite ebenfalls über HTTPS geladen werden. Ist das nicht der Fall, gibt es im Internet-Explorer eine hässliche Meldung, bei anderen Browsern verschwindet einfach das begehrte Schloss-Icon.</p>

<p><img title="IE mixed content" src="http://neunzehn83.de/blog/wp-content/uploads/2011/03/iesux.png" alt="" width="347" height="150" /></p>

<p>Da Objekte (also Bilder, Scripte, CSS-Dateien usw.) meistens mit relativer Pfadangabe geladen werden, ist das aber kein Problem. Anders sieht das bei Benutzung eines CDN oder externen JS-Dateien, z.B. über Google APIs, aus. Hier muss nämlich die komplette URI zum Script angegeben werden, inklusive dem Protokoll. Das ist ein Problem, wenn die Seite sowohl über HTTP als auch HTTPS erreichbar ist. Abhilfe schafft das &#8220;<a href="http://tools.ietf.org/html/rfc3986#section-4.2">network-path reference</a>&#8221; Schema:
<pre>&lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"&gt;&lt;/script&gt;</pre>
In diesem Fall würde <a href="http://jquery.com/">jQuery</a> wahlweise per http oder https geladen werden &#8211; je nach Kontext.</p>

<h2>Google-Analytics</h2>

<p>Der Google-Analytics Code zum Einbauen in die eigene Webseite sieht so oder so ähnlich aus:
<pre>&lt;script type="text/javascript"&gt;
   var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
   document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;</pre></p>

<p>Hier wird je nach Protokoll per <em>document.write</em> ein <em>script-Tag</em> erzeugt. Echt unschön. Mit einer protocol relative URL sähe das so aus:</p>

<p><pre>&lt;script type="text/javascript" src="//google-analytics.com/ga.js"&gt;&lt;/script&gt;</pre></p>

<p>Viel schöner! Warum benutzt dann Google aber keine protokoll-relativen URLs? Schuld ist mal wieder, wie so oft, der IE. Und zwar in der Version 6 &#8211; hier soll es je nach Sicherheitseinstellungen zu Zertifikats-Fehlermeldungen kommen. Wen weder den IE6 noch seine Sicherheitseinstellungen interessieren, kann sein GA-Script also protokoll-relativ einbinden. Ach ja, wo wir schon beim Internet Explorer sind: In der Version 7 und 8 läd dieser protokoll-relative &lt;link&gt; und @import Ressourcen leider <a href="http://www.stevesouders.com/blog/2010/02/10/5a-missing-schema-double-download/">zwei mal herunter</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://neunzehn83.de/blog/2011/03/27/protocol-relative-urls/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

