113 lines
4.1 KiB
PHP
113 lines
4.1 KiB
PHP
<?php
|
|
//实现对用户上传的文件进行加密存储以及处理用户下载请求解密文件
|
|
use Random\RandomException;
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
if (!empty($_POST['upload'])) { //接收文件并加密
|
|
if ($_FILES['uploadFile']['error'] > 0) {
|
|
echo '上传失败';
|
|
} else {
|
|
$file = $_FILES['uploadFile'];
|
|
$fileName = $file['name'];
|
|
$fileTmp = $file['tmp_name'];
|
|
$fileSize = $file['size'];
|
|
$fileType = $file['type'];
|
|
try {
|
|
$fileContent = file_get_contents($fileTmp);
|
|
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
|
$key = sodium_crypto_secretbox_keygen();
|
|
$encrypted = sodium_crypto_secretbox($fileContent, $nonce, $key);
|
|
$protectedFileName = 'data/' . $fileName . '.protected';
|
|
$fp = fopen($protectedFileName, 'w');
|
|
fwrite($fp, $encrypted);
|
|
fclose($fp);
|
|
echo '上传成功';
|
|
$showOnce = true;
|
|
} catch (RandomException $e) {
|
|
error_log('Random number generation failed: ' . $e->getMessage());
|
|
exit(1);
|
|
} catch (SodiumException $e) {
|
|
error_log('Sodium error: ' . $e->getMessage());
|
|
}
|
|
}
|
|
} elseif (!empty($_POST['filename'])) {
|
|
|
|
if (!empty($_POST['key']) && !empty($_POST['nonce'])) {
|
|
$fileName = urldecode($_POST['filename']);
|
|
$file = file_get_contents('data/' . $fileName . '.protected');
|
|
$key = urldecode($_POST['key']);
|
|
$nonce = urldecode($_POST['nonce']);
|
|
$decrypted = null;
|
|
try {
|
|
$decrypted = sodium_crypto_secretbox_open($file, $nonce, $key) or die('解密失败');
|
|
} catch (SodiumException $e) {
|
|
error_log('Sodium error: ' . $e->getMessage());
|
|
}
|
|
if ($decrypted == null) {
|
|
echo '解密失败';
|
|
exit;
|
|
}
|
|
header('Content-Description: File Transfer');
|
|
header('Content-Type: application/octet-stream');
|
|
header('Content-Disposition: attachment; filename="' . basename($fileName) . '"');
|
|
header('Expires: 0');
|
|
header('Cache-Control: must-revalidate');
|
|
header('Pragma: public');
|
|
header('Content-Length: ' . strlen($decrypted));
|
|
echo $decrypted;
|
|
exit;
|
|
} else {
|
|
echo '下载参数不完整';
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>test1</title>
|
|
</head>
|
|
<body>
|
|
<form action="" method="post" enctype="multipart/form-data">
|
|
<label for="file1">要上传的文件:</label>
|
|
<input type="file" id="file1" name="uploadFile" required>
|
|
<input type="submit" name="upload" id="submit1" value="上传文件">
|
|
</form>
|
|
<?php
|
|
if (isset($showOnce) && isset($fileName) && isset($key) && isset($nonce)) {
|
|
unset($showOnce);
|
|
echo '<button onclick="downloadFile()">下载文件</button>';
|
|
}
|
|
?>
|
|
<script>
|
|
function downloadFile() {
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open('POST', '15.test4.php', true);
|
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
xhr.responseType = 'blob';
|
|
|
|
const params = 'filename=<?php echo urlencode(($fileName ?? '')); ?>&key=<?php echo urlencode($key ?? ''); ?>&nonce=<?php echo urlencode($nonce ?? ''); ?>';
|
|
xhr.send(params);
|
|
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
const blob = xhr.response;
|
|
const url = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = '<?php echo $fileName ?? ''; ?>';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
window.URL.revokeObjectURL(url);
|
|
} else {
|
|
console.error('下载失败');
|
|
}
|
|
};
|
|
}
|
|
</script>
|
|
</body>
|