htaccess rewrite rule with 2 variables (1 optional) - .htaccess

I'm aware this has already been asked, but I've tried countless solutions but I'm still not getting the desired result.
I've a page which shows a list of names and the variables data are the starting letter (variable l which can also be a number) and the page number (page_no) and the page number is optional as it should not be displayed in the page 1.
The original URL is the following
https://www.example.com/allnames.php?l=A&page_no=1
I've the following rule
RewriteCond %{QUERY_STRING} ^l=([\w]+)$
RewriteRule ^allnames.php$ /allnames/%1? [R=301,L]
which works fine for page 1, but it doesn't include the page_no variable, so I tried this one but I'm unable to understand what's wrong.
RewriteCond %{QUERY_STRING} ^l=([\w]+)?page_no=([0-9]+)$
RewriteRule ^allmovies.php$ /allmovies/%1/%2? [R=301,L]
the result expected would be, for example
allnames/A or allnames/A/1 for letter A, page 1
allnames/S/8 for letter S, page 8
And the following is the content of the htaccess file
RewriteEngine On
Options +FollowSymLinks -MultiViews
# to prevent loops
RewriteCond %{ENV:REDIRECT_STATUS} !200
#remove index.php
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by apache
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .? - [L]
RewriteRule .? %{ENV:BASE}/index.php [L]
# allnames.php
RewriteCond %{QUERY_STRING} ^l=([\w]+)$
RewriteRule ^allnames.php$ /allnames/%1? [R=301,L]
RewriteRule allnames/ /allnames.php?l=$1&page_no=$2 [L]

RewriteCond %{QUERY_STRING} ^l=([\w]+)?page_no=([0-9]+)$
The regex in the condition (CondPattern) does not allow for the & delimiter between URL parameters. You are also allowing the l parameter value to be entirely omitted (which would result in an ambiguous URL) or contain multiple characters (which you've stated should be a single "letter").
You would seem to need something like the following instead:
RewriteCond %{QUERY_STRING} ^l=([\w])&page_no=([0-9]+)$
But note that this will fail if the l parameter value contains more than one character (or is omitted entirely).
the result expected would be, for example
allnames/A or allnames/A/1 for letter A, page 1
Note that you would still need your first rule (without the page_no URL param) to get allnames/A. You could instead make page_no optional in the second rule, but you would still get a trailing slash (ie. allnames/A/) if that is an issue?

Related

.htaccess rewrite commands acting not as expected

I have the following .htaccess file
RewriteEngine on
RewriteRule ^about$ about.html [NC]
RewriteRule (.*) index.php?url=$1 [L]
# Prevent loops
RewriteCond %{ENV:REDIRECT_STATUS} !200
# Map new URI to file
RewriteRule code/(.*) code.php?id=$1 [L]
first rule replace about with about.html - works
second rule
should have allowed me to write www.example.com/test-me - but when I var_dump $_GET["url"] I get: index.php while I expected $_GET["url"] to return test-me.
third rule:
not working - return 404 error. I expected file code.php on root to return with id as a URL param.
What I am trying to achieve is that when someone types www.example.com/lesson/lesson-name this will trigger the file code.php on the root and plant lesson-name as $_GET['lesson_name']
.
The second rule is triggering a the rewrite engine to start over and since you have no preceding condition (unlike the directive below) it ends up rewriting index.php on the second pass.
Your directives are also in the wrong order. The second rule that catches everything needs to go last. However, as stated, this rule catches everything - including all requests for static resources etc. So, you'll probably need additional conditions to prevent this.
Try the following instead:
Options -MultiViews
RewriteEngine on
RewriteRule ^about$ about.html [NC]
# Map "/lesson/<lesson-name>" to "/code.php?lesson_name=<lesson-name>"
RewriteRule ^lesson/(.*) code.php?lesson_name=$1 [L]
# Map everything else - for example "/index.php?url=test-me"
# Exclude static resources
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?url=$1 [L]

How to redirect 301 with dynamically generated URL while removing a slash?

I have been at this all day long, tried dozens of variations but can't quite seem to get this rewrite to work.
RewriteCond %{THE_REQUEST} /pwreset\.php\ [NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} \s(.+?)/+[?\s]
RewriteRule ^(.+?)/$ https\:\/\/www\.example\.com\/support\/pwreset\.php [L]
The URL it returns is:
https://www.web-jive.com/support/pwreset.php/?key=cdc3b1aa842785f7345be501a30ddc83
What I need to be removed is the pwrest.php trailing slash before the question mark. Where am I going wrong on this?
The idea is to have the first URL below, redirect to the second:
https://example1.com/pwreset.php?key=cdc3b1aa842785f7345be501a30ddc83
https://example2.com/support/pwreset.php?key=cdc3b1aa842785f7345be501a30ddc83
EDIT
Per Mr. White's suggestion, I'm posting the whole .htaccess file.
RewriteEngine On
# Announcements
RewriteRule ^announcements/([0-9]+)/[a-z0-9_-]+\.html$ ./announcements.php?id=$1 [L,NC]
RewriteRule ^announcements$ ./announcements.php [L,NC]
# Downloads
RewriteRule ^downloads/([0-9]+)/([^/]*)$ ./downloads.php?action=displaycat&catid=$1 [L,NC]
RewriteRule ^downloads$ ./downloads.php [L,NC]
# Knowledgebase
RewriteRule ^knowledgebase/([0-9]+)/[a-z0-9_-]+\.html$ ./knowledgebase.php?action=displayarticle&id=$1 [L,NC]
RewriteRule ^knowledgebase/([0-9]+)/([^/]*)$ ./knowledgebase.php?action=displaycat&catid=$1 [L,NC]
RewriteRule ^knowledgebase$ ./knowledgebase.php [L,NC]
#Password reset
RewriteCond %{QUERY_STRING} ^key=[0-9a-f]{32}$
RewriteRule ^pwreset\.php$ https://www.web-jive.com/support%{REQUEST_URI} [R=302,L]
#Redirect to new support URL
RewriteCond %{HTTP_HOST} ^members\.web\-jive\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.members\.web\-jive\.com$
RewriteRule ^/?$ "https\:\/\/www\.web\-jive\.com\/support" [R=301,L]
RewriteCond %{HTTP_HOST} ^members\.web\-jive\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.members\.web\-jive\.com$
The output you are seeing (with the trailing slash on the URL-path) isn't the result of just the directives you posted, so maybe you have a conflict with other directives or you are seeing a cached response.
However, the rule you posted would seem to be far more complex than it needs to be.
1. https://example1.com/pwreset.php?key=cdc3b1aa842785f7345be501a30ddc83
2. https://example2.com/support/pwreset.php?key=cdc3b1aa842785f7345be501a30ddc83
Assumptions:
You don't need to match the key value; just the URL-path (ie. /pwreset.php)
example1.com and example2.com point to different places (the filesystem does not overlap).
To redirect from 1. to 2. try the following at the top of your .htaccess file in the root of example1.com:
RewriteEngine On
RewriteRule ^pwreset\.php$ https://example2.com/support%{REQUEST_URI} [R=302,L]
Any query string (eg. key=abc...) is passed through unaltered.
Note that this is a 302 (temporary) redirect. Only change it to a 301 (permanent) when you have confirmed it works OK.
If you need to check that a key= URL param is present and is set to a 32 hex string (which appears to be what your example represents) then include a condition before the above RewriteRule that checks against the QUERY_STRING server variable. For example:
RewriteCond %{QUERY_STRING} ^key=[0-9a-f]{32}$
RewriteRule ^pwreset\.php$ https://example2.com/support%{REQUEST_URI} [R=302,L]
If any other URL params are present on the request then the redirect will fail.
Aside:
RewriteRule ^(.+?)/$ https\:\/\/www\.example\.com\/support\/pwreset\.php [L]
This looks very cPanel-esque. There is no need to backslash colons, slashes and dots in the RewriteRule susbtitution argument. This is an "ordinary" string, not a regex. These characters have no special meaning here.

.htaccess rewrite if nothing specified

I'm trying to modify my .htaccess file to link to three different places, based on the input after the endpoint:
"/api" - Link to the API
"/ABCD123" - If it's a 7 character
alphanumeric string, link to a specific page
"/" - If nothing specified, or for any other inputs link to the homepage.
Here is my .htaccess file:
Options -Indexes
RewriteEngine On
RewriteRule ^api/(.*) ./api/index.php [R,L]
RewriteRule ^([a-zA-Z0-9]{7})$ index.php?l=$1 [L]
RewriteRule ^(.+)$ everythingelse.php [L]
Even though I have the [L] flag specified I always seem to get redirected to the everythingelse.php route, even if I have the 7 character string.
How can I rewrite to match this correctly?
Your rules are looping and executing more than once. L flag only breaks current loop but mod_rewrite can loop again and execute all the matching rules.
Options -Indexes
RewriteEngine On
# skip all files and directories from rewrite rules below
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^api/(.*)$ /api/index.php [R,L]
RewriteRule ^([a-zA-Z0-9]{7})$ index.php?l=$1 [L,QSA]
RewriteRule . everythingelse.php [L]

Force redirect for certain files (based on referer) and trigger a 404 page otherwise

We distribute different versions of a software product through a single download link. The delivery is based on the referer in conjunction with a default value, which works fine. In addition the user should be redirected to a 404-page, in case the wrong filename was used.
At the moment the .htaccess-file looks like this:
# stop directory listing
Options -Indexes
# turn rewrite engine on
RewriteEngine On
# force 404 if file name is missing or wrong
RewriteCond %{REQUEST_URI} !^(download_mac\.zip|download_pc\.zip)$
RewriteRule (.*) 404/index.html [L]
# an example based on the referer
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-a\.com [OR]
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-b\.com
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ domain_ab/$1 [L]
# last rule if no referer matches
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ default/$1 [L]
So I have one issue and one additional question with this file:
The first rule, to force 404, is very greedy and gets the error page every time, no matter what URL is called. I also tried single statements like RewriteCond %{REQUEST_URI} !^download_mac\.zip$ without any effect. How can I fix this?
How can I get rid of the filenames in any other rule? I tried things like RewriteRule ^(.*)$ default/$1 [L] but it gives me a hard time and an 500 Internal Server Error.
You can avoid repeating your filenames by using an Env variable like this:
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ - [E=ALLOWED:$1,NC]
RewriteCond %{ENV:ALLOWED} ^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /404/index.html [L]
RewriteCond %{ENV:ALLOWED} !^$
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-a\.com [OR]
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-b\.com
RewriteRule ^ /domain_ab/%{ENV:ALLOWED} [L]
RewriteCond %{ENV:ALLOWED} !^$
RewriteRule ^ /default/%{ENV:ALLOWED} [L]
You can just move the rewrite rule to the end. The other rules handle the valid cases and if none of them matches the last rule applies
# an example based on the referer
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-[ab]\.com
RewriteRule ^download_(mac|pc)\.zip$ domain_ab/$0 [L]
# last rule if no referer matches
RewriteRule ^download_(mac|pc)\.zip$ default/$0 [L]
# force 404 if file name is missing or wrong
RewriteRule ^ 404/index.html [L]

Rewriting urls using mod_rewrite : Error with multiple rules

I have following code in .htaccess
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)(/([^/]+))?(/(edit)+)(/([^/]+))?/?$ edit.php?secret=Y7qD7&category=$1&slug=$3&edit=$5&part=$7 [L]
RewriteRule ^([^/]+)(/([^/]+))?/?$ content.php?category=$1&slug=$3 [L]
RewriteRule ^(/)?$ content.php [L]
What I expect to achieve is
http://example.com/test/test1/edit/part to edit.php?category=test&slug=test1&edit=edit&part=part
http://example.com/test/edit/part to edit.php?category=test&slug=&edit=edit&part=part
(above rewrite is working as expected)
`http://example.com/test/test/` to `content.php?category=test&slug=test`
`http://example.com/test/` to `content.php?category=test&slug=`
(Please note that there is no "/edit/" & "/part/" in above 2 urls)
for above two rewrites, first one is working fine but the second one is not working as expected. The last one get rewrite to content.php?category=content.php&slug= which is not correct.
Also trailing slash should not make a difference for the rewrite.
Could somebody please show me what I'm doing wrong here?
I didn't check why the rule in your question doesn't work as expected, but you may try this instead:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/([^/]+)/?([^/]*)?/?([^/]*)?/?([^/]*)?/?
RewriteRule .* edit.php?key1=%1&key2=%2&key3=%3&key4=%4 [L]
Maps silently:
http://example.com/val1/ up to
http://example.com/val1/val2/val3/val4/ with or without trailing slashes
To:
http://example.com/edit.php?key1=val1&key2=val2&key3=val3&key4=val4
The maximum quantity of valN values passed in the incoming URL, is 4. The minimum is 1. That range can be adjusted modifying the rule, though.
When any valN is not present in the incoming URL, the value in the corresponding key-value pair in the query added to the substitution URL, will be empty.
However, the key will always be present in the query as all keys are fixed strings not passed by the incoming URL.
This rule-set is tested and working and it should be tested without any other rule that might get in conflict with it. I didn't check the other rules in the question and can't say if they work or if they could affect this one. That was not part of the question.
UPDATE
Redirecting to edit.php:
Mapping to edit.php is required only when there are 3 or 4 folders in the URL-path.
The modified rule-set is:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !edit\.php [NC]
RewriteCond %{REQUEST_URI} ^/([^/]+)/([^/]+)/([^/]+)/?([^/]*)?/?$ [NC]
RewriteRule .* edit.php?key1=%1&key2=%2&key3=%3&key4=%4 [L,QSA]
Maps silently:
http://example.com/val1/val2/val3/ up to
http://example.com/val1/val2/val3/val4/ with or without trailing slashes
To:
http://example.com/edit.php?key1=val1&key2=val2&key3=val3&key4=val4
The maximum quantity of valN values passed in the incoming URL, is 4. The minimum is 3.
Redirecting to content.php:
Mapping to content.php is very similar to the previous one, except is done only when the number of folders is 1 or 2.
So the rule-set is basically the same with less regex groups:
RewriteCond %{REQUEST_URI} !content\.php [NC]
RewriteCond %{REQUEST_URI} ^/([^/]+)/?([^/]*)?/?$ [NC]
RewriteRule .* content.php?key1=%1&key2=%2 [L,QSA]
Maps silently:
http://example.com/val1/ up to
http://example.com/val1/val2/ with or without trailing slashes
To:
http://example.com/content.php?key1=val1&key2=val2
The maximum quantity of valN values passed in the incoming URL, is 2. The minimum is 1.
The complete rule-set is like this:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !edit\.php [NC]
RewriteCond %{REQUEST_URI} ^/([^/]+)/([^/]+)/([^/]+)/?([^/]*)?/?$ [NC]
RewriteRule .* edit.php?key1=%1&key2=%2&key3=%3&key4=%4 [L,QSA]
RewriteCond %{REQUEST_URI} !content\.php [NC]
RewriteCond %{REQUEST_URI} ^/([^/]+)/?([^/]*)?/?$ [NC]
RewriteRule .* content.php?key1=%1&key2=%2 [L,QSA]
Hope I understood what you want.

Resources