Creating streams from strings in PHP
I’m in the process of writing an API that relies on (file-)streams to be passed around.
There are situations where a string instead needs to be used, and for these purposes the data: stream wrapper is used. Initially I thought it was only possible to encode the actual string in base64, which I didn’t like because of the added footprint.
<?php
$string = "I should have really done some laundry tonight.";
$stream = fopen('data://text/plain;base64,' . base64_encode($string),'r');
echo stream_get_contents($stream);
?>
Quickly checking out the rfc, it turns out that ‘;base64’ can be omitted to just pass along the raw data, which makes a lot more sense in the context of PHP.
Thankfully, PHP gladly supports it:
<?php
$string = "I tried, honestly!";
$stream = fopen('data://text/plain,' . $string,'r');
echo stream_get_contents($stream);
?>
Update June 23th, 2013
Just in case anyone stumbles upon this, I would no longer recommend using the data uri for this purpose.
Since PHP 5.1 we have php://memory
and php://temp
. The former keeps the
entire string into memory, and the latter automatically writes to a file as
soon as the stream exceeds a certain amount of memory.
This is how you use it:
<?php
$string = 'Some bad-ass string';
$stream = fopen('php://memory','r+');
fwrite($stream, $string);
rewind($stream);
echo stream_get_contents($stream);
A bit more info can be found on php.net.
Comments
Josh •
My favorite usage of the data: wrapper is for raw uploaded csv data. If you let user's cut-n-paste a csv for upload you can use the data: wrapper to fopen the POST data then fgetcsv() on it to save yourself from parsing it manually.Michael Gauthier •
Great tip, thanks! I might use this to simplify some code I have that works with either IPC pipes or strings.ellisgl •
@Josh: Thanks for an awesome example of how to use it.aparimana •
remember to urlencode() your $string before passing it to fopen - PHP will always urldecode(), to serve the data up, which will cause problems if your input data happens to contain sequences that look like URL encoded characters ( eg input string 'this%26that' will be output 'this&that')
Evert •
I should really update this post, but I would _not_ recommend using the data:// url. Use php://memory and php://temp instead!
Nicholas Ruunu •
Is it possible to write initial data to a read only stream with php://temp?
Markus •
instead of base64_encode() in php which consumes a lot of php memory you should use
stream_filter_append($fh, 'convert.base64-encode');
which is not limited by php-memory limits AFAIK
Jasmine Hegman •
Thank you for this fine article w/ update! I know this is old and sort of minor but in your last code example you open the php://memory string with 'r+' and then write to it -- I think that should be 'w+' :o)
Evert •
r+ actually works too. Judging from the documentation is looks like the only difference is that w+ creates a new file if it doesn't already exist, but that's not really relevant here.
Jasmine Hegman •
Oh you are so right, I don't know what I was thinking! I guess my brain decided to pretend the + symbol was meaningless. :3
linoge •
Thank you very much for the article, I was looking exactly for this, and it's such a nice thing that you added the update c;
Matt Styles •
Beautiful, thank you!
Hugo Franco de Campos •
Is there any concern about keep large strings in memory using fopen? I'm sending a large csv string to a file storage and I have no idea if I should use memory, temp or anything else.
rinogo •
Thanks for your short examples on this, especially for the 2013 update! Exactly what I was looking for.