数据库中存储的PHP文件已损坏

数据库中存储的PHP文件已损坏,php,mysqli,Php,Mysqli,我正在尝试创建一个平台,在这个平台上,用户可以在数据库中存储文件。我认为问题在于我没有在数据库中正确插入文件,因为每当我下载它们时,我都无法打开它们 我的数据库结构如下所示: ID -> INT file -> LongBlob (I need to insert files at least at maximum with 10MB) file_name -> Varchar file_type -> Varchar file_size ->

我正在尝试创建一个平台,在这个平台上,用户可以在数据库中存储文件。我认为问题在于我没有在数据库中正确插入文件,因为每当我下载它们时,我都无法打开它们

我的数据库结构如下所示:

ID        -> INT
file      -> LongBlob (I need to insert files at least at maximum with 10MB)
file_name -> Varchar
file_type -> Varchar
file_size -> Varchar 
要插入这些文件,以下是mysqli代码:

$_fileName = $_FILES['myfile']['name']; 
$_fileTmp  = $_FILES['myfile']['tmp_name'];
$_fileType = $_FILES['myfile']['type'];
$_fileSize = $_FILES['myfile']['size'];
$_file     = addslashes(file_get_contents($_FILES[0]['tmp_name']));
$query = $mysqli->prepare("INSERT INTO files (file, file_name, file_type, file_size)
                                      VALUES (?, ?, ?, ?)");
/*
    b = blob
    s = string
*/
$query->bind_param("bsss", $_file, $_fileName, $_fileType, $_fileSize);
$query->execute();
我相信这是正确的,但是。。 最后,要下载我使用的文件:

header("Content-length:" . $file['file_size']);
header("content-type:" .   $file['file_type']);
header("Content-disposition: download; filename=" . $file['file_name']);

echo $file['file'];
虽然当我下载文件并试图打开其损坏的文件(如.rar文件或zip文件)时。 还有,我试过使用.txt文件,结果都是空的。这是什么

谢谢

编辑:很明显,我知道存储在磁盘上比存储在数据库中要好。但是,在这种情况下,我不能存储在磁盘中,因为其他用户没有访问它的权限。如果人们出于某种原因猜测了他们可以下载的文件的名称(比如图像),这就是为什么我要存储在数据库中以避免这种情况

我还删除了
addslashes()
,但它仍然会导致文件损坏

编辑-已解决

问题出在我的
bind_param()
上。 表示“b”代表Blob,但它将以数据包的形式发送。我相信,这种情况把事情搞砸了

我所要做的就是在我的
bind_param()
中从“b”改为“s”(字符串)

评论表明,问题并非如原始问题所断言的那样是数据损坏,而是数据最初没有存储在数据库中。答案也随之改变

您正在使用
bind\u参数
存储blob。相反,我们希望您使用
发送长数据
。根据
bind param
文档:

如果在$types中指定了“b”,则相应的变量应设置为null,并且必须使用mysqli_stmt::send_long_data()或mysqli_stmt_send_long_data()发送blob,否则blob值将被视为空

这意味着实际:

$_file = addslashes(file_get_contents($_FILES[0]['tmp_name']));
$query = $mysqli->prepare("INSERT INTO files
                       (file, file_name, file_type, file_size)
                       VALUES (?, ?, ?, ?)");
$query->bind_param("bsss", $_file, $_fileName, $_fileType, $_fileSize);
$query->execute();
应该是:

$query = $mysqli->prepare("INSERT INTO files
                           (file, file_name, file_type, file_size)
                           VALUES (?, ?, ?, ?)");
$query->bind_param("bsss", NULL, $_fileName, $_fileType, $_fileSize);
$query->send_long_data(0, file_get_contents($_FILES[0]['tmp_name']));
$query->execute();
附加说明
  • 返回需要转义的字符前带有反斜杠的字符串。例如:

    "select * from User where UserName = '" . $userName . "'"
    
    如果按原样传递到数据库,将存在SQL注入的风险,因为如果用户名为“
    ”;drop table user;”
    ,则执行的查询将是:

    select * from User where UserName = ''; drop table User; ''
    
    addslashes
    将用于避免攻击:

    "select * from User where UserName = '" . addslashes($userName) . "'"
    
    给出:

    select * from User where UserName = '\'; drop table User; \''
    
    类似地,参数化查询使得通过转换特殊字符来执行SQL注入变得不可能。这意味着当用户名作为参数传递时,它将被视为数据,而不是查询的一部分。由于在将值作为参数传递之前添加斜杠,这意味着您实际上在存储反斜杠,从而损坏数据

  • 为什么要在MySQL中存储10MB的文件?一般的解决方案是将文件存储在磁盘上,而不是存储在RDBMS中

    • 接收文件非常简单,只需将文件从临时目录复制/移动到特定目录即可

    • 通过以下功能将文件发送给用户也很容易

  • 为什么将文件大小存储为
    varchar()
    ,而它是一个整数

  • 我不能存储在磁盘中,因为其他用户没有访问它的权限。如果人们出于某种原因猜测了他们可以下载的文件的名称(比如图像),这就是为什么我要存储在数据库中以避免这种情况


    这纯粹是一种错觉。当然,文件系统可以提供相同级别的安全性。没有人强迫您在web根目录中存储文件。您可以将它们存储在上面,从而无法直接访问。就这么简单。

    你为什么打电话给addslashes?据我所知,file\u get\u contents函数返回文件的内容,不是吗?调用addslashes函数会损坏文件内容。您必须按“原样”插入文件,而不进行转换。最好将文件存储在光盘上,并将引用放入数据库。@mhouse请查看我编辑的帖子。我也这么想,他为什么要将文件插入数据库?。但他可能有两个原因:第一个是引用完整性。该文件始终与数据库中的记录一起存在@你的常识:我已经有一段时间没有使用PHP了,也不知道它有什么问题。请您花几秒钟时间解释一下我的答案有什么问题,并告诉我答案是可以编辑的还是应该删除?谢谢。@MainMa,1。阅读我编辑的帖子;2.这不是瓦查尔的问题;3.感谢您对
    addslashes()
    的解释,但这也不是
    addslashes()
    的错误。我删除了它,但仍然无法工作。当我下载文件时,它已损坏。@user3355243:您对安全问题的编辑是错误的:您只需将文件存储在web服务器提供服务的目录之外。@user3355243:数据库中的数据与文件匹配吗?这将有助于发现问题是在您存储文件的阶段,还是在您将文件发送给用户的阶段。您可以参考任何关于如何实现这一点的教程吗?我怀疑是否有任何关于这一基本问题的教程。与其从数据库中读取文件,不如从文件中读取。这就是全部
    select * from User where UserName = '\'; drop table User; \''