I run into a very weird situation with file_exists function. The hosting company said their php was configured in CGI mode instead of PHP mode. below is the code. It checks the existence of the file called test.txt in data folder on the fly during 50 seconds or so when loading the page containing the code. If file found, display "File exists" and exits the while loop. If no file found in 50 seconds, display "File does not exist" and breaks the loop too finishing loading the page.
Strange thing 1: it was not working as expected, can find the file only first time loading the page when file is there. It continues displaying "File exists" even after test.txt got removed when I refresh the page. If test.txt is not in the data folder at all, it displays "file not exists" even after I move back test.txt in the folder.
Strange thing 2: If I put a bigger file say over 170K in size, it looks working well, small files not though, especially under 40 bytes. I have tried many different ways to check file existence including absolute path, still no luck.
Thanks for any clue!
loading page...
$counter= 1;
while ($counter++) {
sleep(5);
if (file_exists("data/test.txt")) {
echo "File exists";
break;
}
if ($counter>10){
echo "File does not exist";
break;
}
}
PHP caches the results. Use clearstatcache(); before you use file_exists().
Since you are checking the existence of this file multiple times in a loop, you might need to consider caching as an issue here.
Taken from the documentation of file_Exists() -
Note: The results of this function are cached. See clearstatcache() for more details.
Perhaps you should try modifying your script to something like this -
while ($counter++) {
sleep(5);
clearstatcache();
if (file_exists("data/test.txt")) {
echo "File exists";
break;
}
...
}
Related
I have a script that runs with each visitor. Each visit writes some information to a file. I first check if the file exists using file_exists, and it if does I write to it using file_put_contents using the LOCK_EX flag. For example:-
$file = "myfile.txt";
if ( file_Exists($file) ) {
file_put_contents($file, "some content", LOCK_EX);
} else {
echo "file does not exist";
}
However, on rare occasions, during high traffic, the file_exist check fails even though the file exists. I'm assuming the file lock is preventing file_exists from checking the file, but I cant find any information that confirms this.
Can anybody corroborate my assumption, or is there another possible reason for the file_exists function to throw false?
Thanks
My environment is: Windows, MsSQL and PHP 5.4.
My scenario:
I'm doing a small shell script that creates a full backup from my wanted database to a temp folder and then moves it to a new location.
The backup goes fine and the file is created to my temp folder. Then I rename it to the 2nd folder and sometimes it goes ok, sometimes it cannot find the source file.
Of course at this point I know that I could skip the temporary location alltogether, but the actual problem with not finding the file bothers me. Why is it so random and might it also affect other file functions I've written before this one... Also i need to be able to control how and when the files move to the destination.
The base code is simple as it should be (although this is a simplified version of my actual code, since I doubt anyone would be interested in my error handling/logging conditions):
$query = "use test; backup database test to disk '//server01/temp/backups/file.bak', COMPRESSION;";
if($SQLClass->query($query)) {
$source="////server01//temp//backups//file.bak";
$destination="////server02//storage//backups//file.bak";
if(!rename($source , $destination)) {
//handleError is just a class function of mine that logs and outputs errors.
$this->handleError("Moving {$source} to {$destination} failed.");
}
}
else {
die('backup failed');
}
What I have tried is:
I added a file_exists before it and it can't find the source file either, when rename can't.
As the file can't be found, copy() and unlink() will not work either
Tried clearstatcache()
Tried sleep(10) after the sql backup completes
None of these didn't help at all. I and google seem to be out of ideas on what to do or try next. Of course I could some shell_execing, but that wouldn't remove my worries about my earlier products.
I only noticed this problem when I tried to run the command multiple times in a row. Is there some sort of cache for filenames that clearstatcache() won't touch ? It seems to be related to some sort of ghost file phenomena, where php is late to refresh the file system contents or such.
I would appreciate any ideas on what to try next and if you read this far thank you :).
You may try calling system's copy command.
I had once problem like yours (on Linux box) when i had to copy files between two NFS shares. It just failed from time to time with no visible reasons. After i switched to cp (analog of Windows copy) problem has gone.
Surely it is not perfect, but it worked for me.
It might be cache-related, or the mysql process has not yet released the file.
mysql will dump the file into another temp file, first and finally moves it to your temp folder.
While the file is beeing moved, it might be inaccessible by other processes.
First I would try to glob() all the files inside temp dir, when the error appears. Maybe you notice, its still not finished.
Also have you tried to implemente something like 10 retry iterations, with some delay?
$notMoved = 0;
while($notMoved < 10){
$source="////server01//temp//backups//file.bak";
$destination="////server02//storage//backups//file.bak";
if(!rename($source , $destination)) {
//handleError is just a class function of mine that logs and outputs errors.
if ($notMoved++ < 10){
sleep(20);
} else {
$this->handleError("Moving {$source} to {$destination} failed.");
break;
}
}else{
break;
}
}
To bypass the issue:
Don't dump and move
Move then dump :-)
(ofc. your backup store would be one behind then)
$source="////server01//temp//backups//file.bak";
$destination="////server02//storage//backups//file.bak";
if(!rename($source , $destination)) {
//handleError is just a class function of mine that logs and outputs errors.
$this->handleError("Moving {$source} to {$destination} failed.");
}
$query = "use test; backup database test to disk '//server01/temp/backups/file.bak', COMPRESSION;";
if($SQLClass->query($query)) {
//done :-)
}
else {
die('backup failed');
}
Try
$source = "\\server01\temp\backups\file.bak";
$destination = "\\server02\storage\backups\file.bak";
$content = file_get_content($source);
file_put_contents($destination, $content);
When I use file_get_contents on a path like /a/path/to/a/../file.php, it gets the content just fine. If I call file_exists first (or is_file or realpath), the return values indicate that the file does not exist. What seems to be the issue?
Edit: Here is some additional information condensed from comments to answers:
I am running Mac OS X 10.9 with php 5.5.6, so safe mode should not be an issue (it was removed in version 5.4)
I tried clearing the file cash by calling clearstatcache(true, $dir1)
The file in question is 362 bytes in size, but I reproduced this issue with several different files in a medley of locations.
open_basedir is commented out in the php.ini
The file is local (the first file I tried was in the same directory as the script)
The issue exists in the command line (phpUnit) and in the browser.
The permissions on the file in questions are -rwxrwxrwx (I sudo-chmod-777ed the file)
This is a code snippet that creates the behavior:
$dir1 = '/a/path/to/a/../file.php';
$dir2 = '/a/path/to/file.php';
echo "File content dir1:\n";
echo file_get_contents($dir1);
echo "\ndir1 exists: ".(int)file_exists($dir1);
echo "\n\nFile content dir2:\n";
echo file_get_contents($dir2);
echo "\ndir2 exists: ".(int)file_exists($dir2);
the output is:
File content dir1:
The actual content of the file. I promise!
dir1 exists: 0
File content dir2:
The actual content of the file. I promise!
dir2 exists: 1
It sounds like you have safe mode turned on and are attempting to access a file that PHP would consider unsafe when running in safe mode. From the manual:
Warning
This function returns FALSE for files inaccessible due to safe mode restrictions. However these files still can be included if they are located in safe_mode_include_dir.
EDIT: You can also reproduce this behavior if /a/path/to/a/ is not a real path. For example:
<?php
$dir1 = '/realDir/realDir2/filetoinclude.php';
echo "File content dir1:\n";
echo file_get_contents($dir1); // outputs file contents
echo "\ndir1 exists: ".(int)file_exists($dir1); // outputs 1
$dir2 = '/realDir/realDir2/realDir3/../filetoinclude.php';
echo "\n\nFile content dir2:\n";
echo file_get_contents($dir2); // outputs file contents
echo "\ndir2 exists: ".(int)file_exists($dir2); // outputs 1
$dir3 = '/realDir/realDir2/NotARealDirectory/../filetoinclude.php';
echo "\n\nFile content dir3:\n";
echo file_get_contents($dir3); // outputs file contents
echo "\ndir3 exists: ".(int)file_exists($dir3); // outputs 0
This is because file_exists needs to traverse the entire path, literally, so it looks for the missing directory and fails. I'm not sure exactly what file_get_contents does that is different, and I can't find much on Google, but it clearly does some parsing of the path that is different from what file_exists does.
I am providing the workaround that I developed with a regex, if others have this same issue. I hate to be using this hack, and I still don't understand why I am having this issue, but hopefully someone will come up with an actual solution.
Before calling file_exists I now call this function:
function resolve($path) {
$regex = "/(.?)(\/[^\/]*\/\.\.)(.*)/";
$result = preg_replace($regex, "$1$3", $path);
if ($result != $path) {
$result = resolve($result);
}
return $result;
}
I have a script that re-writes a file every few hours. This file is inserted into end users html, via php include.
How can I check if my script, at this exact moment, is working (e.g. re-writing) the file when it is being called to user for display? Is it even an issue, in terms of what will happen if they access the file at the same time, what are the odds and will the user just have to wait untill the script is finished its work?
Thanks in advance!
More on the subject...
Is this a way forward using file_put_contents and LOCK_EX?
when script saves its data every now and then
file_put_contents($content,"text", LOCK_EX);
and when user opens the page
if (file_exists("text")) {
function include_file() {
$file = fopen("text", "r");
if (flock($file, LOCK_EX)) {
include_file();
}
else {
echo file_get_contents("text");
}
}
} else {
echo 'no such file';
}
Could anyone advice me on the syntax, is this a proper way to call include_file() after condition and how can I limit a number of such calls?
I guess this solution is also good, except same call to include_file(), would it even work?
function include_file() {
$time = time();
$file = filectime("text");
if ($file + 1 < $time) {
echo "good to read";
} else {
echo "have to wait";
include_file();
}
}
To check if the file is currently being written, you can use filectime() function to get the actual time the file is being written.
You can get current timestamp on top of your script in a variable and whenever you need to access the file, you can compare the current timestamp with the filectime() of that file, if file creation time is latest then the scenario occured when you have to wait for that file to be written and you can log that in database or another file.
To prevent this scenario from happening, you can change the script which is writing the file so that, it first creates temporary file and once it's done you just replace (move or rename) the temporary file with original file, this action would require very less time compared to file writing and make the scenario occurrence very rare possibility.
Even if read and replace operation occurs simultaneously, the time the read script has to wait will be very less.
Depending on the size of the file, this might be an issue of concurrency. But you might solve that quite easy: before starting to write the file, you might create a kind of "lock file", i.e. if your file is named "incfile.php" you might create an "incfile.php.lock". Once you're doen with writing, you will remove this file.
On the include side, you can check for the existance of the "incfile.php.lock" and wait until it's disappeared, need some looping and sleeping in the unlikely case of a concurrent access.
Basically, you should consider another solution by just writing the data which is rendered in to that file to a database (locks etc are available) and render that in a module which then gets included in your page. Solutions like yours are hardly to maintain on the long run ...
This question is old, but I add this answer because the other answers have no code.
function write_to_file(string $fp, string $string) : bool {
$timestamp_before_fwrite = date("U");
$stream = fopen($fp, "w");
fwrite($stream, $string);
while(is_resource($stream)) {
fclose($stream);
}
$file_last_changed = filemtime($fp);
if ($file_last_changed < $timestamp_before_fwrite) {
//File not changed code
return false;
}
return true;
}
This is the function I use to write to file, it first gets the current timestamp before making changes to the file, and then I compare the timestamp to the last time the file was changed.
I'm writing a PHP application and in my code i want to create create and return images to the browser. However, sometimes i'm getting some weird results where the image cannot be created since the file does not seem to exist.
Here is a sample error message I get and the code in a nutshell. I do know that the image exists, but still the method sometimes fails, and sometimes it succeeds, even for the same file.
The error:
Warning: imagecreatefrompng(path/to/image.png) [function.imagecreatefrompng]: failed to open stream: No such file or directory in file test.php on line 301
The code:
if (file_exists($filename)) {
$image = imagecreatefrompng($filename);
}
I would greatly appreciate any hints or tips of what might be wrong and how I can improve the code to be more stabile.
I suggest you use is_readable
if (is_readable($filename)) {
$image = imagecreatefrompng($filename);
}
The file may "exist" but is the file accessible? what does file_exists actually do?
if it opens the file and then closes it make sure that the file is actualy closed and not locked before imagecreatedfrompng fires.
it would be a good idea to try catching the error in a loop and make 4 or 5 attempts before handing back a controlled error.
maybe try is_readable() or is_writable() instead?
Have you considered checking for the correct permissions? If the file cannot be read, but the directory can, you would get file_exists(...) = true, but would not be able to open a handle to the file.
Use is_readable() to check whatever you have permission to access that file.
You can try GD :
IF($img = #GETIMAGESIZE("testimage.gif")){
ECHO "image exists";
}ELSE{
ECHO "image does not exist";
}
bro check for white spaces in your filepath. I recently had this issue while i was tring to include a file from a module i was creating for an app. Other modules included well when called but one didnt. It turned out that there was a white space in the filepath. I suggest u try php trim() function. If this works holla.