views:

446

answers:

1

I'm working locally across two "domains". I have enterprise.local and application.local virtual hosts on my machine and I need to set a domain cookie for "local" or ".local" I'm having some trouble getting the cookie to set properly, though. In application.local, I have this:

setcookie( 'iPlanetDirectoryPro', trim( $token_id ), '0', '/', '.local' );
header( 'Location: /adcom-sso' );

I've also tried this:

header( 'Set-Cookie: iPlanetDirectoryPro=' . trim( $token_id ) . '; path=/' );
header( 'Location: /adcom-sso' );

Using setcookie(), no cookie is ever set. Using the Set-Cookie header, the cookie is set. I've removed the redirection from both and the result never changes. It works for Set-Cookie, but not for setcookie(). That would be fine since I don't really have a preference which solution I use, but in the Set-Cookie solution, as soon as I add a domain it all breaks down:

header( 'Set-Cookie: iPlanetDirectoryPro=' . trim( $token_id ) . '; path=/; domain=local' );

As soon as I add in the domain value, I get a header error:

Header may not contain more than a single header, new line detected.

I've tried the domain value as "local" and ".local". The behavior doesn't change.

I rarely have to explicitly access cookies, so I hope I'm just missing something obvious, but I surely don't see it. Any insight would be much appreciated.

UPDATE: I think I've narrowed this down a bit further. It seems that both ways will work as long as I don't include a domain value. Could there be a problem with using "local" or ".local" as the specific domain for the cookie?

+2  A: 

EDIT: I've now had a look at RFC2109, 4.3.2 Rejecting Cookies:

  • The value for the Domain attribute contains no embedded dots or does not start with a dot.

    ...

  • A Set-Cookie with Domain=.com or Domain=.com., will always be rejected, because there is no embedded dot.

It seems that the browser is rejecting '.local' due to security concerns. To set a cookie for a domain, it must have at least two dots (e.g. '.cookiedomain.local').

Setting a cookie from one subdomain (e.g. one.local) for another subdomain (e.g. another.local) isn't possible AFAIK. What you can do to overcome this problem is redirecting the user to a cookie domain that sets/gets all cookies and redirects the user again to where they came from with the cookie data included in the url as query parameters. Microsoft does (or did) it like this for its own domains (msn.com, microsoft.com).


The error that you get ("Header may not contain...") is only triggered if the string you pass as an argument to header() contains a linefeed character that is not followed by either a space or a tab (which would continue the header on the next line).

Now, setcookie() will actually urlencode() its value (setrawcookie() will not), so a linefeed will not cause an error there.

The trim() function, on the other hand, will strip whitespace only from the beginning and end of its argument and leave any other linefeed characters intact. So perhaps you could try something like preg_replace('/\s+/', '') instead.

Why the setcookie() approach doesn't work for you isn't immidiately obvious to me. Could be that you are actually seeing the cookie (set with setcookie()) but aren't expecting url escapes in it, and are silently rejecting it somewhere in your code.

However, that doesn't explain why your first header() seems to work (with linefeeds in it); it seems that some of your cookie values have linefeeds in them and some do not.

Setting the domain to '.local' (leading '.') is the right thing to do, by the way, if you want subdomains to see the cookie.

Some additional caveats about setting cookies with setcookie() are discussed in the PHP documentation (especially user comments).

Inshallah
I've actually tried all of those. Originally, I wasn't trimming at all. I also tried setrawcookie(), although I didn't include it here for the sake of simplicity. In the Set-Cookie solution, I also tried manually urlencode()'ing the $token_id. I just tried the preg_replace() idea and it didn't change anything. Thanks.
Rob Wilkerson
"Header may not contain..." will *not* get triggered unless you have a linefeed in there. I've looked at the PHP source code (`sapi_header_op()`). You definitely have a linefeed problem with that error.
Inshallah
What I ultimately tracked down matched your edit. As soon as I tried ".local.com" everything went smoothly. In this case, the problem was because of my dev environment where I keep my "domains" simple. It should never be a problem up the stack towards production environments. Thanks for your help.
Rob Wilkerson