Base64 email attachments are not uploading

China☆狼群 提交于 2019-12-05 19:09:17

disclaimer the problematic script in question has more issues, which I will not address, and the answer below is meant as a quick fix for the problem at hand, while hoping to enlighten some readers who were not able to diagnose the problems themselves. /disclaimer

There are two main problems.

Problem 1: split header lines

Look at these headers:

Content-Disposition: inline;
    filename=CV-IT.pdf
Content-Type: application/pdf;
    name="CV-IT.pdf"

versus

Content-Type: application/pdf; name="CV-IT.pdf"
Content-Disposition: attachment; filename="CV-IT.pdf"

Now look at the part that processes these lines:

$info = split("\n",$parts[0]);
..
foreach($info as $line)
{
    if( preg_match("/Content-Type: (.*);/",$line,$matches) )
    {
        $type = $matches[1];
    }
    if( preg_match("/Content-Disposition: attachment; filename=\"(.*)\"/",
        $line,$matches) ) {
        $name = time() . "_" . $matches[1];
    }
    ..
}

This splits the header in lines, and then tries to match every line. Now look at the two headers. The second (working) one has 2 lines, which are perfectly matched.

The first (not working) one has 4 (!) lines. None of these 4 lines matches the patterns.

There are countless ways of tackling this problem, and I'll take a quick&dirty oneliner. Add this line before $info = split("\n",$parts[0]);

$parts[0] = preg_replace("/\r?\n\s+/"," ",$parts[0]);

it will turn the split headers into oneliners again by looking for newlines followed by whitespace, and replacing them with just one space.

Problem 2: wrong pattern

Assuming you applied the fix above, you have this pattern:

if( preg_match("/Content-Disposition: attachment; filename=\"(.*)\"/", ...

trying to match this line:

Content-Disposition: inline; filename=CV-IT.pdf

Two things go wrong here:

problem 2a: disposition inline/attachment

The pattern clearly looks for the word "attachment", while the line says "inline". This is fixed by replacing attachment by (attachment|inline), which indicates an alternative. (note that this also captures the disposition type)

problem 2b: filename double quotes

The pattern further looks for filename="(.*)", while the line has a filename without the quotes.

This is also no major issue, if you insert ? after the ", to indicate that the " is optional, all will work. To make it perfect, you must also ensure that the . will not match the ending " if available, so replace filename="(.*)" with:

filename="?([^"]+)"?

where [^"]+ stands for 'anything but "'.

So if you change these lines:

if( preg_match("/Content-Disposition: attachment; filename=\"(.*)\"/",
    $line,$matches) ) {
    $name = time() . "_" . $matches[1];
}

into

if( preg_match('/Content-Disposition: (attachment|inline); filename="?([^"]*)"?/',
    $line,$matches) ) {
    $disposition = $matches[1];
    $name = time() . "_" . $matches[2];
}

it should work. (note that I changed the pattern to use single quotes, so that you need not escape the double quotes, making things legible)

To make this script fool proof, you should really read the appropriate RFCs, to see what more is to be expected in email headers. This script has a lot of assumptions buried in it.

The problem is that my script is not looking for inline content, only for attached content. With the way you have attached the file, it is inline, hence the

Content-Disposition: inline; filename=CV-IT.pdf

If you attach it, you would instead see Content-Disposition: attachment; filename="CV-IT.pdf"

The Content-Disposition handling is around line 54-64 of the script on my site (linked in original question).

seems you used preg_match to get the boundary of the mail near line 166:

if (preg_match("/boundary=(.*boundary)$/",$line,$matches)){
    $boundary = $matches[1];

You used the "/" character as delimiter of pattern of regular expression and you have the "/" in your boundary content at the same time.

So this may be the reason why your code does not work.

Try this:

if (preg_match("{boundary=(.*boundary)$}",$line,$matches)){
    $boundary = $matches[1];
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!