如何为laravel中的每个用户生成唯一的随机值并将其添加到数据库

时间:2015-02-15 08:28:24

标签: php mysql laravel random eloquent

我正在开发一个活动组织网站。在这里,当用户注册一个事件时,他将获得一个唯一的随机数(10位数),我们用它来生成条形码并将其邮寄给他。现在,

  1. 我想为每个注册的活动提供唯一的号码。
  2. 还随机
  3. 一种解决方案是获取数组中的所有随机数并使用Php rand(1000000000,9999999999)生成随机数并循环并检查所有值。获取不等于数组中任何值的第一个值,并将其添加到数据库中。

    但我认为可能有更好的解决方案。有什么建议吗?

8 个答案:

答案 0 :(得分:14)

您可以使用php的uniqid()函数根据microtime生成唯一ID(当前时间,以微秒为单位)

示例:

<?php
echo uniqid();
?>

输出:

56c3096338cdb

答案 1 :(得分:8)

你的逻辑在技术上并不是错误的。但是,如果您的应用程序吸引了大量用户,那么就资源和计算时间而言,获取所有随机数可能会变得不必要的昂贵。

我建议使用另一种方法,在其中生成随机数,然后根据数据库进行检查。

function generateBarcodeNumber() {
    $number = mt_rand(1000000000, 9999999999); // better than rand()

    // call the same function if the barcode exists already
    if (barcodeNumberExists($number)) {
        return generateBarcodeNumber();
    }

    // otherwise, it's valid and can be used
    return $number;
}

function barcodeNumberExists($number) {
    // query the database and return a boolean
    // for instance, it might look like this in Laravel
    return User::whereBarcodeNumber($number)->exists();
}

答案 2 :(得分:2)

通过阵列循环不会那么高效。如果你的数据库变得太大,那么它会减慢整个过程的速度,并且当两个线程在同一个随机数的数组中循环时,可能会出现这种情况,并且可以找到它并将相同的数字返回给两个故障单。 / p>

因此,您可以将10位注册ID设置为主键,而不是循环遍历数组,您可以插入注册详细信息以及随机生成的数字,如果数据库插入操作成功,您可以返回注册ID,但如果没有,则重新生成随机数并插入。

替代解决方案将更有效 您可以使用时间戳来生成10位唯一注册号,而不是10位数的随机数,并使其随机化,您可以随机化时间戳的前2位或3位数

答案 3 :(得分:1)

为了避免在每次创建新代码时都必须检查是否存在匹配代码的问题,我只是捕获MySQL的重复记录异常(错误代码1062)。如果捕获到该错误,我只需再次调用该函数,直到保存成功。这样,它只需要在与现有代码冲突时生成新代码。运行速度更快 - 但随着用户数量接近可能的条形码数量,显然会慢一些。

function generateBarcode($user_id) {
    try {
        $user = User::find($user_id);
        $user->barcode = mt_rand(1000000000, 9999999999);
        $user->save();

    } catch (Exception $e) {
        $error_info = $e->errorInfo;
        if($error_info[1] == 1062) {
            generateBarcode($user_id);
        } else {
            // Only logs when an error other than duplicate happens
            Log::error($e);
        }

    }
}

因此,只需遍历要为其分配代码的所有用户:

foreach(User::all() as $user) {
    generateBarcode($user->id);
}

如果进行了最大次数的尝试,你还可以添加一些逻辑来逃避函数循环,但我从未打扰过因为碰撞不太可能。

答案 4 :(得分:1)

这很好:

do {
   $refrence_id = mt_rand( 1000000000, 9999999999 );
} while ( DB::table( 'transations' )->where( 'RefrenceID', $refrence_id )->exists() );

答案 5 :(得分:1)

<?php
declare(strict_types=1);

namespace App\Helpers;


use App\Exceptions\GeneratorException;

class GeneratorHelper
{
    public static $limitIterations = 100000;

    /**
     * @param string $column
     * @param string $modelClass
     * @return string
     * @throws GeneratorException
     */
    public static function generateID(string $modelClass, string $column): string
    {
        return self::run(
            $modelClass,
            $column,
            self::IDGenerator(),
            'Generation id is failed. The loop limit exceeds ' . self::$limitIterations
        );
    }

    /**
     * @param string     $modelClass
     * @param string     $column
     * @param \Generator $generator
     * @param string     $exceptionMessage
     * @param array      $whereParams
     * @return string
     * @throws GeneratorException
     */
    protected static function run(string $modelClass, string $column, \Generator $generator, string $exceptionMessage, array $whereParams = []): string
    {
        try {
            foreach ($generator as $id) {
                $query = $modelClass::where([$column => $id]);
                foreach ($whereParams as $param) {
                    $query->where(...$param);
                }
                if (!$query->first()) {
                    return $id;
                }
            }
        } catch (\Throwable $e) {
            $exceptionMessage = $e->getMessage();
        }

        throw new GeneratorException($exceptionMessage);
    }

    protected static function IDGenerator(): ?\Generator
    {
        for ($i = 1; $i <= self::$limitIterations; $i++) {
            yield (string)random_int(1000000000, 9999999999);            
        }
        return null;
    }
}

样本用量

$card->number = GeneratorHelper::generateID(Card::class, 'number');

答案 6 :(得分:0)

我做了类似的事

/**
 * Generate unique shipment ID
 * 
 * @param int $length
 * 
 * @return string
 */ 
function generateShipmentId($length)
{
    $number = '';

    do {
        for ($i=$length; $i--; $i>0) {
            $number .= mt_rand(0,9);
        }
    } while ( !empty(DB::table('shipments')->where('id', $number)->first(['id'])) );

    return $number;
}

答案 7 :(得分:0)

一个解决方案可能是这样的:

use Illuminate\Support\Facades\Validator;
private function genUserCode(){
    $this->user_code = [
        'user_code' => mt_rand(1000000000,9999999999)
    ];

    $rules = ['user_code' => 'unique:users'];

    $validate = Validator::make($this->user_code, $rules)->passes();

    return $validate ? $this->user_code['user_code'] : $this->genUserCode();
}

它会生成一个介于1000000000和9999999999之间的随机数。之后,它将根据该表验证该数字。如果为true,则返回数字,否则再次运行该函数。