Welcome Guest, Not a member yet? Register   Sign In
How to use query strings with CodeIgniter and stay alive to talk about it
#1

[eluser]rankorn[/eluser]
I am writing this post after several long nights of searching, reading and thinking about query strings and the CodeIgniter URL system.

I love how CodeIgniter deals with URLs that are more user friendly etc, but I (like many other) came to the point where I had no choice but to use a query string, which was sent to my server from an external application.

I want to present my solution, and hopefully help others who have the same problem. Since I did not wanted to hack the CodeIgniter code, I found a solution based on mod_rewrite and some configuration change.

The idea is:
1. Add a RewriteRule that takes the query string and add it to the request path, so it will look like a controller method parameter.
2. Change the $config['permitted_uri_chars'] so it will accept = and &
3. In the controller method, use parse_str to extract the get parameters

Here are examples:
Add the following to the .htaccess file after the standard index.php rule:
Code:
RewriteRule somthing\.php /index.php?/myController/myMethod/%{QUERY_STRING} [L]

Change the permitted uri chars to:
Code:
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_&=-';

Now the controller can be:
Code:
class MyController extends Controller {
    
    public function myMethod($queryString) {
        parse_str($queryString);
        // you now have the query string parameters
    }
}

So now, if you get
Code:
something.php?var1=abc&var2=def
This will map to MyController::myMethod with var1 and var2 as local variables.

I think this solution is easy and pretty clean, it does not break the CodeIgniter model but still enables query strings if needed.

Ran.
#2

[eluser]MadZad[/eluser]
rankorn,
Looks like a very nice solution. Faced with that issue, I probably would have enabled GET and relied on the user guide and whatever forum posts I would have found - and I'll bet you explored that as well.

What I really like about your approach is the attitude of "for THIS PARTICULAR url, I'll give the query string to a specific controller". That contains the functionality and avoids global changes for an issue that is probably the exception. Kudos.

The one thing I'll recommend is to have defensive code in MyController for handling the query string. Immediately calling parse_str is tempting, but the query string can be anything and I'd consider it malicious until proven otherwise. I'm a big fan of whitelisting input. So, in your example, whitelisting could ONLY produce local variables of var1 and var2. There was a nice 3-part article in php|architect back in July-Sept 2005 on whitelisting that I could recommend. For example, pass an array to parse_str, then your whitelisting code can turn only expected elements into local vars. After whitelisting, of course validate the values, and plan on handling bad input.
#3

[eluser]rankorn[/eluser]
Thank you MadZad, for the interesting input.

I actually did not put too much tought on parsing the query string (since I was too excited just getting the data in my controller...)

With your experience, do you think passing the second array argument to parse_str() is enough? can you post a small example of using whitelisting?

Ran.
#4

[eluser]Unknown[/eluser]
What are people doing to support query strings necessary for analytics support? In particular, Google Analytics has been using javascript to read the query string and log information, these query strings inevitably including "?","=", and "&", and can sometimes span across all pages. I don't need query string support per se so I've been going with friendly URLs and have enable_query_strings turned off, but I would like them to remain in the URL so that javascript can pick them up.

At the moment if there's a "?var=foo" in the URI it gets treated as a parameter, and my controllers / methods don't expect them, spitting out an error. I'm working on an .htaccess method to rewrite and ignore everything after the "?", but are there other methods I should be considering?

cheers,
matt
#5

[eluser]rankorn[/eluser]
Making mod_rewrite ignore the query string is very easy. All you have to do is add '?' after the URL you want to rewrite to.

This way, your controller will not get the query string but the JavaScript running on the browser will see it in the URL.

Ran.
#6

[eluser]MadZad[/eluser]
Quote:With your experience, do you think passing the second array argument to parse_str() is enough? can you post a small example of using whitelisting?

This is what would come to my mind in utilizing the 2nd arg to parse_str (just thinking and typing, just take the essence, there's likely errors)

Code:
$whitelist_params = array("p1", "p2", "p3", "p4");
$safe_qs = array();
parse_str($queryString, $wl_temp);
foreach ($whitelist_params as $wl_item) {
    if (array_key_exists($wl_item, $wl_temp) {
        $safe_qs[$wl_item] = $wl_temp[$wl_item];
    }
}

So your code would access $safe_qs['p1'] instead of $p1. Not as concise, but I prefer it this way because it keeps user-supplied info in a box, and I'm less likely to mistake it for a true local variable later in the code.

The reason I would do something like this is because just using parse_str with one argument means your code could have unintended local variables that have been set by a malicious user. For example, if your code used but did not initialize $my_var, and you did not expect it to appear on the query string, bad things could happen if someone spoofs a url: www.mysite.com/mypage?my_var=12345

If this all sounds like overkill, than it probably is for your application. However, I've found this level of paranoia to be useful for the php sites I work on, so I've gotten into the habit of always whitelisting GET and POST input. In the CodeIgniter world, my controllers will usually have a helper function (starting with an underscore, of course) where I put whitelisting code together with setting up CI's validation so it's not cumbersome at all.

Quote:I actually did not put too much tought on parsing the query string (since I was too excited just getting the data in my controller...)
Yea, your post was about getting the query string to the controller, so my reply was somewhat of a thread hijack. I just couldn't keep my big, whitelisting mouth shut.

Hope this helps, or inspires better ideas...




Theme © iAndrew 2016 - Forum software by © MyBB