0

I am trying to download a zip file through php. The filename is stored in a database and all the files are stored in a folder named "products". This is the code I am using:

function downloadProduct($id, $connection){
    $sql = "SELECT filename FROM productdata WHERE id = '$id'";
    $query = mysqli_query($connection, $sql);
    if(mysqli_num_rows($query) == 1){
        $file = basename(mysqli_fetch_assoc($query)["filename"]);
        $filePath = "products/" . $file;
        if(file_exists($filePath)){
            header("Cache-Control: public");
            header("Content-Description: File Transfer");
            header("Content-Disposition: attachment; filename=$file");
            header("Content-Type: application/zip");
            header("Content-Transfer-Encoding: binary");

            readfile($filePath);
            exit;
        }
        echo("<script>alert('This file (' + '$file' + ') does not exist.')</script>");
    }
    else{
        echo("<script>alert('Can not download this file.')</script>");
    }
}

The filepath is always the correct one (when I alert it), but when the file is read, it does not stop displaying these characters on the bottom of my page:

.I*��9UZ��3�8s�A��u�sz]���~������x�����9&NU�""c$M��.��^��N���U�ַΣ�p�hc��K��b�>�Sզ�<��k��l��rofz~���ۛ9�[��͜���֡�\�n�z�y��϶T�W�;�᧔e���{qO #m�/�#�L�=�a�_��e��l)5�e�q�&�#��g��s-������{L|i�[8�ZV�|v+�\��G���I�iDShS�g�n(7���� W���˛������T�k�p�K���/]�^��7��,Uwf�ZѼ�"U���L\T%���7<�MP���,_���S�3�>M�9�>ǩ_�V��ᯇ.�iUι�a����F�K�ڦéc�9��ܗki�KK�u��\�u�F䨪���b������3��q���ָ~�e\o�׷���:G�U�q��K���V��

I also tried different headers, but it didn't changed anything. The code seems to be correct for me. I hope someone can help me. Thank you.

philale
  • 437
  • 4
  • 15
  • Your code is vulnerable to [**SQL injection**](https://en.wikipedia.org/wiki/SQL_injection) attacks. Instead of building queries with string concatenation, always use [**prepared statements**](https://secure.php.net/manual/en/pdo.prepare.php) with [**bound parameters**](https://secure.php.net/manual/en/pdostatement.bindparam.php). See [**this page**](https://phptherightway.com/#databases) and [**this post**](https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php) for some good examples. – Alex Howansky Apr 05 '21 at 18:14
  • 1
    You'd see this sort of behavior if you've got any output being generated before this function fires. – Alex Howansky Apr 05 '21 at 18:16
  • @AlexHowansky Thank you for the information! I will try to change it. The page gets redirected with an url paramenter and then the function gets called. Thank you for the quick answer! – philale Apr 05 '21 at 18:29
  • In response to a single HTTP request you can either present a web content for the browser to display, or you can deliver a file to save. You cannot do both at once. Pages that _appear_ to do this use `` redirects to trigger a second request to download the actual file. – Sammitch Apr 05 '21 at 20:32
  • Thank you for your answer! Could you please give an example? I also need to "post" the id to php. – philale Apr 05 '21 at 21:02

1 Answers1

1

This looks like a header problem. I use these headers for output of a ZIP file:

header('Content-type: application/octet-stream');
header('Content-Transfer-Encoding: binary');
header('Content-disposition: attachment; filename='.$filename);

You could give them a try. It is the extension of the file that makes it a ZIP file, not the Content-Type header.

I am not sure this will help. Many other issues could cause your problem.

KIKO Software
  • 15,283
  • 3
  • 18
  • 33