Htaccess wild card Request Contains? - .htaccess

I am trying to write a conditional statement in .htaccess, what is the correct way to part match against the request?
I have this which matches a request for /myfile.xml but also want to match /myfile.
<If "%{REQUEST_URI} == '/myfile.xml'">

I have this which matches a request for /myfile.xml but also want to match /myfile
That doesn't sound like a "contains" operation, as the title suggests, since you would seem to want to match just one or the other.
For this you could just use the logical "or" operator (ie. ||). For example:
<If "%{REQUEST_URI} == '/myfile.xml' || %{REQUEST_URI} == '/myfile'">
Matches /myfile.xml or /myfile.
Or, you could use a regular expression:
<If "%{REQUEST_URI} =~ m#^/myfile(\.xml)?$#">
Reference:
https://httpd.apache.org/docs/2.4/expr.html
HOWEVER, depending on what you are actually trying to do, an <If> expression might not be the correct tool for the job.

Related

what does $1 in .htaccess file mean?

I am trying to understand the meaning of this line in the .htaccess file
RewriteRule ([a-z0-9/-]+).html $1.php [NC,L,QSA]
basically what does $1.php ? what file in the server
if we have home.html where this gonna redirect to? home.php?
$1 is the first captured group from your regular expression; that is, the contents between ( and ). If you had a second set of parentheses in your regex, $2 would contain the contents of those parens. Here is an example:
RewriteRule ([a-z0-9/-]+)-([a-z]+).html$ $1-$2.php [NC,L,QSA]
Say a user navigates to hello-there.html. They would be served hello-there.php. In your substitution string, $1 contains the contents of the first set of parens (hello), while $2 contains the contents of the second set (there). There will always be exactly as many "dollar" values available in your substitution string as there are sets of capturing parentheses in your regex.
If you have nested parens, say, (([a-z]+)-[a-z]+), $1 always refers to the outermost capture (in this case the whole regex), $2 is the first nested set, and so on.
.htaccess files can contain a wide variety of Apache configuration directives, but this one, like many, is to do with the URL rewriting module, mod_rewrite.
A RewriteRule directive has 3 parts:
a Pattern (regular expression) which needs to match against the current URL
a Substitution string, representing the URL to serve instead, or instruct the browser to redirect to
an optional set of flags
In this case, you have a regular expression which matches anything ending in .html which consists only of letters a-z, digits 0-9, / and -. However, it also contains a set of parentheses (...), which mark a part of the pattern to be "captured".
The Substitution string can then reference this "captured" value; the first capture is $1, and the second would be $2, and so on.
In this case, the captured part is everything before the .html, and the Substitution is $1.php, meaning whatever string came before .html is kept, but the .html is thrown away and .php is stuck on instead.
So for your specific example, accessing home.html will instead act as though you had requested home.php.
It's a reference to the first capture group denoted by the parentheses in the pattern ([a-z0-9/-]+).html$. If there were two (.*)-(.*) then you would access $1 for the first capture group and $2 for the second, etc...
$1 refers to the first group caught by your regex (ie between parenthesis). In your case it refers to :
([a-z0-9/-]+)
For the URL mypage.html, $1 will contain "mypage", and the rule will redirect to mypage.php.

htaccess rewrite query string vs back reference?

I'm trying to rewrite this:
http://www.domain.com/johns-wishlist-12
to this:
index.php?route=wishlist/shared_wishlist&id=12&name=johns
I've read some good tutorials, but none of them really explain how back references work (when using more than one)... I also don't understand when to use {QUERY_STRING}, as opposed to just back references?
Could use a little help... this is what I have for the above:
RewriteRule ^([a-z0-9]*)-wishlist-([0-9]*)/?$ index.php?route=wishlist/shared_wishlist&id=$1&name=$2 [L,QSA]
Obviously "johns" and "12" will change based on the user...
so should I be using a rewrite condition {QUERY_STRING} in this case? why?
The %{QUERY_STRING} variable is used to match against the request's query string. In your case, the request is for http://www.example.com/johns-wishlist-12, so there is no query string there. You are rewriting to a URI with a query string, though, so the only thing that matters is the next time around when the rules loop (which may not happen), if you had another rule that matched against the %{QUERY_STRING} variable, the query string that you created will show up there.
The $ something in your rule's target are backreferences to a "grouped" match in the rule's pattern. Whenever you have a () in your pattern, that groups the match which can then be backreferenced using a $. In the case of a condition, the backreferences are % instead.

Two RewriteRules interfering, only one works at a time

On htaccess file with two RewriteRules, each works alone, but not both together
RewriteRule ^([1-9]+)/.*/(.*) /sortir/index.php?com=page1&t=$1&l=$2 [QSA]
RewriteRule ^([1-9]+)/([1-9]+)/.* /sortir/index.php?com=page2&t=$1&v=$2 [QSA]
If I delete first, second works.
If I delete second, first works.
The link called for the first is like :
http://example.com/33/xxxx/city so $1 is 33 and $2 is city
The link called for the second is like :
http://example.com/33/432/xxxx/city/yyyyy so $1 is 33 and $2 is 432
Although, as anubhava notes, more details would be helpful, there are at least a few issues I can point out with your current rules.
First, reverse the order of the rules. The second rule is less general since it starts with two sections of numbers and additional sections of text. Match that first, then match the more general rule.
Second, end each rule with the L flag, otherwise processing will continue to the second rule after the first is finished.
Third, update your matches so that they don't match a slash. This forces the pattern to match the exact directory structure you're looking for rather than matching any arbitrary number of directory levels.
With those things in mind, here are some updated rules to play with:
First rule matches http://example.com/33/432/xxxx/city/yyyy
Second rule matches http://example.com/33/xxxx/city
RewriteRule ^([1-9]+)/([1-9]+)/[^/]+/[^/]+/.* /sortir/index.php?com=page2&t=$1&v=$2 [QSA, L]
RewriteRule ^([1-9]+)/[^/]*/([^/]*)$ /sortir/index.php?com=page1&t=$1&l=$2 [QSA, L]
If this is not the exact rule set you need, it should at least get you closer.
Both conditions are overlapping since this regex:
^([1-9]+)/.*/(.*)
will also match
^([1-9]+)/.*/(.*)
hence only one will fire. Why don't you explain your requirements clearly then we can help you write RewriteRule in unambiguous manner.

htaccess - mod_rewrite "same" rules have to work for both

I really had troubles making a title. So if you have something better, please edit it.
Now to the question:
I'm trying to rewrite some URL's with mod_rewrite in my .htaccess file.
So, what I'm trying to do is to make 2 of the same queries, which of course won't work. Only for one of the rules. So I was thinking if there's some way to tell that if the first rule fails go to the next one? Or - if a rule fails keep looking for another?
Those are my rules which is identical except for the last parameter.
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&val=$2
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&p=$2
Correct me if I'm wrong but, if you are passing the arguments in via GET, then index.php should handle the error that would happen if it were missing a GET variable.
In index.php, treat $_GET["p"] like you would treat $_GET["val"], actually, why not use isset() and set p equal to val (if p isn't already set)
The rewrite won't check to see if the page you are calling in your rule is actually valid. It will just try to serve it up and then because you don't have [L] it will try to serve up the next one too.
What you should probably do is change your first URL to pass that $2 value as two different parameters
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&val=$2
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&p=$2
should be
RewriteRule ^udforsk/([a-z-]+)/([0-9]+)$ index.php?page=udforsk&q=1&s=$1&val=$2&p=$2
Then let your index.php do the work of picking which parm to use "val" or "p" based on logic in the php script.
For sure in your php code use "isset" to test for the variable.
$value = (isset($_REQUEST["val"]) ? $_REQUEST["val"] : (isset($_REQUEST["p"]) ? $_REQUEST["p"] : "error"));
$value will hold the contents of "val" or "p" or the word "error" if neither of the others are set.

Make an optional Get variable with this htaccess

I have this rule in my .htaccess:
RewriteRule ^build_system/([^/]+)/([^/]+)/([^/]+)/?$ /po_systems/build_system.php?business_id=$1&system_id=$2&quantity=$3
Which works great for this url:
http://somesite.com/po_systems/build_system/60/495C31/1
But now I need an optional 4th Get variable to this rule that will give me the $_GET variable step like this:
http://somesite.com/po_systems/build_system/60/495C31/1/2
$_GET['step'] // 2
But I also need the rule to work if there is no 4th Get variable. So basically I need both 3 and 4 Get variables to work, making the 4th optional.
I would write it with two separate rules:
RewriteRule ^build_system/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /po_systems/build_system.php?business_id=$1&system_id=$2&quantity=$3&step=$4 [S=1]
RewriteRule ^build_system/([^/]+)/([^/]+)/([^/]+)/?$ /po_systems/build_system.php?business_id=$1&system_id=$2&quantity=$3
If there are 4 path components, the first rule will match, and skip the next rule ([S=1]). Otherwise the next rule will try to match.
#Ulrich Palha's solution probably also works, but the regular expression is getting complicated. It will pass an empty step= parameter if there's no 4th path component, which may be fine. My solution will pass no step parameter if there's no 4th path component. Either way should work.
try
RewriteRule ^build_system/([^/]+)/([^/]+)/([^/]+)/?([^/]*)/?$ /po_systems/build_system.php?business_id=$1&system_id=$2&quantity=$3&step=$4

Resources