Puncte:1

.htaccess mod_rewrite nu prinde toate RewriteRules

drapel de

Există o aplicație PHP cu un router PHP ca punct de intrare pentru toate solicitările plasate în interiorul index.php. Încerc să scriu un fișier .htaccess pentru a redirecționa fiecare cerere către index.php, cu excepția solicitărilor API și a resurselor de proiectare. Deci încerc să obțin următorul comportament:

  1. example.com/api/v1/* ar trebui să servească api_v1.php
  2. example.com/any_path/resource.css => ar trebui să servească resursă.css dacă există (sunt permise mai multe extensii; .css este doar un exemplu)
  3. servi index.php pentru orice nu s-a încadrat în condițiile de mai sus

Dat fiind .htaccess este evaluat de sus în jos, de la condițiile particulare la cele generale și acel steag [L] ar rupe execuția dacă ceva se potrivea, am reușit să vin cu următoarele .htaccess:

RewriteEngine Pornit

# Preveniți redirecționarea 301 cu bară oblică atunci când folderul există și nu are atașat o bară oblică
# Aceasta nu este o problemă de securitate aici, deoarece este folosit un router PHP și toate căile sunt redirecționate
DirectorySlash Off

#1. Rescrieți pentru adresa URL API
RewriteRule ^api/v1/(.*)$ api_v1.php [L,NC]

#2. Rescrieți în index.php, cu excepția fișierelor design/document/favicon/roboți care există
RewriteCond %{REQUEST_URI} !.(css|js|png|jpg|jpeg|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$
RewriteCond %{REQUEST_URI} !^(roboți\.txt|favicon\.ico)$ [SAU]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L]

#3. Rescrie orice altceva
RewriteRule ^(.*)$ index.php [L]

Folosind codul de mai sus, se pare că accesând example.com/api/v1/ nu execută api_v1.php. În schimb, ar continua și s-ar executa index.php

example.com/api/v1/ ar funcționa numai dacă elimin toate condițiile după linia 8.

Ce greșesc aici?

drapel kz
Este puțin neclar exact ce încerci să faci.Ar trebui să fie rescrise anumite solicitări în `index.php` chiar dacă există ca fișier fizic, dar nu unul dintre tipurile de fișiere menționate? Solicitările de resurse (`.css`, `.jpg`, etc.) ar trebui să fie rescrise în continuare în `index.php` dacă nu există? (adică aveți adrese URL legitime care au o „extensie de fișier” ca aceasta?)
caffeine avatar
drapel de
@MrWhite Da, dacă nu este găsit un fișier .css, rescrieți în index.php, astfel încât să pot gestiona corect eroarea 404 de la index.php. Dacă există fișierul .css, serviți-l, altfel rescrieți în index.php
drapel kz
Dar ce se întâmplă cu tipurile de fișiere pe care nu le-ați declarat în mod explicit? Acestea ar trebui direcționate prin `index.php` indiferent dacă există sau nu? (Trebuie să indicați în mod explicit o listă de tipuri de fișiere cunoscute?)
caffeine avatar
drapel de
Da, orice NU este în acea listă, indiferent dacă există sau nu, ar trebui rescris în index.php. Singura complicație aici este că rescriu și în index.php pentru numele fișierelor care sunt în listă, dar NU există pe server. Practic, încerc să servesc direct fișiere .css dacă acestea există, altfel rescriu totul în index.php (referindu-ne la condițiile #2 și #3)
drapel kz
Mi-am actualizat răspunsul cu o soluție completă bazată pe comentariile dvs.
Puncte:1
drapel kz

se pare că accesarea site.com/api/v1/ nu execută api_v1.php. În schimb, ar continua și ar executa index.php

Da, pentru că prima regulă rescrie cererea către api_v1.php și asta ajunge să fie rescris index.php prin a doua regulă (pentru că php nu se află în lista extensiilor excluse din prima condiție, a doua condiție este de asemenea reușită, așa că a treia condiție nu este procesată - vezi mai jos) în timpul celei de-a doua treceri a motorului de rescrire. Într-o director context (ex. .htaccess) cel L flag nu oprește toate procesările, ci doar oprește trecerea curentului prin motorul de rescrire. Motorul de rescrire trece în buclă până când adresa URL trece neschimbată.

Puteți rezolva acest lucru pe Apache 2.4 folosind Sfârşit steag, în loc de L, pe prima regulă pentru a opri toate procesările de către motorul de rescriere.

De exemplu:

RewriteRule ^api/v1/ api_v1.php [NC,END]

(Am eliminat trailingul (.*)$ pe regex, deoarece nu este necesar aici și face ca regex-ul să fie marginal mai puțin eficient.)

Cu toate acestea, faptul că o cerere pentru un existent .php fișierul este rescris de regulile tale ulterioare demonstrează cu adevărat că a doua și a treia regulă nu par să funcționeze așa cum a fost prevăzut...

#2. Rescrieți în index.php, cu excepția fișierelor design/document/favicon/roboți care există
RewriteCond %{REQUEST_URI} !.(css|js|png|jpg|jpeg|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$
RewriteCond %{REQUEST_URI} !^(roboți\.txt|favicon\.ico)$ [SAU]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L]

#3. Rescrie orice altceva
RewriteRule ^(.*)$ index.php [L]

Dacă solicitați ceva.php apoi primul condiție are succes (pentru că .php este nu incluse în listă). A doua condiție este de asemenea reușită (nu este robots.txt sau favicon.ico). Deoarece a doua condiție este în mod explicit OR cu a treia condiție, a treia condiție nu este procesată.Toate condițiile sunt reușite și cererea este rescrisă la index.php (indiferent daca ceva.php există sau nu).

Dacă, pe de altă parte, solicitați resursă.css apoi primul condiție eșuează (pentru că are un .css extensie). Deoarece această condiție este implicit AND'd, nu sunt procesate alte condiții și regula nu este declanșată. A treia regulă se rescrie apoi necondiționat resursă.css la index.php, indiferent dacă există sau nu!

Deci, acest lucru nu verifică dacă o resursă solicitată (css, jpg, etc.) „există” așa cum ar părea să implice comentariul precedent. A treia condiție (care verifică că cererea nu se mapează la un fișier) este procesată numai atunci când condiția anterioară OR eșuează ȘI prima condiție are succes. Cu alte cuvinte, a treia condiție este procesată doar atunci când solicitați /roboți.txt - ceea ce sunt sigur că nu este intenția ta.

Cu alte cuvinte, regulile #2 și #3 (în ciuda complexității lor aparente) ar părea să se rescrie destul de mult Tot la index.php.

Soluție completă

Pe baza comentariilor dvs. suplimentare:

  • Pentru un subset de tipuri de fișiere, serviți resursa - dacă aceasta există. Dacă resursa nu există, trimiteți cererea către index.php.

  • Pentru alte tipuri de fișiere, trimiteți solicitarea la index.php, indiferent dacă resursa respectivă există sau nu.

  • Câteva solicitări (ex. /roboți.txt și /favicon.ico) nu trebuie trimis la index.php.

Încercați următoarele:

# Preveniți redirecționarea 301 cu bară oblică atunci când folderul există și nu are atașat o bară oblică
# Aceasta nu este o problemă de securitate aici, deoarece este folosit un router PHP și toate căile sunt redirecționate
DirectorySlash Off

# Deoarece „DirectorySlash Off” este setat, asigurați-vă că listările de directoare mod_auotindex sunt dezactivate
Opțiuni -Indici

RewriteEngine Pornit

#1. Rescrieți pentru adresa URL API
RewriteRule ^api/v1/ api_v1.php [NC,END]

#2. Adresele URL/fișierele cunoscute sunt difuzate direct
RewriteRule ^(index\.php|roboți\.txt|favicon\.ico)$ - [END]

#3.Anumite tipuri de fișiere (resurse) sunt servite direct dacă există
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule \.(css|js|png|jpe?g|bmp|gif|ttf|eot|svg|woff|woff2|ico|webp|pdf)$ - [END]

#4. Rescrie totul
RewriteRule ^ index.php [END]

Regulile se termină mai devreme pentru orice trebuie servit direct, așa că trebuie doar să rescriem index.php o dată în ultima regulă.

Rețineți că am inclus index.php în regula #2. Aceasta este o optimizare, deși nu este strict necesară dacă se utilizează Sfârşit steag (spre deosebire de L) pe ultima regulă.

Opțional, puteți alege să redirecționați oricare direct solicită să index.php înapoi la rădăcină (pentru canonizarea URL-ului pentru motoarele de căutare). Asta pentru orice eventualitate /index.php este expus (sau ghicit) utilizatorului final.

De exemplu, adăugați următoarele după prima regulă pentru API:

#1.5 Redirecționați solicitările directe către „/index.php” înapoi la „/” (rădăcină)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php$ / [R=301,L]

The condiție care verifică împotriva REDIRECT_STATUS variabila de mediu este necesară pentru a preveni o buclă de redirecționare - pentru a evita redirecționarea URL-ului rescris. (Deși, din nou, acest lucru nu este strict necesar dacă se utilizează Sfârşit steag pe regula ultima/rescrie.)

caffeine avatar
drapel de
Mulțumesc pentru explicațiile ample. Acest lucru a rezolvat cu siguranță problema mea și a adus câteva informații foarte utile pe acest subiect.
Puncte:0
drapel ng

Încercați să plasați o condiție de rescriere înaintea fiecărei reguli și apoi încălcați regula. Cu alte cuvinte, fiecare condiție trebuie să aibă propria sa regulă.

condiție -> regulă
condiție -> regulă
...

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.