I have a django app running on a subdomain, subdomain.domain.com/appname, but I don't want the app name to show up in any of my urls. I have accomplished this via .htaccess
RewriteEngine On
RewriteCond %{REQUEST_URI} !admin
RewriteCond %{REQUEST_URI} !appname
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /appname/$1 [L]
This accompishes the case where the requested url is subdomain.domain.com/home and it is served from subdomain.domain.com/appname/home.
However, I'd also like to accomplish the reverse, where the requested url is subdomain.domain.com/appname/home, and the displayed url changes to subdomain.domain.com/home, which then triggers the rule above and is served from subdomain.domain.com/appname/home
I tried the following but got an error that I have a loop
RewriteEngine On
RewriteCond %{REQUEST_URI} appname
RewriteRule ^appname/(.*)$ /$1 [N,R=301]
RewriteCond %{REQUEST_URI} !admin
RewriteCond %{REQUEST_URI} !appname
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /appname/$1 [L]
Try without the 'N' flag:
'next|N' (next round)
Re-run the rewriting process (starting again with the first rewriting rule). This time, the URL to match is no longer the original URL, but rather the URL returned by the last rewriting rule. This corresponds to the Perl next command or the continue command in C. Use this flag to restart the rewriting process - to immediately go to the top of the loop.
Be careful not to create an infinite loop!
http://httpd.apache.org/docs/current/mod/mod_rewrite.html
Related
I am simply trying to rewrite automatically this:
From: mysite.com/channel.php?id=BBC&name=British Broadcasting Company &date=today
To: mysite.com/channel-britishbroadcastingcompany-today.html
I've tried with:
RewriteRule ^channel-(.*)-(.*)\.html$ /channel.php?id=1&name=$2&date=$3 [R]
But nothing happens.
Hope this simplest one will help you out. This will redirect if
1. REQUEST_URI is /channel.php
2. QUERY_STRING matches this pattern id=something&name=something&date=something
Redirect this to /channel-%1-%2.html here
1. %1 will hold value of name parameter
2. %2 will hold value of date parameter
RewriteEngine on
Options -MultiViews
RewriteCond %{REQUEST_URI} ^/channel\.php$
RewriteCond %{QUERY_STRING} id=.*?&name=(.*?)&date=(.*)
RewriteRule .* /channel-%1-%2.html? [R=301]
As per the requirement specified by OP to first redirect url on html page on the basis of some query parameters then rewriting the request on previous page. So the complete code of .htaccess will be like this.
RewriteEngine on
Options -MultiViews
RewriteCond %{REQUEST_URI} ^/channel\.php$
RewriteCond %{QUERY_STRING} id=.*?&name=(.*?)&date=(.*)
RewriteRule .* /channel-%1-%2? [R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/channel\-(.*?)\-(.*?)
RewriteRule .* /channel.php? [L]
Explanation of 2nd part which is added.
1. REQUEST_FILENAME if file does not exist as a file and directory.
2. REQUEST_URI If request_uri starts with such pattern channel-somewords-somewords
then rewrite request on /channel.php
If I understand the problem correctly, You currently have a file channel.php and what You want to achieve is get more "friendly" URLs for SEO and general aesthetics in the browser location bar but still have channel.php handle your requests.
If this is really the case then You need a two-way rewrite.
First, You need to take your original URL and redirect it to a new, pretty version.
Second, You need to rewrite this pretty URI internally and still feed it to channel.php behind the scenes.
RewriteEngine On
RewriteBase /
# This part rewrites channel.php?name=X&date=Y into channel-X-Y.html
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_METHOD} =GET
RewriteCond %{QUERY_STRING} (.*\&)?name=([^&]+)\&date=([^&]+)(?:\&(.*))?
RewriteRule ^channel.php$ channel-%2-%3.html?%1%4 [R,L,NE]
# This part rewrites it back into channel.php but keeps the "friendly" URL visible
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^channel-(.*)-(.*).html$ channel.php?name=$1&date=$2 [L,QSA]
Note that the first rule-set limits the rewrite to method GET - otherwise You will lose any submitted POST data.
It also allows for any other query-string parameters to surround name and date (the rest of query-string parameters will pass-through to .html URI and then will be picked back up by channel.php)
Also note the ENV:REDIRECT_STATUS rule - this is crucial, without that part You'll be stuck in redirect loop.
See
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-s
RewriteRule ^([a-z0-9-_.]+)/?$ index.php?id=$1 [NC,L]
RewriteRule ^([a-z0-9-_.]+)/([a-z0-9]+)/?$ index.php?id=$1&goto=$2 [NC,L]
What it's going to do is check the index.php and replace to some like, site/dir/index.php to site/dir/namehere than in index.php you can use explode() to separate the values of current url ang get the variables
I am assuming you are asking for rewrite although you are using redirect flag in your current rules, and also assuming BBC to be static in id variable then try with below,
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^channel-([^/]+)-([^/]+).html$ channel.php?id=BBC&name=$1&date=$2 [L]
I'm having some problems rewriting URLs with the following rules
RewriteEngine on
RewriteRule ^page/(.*)$ index.php?pag=cms&title=$1 [NC]
RewriteRule ^admin/(.*)$ admin/$1 [NC]
RewriteRule ^(.*)$ index.php?pag=$1 [NC,L]
What I'm trying to achieve is to check if the URL is a cms page or not and leave admin URLs as they are.
If I remove the last condition it works but I will have no rule for not cms pages.
Ideally I would want to have just one rule for every page (cms or not) but I can't figure out how to check that other than using page/ in the URL.
Mod_rewrite will keep looping through all the rules until the URI stops changing (or it reaches its internal redirect limit, resuling in a 500 error). You need to add a few conditions to the last rule so that it won't rewrite URI's that's already been properly routed:
RewriteRule ^page/(.*)$ index.php?pag=cms&title=$1 [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?pag=$1 [NC,L]
Additionally, the second rule does nothing except a passthrough, so you can replace it with
RewriteRule ^admin/(.*)$ - [NC,L]
You need these rules:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
From the Apache documentation:
'-d' (is directory)
Treats the TestString as a pathname and tests whether or not it exists, and is a directory.
'-f' (is regular file)
Treats the TestString as a pathname and tests whether or not it exists, and is a regular file.
I want to have all the URLs on my site handled by a single script. So I put in a rewrite rule like this:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /myscript.php?p=$1 [L]
But I don't want to allow access to my script on URLs that actually contain "myscript.php" in them so I would like to redirect those back to the main site:
Redirect 301 /myscript.php http://example.com/
The problem is that if I put both of those rules into my .htaccess file it causes an infinite loop. How do I get them both to work at the same time?
I would also like to be able to redirect things like:
/myscript.php?p=foo -> /foo
You can set an environment variable
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !myscript\.php
RewriteRule (.*) /myscript.php?p=$1 [L,E=LOOP:1]
and test for that in your second rule
RewriteCond %{ENV:REDIRECT_LOOP} !1
RewriteRule ^myscript\.php$ / [R,L]
Never test with 301 enabled, see this answer Tips for debugging .htaccess rewrite rules for details.
Using an environment variable is perfectly OK, however, you don't need to manually set this environment variable yourself. Apache provides the REDIRECT_STATUS environment variable which can be used for this purpose.
REDIRECT_STATUS is empty (or not set) on the initial request. It is set to 200 on the first (successful) internal rewrite. Or some other HTTP status code in the case of an error (404 etc.).
So, instead of checking that REDIRECT_LOOP is not 1, we can simply check that REDIRECT_STATUS is empty to ensure we are testing the initial request and not the rewritten request. For example:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^myscript\.php$ / [R,L]
(Note that it is just REDIRECT_STATUS, there is no STATUS variable at the start of the request.)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !myscript\.php
RewriteRule (.*) /test/myscript.php?p=$1 [L,E=LOOP:1]
Aside: The RewriteCond directive that checks against the REQUEST_URI doesn't really do anything here. If the first condition is true (ie. it's not a file), then this condition must also be true. However, it could be optimised by including this condition first. This would then avoid the file check on every request (including the rewritten request). For example:
RewriteCond %{REQUEST_URI} !^/test/myscript\.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /test/myscript.php?p=$1 [L]
Or, you could include a pre-check (an exception) before this rule instead that halts processing when myscript.php is requested:
RewriteRule ^test/myscript\.php$ - [L]
However, if you do this, then the above canonical redirects must appear before these rules, otherwise they will never be processed. (Putting the canonical redirects first is generally preferable anyway.)
I have one hosting account that I am running using to run multiple sites, masterhost.com. Under masterhost.com I have site1.com, site2.com, etc... and am using this piece of code in the masterhost directory to reroute the domain request from the masterhost directory to the site1 directory.
RewriteCond %{HTTP_HOST} ^(www.)?site1.com$
RewriteCond %{REQUEST_URI} !^/site1/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /site1/$1/
RewriteCond %{HTTP_HOST} ^(www.)?site1.com$
RewriteRule ^(/)?$ site1/index.php
However Joomla on site1.com is having some issues with with this, and is routing the default images path back to masterhost.com/images.
Is there a rewrite I could use that would recognize any request http://www.site1.com/images and write it to http://www.masterhost.com/site1/images?
I believe the problem is these two lines:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Basically, if the image exists on mainsite.com, these rules will prevent the request from being redirected to site1. So, for example, if you have mainsite.com/img/logo.png and site1.com/img/logo.png, site1.com would show the logo for mainsite.com.
Also, with this rule:
RewriteRule ^(.*)$ /site1/$1/
I don't believe the trailing slash should be there.
Finally, you didn't ask about it, but the last rule probably also doesn't work? If it does, removing the !-f and !-d checks above will break it. This would be because if a user requests site1.com/, the first rule redirects that to /site1/, which will never match the rule ^(/)?$. So, that rule needs to be changed to:
RewriteRule ^site1(/)?$ site1/index.php
You may or may not need a slash between ^ and site1 in that rule, depending on your RewriteBase directive.
i have a strange apache mod_rewrite problem. I need to hide a sub-directory from the user, but redirect every request to that sub-directory. I found several quite similar issues on stackoverflow, but nothing really fits, so i decided to post a new question.
My .htaccess looks like this:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)?$ foo/$1 [QSA,L]
The document-root only contains the following folder/files:
/foo/bar/index.html
I would now expect that example.com/bar and example.com/bar/ would just show me the contents of index.html.
Instead example.com/bar/ show me the content as expected but example.com/bar redirects me with a 301 to example.com/bar/foo/ an then shows the contents. I really don't get why there is a 301 redirect in this case.
When i put something this
RewriteCond %{REQUEST_URI} !^[^.]*/$
RewriteCond %{REQUEST_URI} !^[^.]*\.html$
RewriteCond %{REQUEST_URI} !^[^.]*\.php$
RewriteRule ^(.*)$ $1/ [QSA,L]
on top of that rule it seems to work, but that would require me to list every used file extension...
Is there any other way i can omit the redirect, the folder "bar" should never be seen by an outside user.
Thanks in advance!
1st rewrite rule is redirect from /foo/(.) to ($1) and second - from (.) to $1.
just idea, this has not been tested.
Better late than never...
Got it working with a simple RewriteRule which append a / to every url that doesn't have on.
# only directories
RewriteCond %{REQUEST_FILENAME} !-f
# exclude there directories
RewriteCond %{REQUEST_URI} !^/excluded-dirs
# exclude these extensions
RewriteCond %{REQUEST_URI} !\.excluded-extension$
# exclude request that already have a /
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ /$1/ [R=301,L]