Kawałek Kodu

Bez obaw! Nie będziemy negować zalet ziołolecznictwa, ani dyskredytować hashtagów, ani tym bardziej używać środków psychoaktywnych podczas przekierowań użytkowników. Będzie po prostu o hash - najbardziej leniwej części URL. Będziemy go nazywać hash, choć poprawnie by było nazwać fragmentem lub kotwicą.

#iSerwer

Hash jako część URL chyba najbardziej kojarzony jest działaniami po stronie klienta - głównie kotwicami do fragmentów podstrony. Ale nie tylko, nie ma żadnego problemu z przekierowaniami po stronie PHP, .htaccess czy reguł nginx na adresy z hash.

Załóżmy, że w bardzo ważnym regulaminie na naszej bardzo ważnej stronie zaszły jakieś zmiany. Zmiany te są umieszczone w sekcji z id="zmiany". URL kierujący do regulaminu z hash o takiej wartości zakotwiczy stronę, tj. przesunie ją, do miejsca tej sekcji. Dzięki temu użytkownik trafi do miejsca, które powinien najpierw przeczytać.

RewriteEngine On

RewriteCond %{REQUEST_URI} ^/regulamin$
RewriteRule ^(.*)$ /regulamin#zmiany [R=302,L]

Gdybyśmy to robili w PHP, to wtedy:

<?php

header("Location: regulamin#zmiany");
exit();

A w nginx:

location /regulamin {
  return 302 "http://$http_host$request_uri#zmiany";
}

#iPrzekierowanie

A co się dzieje z hash kiedy kierujemy na URL, pod którym zasób nie jest dostępny natomiast jest dostępny pod innym URL? Czy hash ginie w trakcie takiego przekierowania? Jak się okazuje, nie. Jeśli mamy do czynienia z przekierowaniami o statusie 300, 301, 302 oraz 303, to nowy URL powinien być traktowany jako miejsce docelowe zasobu, którego żądamy, jednocześnie zachowując hash pod warunkiem, że nowy adres nie kieruje na inny hash. Najprostszym przykładem będzie przekierowane na adres z "bez www" na "z www". Jeśli więc użytkownik wybiera adres: http://domena.pl/podstrona.html#sekcja, to po przekierowaniu powinien dostać się na www.domena.pl, czyli na: http://www.domena.pl/podstrona.html#sekcja. Po prostu ma się znaleźć możliwie najbliżej żądanego zasobu. O zachowanie hash dba przeglądarka.

#iPraktycznyPrzyklad

Przekierowanie z "bez www" na "z www", to prosty przykład, ale akurat najmniej praktyczny. Wyobraź sobie, że pewne podstrony serwisu są dostępne po zalogowaniu, a dokładnie nie podstrony, ale ich wybrane sekcje. Mogą to być stricte sekcje tekstowe, ale też zakładki czy slider z nawigacją hash. Kiedy użytkownik próbuje się dostać do takiej podstrony, albo wpisując ręcznie adres, albo z samego serwisu czy z mailingu, zostaje przekierowany najpierw do strony logowania. Wiemy już, że hash nam nie zginie. Wiemy też, że możemy w PHP przekierować na URL z hash po zalogowaniu, czyli de facto wrócić na żądaną przez użytkownika stronę przed zalogowaniem. Skąd jednak PHP ma wiedzieć jaki jest hash?

#iJavaScript

Brakuje nam więc jednego elementu, a właściwie fragmentu, czyli hash. Musimy mieć możliwość przekazania go do PHP, a zrobimy to dzięki JavaScript. Kiedy użytkownik będzie chciał się dostać do podstrony dostępnej tylko dla zalogowanych, to przekierujemy go na URL logowania wraz ze zmienną powrotu. Niech to będzie zmienna o nazwie backURL. W formularzu logowania zapisujemy jej wartość w polu INPUT o typie hidden. Połowa sukcesu za nami, bo mamy adres żądanej podstrony, ale bez hash. Dodajemy jednak krótki skrypt:

document.querySelector('form input[name="backURL"]').value += document.location.hash;

Ponieważ hash został zachowany w URL, to pobieramy go i doklejamy do naszego adresu powrotu. Kiedy teraz proces autoryzacji przebiegnie poprawnie, to możemy na podstawie wartości zmiennej backURL przekierować użytkownika na w pełni poprawny URL.

#wPseudokodzie

if(glowna){
  wyświetl linki do podstrony z hash
}
else if(podstrona){
  if(zalogowany){
    wyświetl podstronę
  }
  else{
    przekieruj na logowanie
    ze zmienną backURL,
    tu nie doklejamy hash,
    zrobi to za nas przeglądarka,
    czyli np.:
    header('Location: zaloguj?backURL=' . urlencode('podstrona'));
  }
}
else if(logowanie){
  if(metoda to GET){
    wyświetl formularz logowania:

    <form method="post" action="zaloguj">
       <label><input type="text" name="login"/></label>
       <label><input type="text" name="password"/></label>
       <input type="submit" value="Zaloguj" />
       <input type="hidden" name="backURL" value="<?php echo $_GET['backURL'] ?? '';?>" />
     </form>
     <script>
       document.querySelector('form input[name="backURL"]').value += document.location.hash;
     </script>

  }
  elseif(metoda to POST){
    if(jeśli logowanie ok){
      przekieruj na URL
      na podstawie zmiennej
      backURL z $_POST,
      którą otrzymaliśmy
      z formularza, i która
      zawiera hash
    }
  }
}

I obsługa hash w przekierowaniach już w działaniu.

Mam nadzieję, że pomimo dużej ilości #, wpis nie okazał się kompletną sieczką. Do przeczytania!

 

Przydatne linki:
Obsługa hash w URL w trakcie przekierowań, według W3C