I'm out of solutions here after over a week of tries and errors.
I'm looking to add a GET parameter to an URL as a rewrite, if the actual rewrite contains an additional value. For example: /foo should redirtect to index.php?p=test1 and /foo/barshould add a second GET argument, let's name it test so it gets index.php?p=test1&test=something.
My current not working set if the following:
RewriteRule ^/?acadie/lisette/?$ index.php?p=contact_single&id=531&ID_AGENT=1380 [QSA,L,S=1]
RewriteRule ^/?acadie/?$ index.php?p=contact_single&id=531 [QSA,L]
If I add RewriteRule .* - [F] before the second statement, it successfully got 403, so I assume my rule is just ignored at all. If I reverse them, same.
What I'm doing wrong?
I'm running Apache 2.4.29
Related
I am trying to both rewrite and redirect this URL:
https://www.domain.com/video-lessons-page.php?item=stocks
to go to this URL:
https://www.domain.com/stocks-video-lessons
Here is the code I'm currently working with:
RewriteCond %{QUERY_STRING} ^item=([^&]+)
RewriteRule ^/?video-lessons-page\.php$ https://www.domain.com/%1-video-lessons? [R=301,L]
RewriteRule ^(stocks|finance|accounting)-video-lessons$ video-lessons-page.php?item=$1 [NC,L]
Unfortunately with the above code I'm having issues. The first two lines work great by themselves in that it redirects /video-lessons-page.php?item=stocks to /stocks-video-lessons.
And the third line also works great by itself to where the /stocks-video-lessons URL functions correctly with the GET variable and the page's code.
But putting them together is problematic. Right now I'm getting errors like "www.domain.com redirected you too many times." etc. Any ideas?
Just to clarify, presumably you have already changed all your internal URLs to the form /stocks-video-lessons and the reason for the external redirect is because the "ugly" URLs have already been indexed and linked externally?
As you have found, you are getting a redirect loop because these two rules conflict and it's constantly redirecting/rewriting from one to the other.
You need to redirect when only the initial request contains the URL /video-lessons-page.php, not the rewritten URL (which is what's happening here). You can check the initial request by checking against THE_REQUEST server variable (which contains the full HTTP request as sent by the browser).
Something like the following:
RewriteCond %{THE_REQUEST} /video-lessons-page\.php?item=(\w+)
RewriteRule ^video-lessons-page\.php$ https://www.example.com/%1-video-lessons? [R=301,L]
RewriteRule ^(stocks|finance|accounting)-video-lessons$ video-lessons-page.php?item=$1 [L]
Note you must clear your browser cache before testing, since 301 (permanent) redirects will be cached by the browser. (Often easier to test with 302 redirects.) Only use the NC flag if you specifically need a case-insensitive match.
UPDATE: I've changed the regex on the query string parameter value, from ([^&]+) to the slightly more restrictive (\w+). \w being the shorthand character class for a word character (which naturally excludes & and crucially spaces). Since THE_REQUEST contains a string of the form:
GET /video-lessons-page.php?item=stocks HTTP/1.1
...we need to stop capturing before the space. The previous pattern ([^&]+) would have captured everything to the end of the string ie. "stocks HTTP/1.1". So, I would have expected a 404, since an invalid redirect would have occurred but the internal rewrite would have failed. (?)
Thanks to w3dk's guidance, I figured it out, just needed a QUERY_STRING to stay in place in addition to the THE_REQUEST.
Final code:
RewriteCond %{THE_REQUEST} video-lessons-page\.php
RewriteCond %{QUERY_STRING} ^item=([^&]+)
RewriteRule ^video-lessons-page\.php$ https://www.example.com/%1-video-lessons? [R=301,L]
RewriteRule ^(stocks|finance|accounting)-video-lessons$ video-lessons-page.php?item=$1 [L]
I have a very small question. I created a .htaccess file that suppose to rewrite a condition example.com/user/foo/bar as example.com/user.php?username=$1&tab=$2 so username name will be foo and the viewing tab must be bar.
But when there is no bar data provided exactly like example.com/user/foo/ it goes to user with default tab (default tab is generated in script.php file).
But I saw some website that they can do it just like example.com/user/foo, without the / at of the line. When I do example.com/foo to go to user, it says page not found. My correspoding .htaccess line is:
RewriteEngine On
RewriteRule ^user/(.*)/(.*)$ user.php?username=$1&tab=$2 [L]
Please help me with this sitiation.
Your match rule is ^user/(.*)/(.*)$, which means that the second slash must be there (since it's specified), but the text afterwards is optional (since * matches zero or more characters).
Really, I'd add two rewrite rules to do both differently (and to prevent using complicated regex), e.g.
RewriteRule ^user/(.*)/(.*)$ user.php?username=$1&tab=$2 [L]
RewriteRule ^user/(.*) user.php?username=$1 [L]
Alternatively, you can make the 2nd parameter optional:
RewriteRule ^user/([^/]+)/?(?:(.*)|)$ user.php?username=$1&tab=$2 [L]
As long as you don't mind having no value for $_GET['tab']
today i tried to create .htaccess file that replacing ? and = with / ,
test.php code:
<?php
echo $_GET['myparam'];
?>
.htaccess:
i used this writerule:
RewriteEngine On
RewriteBase /
RewriteRule ^test/myparam/([0-9]+)/?$ test.php?myparam=$1 [NC,QSA,L]
ok, i navigated to www.web.com/test.php?myparam=123
there is no redirect to www.web.com/test/myparam/123
so navigated to: www.web.com/test/myparam/123 (Manually) and the php script is worked,
i changed the myparam value to abc instead of 123 : www.web.com/test/myparam/abc
and then it redirects to 404 not found page...(the server don't know that abc is not directory when integer works when string 404)
!so what i want to do:!
www.web.com/ test .php? inttParam = 1 & strrParam = stringhere & p = 1
TO
www.web.com/ test/inttParam/1/strrParam/stringhere/p/1
and when i use $_GET['p'] it will work.
i changed the myparam value to abc instead of 123 and it didn't work
Well of course it won't work since your rule is matching only numbers in the end:
RewriteRule ^test/myparam/([0-9]+)/?$ test.php?myparam=$1 [NC,QSA,L]
change your rule to this to make it work with anything:
RewriteRule ^test/myparam/([^/]+)/?$ test.php?myparam=$1 [NC,QSA,L]
To make it recursion based generic rule to convert /test/inttParam/1/strrParam/stringhere/p/2 to /test.php?p=2&strrParam=stringhere&inttParam=1`:
RewriteRule "^(test)(?:\.php)?/([^/]+)/([^/]*)(/.*)?$" /$1.php$4?$2=$3 [NC,L,QSA]
RewriteEngine on
# do not affect files
RewriteCond %{REQUEST_URI} !(\..{2,4})$
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^(.*)$ index.php?parameter1=$1&%1 [L]
Something like that perhaps?
ok, i navigated to www.web.com/test.php?myparam=123
there is no redirect to www.web.com/test/myparam/123
I don't know if that means that you also want to make a redirection (presumably 301) from the one with GET params to the one with slashes.
If so, I would recommend to use the previous answer from anubhava and handle any 301 redirection with PHP. Actually, you can redirect with "RewriteRule" using the "R" flag, but I admit that I woundn't know how to solve this particular case.
Anyway, I think there is no need, unless old URLs with GET params were working well at SEO and you didn't wan't to lose ranking.
I have a site written in php which creates 'pretty' urls for each item (on category and search pages) like this,
mysite.com/category/slug-for-item-one/1
mysite.com/category/slug-for-item-two/2
The /category/ and /slug/ is dependent upon the numeric id of the item
I have mod_rewrite serve the actual content from urls like this:
mysite.com/view-item.php?id=1
mysite.com/view-item.php?id=2
The content for each item is retrieved using just the items id.
Here's my htaccess:
RewriteEngine on
RewriteRule ^([^/\.]+)/?$ view-item.php?id=$1 [L]
RewriteRule ^([^/\.]+)/([^/\.]+)/?$ view-item.php?pid=$2 [L]
RewriteRule ^([^/\.]+)/([^/\.]+)/([^/\.]+)/?$ view-item.php?id=$3 [L]
Everythings ok so far but, if someone lands on on a url like,
mysite.com/1
mysite.com/catey/slug-for-item-one/1
or
mysite.com/category/slug-item-one/1
the content is still served, but how can I automatically reset or redirect to the canonical version of the url, to:
mysite.com/category/slug-for-item-one/1
I've searched SO and google extensively for an answer, but no luck. I've only used mod_rewrite for simple redirects such as from without www. to with www. and my understanding is tentative thus I'm struggling to understand how to proceed at the moment.
Can anyone point me in the right direction?
Thank you everyone for your help. Much appreciated. I'm working on an implementation of Jon Lin's answer as I'm more familiar with using php/mysql databases and understand how and why it should work. I aim to be done by Friday and will update this page when finished. Many thanks, Karl.
* UPDATE *
I have implemented Jon Lin's answer and now my 'pretty' urls, when mistyped are now redirected to the correct or 'canonical' url just as on SO. Thank you Jon and everyone who contributed!
I think you are going to need two sets of rewrite rules to accomplish this.
The first set of rules would be used to send 301 redirects to the client to ensure they are referencing the canonical URLs:
RewriteRule ^/1 /category/slug-for-item-one/1 [R=301,L]
Then a second set of rules that use passthroughs [PT] to serve up the content:
RewriteRule ^([^/\.]+)/([^/\.]+)/([^/\.]+)/?$ view-item.php?id=$3 [PT,L]
Or something along those lines...
Easy as pie:
RewriteCond %{REQUEST_URI} ^([^/\.]+)/([^/\.]+)/([^/\.]+)/$
RewriteCond %1 !category
RewriteRule ^([^/\.]+)/([^/\.]+)/([^/\.]+)/$ $1/category/$3/
This means: if the request does look like category/slug-for-item-two/2 and the first match is not the word category (whatever it is) then force the redirect to category/slug-for-item-two/2
Please tell me if it works
Update (after your comment):
Here's what should work:
Create 2 map files (see mod_rewrite.html#rewritemap to learn how to do).
Create a mapfile where you put all the categories you need:
RewriteMap mapcategories \
dbm:/web/htdocs/yoursite/rewriterules/categories.map
In the mapfile create simple entries like:
shirts 1
hats 2
condoms 3
vegetables 4
mother-in-laws 5
...
Now do another file with the opposite:
RewriteMap mapcategoriesreverse \
dbm:/web/htdocs/yoursite/rewriterules/categoriesreverse.map
In the mapfile create simple entries like:
1 shirts
2 hats
3 condoms
4 vegetables
5 mother-in-laws
...
Then here you go for the hard part:
RewriteCond %{REQUEST_URI} ^([^/\.]+)/([^/\.]+)/([^/\.]+)/$
# The following rule will try to search into the categories map file
# and if not found, assign CATEGORY to "notfound"
RewriteRule ^([^/\.]+)/([^/\.]+)/([^/\.]+)/$ \
- [QSA,E=CATEGORY:${mapcategories:%1|notfound}]
# if the CATEGORY is not empty and is not found:
RewriteCond %{ENV:CATEGORY} notfound
# do a reverse map to get the *real* category:
RewriteRule ^([^/\.]+)/([^/\.]+)/([^/\.]+)/$ \
- [QSA,E=CATEGORYREVERSE:${mapcategoriesreverse:%1|notfound}]
# if the CATEGORYREVERSE is not empty and is not found:
RewriteCond %{ENV:CATEGORYREVERSE} notfound
# this should never happen => 404:
RewriteRule . - [R=404,L]
# If reach here = if the CATEGORYREVERSE is not empty
# this means it has properly been found:
RewriteCond %{ENV:CATEGORYREVERSE} !^$
# Inject the right category:
RewriteRule ^([^/\.]+)/([^/\.]+)/([^/\.]+)/$ \
%{ENV:CATEGORYREVERSE}/$2/$3/ [QSA]
This way everything is dynamic but it's (much) longer and (a little bit) more complex.
Olivier
This is probably something you want to implement in your view-item.php instead of trying to use mod_rewrite. When you are generating the links internally within your content, you can use the ID's to lookup categories and slugs. This would be how you normally go about generating one of the pretty SEO friendly links.
You first need pass the category and slug into the request. Something along the lines of:
RewriteEngine on
RewriteRule ^([^/\.]+)/?$ view-item.php?id=$1 [L]
RewriteRule ^([^/\.]+)/([^/\.]+)/?$ view-item.php?pid=$2&cat=$1 [L]
RewriteRule ^([^/\.]+)/([^/\.]+)/([^/\.]+)/?$ view-item.php?id=$3&cat=$1&slug=$2 [L]
At the top of your view-item.php, simply check if the cat and slug parameters exist, compare them to the actual category and slug when you do the lookup for the id. If one of them doesn't match (or is missing, if you want), then redirect the browser to the correct link with the correct category and slug using the header() function:
header('HTTP/1.1 301 Moved Permanently');
header("Location: " . $correct_url);
exit();
After they get redirected, the process repeats itself, but this time, view-item.php sees the correct category and slug so the page gets served like normal.
I've following 2 rules in my .htaccess file -
1. RewriteRule ^myscript/([A-Za-z0-9]{0,1})\?page=([0-9]?)$ /myscript.php?action=check&var=$1&page=$2 [L]
2. RewriteRule ^myscript/([A-Za-z0-9]{0,1})$ /myscript.php?action=check&var=$1 [L]
so that visitng /myscript/d sends a request as /myscript.php?action=check&var=d
I am trying to add an option page parameter so that visiting /myscript/d?page=5 sends the requests as /myscript.php?action=check&var=d&page=5
to achieve this I tried this
RewriteRule ^myscript/([A-Za-z0-9]{0,1})\?page=([0-9]?)$ /myscript.php?action=check&var=$1&page=$2 [L]
But this rules is being ignored and the request is sent as /myscript.php?action=check&var=d (i.e. 2nd rule from the above is being applied). What am I doing wrong here? What changes do I need to make it get it working?
Thanks for your help.
Use 2nd rule only and add QSA flag:
RewriteRule ^myscript/([A-Za-z0-9]{0,1})$ /myscript.php?action=check&var=$1 [QSA,L]
This will pass existing query parameter to the new URL:
/myscript/d?page=5&say=hello
=>
/myscript.php?action=check&var=d&page=5&say=hello
Apache documentation: http://httpd.apache.org/docs/current/rewrite/flags.html#flag_qsa