Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Path info vs inne rozwiązania do routingu
Forum PHP.pl > Forum > PHP
Inscure
Witam,

Do tej pory stosowałem $_SERVER['PATH_INFO'], ale jak się okazuje, nie na każdym serwerze jest ono dostępne.
Przykładowo, na jednym z serwów, z których korzystam, zamiast PATH_INFO jest ORIG_PATH_INFO, zaś na nginx nie ma obu tych indeksów.

Ciekaw jestem czego wy używacie w swoich projektach.
Myślałem na URL_REQUEST. Są jakieś przeciwwskazania?

Wymagania co do działania:
- PHP 5.2.17 lub nowsze
- serwer Apache, IIS oraz nginx
- przyzwoity wygląd linków bez korzystania z htc

Proszę o propozycję smile.gif
by_ikar
Cytat
zaś na nginx nie ma obu tych indeksów.

Są, jedynie zależy od ciebie jak sobie te regułki ustawisz. Na domyślnych to może ich nie być, ale ktoś kto używa nginx'a raczej ma świadomość tego że można to sobie skonfigurować - jeżeli takiej nie ma, to niech doczyta.

QUERY_STRING jest zawsze, możesz jakoś próbować tym operować. Ale łatwiej będzie "odjąć" SCRIPT_NAME od REQUEST_URI które również są zawsze. Efektem czego otrzymasz coś na wzór PATH_INFO.
Inscure
Cytat(by_ikar @ 22.06.2012, 04:48:13 ) *
Są, jedynie zależy od ciebie jak sobie te regułki ustawisz. Na domyślnych to może ich nie być, ale ktoś kto używa nginx'a raczej ma świadomość tego że można to sobie skonfigurować - jeżeli takiej nie ma, to niech doczyta.


Sobie bym skonfigurował, ale gdy ktoś korzysta z usług firmy "x", to ma problem, bo sam nie posiada uprawnień, a usługodawca nie zawsze jest chętny by cokolwiek zmienić w konfiguracji serwera.
by_ikar
OK, więc albo zabawa z query_string, albo najprościej wyciąć różnicę między request_uri a script_name a w efekcie dostaniesz to samo co w path_info.
Gligamesh
  1. $dir = substr($_SERVER['SCRIPT_NAME'], 0, -strlen('index.php'));
  2. $path = rawurldecode(substr($_SERVER['REQUEST_URI'], strlen($dir)));
by_ikar
@UP osobiście proponowałbym takie rozwiązanie:

  1. $pathInfo = str_replace(dirname($_SERVER['SCRIPT_NAME']), '', $_SERVER['REQUEST_URI']);


Załóżmy że zmienna $_SERVER['SCRIPT_NAME'] zawiera taką ścieżkę:

Kod
/test/index.php


a zmienna $_SERVER['REQUEST_URI'] zawiera taką ścieżkę:

Kod
/test/dasdasd


Efektem końcowym będzie:

Kod
/dasdasd


Aby taki efekt osiągnąć trzeba cały ruch przekierować na skrypt (oczywiście pomijając obrazki, arkusze styli itp).
Inscure
Muszę uwzględnic jeszcez sytuację, gdy mod rewrite nie jest załadowany, wtedy link wygląda mniej więcej tak: /index.php/ctrl/act/
Zastosowałem coś takiego:

Cytat
protected function setEnv()
{
/**
* Lokalizacja na serwerze wykonywanego skryptu.
* Nie zawiera nazwy pliku w przeciwieństwie do $_SERVER['SCRIPT_NAME'].
* Przy korzystaniu z `rewrite module` obcina żądanie o wartość tej zmiennej.
*/
$script_path = str_replace($this->_index_file, '', $_SERVER['SCRIPT_NAME']);

define('PATH_INFO', str_replace(array($_SERVER['SCRIPT_NAME'], $script_path), '', $_SERVER['REQUEST_URI']));
}


Cytat
$this->_index_file = 'index.php'


Chyba już nie bardzo da się to uprościc.
by_ikar
A to w takim wypadku wystarczy dodać do dirname index.php i wtedy skrypt wyglądać może tak:

  1. $pathInfo = str_replace(array(dirname($_SERVER['SCRIPT_NAME']), '/index.php'), '', $_SERVER['REQUEST_URI']);


Jedynie musisz uwzględnić w routerze że w momencie kiedy $pathInfo jest puste, znaczy że jesteś na głównej stronie. Nie musisz tego w routerze robić, możesz w tym skrypcie, w taki sposób:

  1. $pathInfo = str_replace(array(dirname($_SERVER['SCRIPT_NAME']), '/index.php'), '', $_SERVER['REQUEST_URI']);
  2. $pathInfo = empty($pathInfo) ? '/' : $pathInfo;


I wtedy czy będziesz miał przekierowanie ruchu na jeden plik, czy go mieć nie będziesz, powyższy skrypt będzie każdorazowo wyświetlać to samo co path_info. Cały problem możesz mieć później. Problemem tym będą linki do przeróżnych podstron. O ile na apache wykryjesz jeszcze w jakiś sposób czy jest włączony mod_rewrite. O tyle nie wykryjesz w nginx i nie wiem czy w iis tak samo, nie wiem czy wykryjesz że cały ruch jest przekierowany na jeden plik. Dlatego też musisz raczej podjąć decyzję czy chcesz żeby działało to wszędzie, więc wówczas wszystkie twoje linki najlepiej jak będą wyglądać tak:

Kod
localhost/index.php/jakas-podstrona


Możesz to jeszcze zrobić inaczej. Podczas instalacji systemu, sprawdzić czy jakaś przykładowa strona zadziała, poprzez ajax i przesłanie wyniku do instalatora, który ustawi że tak, a nie inaczej mają być ustawione linki. Oczywiście z zmianą gdzieś w panelu administratora wink.gif

BTW po co ci jakaś zmienna _index_file? Nie lepiej sobie odpuścić, i niech to zawsze będzie index.php ?
Inscure
Linki mam tworzone dynamicznie dzięki implementacji odpowiedniej funkcji, którą rejestruję w systemie szablonów OPT, przez co może byc używana w plikach tpl.
Działa to mniej więcej na takiej zasadzie, że jako argumenty przesyłam nazwe kontrolera, akcję oraz parametry, a skrypt sam albo dodaje index.php do zwracanego adresu, albo nie - w zależności od wyniku metody systemowej, sprawdzającej czy mod rewrite jest załadowany.

Co do sytuacji pustej zmiennej, to oczywiście mam to uwzględnione, bo to przecież podstawowa sprawa smile.gif

Potrzebna była jeszcze drobna poprawka. Ostatecznie wygląda to tak:

Kod
    protected function setEnv()
    {
        $dirname = dirname($_SERVER['SCRIPT_NAME']);
        if ($dirname === $this->_sep)
        {
            $to_replace = $this->_sep.'index.php';
        }
        else
        {
            $to_replace = array($dirname, $this->_sep.'index.php');
        }
        
        define('PATH_INFO', str_replace($to_replace, '', $_SERVER['REQUEST_URI']));
    }


Takie kwestie jak index.php czy separator jako zmienna klasy to już kwestia podejścia do sprawy, więc przyjmijmy że to pomijamy smile.gif
Śmiga aż miło, niestety nie na nginx. Czyli cała praca z przepisywaniem na marne. Okazuje się, że nginx nie przyjmuje niczego co jest po pliku.
Czyli przyjmuje: /index.php ale już nie index.php/ a tym bardziej nie index.php/ctrl/act/

Chyba trzeba dla tego serwera dac tradycyjne linki: index.php?page=ctrl&action=act. Jakieś inne pomysły?
by_ikar
Po co ci wówczas router, jeżeli będziesz miał te linki tradycyjnie? Jeżeli są jakieś serwery na których jest nginx, a nie można go skonfigurować, to bardzo wiele rzeczy tam nie zadziała - nie powinieneś się tym przejmować.. Podaj gdzieś w instalatorze jak konfigurować ngnix'a i jeżeli ktoś tego wykonać nie będzie mógł - trudno, przecież nie wyczarujesz cudów.. IMO nie zrobisz czegoś co będzie działać wszędzie idealnie, i wyglądać tak samo.
toaspzoo
__FILE__
Inscure
No panowie... dzięki za pomoc, chyba tak jak teraz zrobiłem, styknie.
Mianowicie: sprawdzam czy serwer to Apache. Jeśli tak, to w zależności od dostepności mod rewrite w linku jest index.php lub nie ma.
forma odpowiednio: index.php/ctr/act/test-cos/ lub /ctr/act/test-cos/

Jeżeli serwer jest inny, to wychwytuje czy na którejś z podstron wystąpi indeks PATH_INFO w tablicy $_SERVER. Jeżeli tak, to zapisuję informację w cache i generuję linki typu:
index.php/ctr/act/test-cos/

Jeżeli nadal nie wyłapie PATH_INFO, to uznaje, że go nie ma, a wtedy link ma postać: index.php?q=ctr/act/test-cos/
Problemem może być to, że gdy cache się przedawni, to osoba która go bedzie tworzyć ujrzy inne linki, niż kolejna, która odświeży stronę (bo na głównej nie ma PATH_INFO, więc póki ktoś nie wjedzie na podstronę, to po przedawnieniu cache system uznaje, że PATH_INFO nie ma). Aby uniknąc takiego problemu, osoby które wiedzą, że skonfigurowały sobie np. na nginx co trzeba, zmieniają wartość pod indeksem w pliku config.php z FALSE na TRUE.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.