Возникли проблемы с загрузкой PHP - PullRequest
0 голосов
/ 05 сентября 2018

Итак, у меня была эта проблема раньше, но это была проблема с версией PHP. Сейчас дело не в этом.

Никогда не менял код, и он работал нормально. Изменился только хостинг, но я не думаю, что это должно иметь проблему.

Единственное, что я получаю - это мусорный код.

ссылка на скачивание выглядит так: https://example.com/forum/download.php?file=TEST.zip

<?php

$file = 'TEST.zip';
if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header("Content-Type: application/octet-stream");
    header('Content-Disposition: attachment; filename='.basename($file));
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    while (ob_get_level()) {
        ob_end_clean();
    }
    readfile($file);
    exit;
}

?>

1 Ответ

0 голосов
/ 05 сентября 2018

Лучшее, что я могу понять с ограниченным кодом, это удалить эту вещь ?> Я ненавижу этот тег, я никогда не использую его лично.

Это не нужно, если после PHP нет ничего похожего на HTML, и он может действительно повредить загрузку вашего файла, если это так

?>
//empty line here

Из-за того, как работает PHP, он будет выводить что-либо вне тегов в виде контента, поэтому все, что до или после них, может оказаться в вашем файле в зависимости от того, где произойдет вызов и все такое.

Я думаю, exit позаботится об этом, но мне не нравится этот тег. Потому что, если вы включаете кучу файлов PHP в свое приложение, для того, чтобы все испортить, требуется всего один файл с пробелом вне тегов, и удачи вам в этом.

Этот бит

while (ob_get_level()) {
    ob_end_clean();
}

Очищает выходной буфер, если он установлен, который, если это все, что есть в вашем файле, вероятно, не установлен. Лично я бы сделал это так:

<?php  
 //start output buffering
 ob_start();

//be careful with casing
// - Windows is case insensitive
// - Linux is case sensitive
//for example if the file is named text.zip
//it will work on Windows, but be mission on Linux

$file = 'TEST.zip';

//without the file no download can happen
// -- so kill it before header are sent
// -- that way if file is missing we can easily debug it.
if (file_exists($file)) die("Missing required file {$file}");

header('Content-Description: File Transfer');
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));

$debug = '';
while (ob_get_level()) {
    //end all output buffering before file download
    //save this stuff, there could be useful debug information in here.
    $debug .= ob_get_clean();
}

if(!empty($debug)){
    //put "stuff" in a file 
    // -- FILE_APPEND = append to end of log
    // -- lock writing on the file for this opperation
    // --- its possible 2 clients could download the same time.
    file_put_contents(__DIR__.'/download_error.txt', $debug, FILE_APPEND|FILE_EX);
}

//finally output the file
readfile($file);
//this is good
exit;

Таким образом, вы можете записать вывод без путаницы при загрузке. По сути, вы выбрасываете эти вещи, и это может быть полезной информацией.

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

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

SECURITY

В качестве последнего замечания я должен упомянуть, что вы должны быть очень осторожны с этим ?file=TEST.zip Злоумышленник может сделать это.

 ?file=../../../../etc/passwd  //which is a bad example (unless PHP is admin)

По сути, они могут использовать ваш ввод для пересечения структуры каталогов. Лучше было бы сделать это так

 $file = false;
 switch($_GET['file']){
      case 'TEST.zip': //you can even use a hash 
          $file = 'TEST.zip';
      break;

      //you can even use a hash instead of the name
      //this prevents errors caused by things like quotes in the filename.
      //something as simple as switch(md5($_GET['file'])), is finr
      case 'uiOzAWe8aser':
          //then the user has no access to your filesystem
         $file = 'TEST.zip';
      break;
      default: die('File not found '.$_GET['file'];
 }

Конечно, во многих случаях это может быть непрактично, но вы можете проверить это в БД и т. Д.

...