Saturday 17 June 2006

Permanent redirect

Na pewno zdarzyło Ci się kiedyś trafić na stronę z informacją w rodzaju "serwis dostępny teraz pod nowym adresem". Nierzadko data w stopce wskazuje, że przeprowadzka odbyła się już parę lat temu - a użytkownicy (znaczy - Ty) nadal trafiają pod stary adres. Traci też właściciel strony - nie dość, że musi nadal utrzymywać starą domenę strony (aby przekazać użytkownikom informację), to jeszcze wyszukiwarki wyżej oceniają starszy adres, pod niego kierując użytkowników. Nie byłoby wygodniej, gdyby użytkownicy automatycznie trafiali na nową stronę, a wyszukiwarki nie pokazywały już odnośników do starej?


Z pomocą przychodzi kod HTTP Permanent Redirect (301). Najprostsze rozwiązanie, jeśli cały serwis zmienił adres, to wpis w pliku .htaccess:


Options +FollowSymlinks
RewriteBase /
RewriteEngine On
RewriteRule ^.* http://nowy.adres.com%1 [R=permanent,L]

Powyższa regułka włącza mod_rewrite (RewriteEngine On), łapie wszystkie odwołania do strony (^.* - wyrażenie regularne), a następnie przekierowuje je ([R=permanent])na nową domenę, zachowując treść dopasowaną do wyrażenia regularnego (%1). Opcja L oznacza, że serwer ma na tej regule poprzestać zakończyć przetwarzanie pliku .htaccess. mod_rewrite pozwala na złożone przekształcenia adresu, co można wykorzystać, gdy zmieniła się struktura strony. Niestety, nie na wszystkich serwerach jest dostępny. W samym pliku .htaccess przekierowanie można też uzyskać poprzez


Redirect permanent /tutaj/byl/jakis.plik http://nowy.adres.com/jest.tutaj

natomiast w pliku php działanie przekierowania 301 można generować następującym kodem:


<?php
$var_array = explode("/",$_SERVER['REQUEST_URI']);
//print_r($var_array);
$target=$var_array[1];
$url="http://nowy.adres.com/".$target;
header("HTTP/1.1 301 Moved Permanently");
header ( "Location: $url" );
?>
<p>Strona została przeniesiona. Nowy adres:</p>
<a href="<?php echo $url; ?>"><?php echo $url; ?></a>

przy czym samo parsowanie $target trzeba dopasować do swoich potrzeb. Trzeba też pamiętać, że aby header zostało przyjęte przez przeglądarkę, serwer nie może wcześniej wysłać żadnej treści - jeśli np. przed początkiem skryptu w pliku będzie pusta linia, albo chociaż spacja, to przekierowanie nie zadziała.


Przepisywanie adresów za pomocą skryptu php sprawdza się najlepiej, gdy zmieniła się struktura strony - najłatwiej za ich pomocą poprawić adresy wymagające uaktualnienia. A w jaki sposób przekonać Apacha do obsługiwania żądań przy użyciu skryptu? Jeśli interesuje nas przepisywanie adresów z jakiegoś podfolderu, to wystarczy wykorzystać fakt, że Apache, gdy nie znajdzie żądanego adresu, zaczyna przesuwać się w górę wirtualnego drzewa plików, aż trafi na plik potrafiący obsłużyć żądanie. Np. dla http://domena.info/koza/little/beast najpierw zostanie sprawdzone koza/little/beast, potem koza/little, a na końcu koza. Wystarczy poinformować serwer, że koza jest skryptem php poprzez dodanie w .htaccess:


<Files koza>
ForceType application/x-httpd-php
</Files

Globalną obsługę żądań przez skrypt można ustawić za pomocą mod_rewrite:


RewriteRule ^.* rewriter.php [L]

dopasowując według potrzeb wyrażenie regularne.


Jak wyszukiwarki reagują na Permanent Redirect? Z mojego doświadczenia wynika, że po 2 tygodniach nowy adres traktowany jest jako równorzędny staremu, a po 4 tygodniach przejmuje już w całości jego Page Rank (stary adres nie pojawia się więcej w wynikach). Jeśli nie chcesz frustrować użytkowników, pamiętaj też, by uaktualnić linki przychodzące z innych stron - dopóki przekierowanie będzie działać, użytkownicy trafią na stronę, ale jeśli nie planujesz płacić za starą domenę w nieskończoność, wypadało by zupełnie usunąć z sieci odwołania do niej. Linki wchodzące można sprawdzić w logach serwera / statystykach (referer) lub poprzez wyszukiwarki. Tutaj niestety google kłamie bezczelnie, podając tylko małą część znanych mu linków, na szczęście Yahoo (linkdomain:domainname.com albo linksite:domainname.com) oraz MSN (link:domainname.com) zwracają pełną listę (z dokładniejszymi wynikami w Yahoo). Zostaje już tylko skontaktować się z adminem każdej z linkujących stron...

4 comments:

  1. Textile zdaje się mieszać w moim cytacie z kodu. Oczywiście prawidłowo to powinno wyglądać tak:

    RewriteEngine on
    RewriteCond %{REQUEST_URI} ^/$ [OR]
    RewriteCond %{REQUEST_URI} ^/index\.[^/]+$
    RewriteRule ^.*$ http://demo.xml-intl.com/editor [r=301,L]

    No.

    ReplyDelete
  2. Zauważ, że redirect poszczególnych plików i innych takich, możesz osiągnąć już na poziomie apache’owskiego htaccessa lub httpd.conf. Nie trzeba pisać pehapów ani nic takiego dziwnego.

    Wystarczy użyć prawdziwego sedna mod_rewrite, czyli RewriteCond.

    RewriteEngine on
    RewriteCond %{REQUEST_URI} ^/$ [OR]
    RewriteCond %{REQUEST_URI} ^/index\.[^/]+$
    RewriteRule ^.*$ http://example.com/test/site.html [r=301,L]

    Powyższe przekierowanie złapie wszystkie odniesienia do gołej example.com oraz dodatkowo wszystkie próby znalezienia indeksu i przepchnie je prosto do example.com/test/site.html

    ReplyDelete
  3. Sprowokowałeś mnie do sprawdzenia RFC... i masz rację. Poprawiłem.

    ReplyDelete
  4. Przy przekierowywaniu w PHP należy również dodać w treści strony linka z komunikatem, AFAIR takie są zalecenia RFC.

    ReplyDelete