PHP 8.4.1 Released!

セッションのアップロード状況

INI オプション session.upload_progress.enabled を有効にすると、アップロード中の個々のファイルの進捗状況を PHP で追えるようになります。 この情報は、アップロードのリクエスト自体にとっては特に有用ではありませんが、 ファイルのアップロード中にアプリケーションから別のエンドポイントに POST リクエストを (XHR などで) 送って状態をチェックできるようになります。

アップロードの状況は、アップロードの処理中にスーパーグローバル $_SESSION で取得できます。また、 INI オプション session.upload_progress.name で設定した名前でも POST されます。PHP 側では、この POST リクエストを検出すると $_SESSION 内の配列に値を格納します。配列のインデックスは、INI オプション session.upload_progress.prefixsession.upload_progress.name の値をつなげたものです。つまり、これらの 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 配列のキー errorUPLOAD_ERR_EXTENSION が設定されます。

INI オプション session.upload_progress.freq および session.upload_progress.min_freq で、アップロードの進捗状況を再計算する頻度を制御します。 これらを適切に設定すれば、進捗状況の取得によるオーバーヘッドはほぼ無視できる程度になります。

例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/> フィールドの name
// 次の 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,
),
)
);

警告

ウェブサーバーのリクエストバッファリングを無効にしておかないと、うまく動作しません。 リクエストバッファリングが有効になっていると、PHP 側ではアップロードが完全に終わるまでアップロードされたことがわかりません。 たとえば Nginx などのサーバーは、大きなリクエストをバッファリングするようになっています。

警告

アップロード状況の情報は、あらゆるスクリプトを実行する前に、セッションに書き込まれます。 よって、セッション名を ini_set() 関数や session_name() 関数で変更してしまうと、 アップロード状況の情報が欠落したセッションが提供されることになります。

add a note

User Contributed Notes 11 notes

up
165
s.zarges
12 years ago
Note, this feature doesn't work, when your webserver is runnig PHP via FastCGI. There will be no progress informations in the session array.
Unfortunately PHP gets the data only after the upload is completed and can't show any progress.

I hope this informations helps.
up
63
howtomakeaturn
9 years ago
ATTENTION:

Put the upload progress session name input field BEFORE your file field in the form :

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

If you make it after your file field, you'll waste a lot of time figuring why (just like me ...)

The following form will make you crazy and waste really a lot of time:

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

DON'T do this!
up
24
Anonymous
11 years ago
While the example in the documentation is accurate, the description is a bit off. To clarify:

PHP will populate an array in the $_SESSION, where the index is a concatenated value of the session.upload_progress.prefix and the VALUE of the POSTed session.upload_progress.name variable.
up
14
isius
12 years ago
If you're seeing
"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",
then a misplaced input could be the cause. It's worth mentioning again that the hidden element MUST be before the file elements.
up
6
jortsc at gmail dot com
11 years ago
Note that if you run that code and you print out the content of $_SESSSION[$key] you get an empty array due that session.upload_progress.cleanup is on by default and it cleans the progress information as soon as all POST data has been read.

Set it to Off or 0 to see the content of $_SESSION[$key].
up
5
nihaopaul at gmail dot com
12 years ago
it should be noted that the hidden element come before the file element otherwise you wont get any updates.
up
3
Anonymous
11 years ago
dont't forget, that the session has to be initialized before the form is generated, otherwise the mentioned example above won't work.
up
1
alice at librelamp dot com
8 years ago
There were two gotchas that got me with implementing this.

The first - if you use session_name() to change the name of sessions, this will not work. I discovered this by looking at phpinfo() and seeing that is saw a different session name.

At least in Apache, a better way to set the session is in your apache config use

php_value session.name "your custom name"

It goes within the Directory directive, might work in .htaccess - I don't know.

-=-

Secondly - in apache, don't use mod_mpm_prefork.so

That was the problem I had, that's the default in CentOS 7.

The problem is it causes Apache to wait with any additional requests until the upload is finished.

Commenting that module out and using mod_mpm_worker.so instead fixed that problem, and the progress meter worked.
up
0
raptor98 at email dot cz
2 months ago
Warning:
Do not change session.save_path and session.name (in your application)!

The request for upload info must by POST with same value and name of your hidden input (session.upload_progress.name).

Info:
It works under IIS /FastCGI (at PHP 5.4 and PHP 8.2, other not tested).
up
1
StrateGeyti
10 years ago
It seems like if you send a form with the field like :

<?php echo '<input type="hidden" name="'.ini_get('session.upload_progress.name') .'" value="123" />'; ?>

without any field type "file", the server respons will be an 500 error.
up
1
ricki at rocker dot com
9 years ago
session.upload_progress updates completely ignore custom session handlers set via session_set_save_handler()
To Top