
Ich habe einen Ordner voller E-Mails von einem IMAP-Konto gespeichert, das ich aufgelöst habe.
Der Dateiname dient als Betreff jeder E-Mail.
Wenn nun eine Nicht-ASCII-Kodierung verwendet wird, sieht die Betreffzeile leider so aus, wie sie intern aussieht: Ihr wird das Präfix =_
und die verwendete Kodierung vorangestellt:
=_UTF-8_Q_Auftragsbest=C3=A4tigung_(Kundennummer__)_=_20100819_150312_37.eml
=_windows-1252_Q_Best=E4tigung=3A_Wir_haben_Ihre_=_20100819_150310_28.eml
Kennt jemand ein Tool, mit dem sich dieses Problem auf Dateisystemebene massenhaft beheben ließe?
Eine Lösung müsste 1. das =_ENCODING
Präfix entfernen und 2. wenn möglich die codierten Zeichen im Dateinamen in die im Dateisystem entsprechenden Umlaute umwandeln.
Ich verwende Windows 7 oder XP, aber ich wäre bereit, dies auf eine Linux-VM zu übertragen, da es sich um einegroßOrdner und eine automatisierte Lösung wäreGroßartig.
Antwort1
Ich habe mir ein PHP-Skript geschrieben. Ich dachte, ich teile es, falls jemand anderes ein ähnliches Problem hat. Es funktioniert bei mir und den Kodierungen, die ich brauche (möglicherweise müssen Sie das Kodierungsarray erweitern).
Das Skript konvertiert MIME-kodierte DateienNamenrekursiv in der gesamten angegebenen Verzeichnisstruktur in UTF-8.
Das Ergebnis ist nicht ganz perfekt: Es gibt mehrere Sonderzeichen, die doppelt oder gar nicht konvertiert werden. Soweit ich sehe, liegt das am IMAP-Exporter oder an falschen Kodierungsinformationen in der E-Mail selbst.
mb_decode_mimeheader()
ist das Herzstück des Ganzen.
Für die Öffentlichkeit freigegeben; keinerlei Garantie. PHP 5.2 ist erforderlich.
Es sollte sowohl über die Befehlszeilenschnittstelle als auch über das Internet laufen; ich habe es im Browser getestet.
Erstellen Sie Backups, bevor Sie solche Skripte auf Ihren Daten ausführen.
<?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;
}
}
}
Antwort2
Da Sie bereit sind, auf Linux umzusteigen, könnten Sie einen PHP-Server darauf installieren und ein relativ einfaches Skript zum Neukodieren der Dateien erstellen. Der Schwierigkeitsgrad hängt davon ab, ob Sie schon einmal programmiert haben. Sie können diese Funktionen aufphp.net
Diese Funktionen benötigen Sie
<?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)
?>