Lock the file while reading and writing - php

I have a file which stores some value. Users can add stuff to that file and the counter in that file is updated. But if two users open the file, they'll get the same counter ($arr['counter']). What should I do? Maybe can I lock the file for one user and release the lock after he updates the counter and add some stuff back to the file? Or PHP already locks the file once is opened and I don't need to worry? Here's my current code:
$handle = fopen($file, 'r');
$contents = fread($handle, filesize($file));
fclose($handle);
$arr = json_decode($contents);
//Add stuff here to $arr and update counter $arr['counter']++
$handle = fopen($file, 'w');
fwrite($handle, json_encode($arr));
fclose($handle);

PHP has the flock function which will lock the file before writing to it, example,
$handle = fopen($file, 'r');
$contents = fread($handle, filesize($file));
fclose($handle);
$arr = json_decode($contents);
//Add stuff here to $arr and update counter $arr['counter']++
$handle = fopen($file, 'w');
if(flock($handle, LOCK_EX))
{
fwrite($handle, json_encode($arr));
flock($handle, LOCK_UN);
}
else
{
// couldn't lock the file
}
fclose($handle);

Related

PHP : Can file write mode lose data and size?

I have a problem with my logs file, in the past, I used fopen($file, "w+"); with the w+ mode to generate and I wrote on the file, and I used fwrite function to write data and header.
With the time I changed the mode to fopen($file, "a"); and I use the fputs function to write the header, and fwrite for writing the data, but right after that the size of logs is being Vvery small compared to old files, and I think that I lose the data.
My question: I think that the write mode, block the code (sometimes) to write on the file, is that can be true? if not, are there any other things I need to check to fix the problem?
Past code :
if (file_exists($file)) {
$handle = fopen($file, "a+");
fwrite($handle, $record);
fclose($handle);
} else {
$handle = fopen($file, "w+");
$header = 'Name;Last Name;Age;User;Comment';
fwrite($handle, $header);
fwrite($handle, $record);
fclose($handle);
}
New Code :
if(!file_exists($file)) {
$handle = fopen($file, 'a');
$headers = ['Name', 'Last Name', 'Age', 'User', 'Comment'];
fputs($handle, implode($headers, ';')."\n");
fwrite($handle, $record);
fclose($handle);
} else {
$handle = fopen($file, "a+");
fwrite($handle, $record);
fclose($handle);
}
Example: On the past, the size of a day file is 71Mo, but right after the modifications the size of day file was 7Ko

Open txt file grab the number count +1 and save it again

I have a text file number.txt and inside it there is only the number 1.
I'm using the code below to open the file, get the number, add 1, update the content (must be 2) and save it again. My code is not working. Any suggestions?
$fp = fopen('number.txt', 'c+');
flock($fp, LOCK_EX);
$count = (int)fread($fp, filesize('number.txt'));
ftruncate($fp, 0);
fseek($fp, 0);
fwrite($fp, $count + 1);
flock($fp, LOCK_UN);
fclose($fp);
Works for me
<?php
$handle = fopen("test.txt", "r+");
if ($handle) {
$buffer = fgets($handle, 10);
$nCount = (int)$buffer;
rewind($handle );
fputs($handle, $nCount+1);
fclose($handle);
}
?>
You should be able to do this with just
$path = 'number.txt';
file_put_contents($path, 1+(int)file_get_contents($path));

File manipulation in PHP: lock, read, clear, unlock

I want some PHP to do the following in this order:
Gain exclusive lock to a file (waiting if already locked)
Read the contents of the file
Empty the file of all contents
Remove the lock
But any code I'm coming up with one way or another always relinquishes the lock between the reading and writing.
$fp = fopen('status.txt', 'r+');
flock($fp, LOCK_EX);
$str = fread($fp,1000); // [another hack. I just want it to read everything]
unlink('status.txt');
touch('status.txt');
Any ideas? I don't trust anything I do with files.
I think ftruncate can do what you want, since it works on a file that you already have open.
http://www.php.net/manual/en/function.ftruncate.php
Here's their example:
<?php
$filename = 'lorem_ipsum.txt';
$handle = fopen($filename, 'r+');
ftruncate($handle, rand(1, filesize($filename)));
rewind($handle);
echo fread($handle, filesize($filename));
fclose($handle);
?>
So I think what you want then is something like:
$fp = fopen('status.txt', 'r+');
flock($fp, LOCK_EX);
$str = fread($fp, filesize('status.txt'));
ftruncate($fp, 0);
flock($fp, LOCK_UN);
fclose($fp);

Write to file in PHP?

Well actually, I already know how to write a file, but how do I write data to a file where the newest data added is at the top? I know how to do this, but the newest information is at the bottom. By the way, just to clarify, I do need all of the data to be displayed, not just the newest one.
Do you mean append or prepend? This will append:
$fp = fopen('data.txt', 'w');
fwrite($fp, '1');
fwrite($fp, '23');
fclose($fp);
This will prepend:
$handle = fopen('file.txt', "r+");
$read = fread($handle, filesize($file));
$data = $newStuff . $read;
if (!fwrite($handle, $data)) {
echo 'fail';
} else {
echo 'success';
}
If you want to append some text to the file content it's better to use another function:
file_put_contents('data.txt', '123', FILE_APPEND)

How do I prepend file to beginning?

In PHP if you write to a file it will write end of that existing file.
How do we prepend a file to write in the beginning of that file?
I have tried rewind($handle) function but seems overwriting if current content is larger than existing.
Any Ideas?
$prepend = 'prepend me please';
$file = '/path/to/file';
$fileContents = file_get_contents($file);
file_put_contents($file, $prepend . $fileContents);
The file_get_contents solution is inefficient for large files. This solution may take longer, depending on the amount of data that needs to be prepended (more is actually better), but it won't eat up memory.
<?php
$cache_new = "Prepend this"; // this gets prepended
$file = "file.dat"; // the file to which $cache_new gets prepended
$handle = fopen($file, "r+");
$len = strlen($cache_new);
$final_len = filesize($file) + $len;
$cache_old = fread($handle, $len);
rewind($handle);
$i = 1;
while (ftell($handle) < $final_len) {
fwrite($handle, $cache_new);
$cache_new = $cache_old;
$cache_old = fread($handle, $len);
fseek($handle, $i * $len);
$i++;
}
?>
$filename = "log.txt";
$file_to_read = #fopen($filename, "r");
$old_text = #fread($file_to_read, 1024); // max 1024
#fclose(file_to_read);
$file_to_write = fopen($filename, "w");
fwrite($file_to_write, "new text".$old_text);
Another (rough) suggestion:
$tempFile = tempnam('/tmp/dir');
$fhandle = fopen($tempFile, 'w');
fwrite($fhandle, 'string to prepend');
$oldFhandle = fopen('/path/to/file', 'r');
while (($buffer = fread($oldFhandle, 10000)) !== false) {
fwrite($fhandle, $buffer);
}
fclose($fhandle);
fclose($oldFhandle);
rename($tempFile, '/path/to/file');
This has the drawback of using a temporary file, but is otherwise pretty efficient.
When using fopen() you can set the mode to set the pointer (ie. the begginng or end.
$afile = fopen("file.txt", "r+");
'r' Open for reading only; place
the file pointer at the beginning of
the file.
'r+' Open for reading and
writing; place the file pointer at the
beginning of the file.
$file = fopen('filepath.txt', 'r+') or die('Error');
$txt = "/n".$string;
fwrite($file, $txt);
fclose($file);
This will add a blank line in the text file, so next time you write to it you replace the blank line. with a blank line and your string.
This is the only and best trick.

Categories