What does $1 [QSA,L] mean in my .htaccess file? - .htaccess

I need to change my .htaccess and there are two lines which I don't understand.
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
When I should use these lines ?

Not the place to give a complete tutorial, but here it is in short;
RewriteCond basically means "execute the next RewriteRule only if this is true". The !-l path is the condition that the request is not for a link (! means not, -l means link)
The RewriteRule basically means that if the request is done that matches ^(.+)$ (matches any URL except the server root), it will be rewritten as index.php?url=$1 which means a request for ollewill be rewritten as index.php?url=olle).
QSA means that if there's a query string passed with the original URL, it will be appended to the rewrite (olle?p=1 will be rewritten as index.php?url=olle&p=1.
L means if the rule matches, don't process any more RewriteRules below this one.
For more complete info on this, follow the links above. The rewrite support can be a bit hard to grasp, but there are quite a few examples on stackoverflow to learn from.

If the following conditions are true, then rewrite the URL:
If the requested filename is not a directory,
RewriteCond %{REQUEST_FILENAME} !-d
and if the requested filename is not a regular file that exists,
RewriteCond %{REQUEST_FILENAME} !-f
and if the requested filename is not a symbolic link,
RewriteCond %{REQUEST_FILENAME} !-l
then rewrite the URL in the following way:
Take the whole request filename and provide it as the value of a "url" query parameter to index.php. Append any query string from the original URL as further query parameters (QSA), and stop processing this .htaccess file (L).
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
Apache docs #flag_qsa
Another Example:
RewriteRule "/pages/(.+)" "/page.php?page=$1" [QSA]
With the [QSA] flag, a request for
/pages/123?one=two
will be mapped to
/page.php?page=123&one=two

This will capture requests for files like version,
release, and README.md, etc. which should be
treated either as endpoints, if defined (as in the
case of /release), or as "not found."

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]

.Htaccess from ?p=activate&id=57A5dz into users/activate/id/57A5dz

I would like to rewrite my urls from http://www.domain.com/index.php?p=activate&id=57A5dz into http://www.domain.com/users/activate/id/57A5dz.
I searched a lot around google but nothing worked.
I always see the 404 page..
My .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ \?p=$1 [QSA,L]
RewriteRule ^(.*)/(.*)/$ ?page=$1&id=$2
RewriteCond %{REQUEST_URI} ^/web-gallery/images/
RewriteRule ^images/(.+)$ /web-gallery/images/$1
And i also tried to add this:
RewriteRule ^([^/]+)/(\d+)/.*$ $1&id=$2 [L]
Thank you
First let's take a closer look at your rules to understand what they do.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ \?p=$1 [QSA,L]
If the requested url is not a directory and the requested file is not a file and it the part behind the hostname and before the query string matches ^(.*)$, internally rewrite it to whatever it was and append p= + whatever was matched to the query string. A request to example.com/cookies?are=evil would be rewritten to example.com/cookies?are=evil&p=cookies.
RewriteRule ^(.*)/(.*)/$ ?page=$1&id=$2
If the requested url contains at least 2 path segments, internally rewrite it to the same page and replace the query string with page = everything before the last path segment & id = what is behind it.
RewriteCond %{REQUEST_URI} ^/web-gallery/images/
RewriteRule ^images/(.+)$ /web-gallery/images/$1
If the requested url (or rewritten url) begins with web-gallery/images, rewrite images/something to web-gallery/images/something. There is however no url that matches both the condition and the first argument of rewriterule, so this rule is never, ever, executed.
RewriteRule ^([^/]+)/(\d+)/.*$ $1&id=$2 [L]
If the requested url has more than 2 path segments, where the first path segment doesn't contain a / and the second path segment contains only numbers, drop the rest of the path, and internally rewrite the url to whatever the first path segment was, followed by a & outside a query string and add id=numbers_matched to it. http://example.com/test/1/some/thing?cookies=evil&butter=too would be rewritten to http://example.com/test&id=1?var=2&butter=too.
To look back at what you wanted. You want the user to see http://www.domain.com/users/activate/id/57A5dz. This doesn't make sense to the server, so you'll have to internally rewrite it to let it make sense to the server. http://www.domain.com/index.php?p=activate&id=57A5dz should just do that. We want to match on the first url, and use those matches on the second url. The following (untested) rewriterule should do the trick for you. I hope above explanation gives you a better understanding of how these rules work.
RewriteRule ^users/([^/]+)/id/([^/]+)/?$ /index.php?p=$1&id=$2 [L]

RewriteRule subtle differences - one in the same?

I'm trying to better understand mod_rewrite and I've come across some differences, which I think do the same thing? In this case, no existing files or directories and rewriting to an index.php page.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
Do I need the [OR] or can I leave it off?
What are the differences or advantages of the following rules? I'm currently using the first one, but I've come across the last four in places like WordPress:
#currently using
RewriteRule ^(.+)$ index\.php?$1 [L]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Do I need the [OR] or can I leave it off?
In this case you need the [OR] because RewriteCond's are inherently ANDed, and it's not the case that a request is both a file and a directory (as far as mod_rewrite is concerned).
RewriteRule ^(.+)$ index\.php?$1 [L]
This rewrites all requests that aren't for the document root (e.g. http://domain.com/) as a query string for index.php, thus a request for http://domain.com/some/path/file.html gets internally rewritten to index.php?some/path/file.html
RewriteRule ^index\.php$ - [L]
This is a rule to prevent rewrite looping. The rewrite engine will continue to loop through all the rules until the URI is the same before the rewrite iteration and after (without the query string). If the URI starts with index.php simply stop the current rewrite iteration (what the - does). The rewrite engine sees that the URI before sending it through the rules was index.php and after the rules was index.php, thus the rewrite engine stops and all rewriting is done. This prevents mod_rewrite from rewriting things to index.php?index.php which the first rule would do upon the 2nd pass through the rewrite engine if it isn't for this rule.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
This is the catch-all. If the first rule never gets applied, and the request isn't for an existing file or directory, send the request to index.php. Though in this case, it looks like this rule will never get applied.
EDIT:
is there a way to ignore a certain rule if a condition is true? For example, www.domain.com/some/path > index.php?some/path, but if the URI is www.domain.com/this/path > no rewrite?
You'd have to add 2 conditions, one that checks to make sure the requested host isn't "www.domain.com" and one to check that the URI isn't "/this/path":
RewriteCond %{HTTP_HOST} !^(www\.)?domain\.com$ [NC,OR]
RewriteCond %{REQUEST_URI} !^/some/path
The [NC] indicates that the condition's match should ignore case, so when someone enters the URL http://WWW.domain.com/ in their address bar, it will match (or in this case, not match). The second condition matches when the URI starts with "/some/path", which means requests for http://domain.com/some/path/file.html will match and NOT get rewritten. If you want to match exactly "/some/path", then the regular expression needs to be !^/some/path$.
Why not use [OR] in the final block between !-f and !-d?
This is the logical negation of -f OR -d: "if the file exists, don't rewrite, OR if the directory exists, don't rewrite" turns into "if the file doesn't exist, AND if the directory doesn't exist, then rewrite"

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 directory to file redirect problem

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

Resources