seeseekey.net - Invictus Deus Ex Machina

Vor eini­gen Stun­den wurde die neue Ver­sion der Media­Wiki Soft­ware frei­ge­ge­ben. In dem Release wurde die mini­male benö­tigte PHP Ver­sion auf 5.3.2 ange­ho­ben. An Ver­bes­se­rung sind die neue Diff­an­zeige, sowie Ver­bes­se­run­gen für Far­ben­blinde hin­zu­ge­kom­men. Des wei­te­ren gibt es eine neue Spe­zi­al­seite („Special:MostInterwikis“) sowie das neue Schlüs­sel­wort „{{PAGEID}}“ wel­ches die Sei­ten ID ermit­telt. Neben den Ver­bes­se­run­gen sind auch einige neue Spra­chen wie die Emi­lia­ni­sche Spra­che hin­zu­ge­kom­men. Die neue Ver­sion der Media­Wiki kann unter http://www.mediawiki.org/wiki/MediaWiki/de bezo­gen werden.

Manch­mal möchte man zu ein paar Audi­o­da­teien einen RSS Feed haben, z.B. für einen pri­va­ten Pod­cast. Natür­lich kann man sich einen sol­chen Feed von Hand zusam­men­bauen, ein­fa­cher ist es mit die­sem klei­nen PHP Skript:

<?php
  //Podcast Feed Script
  //Copyright (c) 2012 by seeseekey <seeseekey@gmail.com>
  //
  //This program is free software: you can redistribute it and/or modify
  //it under the terms of the GNU General Public License as published by
  //the Free Software Foundation, either version 3 of the License, or
  //(at your option) any later version.
  //
  //This program is distributed in the hope that it will be useful,
  //but WITHOUT ANY WARRANTY; without even the implied warranty of
  //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  //GNU General Public License for more details.
  //
  //You should have received a copy of the GNU General Public License
  //along with this program.  If not, see <http://www.gnu.org/licenses/>.

  //Basis URL ermitteln
  $baseURL="http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  $baseURL=dirname($baseURL) . "/";

  //XML Header setzen
  header('Content-type: text/xml');

  //RSS Datei zusammenbauen
  $output = '<rss version="2.0">'."\n";
  $output .= '  <channel>'."\n";
  $output .= '    <title>seeseekey.net (privater Podcast)</title>'."\n";
  $output .= '    <description>Ein privater Podcast von seeseekey.net</description>'."\n";
  $output .= '    <link>http://seeseekey.net</link>'."\n";
  $output .= '    <copyright>(c) 2012 by seeseekey</copyright>'."\n";

  //Audio Dateien in RSS Feed einpflegen
  $files = scandir('.');
  foreach ($files as $file)
  {
    $pathparts = pathinfo($file);
    if($pathparts['extension']!="mp3") continue;

    $output .= '    <item>'."\n";
    $output .= '      <title>'.$file.'</title>'."\n";
    $output .= '      <enclosure url="'.$baseURL.$file.'" length="'.filesize($file).'" type="audio/mpeg"/>'."\n";
    $output .= '    </item> '."\n";
  };

  //RSS Feed wieder schließen
  $output .= '  </channel>'."\n";
  $output .= '</rss>'."\n";

  //RSS Feed ausgeben
  echo($output);
?>

Die­ses Skript ließt alle MP3 Dateien aus einem Ord­ner aus und baut dar­aus einen RSS Feed. Die­ser kann dann in der Pod­cas­ting App der Wahl ein­ge­fügt wer­den, indem man die URL angibt so z.B. „http://example.org/podcast.php“. Das Skript selbst steht dabei unter der GPLv3 und lässt sich auch unter https://github.com/seeseekey/archive/blob/master/Web/podcast.php herunterladen.

Im Open Source Bereich gibt es ja durch­aus einige Ticket­sys­teme, wie z.B. das Open Ticket Request Sys­tem (OTRS). Pro­ble­ma­tisch an den meis­ten Open Source Ticket­sys­te­men ist dabei der Umstand das diese meist nicht bei den Wald- und Wie­sen­pro­vi­dern lau­fen, da es dort meist nur PHP und MySQL gibt. OTRS z.B. benö­tigt Perl, andere Sys­teme benö­ti­gen Ruby. Auf der Suche nach einem Sys­tem wel­ches auf einem sol­chen LAMP Sys­tem läuft, habe ich osTi­cket gefun­den. Dabei han­delt es sich um ein freies Ticket­sys­tem unter GPL. Pro­ble­ma­tisch sehe ich bloß das letzte Release wel­ches im Jahr 2010 auf­ge­legt wur­den. Das Sys­tem selbst ist unter http://osticket.com zu fin­den. Der­zeit scheint es lei­der kein halb­wegs aktu­el­les Open Source Ticket­sys­tem (wel­ches unter PHP und MySQL läuft) zu geben.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://de.wikipedia.org/wiki/Open_Ticket_Request_System
http://en.wikipedia.org/wiki/Comparison_of_ticket-tracking_systems

Um Piwik in die Media­Wiki zu inte­grie­ren gibt es eine Exten­sion die auf den „Piwik Inte­gra­tion“ hört. Das Pro­blem die­ser Exten­sion ist das sie seit 2009 nicht mehr wei­ter­ent­wi­ckelt wurde. Bedingt dadurch funk­tio­niert das ganze nicht mehr mit der aktu­el­len Media Wiki Version.

Abhilfe schafft hier die Exten­sion „PCR GUI Ins­erts“ wel­che unter http://www.mediawiki.org/wiki/Extension:PCR_GUI_Inserts zu fin­den ist. Mit die­ser Exten­sion ist es mög­lich Code auf der Media­Wiki ein­zu­bin­den. Im Gegen­satz zu ande­ren Ver­fah­ren, wie z.B. dem direk­ten edi­tie­ren der Tem­pla­te­da­teien funk­tio­niert diese Lösung auch nach einem Update der Media­Wiki Ver­sion weiter.

Für die Instal­la­tion muss man dabei fol­gende Schritte befolgen:

  • Exten­sion her­un­ter­la­den
  • den ent­pack­ten Ord­ner in den „exten­si­ons“ Ord­ner der Media­Wiki hochladen
  • die „LocalSettings.php“ bearbeiten

Bei der Bear­bei­tung der „LocalSettings.php“ muss nur die Zeile:

require_once( "$IP/extensions/PCRGUIInserts/pcr_guii.php" );

an das Ende der Datei ange­fügt wer­den. Danach ist die „PCR GUI Ins­erts“ Erwei­te­rung aktiv. Nun muss nur noch der Piwik Tracking Code ein­ge­baut wer­den. Dazu gibt es in der ent­spre­chen­den Wiki ein schö­nes Bei­spiel:

$wgPCRguii_Inserts['SkinAfterBottomScripts']['on'] = true;
$wgPCRguii_Inserts['SkinAfterBottomScripts']['content'] = '<script type="text/javascript">
var pkBaseURL = (("https:" == document.location.protocol) ? "https://piwik.example.com/" : "http://piwik.example.com/");
document.write(unescape("%3Cscript src=\'" + pkBaseURL + "piwik.js\' type=\'text/javascript\'%3E%3C/script%3E"));
</script><script type="text/javascript">
try {
var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 2);
piwikTracker.trackPageView();
piwikTracker.enableLinkTracking();
} catch( err ) {}
</script><noscript><p><img src="http://piwik.example.com/piwik.php?idsite=2" style="border:0" alt="" /></p></noscript>';

Diese Zei­len wer­den dabei auch in die „LocalSettings.php“ geschrie­ben. Natür­lich müs­sen die ent­spre­chen­den Domain­na­men ange­passt wer­den, sowie die pas­sende Num­mer für die zu tra­ckende Web­seite benutzt werden.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://de.wikipedia.org/wiki/Piwik
http://de.wikipedia.org/wiki/MediaWiki

Manch­mal benö­tigt man eine MySQL Kom­man­do­zeile, hat aber kein „phpmyad­min“ zur Ver­fü­gung. Für einen sol­chen Fall wäre es schön wenn man eine kleine Anwen­dung hätte wel­che die­ses Pro­blem löst. Genau hier setzt die PHP Anwen­dung „Admi­ner“ an. Dabei han­delt es sich sozu­sa­gen um eine „phpmyad­min“ Minimalversion.

SQL-Query Ansicht im Adminer

Das schöne am Admi­ner ist das er nur aus einer Datei besteht und so unkom­pli­ziert „instal­liert“ wer­den kann. Zu fin­den ist das ganze unter http://www.adminer.org.

Wie Heise ges­tern berich­tete (http://www.heise.de/newsticker/meldung/Gefahr-durch-offene-PHP-Luecke-1567433.html) gibt es eine wun­der­schöne Sicher­heits­lü­cke im Bezug auf CGI und PHP. So führt der Aufruf:

http://localhost/index.php?-s

dazu das der Quell­code der Web­seite aus­ge­ge­ben wird. Das ist natür­lich unprak­tisch wenn dort Kon­fi­gu­ra­ti­ons­va­ria­blen ent­hal­ten z.B. die Zugangs­da­ten für eine Daten­bank­ver­bin­dung. Zur Lösung des Pro­blems gibt es drei Varianten:

  • PHP Ver­sion mit dem Bug­fix einspielen
  • Rewrite Anwei­sung in die .htaccess
  • Wrap­per wel­cher vor dem PHP-CGI auf­ge­ru­fen wird

Die erste Vari­ante schei­det aus, da der aktu­elle Bug­fix leicht umgan­gen wer­den kann. Die zweite Vari­ante (ein­zu­tra­gen in eine „.htac­cess“) sieht so aus:

RewriteEngine on
RewriteCond %{QUERY_STRING} ^[^=]*$
RewriteCond %{QUERY_STRING} %2d|\- [NC]
RewriteRule .? - [F,L]

Die dritte Vari­ante setzt einen Wrap­per vor den eigent­lich Auf­ruf und fil­tert die ent­spre­chen­den Anwei­sun­gen her­aus. Dazu ändert man in der „httpd.conf“ die Zeile:

Action  application/x-httpd-php /cgi-bin/php-cgi.exe

in

Action  application/x-httpd-php /cgi-bin/php-cgi-wrapper.exe

und star­tet den Apa­che Ser­ver neu. Der Quell­text des Wrap­pers sieht dabei so aus:

#include <process.h>

#define PHP_ORIG "php-cgi.exe"

int main(int argc, char **argv)
{
    if(argc>1) argv[1]=0;
    _execv(PHP_ORIG, argv);
}

Das ganze kann hier auch als fer­ti­ges Visual Stu­dio Pro­jekt oder gleich als aus­führ­bare Datei her­un­ter­ge­la­den werden.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://www.kb.cert.org/vuls/id/520827
http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/
http://www.heise.de/newsticker/meldung/PHP-patcht-schnell-aber-nicht-gruendlich-1567906.html

Manch­mal ist es gewünscht das eine PHP Anwen­dung eine Datei an den Cli­ent sen­det. Das könnte dann z.B. so aussehen:

header("Content-type: application/pdf");
header("Content-Length: " . strlen($tmp));
echo $tmp;

Diese Vari­ante funk­tio­niert im ers­ten Moment erst ein­mal ohne Pro­bleme in allen Brow­sern. Zum Pro­blem wird dies erst, wenn die Seite über HTTPS zu errei­chen sein soll. In die­sem Fall stürzt der Inter­net Explo­rer ohne Feh­ler­mel­dung ab. Der Trick hier ist es einen „Cache-Control“ Ein­trag hin­zu­zu­fü­gen (wel­chen der Inter­net Explo­rer bei HTTPS anschei­nend benötigt)

header("Cache-Control:  maxage=1");
header("Pragma: public");
header("Content-type: application/pdf");
header("Content-Length: " . strlen($tmp));
echo $tmp;

Mit die­ser Vari­ante funk­tio­niert das ganze dann auch im Inter­net Explo­rer unter HTTPS.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://stackoverflow.com/questions/773308/ie-https-generating-pdf-from-php-file-doesnt-work

Nach dem Update der Media­Wiki Soft­ware auf die Ver­sion 1.18 bekam ich fol­gen­den Fehler:

Fatal error: Cannot redeclare wfprofilein() (previously declared in /www/wiki/includes/profiler/Profiler.php:14) 
in /www/wiki/includes/ProfilerStub.php on line 25

Die Lösung des Pro­ble­mes war ganz ein­fach. Irgend­wie wurde der Pro­fi­ler akti­viert. Dies äußerte sich darin das es im Haupt­ord­ner der Soft­ware eine Datei namens StartProfiler.php gab. Wenn man diese Datei ent­fernt, ist das Pro­blem gelöst.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://www.mediawiki.org/

Bei einer mul­ti­lin­gua­len Webap­pli­ka­tion wel­che in PHP geschrie­ben ist, kann man natür­lich zur Über­set­zung mit asso­zia­ti­ven Arrays arbei­ten und dann je nach Spra­che die rich­tige PHP Datei einbinden.

$lang['welcome'] = 'Willkommen auf dieser Webseite.';
$lang['maintenance'] = 'Die Webseite befindet sich in der Wartung.';

Das Pro­blem an die­ser Vari­ante ist, das sie nicht wirk­lich gut zu pfle­gen ist. Schö­ner ist es das ganze mit get­text zu über­set­zen, da man hier nur die po Dateien über­set­zen muss, und man das nicht im Quell­text tun muss.

Das Pro­blem an die­ser Vari­ante ist aller­dings, das nicht auf jeden Web­ser­ver get­text vor­han­den ist. Hier hilft das Paket php-gettext wel­ches unter https://launchpad.net/php-gettext/ zu fin­den ist. Mit Hilfe die­ses Pake­tes, kann man get­text nut­zen ohne sich darum küm­mern zu müs­sen ob es instal­liert ist. php-gettext wrappt das ganze und emu­liert nicht vor­han­dene Funktionen.

Das ganze zu benut­zen ist auch rela­tiv einfach:

 //gettext initialisieren
 $locale = "de_DE"; //Sprache definieren
 $domain = 'default'; //Domäne definieren
 $encoding = 'UTF-8'; //Zeichenkodierung definieren

 //include gettext
 require_once('./ext/php-gettext/gettext.inc');

 //Sprache setzen
 T_setlocale(LC_MESSAGES, $locale);

 //Pfad zu den Übersetzungen definieren
 T_bindtextdomain($domain, './locale/');

 //Zeichenkodierung setzen
 T_bind_textdomain_codeset($domain, $encoding);

 //Domäne setzen
 T_textdomain($domain);

Nach­dem dies getan ist, kann damit begon­nen wer­den die Texte in der Anwen­dung zu über­set­zen. Dabei wird aus einem:

echo 'Willkommen auf dieser Webseite.';

ein:

echo T_('Willkommen auf dieser Webseite.');

T_ ist dabei der Name der Über­set­zungs­funk­tion wel­che von php-gettext bereit­ge­stellt wür­den. Unter rei­nem get­text würde diese Funk­tion nur _ hei­ßen. Nach­dem man sei­nen Quell­text mit den ent­spre­chen­den Funk­tio­nen bestückt hat muss man diese Strings aus den PHP Dateien extra­hie­ren. Da man das nicht von Hand machen möchte nut­zen wir dazu fol­gen­des klei­nes Skript:

 #!/bin/sh

 #Schreibe alle PHP Dateien in eine Textdatei
(find ./data -name "*.php" && find ./system -name "*.php") > update-translations.txt

 #Rufe xgettext auf um die pot Datei zu erzeugen
 xgettext -f update-translations.txt -kT_ngettext:1,2 -kT_ --language=PHP -o update-translations.pot

Mit die­ser pot Datei kann mit­tels PoEdit (http://www.poedit.net/) eine po Datei erzeugt wer­den. Diese po Dateien kön­nen auch wie­der mit­tels der pot Datei aktua­li­siert wer­den, falls spä­ter neue Strings dazu kom­men oder ver­schwin­den. Beim spei­chern gene­riert PoEdit aus der po Datei eine mo Datei, bei wel­cher es sich um die binäre Rep­re­sen­ta­tion der po Datei han­delt. Diese mo Datei wird von get­text letzt­end­lich zur Über­set­zung genutzt.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://phpmagazin.de/itr/online_artikel/psecom,id,874,nodeid,62,_language,de.html
http://blog.medianetix.de/2008/12/ubersetzung-von-quelltexten-mit-gettext-und-poedit/