根据您的代码使用$folder
所做的操作,您可能容易受到SQL injection的影响。
为了更好的安全性,请考虑转移到PDO或MySQLi和using prepared statements。我写了一个名为EasyDB的库,以便开发人员更容易采用更好的安全措施。
快速,神志清醒,和有效的方式从数据库中选择N个不同的随机元素如下:
- 获取符合你条件的行(即
WHERE folder = ?
)的数量。
- 生成一个介于0和这个数字之间的随机数。
- 像你一样选择一个给定偏移量的行。
- 将先前生成的行的ID存储在不断增长的列表中,以从结果中排除,并减少行数。
使用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
刚刚更新了我的答案。 –