Saubere URLs mit „lesbaren“ Titeln erzeugen

Die als „Permalink“ oder „Slug“ bekannten Endungen von URLs, die meist den Titel abbilden, kennen wohl die meisten Internetnutzer. Dieser Beitrag hat zum Beispiel den Slug saubere-urls-mit-lesbaren-titeln-erzeugen.

Diese Art und Weise des Aufrufs ist eine leserfreundliche Alternative zum Aufruf via ID (index.php?id=3242) und bietet vor allem den Vorteil, dass der Leser sofort anhand der URL erkennen kann, welchen Artikel er aufgerufen hat.

Das Erzeugen eines URL Slugs ist nicht ganz so trivial. Zwar gibt es sehr einfache Methoden (zum Beispiel alle Zeichen zu verwerfen, die nicht a-z oder 0-9 sind), aber dann verliert die URL besonders im Deutschen viel Sinn. Denn Umlaute oder das ß würden komplett unter den Tisch fallen.

Bei Matteo Spinelli habe ich eine schöne Funktion gefunden, die ich jetzt benutze, um eigene Slugs zu erstellen. Alle nicht darstellbaren Zeichen werden bei dieser Funktion durch ähnliche Buchstaben ersetzt, also zum Beispiel das ß durch Doppel-S, ö und Ö durch o und so weiter.

Ich habe die Funktion für meine Zwecke angepasst und erweitert. Sie erzeugt jetzt einzigartige Slugs, vorausgesetzt niemand nutzt den gleichen Titel in exakt der gleichen Sekunde (das genügt als „uniqueness“ für meinen Anwendungsfall).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * Generate a readable (URL-valid) slug from a given string
 * @param string $str
 * @return string
 */
public static function slug($str){
 
	setlocale(LC_ALL, 'en_US.UTF8');
	$slug = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
	$slug = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $slug);
	$slug = strtolower(trim($slug, '-'));
	$slug = preg_replace("/[\/_|+ -]+/", '-', $slug);
	$slug = (time()-1388530800).'-'.$slug; //1388530800 => 2014-01-01
	return $slug;
 
}

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.

Sprache des Benutzers oder Browsers erkennen (PHP)

Es gibt eine Menge Scripts im Web, die die Brwosersprache mithilfe von PHP erkennen lassen wollen. Die meisten davon sind recht zweckmäßig, allerdings vernachlässigen sie einige Fälle. Zum Beispiel gehen diese Scripts oft davon aus, dass die erste übermittelte Sprache in den Accept-Headers auch die bevorzugte Sprache ist. Das muss aber nicht zwingend sein. Zudem werden auch Gewichtungen oft nicht beachtet.

Mit der unten stehenden Funktion ermitteln Sie zuverlässig die bevorzugte Sprache des Nutzers, sofern der Accept-Language-Header gesetzt ist. Die Funktion beachtet die Gewichtung (sofern nicht vorhanden wird sie gemäß RFC 2616 auf 1.0 gesetzt) und die Reihenfolge spielt keine Rolle.

Die Funktion gibt immer die beiden Buchstaben zurück, die die Sprache bestimmen. Also beispielsweise „de“ wenn der Accept-Language-Header „de-de“ oder auch „de“ als höchste Gewichtung gesetzt hat. Wenn Sie die volle Bezeichnung wünschen, entfernen Sie einfach die Substr-Funktion in Zeile 16.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * Detect Browser Language
 */
function getPreferredLanguage(){
 
	$acceptedLanguages = @explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
	$preferredLanguage = null;
	$maxWeight = 0.0;
 
	foreach((array)$acceptedLanguages as $acceptedLanguage){
 
		$weight = (float)@substr(explode(';', $acceptedLanguage)[1], 2);
		if(!$weight){$weight = 1.0;}
 
		if($weight > $maxWeight){
			$preferredLanguage =  substr($acceptedLanguage, 0, 2);
			$maxWeight = $weight;
		}
	}
 
	return $preferredLanguage;
}

Kommentare wieder aktiviert

Nachdem ich mit Spam überflutet wurde (13k Nachrichten in 2 Wochen) und die Gegenmaßnahmen nicht fruchteten, hatte ich das Kommentar-System deaktiviert. Ich starte jetzt einen neuen Versuch – diesmal mit Disqus – und die Kommentarfunktion ist bis auf weiteres wieder aktiviert. Mal sehen, wie es läuft.

Happy Commenting.

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

Sendmail über externen Mailserver (anderer Port) senden lassen

Wenn man das im letzten Beitrag beschriebene Problem mit Mails hat (Port 25 geblockt) und bereits einen externen Mailserver wie dort beschrieben eingerichtet hat, muss man nun noch den Weitertransport über diesen Server organisieren.

Dazu geht man bei dem hinter der Firewall befindlichen Server mit der MTA sendmail (habe ich wegen der Einfachheit gewählt) wie folgt vor:

Zuerst stoppen wir sendmail

service sendmail stop

und editieren /etc/mail/sendmail.mc

define(`SMART_HOST',`smtp.myisp.net')dnl
define(`RELAY_MAILER_ARGS', `TCP $h 587')
define(`ESMTP_MAILER_ARGS', `TCP $h 587')
FEATURE(`authinfo',`Hash -o /etc/mail/authinfo.db')dnl

Mit dem Befehl

m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf

wird die Config geprüft und in einem für sendmail lesbaren Format gespeichert.

Danach wird die Datei /etc/mail/authinfo mit folgendem Inhalt angelegt:

AuthInfo:ispdomain.net "U:my_username" "P:my_password" "M:PLAIN"
AuthInfo: "U:my_username" "P:my_password" "M:PLAIN"

Statt PLAIN kann auch ein anderer vom Relayserver unterstützter Authentifizierungsmechanismus gewählt werden.

makemap hash /etc/mail/authinfo < /etc/mail/authinfo

schreibt die Auth-Daten in eine von sendmail lesbare Hashfile (authinfo.db).

Jetzt kann sendmail wieder gestartet werden

service sendmail start

und sollte Mails nun über Port 587 an den Relay-Server weiterleiten, der sie schließlich ausliefert.

Postfix auf mehreren Ports „horchen“ lassen

Viele Netzwerke verbieten den Zugriff auf Port 25, um zu verhindern, dass Spam von ihrem Netzwerk aus gesendet wird (wenn auch nicht über ihren eigenen Mailserver). Muss man trotzdem öfter Mails aus einem solchen Netzwerk verschicken, bietet es sich an, Postfix auf dem Mailserver einen zweiten Port zuzuweisen.

Das ginge zwar auch in der master.cf, eventuell müssten dann aber noch einige andere Sachen geändert werden. Einfacher geht es, indem man iptables anweist, vom zweiten Port aus an 25 umzuleiten:

1
iptables -t nat -A PREROUTING -p tcp --dport 587 -j REDIRECT --to-ports 25

Mit

1
iptables-save

wird die Änderung auch nach dem Serverneustart direkt wieder übernommen.

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)

Root-Partition online vergrößern

Die Root-Partition vergrößern – das klingt schon mal scary. Aber dann auch noch online – das heißt ohne Live-CD, während des Betriebs? Warum um alles in der Welt sollte man sowas machen wollen? Ganz einfach, man stelle sich einen Server vor, bei dem die Root-Partition vergrößert werden soll und zu dem man keinen physischen Zugang hat. Voilà, das Szenario.

HINWEIS: Diese Methode funktioniert nur, wenn der zusätzliche Speicherplatz direkt an die zu vergrößernde Partition anschließt!

HINWEIS: Die hier vorgestellte Methode wurde von mir auf einem CentOS-Server live und erfolgreich angewendet, trotzdem gibt’s wie immer keine Garantie – und man sollte ein Backup in der Hinterhand haben.

Während viele Websites sagen, dass es nicht möglich wäre, die Partition ohne Live-CD oder Rettungssystem zu vergrößern, habe ich auf dem Blog von RaftaMan eine Anleitung gefunden, die genau das ermöglicht. Um einen Neustart des Systems kommt man zwar nicht herum (der Kernel muss die neue Partitionsgröße einlesen bevor man das Filesystem daran anpassen kann), aber es geht alles ohne von CD zu booten.

Also, los geht’s:

1
fdisk -l

zeigt uns die Devices und darauf enthaltenen Partitionen an. Um eine Partition zu bearbeiten müssen wir zunächst in fdisk das Device aufrufen:

1
fdisk /dev/sda

würde jetzt für die erste Festplatte stehen. Auf der Befehlszeile drücken wir nun „p“ und „Enter“, worauf uns noch einmal (zur Sicherheit) die Partitionen angezeigt werden:

1
2
3
4
5
6
7
Command (m for help): p
Disk /dev/sda: 5218 MB, 5218304000 bytes
255 heads, 63 sectors/track, 634 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
 
    Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1         634     5092573+  83  Linux

Den Anfangssektor unbedingt merken oder aufschreiben, wird er falsch gesetzt kann das alle Daten unbrauchbar machen! Diese Partition müssen wir jetzt löschen (oh ja, richtig gehört), aber keine Angst es gehen dabei keine Daten verloren solange der Anfangssektor gleich und die Partition nachher größer als vorher ist. Also geben wir jetzt ein „d“ und „Enter“ ein, worauf wir nach der Nummer der Partition gefragt werden. Da die Zählung bei 1 beginnt also in unserem Fall eine 1. Und noch mal „Enter“.

Als nächstes erstellt man eine neue Partition mit „n“ und „Enter“. Dabei nutzt man den gleichen Partitionstyp und den gleichen Startsektor wie bei der Ausgangspartition. Der Endsektor kann innerhalb der angezeigten Grenzen beliebig gewählt werden, sollte aber größer sein als der Ursprüngliche, damit die Partition keine Daten verliert.

1
2
3
4
5
6
7
8
9
Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-934, default 1):
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-934, default 934): 850

Falls die Ausgangspartition das „boot“-Flag gesetzt hatte, müssen wir das auch hier wieder setzen:

1
2
Command (m for help): a
Partition number (1-4): 1

Schlussendlich schreiben wir die Änderungen mit „w“ und „Enter“ in die Partitionstabelle. Die Bestätigung sollte fast sofort erscheinen und uns darauf hinweisen, dass ein Neustart erforderlich ist.

1
2
3
4
5
6
7
8
9
Command (m for help): w
The partition table has been altered!
 
Calling ioctl() to re-read partition table.
 
WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table.
The new table will be used at the next reboot.
Syncing disks.

Nach dem Neustart, den wir direkt durchführen, kann das Filesystem problemlos live an die neue Partitionsgröße angepasst werden:

1
2
3
4
5
resize2fs /dev/sda1
resize2fs 1.39 (29-May-2006)
Filesystem at /dev/sda1 is mounted on /; on-line resizing required
Performing an on-line resize of /dev/sda1 to 1522150 (4k) blocks.
The filesystem on /dev/sda1 is now 1522150 blocks long.

Und fertig. Der neue Speicherplatz steht vollständig zur Verfügung.