Web 開発者を長年悩ませてきた問題は、ファイル アップロードの進行状況バーなどのリアルタイム情報をアプリケーションに追加する方法です。ユーザーはせっかちで、ブラウザが何かをしている間、ブラウザがフリーズしているのではないか、接続が遅いのではないかと考えながら座って待ちたくありません。進行状況インジケーターを提供してユーザーに有益な情報を提供し、何が起こっているかを正確に知らせます。
最初に考えてみると、最初にユーザーのコンピュータからファイルのサイズを取得し、次にファイルがサーバーにアップロードされるディレクトリで簡単な計算を行うことで、これを簡単に実現できると思うかもしれません。 2 番目の考えについては、物事は思っているほど単純ではないことがわかります。
JavaScript はファイルの名前、タイプ、さらにはネイティブ画像の幅と高さにアクセスできますが、ファイルのサイズにアクセスできるようになったのは HTML5 になってからです。残念ながら、HTML5 はまだ未完成の標準であり、すべてのブラウザで均一にサポートされているわけではありません。もう 1 つの解決策は、インストールされている Flash、Java、または ActiveX プラグインに依存することです。いいえ、それはパスします。もう 1 つの解決策は、オプションの PHP キャッシュ拡張機能をインストールすることです。ただし、ホスティング環境によっては利用できない場合があり、このような小さなタスクには過剰に思えるかもしれません。
すべてのオプションが煩わしいものでいっぱいのようで、ミッションはすぐに頭の痛いものになってしまいました。しかし、ヨーダの言葉を借りれば、「そんなものはありません…あるのです。」 PHP 5.4 では、新しい設定オプションのセットを使用して session.upload_progress を再度実行しました。
この記事では、この機能を使用して、外部ライブラリやブラウザーの依存関係を使用せずに、単純なアップロードの進行状況バーを作成する方法を説明します。まず、その仕組みについて説明し、次にタスクを完了するために必要な 4 つのファイル (アップロード フォーム、JavaScript、少しの CSS、およびファイルがロードされたステータスを返す) を作成する手順を説明します。
会議のアップロードの進行状況
ファイルのアップロードを許可するための通常の要件に加えて、進行状況を追跡するための要件がさらに 2 つあります。 session.upload_progress.enabled ディレクティブが有効になっている必要があり、Web フォームには session.upload_progress.name ディレクティブで指定された名前の非表示フィールドが存在する必要があります。 session.upload_progress.enabled が true (PHP 5.4 およびおそらくそれ以降のデフォルト) で、$_POST[session.upload_progress.name ] がファイル転送アップロードに関する $_SESSION スーパーグローバル配列で使用できる場合。
ファイル転送中の print_r() による $_SESSION 配列出力は次のようになります。
Array ( [upload_progress_myForm] => Array ( [START_TIME] => 1323733740 [CONTENT_LENGTH] => 721127769 [ bytes_processed] => 263178326 [完了] => [ファイル] =>array ([0] =>array ([FIELD_NAME] => USERFILE [名前] =>ubuntu-10.04.3-desktopi386 .iso [tmp_nameの値] => [エラー] => 0 [完了] => [START_TIME] => 1323733740 [bytes_processed] => 263178026 ) ) ) ) )
ローカルまたは高速ネットワーク上で開発し、小さなファイルをアップロードする場合、転送は非常に迅速に行われるため、進行状況を視覚的に観察することはできません。この場合、大きなファイルを転送してみるとよいでしょう。より大きなアップロードを許可するように php.ini ファイル、具体的には post_max_size ディレクティブと Upload_max_filesize ディレクティブを設定していることを確認し、運用環境に移行するときにそれらが適切な値であることを確認してください。
フォームの作成
最初に説明するファイルはアップロード フォームです。物事をできるだけ簡単にするために、この例では一度に 1 つのファイルのアップロードのみを処理できるように投稿します。また、アップロード後にファイルを保存する必要もありません。
form.php のコードは次のとおりです。
<?PHP 如果($ _SERVER [ “REQUEST_METHOD” ] == “POST” &&!空($ _FILES [ “userfile的” ])){ / / move_uploaded_file()以 } ?> <HTML> <HEAD> <TITLE>文件上传进度条</ TITLE> <链接相对= “样式表” 类型= “文/ CSS” HREF = “style.css文件” > </ HEAD> <BODY> <分区编号= “bar_blank” > <分区编号= “bar_color” > </ DIV> </ DIV> <分区编号= “状态” > </ DIV> <形式的行动= “<PHP的回声$ _SERVER?[” PHP_SELF “];?>” 方法= “POST” ID = “myForm的” 是enctype = “多部分/窗体的数据” 目标= “hidden_iframe” > <输入类型= “隐藏” 值= “myForm的” 名称= “<?PHP的回声ini_get(” session.upload_progress.name ?“);>” > <输入类型= “文件” 名称= “USERFILE” > <BR> <输入类型= “提交” 值= “开始上传” > </ FORM> <iframe的ID = “hidden_iframe” 名称= “hidden_iframe” SRC = “关于:空白” > </ IFRAME> <脚本类型= “文/ JavaScript的” SRC = “的script.js” > </ SCRIPT> </ BODY> </ HTML>
この例では、物事を単純にするために実際にファイルを処理するコードは省略されています。このようなコードがどのようなものであるかに興味がある場合は、Timothy Boronczyk による記事「File Uploading with PHP」を参照してください。
ページのタイトルを提供し、スタイルシートを含むヘッダー セクションの後に、div 要素の小さなコレクションが見つかります。 ID「bar_blank」のDIVはコンテナのプログレスバーです。 ID「bar_color」の div は、ファイルのアップロードの進行状況を動的に更新します。 「ステータス」div には、アップロードされた値のパーセントが表示されます。
该窗体设置为提交给同一个URL,并将其目标属性指向一个隐藏的iframe元素。 提交表单到一个隐藏的框架可以让你保持访问者在同一页上,而工作在后台正在做。 其实,这是一种常见的做法做“的Ajax文件上传”的时候,因为它是不可能直接发送使用JavaScript的一个文件的内容XmlHttpRequest对象。
在表格中,特殊的隐藏字段需要填充$_SESSION数组,接着出现一个文件上传输入和提交按钮。 提交表单将触发一个名为JavaScript函数startUpload()将被包含的JavaScript文件中定义。
在页面的底部是隐藏的框架,其形式将发布和进口script.js文件。
添加一些样式
下一个文件, style.css ,是相当直接的。 我定义的进度条容器的大小并给予它一个1px的黑色边框,进度条的颜色,因为它的加载,无论是IFRAME和进度条是隐藏的。
#bar_blank { 边界:固体1px的#000 ; 高度:20像素; 宽度:300像素; } #bar_color { 背景色:#006666 ; 高度:20像素; 宽度:0PX ; } #bar_blank,#hidden_iframe { 显示:无; }
客户端功能
该script.js文件是最大的组文件。 它包含六大功能,我将在下面讨论。 很多人喜欢用jQuery来提供一些功能在这里,你当然可以这样做,如果你愿意的话,但我个人更喜欢老派的做法。 类似于如何日本人放在手工制作的货物价值较高的,我只是觉得更热衷于代码,如果是我自己。
功能toggleBarVisibility(){ 变种E =的document.getElementById(“bar_blank” ); e.style.display =(e.style.display == “块” ?) “ 无” :“块” ; } 功能createRequestObject(){ 变种的http; 如果(navigator.appName == “Microsoft Internet Explorer的” ){ HTTP = 新的ActiveXObject(“Microsoft.XMLHTTP” ); } 否则{ HTTP = 新的XMLHttpRequest(); } 返回的http; } 功能sendRequest将(){ 变种的http = createRequestObject(); http.open(“GET” ,“progress.php” ); http.onreadystatechange = 函数(){用handleResponse(HTTP);}; http.send(空); } 功能用handleResponse(HTTP){ 无功响应; 如果(http.readyState == 4){ 响应= http.responseText; 的document.getElementById(“bar_color” 。)共0则回应+ “%” ; 的document.getElementById( “ 地位” 。)的innerHTML =响应+ “%” ; 如果(响应<100){ 的setTimeout(“sendRequest将()” ,1000); } 否则{ toggleBarVisibility(); 的document.getElementById( “ 地位” 。)的innerHTML = “Done(完成)。” ; } } } 功能startUpload(){ toggleBarVisibility(); 的setTimeout(“sendRequest将()” ,1000); } (函数(){ 的document.getElementById(“myForm会” )的onsubmit = startUpload; })();
该toggleBarVisibility()函数上的“bar_blank”的div根据需要显示或隐藏进度条设置合适的样式。 最初,它开始时隐藏,但会一次上传开始出现,然后再次隐藏当上载完成。
该createRequestObject()函数创建一个XMLHttpRequest或ActiveXObject根据用户的浏览器对象。 这可能是该功能大多数人都期待的jQuery或其他一些JavaScript框架来提供。
该sendRequest()函数请求progress.php文件与一个GET请求,然后调用handleResponse()函数来处理返回的数据。
该handleResponse()函数处理从响应progress.php这将是依赖于文件上传进度多项1-100之间。 我也更新了“状态”的div适当的值。 如果电流的百分比低于100然后调用JavaScript的原生setTimeout()函数来1秒后发送的更新另一个请求(你可能需要调整该值如适用),否则我再次隐藏进度条和状态设置为“完成”。
该startUpload()函数使得载栏可见,并发送一个更新请求的1秒的延迟。 这个小的延迟是必要的,为了给上传时间才能启动。
最后一个功能是一个自执行的匿名函数,它注册startUpload()与表单的提交事件。
实时进展
带来一切融合在一起的最后一个文件是progress.php文件:
<?PHP 在session_start(); 美元的关键= ini_get (“session.upload_progress.prefix” )。“myForm的” ; 如果(!空($ _SESSION [ $关键])){ $电流= $ _SESSION [ $关键] [ “bytes_processed” ]; 共$ = $ _SESSION [ $关键] [ “CONTENT_LENGTH” ]; 回声$电流< $总?CEIL ($电流/ $总量* 100):100; } 否则{ 回声100; }
该脚本执行上传输的字节数目前在总文件大小,再乘以100,并四舍五入到给一个百分比分成一些简单的数学。
有关传输的信息,关键在于有一套与session.upload_progress.prefix指令的值的串联和隐藏session.upload_progress.name字段的值。 因为我的形式通过了“myForm会”,会议的重点是与确定ini_get("session.upload_progress.prefix") . "myForm"ini_get("session.upload_progress.prefix") . "myForm" 。
下面是在行动进度条的截图:
微调行为
PHP提供了一些额外的指令来帮助微调会话上传的行为,你应该知道的。 例如,session.upload_progress.cleanup ,这是默认设置为1,清理后,立即上传已经完成了额外的会话数据。 你必须要小心,以避免潜在的竞争条件。
再看看在代码progress.php ,你会发现,我检查,看看是否$_SESSION[$key]为空或不是,然后再继续。我的JavaScript函数火了每一秒,只要结果从返回progress.php小于100。 如果session.upload_progress.cleanup已启用,我的脚本获取99%的上传和1/2-second后上传完成后,$_SESSION[$key]不会为下一个检查存在的。 如果我不考虑到这一点,然后我的JavaScript函数可能保持射击,上传完成之后也是如此。
他の 2 つのディレクティブは session.upload_progress.freq と session.upload_progress.min_freq で、セッションを更新する頻度を決定します。頻度の値は、バイト (つまり 100) または総バイト数のパーセンテージ (つまり 2%) で指定できます。 min_freq の値は秒単位で、更新間の最小秒数を表します。明らかに、min_freq が 1 秒ごとに更新されるように設定されている場合、JavaScript が 100 ミリ秒ごとにチェックするのは無意味です。 概要これで、セッション アップロードの進行状況機能を使用してファイル アップロードの進行状況バーを作成する方法をしっかりと理解できたはずです。今後は、 $_SESSION[$key]["cancel_upload"] を使用して進行中のアップロードをキャンセルするオプションを提供するなど、複数のファイルをアップロードしてみること、またはその他のアイデアを思いつくことをお勧めします。