Bikeblogs reloaded

Auf Wunsch von Vazifar und auch mir selber, habe ich die Liste mit den Schweizer Bikeblogs in eine mySQL DB verfrachtet. Das ganze lässt sich nun auf der Bikeseite. Verwalten kann man die Einträge nicht selber, aber für die 11 momentan eingetragenen Blogs mache ich mir nicht so einen Aufwand.
Zudem ist es noch angedacht, dass man zu jedem Blog eine kleine Beschreibung, von mir aus auch mit Bilder in Links zu Flickr Seiten oder was weiss ich hinzufügen kann. Diese müsste mir aber der Betreiber der Seite senden, falls Interesse besteht.

Ich habe noch einen kleinen Button gebastelt. Nichts wansinniges, aber wer möchte, kann ihn gerne auf die eigene Seite pflanzen.
Der Button http://images.t-error.ch/buttons/bikeblogs.png
Und der Code zum einbinden (Natürlich XHTML valide)
<a href="http://bike.t-error.ch/blogs/">
<img src="http://images.t-error.ch/buttons/bikeblogs.png" width="80" height="15"
    alt="Swiss Bikeblogs" title="Swiss Bikeblogs" border="0" />
</a>

Bikeinformationen auf der Seite

Nachdem ich mich gestern bei der Bikeblog-Suche, manachmal geärgert habe, dass auf der Webseite kaum Informationen über das gefahrene Bike zu finden sind, habe ich gedacht, ich gehe mal mit gutem Beispiel voran. Oder ich versuche es zumindest.
Neu ist in der Navigation oben nun der Tab Bike zu finden. Auch mit Alt + I erreichbar. Dafür verschwand die Seite Link. Da ich meine Lesezeichen sowieso mit del.icio.us verwalte, ist das kein wirklicher Verlust.
Auf der Seite sind Informationen über mein Bike zu finden. zum einen eine kleine Beschreibung, Bilder und noch technische Details. Das zusammentragen der Details war noch schwierig, da im Internet kaum noch Informationen über dieses Bike zu finden sind. Eine Suche nach Wheeler Raceline Comp 1 bringt mich nur auf meine Seite. Toll. Nun ja. Einige Informationen konnte ich zusammentragen und einige werden noch folgen. Wer noch Fragen oder Ergänzungen hat, kann hier oder dort gernen einen Kommentar hinterlassen.
Mein neuer Stolz ist auch die Tourendatenbank. Dort habe ich bereits meine diesjärigen Touren eingetragen und die zukünftigen werden auch folgen. Momentan sind dort Informationen wie Route, Distanz, Durchschnittsgeschwindigkeit usw. zu finden. Zudem werden auch Bilder angezeigt, es sind allerdings dieselben wie im jeweiligen Blogbeitrag.
Mit einem Klick auf die Zeile werden die Zusatzinformationen angezeigt. Ein weiterer klick darauf versteckt sie wieder. Sollte eigentlich intuitiv genug sein.
Wenn ein Interesse besteht, werde ich die Bikeblogliste dort in die Datenbank integrieren, was die Verwalung einfacher macht und wohl auch die Übersichtlichkeit steigert. Auch habe ich vor dort noch einige Informationen über meine Ausrüstung einzubauen.

Und da ich sowieso vorhabe mir ein GPS zu kaufen, werde ich in der Tourendatenbank noch weitere Informationen wie KML Dateien, Höhenprofile usw. veröffentlichen.

Wie schon gesagt: Ergänzungen, Vorschläge, Verbesserungen usw. sind gerne willkommen.

Dateien mit PHP in mySQL DB speichern

Hier schreibe ich, wie man eine Datei in einer mySQL Datenbank speichert. Dafür sollte man sich etwas mit PHP und mySQL auskennen. Ich schreibe hier nicht, wie man Dateien auf den Webspace hochlädt. Zudem gehe ich davon aus, dass die Datei schon auf dem Webspace liegt.

Vorbereitungen

Also los. Zuerst zur Datenbank. Prädestiniert für Binärdateien sind die Blobs (Binary Large Objects). Zudem sollte man den Mimetype in der Datenbank speichern, falls der schon, zum Beispiel durch einen Upload bekannt ist. Also sieht die Tabelle zum Beispiel so aus:
mysql> describe files;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| fileID   | int(11)      |      | PRI | NULL    | auto_increment |
| fileType | varchar(200) |      |     |         |                |
| fileData | blob         |      |     |         |                |
+----------+--------------+------+-----+---------+----------------+

Daten schreiben

Um die Daten in die DB zu schreiben, muss zuerst den Inhalt der Datei auslesen. Die macht man so:
<?
// die datei, die in die db geschrieben wird
$file="bild.jpg";

// datei oeffnen
// das r steht fuer read und das b fuer binary
$fp=@fOpen($file,"rb")or die("konnte die datei nicht oeffnen");

// daten auslesen
$content=fRead($fp,fileSize($file));

// datei schliessen
fClose($fp);
?>
Nun ist der Inhalt der Datei in der Variable $content gespeichert.
Jetzt muss der Inhalt der Datei noch in die Datenbank geschrieben werden. Da die Datei in diesem Beispiel ein JPG ist nehme ich ich den Mimetype image/jpeg. Sollte dieser Typ nicht bekannt sein, muss auf die Datei mime.types zurückgegriffen werden. Dieser Mimetype ist wichtig, da er nachher als Content-type an den Browser gesendet wird.
Nun zur mySQL Query:
<?
mysql_query
("
    INSERT INTO
        files
        (
            `fileType`,
            `fileData`
        )
    VALUES
        (
            'image/jpeg',
            '"
.addSlashes($content)."'
        )"
);
?>
Die Funktion addSlashes() ist wichtig, da es sonst zu mySQL Fehler kommt, da das Zeichen ' im Dateiinhalt sein könnte.

Daten auslesen


<?
// id setzen. kann auch per $_GET bzw. $_POST geschehen
$id=1;

// daten auslesen
$result=$db->query("
                SELECT
                    fileType,
                    fileData
                FROM
                    files
                WHERE
                    fileID="
.$id);

$type=mysql_result($result,0,"fileType");
$data=mysql_result($result,0,"fileData");

// headers
// den content-type (mimetype) senden. aus der db
header("Content-type: ".$type);

// die groesse des inhalts anzeigen. damit der browser die verbleibende zeit berechnen kann.
header("Content-Length: ".strLen($data));

// die anzeige und der filename der datei.
// content-disposition: attachment oeffnet einen speichern unter dialog
// content-disposition: inline oeffnet das file im browser falls moeglich (pdf)
header("Content-Disposition: attachment; filename=bild.jpg");

echo 
$data;
?>


Keine grosse Kunst, allerdings gibt es doch einige Dinge, die man beachten sollte.

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

Von Spamfressern und Designänderungen

Ich bin entzückt. Seit dem Einbau des neuen Spamfilters am Samstag habe ich keinen einzigen Spambeitrag mehr erhalten. Und da bin ich froh. Der Counter, den ich gestern noch eingebaut habe zeigt schon 156 Versuche an. Und das in knapp 24 Stunden. Lieber in einem Counter als in meiner Datenbank. Auch Yoda versucht die Spamer auszutricksen. Wie erfolgreich er ist, wird sich sicher noch zeigen.
Zudem habe ich heute noch einwenig am Design geschraubt. Grundsätzlich bin ich damit ja zufrieden, nur das Logo gefällt mir nicht so. Ich habe nun mal einen Verlauf reingezogen und die Schrift verändert, aber wirklich zufrieden bin ich noch nicht. Leider bin ich grafisch nicht so begabt. Vieleicht werde ich aber noch Fotos in den Header aufnehmen, wenn ich mal Zeit habe.
Sollte jemand aber grafisch begat sein und genug Zeit haben, so sage ich bei einem guten Logo nicht nein :)