<?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 Interaktionsdesigner - PHP, jQuery und CSS &#187; Entwicklung</title>
	<atom:link href="http://www.interaktionsdesigner.de/category/entwicklung/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.interaktionsdesigner.de</link>
	<description>Pauls Blog beschäftigt sich mit Webentwicklungsthemen, im Focus stehen jQuery, TYPO3, CSS und PHP.</description>
	<lastBuildDate>Sat, 05 Jun 2010 21:13:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Viele Elemente dynamisch aktualisieren</title>
		<link>http://www.interaktionsdesigner.de/2009/07/24/viele-elemente-dynamisch-aktualisieren/</link>
		<comments>http://www.interaktionsdesigner.de/2009/07/24/viele-elemente-dynamisch-aktualisieren/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 18:10:57 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=555</guid>
		<description><![CDATA[Ein aktuelles Projekt interagiert auf sehr starke Art und Weise mit dem Benutzer. Das bedeutet neben einer anpassbaren Oberfläche wird der Benutzer ständig über den Status diverser Objekte auf dem laufenden gehalten. Dabei können sich verschiedene Objekte untereinander beeinflussen.
jQuery bietet ja ein tolles Ajaxkonstrukt an mit dem es kein Problem ist Daten vom Server zu [...]]]></description>
			<content:encoded><![CDATA[<p>Ein aktuelles Projekt interagiert auf sehr starke Art und Weise mit dem Benutzer. Das bedeutet neben einer anpassbaren Oberfläche wird der Benutzer <strong>ständig über den Status</strong> diverser Objekte auf dem laufenden gehalten. Dabei können sich verschiedene Objekte untereinander beeinflussen.</p>
<p>jQuery bietet ja ein tolles Ajaxkonstrukt an mit dem es kein Problem ist Daten vom Server zu holen. Aber auf die Dauer wird es doch etwas nervig immer wieder zu tippen.</p>
<p>Und weil <strong>"objektorientiertes Javascript"</strong> und selber entwickeln so viel <strong>Spaß</strong> macht, habe ich mir eine alternative Lösung einfallen lassen: Im Projekt werden an geeigneter Stelle <em>Elemente</em> erzeugt, die alle benötigten Informationen enthalten.</p>
<p>Diese werden in einem <em>Updater</em> registriert, welcher sich um die regelmäßige Abfrage kümmert. Das war die Theorie und jetzt kommt die <strong>Praxis</strong>.</p>
<p><span id="more-555"></span></p>
<h2>Das Element</h2>
<p>Ein Element besteht aus <strong>einer URL</strong> auf dem Server, <strong>dem Typ</strong> der zurückerwartenden Daten und <strong>einer Funktion</strong> die aufgerufen wird, wenn die Aktion erfolg hatte. Im Quelltext sieht das so aus:</p>
<pre><code class='javascript'>var Paul = new element('count/paul', 'json', function(j) {<br />
&nbsp;&nbsp;alert("Paul hat "+j.count+" Einträge.");<br />
});</code></pre>
<p>Diese Elemente können überall im Projekt erzeugt werden. Alternativen zu <em>json</em> sind alle Formen die jQuerys Ajaxfunktion erkennt: <em>Html</em>, <em>Text</em> und <em>Jsonp</em>.</p>
<h2>Der Updater</h2>
<p>Ganz am Anfang (oder am Ende, je nach Geschmack) wird der Updater initalisiert:</p>
<pre><code class='javascript'>var Updater = new updater();</code></pre>
<p>Der Updater akzeptiert zwei Einstellungen:</p>
<pre><code class='javascript'>Updater.intervall = 1000; // Zeit bis zur nächsten Abfrage<br />
Updater.baseurl = "http://kleiner.test.com/"; // String der vor jede URL geschrieben wird</code></pre>
<p>Und hat eine handvoll Funktionen für den dynamischen Umgang mit dem Objekt:</p>
<pre><code class='javascript'>Updater.start(); // Startet den Vorgang sofern Elemente vorhanden sind<br />
Updater.stop(); // Stoppt die Aktualisierungen<br />
Updater.isRunning(); // Prüft ob sich der Updater in Aktion befindet<br />
Updater.log(); // Schreibt alle gespeicherten Elementen in die Konsole<br />
Updater.register(Element); // Fügt ein neues Element hinzu<br />
Updater.remove(Element); // Entfernt ein Element</code></pre>
<h2>Die Verwendung</h2>
<p>Dem Updater werden <strong>beliebig viele Elemente</strong>, auch zur Laufzeit, übergeben:</p>
<pre><code class='javascript'>Updater.register(Paul);<br />
Updater.start();</code></pre>
<p>Das wars! Die Funktion im übergebenen Element wird jetzt, im erfolgsfall, alle 1000 Millisekunden aufgerufen.</p>
<h2>Die technische Seite vom Element</h2>
<p>So sieht das Element aus:</p>
<pre style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#3f7bc6;">function</span> <span style="color:#4080ff;">element</span>(url, dataType, successFunction) {

  <span style="color:#e27600;">//einstellungen
</span>  <span style="color:#3f7bc6;">this</span>.url = url;
  <span style="color:#3f7bc6;">this</span>.data = {};
  <span style="color:#3f7bc6;">this</span>.type = <span style="color:#df2800;">'get'</span>
  <span style="color:#3f7bc6;">this</span>.dataType = dataType || <span style="color:#df2800;">'html'</span>;

  <span style="color:#e27600;">//callback um die daten zu bekommen
</span>  <span style="color:#3f7bc6;">this</span>.getData = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">this</span>.data;
  }

  <span style="color:#e27600;">//callback um an die URL zu kommen
</span>  <span style="color:#e27600;">//erster parameter ist die im Updater gespeicherte baseurl
</span>  <span style="color:#3f7bc6;">this</span>.getUrl = <span style="color:#3f7bc6;">function</span>(BASEURL) {
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">this</span>.url;
  }

  <span style="color:#e27600;">//callback wenn eine antwort vorliegt
</span>  <span style="color:#e27600;">//erster Parameter ist die Antwort vom Server, zweiter der Updater an sich
</span>  <span style="color:#3f7bc6;">this</span>.success = successFunction || <span style="color:#3f7bc6;">function</span>(html, Updater) {
    console.<span style="color:#4080ff;">log</span>(<span style="color:#df2800;">'Anfrage #'</span>+Updater.counter);
    console.<span style="color:#4080ff;">log</span>(html);
  }

  <span style="color:#e27600;">//callback wenn ein fehler aufgetreten ist
</span>  <span style="color:#e27600;">//erster parameter ist der Updater an sich um dieses Element daraus zu entfernen
</span>  <span style="color:#3f7bc6;">this</span>.error = <span style="color:#3f7bc6;">function</span>(Updater) {
    <span style="color:#e27600;">//bei einem fehler entfernt sich das objekt selbstständig aus dem updater
</span>    Updater.<span style="color:#4080ff;">remove</span>(<span style="color:#3f7bc6;">this</span>);
  }

}</pre>
<p>Zwei Funktionen sind wichtig: <strong>getData()</strong> wird aufgerufen, bevor die Anfrage an den Server gesendet wird. Der Rückgabewert der Funktion wird an den Server geschickt.</p>
<p>Damit ist es also möglich, auf <strong>Veränderungen im Frontend</strong> zu reagieren. Zum Beispiel:</p>
<pre><code class='javascript'>Paul.getData = function() {<br />
&nbsp;&nbsp;return {relation: $('body').attr('rel'), project: $('#project_selector').val()};<br />
}</code></pre>
<p>Schön, oder? Natürlich kann man sich noch viel einfallen lassen. Etwa mit der URL, welche mit Hilfe der Funktion <strong>getUrl()</strong> aus dem Element geholt wird. Es soll ja Fälle geben (<em>CakePHP</em>), bei denen es leichter ist Daten per URL zu übergeben:</p>
<pre><code class='javascript'>Paul.getUrl = function(BASEURL) {<br />
&nbsp;&nbsp;return BASEURL+this.url+'/'+$('#team .paul').attr('rel');<br />
}</code></pre>
<p>Die Funktionen <strong>success(return, Updater)</strong> und <strong>error(Updater)</strong> erklären sich von selbst und haben als Parameter immer das umfassende Element dabei. Deshalb kann sich das Objekt in einem Fehlerfall auch selbstständig entfernen. Es könnte auch das Intervall verändern, ein neues Objekt hinuzfügen, oder was auch immer!</p>
<h2>Die technische Seite vom Updater</h2>
<p>Als erstes der gesamte Block Quelltext:</p>
<pre style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#3f7bc6;">function</span> <span style="color:#4080ff;">updater</span>() {

  <span style="color:#e27600;">//einstellungen
</span>  <span style="color:#3f7bc6;">this</span>.intervall = <span style="color:#fe2d00;">1000</span>;
  <span style="color:#3f7bc6;">this</span>.elements = <span style="color:#3f7bc6;">new</span> <span style="color:#4080ff;">Array</span>();
  <span style="color:#3f7bc6;">this</span>.active_element = <span style="color:#fe2d00;">0</span>;
  <span style="color:#3f7bc6;">this</span>.baseurl = BASEURL;

  <span style="color:#3f7bc6;">this</span>.running = <span style="color:#3f7bc6;">false</span>;
  <span style="color:#3f7bc6;">this</span>.counter = <span style="color:#fe2d00;">0</span>;
  <span style="color:#3f7bc6;">this</span>.timeout = <span style="color:#df2800;">''</span>;

  <span style="color:#e27600;">//alle elemente anzeigen
</span>  <span style="color:#3f7bc6;">this</span>.log = <span style="color:#3f7bc6;">function</span>() {
    console.<span style="color:#4080ff;">log</span>(<span style="color:#3f7bc6;">this</span>.elements);
  }

  <span style="color:#e27600;">//neues element hinzufügen
</span>  <span style="color:#3f7bc6;">this</span>.register = <span style="color:#3f7bc6;">function</span>(element) {
    <span style="color:#3f7bc6;">this</span>.elements.<span style="color:#4080ff;">push</span>(element);
  };

  <span style="color:#e27600;">//ein element entfernen
</span>  <span style="color:#3f7bc6;">this</span>.remove = <span style="color:#3f7bc6;">function</span>(element) {
    <span style="color:#3f7bc6;">for</span>(i <span style="color:#3f7bc6;">in</span> <span style="color:#3f7bc6;">this</span>.elements) {
      <span style="color:#3f7bc6;">if</span>(<span style="color:#3f7bc6;">this</span>.elements[i] == element) {
        <span style="color:#e27600;">//delete this.elements[i];
</span>        <span style="color:#3f7bc6;">this</span>.elements.<span style="color:#4080ff;">splice</span>(i, <span style="color:#fe2d00;">1</span>);
        <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">true</span>;
      }
    }
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">false</span>;
  }

  <span style="color:#e27600;">//elemente durchgehen
</span>  <span style="color:#3f7bc6;">this</span>.process = <span style="color:#3f7bc6;">function</span>(active_element) {
    <span style="color:#3f7bc6;">this</span>.active_element = active_element || <span style="color:#fe2d00;">0</span>;

    <span style="color:#3f7bc6;">if</span>(<span style="color:#3f7bc6;">this</span>.elements[<span style="color:#3f7bc6;">this</span>.active_element]) {
      _this = <span style="color:#3f7bc6;">this</span>;
      _elem = <span style="color:#3f7bc6;">this</span>.elements[<span style="color:#3f7bc6;">this</span>.active_element];

      <span style="color:#e27600;">//ajaxaufruf
</span>      $.<span style="color:#4080ff;">ajax</span>({
        <span style="color:#e27600;">//einstellungen
</span>        url: _elem.<span style="color:#4080ff;">getUrl</span>(_this.baseurl),
        data: _elem.<span style="color:#4080ff;">getData</span>(),
        type: _elem.type,
        dataType: _elem.dataType,

        <span style="color:#e27600;">//hat funktioniert!
</span>        success: <span style="color:#3f7bc6;">function</span>(result) {
          _elem.<span style="color:#4080ff;">success</span>(result, _this);
        },

        <span style="color:#e27600;">//ein fehler
</span>        error: <span style="color:#3f7bc6;">function</span>(error) {
          <span style="color:#e27600;">//das object soll entscheiden wie es weitergeht
</span>          _elem.<span style="color:#4080ff;">error</span>(_this);
        },

        <span style="color:#e27600;">//wie auch immer soll das nächste element aufgerufen werden
</span>        complete: <span style="color:#3f7bc6;">function</span>() {
          _this.<span style="color:#4080ff;">next</span>();
        }
      });     

    }
    <span style="color:#3f7bc6;">else</span> {
      <span style="color:#3f7bc6;">this</span>.active_element = <span style="color:#fe2d00;">0</span>;
      <span style="color:#3f7bc6;">this</span>.<span style="color:#4080ff;">next</span>();
    }
  };

  <span style="color:#e27600;">//ruft process erneut auf, verzögert um intervall mit dem activen element
</span>  <span style="color:#3f7bc6;">this</span>.next = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">if</span>(<span style="color:#3f7bc6;">this</span>.<span style="color:#4080ff;">isRunning</span>()) {
      <span style="color:#e27600;">//nur so zum spaß
</span>      <span style="color:#3f7bc6;">this</span>.counter++;

      <span style="color:#e27600;">//zeit die bis zum nächsten aufruf vergehen soll
</span>      <span style="color:#3f7bc6;">var</span> _intervall = <span style="color:#fe2d00;">0</span>;

      <span style="color:#e27600;">//nächstes element suchen
</span>      <span style="color:#3f7bc6;">this</span>.active_element++;

      <span style="color:#e27600;">//schon am ende angelangt?
</span>      <span style="color:#3f7bc6;">if</span>(<span style="color:#3f7bc6;">this</span>.active_element &gt;= <span style="color:#3f7bc6;">this</span>.elements.length) {
        <span style="color:#3f7bc6;">this</span>.active_element = <span style="color:#fe2d00;">0</span>;

        <span style="color:#e27600;">//längerer intervall bis es wieder los geht
</span>        _intervall = <span style="color:#3f7bc6;">this</span>.intervall;
      }

      <span style="color:#e27600;">//erneut aufrufen
</span>      _this = <span style="color:#3f7bc6;">this</span>;
      _this.timeout = window.<span style="color:#4080ff;">setTimeout</span>(<span style="color:#3f7bc6;">function</span>() {
        _this.<span style="color:#4080ff;">process</span>(_this.active_element);
      }, _intervall);
      <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">true</span>;
    }
    <span style="color:#3f7bc6;">else</span> {
      <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">false</span>;
    }
  }

  <span style="color:#e27600;">//startet den vorgang
</span>  <span style="color:#3f7bc6;">this</span>.start = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">this</span>.active_element = -<span style="color:#fe2d00;">1</span>;
    <span style="color:#3f7bc6;">this</span>.running = <span style="color:#3f7bc6;">true</span>;
    <span style="color:#3f7bc6;">this</span>.counter = <span style="color:#fe2d00;">0</span>;
    <span style="color:#3f7bc6;">this</span>.<span style="color:#4080ff;">next</span>();
  }

  <span style="color:#e27600;">//stoppt das updaten
</span>  <span style="color:#3f7bc6;">this</span>.stop = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">this</span>.running = <span style="color:#3f7bc6;">false</span>;
    window.<span style="color:#4080ff;">clearTimeout</span>(<span style="color:#3f7bc6;">this</span>.timeout);
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">this</span>.counter;
  }

  <span style="color:#e27600;">//prüfen ob der Updater läuft
</span>  <span style="color:#3f7bc6;">this</span>.isRunning = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">this</span>.running;
  }
}</pre>
<p>Nett, oder? Was ist passiert? Die Einstellungen sollten klar sein. In der Variable <strong>timeout</strong> wird der aktuelle Timeout gespeichert. Damit kann man beim Abbrechen alle Verbindungen trennen, anstatt noch eine ausführen zu müssen.</p>
<p><strong>Log()</strong>, <strong>register()</strong> und <strong>remove()</strong> sind an sich uninteressant. Außer eine Erwähnung, dass der Operator <em>delete</em> ein Element zwar entfernt, aber danach nicht das Array neu durchnummeriert. Da liegen dann lauter "<em>undefinied</em>" rum. Deshalb habe ich <strong>splice()</strong> benutzt. Funktioniert super.</p>
<p>Spannend wird es in der Funktion <strong>process()</strong>. Diese wird für jedes Element aufgerufen. Als Parameter erwartet sie den <strong>Key</strong> vom aktiven Element. Wenn ein Element vorhanden ist, wird die Ajaxabfrage ausgeführt.</p>
<p>Innerhalb der Funktion Ajax() bekommt das <em>this</em> eine neue Bedeutung. Deshalb musste ich es in <em>_this</em> zwischenspeichern.</p>
<p>Die Funktion ruft also, je nach umstand, <strong>success()</strong> oder <strong>error()</strong> auf und übergibt die Kontrolle an das Element. In jedemfall wird aber <strong>_this.next()</strong> durch die Funktion <strong>Ajax.complete()</strong> aufgerufen. Diese wird, unabhängig vom Status, nach jeder Ajaxanfrage ausgeführt.</p>
<p>In der Funktion <strong>next()</strong> wird das nächste Objekt gesucht. Sofern der Updater läuft <strong>isRunning() </strong>wird der Counter erhöht und das Intervall auf Null gesetzt. Das passiert, weil alle registrierten Elemente sofort nacheinander aufgerufen werden sollen und erst anschließend die in <em>this.intervall</em> angegebene Zeit gewartet wird.</p>
<p>Wenn alle Elemente durchgearbeitet wurden, wird der <strong>Index auf Null</strong> und der <strong>Intervall auf die eingestellte Zeit</strong> gesetzt.</p>
<p>Anschließend gibt es ein klassisches <strong>window.setTimeout()</strong> um das ganze Spielchen wieder von vorne anzufangen.</p>
<p><strong>Start()</strong>, <strong>stop()</strong> und <strong>isRunning()</strong> erklären sich wieder von selbst, und damit ist die Vorstellung beendet!</p>
<h2>Fazit</h2>
<p>Der große nächste Erweiterungsschritt ist in dem Updater alle Anfragen zu sammeln und<strong> in einem Packet</strong> an den Server zu schicken. Die Antwort kann dann direkt vom Updater auseinander gefriemelt und an die verschiedenen Elemente verteilt werden.</p>
<p>Dazu muss der Server allerdings noch vorbereitet werden, und bisher sind es noch nicht viele Benutzer. Aber ich denke es ist eine <strong>solide Grundlage</strong> die gut erweitert werden kann.</p>
<p>Das war auch die Intention dieses Postings. Hast du einen <strong>Vorschlag</strong>? <strong>Kritik</strong>? <strong>Hinweis</strong>? Freue mich über Kommentare und Inspiration. Danke für die Aufmerksamkeit.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2009/07/24/viele-elemente-dynamisch-aktualisieren/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automatisch erkennen wie CSV Dateien aufgebaut sind</title>
		<link>http://www.interaktionsdesigner.de/2009/02/25/automatisch-erkennen-wie-csv-dateien-aufgebaut-sind/</link>
		<comments>http://www.interaktionsdesigner.de/2009/02/25/automatisch-erkennen-wie-csv-dateien-aufgebaut-sind/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 17:04:49 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=285</guid>
		<description><![CDATA[CSV Dateien sind z.B. Exports aus Datenbanken oder Excel. Der Name steht für Comma-Separated Values und bedeutet, dass die Werte von einem Komma getrennt sind. Damit kann man einfach eine CSV importieren und zum Beispiel in PHP weiter verarbeiten.
Tja, einfach ist das natürlich nicht und jedes Programm erstellt andere CSV Dateien. Ich habe eine Funktion [...]]]></description>
			<content:encoded><![CDATA[<p>CSV Dateien sind z.B. <strong>Exports aus Datenbanken oder Excel</strong>. Der Name steht für <em>Comma-Separated Values </em>und bedeutet, dass die Werte von einem Komma getrennt sind. Damit kann man <strong>einfach</strong> eine CSV importieren und zum Beispiel in PHP weiter verarbeiten.</p>
<p>Tja, einfach ist das natürlich nicht und jedes Programm erstellt <strong>andere CSV Dateien</strong>. Ich habe eine Funktion geschrieben die versucht <strong>automatisch</strong> zu erkennen wie eine CSV Datei aufgebaut ist. <a title="Automatische CSV Erkennung" href="http://interaktionsdesigner.de/stuff/csv.php" target="_blank">Hier ist eine Demo</a> und im folgenden Artikel kommt die Funktionsweise.<span id="more-285"></span>Die Funktion erwartet einen String, z.B. <pre><code class=''>"spalte1", "spalte2", "spalte3"</code></pre> und gibt dann ein Array zurück mit den Keys <em>delimiter</em> und <em>enclosure</em>. Aus dem obrigen Beispiel wäre das dann <pre><code class=''>Array(&nbsp;&nbsp;[delimiter] =&gt; ; &nbsp;&nbsp;[enclosure] =&gt; ")</code></pre></p>
<p>Hier kommt die <strong>komplette Funktion</strong> und anschließend ein paar erklärende Worte.<pre><code class='php'>function csv_autodetect($string) {<br />
&nbsp;&nbsp;$str = trim($string);<br />
&nbsp;&nbsp;$char = '';<br />
&nbsp;&nbsp;$e = '';<br />
&nbsp;&nbsp;$d = array();<br />
&nbsp;&nbsp;$open = false;<br />
&nbsp;&nbsp;$strip = false;<br />
&nbsp;&nbsp;for($i = 0; $i &lt; strlen($str); $i++) {<br />
&nbsp;&nbsp;[tab]$char = $str[$i];<br />
&nbsp;&nbsp;[tab]if(preg_match('=[\W]=', $char) &amp;&amp; ord($char) != 32) {&nbsp;&nbsp;[tab]&nbsp;&nbsp;<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;if($i == 0)<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;[tab]$e = $char;<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;if($char == '\\')<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;[tab]$strip = true;<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;else<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;[tab]$strip = false;<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;if($char == $e &amp;&amp; !$strip) {<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;[tab]$open = $open ? false : true;<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;}<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;else {<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;[tab]if(!$open &amp;&amp; !$strip)<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;[tab]&nbsp;&nbsp;$d[$char]++;<br />
&nbsp;&nbsp;[tab]&nbsp;&nbsp;}<br />
&nbsp;&nbsp;[tab]}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;asort($d);<br />
&nbsp;&nbsp;$dd = array_keys($d, array_pop($d));<br />
&nbsp;&nbsp;$return['delimiter'] = $dd[0];<br />
&nbsp;&nbsp;$return['enclosure'] = $e;<br />
&nbsp;&nbsp;return $return;&nbsp;&nbsp;<br />
}</code></pre></p>
<p>Nachdem einige Variablen vorbelegt wurden, erfolgt die <strong>zeichenweise Untersuchung des Strings</strong>. Wenn es sich um ein Sonderzeichen handelt, dann beginnt die Untersuchung.</p>
<p><pre><code class='php'>if($i == 0)<br />
&nbsp;&nbsp;$e = $char;</code></pre>Wenn das erste Zeichen des Strings ein <strong>Sonderzeichen</strong> ist und kein Leerzeichen, dann ist es mit Sicherheit jenes, welches die Werte umfasst (<em>e = Enclosure</em>).<br />
<pre><code class='php'>if($char == '\\')<br />
&nbsp;&nbsp;$strip = true;<br />
else<br />
&nbsp;&nbsp;$strip = false;</code></pre>Wenn es sich um ein <strong>Backslash</strong> handelt, dann wird das nächste Zeichen ignoriert. Damit sind dann Fälle wie <em>"eine \"Spalte\"";</em> auch möglich.<br />
<pre><code class='php'>if($char == $e &amp;&amp; !$strip)<br />
$open = $open ? false : true;</code></pre>Wenn es also das umschließende Zeichen ist, und nicht durch ein Backslash auskommentiert wurde (<em>$strip</em>), dann wird der Status von <em>$open</em> geändert. Durch diese Beachtung ist es dann möglich den Delimeter innerhalb einer Spaltenbezeichnung zu benutzen (z.B. <em>"spalte1", "spalte1,5", "spalte2"</em>). Wenn es sich nicht um das umschließende Zeichen handelt, dann muss weiter überlegt werden:<br />
<pre><code class='php'>if(!$open &amp;&amp; !$strip)<br />
&nbsp;&nbsp;$d[$char]++;</code></pre>Wenn sich das Zeichen nicht innerhalb einer Spaltenbezeichnung befindet und auch nicht auskommentiert wurde, dann wird das Arrayelement <em>$d</em> (<em>d = Delimiter</em>) mit dem Zeichen als Schlüssel um eins erhöht.</p>
<p>Der Grund dafür ist das eventuelle Auftreten von Sonderzeichen in einer Spaltenbezeichnung ohne Enclosure (z.B. spalte1, spalte2&amp;3, spalte4). Am Ende wird das Zeichen als Delimeter erwartet welches <strong>am häufigsten gefunden</strong> wurde. Das gibt zwar ein Problem bei einem String wie <em>c&amp;a, p&amp;c, m&amp;m</em> - aber dann muss man seine Felder halt mit einem Zeichen umschließen.</p>
<p><strong>Ende!</strong> Wer jetzt in seinem Kopf die Idee spinnt daraus ein Tool zu bauen welches <strong>CSV Dateien in eine Datenbank importiert</strong>, dem sei geraten noch ein paar Tage zu warten oder mir eine Mail zu schicken. Hab da was tolles in der mache was demnächst veröffentlicht wird <img src='http://www.interaktionsdesigner.de/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>Wer <em>Ideen</em>, <em>Probleme</em> und <em>Verbesserungsvorschläge</em> hat kann diese gerne in den Kommentaren los werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2009/02/25/automatisch-erkennen-wie-csv-dateien-aufgebaut-sind/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>processDatamap_postProcessFieldArray()</title>
		<link>http://www.interaktionsdesigner.de/2008/09/25/processdatamap_postprocessfieldarray/</link>
		<comments>http://www.interaktionsdesigner.de/2008/09/25/processdatamap_postprocessfieldarray/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 16:41:06 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[TYPO3]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=83</guid>
		<description><![CDATA[Manchmal hasst man TYPO3 für diese Funktionsnamen. Wenn man dann durchschaut hat, was damit gemeint ist, verliebt man sich wieder in das riesen CMS.
In diesem Beitrag will ich erklären wie es dank Hooks und dem TCEMain Objekt möglich wird, in die TYPO3 internen Speicherfunktionen zu kommen. Das braucht man für seine eigenen Extensions oder wenn [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-84" title="TYPO3 Logo" src="http://www.interaktionsdesigner.de/wp-content/uploads/2008/09/logo_save-area_01.jpg" alt="TYPO3 Entwicklung und Liebe" width="334" height="141" />Manchmal hasst man TYPO3 für diese Funktionsnamen. Wenn man dann durchschaut hat, was damit gemeint ist, verliebt man sich wieder in das riesen CMS.</p>
<p>In diesem Beitrag will ich erklären wie es dank Hooks und dem TCEMain Objekt möglich wird, in die TYPO3 internen Speicherfunktionen zu kommen. Das braucht man für seine eigenen Extensions oder wenn man vor dem Speichern die Daten manipulieren möchte.<span id="more-83"></span><br />
Vorne weg sei gesagt, dass Robert Lemke schon ein <a href="http://typo3.org/development/articles/how-to-use-existing-hooks/" target="_blank">ausführliches, englisches Tutorial</a> geschrieben hat welches die Sache sehr gut und ansehnlich erklärt. Wer nicht so viel Zeit hat oder keine Lust auf Englisch, dem wünsche ich viel Spaß!</p>
<h2>Eine eigene Klasse</h2>
<p>Wir brauchen eine neue Datei in der wir unsere eigene Funktionalität festhalten. Diese braucht eine einzige Funktion, welche schon im Titel erwähnt ist: <strong>processDatamap_postProcessFieldArray</strong>.</p>
<pre><code class="php">class tx_EXTNAME_tcemainprocdm {
	function processDatamap_postProcessFieldArray($status, $table, $id, &amp;$fieldArray) {
		// ACTION!
	}
}</code></pre>
<p><em>EXTNAME</em> ist hier wie im folgenden stets entsprechend anzupassen.<br />
Wir erstellen also eine Funktion die eine ganze Reihe Parameter bekommt. Bei Robert Lemke hat sie auch noch ein <strong>&amp;$this</strong> als letzten Parameter, da hat er bei mir aber rumgemeckert.<br />
<strong>$status</strong> beinhaltet die gewählte Aktion (z.B. "update" oder "insert").<br />
In <strong>$table</strong> steht die Tabelle um die es geht.<br />
Und <strong>$id</strong> kennzeichnet den betreffenden Datensatz. Reicht für meine Zwecke.</p>
<h2>Den Hook registrieren</h2>
<p>Dafür wechseln wir in die Datei <strong>ext_localconf.php</strong> und fügen eine Zeile hinzu, welche unsere Klasse referenziert:</p>
<pre><code class="php">$GLOBALS["TYPO3_CONF_VARS"]["SC_OPTIONS"]["t3lib/class.t3lib_tcemain.php"]["processDatamapClass"][] = "EXT:EXTNAME/class.tx_EXTNAME_tcemainprocdm.php:tx_EXTNAME_tcemainprocdm";</code></pre>
<p>Der Datei <strong>t3lib_tcemain.php</strong> wird also unser Hook zugeteilt. Es ist darauf zu achten das dem Array ein neues Element hinzugefügt wird und durch das Konstrukt <em>Dateipfad<strong>:</strong>Klassenname</em> die Einbindung mittels <em>require</em> entfällt. Praktisch!</p>
<h2>Das wars!</h2>
<p>Nichts leichter als das. Wenn man mit Echo in der eigenen Funktion etwas ausgibt erscheint es nach dem Speichern eines Datensatzes über der Leiste mit den Speichernknöpfen, also keine Hemmungen und viel Spaß mit dem Logikmonster TYPO3!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/09/25/processdatamap_postprocessfieldarray/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PDF Formulare im Acrobat besiegen</title>
		<link>http://www.interaktionsdesigner.de/2008/09/10/pdf-formulare-im-acrobat-besiegen/</link>
		<comments>http://www.interaktionsdesigner.de/2008/09/10/pdf-formulare-im-acrobat-besiegen/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 08:15:54 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=77</guid>
		<description><![CDATA[Der (verdammte) Acrobat bietet die Möglichkeit interaktive Formulare zu erstellen. Und kaum erstellt jemand ein Formular, fallen ihm diverse Abhängigkeiten und Sonderfunktionen ein, die es abzubilden gilt. Zum Glück ist es möglich mit JavaScript dynamisch auf die Eingaben zu reagieren, aber einfacher macht es die Sache nicht gerade.
Hier kommt eine kleine Anleitung wie man den [...]]]></description>
			<content:encoded><![CDATA[<p>Der (verdammte) Acrobat bietet die Möglichkeit interaktive Formulare zu erstellen. Und kaum erstellt jemand ein Formular, fallen ihm diverse Abhängigkeiten und Sonderfunktionen ein, die es abzubilden gilt. Zum Glück ist es möglich mit JavaScript dynamisch auf die Eingaben zu reagieren, aber einfacher macht es die Sache nicht gerade.</p>
<p>Hier kommt eine kleine Anleitung wie man den Inhalt auf Buchstaben und Leerzeichen überprüft und eine Abhängigkeit von mehreren "Kontrollkästchen" - auch Checkboxen genannt - erzeugt.<span id="more-77"></span></p>
<h2>Grundlegend</h2>
<p>In den JavaScripten gibt es zwei Objekte die für mich interessant sind.</p>
<pre>this</pre>
<p>Bezieht sich auf das gesamte Dokument und beinhaltet u.a. alle Formularfelder.</p>
<pre>event</pre>
<p>Beinhaltet das aktuelle, angeklickte Element und erlaubt den Status zu setzen.</p>
<h2>1. Inhalt auf "echte Zeichen" überprüfen</h2>
<p>Wir haben ein Textfeld zur Eingabe von Formulardaten. Hinter einem Doppelklick verstecken sich die Feldeigenschaften. Hinter dem Button "Validierung" gibt es die Möglichkeit ein "Benutzerdefiniertes Validierungsscript aus(zu)führen". Perfekt. Nehmen wir, und so siehts aus:</p>
<pre><code class="javascript">if(event.value.search(/[^a-z ]/gi) == -1) {
    event.rc = true;
}
else {
  event.rc = false;
  app.alert("Bitte geben Sie nur Buchstaben ein.");
}</code></pre>
<p>Über die Eigenschaft <strong>event.value</strong> bekommen wir den Inhalt des Formularfeldes nach der Eingabe (das regelt das PDF für uns). Mit der Funktion <a href="http://de.selfhtml.org/javascript/objekte/string.htm#search" target="_blank">search()</a> wende ich einen regulären Ausdruck auf den Inhalt an. <em>[a-z ]</em> trifft auf alle Buchstaben und das Leerzeichen zu. Mit "i" wird die Groß- und Kleinschreibung ignoriert und "g" durchsucht den String bis zum Ende. Mit dem Dach (^) negieren wir die Auswahl - wird also nichts anderes außer Buchstaben oder das Leerzeichen gefunden, ist alles in Ordnung und der <strong>Return Code (rc)</strong> wird positiv; der Inhalt hat die Validierung bestanden (<a href="http://www.addedbytes.com/cheat-sheets/regular-expressions-cheat-sheet/" target="_blank">bei AddedBytes gibts ein gutes Cheat Sheet zu regulären Ausdrücken</a>).<br />
Ist dies <strong>nicht</strong> der Fall, negieren wir den Return Code, was ein verlassen des Feldes verhindert, bzw. den Standardwert setzt. Über <strong>app.alert()</strong> wird der Benutzer noch darauf hingewiesen (ohne <strong>app</strong> funktioniert es nicht).</p>
<h2>2. Abhängigkeiten von Checkboxen</h2>
<p>Das Problem: Wenn eine Checkbox gewählt ist, dann dürfen eine ganze Reihe <strong>anderer</strong> Felder <strong>nicht</strong> ausgewählt werden. Alltäglich...<br />
Bei den Checkboxen gibt es keine Validierung, deshalb fügen wir eine neue Aktion hinzu: Bei <em>"Maustaste loslassen"</em> wird ein JavaScript ausgeführt, undzwar folgendes.</p>
<pre><code class="javascript">if(this.getField("FELDNAME_1").value == "VALUE_1") {
  this.resetForm(["FELDNAME_2"]);
}</code></pre>
<p>Bedeutet: über <strong>this.getField().value</strong> bekommen wir den Inhalt der ersten Checkbox (mit Namen FELDNAME_1), welche die Abhängigkeit auslösen soll. Ist sie nicht ausgewählt, besitzt sie auch keinen Inhalt (VALUE_1).<br />
Falls doch, wird mit <strong>this.resetForm()</strong> der Standard wieder hergestellt. Als Parameter wird der Feldname als Array übergeben. Es könnten also auch mehrere Felder zurück gesetzt werden mit <em>resetForm(["FELD_1", "FELD_2"])</em> - man achte auf die korrekte Klammerung.</p>
<h2>Fazit</h2>
<p>Alles in allem eine ehr anstrengende Geschichte, aber ich denke sie funktioniert. Die Informationen im Netz sind spärlich, geholfen hat mir aber das endlose PDF<a href="http://www.adobe.com/devnet/acrobat/javascript.html" target="_blank"> JavaScript in Acrobar API</a>. Die <a href="http://help.adobe.com/de_DE/Acrobat/9.0/Standard/WS58a04a822e3e50102bd615109794195ff-7e1e.w.html" target="_blank">offizielle Acrobat Hilfe</a> bietet einen ersten Einstieg - und setzt erfreulicher Weise auf jQuery <img src='http://www.interaktionsdesigner.de/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/09/10/pdf-formulare-im-acrobat-besiegen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Schöner Lokal entwickeln</title>
		<link>http://www.interaktionsdesigner.de/2008/08/09/schoner-lokal-entwickeln/</link>
		<comments>http://www.interaktionsdesigner.de/2008/08/09/schoner-lokal-entwickeln/#comments</comments>
		<pubDate>Sat, 09 Aug 2008 12:13:10 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=59</guid>
		<description><![CDATA[Mit einfachen Mitteln ist auf dem eigenen Rechner ein Webserver installiert und die Entwicklung von spannenden Projekten kann beginnen. Für die lokale Entwicklung ist das Directorylistning vom Apache Webserver schon sehr praktisch.

Nur leider sieht es nicht besonders schön aus. Mit einfachen Mitteln lässt sich das aber sehr schnell ändern, und schon surft man voller Freude [...]]]></description>
			<content:encoded><![CDATA[<p>Mit <a href="http://www.mamp.info/de/index.php" target="_blank">einfachen Mitteln</a> ist auf dem eigenen Rechner ein Webserver installiert und die Entwicklung von spannenden Projekten kann beginnen. Für die lokale Entwicklung ist das Directorylistning vom Apache Webserver schon sehr praktisch.</p>
<p><img class="aligncenter size-full wp-image-60" title="vorher" src="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/vorher.png" alt="" width="500" height="216" /></p>
<p>Nur leider sieht es nicht besonders schön aus. Mit einfachen Mitteln lässt sich das aber sehr schnell ändern, und schon surft man voller Freude durch die eigene Ordnerstruktur.<span id="more-59"></span><br />
So könnte man es machen:</p>
<p><strong>Standardschriftart im Browser ändern.</strong> Mit zweieinhalb Klicks ist Verdana oder Arial eingestellt was einen wesentlich angenehmeren Eindruck auf ungestylten Seiten hinterlässt. Im Firefox gehts über <em><br />
Einstellungen</em> &gt; <em>Inhalte</em> &gt; <em>Schriftarten und Farben</em>.</p>
<p><strong>Die htaccess im Heimatverzeichnis anpassen.</strong> Der Apache Webserver bietet umfangreiche Möglichkeiten um das Listning anzupassen. Besonders interessant wird es mit eigenen Header- und Footer-Dateien. So sieht es bei mir aus:</p>
<pre><code class="htaccess"># Serversignatur ausschalten. Ich weiß ja schon was ich für einen Server installiert habe.
ServerSignature Off

# Anzeigen vom Verzeichnisinhalt, sofern keine index.html/index.php vorhanden ist.
Options +Indexes

# Jetzt wirds verschönert!
IndexOptions HTMLTable FancyIndexing

# Einen eigenen Header einbinden. In dem ist Platz für CSS und JavaScript
HeaderName /server/header.html

# Wir brauchen überhaupt keinen Footer.
IndexIgnore footer.html

# Verhindern das die Tabelle in eigene Bodytags verschachtelt wird
IndexOptions SuppressHTMLPreamble

# Manchmal will man auch die kleinen Icons anklicken.
IndexOptions IconsAreLinks

# Zeigt die HTML Titel in den Beschreibungen an.
# Kommt aber selten zum Einsatz, da meistens eine index Datei vorhanden ist
IndexOptions ScanHTMLTitles

# Die Spalte Beschreibung soll lang genug sein
IndexOptions DescriptionWidth=*

# Und eine Standardsortierung. Die zickt aber manchmal rum...
IndexOrderDefault Ascending Name</code></pre>
<p>Das wars! Und schon sieht das ganze wesentlich angenehmer aus.</p>
<p><a href="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/nachher-1.png"><img class="aligncenter size-full wp-image-61" title="nachher-1" src="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/nachher-1.png" alt="" width="500" height="186" /></a></p>
<p>Tiefschürfende Informationen über alle Möglichen htaccess Einstellungen gibt es bei <a href="http://www.trash.net/faq/htaccess.shtml" target="_blank">trash.net</a> (de) oder direkt von den <a href="http://httpd.apache.org/docs/2.0/howto/htaccess.html" target="_blank">Machern</a> (en).</p>
<p>Wer keine Lust hat selber Dateien anzulegen, lädt sich <a href="http://www.interaktionsdesigner.de/stuff/htaccess.zip">dieses Archiv</a> runter und entpackt es in das Heimatverzeichnis des Webservers. In der <em>header.html</em> befindet sich das Styling welches die Ausgabe einfärbt.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/08/09/schoner-lokal-entwickeln/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Der einfachste Blindtextgenerator</title>
		<link>http://www.interaktionsdesigner.de/2008/08/07/der-einfachste-blindtextgenerator/</link>
		<comments>http://www.interaktionsdesigner.de/2008/08/07/der-einfachste-blindtextgenerator/#comments</comments>
		<pubDate>Thu, 07 Aug 2008 13:19:25 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=55</guid>
		<description><![CDATA[Der Trend geht dahin Webseiten nicht mehr mit ausschließlich mit Photoshop zu gestallten, sondern die Entwicklung direkt im Browser voran zu treiben. Das hat den Vorteil das interaktive Möglichkeiten schneller umgesetzt und besser kommuniziert werden können.
Und was fehlt? Mengen an Blindtext! Da wir gerade ein neues Projekt auf diese Art und Weise begonnen haben, standen [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/blindtext.png"><img class="alignright size-full wp-image-56" title="blindtext" src="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/blindtext.png" alt="" width="232" height="162" /></a>Der Trend geht dahin Webseiten nicht mehr mit ausschließlich mit Photoshop zu gestallten, sondern die Entwicklung direkt im Browser voran zu treiben. Das hat den Vorteil das interaktive Möglichkeiten schneller umgesetzt und besser kommuniziert werden können.</p>
<p>Und was fehlt? <strong>Mengen an Blindtext!</strong> Da wir gerade ein neues Projekt auf diese Art und Weise begonnen haben, standen wir vor genau diesem Problem. Es folgt ein einfacher Lösungsansatz mit PHP.<br />
<span id="more-55"></span></p>
<p>Wer jetzt Mengen an Text erwartet hat, den muss ich leider entäuschen. Ich habe eine Mini-PHP Klasse geschrieben: <em>Blindtext</em>.<br />
Diese besitzt genau eine Funktion: <em>get()</em>. Die Funktion kann aufgerufen werden ohne ein neues Objekt der Klasse zu erzeugen und kann mit zwei Parametern gesteuert werden. Die in Klammern gesetzten Werte sind die Standardwerte.</p>
<p><strong>$length</strong> (= 100) - Anzahl von Zeichen die der Blindtext enthalten soll<br />
<strong>$dot</strong> (= true) - Setzt einen Punkt an das Ende des Blindtexts, wenn true</p>
<p>So einfach! Das Besondere an der Klasse ist die dynamische Ausgabe. Es ist ein String (Lorem ipsum...) gespeichert von dem zufällig die ersten Zeichen abgeschnitten werden. Damit erhält man nicht immer den gleichen Blindtext.</p>
<p>So gehts:</p>
<pre><code class="php">&lt;?
  include("blindtext.php");
  echo blindtext::get(200);
?&gt;</code></pre>
<p>Ich spare mir jetzt mal die Ausgabe als Beispiel dazu zu schreiben.</p>
<p>Hier ist der <a href="http://www.interaktionsdesigner.de/stuff/blindtext.zip">download</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/08/07/der-einfachste-blindtextgenerator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aus der Mitte entspringt ein RTE</title>
		<link>http://www.interaktionsdesigner.de/2008/07/28/aus-der-mitte-entspringt-ein-rte/</link>
		<comments>http://www.interaktionsdesigner.de/2008/07/28/aus-der-mitte-entspringt-ein-rte/#comments</comments>
		<pubDate>Mon, 28 Jul 2008 14:44:14 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[TYPO3]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=54</guid>
		<description><![CDATA[Zur Zeit entwickle ich meine erste große TYPO3 Extension die das Aktualisieren der Inhalte für Redakteure und Administratoren vereinfachen soll. Dazu demnächst mehr - erstmal geht es um die Konfiguration des RTE. Es ist unglaublich wie viele verschiedene Ansätze es dazu gibt, wie weit sich die Konfiguration verschachteln lässt und wie unglaublich nervig das werden [...]]]></description>
			<content:encoded><![CDATA[<p>Zur Zeit entwickle ich meine erste große TYPO3 Extension die das Aktualisieren der Inhalte für Redakteure und Administratoren vereinfachen soll. Dazu demnächst mehr - erstmal geht es um die <strong>Konfiguration des RTE</strong>. Es ist unglaublich wie viele verschiedene Ansätze es dazu gibt, wie weit sich die Konfiguration verschachteln lässt und wie unglaublich nervig das werden kann.</p>
<p>Aber ich habe einige Ansätze gefunden die funktionieren.<br />
<span id="more-54"></span></p>
<h2>TSConfig erweitern</h2>
<p>Normalerweise definieren wir den <strong>RTE</strong> über das TSConfig Feld der Root Seite. Da der Benutzer der Extension dies aber nicht tun soll, erledigen wir das über die <strong>ext_localconf.php</strong> unserer Extension.</p>
<p>Hier ist es Möglich eine Variable, z.B. $rte_config, dem TSConfig hinzufügen:</p>
<pre><code class="php">t3lib_extMgm::addPageTSConfig($rte_config);</code></pre>
<p>In meinem konkreten Fall habe ich ein weiteres Tag definiert, <em>hivar</em>, welches ich gesondert formatieren möchte. Zur Lösung führte dann endlich folgendes:</p>
<pre>RTE.default {
  ignoreMainStyleOverride = 0
  mainStyleOverride = hivar { color:darkred; usw. usf. }
}</pre>
<p>Hinter <strong>mainStyleOverride</strong> kann man natürlich alles mögliche packen, besonders wichtig ist die zweite Zeile. Ansonsten zeigt es keine Wirkung, egal was man tut!</p>
<h2>Grafiken über CSS im RTE</h2>
<p>Möchte man <strong>per CSS Grafiken einbinden</strong>, muss man zwei Ebenen nach oben wechseln um im Rootverzeichnis des Projektes zu landen. Von hieraus am besten straight zur eigenen Extension:</p>
<pre><code class="css">background-image:url(../../typo3conf/ext/hivars/ext_icon.gif)</code></pre>
<h2>Eigene Tags hinzufügen</h2>
<p>Besonders angenehm ist auch die relativ neue Funktion <strong>addToList</strong>, womit ein komplettes überschreiben der vorhandenen Einstellung vermieden wird:</p>
<pre>allowTags:=addToList(hivar)</pre>
<h2>Ausblick</h2>
<p>Demnächst, oder in dringenden Fällen auf Anfrage, gibt es die gesamte RTE Konfiguration. Davor muss ich noch einige Dinge erweitern, vervollständigen und die Wechselwirkungen mit vorhanden Einstellungen untersuchen. Zum Glück haben wir einige Projekte in denen ich testen kann und die verwirrten Redakteure beobachten wenn irgendwas nicht mehr funktioniert.</p>
<p>Hoffentlich bleibt es nicht für immer so warm...</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/07/28/aus-der-mitte-entspringt-ein-rte/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Plugin SpamKill!</title>
		<link>http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/</link>
		<comments>http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 17:03:06 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=45</guid>
		<description><![CDATA[Na, genervt vom Spam in den Kommentaren? Meine Erfahrungen mit den fiesen Spamrobotern habe ich jetzt in ein WordPress Plugin gepackt und biete es zum freien Einsatz an.
Hier auf dem Blog ist es schon im Einsatz, hat aber bisher noch nichts abwehren müssen. Direkt zum Download.

Funktionsweise
Die ausführliche Beschreibung finden Sie hier. Die Regeln habe ich [...]]]></description>
			<content:encoded><![CDATA[<p>Na, genervt vom Spam in den Kommentaren? Meine Erfahrungen mit den fiesen Spamrobotern habe ich jetzt in ein WordPress Plugin gepackt und biete es zum freien Einsatz an.<br />
Hier auf dem Blog ist es schon im Einsatz, hat aber bisher noch nichts abwehren müssen. <a href="http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/#download">Direkt zum Download</a>.</p>
<p><span id="more-45"></span></p>
<h2>Funktionsweise</h2>
<p><a href="http://www.interaktionsdesigner.de/2008/05/14/spamschutz-ohne-kompromisse/" target="_new">Die ausführliche Beschreibung finden Sie hier.</a> Die Regeln habe ich weiter vereinfacht. Mein PlugIn prüft aktuell nur 3 von 5:</p>
<ol>
<li><strong>Zeit</strong><br />
Ein Kommentator muss mind. 5s benötigen um einen Kommentar zu schreiben. Ansonsten ist er eine Machine.</li>
<li><strong>Vertauschte Bezeichnungen</strong><br />
Im HTML Formular sind Name und Emailfeld von den Bezeichnungen her vertauscht. Ist eine E-Mailadresse im Namenfeld eingetragen, handelt es sich mit ziemlicher Sicherheit um unerwünschte Werbung.</li>
<li><strong>Hiddenfield</strong><br />
Ein verstecktes Formularfeld (&lt;input type="hidden") muss leer bleiben. Spamroboter füllen meistens sinnlos alles aus.</li>
</ol>
<p>Schon wenn eine der Regeln zutritt wird der Kommentar abgewiesen.<br />
Zum verfolgen der Tätigkeiten wird eine simple Logdatei beschrieben. Dieses Verhalten sollte man bei vielen Spamnachrichten abschalten.</p>
<h2>Installation</h2>
<p>Nach dem Download in den Ordner <em>wp-content/plugins/</em> verschieben und im WordPress Backend aktivieren.</p>
<p>Anschließend müssen noch ein paar Dinge im Formular der Kommentareingabe angepasst werden. Je nach Theme unterschiedlich, meistens findet sich dies aber in der Datei <em>wp-content/themes/THEME-NAME/comments.php</em>.</p>
<ol>
<li><strong>Attribut Action vom Form-Tag</strong>
<p>Ich habe keinen anderen Weg gefunden in die Abarbeitung einzugreifen. Deshalb habe ich sie ersetzt. Das Attribut Action muss auf folgende Datei zeigen:</p>
<pre>&lt;?php echo get_option('siteurl'); ?&gt;/wp-content/plugins/id-spamkill/id-comments-without-spam.php</pre>
</li>
<li><strong>Bezeichnungen vertauschen</strong>
<p>Name und ID vom Namen und E-Mailfeld vertauschen. Nicht vergessen auch das for-Attribut vom Label anzupassen. Bei mir sieht es jetzt so aus:</p>
<pre><code class="html">&lt;p class="first"&gt;
	&lt;label for="email"&gt;Name &lt;?php if ($req) echo "(erforderlich)"; ?&gt;&lt;/label&gt;
	&lt;input class="styling" type="text" name="email" id="email" value="&lt;?php echo $comment_author; ?&gt;" size="22" tabindex="1" /&gt;
&lt;/p&gt;

&lt;p&gt;
	&lt;label for="author"&gt;eMail &lt;?php if ($req) echo "(erforderlich)"; ?&gt;&lt;/label&gt;
	&lt;input class="styling" type="text" name="author" id="author" value="&lt;?php echo $comment_author_email; ?&gt;" size="22" tabindex="2" /&gt;
	&lt;span&gt;(wird nicht veröffentlicht)&lt;/span&gt;
&lt;/p&gt;</code></pre>
</li>
<li>Innerhalb der beiden Form-Tags müssen die Hooks abgearbeitet werden. Auch das sollte bei den meisten Themes schon vorhanden sein:
<pre><code class="php">&lt;?php do_action('comment_form', $post-&gt;ID); ?&gt;</code></pre>
</li>
</ol>
<p>Zu guter letzt muss die Datei <em>wp-content/plugins/id-spamkill/id-spamlog.txt</em> für das Script noch beschreibbar gemacht werden (z.B. mit chmod(0777)). Das wars! Einträge werden gefiltert.</p>
<h2>Konfiguration</h2>
<p>Viel muss beim Plugin nicht konfiguriert werden. Da es so wenige Sachen sind sie noch nicht als "normale" Einstellungen über das Backend erreichbar sondern in der Datei <em>id-spamkill.php</em> zu finden. Ab Zeile 13 geht es los:</p>
<pre><code class="php">protected $logSpam = true;   // Spamlog speichern?
protected $logFile = "id-spamlog.txt";    // Datei in der das Spamlog gespeichert wird
protected $logSep = "\n-----------------------------------------------\n";    // Trennezeichen zwischen dein einzelnen Einträgen der Logdatei.</code></pre>
<h2 id="download">Download</h2>
<p>Das Plugin kann als <a href="http://www.interaktionsdesigner.de/wp-content/uploads/2008/07/id-spamkill-01.zip">Archiv herunter geladen werden</a>. Bei der Verwendung wäre eine kurze Nachricht nett.</p>
<h2>Fazit</h2>
<p>Das Plugin ist in einer sehr frühen Version und bietet noch viel Raum nach oben. Gerade die aufwendige Installation stört mich gewaltig, aber ich habe bisher keinen anderen Weg gefunden um so tiefgreifend das System zu verändern.</p>
<p>Ich habe ein gutes Gefühl und lade alle Besucher herzlich ein, mit mir zu beoachten welcher Spamkommentator es als erstes schafft durch zu kommen.</p>
<p>Bei Fragen, Problemen und Anregungen stehe ich gern zur Verfügung.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Save the Webdevelopers!</title>
		<link>http://www.interaktionsdesigner.de/2008/06/30/save-the-webdevelopers/</link>
		<comments>http://www.interaktionsdesigner.de/2008/06/30/save-the-webdevelopers/#comments</comments>
		<pubDate>Mon, 30 Jun 2008 13:56:26 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=41</guid>
		<description><![CDATA[Heute war ein schöner Tag im Feedreader betreffs Browserkompalibilität. Im außergewöhnlich guten Blog WebAppers finden sich 10 lesenswerte Punkte die es bei der Programmierung zu beachten gibt.
Besonders gefreut habe ich mich über den dritten Punkt: "Use -moz-opacity:0.99 on text elements to clean up rendering in Firefox". Gleich getestet und es stimmt: Mit dieser CSS Angabe [...]]]></description>
			<content:encoded><![CDATA[<p>Heute war ein schöner Tag im Feedreader betreffs Browserkompalibilität. Im außergewöhnlich guten Blog <a href="http://www.webappers.com/" target="_blank">WebAppers</a> finden sich <a href="http://www.webappers.com/2008/06/27/how-to-get-cross-browser-compatibility-every-time/" target="_blank">10 lesenswerte Punkte</a> die es bei der Programmierung zu beachten gibt.</p>
<p>Besonders gefreut habe ich mich über den dritten Punkt: "<em>Use -moz-opacity:0.99 on text elements to clean up rendering in Firefox</em>". Gleich getestet und es stimmt: Mit dieser CSS Angabe verhindert man das lästige zucken der Schrift bei JavaScript Effekten!</p>
<p>Insgesamt finde ich es aber falsch jedes Mal alle Schwächen vom IE6 auszubügeln. Den betreffenden Benutzern muss klar gemacht werden, dass sie alte und schlechte Software benutzen. Einen guten Weg geht die Initiative <a href="http://www.savethedevelopers.org/">SaveTheDevelopers.org</a>. Mit einem kleinen JavaScript werden die Besucher dezent auf den Umstand aufmerksam gemacht.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/06/30/save-the-webdevelopers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spamschutz ohne Kompromisse!</title>
		<link>http://www.interaktionsdesigner.de/2008/05/14/spamschutz-ohne-kompromisse/</link>
		<comments>http://www.interaktionsdesigner.de/2008/05/14/spamschutz-ohne-kompromisse/#comments</comments>
		<pubDate>Wed, 14 May 2008 13:36:00 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Papyros]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=35</guid>
		<description><![CDATA[Am meisten nerven überflutete Datenbanken voller Spam. Und auf dem zweiten Platz landen die Techniken das zu verhindern!
Nervige Captchas, Rechenaufgaben, Fragen; größtenteils leicht zu beantworten und trotzdem hinderlich. Hier kommt ein Weg um Spam in Gästebüchern zu verhindern und dabei volle Nutzerfreundlichkeit zu erhalten.
Möglich wird das komplett auf Seite des Servers damit der arme User [...]]]></description>
			<content:encoded><![CDATA[<p>Am meisten nerven überflutete Datenbanken voller Spam. Und auf dem zweiten Platz landen die Techniken das zu verhindern!<br />
Nervige Captchas, Rechenaufgaben, Fragen; größtenteils leicht zu beantworten und trotzdem hinderlich. Hier kommt ein Weg um Spam in Gästebüchern zu verhindern und dabei volle Nutzerfreundlichkeit zu erhalten.<br />
Möglich wird das komplett auf Seite des Servers damit der arme User nicht verwirrt wird.</p>
<p><span id="more-35"></span></p>
<p><strong>Jetzt auch als <a title="ID SpamKill Spam Kommentare verhindern" href="http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/">WordPress Plugin</a> verfügbar!</strong></p>
<h2>Ein Gästebuch voller Spam</h2>
<p>Das Gästebuch von <a href="http://www.papyros.org">Papyros</a> eignet sich zu testzwecken sehr gut. Selten schreiben echte Menschen, Bots werden aber magisch angezogen. Vor der Abschaltung waren es 30 bis 40 Einträge pro Tag die veröffentlich wurden. Dagegen wurden etwa 7000 aussortiert.</p>
<h2>Fünf einfache Regeln</h2>
<p>Nachfolgende Regeln wende ich auf jeden neuen Eintrag an. Die technische Umsetzung folgt.</p>
<ol>
<li><strong>Zeit</strong><br />
Ein Spamroboter will sehr viele Nachrichten verbreiten und das in möglichst kurzer Zeit. Das kann natürlich kein Mensch.<br />
Schon an einer Zeitspanne von mind. 5ms scheitern die meisten Bots.</li>
<li><strong>Vertauschte Bezeichnungen</strong><br />
Offensichtlich werden die Formulare auf simpelste Art und Weise gescannt, ohne Berücksichtigung der Labels. Wir vertauschen<br />
Name und Mailfeld. Sobald eine E-Mailadresse im "Mail"-Feld eingetragen wird, haben wir Spam! (ja, das ist verwirrend)</li>
<li> <strong>Hiddenfield</strong><br />
Ein verstecktes Feld (input type="hidden") muss leer bleiben damit die Nachricht akzeptiert wird.</li>
<li> <strong>Anzahl Links im Text</strong><br />
Links werden natürlich immer verbreitet. Den Benutzern ist ein Link pro Nachricht erlaubt.</li>
<li> <strong>Korrekte E-Mailadresse</strong><br />
Mit einem ganz langem regulären Ausdruck überprüfen wir die E-Mailadresse. Das führt überwiegend zu Erfolg.</li>
</ol>
<h2>Funktionierts?</h2>
<p>Ja! Seit guten 24 Stunden ist der Filter jetzt im <a href="http://www.papyros.org/gaestebuch.html">Einsatz</a> und hat<br />
schon 44 Nachrichten abgewiesen. Alle Nachrichten laden im Spamlog und sehen typischer Weise so aus:</p>
<pre>E-Mailadresse im Namenfeld
Zu viele Links im Text
Die E-Mailadresse ist nicht korrekt
---------------
Hi, The new changes to the site look great. &lt;a href= &lt;a href="http://www.flingblogger.com/hotfling6/senior-relationships-the-best-dating-site.html"&gt;senior relationships-the best dating [...]</pre>
<p>Für Informationszwecke logge ich die Nachrichten und Gründe der Ablehnung mit.</p>
<h2>Technische Umsetzung</h2>
<p><strong>HTML</strong><br />
Ein wirksamer Schutz lässt sich sehr schnell und einfach implementieren. Im Formular brauchen wir nur geringe Änderungen:</p>
<pre><code class="html">&lt;form method="post" action="gaestebuch.html<strong>?s=&lt;?=time()?&gt;</strong>"&gt;
	&lt;input type="hidden" name="nachname" value=""&gt;

		&lt;label for="mail"&gt;Name:&lt;/label&gt;
			&lt;input type="text" name="<strong>mail</strong>" value=""&gt;&lt;br&gt;

		&lt;label for="name"&gt;E-Mail:&lt;/label&gt;
			&lt;input type="text" name="<strong>name</strong>" value=""&gt;&lt;br&gt;

		&lt;label for="text"&gt;Eintrag:&lt;/label&gt;
				&lt;textarea name="text"&gt;&lt;/textarea&gt;&lt;br&gt;

		&lt;label&gt;&lt;/label&gt;
			&lt;input type="submit" value="Eintragen!" style="width:auto"&gt;
&lt;/form&gt;
	</code></pre>
<p>Name und E-Mailfeld sind intern bezeichnet. Werden "for" Attribute vom Labelelement eventuell vorgelesen?<br />
Zur Messung der Zeit wird die aktuelle Zeit als GET-Parameter mitübergeben.</p>
<p><strong>PHP</strong><br />
Die oben angesprochenen Regeln sind nichts weiter als einfache if-Statements. Fehlermeldungen werden in ein Array geschrieben,<br />
wenn dieses nicht leer ist, kein Eintrag im Gästebuch gemacht. So sieht das bei mir aus:</p>
<pre><code class="php">// === spam robot filter ===
$spam = Array();

// Wurde das Formular zu schnell ausgefüllt?
$pt = time() - $_GET["s"];
if($pt &lt; 5)
	$spam[] = "Zu schnell ausgefüllt ($pt ms)";

// Vertauschte Bezeichnungen Name und Mail
if(ereg('^[-!#$%&amp;\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.'@'.'[-!#$%&amp;\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.'[-!#$%&amp;\'*+\\./0-9=?A-Z^_`a-z{|}~]+$', $_POST["mail"]))
	$spam[] = "E-Mailadresse im Namenfeld";

// Leeres Feld Nachname
if(!empty($_POST["nachname"]))
	$spam[] = "Eingabewerte im Hiddenfeld 'Nachname'";

// Anzahl Links im Text
if(substr_count($text, "http://") &gt; 1)
	$spam[] = "Zu viele Links im Text";

// E-Mailadresse korrekt?
if(!ereg('^[-!#$%&amp;\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.'@'.'[-!#$%&amp;\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.'[-!#$%&amp;\'*+\\./0-9=?A-Z^_`a-z{|}~]+$', $_POST["name"]))
	$spam[] = "Die E-Mailadresse ist nicht korrekt";

	</code></pre>
<p>Fertig!</p>
<h2>Probleme</h2>
<p>Mal abgesehen davon das niemand mehr Gästebucheinträge schreibt, ist mir noch nichts kritisches aufgefallen. Vielleicht könnte durch das verschicken, ausdrucken, einscannen und hochladen des Formulars der Timestamp durcheinander kommen.</p>
<h2>Erweiterungen</h2>
<p>Sollten die Bots es irgendwann geschafft haben und Einträge verfassen, dann habe ich noch ein paar Dinge, die ich gerne ausprobieren würde. Dazu dann bei Gelegenheit. Bisher läuft es wunderbar.</p>
<h2>Fazit</h2>
<p>Genau heute kam der erste Spamkommentar über diesen Blog rein. <span style="text-decoration: line-through;">Wie schreibt man WordPress Plugins?!</span> <a href="http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/">Hier ist ein Vorschlag!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/05/14/spamschutz-ohne-kompromisse/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
