Using a php://memory wrapper causes errors
Asked Answered
A

3

6

I'm trying to extend the PHP mailer class from Worx by adding a method which allows me to add attachments using string data rather than path to the file.

I came up with something like this:

public function addAttachmentString($string, $name='', $encoding = 'base64', $type = 'application/octet-stream')
{
  $path = 'php://memory/' . md5(microtime());
  $file = fopen($path, 'w');
  fwrite($file, $string);
  fclose($file);

  $this->AddAttachment($path, $name, $encoding, $type);
}

However, all I get is a PHP warning:

PHP Warning:  fopen() [<a href='function.fopen'>function.fopen</a>]: Invalid php:// URL specified

There aren't any decent examples with the original documentation, but I've found a couple around the internet (including one here on SO), and my usage appears correct according to them.

Has anyone had any success with using this?

My alternative is to create a temporary file and clean up - but that will mean having to write to disc, and this function will be used as part of a large batch process and I want to avoid slow disc operations (old server) where possible. This is only a short file but has different information for each person the script emails.

Amias answered 7/6, 2010 at 5:31 Comment(1)
I am waaay to late on this, but wouldn't memory buffers be deleted on fclose()?Frants
M
2

Quickly looking at http://php.net/manual/en/wrappers.php.php and the source code, I don't see support for the "/' . md5(microtime());" bit.

Sample Code:

<?php
print "Trying with md5\n";
$path = 'php://memory/' . md5(microtime());
$file = fopen($path, 'w');
if ($file)
{
    fwrite($file, "blah");
    fclose($file);
}
print "done - with md5\n";

print "Trying without md5\n";
$path = 'php://memory';
$file = fopen($path, 'w');
if ($file)
{
    fwrite($file, "blah");
    fclose($file);
}
print "done - no md5\n";

Output:

buzzbee ~$ php test.php 
Trying with md5

Warning: fopen(): Invalid php:// URL specified in test.php on line 4

Warning: fopen(php://memory/d2a0eef34dff2b8cc40bca14a761a8eb): failed to open stream: operation failed in test.php on line 4
done - with md5
Trying without md5
done - no md5
Momism answered 7/6, 2010 at 5:49 Comment(3)
hmm... yeah, i tried this as well - one problem I had is that I didn't get the content attached. That might be because phpmailer is using the wrong method for this thing... I have just realised that there is an AddStringAttachment method already in phpmailer (solves immediate problem) - but it's nice to learn about the php://memory wrapperAmias
$path = 'php://memory/' . md5(microtime()); breaks everything, you need to use $path = 'php://memory';Threw
its fails because you are closing file descriptor, as written in manual ! **php://memory and php://temp are not reusable, i.e. after the streams have been closed there is no way to refer to them again. ** use rewind($file); insteaf fclose($file); !Eton
D
20

It's just php://memory. For example,

<?php
    $path = 'php://memory';
    $h = fopen($path, "rw+");
    fwrite($h, "bugabuga");
    fseek($h, 0);
    echo stream_get_contents($h);

yields "bugabuga".

Distrustful answered 7/6, 2010 at 5:48 Comment(1)
remember that rewind($h); and fseek($h, 0); is same !Eton
M
2

Quickly looking at http://php.net/manual/en/wrappers.php.php and the source code, I don't see support for the "/' . md5(microtime());" bit.

Sample Code:

<?php
print "Trying with md5\n";
$path = 'php://memory/' . md5(microtime());
$file = fopen($path, 'w');
if ($file)
{
    fwrite($file, "blah");
    fclose($file);
}
print "done - with md5\n";

print "Trying without md5\n";
$path = 'php://memory';
$file = fopen($path, 'w');
if ($file)
{
    fwrite($file, "blah");
    fclose($file);
}
print "done - no md5\n";

Output:

buzzbee ~$ php test.php 
Trying with md5

Warning: fopen(): Invalid php:// URL specified in test.php on line 4

Warning: fopen(php://memory/d2a0eef34dff2b8cc40bca14a761a8eb): failed to open stream: operation failed in test.php on line 4
done - with md5
Trying without md5
done - no md5
Momism answered 7/6, 2010 at 5:49 Comment(3)
hmm... yeah, i tried this as well - one problem I had is that I didn't get the content attached. That might be because phpmailer is using the wrong method for this thing... I have just realised that there is an AddStringAttachment method already in phpmailer (solves immediate problem) - but it's nice to learn about the php://memory wrapperAmias
$path = 'php://memory/' . md5(microtime()); breaks everything, you need to use $path = 'php://memory';Threw
its fails because you are closing file descriptor, as written in manual ! **php://memory and php://temp are not reusable, i.e. after the streams have been closed there is no way to refer to them again. ** use rewind($file); insteaf fclose($file); !Eton
I
1

The problem here simply is the type and the syntax:

php://memory and php://temp are read-write streams that allow temporary data to be stored in a file-like wrapper. The only difference between the two is that php://memory will always store its data in memory, whereas php://temp will use a temporary file once the amount of data stored hits a predefined limit (the default is 2 MB). The location of this temporary file is determined in the same way as the sys_get_temp_dir() function.

In short, the type you want is temp instead and the syntax you want is:

php://temp/maxmemory:$limit

The $limit is in bytes. You want to count that using safe byte functions.

Inventory answered 31/5, 2016 at 12:57 Comment(2)
so if I use something like fopen('php://temp/maxmemory:1048576', 'w'), what will be my 'filepath' then? The whole "'php://temp/maxmemory:1048576'" ? I need this filepath to use in other functions. ThanksAzelea
@Azelea Check sys_get_temp_dir() … or even better: Open a new question, reference this question and answer there.Inventory

© 2022 - 2024 — McMap. All rights reserved.