first commit
This commit is contained in:
75
README.md
Normal file
75
README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Minimal Chunked File Storage (PHP)
|
||||
|
||||
This is a minimalistic PHP-based file storage system with:
|
||||
|
||||
* Password-protected admin panel
|
||||
* Chunked file upload for large files (GB+)
|
||||
* Upload progress display
|
||||
* File listing with download and delete options
|
||||
* Direct link copy button
|
||||
* No external libraries required
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
* Chunked upload via JavaScript + `fetch`
|
||||
* Server-side chunk handling and merging
|
||||
* No CSS or frontend frameworks
|
||||
* Fully self-contained (no Composer needed)
|
||||
|
||||
## 🛠 Requirements
|
||||
|
||||
* PHP 7.4+
|
||||
* A web server (or use PHP's built-in server)
|
||||
|
||||
## 📁 Folder Structure
|
||||
|
||||
```
|
||||
/simple-file-share/
|
||||
├── index.php
|
||||
├── upload/ # Final uploaded files
|
||||
├── upload_chunks/ # Temporary chunk storage
|
||||
├── upload_chunk.php
|
||||
├── merge_chunks.php
|
||||
└── config.php # Configuration (password and paths)
|
||||
```
|
||||
|
||||
## 🔐 Configuration
|
||||
|
||||
Create `config.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
define('PASSWORD', 'your_password_here');
|
||||
define('UPLOAD_DIR', __DIR__ . '/upload/');
|
||||
define('CHUNK_DIR', __DIR__ . '/upload_chunks/');
|
||||
```
|
||||
|
||||
## ▶️ Run the Server
|
||||
|
||||
Use PHP's built-in server:
|
||||
|
||||
```bash
|
||||
php -S localhost:8000
|
||||
```
|
||||
|
||||
Then open:
|
||||
|
||||
```
|
||||
http://localhost:8000
|
||||
```
|
||||
|
||||
## 📤 Uploading Files
|
||||
|
||||
* Select a file in the UI.
|
||||
* It is split into 1MB chunks (adjustable in JS).
|
||||
* Upload progress is shown.
|
||||
* File is merged server-side and available for download.
|
||||
|
||||
## 🧹 Cleanup
|
||||
|
||||
* Temporary chunk files are automatically deleted after merging.
|
||||
* Files can be deleted via the admin interface.
|
||||
|
||||
## 📝 License
|
||||
|
||||
This project is public domain / MIT – use freely.
|
||||
4
config.php
Normal file
4
config.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
define('PASSWORD', 'your_password_here');
|
||||
define('UPLOAD_DIR', __DIR__ . '/upload/');
|
||||
define('CHUNK_DIR', __DIR__ . '/upload_chunks/');
|
||||
87
index.php
Normal file
87
index.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
session_start();
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
if (!file_exists(UPLOAD_DIR)) mkdir(UPLOAD_DIR);
|
||||
if (!file_exists(CHUNK_DIR)) mkdir(CHUNK_DIR);
|
||||
|
||||
if (!isset($_SESSION['logged_in']) || ($_GET['action'] ?? '') === 'logout') {
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['password'] ?? '') === PASSWORD) {
|
||||
$_SESSION['logged_in'] = true;
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
echo '<form method="post">
|
||||
<h3>Login</h3>
|
||||
<input type="password" name="password" placeholder="Password">
|
||||
<button type="submit">Login</button>
|
||||
</form>';
|
||||
exit;
|
||||
}
|
||||
|
||||
// Удаление
|
||||
if (isset($_GET['delete'])) {
|
||||
$f = basename($_GET['delete']);
|
||||
@unlink(UPLOAD_DIR . $f);
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$files = array_diff(scandir(UPLOAD_DIR), ['.', '..']);
|
||||
?><!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"><title>Файловое хранилище</title></head>
|
||||
<body>
|
||||
<h3>Файловое хранилище</h3>
|
||||
<p><a href="?action=logout">Выйти</a></p>
|
||||
<input type="file" id="fileInput">
|
||||
<div id="progress"></div>
|
||||
<ul>
|
||||
<?php foreach ($files as $file): $url = 'upload/' . rawurlencode($file); ?>
|
||||
<li>
|
||||
<?= htmlspecialchars($file) ?>
|
||||
[<a href="<?= $url ?>" target="_blank">Скачать</a>]
|
||||
[<a href="?delete=<?= urlencode($file) ?>" onclick="return confirm('Удалить?')">Удалить</a>]
|
||||
<button onclick="copyLink('<?= $url ?>')">Копировать ссылку</button>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
function copyLink(link) {
|
||||
navigator.clipboard.writeText(location.origin + '/' + link).then(() => alert("Скопировано"));
|
||||
}
|
||||
|
||||
const input = document.getElementById('fileInput');
|
||||
input.addEventListener('change', async () => {
|
||||
const file = input.files[0];
|
||||
if (!file) return;
|
||||
const chunkSize = 1024 * 1024; // 1MB
|
||||
const totalChunks = Math.ceil(file.size / chunkSize);
|
||||
|
||||
for (let i = 0; i < totalChunks; i++) {
|
||||
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
|
||||
const formData = new FormData();
|
||||
formData.append('chunk', chunk);
|
||||
formData.append('filename', file.name);
|
||||
formData.append('index', i);
|
||||
formData.append('total', totalChunks);
|
||||
|
||||
await fetch('upload_chunk.php', { method: 'POST', body: formData });
|
||||
document.getElementById('progress').innerText = `Загружено: ${i+1}/${totalChunks}`;
|
||||
}
|
||||
|
||||
await fetch('merge_chunks.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ filename: file.name, total: totalChunks })
|
||||
});
|
||||
|
||||
alert('Готово!');
|
||||
location.reload();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
21
merge_chunks.php
Normal file
21
merge_chunks.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$filename = basename($data['filename']);
|
||||
$total = intval($data['total']);
|
||||
$tmpDir = __DIR__ . '/upload_chunks/' . $filename;
|
||||
$finalPath = __DIR__ . '/upload/' . $filename;
|
||||
|
||||
$out = fopen($finalPath, 'w');
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$partPath = "$tmpDir/$i.part";
|
||||
$in = fopen($partPath, 'r');
|
||||
stream_copy_to_stream($in, $out);
|
||||
fclose($in);
|
||||
unlink($partPath);
|
||||
}
|
||||
fclose($out);
|
||||
rmdir($tmpDir);
|
||||
http_response_code(200);
|
||||
8
upload_chunk.php
Normal file
8
upload_chunk.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
$filename = basename($_POST['filename']);
|
||||
$index = intval($_POST['index']);
|
||||
$tmpDir = __DIR__ . '/upload_chunks/' . $filename;
|
||||
if (!file_exists($tmpDir)) mkdir($tmpDir, 0777, true);
|
||||
|
||||
move_uploaded_file($_FILES['chunk']['tmp_name'], "$tmpDir/$index.part");
|
||||
Reference in New Issue
Block a user