Eine Datei kopieren und kaputte Sektoren überspringen mit PHP

Posted by in Allgemein, PHP

Ich stand heute mal wieder vor dem Problem kaputte Dateien von einer DVD zu retten. Für so etwas gibts es natürlich tolle Tools wie Isobuster etc. Aber diese haben ein kleines Problem: sie versuchen die Dateien in sehr kleinen Blöcken zu lesen. Wenn man da mal einen Bereich von 30 – 40 MB hat der zerschossen ist, dauert das Auslesen mal locker 24h und mehr. Wenn man aber bereit ist auch etwas mehr Verlust in Kauf zu nehmen aber die Datei dafür in absehbarer Zeit da zu haben ist man aufgeschmissen.

Jedoch nicht als Programmierer. Also habe ich mir schnell ein kleines Programm in PHP geschrieben, welches eine Datei in 1 MB Blöcken kopiert und bei Fehlern diese einfach mit 0x00 Zeichen auffüllt. Ich poste es einfach mal, falls es jemand einmal brauchen kann 😉

/**
 * Eine Datei kopieren und kaputte Sektoren überspringen
 */
 
 
define('BLOCKSIZE', 1024*1024); // 1 MB
 
 
if (count($argv) != 3) {
    showHelp();
}
else {
    copyFile($argv[1], $argv[2]);
}
 
function showHelp()
{
    echo "COPYIGNORE FROM TO\n";
}
 
function copyFile($from, $to)
{
    echo "Kopiere: $from => $to\n";
 
    if (!file_exists($from)) {
        die("$from nicht gefunden");
    }
 
    $handleFrom = fopen($from, "rb") or die ("$from konnte nicht geöffnet werden.");
    $handleTo = fopen($to, "wb") or die ("$to konnte nicht geöffnet werden.");
 
    $size = filesize($from);
    $c = 0;
    while ($c < $size) {
        $chunkSize = ($size - $c > BLOCKSIZE) ? BLOCKSIZE : $size - $c;
        $data = fread($handleFrom, $chunkSize);
        if ($data !== false) {
 
            fwrite($handleTo, $data);
 
            // Wenn wir einen Lesefehler finden mit 0x00 auffüllen und zum nächsten Block springen
            if (strlen($data) != $chunkSize) {
                fwrite($handleTo, str_pad('', ($chunkSize - strlen($data)), chr(0)));
                fseek($handleFrom, ($c+ $chunkSize)); // positionieren wo er sein sollte
                echo 'x';
            }
            else {
                echo '.';
            }
        }
        else {
            fwrite($handleTo, str_pad('', $chunkSize, chr(0)));
            echo 'x';
        }
        $c += $chunkSize;
    }
 
    fclose($handleFrom);
    fclose($handleTo);
    echo "done.\n";
}