Das Putzlowitsch Test- und SEO-Blog

Direkte Bild-Aufrufe auf Seite weiterleiten – so gehts

Das Problem

In den letzten Tagen ist die Aufregung ob der neuen Google-Bildersuche recht groß und viele versuchen, einen Ausweg aus den sinkenden Besucherzahlen zu finden.

In der neuen Bildersuche werden die Bilder direkt in Original-Auflösung auf der Ergebnisseite geladen. Der Nutzer hat also wenig Anlaß, die Ursprungsseite zu besuchen.

Google-Bildersuche: Links

Google-Bildersuche: Links zu Seite/Bilder

Immerhin gibt es vier Links (grün), die den Benutzer auf die Ursprungsseite mit dem Bild führen. Dazu kommt ein Link direkt zum Bild [Bild ansehen] und indirekt die Möglichkeit, per Rechtsklick und „Grafik anzeigen“ nur das Bild aufzurufen.

Der direkte Link zum Bild bringt allerdings keine Besucher auf die Seite. Daher gibt es die Idee, den direkten Aufruf eines Bildes aus der Bildersuche auf eine Seite mit dem Bild umzuleiten.

Achtung!
Lest bitte vorher die Hinweise von Google zu „Bilder-Cloaking“ und überlegt Euch, ob Ihr das Riskio eingehen wollt.

So gehts

Um zu erkennen, ob jemand von der Bildersuche kommt, kann man den Referrer auswerten. Vereinfacht gesagt, könnte man folgende Regel formulieren:

„Ist die Referrer-Domain google.* und die angeforderte Datei ein Bild (jpeg,png,…), dann leite den Nutzer auf eine Seite mit dem Bild um.“

In der .htaccess könnte das so aussehen:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond	%{REQUEST_FILENAME} -f
RewriteCond	%{HTTP_REFERER}	^http(s)?://(www\.)?google [NC]
RewriteRule	\.(jpg|png|gif)$	/redirect.php	[L]
</IfModule>

Zunächst wird Rewrite eingeschaltet und die Basis festgelgt.
Dann wird geprüft, ob es die angeforderte Datei überhaupt gibt und ob der Referrer Google ist. Falls ja und die Datei ein Bild ist, wird das PHP-Skript zur Weiterleitung aufgerufen.

So weit, so gut, nur gibt es noch einige Probleme zu lösen.

Leider wird der Referrer auch gesendet, wenn das Bild als Bild auf der Google-Seite geladen wird. Da soll natürlich keine Weiterleitung erfolgen, weil das im Kontext eines Bilder zu einem Fehler führt. Kann man also unterscheiden, ob das Bild geladen wird oder ein Link auf das Bild aufgerufen wird? Ja, mann kann. Zumindest meistens.

Außerdem wird ein bereits geladenes Bild vom Browser im Cache vorgehalten, was zu unvorhergesehenen Ergebnissen bei der Weiterleitung führen kann. Kann man das verhindern? Ja, man kann.

Meine Problemlösungen

Als technische Basis setze ich einen Apache-Server mit den aktiven Modulen mod_rewrite, mod_headers und mod_setenvif voraus. Wobei das Modul mod_setenvif nicht zwingend erforderlich ist, es macht die Sache aber übersichtlicher:

<IFModule mod_headers.c>
Header	set	 Cache-Control "no-cache, no-store, must-revalidate"	env=NO_CACHE
Header	unset	 Expires	env=NO_CACHE
Header	unset	 Last-Modified	env=NO_CACHE
Header	unset	 ETag	env=NO_CACHE
</IfModule>

<IfModule mod_setenvif.c>
SetEnvIf Accept "text/html"	REQ_HTML=1
SetEnvIf Referer "^https?://(([^\.]+?\.)?([^\.]+?\.)?[^\.]+?)/"	DOM_REFERER=$1
</IfModule>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /bilder

RewriteCond	%{REQUEST_FILENAME} -f
RewriteRule	\.(jpg|gif|png)$	-	[NC,C]

RewriteCond	%{ENV:DOM_REFERER}	google\.de$ [NC,OR]
RewriteCond	%{ENV:DOM_REFERER}	google\.at$ [NC,OR]
RewriteCond	%{ENV:DOM_REFERER}	google\.ch$ [NC,OR]
RewriteCond	%{ENV:DOM_REFERER}	example\.com
RewriteRule	.*	-	[E=DO_RDR:1,E=NO_CACHE:1]

RewriteCond	%{ENV:REQ_HTML} 1
RewriteCond	%{ENV:DO_RDR} 1
RewriteRule	([^-]+)-([0-9]+)\.(jpg|gif|png)$	/bild-$1-$2.html	[R=302,L]
</IfModule>

Zur Unterscheidung von Bildaufruf (img src=…) und Link verwende ich den Wert von „Accept“ im HTTP-Request-Header. Nach meiner Beobachtung enthält dieses Header-Feld bei Bild-Aufrufen nicht den Typ „text/html“, beim Aufruf von Links, auch zu Bildern, aber schon. Wenn also „text/html“ im Accept-Header zu finden ist, dürfte es sich um den Link zum Bild und nicht um das Laden des Bildes in der Google-Ansicht handeln.

<IfModule mod_setenvif.c>
SetEnvIf Accept "text/html"	REQ_HTML=1
SetEnvIf Referer "^https?://(([^\.]+?\.)?([^\.]+?\.)?[^\.]+?)/"	DOM_REFERER=$1
</IfModule>

Den Accept-Header werte ich in einer SetEnvIf Anweisung aus und setze eine entsprechende Variable, die ich später in den Rewrite-Regeln auswerten kann. Zudem extrahiere ich in dem Block den Domain-Namen aus dem Referer, da ich diesen auch in anderen Rewrite-Regeln benötige.

RewriteCond	%{REQUEST_FILENAME} -f
RewriteRule	\.(jpg|gif|png)$	-	[NC,C]

Mit den Rewrite-Regeln prüfe ich zunächst die Existenz der Datei und über die Datei-Erweiterung, ob ein Bild aufgerufen wird. Falls nicht, wir der zweite Block der Rewrite-Regeln gar nicht erst ausgeführt.

RewriteCond	%{ENV:DOM_REFERER}	google\.de$ [NC,OR]
RewriteCond	%{ENV:DOM_REFERER}	google\.at$ [NC,OR]
RewriteCond	%{ENV:DOM_REFERER}	google\.ch$ [NC,OR]
RewriteCond	%{ENV:DOM_REFERER}	example\.com
RewriteRule	.*	-	[E=DO_RDR:1,E=NO_CACHE:1]

Im zweiten Block wird eine Liste von Referrer-Domains abgearbeitet, für die die Weiterleitung erfolgen soll. In dem Fall sind es die drei Google-Domains, von denen die meisten meiner Besucher kommen (exemple.com ist nur ein Platzhalter). Die Abfrage nach dem Referer kann man natürlich auch anders gestalten. Das hängt halt davon ab, was man damit erreichen will. Hier setze ich mir wieder ein Flag (DO_RDR), das ich später für die Weiterleitung auswerte.

<IFModule mod_headers.c>
Header	set	 Cache-Control "no-cache, no-store, must-revalidate"	env=NO_CACHE
Header	unset	 Expires	env=NO_CACHE
Header	unset	 Last-Modified	env=NO_CACHE
Header	unset	 ETag	env=NO_CACHE
</IfModule>

Außerdem setze ich einen Wert (NO_CACHE), mit dem am Ende geprüft wird, ob das Caching deaktiviert werden soll. Der Block mod_headers steht zwar am Anfang, der Webserver führt diese Anweisungen aber erst ganz zum Schluß aus, kurz bevor die Antwort an den Client gesendet wir. Damit wird das Caching des von Google direkt geladenen Bildes verhinert.

RewriteCond	%{ENV:REQ_HTML} 1
RewriteCond	%{ENV:DO_RDR} 1
RewriteRule	([^-]+)-([0-9]+)\.(jpg|gif|png)$	/bild-$1-$2.html	[R=302,L]

Im dritten Rewrite-Block erfolgt dann die Weiterleitung, falls es sich um einen Link-Request (REQ_HTML) handelt und eine Weiterleitung überhaupt ausgeführt werden soll (DO_RDR).

Wohin weiterleiten?

Ein weiteres Problem kann die eigentliche Weiterleitung sein. Wohin soll die Reise gehen?

Im Beispiel ist das relativ einfach. Die Bilder liegen in einem Unterverzeichnis /bilder/ und der Dateinamen besteht aus Bezeichnung und laufender Nummer. Die Zielseiten mit den Bildern bestehen auch aus Bezeichnung und laufender Nummer. Damit läßt sich schon in der .htaccess Datei die Weiterleitungsregel unmittelbar formulieren.

/bilder/tomaten-7.jpg -> /bild-tomaten-7.html
/bilder/banane-23.jpg -> /bild-banane-23.html
...

Schön, wenn man so eine klare Struktur für seine Bilder hat. Ich habe die leider nicht. :-)

RewriteCond	%{ENV:REQ_HTML} 1
RewriteCond	%{ENV:DO_RDR} 1
RewriteRule	.*	/rdr.php	[L]

Also muß die Weiterleitung z.B. von einem PHP-Skript erledigt werden, in dem man dann praktisch beliebige Weiterleitunsziele adressieren kann.

In WordPress gibt es für die über die Mediathek hochgeladenen Bilder jeweils eine Attachment-Seite. Nun könnte man sich die Informationen zum Weiterleitungsziel aus der WP-Datenbank holen. Aus Performance-Gründen habe ich da einen etwas anderen Weg gewählt.

Für WordPress, wie z.B. hier bei schnurpsel.de, sieht das rdr.php-Skript so aus:

<?php
define( 'THISPATH', dirname(__FILE__) . '/' );
@include( THISPATH.'redir.php' );

function set_404() {
	header( "HTTP/1.0 404 Not Found", true, 404 );
	echo <<<EOT
<!DOCTYPE html>
<html>
<head><title>404 Not Found</title></head>
<body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
EOT;
	exit;
}

function set_header( $ctype ) {
	@header( "Content-type: $ctype" );
	@header( 'Cache-Control: no-cache' );
	@header( 'Cache-Control: max-age=0', false ); 
	@header( 'Expires:'.gmdate('D, d M Y H:i:s', 0 ).' GMT' );
}

function redirect( $url, $status = 302 ) {
	@header( 'Cache-Control: no-cache, no-store, must-revalidate' );
	@header( "Location: $url", true, $status );
	exit();
}

$img_uri = urldecode( $_SERVER['REQUEST_URI'] );
$redir_url = $redir_b[$img_uri];

if( !$redir_url && @preg_match( '~(.+?)-(1600|1200)\.(jpg|png|gif)$~', $img_uri, $treffer ) ) {
	$redir_url = $redir_b[$treffer[1].'.'.$treffer[3]];
}

if( $redir_url )
	redirect( $redir_url );
else {
	$img_file = THISPATH.$img_uri;
	$img_size = @getimagesize( $img_file );
	if( $img_size ) {
		set_header( $img_size['mime'] );
		@readfile( $img_file );
		exit;
	}
}
set_404();
?>

Download: rdr.zip

In meinem rdr-Skript includiere ich eine weitere PHP-Datei (redir.php), die nur ein Array mit den Weiterleitungszielen für die Bilder enthält. Falls kein Weiterleitungsziel gefunden wird, gebe ich einfach das Bild selbst aus.

Die redir.php PHP-Datei lasse ich mir von einem Skript durch WordPress erstellen:

<?php
define( 'THISPATH', dirname(__FILE__) . '/' );
define( 'WP_USE_THEMES', false );
define( 'USE_ATTACHMENT_URL', true );

@include( THISPATH.'redir.php' );

require('./wp-blog-header.php');

echo '<pre>';

$args = array( 'post_type' => 'attachment', 'posts_per_page' => -1, 'post_mime_type' => 'image', 'post_parent' => null ); 
$attachments = get_posts( $args );
if ( $attachments ) {
	foreach ( $attachments as $post ) {
		$attachment_url = wp_get_attachment_url( $post->ID );
		$attachment_uri = @parse_url( $attachment_url, PHP_URL_PATH );
		if( USE_ATTACHMENT_URL )
			$page = get_attachment_link( $post->ID );
		else
			$page = get_permalink( $post->post_parent );
		if( $page && $attachment_uri && !$redir_b[$attachment_uri] ) {
			if( strpos( $page, 'attachment_id' ) === false ) {
				$redir_b[$attachment_uri] = $page;
				echo "+ $attachment_uri -> $page\r\n";
			}
			else
				echo "- $attachment_uri -> $page\r\n";
		}
		else
			echo "* $attachment_uri -> $page\r\n";
	}
}

$export_data = "<?php\r\n\$redir_b = ";
$export_data .= var_export( $redir_b, true );
$export_data .= ";\r\n\r\n?>";
file_put_contents( THISPATH.'new_redir.php', $export_data );
echo '</pre>';
?>

Download: get-redir.zip

Mit der Konstante ‚USE_ATTACHMENT_URL‘ wird festgelegt, ob die Weiterleitung auf die Attachment-Seite (true) oder zur Artikel-Seite mit dem Bild (false) erfolgen soll.

Zum Anfang wird die bestehende ‚redir.php‘ geladen. Es werden dann nur Einträge hinzugefügt, die es noch nicht gibt.

Außerdem prüfe ich, ob es die Attachment-Seite wirklich gibt, denn für Bilder ohne Eltern-Seite bzw. Bilder in nicht veröffentlichten Artikeln wird kein Permalink zurückgeliefert, sonder nur die URL mit dem ‚attachment_id‘-Parameter.

Am Ende wird eine neue Datei ’new_redir.php‘ geschrieben, mit der man dann die alte ‚redir.php‘ ersetzen kann.

Folgende Dateien sind an der Methode beteiligt:
/rdr.php
/redir.php
/wp-content/uploads/.htaccess

In der .htaccess-Datei muß die RewriteBase entsprechend angepaßt werden:

RewriteBase /wp-content/upload

Für meine Putzlowitscher Zeitung enthält das Array etwas mehr als 2000 Einträge. Das ergibt eine Dateigröße von ca. 350k. Wer deutlich mehr Bilder in WP verwaltet, muß sich ggf. etwas anderes einfallen lasse.

So ein Array hat aber den Vorteil, daß ich darin auch beliebige, andere Weiterleitungsziele definieren kann.

Noch ein paar Tips und Hinweise

Falls sich alle Eure Bilder in einem Unterverzechnis befinden, bei WordPress z.B. /wp-content/uploads/, dann packt die .htaccess-Datei genau dort rein. Für alle anderen, normalen Seitenaufrufe wird sie dann gar nicht erst abgearbeitet.

Was irgendwie möglich ist, sollte schon in der .htaccess-Datei erledigt werden. Der Aufruf eines Skriptes, eventuell sogar mit Datenbankabfragen, kostet mehr Server-Leistung und verschlechtert die Performance.

Ihr könnt sogar unterscheiden, ob jemand den Button [Bild ansehen] angeklickt oder per Rechtsklick das Bild aufgerufen hat. Beim Rechtsklick wird ggf. vom Browser als Referer die komplette Google-Such-URL übermittelt. Das kann man zur Unterscheidung auswerten, z.B. ob der Parameter tbm=isch im Referer enthalten ist.

Das Speichern mit Rechtsklick auf das Original-Bild in der Bildersuche funktioniert nicht. Es wird die HTML-Seite des Weiterleitungs-Ziels gespeichert. :-)

Ich habe bisher nur mit wenigen Browsern getestet. Bei denen hat es aber funktionert, wie es soll.

Ich übernehme keine Haftung für Schäden, die möglicherweise durch die Umsetzung der hier vorgestellten Methoden entstehen.

14 Kommentare »

Das Strato SSL Zertifikat – gut für den Nutzer (und für Google)

Sicher ist sicher

Gestern bestellt, heute schon aktiv, so schnell ging das mit dem Strato-SSL-Zertifikat für meine Domain schnurpsel.de. Zu erkennen ist das an dem Schloß-Symbol oben in der Adresszeile des Browsers.

Schnurpsel mit Strato-SSL

Alle Daten, die zwischen Eurem Webbrowser und meiner Website hin- und hergeschickt werden sind nun verschlüsselt. Das bedeutet, daß niemand mitlesen kann, welche Seiten Ihr aufruft oder welche Daten Ihr als Kommentar abschickt.

Der Spaß kostet mich zwar 2,99 Euro im Monat, aber das ist es mir wert. :-)

Das Strato Single-Domain SSL-Zertifikat

Strato bietet für die Webhosting-Pakete zwei Zertifikate an. Ein Single-Domain-Zertifikat für 2,99 Euro im Monat, das genau für die Domain gilt, für die es bestellt wird. In meinem Fall ist das schnurpsel.de, es funktioniert aber auch für www.schnurpsel.de. Das war noch nicht immer so, wie hier ein Nutzer schreibt.

Es gibt zudem ein Wildcard-Zertifikat für 9,99 Euro im Monat, das auch alle Subdomains mit abdeckt, wie z.B. testblog.schnurpsel.de oder bilderdieb.schnurpsel.de. Aber das ist mir dann doch zu teuer und die Subdomains sind praktisch nur Testseiten.

So sehen die Daten des Zertifikates aus:

Strato SSL-Zertifikat für www.schnurpsel.de

Ausgestellt ist es von Strato für www.schnurpsel.de, als Alternativ-Name ist aber auch schnurpsel.de eingetragen.

Das Zertifikat wird vom Browser ohne weitere Nachfrage akzeptiert, weil es in der Zertifikatshierarchie auf ein vertrauenswürdiges Root-Zertifikat von „Equifax Secure CA“ zurückgeht.

Besonderheiten beim Strato-SSL-Zertifikat

Viele Domains unter einer IP-Adresse

Ursprünglich funktioniert SSL nur dann, wenn unter einer IP-Adresse genau eine Website, also Domain angesprochen wird. Das liegt daran, daß die Verschlüsselung bereits bei der ersten Kontaktaufnahme des Browsers mit dem Server ausgehandelt wird und zu dem Zeitpunkt noch keine Information über die gewünschte Domain übertragen wird.

Beim Shared Webhosting der großen Anbieter wie auch Strato tummeln sich unter einer IP-Adresse aber viele Domains, so das hier SSL nicht ohne Weiteres funktioniert. Der Weg aus dem Dilemma ist eine Erweiterung des SSL-Standards von 2003 für das Multidomain-Hosting, die Server Name Indication (SNI). Hier wird der gewünschte Domainname bereits bei der Aushandlung, allerdings unverschlüsselt, übertragen.

Damit ist es möglich, auch mehrere Domains unter einer IP-Adresse mit individuellen SSL-Zertifikaten anzusprechen. Genau diese Erweiterung nutz auch Strato für die SSL-Zertifikate.

Die Sache hat eber einen kleinen Haken. Ältere Browser oder Geräte unterstützen den SNI-Standard nicht und so sind Websites damit nicht erreichbar. Der oben verlinkte Wikipedia-Artikel enthält eine Liste der Browser- und Systeme, die SNI unterstützen.

Die http auf https Weiterleitung

Damit künftig die Seite nur noch über https aufgerufen werden kann, sollten die http-Aufrufe auf https-Aufrufe weitergeleitet werde. Dazu bietet Strato im Kundenbereich die Option „SSL erzwingen“ an.

Strato-Option SSL erzwingen

Eigentlich eine feine und bequeme Sache, wäre da nicht ein Problem. Die Weiterleitung, die mit dieser Option ausgelöst wird, hat den Status 302 Found, was folgendes bedeutet:

„Die angeforderte Ressource steht vorübergehend unter der im „Location“-Header-Feld angegebenen Adresse bereit. Die alte Adresse bleibt gültig.“

Genau das wollen wir aber nicht, die Seite soll nun immer und nur per https erreichbar sein. Richtig wäre also der Status 301 Moved Permanently:

„Die angeforderte Ressource steht ab sofort unter der im „Location“-Header-Feld angegebenen Adresse bereit (auch Redirect genannt). Die alte Adresse ist nicht länger gültig.“

So soll es sein. Mein Tip daher für Euch: Setzt nicht die Option im Strato-Kundenmenü aktiv, sondern macht die Umleitung in der .htaccess selber. Das ist auch nicht weiter kompliziert. Bei mir steht folgendes drin:

# HTTPS erzwingen 
RewriteCond %{ENV:HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Das muß natürlich nach dem RewriteEngine On, aber am besten noch vor allen anderen RewriteRules stehen.

Warum Strato per 302 weiterleitet, keine Ahnung. Vielleicht sollte man sie mal auf den Fehler hinweisen. Mit den Statuscodes haben die es eh nicht so, wenn ich da noch an die Sache mit dem 410 denke.

https – ein Rankingvorteil bei Google

Als ich gestern das SSL-Zertifikat bei Strato bestellt hatte, wußte ich noch nicht, daß Google heute bekannt geben würde, daß die sichere SSL-Verschlüsselung ein Ranking-Faktor ist. Tja, Zufälle gibt es manchmal. :-)

Ist also alles prima und ich habe intuitiv das Richtige getan. Oder doch nicht?

Mir ist aufgefallen, daß meine Seiten hier bei Schnurpsel jetzt langsamer geladen werden. Zumindest kommt es mir so vor. Und da die Seitengschwindigkeit auch ein Rankingfaktor ist bleibt abzuwarten, was nun passiert. Überwiegt der Vorteil durch SSL oder der Nachteil durch die schlechtere Geschwindigkeit. Ich werde sehen…

19 Kommentare »

Google sperrt mich aus – Suchergebnis führt ins Leere

Draufgeklickt

Google-Redirect per JavaScriptSeit heute kann ich bei Google keine Suchergebnisse mehr anklicken. Das heißt, anklicken kann ich sie schon, nur es passiert nichts.

Wenn ich den Ergebnislink mit der rechten Maustaste in einem neuen Tab öffne, sehe ich nur eine leere, weiße Seite.

Ganz leer ist die Seite aber nicht wirklich, sie enthält einen ca. 2500 Zeichen langen JavaScript-Code (siehe Screenshot).

Weitergeleitet

Google-JavaScript: Security ErrorDas eigentliche Problem liegt beim Google-URL-Redirector, der beim Klick auf das Ergebnis nicht direkt zur Zielseite führt, sondern über eine Weiterleitungsseite die Zielseite aufruft.

Diese Weiterleitungsseite leitet per JavaScript weiter und dabei gibt es einen Fehler, den mir die im FireFox eingebaute Webconsole anzeigte:

uncaught exception: [Exception... "Security error"  
code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)"
location: ... Line: 1"]

Unerlaubt

Aber warum, was verursacht den Fehler? Nach meinen Recherchen dürfte es am versuchten Zugriff auf den localStorage liegen. Der localStorage ist eine neue Erfindung von HTML 5 und sowas ähnliches wie Cookies, nur besser. Die Beschreibung des localStorage bei w3.org nennt auch Fälle, in denen der Browser einen SecurityError ausgeben kann oder soll.

Damit ist die Ursache für mich auch klar, ich erlaube google.de nicht, Cookies zu speichern. Offensichtlich gilt diese Regel dann auch für den neuen HTML5-localStorage. Warum nun Google unbedingt bei der Weiterleitung etwas in diesem lokalen Speicher ablegen will, weiß ich nicht. Es ging ja bisher auch ohne.

Ausgesperrt

Meine Lösung des Problems: Ich sperre die URL des für den ganzen Weiterleitungs-Kram verantwortlichen JavaScripts im Router. Damit werden die URLs der Suchergebnisse wieder direkt aufgerufen und die Weiterleitungsseite kommt gar nicht erst zum Zuge.

Das hat mich ohnehin schon länger gestört, das ich nicht einfach eine URL von der Suchergebnisseite per Rechtsklick in die Zwischenablage kopieren kann. Nun geht auch das wieder. :-)

Man kann aber auch einfach die Cookies für Google erlauben, dann klappts auch wieder mit der Weiterleitung. Oder JavaScript deaktivieren, das hilft auch. :-)

Weitere Artikel mit Bezug zu diesem:
12 Kommentare »

Google-Suche Ziel-URL wird weitergeleitet

Google-Suche: Ziel-URL direktBisher war es ja so, daß man bei der Google-Suche von der Trefferseite mit einem Klick direkt auf die Zielseite kam. Im Link stand also direkt die Adresse der Zielseite drin, also z.B.:

<a href="http://putzlowitsch.de/">

Wenn man mit der Maus über einem Link stehenbleibt, wird in der Statuszeile das Linkziel entsprechend angezeigt.

Google-Suche: Ziel-URL mit WeiterleitungHeute ist mir nun aufgefallen, das sich nach einem Klick auf den Link das Linkziel plötzlich ändert. Ich mache das z.B. oft mit der rechten Maustaste, um mir den Link mit „Link-Adresse kopieren“ in die Zwischenablage zu holen. Leider verwandelt sich der Link nun in einen Weiterleitungslink über den Google-URL-Redirector:

<a href="/url?url=http://putzlowitsch.de/&ved=0CBQ...">

Diese Umwandlung wird per Javascript mit dem onmousedown-Ereignis bewerkstelligt und ist natürlich nicht nur beim Klick mit der rechten Maustaste sondern auch bei einem normalen Klick wirksam.

Falls kein Javascript aktiv ist, steht die Weiterleitungs-Adresse auch bereits direkt im Linkziel drin:

<a href="/url?q=http://putzlowitsch.de/&sa=U&ei=ufP9T...>

Gut möglich, daß mir das nur bisher nicht aufgefallen war und es diese Weiterleitung schon länger gibt. Ich finde es allerdings eher unpraktisch. Zudem muß ich nun wieder mal meine PHP-Skripte anpassen…

7 Kommentare »

WordPress 2.3 – Problem ohne www bei Strato

Hintergrund

Es war mir ja schon fast am Anfang meiner Strato-Zeit aufgefallen. Die Servervariable HTTP_HOST liefert immer den Hostname mit einem vorangestellten www zurück, selbst dann, wenn der Aufruf ohne www erfolgte. Eigentlich eine eigenwillige, wenn nicht gar falsche Konfiguration des Strato-Severs, denn die Variable HTTP_HOST soll eigentlich genau das enthalten, was der Browser im HTTP-Requestheader übermittelt. Wenn ich also die Seite schnurpsel.de aufrufe, dann sollte eben das da drin stehen, und nicht etwa www.schnurpsel.de. Aber genau das passiert bei Strato (PowerWeb A und S).

Problem

Bisher stellte das auch kein Problem dar, mit dem Neuen WordPress 2.3 aber schon (deshalb war meine Seite gestern Abend auch zeitweise nicht erreichbar). Ab WordPress 2.3 ist eine Funktion integriert, die ein sogenanntes „Canonical Redirect“ ausführt. Auf das Strato-Problem bezogen bedeutet das, daß eine Weiterleitung z.B. dann stattfindet, wenn der Aufruf der Seite nicht so erfolgt, wie das in der WordPresskonfiguration eingestellt ist.
Wenn z.B in WordPress als Blog-Adresse (URL)

http://schnurpsel.de

eingetragen ist, jemand aber die Seite mit

http://www.schnurpsel.de

aufruft, wird er auf

http://schnurpsel.de

umgeleitet (und anders rum). An sich eine sinnvolle Sache, gerade unter SEO-Aspekten.

Was passiert nun aber bei Strato? Die funktion redirect_canonical schaut in HTTP_HOST nach, wie die Seite aufgerufen wurde, stellt fest, daß da ein www steht, aber das Blog ohne www konfiguriert ist. Also wird flux auf die Adresse ohne www weitergeleitet (diese Information bekommt der Browser zurück). Der ruft dann brav die Seite erneut ohne www auf, weil aber Strato das www wieder vorneran stellt, leitet redirect_canonical erneut um, der Browser ruft wieder brav ohne www auf usw. usw. Es ensteht also eine Weiterleitungs-Endlosschleife, die der Browser dann aber (hoffentlich) nach ein paar Versuchen mit einer Meldung beenden sollt. Beim Firefox sieht das dann so aus:

Fehler: Umleitungsfehler
Die aufgerufene Website leitet die Anfrage so um, dass sie nie beendet werden kann.

Das alles tritt aber nur beim Blog selber auf, der Adminbereich ist davon nicht betroffen.

Lösung

Aber auch hier gibt es mit einem bißchen Basteln Abhilfe. Glücklicherweise gibt es in den Servervariablen einen Eintrag, der die tatsächlich aufgerufene Adresse enthält, nämlich SCRIPT_URI. Dieser enthält die vollständigen Aufrufadresse mit http und gegebenfalls Verzeichnis und Dateiname, z.B.

http://schnurpsel.de

Hier kann man einfach den echten Hostanamen extrahieren und der Variable HTTP_HOST zuweisen. Und schon ist die Welt wieder in Ordnung :-)

Also WordPress-Plugin sehen die paar Zeilen PHP-Code dann so aus:

<?php
/*
Plugin Name: 123 True HTTP Host
Plugin URI: http://schnurpsel.de/wordpress-23-problem-ohne-www-bei-strato-65/
Description: Setzt den wahren HTTP_HOST aus dem Request. Bei Strato wird immer www davor geschrieben.
Author: Ingo Henze
Version: 0.10
Author URI: http://putzlowitsch.de/
*/ 
$plw123thh = parse_url( $_SERVER['SCRIPT_URI'] );
if( isset( $plw123thh['host'] ) && ($plw123thh['host']!=$_SERVER['HTTP_HOST']) )
  $_SERVER['HTTP_HOST'] = $plw123thh['host'];
?>

Mann kann den Quelltext hier einfach rauskopieren, in einer Datei speichern,auf den Server in das Pluginverzeichnis kopieren und aktivieren. Oder man nimmt das fertige Plugin als ZIP-Datei.

Download: 123 True HTTP Host 0.10

Im Übrigen tritt das Problem mit der Weiterleitungs-Endlosschleife bei einer Konfiguration mit www nicht auf, allerdings funktioniert dann das redirect_canonical auch nicht, weil die Seiten ja scheinbar immer korrekt mit www aufgerufen werde.

116 Kommentare »