getFilename() returns NULL for long attachment filenames
| Q | A |
|---|---|
| ddeboer/imap version | 1.12.2 / 1.13.1 |
| PHP version | 7.4.28 / 8.1.3 |
| IMAP provider | imap.ionos.es |
Summary
Long filenames splitted across multiple lines in the message are not retrieved correctly by the function $attachment->getFilename()
$message->getRawMessage() output:
...
--=_6cc5e393f9284e5e531157803beddb81
Content-Transfer-Encoding: base64
Content-Type: text/csv;
name*0*=utf-8''BTP%20Cerrados%20%C3%9Altimo%20Mes%20Tickets-20220311-0603;
name*1*=03.csv
Content-Disposition: attachment;
filename*0*=utf-8''BTP%20Cerrados%20%C3%9Altimo%20Mes%20Tickets-20220311-;
filename*1*=060303.csv;
size=247245
77u/Ik7Dum1lcm8gZGUgVGlja2V0IjsiRmVjaGEgZGUgY3JlYWNpw7NuIjtBc3VudG87RGU7IkRl
...
Current behavior
$attachment->getFilename() returns NULL
Expected behavior
$attachment->getFilename() should return "BTP Cerrados Último Mes Tickets-20220311-060303.csv"
I don't use this library, but was searching for some libraries that could handle quite some different scenario's. One of those scenario's would be the same like this issue.
When fetching the structure from an email holding an attachment 'with no name', the part holding the attachment looks like this:
...
->disposition = "ATTACHMENT",
->ifdparameters = 1,
->dparameters = array(
0 => {stdClass}( attribute = "FILENAME*0", value = "a very long filename limited by 60chars"),
1 => {stdClass}( attribute = "FILENAME*1", value = "remaining chars.txt")
)
I solved getting the filename of the attachment in my own code like this:
/** @var stdClass $part a part returned by `imap_fetchstructure()`
$filename = '';
$filenameParts = array();
if($part->ifdparameters) {
foreach($part->dparameters as $i => $object) {
if(strtolower($object->attribute) === 'filename') {
$filename = $object->value;
}elseif(strtolower($object->attribute) === 'filename*'.$i){
$filenameParts[] = $object->value;
}
}
}
if(!$filename && $part->ifparameters) {
foreach($part->parameters as $object) {
if(strtolower($object->attribute) == 'name') {
$filename = $object->value;
}
}
}
if(!$filename && $filenameParts){
$filename = implode('', $filenameParts);
}
return iconv_mime_decode($filename , ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8');
Retrieving the filename should handle at least 3 cases:
- filename is in a parameter named 'FILENAME'
- filename is split in parameters named 'FILENAME*N' where N is the index of the parameter
- filename is in a parameter named 'NAME'
But look when looking at Ddeboer\Imap\Message\Parameters::$attachmentCustomKeys, there also seems to be a case where attributes are named exactly 'FILENAME*' or 'NAME*' ???
Are there any official docs on reading the filename from the structure? I failed to find anything other then cases 1. and 3 from non-official programming examples.