Probleme mit Mod-Rewrite

Nach einem Software Update von dem Server auf dem diese Homepage läuft, scheint es nun einige Probleme mit dem Mod-Rewrite zu geben. Darum werden gewissen Seite gar nicht mehr angezeigt und bei den restlichen Fehlt das CSS File.
Ich konnte den Fehler noch nicht finden, aber das wird schon wieder. Das hat man halt davon, wenn man es vorher nicht testet ;)

t-error.ch fürs iPhone

Da ich jetzt auch mit einem iPhone unterwegs bin, habe ich meine Homepage etwas angepasst, damit man sie mit dem iPhone etwas besser ansehen kann. Eigentlich kann man mit dem Safari jede Website ansurfen und sie wird auch vernünftig dargestellt, allerdings ist eine vereinfachte Webseite ab dem kleinen Bildschirm etwas besser lesbar.
Meine Seite ist nun auch über http://i.t-error.ch/ erreichbar. Einige Dinge werde ich dort sicher noch anpassen, aber so kann man die Texte sehr gut lesen und auch schnell einen Kommentar verfassen. Ich würde mich natürlich auch über Feedback von anderen iPhone-Usern freuen. Und so sieht das dann aus:
http://images.t-error.ch/blog/1044/iphone_quer.jpg http://images.t-error.ch/blog/1044/iphone_hoch.jpg

Dritter Geburtstag!

http://images.t-error.ch/blog/955/fireworks.jpg

Zum Glück habe ich in der "vor x Jahren" Box noch gesehen, dass ich genau heute vor drei Jahren den ersten Beitrag in diesem Blog geschrieben habe. Drei Jahre sind doch eine Menge und es macht mir immer (meistens) noch Spass. Ich habe auch vor hier weiter zu machen und den Blog auch weiter zu entwickeln. Es gibt noch viele Dinge, die man verbessern und anpassen kann; so wird mir sicher nicht langweilig :)

In zwischen habe ich in diesen drei Jahren 938 Beiträge geschrieben; das sind 0.856 pro Tag. Vor fast einem Monat wurde hier die magische Grenze von 1000 Kommentaren gebrochen. Inzwischen sind es 1025 was 0.935 pro Tag sind. Vielen Dank an dieser Stelle nochmals an diejenige die hier regelmässig oder auch nur ab und zu einen Kommentar hinterlassen. Das ist unter andrem ein Grund, der mich so am Bloggen hält.

Die Besucherstatistik hält sich seit letztem Jahr etwa auf demselben Niveau, womit ich ganz zufrieden sind. Und nur hohe Besucherzahlen sind ja nicht alles :)
http://images.t-error.ch/blog/955/analytics.jpg


Nun denn: Auf das nächste Jahr!

1000 Kommentare!

Nach fast drei Jahren (1065 Tagen) war es heute soweit. Marco hat den 1000sten Kommentar Kommentar in diesem Blog geschrieben.
Ich denke, das ist wieder mal ein guter Zeitpunkt um all den Kommentieren hier zu danken, sei es nun den "Vielkommentieren" oder den "Gelegenheitskommentieren", Ich freue mich immer über einen Kommentar und sei es nur ein "Danke für den Tipp" oder "Schöne Fotos". Das zeigt doch, dass noch andere Leute etwas von meinem "Tagebuch" haben.
Speziellen dank natürlich an die Stammleser und -kommentierer; hier diejenigen 10 mit den meisten Kommentaren:
Eine Benachrichtigungsfunktion für die Kommentare ist geplant, ich denke, das würde auch noch zu weiteren Diskussionen anregen, aber das ist leider nicht ganz so einfach.

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.

Blogroll angepasst

In meiner Blogroll hatte ich bisher die sieben Blogs, die ich am meisten gelesen habe. Mit der Zeit gibt es aber immer mehr Blog die ich gerne lese und auch gerne in der Blogroll habe. Nur möchte ich dort aber keine riesige Liste mit allen Blog haben, da das einfach zu viel Platz braucht. Nun habe ich es so gemacht, dass immer sieben zufällig ausgewählte Blogs aus der Liste angezeigt werden. So sieht es jedes mal etwas anders aus.

Diese Blogs sind momentan in der Liste, aber es werden sicher noch mehr:
Und so sieht es dann aus:
http://images.t-error.ch/blog/914/blogroll.jpg

Kleine Anpassung am Design

Heute habe ich noch eine kleine Anpassung am Design vorgenommen. So hat man nun auf der Startseite, den Themen, Tags usw. jeweils auch oben die Möglichkeit zur nächsten Seite zu blättern, oder zum Archiv zu gelangen. In einem zweiten Schritt möchte ich die Links noch etwas besser machen, das heisst gleich Links zu den fünf nächsten, bzw vorherigen Seiten. Auch das Archiv sollte ich mal etwas anpassen.
http://images.t-error.ch/blog/838/seiten.jpg


Zudem habe ich noch bemerkt, dass das Design nun genau ein Jahr alt ist. Wie die Zeit doch vergeht. Aber das Design gefällt mir noch immer :)

Moblogscript in PHP

Eigentlich wollte ich ja schon seit längerem etwas über mein Moblog-Script schreiben. Eigentlich seit dem Wunsch von Znuk, aber leider ist es bisher immer beim "wollen" geblieben. Da ich nun mein Script etwas verbessert habe, greife ich die Gelegenheit gleich beim Schopf und erkläre die Funktionsweise kurz.

Funktionsweise

In der Theorie sieht das ganze sehr simpel aus. Ich mache auf meinem Handy (Samsung SGH-600E) ein Foto, und sende es per Mail an eine (geheime) Mailadresse. Auf dem Webserver wird nun alle 15 Minuten ein PHP-Script aufgerufen, welches überprüft ob in der Mailbox neue Mails sind, diese dann verarbeitet und schlussendlich einen neuen Beitrag auf meiner Homepage erstellt.

Spammails

Ein Problem an der Sache sind die Spammails. Das Problem kann man aber einfach umgehen, indem man eine Mailadresse nimmt, die nicht so schnell erraten werden kann, diese nirgens publiziert und im PHP-Script noch eine Passwortabfrage einbaut. Ich bin hier auf Nummer sicher gegangen und habe alle beiden Methoden eingesetzt, den schliesslich möchte ich keine Spammails auf meiner Homepage.

Mailaufbau

Damit das ganze mit dem Passwortschutz und der zuordnung zum richtigen Thema auch funktioniert, muss das E-Mail natürlich auch immer gleich aufgebaut werden. Bei mir sieht das nun folgendermassen aus:
passwort
Thema
Ort
Text für die Homepage
Auf der ersten Zeile steht das Passwort, welches auch als erstes geprüft wird, darauf gehe ich aber spätzer genauer ein. Darauf folgt das Thema, in welches der Aktrikel gehört. Zum Bsp. "Bike", "Diverses" usw. Da ich Moblogs ja immer von unterwegs versende ist es interessant von wo das Mail versendet wurde. Mein Handy hat noch keinen GPS Empfänger und so kann ich auch keine Koordinaten angeben, also muss ich mich auf den Ortsnamen beschränken. Aber das reicht im Normalfall bestens aus. Zum Schluss folgt der Text, welcher auf der Homepage stehen soll.
Das Problem, welches ich meistens habe, ist das Tippen auf der kleinen "Tastatur" auf dem Handy, aber für kurze Nachrichten reicht es meist und wirklich wichtig ist ja das Bild.

Das Script

Nun zum wirklich spannenden Teil dieses Beitrags. Das Script ist in PHP geschrieben und wird alle 15 Minuten aufgerufen. Wenn ein neues Mail vorhanden ist wird das Passwort geprüft und der Artikel erstellt, sofern das Passwort natürlich korrekt ist.
Die Verbindung zur Datenbank und das schreiben der Daten in die DB habe ich hier ausgelassen, da dies ja je nach Blogsoftware bzw. Tabellenstruktur variert. Das Script gibt einfach Variabeln mit dem Inhalt zurück und diese können dann nach belieben in die DB geschrieben werden.

Voraussetzungen

Damit das Script richtig funktioniert, bzw die Mails auch lesen und bearbeiten kann müssen die Imap-Funktionen von PHP Installiert sein. Sonst wird es zu kompliziert.

Ablauf

Damit man einen groben Überblick über das Script bekommt fasse ich hier den Ablauf des Scripts etwas zusammen.
  1. Überprüfen ob neue Mails vorhanden sind
  2. Passwort des Mails überprüfen
  3. Headerdaten auslesen (Betreff, Datum & Zeit)
  4. Text auslesen
  5. Attachments auslesen
  6. Text aufteilen (Thema, Ort und Text)
  7. Bilder speichern
  8. (Daten in die Datenbank schreiben)
  9. E-Mail löschen
  10. Verbindungen trennen

Code

Zuerst werden einige Konstanten definiert, die Hostname vom Mailserver, Benutzername, Passwort usw. beinhalten.
<?
// Konfiguration
define("MAIL_HOST","{mail.server.ch:143}");                // Hostname und Port vom Mailserver
define("MAIL_USER","moblog@adresse.ch");                   // Der Benutzername
define("MAIL_PASS","passwort");                            // Passwort vom Mailaccount

define("PASS","passwort");                                 // Das Passwort das im Mail stehen soll 
define("IMAGES_PATH","images/");                           // Pfad zum Bilderordner
?>



Damit die allfälligen Fehler oder Mitteilungen vom Script auch sinnvoll Protokolliert werden, habe ich eine kleine Funktion geschrieben, welche das aktuelle Datum sowie eine Fehlermeldung zurückgibt. Wenn das Script mit einem Cronjob aufgerufen wird, wird diese nachricht automatisch ins Logfile geschrieben.
<?
// kleine funktion die eine fehlermeldung mit dem aktuellen datum ausgibt
function _log($text)
{
    echo 
date("r")."    ".$text."\n";
}
?>


Nun kann auch schon die Verbindung zum Mailserver hergestellt werden. Die angaben zum Hostnamen usw, werden aus den oben definierten Konstanten gelesen. Wenn die Verbindung zum Mailserver nicht hergestellt werden kann wird eine Fehlermeldung ausgegeben und das Script abgebrochen.
<?
// verbindung zum mailserver herstellen
if(!$mail=imap_open(MAIL_HOST,MAIL_USER,MAIL_PASS))
{
    
_log("Keine Verbindung zum Mail-Server");
    exit;
}
?>


Wenn die Verbindung zum Server steht kann überprüft werden, ob neue, ungelesen Mails auf der Server sind. Ist dies nicht der Fall wird das Script abgebrochen.
<?
// ueberpruefen, ob mails vorhanden sind
$headerstrings=imap_headers($mail);
$mails=count($headerstrings);                              // Die Anzahl der neuen Mails

if($mails==0)
{
    echo 
"keine mails";
    exit;
}
_log($mails." neue E-Mails auf dem Server.");              // Nachricht ausgeben
?>


Ist bekannt ob und wieviele neue Mails vorhanden sind, gehts ans verarbeiten der Mails. Mit einer Schleife wird jedes Mail durchgegangen und überprüft.
Aus Übersichtlichkeitsgründen habe ich hier den Code in zwei Funktionen ausgelagert. Zum einen gibt es die Funktion _getData(). Diese Funktion list die Daten aus dem Mail aus und gibt sie schön sortiert in einem Array zurück. Dieser kann so aussehen:
Array
(
    [header] => Array
        (
            [date] => datum als timestamp
            [email] => mailadresse des absenders
            [name] => name des absenders
            [subject] => betreff
        )
    [text] => Inhalt des Mails (mit Passwort, Thema, Ort und Text)
    [attachment] => Array
        (
            [0] => Array
                (
                    [filename] => Dateiname des ersten Anhangs
                    [content] => Inhalt des ersten Anhangs
                )
            [1] => Array
                (
                    [filename] => Dateiname des zweiten Anhangs
                    [content] => Inhalt des zweiten Anhangs
                )
        )
)


Die zweite Funktion heisst _getMetaData() und sie unterteilt den Inhalt der Nachricht, überprüft das Passwort und gibt die verschiedenen Angaben (Thema, Ort und Text) geordnet zurück.

Nun aber erstmal der Code, der die Funktionen aufruft:
<?
// mail fuer mail durchgehen, daten auslesen, passwort check machen, daten in die db schreiben und das mail loeschen
foreach($headerstrings as $headerstring)
{
    
preg_match("/[0-9]/",$headerstring,$number);           // Numer des E-Mails auslesen

    
$mailData=_getData($headerstring,$number);             // Inhalt aus dem Mail auslesen

    
$meta=_getMetaData($mailData['text']);                 // Inhalt aufteilen

    
if($meta===FALSE)                                      // wenn $meta FALSE ist, stimmt das Passwort nicht
    
{
        
log("falsches pw");
        continue;
    }

    
$mailData['text']=$meta[0];                            // Text des E-Mails
    
$mailData['meta']=$meta[1];                            // Meta Daten des E-Mails (Thema und Ort)

    
foreach($mailData['attachment'] AS $attachment)        // alle attachments durchgehen
    
{
        
$filename=$attachment['filename'];                 // dateiname auslesen

        
$fp=fOpen(IMAGES_PATH.$filename,"w+");             // das attachment abspeichern
        
fWrite($fp,$attachment['content']);
        
fClose($fp);
    }

    
imap_delete($mail,$number[0]);                         // Mail l&ouml;schen
}
?>


Nun zu den Funktionen. Als erstes _getData(), die den Inhalt der Mails ausliest und zurückgibt. Hierzu muss ich vieleicht noch sagen, dass jedes Gerät die Mails etwas anders gestaltet und es so zu Problemen bei dieser Funktion kommen könnte. Mit meinem Handy funktioniert es wunderbar, aber bei anderen Geräten muss man vieleicht die eine oder andere Anpassung vornehmen.
<?
// liest die daten aus einem mail aus, verarbeitet sie und gibt sie als array zur&uuml;ck
function _getData($headerstring,$number)
{
    global 
$mail;
    
$mailData=array();                                     // Array, in den schlussendlich die
                                                           // Daten geschrieben werden

    
$header=imap_fetchheader($mail,$number[0]);            // mailheader auslesen

    
preg_match("/Date: (.*)?[\+|-]/",$header,$date);       // datum des mails auselesen
    
$date=htmlEntities($date[1]);
    
$mailData['header']['date']=strToTime($date);

    
$headerinfo=imap_headerinfo($mail,$number[0],256,256); // liest die headerinformationen aus

    
$mailData['header']['email']=$headerinfo->from[0]->mailbox."@".$headerinfo->from[0]->host// mailadresse des absenders auslesen

    
$decode=imap_mime_header_decode($headerinfo->from[0]->personal); // name des absenders auslesen
    
$mailData['header']['name']=$decode[0]->text;

    
$decode=imap_mime_header_decode($headerinfo->fetchsubject); // betreff auslesen
    
$mailData['header']['subject']=$decode[0]->text;


    
// inhalt der mailnachricht auslesen
    
$struct=imap_fetchstructure($mail,$number[0]);
    
    
// mails mit attachments werden immer als multipart, also mail mit verschieden teile versendet
    // sollte eine mail ohne attachment und mit nur als plaintext versendet worden sein, wird nur der text ausgelesen 
    
if(!empty($struct->parts))
    {
        
// durch alle teile gehen
        
for($i=0;$i<count($struct->parts);$i++)
        {
            
$part=$struct->parts[$i];

            
$msg=imap_fetchbody($mail,$number[0],$i+1);    // inhalt des teils

            // wenn der teil ein attachment, bild und jpg ist.
            
if ($part->disposition==ATTACHMENT OR $part->type==TYPEIMAGE OR ($part->type==TYPEAPPLICATION AND $part->subtype!="SMIL"))
            {
                if(
$part->subtype=="JPEG" OR $part->subtype=="JPG" OR $part->subtype=="OCTET-STREAM")
                {
                    
$attachment=array();

                    
// daten in einen array schreiben.
                    
$attachment['filename']=$part->dparameters[0];
                    
$attachment['filename']=$attachment['filename']->value;
                    
$attachment['content']=base64_decode($msg);

                    
$mailData['attachment'][]=$attachment;
                    unSet(
$attachment);
                }
            }

            
// wenn der teil nur text ist
            
elseif(($part->type==TYPETEXT OR $part->type==TYPEMULTIPART OR $part->disposition==INLINE))
            {
                
$mailData['text']=base64_decode($msg);
            }
        }
    }
    else
    {
        
// wenn das mail als plaintext versendet wurde
        
$mailData['text']=imap_body($mail,$number[0]);
    }

    return 
$mailData;                                      // daten zur&uuml;ckgeben
}
?>


Und nun noch zur zweiten Funktion, welche den Text der Nachricht verarbeitet und das Passwort überprüft.
<?
function _getMetaData($text)
{
    
$text=explode("\n",$text);                             // den text aufteilen

    
if(trim($text[0])!=PASS)                               // ueberprufen, ob die erste zeile dem passwort entspricht
    
{
        return 
FALSE;
    }
    unSet(
$text[0]);

    
$metaData['topic']=trim($text[1]);                     // die zweite zeile als thema (topic) abspeichern
    
unSet($text[1]);

    
$metaData['location']=trim($text[2]);                  // die dritte zeile als ort (location) abspeichern
    
unSet($text[2]);

    
$text=implode("\n",$text);                             // den rest zusammenfuegen und als text speichern

    
return array($text,$metaData);                         // den array zurueckgeben
}
?>


Zum Schluss müssen die gelöschten Mails mit imap_expunge() noch definitiv gelöscht und die Verbindung zum Server getrennt werden.
<? 
// mailbox leeren und verbindung zum server trennen
imap_expunge($mail);
imap_close($mail);
?>


Das ist auch schon der ganze Zauber. Wie schon gesagt müssen die Daten noch in die DB geschrieben werden und idealerweise generiert man für die Bilder auch noch ein Thumbnail, aber das sollte ja kein grosses Problem darstellen.
Wer sich das Script nicht aus den einzelnen Teilen zusammensetzen will, kann es sich hier herunterladen.

Kleine Anpassungen auf dem Blog

Heute habe ich mal wieder einige kleine Verbesserungen an meiner Homepage vorgenommen. Das Problem war, dass viele Suchmaschinen auf der 404 Fehlerseite gelandet sind, weil sie bei den Urls den Slash am Ende nicht angegeben hatten.
Das heisst sie hatten die Seite http://blog.t-error.ch/article/797/herbstlich angefragt, anstelle der Seite http://blog.t-error.ch/article/797/herbstlich/ (Man beachte den Slash am Schluss). Nun habe ich meine .htaccess Datei angepasst, dass die Seite nun wie folgt aufgerufen werden kann:
  • http://blog.t-error.ch/article/797/herbstlich/
  • http://blog.t-error.ch/article/797/herbstlich
  • http://blog.t-error.ch/article/797/
  • http://blog.t-error.ch/article/797
So sollten die Suchmaschinen auch die Seiten finden, die sie erwartet hatten und ich denke auch der eine oder andere Besucher wird so das gewünschte finden.

Dasselbe habe ich auch bei den Themen (http://blog.t-error.ch/topic/1/bike), den Tags (http://blog.t-error.ch/tag/bike) und bei fast allen anderen Seiten so gemacht.

Moblogtest

Da ich gerade am Moblogscript am Schrauben bin, gibts nun einen kleinem Test. Wenn alles funktioniert wie es soll, dann werde ich morgen noch etwas genaueres dazu schreiben.