PHP / MySQL / Linux Stories https://xfragger.de Meine Erfahrungen in der Webentwicklerwelt Sun, 06 Oct 2013 21:52:35 +0000 de-DE hourly 1 Yahoo akzeptiert meine E-Mails nicht https://xfragger.de/396/yahoo-akzeptiert-meine-e-mails-nicht https://xfragger.de/396/yahoo-akzeptiert-meine-e-mails-nicht#comments Sun, 06 Oct 2013 21:47:50 +0000 https://xfragger.de/?p=396 Mein privater Server wird, neben dem Hosting einiger Webseiten/Blogs, auch für den E-Mail-Empfang und -Versand genutzt. Bisher klappte das ziemlich gut und durch diverse Anti-Spam Maßnahmen, bin ich bisher weder im Spamordner meiner Empfänger gelandet, noch bekomme ich extrem viel Spam. Nun habe ich mich gewundert, dass eine Mail an einen Bekannten (***@yahoo.com) nicht zugestellt wurde, Begründung laut log:
postfix/smtp[30458]: 93DE398058A: to=<***@yahoo.de>, relay=mx-eu.mail.am0.yahoodns.net[188.125.69.79]:25, delay=139000, delays=138999/0.07/0.43/0, dsn=4.7.1, status=deferred (host mx-eu.mail.am0.yahoodns.net[188.125.69.79] refused to talk to me: 421 4.7.1 [TS03] All messages from 178.238.228.114 will be permanently deferred; Retrying will NOT succeed. See http://postmaster.yahoo.com/errors/421-ts03.html)


Ich habe diese IP erst seit rund vier Wochen und habe bisher zwei (!!) E-Mails an Yahoo verschickt, welche übrigens NIE ankamen.
Ich habe LANGE gelesen und nicht wirklich Hilfe gefunden, erst google konnte helfen, dabei traf ich auf diese Hilfe-Seite eines amerikanischen Anbieters für virtuelle Server: https://www.intovps.com/client/knowledgebase/15/Yahoo-rejects-your-e-mail-messages–421-.html

Kurz und bündig: Im Text behauptet Yahoo, sie melden diesen Fehler NUR, wenn man Spam versendet hat, was in 99% der Fälle nicht stimmt. Sie lehnen auch NEUE IP-Adressen ab.
Was soll das bitte?
Voraussichtliche Lösung des Problems: Dieses Formular wahrheitsgetreu ausfüllen und hoffen
http://help.yahoo.com/l/us/yahoo/mail/postmaster/bulk.html

Was mich an der ganzen Sache extrem stört: Status Codes im Bereich von 400-499 werden einfach “erneut versucht”. Diese Bedeuten normalerweise “da klappt GERADE etwas nicht, versuchs später wieder”. Das heißt, hätte ich nicht zufällig ins Log geschaut bzw. bescheid bekommen, dass jemand auf meine Mail wartet, hätte ich NIE davon Wind bekommen. Was soll das bitte?

]]>
https://xfragger.de/396/yahoo-akzeptiert-meine-e-mails-nicht/feed 0
NodeJS Modul: Watermarker https://xfragger.de/388/nodejs-modul-watermarker https://xfragger.de/388/nodejs-modul-watermarker#comments Tue, 13 Aug 2013 04:44:02 +0000 https://xfragger.de/?p=388 Ich suchte eine Zeit lang nach einem Tool, um möglichst schnell und einfach einen kompletten Ordner mit Bildern darin auf eine maximale Seitenlänge (je nach Format: Höhe oder Breite) zu beschneiden und ein Wasserzeichen (in eine der Ecken oder mittig) daraufzulegen.

Nachdem ich lange suchte aber nichts kostenloses fand (sah keinen Grund, für so eine einfache Aufgabe ein Tool zu bezahlen), entschied ich mich, das Problem selbst in die Hand zu nehmen. Da ich in den letzten Monaten recht viel mit NodeJS zu tun hatte, war dies das Werkzeug meiner Wahl.

Das, nennen wir es “Projekt”, war innerhalb kurzer Zeit als erster Prototype fertig, habe es dann noch ein wenig “aufgebohrt”, es bei GitHub hochgeladen und auf NPM veröffentlicht.

Es gibt (bisher) lediglich zwei Abhängigkeiten: Async, um einige Abläufe zu parallelisieren und easy-gd, um die Bilder zu beschneiden und das Wasserzeichen draufzulegen.

Die Lösung ist sehr schnell (wenige Sekunden für 30 Bilder auf meinem MacBook Pro I7), absolut zufriedenstellend und via Konsole parametrisierbar. Verbesserungsvorschläge sind via pull-request jederzeit willkommen!

Solltest Du es ausprobieren wollen, benötigst du ein installiertes “gd” (unter MacOSX am besten via “brew install gd”) und ein installiertes NodeJS (>=0.10.0), die “globale” Installation erfolgt dann einfach via “npm install -g node-watermarker” und der Aufruf im Terminal via “nodewatermarker”. Syntax bzw. Konsolenparameter werden dann ausgegeben.

]]>
https://xfragger.de/388/nodejs-modul-watermarker/feed 0
Thunderbird Autokonfiguration für die eigene Domain https://xfragger.de/344/thunderbird-autokonfiguration-fur-die-eigene-domain https://xfragger.de/344/thunderbird-autokonfiguration-fur-die-eigene-domain#comments Thu, 07 Mar 2013 19:33:50 +0000 https://xfragger.de/?p=344 Ihr kennt das, ihr betreibt einen eigenen E-Mail-Server und bei jedem Einrichten eines Postfachs im E-Mail-Client eures Vertrauens, dürft ihr SMTP/IMAP Adresse, sowie SSL/TLS Einstellungen von Hand vornehmen, weil Thundebird diese Daten nicht automatisch ermitteln kann (bzw. es versucht, es aber meistens nicht stimmt, spätestens beim Format des Usernames).

Thunderbird bietet die Möglichkeit, unter der Domain “autoconfig.domain.de” eine XML Datei unter dem Pfad /mail/config-v1.1.xml, für genau diese Einstellungen anzulegen. Andere Mail-Client beachten diese Datei mittlerweile auch (fragt mich bitte nicht welche).

Also, schnell die XML Zusammengebaut (der Block lässt sich mehrfach, einer für jede Domain, wiederholen).

<clientConfig version="1.1">
    <emailProvider id="xfragger.de">
 
        <domain>xfragger.de</domain>
        <displayName>xfragger.de Mail</displayName>
        <displayShortName>xfragger.de</displayShortName>
 
        <incomingServer type="imap">
            <hostname>mail.xfragger.de</hostname>
            <port>993</port>
            <socketType>SSL</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </incomingServer>
 
        <outgoingServer type="smtp">
            <hostname>mail.xfragger.de</hostname>
            <port>25</port>
            <socketType>STARTTLS</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </outgoingServer>
 
    </emailProvider>
 
</clientConfig>

Nun noch dem nginx beibringen, dass er diese Datei für jeden erdenklichen Request an die entsprechende Subdomain ausliefert.

server {
        root /usr/share/nginx/www/autoconfig;
        server_name autoconfig.xfragger.de;
        server_name autoconfig.domain.de;

        try_files $uri /config-v1.1.xml;
}

Hilfreiche Links/Quellen

developer.mozilla.org/en-US/docs/Thunderbird/Autoconfiguration

developer.mozilla.org/en-US/docs/Thunderbird/Autoconfiguration/FileFormat/HowTo

Beginnt man nun sein E-Mail-Konto im Thunderbird einzurichten, bekommt man, nach Eingabe von E-Mail-Adresse und Passwort, folgendes zu sehen:

]]>
https://xfragger.de/344/thunderbird-autokonfiguration-fur-die-eigene-domain/feed 1
Exception: Zend Extension ./filename.php does not exist https://xfragger.de/340/exception-zend-extension-filename-php-does-not-exist https://xfragger.de/340/exception-zend-extension-filename-php-does-not-exist#comments Fri, 01 Feb 2013 05:27:28 +0000 https://xfragger.de/?p=340 Was hat das zu bedeuten?

Wenn man sich auf der Konsole befindet, ruft man ein php-Skript entweder via “php ./filename.php” auf oder fügt in der ersten Zeile eine Interpreterdefinition ein: “#!/usr/bin/php”, danach beginnt das Skript, wie gewohnt, mit Wenn man die Datei nun ausführbar macht (chmod +x filename.php) kann man sie direkt via ./filename.php aufrufen, genau das ist es, was ich mit normalerweise mit cron-jobs mache.

Nun habe ich die genannte Zeile bei rund 20 Skripten eingefügt, die Dateien ausführbar gemacht und bei ca. jeder zweiten, war das Ergebnis das im Titel des Beitrag genannte, ohne dass das Skript wirklich ausgeführt wurde. Recherchen im Netz ergaben, dass das kein unbekanntes Problem sei, aber entweder existierte der StackOverflow-Artikel nicht mehr oder es gab keine Antworten auf die Frage in diversen Foren.

Die Lösung ist ganz einfach: DOS-Zeilen-Enden

OS X und Unix-Systeme nutzen nur einen “LineFeed” (\n), Window dagegen ein CarriageReturn und einen LineFeed (\r\n) um eine Zeile zu beenden. Ist die Datei nun im Window-Format, taucht oben genannter Fehler auf, wenn man versucht, das Skript auf einem Unix-System auszuführen.

Für das Problem gibt es diverse Lösungen, da “dos2unix” nicht zur Verfügung stand, schrieb ich mein eigenes Shellskript, welches alle \r-Zeichen aus einer übergebenen Datei löscht. Ein Konsolenbefehl hätte es getan, aber ich wollte das Ganze während des Deployvorgangs auslösen (und zwar nur für den cron-Ordner).


#!/bin/bash
tr -d '\r' < $1 > /tmp/dos2unix
cat /tmp/dos2unix > $1
rm /tmp/dos2unix

Im Deployskript folgte dann noch dieser Aufruf:

find $pathToCron -type f -name "*.php" -exec [$pathToDos2Unix.sh] \'{}\' \;

]]>
https://xfragger.de/340/exception-zend-extension-filename-php-does-not-exist/feed 0
Bildmanipulation: Seitenverhältnisse beibehalten https://xfragger.de/323/bildmanipulation-seitenverhaltnisse-beibehalten https://xfragger.de/323/bildmanipulation-seitenverhaltnisse-beibehalten#comments Wed, 21 Nov 2012 10:39:45 +0000 https://xfragger.de/?p=323 An sich eine einfache Aufgabe, aber da ich immer wieder damit kollidiere und mich jedes mal neu reindenken darf (ja ich weiß, es gibt Libs dafür, aber diese sind nicht in jedem Projekt verfügbar), dachte ich mir, den Code jetzt einfach mal hier festzuhalten.

In diesem speziellen Fall, geht es darum, dass ein hochgeladen wird und die Seitenverhältnisse einer “Box” angepasst werden müssen.
Es gibt zwei Faktoren, die das ein wenig komplizieren.
1. Das Bild ist in Pixeln definiert, die Box in mm, die “einfache Variante” (maxWidth und maxHeight als Input) geht also nicht
2. Die “Box” darf weder breiter noch höher, nur schmaler oder flacher werden

$imageRatio = $imageWidth / $imageHeight; //pixel
$elementRatio = $element->getWidth() / $element->getHeight(); //mm
if ($imageRatio == $elementRatio) {
    continue;
} elseif (($imageRatio > 1 && $elementRatio > 1) || ($imageRatio < 1 && $elementRatio < 1)) {
    //landscape+landscape OR portrait+portrait
    if ($imageRatio > $elementRatio) {
        $newHeight = $element->getWidth() / $imageRatio;
    } else {
        $newWidth = $element->getHeight() * $imageRatio;
    }
} elseif ($imageRatio >= 1 && $elementRatio <= 1) {
    //landscape/square + portrait/square
    $newHeight = $element->getWidth() / $imageRatio;
} elseif ($imageRatio <= 1 && $elementRatio >= 1) {
    //portrait/square + landscape/square
    $newWidth = $element->getHeight() * $imageRatio;
}
$element->setWidth($newWidth);
$element->setHeight($newHeight);
]]>
https://xfragger.de/323/bildmanipulation-seitenverhaltnisse-beibehalten/feed 0
Developers Shame Day 2010 https://xfragger.de/312/developers-shame-day-2010 https://xfragger.de/312/developers-shame-day-2010#comments Wed, 03 Nov 2010 06:35:10 +0000 https://xfragger.de/?p=312 PHP hates me Autor Nils nimmt am Developers-Shame-Day 2010 teil und ich dachte mir, ich suche auch mal in den Untiefen meines alten Codes nach einem Schmuckstück. Ursprünglich kam die Idee zum DevShameDay von “Cem, dem PHP-Hacker”.
Leider ging in den Jahren einiges verloren, aber ich denke, dass hier ist schlecht genug, um sich dafür zu schämen.

Ich Schätze das ist um 2004 entstanden und lieferte Termine bzw. Events von einem bestimmten Tag, das ganze für einen Webkalender ala Google-Calendar. Was ich noch erwähnen sollte…. die Funktion wurde für jeden sichtbaren Kalendertag aufgerufen!

 function getevents($year,$month,$day){
   global $SELF;
   $month = (strlen($month) < 2) ? '0'.$month : $month;
   $day = (strlen($day) < 2) ? '0'.$day : $day;
   $str = "$year-$month-$day";
   $strx = "$month-$day";
   $sql = "
           SELECT e.name as ename,
                                                e.description as edescr,
                                                e.id as eid,
                                                t.color as tcolor,
                                                e.time_start as time_start,
                                                e.time_end as time_end,
                                                e.remember as rem,
                                        e.date_start as date_start,
                                                e.date_end as date_end,
                                                t.description as tdescription,
                                                t.showtime as showtime
           FROM cal_entry e, cal_types t
           WHERE e.types_id = t.id
             AND (e.date_start <= '$str'
                           AND ( e.date_end >= '$str' AND e.date_end IS NOT NULL OR e.date_start = '$str' AND e.date_end IS NULL )
         OR(t.id = 1 AND right(e.date_start,5) = '$strx')
                         )
                        ORDER BY e.time_start, t.prio
         ";
   $res = mysql_query($sql);
   $out = "<u><a href=\"$SELF?show=new&date=$year-$month-$day\">$day.$month.</a></u>";
   while($row = mysql_fetch_array($res)){
     $tmp = "<a href=\"$SELF?show=edit&eid=".$row["eid"]."&ym=$year-$month\">";
 
                 $tmp .= "<font class=\"entry\" color=\"".$row["tcolor"]."\"><li>";
                 $tmp .= $row["ename"];
                 $starta = explode("-",$row["date_start"]);
                 $outstart = $starta[2].".".$starta[1].".".$starta[0];
                 $enda = explode("-",$row["date_end"]);
                 $outend = $enda[2].".".$enda[1].".".$enda[0];
                 $divbody = "<table border=0 class=entry><tr>";
                 if($row["date_end"] != '' && $row["date_start"] != $row["date_end"]){
                   $divbody .= "<td>Von:</td><td>$outstart</td></tr><tr><td>Bis:</td><td>$outend</td></tr>";
                 }else{
                   $divbody .= "<td>Am:</td><td>$outstart</td></tr>";
                 }
                 if($row["showtime"]) {
                     if(($row["date_end"] == $row["date_start"] || $row["date_end"] == '') && $row["time_end"] != ''){
                       $divbody .= "<tr><td>Von:</td><td>".$row["time_start"]." Uhr</td></tr>";
                             $divbody .= "<tr><td>Bis:</td><td>".$row["time_end"]." Uhr</td></tr>";
                     }elseif($row["date_start"] < $row["date_end"] && $row["date_start"] == $str && $row["time_start"] != ''){
                           $divbody .= "<tr><td>Ab:</td><td>".$row["time_start"]." Uhr</td></tr>";
                     }elseif($row["date_start"] < $row["date_end"] && $row["date_end"] == $str && $row["time_end"] != ''){
                       $divbody .= "<tr><td>Bis:</td><td>".$row["time_end"]." Uhr</td></tr>";
                     }elseif(($row["date_end"] == $row["date_start"] || $row["date_end"] == '') && $row["time_end"] == ''){
                       $divbody .= "<tr><td>Ab:</td><td>".$row["time_start"]." Uhr</td></tr>";
                     }
                 }
                 $rem = ($row["rem"] == true) ? "<font color=green>EMail Erinnerung aktiv</font>" : "<font color=red>EMail Erinnerung inaktiv</font>";
                 $divbody .= "</table>";
                 #$div = "<div title=\"header=[".$row["ename"]."] body=[".$row["edescr"].$divbody"]\">";
                 $div = '<div title="header=['.$row["ename"].'] body=['.nl2br($row["edescr"]).$divbody.$rem.']">';
                 $tmp .= "</div></li></font></a>";
                 $out .= $div.$tmp;
         }
 
   return $out;
 }
]]>
https://xfragger.de/312/developers-shame-day-2010/feed 1
lighttpd: Alle Subdomains auf www.domain.tld umleiten https://xfragger.de/298/lighttpd-alle-subdomains-auf-www-domain-tld-umleiten https://xfragger.de/298/lighttpd-alle-subdomains-auf-www-domain-tld-umleiten#comments Tue, 24 Aug 2010 16:33:26 +0000 https://xfragger.de/?p=298 Ich stand vor kurzem vor dem Problem, das alle Subdomains, die ein Benutzer eingeben könnte, auf www.example.com umleiten sollten.

Aus Googlesicht ist das gut, weil so doppelter Inhalt vermieden wird und für den Benutzer ist es einfach schöner.

Im Internet habe ich einige Beispiele gefunden, wie man www.example.com auf example.com und umgekehrt umleitet, aber keine generelle Lösung. Die Hostdefinition matcht *example.com und *.example.de, weitere sind ohne weiteres möglich.

$HTTP["host"] =~ "^(.*example\.(com|de)$" {
        server.document-root = "/var/www/example.com"
        server.error-handler-404 = "/index.php"
 
        $HTTP["host"] !~ "^(www\.(.*)\.(.*))$"{  #nur wenn es nicht schon www. ist
                $HTTP["host"] =~ "^(.*)\.(.*)\.(.*)$" {   #falls es sich um xxx.*.* handelt
                        url.redirect = ( ".*" => "http://www.%2.%3" )
                }
                $HTTP["host"] =~ "^([^.]*)\.([^.]*)$" {    #falls es sich um *.* handelt (ohne Subdomain)
                        url.redirect = ( ".*" => "http://www.%1.%2" )
                }
 
        }
}

Will man nun noch forum.example.de (nur die .de Variante) erlauben, muss man diese Expression “^(www\.(.*)\.(.*))$” auf “^(www\.(.*)|forum\.example\.de)$” abändern.

]]>
https://xfragger.de/298/lighttpd-alle-subdomains-auf-www-domain-tld-umleiten/feed 0
HTML zu PDF umwandeln, endlich “einfach” (Plattformunabhängig) https://xfragger.de/286/html-zu-pdf-umwandeln-endlich-einfach-plattformunabhangig https://xfragger.de/286/html-zu-pdf-umwandeln-endlich-einfach-plattformunabhangig#comments Sun, 01 Aug 2010 12:47:26 +0000 https://xfragger.de/?p=286 Mal wieder auf der Suche nach einer sinnvollen HTML2PDF Lösung, bin ich auf wkhtmltopdf gestoßen.

Das Tool nutzt Webkit im internen Backend und kann sogar CSS3 rendern. Die Installation unter MaxOSX und Linux ist absolut simpel: runterladen, ablegen, fertig. Unter Windows wird hier noch ein Installationsprozess durchgeführt, über den ich aktuell leider nichts sagen kann (bisher nicht getestet).

Um das Tool auf einer Webseite zu nutzen, habe ich mir ne kleine Klasse geschrieben, die HTML-Code als Input akzeptiert und mir den Pfad der fertigen PDF-Datei zurückliefert.

class HtmlToPdf {
	const TMP = '/tmp/';
	const EXEC = '/usr/local/bin/wkhtmltopdf-amd64'; //anpassen!
	private $executable;
	private $htmlcode;
	private $tmphtmlfile;
	private $targetFilename;
 
	private $options = array(
		'--ignore-load-errors'
	); //Kommandozeilenoptionen für wkhtmltopdf
 
	public function __construct($targetFilename = ''){
		$this->targetFilename = $targetFilename;
	}
 
	public function setHtmlCode($htmlcode){
		$this->htmlcode = $htmlcode;
	}
 
	public function setTargetFilename($targetFilename){
		$this->targetFilename = $targetFilename;
	}
 
	public function generate(){
		$this->createTempHtmlFile();
		$this->convertHtmlfileToPdf();
		return self::TMP.$this->targetFilename;
	}
 
	private function createTempHtmlFile(){
		$filename = tempnam(self::TMP);
		File::move($filename, $filename.'.html'); //nötig, damit die Datei als Input akzeptiert wird
		$filename .= '.html';
		file_put_contents($filename, $this->htmlcode);
		$this->tmphtmlfile = $filename;
	}
 
	private function convertHtmlfileToPdf(){
		if(!$this->targetFilename){
			$this->generateTargetFilename();
		}
		$cmd = self::EXEC.' '.implode(' ', $this->options).' '.$this->tmphtmlfile.' '.self::TMP.$this->targetFilename;
		shell_exec($cmd);
		File::delete($this->tmphtmlfile);
	}
 
	private function generateTargetFilename(){
		$this->targetFilename = uniqueid().'.pdf';
	}
}

Und so nutzt man das Ganze:

$converter = new HtmlToPdf('output.pdf');
$converter->setHtmlCode($htmlcodeWithCSS);
$pdfFile = $converter->generate()

Sehr praktisch ist es, wenn man eine Templateengine (z.B. Smarty) nutzt, hier kann man erst den kompletten Code generieren und ihn dann via $smarty->fetch() in den Konverter übergeben. Über einen Parameter kann man dann noch dafür sorgen, dass der CSS Style nicht ausgelagert, sondern im head-Block ausgegeben wird, da das Tool sonst nicht damit klarkommt.

]]>
https://xfragger.de/286/html-zu-pdf-umwandeln-endlich-einfach-plattformunabhangig/feed 3
PHP 5.3 DateTime Objekt – schwerwiegender Bug? https://xfragger.de/275/php-5-3-datetime-objekt-schwerwiegender-bug https://xfragger.de/275/php-5-3-datetime-objekt-schwerwiegender-bug#comments Wed, 14 Jul 2010 20:14:29 +0000 https://xfragger.de/?p=275 Eigentlich war ich ziemlich begeistert, vom DateTime Objekt. Endlich richtig einfach mit Daten umgehen und das auch noch inkl Zeitzonen etc.
Seitdem ich allerdings mit einem Kollegen einen wirklich “krassen” Bug fand, bin ich nicht mehr so begeistert!

Reproduzierbar ist er folgendermaßen:

$from = new DateTime();
$from->setTime(0, 0, 0);
$from->setISODate(2010, 28, 1); //Montag der 28ten Woche 2010
 
echo $from->format('d.m.Y H:i'); //A
echo $from->getTimestamp(); //B
echo date('Y-m-d H:i', $from->getTimestamp()); //C

A: das ausgegeben Datum stimmt, es ist der 12.07.2010
B: der Timestamp ist viel zu hoch: 1291849200
C: der Beweis, der Timestamp gehört zum 29.05.2011 00:00

Wir haben lange versucht herauszufinden, warum dies passiert. Ein hässlicher Workaround ist dieser:

$from->add(new DateInterval('P0D'));

Wir fügen also ein Interval von 0 Tagen (oder Stunden, Minuten etc) hinzu, wodurch sich eigentlich nichts ändern sollte. Danach stimmt das Ergebnis von ->getTimestamp() allerdings, nämlich 1278885600.

Nachdem wir absolut keinen Grund feststellen konnten, haben wir das Vertrauen verloren und nutzen seitdem Zend_Date, welches, meiner Meinung nach, besser und einfacher zu bedienen ist. Das ZendFramework ist sowieso schon im aktuellen Projekt eingebunden (nicht als Framework an sich, eher als Klassensammlung), als sprach es auch nicht dagegen, einen riesen Klotz an Dateien/Klassen zu integrieren, um nur eine Klasse zu nutzen.

$date = new Zend_Date();
$date->setWeek(28)->setYear(2010)->setWeekday(1);
$date->setHour(0)->setMinute(0)->setSecond(0);
echo $date->getTimestamp();

Liefert das erwartete Ergebnis: 1278885600

Ist das nun wirklich ein riesen DateTime Bug oder liegt ein Denkfehler unsererseits vor?

]]>
https://xfragger.de/275/php-5-3-datetime-objekt-schwerwiegender-bug/feed 2
Iterator oder IteratorAggregated Interface nutzen? https://xfragger.de/266/iterator-oder-iteratoraggregated-interface-nutzen https://xfragger.de/266/iterator-oder-iteratoraggregated-interface-nutzen#comments Mon, 28 Jun 2010 20:30:56 +0000 https://xfragger.de/?p=266 PHP bietet das Iterator Interface an, um Objekte direkt via foreach zu iterieren.

class MyClass implements Interator {
  private $array;
}
 
$obj = new MyClass();
foreach($obj as $key => $val){
  ...
}


Damit dieses Konstrukt funktioniert, benötigt die Klasse “MyClass” ein paar weitere Methoden und ein Attribut, welche vom Interface vorgeschrieben werden:

public function rewind(){
  $this->pointer = 0;
}
public function current(){
  return $this->array[$this->pointer];
}
public function key(){
  return $this->pointer;
}
public function next(){
  $this->pointer++;
}
public function valid(){
  return isset($this->array[$this->pointer]);
}

Nun geht das ganze aber auch viel einfacher und mit saubererem Code, mit dem IteratorAggregate Interface und einem schon vorhandenem Iterator (wie dem ArrayIterator). Das Interface ist ziemlich Ähnlich und implementiert ebenfalls Traversable.

class MyClass implements IteratorAggregate {
  private $array;
  public function getIterator(){
    return new ArrayIterator($this->array);
  }
}
 
$obj = new MyClass();
foreach($obj as $key => $value){
  ...
}
]]>
https://xfragger.de/266/iterator-oder-iteratoraggregated-interface-nutzen/feed 2