2009-12-08 2 views
15

sto discutendo di routing le mie richieste con una delle due opzioni:Mod-Rewrite o router PHP?

Opzione 1: semplice percorso di acquisizione con Mod-Rewrite e imbuto scritto $_GET percorso a index.php per il carico ...

#default routing 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule ^blog/([0-9]+)?$ index.php?rt=blog&params=$1 [L,QSA] 
// ..more custom routes, and then a default route 
RewriteRule ^([A-Za-z]+)/([A-Za-z]+)/(.*)?$ index.php?rt=$1/$2&params=$3 [L,QSA] 

opzione 2: semplicemente instradare le richieste al front controller, e creare una classe PHP routing per gestire il routing ...

#default routing 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule ^(.*)$ index.php?rt=$1 [L,QSA] 

/* --- on front controller, process $_GET['rt'] --- */ 

alla fine della giornata, che sarà correre più veloce, più facile da fissare, ed essere più facile mantenere?

altre idee?

NOTA: non utilizzo un framework noto. Sto costruendo il mio pattern MVC per impararlo.

+0

che cosa si intende per sicuro? –

+0

beh, ho appena pensato che ci siano misure da prendere per essere sicuro che il mio sistema/framework/etc non abbia aperture che non conosco. solo supponendo di essere più ingenuo di quanto mi auguro – johnnietheblack

+0

Apprezzo i tuoi sforzi. –

risposta

16

Di solito in quadri MVC, questo genere di cose viene solitamente gestito meglio da un controller anteriore (denominato index.php o simile). Usa mod_rewrite per nascondere index.php da tutti gli URL in modo che i tuoi utenti vedano dei bei percorsi puliti.

È anche molto più semplice da gestire in PHP rispetto alle direttive di riscrittura di Apache. PHP è molto più flessibile e più facile da scrivere/capire. Non sono sicuro di aver mai visto mod_rewrite usato come unico motore di routing per qualsiasi framework web là fuori, ora che ci penso.

Il tuo secondo snip di codice è la via da seguire per le tue direttive di riscrittura.

+1

Definitivamente d'accordo. Anche più regole per eseguire lo stesso compito di base saranno difficili da gestire e capire dopo un po '. Se guardi uno dei principali framework php (ok forse non ne uso solo Symfony e Zend, hehe) usano solo riscrittura per ottenere il "pretty url" al controller, quindi implementano il routing internamente in una classe di routing di somesort a decifrare i parametri attuali in base a tutti i tipi di regole complesse. Ho seguito questo approccio se fossi in te. – prodigitalson

+4

Sono d'accordo. I siti su cui ho lavorato con oltre 30 percorsi di riscrittura personalizzati sono sempre stati un problema. PS: aggiungi del routing per consentire al server Web di gestire le immagini, js e css. Vedi esempio di framework zend htaccess - http://framework.zend.com/wiki/display/ZFDEV/Configuring+Your+URL+Rewriter – mozillalives

+0

@MarcW Mi piace la tua risposta. Forse potresti raccogliere 300 punti dando la mia domanda al buon vecchio college? http://stackoverflow.com/questions/42172228/is-this-how-an-mvc-router-class-typically-works –

0

Anch'io sono in procinto di creare un sistema LAMP MVC da zero.

MVC Router Class Question

prestazioni

Dopo aver creato uno script di shell bash per compilare Apache 2.4.x dai sorgenti, si nota che una libreria per espressioni regolari compatibili Perl viene cotto nel processo. Ogni volta che deve essere usato il codice dell'espressione regolare, la risposta del server http sarà più lenta. Quindi, l'opzione numero uno è un no go se la prestazione è la tua preoccupazione. C'è un costo per l'analisi coinvolta con le espressioni regolari. Il server Web Apache prende in prestito la logica per le espressioni regolari. Non è un codice di casa sviluppato da Apaches.

Security

La sicurezza è una questione diversa. Innanzitutto, nulla sulla riscrittura degli URL li rende sicuri. È semplice sicurezza attraverso l'oscurità e fare apparire le cose belle dal lato del cliente. Di tanto in tanto, i buchi di sicurezza si trovano nel codice del motore di espressioni regolari. Quindi, in termini di sicurezza reale, ti ritroverai nella stessa posizione di base in cui ti troverei senza alcuna riscrittura: le persone oi robot possono inviare cose cattive al tuo server e hai bisogno di un modo per filtrare e convalidare l'input in modo sistematico. Assicurati di filtrare e convalidare tutti gli input, specialmente ogni parte della stringa di query riscritta che intendi utilizzare.

Pertanto, l'opzione numero uno presenta un'interfaccia più pulita (INPUT_GET/$_GET) per l'avvio delle attività di sicurezza. L'opzione numero due richiede (se si sta cercando di essere approfonditi) di filtrare e convalidare l'intera stringa come primo passo. Il secondo passo (in generale) sarà quello di separare ed estrarre ciò che speri di raccogliere dalla stringa più grande.

Anche in questo caso, è necessario filtrare e convalidare ogni parte della stringa. Quindi, mentre forse è più gestibile (più facile, conveniente) filtrare/convalidare/spezzare/estrarre/la stringa più grande in PHP (diciamo, con un metodo in una classe di sicurezza di qualche tipo), devi comunque lavorare per ogni pezzo , per ogni richiesta L'opzione numero uno evita di dover spezzare la stringa più grande per il costo dell'esecuzione del motore regex a ogni richiesta. Ma, per la maggior parte, puoi iniziare a filtrare e convalidare gli elementi che ti aspetti di ricevere in INPUT_GET o $_GET.

Si noti, tuttavia, che l'opzione 1 è principalmente per le persone che capiscono veramente come funzionano le espressioni regolari e come questo si applica ai potenziali URL che il server può ricevere. Se hai bisogno di più di uno RewriteRule, è possibile che tu possa avere qualcosa del genere (o altri motivi) entrare nel server.

index.php?0=model 

index.php?0=model&1=method 

index.php?0=model&1=method&2=methodArgs 

In questo modo è più facile filtrare e convalidare gli input. Si noti, tuttavia, che l'ultima riga implica che è ancora necessario eseguire alcune suddivisioni in linea e ulteriori filtri/convalida (ma ciò potrebbe non essere necessario per ogni richiesta, come nel caso dell'opzione numero 1).

codice di esempio: Ottenere parametri URL utilizzando l'opzione 2 (Start in basso!)

Nota: Queste sono solo alcune cose da considerare, non "il" modo per farlo.

const QS_ARRAY_LIMIT = 3; 

private function getPairValue($delimiter, $string) 
{ 
    return explode('$delimiter', $string)[1]; //Get the value for a pair. 
} 

private function isMultiValuedQueryString() 
{ 
    return (mb_strpos($this->queryStr, '&', 0, 'UTF-8') > 2); 
} 

private function getAllowedPairs($argsStr) 
{ 
    $pairs = explode('&', $argsStr); 
    $numPairs = count($pairs); 

    if($numPairs > self::QS_ARRAY_LIMIT) 
    { 
     throw new SecurityException("Too many query string pairs ({$numPairs}) submitted to the router.\n"); 
    } 

    return $pairs; 
} 

private function isQueryStrPair($pair) 
{ 
    $equalPos = null; 
    $pairLength = mb_strlen($pair, 'UTF-8'); 

    if($pairLength < 3) 
    { 
     throw new SecurityException("Query string pair is too short: Length: {$pairLength}!, Suspect: {$pair}\n"); //Sends to '/' 
    } 

    $equalPos = mb_strpos($pair, '=', 0, 'UTF-8'); 

    if($equalPos === 0) //The first position. 
    { 
     throw new SecurityException("Query sting pair cannot *start* with an equal sign (=): Suspect: {$pair}\n"); //Sends to '/' 
    } 

    if($equalPos === ($pairLength - 1)) //The last position. 
    { 
     throw new SecurityException("Query sting pair cannot *end* with an equal sign (=): Suspect: {$pair}\n"); //Sends to '/' 
    } 

    return true; 
} 

private function getQueryStringArgs($url) 
{ 
    $delimiter = '?'; 

    if(mb_strpos($url, $delimiter, 0, 'UTF-8') > 0) 
    { 
     return $this->getPairValue($delimiter, $url); 
    } 

    throw new RuntimeException("Malformed URL passed to query string parser."); 
} 

private function associateArgPairs(array $argPairs, array $values) 
{ 
    $i = 0; 

    foreach($argPairs as $key => &value) 
    { 
     if(isset($values[$i])) 
     { 
      $value[$key] = $values[$i]; 
      ++$i; 
     } 
    } 

    return $argPairs; 
} 

private function getQueryStrValues($url) 
{ 
    $delimiter = '='; 
    $argPairs = ['model' => null, 'method' => null, 'methodArgs' => null] 
    $inputValues = []; 
    // ================================================= 
    // Valid query strings might look like (amongst many combinations): 
    // 
    // index.php?arg1=foo&agr2=bar&arg3=/baz/bang/boom 
    // 
    // Or, just one pair with no ampersand,'&'. 
    // 
    // index.php?arg1=foo 
    // ================================================== 

    // Get everything after the question mark, '?'. 
    $queryStringArgsStr = $this->getQueryStringArgs($url); 

    if($this->isMultiValuedQueryString($queryStringArgsStr)) //Check if '&' exists. 
    { 
     foreach($this->getAllowedPairs($queryStringArgsStr) as $pair) 
     { 
      if($this->isQueryStrPair($pair)) 
      { 
       //Get the value for each pair., using '=' as the string delimiter. 
       $inputValues[] = $this->getPairValue($delimiter, $pair); 
      } 
     } 
    } 
    else 
    {  
     if($this->isQueryStrPair($queryStringArgsStr)) 
     { 
      $inputValues[] = $this->getPairValue($delimiter, $queryStringArgsStr); //Get the value for each pair. 
     } 
    } 

    return $this->associateArgPairs($argPairs, $inputValues); 

    //Remember, you will still need to split up $argPairs[$methodArgs] if necessary. 
    //With option #1, you could start closer to this point, 
    //and hence filter and validate sooner. 
} 

Sommario

Se la sicurezza è la preoccupazione principale (vale a dire, l'interfaccia nel vostro sistema di sicurezza), stringere i denti e utilizzare l'opzione numero uno. Apprendimento mod_rewrite e riscrittura degli URL ti rende piuttosto potente. Perché lasciare quel potere sul tavolo? Apache è uno strano animale quando si tratta di configurarlo. Ma, se capisci gli URL e le espressioni regolari, io dico uomo/donna e me ne vado. :-) Se la velocità, la comprensione e la facilità d'uso sono le tue preoccupazioni principali, scegli l'opzione numero uno. Ci sono fanatici che vogliono che tutto sia codificato in PHP, ma devi giudicare da solo quali sono i pro ei contro di entrambe le situazioni.

Aggiornamento: Il mio male. Questo codice funzionerebbe in realtà meglio per l'opzione numero 1. Nell'opzione numero 2, 1 = blah, dove blah sarebbe qualcosa come /trt/43ff/3335/f/3/fr3r/ o qualsiasi altra cosa. Non dovrai cercare e commerciali.

PHP: filter_inpur_array(), (use INPUT_GET)

PHP: Superglobals

PHP: explode()

PHP: foreach (array_expression as $key => $value)

PHP: Multibtye String Functions