Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ PHP NEWS
registrations are freed while still reachable from the cycle collector.
(Ilia Alshanetsky)

- Session:
. Fixed session_destroy() not removing the session file when the files
save handler holds no open descriptor for it. (Ilia Alshanetsky)



24 Sep 2026, PHP 8.4.26

Expand Down
12 changes: 3 additions & 9 deletions ext/session/mod_files.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,16 +599,10 @@ PS_DESTROY_FUNC(files)
return FAILURE;
}

if (data->fd != -1) {
ps_files_close(data);
ps_files_close(data);

if (VCWD_UNLINK(buf) == -1) {
/* This is a little safety check for instances when we are dealing with a regenerated session
* that was not yet written to disk. */
if (!VCWD_ACCESS(buf, F_OK)) {
return FAILURE;
}
}
if (VCWD_UNLINK(buf) == -1 && !VCWD_ACCESS(buf, F_OK)) {
return FAILURE;
}

return SUCCESS;
Expand Down
55 changes: 55 additions & 0 deletions ext/session/tests/session_destroy_no_open_fd.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
--TEST--
Session files: destroy removes session file even without an open descriptor
--INI--
session.use_strict_mode=0
--FILE--
<?php

$dir = __DIR__ . '/aph_ztz_sess_dir';
@mkdir($dir);

$sid = 'abcdefghijklmnopqrstuvwx01234567';
$file = $dir . '/sess_' . $sid;

@chmod($file, 0644);
@unlink($file);
touch($file);
chmod($file, 0444);

ini_set('session.save_path', $dir);
ini_set('session.save_handler', 'files');
ini_set('session.use_cookies', '0');

$done = false;
set_error_handler(function ($errno, $errstr) use (&$done, $file) {
if (!$done && strpos($errstr, 'O_RDWR') !== false) {
$done = true;

// The open failure left the files module without a descriptor,
// yet the session is still being initialized as active here.
var_dump(session_destroy());
var_dump(file_exists($file));
}
return true;
});

session_id($sid);
@session_start();

restore_error_handler();
@chmod($file, 0644);

echo "end\n";
?>
--CLEAN--
<?php
foreach (glob(__DIR__ . '/aph_ztz_sess_dir/*') as $f) {
@chmod($f, 0644);
@unlink($f);
}
@rmdir(__DIR__ . '/aph_ztz_sess_dir');
?>
--EXPECT--
bool(true)
bool(false)
end
Loading