Home
Navigation
Impressum
Coder Welten - Programmierung und Optimierung
Feedreader mit cURL und SimpleXML

Zum Auslesen von RSS- und Atom-Feeds und zum Parsen von CDATA-Abschnitten

HM-Feedleser (Variante mit cURL - Release-Version 1.04)

Vorstellung und Beschreibung des Scripts:

  1. Feedreader mit SimpleXML (Einführung und Vorstellung eines Scripts für einen sicheren Feedreader...)
  2. Feedreader File (Einzelheiten zum Code - Variante mit file_get_contents)
  3. Feedreader mit cURL (Code mit der cURL-Variante und ergänzende Hinweise)
  4. Zugehörige Dateien (Formular, Formular-Klasse und eine CSS-Dateie)
  5. Variante mit Feed-Klasse (zur leichteren Einbindung in HTML-Seiten, Version 1.06)
  6. Feed-Klasse und Methoden (nur für HM-Feedleser ab Version 1.06)
  7. Plugin für WordPress (Feedreader als Plugin für WordPress, Version 1.08)

Sicherheit, Funktionsweise, Lizenz und Verwendung

Wesentliche Hinweise zur Sicherheit und zur Funk­tions­weise, weiter­hin zur Lizenz und zur Verwendung des XML-Feedreaders, wurden bereits einführend vermerkt. Falls Fragen zur Funktions­weise und Ver­wendung be­stehen sollten, lesen Sie bitte zuerst die Ein­führung einschließlich den Vorbemerkungen unter:

» Script für einen sicheren Feedreader...

Ergänzende Hinweise

Beim Code-Listing auf dieser Seite handelt es sich um eine Variante, die mit der PHP Version 5.2 und 5.3 getestet wurde. Im Unterschied zu den Varianten, die nur für PHP ab der Version 5.3 ausgelegt sind, wurden die beiden preg_replace_callback Funktionen nicht als ano­nyme Funktionen sondern noch mit create_function() erstellt. Der restliche Code unter­scheidet sich hingegen nicht von den anderen Varianten bzw. nur durch die Verwendung von file_get_contents und cURL.

Bevor Sie dieses Script testen, sollten Sie sich vergewissern, dass ein Zugriff auf die cURL-Funktionen besteht. Bei Aufruf Ihrer PHP-Info-Datei sollte unter dem Stichpunkt cURL ein Eintrag mit cURL support enabled erscheinen.
Falls dies nicht der Fall sein sollte, muss in der Datei php.ini das Semikolon vor dem Eintrag extension=php_curl.dll entfernt werden, vor­aus­gesetzt es besteht Zugriff auf diese Konfigu­rations­datei.
Weiterhin sollten Sie sich vergewissern, welche PHP Version Ihnen zur Verfügung steht.

Obwohl ebenfalls bereits auf der vorausgehenden Seite auf die Verwendung des Formulars hingewiesen wurde, möchten wir diesen Hinweis noch einmal wiederholen. Benutzen Sie das Formular mög­lichst nur zur Erprobung oder in einem durch ein Passwort geschütz­ten Bereich und blenden Sie das Formular in frei zu­gäng­lichen Bereichen und im Web auf frei zugänglichen Seiten aus. Nur so können Sie gewährleisten, dass Unbefugte keine Feeds aus frag­würdigen oder unsicheren Quellen laden können.

Weitere ergänzende Hinweise zum Thema Sicherheit und zu den einzelnen Funktionen finden Sie auf der Seite: Feedreader File

Nachfolgend eine Übersicht des Inhalts der zum Feed­reader gehören­den Datei, sowie Links zur Seite mit der Lizenz und zum Download.


Code der zum HM-Feedleser gehörenden Dateien:

Bitte vor einem Download lesen:

» Script für einen sicheren Feedreader...

» Lizenz für Software

Download »

Neuste Version » Zum leichteren Einbinden in bestehende Webseiten wurden bei dieser Version die Funktionen zu einer Klasse vereint und ausgelagert »

Weitere Versionen »


Code-Listing der Datei feedleser.php

<?php
/*------------------------------------------------------------------------------------------------------------------
 Software-Name: HM-Feedleser (http://www.coder-welten.de/projekte/feedreader.htm)
 Beschreibung:  PHP-Script für einen sicheren Feedreader mit SimpleXML für RSS- und Atom-Feeds.
 Einzelheiten:  http://www.coder-welten.de/projekte/feedreader-curl.htm
 Autor:         Horst Müller
 Version:       Release 1.04 (Variante mit cURL)
 Datum:         09. Juni 2013
 Lizenz:        Lizenz für Software - http://www.coder-welten.de/projekte/lizenz-fuer-software.htm
 Copyright:     © 2006/2013 - Verlag Horst Müller - Stendal
 -------------------------------------------------------------------------------------------------------------------
*/
$agent = "Mozilla/5.0 (compatible; HM-Feedleser +".$_SERVER["HTTP_HOST"].$_SERVER["PHP_SELF"].")";
ini_set("user_agent", $agent);
header("Content-Type: text/html; charset=UTF-8");

/*-- Die folgenden Werte sollten bei Bedarf editiert werden, $seite = "" muss editiert werden. -------------------*/

error_reporting(E_ALL);                  // Der Wert kann nach Erprobung von E_ALL auf 0 gesetzt werden

/*-- Die Datei oder die Web-Adresse des zu ladenden Feeds, Datei ohne http:// und URL mit http:// eintragen. -----*/

$seite = "http://www.coder-welten.de/projekte/testfeed.rss";
$linkt = "» Weiterlesen «";              // Linktext für den unteren Link
$feedt = "Feed - ";                      // Für den einleitenden Titel des Feeds, kann auch leer bleiben
$maxim = 12;                             // Maximale Anzahl der Ergebnisse pro Seite
$formu = true;                           // Formular anzeigen gleich "true" oder nicht anzeigen gleich "false"
$descr = true;                           // Description anzeigen gleich "true" oder ausblenden gleich "false"
$conte = true;                           // Content anzeigen gleich "true" oder ausblenden gleich "false"
$summa = true;                           // Summary anzeigen gleich "true" oder ausblenden gleich "false"
$maxho = 250;                            // Maximale Höhe für eingebundene Bilder angeben
$maxwe = 250;                            // Maximale Weite für eingebundene Bilder angeben
define("SCHLIESSE", ">");                // Für valides HTML je nach Dokumenttyp-Deklaration bei HTML ">" oder bei XHTML " />"

/*------------------------------------------------------------------------------------------------------------------
 Nachfolgend der HTML-Header der Seite. Sollte das Script in eine andere HTML-Seite eingebunden werden, so ist zu
 berücksichtigen, dass vor ini_set und header() keine Ausgabe von HTML erfolgen darf, auch keine Ausgabe von
 Quelltext oder Leerzeichen.
 -------------------------------------------------------------------------------------------------------------------
*/
?>
<!DOCTYPE html>
<html>

<head>
<title>Feedreader</title>
<?php echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"feedstyle.css\"".SCHLIESSE."\n"; ?>
</head>

<body>
<h1>Feedreader für RSS und Atom</h1>
<?php
/*------------------------------------------------------------------------------------------------------------------
 Ab hier sollte ohne einschlägige Kenntnisse nichts mehr editiert werden. Das Formular für den Aufruf von Feeds von
 unterschiedlichen Web-Adressen kann bei Bedarf über den Wert von $formu ein- oder ausgeblendet werden.
 -------------------------------------------------------------------------------------------------------------------
*/
if ($formu == true) {

    if (file_exists("feedformular.php")) {

        include_once "feedformular.php";

    } else {echo "Formular konnte nicht geladen werden!\n";
    }
}

/*-- Die Funktion wandelt Tags und behandelt Entities außerhalb von CDATA-Abschnitten, falls erforderlich. -------*/

function wandleTags($daten) {

    $wandle  = array(

        "content:encoded" => "content",
        "dc:creator"      => "creator",
        "dc:date"         => "published"
    );
    $daten = strtr($daten, $wandle);
    $daten = preg_replace_callback("/(&[#a-z0-9]+;)/",

        create_function(

            '$enti',
            'return htmlspecialchars(mb_convert_encoding($enti[1], "UTF-8", "HTML-ENTITIES"));'
        ), $daten);

    /*-- Für den Fall, dass der Feed nur als String ohne Zeilenumbrüche ausgeliefert wird. -----------------------*/

    if (strpos($daten, "><item>") !== false) {

        $eing  = array(

            "><item>"        => ">\r\n<item>",
            "><title>"       => ">\r\n<title>",
            "><link>"        => ">\r\n<link>",
            "><description>" => ">\r\n<description>",
            "><content>"     => ">\r\n<content>",
            "><summary>"    => ">\r\n<summary>",
            "><enclosure>"   => ">\r\n<enclosure>",
            "><pubDate>"     => ">\r\n<pubDate>",
            "><updated>"     => ">\r\n<updated>",
            "><published>"   => ">\r\n<published",
            "><author>"      => ">\r\n<author>",
            "><creator>"     => ">\r\n<creator>"
        );
        $daten = strtr($daten, $eing);
    }
    return $daten;
}

/*------------------------------------------------------------------------------------------------------------------
 Die Funktion filtert HTML-Tags innerhalb und außerhalb von CDATA-Abschnitten und wandelt erlaubte Tags in BBCode.
 Weiterhin findet eine erste Überprüfung von Images statt, falls $image nicht gleich false.
 -------------------------------------------------------------------------------------------------------------------
*/
function filtereHTML($daten, $image) {

    $daten = preg_replace("/<p.*?>(.+?)<\/p>/is", "$1[br]", $daten);
    $daten = preg_replace("/<div.*?>(.+?)<\/div>/is", "$1[br]", $daten);
    $daten = preg_replace("/<span.*?>(.*?)<\/span>/is", "$1", $daten);
    $daten = preg_replace("/<br.*?>/i", "[br]", $daten);
    $daten = preg_replace("/<a href.+?>(.*?)<\/a>/is", "$1", $daten);

    if ($image === true) {
        $daten = preg_replace("/<img.*?src=\"([a-z0-9_\/=.:;&?-]+?)\.(jpg|png).*?>/is", "[img]$1.$2[/img]", $daten);
    }
    $eing  = array(

        "<b>"        => "[b]",
        "</b>"       => "[/b]",
        "<i>"        => "[i]",
        "</i>"       => "[/i]",
        "<em>"       => "[i]",
        "</em>"      => "[/i]",
        "<ul>"       => "[ul]",
        "</ul>"      => "[/ul]",
        "<li>"       => "[li]",
        "</li>"      => "[/li]",
        "<strong>"   => "[b]",
        "</strong>"  => "[/b]",
        "{"          => "",
        "}"          => ""
    );
    $daten = strtr($daten, $eing);
    $daten = preg_replace("/<.+?>/is", "", $daten);
    return $daten;
}

/*------------------------------------------------------------------------------------------------------------------
 Die Funktion wandelt erlaubte BBcode-Tags in HTML-Tags zurück und überprüft Images. Falls Bilder die angegeben
 Höchstmaße überschreiten, werden diese gleichmäßig skaliert.
 -------------------------------------------------------------------------------------------------------------------
*/
function formeHTML($daten) {

    $eing  = array(

        "[br]"       => "<br".SCHLIESSE,
        "[b]"        => "<b>",
        "[/b]"       => "</b>",
        "[i]"        => "<em>",
        "[/i]"       => "</em>",
        "[ul]"       => "<ul>",
        "[/ul]"      => "</ul>",
        "[li]"       => "<li>",
        "[/li]"      => "</li>"
    );
    $daten = strtr($daten, $eing);

    $daten = preg_replace("/[\n]/", "\n\t", $daten);
    $daten = preg_replace_callback("/\[img\](.+?)\[\/img\]/",

    create_function ('$bilder',

        '@$format = getimagesize($bilder[1]);

        if($format != false) {

            if ($format["mime"] == "image/jpeg" or $format["mime"] == "image/png") {

                global $maxho, $maxwe;

                $height = $format[1];
                $width  = $format[0];

                if ($height > $maxho){

                    $height  = $maxho;
                    $prozent = ($format[1] / $height);
                    $width   = ($format[0] / $prozent);
                }
                if ($width > $maxwe){

                    $width   = $maxwe;
                    $prozent = ($format[0] / $width);
                    $height  = ($format[1] / $prozent);
                }
                return "<img src=\"".htmlspecialchars($bilder[1], ENT_QUOTES)."\" alt=\"Bild\"".
                       " height=\"".round($height)."\" width=\"".round($width)."\"".SCHLIESSE;
            }
        }'
    ), $daten);
    return $daten;
}

/*-- Die Funktion wandelt Datum und Uhrzeit in ein lesbares Format um. -------------------------------------------*/

function formeDatumZeit($daten) {

    $daten = preg_replace("/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/", "$3.$2.$1 um $4:$5 Uhr", $daten);
    $daten = substr($daten, 0, 23);
    return $daten;
}

/*-- Die Funktion prüft enthaltene Links auf unerlaubte Zeichen und entfernt diese erforderlichenfalls. ----------*/

function filtereLinks($daten) {

    if (($pos = strpos($daten, "#")) !== false) {
        $daten = substr($daten, 0, $pos);
    }
    $daten = preg_replace("/[^a-z0-9_\/=.:;&?-]/is", "", $daten);
    return $daten;
}

$link  = false;                     // Bekanntmachung der Variablen $link, $lesen und $enco sowie Startwert von $si
$lesen = false;
$image = false;                     // $image false zuweisen
$enco  = "";
$si =  0;

echo "<div class=\"feed\">\n";

/*-- Der Feed wird mit cURL geladen und im Anschluß erfolgt die Ausgabe des Feeds --------------------------------*/

class WieBot {

    public  $antwort;
    public  $agent;
    private $httpcode = array(200, 301, 304);

    public function getVerbindung() {

        $cwbot = curl_init($this->antwort);                     // cURL-Session initialisieren

        curl_setopt($cwbot, CURLOPT_HEADER, false);             // Response Header nicht mit in die Ausgabe aufnehmen
        curl_setopt($cwbot, CURLOPT_USERAGENT, $this->agent);   // User Agent für den Request Header setzen
        curl_setopt($cwbot, CURLOPT_RETURNTRANSFER, true);      // Rückgabe als String

        if (curl_exec($cwbot) !== false) {
            $this->antwort = curl_exec($cwbot);                 // Ausführung der cURL-Session oder eine Fehler-Mitteilung ausgeben
        } else {
            $this->antwort = "Fehler: ".curl_error($cwbot);
        }
        if (stripos($this->antwort, "Fehler:") !== 0) {
            $status = curl_getinfo($cwbot, CURLINFO_HTTP_CODE);

            if (!in_array($status, $this->httpcode, true)) {
                $this->antwort = "Fehler: ".$status;
            }
        }
        curl_close($cwbot);                                     // Session beenden und Resourcen freigeben
        return $this->antwort;
    }
}

$vonbot = new WieBot();                                         // Erzeugen und Instanziieren des Objektes WieBot
$vonbot->agent   = $agent;                                      // User Agent als Wert für Eigenschaften übernehmen
$vonbot->antwort = $seite;                                      // Der Eigenschaft $antwort den Wert von $seite zuweisen
$data   = $vonbot->getVerbindung();                             // Den Rückgabewert der Methode getVerbindung an SimpleXML übergeben

/*-- Beginn der Ausgabe ------------------------------------------------------------------------------------------*/

if (stripos($data, "Fehler:") !== 0 and $data != false) {

    $pxml = simplexml_load_string(wandleTags($data), "SimpleXMLElement", LIBXML_NOCDATA);

    /*--------------------------------------------------------------------------------------------------------------
     Auswählen, ob Feedtitel und Eintritt für RSS oder für Atom, wobei channel->title und channel->item der RSS 2.0
     Specification für Feeds entspricht, title und entry hingegen der Specification für Atom-Feeds und item RSS 1.0
     ---------------------------------------------------------------------------------------------------------------
    */
    if ($pxml->channel->title) echo "<h2>".$feedt.formeHTML(htmlspecialchars(filtereHTML($pxml->channel->title, $image), ENT_QUOTES))."</h2>\n";
    if ($pxml->title)          echo "<h2>".$feedt.formeHTML(htmlspecialchars(filtereHTML($pxml->title, $image), ENT_QUOTES))."</h2>\n";

    if ($pxml->channel->item) $lesen = $pxml->channel->item;
    if ($pxml->entry)         $lesen = $pxml->entry;
    if ($pxml->item)          $lesen = $pxml->item;

    if (strlen($lesen[0]->title) > 0 or strlen($lesen[1]->title) > 0) {

        foreach ($lesen as $nachricht) {

            if ($nachricht->title != false) {

                /*-- Auswählen, ob Link für RSS $nachricht->link oder Atom $nachricht->link->attributes() --------*/

                if ($nachricht->link) {

                    if ((string)$nachricht->link) {
                        $link = $nachricht->link;
                    }
                    elseif ($nachricht->link->attributes()) {
                        $attr = $nachricht->link->attributes();
                        $link = $attr["href"];
                    }
                }

                /*-- Titel mit Link ------------------------------------------------------------------------------*/

                if ($nachricht->title) {
                    echo "\x20\x20<h3><a href=\"".htmlspecialchars(filtereLinks($link), ENT_QUOTES)."\" target=\"_blank\">".
                    formeHTML(htmlspecialchars(filtereHTML($nachricht->title, $image), ENT_QUOTES))."</a></h3>\n";
                }

                /*--------------------------------------------------------------------------------------------------
                 Einen Hinweis anzeigen, falls Bilder als Beilage mit enclosure der Nachricht hinzugefügt wurden.
                 ---------------------------------------------------------------------------------------------------
                */
                if ($nachricht->enclosure) {

                    if ($nachricht->enclosure->attributes()) {
                        $url = $nachricht->enclosure->attributes();

                        if (strpos($url["url"], ".jpg") or strpos($url["url"], ".png")) {

                            $enco = "<br".SCHLIESSE."\n\x20\x20<span class=\"klein\">Beilage Medien: ".
                                     htmlspecialchars(filtereLinks($url["url"]), ENT_QUOTES)."</span>";
                        }
                    }
                }

                /*-- true erst einmal nur für description und falls kein Fund, dann  auch für content und summary */

                $image = true;

                /*-- description und content für RSS und summary für Atom ----------------------------------------*/

                if ($nachricht->description and $descr != false) {
                    echo "\x20\x20<p>".formeHTML(htmlspecialchars(filtereHTML($nachricht->description, $image), ENT_QUOTES))."</p>\n";

                    if ((strpos((string)$nachricht->description, "<img")) !== false) {
                        $image = false;
                    }
                }
                if ($nachricht->content and $conte != false) {
                    echo "\x20\x20<p>".formeHTML(htmlspecialchars(filtereHTML($nachricht->content, $image), ENT_QUOTES))."</p>\n";
                }
                if ($nachricht->summary and $summa != false) {
                    echo "\x20\x20<p>".formeHTML(htmlspecialchars(filtereHTML($nachricht->summary, $image), ENT_QUOTES))."</p>\n";
                }

                $image = false;  /*- Nur für den Fall, dass false nicht durch description ausgelöst wurde */

                /*-- Link unten ----------------------------------------------------------------------------------*/

                if ($link != false) {
                    echo "\x20\x20<p class=\"unten\"><a href=\"".htmlspecialchars(filtereLinks($link), ENT_QUOTES)."\" target=\"_blank\">".
                         $linkt."</a><br".SCHLIESSE."\n";
                }

                /*-- pubDate für RSS und published und updated für Atom ------------------------------------------*/

                if ($nachricht->pubDate) {
                    echo "\x20\x20<br".SCHLIESSE."".htmlspecialchars(substr($nachricht->pubDate,  0, 16), ENT_QUOTES).
                         " um ".htmlspecialchars(substr($nachricht->pubDate, 17,  5), ENT_QUOTES)." Uhr";

                } elseif ($nachricht->updated) {
                    echo "\x20\x20<br".SCHLIESSE.formeDatumZeit($nachricht->updated)."\n";

                } elseif ($nachricht->published) {
                    echo "\x20\x20<br".SCHLIESSE.formeDatumZeit($nachricht->published)."\n";
                }

                /*-- Autor oder Creator für RSS und Atom ---------------------------------------------------------*/

                if ($nachricht->author) {
                    echo " von ".htmlspecialchars(filtereHTML($nachricht->author, $image), ENT_QUOTES).$enco."</p>\n";

                } elseif ($nachricht->creator) {
                    echo " von ".htmlspecialchars(filtereHTML($nachricht->creator, $image), ENT_QUOTES).$enco."</p>\n";

                } else {
                    echo "\x20\x20".$enco."</p>\n";
                }

                /*-- Trennlinie zwischen den einzelnen Mitteilungen ----------------------------------------------*/

                echo "\x20\x20<hr class=\"linie\"".SCHLIESSE."\n";
                $si++;
                if ($si == $maxim) {break;
                }
            }
        }
    } else { echo "<br".SCHLIESSE."Mehrere Titel oder Items scheinen fehlerhaft zu sein!\n";
    }
} else { echo "<br>".htmlspecialchars($data, ENT_QUOTES)."\n<br".SCHLIESSE."Feed konnte nicht geladen werden!\n";
}
?>
</div>
</body>
</html>

Copyright © Verlag Horst Müller - Stendal - 2006 - Impressum - Datenschutz - Nutzungsbedingungen