Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:12170 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 48710 invoked by uid 1010); 14 Aug 2004 22:47:42 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 48681 invoked from network); 14 Aug 2004 22:47:42 -0000 Received: from unknown (HELO smtp02.mrf.mail.rcn.net) (207.172.4.61) by pb1.pair.com with SMTP; 14 Aug 2004 22:47:42 -0000 Received: from 146-115-58-203.c3-0.wtr-ubr1.sbo-wtr.ma.cable.rcn.com ([146.115.58.203] helo=[192.168.10.3]) by smtp02.mrf.mail.rcn.net with esmtp (Exim 3.35 #7) id 1Bw7JN-0002AG-00 for internals@lists.php.net; Sat, 14 Aug 2004 18:47:41 -0400 Message-ID: <411E967D.4000106@rcn.com> Date: Sat, 14 Aug 2004 18:47:25 -0400 User-Agent: Mozilla Thunderbird 0.7.2 (Windows/20040707) X-Accept-Language: en-us, en MIME-Version: 1.0 To: internals@lists.php.net Content-Type: multipart/mixed; boundary="------------040207080207040608010202" Subject: [PATCH] PHP_IMAP New Function "imap_partialbody" to fetch chunks of a MIME attachment From: crispin@rcn.com (Crispin Olson) --------------040207080207040608010202 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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)data = emalloc(size+1); + f(stream,size,buffer->data); + buffer->size = size; + md->stream->sparep=buffer; + return buffer->data; +} +/* {{{ proto string imap_partialbody(resource stream_id, int msg_no, int section, int start, int len [, int options]) + Get a specific body section chunk */ +PHP_FUNCTION(imap_partialbody) +{ + zval **streamind, **msgno, **sec, **start, **len, **flags; + pils *imap_le_struct; + long status; + char *body; + SIZEDTEXT *retbuff; + int myargc=ZEND_NUM_ARGS(); + + if (myargc < 5 || myargc > 6 || zend_get_parameters_ex(myargc, &streamind, &msgno, &sec, + &start, &len, &flags) == FAILURE) { + ZEND_WRONG_PARAM_COUNT(); + } + + ZEND_FETCH_RESOURCE(imap_le_struct, pils *, streamind, -1, "imap", le_imap); + + convert_to_long_ex(msgno); + convert_to_string_ex(sec); + convert_to_long_ex(start); + convert_to_long_ex(len); + if (myargc == 6) { + convert_to_long_ex(flags); + } + + if (myargc < 6 || !(Z_LVAL_PP(flags) & FT_UID)) { + /* only perform the check if the msgno is a message number and not a UID */ + PHP_IMAP_CHECK_MSGNO(Z_LVAL_PP(msgno)); + } + + /* Set up the callback */ + mail_parameters(imap_le_struct->imap_stream,SET_GETS,mm_gets); + status = mail_partial_body(imap_le_struct->imap_stream, Z_LVAL_PP(msgno), Z_STRVAL_PP(sec), + Z_LVAL_PP(start), Z_LVAL_PP(len), + myargc==6 ? Z_LVAL_PP(flags) : NIL); + mail_parameters(imap_le_struct->imap_stream,SET_GETS,NIL); + retbuff = imap_le_struct->imap_stream->sparep; + if (status == NIL) { + php_error(E_WARNING, "%s(): No body information available", get_active_function_name(TSRMLS_C)); + RETURN_FALSE; + } + RETVAL_STRINGL(retbuff->data, retbuff->size, 1); + efree(retbuff->data); + efree(retbuff); +} +/* }}} */ + /* {{{ proto string imap_base64(string text) Decode BASE64 encoded text */ PHP_FUNCTION(imap_base64) Index: php_imap.h =================================================================== RCS file: /repository/php-src/ext/imap/php_imap.h,v retrieving revision 1.24.2.3 diff -u -r1.24.2.3 php_imap.h --- php_imap.h 13 Jun 2003 14:45:36 -0000 1.24.2.3 +++ php_imap.h 14 Aug 2004 22:44:38 -0000 @@ -114,6 +114,7 @@ PHP_FUNCTION(imap_body); PHP_FUNCTION(imap_fetchstructure); PHP_FUNCTION(imap_fetchbody); +PHP_FUNCTION(imap_partialbody); PHP_FUNCTION(imap_expunge); PHP_FUNCTION(imap_delete); PHP_FUNCTION(imap_undelete); --------------040207080207040608010202--