Search code examples
phpregexapache.htaccessmod-rewrite

Rewrite urls for a php switch statement


I am trying different combinations using .htaccess to create friendly urls however none are working.

I have a php file called users.php like so:

<?php

use A\B\App\Url;

require_once("../../vendor/autoload.php");


$action = Url::getParam('action');

switch($action) {
    
    case "add":
    require_once('user/add.php');
    break;
    
    case "edit":
    require_once('user/edit.php');
    break;

    case "delete":
    require_once('user/delete.php');
    break;
    
    default:
    require_once('user/list.php');

}

and based on the action parameter it sends you to a folder called user and a page like add or edit so the url is like so:

Url 1: http://project.blu/users?action=edit

Url 2 (with id parameter): http://project.blu/users?action=edit&id=1

I want to achieve these desired urls:

Url 1: http://project.blu/users/edit

Url 2 (with id parameter): http://project.blu/users/edit/1

I have tried this code but it does not do the trick and I am assuming because the switch statement needs to see the action parameter in order to know which page to display:

Url 1 tried solution:

RewriteRule ^users/([-\w]+)$ users.php?action=$1 [NC,L]

Url 2 tried solution:

RewriteRule ^users/([-\w]+)$/(\d+)$ users.php?action=$1&id=$2 [NC,L]

neither have worked out for me.

Note: I have other rules in place that remove the .php from the url and those work fine so for example this url http://project.blu/users I can view the page no problem.

Here my full .htaccess file:

Options +FollowSymLinks -MultiViews
RewriteEngine on

# if URL has /pages/ then remove and redirect
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^Pages/(.+)$ /$1 [L,R=301,NC]

# landing page for app subdomain to show index.php
RewriteRule ^$ Pages/index.php [L]

# check & rewrite if a matching .php file exists in pages/ subdirectory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [NC,L] 

# skip all files and directories from rewrite rules below
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

RewriteRule ^users/([\w-]+)/?$ users.php?action=$1 [NC,L,QSA]

RewriteRule ^users/([\w-]+)/(\d+)/?$ users.php?action=$1&id=$2 [NC,L,QSA]

# Redirecting to the error page when nothing is found
ErrorDocument 404 /error

I also have another .htaccess in the root of my folder with this content:

Options +FollowSymLinks -MultiViews
RewriteEngine on

# send all the traffic to /Pages/
RewriteRule .* src/Pages/$0 [L]

and this is an image of my folder structure:

enter image description here


Solution

  • Site root .htaccess:

    Options +FollowSymLinks -MultiViews
    RewriteEngine on
    
    # send all the traffic to /src/
    RewriteRule .* src/$0 [L]
    

    You can use these rules in your src/.htaccess:

    Options -MultiViews
    RewriteEngine On
    
    # landing page for app subdomain to show index.php
    RewriteRule ^$ Pages/index.php [L]
    
    # skip all files and directories from rewrite rules below
    RewriteCond %{ENV:REDIRECT_STATUS} 200 [OR]
    RewriteCond %{REQUEST_FILENAME} -d [OR]
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^ - [L]
    
    # route dummy URLs to their php files inside Pages/ folder
    
    RewriteRule ^(users|locations)/([\w-]+)/?$ Pages/$1.php?action=$2 [NC,L,QSA]
    
    RewriteRule ^(users|locations)/([\w-]+)/(\d+)/?$ Pages/$1.php?action=$2&id=$3 [NC,L,QSA]
    
    # check & rewrite if a matching .php file exists in Pages folder
    RewriteCond %{DOCUMENT_ROOT}/src/Pages/$1.php -f
    RewriteRule ^(.+?)/?$ Pages/$1.php [L]
    

    It is important to disable MultiViews or content negotiation services of Apache.

    Option MultiViews (see http://httpd.apache.org/docs/2.4/content-negotiation.html) is used by Apache's content negotiation module that runs before mod_rewrite and makes Apache server match extensions of files. So if /file is the URL then Apache will serve /file.html.