PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/FuChi/ushahidi/application/libraries/Imap.php

https://github.com/dannyrealfox/Fu-Chi--Future-Chinatown
PHP | 408 lines | 256 code | 71 blank | 81 comment | 46 complexity | 43bd862a0042f2dc172b3d21c2c8f8f7 MD5 | raw file
  1. <?php defined('SYSPATH') OR die('No direct access allowed.');
  2. /**
  3. * Imap library. Wrapper to read email using IMAP/POP3.
  4. * @package Imap
  5. * @author Ushahidi Team
  6. * @copyright (c) 2009 Ushahidi Team
  7. * @license http://www.ushahidi.com/license.html
  8. */
  9. class Imap_Core {
  10. private $imap_stream;
  11. /**
  12. * Opens an IMAP stream
  13. */
  14. public function __construct()
  15. {
  16. // Set Imap Timeouts
  17. imap_timeout(IMAP_OPENTIMEOUT,90);
  18. imap_timeout(IMAP_READTIMEOUT,90);
  19. // If SSL Enabled
  20. $ssl = Kohana::config('settings.email_ssl') == true ? "/ssl" : "";
  21. // Do not validate certificates (TLS/SSL server)
  22. //$novalidate = strtolower(Kohana::config('settings.email_servertype')) == "imap" ? "/novalidate-cert" : "";
  23. $novalidate = "/novalidate-cert";
  24. // If POP3 Disable TLS
  25. $notls = strtolower(Kohana::config('settings.email_servertype')) == "pop3" ? "/notls" : "";
  26. /*
  27. More Info about above options at:
  28. http://php.net/manual/en/function.imap-open.php
  29. */
  30. $service = "{".Kohana::config('settings.email_host').":"
  31. .Kohana::config('settings.email_port')."/"
  32. .Kohana::config('settings.email_servertype')
  33. .$notls.$ssl.$novalidate."}";
  34. // Check if the host name is valid, if not, set imap_stream as false and return false
  35. if(count(dns_get_record("".Kohana::config('settings.email_host')."")) == 0)
  36. {
  37. $this->imap_stream = false;
  38. return false;
  39. }
  40. if ( $imap_stream = @imap_open($service, Kohana::config('settings.email_username')
  41. ,Kohana::config('settings.email_password')))
  42. {
  43. $this->imap_stream = $imap_stream;
  44. } else {
  45. // We don't usually want to break the entire scheduler process if email settings are off
  46. // so lets return false instead of halting the entire script with a Kohana Exception.
  47. $this->imap_stream = false;
  48. return false;
  49. //throw new Kohana_Exception('imap.imap_stream_not_opened', $throwing_error);
  50. }
  51. }
  52. /**
  53. * Get messages according to a search criteria
  54. *
  55. * @param string search criteria (RFC2060, sec. 6.4.4). Set to "UNSEEN" by default
  56. * NB: Search criteria only affects IMAP mailboxes.
  57. * @param string date format. Set to "Y-m-d H:i:s" by default
  58. * @return mixed array containing messages
  59. */
  60. public function get_messages($search_criteria="UNSEEN",
  61. $date_format="Y-m-d H:i:s")
  62. {
  63. global $htmlmsg,$plainmsg,$attachments;
  64. // If our imap connection failed earlier, return no messages
  65. if($this->imap_stream == false)
  66. {
  67. return array();
  68. }
  69. $no_of_msgs = imap_num_msg($this->imap_stream);
  70. $max_imap_messages = Kohana::config('email.max_imap_messages');
  71. // Check to see if the number of messages we want to sort through is greater than
  72. // the number of messages we want to allow. If there are too many messages, it
  73. // can fail and that's no good.
  74. $msg_to_pull = $no_of_msgs;
  75. if($msg_to_pull > $max_imap_messages){
  76. $msg_to_pull = $max_imap_messages;
  77. }
  78. $messages = array();
  79. for ($msgno = 1; $msgno <= $msg_to_pull; $msgno++)
  80. {
  81. $header = imap_headerinfo($this->imap_stream, $msgno);
  82. if( ! isset($header->message_id) OR ! isset($header->udate))
  83. {
  84. continue;
  85. }
  86. $message_id = $header->message_id;
  87. $date = date($date_format, $header->udate);
  88. if (isset($header->from))
  89. {
  90. $from = $header->from;
  91. }else{
  92. $from = FALSE;
  93. }
  94. $fromname = "";
  95. $fromaddress = "";
  96. $subject = "";
  97. $body = "";
  98. $attachments = "";
  99. if ($from != FALSE)
  100. {
  101. foreach ($from as $id => $object)
  102. {
  103. if (isset($object->personal))
  104. {
  105. $fromname = $object->personal;
  106. }
  107. if (isset($object->mailbox) AND isset($object->host))
  108. {
  109. $fromaddress = $object->mailbox."@".$object->host;
  110. }
  111. if ($fromname == "")
  112. {
  113. // In case from object doesn't have Name
  114. $fromname = $fromaddress;
  115. }
  116. }
  117. }
  118. if (isset($header->subject))
  119. {
  120. $subject = $this->_mime_decode($header->subject);
  121. }
  122. // Fetch Body
  123. $this->_getmsg($this->imap_stream, $msgno);
  124. if ($htmlmsg)
  125. {
  126. // Convert HTML to Text
  127. $html2text = new Html2Text($htmlmsg);
  128. $htmlmsg = $html2text->get_text();
  129. }
  130. $body = ($plainmsg) ? $plainmsg : $htmlmsg;
  131. // Fetch Attachments
  132. $attachments = $this->_extract_attachments($this->imap_stream, $msgno);
  133. // Convert to valid UTF8
  134. $body = htmlentities($body);
  135. $subject = htmlentities(strip_tags($subject));
  136. array_push($messages, array('message_id' => $message_id,
  137. 'date' => $date,
  138. 'from' => $fromname,
  139. 'email' => $fromaddress,
  140. 'subject' => $subject,
  141. 'body' => $body,
  142. 'attachments' => $attachments));
  143. // Mark Message As Read
  144. imap_setflag_full($this->imap_stream, $msgno, "\\Seen");
  145. }
  146. return $messages;
  147. }
  148. /**
  149. * Delete a message
  150. * @param int message number
  151. */
  152. public function delete_message($msg_no)
  153. {
  154. imap_delete($this->imap_stream, $msg_no);
  155. }
  156. /**
  157. * Closes an IMAP stream
  158. */
  159. public function close()
  160. {
  161. @imap_close($this->imap_stream);
  162. }
  163. private function _mime_decode($str)
  164. {
  165. $elements = imap_mime_header_decode($str);
  166. $text = "";
  167. foreach ($elements as $element)
  168. {
  169. $text.= $element->text;
  170. }
  171. return $text;
  172. }
  173. /**
  174. * Extract Attachments from Email
  175. */
  176. private function _extract_attachments($connection, $message_number) {
  177. $attachments = array();
  178. $structure = imap_fetchstructure($connection, $message_number);
  179. if(isset($structure->parts) && count($structure->parts)) {
  180. for($i = 0; $i < count($structure->parts); $i++) {
  181. $attachments[$i] = array(
  182. 'is_attachment' => false,
  183. 'file_name' => '',
  184. 'name' => '',
  185. 'attachment' => ''
  186. );
  187. if($structure->parts[$i]->ifdparameters) {
  188. foreach($structure->parts[$i]->dparameters as $object) {
  189. if(strtolower($object->attribute) == 'filename') {
  190. $attachments[$i]['is_attachment'] = true;
  191. $attachments[$i]['file_name'] = $object->value;
  192. }
  193. }
  194. }
  195. if($structure->parts[$i]->ifparameters) {
  196. foreach($structure->parts[$i]->parameters as $object) {
  197. if(strtolower($object->attribute) == 'name') {
  198. $attachments[$i]['is_attachment'] = true;
  199. $attachments[$i]['name'] = $object->value;
  200. }
  201. }
  202. }
  203. if($attachments[$i]['is_attachment']) {
  204. $attachments[$i]['attachment'] = imap_fetchbody($connection, $message_number, $i+1);
  205. if($structure->parts[$i]->encoding == 3) { // 3 = BASE64
  206. $attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']);
  207. }
  208. elseif($structure->parts[$i]->encoding == 4) { // 4 = QUOTED-PRINTABLE
  209. $attachments[$i]['attachment'] = quoted_printable_decode($attachments[$i]['attachment']);
  210. }
  211. }
  212. }
  213. }
  214. $valid_attachments = array();
  215. foreach ($attachments as $attachment)
  216. {
  217. $file_name = $attachment['file_name'];
  218. $file_content = $attachment['attachment'];
  219. $file_type = strrev(substr(strrev($file_name),0,4));
  220. $new_file_name = time()."_".$this->_random_string(10); // Included rand so that files don't overwrite each other
  221. $valid_attachments[] = $this->_save_attachments($file_type, $new_file_name, $file_content);
  222. }
  223. // Remove Nulls
  224. return array_filter($valid_attachments);
  225. }
  226. /**
  227. * Save Attachments to Upload Folder
  228. * Right now we only accept gif, png and jpg files
  229. */
  230. private function _save_attachments($file_type,$file_name,$file_content)
  231. {
  232. if ($file_type == ".gif"
  233. OR $file_type == ".png"
  234. OR $file_type == ".jpg")
  235. {
  236. $attachments = array();
  237. $file = Kohana::config("upload.directory")."/".$file_name.$file_type;
  238. $fp = fopen($file, "w");
  239. fwrite($fp, $file_content);
  240. fclose($fp);
  241. // IMAGE SIZES: 800X600, 400X300, 89X59
  242. // Large size
  243. Image::factory($file)->resize(800,600,Image::AUTO)
  244. ->save(Kohana::config('upload.directory', TRUE).$file_name.$file_type);
  245. // Medium size
  246. Image::factory($file)->resize(400,300,Image::HEIGHT)
  247. ->save(Kohana::config('upload.directory', TRUE).$file_name."_m".$file_type);
  248. // Thumbnail
  249. Image::factory($file)->resize(89,59,Image::HEIGHT)
  250. ->save(Kohana::config('upload.directory', TRUE).$file_name."_t".$file_type);
  251. $attachments[] = array(
  252. $file_name.$file_type,
  253. $file_name."_m".$file_type,
  254. $file_name."_t".$file_type
  255. );
  256. return $attachments;
  257. }
  258. else
  259. {
  260. return null;
  261. }
  262. }
  263. // Random Character String
  264. private function _random_string($length)
  265. {
  266. $random = "";
  267. srand((double)microtime()*1000000);
  268. $char_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  269. $char_list .= "abcdefghijklmnopqrstuvwxyz";
  270. $char_list .= "1234567890";
  271. // Add the special characters to $char_list if needed
  272. for($i = 0; $i < $length; $i++)
  273. {
  274. $random .= substr($char_list,(rand()%(strlen($char_list))), 1);
  275. }
  276. return $random;
  277. }
  278. private function _getmsg($mbox,$mid)
  279. {
  280. // input $mbox = IMAP stream, $mid = message id
  281. // output all the following:
  282. global $htmlmsg,$plainmsg,$attachments;
  283. // the message may in $htmlmsg, $plainmsg, or both
  284. $htmlmsg = $plainmsg = '';
  285. $attachments = array();
  286. // HEADER
  287. $h = imap_header($mbox,$mid);
  288. // add code here to get date, from, to, cc, subject...
  289. // BODY
  290. $s = imap_fetchstructure($mbox,$mid);
  291. if (@!$s->parts) // not multipart
  292. $this->_getpart($mbox,$mid,$s,0); // no part-number, so pass 0
  293. else { // multipart: iterate through each part
  294. foreach ($s->parts as $partno0=>$p)
  295. $this->_getpart($mbox,$mid,$p,$partno0+1);
  296. }
  297. }
  298. private function _getpart($mbox,$mid,$p,$partno)
  299. {
  300. // $partno = '1', '2', '2.1', '2.1.3', etc if multipart, 0 if not multipart
  301. global $htmlmsg,$plainmsg,$attachments;
  302. // DECODE DATA
  303. $data = ($partno)?
  304. imap_fetchbody($mbox,$mid,$partno): // multipart
  305. imap_body($mbox,$mid); // not multipart
  306. // Any part may be encoded, even plain text messages, so check everything.
  307. if ($p->encoding==4)
  308. $data = quoted_printable_decode($data);
  309. elseif ($p->encoding==3)
  310. $data = base64_decode($data);
  311. // no need to decode 7-bit, 8-bit, or binary
  312. // TEXT
  313. if ($p->type==0 && $data) {
  314. // Messages may be split in different parts because of inline attachments,
  315. // so append parts together with blank row.
  316. if (strtolower($p->subtype)=='plain')
  317. $plainmsg .= trim($data) ."\n\n";
  318. else
  319. $htmlmsg .= $data ."<br><br>";
  320. }
  321. // EMBEDDED MESSAGE
  322. // Many bounce notifications embed the original message as type 2,
  323. // but AOL uses type 1 (multipart), which is not handled here.
  324. // There are no PHP functions to parse embedded messages,
  325. // so this just appends the raw source to the main message.
  326. elseif ($p->type==2 && $data)
  327. {
  328. $plainmsg .= trim($data) ."\n\n";
  329. }
  330. // SUBPART RECURSION
  331. if (isset($p->parts))
  332. {
  333. foreach ($p->parts as $partno0=>$p2)
  334. $this->_getpart($mbox,$mid,$p2,$partno.'.'.($partno0+1)); // 1.2, 1.2.1, etc.
  335. }
  336. }
  337. } // End Imap