Pimped Apache Server Status Update v1.10

Montag, 19. Mai, 2014

Mein PHP Tool “Pimped Apache Server Status” macht den Apache Status lesbar. Dies funktioniert auch mit mehreren Webservern gleichzeitig und eignet sich so auch zum Live Monitoring von loadbalancten Webseiten.

Im letzten Update kamen 2 Boxen in der oberen Reihe hinzu. Sie zeigen die Anzahl der abgefragten Webserver an und wie lange dies brauchte.

2014-05-19-pimped-apache-status-v110.png

Im LAN bei mir auf Arbeit wird der Status von 19 Webservern in weniger als 0.3 Sekunden geholt.
Wie weit es nach oben skaliert, weiss ich noch nicht. Erfahrungsberichte von anderen Webmastern/ Sysadmins sind daher willkommen!

Update:
Ich habe mich noch einmal genauer belesen…
Die einzelnen Apache Server status werden in der Methode ServerStatus->getStatus() (s. Datei ./classes/serverstatus.class.php) mittels curl_multi_exec() geholt. Bei dieser Funktion erfolgen die Requests - wie ich es auf php.net lese - sequentiell.
Erst ab PHP Version 5.5 gibt es eine Funktion curl_multi_setopt, mit der man parallele Requests steuern kann - aber auf diese PHP-Version ist mein Tool noch nicht getrimmt.

Weiterführende Links:

Linkchecker auf meiner Webseite

Freitag, 14. März, 2014

Hinweis: Dieser Artikel von 2014 ist veraltet. Als Linkchecker verwende ich nun den meinen ahCrawler

In meiner alten Webseite hatte ich in externen Linkchecker direkt als Link im HTML-Code.
Im neuen CMS ist das nicht mehr so. Alle Links verweisen auf die echte Zielseite. Aber ich habe weiterhin einen Linkchecker integriert - allerdings als Javascript-Löung.

So funktioniert es:

Alle Links zeigen auf die Zielseite.

<a href="http://example.com/">Beispiellink</a>

Nun ist es so, dass ich in meinen Artikeln keinerlei externe Links verwende. Alle externen Links sind rechterhand platziert - in einem DIV namens “sbright” (”sb” für sidebar).
Alle Links in diesem Div - also nicht die auf der Seite insgesamt - werden geprüft, ob sie eine externe Referenz besitzen - falls ja, wird das Onclick Event umgebogen auf ein PHP-Skript inc_urlchecker.php. Diese Funktion nutzt jQuery:

/**
 * change external links in the sidebar: a linkchecker will be added
 * @returns {undefined}
 */
function initAddLinkchecker(){
    var sLink=false;
    $("#sbright a").each(function() {
        // do something with external links:
        if (this.href.indexOf("axel-hahn.de")<0){
            sLink=this.href;
            sLink="/axel/php/inc_urlchecker.php?url="+sLink;
            $(this).attr("onclick", "location.href='"+sLink+"'; return false;");
        }
    });
}

In jenem PHP-Skript wird der übergebene Link mit einem Http Head Request mittels Curl geprüft.

// from http://php.net/manual/en/function.get-headers.php
function get_headers_curl($url) {
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_NOBODY, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);

    $r = curl_exec($ch);
    $r = preg_split("/n/", $r);
    return $r;
}

Ist der Http-Response Code OK (200er und 300er Http-Statuscodes) wird der Besucher weitergeleitet. Wenn nicht, gibt es einen entsprechenden Hinweis im Webbrowser samt Entschuldigung, Fehlermeldung und Link zurück zur letzten Seite.

Ach so, und vom letzten Test eines Links wird der Response Header in eine (Sqlite) Datenbank geschrieben. Die sehe ich gelegentlich ein und weiss, welche Links ins Nirvana gehen.

Weiterführende Links:

Webseite umgestellt auf Concrete 5

Dienstag, 11. März, 2014

Wer ab und an auf meiner Webseite war, wird es bemerkt haben: sie sieht nun anders aus. Die bisherigen Inhalte sind (zumeist) noch da, haben aber eine neue URL.

Ich habe meine Webseite auf das CMS Conrete 5 umgestellt.

Wer eine alte Adresse ansurft …
… sei es, er wählt einen Bookmark, einen nunmehr veralteten Link aus einem Forum oder dem noch nicht aktualisierten Suchindex einer Suchmaschine, der kommt auf eine Umleitungsseite.
Diese Umleitungsseite kennt das Mapping von der alten zur neuen URL. Suchmaschinen werden sofort mit einem 30x auf die neue Seite umgeleitet (Google hat übrigens so sehr schnell gelernt!); andere Benutzer bekommen einen Hinweis und den neuen Link angeboten.

Apache-Rewrite Regel für alte Seiten:

RewriteRule ^(axel.*).html$ /(...)/redirector_phpcms.php [PT,QSA]

Wenn das Redirect-Skript einen Bot erkennt, dann gibt es statt der Hinweis-Seite ein 301:

// ----- Bots ein 30x senden
if ($sNewUrl){
    if (
            stripos($_SERVER["HTTP_USER_AGENT"], "spider")>0
            || stripos($_SERVER["HTTP_USER_AGENT"], "bot")>0
            || stripos($_SERVER["HTTP_USER_AGENT"], "wget")>0
            (...)
       ){
            header("HTTP/1.1 301 Moved Permanently");
            header("Location: $sNewUrl");
       }
}

Warum das Ganze?
Bisher habe ich einen Parser verwendet, dessen Entwicklung seit einer gefühlten Ewigkeit eingestellt ist. Securitymässg ist das keine so tolle Ausgangslage.
Die Wahl fiel deshalb auf Concrete 5, weil ich bereits andere Webseiten damit umgesetzt habe und das Benutzerinterface beim Bearbeiten ganz nett und angenehm finde.

Was blieb gleich?
Die visuelle Menüstruktur blieb weitestgehend identisch. Die neue Webseite wurde aufgeschaltet, als ich ca. 95% der Inhalte und Funktionen drin hatte. Nur mit neuen URLs halt. Was fehlt, sind Fotos und VB-Script- und einige veraltete Javascript-Seiten.
Was sonst so gleich blieb:

  • Statistik erfolgt weiterhin mit Piwik
  • die Suche ist immernoch die von Sphider
  • mein bisheriger HTML5-Audioplayer ist integriert (AMC Player)
  • RSS News zu div. Themen werden im Hintergrund aktualisiert

Um meine Inhalte übernehmen zu können, brauchte ich unbedingt den Ersetzungsmechanismus aus dem bisherigen Parser. Dafür habe ich eine PHP-Klassse (mit Hilfe der Originalvorlage) geschrieben.

Was ist neu?
Neben dem Unterbau und den URLs (eben wg. des neuen CMS)

  • werden Elemente von Bootstrap 3 genutzt: Menüs, Icons, Tabellen und andere Elemente nutzen dieses Framwork.
  • das Layout wurde etwas frischer.
  • Seiten können Tags haben. Mit Klick auf einen Tag kommt man zu einer Suchseite, die Seiten aufzeigt, die denselben Tag verwenden.
  • Seiten-Inhalte zu verwalten ist für mich einfacher. Davon habt ihr zwar nichts direkt, aber ihr profitiert davon.

weiterführende Links

  • Concrete 5 (CMS; Opensource)
  • Matomo.org (Statistik-Tool; früher: Piwik)
  • Bootstrap (HTML-Framework)
  • http://www.sphider.eu/ - Sphider (PHP-Suchmaschine - Anm.: hat bekannte Sicherheitslücken und wird nicht mehr weiterentwickelt)
  • AMC Player (HTML5 Audioplayer für surround und stereo)
  • RSS-News (im Menü rechts dann eine Rubrik wählen)

Mysql-connect sehr langsam?

Mittwoch, 28. August, 2013

Für Windows gibt es fixfertige Pakete für die Kombination Apache + Php + Mysql + X, wie z.B. XAMPP oder Wamp.

Für ein kleines Projekt habe ich auf eine solche zurückgegriffen und irgendwie war es langsam. Was genau langsam war, war nach einigem Debugging lokalisiert:

(...)
$iStart=microtime(true);
mysql_connect($hostname . ":" . $hostport, $username, $password);
echo microtime(true) - $iStart."s to open DB $database<br>";
(...)

Das mysql_connect() brauchte regelmässig 1 Sekunde - die anschliessenden Queries 0.00x Sekunden.

Ursache ist der Zugriff mit dem Hostnamen “localhost” auf die Loopback-Adresse. Wenn man den Mysql-Service auf eine IP-Adresse bindet, geht es massiv schneller. Konfiguriert wird dies in der my.ini im Installationsverzeichnis von Mysql. Oder man verbindet sich auf die IP-Adresse 127.0.0.1.
Ach, und unter Windows den Eintrag lower_case_table_names=2 nicht vergessen - daher schiebe ich es mal hinterher:

(...)
bind-address="127.0.0.1"
bind-address = ::1          # fuer ipv6
lower_case_table_names=2 
(...)

Nach Änderung der Konfiguration muss man den Mysql-Dienst neu starten, damit es wirksam wird.

Weiterführende Links:

Ausgabe des Blogs wurde verbessert

Montag, 22. Juli, 2013

Ein paar Kleinigkeiten verbessert man immer mal wieder hier und da …

1) Microdata eingeführt

Naja, zumindest einmal rudimentär. Vielleicht können Suchmaschinen dann etwas genauer die Bloginhalte analysieren.
Die Anpassung erfolgte in den Template-Files unter
[Flatpress-Root]/fp-interface/themes/[Theme-Name]/*.tpl
anhand des Links [01] (s.u.).

2) Filtertyp und Wert anzeigen
Wenn man im Archiv Monat/ Jahr wählte oder aber eine der Kategorieen, so war funktionell die darauffolgende Ansicht korrekt, aber es wurde in Flatpress nicht ausgegeben, dass und welche Filteraktion gerade greift. Nun wird der Anzeigemodus eingeblendet:

2013-07-22-h2-nach-datum.png 2013-07-22-h2-archiv.png 2013-07-22-h2-artikel.png
[Weiterlesen…]

Pimped Apache Status - ZPanel Modul verfügbar

Montag, 15. Juli, 2013

Ist doch schön, dass Leute Gefallen an meinem Tool finden.
Vor ein paar Tagen hat mir Russel einen Fix gesendet, weil das Curl-Multiexec (das holt von allen Webservern parallel die Statusinformationen ab) in seiner Umgebung zu lange brauchte. Und nebenbei weiss ich nun auch, dass es auch ein ZPanel Modul für meine PHP-Applikation gibt.

Nachtrag:
Ich hab soeben auch auf Version 1.08 aktualisiert, die den Fix für curl und als neues Feature die Anzeige von Balken enthält.

2013-07-15-apachestatus_bars_02.png

  • Pimped Apache Status - Webseite
  • Pimped Apache Status - auf Sourceforge
  • http://forums.zpanelcp.com/showthread.php?28323-Pimped-Apache-Status - ZPanel Forum mit Installationsanleitung für ZPanel (Anm.: Die Webseite forums.zpanelcp.com wurde deaktiviert)

Pimped Apachestatus - v1.0 released

Dienstag, 20. November, 2012

Viele kennen den Apache Webserver … und dann wohl auch dessen Server-status Seite. Weil man diese HTML-Seite nicht wirklich toll lesen und verwerten kann, habe ich mir ein Tool geschrieben, das diese Seite parst und durch verschiedene Filter gejagt, die verschiedensten Infos als Tabellen darstellt:

  • nur aktive Requests anzeigen
  • häufigste Requests
  • längste Requests
  • u.v.m.

Alle Tabellen sind per Mausklick sortierbar und lassen sich durch Texteingabe filtern.
Die Tabellen lassen sich exportieren, z.B. CSV oder XML.

Das Ganze funktioniert nicht nur mit einem einzelnen Apache-Server - man kann mehrere Apache-Server, die gemeinsam hinter einem Loadbalancer dieselbe Webseite ausliefern, in einer Tabelle zusammenfassen. Die häufigsten oder längsten Requests auf 5 oder 10 Servern zu ermitteln - das ist mit Lesen der Server-Status-Seiten unmöglich - mit meinem Tool wird’s zum Kinderspiel.

Seit einem Jahr sind immer wieder etliche Versionen veröffentlicht wurden, bei denen ich das Gefühl hatte: “Ja eigentlich funktioniert ja alles, wie es soll”.

Heute - ja heute - ist alles anders: mein heutiger Release heisst Version 1.0. Tusch!!!

2012-11-20-pimped-apache-status-was-released.jpg 2012-11-20-pimped-apache-status-worker.jpg 2012-11-20-pimped-apache-status-most-requested.jpg

Weiterführende Links:

PHP-Schnipsel: Hintergrundjobs durch Seitenaufrufe auslösen lassen

Sonntag, 6. März, 2011

Wenn man bei seinem Provider keinen Cronjob einrichten kann, aber genügend Besucher hat, kann man ggf. Hintergrundjobs während der Seitenaufrufe auslösen. Man muss dafür sorgen, dass nicht jeder einzelne Seitenaufruf die Verarbeitung triggert, sondern es soll max alle n Sekunden geschehen.

In PHP definiere ich ein Array mit der Konfiguration und ein Arbeitsverzeichnis. Im Arbeitsverzeichnis wird bei Ausführung eines Jobs eine Datei zum Merken des letzten Ausführungsdatums getoucht (jaja, ein schönes deutsches Wort). Soll derselbe Job erneut ausgeführt werden, wird das Alter der Datei im Arbeitsverzeichnis geprüft. Wenn das Alter Älter als mein definiertes Limit ist, dann wird der Job erneut ausgeführt - ansonsten nicht.

Klingt einfach … - ist es auch ;-)

Voraussetzungen, damit das nachfolgende Beispiel funktioniert:

  • wget muss am Webserver vorhanden sein (alternativ liessen sich auch curl oder lynx verwenden)
  • PHP-Funktion exec muss zugelassen sein
  • getestet wurde es nur mit einem Unix-System als Webserver (für Windows s. Anmerkungen unten)

[Weiterlesen…]

PHP mit Sqlite - mein erster Gehversuch

Donnerstag, 28. Oktober, 2010

Ich habe mal einen Download-Zähler gebaut: mittels .htaccess werden alle Dateizugriffe auf ein PHP-Skript umgebogen, welches einmal die angeforderte Datei ausliefert und den Zugriff protokolliert.

In PHP5 ist Sqlite direkt mitgeliefert. Die Sqlite Datenbank ist eine Textdatei, auf die ohne einen laufenden Server zugegriffen wird. Für kleine Webauftritte, wo das Webroot nicht auf einem NFS- oder SMB-Share liegt, ist dies problemlos.

Der wesentliche Vorteil einer SQl-Datenbank zu einer (CSV-) Textdatei ist die Auswertung der Daten: mit SQL Queries kommt man schnell zu den gewünschten Informationen.

Ich definiere mal in PHP eine Variable mit dem Dateinamen zur Datenbank:

$sqliteDB = $_SERVER['DOCUMENT_ROOT']."/sqlite/downloads.sqlite";

In dieser Datenbank ist - weil es zum Einstieg einfacher ist: mit einem grafischen Tool - eine Tabelle angelegt worden:

CREATE TABLE "downloadcount" (
   "id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL  UNIQUE ,
  "time" DATETIME,
  "file" TEXT,
  "ext" TEXT,
  "ip" TEXT,
  "referrer" TEXT,
  "usaeragent" TEXT
)

Dann muss man nur noch wissen, welcher Sqlite Treiber beim Provider vorhanden ist. Das kann wahlweise Sqlite2, Sqlite3 oder PDO Sqlite sein. Die Versionen unterscheiden sich bei den Kommandos zum Öffnen der Datenbank oder beim Aufruf zum Ausführen eines Queries.

Bei Sqlite 3

$db = new SQLite3($sqliteDB);

Bei PDO Sqlite 3:

$db = new PDO("sqlite:".$sqliteDB);

Ich beziehe mich mal auf die PDO Variante…
So öffnet man eine DB und fügt mit Ausführung eines SQL Statements einen Eintrag hinzu. Eingefügt werden hier die aktuelle Uhrzeit (des Requests), Dateiname und dessen Erweiterung, IP-Adresse des Aufrufers, Referrer und User-Agent.

// $filename enthält den Dateinamen der heruntergeladenen Datei
$db = new PDO("sqlite:".$sqliteDB);
if ($db) {
  $path_info = pathinfo($filename);
  $ext=$path_info['extension'];

  $sql="INSERT INTO `downloadcount`
    (`time`, `file`, `ext`, `ip`, `referrer`, `useragent`)
    VALUES ('".date("Y-m-d H:i:s")."', '" . $filename . "', '".$ext."', '" . getenv("REMOTE_ADDR") . "',  '" . getenv('HTTP_REFERER') ."','".getenv('HTTP_USER_AGENT')."');
  ";

  // echo "SQL:<br>$sql<br>";
  $db->exec($sql);
}

Weiterführende Links: