What happens when php://temp is opened more than once? - php

If the php://temp (or php://memory) file is opened more than once, will the handles point to the same file? Or will each handle be unique?
I couldn't find an answer in the php docs, so I'm going to write up a test script to find out. I figured it's worth asking here so someone else can find the answer easily.

Each handle points to an independent stream. Example:
$a = fopen('php://memory', 'w+');
$b = fopen('php://memory', 'w+');
fwrite($a, 'foo');
fwrite($b, 'bar');
rewind($a);
rewind($b);
$a_text = stream_get_contents($a); //=> "foo"
$b_text = stream_get_contents($b); //=> "bar"
fclose($a);
fclose($b);
This is not explicitly documented anywhere, but it is implicit in the documentation for streams and wrappers.
From the official php documentation on streams in general, it is clear that for the standard case of streams, each file handle is associated with it's own independent stream.
And in the documentation on IO stream wrappers, it lists the possible wrappers noting exceptions as they occur. There is an exception listed for the first three (stdin, stdout, stderr):
php://stdin, php://stdout and php://stderr allow direct access to the
corresponding input or output stream of the PHP process. The stream
references a duplicate file descriptor, so if you open php://stdin and
later close it, you close only your copy of the descriptor-the actual
stream referenced by STDIN is unaffected.
But no such exception is listed for php://temp or php://memory. Hence it follows that these would work like normal independent streams.
Also, there are some comments on these pages that further imply the Independence of these streams.

My test code:
$f1 = fopen('php://temp', 'rw');
$f2 = fopen('php://temp', 'rw');
fputs($f1, "File One");
fputs($f2, "File Two");
rewind($f1);
echo "First line from F1: ";
echo fgets($f1) . PHP_EOL;
echo "Second line from F1: ";
echo fgets($f1) . PHP_EOL;
fclose($f1);
rewind($f2);
echo "First line from F2: ";
echo fgets($f2) . PHP_EOL;
echo "Second line from F2: ";
echo fgets($f2) . PHP_EOL;
fclose($f2);
And results:
First line from F1: File One
Second line from F1:
First line from F2: File Two
Second line from F2:

Related

How to get the size of a temp stream in PHP?

It seems like this ought to be really obvious, but I can't seem to find the answer anywhere. Assuming I create a stream using php://temp, how do I get the length of the data written?
$stream = fopen('php://temp', 'w+');
// ... do some processing here using fwrite, stream_copy_to_stream, stream_filter_append, etc ...
$num_bytes_in_stream = // What goes here?
php://temp uses a temporary file. The file is empty as long as nothing has been written. fopen expects at least 2 parameters. Mode "w+" can also be used in this case.
$stream = fopen('php://temp','r+');
var_dump(fstat($stream)['size']); //int(0)
$r = fputs($stream,'1234');
var_dump(fstat($stream)['size']); //int(4)
rewind($stream);
$str = fgets($stream,'1234');
var_dump($str, fstat($stream)['size']); //string(4) "1234" int(4)
Try self on https://3v4l.org/Hsodg

PHP File Handling (Download Counter) Reading file data as a number, writing it as that plus 1

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

how can i add email in one by one using read/write in php

how can i add email in one by one using read/write in php
Am getting the following output and create one folder called "update" update folder contain user entered one email is stored and user enter another email id already existing email id replaced to new email id why?
I need one by one email id called
apap#gmail.com
asadsd#gmail.com
here are my code please review
<form action="demo.php" method="post">
<input type="text" name="textEmail">
<input type="submit" value="send">
</form>
Demo.php file are
<?php
// Open the text file
$f = fopen("update.txt", "w");
// Write text
$text = strtr(" ",' ', $_POST['textEmail']);
fwrite($f,$text);
//fwrite($f,$text);
// Close the text file
fclose($f);
// Open file for reading, and read the line
$f = fopen("update.txt", "r");
// Read text
echo fgets($f);
fclose($f);
?>
Open the file in append mode instead of write mode
replace "w" with "a"
$f = fopen("update.txt", "a");
From: http://php.net/manual/en/function.fopen.php
'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it.
'a' Open for writing only; place the file pointer at the end of the file. If the file does not exist, attempt to create it...
Open your file as append mode so that you not need to open the file twice, for writing in the file, for you one email per line you need to use the \n after each email. For reading use the while loop to read end of the file and use fgets to make sure it reads the whole line at a time.
$myfile = fopen("update.txt", "a+");
$txt = $_POST['textEmail']."\n";
fwrite($myfile, $txt);
while(!feof($myfile)) {
echo fgets($myfile) . "<br/>";
}
fclose($myfile);
Documentation: php_file_create and php_file_open
I am unsure on what you are trying to achieve but I will clarify the difference between file write and file append.
Writing to a file when opened in 'w' mode writes from the current file pointer position which when open in 'w' mode is the very beginning of the file, to change this position in this mode use the fseek() method.
Writing to a file when opened in 'a' mode (append mode) will set the file pointer to the last location in the file and in php specifically will always when fwrite() is called will write to the end of the file.
Append File Example
Contents of update.txt before write:
sometext
sometext2
Code that writes to file
$f = fopen('update.txt', 'w');
//Description of 'a' mode from php manual
//Open for writing only; place the file pointer at the end of the file.
//If the file does not exist, attempt to create it. In this mode,
//fseek() has no effect, writes are always appended.
fwrite($f, "somevalue" . "\n");
fclose($f);
Results In an update.txt with contents:
sometext
sometext2
somevalue
Php doc on functions used in this example:
fopen()
fwrite()
<?php
if ($_POST['textEmail'] != '') {
$text = str_replace(" ", ' ', $_POST['textEmail']);
$pattern = '/([a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})/';
preg_match_all($pattern,file_get_contents("update.txt"), $matches);
$emails = $matches[0]; // get Array of all email in file
if (!in_array($text, $emails)) { // echck for existing email
file_put_contents("update.txt", PHP_EOL.$_POST['textEmail'], FILE_APPEND);
}else{
echo 'Email address alerady exist';
}
echo $f = file_get_contents("update.txt");
}
?>
Would you please try this for demo.php ?

Trying to understand the difference between /dev/stdin and php://stdin

As a simple proof of concept, I tried to share a string between forked processes from node to node or from node to php.
Take this simple php code that should log the output of stdin according to the php docs:
echo 'test' | php -r 'echo trim(fgets(STDIN));'
Working fine, but when I'm spawning the process from nodejs:
spawner.js
var fs = require('fs'); var spawn = require('child_process').spawn;
//dummy stdin file
var stdin = fs.openSync('stdin_file', 'w+');
//write the string
fs.writeSync(stdin, 'test');
spawn('php', ['stdin_test.php'], {
cwd: __dirname,
detached: true,
//to fully detach the process nothing should be piped from or to the parent process
stdio: [stdin, fs.openSync('out.log', 'a'), fs.openSync('err.log', 'a')]
})
stdin_test.php
<?php
error_log('php://stdin');
//this should log 'test' but outputs a newline
error_log(trim(fgets(STDIN)));
$t = fopen('/dev/stdin', 'r');
error_log('/dev/stdin:');
//this is working as expected
error_log(trim(fgets($t)));
Why is php://stdin empty? Is it safe to use /dev/stdin? What is the difference between /dev/stdin and php://stdin anyway?
Note that I have this behavior between 2 node processes too: process.stdin is empty but /dev/stdin has the expected result.
Gist available here
stdin man reference
I tested with the following script ( stdin_test.php ) using:
> echo test | php stdin_test.php
stdin_test.php
<?
echo 'STDIN :' ;
echo trim(fgets(STDIN)) ;
echo PHP_EOL;
$stdin_stream = fopen('php://stdin', 'r');
echo 'php://stdin :';
echo trim(fgets($stdin_stream));
echo PHP_EOL;
fclose($stdin_stream);
$stdin_file = fopen('/dev/stdin', 'r');
echo '/dev/stdin :';
echo trim(fgets($stdin_file));
echo PHP_EOL;
fclose($stdin_file);
I get back :
STDIN :test
php://stdin :
/dev/stdin :
If I then comment out the line:
//echo trim(fgets(STDIN));
I get back:
STDIN :
php://stdin :test
/dev/stdin :
If I comment out both of the first stdin echoes (and the file handler pointers), I get:
STDIN :
php://stdin :
/dev/stdin : test
Looking at documentation on php://input and how it is one-time usable unless (after 5.6) "the request body is saved" which is typical for POST requests but not PUT requests (apparently). This has me thinking that they are called "streams" because you get to walk in them once.
Rewind your stdin stream in JS before spawning PHP, else the file pointer will sit at the end of what you just wrote.

Append at the beginning of the file in PHP [duplicate]

This question already has answers here:
Need to write at beginning of file with PHP
(10 answers)
Closed 9 years ago.
Hi I want to append a row at the beginning of the file using php.
Lets say for example the file is containing the following contnet:
Hello Stack Overflow, you are really helping me a lot.
And now i Want to add a row on top of the repvious one like this:
www.stackoverflow.com
Hello Stack Overflow, you are really helping me a lot.
This is the code that I am having at the moment in a script.
$fp = fopen($file, 'a+') or die("can't open file");
$theOldData = fread($fp, filesize($file));
fclose($fp);
$fp = fopen($file, 'w+') or die("can't open file");
$toBeWriteToFile = $insertNewRow.$theOldData;
fwrite($fp, $toBeWriteToFile);
fclose($fp);
I want some optimal solution for it, as I am using it in a php script. Here are some solutions i found on here:
Need to write at beginning of file with PHP
which says the following to append at the beginning:
<?php
$file_data = "Stuff you want to add\n";
$file_data .= file_get_contents('database.txt');
file_put_contents('database.txt', $file_data);
?>
And other one here:
Using php, how to insert text without overwriting to the beginning of a text file
says the following:
$old_content = file_get_contents($file);
fwrite($file, $new_content."\n".$old_content);
So my final question is, which is the best method to use (I mean optimal) among all the above methods. Is there any better possibly than above?
Looking for your thoughts on this!!!.
function file_prepend ($string, $filename) {
$fileContent = file_get_contents ($filename);
file_put_contents ($filename, $string . "\n" . $fileContent);
}
usage :
file_prepend("couldn't connect to the database", 'database.logs');
My personal preference when writing to a file is to use file_put_contents
From the manual:
This function is identical to calling fopen(), fwrite() and fclose()
successively to write data to a file.
Because the function automatically handles those three functions for me I do not have to remember to close the resource after I'm done with it.
There is no really efficient way to write before the first line in a file. Both solutions mentioned in your questions create a new file from copying everything from the old one then write new data (and there is no much difference between the two methods).
If you are really after efficiency, ie avoiding the whole copy of the existing file, and you need to have the last inserted line being the first in the file, it all depends how you plan on using the file after it is created.
three files
Per you comment, you could create three files header, content and footer and output each of them in sequence ; that would avoid the copy even if header is created after content.
work reverse in one file
This method puts the file in memory (array).
Since you know you create the content before the header, always write lines in reverse order, footer, content, then header:
function write_reverse($lines, $file) { // $lines is an array
for($i=count($lines)-1 ; $i>=0 ; $i--) fwrite($file, $lines[$i]);
}
then you call write_reverse() first with footer, then content and finally header. Each time you want to add something at the beginning of the file, just write at the end...
Then to read the file for output
$lines = array();
while (($line = fgets($file)) !== false) $lines[] = $line;
// then print from last one
for ($i=count($lines)-1 ; $i>=0 ; $i--) echo $lines[$i];
Then there is another consideration: could you avoid using files at all - eg via PHP APC
You mean prepending. I suggest you read the line and replace it with next line without losing data.
<?php
$dataToBeAdded = "www.stackoverflow.com";
$file = "database.txt";
$handle = fopen($file, "r+");
$final_length = filesize($file) + strlen($dataToBeAdded );
$existingData = fread($handle, strlen($dataToBeAdded ));
rewind($handle);
$i = 1;
while (ftell($handle) < $final_length)
{
fwrite($handle, $dataToBeAdded );
$dataToBeAdded = $existingData ;
$existingData = fread($handle, strlen($dataToBeAdded ));
fseek($handle, $i * strlen($dataToBeAdded ));
$i++;
}
?>

Categories