8

I have a problem with PHP filemtime function. In my webapp I use Smarty template engine with caching option. In my webapp I can do some actions which generate error, but lets focus on only one action. When I click link on page some content is updated - I can click few times and everything is OK but about one request on 10 fails. Following error occurs:

filemtime() [<a href='function.filemtime'>function.filemtime</a>]: stat failed for

and the line that causes the problem:

 return ($_template->getCachedFilepath() && file_exists($_template->getCachedFilepath())) ? filemtime($_template->getCachedFilepath()) : false ;

As you can see, file exists because it is checked.

Problematic line of code is included in smarty_internal_cacheresource_file.php (part of Smarty lib v3.0.6)

App is run on UNIX system, external hosting.

Any ideas? Should I post more details?

hakre
  • 193,403
  • 52
  • 435
  • 836
lbednaszynski
  • 678
  • 2
  • 12
  • 24

3 Answers3

11

file_exists internally uses the access system call which checks permissions as the real user, whereas filemtime uses stat, which performs the check as the effective user. Therefore, the problem may be rooted in the assumption of effective user == real user, which does not hold. Another explanation would be that the file gets deleted between the two calls.

Since both the result of $_template->getCachedFilepath() and the existance of the file can change in between system calls, why do you call file_exists at all? Instead, I'd suggest just

return @filemtime($_template->getCachedFilepath());

If $_template->getCachedFilepath() can be set to a dummy value such as false, use the following:

$path = $_template->getCachedFilepath();
if (!$path) return false;
return @filemtime($path);
phihag
  • 278,196
  • 72
  • 453
  • 469
  • I understand that file can disappear between two calls, but I am only one who tests this application. I also test it only for one user thats why it is strange for me. I can ignore error by putting @ sign, but the problem will not disappear. – lbednaszynski Aug 19 '11 at 11:35
  • 1
    I don't like solutions that include error suppression, but +1 for the effective/real note. @marchewa check the permissions of the files. – Maxim Krizhanovsky Aug 19 '11 at 11:38
  • Permissions of all cached files are 0644 (rw-r--r--). My scripts create, deletes and try to read these files. As I said only about 10% of requests fail. – lbednaszynski Aug 19 '11 at 11:44
  • @Darhazer What's wrong with error suppression if errors are expected? It's definitely better than look-before-you-leap unless you can guarantee the state won't change. – phihag Aug 19 '11 at 12:15
  • @marchewa If the problem only occurs intermittently, it could very well be that the temporary file is removed after you call `file_exists`, but before `filemtime`. Can you reproduce the problem with two calls to `filemtime`, i.e. using `(@filemtime(..) !== false)` instead of `file_exists`? – phihag Aug 19 '11 at 12:17
  • @phihah I've done what you suggested and right now first call of `filemtime` always emits `E_WARNING`. I suppose you are right from the begining. Earlier in my script I call `clearCache` Smarty function which uses `unlink` function to delete file. When I comment out this line problem disappears, otherwise problem randomly occures. Question is: is it possible that file is physically deleted after some time of calling `unlink` function? – lbednaszynski Aug 22 '11 at 07:36
  • @marchewa No, if the same process(and thread) issues an `unlink` and then a `filemtime` call, the file will not be there. Bear in mind multiple concurrent processes are the rule, not the exception on a webserver. You should go with my original answer - just cal `filemtime` once, and put an `@` in front to suppress the warning. – phihag Aug 22 '11 at 08:05
  • ok, thanks I will do that. I will also post change request to the Smarty developers. – lbednaszynski Aug 22 '11 at 11:44
  • _Smarty 3.1 should already solve the issue_ http://www.smarty.net/forums/viewtopic.php?t=19689&sid=60e6e3293aed78bc712066f03b22f88b – lbednaszynski Aug 23 '11 at 07:27
  • How does one display who is the effective and real user? For debugging. – WoodrowShigeru Aug 21 '20 at 11:47
2

Use:

Smarty::muteExpectedErrors();

Read this and this

kbec
  • 3,415
  • 3
  • 27
  • 42
0

I used filemtime successfully without checking "file_exists" for years. The way I have always interpreted the documentation is that FALSE should be returned from "filemtime" upon any error. Then a few days ago something very weird occurred. If the file did not exist, my Cron job terminated with a result. The result was not in the program output but rather in the Cron output. The message was "file length exceeded". I knew the Cron job ended on the filemtime statement because I sent myself an email before and after that statement. The "after" email never arrived.

I inserted a file_exists check on the file to fix the Cron job. However, that should not have been necessary. I still do not know what was changed on the hosting server I use. Several other Cron jobs started failing on the same day. I do not know yet whether they have anything to do with filemtime.

Jeff
  • 1