Part of the EllisLab Network
   
 
Query String URL Enhancement
Posted: 11 January 2008 02:17 PM   [ Ignore ]  
Summer Student
Total Posts:  7
Joined  01-05-2008

Hi everybody,

I had a problem described in my last post:
http://codeigniter.com/forums/viewthread/68197/

This problem forced me to use query strings and the url I had to parse was as follows:
http://www.mysite.com/index.php?c=mycontroller&m=processAuth&auth_token=3c562b119bd387ec194ade6bab9832c4

I enabled query strings in my config file:
$config[‘enable_query_strings’] = TRUE;
$config[‘controller_trigger’] = ‘c’;
$config[‘function_trigger’] = ‘m’;

I still had issues getting to the auth_token value.

In the end I changed some code in the Router.php file and wanted to submit the code here in case anyone else finds it useful.  It makes query strings act pretty much the same as the regular CodeIgniter URLs.  For example, if you had a controller like:

class myClass extends Controller {
   
function myFunction ($myValue) {
   }
}

Normally, you could call myFunction with a value using a CodeIgniter URL:

www.mySite.com/index.php/myClass/myFunction/123456

With the changes I made to router.php, you can now call it with:

www.mySite.com/index.php?c=myClass&m=myFunction&value=123456

The way the changed code is written now, you only need the “controller_trigger” key in the query string.  The other keys do not matter.  The values will go into the segment array in the order they show up in the query string.

There are a few improvements that could be made but what’s there now is a good start.

I can’t seem to attach the changed Router.php file (renaming or zipping didn’t seem to matter).  But I only changed the _set_route_mapping() function commenting out the following code at the top:

/*
        // Are query strings enabled in the config file?
        // If so, we're done since segment based URIs are not used with query strings.
        if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
        {
            $this->set_class(trim($this->_filter_uri($_GET[$this->config->item('controller_trigger')])));

            if (isset($_GET[$this->config->item('function_trigger')]))
            {
                $this->set_method(trim($this->_filter_uri($_GET[$this->config->item('function_trigger')])));
            }

            return;
        }
*/

and adding the following code near the end of the function:

// check if query strings enabled
        
if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
        
{
            
// at this point the uri_string is the query string
            
$keyValues = split('&', $this->uri_string);
            foreach(
$keyValues as $keyValue) {
                
list($key, $value) = split('=', $keyValue, 2);

                
// just use the value and add in the order they come in
                // at some point may want to utilize keys and ignore order

                
$value = trim($this->_filter_uri($value));

                if (
$value != '')
                    
$this->segments[] = $value;
            
}

        }
else {

the code above goes just above:

// Explode the URI Segments. The individual segments will
            // be stored in the $this->segments array.  
            
foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
            
{
                
// Filter segments for security
                
$val = trim($this->_filter_uri($val));

                if (
$val != '')
                    
$this->segments[] = $val;
            
}

        }
// do not forget this bracket

make sure to add the closing bracket


Hope someone finds it useful. smile

Profile
 
 
Posted: 16 February 2008 02:10 PM   [ Ignore ]   [ # 1 ]  
Summer Student
Total Posts:  7
Joined  01-05-2008

Hi everyone,

Just thought I’d share the following code.  It works with the 1.6.1 version of CI and is a cleaner way to achieve full query string support as described in my first post above.

Put the following in your system/application/config/config.php file:

/*
|--------------------------------------------------------------------------
| Enable Full Query Strings
|--------------------------------------------------------------------------
|
| Full query string support similar to segment based URLs.
|
| **** IMPORTANT **** enable_query_strings above must be set to FALSE
|
| Still uses the trigger configruations above.
*/
$config['enable_full_query_strings'] = TRUE; // enable_query_strings must be false

‘enable_query_strings’ must be FALSE and ‘enable_full_query_strings’ must be TRUE for things to work.

Next we’ll extend the CI_URI class by adding a file called MY_URI.php to system/application/libraries/ with the following code in it:

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

class
MY_URI extends CI_URI {

    
function MY_URI() {
        parent
::CI_URI();
    
}

    
/**     
     * Override for better query string support in CI.
     *
     * Explode the URI Segments. The individual segments will
     * be stored in the $this->segments array.  
     *  
     * @access  private
     * @return  void
     */
    
function _explode_segments()
    
{
        
// check if query strings enabled
        
if ($this->config->item('enable_query_strings') === FALSE AND $this->config->item('enable_full_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
        
{
            
// at this point the uri_string is the query string
            
$keyValues = split('&', $this->uri_string);
            foreach(
$keyValues as $keyValue) {
                
list($key, $value) = split('=', $keyValue, 2);

                
// just use the value and add in the order they come in
                // at some point may want to utilize keys and ignore order

                
$value = trim($this->_filter_uri($value));

                if (
$value != '')
                    
$this->segments[] = $value;
            
}

        }
else {

            
// Explode the URI Segments. The individual segments will
            // be stored in the $this->segments array.  
            
foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
            
{
                
// Filter segments for security
                
$val = trim($this->_filter_uri($val));

                if (
$val != '')
                    
$this->segments[] = $val;
            
}

        }
    }

}

?>

That’s it.  Now you can make requests like:
http://localhost/index.php?c=tester&m=queryStringArgTest&arg1=10&arg2=20

Note this would be the same as a CI segement request like:
http://localhost/tester/queryStringArgTest/10/20

Also note the current implementation only cares about the order of the query string values ... it doesn’t care what the key names are.  But the implementation does check to see if the “controller_trigger” exists, so only that key must be present.  Something like the following would work the same as the example above:
http://localhost/index.php?c=tester&foo=queryStringArgTest&foo=10&foo=20

Eventually I may add some more capability such as mapping the querystring keys to arguments so they could be out of order.  But what I’ve got now works for me.

I haven’t fully tested the code but I’ll let you know if I run into any issues.

I’m learning more and more about the CI framework as I use it.  I’m loving it.  Thanks for putting it out there for people like me to utilize.

Profile
 
 
Posted: 19 February 2008 04:09 PM   [ Ignore ]   [ # 2 ]  
Summer Student
Total Posts:  3
Joined  01-11-2008

I kind of glanced over the code portion, but if I follow you correctly, using your extension here I could have a URL that supports regular query strings and the rest of my urls be friendly correct?

I really need something like this for a search function. The problem is that not every option in a search box is enabled and it makes it really error prone to figure which options were chosen with the segment only URLs. Think of an advanced search capability on a site with different options.

Something even better would be mixed mode. Where I could have host.com/view_items/productName/search?minPrice=1&maxPrice=100&blah;=&blah;=. Grails allows this and it is quite nice, but I can’t use grails smile

regardless, having an either/or solution would be wonderful.

Profile
 
 
Posted: 13 March 2008 01:13 PM   [ Ignore ]   [ # 3 ]  
Summer Student
Total Posts:  24
Joined  12-03-2007

THANK YOU, this is great! it worked perfectly and got my project to the next step.  Saved me tons of time (and impressed my boss). 

I hope they incorporate this in to the CI core.

Profile
 
 
Posted: 23 April 2008 05:31 PM   [ Ignore ]   [ # 4 ]  
Summer Student
Total Posts:  2
Joined  04-23-2008

Thought I share this as I found it incredibly frustrating that I couldn’t mix using paths and query strings and a situation arose that demanded this with very short time frame to sort it out.

If you want urls like:

http://www.yoursite.com/segment/and_so_on/?query=1&query1=2

This’ll work like you’d expect it.

e.g. you can still use :

$this->uri->segment(2)

// but you can also use

$_GET['query']

and

http://www.yoursite.com/segment/and_so_on // Works
http://www.yoursite.com/index.php?c=food&m=menu // Works and pulls up crontroller/method
http://www.yoursite.com/segment/and_so_on/?query=working // Also works

You need to create a file called MY_URI.php in your system/application/libraries/ folder

Put the following in it, it’s really simple just overrides one method.

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

class
MY_URI extends CI_URI {

    
function MY_URI() {
        parent
::CI_URI();
    
}

    
// --------------------------------------------------------------------
    
    /**
     * Override the _parse_request_uri method so it allows query strings through
     *
     * @access    private
     * @return    string
     */    
    
function _parse_request_uri()
    
{
        
if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')
        
{
            
return '';
        
}
        
        $uri
= explode("?",$_SERVER['REQUEST_URI']); // This line is added to the original
        
$request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $uri[0])); // This line changed
        // Everything else is just the same

        
if ($request_uri == '' OR $request_uri == SELF)
        
{
            
return '';
        
}
        
        $fc_path
= FCPATH;        
        if (
strpos($request_uri, '?') !== FALSE)
        
{
            $fc_path
.= '?';
        
}
        
        $parsed_uri
= explode("/", $request_uri);
                
        
$i = 0;
        foreach(
explode("/", $fc_path) as $segment)
        
{
            
if (isset($parsed_uri[$i]) AND $segment == $parsed_uri[$i])
            
{
                $i
++;
            
}
        }
        
        $parsed_uri
= implode("/", array_slice($parsed_uri, $i));
        
        if (
$parsed_uri != '')
        
{
            $parsed_uri
= '/'.$parsed_uri;
        
}

        
return $parsed_uri;
    
}

}

?>

In your system/application/config.php file you need to enable query strings so $_GET isn’t unset and set the uri protocol to REQUEST_URI. With some digging around I’m sure you could get AUTO and the other methods to work as well but just didn’t have the time or the need.

$config['uri_protocol']    = "REQUEST_URI";
$config['enable_query_strings'] = TRUE;

I hope this is of help to someone

Profile
 
 
Posted: 23 April 2008 07:41 PM   [ Ignore ]   [ # 5 ]  
Sr. Research Associate
RankRankRankRankRank
Total Posts:  2612
Joined  06-10-2007

Why not simply enable_query_strings, use PATH_INFO, and use $this->input->get(‘variable’); in the Controller

http://domain.tld/index.php/controller_name/method_name?variable=stop-messing-around
 Signature 

URI Language Identifier | Modular Extensions - PHP5 | Modular Separation - PHP5 | Widget plugin | Access Control library

Profile
 
 
Posted: 24 April 2008 12:07 AM   [ Ignore ]   [ # 6 ]  
Summer Student
Total Posts:  2
Joined  04-23-2008

Wow that works on my live machine perfectly thanks for that. It doesn’t work on my local one, god knows why, probably something I’ve done no doubt.

I wish it was easier to find your answer though. When you google about query strings in codeigniter you just get posts about having to hack away to be able to get them to work which I now see is actually misleading.

Thanks wiredesignz

Profile
 
 
   
 
 
Post Marker Legend
New Topic New posts Hot Topic Hot Topic with new posts New Poll New Poll Moved Topic Moved Topic Sticky Topic Sticky topic
Old Topic No new posts Hot Old Topic Hot Topic with no new posts Old Poll Old Poll Closed Topic Closed Topic Announcement Announcements
Theme
Change Theme
Visitor Statistics
The most visitors ever was 721, on January 06, 2010 09:38 AM
Total Registered Members: 115027 Total Logged-in Users: 60
Total Topics: 122462 Total Anonymous Users: 3
Total Replies: 647375 Total Guests: 480
Total Posts: 769837    
Members ( View Memberlist )