Part of the EllisLab Network
   
 
Bug when using route with subfolder in it ????
Posted: 19 April 2007 11:57 AM   [ Ignore ]  
Grad Student
Rank
Total Posts:  51
Joined  09-12-2006

Hi,
I have found some post that describe the same problem that I have encountered:

Here is the list:
march 2007
fabruary 2007
january 2007 -1
january 2007 -2

The awaited parameters are missing in controler function when we use a target route with a folder in it?

a static example of route that doesn’t work:

$route['myroute'] = "folder/controler/methode/param1/param2";
//that return param2 as param1


and a complex one that doesn’t work:

$route['products/([a-z]+)/(\d+)'] = "folder/controler/methode/$1/id_$2";
//that return id_$2 in $1 place

Both work fine if we shouldn’t used controler into subfolder…..

I have seen that CI 1.5.3 is out since two days, I haven’t test it but I haven’t seen in the changelog any notes about fixing this problem??
Is it Fix in 1.5.3 ??

So I give you the result of my test:

1- Why this problem append:
Because CI use ‘rsegments’ that is returned by CI->uri->rsegment_array(); to find the parameters to be given to the function With the : $directory, $class and $method property of the CI_router classe.

But in the CI_router::_validate_segments() when CI set the $directory router property it unset the directory segment into the rsegment array.
Thus like there is a folder CI search the first param in $rsegments[4] and it is in the $rsegments[3] because the folder was unset.

Test a controler function with an optional param for that it not crash.

function testroute($param = "DEFAULT"){
  
echo "Param =".$param."</BR>";
  echo
"rsegments array: </br>".nl2br(print_r($this->uri->rsegment_array(),true));
}

     

Add in your route.php config:

$route['test1'] = "folder/controler/testroute/param1";


This output DEFAULT as param

$route['test2'] = "folder/controler/testroute/param1/param2";


And this output param2

And you will see that the folder is missing from the rsegments array

2- My Solution:

Some of you, in the post join at the begining, gived solution that toutch the CodeIgniter.php file, and if I have understand change the index awaited for the first parameter by shifting it of a notch on the left? I think 3 instaed of 4.

But as we work with a controler subfolder when we think about URI we wait for the first param at index 4. So my solution is to re-add the folder into the rsegment_array and all work as waited.

In the Router.php system libraries files, in the _compile_segments() methode
At the end of the methode juste before the line $this->rsegments = $segments;
Add this 3 lines:

if($this->fetch_directory() != ''){
     array_unshift
($segments,str_replace("/","",$this->fetch_directory()) );
  
}
  
//just before
  
$this->rsegments = $segments;
}


Try it and tell me if that’s work for you????

Profile
 
 
Posted: 24 April 2007 10:45 PM   [ Ignore ]   [ # 1 ]  
Grad Student
Avatar
Rank
Total Posts:  92
Joined  01-29-2007

Thanks for this fix thierryREY!

It’s working for me. I’m going to see if we can get this implemented in the core since it was being discussed here:
http://codeigniter.com/forums/viewthread/48779/

Profile
 
 
Posted: 25 April 2007 07:58 AM   [ Ignore ]   [ # 2 ]  
Grad Student
Rank
Total Posts:  51
Joined  09-12-2006

Hi, every one…..

I have made some other tests on the routing probleme aboutroute target with subfolder.

And I have found and other case when we should reintroduice the directory into the route segments array.

Here is the complete code of the _compile_segments() function of the Router.php file librarie. The first modification explain in my previous post is named //MODIF_1 (I have added a peace of code from the next post, str_replace()) and the new modification is named //MODIF_2.

function _compile_segments($segments = array())
{    
    $segments
= $this->_validate_segments($segments);

    if (
count($segments) == 0)
    
{
        
//>>>>MODIF_2<<<<
        
if(str_replace("/","",$this->fetch_directory()) != ''){
        array_unshift
($segments,str_replace("/","",$this->fetch_directory()) );
        
}
        $this
->rsegments = $segments;
                
//>>>>END_MODIF_2<<<<
        
return;
    
}
                        
    $this
->set_class($segments[0]);
        
    if (isset(
$segments[1]))
    
{
        
// A scaffolding request. No funny business with the URL
        
if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding')
        
{
            $this
->scaffolding_request = TRUE;
            unset(
$this->routes['scaffolding_trigger']);
        
}
        
else
        
{
            
// A standard method request
            
$this->set_method($segments[1]);
        
}
    }
        
    
// Update our "routed" segment array to contain the segments.
    // Note: If there is no custom routing, this array will be
    // identical to $this->segments
        
    //>>>>MODIF_1<<<<
    
if(str_replace("/","",$this->fetch_directory()) != ''){
        array_unshift
($segments,str_replace("/","",$this->fetch_directory()) );
    
}
        
//>>>>END_MODIF_1<<<<
    
$this->rsegments = $segments;

}

There an other little Change into the _reindex_segments() function when we search difference.

change:

$diff = (count(array_diff($this->rsegments, $this->segments)) == 0) ? FALSE : TRUE;


in

$diff = (count(array_diff($this->segments, $this->rsegments)) == 0) ? FALSE : TRUE;


because,with the first solution, if $this->rsegments =array()is empty => $diff always False even if $this->segments is different.
And also because the source route $this->segments couldn’t be empty

I hope I’m clear

The MODIF_2 resolve a probleme extremely rare. It is when you have an empty route or a route whith only a folder.

$route['test1'] = "";
$route['test2'] = "folder_name";

Those routes works but the $rsegment array is wrong.

without the new modif those route give $segments and $rsegments like this

$segments = array('test1');
$rsegments = array('test1');

//and

$segments = array('test2');
$rsegments = array('test2');

With the modif we have the wishing result:

$segments = array('test1');
$rsegments = array('');

//and

$segments = array('test2');
$rsegments = array('folder_name');

One good thing should be to reintroduice the default class and the default method in the $rsegments array when the route system take it.
Like this the rsegments array always match the real target route.

Profile
 
 
Posted: 29 April 2007 06:32 PM   [ Ignore ]   [ # 3 ]  
Grad Student
Avatar
Rank
Total Posts:  92
Joined  01-29-2007

Hi thierryREY,

I’m impressed.

To make sure we understand. You are proposing three changes:

At line 161 of system/libraries/Router.php add

if($this->fetch_directory() != '') {
    array_unshift
($segments,str_replace("/","",$this->fetch_directory()) );
}

At line 181 of system/libraries/Router.php add

if($this->fetch_directory() != '') {
    array_unshift
($segments,str_replace("/","",$this->fetch_directory()) );
}

At line 261 of system/libraries/Router.php replace

$diff = (count(array_diff($this->rsegments, $this->segments)) == 0) ? FALSE : TRUE;


with this (the difference is the switch of the rsegments and segments)

$diff = (count(array_diff($this->segments, $this->rsegments)) == 0) ? FALSE : TRUE;

Did I understand your post correctly?

For anybody new to the thread:
This patch is designed to allow subdirectory controllers to properly receive parameters that are passed to the controller as well as the other benefits that thierryREY mentioned.

When I get a chance, I will test your code. If anybody else wants to test the proposed changes that would be great (I’m already using the change at line 181, I haven’t had a chance to work with the other two code changes).

Profile
 
 
Posted: 30 April 2007 10:17 AM   [ Ignore ]   [ # 4 ]  
Grad Student
Rank
Total Posts:  51
Joined  09-12-2006

not exactly you have forgot a peace of code in line 161 and 186

line 161:

if(str_replace("/","",$this->fetch_directory()) != ""){
   array_unshift
($segments,str_replace("/","",$this->fetch_directory()) );
}
$this
->rsegments = $segments;

line 186:

if(str_replace("/","",$this->fetch_directory()) !='')
{
   array_unshift
($segments,str_replace("/","",$this->fetch_directory()) );
}

you have forgoten the str_replace() in the both if() conditions and $this->rsegments = $segments; for the line 161 modif

Profile
 
 
Posted: 04 September 2007 01:54 PM   [ Ignore ]   [ # 5 ]  
Summer Student
Total Posts:  4
Joined  03-22-2007

What’s the status of incorporating this fix into the core?  It appears not to be in 1.5.4, correct?

Profile
 
 
Posted: 05 September 2007 05:17 AM   [ Ignore ]   [ # 6 ]  
Grad Student
Rank
Total Posts:  51
Joined  09-12-2006

no change about this bug into the 1.5.4
you are right!!

Profile
 
 
Posted: 18 September 2007 04:56 PM   [ Ignore ]   [ # 7 ]  
Lab Assistant
RankRank
Total Posts:  115
Joined  06-22-2007

Bump! Please fix!

Profile
 
 
Posted: 19 September 2007 02:38 AM   [ Ignore ]   [ # 8 ]  
Lab Assistant
RankRank
Total Posts:  115
Joined  06-22-2007

It looks like the URI.php and Router.php class are being rewritten. Hopefully, these changes will be incorporated.

Profile
 
 
Posted: 19 September 2007 05:00 AM   [ Ignore ]   [ # 9 ]  
Grad Student
Rank
Total Posts:  51
Joined  09-12-2006

Are you sure this change will be incorporate, are you in the dev team????

And if yes,will this debug use my code???

Because my code is not a really clean debug. I made this version for that it work with the CI code with a minimum of changes. But If we really want to debug it we need to create a cleaner version on the debug.

I had this more clean version but it need a little change into the line of the controller function call of the CodeIgniter.php file, it is why I haven’t put it here.

but if you want I can give it???

Profile
 
 
Posted: 19 September 2007 10:20 AM   [ Ignore ]   [ # 10 ]  
Lab Assistant
RankRank
Total Posts:  115
Joined  06-22-2007

I’m not in the dev team, but I use the svn version of CI, which still currently has the bug, but the Router and URI classes have been refactored. I’m just hoping that the dev team will not stop there and will fix this bug. In the current svn version, there is no more _compile_segments() method and the methods have moved around a bit, some that belonged to URI have been sent to Router and vice versa. It makes a fix a lot simpler.

On a side note, I went through the code myself and I realized that this bug is probably due to a misunderstanding of how the php function array_diff() works.

Take 2 arrays:
$segments = array(‘my_directory’,‘my_controller’,‘my_method’,‘var1’,‘var2’);
$rsegments = array(‘my_controller’,‘my_method’,‘var1’,‘var2’);

array_diff($rsegments,$segments) == 0; //we would expect this to return something different

whereas

array_diff($segments,$rsegments) == 1;

This is why the route works for controllers in sub-folders when the request is not rerouted. Somehow the faulty assumptions made about array_diff() accidentally resets the value of $rsegments to reinclude the directory in the array. The controller, action and variables are then accurately mapped inside system/codeigniter/CodeIgniter.php.

Profile
 
 
Posted: 19 September 2007 11:33 AM   [ Ignore ]   [ # 11 ]  
Grad Student
Rank
Total Posts:  51
Joined  09-12-2006

Yes but not only.

It is commented in my post but you are right when you say that the problem with array_diff() is the reason why the real bug appears only when there is a route with a subfolder…..

I will look at the CI svn thanks…..

Profile
 
 
Posted: 27 November 2007 08:03 AM   [ Ignore ]   [ # 12 ]  
Summer Student
Total Posts:  8
Joined  11-18-2007

Thank you really much for this topic, it’s very usefull !

However, it initially didn’t work for me because ‘rsegments’ contained the ‘segments’ elements plus one more.

If we change:

$diff = (count(array_diff($this->segments, $this->regments)) == 0) ? FALSE : TRUE;

by:

if (count($this->rsegments)!=count($this->segments)) $diff = TRUE;
else
$diff = (count(array_diff($this->rsegments, $this->segments)) == 0) ? FALSE : TRUE;

in the _reindex_segments function, it will completely fix it, I think.

Benco.

PS: Sorry for my bad English wink

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 719, on June 06, 2008 10:16 AM
Total Registered Members: 64452 Total Logged-in Users: 23
Total Topics: 80957 Total Anonymous Users: 0
Total Replies: 435677 Total Guests: 178
Total Posts: 516634    
Members ( View Memberlist )