从PHP中的预先设定的集合中随机分配彩票

时间:2017-12-15 17:57:31

标签: php database random

我正在寻找一种原子方法,从票据调查中挑选一张票,然后用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可以根据自动增量从洗牌文件中获取特定位置。

有没有人遇到过类似的问题?它是如何解决的?

提前致谢。

1 个答案:

答案 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;
}