Yii Framework Forum

Custom router question


(Kpsklab) #1

I am just experimenting with custom php routing, the following code works:

class Router
{

    public function run()
    {
        $routes = [
            'dog/indexadmin' => '\\Mini\\Controller\\DogController@indexAdmin',
            'dog/index' => '\\Mini\\Controller\\DogController@index',
            'dog/edit' => '\\Mini\\Controller\\DogController@edit'
        ];

        $uri = explode('/', $_SERVER['REQUEST_URI']);
        $last = array();
        foreach ($uri as $i => $key) {
            $i > 0;
            $key;
            if ($i > 3) {
                $newkey = strtok($key, '?');
                array_push($last, $newkey);
            }
        }

        $totalparts = $i;
        $lastkey = $newkey;

        if ($totalparts > 3) {
            $str = implode(", ", $last);
        }
        $uri = $uri[2] . '/' . $uri[3];
        $newuri = strtok($uri, '?');
        $key_to_check = $newuri;
        if (array_key_exists($key_to_check, $routes)) {
            $uparts = explode('@', $routes[$key_to_check]);
            $controller = isset($uparts[0]) ? $uparts[0] : null;
            $action = isset($uparts[1]) ? $uparts[1] : null;

            call_user_func_array(array($controller, $action), $last);
        }
    }

}

Namely the

call_user_func_array(array($controller, $action), $last);

$last is just uri parameter parts.

The url is something like:

http://localhost/mini3/dog/indexadmin/hello/jims

However, if I wanted to use

           if ($totalparts > 3) {
                $c = new $controller;
                $c->$action($str);
            } else {
                $c = new $controller;
                $c->$action();
            }

Instead of call_user_func_array

If there are no extra parameters like:

http://localhost/mini3/dog/indexadmin

it works. However if there are the extra parameters

/hello/jim

It does not work. My function:

$str = implode(", ", $last);

properly comma separates them for this part:

$c->$action($str);

But just passes all as one string.

If I hard code in

$c->$action("hello",  'jim");

it works.

How would I get 2 or more parameters like “hello”, 'jim" into one variable
to pass to controller, but controller treats them as comma separated individual strings?

In controller I have:

    public function indexAdmin($tmp = null, $name = null)
    {
         echo $tmp . " " . $name;

Followup from a previous question
(Mehdi Achour) #2

Hi,

The problem is that you end up calling:

$c->$action(array("hello", "jim"));

call_user_func_array is the function you are looking for, as it will properly call

$c->$action('hello', 'jim')

Why are you trying to replace it in the first place?


PS: This really doesn’t seem Yii related and might be better suited for StackOverflow than this forum :wink:


(Kpsklab) #3

It’s like being a mad scientist, I love playing around with code. I’m not replacing, I just got curious how to get 2 url parameters into the

$c->$action('hello', 'jim')

from the uri. Thanks for responding.

I can actually get

'hello', 'jim'

passed, but only as one string, some how the controller is treating as a single string.
But again writing it in manually to test, of course works.


(Kpsklab) #4

But I put it in the general php section, where it goes.


(Mehdi Achour) #5

My bad, I didn’t know that this existed :smiley: still new here.


(Mehdi Achour) #6

Well, in this case, let’s dive further.

You are confusing two things similar visually:

  • A string that look like two separate arguments in a function call
  • Two actual separate arguments in a function call

When you’re doing this:

$str = implode(", ", $last);

you are creating a string containing “param1, param2, param3, …”

it’s still a string, so when you pass it like this: $c->$action($str);, the method receives only one argument, the string.

It doesn’t matter if you use “,” or anything else as a separator, PHP will interpret it as a single string.

For mad scientistery only, you could use the evil eval() function:

// Generate the code as you would hardcode it:
$code = '$c->$action("' . implode('", "', $last) . '");';

// Code is now a string containing exactly: $c->$action("hello", "jim");
// You can now have PHP evaluating that code with

eval($code);

But doing something like this would expose you to soooo many security flaws that you could go to the PHP jail :slight_smile:

Imagine if a malicious user passed "); foreach(glob('*.*' as $e)) unlink($e); print(" in your url instead of hello and jim in your URL, what would happen?

You’d end up executing on your server:

$c->$action("");
foreach (glob('*.*' as $e)) unlink($e);
print("");

call_user_func_array is the simplest, safest, built-for-what-you-want solution in this case. It will take an array as a parameter, and will spread its content to the function call, passing as many function arguments as array entries.

Or you could also use the Reflection API to achieve that.

Hope this helps!