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.

T30
  • 11,422
  • 7
  • 53
  • 57
  • 1
    It is cheaper to use `get_headers` to check remote file existence. – baldrs Dec 10 '14 at 16:08
  • @Jordy that's exactly what I am talking about. – baldrs Dec 10 '14 at 16:09
  • @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? – T30 Dec 10 '14 at 16:12
  • 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. – Anthony Dec 10 '14 at 16:18
  • HTTP has no concept of file vs. directory, so is_file() / is_dir() results are undefined ... – Hartmut Holzgraefe Dec 10 '14 at 16:22
  • @T30 then you should preload your attachments if they are remote and then replace them as if they were local ones – baldrs Dec 10 '14 at 17:10
  • @T30 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. – baldrs Dec 10 '14 at 17:24

4 Answers4

26

It doesn't need a workaround, you're just using a function explicitly intended for local files on a remote resource. To attach a remote resource without involving local files, just do this:

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

I would not recommend this directly 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.

Community
  • 1
  • 1
Synchro
  • 35,538
  • 15
  • 81
  • 104
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).

Community
  • 1
  • 1
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • 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.. – T30 Dec 10 '14 at 17:05
  • 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... – T30 Dec 10 '14 at 17:12
  • 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()`. – CodeCaster Dec 10 '14 at 17:14
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
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • 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 url – Mark Baker Dec 10 '14 at 16:26
  • So for you it can be a PhpMailer issue? – T30 Dec 10 '14 at 16:41
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.

marxjohnson
  • 830
  • 7
  • 21
Fobiya
  • 1