This new function is intended to add "chunking" capability to fetching
attachments from an email using the IMAP library. Currently the
attachment fetch is done with imap_fetchbody , and is placed entirely in
memory, ergo - if the attachment is larger than the available memory it
will fail.
This function has the following prototype - string
imap_partialbody(resource stream_id, int msg_no, int section, int start,
int len [, int options])
It's exactly like imap_fetchbody, except it adds the parameters start
(for the start position offset) and len (for the number of bytes to
retrieve). I've also made sure that the correct checks for message
number are in the code (as per the recent change to imap_fetchbody).
It uses the function "mail_partial_body" in the C Client, which doesn't
appear in any of the very dated documentation, but I found a few
postings by Mark Crispin explaining how to use it, and it's also been
used in pine. One complication is that it uses a callback to populate
the buffer, but I found some hints on how to use a "spare pointer "
element in the IMAP stream structure from a post by him in one of the
online IMAP forums here - http://www.webservertalk.com/message299504.html
Obviously the benefit is that a new attachment retrieval could be
implemented in webmail such as IMP that doesn't require the memlimit on
the server to be set to some absurd value, and would be less likely
bring the server to its knees when some idiot mails a 50M video to a
group of his friends. Note however c-client is still greedy about memory
for its cache (theres nothing that can be done about that) - but this
doesn't figure in the PHP memlimit.
A snippet of some resulting PHP using the function (struct is the return
from imap_fetchstructure - note I haven't put anything in to decode the
structure or errorcheck the return for brevity). CHUNKSIZE is how much
to fetch at a time (100K works quite well)
$size=$struct->parts[$partindex]->bytes;
$fp=fopen($attachfile,"w");
for ($i=0;$i<$size;$i+=CHUNKSIZE)
{
$len = (($size-$i)<CHUNKSIZE) ? $size-$i:CHUNKSIZE;
$pbody = imap_partialbody($imap,$msgno,$partno,$i,$len);
fwrite($fp,$pbody);
}
You will find this code works fine on a large attachment, and doesn't
blow the memlimit when its set to the default of 8M.
The next problem of course is that php/php_imap doesn't have a streamed
Base64 decoder - though I've used a simple command line one quite
effectively.
I'm guessing if this is of interest, it will be of most interest to the
HORDE/IMP team?
Crispin Olson