— Привет, это Иван Иваныч. Мы говорили с программистами сайта, у них уйдет больше времени на разработку движка. Ты не мог бы сегодня мне прислать макеты дизайна?
— Ок. Там осталось совсем не много работы.
Недолго думая и понимая, что работы осталось не совсем то и не много, достаю флешку с макетами, вставляю в юсб и вижу перед собой сообщение подобного характера: «Диск поврежден. Произвести восстановление раздела?». Я наивно согласился с предложением Виндовс. После проверки ужаснулся. Флешка была пуста, не было ни одой папки, ни одного файла, но размер занятого пространства оставался прежним ~3.5 Гб. Я как любой здравомыслящий пользователь сдержал панику и обратился с вопросами к знакомым, которые, по моему мнению, что-то в этом понимают, и к Яндексу. Из поисковика я узнал что утилита Виндовс ScanDisk посчитала все файлы «битыми» и перенесла в скрытую папку FOUND.000 и переименовала все файлы к такому образцу file0001.chk, file0002.chk. К сожалению, эта утилита не умеет восстанавливать созданные ей файлы. Ссылкой ниже я нашел решение проблемы, которое на первый взгляд было работающим и спасительным. Сторонний разработчик создал программу, которая восстанавливает такие файлы. Осталось сделать папку видимой и указать программе путь к ней. Включив отображение скрытых файлов и папок на флешке изменений не было. Не появились не файлы ни та злополучная папка FOUND.000. С этого момента я и начал действовать сам.
Я воспользовался силой PHP, потому что это единственный из языков, которые я знаю не относящийся к языкам «песочница».
Первым делом я просканировал корень флешки на наличие каталогов и файлов. И вот оно чудо, папка FOUND.000 существует, но через проводник Виндовс не отображается, странно… Радостный и довольный я просканировал и этот каталог, что бы в дальнейшем просто скопировать из него все файлы .chk в другую папку и пробовать открывать программами. Скан каталога вывел мне массив из 10000 ключей. Открывать каждый файл было не благоразумно. Опять обратился к Яндексу и узнал что существуют сигнатуры файлов. Сигнатура файла – это константа, некий постоянный набор символов, позволяющий однозначно идентифицировать, какого типа данные содержатся в данном файле. Изъясняясь проще – это фрагмент кода в файле, по которому однозначно можно понять, что это за файл, какой программой он создан и другую информацию. К примеру, exe-файл всегда начинается с символов «MZ», Rar-архив имеет в своём коде «Rar!» и т.д. Соответственно, посмотрев файл и изучив его сигнатуру, можно понять какие данные он содержит. Изучив это, я и начал писать программу.
Для начала я создал файл signature.ini, содержащий в себе данные о сигнатуре и относящемуся к ней расширению. Записи сигнатур стоит размещать в зависимости от синтаксиса самого файла, к примеру, <?xml, <?php, <?.. Если сделать наоборот выйдет что xml-файл будет с расширением php.
psd=8BPS
ai=application/vnd.adobe.illustrator
pdf=%PDF-1.
eps=%!PS-Adobe
fla=Saved by Adobe Flash
svg=<svg
jpg=0xFFD8FF
png=PNG
png=0x89504E47
png=0x89504E470D0A1A0A
jpg=0xFFD8FF
png=0x89504E470D0A1A0A
gif=GIF8
tif=0x49492A00
tif=0x4D4D002A
html=<html
html=<!DOCTYPE html
xml=<?xml
php=<?php
На тот момент это были те расширения, за которые я переживал больше всего, поэтому другие не привожу в пример. По данным ассоциациям расширений и сигнатур пошла дальнейшая разработка скрипта.
— Ок. Там осталось совсем не много работы.
Проблема
Недолго думая и понимая, что работы осталось не совсем то и не много, достаю флешку с макетами, вставляю в юсб и вижу перед собой сообщение подобного характера: «Диск поврежден. Произвести восстановление раздела?». Я наивно согласился с предложением Виндовс. После проверки ужаснулся. Флешка была пуста, не было ни одой папки, ни одного файла, но размер занятого пространства оставался прежним ~3.5 Гб. Я как любой здравомыслящий пользователь сдержал панику и обратился с вопросами к знакомым, которые, по моему мнению, что-то в этом понимают, и к Яндексу. Из поисковика я узнал что утилита Виндовс ScanDisk посчитала все файлы «битыми» и перенесла в скрытую папку FOUND.000 и переименовала все файлы к такому образцу file0001.chk, file0002.chk. К сожалению, эта утилита не умеет восстанавливать созданные ей файлы. Ссылкой ниже я нашел решение проблемы, которое на первый взгляд было работающим и спасительным. Сторонний разработчик создал программу, которая восстанавливает такие файлы. Осталось сделать папку видимой и указать программе путь к ней. Включив отображение скрытых файлов и папок на флешке изменений не было. Не появились не файлы ни та злополучная папка FOUND.000. С этого момента я и начал действовать сам.
Поиск решения
Я воспользовался силой PHP, потому что это единственный из языков, которые я знаю не относящийся к языкам «песочница».
Первым делом я просканировал корень флешки на наличие каталогов и файлов. И вот оно чудо, папка FOUND.000 существует, но через проводник Виндовс не отображается, странно… Радостный и довольный я просканировал и этот каталог, что бы в дальнейшем просто скопировать из него все файлы .chk в другую папку и пробовать открывать программами. Скан каталога вывел мне массив из 10000 ключей. Открывать каждый файл было не благоразумно. Опять обратился к Яндексу и узнал что существуют сигнатуры файлов. Сигнатура файла – это константа, некий постоянный набор символов, позволяющий однозначно идентифицировать, какого типа данные содержатся в данном файле. Изъясняясь проще – это фрагмент кода в файле, по которому однозначно можно понять, что это за файл, какой программой он создан и другую информацию. К примеру, exe-файл всегда начинается с символов «MZ», Rar-архив имеет в своём коде «Rar!» и т.д. Соответственно, посмотрев файл и изучив его сигнатуру, можно понять какие данные он содержит. Изучив это, я и начал писать программу.
Реализация
Для начала я создал файл signature.ini, содержащий в себе данные о сигнатуре и относящемуся к ней расширению. Записи сигнатур стоит размещать в зависимости от синтаксиса самого файла, к примеру, <?xml, <?php, <?.. Если сделать наоборот выйдет что xml-файл будет с расширением php.
psd=8BPS
ai=application/vnd.adobe.illustrator
pdf=%PDF-1.
eps=%!PS-Adobe
fla=Saved by Adobe Flash
svg=<svg
jpg=0xFFD8FF
png=PNG
png=0x89504E47
png=0x89504E470D0A1A0A
jpg=0xFFD8FF
png=0x89504E470D0A1A0A
gif=GIF8
tif=0x49492A00
tif=0x4D4D002A
html=<html
html=<!DOCTYPE html
xml=<?xml
php=<?php
На тот момент это были те расширения, за которые я переживал больше всего, поэтому другие не привожу в пример. По данным ассоциациям расширений и сигнатур пошла дальнейшая разработка скрипта.
<?php
ini_set('memory_limit', '512M');
set_time_limit(0);
//директория поиска
$found = "J:/FOUND.000";
//директория обработанных файлов
$repair = "C:/repair";
//список успешно обработанных файлов
$done = array();
$farray = glob($found."/*.CHK");
echo "Скан директории...\n";
flush();
if (scandir($found)) {
echo "Загрузка сигнатур...\n";
flush();
//загружаем сигнатуры
$param = file('./signature.ini');
echo "Восстановление...\n";
flush();
//сканируем директорию
foreach ($farray as $file) {
//нужна проверка файлу?
if(array_search($file, $done) != false) continue;
//получаем содержимое файла
$f = file_get_contents($file);
//пускаем цикл сигнаитур
foreach ($param as $line) {
//отделяем расширение от сигнатуры
$patern = explode("=", $line);
$pat = rtrim($patern[1]);
//ищем необходимые сигнатуры в содержимом файла
if(strpos($f, $pat) === false){
continue;
}
//создание директории
if(!is_dir($repair."/".$patern[0])){
@mkdir($repair."/".$patern[0]);
}
$file_name = explode("/", substr($file, 0, -strlen(strrchr ($file, "."))));
//формируем строку к будущему файлу
$fput = $repair."/".$patern[0]."/".$file_name[count($file_name) - 1].".".$patern[0];
//записываем полученный файл
file_put_contents($fput, $f);
//пишим в массив обработанный файл
$done[] = $file;
echo "Восстановлен файл: ".$fput."\n";
flush();
break;
}
//убираем все ненужное
unset($f);
}
//создаем директорию для непрошедших
@mkdir($repair."/bad_files");
//копируем не прошедшие файлы
foreach($farray as $file) {
if(array_search($file, $done) == false){
$file_name = explode("/", substr($file, 0, -strlen(strrchr ($file, "."))));
copy($file, $repair."/bad_files/".$file_name[count($file_name) - 1]);
}
}
$all_files = count($farray);
$all_done = count($done);
$procent = round($all_done / ($all_files / 100));
echo "Из ".$all_files." восстановлено ".$all_done." (".$procent."%)";
}
?>
* This source code was highlighted with Source Code Highlighter.
Прошу прощения за корявый код.
Скрипт раскладывает файлы по папкам одноименным с расширением. Файлы, которые обработать не удалось, помещает в папку «bad_files».
Заключение
Функционал этого скрипта далеко не идеален, сказать, что работает без косяков нельзя, но он идеально справился с основной поставленной ему задачей – спасти psd-файлы. Оригинальные имена файлов естественно не получить, но это не проблема. После мне дали программ, которые восстанавливают файлы и этот скрипт ушел в категорию «Эксперименты».
3,5 Гб он обработал примерно за 20 минут. Из 10000 восстановлено 1160 файлов (12%), хотя в сигнатуры были занесены не все типы файлов хранящихся на флешке.
Примерно по такому же алгоритму работают и антивирусы. В полнее возможно реализовать антивирус для простого файлообменника на PHP.