Bonjour,

Je viens de faire un tour du web mais les 3/4 des solutions sont en anglais...

Mon site est basé sur un MVC -> Controller / Action / Paramètres (si besoin dans actions)

Mes URL ont donc cette forme :
http://www.monsite.com/Controller/Action/(_paramètres_au_besoin_)/

Mon fichier htaccess est donc écrit de la façon :

RewriteEngine on
RewriteRule (.*) public/$1 [L]
RewriteRule ^(^/]*)/(^/]*)\/$ url.php?controller=$2action=$1 [QSA,L]

J'ai un formulaire :

<form method="GET" action="http://www.monsite.com/controller/action/">
    <input type="text" name="id" />
    <button type="submit">Ajouter</button>
</form>

Donc actuellement quand je valide mon formulaire je suis dirigé vers la page -> http:/www.monsite.com/controller/action/?id=id_saisi

Ce que je souhaite avoir au final : http://www.monsite.com/controller/action/id_saisi/

Tout ce que j'ai pu voir consiste à rajouter une règle au fichier htaccess mais pour mon cas je n'ai jamais réussi à avoir un résultat concluant.

10 réponses


Salut,

attention, le 1er RewriteRule est mal écrit, ça ne veut rien dire.
Aussi, il faut mettre la redirection générale seulement après toutes les autres redirections.

Dans le 2ème RewriteRule, on dirait que tu as inversé $1 et $2.

Je ne suis pas sur,
mais essaie avec ça pour voir :

RewriteEngine on

RewriteRule ^([a-z]+)/([a-z]+)(/([0-9a-z]+))?/?$ url.php?controller=$1&action=$2&param=$4 [L]

RewriteRule ^$ url.php?controller=general&action=home [L]

Remplace general et home par ton controller et ton action qui t'amènent sur ta page d'accueil.

Si tu veux mettre une majuscule à ton controller et ton action dans l'URL (ce qu'il faut faire normalement je crois, par règle SEO), il faudra modifier un peu l'expréssion régulière.

Ça n'accepte qu'un seul paramètre aussi,
je ne sais pas si tu dois pouvoir en accepter plus ou non.
À adapter en fonction de tes besoins.

Important :
Il faut aussi vérifier que ton serveur WEB accepte la réécriture d'URL (que l'option soit activée).

PLJerem
Auteur

Bonjour SLK,

Mon htaccess fonctionne de base.

Pour :

RewriteRule (.*) public/$1 [L]

La règle est très restrictive mais pour le moment je l'utilise, elle me permet de quelle que soit l'url tappée par l'utilisateur on soit pointé vers mon dossier "public" donc le fichier "index.php" qui charge le modéle MVC de mon portail.

J'ai une class Router() qui me permet d'ensuite de charger le controller et à la méthode à utiliser.

J'ai essayé ton code pour être certain qu'on soit bien sur la même base de travail et ce n'est pas très concluant.

En faisant un var_dump de $_SERVER, j'ai de retourné comme variables :

  'SCRIPT_FILENAME' => string 'C:/wamp64/www/monportail/public/index.php' (length=42)
  'REMOTE_PORT' => string '64640' (length=5)
  'REDIRECT_URL' => string '/monportail/public/controller/action/' (length=35)
  'REDIRECT_QUERY_STRING' => string 'url=controller/action/&id=200' (length=31)
  'GATEWAY_INTERFACE' => string 'CGI/1.1' (length=7)
  'SERVER_PROTOCOL' => string 'HTTP/1.1' (length=8)
  'REQUEST_METHOD' => string 'GET' (length=3)
  'QUERY_STRING' => string 'url=controller/action/&id=200' (length=31)
  'REQUEST_URI' => string '/monprojet/controller/action/?id=200' (length=40)
  'SCRIPT_NAME' => string '/monprojet/public/index.php' (length=29)
  'PATH_INFO' => string '/' (length=1)
  'PATH_TRANSLATED' => string 'C:\wamp64\www\index.php' (length=23)
  'PHP_SELF' => string '/monprojet/public/index.php/' (length=30)

Ah d'accord.

Bon alors du coup je ne comprend pas trop...
Est-ce que tu as mis ça dans l'action du formulaire ? http://www.monsite.com/controller/action/
Si oui, comment ça se fait que le REQUEST_URI montre 'mon_projet' ? 'REQUEST_URI' => string '/monprojet/controller/action/?id=200' (length=40)
Dans le REQUEST_URI toujours, on voit 'controller' et 'action', mais il ne faut pas écrire ça tel quel, il faut les remplacer par le nom du controller que tu désires avoir, et le nom de l'action que tu désires avoir non ?

Est-ce que je peux voir comment tu gères tout ça dans 'url.php' ?

PLJerem
Auteur

Je n'ai sûrement pas été très clair dès le début non plus ;)

Pour que ca soit plus simple à comprendre je vais recontextualiser :
Dans le menu de mon portail j'ai un petit formulaire qui permet d'effectuer des réservations de produit directement en tappant leur ID.

Formulaire :

<form method="GET" action="<?= URL; ?>/gestion/reservation_new/">
    <input type="text" name="produit_id" />
    <button type="submit">Réserver</button>
</form>

Du coup pour répondre à ta question :
URL -> http://localhost/monportail/

C'est dans mons Controller "gestion" et par l'action "resevation_new" que je peux afficher la page pour effectuer une nouvelle réservation :

gestionController.php :

class gestionController
    {
        public function reservation_new($produit_id=null)
        {
            // On vérifie que le produit existe bien dans la BDD
            if($this->exist_produit($produit_id)
            {
                // ...
            }
        }
    }

Donc toutes mes pages pointes vers mon fichier index.php qui contient le code suivant :

define('ROOT', dirname(__DIR__));
define('URL', "http://".$_SERVER['HTTP_HOST'].'/monportail');

require_once ROOT.'/app/App.php';
App::load();

Mon application app.php :

class App
{
    public static function load()
    {
        new Router();
    }
}

On continue dans le Router qui me permet de gérer le bon Controller et de choisir l'action à effectuer dedans Router.php :

class Router
{
    protected $controller = 'Home';
    protected $method = 'index';
    protected $params = [];

    public function __construct()
    {
        // On met dans $this->controller le controller contenu dans l'URL si existe
        $url = $this->parseUrl();

        if (file_exists(ROOT . '/app/Controller/' . ucfirst($url[0]) . 'Controller.php')) {
            $this->controller = ucfirst($url[0]);
            unset($url[0]);
        }

        // Inclusion du controller et son instanciation
        require_once ROOT . '/app/Controller/' . $this->controller . 'Controller.php';
        $controller = 'Controller\\' . $this->controller . 'Controller';
        $this->controller = new $controller;

        // Si présence de l'action l'URL
        if (isset($url[1]))
        {
            // Si la méthode existe dans le controller on l'appelle
            if (method_exists($this->controller, $url[1]))
            {
                $this->method = $url[1];
                unset($url[1]);
            }
        }

        // Si $url contient encore des colonnes on les mets en paramètres
        $this->params= $url ? array_values($url) : [];

        call_user_func_array([$this->controller, $this->method], $this->params);
    }

    public function parseUrl()
    {
        if (isset($_GET['url'])) {
            return $url = explode('/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL));
        }
    }
}

Voilà, j'ai enlevé tout ce qui sert à rien mais normalement pour le fonctionnement du chargement de mes pages tu as tout.

alors ca va paraitre tout con mais...

tu peux pas appeler l'action de ton fomultaire comme cela ?

<form method="POST" action="http://www.monsite.com/controller/action/<?php echo $id_a_saisir; ?>">
    <button type="submit">Ajouter</button>
</form>

ou sinon avec un petit peu de JS, tu peux dire que sur le onchange de ton input text, tu met a jour le champ action de ton formulaire avec le bon id.

Bonjour.
Je vois mal comment tu peux avoir une url de type http://www.monsite.com/controller/action/id_saisi alors que tu définies une constante URL avec http://".$_SERVER['HTTP_HOST'].'/monportail, ce qui donnerait donc : http://www.monsite.com/monportail/{controller}/{action}{/params}, en sachant qu'à priori actuellement la valeur de $_SERVER['HTTP_HOST'] est localhost.

PLJerem
Auteur

Hum keulu, ce que tu dis me donnes des idées.

Je peux faire mon formulaire de la sorte :

<form method="POST" action="<?= URL; ?>/gestion/reservation_new/">
    <input type="text" name="produit_id" />
    <button type="submit">Réserver</button>
</form>

Et dans mon Controller Gestion :

class gestionController
    {
        public function reservation_new($produit_id=null)
        {
            // Si produit_id en _POST'produit_id
            if(isset($_POST['produit_id'] ANS is_null($produit_id))
            {
                $produit_id=$_POST['produit_id'];
            }

            // On vérifie que le produit existe bien dans la BDD
            if($this->exist_produit($produit_id)
            {
                // ...
            }
        }
    }

Ca me fait juste rajouter un "SI" en début de méthode.
Techniquement je préférai que le formulaire passe directement sur une URL du type : http://localhost/monportail/gestion/reservation_new/200.../

Lartak, ma rédaction n'a pas été très logique pour décrire mon problème, mais au final c'est bien du http://localhost/monportail/...

Bonjour, je te conseil de suivre ce turoriel https://www.grafikart.fr/tutoriels/php/router-628

PLJerem
Auteur

Bonjour,

Merci pour ta réponse captain-coder.

J'avais suivi le tutoriel en me formant, malheureusement mon portail est tellement avancé qu'il est compliqué d'appliquer des modifications sur le Router que j'ai mis en place.

Au final j'ai utilisé la méthode que j'ai décrit ci-dessus avec la condition d'un $_POST au début de la méthode, elle est toute bête et fonctionne à merveille.

Bonjour, je comprends. Mais à mon avis il faudra un jour ou l'autre passer sur ce genre de système. Bonne journée à toi .