Search code examples
phpapache.htaccessmod-rewrite

Rewrite everything but specific part of URL


I have this user-generated URL: https://example.com/watch.php?name=I9an9O.mp4

What I'm trying to achieve is to grab the part that is inbetween name= and .mp4 (ie. I9an9O)

And this is how I want the URL to look like: https://example.com/I9an9O

I have tried putting this code into .htaccess:

RewriteEngine On
RewriteRule ^([^/]*)\.html$ /watch.php?name=$1 [L]

Unfortunately, I was only able to remove the part that was in front of I9an9O but not the extensions after I9an9O. I used this online Mod Rewrite Tool: https://www.generateit.net/mod-rewrite/index.php

After using it, the result was: https://example.com/I9an9O.mp4.html

What am I doing wrong?


Solution

  • RewriteRule ^([^/]*)\.html$ /watch.php?name=$1 [L]
    

    Not sure why you are matching URLs that end with .html when your URLs should look like /I9an9O.

    You would need to do something like this instead:

    RewriteRule ^\w+$ watch.php?name=$0.mp4 [L]
    

    \w is a shorthand character class that matches upper/lowercase letters, digits and underscores only. So won't match URLs that contain dots (to avoid conflicts with actual files like watch.php) or URLs that contain multiple path segments (folders). The problem with using the more generic regex [^/]* (as in your original example) is that it would potentially match watch.php as well, creating an endless loop.

    The $0 backreference contains the entire URL-path that is matched by the RewriteRule pattern.

    You should be linking to URLs of the form /I9an9O in your HTML source.

    If you are changing an existing URL structure then you will also need to redirect "old" requests of the form /watch.php?name=I9an9O.mp4 to the new URL. This redirect will need to go before the above rewrite.

    The complete .htaccess file would then be something like the following:

    Options -MultiViews
    
    RewriteEngine On
    
    # Redirect direct requests to "/watch.php?name=<name>.mp4" to "/<name>"
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteCond %{QUERY_STRING} ^name=(\w+)\.mp4
    RewriteRule ^watch\.php$ /%1 [QSD,R=301,L]
    
    # Rewrite requests of the form "/<name>" to "watch.php?name=<name>.mp4"
    RewriteRule ^\w+$ watch.php?name=$0.mp4 [L]
    

    Where %1 in the first RewriteRule is a backreference to the captured subpattern in the preceding CondPattern. ie. the I9an9O part of name=I9an9O.mp4.

    The QSD flag is necessary to discard the original query string from the request.

    Test first with 302 (temporary) redirects before changing to a 301 (permanent) in order to avoid potential caching issues.