BLOB数据写入数据库失败
BLOB data fails to be written to a database
我创建了一个数据库,用于存储有关图像以及图像本身的各种数据。我有五个键 (id, name, size, format, file)
。 id
是自动递增的。 file
是 BLOB 类型的值 - (mediumblob)
。休息是其各自的类型。奇怪的是,除 BLOB 图像本身外,所有其他变量都已成功写入数据库。
等待用户使用 $_POST
:
上传图片
if(isset($_POST['file_one_submit'])){
$post = 'file_one_input';
}
定义所有变量。包括 $file
变量:
$file = file_get_contents($_FILES[$post]['tmp_name']);
然后我查询用新信息替换数据库中的记录:
$stmt = $conn -> prepare("REPLACE INTO `images` (id, name, size, format, file) VALUES(?, ?, ?, ?, ?);");
$stmt -> bind_param("isisb", $id, $name, $size, $format, $file);
$stmt -> execute();
执行查询后,数据库中的所有记录都会成功更新,但应包含 BLOB 数据的 file
列除外。我认为 $post
变量可能定义不正确,但是获取上传文件的名称是可行的:
upload_name = $_FILES[$post]['name'];
我试图回显 $file
变量来检查它的内容,并得到一长串数据垃圾,我认为这是在使用 [=23= 转换为 BLOB 期间生成的正确字符串] 函数。
我检查过文件的大小没有超过 mediumblob
BLOB 类型的能力。我还尝试使用 this post 检查代码中的错误,但没有成功。当代码为 运行 时,页面上不会出现任何错误或警告。我还使用 E_STRICT
启用了 error/warning 检查,但仍然没有输出。
我使用 send_long_data
方法让它工作。
(在这些示例中,我删除了示例中一些不相关的列)。
选项 1:使用 send_long_data 方法传递二进制数据
根据https://www.php.net/manual/en/mysqli-stmt.bind-param.php使用b
的好处:
Note:
If data size of a variable exceeds max. allowed packet size
(max_allowed_packet), you have to specify b in types and use
mysqli_stmt_send_long_data() to send the data in packets.
//...
if(isset($_POST['file_one_submit'])){
$post = 'file_one_input';
$id = 1;
$file = NULL;
$stmt = $conn -> prepare("REPLACE INTO `images` (id, file) VALUES(?, ?);");
$stmt->bind_param("ib", $id, $file);
//send_long_data(int $param_num, string $data): bool
$stmt->send_long_data(1, file_get_contents($_FILES[$post]['tmp_name']));
$stmt->execute();
}
?>
<form action="file.php" method="post" enctype="multipart/form-data">
<input type="file" name="file_one_input" />
<input type="submit" name="file_one_submit" value="Upload" />
</form>
选项 2:将 b 更改为 s
我认为使用 b 更好,但如果我将 b 更改为 s(字符串),这似乎也有效:
//...
if(isset($_POST['file_one_submit'])){
$post = 'file_one_input';
$id = 1;
$file = file_get_contents($_FILES[$post]['tmp_name']);
$stmt = $conn -> prepare("REPLACE INTO `images` (id, file) VALUES(?, ?);");
$stmt->bind_param("is", $id, $file);
$stmt->execute();
}
?>
<form action="file.php" method="post" enctype="multipart/form-data">
<input type="file" name="file_one_input" />
<input type="submit" name="file_one_submit" value="Upload" />
</form>
选项b
用于批量发送数据。当您的数据大小超过 max_allowed_packet
(默认为 16MB)时使用。然后,您必须使用方法 send_long_data()
以数据包的形式发送数据。
// $file should be set to NULL
$stmt->bind_param("ssssb", $id, $name, $size, $format, $file);
$fp = fopen($_FILES[$post]['tmp_name'], "r");
while (!feof($fp)) {
$stmt->send_long_data(4, fread($fp, 8192));
}
fclose($fp);
$stmt->execute();
当您确定您的 blob 数据永远不会超过限制时,您可以安全地将其绑定为字符串。默认情况下,您应该将每个变量绑定为字符串 (s
),因为在大多数情况下类型无关紧要。在 99% 的情况下,将所有内容绑定为字符串更容易、更安全。
通常,我推荐 PDO 作为更简单的解决方案,但即使使用 PDO with large objects,您仍然必须以类似的方式处理流。
如果图像用于网页,我建议不要将图像存储在数据库中。相反,写入其他网站 pages/files 树中的文件。然后构建 <img src=$path>
,其中 $path 是相对于 Web 文件根目录的。
这避免了在这个问题中被问到的问题,使数据库更有效率,实际上加快了网页的传送速度。
把路径放在table中,这样在构建网页的时候就可以构建img标签了
因此您可以使用 PHP 流 API 来操纵它。
$conn = new PDO('database settings');
$stmt = $conn->prepare("REPLACE INTO `images` (id, name, size, format, file) VALUES(?, ?, ?, ?, ?);");
$file_tmp = $_FILES['file']['tmp_name'];
$fp = fopen($file_tmp, 'rb');
$stmt->bindParam(1, $id);
$stmt->bindParam(2, $_FILES['file']['name']);
$stmt->bindParam(3, filesize($file_tmp));
$stmt->bindParam(4, $_FILES['file']['type']);
$stmt->bindParam(5, $fp, PDO::PARAM_LOB);
$conn->beginTransaction();
$stmt->execute();
$conn->commit();
此示例打开一个文件并将文件句柄传递给 PDO,以将其作为 LOB 插入。 PDO 将尽最大努力以最有效的方式将文件内容上传到数据库。
更详细的是here
我创建了一个数据库,用于存储有关图像以及图像本身的各种数据。我有五个键 (id, name, size, format, file)
。 id
是自动递增的。 file
是 BLOB 类型的值 - (mediumblob)
。休息是其各自的类型。奇怪的是,除 BLOB 图像本身外,所有其他变量都已成功写入数据库。
等待用户使用 $_POST
:
if(isset($_POST['file_one_submit'])){
$post = 'file_one_input';
}
定义所有变量。包括 $file
变量:
$file = file_get_contents($_FILES[$post]['tmp_name']);
然后我查询用新信息替换数据库中的记录:
$stmt = $conn -> prepare("REPLACE INTO `images` (id, name, size, format, file) VALUES(?, ?, ?, ?, ?);");
$stmt -> bind_param("isisb", $id, $name, $size, $format, $file);
$stmt -> execute();
执行查询后,数据库中的所有记录都会成功更新,但应包含 BLOB 数据的 file
列除外。我认为 $post
变量可能定义不正确,但是获取上传文件的名称是可行的:
upload_name = $_FILES[$post]['name'];
我试图回显 $file
变量来检查它的内容,并得到一长串数据垃圾,我认为这是在使用 [=23= 转换为 BLOB 期间生成的正确字符串] 函数。
我检查过文件的大小没有超过 mediumblob
BLOB 类型的能力。我还尝试使用 this post 检查代码中的错误,但没有成功。当代码为 运行 时,页面上不会出现任何错误或警告。我还使用 E_STRICT
启用了 error/warning 检查,但仍然没有输出。
我使用 send_long_data
方法让它工作。
(在这些示例中,我删除了示例中一些不相关的列)。
选项 1:使用 send_long_data 方法传递二进制数据
根据https://www.php.net/manual/en/mysqli-stmt.bind-param.php使用b
的好处:
Note:
If data size of a variable exceeds max. allowed packet size (max_allowed_packet), you have to specify b in types and use mysqli_stmt_send_long_data() to send the data in packets.
//...
if(isset($_POST['file_one_submit'])){
$post = 'file_one_input';
$id = 1;
$file = NULL;
$stmt = $conn -> prepare("REPLACE INTO `images` (id, file) VALUES(?, ?);");
$stmt->bind_param("ib", $id, $file);
//send_long_data(int $param_num, string $data): bool
$stmt->send_long_data(1, file_get_contents($_FILES[$post]['tmp_name']));
$stmt->execute();
}
?>
<form action="file.php" method="post" enctype="multipart/form-data">
<input type="file" name="file_one_input" />
<input type="submit" name="file_one_submit" value="Upload" />
</form>
选项 2:将 b 更改为 s
我认为使用 b 更好,但如果我将 b 更改为 s(字符串),这似乎也有效:
//...
if(isset($_POST['file_one_submit'])){
$post = 'file_one_input';
$id = 1;
$file = file_get_contents($_FILES[$post]['tmp_name']);
$stmt = $conn -> prepare("REPLACE INTO `images` (id, file) VALUES(?, ?);");
$stmt->bind_param("is", $id, $file);
$stmt->execute();
}
?>
<form action="file.php" method="post" enctype="multipart/form-data">
<input type="file" name="file_one_input" />
<input type="submit" name="file_one_submit" value="Upload" />
</form>
选项b
用于批量发送数据。当您的数据大小超过 max_allowed_packet
(默认为 16MB)时使用。然后,您必须使用方法 send_long_data()
以数据包的形式发送数据。
// $file should be set to NULL
$stmt->bind_param("ssssb", $id, $name, $size, $format, $file);
$fp = fopen($_FILES[$post]['tmp_name'], "r");
while (!feof($fp)) {
$stmt->send_long_data(4, fread($fp, 8192));
}
fclose($fp);
$stmt->execute();
当您确定您的 blob 数据永远不会超过限制时,您可以安全地将其绑定为字符串。默认情况下,您应该将每个变量绑定为字符串 (s
),因为在大多数情况下类型无关紧要。在 99% 的情况下,将所有内容绑定为字符串更容易、更安全。
通常,我推荐 PDO 作为更简单的解决方案,但即使使用 PDO with large objects,您仍然必须以类似的方式处理流。
如果图像用于网页,我建议不要将图像存储在数据库中。相反,写入其他网站 pages/files 树中的文件。然后构建 <img src=$path>
,其中 $path 是相对于 Web 文件根目录的。
这避免了在这个问题中被问到的问题,使数据库更有效率,实际上加快了网页的传送速度。
把路径放在table中,这样在构建网页的时候就可以构建img标签了
因此您可以使用 PHP 流 API 来操纵它。
$conn = new PDO('database settings');
$stmt = $conn->prepare("REPLACE INTO `images` (id, name, size, format, file) VALUES(?, ?, ?, ?, ?);");
$file_tmp = $_FILES['file']['tmp_name'];
$fp = fopen($file_tmp, 'rb');
$stmt->bindParam(1, $id);
$stmt->bindParam(2, $_FILES['file']['name']);
$stmt->bindParam(3, filesize($file_tmp));
$stmt->bindParam(4, $_FILES['file']['type']);
$stmt->bindParam(5, $fp, PDO::PARAM_LOB);
$conn->beginTransaction();
$stmt->execute();
$conn->commit();
此示例打开一个文件并将文件句柄传递给 PDO,以将其作为 LOB 插入。 PDO 将尽最大努力以最有效的方式将文件内容上传到数据库。
更详细的是here