📄 maildir.php
字号:
$olddir = $this->_rootdir . '.' . $folder;
foreach (array('tmp', 'new', 'cur') as $subdir) {
$subdir = DIRECTORY_SEPARATOR . $subdir;
if (!file_exists($olddir . $subdir)) {
continue;
}
// using copy or moving files would be even better - but also much slower
if (!rename($olddir . $subdir, $newdir . $subdir)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('error while moving ' . $subdir);
}
}
// create a dummy if removing fails - otherwise we can't read it next time
mkdir($olddir . DIRECTORY_SEPARATOR . 'cur');
$this->removeFolder($oldName);
}
/**
* create a uniqueid for maildir filename
*
* This is nearly the format defined in the maildir standard. The microtime() call should already
* create a uniqueid, the pid is for multicore/-cpu machine that manage to call this function at the
* exact same time, and uname() gives us the hostname for multiple machines accessing the same storage.
*
* If someone disables posix we create a random number of the same size, so this method should also
* work on Windows - if you manage to get maildir working on Windows.
* Microtime could also be disabled, altough I've never seen it.
*
* @return string new uniqueid
*/
protected function _createUniqueId()
{
$id = '';
$id .= function_exists('microtime') ? microtime(true) : (time() . ' ' . rand(0, 100000));
$id .= '.' . (function_exists('posix_getpid') ? posix_getpid() : rand(50, 65535));
$id .= '.' . php_uname('n');
return $id;
}
/**
* open a temporary maildir file
*
* makes sure tmp/ exists and create a file with a unique name
* you should close the returned filehandle!
*
* @param string $folder name of current folder without leading .
* @return array array('dirname' => dir of maildir folder, 'uniq' => unique id, 'filename' => name of create file
* 'handle' => file opened for writing)
* @throws Zend_Mail_Storage_Exception
*/
protected function _createTmpFile($folder = 'INBOX')
{
if ($folder == 'INBOX') {
$tmpdir = $this->_rootdir . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
} else {
$tmpdir = $this->_rootdir . '.' . $folder . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
}
if (!file_exists($tmpdir)) {
if (!mkdir($tmpdir)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('problems creating tmp dir');
}
}
// we should retry to create a unique id if a file with the same name exists
// to avoid a script timeout we only wait 1 second (instead of 2) and stop
// after a defined retry count
// if you change this variable take into account that it can take up to $max_tries seconds
// normally we should have a valid unique name after the first try, we're just following the "standard" here
$max_tries = 5;
for ($i = 0; $i < $max_tries; ++$i) {
$uniq = $this->_createUniqueId();
if (!file_exists($tmpdir . $uniq)) {
// here is the race condition! - as defined in the standard
// to avoid having a long time between stat()ing the file and creating it we're opening it here
// to mark the filename as taken
$fh = fopen($tmpdir . $uniq, 'w');
if (!$fh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('could not open temp file');
}
break;
}
sleep(1);
}
if (!$fh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("tried $max_tries unique ids for a temp file, but all were taken"
. ' - giving up');
}
return array('dirname' => $this->_rootdir . '.' . $folder, 'uniq' => $uniq, 'filename' => $tmpdir . $uniq,
'handle' => $fh);
}
/**
* create an info string for filenames with given flags
*
* @param array $flags wanted flags, with the reference you'll get the set flags with correct key (= char for flag)
* @return string info string for version 2 filenames including the leading colon
* @throws Zend_Mail_Storage_Exception
*/
protected function _getInfoString(&$flags)
{
// accessing keys is easier, faster and it removes duplicated flags
$wanted_flags = array_flip($flags);
if (isset($wanted_flags[Zend_Mail_Storage::FLAG_RECENT])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('recent flag may not be set');
}
$info = ':2,';
$flags = array();
foreach (Zend_Mail_Storage_Maildir::$_knownFlags as $char => $flag) {
if (!isset($wanted_flags[$flag])) {
continue;
}
$info .= $char;
$flags[$char] = $flag;
unset($wanted_flags[$flag]);
}
if (!empty($wanted_flags)) {
$wanted_flags = implode(', ', array_keys($wanted_flags));
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('unknown flag(s): ' . $wanted_flags);
}
return $info;
}
/**
* append a new message to mail storage
*
* @param string|stream $message message as string or stream resource
* @param null|string|Zend_Mail_Storage_Folder $folder folder for new message, else current folder is taken
* @param null|array $flags set flags for new message, else a default set is used
* @param bool $recent handle this mail as if recent flag has been set,
* should only be used in delivery
* @throws Zend_Mail_Storage_Exception
*/
// not yet * @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
public function appendMessage($message, $folder = null, $flags = null, $recent = false)
{
if ($this->_quota && $this->checkQuota()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('storage is over quota!');
}
if ($folder === null) {
$folder = $this->_currentFolder;
}
if (!($folder instanceof Zend_Mail_Storage_Folder)) {
$folder = $this->getFolders($folder);
}
if ($flags === null) {
$flags = array(Zend_Mail_Storage::FLAG_SEEN);
}
$info = $this->_getInfoString($flags);
$temp_file = $this->_createTmpFile($folder->getGlobalName());
// TODO: handle class instances for $message
if (is_resource($message) && get_resource_type($message) == 'stream') {
stream_copy_to_stream($message, $temp_file['handle']);
} else {
fputs($temp_file['handle'], $message);
}
fclose($temp_file['handle']);
// we're adding the size to the filename for maildir++
$size = filesize($temp_file['filename']);
if ($size) {
$info = ',S=' . $size . $info;
}
$new_filename = $temp_file['dirname'] . DIRECTORY_SEPARATOR;
$new_filename .= $recent ? 'new' : 'cur';
$new_filename .= DIRECTORY_SEPARATOR . $temp_file['uniq'] . $info;
// we're throwing any exception after removing our temp file and saving it to this variable instead
$exception = null;
if (!link($temp_file['filename'], $new_filename)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
$exception = new Zend_Mail_Storage_Exception('cannot link message file to final dir');
}
@unlink($temp_file['filename']);
if ($exception) {
throw $exception;
}
$this->_files[] = array('uniq' => $temp_file['uniq'],
'flags' => $flags,
'filename' => $new_filename);
if ($this->_quota) {
$this->_addQuotaEntry((int)$size, 1);
}
}
/**
* copy an existing message
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function copyMessage($id, $folder)
{
if ($this->_quota && $this->checkQuota()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('storage is over quota!');
}
if (!($folder instanceof Zend_Mail_Storage_Folder)) {
$folder = $this->getFolders($folder);
}
$filedata = $this->_getFileData($id);
$old_file = $filedata['filename'];
$flags = $filedata['flags'];
// copied message can't be recent
while (($key = array_search(Zend_Mail_Storage::FLAG_RECENT, $flags)) !== false) {
unset($flags[$key]);
}
$info = $this->_getInfoString($flags);
// we're creating the copy as temp file before moving to cur/
$temp_file = $this->_createTmpFile($folder->getGlobalName());
// we don't write directly to the file
fclose($temp_file['handle']);
// we're adding the size to the filename for maildir++
// TODO: maybe we should support maildirsize or we just let the MDA do the work
$size = filesize($old_file);
if ($size) {
$info = ',S=' . $size . $info;
}
$new_file = $temp_file['dirname'] . DIRECTORY_SEPARATOR . 'cur' . DIRECTORY_SEPARATOR . $temp_file['uniq'] . $info;
// we're throwing any exception after removing our temp file and saving it to this variable instead
$exception = null;
if (!copy($old_file, $temp_file['filename'])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
$exception = new Zend_Mail_Storage_Exception('cannot copy message file');
} else if (!link($temp_file['filename'], $new_file)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
$exception = new Zend_Mail_Storage_Exception('cannot link message file to final dir');
}
@unlink($temp_file['filename']);
if ($exception) {
throw $exception;
}
if ($folder->getGlobalName() == $this->_currentFolder
|| ($this->_currentFolder == 'INBOX' && $folder->getGlobalName() == '/')) {
$this->_files[] = array('uniq' => $temp_file['uniq'],
'flags' => $flags,
'filename' => $new_file);
}
if ($this->_quota) {
$this->_addQuotaEntry((int)$size, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -