我正在寻找一种原子方法,从票据调查中挑选一张票,然后用PHP提供给某人。到目前为止,我已经想到了一些不同的解决方案,但我不确定它们是多么原子(两个人绝对不能拥有相同的票)。
所有故障单都是在1-N范围内预先生成的(随机数字,因为不能使用故障单)。我认为可行的方法是:
1)使用一个文件来存储洗牌的票据并选择第一个并重写文件(或选择最后一个并且只截断而不重写)。最简单的例子:
function NextTicket()
{
$fh = fopen('tickets.txt', 'rw+');
flock($fh, LOCK_EX)) //hopefully this should prevent parallel access
$all = explode("\n", stream_get_contents($arq));
$return = $all[0]; //ticket to be returned
unset($all[0]);
rewind($fh);
ftruncate($fh,0);
fwrite($fh, implode("\n", $all);
fclose($fh);
return $ticket;
}
2)使用sqlite文件保存所有故障单并一次提取一行(假设插入了洗牌行)。
function NextTicket()
{
$db = new SQLite3('tickets.sqlite');
$db->exec('BEGIN');
$res = $db->query('SELECT rowid,TI_NUMBER FROM tickets LIMIT 1');
$ticket = $res->fetchArray(SQLITE3_ASSOC);
$db->exec('DELETE FROM tickets WHERE rowid='.$ticket['rowid']);
$db->exec('COMMIT');
return $ticket['TI_NUMBER'];
}
3)使用sqlite作为单行计数器而不是连续保存每个票号(我不能使用此方法,因为传递应该是随机的)。
function NextTicket()
{
$db = new SQLite3('/tmp/tickets.sqlite');
$db->exec('BEGIN');
$res = $db->query('SELECT rowid,TI_NUMBER FROM tickets LIMIT 1');
$ticket = $res->fetchArray(SQLITE3_ASSOC);
$res = $db->query('UPDATE tickets SET TI_NUMBER=TI_NUMBER+1 WHERE rowid='.$ticket['rowid']);
$db->exec('COMMIT');
return $ticket['TI_NUMBER'];
}
4)其他方法? Mysql 5.6数据库也可用。自动增量不能用作顺序,我需要从集合中随机排。也许组合1和3可以根据自动增量从洗牌文件中获取特定位置。
有没有人遇到过类似的问题?它是如何解决的?
提前致谢。
答案 0 :(得分:0)
如果您想提供许多随机票,只需使用带有id, number
列的mysql表。将N个随机数设置为它并获取+删除第一个/最后一个。您可以使用从1到N的混洗数组作为源。
但是,如果您只是在数据库中使用计数器并且不提供随机票,该怎么办?结果没关系,因为获胜者的号码也会随机生成。然后一切都会变得更加简单。为了隐藏用户,这些数字不是随机的,只需使用编码函数,即使用自动递增数作为参数。
编码功能的代码:
function encryptNumber($number) {
$ahphaEncodeTable = [
0 => 'N', 1 => 'E', 2 => 'D', 3 => 'O',
4 => 'K', 5 => 'Z', 6 => 'M', 7 => 'R',
8 => 'L', 9 => 'A'
];
$numEncodeTable = [
0 => 3, 1 => 6,
2 => 9, 3 => 0,
4 => 4, 5 => 8,
6 => 1, 7 => 7,
8 => 5, 9 => 2
];
$numbersArr = array_map('intval', str_split($number));
$numbersFirstIndex = key($numbersArr);
$numbersArrKeys = array_keys($numbersArr);
$numbersLastIndex = end($numbersArrKeys);
$resultHash = '';
foreach ($numbersArr as $index => $number) {
if($numbersFirstIndex === $index) {
$resultHash .= $ahphaEncodeTable[$number];
if($numbersFirstIndex === $numbersLastIndex) {
$resultHash .= mt_rand(0, 9);
}
}
elseif($numbersLastIndex === $index) {
if($numbersFirstIndex !== $numbersLastIndex) {
//insert after first letter in string
$resultHash = substr_replace($resultHash, $ahphaEncodeTable[$number], 1, 0);
}
$resultHash .= mt_rand(0, 9);
}
else {
$resultHash .= $numEncodeTable[$number];
}
}
return $resultHash;
}