简体   繁体   English

PHP Mailer上传文件的正确方法

[英]Correct way to upload files in PHP Mailer

Hi can someone help with this bit of code I am trying use to handle and test my file uploads in PHPMailer?您好有人可以帮助我尝试使用这段代码来处理和测试我在 PHPMailer 中的文件上传吗? It basically checks that the file is correct and then renames the file name by using the users name plus field name and a date and time.它主要检查文件是否正确,然后使用用户名加上字段名以及日期和时间重命名文件名。 There are multiple files but I am not using a multi uploader but instead separate fields so I can keep a track of which file is which.有多个文件,但我没有使用多上传器,而是使用单独的字段,因此我可以跟踪哪个文件是哪个。

The script seems to work and there are no errors in the php error logs but I'm told this is a security flaw in my previous post and that my "pathinfo call should be testing the path to the tmp_name of the actual file and NOT the given original name. This is a serious security flaw."该脚本似乎有效,并且 php 错误日志中没有错误,但有人告诉我这是我之前帖子中的一个安全漏洞,我的“pathinfo 调用应该测试实际文件的 tmp_name 的路径,而不是原名。这是一个严重的安全漏洞。”

Unfortunately I'm not sure which of the 2 usages of pathinfo is wrong.不幸的是,我不确定 pathinfo 的两种用法中哪一种是错误的。 If I change $file["name"] to $file["tmp_name"] for $imageFileExt then I don't get a file extension and if I change $file["name"] to $file["tmp_name"] on $imageFileType then I just get wrongfile error.如果我将 $file["name"] 更改为 $file["tmp_name"] 以获得 $imageFileExt,那么我不会得到文件扩展名,如果我将 $file["name"] 更改为 $file["tmp_name"] $imageFileType 然后我就得到 wrongfile 错误。 Any help would be much appreciated.任何帮助将非常感激。 Thanks.谢谢。

    foreach ( $_FILES as $key => $file ) {
    
    //get the file extension
                $imageFileExt = strtolower( pathinfo( $file["name"], PATHINFO_EXTENSION ) );
    
//change the name of each file in $_FILES array to 
//the persons name plus file field plus date plus time plus file extension 
//such as :joe_bloggs_bank_statement_1_9_10_21_10_55.jpg
//and joe_bloggs_pay_slip_1_9_10_21_10_55.jpg
                $file['name'] = clean($_POST['appName']). "_" . $key . "_" . $dateKey . "." . $imageFileExt;
    
    // get the file type
                $target_file = $target_dir . basename($file["name"]);
                $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
    
    
    // get file size
                $check = getimagesize($file["tmp_name"]);
                if($check === false) {
                    $fileMessage .=  $key."=noimage,";
                    $uploadOk = 0;
                }
    
    // Allow certain file formats
    
            else if($imageFileType !== "jpg" && $imageFileType !== "png" && $imageFileType !== "jpeg"
                   && $imageFileType !== "gif" ) {
                    $fileMessage .=  $key."=wrongfile,";
                    $uploadOk = 0;
                }
    
    // Check if file already exists
            else if (file_exists($target_file)) {
                    $fileMessage .=  $key."=fileexists,";
                    $uploadOk = 0;
                }
    
    
    // Check file size
            else if ($file["size"] > 20000000) { //20mb
                    $fileMessage .=  $key."=toobig,";
                    $uploadOk = 0;
                }
    // creates a set of links to the uploaded files on the server 
    // to be placed in the body of the email (the files themselves do not get attached in the email
                $fileString .= strtoupper($key).": <a href='example.com/uploads/".$file['name']."'>".$file['name']."</a><br>";
    
    
            }

I think you may be confused by the distinction between these things.我想你可能会对这些东西之间的区别感到困惑。 The file itself is a bunch of bytes provided by the user.文件本身是用户提供的一堆字节。 Its filename is metadata about that file, also supplied by the user.它的文件名是关于该文件的元数据,也是由用户提供的。 The tmp_name is also metadata about the file, but is safe because it is not supplied by the user. tmp_name 也是关于文件的元数据,但它是安全的,因为它不是由用户提供的。

At no point are you using move_uploaded_file() or is_uploaded_file() .您绝不会使用move_uploaded_file()is_uploaded_file() These are necessary to validate that the uploaded files are real uploaded files that have been handled correctly by PHP before your script is run.这些对于验证上传的文件是真正的上传文件是必要的,并且在您的脚本运行之前已由 PHP 正确处理。 That's the very first thing you should do before trusting anything else in $_FILES .在信任$_FILES中的任何其他内容之前,这是您应该做的第一件事。

The reason it's important to not trust the name property is that filenames can be used as an attack vector, for example by including path traversal sequences (such as ../ ), SQL escapes ( ' ), or characters that might do unexpected things if used in shell contexts ( \ , > , etc).不信任name属性很重要的原因是文件名可以用作攻击向量,例如通过包含路径遍历序列(例如../ )、SQL 转义符 ( ' ) 或可能执行意外操作的字符在 shell 上下文中使用( \>等)。 The tmp_name is generated by PHP itself and does not contain user-supplied data, though you need to use the functions mentioned above to ensure that this is real data and not also injected by the user. tmp_name由 PHP 自己生成,不包含用户提供的数据,但您需要使用上述函数来确保这是真实数据,而不是用户注入的数据。

Similarly, the filename can't be relied upon to tell you accurately what type a file is – search for "polyglot files" for why that can be a problem.同样,不能依赖文件名来准确地告诉您文件的类型——搜索“多语言文件”以了解这可能成为问题的原因。

You don't show what's in your clean() function, so we can't say whether what it does is effective.你没有显示你的clean() function 中有什么,所以我们不能说它所做的是否有效。

In your previous question I referred you to the PHPMailer send file upload example .在您之前的问题中,我向您推荐了 PHPMailer 发送文件上传示例 This shows how to handle an upload safely.这显示了如何安全地处理上传。 For example, it takes whatever name is provided and hashes it, producing a string that is guaranteed to be safe from user-supplied data that is not.例如,它采用提供的任何名称并对其进行哈希处理,从而生成一个保证不受用户提供的数据影响的字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM