PHPMailer - attach remote file with URL
Asked Answered
C

4

12

PHPMailer checks is_file for every attachment (in addAttachment function, in class.phpmailer.php file):

if (!@is_file($path)) {
    throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
}

My problem is that I can make work is_file only giving full local path to file, not URLs:

is_file('C:/wamp/www/myFolder/rocks.png');      //True
is_file('http://localhost/myFolder/rocks.png'); //False :(

So I can't attach any file from the remote server.

What am I doing wrong?? It can be a permission issue?

EDIT:

I know that there are other ways to check if file exists.

But is_file is in the PhpMailer library, I prefer to not touch it and I want to know if it's possible to make it work using its methods.

Thanks.

Cricket answered 10/12, 2014 at 16:6 Comment(7)
It is cheaper to use get_headers to check remote file existence.Lavonna
@Jordy that's exactly what I am talking about.Lavonna
@baldrs: I know that there are better ways to check if file exists, but this is written in the PhpMailer function. I would know how it can work. Or it's a PhpMailer issue?Cricket
Tip As of PHP 5.0.0, this function can also be used with some URL wrappers. Refer to Supported Protocols and Wrappers to determine which wrappers support stat() family of functionality.Windpipe
HTTP has no concept of file vs. directory, so is_file() / is_dir() results are undefined ...Imf
@Cricket then you should preload your attachments if they are remote and then replace them as if they were local onesLavonna
@Cricket your solution will only work on your own server, and even there it is quite doubtful. 100% working solution is to check existence of remote resource, valuidate it, download to a temporary location, attach it, send it and then wipe it out. Will work for any accessible url.Lavonna
D
27

It doesn't need a workaround, you're just using a function explicitly intended for local files on a remote resource. This is a deliberate choice by PHPMailer because it dos not want to act as an HTTP client – that's an entirely separate job better handled by other code. To attach a remote resource without involving local files, just do this:

$mail->addStringAttachment(file_get_contents($url), 'filename');

While this makes the HTTP request your responsibility (as PHPMailer intends), I would not recommend this direct inline approach because it makes error handling more difficult (e.g. if the URL fails to respond).

This is essentially a duplicate of this question.

Downy answered 10/12, 2014 at 17:37 Comment(1)
Used this, worked like a charm. Hats-off to you!Proctoscope
H
1

Later in code it uses file_get_contents() to include the attachment's contents. While file_get_contents() supports HTTP, is_file() doesn't.

Given you don't want to alter PhpMailer, you'll have to download the file from HTTP yourself and provide the temporary path to PhpMailer. After sending you can delete the temporary file.

Something like this (from PHP manual: sys_get_temp_dir and Download File to server from URL):

$attachmentUrl = "http://example.com/image.jpg";
$tempFile = tempnam(sys_get_temp_dir(), 'mailattachment');  
file_put_contents($tempFile, $attachmentUrl);

Then you can attach $tempFile, send your mail and unlink($tempFile).

Hausner answered 10/12, 2014 at 17:0 Comment(3)
Thank you! I'll test your code even though I've found a solution (see my answer). What I can't understand is if I'm using this library in a wrong way, or all those who use it have this problem..Cricket
It gives me two errors: Warning: tempnam() [function.tempnam]: SAFE MODE Restriction in effect. The script whose uid is 10328 is not allowed to access /tmp owned by uid 0 for the second line, and Warning: file_put_contents() [function.file-put-contents]: Filename cannot be empty for the third...Cricket
I don't know what the best practice is. Perhaps create a writable directory under your www-root instead of using sys_get_temp_dir().Hausner
J
0

Quoting from the PHP docs:

As of PHP 5.0.0, this function can also be used with some URL wrappers. Refer to Supported Protocols and Wrappers to determine which wrappers support stat() family of functionality.

Of the standard streams, the following support stat()

  • file:// — Accessing local filesystem
  • php:// — Accessing various I/O streams
    • php://memory
    • php://temp
  • phar:// — PHP Archive
  • ssh2:// — Secure Shell 2
    • ssh2.sftp
  • rar:// — RAR

and the following do not

  • http:// — Accessing HTTP(s) URLs
  • zlib:// — Compression Streams
  • data:// — Data (RFC 2397)
  • glob:// — Find pathnames matching pattern
  • ssh2:// — Secure Shell 2
    • ssh2.shell
    • ssh2.exec
    • ssh2.tunnel
    • ssh2.scp
  • ogg:// — Audio streams
  • expect:// — Process Interaction Streams

While the following are limited

  • ftp:// — Accessing FTP(s) URLs
    • filesize()
    • filetype()
    • file_exists()
    • is_file()
    • is_dir()
    • filemtime() — since PHP 5.1.0
Jejune answered 10/12, 2014 at 16:22 Comment(2)
Nothing to do with version.... you're trying to access http://localhost/myFolder/rocks.png but the http:// stream does not support stat(), so is_file() is not possible with that urlJejune
So for you it can be a PhpMailer issue?Cricket
E
0

I'm just a beginner in web development, maybe I'm wrong, but I have this code working:

$filePath1 = __DIR__  . "/files/" . $_FILES['foto-item']['name'];

__DIR__ indicates the absolute path to the file. It works on both local and remote servers.

Emigrant answered 22/3, 2023 at 21:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.