I am trying to make a counter. What I mean by that is a button that uses a XHTMLrequest and just runs this PHP.
My question is why is my counting code changing the value of the text document to the number 1. If I just change the value to for example 24, instead of adding 1 and changing the value to 25, it changes the value to the number 1.
<?php
$fp = false;
// Open file for reading, then writing
while ( ($fp=fopen('clicks.txt','r+'))===false ) {
usleep(250000); // Delay 1/4 second
}
// Obtain lock
while ( !flock($fp, LOCK_EX) ) {
usleep(250000); // Delay 1/4 second
}
// Read Clicks
$clicks = trim(fread($fp,1024));
// Add click
$clicks++;
// Empty file
ftruncate($fp,0);
// Write clicks
fwrite($fp, $clicks);
// Release Lock
flock($fp, LOCK_UN);
// Release handle
fclose($fp);
?>
It is because when you read in the information from the file it is a string and needs to be converted to an integer before you can add 1 to it.
change:
$clicks = trim(fread($fp,1024));
to
$clicks = intval(trim(fread($fp,1024)));
Replace $clicks++; with $clicks = $clicks + 1;.
I notice you ftruncate but never rewind the file. Remember that the pointer stays where it last read from, then truncating it makes the file 0 but the pointer remains the same.
Citing the PHP documentation:
<?php
$filename = 'lorem_ipsum.txt';
$handle = fopen($filename, 'r+');
ftruncate($handle, rand(1, filesize($filename)));
rewind($handle);
echo fread($handle, filesize($filename));
fclose($handle);
?>
Note that PHP's example rewinds the file as well.
Related
I'm trying to make a download counter in a website for a video game in PHP, but for some reason, instead of incrementing the contents of the downloadcount.txt file by 1, it takes the number, increments it, and appends it to the end of the file. How could I just make it replace the file contents instead of appending it?
Here's the source:
<?php
ob_start();
$newURL = 'versions/v1.0.0aplha/Dungeon1UP.zip';
//header('Location: '.$newURL);
//increment download counter
$file = fopen("downloadcount.txt", "w+") or die("Unable to open file!");
$content = fread($file,filesize("downloadcount.txt"));
echo $content;
$output = (int) $content + 1;
//$output = 'test';
fwrite($file, $output);
fclose($file);
ob_end_flush();
?>
The number in the file is supposed to increase by one every time, but instead, it gives me numbers like this: 101110121011101310111012101110149.2233720368548E+189.2233720368548E+189.2233720368548E+18
As correctly pointed out in one of the comments, for your specific case you can use fseek ( $file, 0 ) right before writing, such as:
fseek ( $file, 0 );
fwrite($file, $output);
Or even simpler you can rewind($file) before writing, this will ensure that the next write happens at byte 0 - ie the start of the file.
The reason why the file gets appended it is because you're opening the file in append and truncate mode, that is "w+". You have to open it in readwrite mode in case you do not want to reset the contents, just "r+" on your fopen, such as:
fopen("downloadcount.txt", "r+")
Just make sure the file exists before writing!
Please see fopen modes here:
https://www.php.net/manual/en/function.fopen.php
And working code here:
https://bpaste.net/show/iasj
It will be much simpler to use file_get_contents/file_put_contents:
// update with more precise path to file:
$content = file_get_contents(__DIR__ . "/downloadcount.txt");
echo $content;
$output = (int) $content + 1;
// by default `file_put_contents` overwrites file content
file_put_contents(__DIR__ . "/downloadcount.txt", $output);
That appending should just be a typecasting problem, but I would not encourage you to handle counts the file way. In order to count the number of downloads for a file, it's better to make a database update of a row using transactions to handle concurrency properly, as doing it the file way could compromise accuracy.
You can get the content, check if the file has data. If not initialise to 0 and then just replace the content.
$fileContent = file_get_contents("downloadcount.txt");
$content = (!empty($fileContent) ? $fileContent : 0);
$content++;
file_put_contents('downloadcount.txt', $content);
Check $str or directly content inside the file
I have this small piece of code on my website that i use to count downloads.
its pretty simple really,
counter.php sends the command and counter.txt is just a 1 line text file with a number that auto goes up every time the link is clicked.
My question is, is it possible to have 2 counter.txt files and add them to a third counter.txt file? so it would look something like:
counter.txt + counter2.txt = counter3.txt ?
$counter = 'counter.txt';
$download = 'downloadurlhere';
$number = file_get_contents($counter); // read count file
$number++; // increment count by 1
$fh = fopen($counter, 'w'); // open count file for writing
fwrite($fh, $number); // write new count to count file
fclose($fh); // close count file
header("Location: $download"); // get download
So essentially i want to offer 2 downloads
a light version and a full version
and then keep track of each download count separately. but then also have a count for the total of both downloads.
oh and to make sure i include enough detail, on the download.php page i echo the counter.txt file with
<?php echo file_get_contents('counter.txt');?>
Adding the counters of two files should be easy. You just have to read each file and then the variables are added and written to third counter file or whatever you desire. An example:
<?php
$first=file_get_contents("counter1.txt");
$second=file_get_contents("counter2.txt");
$sum=$first+$second;
file_put_contents("counter3.txt",$sum);
?>
So here was the end result, I had to swap around the txt files for counter.txt and urls but this worked perfectly...
$count = 'counterfull.txt';
$total = 'total.txt';
$download = 'URL';
$number1 = file_get_contents($count);
$number1++;
$fh = fopen($count, w);
fwrite($fh, $number1);
fclose($fh);
$number2 = file_get_contents($total);
$number2++;
$fh = fopen($total, w);
fwrite($fh, $number2);
fclose($fh);
header("Location: $download");
I have this very simple program in PHP that does not want to work. It returns the same error as topic for unknown reasons to me.
$file = 'counter.txt';
$counter = file_get_contents($file);
if(flock($file, LOCK_EX)){
$counter += 1;
echo $counter;
$write = fopen($file, 'w') or die('Unable');
fwrite($write, $counter);
flock($file,LOCK_UN);
}
You have a few things out of order,
$file = 'counter.txt';
$counter = file_get_contents($file);
$write = fopen($file, 'w') or die('Unable'); //move this line
if(flock($write, LOCK_EX)){ //-- change this
$counter += 1;
echo $counter;
fwrite($write, $counter);
flock($write,LOCK_UN); //-- change this
}
The main problem is flock takes a (stream)resource as it's input, and the filename is just a string. So instead of $file you just need to use $write which is your file handle (resource), and then move fopen before the flock call.
If you are writing a single line do this instead
$file = 'counter.txt';
$counter += 1;
if(!file_put_contents($file, $counter, LOCK_EX)) or die('Unable');
http://php.net/manual/en/function.file-put-contents.php
It's pretty much equivalent to what you have there. Well except it's way shorter 3 vs 9 lines, easier, and Kooler.
I could even reduce this further down to 1 line:
if(!file_put_contents('counter.txt', ++$counter, LOCK_EX)) or die('Unable');
The LOCK_EX flag is Lock exclusive, basically the same thing as flock, just in this case PHP handles all the file stream stuff for you.
The real difference is if you do this in a loop, it's expensive getting file handles so to loop output into file_put_content is way less efficient then to open the file (outside the loop) and write to the same handle during inside a loop.
Hesse the reason I said this above.
If you are writing a single line do this instead
Hope that makes sense.
Based on laracasts
Solution was to give Apache group (www-data) read and write permissions to /storage/framework/cache applying recursively.
I am developing a text collection engine using fwrite() to write text but I want to put a file size cap of 1.5 mb on the writing process so if the file is larger that 1.5mb it will start writing a new file from where it left off and so on until it writes the contents of the source file into multiple files. I have Google-searched but many of the tutorials and examples are too complex for me because I am a novice programmer. The code below is inside a for loop which fetches the text ($RemoveTwo). It does not work as I need. Any help would be appreciated.
switch ($FileSizeCounter) {
case ($FileSizeCounter> 1500000):
$myFile2 = 'C:\TextCollector/'.'FilenameA'.'.txt';
$fh2 = fopen($myFile2, 'a') or die("can't open file");
fwrite($fh2, $RemoveTwo);
fclose($fh2);
break;
case ($FileSizeCounter> 3000000):
$myFile3 = 'C:\TextCollector/'.'FilenameB'.'.txt';
$fh3 = fopen($myFile3, 'a') or die("can't open file");
fwrite($fh3, $RemoveTwo);
fclose($fh3);
break;
default:
echo "continue and continue until it stops by the user";
}
Try doing something like this. You need to read from a source then write piece by piece all the while checking for end of file from the source. When you compare the max and buffer values, if they are true, then close the current file and open a new one with an auto-incremented numeric:
/*
** #param $filename [string] This is the source
** #param $toFile [string] This is the base name for the destination file & path
** #param $chunk [num] This is the max file size based on MB so 1.5 is 1.5MB
*/
function breakDownFile($filename,$toFile,$chunk = 1)
{
// Take the MB value and convert it into KB
$chunk = ($chunk*1024);
// Get the file size of the source, divide by kb
$length = filesize($filename)/1024;
// Put a max in bits
$max = $chunk*1000;
// Start value for naming the files incrementally
$i = 1;
// Open *for reading* the source file
$r = fopen($filename,'r');
// Create a new file for writing, use the increment value
$w = fopen($toFile.$i.'.txt','w');
// Loop through the file as long as the file is readable
while(!feof($r)) {
// Read file but only to the max file size value set
$buffer = fread($r, $max);
// Write to disk using buffer as a guide
fwrite($w, $buffer);
// Check the bit size of the buffer to see if it's
// same or larger than limit
if(strlen($buffer) >= $max) {
// Close the file
fclose($w);
// Add 1 to our $i file
$i++;
// Start a new file with the new name
$w = fopen($toFile.$i.'.txt','w');
}
}
// When done the loop, close the writeable file
fclose($w);
// When done loop close readable
fclose($r);
}
To use:
breakDownFile(__DIR__.'/test.txt',__DIR__.'/tofile',1.5);
I am trying to use a php call through AJAX to replace a single line of a .txt file, in which I store user-specific information. The problem is that if I use fwrite once getting to the correct line, it leaves any previous information which is longer than the replacement information untouched at the end. Is there an easy way to clear a single line in a .txt file with php that I can call first?
Example of what is happening - let's say I'm storing favorite composer, and a user has "Beethoven" in their .txt file, and want's to change it to "Mozart", when I used fwrite over "Beethoven" with "Mozart", I am getting "Mozartven" as the new line. I am using "r+" in the fopen call, as I only want to replace a single line at a time.
If this configuration data doesn't need to be made available to non-PHP apps, consider using var_export() instead. It's basically var_dump/print_r, but outputs the variable as parseable PHP code. This'd reduce your code to:
include('config.php');
$CONFIG['musician'] = 'Mozart';
file_put_contents('config.php', '<?php $CONFIG = ' . var_export($CONFIG, true));
This is a code I've wrote some time ago to delete line from the file, it have to be modified. Also, it will work correctly if the new line is shorter than the old one, for longer lines heavy modification will be required.
The key is the second while loop, in which all contents of the file after the change is being rewritten in the correct position in the file.
<?php
$size = filesize('test.txt');
$file = fopen('test.txt', 'r+');
$lineToDelete = 3;
$counter = 1;
while ($counter < $lineToDelete) {
fgets($file); // skip
$counter++;
}
$position = ftell($file);
$lineToRemove = fgets($file);
$bufferSize = strlen($lineToRemove);
while ($newLine = fread($file, $bufferSize)) {
fseek($file, $position, SEEK_SET);
fwrite($file, $newLine);
$position = ftell($file);
fseek($file, $bufferSize, SEEK_CUR);
}
ftruncate($file, $size - $bufferSize);
echo 'Done';
fclose($file);
?>