Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: уникальная строка

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (1): [1]   

> Без описания
kuller
Отправлено: 20 Марта, 2016 - 02:45:27
Post Id



Частый посетитель


Покинул форум
Сообщений всего: 561
Дата рег-ции: Нояб. 2009  


Помог: 2 раз(а)




У меня генерируется случайная строка, которая потом хиширую через md5 и сохраняется в базу. По сути получается что та типа пароля. Хочу избежать такого случая что если строка которая сгенерировалась была ранее записана базу, тогда перезапустилась бы функция генерации, и так до тех пор пока строка не станет уникальной. Как это сделать?

Вот сама функция
PHP:
скопировать код в буфер обмена
  1.  
  2. function generatePassword($length = 8)
  3. {
  4.         $chars = 'abdefghknqrstyzABDEFGHKNQRSTYZ23456789';
  5.         $numChars = strlen($chars);
  6.         $string = '';
  7.         for($i = 0; $i < $length; $i++)
  8.         {
  9.                 $string .= substr($chars, rand(1, $numChars) - 1, 1);
  10.         }
  11.         return $string;
  12. }
  13.  

(Отредактировано автором: 20 Марта, 2016 - 02:52:44)

 
 Top
Viper
Отправлено: 20 Марта, 2016 - 09:39:50
Post Id



Активный участник


Покинул форум
Сообщений всего: 4555
Дата рег-ции: Февр. 2007  
Откуда: Симферополь


Помог: 98 раз(а)




Вам что нужно? Рандомную строку никогда не повторяющуюся или пароль зашифровать?


-----
Список фильмов с описанием, блекджеком и... для Joomla? -> https://киноархив[dot]com
Демо нового движка для сайта php.su -> php[dot]su, проект на гитхабе
 
 Top
kuller
Отправлено: 20 Марта, 2016 - 14:22:27
Post Id



Частый посетитель


Покинул форум
Сообщений всего: 561
Дата рег-ции: Нояб. 2009  


Помог: 2 раз(а)




Viper пишет:
Вам что нужно? Рандомную строку никогда не повторяющуюся или пароль зашифровать?


да, чтоб рандомная строка не когда не повторялась
 
 Top
3d_killer
Отправлено: 20 Марта, 2016 - 14:29:07
Post Id



Участник


Покинул форум
Сообщений всего: 1916
Дата рег-ции: Апр. 2011  
Откуда: Ростов-на-Дону


Помог: 21 раз(а)




писать в базу только потом сравнивать если есть то генерировать заново
 
My status
 Top
kuller
Отправлено: 20 Марта, 2016 - 14:45:26
Post Id



Частый посетитель


Покинул форум
Сообщений всего: 561
Дата рег-ции: Нояб. 2009  


Помог: 2 раз(а)




3d_killer пишет:
писать в базу только потом сравнивать если есть то генерировать заново


вот в этом и вопрос... как это написать? понятно что должен быть запущен цыкл... но как это написать? Ведь сверка строки получается должна идти внутри цыкла, а цыклу надо дать какое та условие сколько раз выполняться
 
 Top
3d_killer
Отправлено: 20 Марта, 2016 - 15:00:38
Post Id



Участник


Покинул форум
Сообщений всего: 1916
Дата рег-ции: Апр. 2011  
Откуда: Ростов-на-Дону


Помог: 21 раз(а)




на работоспособность не проверял, но что то типо того:
PHP:
скопировать код в буфер обмена
  1.  
  2. class Password
  3.         {
  4.                 private static $password='';
  5.                 private static $instance = NULL;
  6.                 function __construct($length = 8)
  7.                         {
  8.                                 self::$password=self::generatePassword($length);
  9.                                 if(self::CheckBD(self::$password)){self::Init($length);}
  10.                         }
  11.                 private static function generatePassword($length)
  12.                         {
  13.                         $chars = 'abdefghknqrstyzABDEFGHKNQRSTYZ23456789';
  14.                         $numChars = strlen($chars);
  15.                         $string = '';
  16.                         for($i = 0; $i < $length; $i++)
  17.                                 {
  18.                                 $string .= substr($chars, rand(1, $numChars) - 1, 1);
  19.                                 }
  20.                         return $string;
  21.                         }
  22.                 private static function CheckBD()
  23.                         {
  24.                                 //проверка в базе
  25.                                 //если есть возвращаем true
  26.                                 //если нет возвращаем false
  27.                                        
  28.                         }
  29.                 public static function Init(){self::$instance = new Password();}
  30.                 public static function GetPassword(){return self::$password;}
  31.         }
  32.  
  33.  
  34. Password::Init($lenght);
  35. echo(Password::GetPassword());
  36.  


но скажу что задумка ваша не очень сама по себе

(Отредактировано автором: 20 Марта, 2016 - 15:02:21)

 
My status
 Top
kuller
Отправлено: 20 Марта, 2016 - 15:38:38
Post Id



Частый посетитель


Покинул форум
Сообщений всего: 561
Дата рег-ции: Нояб. 2009  


Помог: 2 раз(а)




3d_killer пишет:
на работоспособность не проверял, но что то типо того:
PHP:
скопировать код в буфер обмена
  1.  
  2. class Password
  3.         {
  4.                 private static $password='';
  5.                 private static $instance = NULL;
  6.                 function __construct($length = 8)
  7.                         {
  8.                                 self::$password=self::generatePassword($length);
  9.                                 if(self::CheckBD(self::$password)){self::Init($length);}
  10.                         }
  11.                 private static function generatePassword($length)
  12.                         {
  13.                         $chars = 'abdefghknqrstyzABDEFGHKNQRSTYZ23456789';
  14.                         $numChars = strlen($chars);
  15.                         $string = '';
  16.                         for($i = 0; $i < $length; $i++)
  17.                                 {
  18.                                 $string .= substr($chars, rand(1, $numChars) - 1, 1);
  19.                                 }
  20.                         return $string;
  21.                         }
  22.                 private static function CheckBD()
  23.                         {
  24.                                 //проверка в базе
  25.                                 //если есть возвращаем true
  26.                                 //если нет возвращаем false
  27.                                        
  28.                         }
  29.                 public static function Init(){self::$instance = new Password();}
  30.                 public static function GetPassword(){return self::$password;}
  31.         }
  32.  
  33.  
  34. Password::Init($lenght);
  35. echo(Password::GetPassword());
  36.  


но скажу что задумка ваша не очень сама по себе


спасибо работает! Я понимаю что количество запросов к базе иза этого может в разы возрасти, но по другому не сделать. Да, и возможно что всегда false будет возвращать т.к. эти записи раз в сутки удаляться будут, но лучше думаю перестраховаться.

не могу понять Password::Init($lenght); что за переменная?
 
 Top
3d_killer
Отправлено: 20 Марта, 2016 - 15:48:46
Post Id



Участник


Покинул форум
Сообщений всего: 1916
Дата рег-ции: Апр. 2011  
Откуда: Ростов-на-Дону


Помог: 21 раз(а)




количество символов
(Добавление)
строка Password::Init($lenght); это создание экземпляра класса с заданым количеством символов в пароле
(Добавление)
только тут так private static function CheckBD($password)
 
My status
 Top
Мелкий Супермодератор
Отправлено: 20 Марта, 2016 - 15:59:44
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




Такс, во-первых, rand, mt_rand и прочие shuffle для генерировать паролей использовать нельзя. Используйте random_int, random_bytes (для php5 - есть слой совместимости). openssl_random_pseudo_bytes желательно тоже не использовать.

По реализации в базе безопасно для конкурентного доступа:
PHP:
скопировать код в буфер обмена
  1. while(true) {
  2.     try {
  3.         //generate string
  4.         // insert into
  5.         break;
  6.     } catch (dbexception $e) {
  7.         if ($e->getCode() == 'код ошибки на уникальный индекс') {
  8.             continue; // плюс, возможно, счётчик попыток
  9.         } else {
  10.             throw $e;
  11.         }
  12.     }
  13. }

Как можно заметить, способ безопасный для конкуретного доступа, но нетранзакционный. Ошибка insert'а потребует rollback. Зато просто и не требует лишних действий.
Можно предварительно делать селект этого значения, но это race condition. Можно внезапно споткнуться.

Способ номер далее:
insert into tablename .... select password from (select :password as password) dt where not exists (select 1 from tablename where tablename.passwordfield = dt.password)
Можно ли тут споткнуться - надо усиленно выяснять для конкретной СУБД. И по mysql и по postgresql честно не помню.

Способ обратный. Конкурентно-безопасный, транзакционный, детерминирован по затрачиваемому времени на обработку запроса (т.е. нет цикла с условием выхода на непонятно какой попытке). Но требует дополнительного обслуживания.
Делаете отдельную табличку из буквально пары полей, в которую изначально генерируете, перемешиваете и пишете какое-то число случайных строк. Лямов этак 10.
Когда понадобилась случайная строка - делаете select for update + delete из этой таблицы (для postgresql >=9.5 стоит посмотреть на select for update skip locked). Для более случайного распределения, можете выбирать where id > случайное_число на первой попытке и только если промахнулись, то без where
Очевидна проблема, что когда-нибудь предварительно сгенерированные строки кончатся и надо предусмотреть механизм их дальнейшего наполнения.


-----
PostgreSQL DBA
 
 Top
Мелкий Супермодератор
Отправлено: 21 Марта, 2016 - 13:08:50
Post Id



Активный участник


Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009  
Откуда: Россия, Санкт-Петербург


Помог: 618 раз(а)




Хм, забыл ещё вариацию первого варианта, которая как раз транзакционная:
mysql insert ignore
postgresql 9.5: insert ... ON CONFLICT DO NOTHING
Если affected_rows = 1, значит такой хэш успешно записали. Если 0 - то надо генерировать другой.


-----
PostgreSQL DBA
 
 Top
kuller
Отправлено: 28 Марта, 2016 - 13:25:38
Post Id



Частый посетитель


Покинул форум
Сообщений всего: 561
Дата рег-ции: Нояб. 2009  


Помог: 2 раз(а)




вот опять данная штука потребовалась для другого проекта. Там должен генерироваться случайны уникальный id. Здесь я решил заранее сгенерировать таблицу с уникальными id и написал следующее

PHP:
скопировать код в буфер обмена
  1.  
  2. <?PHP
  3.  
  4. class Password
  5. {
  6.         private static $password='';
  7.         private static $instance = NULL;
  8.        
  9.         function __construct($length = 5)
  10.         {
  11.                 self::$password=self::generatePassword($length);
  12.                 if(self::CheckBD(self::$password)){self::Init($length);}
  13.         }
  14.        
  15.         private static function generatePassword($length)
  16.         {
  17.                 $chars = '0123456789';
  18.                 $numChars = strlen($chars);
  19.                 $string = '';
  20.                 for($i = 0; $i < $length; $i++)
  21.                                 {
  22.                                 $string .= substr($chars, rand(1, $numChars) - 1, 1);
  23.                                 }
  24.                 return $string;
  25.         }
  26.        
  27.         private static function CheckBD()
  28.         {
  29.                 global $db;
  30.                        
  31.                 $m = Password::GetPassword();
  32.                 $t = $db->super_query("SELECT * FROM ls_generate WHERE user='$m'");
  33.                
  34.                 if($r == $t['user'])
  35.                 {
  36.                         echo false;
  37.                 }else{
  38.                         echo true;
  39.                 }
  40.         }
  41.        
  42.         public static function Init(){self::$instance = new Password();}
  43.         public static function GetPassword(){return self::$password;}
  44. }
  45.  
  46. $c = 99999;
  47. for($i=11111; $i<$c; $i++)
  48. {
  49.         Password::Init($lenght);
  50.         $code = Password::GetPassword();
  51.        
  52.         if($code == 11111 OR $code == 22222 OR $code == 33333 OR $code == 44444 OR $code == 55555 OR $code == 66666 OR $code == 77777 OR $code == 88888 OR $code == 99999 OR $code == 00000)
  53.         {
  54.                 $db->query("INSERT INTO ".PREFIX."_generate (user, gold) VALUES('$code', '1')");
  55.         }else{
  56.                 $db->query("INSERT INTO ".PREFIX."_generate (user, gold) VALUES('$code', '0')");
  57.         }
  58. }
  59.  
  60. ?>
  61.  


т.е. там где 5 одинаковых цифр надо gold присваивать 1. Сделались записи и я решил посмотреть как записались id под gold=1 и увидел что есть повторяющие айдишники. Простые айди я не проверял... может и там есть повторения.... В чем моя ошибка?

(Отредактировано автором: 28 Марта, 2016 - 13:41:13)

 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Вопросы новичков »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB