Réécriture d'URL avec PHP

139

J'ai une URL qui ressemble à:

url.com/picture.php?id=51

Comment convertirais-je cette URL en:

picture.php/Some-text-goes-here/51

Je pense que WordPress fait de même.

Comment créer des URL conviviales en PHP?

Jazerix
la source
1
Vous avez besoin de beaucoup peaufiner la configuration des fichiers Apache ... donnez un exemple de ce dont vous avez réellement besoin? Comment insérez-vous ce texte? est-il prédéfini ou est-il créé dynamiquement? donnez autant d'informations que vous pouvez pour obtenir la bonne réponse ... et oui, l'url pourrait être un peu plus descriptive :)
user123_456
1
Pourquoi PHP? Apache mod_rewriteest tout ce dont vous avez besoin pour cela et il y a beaucoup de questions à ce sujet ici sur SO. Et si vous «pensez» que wordpress fait la même chose, pourquoi ne pas le chercher simplement ? ;)
nietonfir
Pourquoi fais-tu ça? L'objectif est-il de réécrire les URL, si c'est le cas, utilisez .htaccess ou quelque chose de similaire. Si le but est simplement de changer la chaîne, $ _GET obtient uniquement la chaîne de requête?
adeneo
Le texte serait le titre d'une image et ensuite l'identifiant après la barre oblique :) Je vais devoir regarder ce que mod_rewrite d'Apache a à offrir. J'espère que ce n'est pas trop difficile: D
Jazerix

Réponses:

194

Vous pouvez essentiellement le faire de 2 façons:

La route .htaccess avec mod_rewrite

Ajoutez un fichier appelé .htaccessdans votre dossier racine et ajoutez quelque chose comme ceci:

RewriteEngine on
RewriteRule ^/?Some-text-goes-here/([0-9]+)$ /picture.php?id=$1

Cela dira à Apache d'activer mod_rewrite pour ce dossier, et s'il lui est demandé une URL correspondant à l'expression régulière, il la réécrit en interne à ce que vous voulez, sans que l'utilisateur final ne le voie. Facile, mais inflexible, donc si vous avez besoin de plus de puissance:

La route PHP

Mettez plutôt ce qui suit dans votre .htaccess: (notez la barre oblique)

FallbackResource /index.php

Cela lui dira d'exécuter votre index.phppour tous les fichiers qu'il ne peut normalement pas trouver sur votre site. Dans là, vous pouvez alors par exemple:

$path = ltrim($_SERVER['REQUEST_URI'], '/');    // Trim leading slash(es)
$elements = explode('/', $path);                // Split path on slashes
if(empty($elements[0])) {                       // No path elements means home
    ShowHomepage();
} else switch(array_shift($elements))             // Pop off first item and switch
{
    case 'Some-text-goes-here':
        ShowPicture($elements); // passes rest of parameters to internal function
        break;
    case 'more':
        ...
    default:
        header('HTTP/1.1 404 Not Found');
        Show404Error();
}

C'est ainsi que font les grands sites et les systèmes CMS, car cela permet beaucoup plus de flexibilité dans l'analyse des URL, des URL dépendantes de la configuration et de la base de données, etc. Pour une utilisation sporadique, les règles de réécriture codées en dur fonctionneront .htaccessbien.

Niels Keurentjes
la source
Au lieu de le coder en dur, vous pouvez simplement utiliser regex pour ignorer complètement la chaîne. En d'autres termes, la seule chose qui compte est la partie ID. Aller à picture.php/invalid-text/51redirigerait également vers le même endroit. Vous pouvez également ajouter une vérification pour voir si la chaîne est correcte et sinon, rediriger à nouveau vers l'emplacement correct. C'est ainsi que je l'ai fait sur l'un de mes sites en utilisant htaccess.
Mike
7
Pratique pour les petits sites, mais pas vraiment pratique si vous devez analyser /blog/25ainsi que /picture/51et /download/684. En outre, cela est considéré comme une très mauvaise pratique (et vous pénalisera Google PR!) Si toutes les URL générées aléatoirement ne renvoient pas correctement 404.
Niels Keurentjes
5
au moins sur mon système, c'était FallbackResource /index.php(notez la barre oblique principale)
Jack James
4
@olli: le commentaire de mauvaise pratique fait spécifiquement référence à "ne pas renvoyer de 404 pour des URL inexistantes", ce qui est résolu par la solution dans la réponse elle-même. En ce qui concerne la première question - FallbackResourcene démarre que pour les fichiers qui n'existent pas réellement sur le système de fichiers, d'où le repli . Donc, si vous avez un fichier /static/styles.csset que vous vous y référez, http://mydomain.tld/static/styles.cssle code n'est jamais exécuté, ce qui le fait fonctionner comme prévu et prévu de manière transparente.
Niels Keurentjes
vous devriez utiliser à la if($elements[0] === NULL)place, car $elementscela retournera toujours un compte de un, même s'il est vide.
fireinspace
57

Si vous souhaitez uniquement modifier l'itinéraire pour picture.phpajouter une règle de réécriture, cela .htaccessrépondra à vos besoins, mais si vous voulez la réécriture d'URL comme dans Wordpress, PHP est le chemin. Voici un exemple simple pour commencer.

Structure des dossiers

Il y a deux fichiers nécessaires dans le dossier racine .htaccesset index.php, et il serait bon de placer le reste des .phpfichiers dans un dossier séparé, comme inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

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

Ce fichier a quatre directives:

  1. RewriteEngine - activer le moteur de réécriture
  2. RewriteRule- refuser l'accès à tous les fichiers du inc/dossier, rediriger tout appel vers ce dossier versindex.php
  3. RewriteCond - permettre un accès direct à tous les autres fichiers (comme les images, css ou scripts)
  4. RewriteRule - rediriger n'importe quoi d'autre vers index.php

index.php

Puisque tout est maintenant redirigé vers index.php, il sera déterminé si l'url est correcte, tous les paramètres sont présents et si le type de paramètres est correct.

Pour tester l'url, nous avons besoin d'un ensemble de règles, et le meilleur outil pour cela est une expression régulière. En utilisant des expressions régulières, nous tuerons deux mouches d'un seul coup. Url, pour réussir ce test doit avoir tous les paramètres requis qui sont testés sur les caractères autorisés. Voici quelques exemples de règles.

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

La prochaine étape consiste à préparer la requête uri.

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

Maintenant que nous avons la requête uri, la dernière étape consiste à tester uri sur les règles des expressions régulières.

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
    }
}

Une correspondance réussie, puisque nous utilisons des sous-modèles nommés dans regex, remplira le $paramstableau presque de la même manière que PHP remplit le $_GETtableau. Cependant, lors de l'utilisation d'une URL dynamique, le $_GETtableau est rempli sans aucune vérification des paramètres.

    / image / un peu + texte / 51

    Tableau
    (
        [0] => / image / du texte / 51
        [text] => du texte
        [1] => du texte
        [id] => 51
        [2] => 51
    )

    picture.php? text = certains + texte & id = 51

    Tableau
    (
        [text] => du texte
        [id] => 51
    )

Ces quelques lignes de code et une connaissance de base des expressions régulières suffisent pour commencer à construire un système de routage solide.

Source complète

define( 'INCLUDE_DIR', dirname( __FILE__ ) . '/inc/' );

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
        include( INCLUDE_DIR . $action . '.php' );

        // exit to avoid the 404 message 
        exit();
    }
}

// nothing is found so handle the 404 error
include( INCLUDE_DIR . '404.php' );
Danijel
la source
2
Comment lisez-vous les paramètres? Cela ne fonctionne pas avec $ post_id = htmlentities ($ _ GET ['post']);
andrebruton
@Danijel Puis-je avoir un code source complet? J'ai essayé le code ci-dessus mais seul le texte était sorti, CSS sans effet. Je vous remercie.
4 Leave Cover
6

c'est un fichier .htaccess qui transmet presque tout à index.php

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !-l
RewriteCond %{REQUEST_FILENAME} !\.(ico|css|png|jpg|gif|js)$ [NC]
# otherwise forward it to index.php
RewriteRule . index.php

alors c'est à vous d'analyser $ _SERVER ["REQUEST_URI"] et de vous diriger vers picture.php ou autre

Luca Rocchi
la source
8
Apache a introduit la FallbackResourcedirective il y a quelques versions majeures, qui est désormais le moyen préféré d'implémenter ce comportement à un coût de performance inférieur car il n'a pas besoin de lancer tout le moteur de réécriture. Documentation ici . Vos règles sont également imparfaites car vous ne référencez pas les répertoires ( !-d) et tous les filtres d'extension sont obsolètes - ils -fdevraient déjà les attraper.
Niels Keurentjes
5

PHP n'est pas ce que vous recherchez, consultez mod_rewrite

Rauchmelder
la source
cela affectera-t-il toutes les URL?
Jazerix
@Jazerix Cela dépend des règles que vous définissez.
nietonfir
2

Bien que déjà répondu, et l'intention de l'auteur est de créer une application de type contrôleur frontal, mais je publie une règle littérale pour le problème posé. si quelqu'un a le problème pour le même.

RewriteEngine On
RewriteRule ^([^/]+)/([^/]+)/([\d]+)$ $1?id=$3 [L]

Ci-dessus devrait fonctionner pour l'URL picture.php/Some-text-goes-here/51. sans utiliser index.php comme application de redirection.

Abhishek Gurjar
la source
J'ai besoin de savoir quelle URL nous devons écrire en href? parce que je reçois 404
questions