Як створити свою файлову систему на основі blob полів у базі даних. Чому це зручно. Питання ефективності

Шановні читачі. Це третя стаття з циклу по базах даних.

Зміст:
  1. Як зробити різний часовий пояс у різних базах даних на одному сервері.
  2. Як вести логи змін даних в базі даних, зберігаючи їх в іншій базі даних (база основна база даних не забивалася сміттям і не зростала)
  3. Як створити свою файлову систему на основі blob полів у базі даних. Чому це зручно. Питання ефективності зберігання файлів (як отримати максимальну швидкодію і при цьому мінімальний займане місце)
Даний спосіб – спосіб реалізації зберігання файлів, доданих користувачем на сайті, через веб інтерфейс. Це не буде «файловою системою в тому розумінні, як це організовано в операційній системі.

Приклад, описаний у цій статті, буде вирішувати завдання стояла колись у мене: „Виділити розділ всередині аккаунта компанії на веб-сайті, де співробітники компанії зможуть зберігати свої файли, створювати папки (назвемо його “Диск»). Диск повинен бути ізольованим від акаунтів інших компаній і повинен інтегруватися в процеси роботи облікового запису (організація зберігання файлів, прикладених до завдань, проектів, картками контрагентів, звітів тощо) ".

Відразу зауважу, що даний спосіб, з точки зору швидкодії, менш ефективний простого збереження файлів на веб-сервері. Але він має певні переваги, які в моєму випадку переважили вади втрати швидкості завантаження.

Недоліки: Збільшений час завантаження файлу

Переваги
  1. Розподілена структура зберігання. Тобто не обов'язково зберігати файли клієнта на самому веб-сервері. Можна зберігати їх де завгодно, на будь-яких серверах мережі. Легко переміщати їх з сервера на сервер у разі необхідності.
  2. Зручність резервного копіювання файлів клієнта. Можна все робити стандартними засобами бекапу.
  3. Безпека. Цей спосіб позбавлений основних вразливостей веб додатків при завантаженні файлів (ознайомитися з ними можна наприклад тут). Так само спосіб здійснює фізичну ізоляцію даних клієнта, від даних інших клієнтів, бо у кожної компанії своя БД.
Основним аргументом реалізації даної системи зберігання файлів послужила можливість розподіленого зберігання. В принципі можна використовувати рішення типу cifs і samba, примонтувати мережеві диски від інших машин і там зберігати файли клієнтів. Але в той час мені прийшло ось таке ось, не зовсім стандартне рішення, і я ним повністю задоволений.

В даній статті ми будемо розглядати процес реалізації від простого до складного:
  1. Загальна організація структури зберігання.
  2. Збереження файлів у blob-поля. Пряме вилучення.
  3. Збереження файлів з проміжною архівацією в blob-поля. Витяг з проміжною разархивацией.
  4. Збереження файлів з відкладеним і вибіркової архівацією (не всі файли має сенс архівувати, в яких випадках шкурка вичинки не варта, а так же не завжди має сенс архівувати відразу).
  5. Потім ми розглянемо організацію структури каталогів, організацію прав доступу, операції з файлами, деякі окремі випадки і т. п.
    Отже почнемо.
Отже почнемо.

В якості бази даних, використовується firebird 3

1. Загальна організація структури зберігання.

Як і в попередній статті (за зберігання логів), не варто в основній робочій базі зберігати файли, це буде багато сміття, проблеми з бекапами і т. д. Для цього краще виділити окрему базу даних. Назвемо її «Файлова БД». В основній базі даних повинна зберігатися структура каталогів і посилання на файли, а самі двійкові дані з файлів, будуть зберігатися у файловій БД.
У цьому випадку ви отримаєте зручність бекапів, і швидку базу даних. Наприклад, я в своїй системі даю користувачам можливість самостійно планувати графік своїх бекапів, в тому числі і бекапів файлової бази даних. Більш того, навіть є можливість автоматичного закидання архіву бекапу користувачеві на його FTP (наприклад, якщо він бекапи бажає зберігати на своєму обладнанні і не платити за оренду місця в хмарі). Така реалізація можлива саме завдяки зберігання файлів в окремій базі і організації розподіленої системи зберігання.

Так само завдяки такій організації, веб-сервер виконує тільки функції веб-сервера, а не файлового сховища. Можна більш грамотно організувати розподіл ресурсів в мережі. При величезній кількості клієнтів (величезній кількості баз даних і файлових структур) нерозподілений організація зберігання даних буде просто неприйнятна. Структура повинна бути необмежено масштабованої, а так само простий.

Схему можна представити наступним чином:

image

При цьому кожен з елементів може бути (і краще зробити так) на своєму окремому сервері.
Структура зберігання даних може бути організована наступним чином
В основній базі даних створюється структура з даними про доданому файлі

CREATE TABLE FILES_ (
ID BIGINT,
DATA TIMESTAMP, --Дата додавання файлу
DATA_DEL TIMESTAMP, --Дата видалення файлу 
USER_ INTEGER, --Юзер, який додав файл
USER_DEL INTEGER, --Юзер, видалив файл
ID_FILE INTEGER, --ID файлу у файловій БД
FILE_NAME VARCHAR(256), --Назва файла
FILE_NAME_TMP VARCHAR(256), --Назва файла при закачуванні
CONTENT_TYPE VARCHAR(100), --Тип вмісту файлу
STATUS SMALLINT, --Статус файлу (є або видалений)
SIZE BIGINT, --Розмір файлу
SIZE_ZIP BIGINT, --Розмір файлу архіву
SIZE_ZIP_2 BIGINT, --Тестовий прогін архівації
ZIP_USE SMALLINT, --Якого типу архіватор використовується
ID_FOLDER INTEGER, --Ідентифікатор каталогу, де лежить файл
FLAG_ZIP SMALLINT --Прапор використання архівації
);


Структура файлової базі даних може бути такою (мінімум даних про файл та файл в blob поле)

CREATE TABLE FILES_ (
ID BIGINT,
DATA TIMESTAMP,
USER_ INTEGER, --Юзер, який додав файл
FILE_NAME VARCHAR(256), --Назва файла
CONTENT_TYPE VARCHAR(100), --Тип вмісту файлу 
FILE_DATA BLOB SUB_TYPE 0 SEGMENT SIZE 80, --Бінарна послідовність файлу
STATUS SMALLINT, --Статус (є або видалений)
SIZE INTEGER, --Розмір файлу
SIZE_ZIP INTEGER, --Розмір файлу архіву
ZIP_USE SMALLINT --Якого типу архіватор використовується
);


Тут є деяка надмірність даних у цих двох таблицях відносно один одного, але надалі вона стане в нагоді, наприклад, при операції відкладеної архівації, при налагодженні, при подальших аналізах даних і т. п. Не городити ж єдиний запит в кілька БД.

Почнемо розгляд з простою запису файлу в blob поле.

2.1. Збереження файлів у blob-поля.

Веб форми і процес закачування файлу в каталог на веб-сервері ми не будемо розглядати тут. Передбачається, що читач з цим знаком.
Отже, користувач натиснув на веб формі кнопку, файл завантажився і зберігся в каталозі веб-сервера (нехай буде наприклад tmp).
Дані файла у цей момент у нас є в глобальному масиві FILES.
(приклади буду наводити на PHP)

PS: Для простоти викладу, я свідомо опускаю перетворення небезпечних спецсимволов до мнемоникам, примусове приведення числових даних до числа і т. п. Передбачається, що у читача є свої процедури для цього і він усвідомлює небезпеку sql-ін'єкцій. Якщо цього немає, то дуже рекомендую ознайомитись з даною темою і робити відповідні перетворення.

//Коннект до файлової базі даних.
$dbh_file = ibase_connect(...);

//Відкриваємо наш файл для читання
$fd = fopen($_FILES[...]['tmp_name'], 'r');

//Додаємо дані файлу в змінну
$blob = ibase_blob_import($dbh_file, $fd);

//Закриваємо файл 
fclose($fd);

//Якщо все успішно, то виробляємо даних файлу у файловій БД.
if (!is_string($blob)) {
} else {

$query = 'INSERT INTO FILES_ (
USER_,
NAME_FILE,
CONTENT_TYPE,
FILE_DATA,
SIZE,
SIZE_ZIP,
ZIP_USE)
VALUES (
'.$USER_.',
'.$_FILES[...]['name'].',
'.$file_type.',
?,
'.$_FILES[...]['size'].',
'.$_FILES[...]['size'].',
0) 
RETURNING ID';

$prepared = ibase_prepare($dbh_file, $query);
$res_query = ibase_execute($prepared, $blob);
$prom_query = ibase_fetch_row($res_query);

$Prom_query[0] – значення ID записаного файлу.
Після успішної запису даних файлу у файловій БД треба записати дані про файл нашу основну БД.


//Робить перевірку, що все ок, ID нового файлу є.
if (isset($prom_query[0]))

//Робимо коннект до основної базі 
$dbh_osn = ibase_connect(...);
$query2 = '
INSERT INTO FILES (
USER_,
ID_FILE,
FILE_NAME,
SIZE,
SIZE_ZIP,
CONTENT_TYPE,
FILE_ NAME_TMP,
ZIP_USE)
VALUES (
'.$USER_.',
'.$prom_query[0].',
'. $_FILES[...]['name']).',
'. $_FILES[...]['size'].',
'. $_FILES[...]['size'].',
'.$_FILES[...]['type'].',
'.basename($_FILES[...]['tmp_name']).',
0)';

$res_query2 = ibase_query($dbh_osn, $query2);

//Останнім кроком видаляємо оригінал файлів у папці tmp.
unlink($_FILES[...]['tmp_name']);

Все, у нас файл записаний у файлову БД. На веб-сервері, його немає. В основний БД є інформація про файл, його статус, тип, розмір та ідентифікатор файлової БД.

2.2. Читання файлу з БД.

Коли користувач клікає на посилання з ім'ям файлу, нам треба здійснити зворотний процес. Отримати файл з БД і піднести браузеру користувача цю послідовність даних, сказавши якого типу цей файл.
У засланні в якості GET параметрів повинен бути вказаний ідентифікатор файлу (або хеш ідентифікатора з сіллю – залежить від вимог до безпеки системи, ми будемо розглядати поки просту ситуацію)
Наприклад, посилання може виглядати наступним чином Файл.

На етапі простого читання з БД (без архівування даних), нам досить обігу в файлову БД.

//Робимо коннект до бази даних 
$dbh_file = ibase_connect(...)

$query="select 
p.file_data, 
p.CONTENT_TYPE, 
p.FILE_NAME, 
p.size

from FILES p where p.id=".$_GET['id'];
$res = ibase_query($dbh_file, $query); 
$data = ibase_fetch_row($res);

При вказівці типу даних у header, виявлена індивідуальна проблема з браузером Chrome. Йому принципово необхідно, щоб filename в header було з одинарними лапками, іншим же браузерам принципово необхідно без лапок. Для цього, наприклад, можна використовувати наступне рішення.

preg_match("/(MSIE|Opera|Firefox|Chrome|Version)(?:\/| )([0-9.]+)/", $_SERVER['HTTP_USER_AGENT'], $browser_info);
list(,$browser,$version) = $browser_info;

if ($browser=='Chrome')
header("Content-Disposition: attachment; filename='".str_replace(' ','_',$data[2])."'");
else
header("Content-Disposition: attachment; filename=".str_replace(' ','_',$data[2]));

Заміна пробілу на "_" здійснюється для коректного відображення імені файлу при завантаженні, бо швидше за все по прогалині ім'я обріже.

Після цього виводимо двійкові дані файлу в тіло скрипта

echo ibase_blob_echo($data[0]);

PS: Тут хочу звернути увагу на типову помилку. Перед <?php і після ?> не повинно бути ніяких символів – інакше нічого не вийде.

Тепер при натисканні на посилання file_b.php?id=123, у користувача завантажиться віконце для його скачування файлу (з його ім'ям і потрібного типу).

3.1. Завантаження файлу з проміжним архівуванням

Ми розглянули досить простий, базовий спосіб зберігання файлів. Тепер трохи вдосконалимо його. Адже в базі даних зберігатися бінарна послідовність, чому б не зробити її коротшою і заощадити місце. Для цього, перед тим як записати дані файлу в blob, заархивируем його.

Трохи статистики:
У перший раз ця думка мені прийшла близько 1.5 років тому. В той момент я якраз розробляв модуль узгодження рахунків для однієї компанії і вирішив експериментально їм інтегрувати дану функцію. У даний модуль додаються всілякі файли з інформацією по рахунках і договорами, pdf, xls, doc тощо

За 1.5 роки в середньо-типовий компанії зі штатом 50-70 чоловік, до одного модуля було докладено(на поточний момент) 4085 файлів загальним об'ємом 1526 мб, при цьому на диску це все займає 1240 мб. Тобто архівація zip-архівом, дала економію близько 20%. Це досить непогано.
В ті часи архівація реалізовувалася мною через бібліотеку zip.lib.php прямо в скрипті. Пізніше я прийшов до висновку, що цей спосіб не оптимальним і по стисненню і за швидкодією. В поточний момент на практиці використовується архіватор 7zip.
Завантаження файлу з архівуванням особливих проблем не викликає. Необхідно тільки перед тим, як зберегти blob послідовність файлу в базу даних, архівування, наприклад так:

exec('7z a <ваш файл> <архівний файл>);

А потім в кінці крім оригіналу, видалити ще і його архів з веб-сервера.

А ось процес вилучення такого файлу користувачеві вже набагато цікавіше.

3.2. Читання файлу БД з вилученням його з архіву

Просто так, як в прямому витягу, вчинити не вийде. Після того, як користувач клацне по посиланню, спочатку треба вважати файл, зберегти його на веб-сервері, розархівувати, а потім передати користувачеві.

Тобто коли користувач клікає на посилання file_b.php?id=123, скрипт повинен смикнути інший скрипт, який вважає себе дані з blob файлу (абсолютно аналогічно з п. 2.2) після зберегти цей файл на диск сервера, потім запустити його розархівування, і дані з отриманого файлу вивести в себе, підставивши потрібний header, щоб користувачеві вилізло віконце – що він завантажує файл.

Для цих цілей використовуємо CURL.

Після визначення типу браузера і підстановки header, робимо наступне.

//Генеруємо випадкове ім'я файлу і відкриваємо файл для читання

//Відкриваємо файл
$fp = fopen($path, 'w');

//Смикаємо curl-му посилання на скрипт, який зчитує дані з blob файлу, і виводимо їх у відкритий файл.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_exec($ch);
curl_close($ch);

fclose($fp);

Таким чином, у файлі з ім'ям $path, виявляється наш заархівований файл. Виробляємо його розархівування.

exec('7z e '.$path.' –o <каталог розархівації> -y');

Після цього зчитуємо файл і інтегруємо його дані в наш скрипт за допомогою fpassthru

$stream = fopen(<ім'я файлу>,'r');
fpassthru($stream);
fclose($stream);

Тепер все повинно вийти.

4. Збереження файлів з проміжною архівацією в blob-поля.

Тепер розглянемо питання швидкодії.
Місце то ми звичайно заощаджуємо. Але замість того, щоб користувач чекав тільки час завантаження файлу на сервер, ми змушуємо його чекати ще і час архівації, і додавання файлу в blob полі. Для користувача час завантаження файлу найчастіше збільшується навіть більш ніж в 2 рази.
При витяганні аналогічно, замість того, щоб вважати дані безпосередньо, ми починаємо їх спочатку зберігати, розархівувати, а потім вже надавати користувачеві.
Все це не дуже добре.
Що ж можна зробити в даному випадку?

1) По-перше, можна рознести процес завантаження файлу, і процес його архівації. Тобто користувач завантажує файл в оригінальному вигляді. А вже потім, скрипт запускається з якоюсь періодичністю, буде дивитися на знову завантажені файли і їх архівувати. У цьому випадку для користувача завантаження файлів буде відбуватися набагато швидше, а ми при цьому будемо економити місце. Більше того, роботу даного скрипта можна організувати на іншому сервері, і він не буде споживати ресурсів веб-серверу (навіщо нам сервер перевантажений ще й змушувати займатися архівуванням?), цей процес може відбуватися в стороні, не поспішаючи.

2) По друге, далеко не всі типи файлів має сенс стискати. Наприклад, якщо різниця між стислим і несжатым файлом буде менше 10%, то гра точно не варта свічок, економія місця мінімальна – напруж процесора і час очікування користувача – максимальні. Для себе я обрав наступні типи погано стислих файлів, які архіватор навіть не чіпає, а просто ставить галочку (оброблено більше не чіпати) ZLSX,DOCX,RAR,GZ,ZIP,JAR,TAR,ARJ,UC2,GZ,UUE,LHA,CAB,LZH,ACE,TGZ,7Z,AVI,MPG,3GP,WMV,ASF,FLV,MP3,AAC,WMA,AMR,TIF,JPG,JP2,GIF,PNG.

3) Т. к. при витяганні файлу, ми теж проводимо роботу по разархивированию, то навіть якщо файл не є типом з п. 2 – все одно не факт що його має сенс архівувати. Порожня архівація – з'їдання своїх ресурсів і що більш страшно – часу очікування користувача. Тому система, перед тим як заархівувати файл – повинна перевірити, якщо в цьому сенс. Для цього довелося зробити систему превентивної архівації, тобто скрипт спочатку «пробує» — він завантажує файл, що зберігає його, але перед тим як оригінал замінити архівом – відбувається перевірка, на скільки відсотків відрізняється розмір архіву від розміру оригіналу. Якщо ця величина знову ж таки, менше 10% — то архівація ніякого сенсу не має. Такі файли відзначаються як оброблені і не архівуються.
Типові представники таких xlsx файлів. Формат вже сам по собі стислий, але за фактом зустрічаються дуже відмінні файли, які можна стиснути на 50%, а якісь дай бог на 5%. Залежить від начинки.

4) Так само не має сенсу архівувати файли розміром менше 250 байт, архів вийде більше оригіналу.

5) Не потрібно архівувати файли великого розміру. Емпірично виведено, що це в районі 15 мб і більше. Навіть, якщо він добре стискується – на його розархівування доведеться витратити певний час (крім того, що його треба витягти з blobа) – такі тимчасові очікування користувачів можуть напружувати.

5. Організація структури каталогів, організація прав доступу, операції з файлами, деякі окремі випадки.

Поки ми розглянули тільки систему зберігання файлів. Це базова річ, на якій грунтується все інше. Але для повноцінної Файлової системи" ще необхідно як-то ці файли структурувати, призначати права доступу і т. д.

Можливо, ця глава не всім буде цікава, тому що реалізація даної структури буде дуже сильно залежати від поставленого завдання. Я реалізовував цю структуру для хмарного сервісу erp-platforma.com, тому в цій главі розгляну завдання, які повинна вирішувати файлова система для сервісу організації роботи компанії:

1) Класика – Дерево каталогів, файлів. Механізм додатки файлів, редагування їх метаданих, видалення.

2) До цього пункту необхідно невеликий вступ.
Розглянемо не для всіх очевидну річ в роботі систем автоматизації: коли ви додаєте файл до завдання, він фізично зберігається не на завданні, а на диску. У задачі знаходиться лише посилання на цей файл.
Коли місце на диску закінчується, системного адміністратора можливо знадобитися його очистити. І перебирати йому всі завдання за двадцять років, видаляючи з них файли – ну це просто нерозумно.
Тобто повинна бути якась файлова структура, наприклад, службовий каталог «Завдання» на диску, де будуть зберігатися всі файли, прикладаються до завдань, і сисадмін старі файли може просто почистити.
Але що вийде, якщо він їх забере? У завданнях залишаться посилання, які нікуди не ведуть! Теж не є гуд. Отже, в задачах повинна бути не посилання, а таке собі «вікно» в Диск, у якому завдання буде бачити тільки свої файли.
Але просто «вікна» мало. Користувач може «пам'ятати» що доклав файл, а «злий» сисадмін його тихо видалить з диска і скаже користувачу що він божевільний. Тому, дані файлу можна видалити, але ось запис що файл був, повинна залишитися десь в засіках і в нашому «вікні» посилання таки повинна виводиться якимось сірим, неактивним кольором.

«Завдання» я навів для прикладу, аналогічно файли можуть прикладатися до проектів, підрядникам, працівникам, об'єктів і т. п. Т. е. система повинна бути універсальна.

Але і це ще не все. Наприклад, замовник, може запросто захотіти, щоб у контрагентів було 2 області додатки файлів, наприклад область де прикладаються рахунку та область де прикладаються документи. Тобто ці «вікна» повинні прив'язуватися не просто до сторінки та її вхідними даними, а до конкретних елементів сторінки.

Підіб'ємо підсумок пункту: файлова система повинна підтримувати якісь «вікна» в неї з зовнішньої системи. Кожне вікно повинно мати функції операції з файлами в межах своїх рамок.

3) вам потрібно знайти в папці файли, які були додані до такого контрагенту, або такого проекту або ще з якихось невідомих нам ознаками, при цьому не важливо як ці файли можуть називатися.
Тобто потрібна певна система пошуку не тільки за назвами файлів, але і по їх приналежності зовнішнім структурам.

PS: На мій погляд, такі речі оптимально реалізовувати за допомогою хэштегов. Для цих цілей, у файлах, можна ввести ще кілька властивостей: «системні хештегі» і «власні хештегі». У системних пишуться системні назви, наприклад ПІБ контрагента. У будь – довільно користувачем, при додатку файлу.

4) Права доступу. Само собою хто-то повинен мати права переглядати ті чи інші папки, хтось ні. Права на додавання, видалення. А може так вийти, що у користувача повинен бути доступ до задачі і файлів прикладеним до неї, а до теки, в якій ці файли доступу не бути. Тобто «вікно» повинна мати свої права. У системного адміністратора повинен бути механізм для призначення або вилучення прав доступу тим або іншим користувачам.

Ось такі вийшли вимоги до структури файлової системи.

Реалізація всіх цих речей – досить складний і розгалужений код в скриптах і в структурі БД, тому в рамках статті таке не привести. І так вже дуже велика стаття виходить.
Я опишу базові принципи реалізації кожної з задач.

Структуру каталогів вести досить просто. Це проста таблиця БД компанії, у якої є:
1) Назву папки
2) Творець папки
3) Вузол папки в якому знаходиться дана папка
4) Статус папки
5) Ідентифікатор папки
6) Загальні права на папку за замовчуванням (що можуть усі користувачі робити у теці, якщо їм не видано спеціальні права)

Детальніше по кожному пункту:

1) ім'я папки може дублюватися на різних рівнях дерева, в різних вузлах. В одному вузлі назва папки дублюватися не може. Даний механізм реалізувати дуже просто, достатньо поставити унікальний індекс на поля 1 і 3 таблиці. При дублюванні імені в одному вузлі – система видасть помилку.

2) Творця папки треба записати. Творець папки має на неї завжди повні права, якщо інше не прописано адміністратором в ролі користувача. Наприклад, навіть якщо користувач створив папку – адміністратор системи може все ж закрити йому доступ до неї, зробивши відповідний запис у ролі.

Творець папки може налаштувати права за замовчуванням для інших користувачів. Тобто бачать інші папку, чи можуть вони дивитися файли тільки для читання, або можуть їх видаляти, редагувати користувальницькі хештегі і т. п. Знову ж таки, ці параметри можуть перекриватися системним адміністратором.

3) У папці прописується вузол іншої папки, в якій вона знаходиться. Це потрібно для побудови деревоподібної системи папок.

4) Статус папки. Папка може бути робочою, або її можна видалити. Питання насправді не простий. Тут кожен розробник може для себе вирішувати що робити, можна, наприклад, організувати службову папку «Кошик», в якій будуть відображатися папки зі статусом видалено. Можна їх реально видаляти – але тоді треба пропрацювати, що робити з файлами в папці, а так само зі зв'язками папки в структурі системи. Правильне рішення, на мій погляд, не давати фізично видаляти запис папки, поки на неї є посилання в системі і в ній є якісь файли. Чистимо файли, чистимо зв'язку, і після цього – будь ласка, знімайте. Інакше можна отримати глюки в залежних модулях.

5) Кожна папка повинна мати свій ідентифікатор. Назви різних папок в різних вузлах може дублюватися, а ідентифікатори — ні. При програмуванні системи, коли користувач на веб сторінці створює елемент Файл, в цьому елементі він завжди вказує ідентифікатор папки, і саме в цій папці система буде зберігати файли, прикладаються в цьому модулі, через цей елемент.

6) Права папки за замовчуванням. При перегляді користувачем папки система спочатку повинна перевірити записи на цю папку в ролі користувача, якщо стоять хоч якісь настройки прав (права на всі, або навпаки заборона всіх дій), то застосовуватися повинні ці правила, якщо ж не написано нічого повинні вступати правила, виставлені творцем папки.
У своїй розробці, систему прав на папки, я інтегрував в загальну систему прав і адміністратора компанії додавання в роль користувача папки викликати проблем не має (як приклад, реалізацію прав доступу до елементів системи, можна почитати здесь).

Для зв'язки файлу з елементом сторінки є витончене рішення.
Треба обчислити хеш-суму, в якій повинен бути унікальний ідентифікатор елемента сторінки, і ці сторінки (наприклад, номер проекту або завдання). Цей хеш буде завжди унікальним і повинен зберігатися в запису даних файлу. При завантаженні сторінки в момент відображення «вікна», повинен обчислюватися цей сполучних хеш і по ньому проводитися пошук файлів і висновок на сторінку їхнього списку.
Так само «вікно» має знати каталог, в який додавати файли нові файли.

Записи хэштегов до файлів. З користувацькими (довільними) хэштегами проблем немає, треба зробити користувачеві при додаванні файлу (або при його редагуванні) можливість внесення позначок до файлу.
Складніше з системними хэштегами. Наприклад, кожен доданий файл до завдання треба ставити тег "#Задача №...#". Потім в папці Завдання, користувач, ввівши в рядок пошуку, наприклад “№...#“, отримає всі файли цікавить завдання. У мене даний функціонал реалізований на рівні мови програмування, в властивостях елементу форми «Файл» (статті я це називав «вікном»). У його властивостях можна задавати рядок з елементами ідентифікаторів, і зв'язувати дані елементи з необхідним джерелом даних. Решта система побудує автоматично.

Ще, в якості приємного бонусу, можна розглянути окремий випадок файлової гри з blob полів – Систему зберігання зображень.

У якийсь момент, в розробці внутрішньої мови програмування, я зіткнувся з необхідністю введення нестандартного типу даних. Є різні типи даних, integer, varchar, timestamp і т. д. Але ось типу image в базах даних немає. А потрібен. Наприклад, дуже зручно взяти і запитом вивести таблицю, в якій будуть зображення, наприклад стрілки вгору, вниз для переміщення даних, видалення даних і т. п. Щоб це вже все було в базі і оброблялося на рівні бази, а не городити кожен раз щось в інтерфейсі користувача. Наприклад, ось такі речі у мене можна виводити одним запитом:

image

Це можливо завдяки використанню blob полів.
У файловій базі клієнта, крім таблиці зберігання файлів, можна створити приміром таблицю IMG і там організувати зберігання зображень. На фізичному рівні, в базі даних з цим типом, буде зберігатися тільки ідентифікатор зображення. При виведенні даних сторінки, скрипт інтерпретатора, зустрівши тип даних image, з цього ідентифікатора звернеться в файлову базу даних і виведе зображення з blob-поля. При цьому користувач не буде бачити всієї цієї внутрішньої кухні. Він просто вкаже у вихідних даних процедури параметр з типом image і зробить у процедурі запит, що виводить поле таблиці з типом image у цей параметр. Дуже зручний механізм.

На цьому цикл по базах даних поки закінчую.

Якщо є пропозиції по поліпшенню механізмів описаних у статті, або альтернативної організації зберігання файлів з аналогічними можливостями, пишіть коментарі.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.