【问题标题】:php how to test if file has been uploaded completelyphp如何测试文件是否已完全上传
【发布时间】:2012-04-15 09:59:55
【问题描述】:

有没有办法检查文件是否已经完全上传到服务器上?我的场景:用户通过 ftp 上传文件,而我的其他 PHP 任务正在 cronjob 中运行。现在我想检查文件是否已上传或用户是否仍在上传。这很重要,因为那时我知道我是否可以使用该文件或等到它上传。谢谢。

【问题讨论】:

  • 你的 FTP 服务器是什么?
  • 单独使用 php 实现这一点肯定没有简单的方法。如果事先不知道关于正在上传的文件的信息(例如哈希和),则在不分析 ftp 服务进程本身的情况下,无法确定文件传输是否完成或仍在进行中,或者是否可能被中断。您需要与 ftp 服务通信,看看它是否可以提供需求信息。
  • 如何检查文件是否正在被进程使用?您可以为此使用LSOF。您新发现的文件应该在 FTP 服务器进程中“打开”,直到它完全上传。
  • 所以没有可靠的方法来检查不完整的上传? :(

标签: php


【解决方案1】:

如果您可以控制执行上传的应用程序,您可以要求它将文件上传到name.tmp,并在上传完成后将其重命名为name.final。您的 PHP 脚本只能查找 *.final 名称。

【讨论】:

  • 一种无用的答案。显然,在许多情况下,这将是第一个选项,我敢肯定 OP 已经想到了 b4 询问 Q。但是如果您无权访问 ftp 服务器设置或者您不想添加另一个依赖项怎么办在您的应用中(ftp 设置)
  • @Alex 其实我这些年的经验是,问这个问题的大多数人从来没有考虑过这种方法。他们都在寻找一些自动化的方法。这不依赖于任何服务器设置。
  • 如果您的应用只需要查看完整的文件并且您依赖另一个应用配置 - ftp srv
  • @Alex 我的方法只是依赖于客户端在上传文件后重命名文件,而不是服务器做任何特别的事情。而且我特别说过,这仅适用于您可以修改客户端应用程序的情况。
  • @Shaheer 为什么这不是最好的方法,你会怎么做?
【解决方案2】:

我遇到了同样的情况,并找到了一个适合我的快速解决方案:

通过 FTP 上传文件时,filemtime($yourfile) 的值会不断修改。当time() minus filemtime($yourfile) 大于X 时,上传已停止。在我的场景中,30 对 x 来说是一个很好的值,您可能想要使用任何不同的值,但它至少应该是 3。

我知道这种方法并不能保证文件的完整性,但是,因为除了我之外没有人会上传,我敢假设。

【讨论】:

    【解决方案3】:

    如果你在 linux 上运行 php,那么 lsof 可以帮助你

    $output = array();
    exec("lsof | grep file/path/and/name.ext",$output);
    if (count($output)) {
      echo 'file in use';
    } else {
      echo 'file is ready';
    }
    

    编辑: 以防出现权限问题。通过使用 sudo 或 suid 方法,php 脚本可以获得执行 lsof 命令所需的权限。要设置 suid,您必须以 root 身份发出以下命令。

    su root
    chmod u+s /usr/sbin/lsof
    

    【讨论】:

    • 这不起作用。当我在 linux 控制台中运行命令时,我看到了正在使用该文件的进程,但是当我使用 PHP exec 运行命令时,没有返回任何内容。可能是因为 PHP 无权查看正在使用该文件的进程?
    • 你可以使用suid覆盖权限问题
    • 查看stackoverflow.com/a/2527080/1488762 以更有效地使用lsof,结果为:exec("lsof $filename >/dev/null", $dummy, $status); if (!$status) { /*in use*/ }
    【解决方案4】:

    有很多不同的方法可以解决这个问题。仅举几例:

    1. 使用在上传之前创建并在上传完成后删除的signal file
    2. 查明您的FTP server 是否有configuration option,例如为未完成的文件提供扩展名“.part”或在文件系统级别锁定文件(如vsftp)。
    3. 通过解析 UNIX/Linux lsof 命令的输出获取该目录中所有当前打开文件的列表,并检查您正在检查的文件是否在该列表中(如果您遇到权限问题)。
    4. 检查该文件的last modification 是否早于特定阈值。

    您的用户似乎可以使用他们想要的任何 FTP 客户端,所以不能使用第一种方法(信号文件)。第二和第三个答案需要对 UNIX/Linux 有更深入的了解,并且是系统依赖的。

    所以我认为method #4 是进入PHP 的方法,只要处理延迟(取决于配置的阈值)没有问题。它很简单,不依赖任何外部命令:

    // Threshold in seconds at which uploads are considered to be done.
    $threshold = 300;
    
    // Using the recursive iterator lets us check subdirectories too
    // (as this is FTP anything is possible). Its also quite fast even for
    // big directories.
    $it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($uploadDir);
    
    while($it->valid()) {
      // Ignore ".", ".." and other directories. Just recursively check all files.
      if (!$it->isDot() && !$it->isDir()) {
        // $it->key() is the current file name we are checking.
        // Just check if it's last modification was more than $threshold seconds ago.
        if (time() - filemtime($it->key() > $threshold)) {
          printf("Upload of file \"%s\" finished\n", $it->key());
    
          // Your processing goes here...
    
          // Don't forget to move the file out so that it's not identified as
          // just being completed everytime this script runs. You might also mark
          // it in any way you like as being complete if you don't want to move it.
        }
      }
      $it->next();
    }
    

    我希望这对遇到此问题的人有所帮助。


    类似问题:

    Verify whether ftp is complete or not?

    PHP: How do I avoid reading partial files that are pushed to me with FTP?

    【讨论】:

    • @Alex 谢谢,我没有意识到这一点并更新了我的答案。但正如 Nasir 指出的那样,这是权限问题,可以修复。最后,我认为方法#4是最直接的方法:)
    【解决方案5】:

    一种可能的解决方案是使用循环每隔几秒检查一次文件大小,如果两个循环之间的大小相同,则假定它已上传。

    类似:

        $filesize = array();
        $i = 0;
        while(file_exists('/myfile.ext')) {
        $i++;
    
        $filesize[$i] = filesize('/myfile.ext');
    
        if($filesize[$i - 1] == $filesize[$i]) {
        exit('Uploaded');
        }
    
    sleep(5);
    
    }
    

    【讨论】:

    • 这仍然只是一个假设。在很多情况下,文件大小在两个这样的时间间隔之间保持不变
    【解决方案6】:

    您可以使用以下方法设置线程以获取详细信息: ll -h

    获取大小列并在一定时间间隔后进行比较,如果它在 2 或 3 个时间间隔内保持不变,则可以完成上传。

    如果您需要更精确的解决方案,并且正在寻找更复杂的方法(但高效),请查看:

    http://www.php.net/manual/en/function.inotify-read.php

    您可以在我提供的链接中查看example, 您需要检查事件代码IN_CLOSE_WRITE

    取自: LINUX: how to detect that ftp file upload is finished

    【讨论】:

      【解决方案7】:

      保留修改日期的sql记录并检查是否有新修改的文​​件。

      <?php 
      $filename = 'somefile.txt';
      if (file_exists($filename)) {
      echo "$filename was last modified: " . date ("F d Y H:i:s.", filemtime($filename));
      }
      ?>
      

      【讨论】:

      • 这会告诉上传何时开始,它不会告诉上传何时结束。
      【解决方案8】:

      通过查看上传错误信息,您可以确认文件是完整上传还是部分上传

      如果上传错误代码为 3,则文件已部分上传

      假设您的文件上传字段名称 myfile

      $error=$_FILES['myfile']['error'];
      if($error>0){
      //Upload Error IS Present check what type of error
      switch($error){
          case 1:
              // UPLOAD_ERR_INI_SIZE
              // Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
              break;
          case 2:
              // UPLOAD_ERR_FORM_SIZE
              // Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
              break;
          case 3:
              // UPLOAD_ERR_PARTIAL
              // Value: 3; The uploaded file was only partially uploaded.
              break;
          case 4:
              // UPLOAD_ERR_NO_FILE
              // Value: 4; No file was uploaded.
              break;
          case 6:
              // UPLOAD_ERR_NO_TMP_DIR
              // Value: 6; Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3.
              break;
          case 7:
              // UPLOAD_ERR_CANT_WRITE
              // Value: 7; Failed to write file to disk. Introduced in PHP 5.1.0.
              break;
          case 8:
              // UPLOAD_ERR_EXTENSION
              // Value: 8; A PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop; examining the list of loaded extensions with phpinfo() may help. Introduced in PHP 5.2.0.
              break;
      }
      
      }else{
          //File IS Uploaded you can move or validate other things
      }
      

      情况 3 可以检查部分上传

      如果你想通过 FTP 程序跟踪文件上传,如果你正在运行 VSFTPD,那么你可以跟踪

      file=/var/log/vsftpd.log
      initial_files=`grep -c 'OK UPLOAD' $file`;
      while [ TRUE ]
      do
      current_files=`grep -c 'OK UPLOAD' $file`;
      if [ $current_files == $initial_files ]; then
           echo "old File Not Uploaded";
      else
           echo "new File Uploaded Process New File";
      new_file=`grep 'OK UPLOAD' $file | tail -1`;
      echo $new_file;
      initial_files=$current_files;
      fi
      sleep 1
      done
      

      理解有问题请回复

      【讨论】:

      • 他没有在网页上使用上传脚本,他正在上传到 FTP 服务器。后台进程需要检查上传是否完成。
      【解决方案9】:

      通过下一个代码上传后检查文件

      if (file_exists('http://www.domain.com/images/'.$filename)) :
      
          // Write some response as you like as a success message
      
      endif;
      

      注意:您必须自己更改图像路径,

      祝你好运:)

      【讨论】:

      • 请使用“`”标记代码 - 即if (file_exists('http://www.domain.com/images/'.$filename))
      • 客户端一开始上传就会报告文件存在,不会等待上传完成。
      • 您好,但是它会在将文件移动到不在临时文件夹中的首选文件夹后检查文件是否存在
      • 您认为 ftp-server 会这样做 - 这是不被允许的。还有服务器上传文件。您还可以通过http 检查文件是否存在,但没有提及原因。这根本无法回答问题。
      【解决方案10】:

      同意哈桑。可以使用php的file_exist函数查看。

      保存您在用户将文件(或重命名的文件,如果您正在重命名)上传到数据库中的任何表时获取的文件名。现在,您的 cron 每次运行时都会从数据库表中获取该名称,并检查该文件是否已上传。

      <?php
      $filename = '/var/www/YOUR_UPLOAD_FOLDER/xyz.txt'; //get xyz name from database
      
      if (file_exists($filename)) {
         // YOU CAN WORK WITH YOUR FILE AND CAN DELETE RELATIVE RECORD FROM DB TABLE.
      } else {
         // YOU SHOULD WAIT WHILE FILE IS UPLOADING.
      }
      ?>
      

      【讨论】:

        【解决方案11】:
        <?php
            if (move_uploaded_file($_FILES["uploader_name"]["tmp_name"], $path_name)):
                //print true condition
            else:
                //print false condition
            endif;
        ?>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-12
          • 1970-01-01
          • 2012-04-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多