Php session cookie not being set

can't get php's $_SESSION to work on my local machine

it's working just fine on a live server but it's not working on a local machine

i have tried with apache and php on windows, apache and php on mac and apache and php on debian, none of them work ( my live server is also running debian 9, the same one i tried locally )

in firefox' developer tools > network > headers i can see that php is sending the set-cookie but for some reason it's not being set ( no cookies in storage > cookies, and my script isn't working as it should when cookie is set )

i'm not using ssl/https and i have set "session.cookie_secure = 0 and off" but for some reason this is what the set-cookie header looks like: "Set-Cookie: PHPSESSID=XXXXX;path=/;HttpOnly;Secure", i don't think php should be setting the Secure flag since i explicitly disabled it in php.ini?

and yes, every file that uses session functionality has a session_start() in it

there are no apache/php errors whatsoever, i even have xdebug enabled

tested using localhost, 127.0.0.1, 10.0.0.10 ( my lan ip ), and custom hostname, none work

i'm out of ideas, tried everything i could think of

works on a live debian 9 server with php 7.2 and default configuration

doesn't work on a local debian 9 server with php 7.2 and default configuration

doesn't work on windows with the same apache/php versions

doesn't work on mac with apache 2.4 and php 7.3, not even with session.cookie_secure=0 set

checked for both apache and php errors, there are none

used firefox' developer tools to see headers/cookies

checked my code and made sure it has session_start() and everything else is correct

i even tried manually setting the cookie with the secure flag set to false and again "Secure" is being set in Set-Cookie header, this was the code:

setcookie("PHPSESSID", "7nhqdim7uu2viae7vhhf9os5ue", 0, "/", "", false, false);

and here is the code i use for testing:

<?php
session_start();

var_dump($_SESSION);

if(isset($_POST['submit']))
{
  $_SESSION['value'] = $_POST['example'];
  header('Location: /session.php'); // session.php is this file
}

if(isset($_SESSION['value']) && $_SESSION['value'] == 'example')
{
  echo "value is " . $_SESSION['value'] . '<br>';
}
?>
<form method="post">
  <input type="text" name="example" value="example">
  <input type="submit" name="submit" value="submit">
</form>

(PHP 4, PHP 5, PHP 7, PHP 8)

session_set_cookie_paramsSet the session cookie parameters

Description

session_set_cookie_params(
    int $lifetime_or_options,
    ?string $path = null,
    ?string $domain = null,
    ?bool $secure = null,
    ?bool $httponly = null
): bool

session_set_cookie_params(array $lifetime_or_options): bool

This function updates the runtime ini values of the corresponding PHP ini configuration keys which can be retrieved with the ini_get().

Parameters

lifetime_or_options

When using the first signature, lifetime of the session cookie, defined in seconds.

When using the second signature, an associative array which may have any of the keys lifetime, path, domain, secure, httponly and samesite. The values have the same meaning as described for the parameters with the same name. The value of the samesite element should be either Lax or Strict. If any of the allowed options are not given, their default values are the same as the default values of the explicit parameters. If the samesite element is omitted, no SameSite cookie attribute is set.

path

Path on the domain where the cookie will work. Use a single slash ('/') for all paths on the domain.

domain

Cookie domain, for example 'www.php.net'. To make cookies visible on all subdomains then the domain must be prefixed with a dot like '.php.net'.

secure

If true cookie will only be sent over secure connections.

httponly

If set to true then PHP will attempt to send the httponly flag when setting the session cookie.

Return Values

Returns true on success or false on failure.

Changelog

VersionDescription
8.0.0 path, domain, secure and httponly are nullable now.
7.3.0 An alternative signature supporting an lifetime_or_options array has been added. This signature supports also setting of the SameSite cookie attribute.
7.2.0 Returns true on success or false on failure. Formerly the function returned void.

See Also

  • session.cookie_lifetime
  • session.cookie_path
  • session.cookie_domain
  • session.cookie_secure
  • session.cookie_httponly
  • session.cookie_samesite
  • session_get_cookie_params() - Get the session cookie parameters

final dot wharf at gmail dot com

11 years ago

As PHP's Session Control does not handle session lifetimes correctly when using session_set_cookie_params(), we need to do something in order to change the session expiry time every time the user visits our site. So, here's the problem.

<?php
  $lifetime
=600;
 
session_set_cookie_params($lifetime);
 
session_start();
?>

This code doesn't change the lifetime of the session when the user gets back at our site or refreshes the page. The session WILL expire after $lifetime seconds, no matter how many times the user requests the page. So we just overwrite the session cookie as follows:

<?php
  $lifetime
=600;
 
session_start();
 
setcookie(session_name(),session_id(),time()+$lifetime);
?>

And now we have the same session cookie with the lifetime set to the proper value.

frank at frankforte dot ca

2 years ago

The following appears to work for setting the SameSite attribute on session cookies for PHP < 7.3.

<?php

    $secure

= true; // if you only want to receive the cookie over HTTPS
   
$httponly = true; // prevent JavaScript access to session cookie
   
$samesite = 'lax';

    if(

PHP_VERSION_ID < 70300) {
       
session_set_cookie_params($maxlifetime, '/; samesite='.$samesite, $_SERVER['HTTP_HOST'], $secure, $httponly);
    } else {
       
session_set_cookie_params([
           
'lifetime' => $maxlifetime,
           
'path' => '/',
           
'domain' => $_SERVER['HTTP_HOST'],
           
'secure' => $secure,
           
'httponly' => $httponly,
           
'samesite' => $samesite
       
]);
    }
?>

Danack dot Ackroyd at gmail dot com

11 years ago

Setting the domain for cookies in session_set_cookie_params() only affects the domain used for the session cookie which is set by PHP.

All other cookies set by calling the function setcookie() either:
i) Use the domain set explicitly in the call to setcookie()
or
ii) Don't set the domain at all on the cookie and so the browser assumes it's for the current domain.

So to make all your cookies be available across all sub-domains of your site you need to do this:

<?php
$currentCookieParams
= session_get_cookie_params(); $rootDomain = '.example.com'; session_set_cookie_params(
   
$currentCookieParams["lifetime"],
   
$currentCookieParams["path"],
   
$rootDomain,
   
$currentCookieParams["secure"],
   
$currentCookieParams["httponly"]
);
session_name('mysessionname');
session_start(); setcookie($cookieName, $cookieValue, time() + 3600, '/', $rootDomain);
?>

passerbyxp at gmail dot com

10 years ago

One might want to be noted that the browsers are case-sensitive to the $path parameter.

For example, if you do this:
<?php
session_set_cookie_params
(0,"/webapp/");
session_start();
?>

and you visit your site in this way:
example.com/WebApp/

You would get a new session on every request.

I'm not sure if this is the standard, but I see this happens on IE 6, Firefox 12 (Palemoon, actually), Chrome 19 (Portable version), and on both IIS and Apache.

werner dot avenant at gmail dot com

10 years ago

Please take note of the garbage collection "feature" on systems like Ubuntu and Debian.

apt-get installs a cron script at /etc/cron.d/php5 that checks the session.gc_maxlifetime variable and then deletes all old sessions every 9 and 39 minutes.

The problem is: If you set the maxlifetime for a specific virtual host, those settings will be ignored. Lets say you want your server to store sessions for only 30 minutes, but for one special website you want all sessions to be 24 hours. If you set the session.gc_maxlifetime in .htaccess, your apache conf or use ini_set in your code, it won't work and sessions will still be destroyed after 30 minutes. That's because /usr/lib/php5/maxlifetime (found in that cron file) will always return the value in your php.ini, not the values you set in .htaccess.

A workaround is to set the maxlifetime to the maximum your sites require, and then configure a shorter maxlifetime in your .htaccess for those sites that don't need it.

Another solution is to give the php5 file in /etc/cron.d sane values, ie, only let it run at 3am in the morning, but you'll have to remember to block the replacement of this file it every time you update php.

shrockc at inhsNO dot SPAMorg

20 years ago

when setting the path that the cookie is valid for, always remember to have that trailing '/'.

CORRECT:
session_set_cookie_params (0, '/yourpath/');

INCORRECT:
session_set_cookie_params (0, '/yourpath');

no comment on how long it took me to realize that this was the cause of my authentication/session problems...

Miki

12 years ago

REMEMBER, that if you have a multi-subdomain site, you must put the following to enable a session id on the whole website:

<?php
session_set_cookie_params
(0, '/', '.example.com');
session_start();
?>

Otherwise, you'll have 2 diffrent sessions on e.g. news.example.com and download.example.com

Anonymous

14 years ago

In Response to RC
>23-Apr-2008 04:45
>For anyone looking for which browsers support the HTTPOnly >flag, per my research:
>
>IE 6 SP 1 and higher.
>Firefox 3 and higher.
>Opera 9.50 and higher.

Firefox 2.0 also supports them, but only since version 2.0.0.5.

http://bugzilla.mozilla.org/show_bug.cgi?id=178993

dan at vespernet dot co dot uk

14 years ago

The below note is an excellent example of how to 'reset' the session expiration time upon a page refresh.

However, take care to compensate for when the session expires and doesn't renew itself (a bug I believe). If the below example is run every time a script is executed, it will give an 'Undefined index <session name> error' after the session fails to renew. Precede it with and if isset() condition.

<?php
private function startSession($time = 3600, $ses = 'MYSES') {
   
session_set_cookie_params($time);
   
session_name($ses);
   
session_start();// Reset the expiration time upon page load
   
if (isset($_COOKIE[$ses]))
     
setcookie($ses, $_COOKIE[$ses], time() + $time, "/");
}
?>

The above example states that a session will last an hour without a page refresh until it is scrapped. Upon a page refresh, the expiration time is reset back to one hour again. If you wish to give users the option of 'staying logged in forever', just feed startSession a value of '99999999', which should last about 3 years.

jordi at jcanals dot net

17 years ago

Something that has taken me some time to debug: session_set_cookie_params() does not work when the domain param is just a one level domain, like it was a TLD.

I have a site in an intranet and our internal domain is .local, so trying to set the cookie session to the .local domain does not work:

session_set_cookie_params(0, '/', '.local'); // Does not work

In all test I've done, setting the domain only works for SLDs and above:

session_set_cookie_params(0 , '/', '.sld.local'); Does work

This is nothing to do with PHP but the http protocol, witch does not permit setting cookies for TLDs for obvious security reasons.

jan at dewal dot net

12 years ago

The information above about this function that it can only be used BEFORE session_start depends on how you use it. Because its also useful AFTER a session has started as follows:

Example you wand to change an already set value of the session cookie expire time:

<?php// Here we start as usual
session_set_cookie_params('3600'); // 1 hour
session_start();// More code...

// Now we found in some database that the user whishes
// the cookie to expire after for example 10 minutes
// we can change it instantly !

session_set_cookie_params('600'); // 10 minutes.
session_regenerate_id(true); // This will delete old cookie and adopt new expire settings and the
// old cookie variables in a new cookie
?>

Please note i only explained the browser (client) side changes of session cookie's expire time.

eion at robbmob dot com

1 year ago

Unfortunately session_set_cookie_params() cannot be called during an active session, it'll just E_WARNING and return false, which means calling session_regenerate_id() (eg, during login to prevent a session fixation attack) could end up using old cookie settings (eg, not "SameSite=Strict")

To ensure any future sessions are being created with the right cookie settings, you're better off to use ini_set() to set the cookie parameters - which is all that session_set_cookie_params() does under the hood anyway

Ashus

13 years ago

Cross-domain Cookies do work in all browsers (path '/' server '.example.com'), except the case you try it in IE6/7 and the server name is retreived from :etc/hosts: file, in that case the cookie won't be even saved.

php at mike2k dot com

21 years ago

[Editor's Note:

Rasmus' Solution from the PHP-General list:

Just use a session cookie (by not providing an expiry time) and add the
server's expiry timestamp to the value of the cookie.  Then when you get
that cookie sent to you, check it against your server's time and make the
decision on whether to accept the cookie or not based on that.

That way you are immune from people not having their system clocks set
right.

-Rasmus

]

A couple things I noticed when using this. I think it only works if you set the session_set_cookie_params() function BEFORE the session_start() function.

Also, when you set the "lifetime" on the cookie, it takes the seconds offset from the SERVER. it sends the cookie encoded to timeout at the SERVER time. So if your server is +2 minutes ahead of the client, and you set the cookie to timeout after 30 seconds, the client actually has 2 minutes and 30 seconds before the cookie times out. I don't know if there's any way that this can be patched in future versions, and the only alternative I think is setting cookies in javascript, which is hardly the point when using all these specific session functions.

brandan, bildungsroman.org

14 years ago

i found it somewhat difficult to work with sessions due to the documentation not really denoting the necessity for the session name to be set via session_name() in order for session_set_cookie_params() to be of any use.  i found no reference to session_name() in this article, and my session functions would have been a disastrous mess were it not for a friend familiar with session.

so, in essence, for anybody wondering about where to start: declare a session name before using session_set_cookie_params(), otherwise you might agitate php to the point of committing some atrocity against your webserver.

William Leslie

14 years ago

"Info at xyzsite dot ru" writes that Internet Explorer does not correctly handle cookies whose domain contains an underscore character.

However, There's a good reason for this apparently faulty behavior: the underscore character is forbidden in DNS names.  RFC 3696 says:

"The labels ... that make up a domain name must consist of only the ASCII alphabetic and numeric characters, plus the hyphen.  No other symbols or punctuation characters are permitted, nor is blank space."

If the underscore works in Mozilla or other browsers, it's only because they are being lenient in the validation of domain names.

gavin_spam at skypaint dot com

20 years ago

The first argument to session_set_cookie_params is the number of seconds in the future (based on the server's current time) that the session will expire.  So if you want your sessions to last 100 days:

$expireTime = 60*60*24*100; // 100 days
session_set_cookie_params($expireTime);

I was using time()+$expireTime, which is WRONG (a lot of the session_set_cookie_params() examples I found get this wrong, but probably don't care because they are just doing "infinite" sessions).

eddie at roosenmaallen dot com

14 years ago

Further to "info at xyzsite dot ru" and William Leslie, Safari on OS X also doesn't honour cookies with an underscore in the subdomain.

The workaround I've found is to specify the parent domain as the cookie domain -- instead of "bad_name.example.com", set the path to ".example.com"; it's suboptimal, but gets the job done.

info at xyzsite dot ru

14 years ago

Just one more bad situation - cookies in Internet Explorer do not work with '_' in domain name. FF and Opera are O.K. So if your hostname is like test_host.example.com, IE cookies will not function correctly/

RC

14 years ago

For anyone looking for which browsers support the HTTPOnly flag, per my research:

IE 6 SP 1 and higher.
Firefox 3 and higher.
Opera 9.50 and higher.

As of Safari 3.1.1 (April 2008), Safari did not yet support this flag.

This cookie flag was developed by Microsoft and is slowly making its way into other browsers: http://msdn2.microsoft.com/en-us/library/ms533046.aspx

session_start() writes the PHPSESSID cookie, which is the session identifier. You don't need to (nor should) set the PHPSESSID cookie with setcookie().

Do PHP sessions use cookies?

Yes. PHP sessions rely on a cookie containing a session key. Your session data are stored only on your server, but a unique ID is assigned to each session and that ID gets saved in a cookie.

Can PHP session work without cookies?

You can also login without Cookies only by Session Id and Time, but you have to write them both in your Database direct after Successful Login. I have in index. php something like this that will always generate a new session id based on time and the old session id if conditions are not verified.
Both of them accomplish much the same thing. The main difference between cookies and sessions is that information stored in a cookie is stored on the visitor's browser, and information stored in a session is not—it is stored at the web server. This difference determines what each is best suited for.