#php #mysql #file #pdo #upload
#php #mysql #файл #pdo #загрузка
Вопрос:
Мне нужно загружать и скачивать файлы с помощью php / mysql в моем собственном маленьком проекте.
Файлы загружаются через форму с использованием POST и обрабатываются следующим образом:
<?
$passName1 = $_FILES['passport1']['name'];
$tmpName1 = $_FILES['passport1']['tmp_name'];
$fileSize1 = $_FILES['passport1']['size'];
$fileType1 = $_FILES['passport1']['type'];
$fp1 = fopen($tmpName1, 'r');
$pass_1_content = fread($fp1, filesize($tmpName1));
fclose($fp1);
?>
Затем я загружаю их с помощью этой функции:
$passport1id = insert_user_file ($db, $passName1, $fileType1, $fileSize1, $pass_1_content);
function insert_user_file ($db, $name, $type, $size, $content) {
try {
echo "<br>start insert file $name";
$insertfile = new PDO("mysql:host=".$db['server'].";dbname=".$db['db'], $db['mysql_login'], $db['mysql_pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
// set the PDO error mode to exception
$insertfile->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepare sql and bind parameters
$stmt=$insertfile->prepare ("INSERT INTO files (name, size, type, content, created) VALUES (:name, :size, :type, :content, NOW())");
$stmt->bindParam(":name", $name);
$stmt->bindParam(":size", $size);
$stmt->bindParam(":type", $type);
$stmt->bindParam(":content", $content);
$stmt->execute();
$file_id = $insertfile->lastInsertId();
return $file_id;
}
catch(PDOException $e) {
echo 'error: '. $e->getMessage();
return false;
}
}
Наличие addslashes() к имени / содержимому файла, похоже, не имеет никакого значения.
Кажется, работает нормально, однако, когда я возвращаю файл с помощью функции ниже, он кажется поврежденным:
get_file ($db, $_GET['id']);
function get_file ($db, $fileid){
try {
$get_file = new PDO("mysql:host=".$db['server'].";dbname=".$db['db'], $db['mysql_login'], $db['mysql_pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
$get_file->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$file = $get_file->prepare("SELECT * FROM files where fileid=:fileid");
$file->bindParam(":fileid", $fileid);
$file->execute();
$file_data = $file->fetch(PDO::FETCH_ASSOC);
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header("Content-length: {$file_data['size']}");
header("Content-type: {$file_data['type']}");
header("Content-Disposition: attachment; filename={$file_data['name']}");
echo $file_data['content'];
exit;
}
catch(PDOException $e) {
//echo 'error: '. $e->getMessage();
return false;
}
}
Комментарии:
1. Это
addslashes()
совершенно бесполезно. Вы используете подготовленную инструкцию с заполнителями. БД уже (внутренне) выполнит все необходимые экранирования, чтобы сохранить данные в безопасности. Все, что вы делаете, это в основном ДВОЙНОЕ кодирование, так что да, данные повреждены, потому что вы добавляете кучу обратных косых черт, которых нет в исходных данных, и они НЕ удаляются БД.2.
$pass_1_content = addslashes($pass_1_content);
Вы сами все испортили3. затем откройте поврежденную версию в текстовом / шестнадцатеричном редакторе и сравните ее с оригиналом. Убедитесь, что вы фактически получили точно такие же байты. возможно, у вас там есть предупреждения php, потому что что-то сбилось в скрипте загрузки.
4. @MarcB PHP использует копирование при записи, поэтому он не удваивает объем памяти, если вы не измените исходный массив. Поскольку строки неизменяемы, их никогда не нужно копировать.
5. каков тип поля, в котором вы это храните? если это не
blob
так (или варианты), то на него распространяются правила перевода набора символов, и некоторый случайный двоичный мусор в необработанных данных МОЖЕТ выглядеть как символ Юникода и при извлечении переводиться во что-то другое (например, сопоставление win1252 в поле, utf8 при подключении к php).
Ответ №1:
Я решил проблему! Глупый я, я должен был поместить сюда весь код, потому что это привело к путанице!
<?php
ob_start();
session_start();
require_once 'functions.php';
/*
if(!isset($_SESSION['logged']) OR $_SESSION['logged'] == false){
header ("Location: index.php");
exit;
}
*/
//somecode here
//echo "logged in ok";
get_file ($db, $_GET['id']);
?>
Виновник находится в строке 2 ob_start(); который отменяет предупреждения типа:
Warning: Cannot modify header information - headers already sent by (output started at /sata2/home/users//functions.php:289) in /sata2/home/users//functions.php on line 130
В строке 289 было несколько пробелов после ?> //some spaces were here
Это очень глупая ошибка. Большое спасибо @MarcB за намек на то, что могли быть предупреждения, которые я мог пропустить. Никогда не оставляйте пробелы после ?>
Комментарии:
1. Хороший улов. И, как правило, вам НЕ нужен финал / закрытие
?>
в PHP-скриптах. это необходимо только в том случае, если есть другой контент, отличный от PHP, который требует вывода (который, оказывается, у вас был).