目录中的CakePHP应用程序会破坏使用查询字符串完成的重定向

My CakePHP 2.0 application url is: http://localhost/testapplication/

and when I do redirects on a login from a link I use a query string e.g.

localhost/testapplication/login?continue=/testapplication/admin/posts

The redirect is done using:

            if(isset($this->params['url']['continue']))
            {
                $pathtoredirect = $this->params['url']['continue'];
            }
            else
            {
                $pathtoredirect = $this->Auth->redirect();
            }

            return $this->redirect($pathtoredirect);

However when I do the redirect I will end up at a URL like:

localhost/testapplication/testapplication/admin/posts

As you can see it redirects to the passed url but because the passed url also contained the base directory it duplicates it breaking the url redirect and ending up at a 404!

Any ideas on how to get around this problem?

Just to confirm:

  • The url does start with a / so it does redirect at the root level, but the problem is that root level is a directory so it duplicates it as it's also passed in the query

If you construct a path in either of the following ways:

$continue = Router::url(array('controller' => 'admin', 'action' => 'posts'));
$continue = Router::url('/admin/posts');

then Router::url will prepend the base path /application. Then if you call Router::url again on the resulting url (or redirect to it) Router::url will prepend it again. That's the way it works, and there's nothing you can do about it.

In reality, the url /application/admin/posts is ambiguous, but CakePHP reads it as controller=application, action=admin, and the first argument is posts.

The only ways to circumvent this are:

Use an absolute url:

$continue = Router::url(array('controller' => 'admin', 'action' => 'posts'), true);

Or make sure Router::url is only called once, e.g.:

$continue = '/admin/posts';

Or after login

$pathtoredirect = FULL_BASE_URL . $this->params['url']['continue'];

It seems like you have a couple options here. If $this->params['url']['continue'] is exactly what you pass in with your query string, is it possible for you to modify your query string so it is just /admin/posts so the complete URL will be application/admin/posts?

You may not have to do this, but I'd need to see exactly what $this->params['url']['continue'] looks like. Please do a die(debug($this->params['url']['continue'])); somewhere before your redirect so we can investigate further.

Okay the fix was to do the following:

Get the full URL (as mentioned by others) here using a helper:

class LinkHelper extends AppHelper
{
    public function selfURL()
    {
        $pageURL = 'http';

        //if ($_SERVER["HTTPS"] == "on")
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')
        {
            $pageURL .= "s";
        }
        $pageURL .= "://";
        if ($_SERVER["SERVER_PORT"] != "80")
        {
            $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
        } 
        else
        {
            $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
        }

        $pageURL = urlencode($pageURL);

        return $pageURL;  
    }

}

Then when using the URLs making sure to encode and decode them for use in the address bar

e.g. $pathtoredirect = urldecode($this->params['url']['continue']);