skip to Main Content

I have read a ton and tried a ton of solutions, but can’t find one specific to my needs.

In my htaccess I have the following:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^profile/([w-]+)/?$ profile.php?username=$1 [L,QSA]
RewriteRule ^profile/([w-]+)/([w-]+)/?$ profile.php?username=$1&type=$2 [L,QSA]
RewriteRule ^profile/([w-]+)/([w-]+)/([w-]+)/?$ profile.php?username=$1&type=$2&o=$3 [L,QSA]

This works wonderfully, except for 1 small problem.

If profile/username does not have a / the links on the page will break unless absolute urls are used. So <a href="./1"> will end up as profile/1 instead of profile/username/1

If I change the first rewrite to the following:

RewriteRule ^profile/([w-]+)/$ profile.php?username=$1 [L,QSA]

then https://myurl/username will return a 404 which I do not want – I want it to force the / on the end if it does not exist.

I have tried adding:

RewriteRule ^(.*)([^/])$ /$1$2/ [L,R=301] 

I have tried

RewriteRule ^(.*)$ https://nmyurl/$1/ [L,R=301]

Just can’t figure out how to do this with the rewrite conditions already in place.

3

Answers


  1. Chosen as BEST ANSWER

    So unfortunately I wasn't able to actually achieve what I was hoping to because there are multiple levels of variables that may or may not exist.

    In part I used the solution provided by Amit:

    RewriteCond %{REQUEST_URI} ^/profile/
    RewriteRule !/$ %{REQUEST_URI}/ [L,R]
    

    However this wasn't enough, because as pointed out by MrWhite there are 3 separate potential url's.

    https://myurl/profile/username/
    https://myurl/profile/username/type/
    https://myurl/profile/username/type/o/
    

    In this sitation username should always exist, but type and o may or may not exist.

    So what I did was detect the level of the url and then created conditional . and .. using php.

    The variable o is always numeric and variable type is never numeric so this worked for me.

    if (isset($_GET['o'])) { $o = strip_tags($_GET['o']); }
    elseif (isset($_GET['type']) && is_numeric($_GET['type'])) { $o = strip_tags($_GET['type']); }
    

    Then I detect:

    // if o is set or if type is numberic, use ..
    if (isset($_GET['o']) || (isset($_GET['type']) && is_numeric($_GET['type']))) {
      $dots = '..';
    // if o is not set and type is not numeric just use .
    } else {
      $dots = '.';
    }
    

    end result of <a href="'.$dots.'/1/">1</a>:

    if url is https://myurl/profile/username/
    result is https://myurl/profile/username/1/
    
    if url is https://myurl/profile/username/3/
    result is https://myurl/profile/username/1/
    
    if url is https://myurl/profile/username/type/3/
    result is https://myurl/profile/username/type/1/
    

    Which was the desired outcome.


  2. To add an optional traling at the end of your profile URLs you can use this

    RewriteEngine on
    
    RewriteCond %{REQUEST_URI} ^/profile/
    RewriteRule !/$ %{REQUEST_URI}/ [L,R]
    
    Login or Signup to reply.
  3. If profile/username does not have a / the links on the page will break unless absolute urls are used. So <a href="./1"> will end up as profile/1 instead of profile/username/1

    If the issue only applies to URLs of the form /profile/<username> then I would be specific and only append the trailing slash to these specific URLs, otherwise, you are going to get a lot of redirects (which could be detrimental to SEO).

    However, you should ensure that internal links are for the canonical URL (ie. with the trailing slash).

    For example, the following should go before your existing rewrites:

    RewriteRule ^(profile/[w-]+)$ /$1/ [R=301,L]
    

    Since the canonical URL requires a trailing slash this should be a 301 (permanent) redirect. (But test with a 302 first.)


    Alternatively, instead of redirecting in .htaccess (if you are still linking to the slashless URL internally) then you could add a base element (that includes the trailing slash) to the head section to state what relative URLs should be relative to.

    For example:

    <base href="/profile/<username>/">
    

    Aside:

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^profile/([w-]+)/?$ profile.php?username=$1 [L,QSA]
    RewriteRule ^profile/([w-]+)/([w-]+)/?$ profile.php?username=$1&type=$2 [L,QSA]
    RewriteRule ^profile/([w-]+)/([w-]+)/([w-]+)/?$ profile.php?username=$1&type=$2&o=$3 [L,QSA]
    

    The two RewriteCond directives would seem to be entirely superfluous. RewriteCond directives only apply to the first RewriteRule that follows. But the RewriteRule patterns are unlikely to match real files anyway (unless you have files without extensions or directories with the same name).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search