weird PHP filesize behavior - php

In the code below I...
open a textfile, write four characters to it, and close it again,
re-open it, read the contents, and use filesize to report the size of the file. (It's 4, as it should be),
manipulate those contents and tack on four more characters as well. Then I write that new string to the textfile and close it again,
use filesize again to report how big the file is.
To my surprise, the answer it gives is still 4 even though the actual size of the file is 8! Examining the contents of the file proves that the write works and the length of the contents is 8.
What is going on??
By the way I have to use fread and fwrite instead of file_get_contents and file_put_contents. At least I think I do. This little program is a stepping stone to using "flock" so I can read the contents of a file and rewrite to it while making sure no other processes use the file in between. And AFAIK flock doesn't work with file_get_contents and file_put_contents.
Please help!
<?php
$filename = "blahdeeblah.txt";
// Write 4 characters
$fp = fopen($filename, "w");
fwrite($fp, "1234");
fclose($fp);
// read those characters, manipulate them, and write them back (also increasing filesize).
$fp = fopen($filename, "r+");
$size = filesize($filename);
echo "size before is: " . $size . "<br>";
$t = fread($fp, $size);
$t = $t[3] . $t[2] . $t[1] . $t[0] . "5678";
rewind($fp);
fwrite($fp, $t);
fclose($fp);
// "filesize" returns the same number as before even though the file is larger now.
$size = filesize($filename);
echo "size after is: " . $size . " ";
?>

From http://php.net/manual/en/function.filesize.php
Note: The results of this function are cached. See clearstatcache() for more details.

When you open a file by fopen() function you can obtain proper size at any time using fstat() function:
$fstat=fstat($fp);
echo 'Size: '.$fstat['size'];
Example:
$filename='blahdeeblah.txt';
$fp=fopen($filename, 'a');
$size=#filesize($filename);
echo 'Proper size (obtained by filesize): '.$size.'<br>';
$fstat=fstat($fp);
echo 'Proper size (obtained by fstat): '.$fstat['size'].'<br><br>';
fwrite($fp, '1234');
echo 'Writing 4 bytes...<br><br>';
$fstat=fstat($fp);
echo 'Proper size (obtained by fstat): '.$fstat['size'].'<br>';
fclose($fp);
$size=#filesize($filename);
echo 'Wrong size (obtained by filesize): '.$size;

Note that cached value is used only in current script. When you run the script again filesize() reads new (proper) size of file.
Example:
$filename='blahdeeblah.txt';
$fp=fopen($filename, 'a');
$size=#filesize($filename);
echo 'Proper size: '.$size.'<br>';
fwrite($fp, '1234');
fclose($fp);
$size=#filesize($filename);
echo 'Wrong size: '.$size;

Related

Shared access: How to fix "fread(): Length parameter must be greater than 0"?

When I run this function on multiple scripts one script generated warning:
fread(): Length parameter must be greater than 0
function test($n){
echo "<h4>$n at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$fp = fopen("$n.txt", "r");
$s = fread($fp, filesize("$n.txt") );
fclose($fp);
$fp = fopen("$n.txt", "w");
$s = $_SERVER['HTTP_USER_AGENT'].' '.time();
if (flock($fp, LOCK_EX)) { // acquire an exclusive lock
fwrite($fp, $s);
// fflush($fp);// flush output before releasing the lock
flock($fp, LOCK_UN); // release the lock
} else {
echo "Couldn't get the lock!";
}
}
}
I try to write reading of the file for multiple users, but only one user can write the file. I know that when I use fwrite with flock - LOC_EX, next scripts must wait till the write is finished. But here it seems like filesize doesn't wait till the write operation is finished. My opinion is that it tries to reach the file when the file size is 0, and as a result this produces the problem: 0 bytes will be read from the file, when it is written by original script.
Is it possible to fix this for fread function?
Purpose of this script is to test fread with some limit and to check the data which I read later, if the data are really written when I did not used fflush.
function test($n){
echo "<h4>$n at ".time()."</h4>";
for ($i = 0; $i<50; $i++ ){
$start = microtime(true);
$fp = fopen("$n.txt", "r");
if(filesize($n.txt) > 0)
{
$s = fread($fp, filesize($n.txt) );
fclose($fp);
$fp = fopen("$n.txt", "w");
$s = $_SERVER['HTTP_USER_AGENT'].' '.time();
if (flock($fp, LOCK_EX)) { // acquire an exclusive lock
fwrite($fp, $s);
// fflush($fp);// flush output before releasing the lock
flock($fp, LOCK_UN); // release the lock
} else {
echo "Couldn't get the lock!";
}
}
else
{
echo "Filesize must be greater than 0";
}
}
}
please change $s variables name its use same things two time
$fp = fopen("$n.txt", "r");
$s = fread($fp, filesize("$n.txt") );
fclose($fp);
The error occurs in the middle line of the above three lines.
Firstly, these three lines could be rewritten into a single line as follows:
$s = file_get_contents("$n.txt");
However, these isn't necessary, as these three lines are entirely redundant in your code. They don't do anything useful.
What they do is open a file, store its contents to $s and then close it.
But you are then immediately setting $s to a different value, thus throwing away the previous value, and making it pointless to have read it from the file in the first place.
If you need to keep the original contents of the file, then use file_get_contents() and make sure you don't overwrite the contents of the variable.
If you don't need the original contents of the file, then just delete those three lines from your code.
Incidentally, this error highlights a couple of good coding practices that you should take on board: Firstly, never re-use a variable for two different things, and secondly always give your variables (and functions) good names. $s is not a good name; $previousFileContents would be a better name; it would have made the error much more obvious.

Read first 3000 bytes of a text file in php

Solved! I used an existing json file that I was using to display diagrams on the page.
I have a 2000 line text file. I want to read in the first 3000 bytes to a php variable. This works, but only at the cost of reading in the entire text file:
$little_diagrams = ('assets/diagrams.txt'); $mason = file($little_diagrams);
I tried this, but it doesn't work. Any ideas on why?
$little_diagrams = file_get_contents("assets/diagrams.txt", NULL, NULL, 0, 3000);
$mason = file($little_diagrams);
The trouble is that I have to process lines in "assets/diagrams.txt" such as:
2833|6979|Poloskov|||Nikolayev|Igor|2272|1n3rk1/3p1ppp/5q2/2p1P3/2B2P2/r2Q2P1/1b2N2P/1R3K1R|
2832|6979|Poloskov|||Nikolayev|Igor|2272|r2qk2r/1b1p1ppp/n4b2/2pN4/2B1P3/8/PP3PPP/R2QK1NR|
2831|6978|Nikolayev|Igor|2272|Buturin|Vladimir (IM)|2405|r3r1k1/1ppb1pp1/3p1n1p/2nP4/p3P3/4NP2/PPBN1KPP/R3R3|
2830|6978|Nikolayev|Igor|2272|Buturin|Vladimir (IM)|2405|r2qr1k1/1ppb1pp1/p1np1n1p/8/3PP3/4NN2/PPB2PPP/R2Q1RK1|
2829|6977|Nikolayev|Igor|2272|Tabatadze|Tamaz|2288|2rqk2r/4bp1p/p1n1b3/3pP3/Pp1P2p1/1P3p2/1B2NPPP/2RQNRK1|
2828|6976|Lutsko|Igor|2307|Nikolayev|Igor|2272|6r1/1pp2p1k/p2p3p/2bP4/2P2r2/1P4NP/P2R1P1K/5R2|
NEW CODE: (doesn't work, no diagrams are displayed at http://communitychessclub.com/ left column bottom)
$filename = "assets/diagrams.txt";
$handle = fopen($filename, "r");
$little_diagrams = fread($handle, 3000); //<<--- as per your need
fclose($handle);
$X = 5000; $line = 0;
foreach($little_diagrams as $line) {$X++; if ($X >= 5040) {break;} $token = explode("|", $line); //etc
}
<?php
$filename = "c:\\files\\yourfile.txt";
$handle = fopen($filename, "rb");
//$little_diagrams = fread($handle, filesize($filename));
$little_diagrams = fread($handle, 3000); //<<--- as per your need
fclose($handle);
?>
Try above code and read this fread function documentation
I hope this will help also see the example code Example #2 Binary fread() example
fread takes two arguments
string fread ( resource $handle , int $length )
second is length part
length bytes have been read as per documentation
fread() reads up to length bytes from the file pointer referenced by handle. Reading stops as soon as one of the following conditions is met:
UPDATED BELOW
Note:
You can use file_get_contents() to return the contents of a file as a string.
change second argument to FALSE from NULL then try hope it will work
so in my opinion correct code will be like below take a try
<?php
//however working with null also
$file_content =file_get_contents('demoTest.txt',FALSE,NULL,0,3000);
echo 'File Size: '.filesize('demoTest.txt');
echo '<br/> CONTENT HERE<br />'.$file_content;
echo '<br /><br />String Length: '.strlen($file_content);
?>
read the documentation at here for file function

Reading a big multi GB size text file in php

I have a 197gb text file that I want to read and push the contents into MySql database. I know, I can't put that big file in PHP buffer and read it as whole, So I want to read few hundred lines as a time and keep on reading next and next to read the whole file.
I am trying it with this but the page returns nothing
<?php
$i = 0;
$handle = fopen("./data/200gbfile.txt", "r") or die("Couldn't get handle");
if ($handle) {
while (($line = fgets($handle)) !== false) {
echo $line . "<br />";
if ($i > 100) {
exit;
}
$i++;
}
fclose($handle);
} else {
echo "Error Opeing File!";
}
?>
Is there a limit of the max file size to be handled in php setting?
EDIT: for the 197gb file in question, fopen is failing to return anything and
the output page is just going blank.
You can read the file in chunks to save memory:
For example:
$fd = #fopen("./data/200gbfile.txt", "r");
while (!feof($fd)) {
$data = fread($fd, 1024); // read the file in 1024kb chunks
// handle current data (read line by line for example)
}
fclose($fd);
But no idea if that works with a file with 100Gbytes+.
Edit: # with fopen is required as suggested by Roman.
you can use ini_set('memory_limit','16M'); to set size accordingly but i don't wether it will handle such huge file. never tested that..

My php script won't open files that aren't in its root directory

This is a php script for a user login system that I am developing.
I need it to read from, and write to, the /students/students.txt file, but it won't even read the content already contained in the file.
<?php
//other code
echo "...";
setcookie("Student", $SID, time()+43200, "/");
fopen("/students/students.txt", "r");
$content = fread("/students/students.txt", filesize("/students/students.txt"));
echo $content;
fclose("/students/students.txt");
fopen("/students/students.txt", "w");
fwrite("/students/students.txt", $content."\n".$SID);
fclose("/students/students.txt");
//other code
?>
You are not using fopen() properly. The function returns a handle that you then use to read or edit the file, for example:
//reading a file
if ($handle = fopen("/students/students.txt", "r"))
{
echo "info obtained:<br>";
while (($buffer = fgets($handle))!==false)
{ echo $buffer;}
fclose($handle);
}
//writing/overwriting a file
if ($handle = fopen("/students/students.txt", "w"))
{
fwrite($handle, "hello/n");
fclose($handle);
}
Let me know if that worked for you.
P.S.: Ty to the commentators for the constructive feedback.
There are many ways to read/write to file as others have demonstrated. I just want to illustrate the mistake in your particular approach.
fread takes a file handle as param, NOT a string that represents the path to the file.
So your line:
$content = fread("/students/students.txt", filesize("/students/students.txt")); is incorrect.
It should be:
$file_handle = fopen("/students/students.txt", "r");
$content = fread($file_handle, filesize("/students/students.txt"));
Same thing when you write contents to file using fwrite. Its reference to the file is a File Handle opened using fopen NOT the filepath. when opening a file using fopen() you can also check if the $file_handle returned is a valid resource or is false. If false, it means the fopen operation was not successful.
So your code:
fopen("/students/students.txt", "w");
fwrite("/students/students.txt", $content."\n".$SID);
fclose("/students/students.txt");
Needs to be re-written as:
$file_handle = fopen("/students/students.txt", "w");
fwrite($file_handle, $content."\n".$SID);
fclose($file_handle);
You can see that fclose operates on file handles as well.
File Handle (as per php.net):
A file system pointer resource that is typically created using fopen().
Here are a couple of diagnostic functions that allow you to validate that a file exists and is readable. If it is a permission issue, it gives you the name of the user that needs permission.
function PrintMessage($text, $success = true)
{
print "$text";
if ($success)
print " [<font color=\"green\">Success</font>]<br />\n";
else
print(" [<font color=\"red\">Failure</font>]<br />\n");
}
function CheckReadable($filename)
{
if (realpath($filename) != "")
$filename = realpath($filename);
if (!file_exists($filename))
{
PrintMessage("'$filename' is missing or inaccessible by '" . get_current_user() . "'", false);
return false;
}
elseif (!is_readable($filename))
{
PrintMessage("'$filename' found but is not readable by '" . get_current_user() . "'", false);
return false;
}
else
PrintMessage("'$filename' found and is readable by '" . get_current_user() . "'", true);
return true;
}
I've re-written your code with (IMO) a cleaner and more efficient code:
<?php
$SID = "SOMETHING MYSTERIOUS";
setcookie("Student", $SID, time()+43200, "/");
$file = "/students/students.txt"; //is the full path correct?
$content = file_get_contents($file); //$content now contains /students/students.txt
$size = filesize($file); //do you still need this ?
echo $content;
file_put_contents($file, "\n".$SID, FILE_APPEND); //do you have write permissions ?
file_get_contents
file_get_contents() is the preferred way to read the contents of a
file into a string. It will use memory mapping techniques if supported
by your OS to enhance performance.
file_put_contents
This function is identical to calling fopen(), fwrite() and
fclose() successively to write data to a file. If filename does not
exist, the file is created. Otherwise, the existing file is
overwritten, unless the FILE_APPEND flag is set.
Notes:
Make sure the full path /students/students.txt is
correct.
Check if you've read/write permissions on /students/students.txt
Learn more about linux file/folder permissions or, if you don't access to the shell, how to change file or directory permissions via ftp
Try to do this:
fopen("students/students.txt", "r");
And check to permissions read the file.

What is the best way to write a large file to disk in PHP?

I have a PHP script that occasionally needs to write large files to disk. Using file_put_contents(), if the file is large enough (in this case around 2 MB), the PHP script runs out of memory (PHP Fatal error: Allowed memory size of ######## bytes exhausted). I know I could just increase the memory limit, but that doesn't seem like a full solution to me--there has to be a better way, right?
What is the best way to write a large file to disk in PHP?
You'll need a temporary file in which you put bits of the source file plus what's to be appended:
$sp = fopen('source', 'r');
$op = fopen('tempfile', 'w');
while (!feof($sp)) {
$buffer = fread($sp, 512); // use a buffer of 512 bytes
fwrite($op, $buffer);
}
// append new data
fwrite($op, $new_data);
// close handles
fclose($op);
fclose($sp);
// make temporary file the new source
rename('tempfile', 'source');
That way, the whole contents of source aren't read into memory. When using cURL, you might omit setting CURLOPT_RETURNTRANSFER and instead, add an output buffer that writes to a temporary file:
function write_temp($buffer) {
global $handle;
fwrite($handle, $buffer);
return ''; // return EMPTY string, so nothing's internally buffered
}
$handle = fopen('tempfile', 'w');
ob_start('write_temp');
$curl_handle = curl_init('http://example.com/');
curl_setopt($curl_handle, CURLOPT_BUFFERSIZE, 512);
curl_exec($curl_handle);
ob_end_clean();
fclose($handle);
It seems as though I always miss the obvious. As pointed out by Marc, there's CURLOPT_FILE to directly write the response to disk.
Writing line by line (or packet by packet in case of binary files) using functions like fwrite()
Try this answer:
$file = fopen("file.json", "w");
$pieces = str_split($content, 1024 * 4);
foreach ($pieces as $piece) {
fwrite($file, $piece, strlen($piece));
}
fclose($file);

Categories