Kategorie-Archive: Tipps & Tricks

Eclipse zu IPv4 zwingen

Manchmal muss man Eclipse seinen Willen aufzwingen. Um eine Android-App zu debuggen, wollte ich den Android Debug Monitor nutzen. Leider bekam ich immer die Meldung Failed to initialize monitor thread: unable to establish loopback connection.

Diverse Tipps aus dem Internet wie das Abstellen des toredo-Adapters über die Systemsteuerung brachten nichts. Auch alle Versuche, Eclipse über die eclipse.ini zur Nutzung von IPv4 zu bringen, scheiterten. Letzendlich bin ich – wie schon oft – auf stackoverlow auf die Lösung gestoßen. Dickes Danke hier an Ebrahim Byagowi.

Man muss einfach nur setx _JAVA_OPTIONS -Djava.net.preferIPv4Stack=true in der Kommandozeile laufen lassen. Danach hat der Monitor einwandfrei funktioniert.

Direkter Joomla-Logout ohne Zwischenseite (J!2.5 und höher)

Bei Joomla gibt es ein Problem, wenn man sich direkt ausloggen möchte. Ich nutze beispielsweise ein Menü (Modul), in dem ich gerne einen Abmelden-Link haben möchte.

Da gibt es dann 3 Optionen:

  1. Ich baue eine Form ein, die den direkten Logout erlaubt. Das ist lässt sich dann sehr schlecht mit CSS stylen.
  2. Ich leite den Nutzer auf eine Zwischenseite von com_users weiter, wo er sich ausloggen kann. Das ist umständlich.
  3. Ich baue einen direkten Logout-Link mit dem nötigen Token.

Der 3. Weg ist natürlich die beste Lösung, allerdings habe ich ihn nirgendwo beschrieben gesehen. Daher jetzt hier kurz und knapp:

<a href="<?php echo JRoute::_('index.php?option=com_users&task=user.logout&'.JSession::getFormToken().'=1'); ?>"><?php echo JText::_('JLOGOUT'); ?></a>

Intel WiDi findet keinen Adapter o.ä.

Intels WiDi-Technologie ist eigentlich eine Feine Sache. Per Drahtlosnetzwerk wird der Fernseher zum Zweitmonitor und man kann trotzdem gleichzeitig eine Internetverbindung über den Adapter offen halten. Allerdings hat die Technik noch so ihre „Kinderkrankheiten“. Oft wird kein Adapter gefunden, Treiberversionen sind inkompatibel oder was einmal funktioniert hat, arbeitet auf einmal nicht mehr (zuverlässig).

Bei den Treibern sollten einfach die jeweils aktuellsten Versionen verwendet werden. Zwischen den anderen Versionen – besonders wenn der Wireless-Treiber älter als der WiDi-Treiber ist – kann es Inkompatibilitäten geben. Verwenden Sie stets die vollständigen Treiber von Intel, also inklusive des „Intel PROSet/Wireless Connection Utility“, da andere Versionen ggf. fehlende DLL-Dateien nicht installieren können (da sie nicht im Paket enthalten sind).

Ansätze zur Lösung von nicht gefundenen WiDi-Geräten, Verbindungsfehlern oder Verbindungsabbrüchen:

  • Löschen Sie im Gerätemanager alle „Microsoft Virtual WiFi Miniport Adapter #x“. Diese werden von der WiDi-Software beim nächsten Start „resettet“ wieder angelegt.
  • Aktivieren Sie im Gerätemanager beim Intel-Treiber WMM. Das wird manchmal von Windows deaktiviert, z.B. wenn virtuelle Netzwerktreiber installiert werden.

Gerätemanager

Von iFrames auf Parent-Window zugreifen (cross-domain)

Will man eine Funktion im Elternfenster eines iFrame aufrufen, so ist das normalerweise kein Problem.

1
window.parent.functionname();

und fertig ist die Kiste. Ganz anders sieht es aber aus, wenn der iFrame nicht in der gleichen Domain liegt. Cross-Domain-Zugriff auf Funktionen (und Eigenschaften) ist nämlich verboten.

Hierfür gibt es seit einiger Zeit eine Lösung, die inzwischen viele Browser implementieren: postMessage. Wenn man nicht gerade IE6/7 unterstützen muss, kann man diese Funktion nutzen, um sich das Leben einfacher zu machen.

Im iFrame sendet man dabei eine Nachricht an das Hauptfenster:

1
window.parent.postMessage('close', '*');

und im Hauptfenster empfängt man die Nachricht und wertet sie aus:

1
2
3
4
window.addEventListener("message", function(event) {
    if(event.data === 'close'){
	doSomething();
    }

Unterstützt wird diese praktische Funktion von Firefox 3+, IE 8+, Chrome 4+, Safari 4+, Opera 10+ und allen derzeit gängigen Mobilbrowsern.

caniuse
(Bild von caniuse.com)

phpmyadmin sicher(er) zur Verfügung stellen

Möchte man phpmyadmin mehreren Domains zur Verfügung stellen, so bietet sich dafür das Debian-Paket „phpmyadmin“ an:

1
apt-get install phpmyadmin

Danach kann man unter /etc/phpmyadmin/apache.conf eine config finden, die man per

1
ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf.d/phpmyadmin.conf

in das Apache-Verzeichnis einbindet.

Jetzt muss an hier aber noch ein wenig gefeilt werden, denn so stellt man phpmyadmin grundsätzlich auch über HTTP – also unverschlüsselt – zur Verfügung. Administriert jetzt jemand über ein öffentliches Netzwerk seine Datenbank (immer an den DAU denken, auch wenn es sich erst mal vollkommen an den Haaren herbeigezogen anhört), hat man ruck-zuck ein Problem.

Deshalb leite ich grundsätzlich alle HTTP-Anfragen an phpmyadmin einfach nach HTTPS weiter. Dazu öffnet man die /etc/phpmyadmin/apache.conf und fügt ganz oben folgenden Text ein:

1
2
3
4
5
6
7
8
9
<IfModule mod_rewrite.c>
        <IfModule mod_ssl.c>
                <Location ~ "/phpmyadmin(/|$)">
                        RewriteEngine on
                        RewriteCond %{HTTPS} off
                        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI}
                </Location>
        </IfModule>
</IfModule>

Jetzt wird jeder Besucher von http://domain.de/phpmyadmin zu https://domain.de/phpmyadmin umgeleitet, was phpmyadmin ein ganzes Stück sicherer macht. Trotzdem ist zu überlegen, ob man die Software nicht lieber zusätzlich mit einem .htaccess-Schutz versieht. Wie das geht, erfährt man unter anderem bei SELFHTML.

SoftAP oder: „Wie verwende ich meine WLAN-Karte als Router?“

Windows 7 verfügt über eine Fähigkeit, über die nur wenige Bescheid wissen: Mit zwei einfachen Befehlen verwandelt man jede aktuelle WLAN-Karte in einen (sehr einfachen) Router, über den Clients per ICS (Internet Connection Sharing) auch die Internetverbindung mitbenutzen kann. Der sogenannte SoftAP enthält dabei auch einen DHCP-Server, sodass man sich um die manuelle Vergabe von passenden IP-Adressen keine Sorge machen muss.

Hier nun die Vorgehensweise:

  1. Das Startmenü öffnen
  2. cmd tippen – Rechsklick -> als Administrator ausführen
  3. netsh wlan set hostednetwork mode=allow ssid="mynet" key="mynetpassword" keyUsage=persistent
  4. netsh wlan start hostednetwork
  5. Netzwerk & Freigabecenter -> Adaptereinstellungen -> Rechtsklick auf den Adapter, der die Verbindung zum Internet herstellt -> Eigenschaften
  6. Registerkarte „Freigabe“
  7. Häkchen bei „Anderen Benutzern im Netzwerk gestatten…“ setzen und den neu geschaffenen virtuellen Adapter als Heimnetzverbindung auswählen

Ggf. nach einem Neustart der Internetverbindung steht diese dann über WLAN zur Verfügung. Dazu wählen sich die Clients einfach in das neu geschaffene Netz ein (dieses erscheint nicht als Ad-Hoc-Netz sondern als reguläres WLAN).

Aussschalten kann man den SoftAP natürlich auch:

netsh wlan stop hostednetwork

Für Windows vor Windows 7 steht mit Connectify für rund 35 Euro eine Lösung zur Verfügung und unter Linux gibt es wie hier im Ubuntu-Wiki beschrieben die Möglichkeit, solch ein Netz via hostapd aufzubauen.

Passwörter aus dem Windows Credential Manager auslesen

Eine ganz nützliches Programm, über das ich vor kurzem beim Umzug auf einen neuen Laptop gestoßen bin, möchte ich dem geneigten Leser nicht vorenthalten: Network Password Recovery. Damit kann man Passwörter, die im Windows Credential Manager gespeichert sind (z.B. Remote-Anmeldeinformationen im LAN oder das Passwort für die Windows Live ID), auslesen.

Mithilfe dieses Tools konnte ich 2 Passwörter für LAN-PCs wiederherstellen und mir so eine Passwortänderung auf diesen Maschinen ersparen. Die Software wird kostenlos von Nirsoft (u.a. bekannt für das Kommandozeilenutility NirCmd) zum Download angeboten und ist nur rund 500kB groß. Probleme bereiten dem Tool nur das Heimnetzgruppen-Passwort und Passwörter aus virtualapp/digital (hier ist zudem nicht ganz klar, wozu diese dienen). Für meine Zwecke war es also perfekt :)

Nodejs-Server via Apache-Reverse-Proxy und Monit

Um einen Nodejs-Server aufzusetzen braucht es nicht viel. Eigentlich nur die Binaries und eine JS-Datei mit dem eigentlichen Server. Doch wenn man den Server dauerhaft und bequem zugreifbar betreiben möchte, sind ein paar mehr Schritte notwendig.

Zunächst wird Nodejs und der Paketmanager npm installiert:

1
apt-get install nodejs npm

Danach richten wir den Proxy ein, sonst wäre ein Aufruf nur über einen Nicht-Standard-Port (80 ist ja schon vom Apachen belegt) möglich. In der Regel verwendet Nodejs hier Port 3000, aber das ist je nach Script unterschiedlich. Wir aktiviren also zunächst den Passthrough-Modus:

1
2
a2enmod proxy
a2enmod proxy_http

Für die eigentliche Einrichtung kann jetzt ein eigener VHost (z.B. eine Subdomain) angelegt werden, oder – wie in meinem Beispiel – ein Unterverzeichnis hergenommen werden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<VirtualHost ip:80>
	ServerName   myhost.com:80
	ServerAlias  www.myhost.com
	UseCanonicalName Off
	DocumentRoot /var/www/vhosts/myhost/httpdocs
	ErrorLog  /var/www/vhosts/myhost/statistics/logs/error_log
 
	...
 
	<Directory /var/www/vhosts/myhost/httpdocs>
		Options -Includes +ExecCGI
	</Directory>
 
	<Proxy *>
  		Order deny,allow
  		Allow from all
	</Proxy>
 
	<Location /mynodejspath>
  		ProxyPass http://localhost:3000
  		ProxyPassReverse http://localhost:3000
	</Location>
</VirtualHost>

Würde man nun nodejs manuell starten, könnte man schon per http://myhost.com/mynodejspath darauf zugreifen. Da Nodejs aber noch ein wenig fehleranfällig ist und dann gern mal sang- und klanglos abtritt, benutze ich monit zur Überwachung und ggf. zum Neustart des Servers (der Nodejs-App).

1
apt-get install monit

Als Startscript verwende ich ein Standard-init.d-Script, sodass ich auch beim Systemstart problemlos den Nodejs-Server mitstarten lassen kann. Dabei ist zu beachten, dass ich auf Benutzer „root“ prüfe und den Nodejs-Server ggf. über einen extra User starte. Andere Nutzer starten die Nodejs-App mit diesem Script als sie selbst.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash
DIR=/var/www/vhosts/myhost/httpdocs/mynodejspath
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NODE_PATH=/usr/lib/node_modules
NODE=/usr/bin/node
 
test -x $NODE || exit 0
 
function start_app {
  if [ $(whoami) = "root" ]
  then
    NODE_ENV=production nohup sudo -u nodejsusername "$NODE" "$DIR/app.js" 1>>"$DIR/logs/node.log" 2>&1 &
    echo $! > "$DIR/pids/node.pid"
  else
    NODE_ENV=production nohup "$NODE" "$DIR/app.js" 1>>"$DIR/logs/node.log" 2>&1 &
    echo $! > "$DIR/pids/node.pid"
  fi
}
 
function stop_app {
  kill `cat $DIR/pids/node.pid`
}
 
case $1 in
   start)
      start_app ;;
    stop)
      stop_app ;;
    restart)
      stop_app
      start_app
      ;;
    *)
      echo "usage: myapp {start|stop|restart}" ;;
esac
exit 0

Die Verzeichnisse „pids“ und „logs“ müssen unter dem App-Pfad noch angelegt werden. Danach kommt das Monit-Script nach /etc/monit/noderc:

1
2
3
4
5
6
7
8
9
10
#!monit
set logfile /var/log/monit.log
 
check process nodejs with pidfile "/var/www/vhosts/myhost/httpdocs/mynodejspath/pids/node.pid"
    start program = "/etc/init.d/myapp start"
    stop program  = "/etc/init.d/myapp stop"
    if failed port 3000 protocol HTTP
        request /
        with timeout 10 seconds
        then restart

… und ein Starter-init.d Script nach /etc/init.d/monit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
 
case $1 in
   start)
      monit -d 60 -c /etc/monit/noderc
      ;;
    stop)
      killall monit
      ;;
    restart)
      stop_app
      start_app
      ;;
    *)
      echo "usage: monit {start|stop|restart}" ;;
esac
exit 0

Ein Symlink nach rc2.d komplettiert die Automatisierung:

1
2
cd /etc/rc2.d/
ln -s ../init.d/monit S99monit

 

Somit haben wir viele Probleme gelöst:

  • Nodejs startet mit dem Server
  • Es wird überwacht und falls notwendig neu gestartet
  • Der Jeweilige Besitzer (und root) können es manuell neu starten
  • Es läuft mit eingeschränkten Userrechten
  • Es ist über Port 80 zugreifbar
  • und wir haben wieder etwas gelernt 😉

Lange Zend DB-Queries bringen PHP/Apache zum Absturz

Beim Programmieren einer Anwendung mit Zend und IBM DB2 bin ich auf ein Phänomen gestoßen, das zunächst unerklärlich schien. Führte ich einen langen Query aus (in diesem Fall sollte ein längerer XML-String in ein XML-Datenfeld der IBM DB2 Express-C geschrieben werden), so stürzte Apache ohne Fehlermeldung ab. In den Logs tauchte nur „restarting“ auf, sonst nichts.

Nach etwas Recherche stellte sich heraus, dass wohl eine fehlerhafte Implementierung der PCRE-Erweiterung Schuld an dem Desaster ist. Ist Backtracking auf einen zu hohen Wert eingestellt, so konsumiert PCRE (Zend Framework benutzt preg_match(), um SQL-Queries auf Korrektheit zu prüfen) den gesamten Stack, wodurch der Prozess sang- und klanglos abgeschossen wird.

Eine Erklärung zu PCRE-Backtracking gibt es hier: http://www.regular-expressions.info/catastrophic.html.

Für PHP ist die Lösung relativ simpel, der voreingestellte Wert von 100.000 für pcre.backtrack_limit und pcre.recursion_limit muss (entgegen einiger Aussagen in diversen Bugreports und Tutorials) heruntergesetzt werden. In meiner PHP.ini sieht das zurzeit folgendermaßen aus:

1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
[Pcre]
;PCRE library backtracking limit.
; http://php.net/pcre.backtrack-limit
pcre.backtrack_limit=1000
 
;PCRE library recursion limit.
;Please note that if you set this value to a high number you may consume all
;the available process stack and eventually crash PHP (due to reaching the
;stack size limit imposed by the Operating System).
; http://php.net/pcre.recursion-limit
pcre.recursion_limit=1000

Damit laufen meine Queries (~1800 Zeichen pro Query) anstandslos durch. Bei Bedarf kann dieser Wert auch weiter abgesenkt werden, auf 500 zum Beispiel. Da die PCRE-Funktion einen Aufwand von O(2^n) hat, bringt auch diese relativ kleine Änderung wieder recht viel.

Einzelne Datenbank/Tabelle aus MySQL-Dump wiederherstellen

Auf meinem Rootserver läuft jeden Tag ein Backup mit fwbackups, welches meine Dateien und Datenbanken mittels externem Script sichert und, ebenfalls mit Hilfe eines externen Scripts, auf einen FTP-Backupspace lädt. Das ist – einmal eingerichtet – sehr komfortabel. Möchte ich nun aber an die Daten heran und nur eine Datenbank oder Tabelle zurückspielen so müsste ich eigentlich einen zweiten MySQL-Server starten, das Backup einspielen und dann nur das gewünschte exportieren. Das wäre extrem umständlich, daher habe ich nach einem einfacheren Weg gesucht und ihn auch gefunden:

Nur eine Datenbank zurücksichern:

sed -n '/^-- Current Database: `dbname`/,/^-- Current Database: `/p' dumpfile > dbname.sql 2>error

Nur eine Tabelle zurücksichern:

sed -n -e '/CREATE TABLE.*mytable/,/CREATE TABLE/p' mysql.dump > mytable.dump

Hat man mehrere Tabellen, die ähnlich heißen sollte man Backquotes für die Namen verwenden.

 
Danke an uloBasEI von stackoverflow.com und Prabhat Kumar von adminlinux.blogspot.com für diese Tipps.

//Update: Danke an Kai Hessing, der mich per Mail aufmerksam gemacht hat, dass es mit obriger SQL-Anweisung ein Problem gibt, wenn die Tabelle vor der Rücksicherung schon existiert. Also dann entweder die Tabelle erst löschen oder folgendes Kommando benutzen:

sed -n -e '/DROP TABLE.*MYTABLE/,/UNLOCK TABLES/p' $BACKUPDIR/$FILE > $BACKUPDIR/$FILE.mytable
css.php