3 simple htaccess tasks, so why am I looping? - regex

I am trying to accomplish 3 fairly standard url mods in my htaccess file, but unfortunately I am getting thrown in a loop. What am I doing wrong?
# force a trailing slash
RewriteRule ^profile/([^/]+)$ /profile/$1/ [R=301,L]
# check for trailing parameters
RewriteCond %{QUERY_STRING} ^(.*)$
# put it all together
RewriteRule ^profile/([^/]+)/$ /profile/index.php?username=$1&%1 [NC,L]

The pattern of your first rule, ^profile/([^/]+)$, does also match the destination of your second rule, profile/index.php.
You could simply exclude that file with an additional RewriteCond for the first rule:
RewriteCond $1 !=index.php
RewriteRule ^profile/([^/]+)$ /profile/$1/ [R=301,L]

Related

String repeats 20 times in RewriteRule if i try to use it with $1, $2 etc. back-references. Weird. Why?

I try to do a RewriteRule redirect in .htaccess where the output URL has some additional text beside the captured text from the capture groups.
Original url: https://example.com/places/europe/hungary/budapest/
My regex pattern: ^places/([a-zA-Z-_]+/)?([a-zA-Z-_]+/)?([a-zA-Z-_]+/)?
i want to add a 'text-' string in the destination url around some $1, $2..
The full line in .htaccess: RewriteRule ^places/([a-zA-Z-_]+/)?([a-zA-Z-_]+/)?([a-zA-Z-_]+/)? https://example.com/places/$1text-$2$3 [R=301,L]
but it outputs exactly this:
https://example.com/places/europe/text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-text-hungary/budapest/
Instead of this: https://example.com/places/europe/text-hungary/budapest/
Yep, the additional 'text-' is repeating 20x times instead of 1.
If I don't put the 'text-' in the substitution string, all works as expected i.e:
https://example.com/places/$1$2$3 [R=301,L]
gives
https://example.com/places/europe/hungary/budapest/
What may cause this strange (to me) anomaly?
Is this should work without glitches or what is the correct syntax for this case?
All the other code in the .htaccess file (positioned after this RewriteRule part in question):
# BEGIN rlrssslReallySimpleSSL rsssl_version[3.3.5]
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
# END rlrssslReallySimpleSSL
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Yes it's a wordpress install.
Thanks a lot for any help!
As suggested in comments by Amit that you're running into this issue because pattern [a-zA-Z_-]+/ matches original string hungary as well as the target string text-hungary, thus results in a redirect loop.
You may use this rule with a negative lookahead to prevent a redirect loop as you're experiencing in your current rule:
RewriteRule ^places/([a-zA-Z_-]+/)((?!text-)[a-zA-Z_-]+/)([a-zA-Z_-]+/?)$ /places/$1text-$2$3 [R=301,L]
(?!text-) is a negative lookahead condition that will fail the match when $2 starts with text-.
Also note that an unescaped - should be placed at the start or end of a character class [...].
Make sure to clear your browser cache before testing this change.

How to create .htaccess for multiple parameters in URL?

I need using this .htaccess file. It only changes the URL from www.mydomain.com/users/user?usernam=myname123&profile=myprofile123&data=mydata123 to www.example.com/users/myname123/myprofile123/mydata123 .
i use
RewriteEngine On
RewriteRule ^user\.php$ - [L]
RewriteRule ^([0-9a-zA-Z\-_.]*)/?$ /users/user.php?username=$1&profile=$2&data=$3[L,QSA]
htaccess in users folder
not work
With your shown samples, could you please try following rules. This will take anything in REQUEST_URI starting.
RewriteEngine ON
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{THE_REQUEST} /([^/]*)/([^/]*)/([^/]*)/([^/]*)/?\s
RewriteRule ^(.*) /%1?username=%2&profile=%3&data=%4 [NE,L,NC]
OR(either use above or following one) in case you want to match users in URI then run rules then try following.
RewriteEngine ON
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{THE_REQUEST} /users/([^/]*)/([^/]*)/([^/]*)/?\s
RewriteRule ^(.*) /users?username=%1&profile=%2&data=%3 [NE,L,NC]
Explanation: Adding detailed explanation for above.
RewriteEngine ON: Enabling RewriteEngine here to enable mod rule writing.
RewriteCond %{QUERY_STRING} ^$: Checking condition if query string is NULL then go further in rules.
RewriteCond %{THE_REQUEST} /users/([^/]*)/([^/]*)/([^/]*)/?\s: Matching regex in THE_REQUEST from /users to till spaces and capturing 3 groups values into back references to be used later.
RewriteRule ^(.*) /users?username=%1&profile=%2&data=%3 [NE,L,NC]: Using url rewrite to change URI to as per OP's request which has back references values in it.

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]

htaccess RewriteRule regex

I have hundreds of these old links I need to redirect.
Here is one example:
/index.php?option=com_content&view=article&id=433:seventh-character-code-categories-and-icd-10-cm&Itemid=101&showall=1
to
/seventh-character-code-categories-and-icd-10-cm
Essentially I need to remove the /index.php?option=com_content&view=article&id=433: part.
I tried this but I am getting confused with the [0-9] and : parts, so the following does not work:
RewriteRule ^/index.php?option=com_content&view=article&id=[0-9]:(.*)$ /$1 [L,R=301]
Say you want to capture from after : to right before & in the query string you mentioned, then try this expression:
^[^\:]*\:([^\&]*)\&.*$
As #starkeen mentioned in comments, you got to check against the query string. This can be done using RewriteCond %{QUERY_STRING}
So if index.php is in the root folder:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^\/index\.php$
RewriteCond %{QUERY_STRING} ^[^\:]*\:([^\&]*)\&.*$
RewriteRule ^(.*)$ http://example.com/%1 [R=301,L]
Here's another example. This one is for a sub folder:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^\/pages\/index\.php$
RewriteCond %{QUERY_STRING} ^[^\:]*\:([^\&]*)\&.*$
RewriteRule ^(.*)$ /pages/%1? [R=301,L]
Also, notice the ? at the end of the url /pages/%1?, this prevents from re-attaching the query string.
Another thing, captured groups will be set to variables %{number} since set in the RewriteCond.
BTW, depending on your server's configuration, you may need to add the NE flag, like [NE,L,R=301] Plus test whether it is necessary to double escape the literal characters.
what is about direct approach. Skip all till semicolon, mach string till & and replace all with first much
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} [^:]+:([\w-]+[^&]).*
RewriteRule .*$ \/%1? [R=301,L]
</IfModule>

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.