(last updated: )

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.

Web mentions

Comments

  • Josh

    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

    Michael Gauthier

    Great tip, thanks! I might use this to simplify some code I have that works with either IPC pipes or strings.
  • ellisgl

    ellisgl

    @Josh: Thanks for an awesome example of how to use it.
  • aparimana

    <p>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&amp;that')</p>
    • Evert

      Evert

      <p>I should really update this post, but I would _not_ recommend using the data:// url. Use php://memory and php://temp instead!</p>
      • Nicholas Ruunu

        <p>Is it possible to write initial data to a read only stream with php://temp?</p>
  • Markus

    <p>instead of base64_encode() in php which consumes a lot of php memory you should use</p><p><code>stream_filter_append($fh, 'convert.base64-encode');</code><br>which is not limited by php-memory limits AFAIK</p>
  • Jasmine Hegman

    <p>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)</p>
    • Evert

      Evert

      <p>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.</p>
      • Jasmine Hegman

        <p>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</p>
  • linoge

    <p>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;</p>
  • Matt Styles

    <p>Beautiful, thank you!</p>
  • Hugo Franco de Campos

    <p>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.</p>
  • rinogo

    <p>Thanks for your short examples on this, especially for the 2013 update! Exactly what I was looking for.</p>