Differences Between: [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 /** 3 * Copyright 2011-2017 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file LICENSE for license information (BSD). If you 6 * did not receive this file, see http://www.horde.org/licenses/bsd. 7 * 8 * @category Horde 9 * @copyright 2011-2017 Horde LLC 10 * @license http://www.horde.org/licenses/bsd New BSD License 11 * @package Mail 12 */ 13 14 /** 15 * This object allows easy access to parsing mbox data (RFC 4155). 16 * 17 * See: 18 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats 19 * 20 * @author Michael Slusarz <slusarz@horde.org> 21 * @category Horde 22 * @copyright 2011-2017 Horde LLC 23 * @license http://www.horde.org/licenses/bsd New BSD License 24 * @package Mail 25 * @since 2.5.0 26 */ 27 class Horde_Mail_Mbox_Parse 28 implements ArrayAccess, Countable, Iterator 29 { 30 /** 31 * Data stream. 32 * 33 * @var resource 34 */ 35 protected $_data; 36 37 /** 38 * Parsed data. Each entry is an array containing 3 keys: 39 * - date: (mixed) Date information, in DateTime object. Null if date 40 * cannot be parsed. False if message is not MBOX data. 41 * - start: (integer) Start boundary. 42 * 43 * @var array 44 */ 45 protected $_parsed = array(); 46 47 /** 48 * Constructor. 49 * 50 * @param mixed $data The mbox data. Either a resource or a filename 51 * as interpreted by fopen() (string). 52 * @param integer $limit Limit to this many messages; additional messages 53 * will throw an exception. 54 * 55 * @throws Horde_Mail_Parse_Exception 56 */ 57 public function __construct($data, $limit = null) 58 { 59 $this->_data = is_resource($data) 60 ? $data 61 : @fopen($data, 'r'); 62 63 if ($this->_data === false) { 64 throw new Horde_Mail_Exception( 65 Horde_Mail_Translation::t("Could not parse mailbox data.") 66 ); 67 } 68 69 rewind($this->_data); 70 71 $i = 0; 72 $last_line = null; 73 /* Is this a MBOX format file? */ 74 $mbox = false; 75 76 while (!feof($this->_data)) { 77 if (is_null($last_line)) { 78 $start = ftell($this->_data); 79 } 80 81 $line = fgets($this->_data); 82 83 if (is_null($last_line)) { 84 ltrim($line); 85 } 86 87 if (substr($line, 0, 5) == 'From ') { 88 if (is_null($last_line)) { 89 /* This file is in MBOX format. */ 90 $mbox = true; 91 } elseif (!$mbox || (trim($last_line) !== '')) { 92 continue; 93 } 94 95 if ($limit && ($i++ > $limit)) { 96 throw new Horde_Mail_Exception( 97 sprintf( 98 Horde_Mail_Translation::t("Imported mailbox contains more than enforced limit of %u messages."), 99 $limit 100 ) 101 ); 102 } 103 104 $from_line = explode(' ', $line, 3); 105 try { 106 $date = new DateTime($from_line[2]); 107 } catch (Exception $e) { 108 $date = null; 109 } 110 111 $this->_parsed[] = array( 112 'date' => $date, 113 'start' => ftell($this->_data) 114 ); 115 } 116 117 /* Strip all empty lines before first data. */ 118 if (!is_null($last_line) || (trim($line) !== '')) { 119 $last_line = $line; 120 } 121 } 122 123 /* This was a single message, not a MBOX file. */ 124 if (empty($this->_parsed)) { 125 $this->_parsed[] = array( 126 'date' => false, 127 'start' => $start 128 ); 129 } 130 } 131 132 /* ArrayAccess methods. */ 133 134 /** 135 */ 136 public function offsetExists($offset) 137 { 138 return isset($this->_parsed[$offset]); 139 } 140 141 /** 142 */ 143 public function offsetGet($offset) 144 { 145 if (!isset($this->_parsed[$offset])) { 146 return null; 147 } 148 149 $p = $this->_parsed[$offset]; 150 $end = isset($this->_parsed[$offset + 1]) 151 ? $this->_parsed[$offset + 1]['start'] 152 : null; 153 $fd = fopen('php://temp', 'w+'); 154 155 fseek($this->_data, $p['start']); 156 while (!feof($this->_data)) { 157 $line = fgets($this->_data); 158 if ($end && (ftell($this->_data) >= $end)) { 159 break; 160 } 161 162 fwrite( 163 $fd, 164 (($p['date'] !== false) && substr($line, 0, 6) == '>From ') 165 ? substr($line, 1) 166 : $line 167 ); 168 } 169 170 $out = array( 171 'data' => $fd, 172 'date' => ($p['date'] === false) ? null : $p['date'], 173 'size' => intval(ftell($fd)) 174 ); 175 rewind($fd); 176 177 return $out; 178 } 179 180 /** 181 */ 182 public function offsetSet($offset, $value) 183 { 184 // NOOP 185 } 186 187 /** 188 */ 189 public function offsetUnset($offset) 190 { 191 // NOOP 192 } 193 194 /* Countable methods. */ 195 196 /** 197 * Index count. 198 * 199 * @return integer The number of messages. 200 */ 201 public function count() 202 { 203 return count($this->_parsed); 204 } 205 206 /* Magic methods. */ 207 208 /** 209 * String representation of the object. 210 * 211 * @return string String representation. 212 */ 213 public function __toString() 214 { 215 rewind($this->_data); 216 return stream_get_contents($this->_data); 217 } 218 219 /* Iterator methods. */ 220 221 public function current() 222 { 223 $key = $this->key(); 224 225 return is_null($key) 226 ? null 227 : $this[$key]; 228 } 229 230 public function key() 231 { 232 return key($this->_parsed); 233 } 234 235 public function next() 236 { 237 if ($this->valid()) { 238 next($this->_parsed); 239 } 240 } 241 242 public function rewind() 243 { 244 reset($this->_parsed); 245 } 246 247 public function valid() 248 { 249 return !is_null($this->key()); 250 } 251 252 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body