Przekieruj wszystkich do index.php za pomocą htaccess

131

Piszę prosty framework MVC oparty na PHP. Chcę, aby ten framework mógł być zainstalowany w dowolnym katalogu.

Mój skrypt PHP pobiera żądanie uri i dzieli je na segmenty. Sprawia, że ​​segment 1 jest kontrolerem, a segment 2 działaniem. Wszystko idzie dobrze, kiedy robię to:

http://www.example.com/mvc/module/test/

Przejdzie do konkretnego kontrolera modułu i metody. Teraz mam domyślny kontroler, kontroler domowy, który znajduje się w folderze home.

Teraz, gdy uzyskam bezpośredni dostęp do tego folderu http://www.example.com/mvc/home/ Zostanie wyświetlony kod 403 zabroniony, ponieważ ten folder istnieje, zamiast tego powinien również wrócić do http://www.example.com /mvc/index.php

Jeśli zainstalowałbym framework w innym folderze, powiedzmy, że framework folderów musi przekierować z powrotem do http://www.example.com/framework/index.php

Chciałbym przekierować każdy folder i plik php z powrotem do index.php, pozostawiając wszystko inne tak, jak jest.

Mój pierwszy problem, jaki napotkałem, polegał na tym, że nigdy nie przekierowywał do właściwego folderu, zawsze do głównego folderu domeny.

Oto, czego próbowałem:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
David Ericsson
źródło
Żeby upewnić się, że dobrze rozumiem twoje pytanie: chcesz przekierować każde żądanie do katalogu głównego, index.php czy chcesz przekierować każde żądanie wysłane do tego konkretnego folderu index.php ?
Technoh
Do folderu, w którym znajduje się plik htaccess, katalogu głównego platformy. W moim przykładzie z powrotem do katalogu mvc
David Ericsson

Odpowiedzi:

259

Twoja reguła przepisywania wygląda prawie dobrze.

Najpierw upewnij się, że .htaccessplik znajduje się w katalogu głównym dokumentu (w tym samym miejscu index.php), w przeciwnym razie wpłynie to tylko na podfolder, w którym się znajduje (i wszystkie podfoldery w nim - rekurencyjnie).

Następnie wprowadź niewielką zmianę w swojej regule, aby wyglądała mniej więcej tak:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?path=$1 [NC,L,QSA]

W chwili, gdy po prostu dopasowujesz, na .którym jest jedna instancja dowolnej postaci, musisz przynajmniej .*dopasować dowolną liczbę instancji dowolnej postaci.

$_GET['path']Zmienna będzie zawierać strukturę katalogów fałszywe, więc /mvc/module/testna przykład, które można następnie wykorzystać w index.php w celu określenia kontrolera i działania, które chcesz wykonać.


Jeśli chcesz, aby cały shebang został zainstalowany w podkatalogu, na przykład /mvc/lub /framework/najmniej skomplikowanym sposobem, jest nieznaczna zmiana reguły przepisywania, aby wziąć to pod uwagę.

RewriteRule ^(.*)$ /mvc/index.php?path=$1 [NC,L,QSA]

I upewnij się, że twój plik znajduje się w index.phptym folderze, podczas gdy .htaccessplik znajduje się w katalogu głównym dokumentu.


Alternatywa dla$_GET['path'] (zaktualizowany luty '18 i styczeń '19)

W rzeczywistości nie jest konieczne (ani nawet obecnie) ustawianie ścieżki jako $_GETzmiennej, wiele frameworków będzie polegać na $_SERVER['REQUEST_URI']pobieraniu tych samych informacji - zwykle w celu określenia, którego kontrolera użyć - ale zasada jest dokładnie taka sama.

Upraszcza to RewriteRulenieco, ponieważ nie musisz tworzyć parametru ścieżki (co oznacza, że ​​oryginał OP RewriteRule będzie teraz działał):

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L,QSA]

Jednak nadal obowiązuje zasada dotycząca instalacji w podkatalogu, np

RewriteRule ^.*$ /mvc/index.php [L,QSA]



Flagi:

NC = Bez wielkości liter (wielkość liter nie ma znaczenia, nie jest to konieczne, ponieważ we wzorcu nie ma znaków)

L = Ostatnia (przestanie pisać po tym przepisaniu, więc upewnij się, że jest to ostatnia rzecz na twojej liście przeróbek)

QSA= Ciąg zapytania Dołącz, na wypadek gdybyś miał ?like=penguinsna końcu coś takiego, co chcesz zachować i przekazać do index.php.

CD001
źródło
1
powinien to być index.php? path = $ 1
Jacek Pietal
1
@Prozi jeśli nie jesteś w podkatalogu i index.php jest w docroot, to trzeba wiodącym / - z Options +Indexesi index.php zawarte w DirectoryIndexty mógł opuścić off index.php całkowicie i po prostu użyć /?path=$1Dotyczy to kiedy robi przepisywanie przez .htaccess zamiast w <Directory>dyrektywie typu httpd-vhosts.conf .
CD001
Jeśli używasz tego i polegasz na $ _GET ['path'], będziesz miał kłopoty w przypadku przejścia na serwer nginx ...
zaledwie
3
Niezły post! Warto zauważyć, że użytkownik może nadpisać, $_GET['path']jeśli doda path=whateverdo adresu URL.
rybo111
1
@Liviuge - prawda, ale początkowo przechodziłem całą ścieżkę, $_GETwięc wymagałoby (.*)to ... to zabawne, ale RewriteRule, z którego OP korzystał 6 lat temu, wtedy nie działało dla nich - ale z architekturą MVC ewoluował z PHP (jak umieściłem w zaktualizowanym bitu z 18 lutego ), teraz ... chyba wyprzedzili swój czas :) /mvc/Oczywiście nadal potrzebuje poprawnej ścieżki do katalogu.
CD001
28

Aby przekierować wszystko, co nie istnieje index.php, możesz również użyć FallBackResourcedyrektywy

FallbackResource /index.php

Działa tak samo, jak w ErrorDocumentprzypadku żądania nieistniejącej ścieżki lub pliku na serwerze, dyrektywa po cichu przekazuje żądanie do index.php.

Jeśli chcesz przekierować wszystko ( including existant files or folders) do index.php, możesz użyć czegoś takiego:

RewriteEngine on

RewriteRule ^((?!index\.php).+)$ /index.php [L]

Zauważ, że wzorzec ^((?!index\.php).+)$ pasuje do każdego uri, z wyjątkiem index.phptego, że wykluczyliśmy ścieżkę docelową, aby zapobiec nieskończonemu błędowi zapętlenia.

Amit Verma
źródło
Ale możesz również użyć:DirectoryIndex index.php
Shao
1
Użyj *zamiast +we wzorcu, jeśli chcesz również przekierować samą ścieżkę główną.
Mir-Ismaili
15

Możesz użyć czegoś takiego:

RewriteEngine on
RewriteRule ^.+$ /index.php [L]

Spowoduje to przekierowanie każdego zapytania do pliku index.php katalogu głównego. Należy pamiętać, że przekierowuje również zapytania dotyczące istniejących plików, takich jak obrazy, pliki javascript lub arkusze stylów.

Technoh
źródło
1
To rozwiązanie prawie mi się udało. Ciągle otrzymuję komunikat „AH00124: Żądanie przekroczyło limit 10 wewnętrznych przekierowań”. Dodałem wcześniej "RewriteRule ^ index \ .php - [L]" i działa idealnie!
Fredster
11

Jest jedna "sztuczka" na ten problem, która pasuje do wszystkich scenariuszy, jest to tak oczywiste rozwiązanie, że będziesz musiał spróbować, aby uwierzyć, że faktycznie działa ... :)

Oto jest ...

<IfModule mod_rewrite.c>

   RewriteEngine On

   RewriteCond %{REQUEST_FILENAME}  -f [OR]
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteRule ^(.*)$ index.php [L,QSA]

</IfModule>

Zasadniczo prosisz MOD_REWRITE o przekazanie do index.phpżądania URI zawsze, gdy plik istnieje ORAZ zawsze, gdy żądany plik nie istnieje !

Podczas badania kodu źródłowego MOD-REWRITE, aby zrozumieć, jak to działa, zdałem sobie sprawę, że wszystkie jego sprawdzenia mają miejsce zawsze po weryfikacji, czy plik, do którego się odwołuje, istnieje, czy nie. Dopiero wtedy RegExsą przetwarzane. Nawet jeśli Twój identyfikator URI wskazuje folder, Apache wymusi sprawdzenie plików indeksu wymienionych w jego pliku konfiguracyjnym.

Opierając się na tym prostym odkryciu, okazało się oczywiste, że prosta weryfikacja pliku wystarczyłaby dla wszystkich możliwych wywołań , o ile dwukrotnie dotkniemy sprawdzania obecności pliku i skierujemy oba wyniki do tego samego punktu końcowego, obejmując 100% możliwości.

WAŻNE: Zauważ, że nie ma znaku „ / ” w index.php. Domyślnie MOD_REWRITE użyje folderu, który jest ustawiony jako „folder podstawowy” do przekazywania dalej. Piękno polega na tym, że niekoniecznie musi to być „folder główny” witryny, dzięki czemu to rozwiązanie działalocalhost/ każdego podfolderu, który go zastosujesz.

Ostatecznie niektóre inne rozwiązania, które testowałem wcześniej (te, które wydawały się działać dobrze) zepsuły zdolność PHP do „wymagania” pliku poprzez jego ścieżkę względną, co jest kłopotliwe. Bądź ostrożny.

Niektórzy mogą powiedzieć, że jest to nieeleganckie rozwiązanie. Może tak jest, ale jeśli chodzi o testy, w kilku scenariuszach, kilku serwerach, kilku różnych wersjach Apache itp., To rozwiązanie działało w 100% we wszystkich przypadkach!

Julio Marchi
źródło
Dzięki, to rozwiązało mój problem polegający na tym, że FallbackResource index.phplinia działała na komputerze Mac (OS X 10.11), ale nie działała pod Centosem 7.5. Jednak: RewriteRulepowoduje to również przepisanie na przykład lokalizacji plików CSS. Ponieważ potrzebowałem przekierować tylko pliki PHP, zmodyfikowałem regułę na RewriteRule ^(.*)php$ index.php [L,QSA]. YMMV.
Laryx Decidua
1
Cieszę się, że to pomogło. Masz rację, celuje w WSZYSTKIE pliki, ponieważ pytanie brzmiało: „ Przekieruj wszystko do index.php używając htaccess ”. Istnieją inne, bardziej eleganckie sposoby przekierowywania tylko plików PHP, na przykład RewriteRule ^(.*)\.php$ index.php [L,NE,QSA](które nie wymagają warunków do działania). Obecnie jednak stosuję mniej kosztowną regułę: RewriteRule ^.+$ index.php [L,NE,QSA]którą można łączyć z warunkami RewriteCond %{REQUEST_FILENAME} !-fi RewriteCond %{REQUEST_FILENAME} !-d, a nawet RewriteCond $1 !^(index\.php|assets|robots\.txt|favicon\.ico)być naprawdę specyficzną.
Julio Marchi
5

Głupia odpowiedź, ale jeśli nie możesz dowiedzieć się, dlaczego nie przekierowuje, sprawdź, czy dla folderu internetowego jest włączona następująca opcja.

AllowOverride All

Umożliwi to uruchomienie htaccess, który musi być uruchomiony! (są alternatywy, ale ich brak spowoduje problemy https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride )

Antony
źródło
0

Po wykonaniu czynności nie zapomnij zmienić tagu kotwicy, home

Przykład:

.htacces file
RewriteEngine On

RewriteRule ^about/$ /about.php

PHP file:
<a href="about/"> about</a>
Collins Benson
źródło
Zawsze pamiętaj, aby zmienić tag <a>.
Collins Benson,
2
Co oznacza po wykonaniu zakazu zmiany tagu strona główna ?
Enrico Maria De Angelis
0

na wypadek, gdybyś nadal zastanawiał się, jak przekierować wszystkie żądania, jeśli katalog istnieje (dla podstawowych folderów i plików platformy) do programu obsługi indeksu struktury, po kilku próbach błędu / sukcesu właśnie zauważyłem, że wystarczy zmienić RewriteCond w .htaccess plik

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

powyższy warunek to "not found files" i "not found files", ok, a co jeśli po prostu usunie "not found" (! -d) i zakończy się czymś takim jak poniżej:

RewriteEngine on
RewriteBase /framework/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /framework/index.php [L,QSA]

U mnie zadziałało jak urok

AugustoM
źródło