您可能想知道为什么要将文件“放入”数据库,而不仅仅是文件系统。好吧,大多数时候,你不会。
在 PHP 应用程序需要存储整个文件的情况下,首选方法是将文件保存到服务器的文件系统上,并将文件的物理位置存储在数据库中。这通常被认为是存储文件的最简单,最快的方法。
但是,您可能会发现自己希望将文件本身与数据库中的其他数据一起保留。这使您可以 – 或者更确切地说:MySQL – 完全控制文件数据,而不仅仅是文件在服务器上的位置。
不过,这种方法有一些缺点,例如;性能下降,增加了 PHP 代码和数据库结构的复杂性。在实际应用程序中使用它之前,您应该仔细考虑这一点。
话虽如此,本文演示了如何将文件从浏览器上传到 MySQL,以及如何将文件发送回浏览器。
开始之前
为了顺利完成此操作,您应该熟悉以下内容:
作战计划
与所有程序一样,在我们开始编写之前,我们需要提前计划一点。只是为了让我们在写之前知道我们要写什么。
在开始程序之前,我们需要设计数据库。这不是一个复杂的设计,因为我们不是在谈论创建一些复杂的归档系统。我们只需要一个表,其中包含文件的 BLOB 字段和各种其他字段来存储有关文件的信息,例如名称、大小、类型。
现在。该程序的第一阶段是将文件从我们的用户获取到我们的 PHP 可以与之交互的服务器上。这是该过程最简单的部分,只需要一个基本的 HTML 表单。
第二阶段涉及读取上传的文件,确保它已成功上传并将其添加到数据库中。这与将文件上传到文件系统时使用的过程类似,但使用 MySQL 函数而不是文件系统函数。
第三阶段是列出已上传并保存在数据库上的所有文件,并带有一个链接,以便可以下载。这里唯一的问题是该文件在服务器上不存在,那么我们如何创建指向它的链接呢?这是第 4 阶段处理的问题,我们在第 3 阶段需要做的就是创建一个链接,其中包含嵌入在 URL 中的要下载的文件的 ID。
第四部分,也是最后一部分,是这个过程最令人困惑的部分。我们获取文件并将其发送到客户端浏览器的部分。
我们首先使用 MySQL 函数和阶段 3 发送的 ID 从数据库中获取文件数据。然后我们设置一些标头,让浏览器知道会发生什么,然后最终发送文件的内容。
现在,使用此摘要作为指南,让我们开始编写我们的程序。
阶段 0:构建数据库
数据库很简单。一个表,其中包含一个用于文件数据的 BLOB 字段和几个用于与文件相关的各种信息的字段:
CREATE TABLE `file` (
`id` Int Unsigned Not Null Auto_Increment,
`name` VarChar(255) Not Null Default 'Untitled.txt',
`mime` VarChar(50) Not Null Default 'text/plain',
`size` BigInt Unsigned Not Null Default 0,
`data` MediumBlob Not Null,
`created` DateTime Not Null,
PRIMARY KEY (`id`)
)
如您所见,我们存储文件名,包括扩展名。
我们有 mime 类型,我们用它来让浏览器知道我们正在处理哪种文件。
文件的大小(以字节为单位)。
最后是数据本身,在 MediumBlob 字段中。
第 1 阶段:上传文件
现在,我们需要从用户那里获取文件。我们设计的表格不需要用户提供任何其他信息,因此我们将使这变得简单,并创建一个只有一个“文件”输入字段和一个提交按钮的 HTML 表单:
<head>
<title>MySQL file upload example</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<form action="add_file.php" method="post" enctype="multipart/form-data">
<input type="file" name="uploaded_file"><br>
<input type="submit" value="Upload file">
</form>
<p>
<a href="list_files.php">See all files</a>
</p>
</body>
</html>
请注意 元素的第三个属性,“enctype”。这告诉浏览器如何将表单数据发送到服务器。实际上,在发送文件时,必须将其设置为“多部分/表单数据”。
如果以任何其他方式设置或根本不设置,则您的文件可能无法正确传输。
在底部,我们有一个指向我们将在第 3 阶段创建的列表的链接。
阶段 2:将文件添加到数据库
在阶段 1 中构建的窗体中,我们将操作属性设置为“add_file.php”。这是我们将在该过程的这一阶段构建它的文件。
此文件需要检查文件是否已上传,确保上传时没有错误,并将其添加到数据库中:
// Check if a file has been uploaded
if(isset($_FILES['uploaded_file'])) {
// Make sure the file was sent without errors
if($_FILES['uploaded_file']['error'] == 0) {
// Connect to the database
$dbLink = new mysqli('127.0.0.1', 'user', 'pwd', 'myTable');
if(mysqli_connect_errno()) {
die("MySQL connection failed: ". mysqli_connect_error());
}
// Gather all required data
$name = $dbLink->real_escape_string($_FILES['uploaded_file']['name']);
$mime = $dbLink->real_escape_string($_FILES['uploaded_file']['type']);
$data = $dbLink->real_escape_string(file_get_contents($_FILES ['uploaded_file']['tmp_name']));
$size = intval($_FILES['uploaded_file']['size']);
// Create the SQL query
$query = "
INSERT INTO `file` (
`name`, `mime`, `size`, `data`, `created`
)
VALUES (
'{$name}', '{$mime}', {$size}, '{$data}', NOW()
)";
// Execute the query
$result = $dbLink->query($query);
// Check if it was successfull
if($result) {
echo 'Success! Your file was successfully added!';
}
else {
echo 'Error! Failed to insert the file'
. "
{$dbLink->error}";} }else {echo 'An error accured while the file was being uploaded. '. 'Error code: '. intval($_FILES['uploaded_file']['error']); }// Close the mysql connection$dbLink->close();}else {echo 'Error! A file was not sent!';}// Echo a link back to the main pageecho '
Click here to go back
阶段 3:列出所有现有文件
因此,现在我们的数据库中有几个文件,我们需要创建一个文件列表并链接它们,以便可以下载它们:
// Connect to the database
$dbLink = new mysqli('127.0.0.1', 'user', 'pwd', 'myTable');
if(mysqli_connect_errno()) {
die("MySQL connection failed: ". mysqli_connect_error());
}
// Query for a list of all existing files
$sql = 'SELECT `id`, `name`, `mime`, `size`, `created` FROM `file`';
$result = $dbLink->query($sql);
// Check if it was successfull
if($result) {
// Make sure there are some files in there
if($result->num_rows == 0) {
echo '
There are no files in the database
';}
else {
// Print the top of a table
echo '
';
';
Name
Mime
Size (bytes)
Created
// Print each file
while($row = $result->fetch_assoc()) {
echo "
";
{$row['name']}
{$row['mime']}
{$row['size']}
{$row['created']}
Download }
// Close table
echo '
}
// Free the result
$result->free();
}
else
{
echo 'Error! SQL query failed:';
echo "
{$dbLink->error}";}// Close the mysql connection$dbLink->close();?>
第 4 阶段:下载文件
这部分是通常引起最多混乱的部分。
要真正了解其工作原理,您必须了解浏览器如何下载文件。当浏览器从 HTTP 服务器请求文件时,服务器响应将包含有关它所包含内容的确切信息。这些信息位称为标头。标头通常包括有关要发送的数据类型、响应大小的信息,如果是文件,还包括文件名。
当然还有很多其他的标题,我不会在这里介绍,但值得研究!
现在,这段代码。我们从读取第 3 阶段链接发送的 ID 开始。如果 ID 有效,我们获取有关我们收到的 ID 的文件的信息,发送标头,最后发送文件数据:
// Make sure an ID was passed
if(isset($_GET['id'])) {
// Get the ID
$id = intval($_GET['id']);
// Make sure the ID is in fact a valid ID
if($id <= 0) {
die('The ID is invalid!');
}
else {
// Connect to the database
$dbLink = new mysqli('127.0.0.1', 'user', 'pwd', 'myTable');
if(mysqli_connect_errno()) {
die("MySQL connection failed: ". mysqli_connect_error());
}
// Fetch the file information
$query = "
SELECT `mime`, `name`, `size`, `data`
FROM `file`
WHERE `id` = {$id}";
$result = $dbLink->query($query);
if($result) {
// Make sure the result is valid
if($result->num_rows == 1) {
// Get the row
$row = mysqli_fetch_assoc($result);
// Print headers
header("Content-Type: ". $row['mime']);
header("Content-Length: ". $row['size']);
header("Content-Disposition: attachment; filename=". $row['name']);
// Print data
echo $row['data'];
}
else {
echo 'Error! No image exists with that ID.';
}
// Free the mysqli resources
@mysqli_free_result($result);
}
else {
echo "Error! Query failed:
{$dbLink->error}";}@mysqli_close($dbLink); }}else {echo 'Error! No ID was passed.';}?>
任何像样的浏览器都应该能够读取标题并了解这是什么类型的文件,并且要下载而不是打开它。
终点线
所以,正如你所看到的,这并不像人们想象的那么复杂。
当然,这段代码只是为了演示目的而编写的,我不建议在不增加一点额外安全性的情况下使用它。未经编辑,此代码基本上允许任何人将任何内容上传到您的服务器,这不是一个好主意!
我希望这有所帮助,并祝你一切顺利。
原创文章,作者:筱凯,如若转载,请注明出处:https://www.jingyueyun.com/ask/206.html