Fallen beim Statuscheck lang laufender PHP-Jobs mit Ajax – I

Wir entwickeln gerade ein User-Interface für eine PHP-basierte “Supply Chain Netzwerk-Simulation”. Dabei kommen Javascript, jQuery und Ajax zum Einsatz. Vor kurzem mussten wir uns mit dem Problem befassen, wie man mit periodischen Ajax-Jobs den zwischenzeitlichen Status von lang laufenden PHP-Berechnungs- und Simulationsjobs abfragt. Dabei sind wir in zwei Fallen getappt, die uns eigentlich hätten bekannt sein müssen. Aber inaktives Wissen schützt manchmal nicht vor naiven Herangehensweisen :-).

Ich stelle die relevanten Punkte in mehreren Blog-Beiträgen mal für interessierte Leser zusammen. Die erste potentielle Falle liegt auf der PHP-Seite und hat mit Sessions zu tun; die zweite Falle liegt im JS/jQuery-Bereich des Clients und hat damit zu tun, dass sich die Bedeutung der “this”-Referenz kontext-abhängig und damit trotz konsequenten Einsatzes von Objekt-Patterns ggf. unerwartet ändern kann.

Aufgabenstellung

Wir haben es mit folgender Aufgabe zu tun:
Ein lang laufender PHP Job [wir nennen ihn nachfolgend “RUN”] wird von einem User-Interface (Web-Seite im Browser – nachfolgend “CLIENT” genannt) gestartet. In unserem Fall ist RUN z.B. eine 60 Sekunden lang laufende PHP-Simulationsberechnung. Dieser PHP-Job schreibt seinen sehr langen fachlich-technischen Ergebnis-Output einerseits in Datenbanktabellen, aber Teile davon zur direkten User-Information sukzessive auch in ein separat geöffnetes zweites Fenster des Browsers. Gleichzeitig – d.h. während der Laufzeit – wollen wir aber zu verschiedenen Zwischenschritten des RUNs knappe Statusmeldungen abfragen und diese in speziellen DIVs des ursprünglichen CLIENT-Windows anzeigen. Um diese Zielsetzung zu erreichen, sehen wir 3 Schritte vor:

  1. Unmittelbar vor dem Start von RUN über eine Submit-Ereignis öffnen wir per Javascript ein zweites Browserfenster.
  2. RUN wird vom CLIENT-Window per Javascript und eine gezielte “submit”-Methode mit geeignetem Target so gestartet, dass sein primärer fachlich/technischer Output an das zuvor geöffnetes zweite Browserfenster übermittelt wird.
  3. RUN schreibt seine Statusmeldungen auf dem PHP-Server kontinuierlich in einen selbst verwalteten Message-Buffer.
  4. Vom CLIENT-Window aus starten wir kurz nach dem Submit von RUN mittels Javascript und JQuery periodisch Ajax-PHP-Jobs, die die Änderungen im Message-Buffer des Servers abfragen und zum CLIENT transferieren. Diese kurz laufenden Ajax-Jobs nennen wir nachfolgend “CHECKER”.
     
    Die durch die CHECKER ermittelten Statusdaten werden z.B. als JSON-Daten über den jeweils geöffneten Ajax-Kanal zum CLIENT transferiert. Dort werden sie über Callback-Methoden definierter Javascript-Objekte ausgewertet, aufbereitet und mit jQuery in die dafür vorgesehenen, speziellen DIVs des CLIENTs geschrieben.
    [Für den periodischen Start kann man Javascripts “setInterval” einsetzen und über die ermittelten Status-Daten den Timer am CLIENT nach dem Ende des RUN-Jobs auf dem Server auch wieder abbrechen.]

Unser erster naiver Ansatz für den Message-Buffer war der, den PHP-Sessionspeicher als Ort eines Message-Arrays zu nutzen. Ein Motiv dafür war der technisch einfache Zugriff auf die Daten des Sessionspeichers. Mit diesem Ansatz sind wir (natürlich) kläglich gescheitert.

Falle 1: Locked $_Session-Array

Normalerweise nutzen wir Ajax im Rahmen unseres CMS-Frameworks “ixCMF”. Damit werden Formular- und Webseiten des CMS selbst, wie später auch die Ergebnisseiten dynamisch auf Basis von Datenbank-Inhalten und PEAR-ITX-Templates erstellt. Das funktioniert zuverlässig und
schnell. Die zum Browser übermittelten HTML-Seiten nutzen dann wiederum Ajax-Funktionalitäten, um bestimmte Transaktionen wie ein Zwischenspeichern oder Abfragen von Daten im Hintergrund asynchron zu bewältigen.

Für Transaktionen des CMS wird auch der PHP Session-Speicher genutzt. Strukturell und vom Bedienungsablauf sind die Verhältnisse allerdings so, dass über die ixCMF-PHP-Programme und Ajax-Jobs ein Zugriff auf den Sessionspeicher während einer Websitzung des Users sequentiell und damit synchron abläuft. Über parallele, asynchrone Abfragen des Sessionspeichers durch mehrere gleichzeitig arbeitende PHP-Ajax-Jobs mussten wir uns bislang nie Gedanken machen. Da die Ajax-Jobs den Sessionspeicher lesend nutzen, gab es auch keinen Anlass, sich über potentielle Inkonsistenzen aufgrund parallel schreibender Jobs Sorgen zu machen.

Denkt man über das oben als Aufgabe beschriebene Szenario aber erst einmal in allgemeingültiger Form nach, dann fallen einem jedoch zwei Dinge auf:

  • Es kann zu Race-Conditions kommen. Parallel laufende Jobs können sich gegenseitig Session-Daten zerstören, wenn sie gleichzeitig schreibend auf ein und denselben Sessionspeicher zugreifen dürfen.
  • Sequentielle Zugriffe auf den Sessionspeicher lassen sich vom Webserver und nicht zuletzt auch von den PHP-Programmen selbst besser steuern und überwachen. Dies dient u.a. der Sicherheit. Ein parallel erlaubter Zugriff würde viele mögliche Schutz-Mechanismen wie die sequentiell Vergabe und Überwachung von kryptierten zufälligen Transaktionsnummern oder zusätzliche zeit- und ID-bezogene Schutzmechanismen über sequentiell vergebene kryptierte Cookies, die über eine Session hinweg verfolgt werden sollen, von vornherein aushebeln.

Der erste Punkt ist aufgrund der speziellen Session-Behandlung von PHP im Detail ggf. noch komplexer, als man meinen möchte. Siehe hierzu die gründliche Diskussion unter folgendem Link.
https://00f.net/2011/01/19/thoughts-on-php-sessions/

Der zweite Punkt hätte uns eigentlich selbst sofort zu denken geben müssen, da wir entsprechende Session-Schutz-Mechanismen im Rahmen unseres ixCMF-Frameworks selbst programmiert und immer wieder genutzt haben.

Jedenfalls gilt: Aus den genannten Gründen wird der Standardzugriff auf Sessions von PHP sequentialisiert:

PHP -Programme können nur sequentiell auf einen Standard-Session-Speicher zugreifen. Der Job, der sich gerade über session_start() den Zugriff verschafft hat, sperrt den Sessionspeicher gegen Zugriffe von anderen Programmen vollständig, bis er die Session über “session_commit” oder “session_write_close” freigegeben hat. Oft geschieht dies erst implizit am Ende der Laufzeit eines PHP-Programms.

Zu welchem Verhalten führt das in unserem Szenario ? Ganz einfach:

RUN blockt den Sessionspeicher bis zum Ende seiner Laufzeit und alle zwischenzeitlich gestarteten Ajax-Jobs müssen bis dahin warten. Damit aber wird eine zwischenzeitliches Verfolgen der Statusmeldungen von RUN unmöglich. Sprich: der ganze geplante parallele und periodische Abgriff von Statusinformationen, die RUN in S_SESSION hinterlegen sollte, funktioniert nicht. Es kommt vielmehr zu einem sinnlosen Stau der CHECKER-Jobs und jeder dieser Jobs ermittelt nach Abschluss von RUN Statusdaten raus, die bereits veraltet sind.

Das gleiche Sperr- und Warteverhalten erleben viele User und Administratoren in schlecht durchdachten Systemen, wenn schnell hintereinander gestartete PHP-Jobs die gleiche Session nutzen sollen oder müssen.

session_write_close() ist keine Lösung!

Nun empfehlen viele durch ähnliche Probleme Betroffene in Internet-Beiträgen die frühest mögliche Anwendung von “session_write_close()” als
Lösung. Siehe hierzu die am Ende des Beitrags als Beispiele angegebenen Links. Die Idee ist eine frühzeitige Freigabe des Sessionspeichers durch das jeweilige Programm, das aktuell auf den Sessionspeicher zugreift. Das mag ja in vielen Fällen gehen, nicht aber in unserem:

Hat ein Programm den Sessionspeicher über “session_commit()” oder “session_write_close()” erst einmal freigegeben, können zwar andere Programme auf den Sessionspeicher zugreifen, es selbst aber während seiner Laufzeit nicht mehr !

Die kurz laufenden Ajax-CHECKER-Jobs könnten session_write_close() nutzen – nicht aber RUN. Denn RUN muss fortwährend Statusinformationen in den Sessionspeicher schreiben – und die erste Session-Freigabe über die genannten Kommandos würde nachfolgende Schreibaktionen in die Session unmöglich machen.

Lösung für Falle 1: Nutze eine Datenbank zum Schreiben von Statusinformationen lang laufender Jobs

Wir haben uns dann sinnvollerweise entschlossen, als Ort für den Status-Message-Buffer von RUN eine spezielle Tabelle in einer MariaDB/MySQL-Datenbank zu nutzen, die für die Simulationsrechnungen sowieso erforderlich ist. Eine Alternative wäre ein File als Message-Buffer gewesen. Wir haben Files aber verworfen, weil sie aus unserer Sicht wieder andere Nachteile haben und uns der Zugriff auf einen Datenbank-Tabelle letztlich einfacher, flexibler und ausbaufähiger erschien. Zumal in unserem auf Datenbank-Nutzung ausgelegten Framework.

Die Nutzung einer Datenbank hat über die Lösung des oben besprochenen Session-Locks hinaus noch andere Vorteile:

  • Es zwingt zur sauberen Strukturierung der Status-Information. Das vereinfacht zudem auch den XML- oder JSON-Transfer der Daten im Zuge der periodischen Ajax-Prozess.
  • Erweiterungen sind zügig möglich. Die Feldstruktur ist über Schema-Verfahren insgesamt schnell geändert.
  • Es ist einfach, nur die seit dem letzten CHECKER-Zugriff neu eingetragenen Daten zu selektieren.
  • Liegt die Datenbank auf ein- und demselben LAMP-Server , ist sowohl der schreibende Zugriff durch RUN als auch der lesende Zugriff durch die CHECKER wegen der Kürze der Tabelle extrem performant. Man kann das Intervall für die zu startenden Ajax-CHECKER auf diese Performance hin anpassen.
  • Man kann die Timestamps der Datenbank nutzen, um genaue Zeitinformationen über das Ende der Zwischenschritte zu erhalten.
  • Die Statusinformation kann über die Laufzeit und Garbage Collection Time hinaus aufbewahrt und in weiteren Tabellen historisiert werden.
  • Für eine Historisierung von RUNs kann man in der Bank noch andere nützliche Daten hinterlegen.

Je nach Netz-Anbindung an den Server und dessen Leistungsfähigkeit können wir durch Nutzung der Datenbank als Message-Buffer von RUNs nun mit CHECKER-Jobs im Abstand von 250 bis 500 msec arbeiten, ohne Server und Client übermäßig zu belasten. Damit eröffnen sich während der Laufzeit der Simulationen alle Möglichkeiten einer kontinuierlichen, sehr fein-granularen Statusinformation im gleichen CLIENT-Window, von dem aus der RUN-Job ursprünglich gestartet wurde. Eine Darstellung von fachlich-technischem Output in einem zweiten Browserfenster während der Laufzeit bleibt davon unberührt und ist unbenommen möglich.

In einem kommenden zweiten
Fallen beim Statuscheck lang laufender PHP-Jobs mit Ajax – II
befassen wir uns prophylaktisch mit potentiellen “this”-Fallen auf der Javascript/jQuery-Seite der Ajax-Prozesse. In späteren Beiträgen werden wir dann die gewonnen Erkenntnisse zu einem Verfahren
zusammensetzen, das es erlaubt den “RUN” wie die “CHECKER”-Jobs systematisch mit Ajax zu behandeln. .

Links

Nutzung von commit_session oder write_close-session
http://konrness.com/php5/how-to-prevent-blocking-php-requests/
http://blog.preinheimer.com/index.php?/archives/416-PHP-and-Async-requests-with-file-based-sessions.html
http://www.held.org.il/blog/2008/02/php-session-locks/

Sicherheit
http://php.net/manual/de/session.security.php
http://phpsec.org/projects/guide/4.html

phpMyAdmin – Versionscheck – Firewalls

Gerade arbeite ich an einem Projekt, in dem die Anzahl der Tabellen auf einem MySQL-Server mit mehreren Datenbanken rasant steigt. Zur Verwaltung nutze ich u.a. phpMyAdmin in der Version 4.0.1. Nun haben wir kürzlich die ersten Testsysteme auf einen größeren Server mit einer restriktiven Firewall verlagert. Danach fiel mir auf, dass phpMyAdmin unmittelbar nach dem Login für ca. 1 Minute nicht reagiert, wenn man sich die Tabellen der angelegten Datenbanken auflisten lassen will. Irgendwann kommt dann jedoch die erwartet Übersicht über die Tabellen. Und danach funktioniert auch alles wieder so rasch wie erwartet.

Diese initale Verlangsamung von phpMyAdmin – besser dieses initiale Hängenbleiben – machte mich total nervös. Zumal dieses Verhalten für mich neu war, und ich es auf anderen Systemen bislang nicht beobachtet hatte. Wartezeiten von 1 Minute sind während hektischer Entwicklungsarbeiten nicht tolerierbar. Das beschriebene Verhalten tritt nämlich immer wieder auf, wenn die maximale Inaktivitätszeit, die in phpMyAdmin oder in den php-Einstellungen des Servers gesetzt ist, abläuft und man sich erneut einloggen muss. Und dann will man natürlich keine zusätzliche Verzögerung bei der Abfrage nach den vorhandenen Tabellen im Minutenbereich erleben.

Also hieß es: Logs einsehen. Die Firewall zeigte denn auch tatsächlich, dass der Server, auf dem phpMyAdmin installiert war, versucht, eine HTTP-Verbindung zu der Adresse 216.34.181.97 aufzubauen. Solche aktiven HTTP- Verbindungen in die weite Welt werden von unserem Server aus aber nicht zugelassen.

Ein Nachforschen mit “whois” zeigt, dass diese Adresse möglicherweise unter der Hoheit von SourceForge steht. Oder aber etwas mit phpmyadmin.net zu tun hat. Ok – für einen Test mal die Firewall-Regeln abändern und die Verbindung vorübergehend zulassen. Und siehe da:

Keine initiale Verlangsamung mehr, sondern ein gewohnt spritzig reagierendes phpMyAdmin. Reproduzierbar! Dass phpMyAdmin nach dem Startup so langsam reagierte, rührte also daher, dass das Programm die genannte HTTP-Verbindung erwartete, aber nicht bekam – und den Verbindungsversuch in einer solchen Situation vermutlich mehrfach startete, bis es schließlich aufgab.

Es ergeben sich mehrere Fragen:

Frage 1: Wozu dient dieser Verbindungsversuch von phpMyAdmin ?
Vermutlich(!) zur Abfrage von Update-Informationen (neue Versionen, …). Siehe hierzu den Informationsbereich auf der ersten Seite nach dem Öffnen von phpMyAdmin. Dort wird dargestellt, welche Version man gerade im Einsatz und ob es eine neuere gibt. Aber wer weiß …. in diesen Zeiten …. Ich habe es jedenfalls nicht persönlich im Code überprüft.

Frage 2: Gibt es einen Parameter, um das abzustellen ? Oder muss man mit einem initial sehr langsamen phpMyAdmin hinter einer Firewall leben ?
Nein, muss man nicht – und ja, es gibt einen Parameter. Siehe :
http://wiki.phpmyadmin.net/pma/Config#VersionCheck

In meiner Situation half es demzufolge, in der Datei “config.inc.php” folgende Einstellung einzufügen:

$cfg[‘VersionCheck’] = false;

Das fand ich dann doch sehr beruhigend. Und es löste mein Problem – die http-Anfrage findet danach nicht mehr statt. Und phpMyAdmin läuft dann trotz restriktiver Firewall-Einstellungen performant.

Ich habe das Thema auch im phpMyAdmin-Bereich unter “Stackoverflow” angesprochen.
http://stackoverflow.com/questions/18766123/required-but-not-granted-http-access-to-216-34-181-97-slows-phpmyadmin-down
Wurde wirklich sehr schnell beantwortet. Das Verhalten wurde von einem interessierten Zeitgenossen bestätigt. Dort kam dann noch der Tipp, dass man die Abfrage auch über einen Proxy abarbeiten kann. Siehe
https:
//phpmyadmin.readthedocs.org/en/latest/config.html#cfg_VersionCheckProxyUrl

Danke hierfür an M. Delisle.

Abschließend bleiben folgende Fragen an die phpMyAdmin-Entwickler offen:
Könnte man das Thema mit dem Versionscheck nicht auch anders lösen? Wieso muss diese Abfrage überhaupt automatisiert ablaufen? Und wenn schon – warum nicht dezent und asynchron im Hintergrund (Ajax) mit Einstellungen, die den User nicht blockieren ?

Ich bin daher schon gespannt auf die nächste Version dieses wichtigen und nützlichen Tools.

Opensuse 12.3, mysql/mariadb, logrotate-Fehler

Nach der Umstellung auf die Maria DB unter Opensuse 12.3 bin ich mal wieder über einen mysql-logrotate-Fehler gestolpert.

2013-05-18T10:45:03.378467+02:00 myserv logrotate: ALERT exited abnormally with [1]
2013-05-18T10:45:03.379471+02:00 myserv logrotate: #007/usr/bin/mysqladmin: flush failed; error: ‘Unknown error’
2013-05-18T10:45:03.379739+02:00 myserv logrotate: /logrotate.d/mysql failed, probably because
2013-05-18T10:45:03.379926+02:00 myserv logrotate: the root acount is protected by password.
2013-05-18T10:45:03.380190+02:00 myserv logrotate: See comments in /logrotate.d/mysql on how to fix this
2013-05-18T10:45:03.380359+02:00 myserv logrotate: error: error running non-shared postrotate script for /var/log/mysql/mysqld.log of ‘/var/log/mysql/mysqld.log ‘

Die Ursache dieses Fehlers ist, dass der mysql-root-Account – also der Administrator Account für die mysql/mariadb-Datenbank – natürlich mit einem Passwort geschützt ist. Wo muss man das eintragen ?

Der Hinweis in der Fehlermeldung ist ein wenig irreführend. Natürlich gibt es kein “/logrotate.d”-Verzeichnis. Aber sehr wohl ein Verzeichnis “/etc/logrotate.d”. Dort findet man auch die Steueranweisungen für mysql, und zwar in der Datei:

/etc/logrotate.d/mysql

In dieser Datei findet man folgenden Hinweis:

# If the root user has a password you have to create a
# /root/.my.cnf configuration file with the following
# content:
#
# [mysqladmin]
password = %Tromsoe!
user= root
#
# where “” is the password.
#
# ATTENTION: This /root/.my.cnf should be readable ONLY
# for root !

Das machte die Sache schon klarer, löste sie aber nicht, denn das .my.cnf – File war bei mir bereits korrekt vorhanden.
Also lag der Verdacht nahe, dass es noch ein weiteres rechte-Problem beim Zugriff auf das Log-Verzeichnis für MySQL selbst geben könnte.

Folgender Novell-Bugzilla-Beitrag und die darin beschriebenen Schritte lösten dann mein Problem

https://bugzilla.novell.com/show_bug.cgi?id=763150#c7

This bug seems to occur still on openSuSe 12.3. Simply
chown mysql /var/log/mysql
chmod 750 /var/log/mysql
will fix it.

Danke an den Autor Thomas Wagner !

Kurzreview Eclipse 4.3 Kepler mit PDT und Aptana

Vor einiger Weile hatte ich mich wegen der miserablen Performance enttäuscht von Eclipse 4.2 Juno mit PDT abgewandt. Besonders bei Benutzung der neuen GTK-Oberfläche tauchten immer wieder lange andauernde 100%-Peaks in der CPU-Belastung von 1 bis 2 CPU-Cores auf. Auf meinem schwachbrüstigen Laptop eine Katastrophe – aber auch auf einem gut ausgestatten Desktop-Rechner eine echte Belastung.

Im besonderen galt dies beim Hin- und Herziehen von Tabs zwischen zwei getrennten parallelen, vertikalen Editor-Bereichen der GUI von Juno. Das Öffnen des Outline-Bereiches machte das System nochmal träger. Die parallel Sicht auf mehrere geöffnete Files sowie den Outline-Bereich benötige ich beim Arbeiten mit vielen Klassenbibliotheken aber immer wieder.

Es half keine Herumdoktern an den Speichereinstellungen für die JVM. Genausowenig half eine Umstellung auf die klassische Eclipse GUI. Daneben gab es auch immer wieder seltsame Probleme mit einer parallelen Installation von Aptana und PDT 3.1/3.2. Die Content Assist Vorschläge wurden entweder gar nicht oder nicht immer vollständig angezeigt. Die Schwierigkeiten waren sowohl bei Einsatz von Suns JVM für Java 7 als auch von OpenJDK 1.7 gegeben. Alles unter Opensuse 12.2 und 12.3 (64 Bit).

Für meine PHP-Entwicklungsarbeiten griff ich aus diesen Gründen bis gestern immer noch auf Eclipse 3.7 “Indigo” zurück.

Nun ist Eclipse in der Version 4.3 unter dem Namen “Kepler” erschienen. Daher habe ich gestern erneut einen Anlauf mit dieser aktuellen Eclipse-Version und dem zugehörigen PDT 3.2 plus Aptana Studio 3 unternommen. Und diesmal wurde ich nicht entäuscht:

Alles funktioniert wie es soll und das wirklich performant. Allerdings musste ich meine unter Indigo aufgebauten Workspaces unter Rückgriff auf vorhandene SVN-Repositories komplett neu aufbauen. Erst danach lief alle fehlerfrei.

eclipse_kepler_1_600

An den Standard Speichereinstellungen habe ich nichts verändert. Die “eclipse.ini” sieht daher wie folgt aus:

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
–launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.200.v20130521-0416
-product
org.eclipse.epp.package.standard.product
–launcher.defaultAction
openFile
-showsplash
org.eclipse.platform
–launcher.XXMaxPermSize
256m
–launcher.defaultAction
openFile
–launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-XX:MaxPermSize=256m
-Xms40m
-Xmx512m

Es gab und gibt nach bislang 12 Stunden Arbeit keinerlei Hänger und keine Peaks in der CPU zu bemängeln! Das Arbeiten mit mehreren parallel angezeigten Editor- und GUI-Bereichen läuft sehr flüssig. Das Verschieben von Tabs für geöffnete Dateien zwischen zwei Darstellungsbereichen führt zwar zu einer kurzfristigen Belastung mehrerer CPU-Kerne – aber eben wirklich nur sehr kurzzeitig und das ist nicht als Bremse für das Arbeiten wahrnehmbar. Auch die Build-Operation für Projekte laufen mit angemessener Geschwindigkeit.

Aptana lässt sich parallel zu PDT einsetzen. Man kann zwischen den verschiedenen “Natures” entsprechend “facettierter” Projekte nach Lust und Laune hin- und herschalten. Die Content-Assists-Hinweise kommen entsprechend. Ich nutze z.T. den Aptana-Editor, um HTML-Code in TPL-Files für die Template-Engines Pear-ITX oder Smarty zu bearbeiten. Ich schätze dabei die browser-bezogenen Content Assist Hinweise. Aber auch der Wechsel zum normalen WST-HTML-Editor mit dessen Content-Assists-Fähigkeiten für HTML- und CSS-Vorschlägen klappt einwandfrei.

Aptanas PHP-Unterstützung benutze ich in der Regel nicht und
habe ich daher nicht wirklich getestet. Ein kurzes Umschalten auf die Aptana Editoren und Aptanas Content Assist für PHP zeigte mir aber keine unerwarteten Probleme.

Die SVN-Anbindung über Subversive und die Polarion-Konnektoren lief wie erwartet. Ein Gleiches gilt für MyLyn

Kurzum:
Für PHP-Projekte stellt Eclipse 4.3 “Kepler” endlich eine ernsthafte, weil funktionierende und performante “Eclipse 4.x”-Alternative zu Indigo dar. Ich kann den Umstieg wirklich empfehlen.

Ein kleiner Wermutstropfen
Schade irgendwie, dass es der HTML-“Web Page Editor” bisher nicht in die “WTP 3.5” -Repositories von Kepler geschafft zu haben scheint. Aber eine Installation aus den WTP 3.3.2 Ressourcen scheint keine größere Probleme zu machen.

phpMyAdmin Vers. 4.x und 5.x – Configuration Storage, Control User pma und zugehörige Tabellen

PhpMyAdmin hat sich ja seit der Version 4 dahingehend geändert, dass man seine Konfigurationseinstellungen für die GUI partiell in dafür bereitgestellten Datenbanktabellen hinterlegen muss. Hat man diese Tabellen nicht angelegt, weisen einen nach der phpMyAdmin-Grundinstallation Hinweise am unteren Ende der GUI auf bestehende Konfigurationsdefizite hin.

Ich vergesse nach der erfolgreich abgeschlossenen Einrichtung von phpMyAdmin auf einem Kundenserver leider selbst immer wieder, was genau man für die Einrichtung der “Konfigurationsdatenbank” und des zugehörigen Users im Rahmen der phpMyAdmin-Installation tun muss. Der Vorgang ist leider etwas umständlich. Wer immer sich diesen Installationsweg ausgedacht hat, sollte mal einen Kurs in Usability belegen.

Ich kritisiere dabei gar nicht die technische Umsetzung der Speicherung der Konfigurationseinstellungen für verschiedene User in Tabellen. Es geht mehr darum, welchen Aufwand man bei der Installation betreiben muss, um überhaupt ein konfigurierbares phpMyAdmin zu bekommen, das die vorgenommenen GUI-Einstellungen beim Verlassen des Programms nicht vergisst. Das ist wirklich keine Reklame für Opensource …. ganz im Gegensatz zu den schnörkellosen, einfach zu installierenden und gut zu bedienenden 3er-Versionen von phpMyAdmin.

Zudem ist die Basiseinstellung des 4er-GUI-Layouts in mancherlei Hinsicht einfach grässlich und im Vergleich zu den 3er-Versionen des Programms wenig ergonomisch. Daher schreibe ich die notwendigen Schritte hier mal auf.

Addendum 18.07.2022: Obwohl dieser Post ursprünglich für die Version 4.3 geschrieben wurde, gilt der Inhalt analog für aktueller Versionen 5.x.

Schritt 1: Einrichten der Konfigurationstabellen

Im Installationsverzeichnis von phpMyAdmin auf dem Web-Server – in meinem Fall

/srv/www/htdocs/phpmyad/

befindet sich ein Subverzeichnis “examples” mit folgender Datei:

examples/create_tables.sql

Addendum 18.07.2022: In einer aktuellen Version 5.2 von phpMyAdmin befindet sich die Datei im Verzeichnis “sql”.

Die Datei beinhaltet die notwendigen SQL-Statements zur Generierung der erforderlichen Tabellen. Zur Durchführung der Statements importiert man die Datei einfach mit phpMyAdmin:

phpmyad_1_600

Danach findet man folgende Tabellen einer neuen Datenbank “phpmyadmin” vor:

phpmyad_2

Addendum 18.07.2022: In aktuelleren Versionen von phpMyAdmin hat sich die Anzahl der Tabellen der Datenbank “phpmyadmin” erhöht:

Achtung:

Verwaltet man mit einer phpMyAdmin-Installation mehrere MySQL-Datenbank-Instanzen auf unterschiedlichen Datenbankservern, so muss man diesen Import-Schritt auf jeder Datenbank-Server–Instanz vornehmen!

Schritt 2: Anlegen eines Control-Users “pma”

Nun legt man mit Hilfe von phMyAdmin einen Datenbank-User “pma” an und erteilt ihm alle Rechte an der eben angelegten Datenbank “phpmyadmin”. Am einfachsten geht das über den Reiter “Rechte” bei geöffneter Datenbank “phpmyadmin”:

phpmyad_4_600

phpmyad_3_600

Dieser User mit den Rechten am sog. “Configuration Storage”, nämlich der Datenbank phpmyadmin, wird auch als “Control User” bezeichnet. Wir merken uns das vergebene Password. Auch diesen Schritt muss man natürlich für jede der mit der aktuellen phpMyAdmin-Installation ggf. verwalteten Datenbank-Server-Instanzen vornehmen.

Hinweis: Greift man nicht über “localhost” sondern einen Domainnamen auf phpMaAdmin zu, so muss der User pma auch für die Domaine angelegt werden, der der aktuelle Host zugeordnet ist. Also etwa

Create USER 'pma'@'mytux.mylocaldomain.de' IDENIFIED BY 'DEIN_PMA_PASSWORD';

Auch dieser User muss die nötigen Rechte an der Bank “phpmyadmin” erhalten.

Addendum 18.07.2022: Die Einschränkungen der Rechte des Users ‘pma’ durch die ersten Statements sind relativ restriktiv. Eine andere Wahl der Rechtezuteilung findet ihr hier:
www.workshop.ch/ openmind/ 2013/12/24/ phpmyadmin-zusatzfunktionen-aktivieren-mit-dem-configuration-storage/

Schritt 3: Ergänzung der Datei “config.inc.php”

Der nächste Schritt besteht darin, die Datei “confic.inc.php” im phpMyAdmin-Installationsvezeichnis des Webservers um Informationen zum User “pma” und zu den eben angelegten Konfigurationstabellen zu ergänzen:

$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';<br>
$cfg['Servers'][$i]['controluser'] = 'pma';<br>
$cfg['Servers'][$i]['controlpass'] = 'DEIN_PMA_PASSWORD';<br>
 <br>
$cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';<br>
$cfg['Servers'][$i]['relation'] = 'pma__relation';<br>
$cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';<br>
$cfg['Servers'][$i]['table_info'] = 'pma__table_info';<br>
$cfg['Servers'][$i]['column_info'] = 'pma__column_info';<br>
$cfg['Servers'][$i]['history'] = 'pma__history';<br>
$cfg['Servers'][$i]['recent'] = 'pma__recent';<br>
$cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';<br>
$cfg['Servers'][$i]['tracking'] = 'pma__tracking';<br>
$cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';<br>
$cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';<br>
$cfg['Servers'][$i]['designer_coords'] = 'pma__designer_coords';<br>

Addendum 18.07.2022: In aktuelleren Versionen 5.x sieht das so aus:

/**
 * phpMyAdmin configuration storage settings.
 */

/* User used to manipulate with storage */
$cfg['Servers'][$i]['controluser'] = 'pma';
$cfg['Servers'][$i]['controlpass'] = 'YOUR_PMA_PASSWORD';

/* Storage database and tables */
$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
$cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
$cfg['Servers'][$i]['relation'] = 'pma__relation';
$cfg['Servers'][$i]['table_info'] = 'pma__table_info';
$cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
$cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
$cfg['Servers'][$i]['column_info'] = 'pma__column_info';
$cfg['Servers'][$i]['history'] = 'pma__history';
$cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
$cfg['Servers'][$i]['tracking'] = 'pma__tracking';
$cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
$cfg['Servers'][$i]['recent'] = 'pma__recent';
$cfg['Servers'][$i]['favorite'] = 'pma__favorite';
$cfg['Servers'][$i]['users'] = 'pma__users';
$cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
$cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
$cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
$cfg['Servers'][$i]['central_columns'] = 'pma__central_columns';
$cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings';
$cfg['Servers'][$i]['export_templates'] = 'pma__export_templates';

Man beachte dabei, dass es zwischen dem Prefix “pma” und dem Tabellennamen 2 (!) Unterstriche gibt.

Im diskutierten Beispiel sind wir davon ausgegangen, dass wir die Serverinstanz mit dem Index “$i” mit den Informationen versorgt haben.

Natürlich gilt auch hier, dass man diese Einstellungen separat pro MySQL-Datenbankserver-Instanz, die mit phpMyAdmin verwaltet werden soll, anlegen muss. Sind mehrere Instanzen gegeben, ist es also wichtig, im Script “config.inc.php” den Index $i explizit hochzuzählen bzw. auf den richtigen Wert für die jeweilige Instanz zu setzen.

Man verlässt dann phpMyAdmin und loggt sich erneut in die GUI ein. Es sollten nun keine Hinweise mehr zu Konfigurationsdefiziten erscheinen.

Schritt 4: Vornehmen von Änderungen

Wir sind nun in der Lage, die gewünschten Änderungen am GUI-Layout pro Serverinstanz vorzunehmen und dauerhaft in den angelegten Tabellen zu hinterlegen. Als Beispiel ändern wir die parallele Anzeige von Icons und Menüpunkt-Texten auf den Seiten zur Bearbeitung der Tabellen so ab, dass nur noch die Icons angezeigt werden:

phpmyad_5_600

Nicht vergessen, den Button “Speichern” zu drücken. Ganz so praktisch und informativ wie die GUIs der 3er-Version wird phpMyAdmin in der Version wohl erst wieder nach einiger Zeit werden.

Trotzdem viel Spaß beim künftigen Herumprobieren mit eigenen Einstellungen in den aktuellen Versionen von phpMyAdmin.

Adendum 18.07.2022: Bevor ich es vergesse: Der schlimmste lebende Faschist und Kriegsverbrecher ist der Putler!