请注意,当您的 Web 服务器通过 FastCGI 运行 PHP 时,此功能不起作用。会话数组中将没有进度信息。
不幸的是,PHP 只有在上传完成后才能获取数据,并且无法显示任何进度。
希望这些信息有所帮助。
当 session.upload_progress.enabled INI 选项启用时,PHP 将能够跟踪正在上传的单个文件的上传进度。此信息对于实际的上传请求本身并不是特别有用,但在文件上传期间,应用程序可以向单独的端点发送 POST 请求(例如,通过 XHR)以检查状态。
当上传正在进行时,上传进度将在 $_SESSION 超全局变量中可用,并且当将与 session.upload_progress.name INI 设置同名的变量 POST 时。当 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 处理程序已成功或未成功完成时为 true
"files" => array(
0 => array(
"field_name" => "file1", // <input/> 字段的名称
// 以下 3 个元素等于 $_FILES 中的那些
"name" => "foo.avi",
"tmp_name" => "/tmp/phpxxxxxx",
"error" => 0,
"done" => true, // POST 处理程序已完成处理此文件时为 true
"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 Warning: Unknown: The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in Unknown on line 0",
那么放错位置的输入可能是原因。值得再次提及的是,隐藏元素必须位于文件元素之前。
请注意,如果您运行该代码并打印出 $_SESSSION[$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.save_path 和 session.name(在您的应用程序中)!
上传信息请求必须是 POST,并且具有与您的隐藏输入(session.upload_progress.name)相同的 value 和 name。
信息
它可以在 IIS /FastCGI 下工作(在 PHP 5.4 和 PHP 8.2 中,其他版本未测试)。
看起来,如果您发送一个带有如下字段的表单
<?php echo '<input type="hidden" name="'.ini_get('session.upload_progress.name') .'" value="123" />'; ?>
并且没有任何“文件”类型的字段,服务器将返回 500 错误。
session.upload_progress 更新完全忽略通过 session_set_save_handler() 设置的自定义会话处理程序。