Text file-based sequential url rotator isn't working - php

I'm trying to create a text file-based sequential url rotator by using the following code (original source):
<?php
$linksfile ="urlrotator.txt";
$posfile = "pos.txt";
$links = file($linksfile);
$numlinks = count($linksfile);
$fp = fopen($posfile, 'r+') or die("Failed to open posfile");
flock($fp, LOCK_EX);
$num = fread($fp, 1024);
if($num<$numlinks-1) {
fwrite($fp, $num+1);
} else {
fwrite($fp, 0);
}
flock($fp, LOCK_UN);
fclose($fp);
header("Location: {$links[$num]}");
?>
After my testing, I found that it keeps appending new position number as a string after the existing content of pos.txt and thus the script only works at the first time.
I tried adding the following line of code before the if else statement in order to clear the existing content of pos.txt before updating it.
file_put_contents($posfile, "");
But then error ocurred at the line of redirection saying Undefined index: ...... .
Where could possibly go wrong?

I believe your problem comes from the mode you are using. When you say
After my testing, I found that it keeps appending new position number as a string after the existing content of pos.txt and thus the script only works at the first time.
it points me to the mode usage of fopen.
The mode you should use is w, as it will "replace" the content of what is inside pos.txt.
$fp = fopen($posfile, 'w') or die("Failed to open posfile");
Doing so will prevent your from accessing what was in pos.txt. So you need to have something like this:
$num = file_get_contents($posfile);
$fp = fopen($posfile, 'w') or die("Failed to open posfile");
flock($fp, LOCK_EX);
if($num<$numlinks-1) {
fwrite($fp, $num+1);
} else {
fwrite($fp, 0);
}
flock($fp, LOCK_UN);
fclose($fp);

Related

No errors, but fwrite() won't write to file

I've been following PHP and MySQL Web Development 5th edition, but I'm stuck on Chapter 2 because I cannot write to a file.
Here's the code:
// open file for appending
$fp = fopen('orders.txt', 'ab', true);
if (!$fp) {
echo "<p><strong> Your order could not be processed at this time.
Please try again later.</strong></p>";
exit;
}
flock($fp, LOCK_EX);
$bytes = fwrite($fp, $outputstring, strlen($outputstring));
echo $bytes;
flock($fp, LOCK_UN);
fclose($fp);
The echo gives me 65, which seems right, but orders.txt is always completely blank. Could someone give me some advice? I'm using Webstorm with a server hosted on GoDaddy if that matters.
Perhaps you meant
$fp = fopen('orders.txt', 'a', true);
instead of
$fp = fopen('orders.txt', 'ab', true);
Note that you can also use the 'w' mode instead of 'a' if you would like to overwrite the file instead of appending at the end of it.

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.

Create CSV File in PHP and Save to SFTP using phpseclib

I need to generate a CSV file from a MySQL query and save the file to an SFTP server. I have tried the code below. The CSV file gets created, but it is empty. I also receive an error message in the browser that says Warning: is_file() expects parameter 1 to be a valid path, resource given in regard to this line $sftp->put($fileName, $fp, NET_SFTP_LOCAL_FILE);. If I move fclose($fp); to the last line, I don't get the error but data still doesn't appear in the file. Could someone please let me know how to get the data to save in the file that was created?
$fileName = 'dataFiles/reports/Report Summary/Report Summary.csv';
$sql = mysqli_query($db, "
SELECT *
FROM reports
WHERE reportID = 1
");
$fp = fopen('php://output', 'w');
$first = true;
while($row = mysqli_fetch_assoc($sql)){
if ($first) {
fputcsv($fp, array_keys($row));
$first = false;
}
fputcsv($fp, $row);
}
fclose($fp);
$sftp->put($fileName, $fp, NET_SFTP_LOCAL_FILE);
Try something like this:
<?php
$fp = fopen('php://temp', 'r+');
// do stuff
rewind($fp);
$sftp->put($filename, $fp);
phpseclib (assuming you're using a new enough version) will detect that the second parameter is a stream resource and will try to read from it accordingly.
The second argument is not a handle but the content directly.
I think you could do: stream_get_contents($fp); in the second argument.
$content = stream_get_contents($fp);
fclose($fp);
$sftp->put($fileName, $content, NET_SFTP_LOCAL_FILE);

php counter for webpage with GET variable for each page variable

i use this
<?php $handle = fopen("counter.txt", "r"); if(!$handle){
echo "could not open the file" ; } else {
$counter = (int ) fread($handle,20);
fclose ($handle);
$counter++;
echo" <strong> you are visitor no ". $counter . " </strong> " ; $handle = fopen("counter.txt", "w" ); fwrite($handle,$counter) ;
fclose ($handle) ;
} ?>
but its makes a counter for the page tst.php every entry.
i want to make counting for this page tst.php?id=1
but if i change to tst.php?id=2 to store this data to but from zero and counting.
and then return to tst,php?id=1 and showing the continuing counting of visits to this page.
and the another tst.php?id=....
for every id page!
You can try something like:
<?php
$const='counter';
$id=$_GET['id'];
$ext='.txt';
if(file_exists($const.$id.$ext))
{
$file=fopen($const.$id.$ext,'r');
$data=fread($file,filesize($const.$id.$ext));
fclose($file);
$file=fopen($const.$id.$ext,'w');
fwrite($file,$data+1);
}
else
{
$file=fopen($const.$id.$ext,'w+');
fwrite($file,1);
fclose($file);
}
?>
This will create files for each 'id' that you pass in the url.
Copy the above code in file for ex: counter.php and include in the file wherever the counter is required as :
<?php
include "counter.php"
?>
Hope this resolves your issue!
Each time a page is loaded, consider using parse_url() to determine the end query string. Enter that into your file.
$query = parse_url($url, PHP_URL_QUERY);
Try following code, which will work same way as your code except storing counter for individual id in individual file:
$fp = fopen("counter.txt".$_GET["id"], "r+");
while(!flock($fp, LOCK_EX)) { // acquire an exclusive lock
// waiting to lock the file }
$counter = intval(fread($fp, filesize("counter.txt".$_GET["id"]))); $counter++;
ftruncate($fp, 0); // truncate file fwrite($fp, $counter); // set your data fflush($fp); // flush output before releasing the lock flock($fp, LOCK_UN); // release the lock
fclose($fp);
I think you want a separate counter for every page.
If yes, here is an edited version of your code:
$fp = fopen('counter'.intval($_GET['id']).'.txt', 'r+');
while(!flock($fp, LOCK_EX)) { // acquire an exclusive lock
// waiting to lock the file
}
$counter = intval(fread($fp, filesize('counter'.intval($_GET['id']).'.txt'))); $counter++;
ftruncate($fp, 0); // truncate file
fwrite($fp, $counter); // set your data
fflush($fp); // flush output before releasing the lock
flock($fp, LOCK_UN); // release the lock
fclose($fp);
I put the id into the filename.
Edit:
To make it in one counter.txt file(it is inefficient):
$fh = fopen('counter.txt', 'c+'); //Open file
while(!flock($fh, LOCK_EX)) {} //Lock file
$var = json_decode(fread($fh, filesize('counter.txt'))); //Json decode file to array
if(isset($var)) $var[(int)$_GET['id']]++; else $var[(int)$_GET['id']] = 1; //Increment the id's array value by one
ftruncate($fh, 0); //Erase file contents
fwrite($fh, json_encode($var)); //Write json encoded array
fflush($fh); //Flush to file
flock($fh, LOCK_UN); //Unlock file
fclose($fh); //Close file
But as said by h2ooooooo, a DB based solution will be better.(I will write it if you want)

Using php, how to insert text without overwriting to the beginning of a text file

I have:
<?php
$file=fopen(date("Y-m-d").".txt","r+") or exit("Unable to open file!");
if ($_POST["lastname"] <> "")
{
fwrite($file,$_POST["lastname"]."\n");
}
fclose($file);
?>
but it overwrites the beginning of the file. How do I make it insert?
I'm not entirely sure of your question - do you want to write data and not have it over-write the beginning of an existing file, or write new data to the start of an existing file, keeping the existing content after it?
To insert text without over-writing the beginning of the file, you'll have to open it for appending (a+ rather than r+)
$file=fopen(date("Y-m-d").".txt","a+") or exit("Unable to open file!");
if ($_POST["lastname"] <> "")
{
fwrite($file,$_POST["lastname"]."\n");
}
fclose($file);
If you're trying to write to the start of the file, you'll have to read in the file contents (see file_get_contents) first, then write your new string followed by file contents to the output file.
$old_content = file_get_contents($file);
fwrite($file, $new_content."\n".$old_content);
The above approach will work with small files, but you may run into memory limits trying to read a large file in using file_get_conents. In this case, consider using rewind($file), which sets the file position indicator for handle to the beginning of the file stream.
Note when using rewind(), not to open the file with the a (or a+) options, as:
If you have opened the file in append ("a" or "a+") mode, any data you write to the file will always be appended, regardless of the file position.
A working example for inserting in the middle of a file stream without overwriting, and without having to load the whole thing into a variable/memory:
function finsert($handle, $string, $bufferSize = 16384) {
$insertionPoint = ftell($handle);
// Create a temp file to stream into
$tempPath = tempnam(sys_get_temp_dir(), "file-chainer");
$lastPartHandle = fopen($tempPath, "w+");
// Read in everything from the insertion point and forward
while (!feof($handle)) {
fwrite($lastPartHandle, fread($handle, $bufferSize), $bufferSize);
}
// Rewind to the insertion point
fseek($handle, $insertionPoint);
// Rewind the temporary stream
rewind($lastPartHandle);
// Write back everything starting with the string to insert
fwrite($handle, $string);
while (!feof($lastPartHandle)) {
fwrite($handle, fread($lastPartHandle, $bufferSize), $bufferSize);
}
// Close the last part handle and delete it
fclose($lastPartHandle);
unlink($tempPath);
// Re-set pointer
fseek($handle, $insertionPoint + strlen($string));
}
$handle = fopen("file.txt", "w+");
fwrite($handle, "foobar");
rewind($handle);
finsert($handle, "baz");
// File stream is now: bazfoobar
Composer lib for it can be found here
You get the same opening the file for appending
<?php
$file=fopen(date("Y-m-d").".txt","a+") or exit("Unable to open file!");
if ($_POST["lastname"] <> "")
{
fwrite($file,$_POST["lastname"]."\n");
}
fclose($file);
?>
If you want to put your text at the beginning of the file, you'd have to read the file contents first like:
<?php
$file=fopen(date("Y-m-d").".txt","r+") or exit("Unable to open file!");
if ($_POST["lastname"] <> "")
{
$existingText = file_get_contents($file);
fwrite($file, $existingText . $_POST["lastname"]."\n");
}
fclose($file);
?>

Categories