tags:

views:

372

answers:

3

I am trying to make a simple redirector controller in CakePHP. I'd like the URL to be of the form:

http://example.com/redirector/&lt;numeric id>/<url to redirect to>

For example,

http://example.com/redirector/1/http://www.google.com

The URL that I need to redirect could be more complex, of course, including slashes, parameters and anchors.

I can't seem to be able to figure out how to write the route configuration so that my action would look something like:

class RedirectsController extends AppController {

    function myredirectaction($id, $url) {
        $this->autoRender = false;
        $this->redirect($url);
    }

It seems like whatever I try, the "/"'s in the url-to-redirect-to confuses my route attempt and splits the URL into pieces, and this no longer matches my action definition. What should I do?

I am new to PHP and CakePHP, so any advice you can give is appreciated.

Update:

So instead of the example URL above, it has been URL-escaped to look like this:

http://example.com/redirector/1/http%3A%2F%2Fwww.google.com

However, my routing is still not working. Here's what I have in routes.php:

Router::connect(
 '/redirector/:id/:url',
 array('controller' => 'redirects', 'action' => 'myredirectaction'),
 array(
  'id' => '[0-9]+',
  'url' => 'http.*'
 )
);

This is what I get when I try that URL:

Warning (2): array_merge() [function.array-merge]: Argument #1 is not an array [CORE/cake/dispatcher.php, line 301]

Code | Context

$fromUrl    = "redirector/1/http://www.google.com"
$params = array(
    "pass" => array(),
    "named" => array(),
    "id" => "1",
    "url" => "http://www.google.com",
    "plugin" => null,
    "controller" => "redirects",
    "action" => "myredirectaction",
    "form" => array()
)
$namedExpressions   = array(
    "Action" => "index|show|add|create|edit|update|remove|del|delete|view|item",
    "Year" => "[12][0-9]{3}",
    "Month" => "0[1-9]|1[012]",
    "Day" => "0[1-9]|[12][0-9]|3[01]",
    "ID" => "[0-9]+",
    "UUID" => "[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}"
)
$Action = "index|show|add|create|edit|update|remove|del|delete|view|item"
$Year   = "[12][0-9]{3}"
$Month  = "0[1-9]|1[012]"
$Day    = "0[1-9]|[12][0-9]|3[01]"
$ID = "[0-9]+"
$UUID   = "[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}"
$url    = array(
    "url" => "/redirector/1/http://www.google.com"
)

array_merge - [internal], line ??
Dispatcher::parseParams() - CORE/cake/dispatcher.php, line 301
Dispatcher::dispatch() - CORE/cake/dispatcher.php, line 118
[main] - APP/webroot/index.php, line 88

And more warnings from my action since it did not get the two expected arguments.

Of course, I've changed my action to urldecode($url) before using the $url.

+2  A: 

To place slashes and other special characters, use their ACSII codes instead. For a list of the codes and their respective characters, refer to this documentation:

http://www.ascii.cl/htmlcodes.htm

BraedenP
It turns out that even by encoding the URL, the server was still passing the decoded URL to PHP. This could perhaps be changed by changing the server configuration, but that is not an option for all cases.
Heikki Toivonen
+1  A: 

You need to add a pass array to pass the variables to your action.

Router::connect(
        '/redirector/:id/:url',
        array('controller' => 'redirects', 'action' => 'myredirectaction'),
        array(
                'id' => '[0-9]+',
                'url' => 'http.*',
                'pass' => array('id', 'url')
        )
);

You can find additional information about why here: http://book.cakephp.org/view/543/Passing-parameters-to-action

Jason
That indeed helps, but is still not enough to deal with the URL the way I wanted due to encoding/decoding issues and path separators.
Heikki Toivonen
Because of the colon and the possible question mark in the url, the URL needs to be URL encoded. Otherwise, you could call func_get_args() and rejoin the arguments with slashes yourself.I'm not sure about any other http servers, but if you're using Apache, you might also check if you have AllowEncodedSlashes set. It can cause trouble with encoded URLs if it is not on.
Jason
A: 

I can't seem to make this work with the URL like I was originally hoping for. The best I have been able to do is to supply the URL to redirect to in the parameters. So routing becomes simply:

Router::connect(
        '/redirector',
        array('controller' => 'redirects', 'action' => 'myredirectaction')
);

And the controller action becomes (error handling omitted):

function myredirectaction() {
    $this->autoRender = false;
    $redirect_url = $this->params['url']['theurl'];
    $this->redirect($redirect_url);
}

And the URL is of the form:

http://example.com/redirector?theid=1&amp;theurl=http://www.google.com
Heikki Toivonen