Slyweb
На разработку сайта! Скидки 50%!

Кросс-браузерный прогрессбар jQuery + PHP

jQuery Nivo Slider

До сих пор, из-за отсутствия поддержки браузерами Internet Explorer индикации окончания загрузки файлов, приходится искать всевозможные решения для отображения процесса загрузки в процентах. Для обычных хостингов добиться правильного кроссбраузерного решения ещё сложнее, так как кроссбраузерный способ, изложенный в этой статье будет рассчитан для выделенных серверов или VPS, однако есть и объяснение не кроссбраузерного, но так же рабочего варианта.

Один из вариантов - использовать для браузеров на WebKit и Mozilla встроенных возможностей, соответствующих стандартам W3C и установка flash загрузки для Internet Explorer. Однако, указанное решение мне не подходит, так как flash всегда казалась излишней на web страницах и затрудняющей доступ к приложению из-за необходимости установки соответствующего flash плагина. Поэтому я выбрал APC и jQuery с PHP.

APC, jQuery и PHP

Плюсы APC, jQuery и PHP:

  • кроссбраузерный прогрессбар

Минусы APC, jQuery и PHP:

  • дополнительная настройка сервера;
  • точность загрузки не совсем верная, по сравнению с встроенными решениями для браузеров;

Для начала установите APC и настройте его, как показано на изображении:

APC, jQuery и PHP

откройте терминал и введите следующие команды:

  • Код
  • Чистый код
  1.yum install php-pear

        
  • Код
  • Чистый код
  1.yum install php-devel

        
  • Код
  • Чистый код
  1.yum install httpd-devel

        
  • Код
  • Чистый код
  1.pecl install apc

        

Если при установке возникнут следующие ошибки:

  • Код
  • Чистый код
  1.running: make
  2.
  3./var/tmp/APC/apc.c:463: error: 'apc_regex' has no member named 'preg'
  4./var/tmp/APC/apc.c:463: error: 'apc_regex' has no member named 'preg'
  5./var/tmp/APC/apc.c:464: error: 'apc_regex' has no member named 'nreg'
  6./var/tmp/APC/apc.c:464: error: 'apc_regex' has no member named 'nreg'
  7.
  8.make: *** [apc.lo] Error 1
  9.
10.ERROR: 'make' failed

        

необходимо выполнить:

  • Код
  • Чистый код
  1.# yum install pcre-devel

        

если не помогло, то:

  • Код
  • Чистый код
  1.yum install pcre-devel
  2.pecl install apc-beta

        

APC необходимо включать как модуль в конфигурационном файле apache и php.ini:

  • Код
  • Чистый код
  1.echo "extension=apc.so" > /etc/php.d/apc.ini

        

Ещё необходимо установить параметр частоты обновления кэша загрузки файла apc.rfc1867_freq в php.ini, например так:

  • Код
  • Чистый код
  1.apc.rfc1867_freq = 10k

        

После этого перезагрузите сервер:

  • Код
  • Чистый код
  1./etc/init.d/httpd restart

        

Если у вас PHP 5.4, - APC не нужен! Подробно об этом написано в последнем разделе статьи.

jQuery и PHP

После того как настроили APC, напишем скрипты загрызающие файлы на сервер:

  • index.php - файл с кнопкой загрузки;
  • upload_process.php - файл обрабатывающий запросы и возвращающий количество загруженного файла;

index.php

  • Код
  • Чистый код
  1.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2.<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
  3.<head>
  4.<title>Progressbar</title>
  5.
  6.
  7.<?php
  8.//скрипт загружающий файл
  9.$image_folder = "uploads/";
10.$uploaded = false;
11.
12.if(isset($_POST['upload_image'])){
13. if($_FILES['userImage']['error'] == 0 ){
14. $up = move_uploaded_file($_FILES['userImage']['tmp_name'], $image_folder.$_FILES['userImage']['name']);
15. if($up){
16. $uploaded = true;
17. }
18. }
19.}
20.?>
21.
22.<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
23.
24.<script type="text/javascript">
25.$(document).ready(function(){
26. var loader;
27.
28. // загружаем файл по событию submit
29.
30. $("#uploadImage").submit(function(e){
31. var randIDS = Math.random();
32. var p = $(this);
33.
34. p.attr('target','tmpForm');
35. // в этот же файл(index.php) загружаем наш файл
36. p.attr('action','index.php?progress='+randIDS);
37.
38. // если первый раз, то создаём нужные элементы
39. if($("#tmpForm").length == 0){
40.
41. var hidden = $("<input>");
42. hidden.attr({
43. name:"APC_UPLOAD_PROGRESS",
44. id:"progress_key",
45. type:"hidden",
46. value:randIDS
47. });
48. $("#uploadImage").prepend(hidden);
49. var frame = $("<iframe>");
50. frame.attr({
51. name:'tmpForm',
52. id:'tmpForm',
53. action:'about:blank',
54. border:0
55. }).css('display','none');
56. p.after(frame);
57. } else {
58. // иначе просто меняем переменную
59. $('#progress_key').attr({value:randIDS});
60.
61. }
62.
63. // начало загрузки файла на сервер
64. $.get("get_progress.php", {progress_key:randIDS, rand:Math.random()},
65. function(data){
66. var uploaded = parseInt(data);
67. if(uploaded == 100){
68. $(".progress, .badge").hide();
69. clearInterval(loadLoader);
70. }
71. else if(uploaded < 100)
72. {
73. $(".progress, .badge").show();
74. $(".badge").text(uploaded+"%");
75. var cWidth = $(".bar").css('width', uploaded+"%");
76. }
77. if(uploaded < 100)
78. // если статус загрузки меньше 100 то запускаем повтороную проверку
79. loader = setInterval(loadLoader,2000);
80. });
81.
82. var loadLoader = function(){
83. $.get("get_progress.php", {progress_key:randIDS, rand:Math.random()}, function(data)
84. {
85. var uploaded = parseInt(data);
86. if(uploaded == 100){
87. $(".progress, .badge").hide();
88. $('#status').empty().text('Загрузка файла звершена!');
89. // если статус загрузки равен 100, то останавливаем интервал
90. clearInterval(loader);
91. }
92. else if(uploaded < 100)
93. {
94.
95. $(".progress, .badge").show();
96. $(".badge").text(uploaded+"%");
97. var cWidth = $(".bar").css('width', uploaded+"%");
98. }
99. });
100. }
101. });
102.});
103.</script>
104.
105.</head>
106.<body>
107.<form name="uploadImage" id="uploadImage" enctype="multipart/form-data" action="" method="post" class="well">
108. <label>Upload File</label>
109. <input type="file" name="userImage" id="userImage" />
110. <span class="badge badge-info" style="display:none;">0%</span>
111. <input type="submit" class="btn btn-success" name="upload_image" id="upload_image" value="UPLOAD FILE" />
112. <div class="progress" style="display:none;"><div class="bar" style="width:0%;"></div></div>
113. <span id="status"></span>
114.</form>
115.</body>
116.</html>

        

upload_process.php

  • Код
  • Чистый код
  1.<?php
  2.session_start();
  3.error_reporting(0);
  4./*
  5.// For PHP 5.4 users
  6.$progress_key = ini_get("session.upload_progress.prefix")."uploadImage"; // uploadImage is a Form name
  7.$current = $_SESSION[$progress_key]["bytes_processed"];
  8.$total = $_SESSION[$progress_key]["content_length"];
  9.echo $current < $total ? ceil($current / $total * 100) : 100;
10.*/
11.// For PHP 5.2+ php_apc.dll or php_apc.so holder
12.if(isset($_GET['progress_key']) and !empty($_GET['progress_key'])){
13.$status = apc_fetch('upload_'.$_GET['progress_key']);
14. echo $status['current']/$status['total']*100;
15.exit;
16.}
17.?>

        

Более правильное решение отслеживания статуса загрузки

Этот способ основывается на отправке файла через ajax и обработчике собтия xhr.upload.onprogress http://hacks.mozilla.org/2009/06/xhr-progress-and-richer-file-uploading-feedback/

  • Код
  • Чистый код
  1.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2.<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
  3.<head>
  4.<title>HTML5 Bananagrams</title>
  5.
  6.
  7.
  8.
  9.<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
10.
11.
12.</head>
13.<body>
14.<script type="text/javascript">
15.$(function(){
16. $('#send').click(function(){
17.
18.
19. var xhr = new XMLHttpRequest();
20.
21. xhr.upload.onprogress = function(evt) {
22. console.log(evt);
23. if (evt.lengthComputable){
24. var percentComplete = (evt.loaded / evt.total)*100;
25.
26. $('#progressbar').text( percentComplete );
27.
28. }
29.
30. };
31.
32.
33. fileField = document.getElementById("qqfile");
34.
35.
36. if (fileField) {
37. var fileToUpload = fileField.files[0];
38. console.log(fileToUpload.name);
39.
40. var queryString = fileToUpload.name;
41. xhr.open("POST", 'upload.php', true);
42. xhr.setRequestHeader("Cache-Control", "no-cache");
43. xhr.setRequestHeader("Content-Type", "multipart/form-data");
44. xhr.setRequestHeader("X-File-Name", fileToUpload.name);
45. xhr.setRequestHeader("X-File-Size", fileToUpload.size);
46. xhr.setRequestHeader("X-File-Type", fileToUpload.type);
47. //xhr.setRequestHeader("Content-Type", "application/octet-stream");
48. xhr.send(fileToUpload);
49.
50. }
51. });
52.});
53.</script>
54.
55.
56.<form method="post" enctype="multipart/form-data" action="upload.php" target="fileupload">
57. <input type="file" name="qqfile" id="qqfile">
58. <input id="send" type="button" value="Upload file using XHR">
59.
60.</form>
61.<div id="progressbar"></div>
62.
63.
64.
65.
66.</body>
67.</html>

        

на сервере:

  • Код
  • Чистый код
  1.<?php
  2.
  3.$path = "uploads/";
  4.$filename = $_SERVER['HTTP_X_FILE_NAME'];
  5.$filesize = $_SERVER['CONTENT_LENGTH'];
  6.
  7.
  8.file_put_contents($path . $filename,
  9.file_get_contents('php://input')
10.);
11.
12.?>

        

Для тех у кого PHP 5.4

В новой версии PHP допускается использоваться глобальную переменную $_SESSION, для извлечения значения размера загруженного файла, подробная информация находится по адресу: http://php.net/manual/en/session.upload-progress.php


Александр Ермаков