Друг начин, който ми харесва и ползвам, касае прикачането на няколко картинки към даден запис от база данни.
За целта ни трябва единствено дефинирано поле от някакъв целочислен тип, в която да съхраняваме
информацията. Идеята е, на базата на това число чрез побитови операции да сравняваме и определяме с кои точно картинки разполагаме.
ДЕФИНИРАНЕ НА ПОЛЕТО ЗА БАЗАТА ДАННИ
Представи си, че даден потребител има портретна снимка, аватар и няколко фотоснимки. Да приемем, че максималният им общ брой не може да бъде повече от 10
На базата на тази информация правим следното:
повдигаме числото 2 на степен 10, което прави 1024. Най близкият целочислен тип до тази стойност в MySQL е SMALLINT UNSIGNED
Съответно си правим и табличката:
$Query = "CREATE TABLE IF NOT EXISTS Users (
Id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (Id), /* Няма нужда от обяснение */
UserName VARCHAR(255), /* Потребителско име */
Mail VARCHAR(127) DEFAULT NULL, /* Електронна поща на потребителя */
Description TEXT DEFAULT NULL, /* Описание на потребителя */
Pictures SMALLINT UNSIGNED, /* Информация за картинките на потребителя */
INDEX(UserName));";
SMALLINT UNSIGNED е в обхвата от 0 to 65535, така че, можем да имаме максимален брой от 15 различни снимки за един потребител (2 на степен 16 = 65536)
ИЗВЛИЧАНЕ НА ИНФОРМАЦИЯТА
Сега малко за побитовата операция & ("и")
Нека имаме едно двоично число - 000000000110101 - (това число е равно на десетичното 53)
Да разгледаме къде имаме единици:
- най вдясно имаме числото 1, това означава, че потребителят е качил портретната си снимка
- след него на втора позиция (от дясно на ляво) имаме числото 0, това означава, че потребителят НЕ е качил аватар
- от там нататък, имаме три единици, което означава, че потребителят е качил три фотоснимки.
Да си представим, че искаме да покажем фотоснимките на потребителя - правим си т. нар. "маска".
Интересува ни дали на петата позиция (от дясно на ляво) има единица
Възможността беше най много за 15 картинки, така че маската трябва да е от 15 позиции: 000000000010000
(десетично 16 - което между другото може лесно да се изчисли, като знаем коя позиция ни трябва: 2 на степен (5-1))
Мястото на нулите в маската, показва, че не се интересуваме какви са числата на тези позиции.
Нека да сложим едно под друго двете числа:
000000000010000 - маска
000000000110101 - число идващо от базата данни (десетично 53)
Резултатът от операцията & (побитово "и")ще бъде
000000000010000 (десетично 16)
Сам по себе си фактът, че това число не е 0 (заради съществуващата единица) показва, че потребителят има сложена фотоснимка на тази позиция. Можем разбира се да извикаме снимките като видим дали съществуват с функцията file_exist, но не е препоръчително, понеже тя се обръща към операционната система и става бавно.
Ето например как можем да генерираме списъка с фотоснимките на базата на полето Pictures
<?php
//Приемаме, че $UserId, $UserName и $Pictures са вече извлечени от базата дани
$Html = '';
//Започваме цикъла от 2, понеже снимките се разполагат от вторият бит нататък (без да го включва)
for ($i = 2; $i <= 14; ++$i) {
$Num = $i - 1; //Позиция на фотоснимката
//Генериране на необходимата ни маска за текущата позиция на фотоснимката
$Mask = pow(2, $i);
//Извличане на информацията, дали поредната фотоснимка е качена
$Pic = $Pictures & $Mask;
//Генериране на html код за изображението, ако то е налично
if ($Pic) $Html .= "$Num - <img src=\"images/pic_$UserId-$i.jpg\" alt=\"$UserName\" /><br />";
}
//Показване на html кода
echo $Html;
?> |
ПРОМЯНА НА ИНФОРМАЦИЯТА
Обратната операция - слагане на информацията за това, че потребителят току що е качил снимка, става с побитовото "изключващо или" - "^"
Например искаме да зададем нова стойност, която да отразява, че потребителят току що е качил снимка на 11-та позиция - маската ни ще бъде: 2 на степен (11-1) което е равно на 1024
000010000000000 - маска (десетично 1024)
000000000110101 - число идващо от базата данни (десетично 53)
Резултатът от операцията ^ (изключващо или ) ще бъде
000010000110101 (десетично 1077)
Или иначе казано
$Position = 11;
$Pictures = $Pictures ^ pow(2, ($Postition-1)); |
Така новата стойност 1077 записваме в базата данни.
ПРЕДИМСТВА
Слагането на самите картинки в базата данни коства много ресурси при последваща работа с тази база данни. При малък брой потребители, това може и да не се забележи много, но при нарастване на броя потребители и съответно техните снимки, всякакво четене от такава база данни ще бъде излишно натоварено.
От друга страна, предложеният начин за съхраняване информацията за картинки е много по-икономичен откъм компютърни ресурси:
- Съхранява се само едно число
- Размера на картинките по никакъв начин не влияе на бързодействието на базата данни
- Пести се процесорно време и памет при извличане на картинките и пращането им към браузъра, понеже се избягва допълнителна конекция и претърсване на базата данни в допълнителният скрипт за изпращане на изображението към браузъра
НЕДОСТАТЪЦИ
- За начинаещите програмисти алгоритъмът е сложен. Но този аргумент напълно отпада, когато се преследва високо бързодействие или се работи с много записи.
- Възможност от "десинхронизация" - т.е. в базата данни числото да показва че такава картинка съществува, а физически да я няма качена в съответната папка, поради някаква грешка например. Това лесно се избягва със съвсем малко допълнителен код.
- Ограничен брой възможни позиции - 63 заради най големият възможен целочислен тип - BIGINT UNSIGNED. Съществуват обаче заобиколни начини, в основата си лежащи на този подход
- Картинките не са защитени от механизма за сигурност на базата данни. (потребител и парола)
ЗАБЕЛЕЖКИ
Кодът който съм писал не съм го тествал. Писал съм го единствено с цел обяснение на самият метод. Ако имате забележки или предложения, обаждайте. Възможно е да съм сгрешил някъде в някое число, но идеята все пак е да се изясни същността на метода.