⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 maildir.php

📁 希望此段源编码能给所有需要它的朋友带去快乐
💻 PHP
📖 第 1 页 / 共 3 页
字号:
	    }
    }

    /**
     * set flags for message
     *
     * NOTE: this method can't set the recent flag.
     *
     * @param   int   $id    number of message
     * @param   array $flags new flags for message
     * @throws  Zend_Mail_Storage_Exception
     */
    public function setFlags($id, $flags)
    {
        $info = $this->_getInfoString($flags);
        $filedata = $this->_getFileData($id);

        // TODO: move file from new to cur
        $new_filename = dirname($filedata['filename']) . DIRECTORY_SEPARATOR . "$filedata[uniq]$info";

        if (!@rename($filedata['filename'], $new_filename)) {
            /**
             * @see Zend_Mail_Storage_Exception
             */
            require_once 'Zend/Mail/Storage/Exception.php';
            throw new Zend_Mail_Storage_Exception('cannot rename file');
        }

        $filedata['flags']    = $flags;
        $filedata['filename'] = $new_filename;

        $this->_files[$id - 1] = $filedata;
    }


    /**
     * stub for not supported message deletion
     *
     * @return  null
     * @throws  Zend_Mail_Storage_Exception
     */
    public function removeMessage($id)
    {
        $filename = $this->_getFileData($id, 'filename');
        
        if ($this->_quota) {
	        $size = filesize($filename);
	    }
        
        if (!@unlink($filename)) {
            /**
             * @see Zend_Mail_Storage_Exception
             */
            require_once 'Zend/Mail/Storage/Exception.php';
            throw new Zend_Mail_Storage_Exception('cannot remove message');
        }
        unset($this->_files[$id - 1]);
        // remove the gap
        $this->_files = array_values($this->_files);
        if ($this->_quota) {
	        $this->_addQuotaEntry(0 - (int)$size, -1);
	    }
    }
    
	/**
	 * enable/disable quota and set a quota value if wanted or needed
	 *
	 * You can enable/disable quota with true/false. If you don't have
	 * a MDA or want to enforce a quota value you can also set this value
	 * here. Use array('size' => SIZE_QUOTA, 'count' => MAX_MESSAGE) do
	 * define your quota. Order of these fields does matter!
	 *
	 * @param bool|array $value new quota value
	 * @return null
	 */
    public function setQuota($value) {
    	$this->_quota = $value;
    }
    
    /**
     * get currently set quota
     *
     * @see Zend_Mail_Storage_Writable_Maildir::setQuota()
     *
     * @return bool|array
     */
    public function getQuota($fromStorage = false) {
    	if ($fromStorage) {
			$fh = @fopen($this->_rootdir . 'maildirsize', 'r');
			if (!$fh) {
				/**
				 * @see Zend_Mail_Storage_Exception
				 */
				require_once 'Zend/Mail/Storage/Exception.php';
				throw new Zend_Mail_Storage_Exception('cannot open maildirsize');
			}
			$definition = fgets($fh);
			fclose($fh);
			$definition = explode(',', trim($definition));
			$quota = array();
			foreach ($definition as $member) {
				$key = $member[strlen($member) - 1];
				if ($key == 'S' || $key == 'C') {
					$key = $key == 'C' ? 'count' : 'size';
				}
				$quota[$key] = substr($member, 0, -1);
			}
			return $quota;
    	}
    	
    	return $this->_quota;
    }
    
    /**
     * @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating maildirsize"
     */
    protected function _calculateMaildirsize() {
    	$timestamps = array();
    	$messages = 0;
    	$total_size = 0;

		if (is_array($this->_quota)) {
			$quota = $this->_quota;
		} else {
			try {
				$quota = $this->getQuota(true);
			} catch (Zend_Mail_Storage_Exception $e) {
				throw new Zend_Mail_Storage_Exception('no quota defintion found');
			}
		}
    	
    	$folders = new RecursiveIteratorIterator($this->getFolders(), RecursiveIteratorIterator::SELF_FIRST);
		foreach ($folders as $folder) {
			$subdir = $folder->getGlobalName();
			if ($subdir == 'INBOX') {
				$subdir = '';
			} else {
				$subdir = '.' . $subdir;
			}
			if ($subdir == 'Trash') {
				continue;
			}
			
			foreach (array('cur', 'new') as $subsubdir) {
				$dirname = $this->_rootdir . $subdir . DIRECTORY_SEPARATOR . $subsubdir . DIRECTORY_SEPARATOR;
				if (!file_exists($dirname)) {
					continue;
				}
				// NOTE: we are using mtime instead of "the latest timestamp". The latest would be atime
				// and as we are accessing the directory it would make the whole calculation useless.	
				$timestamps[$dirname] = filemtime($dirname);

				$dh = opendir($dirname);
				// NOTE: Should have been checked in constructor. Not throwing an exception here, quotas will 
				// therefore not be fully enforeced, but next request will fail anyway, if problem persists.
				if (!$dh) {
					continue;
				}
				
								
				while (($entry = readdir()) !== false) {
					if ($entry[0] == '.' || !is_file($dirname . $entry)) {
    	            	continue;
        	    	}
        	    	
        	    	if (strpos($entry, ',S=')) {
        	    		strtok($entry, '=');
        	    		$filesize = strtok(':');
        	    		if (is_numeric($filesize)) {
        	    			$total_size += $filesize;
        	    			++$messages;
        	    			continue;
        	    		}
        	    	}
        	    	$size = filesize($dirname . $entry);
        	    	if ($size === false) {
        	    		// ignore, as we assume file got removed
        	    		continue;
        	    	}
        	    	$total_size += $size;
        	    	++$messages;
				}
			}
		}
		
		$tmp = $this->_createTmpFile();
		$fh = $tmp['handle'];
		$definition = array();
		foreach ($quota as $type => $value) {
			if ($type == 'size' || $type == 'count') {
				$type = $type == 'count' ? 'C' : 'S';
			}
			$definition[] = $value . $type;
		}
		$definition = implode(',', $definition);
		fputs($fh, "$definition\n");
		fputs($fh, "$total_size $messages\n");
		fclose($fh);
		rename($tmp['filename'], $this->_rootdir . 'maildirsize');
		foreach ($timestamps as $dir => $timestamp) {
			if ($timestamp < filemtime($dir)) {
				unlink($this->_rootdir . 'maildirsize');
				break;
			}
		}
		
		return array('size' => $total_size, 'count' => $messages, 'quota' => $quota);
    }
    
    /**
     * @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating the quota for a Maildir++"
     */
    protected function _calculateQuota($forceRecalc = false) {
    	$fh = null;
		$total_size = 0;
		$messages   = 0;
		$maildirsize = '';
    	if (!$forceRecalc && file_exists($this->_rootdir . 'maildirsize') && filesize($this->_rootdir . 'maildirsize') < 5120) {
    		$fh = fopen($this->_rootdir . 'maildirsize', 'r');
    	}
		if ($fh) {
			$maildirsize = fread($fh, 5120);
			if (strlen($maildirsize) >= 5120) {
				fclose($fh);
				$fh = null;
				$maildirsize = '';
			}
		}
    	
    	if (!$fh) {
    		$result = $this->_calculateMaildirsize();
    		$total_size = $result['size'];
    		$messages   = $result['count'];
    		$quota      = $result['quota'];
    	} else {
    		$maildirsize = explode("\n", $maildirsize);
			if (is_array($this->_quota)) {
				$quota = $this->_quota;
			} else {
				$definition = explode(',', $maildirsize[0]);
				$quota = array();
				foreach ($definition as $member) {
					$key = $member[strlen($member) - 1];
					if ($key == 'S' || $key == 'C') {
						$key = $key == 'C' ? 'count' : 'size';
					}
					$quota[$key] = substr($member, 0, -1);
				}
			}
			unset($maildirsize[0]);
			foreach ($maildirsize as $line) {
				list($size, $count) = explode(' ', trim($line));
				$total_size += $size;
				$messages   += $count;
			}
    	}
    	
    	$over_quota = false;
    	$over_quota = $over_quota || (isset($quota['size'])  && $total_size > $quota['size']); 
    	$over_quota = $over_quota || (isset($quota['count']) && $messages   > $quota['count']);
    	// NOTE: $maildirsize equals false if it wasn't set (AKA we recalculated) or it's only
    	// one line, because $maildirsize[0] gets unsetted.
    	// Also we're using local time to calculate the 15 minute offset. Touching a file just for known the
    	// local time of the file storage isn't worth the hassle.
    	if ($over_quota && ($maildirsize || filemtime($this->_rootdir . 'maildirsize') > time() - 900)) {
    		$result = $this->_calculateMaildirsize();
    		$total_size = $result['size'];
    		$messages   = $result['count'];
    		$quota      = $result['quota'];
			$over_quota = false;
			$over_quota = $over_quota || (isset($quota['size'])  && $total_size > $quota['size']); 
			$over_quota = $over_quota || (isset($quota['count']) && $messages   > $quota['count']);
    	}
    	
    	if ($fh) {
    		// TODO is there a safe way to keep the handle open for writing?
    		fclose($fh);
    	}
    	
    	return array('size' => $total_size, 'count' => $messages, 'quota' => $quota, 'over_quota' => $over_quota);
    }
    
    protected function _addQuotaEntry($size, $count = 1) {
    	if (!file_exists($this->_rootdir . 'maildirsize')) {
    		// TODO: should get file handler from _calculateQuota
    	}
    	$size = (int)$size;
    	$count = (int)$count;
    	file_put_contents($this->_rootdir . 'maildirsize', "$size $count\n", FILE_APPEND);
    }
    
    /**
     * check if storage is currently over quota
     *
     * @param bool $detailedResponse return known data of quota and current size and message count @see _calculateQuota()
     * @return bool|array over quota state or detailed response
     */
    public function checkQuota($detailedResponse = false, $forceRecalc = false) {
    	$result = $this->_calculateQuota($forceRecalc);
    	return $detailedResponse ? $result : $result['over_quota'];
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -