【问题标题】:Corrupt uploaded files with php and mysql使用 php 和 mysql 损坏上传的文件
【发布时间】:2017-02-15 18:45:19
【问题描述】:

我自己的小项目需要用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;
        }
    }

addlashes() 对文件的名称/内容的存在似乎根本没有任何区别。 似乎工作正常,但是当我使用以下函数取回文件时,它似乎已损坏:

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;
        }
    }

【问题讨论】:

  • addslashes() 完全没用。您正在使用带有占位符的准备好的语句。数据库已经(内部)进行任何必要的转义以保证数据安全。您所做的基本上是双编码,所以是的,数据已损坏,因为您添加了一堆原始数据中不存在的反斜杠,并且它们不会被数据库删除。跨度>
  • $pass_1_content = addslashes($pass_1_content);你自己搞坏了
  • 然后将损坏的版本打开到文本/十六进制编辑器中,并将其与原始版本进行比较。确保您实际上收到了完全相同的字节。也许你那里有 php 警告,因为下载脚本中出现了问题。
  • @MarcB PHP 使用写时复制,因此除非您修改原始数组,否则它不会使内存加倍。由于字符串是不可变的,它们永远不需要被复制。
  • 您要存储的字段类型是什么?如果不是blob(或变体),那么它受字符集转换规则的约束,原始数据中的一些随机二进制垃圾可能看起来像一个 unicode 字符并在检索时被转换为其他内容(例如字段上的 win1252 排序规则) , utf8 连接到 php).

标签: php mysql file pdo upload


【解决方案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();覆盖 e 警告,例如:

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 行在?&gt; //some spaces were here 之后有几个空格

这是一个非常愚蠢的错误。非常感谢@MarcB 暗示我可能会错过一些警告。在?&gt;之后永远不要留下空格

【讨论】:

  • 好收获。作为一般规则,您不需要在 PHP 脚本中使用最终/结束 ?&gt;。只有当有其他非 PHP 内容需要输出时才需要(事实证明,你有)。
猜你喜欢
  • 1970-01-01
  • 2017-08-29
  • 1970-01-01
  • 2020-09-27
  • 1970-01-01
  • 2016-05-12
  • 1970-01-01
  • 2014-08-06
  • 1970-01-01
相关资源
最近更新 更多