我使用以下脚本 http://stuporglue.org/recieve-e-mail-and-save-attachments-with-a-php-script/来处理发送给我的电子邮件,但是似乎如果用户从邮件或 Outlook 或任何发送 base64 附件的电子邮件客户端发送电子邮件,它们不会保存在数据库中,并且电子邮件的正文文本也会被跳过。
我想知道是否有人在代码中看到错误,因为我已经查看并且没有看到任何突出的内容。
仔细观察会发现以下内容Mail.app 像这样发送其 base64。
--Apple-Mail=_9E76B10A-4086-43B8-B835-78F184FA43FC
Content-Disposition: inline;
filename=CV-IT.pdf
Content-Type: application/pdf;
name="CV-IT.pdf"
Content-Transfer-Encoding: base64
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
1NVM1hk3kE1G3rlPZKL2CeZ+Hdp
而Gmail则像这样发送。
Content-Type: application/pdf; name="CV-IT.pdf"
Content-Disposition: attachment; filename="CV-IT.pdf"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_gx86pbon0
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
1NVM1hk3kE1G3rlPZKL2CeZ+Hdp
Gmail 附件会保存,而 mail.app 不会保存。
免责声明有问题的脚本有更多问题,我不会解决,下面的答案旨在快速解决手头的问题,同时希望启发一些无法自己诊断问题的读者。/免責聲明
有两个主要问题。
问题 1:拆分标题行
查看这些标头:
Content-Disposition: inline;
filename=CV-IT.pdf
Content-Type: application/pdf;
name="CV-IT.pdf"
对
Content-Type: application/pdf; name="CV-IT.pdf"
Content-Disposition: attachment; filename="CV-IT.pdf"
现在看一下处理这些行的部分:
$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];
}
..
}
这会将标题拆分为行,然后尝试匹配每一行。现在看看两个标题。第二个(工作(有 2 行,完全匹配。
第一个(不工作(有 4 (!( 行。这 4 行都与模式不匹配。
有无数种方法可以解决这个问题,我将采取快速而肮脏的单行本。在$info = split("n",$parts[0]);
之前添加此行
$parts[0] = preg_replace("/r?ns+/"," ",$parts[0]);
它将通过查找换行符后跟空格并仅用一个空格替换它们,将拆分的标题再次转换为单行。
问题2:错误的模式
假设您应用了上述修复程序,则具有以下模式:
if( preg_match("/Content-Disposition: attachment; filename="(.*)"/", ...
尝试匹配此行:
Content-Disposition: inline; filename=CV-IT.pdf
这里有两件事出错:
问题 2a:内联/附件处置
该模式清楚地寻找"附件"一词,而该行则显示"内联"。这是通过将attachment
替换为(attachment|inline)
来修复的,这表示另一种选择。(请注意,这也捕获了处置类型(
问题 2b:文件名双引号
该模式进一步寻找filename="(.*)"
,而该行有一个不带引号的文件名。
这也不是主要问题,如果您在"
后插入?
,以指示"
是可选的,则一切都将起作用。为了使其完美,您还必须确保.
与结尾"
不匹配(如果可用(,因此请将filename="(.*)"
替换为:
filename="?([^"]+)"?
其中[^"]+
代表"除"
以外的任何东西"。
因此,如果您更改这些行:
if( preg_match("/Content-Disposition: attachment; filename="(.*)"/",
$line,$matches) ) {
$name = time() . "_" . $matches[1];
}
到
if( preg_match('/Content-Disposition: (attachment|inline); filename="?([^"]*)"?/',
$line,$matches) ) {
$disposition = $matches[1];
$name = time() . "_" . $matches[2];
}
它应该有效。(请注意,我将模式更改为使用单引号,因此您无需转义双引号,从而使内容清晰易读(
为了使此脚本万无一失,您应该真正阅读相应的 RFC,以了解电子邮件标头中还有什么期望。这个脚本中埋藏着很多假设。
问题是我的脚本没有查找内联内容,而只查找附加内容。通过您附加文件的方式,它是内联的,因此
内容处置:内联;文件名=CV-IT.pdf
如果附加它,则会看到内容处置:依恋;文件名="CV-IT.pdf">
内容处置处理大约在我的网站上脚本的第 54-64 行(在原始问题中链接(。
您使用了preg_match来获取第 166 行附近的邮件边界:
if (preg_match("/boundary=(.*boundary)$/",$line,$matches)){
$boundary = $matches[1];
您使用"/"字符作为正则表达式模式的分隔符,并且同时在边界内容中具有"/"。
所以这可能是你的代码不起作用的原因。
试试这个:
if (preg_match("{boundary=(.*boundary)$}",$line,$matches)){
$boundary = $matches[1];