
У меня есть папка с электронными письмами, сохраненными из учетной записи IMAP, которую я удалил.
Имя файла указывается в теме каждого электронного письма.
К сожалению, при использовании кодировки, отличной от ASCII, строка темы будет выглядеть так же, как она выглядит изнутри — она будет иметь префикс =_
и используемую кодировку:
=_UTF-8_Q_Auftragsbest=C3=A4tigung_(Kundennummer__)_=_20100819_150312_37.eml
=_windows-1252_Q_Best=E4tigung=3A_Wir_haben_Ihre_=_20100819_150310_28.eml
Кто-нибудь знает инструмент, который можно использовать для массового исправления этой проблемы на уровне файловой системы?
Решением было бы 1. удалить =_ENCODING
префикс и 2. если это вообще возможно, преобразовать закодированные символы в имени файла в их соответствующие файловой системе умляуты.
У меня Windows 7 или XP, но я был бы готов перенести это на виртуальную машину Linux, потому что этобольшойпапка и автоматизированное решение было быбольшой.
решение1
Я создал себе PHP-скрипт. Я подумал, что поделюсь им на случай, если у кого-то возникнет похожая проблема. Он работает для меня и нужных мне кодировок (возможно, вам придется расширить массив кодировок).
Скрипт преобразует файл в формате MIMEименарекурсивно по всей указанной структуре каталогов в UTF-8.
Это не дает полностью идеальных результатов: есть несколько специальных символов, которые дважды конвертируются или не конвертируются вообще. Насколько я могу судить, это вина экспортера IMAP или некорректная информация о кодировке внутри самого E-Mail.
mb_decode_mimeheader()
это суть всего.
Выпущено в общественное достояние; никаких гарантий. Требуется PHP 5.2.
Он должен работать как через CLI, так и через веб; я тестировал его в браузере.
Перед запуском подобных скриптов на ваших данных создавайте резервные копии.
<?php
/* Directory to parse */
$dir = "D:/IMAP";
/* Extensions to parse. Leave empty for none */
$extensions = array("eml");
/* Set to true to actually run the renaming */
define ("GO", true);
/* No need to change past this point */
/* Output content type header if not in CLI */
if (strtolower(php_sapi_name()) != "CLI")
header("Content-type: text/plain; charset=utf-8");
$FixNames = new FixEmlNames($dir, $extensions);
$FixNames->fixAll();
class FixEmlNames
{
/* List of possible encodings here */
private $encodings = array("iso-8859-1", "iso-8859-15", "windows-1252", "utf-8");
/* Encoding Prefix. The exporter exports e.g. =_iso-8859-1_ with underscores
instead of question marks */
private $encoding_prefix = "=_";
/* Encoding postfix */
private $encoding_postfix = "_";
/* Temporary storage for files */
private $files;
/* Array of file extensions to process. Leave empty to parse all files and directories */
private $extensions = array();
/* Count of renamed files */
private $count = 0;
/* Count of failed renames */
private $failed = 0;
/* Count of skipped renames */
private $skipped = 0;
/* Transform forbidden characters in host OS */
private $transform_characters = array(":" => "_", "?" => "_", ">" => "_");
function __construct($dir, $extensions = array("eml"))
{
$this->files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
$this->extensions = $extensions;
}
function fixAll()
{
echo "Starting....\n";
while($this->files->valid())
{
if (!$this->files->isDot())
{
$path = $this->files->key();
$ext = pathinfo($path, PATHINFO_EXTENSION);
if ((count($this->extensions) == 0 ) or (in_array($ext, $this->extensions)))
$this->renameOne($path);
}
$this->files->next();
}
echo "Done. ";
/* Show stats */
$status = array();
if ($this->count > 0) $status[] = $this->count." OK";
if ($this->failed > 0) $status[] = $this->failed." failed";
if ($this->skipped > 0) $status[] = $this->skipped." skipped";
echo implode(", ", $status);
}
function renameOne($fullPath)
{
$filename = pathinfo($fullPath, PATHINFO_BASENAME);
$is_mime = false;
// See whether file name is MIME encoded or not
foreach ($this->encodings as $encoding)
{ if (stristr($filename, $this->encoding_prefix.$encoding.$this->encoding_postfix))
$is_mime = true;
}
// No MIME encoding? Skip.
if (!$is_mime)
{
# uncomment to see skipped files
# echo "Skipped: $filename\n";
$this->skipped++;
return true;
}
mb_internal_encoding("UTF-8");
$filename = str_replace("_", "?", $filename); // Question marks were converted to underscores
$filename = mb_decode_mimeheader($filename);
$filename = str_replace("?", "_", $filename);
// Remove forbidden characters
$filename = strtr($filename, $this->transform_characters);
// Rename
if (constant("GO") == true)
{
// We catch the error manually
$old = error_reporting(0);
$success = rename($fullPath, realpath(dirname($fullPath)).DIRECTORY_SEPARATOR.$filename);
error_reporting($old);
if ($success)
{
echo "OK: $filename\n";
$this->count++;
return true;
}
else
{
$error = error_get_last();
$message = $error["message"];
$this->failed++;
echo "Failed renaming $fullPath. Error message: ".$message."\n";
return false;
}
}
else
{
$this->count++;
echo "Simulation: $filename\n";
return true;
}
}
}
решение2
Поскольку вы готовы перейти на Linux, вы можете установить на нем php-сервер и создать довольно простой скрипт для перекодирования файлов. Степень сложности зависит от того, занимались ли вы когда-либо программированием. Вы можете ссылаться на эти функции наphp.net
Вот функции, которые вам понадобятся
<?php
opendir ( string $path [, resource $context ] )
readdir ([ resource $dir_handle ] )
file_get_contents(ENTER THE FILE NAMES HERE WITH A VARIABLE PASSED FROM readdir)
preg_replace(REGULAR EXPRESSION TO REMOVE THE =ENCODING part of the filename)
string mb_convert_encoding ( string $str , string $to_encoding [, mixed $from_encoding ] )
file_put_contents(THE NEW FILE NAME.eml)
?>