我试图允许用户创建位于服务器端的照片存档并下载此存档,而无需等到白页同时发生,直到PHP完成执行为止。
我在index.html上的html表单中有一张照片列表。
<form action="include/download_archive.php" method="POST" id="downloadForm">
<input type="hidden" name="downloadForm" value="downloadForm">
<ul id="photos">
//JavaScript populates this list with photos once the document is ready.
</ul>
</form>
还有一个按钮可以触发提交表单的javascript函数。
document.getElementById('downloadForm').submit();
在处理表单提交的PHP页面(比如download_archive.php)上,我正在阅读图像数组,创建存档,然后提供存档的下载链接。
if(isset($_POST['downloadForm']) && $_POST['downloadForm']=="downloadForm"){
ignore_user_abort(true);
ini_set('max_input_vars','500000' );
set_time_limit(0);
//Checking if the zip already exists and remove it
if(file_exists('../collections/Zips/'.$collection.'.zip'))
unlink('../collections/Zips/'.$collection.'.zip');
//Get the array of images
$images = $_POST['images'];
//Push the images into a new array with the correct path
foreach($images as $image => $value) {
array_push($files, "../collections/".$collection."/".$value);
}
//Create a new archive
$zip = new ZipArchive;
$zip->open('../collections/Zips/'.$collection.'.zip', ZipArchive::CREATE);
//Add the files to the archive
foreach ($files as $file) {
$zip->addFile($file);
}
//Store the relative location to the zip file
$zipPath = '../collections/Zips/'.$collection.'.zip';
//If the zip was succesfully closed, echo a download link.
if($zip->close()){
$link = BASE_URL2."collections/Zips/".$collection.'.zip';
$link = str_replace(" ", "%20", $link);
echo "<a href='".$link."'>Download photos</a>";
}
主要问题是,一旦我选择了主页上的照片并点击了#34;下载&#34;按钮和表单由javascript提交。我必须在主页上等待,直到整个PHP脚本完成,然后我才会被重定向到PHP页面。
我想在PHP页面上有一个表单来处理存档的创建,我将通过主表单提交获取文件数组,然后当PHP页面完全加载时,向fetch请求内部形式,但我在整个这些操作(文件数组)中保存数据时遇到了问题。
我也考虑过asynch PHP,但是找不到一种方法来处理除socket-way之外的其他方式,这似乎是有限的。
我相信我过度复杂,我怎么能做到这一点?
答案 0 :(得分:1)
您可以使用exec运行脚本,将其放在后台,然后将用户带到下一页。在此页面上,您可以对脚本进行ajax检查以完成,同时向用户发送消息或其他内容以便他们知道正在发生的事情。一旦脚本完成;然后,您的页面可以使用链接进行更新以下载文件。
exec('nohup /var/.../script.php > /dev/null 2> /dev/null & echo $!');
这会将脚本作为后台进程运行,而您的页面无需等待它。
您甚至可以在使用$pid = exec($command ,$op);
或$pid = (int)$op[0];
运行时获取流程ID,您可以将其传回页面并进行下一页轮询以完成:
$command = 'ps -p '.$pid;
exec($command, $op);
if (! isset($op[1])) {
// process finished
}
else {
// still running
}
好的 - 这是我完全正常的答案:
的index.php:
<?php
exec('nohup php run.php > /dev/null 2> /dev/null & echo $!', $op);
$pid = (int)$op[0];
header('location: check.php?pid='.$pid);
run.php:
<?php
sleep(5);
check_process.php:
<?php
header("HTTP/1.1 200 OK");
$pid = $_REQUEST['pid'];
$command = 'ps -p '.$pid;
exec($command, $op);
if (! isset($op[1])) {
$output = 'script finished';
}
else {
$output = 'script running';
}
print $output;
check.php:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Check</title>
</head>
<body>
<div id="result"></div>
<script>
check_process('<?=$_REQUEST['pid']?>');
function check_process(pid) {
console.log('pid: '+pid);
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status == 200) {
if(xmlhttp.responseText == 'script running') {
check_process(pid);
}
document.getElementById("result").innerHTML = xmlhttp.responseText;
}
else if (xmlhttp.status == 400) {
alert('There was an error 400');
}
else {
alert('something else other than 200 was returned');
}
}
};
xmlhttp.open("GET", "check_process.php?pid="+pid, true);
xmlhttp.send();
}
</script>
</body>
</html>
将所有这些放在同一目录中并打开index.php。它会产生一个后台进程,例如它会睡5秒钟。它会将您发送到显示脚本正在运行的页面。当剧本死亡时;它会更新页面告诉你它已经完成。我希望这有帮助。如果您有任何疑问,请告诉我。