请注意,当您的 Web 服务器通过 FastCGI 运行 PHP 时,此功能不起作用。会话数组中不会有任何进度信息。
不幸的是,PHP 只能在上传完成后获得数据,无法显示任何进度。
希望这些信息能有所帮助。
当 session.upload_progress.enabled INI 选项启用时,PHP 将能够跟踪正在上传的单个文件的上传进度。此信息对于实际的上传请求本身并不特别有用,但在文件上传期间,应用程序可以向单独的端点发送 POST 请求(例如,通过 XHR)以检查状态。
当上传正在进行时,上传进度将在 $_SESSION 超级全局变量中可用,并且当 POST 一个与 session.upload_progress.name INI 设置相同的名称的变量时。当 PHP 检测到此类 POST 请求时,它将在 $_SESSION 中填充一个数组,其中索引是 session.upload_progress.prefix 和 session.upload_progress.name INI 选项的连接值。该键通常通过读取这些 INI 设置来检索,即
<?php
$key = ini_get("session.upload_progress.prefix") . $_POST[ini_get("session.upload_progress.name")];
var_dump($_SESSION[$key]);
?>
也可以通过将 $_SESSION[$key]["cancel_upload"]
键设置为 **true
** 来取消当前正在进行的文件上传。在同一个请求中上传多个文件时,这只会取消当前正在进行的文件上传和待处理的文件上传,但不会删除已成功完成的上传。当像这样取消上传时,$_FILES 数组中的 error
键将被设置为 **UPLOAD_ERR_EXTENSION
**。
session.upload_progress.freq 和 session.upload_progress.min_freq INI 选项控制应该多长时间重新计算一次上传进度信息。对于这两个设置使用合理的数值,此功能的开销几乎不存在。
示例 #1 示例信息
上传进度数组结构示例。
<form action="upload.php" method="POST" enctype="multipart/form-data"> <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" /> <input type="file" name="file1" /> <input type="file" name="file2" /> <input type="submit" /> </form>
存储在会话中的数据将如下所示
<?php
$_SESSION["upload_progress_123"] = array(
"start_time" => 1234567890, // 请求时间
"content_length" => 57343257, // POST 内容长度
"bytes_processed" => 453489, // 接收并处理的字节数
"done" => false, // POST 处理程序已完成时为真,无论成功与否
"files" => array(
0 => array(
"field_name" => "file1", // <input/> 字段的名称
// 以下 3 个元素等于 $_FILES 中的那些
"name" => "foo.avi",
"tmp_name" => "/tmp/phpxxxxxx",
"error" => 0,
"done" => true, // 当 POST 处理程序已完成处理此文件时为真
"start_time" => 1234567890, // 此文件开始处理的时间
"bytes_processed" => 57343250, // 为此文件接收并处理的字节数
),
// 同一个请求中另一个未完成上传的文件
1 => array(
"field_name" => "file2",
"name" => "bar.avi",
"tmp_name" => NULL,
"error" => 0,
"done" => false,
"start_time" => 1234567899,
"bytes_processed" => 54554,
),
)
);
为了使此功能正常工作,必须禁用 Web 服务器的请求缓冲,否则 PHP 可能只在文件完全上传后才能看到文件上传。已知 Nginx 等服务器会缓冲较大的请求。
上传进度信息在执行任何脚本之前写入会话。因此,通过 ini_set() 或 session_name() 更改会话名称将导致会话没有上传进度信息。
请注意,当您的 Web 服务器通过 FastCGI 运行 PHP 时,此功能不起作用。会话数组中不会有任何进度信息。
不幸的是,PHP 只能在上传完成后获得数据,无法显示任何进度。
希望这些信息能有所帮助。
注意
将上传进度会话名称输入字段放在表单中的文件字段之前
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
<input type="file" name="file1" />
<input type="file" name="file2" />
<input type="submit" />
</form>
如果您将其放在文件字段之后,您将浪费大量时间来弄清楚原因(就像我一样……)
以下表单会让您发疯,并浪费大量时间
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="file" name="file1" />
<input type="file" name="file2" />
<input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
<input type="submit" />
</form>
不要这样做!
虽然文档中的示例是准确的,但描述有点偏差。澄清一下
PHP 将在 $_SESSION 中填充一个数组,其中索引是 session.upload_progress.prefix 的连接值和 POST 的 session.upload_progress.name 变量的值。
如果您看到
"PHP 警告:未知:会话 ID 太长或包含非法字符,有效字符为 a-z、A-Z、0-9 和 '-',在未知行 0 上",
那么放置不当的输入可能是原因。再次值得一提的是,隐藏元素必须位于文件元素之前。
请注意,如果您运行该代码并打印出 $_SESSION[$key] 的内容,您将获得一个空数组,因为 session.upload_progress.cleanup 默认情况下处于开启状态,它会在所有 POST 数据读取完成后清除进度信息。
将其设置为 Off 或 0 以查看 $_SESSION[$key] 的内容。
在实现这个过程中,我遇到了两个问题。
第一个问题 - 如果您使用 session_name() 来更改会话的名称,这将不起作用。我通过查看 phpinfo() 并看到它看到了不同的会话名称而发现了这一点。
至少在 Apache 中,设置会话的更好方法是在您的 Apache 配置中使用
php_value session.name "您的自定义名称"
它位于 Directory 指令中,可能在 .htaccess 中起作用 - 我不知道。
-=-
其次 - 在 Apache 中,不要使用 mod_mpm_prefork.so
这是我遇到的问题,这是 CentOS 7 的默认设置。
问题是它会导致 Apache 在上传完成之前等待任何其他请求。
注释掉该模块并使用 mod_mpm_worker.so 代替解决了这个问题,进度条也开始工作了。
session.upload_progress 更新完全忽略通过 session_set_save_handler() 设置的自定义会话处理程序。
似乎如果您发送一个包含以下字段的表单
<?php echo '<input type="hidden" name="'.ini_get('session.upload_progress.name') .'" value="123" />'; ?>
没有任何类型为“file”的字段,服务器响应将是 500 错误。
如果您在 php.ini 中启用了上传进度,并且您有
<form enctype="multipart/form-data" ...
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" ...
在您的表单中,但您没有指定具有 'type="file"' 的输入,您可能会丢失您的会话 ID。我正在使用 PHP 5.5,并且我在第二次加载此类页面时丢失了我的会话 ID。为了防止这种情况,您可以使用一个虚拟输入,如下所示
<form enctype="multipart/form-data" ... >
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" ... />
<input type="file"' name="dummy" style="display="none;" ... />