В зависимости от того, что делает ваш код с помощью $folder
, вы можете быть уязвимы для SQL injection.
Для лучшей безопасности перейдите к PDO или MySQLi и using prepared statements. Я написал библиотеку под названием EasyDB, чтобы разработчики могли лучше применять методы обеспечения безопасности.
Быстро, в здравом уме, и эффективный способ выбора N различных случайных элементов из базы данных выглядит следующим образом:
- Получить количество строк, которые соответствуют вашему условию (т.е.
WHERE folder = ?
).
- Создайте случайное число от 0 до этого числа.
- Выберите строку с заданным смещением, как и вы.
- Сохраните идентификатор ранее сгенерированной строки в постоянно растущем списке, чтобы исключить из результатов и уменьшить количество строк.
Пример, который использует EasyDB выглядит следующим образом:
// Connect to the database here:
$db = \ParagonIE\EasyDB\Factory::create(
'mysql;host=localhost;dbname=something',
'username',
'putastrongpasswordhere'
);
// Maintain an array of previous record IDs in $exclude
$exclude = array();
$count = $db->single('SELECT count(id) FROM photo_gen WHERE folder = ?', $folder);
// Select _up to_ 40 values. If we have less than 40 in the folder, stop
// when we've run out of photos to load:
$max = $count < 40 ? $count : 40;
// The loop:
for ($i = 0; $i < $max; ++$i) {
// The maximum value will decrease each iteration, which makes
// sense given that we are excluding one more result each time
$r = mt_rand(0, ($count - $i - 1));
// Dynamic query
$qs = "SELECT * FROM photo_gen WHERE folder = ?";
// We add AND id NOT IN (2,6,7,19, ...) to prevent duplicates:
if ($i > 0) {
$qs .= " AND id NOT IN (" . implode(', ', $exclude) . ")";
}
$qs .= "ORDER BY id ASC LIMIT ".$r.", 1";
$row = $db->row($qs, $folder);
/**
* Now you can operate on $row here. Feel free to copy the
* contents of your while($row=...) loop in place of this comment.
*/
// Prevent duplicates
$exclude []= (int) $row['id'];
}
Gordon's answer предлагает использовать ORDER BY RAND()
, который in general is a bad idea и может сделать ваши запросы очень медленно. Кроме того, хотя он говорит, что вам не нужно беспокоиться о том, что существует менее 40 строк (предположительно, из-за вероятности), это будет сбой в кромках.
Быстрое примечание о mt_rand()
: Это предвзятый и прогнозируемый генератор случайных чисел с 4 миллиардами возможных семян. Если вам нужны лучшие результаты, look into random_int()
(только для PHP 7, но я работаю над уровнем совместимости для проектов PHP 5. См. Связанный ответ для получения дополнительной информации.)
. , Вы используете 'limit' без' order by', поэтому произвольные строки возвращаются в любом случае. Я действительно не понимаю, что должен делать код. –
нужно получить случайные 40 элементов из базы данных – Vahagn
Только что обновил мой ответ. –