├── README.md ├── Incoming_Mail_Attachment.php ├── Incoming_Mail.php └── MY_Email.php /README.md: -------------------------------------------------------------------------------- 1 | # CI_Imap 2 | Library to extend CI email class and allow you to received imap mail. 3 | -------------------------------------------------------------------------------- /Incoming_Mail_Attachment.php: -------------------------------------------------------------------------------- 1 | _attachments[$attachment->id] = $attachment; 42 | } 43 | 44 | // -------------------------------------------------------------------- 45 | 46 | /** 47 | * Get attachment array for message. 48 | * 49 | * @return IncomingMailAttachment[] 50 | */ 51 | public function get_attachments() { 52 | return $this->_attachments; 53 | } 54 | 55 | // -------------------------------------------------------------------- 56 | 57 | /** 58 | * Get array of internal HTML links placeholders 59 | * 60 | * @return array attachmentId => link placeholder 61 | */ 62 | public function get_internal_links_placeholders() { 63 | return preg_match_all('/=["\'](ci?d:(\w+))["\']/i', $this->text_html, $matches) ? array_combine($matches[2], $matches[1]) : array(); 64 | } 65 | 66 | // -------------------------------------------------------------------- 67 | 68 | /** 69 | * Get array of internal HTML links placeholders 70 | * 71 | * @return array attachmentId => link placeholder 72 | */ 73 | public function replace_internal_links($base_uri) { 74 | $base_uri = rtrim($base_uri, '\\/') . '/'; 75 | $fetched_html = $this->text_html; 76 | foreach($this->getInternalLinksPlaceholders() as $attachment_id => $place_holder) { 77 | $fetched_html = str_replace($place_holder, $base_uri . basename($this->_attachments[$attachment_id]->file_path), $fetched_html); 78 | } 79 | return $fetched_html; 80 | } 81 | } 82 | 83 | 84 | /* End of file MY_Email.php */ 85 | /* Location: ./system/application/libraries/MY_Email.php */ -------------------------------------------------------------------------------- /MY_Email.php: -------------------------------------------------------------------------------- 1 | disconnect(); 62 | $imap_stream = null; 63 | } 64 | if(!$imap_stream) { 65 | $imap_stream = $this->_init_imap_stream(); 66 | } 67 | } 68 | return $imap_stream; 69 | } 70 | 71 | // -------------------------------------------------------------------- 72 | 73 | protected function _init_imap_stream() { 74 | $imap_stream = @imap_open($this->_full_imap_path(), $this->imap_user, $this->imap_pass); 75 | if(!$imap_stream) { 76 | throw new Exception('Connection error: ' . imap_last_error()); 77 | } 78 | return $imap_stream; 79 | } 80 | 81 | // -------------------------------------------------------------------- 82 | 83 | 84 | protected function _full_imap_path() { 85 | $full_imap_path = "{".$this->imap_host.":".$this->imap_port.$this->imap_path."}".$this->imap_mailbox; 86 | return $full_imap_path; 87 | } 88 | 89 | /** 90 | * Get information about the current mailbox. 91 | * 92 | * Returns the information in an object with following properties: 93 | * Date - current system time formatted according to RFC2822 94 | * Driver - protocol used to access this mailbox: POP3, IMAP, NNTP 95 | * Mailbox - the mailbox name 96 | * Nmsgs - number of mails in the mailbox 97 | * Recent - number of recent mails in the mailbox 98 | * 99 | * @return stdClass 100 | */ 101 | public function check_mailbox() { 102 | return imap_check($this->get_imap_stream()); 103 | } 104 | 105 | // -------------------------------------------------------------------- 106 | 107 | /** 108 | * Get information about the current mailbox. 109 | * 110 | * Returns an object with following properties: 111 | * Date - last change (current datetime) 112 | * Driver - driver 113 | * Mailbox - name of the mailbox 114 | * Nmsgs - number of messages 115 | * Recent - number of recent messages 116 | * Unread - number of unread messages 117 | * Deleted - number of deleted messages 118 | * Size - mailbox size 119 | * 120 | * @return object Object with info | FALSE on failure 121 | */ 122 | public function get_mailbox_info() { 123 | return imap_mailboxmsginfo($this->get_imap_stream()); 124 | } 125 | 126 | // -------------------------------------------------------------------- 127 | 128 | /** 129 | * Get number of messages from the Mailbox. 130 | * 131 | * @return integer 132 | */ 133 | public function get_num_msg() { 134 | return imap_num_msg($this->get_imap_stream()); 135 | } 136 | 137 | // -------------------------------------------------------------------- 138 | 139 | 140 | /** 141 | * Gets status information about the given mailbox. 142 | * 143 | * This function returns an object containing status information. 144 | * The object has the following properties: messages, recent, unseen, uidnext, and uidvalidity. 145 | * 146 | * @return stdClass | FALSE if the box doesn't exist 147 | */ 148 | public function status_mailbox() { 149 | return imap_status($this->get_imap_stream(), $this->imap_path, SA_ALL); 150 | } 151 | 152 | // -------------------------------------------------------------------- 153 | 154 | /** 155 | * Close IMAP Connection 156 | * 157 | */ 158 | protected function _disconnect() { 159 | $imap_stream = $this->get_imap_stream(false); 160 | if($imap_stream && is_resource($imap_stream)) { 161 | imap_close($imap_stream, CL_EXPUNGE); 162 | } 163 | } 164 | 165 | // -------------------------------------------------------------------- 166 | 167 | /** 168 | * Marks mails listed in mailId for deletion. 169 | * @return bool 170 | */ 171 | public function delete_mail($mail_id) { 172 | return imap_delete($this->get_imap_stream(), $mail_id, FT_UID); 173 | } 174 | 175 | // -------------------------------------------------------------------- 176 | 177 | /** 178 | * Deletes all the mails marked for deletion by imap_delete(), imap_mail_move(), or imap_setflag_full(). 179 | * @return bool 180 | */ 181 | public function expunge_deleted_mails() { 182 | return imap_expunge($this->get_imap_stream()); 183 | } 184 | 185 | // -------------------------------------------------------------------- 186 | 187 | /** 188 | * This function performs a search on the mailbox currently opened in the given IMAP stream. 189 | * For example, to match all unanswered mails sent by Mom, you'd use: "UNANSWERED FROM mom". 190 | * Searches appear to be case insensitive. This list of criteria is from a reading of the UW 191 | * c-client source code and may be incomplete or inaccurate (see also RFC2060, section 6.4.4). 192 | * 193 | * @param string $criteria String, delimited by spaces, in which the following keywords are allowed. Any multi-word arguments (e.g. FROM "joey smith") must be quoted. Results will match all criteria entries. 194 | * ALL - return all mails matching the rest of the criteria 195 | * ANSWERED - match mails with the \\ANSWERED flag set 196 | * BCC "string" - match mails with "string" in the Bcc: field 197 | * BEFORE "date" - match mails with Date: before "date" 198 | * BODY "string" - match mails with "string" in the body of the mail 199 | * CC "string" - match mails with "string" in the Cc: field 200 | * DELETED - match deleted mails 201 | * FLAGGED - match mails with the \\FLAGGED (sometimes referred to as Important or Urgent) flag set 202 | * FROM "string" - match mails with "string" in the From: field 203 | * KEYWORD "string" - match mails with "string" as a keyword 204 | * NEW - match new mails 205 | * OLD - match old mails 206 | * ON "date" - match mails with Date: matching "date" 207 | * RECENT - match mails with the \\RECENT flag set 208 | * SEEN - match mails that have been read (the \\SEEN flag is set) 209 | * SINCE "date" - match mails with Date: after "date" 210 | * SUBJECT "string" - match mails with "string" in the Subject: 211 | * TEXT "string" - match mails with text "string" 212 | * TO "string" - match mails with "string" in the To: 213 | * UNANSWERED - match mails that have not been answered 214 | * UNDELETED - match mails that are not deleted 215 | * UNFLAGGED - match mails that are not flagged 216 | * UNKEYWORD "string" - match mails that do not have the keyword "string" 217 | * UNSEEN - match mails which have not been read yet 218 | * 219 | * @return array Mails ids 220 | */ 221 | public function search_mailbox($criteria = 'ALL') { 222 | $mails_ids = imap_search($this->get_imap_stream(), $criteria, SE_UID, $this->imap_server_encoding); 223 | return $mails_ids ? $mails_ids : array(); 224 | } 225 | 226 | // -------------------------------------------------------------------- 227 | 228 | /** 229 | * Get mail data 230 | * 231 | * @param $mail_id 232 | * @return IncomingMail 233 | */ 234 | public function get_mail($mail_id) { 235 | $head = imap_rfc822_parse_headers(imap_fetchheader($this->get_imap_stream(), $mail_id, FT_UID)); 236 | 237 | $CI =& get_instance(); 238 | $CI->load->library('Incoming_Mail'); 239 | $incoming_mail = new $CI->incoming_mail(); 240 | 241 | $incoming_mail->id = $mail_id; 242 | $incoming_mail->date = date('Y-m-d H:i:s', isset($head->date) ? strtotime($head->date) : time()); 243 | $incoming_mail->subject = isset($head->subject) ? $this->decode_mime_str($head->subject, $this->imap_server_encoding) : null; 244 | $incoming_mail->from_name = isset($head->from[0]->personal) ? $this->decode_mime_str($head->from[0]->personal, $this->imap_server_encoding) : null; 245 | $incoming_mail->from_address = strtolower($head->from[0]->mailbox . '@' . $head->from[0]->host); 246 | 247 | if(isset($head->to)) { 248 | $to_strings = array(); 249 | foreach($head->to as $to) { 250 | if(!empty($to->mailbox) && !empty($to->host)) { 251 | $to_email = strtolower($to->mailbox . '@' . $to->host); 252 | $to_name = isset($to->personal) ? $this->decode_mime_str($to->personal, $this->imap_server_encoding) : null; 253 | $to_strings[] = $to_name ? "$to_name <$to_email>" : $to_email; 254 | $this->incoming_mail->to[$to_email] = $to_name; 255 | } 256 | } 257 | $incoming_mail->to_string = implode(', ', $to_strings); 258 | } 259 | 260 | if(isset($head->cc)) { 261 | foreach($head->cc as $cc) { 262 | $incoming_mail->cc[strtolower($cc->mailbox . '@' . $cc->host)] = isset($cc->personal) ? $this->decode_mime_str($cc->personal, $this->imap_server_encoding) : null; 263 | } 264 | } 265 | 266 | if(isset($head->reply_to)) { 267 | foreach($head->reply_to as $reply_to) { 268 | $incoming_mail->reply_to[strtolower($reply_to->mailbox . '@' . $reply_to->host)] = isset($reply_to->personal) ? $this->decode_mime_str($reply_to->personal, $this->imap_server_encoding) : null; 269 | } 270 | } 271 | 272 | $mail_structure = imap_fetchstructure($this->get_imap_stream(), $mail_id, FT_UID); 273 | 274 | if(empty($mail_structure->parts)) { 275 | $this->_init_mail_part($incoming_mail, $mail_structure, 0); 276 | } 277 | else { 278 | foreach($mail_structure->parts as $part_num => $part_structure) { 279 | $this->_init_mail_part($incoming_mail, $part_structure, $part_num + 1); 280 | } 281 | } 282 | 283 | return $incoming_mail; 284 | } 285 | 286 | // -------------------------------------------------------------------- 287 | 288 | protected function _init_mail_part($mail, $part_structure, $part_num) { 289 | 290 | $data = $part_num ? imap_fetchbody($this->get_imap_stream(), $mail->id, $part_num, FT_UID) : imap_body($this->get_imap_stream(), $mail->id, FT_UID); 291 | 292 | if($part_structure->encoding == 1) { 293 | $data = imap_utf8($data); 294 | } 295 | elseif($part_structure->encoding == 2) { 296 | $data = imap_binary($data); 297 | } 298 | elseif($part_structure->encoding == 3) { 299 | $data = imap_base64($data); 300 | } 301 | elseif($part_structure->encoding == 4) { 302 | $data = imap_qprint($data); 303 | } 304 | $params = array(); 305 | 306 | if(!empty($part_structure->parameters)) { 307 | foreach($part_structure->parameters as $param) { 308 | $params[strtolower($param->attribute)] = $param->value; 309 | } 310 | } 311 | 312 | if(!empty($part_structure->dparameters)) { 313 | foreach($part_structure->dparameters as $param) { 314 | $paramName = strtolower(preg_match('~^(.*?)\*~', $param->attribute, $matches) ? $matches[1] : $param->attribute); 315 | if(isset($params[$paramName])) { 316 | $params[$paramName] .= $param->value; 317 | } 318 | else { 319 | $params[$paramName] = $param->value; 320 | } 321 | } 322 | } 323 | 324 | if(!empty($params['charset'])) { 325 | // php-imap fix #46 326 | //$data = iconv(strtoupper($params['charset']), $this->imap_server_encoding . '//IGNORE', $data); 327 | $data = mb_convert_encoding($data, $this->imap_server_encoding, $params['charset']); 328 | } 329 | 330 | // attachments 331 | $attachment_id = $part_structure->ifid 332 | ? trim($part_structure->id, " <>") 333 | : (isset($params['filename']) || isset($params['name']) ? mt_rand() . mt_rand() : null); 334 | 335 | if($attachment_id) { 336 | if(empty($params['filename']) && empty($params['name'])) { 337 | $file_name = $attachment_id . '.' . strtolower($part_structure->subtype); 338 | } else { 339 | $file_name = !empty($params['filename']) ? $params['filename'] : $params['name']; 340 | $file_name = $this->decode_mime_str($file_name, $this->imap_server_encoding); 341 | $file_name = $this->decode_rfc2231($file_name, $this->imap_server_encoding); 342 | } 343 | 344 | $CI =& get_instance(); 345 | $CI->load->library('Incoming_Mail_Attachment'); 346 | $mailattachment = new $CI->incoming_mail_attachment(); 347 | $mailattachment->id = $attachment_id; 348 | $mailattachment->name = $file_name; 349 | if($this->imap_attachemnt_dir) { 350 | $replace = array( 351 | '/\s/' => '_', 352 | '/[^0-9a-zA-Z_\.]/' => '', 353 | '/_+/' => '_', 354 | '/(^_)|(_$)/' => '', 355 | ); 356 | $file_sys_name = preg_replace('~[\\\\/]~', '', $mail->id . '_' . $attachment_id . '_' . preg_replace(array_keys($replace), $replace, $file_name)); 357 | $mailattachment->uploadfileName = $file_sys_name; 358 | $mailattachment->filePath = $this->imap_attachemnt_dir . DIRECTORY_SEPARATOR . $file_sys_name; 359 | 360 | file_put_contents($mailattachment->filePath, $data); 361 | } 362 | $mail->add_attachment($mailattachment); 363 | unset($mailattachment); 364 | } elseif($part_structure->type == 0 && $data) { 365 | if(strtolower($part_structure->subtype) == 'plain') { 366 | $mail->text_plain .= $data; 367 | } else { 368 | $mail->text_html .= $data; 369 | } 370 | } elseif($part_structure->type == 2 && $data) { 371 | $mail->text_plain .= trim($data); 372 | } 373 | 374 | if(!empty($part_structure->parts)) { 375 | foreach($part_structure->parts as $sub_part_num => $sub_part_structure) { 376 | if($part_structure->type == 2 && $part_structure->subtype == 'RFC822') { 377 | $this->_init_mail_part($mail, $sub_part_structure, $part_num); 378 | } else { 379 | $this->_init_mail_part($mail, $sub_part_structure, $part_num . '.' . ($sub_part_num + 1)); 380 | } 381 | } 382 | } 383 | 384 | } 385 | 386 | 387 | 388 | // -------------------------------------------------------------------- 389 | 390 | /** 391 | * Decode Mime String 392 | * 393 | * @param $string, $charset 394 | * @return String 395 | */ 396 | protected function decode_mime_str($string, $charset = 'utf-8') { 397 | $new_string = ''; 398 | $elements = imap_mime_header_decode($string); 399 | for($i = 0; $i < count($elements); $i++) { 400 | if($elements[$i]->charset == 'default') { 401 | $elements[$i]->charset = 'iso-8859-1'; 402 | } 403 | // php-imap fix #46 404 | // $new_string .= iconv(strtoupper($elements[$i]->charset), $charset . '//IGNORE', $elements[$i]->text); 405 | $new_string .= mb_convert_encoding($elements[$i]->text, $charset, $elements[$i]->charset); 406 | } 407 | return $new_string; 408 | } 409 | 410 | // -------------------------------------------------------------------- 411 | 412 | /** 413 | * Decode RFC String 414 | * 415 | * @param $string, $charset 416 | * @return String 417 | */ 418 | protected function decode_rfc2231($string, $charset = 'utf-8') { 419 | if(preg_match("/^(.*?)'.*?'(.*?)$/", $string, $matches)) { 420 | $encoding = $matches[1]; 421 | $data = $matches[2]; 422 | if($this->isUrlEncoded($data)) { 423 | // php-imap fix #46 424 | // $string = iconv(strtoupper($encoding), $charset . '//IGNORE', urldecode($data)); 425 | $string = mb_convert_encoding(urldecode($data), $charset, $encoding); 426 | } 427 | } 428 | return $string; 429 | } 430 | 431 | 432 | 433 | } 434 | 435 | 436 | /* End of file MY_Email.php */ 437 | /* Location: ./system/application/libraries/MY_Email.php */ --------------------------------------------------------------------------------