Mysql хранилище файлов на вашем сайте

Часто для баз данных хостинги дают 30-100 ГБ бесплатно, это можно использовать как отличное файловое хранилище для ваших korni приложений. просто нужен соответствующий “скриптик”.

Вот обычного php пример скрипта, который превращает ваш php сайтик с mysql в append only файловое хранилище (наподобие S3).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
// Настройки подключения к базе данных
$host = 'localhost'; // или ваш хост
$db = 'file_storage';
$user = 'your_username'; // ваше имя пользователя
$pass = 'your_password'; // ваш пароль


// Подключаемся к БД
try {
$pdo = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => 'Ошибка подключения к базе данных: ' . $e->getMessage()]);
exit;
}

// Обработка POST-запроса для загрузки файла
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {

$fileTempPath = $_FILES['file']['tmp_name'];
$originalFileName = basename($_FILES['file']['name']);
$fileData = file_get_contents($fileTempPath);

// Получаем группу файла, если она передана, иначе используем значение по умолчанию
$fileGroup = isset($_POST['group']) ? $_POST['group'] : 'default_group';

// Подготовка и выполнение SQL-запроса
$stmt = $pdo->prepare("INSERT INTO files (file_name, file_data, file_group) VALUES (?, ?, ?)");
if ($stmt->execute([$originalFileName, $fileData, $fileGroup])) {
echo json_encode(['status' => 'success', 'message' => 'Файл загружен успешно', 'file' => $originalFileName]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Не удалось сохранить файл']);
}

exit;
} else {
echo json_encode(['status' => 'error', 'message' => 'Ошибка загрузки файла']);
exit;
}
}

// Обработка GET-запроса для получения списка файлов или содержимого файла
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
if (isset($_GET['file_name'])) {
// Если указан файл, то возвращаем его содержимое
$fileName = basename($_GET['file_name']); // Безопасность: убираем возможные пути
$stmt = $pdo->prepare("SELECT file_data FROM files WHERE file_name = ?");
$stmt->execute([$fileName]);

$fileData = $stmt->fetchColumn();

if ($fileData !== false) {
echo json_encode(['status' => 'success', 'file_name' => $fileName, 'file_data' => $fileData]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Файл не найден']);
}
} else {
// Если файл не указан, возвращаем список файлов
$fileGroup = isset($_GET['group']) ? $_GET['group'] : null;

// Формирование SQL-запроса
$query = "SELECT file_name, file_group FROM files";
if ($fileGroup) {
$query .= " WHERE file_group = ?";
$stmt = $pdo->prepare($query);
$stmt->execute([$fileGroup]);
} else {
$stmt = $pdo->query($query);
}

$files = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(['status' => 'success', 'files' => $files]);
}
exit;
}
?>

Этот скрипт позволяет фактически в одной mysql БД иметь несколько хранилищь (есть “группы файлов”). Если группу не указывать в параметрах - будет использоваться группа по умолчанию.

Настройте БД

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE DATABASE IF NOT EXISTS file_storage;

USE file_storage;

CREATE TABLE IF NOT EXISTS files (
id INT AUTO_INCREMENT PRIMARY KEY,
file_name VARCHAR(255) NOT NULL,
file_data LONGBLOB NOT NULL,
file_group VARCHAR(50) DEFAULT 'default_group',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Создайте индекс для ускорения выборки
CREATE INDEX idx_file_name ON files (file_name);
CREATE INDEX idx_file_name_group ON files (file_group, file_name);

Как использовать скрипт:

  1. Настройка базы данных: Убедитесь, что вы правильно указали настройки подключения к базе данных (адрес, имя пользователя и пароль).

  2. Отправка файла через POST-запрос:
    Вы можете использовать инструмент, такой как Postman, или curl для отправки файла и опциональной группы:

    curl -X POST -F 'file=@path_to_your_file' -F 'group=my_group' http://yourserver.com/your_script.php

  3. Получение списка файлов через GET-запрос:
    Чтобы получить список всех файлов:

    curl -X GET http://yourserver.com/your_script.php

    Чтобы получить файлы из определенной группы:

    curl -X GET 'http://yourserver.com/your_script.php?group=my_group'

Примечания:

  • Убедитесь, что у вашего сервера достаточно памяти для хранения загружаемых файлов, так как они будут сохраняться в базе данных.
  • Вы можете расширить функциональность, добавив проверки на типы файлов и ограничения на размеры загружаемых файлов.

Вот пример, как это работает у меня (в примере адрес скрипта изменен)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$ curl -X POST -F 'file=@Theme2.js' https://mapavlov.ru/VS/MySqlFileStor/tmp.php | jq . 
{
"status": "success",
"message": "Файл загружен успешно",
"file": "Theme2.js"
}


$ curl -X POST -F 'file=@Theme2.js' -F 'group=APP2' https://mapavlov.ru/VS/MySqlFileStor/tmp.php | jq . % Total % Received % Xferd Average {
"status": "success",
"message": "Файл загружен успешно",
"file": "Theme2.js"
}


$ curl -X GET https://mapavlov.ru/VS/MySqlFileStor/tmp.php | jq .
{
"status": "success",
"files": [
{
"file_name": "Theme2.js",
"file_group": "default_group"
},
{
"file_name": "Theme2.js",
"file_group": "default_group"
},
{
"file_name": "Theme2.js",
"file_group": "default_group"
},
{
"file_name": "Theme2.js",
"file_group": "APP2"
}
]
}


$ curl -X GET https://mapavlov.ru/VS/MySqlFileStor/tmp.php?group=APP2 | jq .
{
"status": "success",
"files": [
{
"file_name": "Theme2.js",
"file_group": "APP2"
}
]
}

Как получить сам файл

  1. указываем file_name в GET-запросе: В случае наличия этого параметра, выполняется запрос к базе для получения данных файла.
  2. Запрос на получение данных файла: Если файл найден, он возвращает содержимое. Если файл не найден, возвращает сообщение об ошибке.
  3. Использование basename для безопасности: Это предотвращает возможность атаки с использованием путей к файлам.

Теперь, если вы сделаете GET-запрос с указанием имени файла, получите содержимое этого файла. Если не укажете имя файла, вы получите список всех файлов в базе данных.

1
2
$ curl -X GET  https://mapavlov.ru/VS/MySqlFileStor/tmp.php?file_name=Theme2.js  | wc -c
13682

вы получаете ответ в json такого вида :

1
2
3
4
{
"status": "success",
"file_name": "Theme2.js",
"file_data": "\tfunction printTheme(){\n\t\tif(!!Controls.Theme)\n\t\t{\n\t\t\tprint(\"Controls.Theme.activeColor\", Controls.Theme.activeColor);\n\t\t\tprint(\"Controls.Theme.aiMarkColor\", Controls.Theme.aiMarkColor);\n\t\t\tprint(\"Controls.Theme.aiTextColor\", Controls.Theme.aiTextColor);\n\t\t\tprint(\"Controls.Theme.animationTime\", Controls.Theme.animationTime);\n\t\t\tprint(\"......

Итого

Любой сайт по любому пути одним секретным php скриптом превращается в хранилище файлов, в которое можно дописывать и можно выгружать.

Это лучше чем доступ по ftp т.к. в данном случае извне файлы невозможно удалять…

Получить их можно только если откуда-то знать адрес скрипта и уметь.

Система Korni3 может использовать такой способ для синхронизации файлов и ей не важно что в данном скрипте есть версии файла с переименованием т.к., получив файлы, система корни посчитает их хеш и сама их у себя поименует по их содержимому.