PHPのお勉強!

PHP TOP

session_start

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

session_start新しいセッションを開始、あるいは既存のセッションを再開する

説明

session_start(array $options = []): bool

session_start() は、セッションを作成します。 もしくは、リクエスト上で GET, POST またはクッキーにより渡されたセッション ID に基づき現在のセッションを復帰します。

session_start() がコールされたりセッションが自動的に開始したりするときに、 PHP はセッションの open ハンドラおよび read ハンドラをコールします。 このハンドラとしては、デフォルトで組み込まれている保存ハンドラの他に PHP 拡張モジュールで提供されているもの (SQLite や Memcached など) も使えます。また、自作のハンドラを session_set_save_handler() で定義することもできます。 read コールバックは既存のセッションデータ (独自のシリアライズフォーマットで保存されているもの) を読み込み、 それを復元して自動的にスーパーグローバル $_SESSION に格納します。

名前付きのセッションを使用したい場合、 session_start() の前に session_name() をコールする必要があります。

session_start() は、 session.use_trans_sid が有効の場合に URL 書換え用の内部出力ハンドラを登録します。

ユーザーが ob_start() と共に ob_gzhandler または類似のものを使用している場合、 出力ハンドラの順番は正しく出力を行うために重要です。例えば、 セッション開始時にユーザーは ob_gzhandler を登録する必要があります。

パラメータ

options

オプションの連想配列を指定することができます。これは、現在設定されている セッションの設定ディレクティブ を上書きします。 連想配列のキーにはプレフィックス session. を含めてはいけません。

通常の設定ディレクティブ群に加えて、 read_and_close オプションを指定することもできます。 これを true にすると、セッションを読み込んだらその場ですぐにクローズします。 セッションのデータを書き換えるつもりがない場合は、こうしておけば、意図せぬロックを防げます。

戻り値

この関数は、セッションが正常に開始した場合に true、それ以外の場合に false を返します。

変更履歴

バージョン 説明
7.1.0 セッションを開始できなかった場合、 session_start() は、false を返し、 $_SESSION を初期化しないようになりました。

基本的なセッションの例

例1 page1.php

<?php
// page1.php

session_start();

echo
'Welcome to page #1';

$_SESSION['favcolor'] = 'green';
$_SESSION['animal'] = 'cat';
$_SESSION['time'] = time();

// セッションクッキーが有効なら動作します
echo '<br /><a href="page2.php">page 2</a>';

// あるいは必要に応じてセッション ID を渡します
echo '<br /><a href="page2.php?' . SID . '">page 2</a>';
?>

page1.php を表示した後なら、 page2.php はセッション上の情報を含んでいるはずです。 セッションについてのリファレンス を読むと、 セッションIDの伝達 に関する情報が得られます。 例えば、SID とは何かといったことです。

例2 page2.php

<?php
// page2.php

session_start();

echo
'Welcome to page #2<br />';

echo
$_SESSION['favcolor']; // green
echo $_SESSION['animal']; // cat
echo date('Y m d H:i:s', $_SESSION['time']);

// page1.php と同様に、ここで SID を使うこともできます
echo '<br /><a href="page1.php">page 1</a>';
?>

session_start() のオプションの指定

例3 クッキーの有効期限の上書き

<?php
// これは、有効期限が1日の永続クッキーを送信します
session_start([
'cookie_lifetime' => 86400,
]);
?>

例4 セッションの読み込みとクローズ

<?php
// セッション内で何も変更する必要がないことがわかっている場合は、
// セッションを読み込んですぐにクローズしてしまえば、
// セッションファイルをロックして他のページをブロックしてしまうことを防げます
session_start([
'cookie_lifetime' => 86400,
'read_and_close' => true,
]);

注意

注意:

クッキーに基づくセッションを使用している場合、ブラウザに何か出力を行う前に session_start() をコールする必要があります。

注意:

ob_gzhandler() よりも zlib.output_compression の使用が推奨されています。

注意:

この関数は、設定によって複数の HTTP ヘッダを送信します。 これらのヘッダをカスタマイズするには session_cache_limiter() を参照ください。

参考

add a note

User Contributed Notes 36 notes

up
30
linblow at hotmail dot fr
13 years ago
If you want to handle sessions with a class, I wrote this little class:

<?php

/*
Use the static method getInstance to get the object.
*/

class Session
{
const
SESSION_STARTED = TRUE;
const
SESSION_NOT_STARTED = FALSE;

// The state of the session
private $sessionState = self::SESSION_NOT_STARTED;

// THE only instance of the class
private static $instance;


private function
__construct() {}


/**
* Returns THE instance of 'Session'.
* The session is automatically initialized if it wasn't.
*
* @return object
**/

public static function getInstance()
{
if ( !isset(
self::$instance))
{
self::$instance = new self;
}

self::$instance->startSession();

return
self::$instance;
}


/**
* (Re)starts the session.
*
* @return bool TRUE if the session has been initialized, else FALSE.
**/

public function startSession()
{
if (
$this->sessionState == self::SESSION_NOT_STARTED )
{
$this->sessionState = session_start();
}

return
$this->sessionState;
}


/**
* Stores datas in the session.
* Example: $instance->foo = 'bar';
*
* @param name Name of the datas.
* @param value Your datas.
* @return void
**/

public function __set( $name , $value )
{
$_SESSION[$name] = $value;
}


/**
* Gets datas from the session.
* Example: echo $instance->foo;
*
* @param name Name of the datas to get.
* @return mixed Datas stored in session.
**/

public function __get( $name )
{
if ( isset(
$_SESSION[$name]))
{
return
$_SESSION[$name];
}
}


public function
__isset( $name )
{
return isset(
$_SESSION[$name]);
}


public function
__unset( $name )
{
unset(
$_SESSION[$name] );
}


/**
* Destroys the current session.
*
* @return bool TRUE is session has been deleted, else FALSE.
**/

public function destroy()
{
if (
$this->sessionState == self::SESSION_STARTED )
{
$this->sessionState = !session_destroy();
unset(
$_SESSION );

return !
$this->sessionState;
}

return
FALSE;
}
}

/*
Examples:
*/

// We get the instance
$data = Session::getInstance();

// Let's store datas in the session
$data->nickname = 'Someone';
$data->age = 18;

// Let's display datas
printf( '<p>My name is %s and I\'m %d years old.</p>' , $data->nickname , $data->age );

/*
It will display:

Array
(
[nickname] => Someone
[age] => 18
)
*/

printf( '<pre>%s</pre>' , print_r( $_SESSION , TRUE ));

// TRUE
var_dump( isset( $data->nickname ));

// We destroy the session
$data->destroy();

// FALSE
var_dump( isset( $data->nickname ));

?>

I prefer using this class instead of using directly the array $_SESSION.
up
22
aaronw at catalyst dot net dot nz
9 years ago
As others have noted, PHP's session handler is blocking. When one of your scripts calls session_start(), any other script that also calls session_start() with the same session ID will sleep until the first script closes the session.

A common workaround to this is call session_start() and session_write_close() each time you want to update the session.

The problem with this, is that each time you call session_start(), PHP prints a duplicate copy of the session cookie to the HTTP response header. Do this enough times (as you might do in a long-running script), and the response header can get so large that it causes web servers & browsers to crash or reject your response as malformed.

This error has been reported to PHP HQ, but they've marked it "Won't fix" because they say you're not supposed to open and close the session during a single script like this. https://bugs.php.net/bug.php?id=31455

As a workaround, I've written a function that uses headers_list() and header_remove() to clear out the duplicate cookies. It's interesting to note that even on requests when PHP sends duplicate session cookies, headers_list() still only lists one copy of the session cookie. Nonetheless, calling header_remove() removes all the duplicate copies.

<?php
/**
* Every time you call session_start(), PHP adds another
* identical session cookie to the response header. Do this
* enough times, and your response header becomes big enough
* to choke the web server.
*
* This method clears out the duplicate session cookies. You can
* call it after each time you've called session_start(), or call it
* just before you send your headers.
*/
function clear_duplicate_cookies() {
// If headers have already been sent, there's nothing we can do
if (headers_sent()) {
return;
}

$cookies = array();
foreach (
headers_list() as $header) {
// Identify cookie headers
if (strpos($header, 'Set-Cookie:') === 0) {
$cookies[] = $header;
}
}
// Removes all cookie headers, including duplicates
header_remove('Set-Cookie');

// Restore one copy of each cookie
foreach(array_unique($cookies) as $cookie) {
header($cookie, false);
}
}
?>
up
16
ohcc at 163 dot com
10 years ago
The constant SID would always be '' (an empty string) if directive session.use_trans_sid in php ini file is set to 0.

So remember to set session.use_trans_sid to 1 and restart your server before you use SID in your php script.
up
10
marco dot agnoli at me dot com
7 years ago
I recently made an interesting observation:

It seems that `session_start()` can return `true` even if the session was not properly created. In my case, the disk storage was full and so the session data could not be written to disk. I had some logic that resulted in an infinite loop when the session was not written to disk.

To check if the session really was saved to disk I used:

```
<?php

function safe_session_start() {
# Attempt to start a session
if (!@\session_start()) return false;

#
# Check if we need to perform
# the write test.
#
if (!isset($_SESSION['__validated'])) {
$_SESSION['__validated'] = 1;

# Attempt to write session to disk
@\session_write_close();

# Unset the variable from memory.
# This step may be unnecessary
unset($_SESSION['__validated']);

# Re-start session
@\session_start();

# Check if variable value is retained
if (!isset($_SESSION['__validated'])) {
# Session was not written to disk
return false;
}
}

return
true;
}

if (!
safe_session_start()) {
# Sessions are probably not written to disk...
# Handle error accordingly.
}

?>
```

Took me quite a while to figure this out.

Maybe it helps someone!
up
11
bachtel at [googles email service]dotcom
7 years ago
If you are using a custom session handler via session_set_save_handler() then calling session_start() in PHP 7.1 you might see an error like this:
session_start(): Failed to read session data: user (path: /var/lib/php/session) in ...

As of this writing, it seems to be happening in PHP 7.1, and things look OK in PHP7.0.

It is also hard to track down because if a session already exists for this id (maybe created by an earlier version of PHP), it will not trigger this issue because the $session_data will not be null.

The fix is simple... you just need to check for 'null' during your read function:

<?php

function read($id)
{
//... pull the data out of the DB, off the disk, memcache, etc
$session_data = getSessionDataFromSomewhere($id);

//check to see if $session_data is null before returning (CRITICAL)
if(is_null($session_data))
{
$session_data = ''; //use empty string instead of null!
}

return
$session_data;
}

?>
up
9
emre@yazici
15 years ago
PHP Manual specifically denotes this common mistake:

Depending on the session handler, not all characters are allowed within the session id. For example, the file session handler only allows characters in the range a-z A-Z 0-9 , (comma) and - (minus)!

See session_id() manual page for more details.
up
11
dave1010 at gmail dot com
14 years ago
PHP locks the session file until it is closed. If you have 2 scripts using the same session (i.e. from the same user) then the 2nd script will not finish its call to session_start() until the first script finishes execution.

If you have scripts that run for more than a second and users may be making more than 1 request at a time then it is worth calling session_write_close() as soon as you've finished writing session data.

<?php
// a lock is places on the session, so other scripts will have to wait
session_start();

// do all your writing to $_SESSION
$_SESSION['a'] = 1;

// $_SESSION can still be read, but writing will not update the session.
// the lock is removed and other scripts can now read the session
session_write_close();

do_something_slow();
?>

Found this out from http://konrness.com/php5/how-to-prevent-blocking-php-requests/
up
1
bwz
1 year ago
Be warned of another issue with blocking sessions: if you want to call an external program (or use an external service) that needs to access your website using the same session.

For example I am printing a page as a PDF. I can just save the web page as a HTML file. But the images in the HTML are also private and require the current user session to be seen.

What will happen is that this program might hang indefinitely (or timeout) as session_start waits for the parent PHP process to release the lock. And session_start doesn't obey max_execution_time (as documented in this bug: https://bugs.php.net/bug.php?id=72345 ), so this will effectively kill the server after a few requests, as each one will be hanging forever

It's the same if you use an external HTTP service:

<?php
$pdf
= file_get_contents('http://pdf.website.tld/?url=http://website.tld/print.php');
?>

The service will wait for the website host to release the lock, but it can't as it is waiting for the PDF service to finish...

The nice solution is to release the lock immediately by calling session_write_close after session_start, and when you need to write to the session you do the same again, but as noted it has its own issues. Using a custom session handler is probably the best solution.
up
8
elitescripts2000 at yahoo dot com
10 years ago
3 easy but vital things about Sessions in AJAX Apps.

<?php
// session start

// It is VERY important to include a Period if using
// a whole domain. (.yourdomain.com)
// It is VERY important to set the root path your session will always
// operate in... (/members) will ensure sessions will NOT be interfered
// with a session with a path of say (/admin) ... so you can log in
// as /admin and as /members... NEVER do unset($_SESSION)
// $_SESSION=array(); is preferred, session_unset(); session_destroy();

session_set_cookie_params(0, '/members', '.yourdomain.com', 0, 1);
session_start();
$_SESSION = array();
session_unset();
session_destroy();

session_set_cookie_params(0, '/members', '.yourdomain.com', 0, 1);
session_start();

$_SESSION['whatever'] = 'youwhat';

// session destroying

// To be safe, clear out your $_SESSION array
// Next, what most people do NOT do is delete the session cookie!
// It is easy to delete a cookie by expiring it long before the current time.
// The ONLY WAY to delete a cookie, is to make sure ALL parameters match the
// cookie to be deleted...which is easy to get those params with
// session_get_cookie_params()...
// FInally, use session_unset(); and session_destroy(); in this order to ensure
// Chrome, IE, Firefox and others, are properly destroying the session.
$_SESSION = array();
if (
ini_get('session.use_cookies'))
{
$p = session_get_cookie_params();
setcookie(session_name(), '', time() - 31536000, $p['path'], $p['domain'], $p['secure'], $p['httponly']);
}
session_unset();
session_destroy();

// AJAX and SESSIONS.
// Example... you start a session based PHP page, which then calls an Ajax (XMLHTTP) authenticated
// using the SAME SESSION to Poll and output the data, for example. But, you notice when you
// try to start the Polling AJAX call always HANGS and seems to hang at the session_start().
// This is because the session is opened in the first page, calls the AJAX polling example, and
// tries to open the same session (for authentication) and do the AJAX call, you MUST call
// session_write_close(); meaning you are done writing to the $_SESSION variable, which really
// represents a file that must be CLOSED with session_write_close();....
// THAN you can call your AJAX Polling code to reopen the same session and do its polling...
// Normally, the $_SESSION is closed automatically when the script is closed or finished executing
// So, if you need to keep a PHP page running after opening a SESSION, simply close it when finished
// writing to $_SESSION so the AJAX polling page can authenticate and use the same session in a
// seperate web page...

session_write_close();

?>

Hope this helps someone with their sessions...
Thanks.
up
4
Anonymous
4 years ago
Be careful with the 'read_and_close' option. It doesn't update the session file's last modification time unlike the default PHP behaviour when you don't close the session (or when you use session_write_close explicitly).
Old session files (for me, older than 24 minutes) will be occasionally cleared by the garbage collector (for me every 09 and 39 minute of every hour).
So a session can disappear even if the page regularly sends requests to the server that only reads and closes the session.
up
10
someOne_01 at somewhere dot com
12 years ago
When you have an import script that takes long to execute, the browser seem to lock up and you cannot access the website anymore. this is because a request is reading and locking the session file to prevent corruption.

you can either
- use a different session handler with session_set_save_handler()
- use session_write_close() in the import script as soon you don't need session anymore (best moment is just before the long during part takes place), you can session_start when ever you want and as many times you like if your import script requires session variables changed.

example
<?php
session_start
(); //initiate / open session
$_SESSION['count'] = 0; // store something in the session
session_write_close(); //now close it,
# from here every other script can be run (and makes it seem like multitasking)
for($i=0; $i<=100; $i++){ //do 100 cycles
session_start(); //open the session again for editing a variable
$_SESSION['count'] += 1; //change variable
session_write_close(); //now close the session again!
sleep(2); //every cycle sleep two seconds, or do a heavy task
}
?>
up
4
hu60 dot cn at gmail dot com
5 years ago
The following code shows how the PHP session works. The function my_session_start() does almost the same thing as session_start().

<?php
error_reporting
(E_ALL);
ini_set('display_errors', true);
ini_set('session.save_path', __DIR__);

my_session_start();

echo
'<p>session id: '.my_session_id().'</p>';

echo
'<code><pre>';
var_dump($_SESSION);
echo
'</pre></code>';

$now = date('H:i:s');
if (isset(
$_SESSION['last_visit_time'])) {
echo
'<p>Last Visit Time: '.$_SESSION['last_visit_time'].'</p>';
}
echo
'<p>Current Time: '.$now.'</p>';

$_SESSION['last_visit_time'] = $now;

function
my_session_start() {
global
$phpsessid, $sessfile;

if (!isset(
$_COOKIE['PHPSESSID']) || empty($_COOKIE['PHPSESSID'])) {
$phpsessid = my_base32_encode(my_random_bytes(16));
setcookie('PHPSESSID', $phpsessid, ini_get('session.cookie_lifetime'), ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly'));
} else {
$phpsessid = substr(preg_replace('/[^a-z0-9]/', '', $_COOKIE['PHPSESSID']), 0, 26);
}

$sessfile = ini_get('session.save_path').'/sess_'.$phpsessid;
if (
is_file($sessfile)) {
$_SESSION = unserialize(file_get_contents($sessfile));
} else {
$_SESSION = array();
}
register_shutdown_function('my_session_save');
}

function
my_session_save() {
global
$sessfile;

file_put_contents($sessfile, serialize($_SESSION));
}

function
my_session_id() {
global
$phpsessid;
return
$phpsessid;
}

function
my_random_bytes($length) {
if (
function_exists('random_bytes')) {
return
random_bytes($length);
}
$randomString = '';
for (
$i = 0; $i < $length; $i++) {
$randomString .= chr(rand(0, 255));
}
return
$randomString;
}

function
my_base32_encode($input) {
$BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
$output = '';
$v = 0;
$vbits = 0;
for (
$i = 0, $j = strlen($input); $i < $j; $i++) {
$v <<= 8;
$v += ord($input[$i]);
$vbits += 8;
while (
$vbits >= 5) {
$vbits -= 5;
$output .= $BASE32_ALPHABET[$v >> $vbits];
$v &= ((1 << $vbits) - 1);
}
}
if (
$vbits > 0) {
$v <<= (5 - $vbits);
$output .= $BASE32_ALPHABET[$v];
}
return
$output;
}
up
3
ben dot morin at spaboom dot com
18 years ago
James at skinsupport dot com raises a good point (warning) about additional requests from the browser. The request for favicon.ico, depending on how it is handled, can have unintended results on your sessions.

For example, suppose you have ErrorDocument 404 /signin.php, no favicon.ico file and all pages in your site where the user signs in are also redirected to /signin.php if they're not already signed in.

If signin.php does any clean up or reassigning of session_id (as all good signin.php pages should) then the additional request from the browser for favicon.ico could potentially corrupt the session as set by the actual request.

Kudos to James for pointing it out and shame on me for skimming past it and not seeing how it applied to my problem. Thanks too to the Firefox Live HTTP Headers extension for showing the additional request.

Don't waste days or even hours on this if your session cookies are not being sent or if the session data isn't what you expect it to be. At a minimum, eliminate this case and see if any additional requests could be at fault.