In PHP, is there a way to pipe or stream the contents of one "file" to another?
Here's what I'm doing now,
$rfp = fopen('php://input', 'r');
$wfp = fopen($this->file_path, 'x');
while(!feof($rfp)) {
fwrite($wfp, fread($rfp, 1048576));
}
fclose($wfp);
fclose($rfp);
Which works fine, but it seems funny to read an arbitrary chunk from the input stream before writing it to the output stream. I'd imagine the file system or OS could do it a bit more efficiently if I could just tell it to read from one place and send it straight to another.
In Node you can 'pipe' one file stream to another. Is there a function for this in PHP?
try
copy("php://input", $this->file_path);
or second method:
$objStream = fopen("php://input", "r");
$dest = fopen($this->file_path, 'x');
stream_copy_to_stream($objStream , $dest);
Related
I have this code on PHP that load a local file:
$filename = "fille.txt";
$fp = fopen($filename, "rb");
$content = fread($fp, 25699);
fclose($fp);
print_r($content);
With this code I can see all the contents of the file. But when I change the $filename to a external link, like:
$filename = "https:/.../texts/fille.txt";
I can't see all the contents of the file, he appears cut to me. Whats the problem?
The fread() function can be used for network operations. But network connections work different than file system operations. A network cannot read a bigger file in a single attempt, that is not how typical networks work. Instead they work package based. So data arrives in chunks.
And if you take a look into the documentation of the function you use then you will see that:
Reading stops as soon as one of the following conditions is met:
[...]
a packet becomes available or the socket timeout occurs (for network streams)
[...]
So what you observe actually is documented behavior. You need to continue to read packages in a loop to get the whole file. Until you received an EOF.
Take a look yourself: https://www.php.net/manual/en/function.fread.php
And further down in that documentation you will see that example:
Example #3 Remote fread() examples
<?php
$handle = fopen("http://www.example.com/", "rb");
if (FALSE === $handle) {
exit("Failed to open stream to URL");
}
$contents = '';
while (!feof($handle)) {
$contents .= fread($handle, 8192);
}
fclose($handle);
?>
I have the contents of a file in a string. I need to pass this file to a function where the function is expecting the parameter to be the name of the file, not the contents. The obvious and probably simplest way to do this would be to write the contents to a temp file, then pass that file name to the function, and unlink the file once I'm finished.
However, I'm looking for a solution that doesn't involve writing the file out to the file system and then reading it back in. I've had a need for this in multiple cases, so I'm not looking for a work-around to a specific function, but more of a generic method that will work for any function expecting a file name (like file_get_contents(), for instance).
Here are some thoughts, but not sure how to pursue these yet:
Is it possible to write the contents somewhere in memory, and then
pass that to the function as a filename? Perhaps something using
php://memory.
Is it possible to write the contents to a pipe, then pass the name of the
pipe to the function?
I did a short proof-of-concept trying with php://memory as follows, but no luck:
$data = "This is some file data.\n";
file_put_contents( 'php://memory', $data );
echo file_get_contents( 'php://memory' );
Would be interested in knowing of good ways to address this. Googling hasn't come up with anything for me.
It mainly depends on what the target function does with the file name. If you're lucky, you can register your own stream wrapper:
stream_wrapper_register('demo', 'DemoStream');
$data = "This is some file data.\n";
$filename = 'demo://foo';
file_put_contents($filename, $data );
echo file_get_contents($filename);
Why not use a file in the /tmp/ directory? Like this:
<?php
$filename = '/tmp/mytmpfile';
$data = "This is some file.\n";
file_put_contents($filename, $data);
$result = file_get_contents($filename);
var_dump($result);
Well, as you say you don't want to use a file, you shouldn't use file_get_contents().
But you can achieve the same result by using stream_get_contents(), like this:
<?php
$data = "This is some file data.\n";
$handle = fopen('php://memory', 'r+'); // open an r/w handle to memory
fputs($handle, $data); // write the data
rewind($handle); // rewind the pointer
echo stream_get_contents($handle); // retrieve the contents
One of our systems is running on PHP 4 and no I can't change that.
The fgetcsv function seems to return null no matter what file I upload.
Very simply put:
$handle = fopen($file,"r");
var_dump(fgetcsv($handle));
fclose($handle);
This will print out "NULL".
Doing var_dump on the $handle object does give me a resource:
resource(33) of type (stream)
But I just get NULL when using fgetcsv
I can get the contents of the file using file_get_contents, but then it's more awkawrd to parse it as a csv.
As I say, I can't really do anything about it being on PHP 4. Does anyone know what might be causing this, or shall I find another way?
Thanks
Your original issue may be related to temporary uploaded file usage.
Try to open it after move_uploaded_file
Also, fseek($handle, 0) can help theoretically, because it was read already anywhere.
I can get the contents of the file using file_get_contents
You can try to use tmpfile then:
$csv = file_get_contents($file);
$temp = tmpfile();
fwrite($temp, $csv);
fseek($temp, 0); // prepare for read at start
$data = fgetcsv($temp);
fclose($temp); // file autoremoved here
I was curious to do a test. My question is if is it possible to open file for both reading and writing, so if I have more read-write operations to do on one file I do not need to close the reading status, read, open for write status, write and so on in a loop.
$filename = "test.txt";
$handle = fopen($filename, "rwb");
fseek( $handle , 15360 );
$contents = fread($handle, 51200);
$start = microtime (true);
fseek( $handle , 1 );
fwrite ( $handle , $contents );
fclose($handle);
This test does not work. I expected, I will read the data and move the fseek pointer to begin of the file either 1 or 0 position and then I will write the data. But this action failed for some reason with a result 0 (int) bytes written. Hence my question is, is it possible to do it? Or I need to close file for reading first?
As a related sub-question - is it possible that more users can read or write from files simultaneously from different position. As this should simulate database read/write operations. You know how mysql works - more users can write same table - same file any time. I know this is not problem in C/C++ but is it possible to do it in php?
You can create multiple file handlers on the same file. Just fopen() it twice, one with read only, the other with read/write. Although I'm not sure why you'd want to do so unless you're reading and writing from two different point in the file.
$filename = "test.txt";
$rw_handle = fopen($filename, "c+"); //open for read/write, allow fseek
$r_handle = fopen($filename, "r");
If you want to have multiple processes reading and writing a file from different locations, you'll want to file lock with flock()
I'm creating a class that will store data in a file and I need to know if it's possible to do multiple read/writes using one file handle?
I've done some experiments, and using this code:
$file_name = 'test.txt';
$file = fopen($file_name, 'r+');
echo fread($file, filesize($file_name)) . "<hr />";
fwrite($file, "|".rand());
echo fread($file, filesize($file_name));
fclose($file);
The file gets read the first time, the write works, but the second fread is blank.
Using this code:
$file_name = 'test.txt';
$file = fopen($file_name, 'r+');
echo fread($file, filesize($file_name)) . "<hr />";
fwrite($file, "|".rand());
fclose($file);
$file = fopen($file_name, 'r+');
echo fread($file, filesize($file_name));
fclose($file);
The second fread then works, but it doesn't contain the data that was appended to it in the fwrite just above it.
So basically, I want to create a single file handle as a property of the class, and have it's methods refer to it when reading and writing, but including any changes that other methods might've made to the data.
I do have 2 alternatives if this isn't possible, one being opening and closing the file handle in each method but this seems really inefficient and I'm not sure what a single file open/close 'costs' in terms of performance. The other alternative is that the data is being converted into array for easy manipulation, I could update the array rather than the file every time but then when would I update the file?
Check out fseek to move your pointer within the file and read from there, fread and fwrite are moving that pointer forward.
And you have to use a+ instead of r+, see: the mode of fopen