[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Copyright 2013-2014 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file COPYING for license information (LGPL). If you 6 * did not receive this file, see http://www.horde.org/licenses/lgpl21. 7 * 8 * @category Horde 9 * @copyright 2013-2014 Horde LLC 10 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 11 * @package Imap_Client 12 */ 13 14 /** 15 * A Horde_HashTable implementation for caching IMAP/POP data. 16 * Requires the Horde_HashTable and Horde_Pack packages. 17 * 18 * @author Michael Slusarz <slusarz@horde.org> 19 * @category Horde 20 * @copyright 2013-2014 Horde LLC 21 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 22 * @package Imap_Client 23 * @since 2.17.0 24 */ 25 class Horde_Imap_Client_Cache_Backend_Hashtable 26 extends Horde_Imap_Client_Cache_Backend 27 { 28 /** Separator for CID between mailbox and UID. */ 29 const CID_SEPARATOR = '|'; 30 31 /** 32 * The working data for the current pageload. All changes take place to 33 * this data. 34 * 35 * @var array 36 */ 37 protected $_data = array(); 38 39 /** 40 * HashTable object. 41 * 42 * @var Horde_HashTable 43 */ 44 protected $_hash; 45 46 /** 47 * Mailbox level data. 48 * 49 * @var array 50 */ 51 protected $_mbox = array(); 52 53 /** 54 * Horde_Pack singleton object. 55 * 56 * @var Horde_Pack 57 */ 58 protected $_pack; 59 60 /** 61 * List of mailbox/UIDs to update. 62 * Keys are mailboxes. Values are arrays with three possible keys: 63 * <pre> 64 * - d: UIDs to delete 65 * - m: Was metadata updated? 66 * - u: UIDs to update 67 * </pre> 68 * 69 * @var array 70 */ 71 protected $_update = array(); 72 73 /** 74 * Constructor. 75 * 76 * @param array $params Configuration parameters: 77 * <pre> 78 * - REQUIRED parameters: 79 * - hashtable: (Horde_HashTable) A HashTable object. 80 * 81 * - Optional Parameters: 82 * - lifetime: (integer) The lifetime of the cache data (in seconds). 83 * DEFAULT: 604800 seconds (1 week) [@since 2.19.0] 84 * </pre> 85 */ 86 public function __construct(array $params = array()) 87 { 88 if (!isset($params['hashtable'])) { 89 throw new InvalidArgumentException('Missing hashtable parameter.'); 90 } 91 92 parent::__construct(array_merge(array( 93 'lifetime' => 604800 94 ), $params)); 95 } 96 97 /** 98 */ 99 protected function _initOb() 100 { 101 $this->_hash = $this->_params['hashtable']; 102 $this->_pack = new Horde_Pack(); 103 register_shutdown_function(array($this, 'save')); 104 } 105 106 /** 107 */ 108 public function get($mailbox, $uids, $fields, $uidvalid) 109 { 110 $ret = array(); 111 112 if (empty($uids)) { 113 return $ret; 114 } 115 116 $this->_loadUids($mailbox, $uids, $uidvalid); 117 118 if (empty($this->_data[$mailbox])) { 119 return $ret; 120 } 121 122 if (!empty($fields)) { 123 $fields = array_flip($fields); 124 } 125 $ptr = &$this->_data[$mailbox]; 126 $to_delete = array(); 127 128 foreach ($uids as $val) { 129 if (isset($ptr[$val])) { 130 if (is_string($ptr[$val])) { 131 try { 132 $ptr[$val] = $this->_pack->unpack($ptr[$val]); 133 } catch (Horde_Pack_Exception $e) { 134 $to_delete[] = $val; 135 continue; 136 } 137 } 138 139 $ret[$val] = (empty($fields) || empty($ptr[$val])) 140 ? $ptr[$val] 141 : array_intersect_key($ptr[$val], $fields); 142 } else { 143 $to_delete[] = $val; 144 } 145 } 146 147 $this->deleteMsgs($mailbox, $to_delete); 148 149 return $ret; 150 } 151 152 /** 153 */ 154 public function getCachedUids($mailbox, $uidvalid) 155 { 156 $this->_loadMailbox($mailbox, $uidvalid); 157 return $this->_mbox[$mailbox]['u']->ids; 158 } 159 160 /** 161 */ 162 public function set($mailbox, $data, $uidvalid) 163 { 164 $this->_loadUids($mailbox, array_keys($data), $uidvalid); 165 166 $d = &$this->_data[$mailbox]; 167 $to_add = array(); 168 169 foreach ($data as $k => $v) { 170 if (isset($d[$k]) && is_string($d[$k])) { 171 try { 172 $d[$k] = $this->_pack->unpack($d[$k]); 173 } catch (Horde_Pack_Exception $e) { 174 continue; 175 } 176 } 177 178 $d[$k] = (isset($d[$k]) && is_array($d[$k])) 179 ? array_merge($d[$k], $v) 180 : $v; 181 $this->_update[$mailbox]['u'][$k] = true; 182 unset($this->_update[$mailbox]['d'][$k]); 183 $to_add[] = $k; 184 } 185 186 if (!empty($to_add)) { 187 $this->_mbox[$mailbox]['u']->add($to_add); 188 $this->_update[$mailbox]['m'] = true; 189 } 190 } 191 192 /** 193 */ 194 public function getMetaData($mailbox, $uidvalid, $entries) 195 { 196 $this->_loadMailbox($mailbox, $uidvalid); 197 198 return empty($entries) 199 ? $this->_mbox[$mailbox]['d'] 200 : array_intersect_key($this->_mbox[$mailbox]['d'], array_flip($entries)); 201 } 202 203 /** 204 */ 205 public function setMetaData($mailbox, $data) 206 { 207 $this->_loadMailbox($mailbox, isset($data['uidvalid']) ? $data['uidvalid'] : null); 208 209 $this->_mbox[$mailbox]['d'] = array_merge( 210 $this->_mbox[$mailbox]['d'], 211 $data 212 ); 213 $this->_update[$mailbox]['m'] = true; 214 } 215 216 /** 217 */ 218 public function deleteMsgs($mailbox, $uids) 219 { 220 if (empty($uids)) { 221 return; 222 } 223 224 $this->_loadMailbox($mailbox); 225 226 foreach ($uids as $val) { 227 unset( 228 $this->_data[$mailbox][$val], 229 $this->_update[$mailbox]['u'][$val] 230 ); 231 $this->_update[$mailbox]['d'][$val] = true; 232 } 233 234 $this->_mbox[$mailbox]['u']->remove($uids); 235 $this->_update[$mailbox]['m'] = true; 236 } 237 238 /** 239 */ 240 public function deleteMailbox($mailbox) 241 { 242 /* Do this action immediately, instead of at shutdown. Makes coding 243 * simpler. */ 244 $this->_loadMailbox($mailbox); 245 246 $this->_hash->delete(array_merge( 247 array($this->_getCid($mailbox)), 248 array_values($this->_getMsgCids($mailbox, $this->_mbox[$mailbox]['u'])) 249 )); 250 251 unset( 252 $this->_data[$mailbox], 253 $this->_mbox[$mailbox], 254 $this->_update[$mailbox] 255 ); 256 } 257 258 /** 259 */ 260 public function clear($lifetime) 261 { 262 /* Only can clear mailboxes we know about. */ 263 foreach (array_keys($this->_mbox) as $val) { 264 $this->deleteMailbox($val); 265 } 266 267 $this->_data = $this->_mbox = $this->_update = array(); 268 } 269 270 /** 271 * Updates the cache. 272 */ 273 public function save() 274 { 275 foreach ($this->_update as $mbox => $val) { 276 if (!empty($val['u'])) { 277 $ptr = &$this->_data[$mbox]; 278 foreach ($this->_getMsgCids($mbox, array_keys($val['u'])) as $k2 => $v2) { 279 try { 280 $this->_hash->set( 281 $v2, 282 $this->_pack->pack($ptr[$k2]), 283 array('expire' => $this->_params['lifetime']) 284 ); 285 } catch (Horde_Pack_Exception $e) { 286 $this->deleteMsgs($mbox, array($v2)); 287 $val['d'][] = $v2; 288 } 289 } 290 } 291 292 if (!empty($val['d'])) { 293 $this->_hash->delete(array_values( 294 $this->_getMsgCids($mbox, $val['d']) 295 )); 296 } 297 298 if (!empty($val['m'])) { 299 try { 300 $this->_hash->set( 301 $this->_getCid($mbox), 302 $this->_pack->pack($this->_mbox[$mbox]), 303 array('expire' => $this->_params['lifetime']) 304 ); 305 } catch (Horde_Pack_Exception $e) {} 306 } 307 } 308 309 $this->_update = array(); 310 } 311 312 /** 313 * Loads basic mailbox information. 314 * 315 * @param string $mailbox The mailbox to load. 316 * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. 317 */ 318 protected function _loadMailbox($mailbox, $uidvalid = null) 319 { 320 if (!isset($this->_mbox[$mailbox]) && 321 ($ob = $this->_hash->get($this->_getCid($mailbox)))) { 322 try { 323 $this->_mbox[$mailbox] = $this->_pack->unpack($ob); 324 } catch (Horde_Pack_Exception $e) {} 325 } 326 327 if (isset($this->_mbox[$mailbox])) { 328 if (is_null($uidvalid) || 329 ($uidvalid == $this->_mbox[$mailbox]['d']['uidvalid'])) { 330 return; 331 } 332 $this->deleteMailbox($mailbox); 333 } 334 335 $this->_mbox[$mailbox] = array( 336 // Metadata storage 337 // By default includes UIDVALIDITY of mailbox. 338 'd' => array('uidvalid' => $uidvalid), 339 // List of UIDs 340 'u' => new Horde_Imap_Client_Ids() 341 ); 342 } 343 344 /** 345 * Load UIDs by regenerating from the cache. 346 * 347 * @param string $mailbox The mailbox to load. 348 * @param array $uids The UIDs to load. 349 * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. 350 */ 351 protected function _loadUids($mailbox, $uids, $uidvalid = null) 352 { 353 if (!isset($this->_data[$mailbox])) { 354 $this->_data[$mailbox] = array(); 355 } 356 357 $this->_loadMailbox($mailbox, $uidvalid); 358 359 if (empty($uids)) { 360 return; 361 } 362 363 $ptr = &$this->_data[$mailbox]; 364 365 $load = array_flip( 366 array_diff_key( 367 $this->_getMsgCids( 368 $mailbox, 369 array_unique(array_intersect($this->_mbox[$mailbox]['u']->ids, $uids)) 370 ), 371 $this->_data[$mailbox] 372 ) 373 ); 374 375 foreach (array_filter($this->_hash->get(array_keys($load))) as $key => $val) { 376 $ptr[$load[$key]] = $val; 377 } 378 } 379 380 /** 381 * Create the unique ID used to store the mailbox data in the cache. 382 * 383 * @param string $mailbox The mailbox to cache. 384 * 385 * @return string The cache ID. 386 */ 387 protected function _getCid($mailbox) 388 { 389 return implode(self::CID_SEPARATOR, array( 390 'horde_imap_client', 391 $this->_params['username'], 392 $mailbox, 393 $this->_params['hostspec'], 394 $this->_params['port'] 395 )); 396 } 397 398 /** 399 * Return a list of cache IDs for mailbox/UID pairs. 400 * 401 * @param string $mailbox The mailbox to cache. 402 * @param array $ids The UID list. 403 * 404 * @return array List of UIDs => cache IDs. 405 */ 406 protected function _getMsgCids($mailbox, $ids) 407 { 408 $cid = $this->_getCid($mailbox); 409 $out = array(); 410 411 foreach ($ids as $val) { 412 $out[$val] = $cid . self::CID_SEPARATOR . $val; 413 } 414 415 return $out; 416 } 417 418 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |