Feedstatistik für Online-Feedreader

Wenn man eine Feedstatistik haben will, kann man das entweder auf die bequeme Art mit Feedburner oder ähnlichen Diensten machen, oder selber etwas schreiben. Normalerweise kann man davon ausgehen, dass hinter einem Aufruf des Feeds ein Benutzer ist, welcher einen lokalen Feedreader benutzt (Thunderbird, Firefox, NetNewsWire usw). Online Feedreader wie Google Reader, Bloglines bedienen allerdings mehrere Benutzer und so kann man nicht pro Aufruf einen Benutzer schliessen.
Die Feedreader geben allerdings in den Useragent-Daten an, wieviele Benutzer den Feed abonniert haben und so kann man doch wieder eine gute Statistik zusammenschustern.
Und so sehen die Useragent Angaben zum Beispiel aus:
Google Reader
Feedfetcher-Google; (+http://www.google.com/feedfetcher.html;
123 subscribers; feed-id=0123456789

Bloglines
Bloglines/3.1 (http://www.bloglines.com; 123 subscribers)

Netvibes
Netvibes (http://www.netvibes.com/; 123 subscriber;
feedId: 0123456789)

Newsgator
NewsGatorOnline/2.0 (http://www.newsgator.com; 123 subscribers)


Via Webmeister Blog

Artikel im RSS Feeder verzögern

Welcher Blogger kennt das Problem nicht: man scheibt einen neuen Artikel, liest ihn vor dem veröffentlichen nochmals genau durch beseitigt alle Fehler, und stellt den Artikel danach ins Internet. Auf dem Blog noch kurzen eine Kontrolle, ob alles passt und Prompt findet man noch einen Fehler. Soweit so schlecht, den Fehler noch schnell beseitigen bevor es jemand sieht, das Internet ist ja Realtime. Fast; auf der Seite wird der Fehler nicht mehr angezeigt, dafür haben sich die Feedreader schon die alte und fehlerhafte Version gespeichert.
Dieses Problem kann man ganz einfach beheben. Entweder man machte keine Fehler mehr, oder man zeigt die neuen Artikel erst eine gewisse Zeit (zum Bsp 5 Min) später im RSS-Feed an. Dadurch hat man Zeit um die Fehler zu beheben, bevor die Feedreader überhaupt merken, dass es etwas neues gibt. In meinem Fall war das eine kleine Anpassung in der mySQL Abfrage.

Vorher:
<? mysql_query("... articleDate<".time()." ..."); ?>

Nachher:
<? mysql_query("... articleDate<".(time()-(5*60))." ..."); ?>


Nun hoffe, ich dass die Artikel in den Feedreader (und auch im Blog) etwas weniger Fehler haben.

Google Reader mit Suchfunktion

Endlich. Der Google Reader hat nun auch eine Suchfunktion. Es hat mich bisher immer verwundert, dass etwas vom Suchgiganten Google keine Suche hat. Aber nun wurde sie ja gefunden.
http://images.t-error.ch/news/450/google_reader_search.jpg

RSS Feed mit SimplePie parsen

Ich beschäftige mich nun wieder etwas mehr mit dem Parsen von RSS mit PHP. Unter anderem weil ich mit dem Gedanken spiele einen RSS Aggregator für die Bikeblogs und/oder mir einen Lifestream zu bauen. Dafür eignet sich die Klasse SimplePie sehr gut. Im Gegensatz zu Magpie wird SimplePie etwas aktiver entwickelt.
hier nun mal ein kleines Beispiel, wie man die Daten aus einem RSS Feed ausliest. Wie gesagt ist das mit SimpePie recht einfach.
<?
// SimplePie einbinden
require_once("simplepie/simplepie.inc");

// Neues Objekt erstellen
$pie=new SimplePie;
?>

Nun hat man das SimplePie Objekt erstellt und kann jetzt angeben, welcher Feed geparst werden soll. Alternativ kann man die Feedurl, sowie angeben zum Cachingverhalten auch direkt im Konstruktor angeben. Ich verzichte hier aber darauf, da man bei einem Aggregator oder Lifestream mehrere RSS Dateien parsen muss, ohne jedes mal eine neues Objekt zu erstellen.
<?
// Feed Adresse setzen
$pie->set_feed_url($feed);

// Feed parsen
$pie->init();
?>

Mit der Methode init() wird der Feed nun geparst und man kann sich an das auslesen der Daten machen.
<?
// Anzahl der Elemente im Feed auslesen
$count=$pie->get_item_quantity();

// Jedes Element durchgehen
for($i=0;$i<$count;$i++)
{
    
// Daten auslesen
}
?>
So liest man zuerst die Anzahl der Elemente im Feed aus und geht alle nacheinander durch. Und schlussendlich muss man nur noch die Daten auslesen. Dies sieht so aus:
<?
// Ein "ItemObject" erstellen
$item=$pie->get_item($i);

// Titel
$title=$item->get_title();

// Inhalt
$content=$item->get_content();

// Link
$link=$item->get_link();

// Zeit als Unix Timestamp
$time=$item->get_date("U");
?>

Und alles zusammen sieht dann so aus:
<?
// SimplePie einbinden
require_once("simplepie/simplepie.inc");

// Neues Objekt erstellen
$pie=new SimplePie;

// Feed Adresse setzen
$pie->set_feed_url($feed);

// Feed parsen
$pie->init();

// Anzahl der Elemente im Feed auslesen
$count=$pie->get_item_quantity();

// Jedes Element durchgehen
for($i=0;$i<$count;$i++)
{
    
// Ein "ItemObject" erstellen
    
$item=$pie->get_item($i);

    
// Titel
    
$title=$item->get_title();

    
// Inhalt
    
$content=$item->get_content();

    
// Link
    
$link=$item->get_link();

    
// Zeit als Unix Timestamp
    
$time=$item->get_date("U");
}
?>

In der Api Reference werden alle Funktionen sehr schön und meistens mit einem Beispiel beschrieben.

Neue Feedfunktionalitäten

Heute habe ich einige funktionalitäten zum RSS Feed hinzugefügt. Neu kann man den Feed auch nur für eine bestimmtes Thema, einen Tag oder einen Ort abonieren. Die Adresse sieht fast gleich aus wie im Blog. Man muss nur das http://blog.t-error.ch durch das http://feeds.t-error.ch/blog/ ersetzten.
Bikeinteressierte dürften also an diesem, Panoramafanatiker an diesem und Savogninvernarrte an diesem Feed interessiert sein. Die Links zu den Feeds werde ich wohl zu den jeweiligen Seiten hinzufügen. Momentan muss man noch einwenig selbstständig sein, wenn man diese Funktionalität nutzen will.
Selbstverständlich darf man immer noch den Feed mit allen einträgen Benutzen. Aber vieleicht gibts ja Leute, die nur einem speziellen Thema interessiert sind.

Linktipps von del.icio.us mit PHP erstellen

Wie man schon einmal beobachten konnte, habe ich nun auch meine delicious Links in meinem Blog. Allerdings werden die Links nur jede Woche angezeigt. Dazu habe ich selber ein kleines Script geschrieben.
Das Script wird täglich durch einen Cronjob aufgerufen und liest die Links aus dem RSS Feed von delicious und schreibt sie in eine Datenbank. Dort werden sie aufbewahrt, bis sie von einem anderen Script ausgelesen und auf die Webseite geschreiben werden. Das passiert bei mir wöchentlich.

Für die Technik-Interessierten habe ich hier die Datenbankstruktur und den Code des Scriptes, welches die Links ausliest. Das schreiben der Links in den Blog sollte ja nicht so schwierig sein.
Bei Gelegenheit werde ich die Daten nicht mehr aus dem Feed, sondern aus der API nehmen. Aber so funktionierts ja auch.
Ach ja: Das Script verwendet MagpieRSS um die RSS Datei zu parsen.

Die Tabellenstruktur
mysql> describe delicious;
+----------------+--------------+------+-----+---------+----------------+
| Field          | Type         | Null | Key | Default | Extra          |
+----------------+--------------+------+-----+---------+----------------+
| delID          | int(11)      |      | PRI | NULL    | auto_increment |
| delTitle       | varchar(200) |      |     |         |                |
| delLink        | varchar(200) |      |     |         |                |
| delTags        | varchar(200) |      |     |         |                |
| delDescription | text         |      |     |         |                |
| delLang        | char(2)      |      |     |         |                |
| delDate        | int(11)      |      |     | 0       |                |
| delActive      | tinyint(4)   |      |     | 0       |                |
+----------------+--------------+------+-----+---------+----------------+
Wenn delActive auf 1 ist, bedeutet das, dass der Link schon auf der Homepage angezeigt wird.

Der PHP Code
#!/usr/bin/php
<?
// abstand machen, damits auch schoen aussieht
function space($lenght)
{
    
$count=100-$lenght;
    for(
$i=0;$i<$count;$i++)
    {
        echo 
" ";
    }
}

// alle klassen, funktionen usw einbinden
require_once("/home/t-error/public_html/includes/_head.inc.php");

// magpie einbinden
require("magpierss/rss_fetch.inc");

// rss daten herunterladen und parsen
$data=fetch_rss("http://del.icio.us/rss/blacklord");
$data=$data->items;

// los gehts
foreach($data AS $item)
{
    
// die daten in verstaendliche variabeln schreiben
    
$title=        addSlashes($item['title']);
    
$link=         $item['link'];
    
$date=         intVal($item['date_timestamp']);
    
    
// tags als array speichern
    
$tags=         explode(" ",strToLower($item['dc']['subject']));
    
$description=  NULL;

    
// wenn eine beschreibung geschreiben worden ist
    
if(isSet($item['description']))
    {
        
$description=addSlashes($item['description']);
    }

    
// den lang: tag rausfiltern und die richtige sprache in $lang schreiben
    
$tags_arr=array();
    foreach(
$tags AS $tag)
    {
        if(
preg_match("/^lang:([a-z]{2}$)/",$tag,$result))
        {
            
$lang=$result[1];
        }
        else
        {
            
$tags_arr[]=$tag;
        }
    }

    
// tags wieder zusammensetzten
    
$tags=implode(" ",$tags_arr);

    
// ueberpruefen, ob der link schon in der datenbank ist
    
$res=$db->query("
                SELECT
                    delActive
                FROM
                    "
.TBL_PREFIX.TBL_DELICIOUS."
                WHERE
                    delDate="
.$date." AND
                    delLink='"
.$link."'");

    
// wenn nein: einfuegen. los!
    
if($db->num_rows($res)==0)
    {
        
$db->query("
                INSERT INTO
                    "
.TBL_PREFIX.TBL_DELICIOUS."
                    (
                        `delTitle`,
                        `delLink`,
                        `delDate`,
                        `delTags`,
                        `delDescription`,
                        `delLang`
                    )
                VALUES
                    (
                        '"
.$title."',
                        '"
.$link."',
                        '"
.$date."',
                        '"
.$tags."',
                        '"
.$description."',
                        '"
.$lang."'
                    )"
);
                    
        
// noch eine kleine ausgabe
        
echo $title;
        
space(strLen($title));
        echo 
"[ inserted ]\n";
    }
    
    
// wenn ja: nur aendern, man weiss ja nie
    
else
    {
        if(
$db->result($res,0,"delActive")==0)
        {
            
$db->query("
                    UPDATE
                        "
.TBL_PREFIX.TBL_DELICIOUS."
                    SET
                        `delTitle`='"
.$title."',
                        `delLink`='"
.$link."',
                        `delDate`='"
.$date."',
                        `delTags`='"
.$tags."',
                        `delDescription`='"
.$description."',
                        `delLang`='"
.$lang."'
                    WHERE
                        delDate="
.$date." AND
                        delLink='"
.$link."'");
        }
    }
}
?>

Dieses Script kann, wenn die Zugriffsrechte korrekt gesetzt sind, über die Shell aufgerufen werden.

Verbesserungsvorschläge sind gerne Willkommen

RSS Feed

Ich habe jetzt mal einen RSS Feed für den Blog gebaut. Er ist noch lange nicht fertig, aber es ist valide und das ist ja mal das wichtigste.

Zu finden ist er unter http://feeds.t-error.ch/blog/

Bei gelegenheit werde ich noch einige Features wie Feeds nur für bestimmte Topics oder für den Photolog erstellen, aber für den Anfang sollte das mal reichen.