Файлы Word/Excel повреждены при загрузке с PHP


Я создаю простую функцию загрузки файлов/загрузки файлов в свою базу данных. Единственная сложность заключается в том, что все файлы должны быть зашифрованы с использованием моих причудливых методов шифрования.

Итак, что я делаю, так это создаю запись SQL, в которой хранятся такие вещи, как: id_file, имя файла, расширение, размер, дата и т. Д.

Затем, как только я получу id_file, я возьму содержимое файла, зашифрую его, а затем сохраню содержимое на своем сервере как [id_file].txt.

Тогда вот код для повторная загрузка файла:

header("Pragma: public");
header('Content-Disposition: attachment;filename="'.$file['name'].'.'.$file['extension'].'"');
header('Cache-Control: max-age=0');

echo someFunctionIMadeForGettingAndDecryptingFileContents($_GET['id_file']);

exit;

Действительно простая вещь и отлично работает для всех типов файлов, КРОМЕ .docx и .xlsx. При загрузке файлов .docx или .xlsx Office выдает мне сообщение об ошибке "В слове "ИМЯ ФАЙЛА" найдено нечитаемое содержимое". Вы хотите восстановить содержимое этого документа? Если вы доверяете источнику... бла-бла" Затем я нажимаю "Да". Он немного подумает, и файл откроется просто отлично. Но, очевидно, я не могу позволить своим клиентам использовать это, если они собираются получить эту ошибку каждый раз.

Код, который я написал, отлично работает для всех других типов файлов. Даже файлы .doc, .xls и .zip работают нормально.

Моей первой мыслью было взглянуть на заголовки. Я пробовал всевозможные решения, подобные перечисленным здесь:

Почему мой загруженный файл всегда поврежден или поврежден? PHP, загружающий файл excel, становится поврежденным

Это не сработало.

Я знаю, что проблема может быть связана с добавлением дополнительных отступов или пробелов в файл. Но если я загружу файл .txt, а затем скачаю его снова... Я вижу, что ничего лишнего не добавляется.

Если я MD5 исходный файл (good.docx ) и загруженную версию исходного файла (bad.docx), хэши разные.

Если я изменюсь good.docx чтобы good.zip и распакуйте архив. Затем сделайте то же самое для bad.docx . Затем MD5 оба каталога, хэши одинаковы. И я хешировал каждый файл внутри good.zip и bad.zip и каждый хэш файла является такой же.

Также следует отметить, что в других местах на моем сервере я использую PHPWord и PHPExcel для динамического создания файлов Office, и все эти файлы отлично загружаются. Заголовки/код, которые я использую для PHPExcel, следующие:

header("Pragma: public");
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="'.$filename.'.xlsx"');
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
exit;

(Да, я пытался использовать заголовок "Тип содержимого" в моем другом коде выше, но это не помогло.)

Я также попытался сохранить файл на своем сервере, загрузить его и открыть. Я получаю ту же ошибку при прохождении этого процесса. Вот код, который я использовал для выполнения это:

$f=fopen("/myPath/temp.docx","w");
fwrite($f,someFunctionIMadeForGettingAndDecryptingFileContents($_GET['id_file']));
fclose($f);
exit;

Я попытался создать пустой файл Word под названием"blank.docx ". Затем сделал так, чтобы вместо функции сохранить новый файл.... он заменяет содержимое blank.docx с расшифрованным содержимым файла. Но при загрузке blank.docx после этого процесса я получаю все то же самое... ошибка, но в конце концов она открывается. Ни одно из свойств файла (например, шаблон: Normal.dotm), которые изначально были на blank.docx есть ли на поданном измененные blank.docx .

Я использую офис 2007

ОБНОВЛЕНИЕ

Вот ссылка для загрузки хорошей (оригинальной) версии файла: http://empowerdb.org/good.docx

А вот ссылка для загрузки плохой (обработанной) версии файла: http://empowerdb.org/bad.docx

РЕШЕНИЕ

Как указал г-н Лама ниже, моя функция шифрования отсекала несколько дополнительных нулевых байтов. Но оказалось, что виновник был не так очевиден, как вы думаете. Вот мой шифрование:

trim(base64_encode(IV.mcrypt_encrypt(MCRYPT_RIJNDAEL_128,ENCKEY,$contents,MCRYPT_MODE_CBC,IV)))

Проблема была не в trim() или base64_encode(). Это было с функцией mcrypt. Я решил эту проблему так: перед передачей содержимого файла для шифрования я сделал еще один base64_encode(). Вот так...

$file_contents_encrypted=base64_encode(myEncryptionFunction($file_contents));

И, конечно, обратное при расшифровке.

Код base64_encode технически выполняется дважды. Но я вижу, как это необходимо выполнить в этом случае ДО mcrypt из-за уникального zip-формата .docx и .xlsx

Author: Community, 2014-07-10

1 answers

Ваша функция расшифровки отсекает нулевые байты в конце файлов.

Файл good.docx заканчивается четырьмя 0x00 байтами, в то время как файл bad.docx не заканчивается ни одним. Помимо этих недостающих байтов, файлы идентичны.

$ wc -c good.docx
25123 good.docx

$ wc -c bad.docx
25119 bad.docx

$ tail -c 32 good.docx | od -x
0000000 6666 6365 7374 782e 6c6d 4b50 0605 0000
0000020 0000 0010 0010 041c 0000 5df1 0000 0000

$ tail -c 32 bad.docx | od -x
0000000 7469 4568 6666 6365 7374 782e 6c6d 4b50
0000020 0605 0000 0000 0010 0010 041c 0000 5df1

Если вы пропустите последние четыре байта good.docx, суммы md5 точно совпадут:

$ head -c -4 good.docx | md5sum
fbd32fbcc02d62dfd8bd39d390252a4b *-

$ cat bad.docx | md5sum
fbd32fbcc02d62dfd8bd39d390252a4b *-
 7
Author: Mr. Llama, 2014-07-15 15:31:28