Pull to refresh

Генерация приглашений, похожих на инвайты сайта habrahabr

Reading time 5 min
Views 11K
Скрипт генерирует приглашения для регистрации на сайте в виде картинки 51x51 пикселей формата PNG, написан на PHP, в качестве базы данных использует MySQL. Сделан ради интереса, будет интересен только новичкам.

С помощью библиотеки GD можно без проблем создавать и редактировать изображения различных форматов. Для создания изображений нам понадобиться несколько функций:
int imagecolorallocate(resource image, int red, int green, int blue)

* This source code was highlighted with Source Code Highlighter.
и
int imagecolorallocatealpha(resource image, int red, int green, int blue, int alpha)

* This source code was highlighted with Source Code Highlighter.
обе функции возвращают идентификатор цвета для изображения. Единственное отличие в параметре alpha, который задаёт прозрачность изображения. Но так как с PNG прозрачностью в IE издревле были проблемы, то лучше использовать первую функцию. Первый аргумент image можно получить при помощи функции:
resource imagecreate(int x, int y)

* This source code was highlighted with Source Code Highlighter.
она возвращает идентификатор изображения, представляющий пустое палитровое изображение размером x на y.

Для начала необходимо создать таблицу в базе данных:
CREATE TABLE IF NOT EXISTS `di_invite` (
 `invite_id` int(15) unsigned NOT NULL AUTO_INCREMENT,
 `invite_hash` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
 `invite_serialize` text COLLATE utf8_unicode_ci,
 `invite_username_owner` varchar(25) COLLATE utf8_unicode_ci DEFAULT NULL,
 `invite_username_recipient` varchar(25) COLLATE utf8_unicode_ci DEFAULT NULL,
 PRIMARY KEY (`invite_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

* This source code was highlighted with Source Code Highlighter.
В БД будет храниться уникальный идентификатор каждого приглашения(invite_id), hash приглашения(invite_hash), массив с четырьмя RGB-компонентами, в байтово-поточном представление(invite_serialize), никнейм владельца приглашения(invite_username_owner) и никнейм пользователя, активировавшего его(invite_username_recipient).

Теперь необходимо сформировать массив 3x4, со значениями красного, зелёного и синего компонентов для каждого из четырёх цветов и записать его в БД.
  1. function add_invite() {
  2. // Создаёт четыре случайных цвета и записывает их в массив
  3. $rgb_array = Array();
  4. for ($idx=0; $idx < 4; ++$idx) {
  5.  $rgb = array();
  6.  for($idx2 = 0; $idx2 < 3; ++ $idx2) $rgb[] = mt_rand(0, 255);
  7.  $rgb_array[] = $rgb;
  8. }
  9. // Преобоазует массив в байтово-поточное представление для записи в БД
  10. $serialize = serialize($rgb_array);
  11. // Хэш инвайта
  12. $hash = md5($serialize);
  13. // Вставляет
  14. $_CORE['db']->query('INSERT INTO `di_invite` (`invite_hash`, `invite_serialize`, `invite_username_owner`) VALUES (?, ?, ?);', $hash, $serialize, $_CORE['user']->user_info['user_name']);
  15. if ($_CORE['db']->affected_rows() == 1) return array(true, 'Инвайт "'.$hash.'" создан');
  16. else return array(false, 'ERROR - ошибка базы данных');
  17. return true;
  18. }
* This source code was highlighted with Source Code Highlighter.
Надо подумать над тем, как это приглашение отдать пользователю. Конечно, легче всего это можно сделать представив его в виде картинки. При генерации изображения надо учесть, что вместо активированного инвайта стоит отдавать чёрно белую картинку, иначе же полноценный четырёхцветный инвайт.

  1. if (isset($_GET['hash']{31})) {
  2. // ищет в БД инвайт с таким хэшем
  3. $result = $_CORE['db']->query('SELECT `di_invite`.`invite_serialize`, `di_invite`.`invite_username_recipient` FROM `di_invite` WHERE `di_invite`.`invite_hash` = ?;', $hash);
  4. // если нашли
  5. if ($result && $_CORE['db']->num_rows() == 1) {
  6.  // если инвайт уже использовали, то отдаём чёрно белую картинку
  7.  if ($_CORE['db']->result($result, 0, 'invite_username_recipient') != '') {
  8.   // отдаёи браузеру информацию, о том что это картинка
  9.   header('Content-type: image/png');
  10.   // создаём квадратик 51px на 51px
  11.   $im = ImageCreate(51, 51) or die('Ошибка при создании изображения');
  12.   // выделяет два цвета серый и белый, причём белый будет использован в качестве фона для изображения
  13.   $color[1] = imagecolorallocate($im, 255, 255, 255);
  14.   $color[2] = imagecolorallocate($im, 200, 200, 200);
  15.   // рисует два серых прямоугольника по диагонали
  16.   ImageFilledRectangle($im, 26, 0, 50, 25, $color[2]);
  17.   ImageFilledRectangle($im, 0, 25, 25, 50, $color[2]);
  18.   // Выводит изображение в браузер
  19.   ImagePng($im);
  20.   // Разрушает его
  21.   imagedestroy($im);
  22.  // иначе, если инвайт ещё не использован
  23.  } else {
  24.   // востанавливает массив
  25.   $rgb_array = unserialize(mysql_result($result, 0, 'invite_serialize'));
  26.   header('Content-type: image/png');
  27.   $im = ImageCreate(51, 51) or die('Ошибка при создании изображения');
  28.   // выделяет 4 цвета, из значений массива
  29.   for ($i=0; $i < 4; ++$i)
  30.   $color[$i] = imagecolorallocate($im, $rgb_array[$i][0], $rgb_array[$i][1], $rgb_array[$i][2]);
  31.   // рисует три прямоугольника, чётвёртый (т.е. нулевой элемент массива) цвет по умолчанию являеться фоном изображения
  32.   ImageFilledRectangle($im, 0, 0, 25, 25, $color[1]);
  33.   ImageFilledRectangle($im, 26, 0, 50, 25, $color[2]);
  34.   ImageFilledRectangle($im, 0, 25, 25, 50, $color[3]);
  35.   ImagePng($im);
  36.   imagedestroy($im);
  37.  }
  38. } else {
  39.  exit();
  40. }
  41. } else {
  42. exit();
  43. }
* This source code was highlighted with Source Code Highlighter.
Осталось дело за малым, а именно проверить на валидность приглашение. Чтобы это сделать достаточно считать в массив значение цвета в четырёх углах картинки, и попытаться найти хэш получившегося массива в БД.

  1. function validate_invite($hash_serialize, $userfile) {    
  2. // если при загрузке изображения не было ошибок, размер изображения не превышает допустимый и тип стоответсвует нужному
  3. if (isset($userfile) && is_uploaded_file($userfile['tmp_name']) && $userfile['size'] < 5*1024 && $userfile['type'] == 'image/png' && $userfile['error'] == 0) { 
  4.  // создаём изображение на основе загруженного
  5.  $source = ImageCreateFromPNG($userfile['tmp_name']);  
  6.  // определяем точки в которых будет проверяться цвет
  7.  $x[] = 48; $y[] = 48; $x[] = 2; $y[] = 2; $x[] = 48; $y[] = 2; $x[] = 2; $y[] = 48;
  8.  $rgb_array = Array();
  9.  for ($i = 0; $i < 4; ++$i) { 
  10.   // получает индекс цвета в точке
  11.   $color_index = imagecolorat($source, $x[$i], $y[$i]);
  12.   // получает цвет для индекса
  13.   $color_tran = imagecolorsforindex($source, $color_index); 
  14.   // записываеться в массив
  15.   $rgb = Array();
  16.   $rgb[] = $color_tran['red'];
  17.   $rgb[] = $color_tran['green'];
  18.   $rgb[] = $color_tran['blue'];
  19.   $rgb_array[] = $rgb;
  20.  }      
  21.  // преобоазует массив в байтово-поточное представление для сопоставления с записью в массиве
  22.  $serialize_rgb_array = serialize($rgb_array);  
  23.  // получает хэш
  24.  $hash_serialize_rgb_array = md5($serialize_rgb_array); 
  25.  // ищет запись в бд
  26.  $_CORE['db']->query('SELECT `di_invite`.`invite_id` FROM `di_invite` WHERE `di_invite`.`invite_hash` = ?;', $hash_serialize_rgb_array);
  27.  // если найдено, очищает память, и возвращает true, иначе очищает память и возвращает false
  28.  if ($_CORE['db']->num_rows() < 1) {
  29.   imagedestroy($source);
  30.   return false;
  31.  } else {
  32.   imagedestroy($source);
  33.   $hash_serialize = $hash_serialize_rgb_array;
  34.   return true;
  35.  }
  36. } else return false;
  37. }
* This source code was highlighted with Source Code Highlighter.
Получится, что то похожее на:


P.S. При построение изображения допущена одна неточность, благодаря которой изображения получаются не симметричными.
Tags:
Hubs:
+34
Comments 66
Comments Comments 66

Articles