我试图允许用户在服务器端创建照片存档并下载该存档,而无需在白色页面上等待,也不知道在 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>";
}
主要问题是,一旦我选择主页上的照片并点击“下载”按钮,表单就会通过 JavaScript 提交。我必须在主页上等待,直到整个 PHP 脚本完成,然后我才会重定向到 PHP 页面。
我考虑过在 PHP 页面上有一个表单来处理存档的创建,我将通过主表单提交获取文件数组,然后当 PHP 页面完全加载时,向内部形式,但我在整个这些操作(文件数组)中保存数据时遇到困难。
我也考虑过异步 PHP,但除了似乎有限的套接字方式之外找不到其他方法来处理它。
我认为我把它弄得太复杂了,我怎样才能做到这一点?
最佳答案
您可以使用 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);
运行.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;
检查.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。它将生成一个后台进程,例如,该进程将休眠五秒钟。它将带您到一个显示脚本正在运行的页面。当脚本消失时;它会更新页面以告诉您它已完成。我希望这有帮助。如果您有任何疑问,请告诉我。
关于javascript - 如何在 PHP 开始创建照片存档之前加载页面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48035186/