// +---------------------------------------------------------------------- namespace Think\Cache\Driver; use Think\Cache; defined('THINK_PATH') or exit(); /** * Shmop缓存驱动 */ class Shmop extends Cache { /** * 架构函数 * @param array $options 缓存参数 * @access public */ public function __construct($options=array()) { if ( !extension_loaded('shmop') ) { E(L('_NOT_SUPPORT_').':shmop'); } if(!empty($options)){ $options = array( 'size' => C('SHARE_MEM_SIZE'), 'temp' => TEMP_PATH, 'project' => 's', 'length' => 0, ); } $this->options = $options; $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); $this->options['length'] = isset($options['length'])? $options['length'] : 0; $this->handler = $this->_ftok($this->options['project']); } /** * 读取缓存 * @access public * @param string $name 缓存变量名 * @return mixed */ public function get($name = false) { N('cache_read',1); $id = shmop_open($this->handler, 'c', 0600, 0); if ($id !== false) { $ret = unserialize(shmop_read($id, 0, shmop_size($id))); shmop_close($id); if ($name === false) { return $ret; } $name = $this->options['prefix'].$name; if(isset($ret[$name])) { $content = $ret[$name]; if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { //启用数据压缩 $content = gzuncompress($content); } return $content; }else { return null; } }else { return false; } } /** * 写入缓存 * @access public * @param string $name 缓存变量名 * @param mixed $value 存储数据 * @return boolean */ public function set($name, $value) { N('cache_write',1); $lh = $this->_lock(); $val = $this->get(); if (!is_array($val)) $val = array(); if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { //数据压缩 $value = gzcompress($value,3); } $name = $this->options['prefix'].$name; $val[$name] = $value; $val = serialize($val); if($this->_write($val, $lh)) { if($this->options['length']>0) { // 记录缓存队列 $this->queue($name); } return true; } return false; } /** * 删除缓存 * @access public * @param string $name 缓存变量名 * @return boolean */ public function rm($name) { $lh = $this->_lock(); $val = $this->get(); if (!is_array($val)) $val = array(); $name = $this->options['prefix'].$name; unset($val[$name]); $val = serialize($val); return $this->_write($val, $lh); } /** * 生成IPC key * @access private * @param string $project 项目标识名 * @return integer */ private function _ftok($project) { if (function_exists('ftok')) return ftok(__FILE__, $project); if(strtoupper(PHP_OS) == 'WINNT'){ $s = stat(__FILE__); return sprintf("%u", (($s['ino'] & 0xffff) | (($s['dev'] & 0xff) << 16) | (($project & 0xff) << 24))); }else { $filename = __FILE__ . (string) $project; for($key = array(); sizeof($key) < strlen($filename); $key[] = ord(substr($filename, sizeof($key), 1))); return dechex(array_sum($key)); } } /** * 写入操作 * @access private * @param string $name 缓存变量名 * @return integer|boolean */ private function _write(&$val, &$lh) { $id = shmop_open($this->handler, 'c', 0600, $this->options['size']); if ($id) { $ret = shmop_write($id, $val, 0) == strlen($val); shmop_close($id); $this->_unlock($lh); return $ret; } $this->_unlock($lh); return false; } /** * 共享锁定 * @access private * @param string $name 缓存变量名 * @return boolean */ private function _lock() { if (function_exists('sem_get')) { $fp = sem_get($this->handler, 1, 0600, 1); sem_acquire ($fp); } else { $fp = fopen($this->options['temp'].$this->options['prefix'].md5($this->handler), 'w'); flock($fp, LOCK_EX); } return $fp; } /** * 解除共享锁定 * @access private * @param string $name 缓存变量名 * @return boolean */ private function _unlock(&$fp) { if (function_exists('sem_release')) { sem_release($fp); } else { fclose($fp); } } }