URL Decoded Prior to htaccess Rewrite Rule - php

I have the following rewrite rule in .htaccess :-
RewriteRule ^.*/-y.* /handleurl.php [L]
Its purpose is to display appropriate pages depending on the values in the url, for example:
example.com/books/BookA/-y?act=x will display bookA page
the variable holding the book name is encoded such that ...
example.com/books/Book B/-y?act=x becomes example.com/books/book+B/-y?act=x
... which is fine (it's decoded in handleurl.php)
however if the book is called Book A/B I have ...
example.com/books/Book A/B/-y?act=x which becomes example.com/books/Book+A%2FB/-y?act=x
It appears that htaccess decodes this before the rewrite rule, so the rewrite rule sees too many elements in the URL delineated by the /.
Is there any way I can get the rewrite rule to ignore the encoded / as intended?
I have seen a previous response to a similar question, but I only need the / to be ignored, not other encoded characters.

It appears that htaccess decodes this before the rewrite rule, so the rewrite rule sees too many elements in the URL delineated by the /
This is not the problem. Regardless of whether the URL-path /books/Book+A%2FB/-y is decoded or not makes no difference here*1. Both would match the (rather generous) regex ^.*/-y.* in the RewriteRule pattern.
(*1 But yes, the URL-path matched by the RewriteRule pattern is URL decoded, ie. %-decoded.)
The problem is likely to be that Apache (by default) rejects - with a 404 - any URL that contains a %-encoded slash ie. %2F (or backslash %5C) in the URL-path portion of the URL. This is a security feature, that otherwise "could potentially allow unsafe paths" (source).
However, this can be overridden with the AllowEncodedSlashes directive. But this directive can only be used in a server or virtualhost context. It cannot be used in .htaccess.
You either need to set AllowEncodedSlashes On to allow encoded slashes, which are also decoded, as with other characters. Or set AllowEncodedSlashes NoDecode to permit encoded slashes, but do not decode them - which is preferred and probably what you are expecting.
Aside#1:
RewriteRule ^.*/-y.* /handleurl.php [L]
The regex ^.*/-y.* is very generic, possibly too generic. This is the same as simply /-y. What is the .* after -y intended to match? From your example URLs it looks like -y is always at the end of the URL-path, so this could be anchored, eg. /-y$. And if the URL that you need to match always starts /books/ then maybe this should also be included in the regex?
Aside#2:
...the book name is encoded such that ...
example.com/books/Book B/-y?act=x becomes example.com/books/book+B/-y?act=x ... which is fine (it's decoded in handleurl.php)
This isn't strictly "URL encoded", you have converted the space into a + in the URL-path. The + is a valid "URL encoding" for a space when used in the query string only. A + in the URL-path is a literal + (and will be seen by search engines as such). In the URL-path, a space would be URL encoded as %20. (You may have used the wrong PHP encoding functions, eg. urlencode() instead of rawurlencode()?)
Of course, you are free to convert/encode the URL however you wish to create a more readable URL - providing it's valid.

The rewrite rule was never the problem. I think it was Apache not liking the encoded '/' and the fact that the downstream url handling program was using '/' as a delimiter when identifying the individual url elements. I have to work out: 1) whether I want to allow '/' in the variables that make up the elements of the freindly url, and 2) if so how to pass it without upsetting Apache and how to subsequently disect the url. Maybe I will convert '/' to '~' for the benefit of the URL then convert back to '/' prior to subsequent display. Thank you Mr White.

Related

How to pass forward slash (%2F) in laravel 5 url with addition get parrameters

Users can search my site. Sometimes they might use a search term containing a forward slash (search with / slash) which when submitted by the form turns into %2F in the url.
eg. www.mysite.com/search/search+with+%2F+slash
I have used the answer from here which works great to give me the right page and not send me to a 404.
My problem now is I use pagination on the page and custom filters which are both passed as get vars in the url and when accessing the GET var it's empty.
eg. www.mysite.com/search/search+with+%2F+slash?page=2
This is my current route
$this->get('search/{search_term}', ['uses' => 'SearchController#search'])
->where('search_term', '(.*(?:%2F:)?.*)');
Not sure what do from here
Including an encoded slash (%2F) in the path component of a URL is not a good idea. The HTTP RFC says that this sequence should be "equivalent" to a real slash:
Characters other than those in the "reserved" and "unsafe" sets (see
RFC 2396 [42]) are equivalent to their ""%" HEX HEX" encoding.
In practice, the handling of these URLs is inconsistent. Some web servers (and even some browsers!) will treat %2F as equivalent to a real slash, some will treat it differently, and some tools, including some web application firewalls and proxies, will simply reject URLs which contain such a sequence.
If you need to include user input like this in a URL, you should probably put it in a query string (/search/?q=search+with+%2f+slash).

How to load a specific page for any given pathname URL

Let's say I have a web-page called www.mysite.com
How can I make it so whenever a page is loaded like www.mysite.com/58640 (or any random number) it redirects to www.mysite.com/myPHPpage.php?id=58640.
I'm very new to website development so I don't even really know if I asked this question right or what languages to tag in it...
If it helps I use a UNIX server for my web hosting with NetWorkSolutions
Add this to your .htaccess file in the main directory of your website.
RewriteEngine on
RewriteBase /
RewriteRule ^([0-9]+)$ myPHPpage.php?id=$1 [L]
Brief explanation: it says to match:
^ from start of query/page
[0-9] match numbers
+ any matches of 1 or more
$ end of page requested
The parentheses part say to look for that bit and store it. I can then refer to these replacement variables in the new url. If I had more than one parentheses group then I would use $2, $3 and so on.
If you experience issues with the .htaccess file please refer to this as permissions can cause problems.
If you needed to capture something else such as alphanumeric characters you'd probably want to explore regex a bit. You can do things such as:
RewriteRule ^(.+)$ myPHPpage.php?id=$1 [NC, L]
which match anything or get more specific with things like [a-zA-Z0-9], etc..
Edit: and #Jonathon has a point. In your php file wherever you handle the $_GET['id'] be sure to sanitize it if used in anything resembling an sql query or mail. Since you are using only numbers that makes it easy:
$id = (int)$_GET['id']; // cast as integer - any weird strings will give 0
Keep in mind that if you are not going to just use numbers then you will have to look for some sanitizing function (which abound on google - search for 'php sanitize') to ensure you don't fall to an sql injection attack.

Extract directory from REQUEST_URI

I'm interested in extracting the directory from $_SERVER['REQUEST_URI']. I believe I specifically need to use $_SERVER['REQUEST_URI'] in case the URL is being mod_rewrite'd.
If $_SERVER['REQUEST_URI'] = 'http://example.com/path/to/resource';, then I can just use dirname() on it and get http://example.com/path/to.
If the URI is the directory index page/equivalent, but a query string or hash is appended to it, then $_SERVER['REQUEST_URI'] might be something like 'http://example.com/path/?query' or http://example.com/path/#hash. In this case, dirname() works as well -- both of those resolve to http://example.com/path.
If, however, the URI has no query string or hash, pathname() strips off the bottom-level directory, e.g. http://example.com/path/ becomes http://example.com. My solution was to simply append a hash symbol to every URI, i.e. dirname($_SERVER['REQUEST_URI'].'#'). dirname('http://example.com/path/'.'#') yields http://example.com/path.
But I don't understand how URIs work, so I don't really know if this is safe.
If a URI points to a directory, does it always end in the character /? If I type http://example.com/path in my browser, it redirects to http://example.com/path/, adding the trailing slash. Will this always happen, though?
Do query strings and hashes always get URL-encoded? For example, I can type http://example.com/path/?query=a/b/c in my browser and it gets interpreted as http://example.com/path/?query=a%2Bb%2Bc. But if that conversion didn't happen, then pathname() would return http://example.com/path/?query=a/b, which would be bad.
Can URIs have \s or are directories always separated with /?

Rewritten URL should contain #. How can I resolve this?

Actually I want to rewrite URL through .htaccess.
My actual URL is
front/property/uploadphotos_pid.php?pid=11#NO
I want to convert this to
uploadphotos_pid/11/NO.php
and have written following code:
RewriteRule ^uploadphotos_pid/([a-zA-Z0-9\-]+)/([a-zA-Z0-9\-]+).php$
front/property/uploadphotos_pid.php?pid=$1&#=$2
The fragment identifier (the section of a URI starting with #) is handled entirely client side. It is not sent to the server. The server (which is where mod_rewrite runs) therefore cannot do anything with it.
# must be escaped as %23 in a URL

mod_rewrite: no ? and # in REQUEST_URI

What I'm trying to do:
have pretty URLs in the format 'http://domain.tld/one/two/three', that get handled by a PHP script (index.php) by looking at the REQUEST_URI server variable.
In my example, the REQUEST_URI would be '/one/two/three'. (Btw., is this a good idea in general?)
I'm using Apache's mod_rewrite to achieve that.
Here's the RewriteRule I use in my .htaccess:
RewriteRule ^/?([a-zA-Z/]+)/?$ /index.php [NC,L]
This works really well thus far; it forwards every REQUEST_URI that consists of a-z, A-Z or a '/' to /index.php, where it is processed.
Only drawback: '?' (question marks) and '#' (hash keys) seem to still be allowed in the REQUEST_URI, maybe even more characters that I've yet to find.
Is it possible to restrict those via my .htaccess and an adequate addition to the RewriteRule?
Thanks!
The fragment identifer, e.g. #some-anchor, is controlled by the browser, not the server. JavaScript would be needed to redirect and remove this, although why you would want to do so I am not sure.
[SNIPPED after clarification]
To rewrite only when the query string is empty:
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^/?([a-zA-Z/]+)/?$ /index.php [NC,L]
In mod_rewrite and PHP the variable REQUEST_URI refers to two different part of the URI. In mod_rewrite, %{REQUEST_URI} contains the current URI path; in PHP, $_SERVER['REQUEST_URI'] contains the URI path and query. But in both cases the URI fragment as this part of the URI is not transmitted to the server but only used by the client.
So, when /one/two/three?foo#bar is requested, mod_rewrite’s %{REQUEST_URI} contains /one/two/three and PHP’s $_SERVER['REQUEST_URI'] contains /one/two/three?foo.
The $_SERVER['REQUEST_URI'] variable will contain the original REQUEST_URI as received by the server, before you perform the rewrite. Therefore it's impossible (as far as I know this early in the morning) to remove the query string portion from the REQUEST_URI's attribute, but you naturally have the option of removing it when you process the $_SERVER['REQUEST_URI'] variable in your script.
If you want to only perform your RewriteRule when the query string is not specified, the following should work:
RewriteCond %{QUERY_STRING} !^.+$
RewriteRule ^/?([a-zA-Z/]+)/?$ /index.php [NC,L]
Note that this might be problematic though, since if there's accidentally a query string in a URL that someone uses to link to your site, your script wouldn't be handling it (since the rewrite never happens), so they'll get a 404 response (or whatever the case may be) that might not be as user-friendly as if you had just chosen to silently ignore the trailing information.
If i understand, you want to forbid using of ? and # for your site?
You shouldn't do that, because:
hash (#) is used in AJAX URLs google specification,
question mark (?) is used for example in Google AdWords and Analytics or any Affiliation Program,
So if you force Apache to reject url request containing question mark, people who click on your Ad in AdWords will only see 404 error page.
There is nothing bad in letting people to use both of them. The case is to prevent your site against XSS attacks.
Btw. there is another very importand sign - percent (%) which is used to encode special chars (like Polish or German national letters)

Categories