non mandatory parameter in a friendly-url - .htaccess

I want to write a pretty url for someone.php directory. prolem is it sometimes expects two paramters and sometimes just one. I couldn't handle second parameter.
I can write easily for just 1 parameter
RewriteRule ^someone/([^.?/]+)$ /someone.php?someone=$1 [L]
Howevever i couldn't succeed when i try to add a second parameter. I tried something like this
RewriteRule ^someone/([^.?/]+)/([^.?/]*)$ /someone.php?someone=$1&topic=$2 [L]

You can make the second second capture group optional in your Regex pattern so that the rule can handle both of your new urls.
^someone/([^.?/]+)/?([^.?/]*)?$
The pattern above would match both uris /someone/foo/bar and /someone/foo .
Here is your complete Rule
RewriteRule ^someone/([^.?/]+)/?([^.?/]*)?$ /someone.php?someone=$1&topic=$2 [L]

Related

Use htaccess to change query parameter to iOS app-specific deep-link [duplicate]

I am trying to do the following:
User visits URL with query parameter: http://www.example.com/?invite=1234
I then want them to be deep linked into the app on their iOS device, so they go to: app_name://1234
Any suggestions on how to accomplish this in my .htaccess file?
I tried this but it doesn't work:
RewriteEngine On # Turn on the rewriting engine
RewriteRule ^invite/(.*)/$ app_name://$1 [NC,L]
If RewriteRule won't work, can anyone send me an example code for RewriteCond or JavaScript to achieve what I need?
Not sure how this will work with the iOS device, but anyway...
RewriteRule ^invite/(.*)/$ app_name://$1 [NC,L]
This doesn't match the given URL. This would match a requested URL of the form example.com/invite/1234/. However, you are also matching anything - your example URL contains digits only.
The RewriteRule pattern matches against the URL-path only, you need to use a RewriteCond directive in order to match the query string. So, to match example.com/?invite=1234 (which has an empty URL-path), you would need to do something like the following instead:
RewriteCond %{QUERY_STRING} ^invite=([^&]+)
RewriteRule ^$ app_name://%1 [R,L]
The %1 backreference refers back to the last matched CondPattern.
I've also restricted the invite parameter value to at least 1 character - or do you really want to allow empty parameter values through? If the value can be only digits then you should limit the pattern to only digits. eg. ^invite=(\d+).
I've include the R flag - since this would have to be an external redirect - if it's going to work at all.
However, this may not work at all unless Apache is aware of the app_name protocol. If its not then it will simply be seen as a relative URL and result in a malformed redirect.

.Htaccess redirect with multiple query strings

I tried doing searching and trying to understand how to do a redirect with (multiple) query strings but I didn't have luck. I'm hoping someone here can help me understand this issue :)
I'm working on this ecommerce shop and people are searching the ecommerce search input for content located in a different CMS. For example, the word "returns". This isn't a product in the ecommerce system so of course it returns an error for the results (no products found).
My idea was simply to manually redirect those quieres to the proper landing pages in the CMS.
Here's an example of the URL for "return" on the ecommerce system:
http://www.domain.com/catalog/search.php?mode=search&page=1&substring=return
And here's where I would like to send people:
http://www.domain.com/catalog/Returns.html
Any thoughts on how to do this? Thanks in advance!
Solution
The way to do this is as Phil suggested; but with a few (small) modifications:
RewriteEngine On
RewriteCond %{QUERY_STRING} substring=returns? [NC]
RewriteRule . /catalog/Returns.html? [L]
RewriteCond %{QUERY_STRING} substring=shipping [NC]
RewriteRule . /catalog/Shipping.html? [L]
N.B. In the event you only want to remove one parameter see the Additional Information and Explanations below.
N.B. For more strict matching see Where & becomes a problem below.
Explanation
Background
The best way for me to explain the difference (between the above and Phil's original) and why you were having a problem is to explain what is going on...
RewriteCond %{QUERY_STRING} substring=returns? [NC] checks the query string for instances of the regex that follows it in this case substring=returns?*.
The [NC] flag simply means to match upper and lower case letters.
*Clarification: The regex(substring=returns?) means substr=return is matched literally with or without an s.
Problem
If the condition is met (i.e. the regex pattern is matched in the query string) then the rewrite rule is triggered. This is where the problem lies...
Given the URL: http://example.com/?substring=returns
The original rule:
RewriteRule . /catalog/Returns.html [L]
Rewrites the URL leaving the query string in place, like so:
http://example.com/?substring=returns
http://example.com/catalog/Returns.html?substring=returns
http://example.com/catalog/Returns.html?substring=returns
http://example.com/catalog/Returns.html?substring=returns
http://example.com/catalog/Returns.html?substring=returns
...and so on until limit is reached...
Side note: The [L] flag stops the .htaccess file from going through any more rules but it doesn't stop it looping again.
Solution
The solution then is to overwrite the query string (since we no longer need it) you can do this simply by adding a ? to the end of the RewriteRule:
RewriteRule . /catalog/Returns.html? [L]
N.B. In the event you only want to remove one parameter see the Additional Information and Explanations below.
N.B. For more strict matching see Where & becomes a problem below.
Resources
The following resources may come in helpful in the future:
.htaccess flags
http://httpd.apache.org/docs/current/rewrite/flags.html
Regular expressions
http://www.regular-expressions.info/ - Check out the tutorials section
Additional Information and Explanations
Where & becomes a problem
RewriteCond %{QUERY_STRING} &substring=returns? [NC]
In the above the regex means to match the characters &substring=return with an optional s appended to it.
So it would match the following as expected:
http://example.com/?var1=somvalue&substring=return
http://example.com/?var1=somvalue&substring=returns
http://example.com/?var1=somvalue&substring=return&var2=othervalue
http://example.com/?var1=somvalue&substring=returns&var2=othervalue
Which is fine and given the original query string wouldn't be a problem, however, if I were to navigate to the page and write in the parameters in a different order, the & wouldn't necessarily be there and therefore it wouldn't match (when it should):
http://example.com/?substring=return&var1=somevalue
http://example.com/?substring=returns&var1=somevalue
Simply getting rid of it (as I did) would solve this problem, but it doesn't come risk free.
RewriteCond %{QUERY_STRING} substring=returns? [NC]
If you were to introduce a new parameter secondsubstring for example it would match when it shouldn't:
Good Match > http://example.com/?substring=return&var1=somevalue
Good Match > http://example.com/?var1=somevalue&substring=return
Bad Match > http://example.com/?secondsubstring=return&var1=somevalue
To solve this potential issue you could do the following:
RewriteCond %{QUERY_STRING} ^(.*&)?substring=returns?
The above will match:
http://example.com/?substring=return&var1=somevalue
http://example.com/?var1=somevalue&substring=return
But won't match:
http://example.com/?secondsubstring=return&var1=somevalue
One more potential problem is that the expression would match:
http://example.com/?substring=returning&var1=somevalue
http://example.com/?substring=return%20television&var1=somevalue
My understanding, again, is that this wouldn't be a problem in the given situation. However if it were to be a problem you could do:
RewriteCond %{QUERY_STRING} ^(.*&)?substring=returns?(&|$)
The above checks that the character following return/returns is either an & signalling the end of the variable and the start of a new one or the end of the query string.
Rewriting one parameter
In some circumstances as Phil pointed out it may be preferable to only remove one parameter at a time and leave the rest of the query string untouched.
You can do this, quite simply, by implementing capture groups in the RewriteCond and outputting them in the RewriteRule:
RewriteCond %{QUERY_STRING} ^(.*&)?substring=returns?(&.*)?$ [NC]
RewriteRule . /catalog/Shipping.html?%1%2 [L]
Rewrite explanation
You use %N to insert capture groups from the rewrite condition and $N to insert capture groups from the rewrite rule.
So in this case we redirect to:
/catalog/shipping.html?(RewriteCond Group1)(RewriteCond Group2)
/catalog/Shipping.html?%1%2
The [L] flag - as previously - stops the processing of any rules further down the .htaccess file
Regex explanation
^(.*&)?substring=returns?(&.*)?$
^ Start of string
(.*&)? First capture group
Capture any character . 0 or more times *
Followed by an &
The ? makes the entire group optional
substring=returns? Matches substring=return literally with an optional s
(&.*)? Second capture group
Capture an &
Capture any character . 0 or more times *
The ? again makes the group optional
$ End of string
[L] flag vs [END]
For completeness sake...
The [L] flag stops the .htaccess from going over any more rules further down the .htaccess file.
The [END] flag stops the rewrite process completely.
To illustrate with an example:
while(TRUE){
if(condition1){ continue; }
if(condition2){ continue; }
if(condition3){ continue; }
if(condition4){ continue; }
}
while(TRUE){
if(condition1){ break; }
if(condition2){ break; }
if(condition3){ break; }
if(condition4){ break; }
}
In the above code blocks the [L] flag acts like a continue statement in that it skips the rest of the code block and starts again. Whilst the [END] flag acts as a break statement and stops the loop entirely.
If we were to replace the [L] flag with [END] in Phil's original answer then it would work. With the caveats mentioned in the Where & becomes a problem section above.
RewriteEngine On
RewriteCond %{QUERY_STRING} &substring=returns? [NC]
RewriteRule . /catalog/Returns.html [L]
RewriteCond %{QUERY_STRING} &substring=shipping [NC]
RewriteRule . /catalog/Shipping.html [L]
etc.
Would something like that do the job for you? Note that 'returns?' means 'return' or 'returns'. Are you limited to one search term at a time, or might customers type in a phrase? I think & is safe to use there, but it's possible it's not.
Don't forget to do this stuff ahead of any commands to rewrite Returns.html to Returns.php, do SEO, etc.

Why does my RewriteRule not work when there is a `?` in the URL

I am learning how to write regular expressions for .htaccess redirects.
So far I've managed to figure out everything I needed, except for a couple of regular expressions which don't behave as I expected. I am testing my regular expressions using a desktop application, and they work fine there, but not in the .htaccess file.
FYI: The RewriteBase is set to /site/
This is the incoming URL:
/site/view-by-tag/politics/?el_mcal_month=3&el_mcal_year=2009
I want to grab "politics" and redirect to /site/tags/politics/
Here is what I used:
RewriteRule ^view-by-tag/([a-zA-Z\-]+)/([a-zA-Z0-9\-\/\.\_\=\?\&]+) /tags/$1/ [R=301,L]
I added the capture of all the characters after politics because I am having the issue that when there is a ? in the URL the redirect does not work, and I can't figure out why. In the URL given above, if I remove the ? it works fine, but if the ? is in there, nothing happens. Is there a reason for this?
The same thing happens when I try to capture 307 from /site/?option=com_content&view=article&id=307&catid=89&Itemid=55
I used this regular expression, article&id=([0-9]+) /?p=$1 [R=301,L] but again, when there is a ? in the URL it stops the redirect for doing anything.
What is the reason for that?
The .htaccess file in question is on a Wordpress blog (3.4.1)
The point that you've missed is that the rewrite engine splits the URI into two parts: the REQUEST_URI and the QUERY_STRING. The query string part isn't used in the rule match string so there is no point in constructing rule regexp patterns to look for it.
You can probe and pick out parameters from the query string by using rewrite conditions and condition regexps to set %N variables.
By default the query string is appended to the output substitution string unless you have a ?someparam in it -- in which case it is ignored unless you used the [QSA] (query string append) parameter.
The way that you'd pick up the id in /site/?option=com_content&view=article&id=307&catid=89&Itemid=55 is to use something like:
RewriteCond %{QUERY_STRING} \bid=(\d+)
Before the rule and this would set %1 to 307. Read the rewrite documentation for more general discussion of how to do this.
The query string is must be processed separately in a RewriteCond if you need to manipulate it, and should not be matched inside the RewriteRule Instead, just match the request not including the query string, and use QSA to append the query string onto the redirect:
RewriteRule ^view-by-tag/([A-Za-z-]+)/?$ /tags/$1/ [R=301,L,QSA]
# OR, if you don't want the rest of the query string appended, put a `?` onto
# the redirect to replace it with nothing
RewriteRule ^view-by-tag/([A-Za-z-]+)/?$ /tags/$1/? [R=301,L]
Actually, the QSA may not be needed in a R redirect - I think that the default behavior is to pass the query string with the redirect.
If you need to capture 307 from the query string, do it in a RewriteCond and capture in %1:
# Capture the id in %1
RewriteCond %{QUERY_STRING} id=([\d]+)
# Redirect everything to /, pass %1 into p
RewriteRule . /?p=%1 [LR=301,L]

Problem with .htaccess and RewriteRule

I have url's like games/xbox/2
2 being the page number I need the url rewritten. This is what I'm using:
RewriteRule games/(.*?)/$ games/consoles.php?console=$1
RewriteRule games/(.+?)/(.+?)/$ games/consoles.php?console=$1&page=$2
The first rule works fine but the second is returning consoles.php as $1 instead of xbox
RewriteRule games/([A-Za-z0-9]+)/?$ games/consoles.php?console=$1
RewriteRule games/([A-Za-z0-9]+)/([0-9]+)/?$ games/consoles.php?console=$1&page=$2
Using (.*?) would match even the / character so xbox/2 is treated as a whole
Try something like:
RewriteRule games/([^/]+)/([^/]+)/?$ games/consoles.php?console=$1&page=$2 [L]
RewriteRule games/([^/]+)/?$ games/consoles.php?console=$1 [L]
I first put your most specific rule first - that way you don't do a general match, then a later more specific match mangles that general rewrite.
I also specified the [L] flag to signify that you want the engine to stop looking for more matches at this point. Re-ordering the rules is redundant in this case because of the [L] flag, but it's a good practice to get into.
I also changed the expressions slightly. Rather than using ([A-Za-z0-9]+) like the previous poster said, I changed it to ([^/]+) because that will match everything but a slash, so you can have weird console or game names. If you want to make it more specific feel free to, but this way provides the most general use-case.

RewriteRule in htaccess

Could anyone explain the following line please?
RewriteRule ^(.*)$ /index.php/$1 [L]
The parts of the rewrite rule break down as follows:
RewriteRule
Indicates this line will be a rewrite rule, as opposed to a rewrite condition or one of the other rewrite engine directives
^(.*)$
Matches all characters (.*) from the beggining ^ to the end $ of the request
/index.php/$1
The request will be re-written with the data matched by (.*) in the previous example being substituted for $1.
[L]
This tells mod_rewrite that if the pattern in step 2 matches, apply this rule as the "Last" rule, and don't apply anymore.
The mod_rewrite documentation is really comprehensive, but admittedly a lot to wade through to decode such a simple example.
The net effect is that all requests will be routed through index.php, a pattern seen in many model-view-controller implementations for PHP. index.php can examine the requested URL segments (and potentially whether the request was made via GET or POST) and use this information to dynamically invoke a certain script, without the location of that script having to match the directory structure implied by the request URI.
For example, /users/john/files/index might invoke the function index('john') in a file called user_files.php stored in a scripts directory. Without mod_rewrite, the more traditional URL would probably use an arguably less readable query string and invoke the file directly: /user_files.php?action=index&user=john.
That will cause every request to be handled by index.php, which can extract the actual request from $_SERVER['REQUEST_URI']
So, a request for /foo/bar will be rewritten as /index.php/foo/bar
(I'm commenting here because I don't yet have the rep's to comment the answers)
Point #2 in meagar's answer doesn't seem exactly right to me. I might be out on a limb here (I've been searching all over for help with my .htaccess rewrites...), and I'd be glad for any clarification, but this is from the Apache 2.2 documentation on RewriteRule:
What is matched?
The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string. If you wish to match against the hostname, port, or query string, use a RewriteCond with the %{HTTP_HOST}, %{SERVER_PORT}, or %{QUERY_STRING} variables respectively.
To me that seems to say that for a URL of
http: // some.host.com/~user/folder/index.php?param=value
the part that will actually be matched is
~user/folder/index.php
So that is not matching "all characters (.*) from the beggining ^ to the end $ of the request", unless "the request" doesn't mean what I thought it does.

Resources