Removing the last slash from query parameter using .htaccess - php

I want to remove the last slash character from query parameter's value using .htaccess.
Suppose I have the following URL:
www.example.com/?key_=/job_category/mobile/
Then from /job_category/mobile/ I want to remove the last slash.
After removing the last slash, it would redirect to www.example.com/snapshots/job_category/mobile.html, but with my current settings it redirects to www.example.com/snapshots/job_category/mobile/.html.
My current .htaccess file looks like this:
RewriteEngine On
RewriteCond %{QUERY_STRING} ^key_=(.*)$
RewriteRule ^(.*)$ snapshots/%1.html [R=301,QSD]

You don't need to capture anything in RewriteRule, as all necessary information is already captured by RewriteCond. To remove the trailing slash use an expression like \/*$ (zero or more slashes at the end):
RewriteEngine on
RewriteCond %{QUERY_STRING} ^key_=(.*?)\/*$
RewriteRule ^.*$ /snapshot%1.html [R=301,QSD]

Related

.htaccess redirect /subpage/ to /subpage?/wp-login

Trying to use .htaccess rule to do the wp-login JS check on first visit by appending ?/wp-login to the url since it's interferring with Sucuri firewall when using password protection.
I've created a test subdomain to try to get the htaccess redirect to work before using it on the live site:
RewriteCond %{QUERY_STRING} ^protectedpage$
RewriteRule ^(.*)$ https://testing.no11.ee/protectedpage?/wp-login [R=302,L]
view here: testing.no11.ee/protectedpage
Unfortunately this does not add the query arg to the url. What am I doing wrong here?
Expected result when visiting page should be https://testing.no11.ee/protectedpage?/wp-login as the browser url.
Full htaccess:
# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
RewriteCond %{QUERY_STRING} ^protectedpage$
RewriteRule ^(.*)$ https://testing.no11.ee/protectedpage?/wp-login [R=302,L]
</IfModule>
# END WordPress
RewriteCond %{QUERY_STRING} ^protectedpage$
RewriteRule ^(.*)$ https://testing.no11.ee/protectedpage?/wp-login [R=302,L]
This checks that the QUERY_STRING is set to protectedpage, but in your example it's the URL-path that is /protectedpage, not the query string.
You also need to first check that the query string is not already set to /wp-login, otherwise you'll get a redirect loop.
However, you've also put the code in the wrong place. Note the WordPress comment that precedes the code block - you should not manually edit this code. This directive also needs to go before the WordPress front-controller, otherwise, it's simply never going to get processed.
Try the following instead before the # BEGIN WordPress comment marker:
RewriteCond %{QUERY_STRING} !^/wp-login$
RewriteRule ^(protectedpage)/?$ /$1/?/wp-login [R=302,L]
This matches an optional trailing slash on the requested URL, but it redirects to include the trailing slash in the target URL.
(You do not need to repeat the RewriteEngine on directive.)
No need to include the scheme + hostname if you are redirecting to the same. The $1 backreference simply saves repetition and refers to the matched URL-path, ie. protectedpage (without the trailing slash) in this example.
However, this always redirects and appends /wp-login to this URL - not just the "first visit" - is that really what you require? Otherwise, you need to somehow differentiate between "first" and "subsequent" visits (by detecting a cookie perhaps?)
UPDATE: Minor addition: how would one improve this to add ?/wp-login to all urls that have the page /subpage/ as parent i.e /subpage/page-1 and /subpage/page-2 would result in /subpage/page-1?/wp-login etc? I tried using (.*) but this delets the subpage from the url...
You could do something like the following:
RewriteCond %{QUERY_STRING} !^/wp-login$
RewriteRule ^(subpage/[^/]+)/?$ /$1/?/wp-login [R=302,L]
The [^/]+ subpattern matches any character except / - so only the second path segment, excluding the optional trailing slash. This is similar to .*, but this would capture everything, including any trailing slash, so would result in a double slash in the redirected URL.

Redirect rule to php query but remove any query string in the requested url

My url is being redirected using .htaccess as follows:
RewriteRule ^b/([^/]+)/([^/]+)? b/view.php?id=$2&name=$1
Friendly url -> translates to php url
domain.com/b/hello/2 -> b/view.php?id=2&name=hello
BUT when someone comes to the site as follows:
domain.com/b/hello/2?query=xyz
I don't know how to get rid of the ?query=xyz
I have tried everything including [QSD] and I can't seem to get it to work.
Update
I have managed to get it to work with the following but it does two 301 redirects instead of one:
RewriteCond %{THE_REQUEST} \?[^\ ]+
RewriteRule ^b/(.*)$ /x/$1? [R=301,L]
RewriteRule ^b/([^/]+)/([^/]+)/([^/]+)?$ b/view.php?id=$2&&name=$1
Check if adding the question mark at the end of the rule will cancel appending query string from left side
RewriteRule ^b/([^/]+)/([^/]+)? b/view.php?id=$2&name=$1? [QSD,L]
You can use an additional Rule to catch for GET parameters and strip them off.
RewriteCond %{QUERY_STRING} .+
RewriteRule ^(.*)$ /$1? [R=301,L]
RewriteRule ^b/([^/]+)/([^/]+)? b/view.php?id=$2&name=$1
To make it only work on the /b/ subfolder, use this:
RewriteCond %{QUERY_STRING} .+
RewriteRule ^b/(.*)$ b/$1? [R=301,L]
RewriteRule ^b/([^/]+)/([^/]+)? b/view.php?id=$2&name=$1
The first rule will redirect everything that matches your rule to the URL without any GET parameters (note the ? at the end of the rewrite rule, it will strip off the parameters).
The second rule will match in the case the first rule cannot be applied, i.e., when there are no paramaters

htaccess rewrite a multi-query string into a path

How would i go about changing the query string
file.php?id=number&string=some-words
into this
file/number/some-words/
I know this has been asked a million times before, but I've looked at a number of solutions on here and they were all single query based (as in just ?something and not ?something&something-else).
Also once rewritten, does the php still read the original page query-string when using $_GET or $_REQUEST etc... even though it now appears as a path?
Any help is appreciated.
Thanks.
RewriteRule takes a regular expression which can be as complicated as you want it followed by the real URL that will load your file. You put parenthesis around the parts you want to capture in the regex and can reference those with $1 for first group, $2 for second group and so on in the URL part. For example:
RewriteRule ^(\w+)/(\d+)/(.*)$ index.php?file=$1&id=$2&words=$3
This would match 3 groups:
letters/numbers up to the first slash
some numbers up to the second slash
anything after that including additional slashes
And those can be referenced by $1, $2, $3 as seen in the second part with index.php.
The only issue with this though is that if you are missing any one part, the pattern in the rule won't match. So you either need to have a separate rule for each variant:
#matches all 3 parts
RewriteRule ^(\w+)/(\d+)/(.*)$ index.php?file=$1&id=$2&words=$3
#matches the first 2 parts
RewriteRule ^(\w+)/(\d+)$ index.php?file=$1&id=$2
#matches just the first part
RewriteRule ^(\w+)$ index.php?file=$1
#matches everything else
RewriteRule ^.*$ index.php
Or you can do what is usually called bootstrapping which is where you use a single RewriteRule to redirect everything to a single php file like so:
RewriteRule ^(.*)$ index.php
And then you can just use php to determine what the different parts are. Inside php there is a built in server variable $_SERVER['REQUEST_URI'] that will give you the URI part of the url which is everything after the domain and first slash including any query string parameters. This is based on the URL that the user requested and not the one rewritten by apache. You can explode('/', $_SERVER['REQUEST_URI']) to get the individual parts and do whatever you want with them.
You can place your code in Apache .htaccess files. This could look something like this:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^users/(\d+)*$ ./profile.php?id=$1
RewriteRule ^threads/(\d+)*$ ./thread.php?id=$1
RewriteRule ^search/(.*)$ ./search.php?query=$1
Or you can use only htaccess and php:
htaccess
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^.*$ ./index.php
PHP
<?php
#remove the directory path we don't want
$request = str_replace("/envato/pretty/php/", "", $_SERVER['REQUEST_URI']);
#split the path by '/'
$params = split("/", $request);
?>
And it will still read the original page query-string.

.htaccess rewriterule not working

I have created a .htaccess rewiterule, but it is not doing anything.
The rule is :
RewriteEngine On
RewriteRule ^([^/]*)/([^/]*)\.html$ /showproduct.php?get-uid=$1&prod=$2 [L]
What I want to happen is that the following URL:
http://naturesgifts.co.nz/showproduct.php?get-uid=8&prod=whitesagespray
Changes to:
http://naturesgifts.co.nz/8/whitesagespray.html
However no redirect happens.
Please help.
RewriteCond %{QUERY_STRING} get-uid=([^&]+)&prod=([^&]+)
RewriteRule ^showproduct.php$ /%1/%2.html? [R=301,L]
Line 1: check if the query string contains the param get-uid and the param prod, [^&] matches any characters except & character
Line 2: if the request uri matches to showproduct.php exactly, redirect to /%1/%2.html permanently. %1 is the backreference to the first capture group ([^&]) whereas %2 matches the second capture group. [R=301] flag makes it redirect permanently.

rewrite a folder so all files display under new rewrite rule

Is there a way that I can rewrite a folder so that all the files under that folder follow the same rule? For example:
if i have a folder with say 5 php files (a.php, b.php, c.php, d.php, index.php) in it and i use the following rule:
RewriteRule ^products/storage/?$ /content/products/storage/index.php [QSA,L]
is there a way that I can get all the files to show to be accessed like: site.com/products/apples/a.php, site.com/products/apples/b.php, etc. without having to write a rule for each one?
I tried the following but it didnt work.
RewriteRule ^products/storage/?$ /content/products/storage/ [QSA,L]
I also need it to NOT overwrite my other rules such as:
RewriteRule ^products/storage/?$ /content/products/storage/product-name1/ [QSA,L]
RewriteRule ^products/storage/?$ /content/products/storage/product-name2/ [QSA,L]
any ideas?
Your problem is the trailing $ on the end of the regex. This will only allow a match if the full URI matches products/storage (with optional trailing slash) exactly. Instead, try the following and note the absence of the trailing $ character:
RewriteRule ^products/storage/? /content/products/storage/ [QSA,L]
This will match anything that starts with products/storage (with optional trailing slash). Alternatively, if you wanted to capture and re-use everything in the URI that followed products/storage/ you could try:
RewriteRule ^products/storage(/?.+)?$ /content/products/storage$1 [QSA,L]
UPDATE
Should you need to preserve other RewriteRules as your updated question suggests, you should look to add a RewriteCond condition like so:
RewriteCond !^products/storage/?$
RewriteRule ^products/storage(/?.+)?$ /content/products/storage$1 [QSA,L]
The RewriteCond tells the RewriteRule to only process if the condition is not met.

Categories