|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2006-02-28 11:11 UTC] p at damezin dot com
Description:
------------
readfile() and file_get_contents() returns the old contents from an internal php cache when a symlink is modified. Or it will return the contents of an unlinked symlink().
This problem does not accured when realpath_cache_size is 0.
With php5 on apache2, the problem also exist from 1 page to another. (more disturbing)
Reproduced on php 5.1.1 and 5.1.2 using Ubuntu or Gentoo Linux. Linux Kernels 2.6.11, 2.6.15...
Reproduce code:
---------------
<?php
define('TEST_NUMBER', 2); // 1 ou 2
define('TEST_FILE1', 'testfile1');
define('TEST_FILE2', 'testfile2');
define('TEST_LINK', 'testlink');
// inexistant function in PHP4
if(!function_exists('file_put_contents')) {
function file_put_contents($file, $content) {
$fp = fopen($file,'w');
fputs($fp, $content);
fclose($fp);
}
}
file_put_contents(TEST_FILE1, 42);
file_put_contents(TEST_FILE2, 43);
// creating the TEST_LINK, using a temp. TEST_LINK NEEDED
$uid = uniqid(time());
symlink(TEST_FILE1, TEST_LINK . $uid);
rename(TEST_LINK . $uid, TEST_LINK);
// reading this file one time NEEDED
file_get_contents(TEST_LINK);
if(TEST_NUMBER === 1) {
unlink(TEST_LINK);
$good_result = '';
}
elseif(TEST_NUMBER === 2) {
$uid = uniqid(time());
symlink(TEST_FILE2, TEST_LINK . $uid);
rename(TEST_LINK . $uid, TEST_LINK);
$good_result = file_get_contents(TEST_FILE2);
}
// sleep(2);
// clearstatcache();
$result = @file_get_contents(TEST_LINK);
echo "TEST " . TEST_NUMBER . " : " . (($result == $good_result) ? 'SUCCEED' : 'FAILED') . "\n";
echo "result : [" . $result . "] | ";
echo "expected : [" . $good_result . "]\n";
echo "php version : " . PHP_VERSION."\n";
echo "realpath_cache_size (if available) : " . @ini_get('realpath_cache_size') . "\n";
// cleaning
@unlink(TEST_LINK);
unlink(TEST_FILE1);
unlink(TEST_FILE2);
?>
Expected result:
----------------
dynphp2 root # php testcasephp.php
TEST 1 : SUCCEED
result : [] | expected : []
php version : 4.4.0
realpath_cache_size (if available) :
dynphp2 root # php testcasephp.php
TEST 2 : SUCCEED
result : [43] | expected : [43]
php version : 4.4.0
realpath_cache_size (if available) :
---
TEST 1 : SUCCEED
result : [] | expected : []
php version : 5.0.5
realpath_cache_size (if available) :
TEST 2 : SUCCEED
result : [43] | expected : [43]
php version : 5.0.5
realpath_cache_size (if available) :
Actual result:
--------------
lore ~ # php testcasephp.php
TEST 1 : FAILED
result : [42] | expected : []
php version : 5.1.2
realpath_cache_size (if available) : 16384
lore ~ # php testcasephp.php
TEST 2 : FAILED
result : [42] | expected : [43]
php version : 5.1.2
realpath_cache_size (if available) : 16384
---
TEST 1 : FAILED
result : [42] | expected : []
php version : 5.1.1-gentoo
realpath_cache_size (if available) : 16K
TEST 2 : FAILED
result : [42] | expected : [43]
php version : 5.1.1-gentoo
realpath_cache_size (if available) : 16K
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Nov 02 05:00:01 2025 UTC |
New simplified testcase : <?php define('TEST_FILE1', '/tmp/testfile1'); define('TEST_LINK', '/tmp/testlink'); file_put_contents(TEST_FILE1, '42'); // create TEST_LINK pointing on TEST_FILE1 using a temporary filename (needed) $tmp_link_name = TEST_LINK . uniqid(time()); symlink(TEST_FILE1, $tmp_link_name); rename($tmp_link_name, TEST_LINK); // reading this link/file file_get_contents(TEST_LINK); // remove the link (we have the same bug making this link pointing somewhere else) unlink(TEST_LINK); $good_result = ''; // clearstatcache have no effect clearstatcache(); // fetching result, must be empty (link does not exist) $result = @file_get_contents(TEST_LINK); // on bogus php it return TEST_FILE1 content echo "TEST : " . (($result == $good_result) ? 'SUCCEED' : 'FAILED') . "\n"; echo "result : '" . $result . "' | "; echo "expected : '" . $good_result . "'\n"; echo "php version : " . PHP_VERSION."\n"; echo "realpath_cache_size (if available) : " . @ini_get('realpath_cache_size') . "\n"; // cleaning @unlink(TEST_LINK); unlink(TEST_FILE1); ?>