Bash: Ini Dateien Parsen/ Lesen
Bei einigen Servern habe ich einen Cronjob, der ruft ein Shellskript auf, welches den IST Zustand einiger Dienste auflistet. Also, auf einem Server, welche Mysql- und Postgres-Datenbankschemata es gibt, auf dem nächsten welche Apache VHosts existieren und auf dem Fileserver welche Samba-Shares usw.
Schlussendlich landet es auf einem Wiki (Dokuwiki in diesem Fall - hier sind die Seiten Txt-Dateien im Filesystem - das macht die Sache sehr einfach).
Beim Samba Server war es bis anhin recht unschön, weil umständlich gecodet. Nun habe ich 3 kleine Funktionen hinzugefügt, mit denen ich (endlich :-)) eine INI Datei parsen kann.
Die Funktionen kann man in eine Datei mit Leserechten (ohne Execute-Recht) auslagern, die man im Skript sourct (per source oder Punkt-Kommando).
- _getInisections [Name der Ini-Datei]
listet alle Sektionstitel auf - _getInisectiondata [Name der Ini-Datei] [Name der Sektion]
listet die angegebene Sektion auf. Mit dieser Ausgabe sieht man eine Sektion alleinstehend - und kann sich die Variablen herausziehen … aber wenn man die Variablen kennt, gibt es noch die nächste Funktion - _getIniValue [Name der Ini-Datei] [Name der Sektion] [Name der Variable]
gibt den Wert einer Variable aus der angegebenen Sektion zurück
In der Samba-Konfiguration (/etc/samba/smb.conf) sind die Variablen und Werte nicht zwingend ab Zeilenanfang - daher sind im Regex Leerzeichen und Tabs hinzugefügt.
# Helper for ini files: get all sections # param1 - name of the ini file function _getInisections(){ local myfile=$1 grep "^\[" $myfile | sed 's,^\[,,' | sed 's,\],,' } # Helper for ini files: get all content inside a section # param1 - name of the ini file # param2 - name of the section in ini file function _getInisectiondata(){ local myfile=$1 local mysection=$2 mysection=$( sed "s#/#\/#g" <<< "$mysection" ) sed -e "0,/^\[${mysection}\]/ d" -e '/^\[/,$ d' $myfile | grep -v "^[#;]" } # Helper for ini files: get a value of a variable in a given section # param1 - name of the ini file # param2 - name of the section in ini file # param3 - name of the variable to read function _getIniValue(){ local myfile=$1 local mysection=$2 local myvarname=$3 _getInisectiondata ${myfile} ${mysection} | grep "[^\a][\ \t]*${myvarname}[\ \t]*=.*" | cut -f 2 -d "=" | sed -e 's,^\ *,,' }
Und als Anwendungsbeispiel: ein Snippet mit einem Loop über die Samba-Konfiguration. Ausgegeben wird eine Tabelle mit Name des Shares, Beschreibung (Wert “comment”) und Pfad des Shares (Wert “path”):
smbconf=/etc/samba/smb.conf # Ausgabe des Tabellen-Header in Wiki-Syntax echo "^Share^Kommentar^Pfad^" # Loop ueber alle Sektionen for mysection in `_getInisections $smbconf | grep -v global` do # Ini-Werte aus der Sektion lesen myComment=`_getIniValue ${smbconf} ${mysection} "comment"` mypath=`_getIniValue ${smbconf} ${mysection} "path"` # Ausgabe der Tabellen-Zeile - Pipes sind Spaltentrenner echo "|${mysection}|${myComment}|${mypath}|" done
UPDATES:
- 15.05.2019: Korrektur der fehlenden Backslahes (die wirft das Blogtool immer raus, wenn man es nicht als Html-Entity schreibt) plus verbessertes Handling mit laschen Regex und Leerzeichen. Danke an Frank!
- 04.03.2021: Sektionen mit eckigen Klammern aus Kommentaren ignorieren. Zusätzlich werden Kommentare mit Semikolon am Anfang ebenfalls ignoriert. Ein local macht eine Variable nur innerhalb der Funktion bekannt.
- 09.02.2022 Update von _getIniValue: [^\a] statt ^
- 19.03.2023: Ein Follower Projekt: Ich habe aus der class like Bash Funktionen erstellt. Mit Validator und anständiger Dokumentation https://www.axel-hah … docs/bash_iniparser/
Html5 Audio Events beobachten
Es entsteht gerade eine weitere Demo Seite zu Html 5 Audio:
Nach Eingabe einer beliebigen Audio URL wird diese als Source eines Audio Tags verwendet.
An dieses Audio Tag werden alle dokumentierten Events angeklebt und man kann bei den Interna eines Audio Tags zuschauen und wann welche Events abgesetzt werden.
Sie erscheinen zum einen rechts als Log (mit Zeitangabe in Millisekunden seit Laden der Seite). Damit kann man z.B. messen, wie lange ein Audio laden muss, bis es abgespielt werden kann (readyState=4).
Unten ist die Liste aller Events, die bei Absetzen hervorgehoben werden … und nach und nach schwächer verfärbt sind.
weiterführende Links:
Datenbank-Optimierung - mein Highlight der Woche
Bei meiner Arbeit an der Uni Bern war ein Grossteil der Zeit in die Optimierung von Datenbank-Zugriffen geflossen. Das betraf hauptsächlich ein System für ein Portal für Dozierende und Studierende mit Stundenplänen, Kurseinschreibungen, Feeds zu etlichen Themen und nach Studienjahr getrennt, Kalendersynchronisation von personalisierten Kalendern uvm. Jenes Portal ist uralt und wurde einmal mit PHP4 entwickelt und sollte abgelöst werden. Wurde es aber nicht, sondern es wurde vor vielen Jahren mühsam unter PHP5 lauffähig gemacht, aber der Code blieb noch immer zumeist prozedural, mit vielen Includes und gespickt mit allen erdenklichen Highlights an Programmiersünden, sei es Wartbarkeit, Caching/ Performance, SQL-Injection oder Verständnis von Algorithmen und Gestaltung von Datenbankabfragen. Seit dem ersten Ablösetermin sind nun 8..9 Jahre vergangen … aber Herbst 2019 wird es endlich(!!) abgelöst. Heisst aber: bis dahin muss es weiter am Leben erhalten werden.
Es wurden 5 Applikationsteile, die “am meisten weh tun” ausgemacht und jene optimiert. Letzten Dienstag wurde es eingespielt. Doch, es hat sich gelohnt - da ist so ein markanter Abfall:
Man könnte meinen: da ist was kaputt. Aber nein: es funktioniert genau gleich!!
Ich hoffe, ich kann euch mit diesem Praxis-Beispiel motivieren: macht einmal eine Performance-Analyse und schaut genauer auf die Top 3!
Texte anhand einer Quelle einfärben
Meine Nachrichten-Feeds benennen die Nachrichten-Quelle und färben sie ein. Es entsteht eine “bunt” eingefärbte Quelle, bevor deren Meldungs-Überschrift genannt wird.
Und wie funktioniert es, dass “Tagesschau”, “Spiegel” oder “Heise” jeweils spezifisch eingefärbt sind?
Naja, der Text - also String - der Quelle wird mit einer MD5 Funktion gehasht. Dann erhält man so einen Hexcode aus einem vorgegebenen String.
Wenn man sich vom Beginn des Hex-Strings jeweils die aufeinanderfolgenden 2..3 Stellen herausgreift, kann man diese dem Anteil für rot, grün und blau zuordnen.
Damit der Hintergrund und Vordergrund relativ zueinander passen, definiere ich für beide einen eine Range von..bis. Der ermittelte Wert aus dem Hash wird relativ zum von-bis-Range für Vordergrund und Hintergrund eingeordnet.
Und das ist der zugehörige PHP-Code:
/** * return html code for a span with background color based on a checksum of the given text * @param string $sText text that is used for checksum; if false it returns a gray box * @param string $sContent optional: text to show * @return string */ function _getChecksumSpan($sText, $sContent = '') { if ($sText) { // color ranges in decimal values for RGB from ... to $iFgStart = 60; $iFgEnd = 160; $iBgStart = 180; $iBgEnd = 240; // divider: 3 digits of md5 will be extracted $iFgDivider = 16 * 16 * 16 / ($iFgEnd - $iFgStart); $iBgDivider = 16 * 16 * 16 / ($iBgEnd - $iBgStart); $sHash = md5($sText); $sColor = '' . 'color: rgba(' . ($iFgStart + round(hexdec(substr($sHash, 0, 3)) / $iFgDivider)) . ',' . ($iFgStart + round(hexdec(substr($sHash, 3, 3)) / $iFgDivider)) . ',' . ($iFgStart + round(hexdec(substr($sHash, 6, 3)) / $iFgDivider)) . ',' . '1' . ');' . 'background: rgba(' . ($iBgStart + round(hexdec(substr($sHash, 0, 3)) / $iBgDivider)) . ',' . ($iBgStart + round(hexdec(substr($sHash, 3, 3)) / $iBgDivider)) . ',' . ($iBgStart + round(hexdec(substr($sHash, 6, 3)) / $iBgDivider)) . ',' . '1' . ');' ; } else { $sColor = "color: #888; background: #ccc;"; } return '<span style="' . $sColor . '; border-left: 0.8em solid; padding: 0.1em 0.4em 0.1em 0.3em ;">' . ($sContent ? $sContent : ' ') . '</span>'; }
weiterführende Links:
- meine RSS-Seite: Nachrichten
PHP-Funktion: Passwort-Check bei haveibeenpwned.com
Anbei eine Funktion, die mit der API von haveibeenpwned.com ein Passwort prüft, ob dieses als gehackt gilt.
Wenn die Funktion true zurückliefert, wurde das Passwort gefunden (sprich: wurde gehackt). Diese Funktion kann man z.B. in einer Applikation einbauen, wenn man Benutzer ihr Passwort setzen lässt. Wenn die Funktion true liefert, dann wäre die Benutzereingabe als unsicher zurückzuweisen.
/** * check password in an online database; it returns true if the password * was found in the database * * @see https://haveibeenpwned.com/API/v2 * @param string $sPassword password to check * @param boolean $bShowDebug show debug infos or not (default: false) * @return boolean */ function haveibeenpwned($sPassword, $bShowDebug=false){ // --- make the request $sCheckPwUrl='https://haveibeenpwned.com/api/pwnedpassword/'.sha1($sPassword).'?originalPasswordIsAHash=true'; $context = stream_context_create($opts); $sPwReturn = file_get_contents( $sCheckPwUrl, false, stream_context_create( array( "http" => array( "method" => "GET", "header" => "User-Agent: php-check-4-my-password\r\nAccept: application/vnd.haveibeenpwned.v2+json\r\n" ) ) ) ); $aRespHeader=$http_response_header; echo $bShowDebug ? '<pre>'.$sCheckPwUrl.'<br>' . 'Header: '.print_r($aRespHeader, 1).'<br>' . '$sPwReturn = '.$sPwReturn.'<br>' .'</pre>' : '' ; // --- check result $bFound=array_search('HTTP/1.1 200 OK', $aRespHeader)!==false; echo $bShowDebug ? ( $bFound ? 'ERROR: The password was found in the database :-/' : 'OK: seems not to been hacked yet :-)' ) : ''; return $bFound; }
weiterführende Links:
PHP-Klasse cdnorlocal
Eigentlich begann es als Abfallprodukt. Ich brauchte da in einer Web-Applikation eine Klasse … und habe halt jene kleine Klasse geschrieben: wenn ein Verzeichnis für eine Bibliothek im Vendor-Verzeichnis lokal existiert, dann wirf eine lokale URL zurück. Wenn nicht, dann eine zu einem CDN Hoster. Sowas packt man an sich als Funktion in einen 3 Zeiler.
Damit kann ich abstrahieren, wo eine benötigte Bibliothek tatsächlich liegt. Mein Produkt-Download wird klein, weil ich Bibliotheken nur extern verlinke, statt mit in den Download zu packen. Soll das Produkt auf einem System ohne Internet-Anbindung verwendet werden, kann man die Bibliotheken aber optional lokal legen und auf einen Internet-Zugang verzichten.
Tja und dann kam mir der Sinn, noch eine Admin dafür zu schreiben: ich will live in einer API nach Bibliotheken browsen, Details einsehen, Versionen wechseln, Bibliotheken zu “mir” herunterladen.
Ach so Versionen … da gibt es bei gefragten Produkten in relativ kurzen Intervallen neue Releases. Sei es jQuery, Font-Awesome, Plugins … eigenlich habe ich selbst gar keine Kontrolle über all jene Updates … und wenn was neu ist, dies in meinen Applikationen zu aktualisieren.
Und wenn man Versionen lokal hat und sie schon mal lokal erfragen als auch remote die aktuellste ermitteln kann … machen wir noch einen Versions-Checker für sämtliche lokal gemachten Bibliotheken auf einmal dazu. Es kam eins zum anderen. Ich glaube, ich habe mal ein Grundgerüst. Das wird später einmal eine gute Hilfe, den Überblick über alle meine Bibliotheken und deren Versionen zu behalten.
Browsing (Rendering der API Such-Abfrage bei CDNJS):
Details (Rendering der API Abfrage einer Library bei CDNJS):
Versionscheck: lokal hinterlegte Versionen von Bibliotheken werden mit der online aktuellsten Version verglichen
weiterführende Links:
PHP 7 und Concrete 5 Upgrade
Heute wurden live eingespielt: Updates 2er Domains, um zu PHP 7 kompatibel zu werden
- Concrete 5 wurde aktualisiert: von Version 5.6.x sind alle Inhalte migriert auf v8.1
- Der Source der Blogs wurde gepatcht
- Meine Inhaltsseiten von Putzi4Win wurden durch statische Seiten ersetzt
- In der Suche (ahcrawler) wurde Meedoo aktualisiert
- Auf den Liveseiten wurde PHP5.5 auf Version 7 umgestellt
UPDATE
Und es kamen noch Updates von
- jQuery
- Bootstrap
- Datatables
hinzu
Das war vielleicht etwas viel auf einmal.
Das Meiste läuft, aber die ersten Tage gibt es sicher noch ein paar Holperer. Seht es mir nach :-)
weiterführende Links:
- Concrete 5 concrete5.org (en)
- PHP php.net (en)
- Meedoo - PHP database framework medoo.in (en)
- jQuery Javascript Framework jquery.com (en)
- Bootstrap Framework getbootstrap.com (en)
- Datatables - jQuery Plugin für filterbare und sortierbare Tabellen datatables.net (en)
Innovation Award Oktober 2016 für Klasse ahpwcheck
Ja sowas: mit 37.5 % der Stimmen abgeräumt :-)
Die Javascript-Klasse zählt in einem (Passwort-) Input-Feld Typen von Zeichen und ermittelt Grad der Erfüllung der Anforderungen, Gross- und Kleinschreibung, Ziffern, Sonderzeichen und Anzahl. Plus Mehrsprachigkeit und Callbackfunktion zum Abrunden.
Update:
Auf einen der gesponsorten Preise habe ich verzichtet. Damit können “richtige” oder angehende Programmierer mehr anfangen, als ich. Der Award gehört mir ja bereits - das reicht mir völlig aus :-)
weiterführende Links:
- jsclasses.org: ahpwcheck
- Github: Sourcen inkl. Beispiele
- axel-hahn.de: Docs
Opcache auf WAMP-Server unter MS Windows aktivieren
Auf dem Wampserver für Windows wird die opcache DLL mitgeliefert, ist aber nicht aktiv.
Um es zu aktivieren, muss man die php.ini bearbeiten. Man findet Hinweise, wie die Extension zu aktivieren ist. Mein Fehler war, dass ich per Dateimanager die php.ini im Verzeichnis
C:\wamp\bin\php\php5.5.12\
bearbeitete … was zu keinerlei Resultat führte, weil der Apache Daemon die php.ini aus dem Apache-Verzeichnis anzieht:
C:\wamp\bin\apacheapache2.4.9\bin\php.ini
Also …
Schritt 1:
Mit einem phpinfo() in der Ausgabe prüfen, welches die richtige php.ini ist :-)
Oder direkt im Traymenü unter Php die dortige php.ini zum Bearbeiten anklicken.
Schritt 2:
Die php.ini bearbeiten … in der Sektion “[opcache]” ist die Extension zu aktivieren: die Zeile zend_extension=php_opcache.dll eintragen (sie existiert nicht).
Der Eintrag opcache.enable=1 ist hingegen bereits vorhanden:
(...) [opcache] zend_extension=php_opcache.dll ; Determines if Zend OPCache is enabled opcache.enable=1 (...)
Schritt 3:
Apache neu starten. In der Ausgabe von phpinfo() sieht man dann das zusätzliche Modul … und auch Im Tray-Menü Php -> Php Extensions ist opcache ist das Warnsymbol nun weg.
Wer mag, kann noch einen Viewer wählen, um den Speicherstatus zu prüfen, z.B. ob der zugewiesene Speicher für den Cache korrekt ausgelegt ist.
weiterführende Links:
- Github: opcache-status
- https://easyengine.io/tutorials/php/zend-opcache/ - weitere Webviewer (en)
JS Klasse ahpwcheck ist nominiert für Innovation Award Oktober 2016
Vor einigen Tagen habe ich auf jsclasses.org eine 2. Javascript-Klasse eingerichtet: ahpwcheck. Deren Sourcen sind zuvor auf Github und Doku ebenfalls online gestellt worden.
Und nun wurde diese Klasse für den Innovation Award Oktober 2016 nominiert.
Bitte Voten!!! :-)
weiterführende Links:
- Projektseite auf www.jsclasses.org (en)
- Source von ahpwcheck: Github (en)
- Docs (en)