使用以下代码发送一个 post 请求以复制文件
$.ajax({
url:filename,
type: 'post',
dataType: 'html',
data: {"data":someData},
success: function(data) {
console.log(data);
alert(data);
},
error:function(err){
console.log(err);
}
});
下面的函数复制文件并给我进度
function copyfiles($filename,$filesize){
$remote = fopen('../filestorage/'.$filename, 'r');
$local = fopen('../uploads/'.$filename, 'w');
$read_bytes = 0;
while(!feof($remote)) {
$buffer = fread($remote, 2048);
fwrite($local, $buffer);
$read_bytes += 2048;
$progress = min(100, 100 * $read_bytes / $filesize);
echo json_encode(array("progress"=>$progress));
}
fclose($remote);
fclose($local);
}
但我得到的是一个像下面这样的回应
{"progress":16.956449743335}{"progress":33.91289948667}
{"progress":50.869349230005}{"progress":67.82579897334}
{"progress":84.782248716675}{"progress":100}
我想一个接一个地获取,然后显示复制进度。 请建议我该怎么做。
实现此目的的一种方法是拥有两个服务(或 php 页面等)。一个服务 (s1) 可能是您已经拥有的接受请求并开始复制的服务。另一个服务 (s2) 可能使用正在复制的每个文件的状态进行响应。为了使其正常工作,您需要考虑以下几点
-
服务 S1 应立即使用开始复制的 ID 或文件名进行响应
而复制进度 应保存在映射中,其中文件的键映射到进度值(记住用户可能需要复制多个文件)
客户端应不断调用服务 S2 以获取进度值,并将文件键作为参数传递
服务 S2 应查看该映射,并使用请求的文件密钥的进度进行响应
服务和地图可以轻松地与客户端的http会话一起工作/存储,以便准确地为多个客户端提供服务。可以选择其他存储方法,我认为 http 会话对于这种情况是最直接和最合适的。
编辑
这是一个 php 的演示应用程序,其中服务 s1 正在写入 http 会话,服务 s2 正在从中读取。您的代码被注释掉,以显示您可以放置新代码的位置。
HTML/JS
<body>
<div>
<input type="radio" name="file" value="file1" />file1
<br/>
<input type="radio" name="file" value="file2" />file2
<br/>
<input type="radio" name="file" value="file3" />file3
<br/>
<input type="radio" name="file" value="file4" />file4
<br/><br/>
<input type="button" value="copy files" />
<br/><br/>
<div class="output"></div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="jquery-1.10.1.min.js"><'/script>')</script>
<script>
var progressInterval;
$('input[type=button]').on('click',function(){
var filename = $('input:checked').val();
if(!filename)return;
$.ajax({
url:'service-copy-file.php',
type: 'post',
data: {"filename":filename},
dataType:'json',
success: function(data) {
console.log(data);
if(progressInterval) {
clearInterval(progressInterval);
}
},
error:function(err){
console.log(err);
if(progressInterval) {
clearInterval(progressInterval);
}
}
});
progressInterval = setInterval(function(){
$.ajax({
url:'service-progress.php',
type: 'get',
data: {"filename":filename},
dataType:'json',
success: function(data) {
console.log(data);
$('.output').text((parseInt(data.progress))+"%");
},
error:function(err){
console.log(err);
}
});
}, 1000);
});
</script>
</body>
服务 S1
<?php
copyfiles($_POST['filename'], null);
function copyfiless($filename, $filesize) {
echo json_encode('copying ' . $filename);
}
function copyfiles($filename, $filesize) {
// $remote = fopen('../filestorage/'.$filename, 'r');
// $local = fopen('../uploads/'.$filename, 'w');
// $read_bytes = 0;
//emulate copying of a file for 10secs
$fileKey = $filename;
$progress = 0;
$_SESSION[$fileKey] = $progress;
// while(!feof($remote)) {
while ($progress < 100) {
session_start();
// $buffer = fread($remote, 2048);
// fwrite($local, $buffer);
// $read_bytes += 2048;
// $progress = min(100, 100 * $read_bytes / $filesize);
// echo json_encode(array("progress"=>$progress));
sleep(2); //emulate copying
$progress+=10;
$_SESSION[$fileKey] = $progress;
session_write_close();
}
session_start();
unset($_SESSION[$fileKey]); //completed copy
// fclose($remote);
// fclose($local);
}
?>
服务 S2
<?php
session_start();
getProgress($_GET['filename']);
function getProgress($filename) {
if (isset($_SESSION[$filename])) {
echo json_encode(array("progress" => $_SESSION[$filename]));
} else {
echo json_encode(array("progress" => -1));
// echo json_encode('could not find file:'.$filename);
}
}
?>
这将提供正在复制的文件的实时进度。但是,如果您想从服务器获得响应而不必从客户端轮询它,那么您需要使用 HTTP 服务器推送,这需要更多的努力来实现。
我唯一一次这样做是在 4 年前。不知道它是否会帮助你,但那是我的系统:
-
当进行长时间处理(不仅是文件传输)时,用于执行此操作的 PHP 必须将进程存储到文件(或 mysql db...)中,不要忘记关闭文件(如果您选择文件)以获得读取权限!
-
在此期间,回调(现在
ajax
,但对我来说是自动刷新)调用一个 PHP 函数,该函数返回读取文件(或数据库)的当前进程值
跳它会有所帮助!