mod_rewrite last match - regex

My htaccess is located in localhost/me/.htaccess, and I want to append anything after the last / with .php
e.g. localhost/me/test/index rewrites to localhost/me/test/index.php
So far RewriteRule ^([A-Za-z]+)$ $1.php [NC,L] works for localhost/me/index, but I can't get it working for the first example up there. Why doesn't ^/([A-Za-z]+)$ /$1.php [NC,L] work, and how do I change it to work?

Use this rule:
# add .php file extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.+)$ $1.php [L,QSA]
It will check if such .php exist before rewriting
The main problem you had is your pattern: ^([A-Za-z]+)$ it will match index but not test/index as it only allows a-z characters. You would need to add / into a pattern: ^([a-z/]+)$.
because you have [NC] flag (no case matching), there is no need to have both A-Z and a-z
I'm using more global/general pattern (.+)-- it will match any characters and because it comes with "check if file exist" conditions, there is no need to worry about limited set of characters.

It doesn't work because you're matching only on alpha letters and you don't have a / in the character class, but your URI is me/test/index . Try this:
RewriteEngine On
RewriteRule ^([A-Za-z/]+)$ $1.php [NC,L,QSA]
Also, since you're using [NC], you really only need a-z rather than A-Za-z but it doesn't hurt anything.

Related

How to match quantifiers { 6, } in RewriteRules?

I did a rewrite rule matching document names that are 6 characters, and it succeeds.
RewriteRule ^document\/(.{6})\/?$ document/?name=$1 [NE,L]
Since I know documents are named only up to 12 characters, I added a maximum length quantifier. However, using this, it produces a 500 Server Error:
RewriteRule ^document\/(.{6,12})\/?$ document/?name=$1 [NE,L]
In fact, I'm getting the following results:
(.{6}) works
(.{6,}) faults
(.{6,7}) works
(.{6,8}) works
(.{6,9}) faults
and so on.
I should also mention that https://www.regexpal.com/?fam=109235 tells me there isn't anything wrong with my rule. However I'm still getting the 500 Server Error on use.
Thank you #emma, example URLs to be rewritten:
http://www.mywebsite.com/document/051201-22
http://www.mywebsite.com/document/051201-22/
I'm not quite sure how you'd like to write this RewriteRule. However, this tool might help you to first find an expression, then write and test a RewriteRule. I'm pretty sure, you can write it without using a quantifier. For example:
document\/([0-9]+)
would pass your exampled URLs.
Then, if you wish to only replace the first six digits to the name variable, you might want to write a RewriteRule similar to:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} mywebsite\.com [NC]
RewriteRule document\/([0-9]+) document\/?name=$1 [NE,L]
</IfModule>
For yes or no trailing slashes, these might work:
# No Trailing Slash Policy, if you wish no slash at the end of your URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R] # <- for test, for prod use [L,R=301]
# Trailing Slash Policy, if you wish to have a slash at the end of your URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1/ [L,R] # <- for test, for prod use [L,R=301]
I think you enter in a redirect loop with this setup.
Add a RewritCond to check that there is not a query string in the request
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^document/([^/]{6,12})/?$ document?name=$1 [NE,L]

How to rewrite mp3 filename using .htaccess

I'm tried to protect my mp3 using mod_rewrite in my htaccess file.
I read this threads:
how to write a .htaccess redirect like stackoverflow does for its questions
htaccess rewrite dynamic mp3 to dynamic php?
How to hide filename from url by using .htaccess
this website:
https://code.tutsplus.com/tutorials/using-htaccess-files-for-pretty-urls--net-6049
and this video:
https://www.youtube.com/watch?v=uPlZekNEU60
I was able to rewrite filename to filename.pdf with this rule:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.pdf -f
RewriteRule ^([^\.]+)$ $1.pdf [NC,L]
Now, to protect my mp3 I want to rewrite my url
filename.mp3/?uuid=something to https://cdn.com/123456/t/filename.mp3
I tried this rule:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.mp3 -f
RewriteRule ^([a-zA-Z0-9]{30})$ https://cdn.com/123456/t/$1.mp3 [NC,L]
but it doesn't work
I tried this one:
RewriteRule ^(\w*.mp3)+)$ https://cdn.com/123456/t/$1 [NC,L]
but it puts the website down :(
Any tip?
Your last RewriteRule has a closing parenthesis too much at the end and will repeat matching mp3 1 or more times.
If you remove that parenthesis leaving ^(\w*.mp3)+ it will still repeat one or more times a grouping structure that will match this pattern \w*.mp3. That will match 0+ times a word character followed by any character due to the dot and mp3.
That could for example match zmp3. If you want to match a literal dot you have to escape it.
I think that you meant:
RewriteRule ^(\w+\.mp3/)$ https://cdn.com/123456/t/$1 [NC,L]
You might check if the querystring consist of a single key/value pair:
RewriteCond %{QUERY_STRING} ^uuid=\w+$ [NC]

htaccess URL Rewrite with and without query string

I'm trying to rewrite some urls but my newbness is getting in the way.
URLs input into the address bar
example.com/prefix-suffix.html
example.com/prefix-suffix.html?v=huzzah
Desired output (would like them displayed like)
example.com/prefix/suffix/
example.com/prefix/suffix/huzzah
I've looked at a few other examples like this one, but I just don't understand what they are doing exactly or how rather, which makes it challenging to modify.
If you have the time to explain what each line is doing I would greatly appreciate it.
Thanks.
You can use this code in your DOCUMENT_ROOT/.htaccess file:
RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} \s/+([^-]+)-([^.]+)\.html\s [NC]
RewriteRule ^ /%1/%2/ [R=302,L,NE]
RewriteCond %{THE_REQUEST} \s/+([^-]+)-([^.]+)\.html\?v=([^\s&]+) [NC]
RewriteRule ^ /%1/%2/%3? [R=302,L,NE]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^([^/]+)/([^/]+)/?$ /$1-$2.html [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ /$1-$2.html?v=$3 [L,QSA]
this is a good reference. to summarize the relevant parts:
in the SO question you are referring to, the OP wanted index.php?page=mobile to become index/page/mobile
and the accepted answer to that question was:
RewriteEngine on
RewriteBase /cashearn/
RewriteCond %{THE_REQUEST} /index\.php\?page=([^\s&]+) [NC]
RewriteRule ^ index/page/%1? [R=302,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^index/page/([^/]+)/?$ index.php?page=$1 [L,QSA,NC]
in order to understand how that is working, let's take a close look at this section:
RewriteCond %{THE_REQUEST} /index\.php\?page=([^\s&]+) [NC]
RewriteRule ^ index/page/%1? [R=302,L]
RewriteCond is a condition that must be matched in order for the subsequent RewriteRule to be used.
the pattern-matching is done using regex. the basics are easy to master so i recommend that you look it up. in any case, anything of the form %N (e.g. %1) is a backreference to the "grouped" part of the pattern of the last RewriteCond in the current set of conditions. A "grouped" part is denoted by parentheses. In other words, the %1 in the RewriteRule refers to the ([^\s&]+) in the RewriteCond.
looking at the regex:
square brackets in regex denote a character class so [^\s&] is thus a character class.
the caret ^ when it is inside a character class denotes negation. \s is an escape code for the whitespace character. so, all in all, [^\s&] means "any character except whitespace and &". the character class is appended with + which means "one or more". so, the regex pattern will match one of characters that are included in the character class. for a url, this essentially means any combination of letters, digits and %.
the other characters in the RewriteRule and RewriteCond, other than the "server-variable" %{THE_REQUEST}, are either regex special characters or literals. (by literals i mean that ab in a regex will match the string cab.)
^, the caret, when it isn't inside a character class, is a special character that denotes the beginning of a line. note that ? and . are also literals here, despite the fact that they are included in the list of regex "special characters". that is because they are escaped with a \.
the only thing left to explain is the flags [NC] and [R=302,L]
NC means case-insensitive. L means last, i.e. if there is a match, then subsequent rules will not be processed. 'R' means "redirect" and 302 is the redirect's HTTP status code.
the difference between an internal and external redirect is relevant here. with an internal redirect, the server will silently grab the resources from the filepath specified at the newly formed URL, while the user still sees the original URL in the browser. the R flag indicates an external redirect and this causes the user to initiate a new HTTP transaction with the newly formed URL. Omit R for an internal redirect.

.htaccess RegEx for variable file version

I would like clients to be able to access certain files using an arbitrary version number to bypass caching.
For example, suppose there are two files: styles.css and jquery.min.js They should be able to request either the originals or styles.23.css and jquery.min.5039.css.
The rule I came up with was:
RewriteEngine On
RewriteRule ^(.*)\.(?!\..*)[\d]+\.(.*)$ $1.$2 # strip out version number
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
Broken down, here's my thought on what it should be doing:
^(.*) – starting from the beginning, match all
\. – up to the first period...
(?!\..*) - ...which is not followed by a period and anything,
[\d]+\. – then match if ends in one or more digits followed by a period...
(.*)$ – ...and anything
This RegEx actually works seems to work in PHP but not .htaccess, which has me a bit confused.
Thank you in advance.
Why do you need lookahead etc. Following should work:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+?)\.\d+\.(.*)$ $1.$2 [L]

Help with regular expression with mod_rewrite

I have links like these that I want to change:
mypage.com?page=missions&id=5
mypage.com?page=hello
I tried to change them into easier links with this:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^([^/]*)/([^/]*)$ /index.php?page=$1&id=$2 [L]
It works but if I want to access pages like (mypage.com?page=hello) I have to write:
mypage.com/hello/
and if I write without the slash in the end like this
mypage.com/hello
it doesn't work.
How do I fix it? :)
This should work:
RewriteRule ^([^/]*)(/([^/]*))?$ /index.php?page=$1&id=$3 [L]
This will make the slash optional by including it in an optional group (denoted by (...)?), along with the optional second half of the query string. Since this introduces a new group between the first and second (left parenthesis determines the order), we have to change the second backreference from $2 to $3.
If the logic becomes much more complex than this, it may be easier to split up the rules.
You could add a second rule that omits the second parameter and optionally the slash:
RewriteRule ^([^/]+)/?$ /index.php?page=$1
RewriteRule ^([^/]+)/(\d+)/?$ /index.php?page=$1&id=$2
This might work too:
RewriteRule ^([^/]+)(?:/(\d+))?/?$ /index.php?page=$1&id=$2
For SEO, you'll probably want to redirect requests missing the slash to the same address with a slash. Use RedirectMatch for that.
I read about the trailing slash with SEO (didn't know about it, thank you mathew!) and the final result was this:
RewriteRule ^([a-zA-Z0-9_-]+)/$ /index.php?page=$1 [L]
RewriteRule ^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/$ /index.php?page=$1&id=$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ http://www.mypage.com/$1/ [R=301,L]
So now I force it to have a trailing slash.