web-dev-qa-db-fra.com

Conseils pour le débogage des règles de réécriture .htaccess

De nombreuses affiches ont des problèmes pour déboguer leurs déclarations RewriteRule et RewriteCond dans leurs fichiers .htaccess. La plupart d'entre eux utilisent un service d'hébergement partagé et n'ont donc pas accès à la configuration du serveur racine. Ils ne peuvent pas éviter d'utiliser des fichiers _.htaccess_ pour la réécriture et ne peuvent pas activer un RewriteLogLevel ", comme le suggèrent beaucoup de répondants. Il existe également de nombreux pièges et contraintes spécifiques à _.htaccess_ Configurer un test local La pile LAMP implique une courbe d’apprentissage trop longue pour la plupart.

Donc, voici ma question: comment recommanderions-nous qu'ils déboguent leurs règles elles-mêmes . Je fournis quelques suggestions ci-dessous. D'autres suggestions seraient appréciées.

  1. Comprenez que le moteur mod_rewrite parcourt les fichiers _.htaccess_. Le moteur exécute cette boucle:

    _do
      execute server and vhost rewrites (in the Apache Virtual Host Config)
      find the lowest "Per Dir" .htaccess file on the file path with rewrites enabled
      if found(.htaccess)
         execute .htaccess rewrites (in the user's directory)
    while rewrite occurred
    _

    Ainsi, vos règles seront exécutées à plusieurs reprises et si vous modifiez le chemin de l'URI, elles risquent éventuellement d'exécuter d'autres fichiers _.htaccess_ s'ils existent. Veillez donc à terminer cette boucle, si nécessaire, en ajoutant un RewriteCond supplémentaire pour arrêter le déclenchement des règles. Supprimez également tous les ensembles de règles __ de niveau inférieur _.htaccess_, sauf intention explicite d'utiliser des ensembles de règles à plusieurs niveaux.

  2. Assurez-vous que la syntaxe de chaque expression rationnelle est correcte en effectuant des tests sur un ensemble de modèles de test pour vous assurer que cette syntaxe est correcte et qu'elle correspond à vos attentes avec une gamme complète d'URI de test. Voir réponse ci-dessous pour plus de détails.

  3. Construisez vos règles de manière incrémentielle dans un répertoire de test. Vous pouvez utiliser le "fichier le plus profond _.htaccess_ de la fonction de chemin" pour configurer un répertoire de test séparé (arborescence) et déboguer rulesets ici sans bousiller vos règles principales et arrêter le fonctionnement de votre site. Vous devez les ajouter un par un, car c'est le seul moyen de localiser les échecs selon les règles individuelles.

  4. tilisez un stub de script factice pour vider le serveur et les variables d'environnement. (Voir Listing 2) Si votre application utilise, par exemple, _blog/index.php_, vous pouvez le copier dans _test/blog/index.php_ et l’utiliser pour tester les règles de votre blog dans le sous-répertoire test. Vous pouvez également utiliser des variables d'environnement pour vous assurer que le moteur de réécriture interprète correctement les chaînes de substitution, par exemple.

    _RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]
    _

    et recherchez ces variables REDIRECT _ * dans le vidage phpinfo. BTW, j'ai utilisé celui-ci et découvert sur mon site que je devais utiliser _%{ENV:DOCUMENT_ROOT_REAL}_ à la place. Dans le cas d'un redirecteur en boucle REDIRECT_REDIRECT _ * les variables répertorient le passage précédent. Etc..

  5. Assurez-vous que votre navigateur ne mord pas en mettant en cache les redirections 301 incorrectes. Voir réponse ci-dessous . Merci à lrich Palha pour cela.

  6. Le moteur de réécriture semble sensible aux règles en cascade d'un contexte _.htaccess_ (c'est-à-dire lorsqu'un RewriteRule donne lieu à une substitution et que cela relève de règles supplémentaires), car j'ai trouvé des bogues avec des sous-requêtes internes ( 1) , et incorrect PATH_INFO traitement qui peut souvent être évité en utilisant les drapeaux [NS], [L] et [PT].

Avez-vous d'autres commentaires ou suggestions?

Listing 1 - phpinfo

_<?php phpinfo(INFO_ENVIRONMENT|INFO_VARIABLES);
_
262
TerryE

Voici quelques conseils supplémentaires sur les règles de test susceptibles de faciliter le débogage des utilisateurs sur l'hébergement partagé.

1. Utiliser un agent faux utilisateur

Lors du test d'une nouvelle règle, ajoutez une condition pour ne l'exécuter qu'avec un agent utilisateur fake que vous utiliserez pour vos demandes. De cette façon, cela n'affectera personne d'autre sur votre site.

par exemple

#protect with a fake user agent
RewriteCond %{HTTP_USER_AGENT}  ^my-fake-user-agent$
#Here is the actual rule I am testing
RewriteCond %{HTTP_Host} !^www\.domain\.com$ [NC] 
RewriteRule ^ http://www.domain.com%{REQUEST_URI} [L,R=302] 

Si vous utilisez Firefox, vous pouvez utiliser le ser Agent Switcher pour créer la chaîne fictive d'agent d'utilisateur et le tester.

2. Ne pas utiliser 301 avant d'avoir terminé les tests

J'ai vu tellement de publications où les gens testent encore leurs règles et utilisent 301. NE PAS FAIRE .

Si vous n'utilisez pas la suggestion 1 sur votre site, non seulement vous, mais toute personne visitant votre site à ce moment-là sera affectée par le message 301.

N'oubliez pas qu'ils sont permanents et mis en cache de manière agressive par votre navigateur. Utilisez plutôt un 302 jusqu'à ce que vous soyez sûr, puis changez-le en 301.

3. N'oubliez pas que les 301 sont mis en cache de manière agressive dans votre navigateur.

Si votre règle ne fonctionne pas et qu'elle vous convient, et que vous n'utilisiez pas les suggestions 1 et 2, effectuez un nouveau test après avoir effacé le cache de votre navigateur ou pendant la navigation privée.

4. Utiliser un outil de capture HTTP

Utilisez un outil de capture HTTP tel que Fiddler pour voir le trafic HTTP réel entre votre navigateur et le serveur.

Tandis que d'autres pourraient dire que votre site does not look right, vous pourriez plutôt voir et signaler que all of the images, css and js are returning 404 errors, réduisant rapidement le problème.

Tandis que d'autres rapporteront que vous started at URL A and ended at URL C, vous pourrez voir qu'ils ont commencé à URL A, were 302 redirected to URL B and 301 redirected to URL C. Même si l’URL C était le but ultime, vous saurez que c’est mauvais pour le référencement et qu’il doit être corrigé.

Vous pourrez voir les en-têtes de cache définis côté serveur, relire les demandes, modifier les en-têtes de demande à tester ....


127
Ulrich Palha

Tests de réécriture .htaccess en ligne

J'ai trouvé this l'aide de Google dans RegEx, cela m'a fait gagner beaucoup de temps car je devais télécharger de nouveaux fichiers .htaccess à chaque fois que je fais une petite modification.

du site:

testeur htaccess

Pour tester vos règles de réécriture htaccess, remplissez simplement l'URL à laquelle vous appliquez les règles, placez le contenu de votre htaccess sur la zone de saisie plus grande et cliquez sur le bouton "Vérifier maintenant".

75
JCastell

N'oubliez pas que dans les fichiers .htaccess, c'est une URL relative qui correspond.

Dans un fichier .htaccess, le RewriteRule suivant ne correspondra jamais:

RewriteRule ^/(.*)     /something/$s
12
Krist van Besien

Assurez-vous que la syntaxe de chaque expression rationnelle est correcte

en testant par rapport à un ensemble de modèles de test afin de s’assurer qu’il s’agit d’une syntaxe valide et conforme à votre intention avec une gamme complète d’URI de test.

Voir regexpCheck.php ci-dessous pour un script simple que vous pouvez ajouter à un répertoire privé/test de votre site pour vous aider à le faire. J'ai gardé ce bref plutôt que joli. Il suffit de passer cela dans un fichier regexpCheck.php dans un répertoire de test pour l’utiliser sur votre site Web. Cela vous aidera à construire une expression rationnelle et à la tester à l'aide d'une liste de cas de test. J'utilise le moteur PHP PCRE ici, mais après avoir jeté un coup d'œil au code source Apache, celui-ci est identique à celui utilisé dans Apache. Il existe de nombreux HowTos et tutoriels qui fournissent des modèles et peuvent vous aider à développer vos compétences en expressions rationnelles.

Listing 1 - regexpCheck.php

<html><head><title>Regexp checker</title></head><body>
<?php 
    $a_pattern= isset($_POST['pattern']) ? $_POST['pattern'] : "";
    $a_ntests = isset($_POST['ntests']) ? $_POST['ntests'] : 1;
    $a_test   = isset($_POST['test']) ? $_POST['test'] : array();

    $res = array(); $maxM=-1; 
    foreach($a_test as $t ){
        $rtn = @preg_match('#'.$a_pattern.'#',$t,$m);
        if($rtn == 1){
            $maxM=max($maxM,count($m));
            $res[]=array_merge( array('matched'),  $m );
        } else {
            $res[]=array(($rtn === FALSE ? 'invalid' : 'non-matched'));
        }
    } 
?> <p>&nbsp; </p>
<form method="post" action="<?php echo $_SERVER['SCRIPT_NAME'];?>">
    <label for="pl">Regexp Pattern: </label>
    <input id="p" name="pattern" size="50" value="<?php echo htmlentities($a_pattern,ENT_QUOTES,"UTF-8");;?>" />
    <label for="n">&nbsp; &nbsp; Number of test vectors: </label>
    <input id="n" name="ntests"  size="3" value="<?php echo $a_ntests;?>"/>
    <input type="submit" name="go" value="OK"/><hr/><p>&nbsp;</p>
    <table><thead><tr><td><b>Test Vector</b></td><td>&nbsp; &nbsp; <b>Result</b></td>
<?php 
    for ( $i=0; $i<$maxM; $i++ ) echo "<td>&nbsp; &nbsp; <b>\$$i</b></td>";
    echo "</tr><tbody>\n";
    for( $i=0; $i<$a_ntests; $i++ ){
        echo '<tr><td>&nbsp;<input name="test[]" value="', 
            htmlentities($a_test[$i], ENT_QUOTES,"UTF-8"),'" /></td>';
        foreach ($res[$i] as $v) { echo '<td>&nbsp; &nbsp; ',htmlentities($v, ENT_QUOTES,"UTF-8"),'&nbsp; &nbsp; </td>';}
        echo "</tr>\n";
    }
?> </table></form></body></html>
8
TerryE

Assurez-vous d'utiliser le signe de pourcentage devant les variables, pas le signe du dollar.

C'est %{HTTP_Host}, pas${HTTP_Host}. Error_log ne contiendra rien, il n'y aura pas d'erreurs internes du serveur, votre expression rationnelle est toujours correcte, la règle ne correspondra tout simplement pas. C'est vraiment hideux si vous travaillez beaucoup avec Django/genshi et que vous avez ${} pour la substitution variable dans la mémoire musculaire.

6
Simon

Une de quelques heures que j'ai perdues:

Si vous avez appliqué tous ces conseils et que vous ne faites que 500 erreurs parce que vous n'avez pas accès au journal des erreurs du serveur, le problème ne réside peut-être pas dans le fichier .htaccess, mais dans les fichiers vers lesquels il est redirigé.

Après avoir résolu mon problème .htaccess, j'ai passé deux heures de plus à essayer de le réparer un peu plus, alors que j'avais tout simplement oublié certaines autorisations.

6
Ruben

Définissez les variables d'environnement et utilisez des en-têtes pour les recevoir:

Vous pouvez créer de nouvelles variables d'environnement avec les lignes RewriteRule, comme indiqué par l'OP:

RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]

Mais si vous ne pouvez pas faire fonctionner un script côté serveur, comment pouvez-vous alors lire cette variable d'environnement? Une solution consiste à définir un en-tête:

Header set TEST_FOOBAR "%{REDIRECT_TEST0}e"

La valeur accepte les spécificateurs de format , y compris le spécificateur %{NAME}e pour les variables d'environnement (n'oubliez pas la lettre e minuscule). Parfois, vous aurez besoin d'ajouter le préfixe REDIRECT_, mais je ne sais pas quand le préfixe est ajouté ou non.

6
Flimm

Si vous créez des redirections, testez avec curl pour éviter les problèmes de mise en cache du navigateur. Utilisez -I pour récupérer uniquement les en-têtes http. Utilisez -L pour suivre toutes les redirections.

4
flm

En ce qui concerne 4., vous devez toujours vous assurer que votre "stub de script factice" est bien l'URL cible après toute la réécriture, sinon vous ne verrez rien!

Un truc similaire/apparenté (voir cette question ) consiste à insérer une règle temporaire telle que:

RewriteRule (.*) /show.php?url=$1 [END]

show.php est un script très simple qui affiche simplement ses paramètres $_GET (vous pouvez également afficher les variables d'environnement, si vous le souhaitez).

Cela arrêtera la réécriture au point où vous l'insérez dans l'ensemble de règles, un peu comme un point d'arrêt dans un débogueur.

Si vous utilisez Apache <2.3.9, vous devrez utiliser [L] plutôt que [END], et vous pourrez alors besoin d'ajouter:

RewriteRule ^show.php$ - [L]

Au sommet de votre jeu de règles, si l'URL /show.php est elle-même en cours de réécriture.

3
Doin

J'ai trouvé cette question en essayant de déboguer mes problèmes mod_rewrite, et elle contient certainement des conseils utiles. Mais au bout du compte, le plus important est de vous assurer que votre syntaxe regex est correcte. En raison de problèmes liés à ma propre syntaxe RE, l'installation du script regexpCheck.php n'était pas une option viable.

Mais comme Apache utilise des expressions régulières (PCRE) compatibles avec Perl, tout outil d'aide à l'écriture de fichiers PCRE devrait aider. J'ai déjà utilisé l'outil REGEXPlanet avec Java et les RE Javascript, et je suis heureux de constater qu'ils prennent également en charge Perl.

Il vous suffit de taper votre expression régulière et un ou plusieurs exemples d’URL, et il vous dira si la regex correspond (un "1" dans la colonne "~ =") et, le cas échéant, tous les groupes correspondants (les numéros dans le "fractionné" colonne correspondra aux nombres attendus par Apache, par exemple $ 1, $ 2, etc.) pour chaque URL. Ils prétendent que le support PCRE est "en version bêta", mais c’était juste ce dont j'avais besoin pour résoudre mes problèmes de syntaxe.

http://www.regexplanet.com/advanced/Perl/index.html

J'aurais simplement ajouté un commentaire à une réponse existante mais ma réputation n'est pas encore à ce niveau. J'espère que ça aide quelqu'un.

3
Lambart

Certaines erreurs que j'ai observées se produisent lors de l'écriture _.htaccess_

L'utilisation répétée de ^(.*)$ dans plusieurs règles, l'utilisation de ^(.*)$ rend les autres règles impuissantes dans la plupart des cas, car elles correspondent à toutes les URL d'un seul hit.

Donc, si nous utilisons une règle pour cette URL _sapmle/url_, elle utilisera également cette URL _sapmle/url/string_.


[L] Le drapeau doit être utilisé pour garantir le traitement de notre règle.


Devrait savoir sur:

Différence entre% n et $ n

_%n_ correspond à _%{RewriteCond}_ partie et _$n_ correspond à _%{RewriteRule}_ partie.

fonctionnement de RewriteBase

La directive RewriteBase spécifie le préfixe de l'URL à utiliser pour les directives RewriteRule par répertoire (htaccess) qui se substituent à un chemin relatif.

Cette directive est obligatoire lorsque vous utilisez un chemin relatif dans une substitution dans un contexte par répertoire (htaccess), sauf si l'une des conditions suivantes est remplie:

La requête d'origine et la substitution se trouvent sous DocumentRoot (par opposition à accessible par d'autres moyens, tels que Alias). Le chemin du système de fichiers vers le répertoire contenant RewriteRule, suffixé par la substitution relative, est également valide en tant que chemin d’URL sur le serveur (ce qui est rare). Dans Apache HTTP Server 2.4.16 et versions ultérieures, cette directive peut être omise lorsque la demande est mappée via Alias ​​ou mod_userdir.

2
Abhishek Gurjar

Si vous envisagez d'écrire plus d'une ligne de règles dans .htacesss,
ne songez même pas à essayer une de ces méthodes de correctif pour le déboguer.

J'ai perdu des jours à définir plusieurs règles, sans les commentaires des journaux, pour finalement abandonner.
J'ai Apache sur mon PC, j'ai copié tout le site sur son disque dur, et tout le jeu de règles a été trié très rapidement, en utilisant les journaux.
Ensuite, j'ai passé en revue mes anciennes règles, qui fonctionnaient bien. J'ai vu qu'ils ne faisaient pas vraiment ce qui était désiré. Une bombe à retardement, étant donné une adresse légèrement différente.

Il y a tellement de chutes dans les règles de réécriture que ce n'est pas du tout une logique.
Apache est prêt à fonctionner en 10 minutes: 10 Mo, bonne licence, * NIX/WIN/MAC prêt, même sans installation.
Vérifiez également les lignes d’en-tête de votre serveur et obtenez la même version d’Apache à partir de leur archive, si elle est ancienne. Mon OP est toujours sur 2.0; beaucoup de choses ne sont pas supportées.

1
papo

(Similaire à l'idée de Doin) Pour montrer ce qui est mis en correspondance, j'utilise ce code

$keys = array_keys($_GET);
foreach($keys as $i=>$key){
    echo "$i => $key <br>";
}

Enregistrez-le sur r.php à la racine du serveur puis faites quelques tests dans .htaccess
Par exemple, je souhaite faire correspondre les URL qui ne commencent pas par un préfixe de langue.

RewriteRule ^(?!(en|de)/)(.*)$ /r.php?$1&$2 [L] #$1&$2&...
RewriteRule ^(.*)$ /r.php?nomatch [L] #report nomatch and exit
0
UnLoCo

Je vais laisser cela ici, détail peut-être évident, mais je me suis cogné la tête pendant des heures: soyez prudent en utilisant %{REQUEST_URI} parce que @ Krist van Besien dans sa réponse, vous avez tout à fait raison, mais pas pour la chaîne REQUEST_URI , car la sortie de ce TestString commence par un /. Alors prenez soin de:

RewriteCond %{REQUEST_URI} ^/assets/$  
                            ^
                            | check this pesky fella right here if missing
0
Gruber