Yanix im Detail: Mehrsprachigkeit und Dateiformate

28. Dezember 2007

0 Kommentare

Die Welt ist groß und spricht nicht nur eine Sprache. iBot konnte bisher zwei: Einen wirren Mischmasch aus Deutsch und Englisch. Das wird in Yanix nicht mehr sein.

Ein mächtiges aber effektives System zur Mehrsprachigkeit soll dem Abhilfe schaffen. Über die Realisierung habe ich mir einige Zeit den Kopf zerbrochen. Die meisten PHP-System inkludieren einfach eine PHP-Datei, welche die Definition für viele viele Sprach-Strings enthält. Diese Methode hat jedoch einige Nachteile:

Anfangs wollte ich in Yanix viel auf XML-Dateien setzen, jedoch ist das Parsen von diesen in PHP sehr unbequem. Dann fand ich diesen Befehl, mit welchem sich wirklich sehr einfach .ini-Dateien parsen lassen. Dieses Dateiformat ist uralt, aber sehr praktisch: Es unterstützt Sektionen und hat eine sehr einfache Syntax.

Anfangs setzte ich gerne auf diese Funktion und habe viel (Profile, Plugin-Informationen) damit gemacht, doch stoßte auf ein Problem: Die PHP-Funktion ignoriert Zeilen die es für “ungültig” hält und Sektionen muss man extra wählen.

Ich fand in meiner Klassensammlung schnell einen Parser für .ini-Dateien, optimierte ihn und stellte Teile von Yanix darauf um.

Genug von Formaten, zurück zu der Mehrsprachigkeit! Ich habe für die Yanix-Sprachdateien das .ini-Format gewählt, Sprachdateien schauen nun etwa so aus:

1
2
3
4
5
6
[options]
prefix=[PluginController]
 
[strings]
; General
load_failed_file_not_exists=Could not load %plugin%: file not exists

Im Options-Block werden Einstellungen für dne Sprachparser definiert, im Beispiel soll jedem Eintrag bei Abruf der Prefix [PluginController] voran gestellt werden. Variablen können mit %name% definiert werden und werden vom Parser ersetzt.

Ein praktisches Beispiel (in einem Plugin):

Log::Debug($this->Lang('load_failed_file_not_exists', array('plugin' => 'demo')));

In Plugins wird die Methode Lang() der Klasse PluginBase verwendet, von der jedes Plugin erbt. PluginBase hat ein paar Methoden, dazu aber vielleicht ein anderes Mal mehr dazu.

Die Ausgabe der Konsole:

[D 28.12 14:21:51][PluginController] Could not load demo: file not exists

Plugins und Yanix selbst nutzen getrennte Orte zum Speichern der Sprachdateien. Bei Yanix liegen diese im Ordner lang/, bei den Plugins in deren Ordnern.

Eine weitere Möglichkeit, wenn Plugins z.B. sehr viele Sprachstrings brauchen und oft die selben Variablen darin benötigen, ist diese:

1
2
3
4
5
6
7
8
// Namespace definieren ($this->name ist immer der Pluginname)
Lang::UseNamespace($this->name);
// Allgemeine Variablen definieren
Lang::UseVariables(array('plugin' => $this->name, 'foo' => 'bar'));
 
// Sprachstring ausgeben
$string = __('foo');
Log::Debug($string);

Im Moment bin ich noch dabei, das ganze System zu verfeinern und zu optimieren, bis zum Release ist Yanix dann vollständig übersetzbar! :)

¬ geschrieben von Michael in Allgemein, Yanix

Bequeme Logs

27. Dezember 2007

1 Kommentar

Ich habe mich gerade mit den Prozesskontrollfunktionen von PHP auseinander gesetzt um vielleicht ein paar nützliche Funktionen für Yanix zu finden und bin auf ein Problem gestoßen: Ein Feature der Prozesskontrollfunktionen ist es, Prozesse im Hintergrund laufen zu lassen. Wie soll ich ein Skript debuggen, welches ich nicht sehen kann?

Nach ein bisschen Grübeln kam ich auf die Lösung: Bau dir ein Log-Terminal!

Schritt 1: Logging
Diese funktion schreibt in eine Datei (in meinem Fall log.txt im XAMPP-Ordner) die übergebene Nachricht mit der PID des Prozesses der die Nachricht schreibt. Die PID erhalte ich beim Aufruf von pcntl_fork().

1
2
3
4
5
6
7
8
9
function L($msg)
{
	global $pid;
	$logfile = '/opt/lampp/htdocs/log.txt';
	$msg = '[' . date('H:i:s') . "][{$pid}] " . $msg . "\n";
	$f = fopen($logfile, 'a');
	fwrite($f, $msg);
	fclose($f);
}

Schritt 2: Ausgabe
Als nächstes die Ausgabe. Mit ein bisschen PHP, HTML, Javascript und Prototype entstand eine kleines Skript um diese Ausgaben bequem und hübsch in einem Browser ansehen zu können. Das Skript gibt es hier zum Download. Es unterstützt über AJAX entweder die Anzeige einer Datei welche über den Webserver erreichbar ist oder über PHP eine beliebige Datei des Dateisystems. Mehr dazu in den Kommentaren der Datei.

¬ geschrieben von Michael in PHP, Snippets

Wordpress Antispam

27. Dezember 2007

0 Kommentare

Vor kurzem habe ich schon einmal einen Ansatz entwickelt um einfach und schnell Wordpress-Blogs von dummen Spam zu befreien. Ich wollte diesen Ansatz nun erweitert in eine Wordpress-Plugin zusammenfassen, jedoch ist das Wordpress-System dafür nicht geeignet. Ich kann zwar einen Hook beim Erstellen eines neuen Kommentares einrichten, jedoch ist dann bereits der Kommentar in der Datenbank, was ich eigentlich verhindern will.
Hat jemand ‘ne Idee, wie sich das lösen ließe?

Daher lagere ich den Code nun in eine eigene Datei aus, damit der Aufwand sich bei einem Wordpress-Update in Grenzen hält. ;)

Ich werde noch ein paar Tage den von Spam Karma abgefangenen Müll analysieren, dann veröffentliche ich eine neue Version meines kleinen Antispam-Skriptes. Nieder mit dem Spam!

¬ geschrieben von Michael in Allgemein

Benchmark: $i++ vs ++$i

25. Dezember 2007

1 Kommentar

Der erste im Titel genannte Befehl wird in PHP-Skripten sehr gerne eingesetzt: Er erhöht die Zählvariable $i um 1. Die zweite Anweisung macht genau das gleiche, also wieso miteinander vergleichen?

Im Web kursieren Geschichten, dass letzteres schneller sei als erstere. Zeit für einen Vergleich! Damit der Test auch aussagekräftig genug ist, wird der Befehl gleich 10.000.000 ausgeführt. Das bringt auch neuere PCs kurz zum Schwitzen. ;)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// IncrementBench.php
 
$rounds = 10000000;
 
$start1 = microtime(true);
for ($i = 0; $i < $rounds; $i++);
$end1 = microtime(true);
 
$start2 = microtime(true);
for ($i = 0; $i < $rounds; ++$i);
$end2 = microtime(true);
 
echo "\$i++: ".round($end1 - $start1, 5)."Sekunden\n";
echo "++\$i: ".round($end2 - $start2, 5)."Sekunden\n";

Ausgabe des Benchmarks:
michael@michfrm-home:~/Desktop$ php IncrementBench.php
$i++: 3.30877 Sekunden
++$i: 2.81894 Sekunden

Es gibt wirklich einen Unterschied, oft brauchen tut man ihn aber nicht:

1
2
3
4
5
6
7
// iTest.php
 
$i = 0;
echo $i++ . "\n";
 
$i = 0;
echo ++$i . "\n";

Ausgabe:
0
1

Bei $i++ wird zuerst der aktuelle Wert zutück gegeben und dann die Variable hoch gezählt. Bei ++$i zuerst hochgezählt und dann zurück gegeben.

Hier noch einen Tipp:

<BadBoy_> un –$i is schneller als ++$i
<BadBoy_> also wenn reihenfolge egal dann runterzählen, net hoch ;)

Nachgetestet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// IncrementBench.php (-- Version)
 
$rounds = 10000000;
 
$start1 = microtime(true);
for ($i = $rounds; $i > 0; $i--);
$end1 = microtime(true);
 
$start2 = microtime(true);
for ($i = $rounds; $i > 0; --$i);
$end2 = microtime(true);
 
echo "\$i--: ".round($end1 - $start1, 5)."Sekunden\n";
echo "--\$i: ".round($end2 - $start2, 5)."Sekunden\n";

Ausgabe:

michael@michfrm-home:~/Desktop$ php IncrementBench.php
$i–: 3.07346 Sekunden
–$i: 2.62946 Sekunden

¬ geschrieben von Michael in PHP

Kommentar-Spam wirksam entfernen

17. November 2007

12 Kommentare

Jeden Tag bekomme ich von Spam Karma 2 Mails mit Inhalten wie diesen:

There have been 46 comment spams caught since the last digest report 1 Tag ago.

Es ist gut, dass das Plugin so gut den Müll abfängt jedoch muss ich das ständig selbst aus der Datenbank löschen und das Blocken der IPs bringt auch nicht mehr viel. Daher habe ich jetzt die Rambo-Methode benutzt um dem Spam endlich den gar aus zu machen.

Meist enthalten die Mails nur ein Wort wie “Nice”, “Sorry” oder “Interesting”, manchmal noch ein paar Punkte dazu. Da sich die Spammer so dumm anstellen kann man sie einfach blocken:

Öffne Datei /wp-comments-post.php

Finde diesen Code (Zeile 30 bei WP 2.2.3):

$comment_content      = trim($_POST['comment']);

Füge darunter ein:

$spam_words = array('Nice', 'nice', 'Sorry', 'sorry', 'Interesting', 'interesting', 'Cool', 'cool');
foreach ( $spam_words as $word )
{
	if ( $comment_content == $word ) die('You suck!');
	if ( substr($comment_content, 0, strlen($word)) == $word ) die('You suck!');
}

Mal schauen ob Spam Karma ruhiger wird, das Ergebnis seh ich spätestens beim nächsten Bericht.

// Update:
Auf Anregung von BadBoy_ hier eine verbesserte Version:

$spam_words = array('nice', 'sorry', 'interesting', 'cool');
$as_comment = strtolower($comment_content);
foreach ( $spam_words as $word )
{
	if ( $as_comment == $word ) die('You suck!');
	if ( substr($as_comment, 0, strlen($word)) == $word ) die('You suck!');
}

Wieso eine extra Variable? Falls der Kommentar doch durchgehen sollte, wäre er komplett klein geschrieben. ;)

¬ geschrieben von Michael in Blog, PHP, Snippets

Theme von BenediktRB • Powered by Wordpress • Abonniere den RSS Feed