php.htaccessurl-rewriting

URL rewrite conflict for multiple rules


I am using get method to display pages in Php website. I have blog and services categories and I want my URL structure to look like this:

    https://sample.com/   
    https://sample.com/services
    https://sample.com/services/service-a 
    https://sample.com/blog
    https://sample.com/blog/blog-a

My current htaccess file:

RewriteRule ^([0-9a-zA-Z-_]+)$ index.php?page=$1  
 
RewriteRule ^([0-9a-zA-Z_\-]+)/([0-9a-zA-Z_\-]+)$ index.php?page=$1&services=$2  
RewriteRule ^([0-9a-zA-Z_\-]+)/([0-9a-zA-Z_\-]+)$ index.php?page=$1&blog=$2 [NC,L]

The problem is, I can only display service categories but not blog categories. As in my htaccess last two line have similar pattern, the second line is being ignored; there is conflict, the first rule always wins.

Php code:

    if(isset($_GET["page"])){
      switch($_GET["page"]){
        case 'home': 
          //get home content from db 
          break;    
        case 'services': 
          if(!isset($_GET["services"])){
            //gets services content from db
          }
          else if(isset($_GET["services"]))
          {
            switch($_GET["services"]){
              case 'service-a': 
                //   services/service-a
                break;
              case 'service-b': 
                     //  content services/service-a from db
                    break;
            }
          }
          break;
        case 'blog': 
          if(isset($_GET["blog"])){
            switch($_GET["blog"]){
            case 'blog-post-a': 
                 //  get content of blog/blog-post-a from db
                   break; 
            case 'blog-post-b': 
                 //  get content of blog/blog-post-b from db
                   break;    
               default;
            }
          }
          else{
          //blog page content from db
          }
          break;
      }
    }

How can I resolve this? Thanks.


Solution

  • You just need to make the more specific rules match a more specific pattern, so that no ambiguity exists:

    RewriteEngine on
    RewriteRule ^([0-9a-zA-Z-_]+)$ index.php?page=$1 [L]
    
    RewriteRule ^services/([0-9a-zA-Z_\-]+)$ index.php?page=services&services=$1 [L]
    RewriteRule ^blog/([0-9a-zA-Z_\-]+)$ index.php?page=blog&blog=$1 [L]
    

    You can probably simplify this:

    RewriteEngine on
    RewriteRule ^([0-9a-z-_]+)$ index.php?page=$1 [NC,L]
    
    RewriteRule ^services/([0-9a-z_\-]+)$ index.php?page=services&services=$1 [NC,L]
    RewriteRule ^blog/([0-9a-z_\-]+)$ index.php?page=blog&blog=$1 [NC,L]
    

    Or even:

    RewriteEngine on
    RewriteRule ^([\d\w_-]+)$ index.php?page=$1 [L]
    
    RewriteRule ^services/([\d\w_-]+)$ index.php?page=services&services=$1 [L]
    RewriteRule ^blog/([\d\w_-]+)$ index.php?page=blog&blog=$1 [L]
    

    Maybe just a single rule instead of two, but that is questionable:

    RewriteEngine on
    RewriteRule ^([\d\w_-]+)$ index.php?page=$1 [L]
    
    RewriteRule ^(services|blog)/([\d\w_-]+)$ index.php?page=$1&$1=$2 [L]