7

My problem (probably doesn't occur in your computer)

I have 2 PHP scripts.

The first script read include the second script to get a variable, change the value, and do file_put_contents to change the second script.

<?php
include('second.php'); // in second.php, $num defined as "1" 
$num ++;               // now $num should be "2"
// Change content of second.php
file_put_contents('second.php', '<?php $num='.$num.'; ?>'); 
include('second.php'); // Now here is the problem, $num's value is still "1"
echo $num;             // and I get an unexpected result "1"
?>

The second script simply contains a variable

<?php $num=1; ?>

I expect the result to be "2", but it seems that the second include doesn't read changes made by file_put_contents.

My first guess was there might be concurrency issue in file_put_contents function, so that the second file was not really changed when the second include executed.

I try to test my guess by changing the first script into this:

<?php
include('second.php');
$num ++;
file_put_contents('second.php', '<?php $num='.$num.'; ?>');
// show the contains of second.php
echo '<pre>' . str_replace(array('<','>'), array('&lt;', '&gt;'),
    file_get_contents('second.php')) . '</pre>'; 
include('second.php');
echo $num;
?>

I was really surprised to find that the result of the program is this:

<?php $num=4; ?>
3

This means that file_put_contents read the file correctly (in other words, the file has really been physically changed), but "include" still use the first value.

My Questions

  1. Can anyone explain this?
  2. Is there any workaround (instead of "sleep()") to make "include" read the changes?

I have read this question and found no answer:

Dynamically changed files in PHP. Changes sometimes are not visible in include(), ftp_put()

Temporary workaround

Using eval seems to be temporary workaround. This is not elegant since eval is usually associated with security hole.

<?php
require('second.php');
$num ++;
file_put_contents('second.php', '<?php $num='.$num.'; ?>');
echo '<pre>' . str_replace(array('<','>'), array('&lt;', '&gt;'), file_get_contents('second.php')) . '</pre>';
require('file.php');
echo $num . '<br />';
eval(str_replace(array('<?php','?>'), array('', ''), file_get_contents('second.php')));
echo $num;
?>

This is the result:

<?php $num=10; ?>
9
10
Community
  • 1
  • 1
goFrendiAsgard
  • 4,016
  • 8
  • 38
  • 64
  • 3
    I tested your code. Works fine for me. I get `` followed by `4`. – Mark Miller Jun 06 '14 at 04:41
  • Really? what is your PHP and apache version? I'm working with ubuntu 14.04, apache 2.4.7 and PHP 5.5.9-1. If it is work on your computer, this might be OS issue, not PHP issue. – goFrendiAsgard Jun 06 '14 at 04:48
  • I'm on a windows machine. Tested locally - Apache/2.4.7 (Win32) PHP/5.5.8 – Mark Miller Jun 06 '14 at 04:53
  • I suspect you have an accelerator / optimiser / byte-code cache enabled in your PHP environment that is caching `second.php`. I suggest you write the number to a simple text file (maybe in *properties* file format) instead of a PHP file. – Phil Jun 06 '14 at 04:54
  • 1
    Rule out silent errors. Instead of `include` use `require`. Check for false returns from `file_get/put_contents` calls – FuzzyTree Jun 06 '14 at 04:59
  • @MarkM Thanks, my friend also check this in xampp and find no problem. So Phil comment might be correct. – goFrendiAsgard Jun 06 '14 at 04:59
  • @FuzzyTree: Unfortunately, require doesn't help – goFrendiAsgard Jun 06 '14 at 05:00

1 Answers1

10

Probably you have OPcache installed and enabled (Since Php 5.5: OPcache extension added), caching your second.php file?

See phpinfo() whether it is true.

If so, use opcache_invalidate('second.php') to invalidate cached file or opcache_reset() to reset all cached files.

<?php
include('second.php');
$num ++;

file_put_contents('second.php', '<?php $num='.$num.'; ?>'); 

opcache_invalidate('second.php');//Reset file cache

include('second.php');
echo $num;//2
?>
Zudwa
  • 1,360
  • 10
  • 13
  • 1
    This is exactly the case. Thank you very much for taking time answering. also +1 – goFrendiAsgard Jun 06 '14 at 09:14
  • I've spent around an hour trying to debug my code, then I've noticed the inconsistency between the file system grep and the PHP include. The problem has gone when my debugger (PHPStorm + XDebug) crashed my system (so I had to restart) when I was trying to Get Into the include, hoping to fall into some caching wrapper around it. In my case file changed by the external program (PHPStorm) was written to disk, but later on PHP didn't pick up the changes with include. It was never the case before, why `opcache` could fail? – Tom Raganowicz Dec 08 '16 at 07:38