When a a rewrite rule to allow us to make friendly URL's with an ID number. The story is only pulled through the ID number, so the text at the end doesn't really matter.
RewriteRule ^news/([0-9]+)$ /news/$1/ [R=301,L]
RewriteRule ^news/([a-zA-Z0-9_-]+)/.*$ /news/story.php?id=$1
Our problem comes when any file linked within /news/images/ , it gets redirected as well. So anything that displays an image from /news/images/ doesn't work.
Can someone help me out? How can we limit the rewrite so that it says "If it's in the /images/ subdirectory, don't rewrite the path"?
You could take the simple route and just avoid the rewrite if the file exists:
RewriteRule ^news/([0-9]+)$ /news/$1/ [R=301,L]
# Ignore the RewriteRule if the request points to a file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond $1 !=tags [NC]
RewriteRule ^news/([a-zA-Z0-9_-]+)/.*$ /news/story.php?id=$1
Alternatively, if you wanted to do the directory checking in case the resource request didn't point to a real file, but should directly generate a 404 response, you can try the following:
RewriteRule ^news/([0-9]+)$ /news/$1/ [R=301,L]
# Check if the path segment after /news/ corresponds to an existing directory
# and if so, don't perform the rewrite
RewriteRule %{DOCUMENT_ROOT}/news/$1/ !-d
RewriteCond $1 !=tags [NC]
RewriteRule ^news/([a-zA-Z0-9_-]+)/.*$ /news/story.php?id=$1
Related
BEFORE I installed SSL things were working perfectly!! Here is the code I have in my root webserver .htaccess file:
Options +MultiViews
RewriteEngine On
RewriteCond %{HTTP_HOST} andrea\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://andrea.com/$1 [R,L]
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
It works and it does exactly what I want it to do. So if I go to for example:
www.andrea.com/account
it accesses "www.andrea.com/account.php". Which is what I want.
I do however have a folder in root called "products". There is another ".htaccess" file in that folder and I don't know which of these 2 must be changed to make the following thing below work.
When you go to this url:
http:____/products/view/Hello/Goodbye
I want it to access "view.php" in the 'products' folder and in that php file I could do this:
$id = $_GET["id"]; // This would have "Hello"
$cat = $_GET["cat"]; // This would have "Goodbye"
And this works well when I use this htaccess in the "products" folder:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/?(.*)$ /products/view.php?id=$1&cat=$2
The problem with this code above is, if I go to:
http:____/products/Hello/Goodbye
I want it to access the "index.php" that is in "products" folder. But instead it goes to "view.php" instead!! It's like the htaccess code above forced all to go to view.php (which should only be done if I have the "view/____" in the url.
I want the url above to go to "index.php" in the "products" folder and in that file I should be able to access ID and CAT variables.
Any ideas of what to change in my .htaccess file? Sorry I spent over 2 hours I don't understand a single line at the bottom of my code but it doesn't work :/
Options +MultiViews
First off, you should disable MultiViews. In my answer to your earlier question, my suggestion to use MultiViews was strictly an "alternative" method in the context of your question. You cannot use both methods (mod_rewrite and MultiViews) to work with extensionless URLs. And since you are now wanting to do more things and pass parameters, MultiViews will only create conflicts. (MultiViews will likely "win" and no parameters get passed.)
Also, do you specifically need the additional .htaccess file in the /products subdirectory? It will be (arguably) easier to have a single .htaccess file in the document root. This will avoid having to repeat the HTTP to HTTPS redirect (although you've not actually included an HTTP to HTTPS redirect in the subdirectory .htaccess file?).
# /products/.htaccess
RewriteRule ^([^/]*)/?(.*)$ /products/view.php?id=$1&cat=$2
This directive matches both view/Hello/Goodbye and Hello/Goodbye, which explains why everything is being written to your view.php script. However, it's not actually doing what you say either - which is puzzling. If you request /products/view/Hello/Goodbye then it will rewrite the request to /products/view.php?id=view&cat=Hello/Goodbye - which is not the intention (unless MutliViews is enabled, in which case no parameters will be passed at all).
You need to actually check for views in the requested URL-path before attempting to rewrite to views.php. And if views is not present then rewrite to index.php instead. This "conditional branching" can be achieved by simply arranging the directives in the order of "more specific" rules first.
For example, in your root .htaccess file try the following. (And remove the /products/.htaccess file altogether.)
# Ensure that MultiViews is disabled
Options -MultiViews
RewriteEngine On
# HTTP to HTTPS canonical redirect
RewriteCond %{HTTP_HOST} example\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule (.*) https://example.com/$1 [R=301,L]
# Abort early if the request already maps to (or looks like) a file or directory
RewriteCond %{REQUEST_URI} \.\w{2,4}$ [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# 1. Rewrite "/products/view/<id>/<cat>" to "/products/view.php?id=<id>&cat=<cat>
RewriteRule ^(products/view)/([^/]*)/?(.*) $1.php?id=$2&cat=$3 [L]
# 2. Rewrite "/products/<id>/<cat>" to "/products/index.php?id=<id>&cat=<cat>
RewriteRule ^(products)/([^/]*)/?(.*) $1/index.php?id=$2&cat=$3 [L]
# 3. Extensionless URLs for other requests
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
The order of the 3 rules above is important. The most specific rule is first. Including the L flag to prevent further (unnecessary) processing.
Note that, as per your original directives, for a request of the form /products/view/Hello/Goodbye (or /products/Hello/Goodbye), the Hello/Goodbye part is entirely optional and will naturally result in the id and cat URL parameters being set, but empty.
Also, as per your original directives, a request of the form /products/view/Hello/Goodbye/foo/bar/baz will result in the cat URL parameter being set to Goodbye/foo/bar/baz (anything that follows the initial path segment).
You do not necessarily need to check that a request maps to a file or directory (which is relatively expensive) if you make your regex more specific and only match what you need to match. For example, your regex /([^/]*)/?(.*) currently match pretty much anything. But if your <id> and <cat> variables can only consist of lowercase letters (for example) then this could avoid the need for the filesystem checks.
Other notes:
Do you need to check the hostname in the HTTP to HTTPS redirect? Do you host multiple domains? Otherwise the condition that checks against the HTTP_HOST server variable is not required.
You can use the following rule to rewrite /products/Hello/Goodbye to /products/index.php .
RewriteRule ^Hello/GoodBye/?$ /product/index.php?id=hello&cat=Goodbye [L,NC]
Here is your complete /product/.htaccess .
RewriteEngine on
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
#rewrite /products/Hello/GoodBye to /products/index.php
RewriteRule ^Hello/GoodBye/?$ /products/index.php?id=Hello&cat=Goodbye [L,NC]
###################
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)/?(.*)$ /products/view.php?id=$1&cat=$2
I've been asked to make an existing web site multi-language.
In preparation for this I have had to move all existing pages from /path/page to /en/path/page
To maintain any existing incoming links I now need to set up an htaccess redirect to send any requests from their original urls to the new /en/path/page urls but I'm having trouble getting this to work.
This is what I currently have;
RewriteCond %{REQUEST_URI} !^/en$
RewriteRule ^(.*)$ /en/$1 [R=301,L]
Which I think is meant to check the requested URI and if it doesn't begin with /en then prepend /en onto the requested URI... but I'm obviously mistaken since it doesn't work.
Any help appreciated. Thank you.
UPDATE.
Since this is an ExpressionEngine site and there is an additional rule to remove the index.php portion of the URL here are both rules
# Rewrite for new language based urls
# This is to try and get all current pages going to /en/(old url) with a 301 redirect
RewriteCond %{REQUEST_URI} !^/en(/.*)?$
RewriteRule ^(.*)$ /en/$1 [R=301,L]
# Removes index.php
RewriteCond $1 !\.(gif|jpe?g|png|ico)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
I have also tried this with the language rewrite after the index.php one. I'm still getting stuck in loops.
What it does is, checking whether the URI is not exactly /en, since the $ indicates the end of the string right after en.
Try this, it checks whether the URI is not exactly /en or /en/ or doesn't start with /en/, and if that's the case it will prepend /en/:
RewriteCond %{REQUEST_URI} !^/en(/.*)?$
RewriteRule ^(.*)$ /en/$1 [R=301,L]
update Considering the other rules you have in your .htaccess file, it is necessary to have the language rule not match again for the following internal redirect to /index.php..., otherwise you'll end up with an endless loop.
There may be better ways to prevent this, however the first thing that comes to my mind would be checking for index.php in the first condition:
RewriteCond %{REQUEST_URI} !^/(index\.php|en)(/.*)?$
So this will cause the rule not to apply after the internal redirect. But be careful, this solves the problem for this specific case only in which the internal redirect goes to index.php!
I have a website running at localhost/pm and the RewriteBase is correctly set to /pm/. There is a link tag in my document: <link ... href="themes/default/css/default.css">.
When the url is localhost/pm or localhost/pm/foo the CSS works all right. When there are more slashes in the URL, however, like localhost/pm/foo/bar the relative URL if the stylesheet changes to foo/themes/default/css/default.css.
How do I get this to work without having to put some sort of PHP path resolution in the link tag?
# invoke rewrite engine
RewriteEngine On
RewriteBase /pm/
# Protect application and system files from being viewed
RewriteRule ^(?:system)\b.* index.php/$0 [L]
# Allow any files or directories that exist to be displayed directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite all other URLs to index.php/URL
RewriteRule .* index.php/$0 [PT]
EDIT:
Basically what I need now is this:
If request contains folder name /themes/ scrap everything that is before /themes/ and rewrite the rest to /pm/themes/...
I tried it like this: RewriteRule ^.*(/themes/.*)$ /pm/themes/$1 but I get an internal server error. Why?
If I do it like this: RewriteRule ^.*(/themes/.*)$ /pm/themes/ (ie. just remove $1 from the end) and use the URL http://localhost/pm/foo/themes/foo/ the resulting physical location is http://localhost/pm/themes which is what is expected too, which in turn means that at least my regex is correct. What am I missing?
The RewriteRule is almost correct
RewriteRule ^.*(/themes/.*)$ /pm/themes/$1
This rewrites http://localhost/pm/foo/themes/default/css/default.css to http://localhost/pm/themes/themes/default/css/default.css, which is one themes too much. Use this instead
RewriteRule /themes/(.*)$ /pm/themes/$1 [L]
But now you have an endless rewrite loop, because /pm/themes/.. is rewritten again and again. To prevent this, you need a RewriteCond excluding /pm/themes
RewriteCond %{REQUEST_URI} !^/pm/themes/
RewriteRule /themes/(.*)$ /pm/themes/$1 [L]
Now the request is rewritten only once and you're done.
You probably need to add the following lines before your RewriteRule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
It will only evaluate your rewrite rule if the requested file or directory doesn't exist.
You should post your .htaccess file so we can offer better advice
I'm somewhat new to htaccess rewrite rules, and have been scratching my head for the past few days on what's happening here. No amount of Googling seemed to help, so hopefully somebody knows the answer.
I have a site that can be accessed as:
www.site.com
www.site.com/684
www.site.com/684/some-slug-name-here
All of these scenarios should go to index.php and pass in the optional id=684 and slug=some-slug-name-here
Which works fine.
My problem is I have a separate file. Right now it's called admintagger.php - but this fails when I call it anything. 21g12fjhg2349yf234f.php has the same issue.
The problem is that that I would like to be able to access admintagger.php from www.site.com/admintagger
but it seems to be matching my rule for index, and taking me there instead.
Here is my code:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteRule ^imagetagger$ /imagetagger.php [NC,QSA]
RewriteRule ^([0-9]+)/?(.*)?/?$ index.php?id=$1&slug=$2 [NC,L,QSA]
If you want to arbitrarily be able to access php files via the name (sans extension) then you need to create a general rule for it. But you need to be careful otherwise you may be rewriting legitimate requests for existing resources (like a directory, or a slug). Try this instead:
# make sure we aren't clobbering legit requests:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# see if appending a ".php" to the end of the request will map to an existing file
RewriteCond %{REQUEST_FILENAME}.php -f
# internally rewrite to include the .php
RewriteRule ^(.*)$ /$1.php [L]
Then you can have your routing to index.php right after that:
RewriteRule ^([0-9]+)/?(.*)?/?$ index.php?id=$1&slug=$2 [NC,L,QSA]
Although you may be better off create a separate rule for each of your 3 cases:
RewriteRule ^([0-9]+)/([^/]+)/?$ /index.php?id=$1&slug=$2 [NC,L,QSA]
RewriteRule ^([0-9]+)/?$ /index.php?id=$1 [NC,L,QSA]
RewriteRule ^$ /index.php [L]
I’m trying to use the following .htaccess file
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^images/
RewriteRule (.*) view.php?picid=$1 [L]
RewriteRule ^/user/(.*)$ /users.php?user=$1
I want two things to happen: Whenever someone requests /1234, it redirects to /view.php?picid=1234, and also when someone visits /users/bob, it redirects to /users.php?user=bob.
My code however, doesn’t seem to be working correctly.
There are several ways to do that. Here’s one that should work:
RewriteRule ^user/(.+)$ users.php?user=$1 [L]
RewriteRule ^([0-9]+)$ view.php?picid=$1 [L]
The first rule will catch any request that’s URI path begins with /user/ followed by one or more arbitrary characters. And the second will catch any request that’s URI path begins with / followed by one or more digits.
The initial problem with your rules is that the RewriteRule with (.*) will match everything.
If you do not want it to match a URL with a slash in it (such as users/bob), try ^([^/]*)$
Secondly, after a URL is rewritten, the new URL goes through your rules again. If you want to avoid matching something that has already been rewritten once, you should add a condition like
RewriteCond %{REQUEST_URI} !\.php