Rewrite Urls without breaking real files - .htaccess

So i'm pretty terrible at RewriteRule and .htaccess, and I've been trying to create a RewriteRule which allows me to redirect any request that doesn't already exist in the directory through index.php.
It looks like this at the moment:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?name=$0 [L]
However once I started trying to run ajax requests from a redirected url it breaks and returns the whole redirected page instead of the return data of any script that is in the directory. I'm pretty confused as to how I can make this work. \
What I want to be able to do is to be able to rout every non-real request through index.php and every other request as normal.

You could sneak in another RewriteCond using a RegEx, in case you can find one (or more) for you normal requests. Something like
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !^*your* *RegEx* *for* *normal* *request*
RewriteRule ^(.*)$ index.php?name=$0 [L]

Your htaccess code is correct. "-f" checks for a valid file and "-d" for a valid directory.
My guess is that you issuing relative ajax requests from an url like /some-dir/another-path/ which is internally rewritten to index.php?name=/some-dir/another-path/. A relative ajax request to ie my-ajax-data.php will be made to /some-dir/another-path/my-ajax-data.php, and not /my-ajax-data.php as you might think. Try using absolute URLs in the ajax requests. Well, it's just a shot in the dark.

Related

URL Rewriting using .htaccess

I'm trying to get a url to rewrite using htaccess but can't seem to get it working.
I'm trying to rewrite http://website.com/pages/blog/article.php?article=blog-entry so that it can be entered as http://website.com/pages/blog/blog-entry but i'm getting an error when I try the following:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^pages/blog/(.+)$ pages/blog/article.php?article=$1 [NC,L]
Can anybody see where i'm going wrong as this just gives me a 404 error. Thanks in advance.
Use this rule inside /pages/blog/.htaccess:
RewriteEngine on
RewriteBase /pages/blog/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([\w-]+)/?$ article.php?article=$1 [QSA,L]
I'm trying to rewrite
http://website.com/pages/blog.php?article=blog-entry so that it can be
entered as http://website.com/pages/blog/blog-entry but i'm getting an
error when I try the following:
RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-d RewriteCond
%{REQUEST_FILENAME}\.php -f
RewriteRule ^pages/blog/(.+)$ pages/blog/article.php?article=$1
[NC,L]
Your wording is confusing, but I believe this is what you mean:
The real url is: http://website.com/pages/blog.php?article=blog-entry
you want to be able to use a 'friendly' url: http://website.com/pages/blog/blog-entry to point to the real url.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^pages/blog/(.+)$ /pages/blog/article.php?article=$1 [QSA,L]
The first two tests ask: is this a directory that exists? is this a file that exists? Because article.php is a file, it won't be included in this action, so you won't enter into an endless loop, which is always the risk with incorrectly done rewrite rules.
Take the given url, and use query string append (QSA) to attach the desired data to the actual file that will process the request. This is not a rewrite in that the url the user sees does not change, this only happens internally in apache, which sends the request to the desired target, with the desired information.
You have to test if the file or directory exists because otherwise you'd be applying this rule incorrectly, since it should only be applied when the target does NOT exist. This is basically how all blog/cms 'search engine friendly urls' work, more or less.
Last, since the target is /blog.php?article=blog-entry you can't skip the leading /.
However, it's unclear to me why you'd want the friendly url to be so long, when you can just make it short, and friendlier: like, pages/[article-name]

Rewrite and redirect dynamic url with .htacces

Ok so my website has a dynamic url like this web.com/?city=London I want to change it to web.com/London
While I found the code for rewrite i'm struggling to find one that changes and immediatly redirects people to url in that format.
Well, you could do this:
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} (?:(.*)&)city=([^&]+)(.*)
RewriteRule ^(index.php)?$ %2?%1%3 [R,L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !\.(js|css|jpe?g?|png|gif)$
RewriteCond %{REQUEST_URI} !^index.php
RewriteRule ([^/]+) index.php?city=$1 [L,QSA]
The first part is responsible for rewriting the original URLs to the "pretty" format and redirect the browser to it
Note that the first part only actually rewrites empty uri and "index.php" (assuming thats your directory index file).
The second part, rewrites the request "back" to index.php?city=London, and then serves the newly created request by a sub-request (hiding the real url from the browser).
However, note that this results in an unnecessary redirects of the browser, so instead of relying heavily on part 1 of this scenario, you should consider reconstructing the urls within the server-side application, so they will appear in the "correct" form to begin with.

.htaccess. Redirect requests to ~username folder

Situation:
I'm moving a website from a production environment to a test environment.
The test environment url is similar to http://192.168.1.100/~username/
There are thousands of files which use the following within the html
<img src='/images/image.jpg' />
Since the request is going to root http://192.168.1.100/ the files are 404.
Rather than finding and replacing all of html I'd assume that there is an easy way to fix it with mod_rewrite via .htaccess.
I've tried using the following
RewriteCond %{REQUEST_URI} !^/~username/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /~username/$1
But did not work as expected.
Thanks in advance.
UPDATE
The development environment resides within cpanel/whm. So when the username is removed from the requested url, it now belongs to the root users. So, my question now: How do I update the .htaccess file for the root user to mod_rewrite back to the ~username?
If you remove
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
it appears to work as expected, because any request to the right url will not be rewritten.
you might want to add [L] as a flag to signify it's the last rewrite rule, like so:
RewriteCond %{REQUEST_URI} !^/~username/
RewriteRule ^(.*)$ /~username/$1 [L]

mod_rewrite redirect for non-existent URL's

I've got a an old website that I've taken over. New users essentially get a custom page created for them. It was done in a less than fantastic manner. Currently it actually generates a file named for the slug URL created and symbolically links it to a folder called "/main/". Obviously I want to change this. My plan was simply to have it redirect non-existant folders to "/main/" via .htaccess. Currently this is what my .htaccess looks like:
RewriteEngine on
RewriteCond $1 !^(index\.php|images|robots\.txt|index\.htm)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /main/ [L]
However this generates a redirect loop. What am I missing?
Edit
On that note, I realized I should say I want it to maintain the path that's input. For example if I put http://www.mydomain.com/test_person it should maintain that address, but forward everything to the main folder if that makes sense.
You'll want your rule to not rewrite URLs already beginning with main in order to not have it loop, eg:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !^main/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^[^/]+/(.*)$ /main/$1 [L]
[L] doesn't really mean what you would think [L] should mean in the context of a .htaccess file.
You should be able to get the original url requested from the REQUEST_URI environment variable, but a common thing to do is to pass the slug to the target as a GET variable.
RewriteRule ^([^/]+)/(.*)$ /main/$2?user=$1 [QSA,L]
Or pass everything to a single script which interprets the URL and finds the correct content to return:
RewriteRule ^([^/]+)/(.*)$ /main/index.php?user=$1&path=$2 [QSA,L]

.htaccess Check for file in two locations, otherwise throw 404

The way my site is currently structured, the actual site is in its own separate folder. Here's what I mean:
/projects
/files
/pictures
/tools
/school
/~webroot
.htaccess
This makes the file-system much easier to manage and navigate. An easy way to utilize this, without having everyone navigate to http://domain.com/~webroot/, and still allow them to access files and such like http://domain.com/projects/, is to use the htaccess I wrote below to check for files in both the real root, and ~webroot directories.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /~webroot/$1 [NC,QSA]
RewriteRule ^/?$ /~webroot/index.php [L,QSA]
However, if the file doesn't exist anywhere (root or ~webroot), an HTTP 500 error is thrown instead of an HTTP 404. In order to display my 404 error page, I have to instead use these lines:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/~webroot/$0 !-F
RewriteRule ^(.*)$ /404.shtml [B,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !^/~webroot
RewriteRule ^(.*)$ /~webroot/$1 [NC,QSA]
RewriteRule ^/?$ /~webroot/index.php [L,QSA]
This is all quite messy, and it's only a trick and doesn't actually throw an HTTP 404, which keeps 404s from being documented using my statistics application. Is there a way to: Check if file exists in root, if not check if file exists in ~webroot, if not throw real HTTP 404 error?
I do also have all my ErrorDocument's defined properly.
I know this was a while ago, but wanted to chime in. For a rewrite rule to hit a 404, I always use this:
RewriteRule ^(.*)$ - [R=404,L]
I'm not sure if it's correct, but it works for me. I'm pretty sure it should always be with "L" to prevent further rewriting.
BTW, what is the "B" flag for? I only know the ones listed on the apache mod_rewrite page, so I'm lost on it's meaning.
http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
EDIT: ah, my problem is I look at older version docs. Thank you, Swivelgames. I probably would have never even known I was looking at the older docs if you hadn't pointed that out (need to update my bookmarks).
http://httpd.apache.org/docs/2.3/rewrite/flags.html#flag_b
If you can make your 404 page a PHP file, you can add this before any output to get real 404's:
<?php header("HTTP/1.1 404 Not Found"); ?>
This will cause PHP to trigger a 'real' 404 (from the browsers point of view) which gets passed back to the browser. If your statistics package is internal to your server this approach may or may not work, I'm not sure.
The only other solution I can think of is to redirect to a non-existent file:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !/non-existent-404-generator
RewriteCond %{DOCUMENT_ROOT}/~webroot/$0 !-F
RewriteRule ^(.*)$ /non-existent-404-generator [B,L]

Resources