【问题标题】:Generate multiple guid in PHP for firebase database在 PHP 中为 firebase 数据库生成多个 guid
【发布时间】:2019-05-18 05:52:35
【问题描述】:

我在一个 MySQL 表中有 70,000 行。我正在尝试通过导入 JSON 将它们上传到 Firebase。我已将表格导出为 JSON 格式。输出是一个数组。例如,JSON 如下 -

[
{"question_id":"99","question":"What is your name?"},
{"question_id":"200","question":"What do you do?"}
]

为了在移动应用程序中正确使用 Firebase,我需要将此 JSON 数据作为对象导入,以及如下所示的 GUID -

{
    "-Lf64AvZinbjvEQLMzGc" : {
      "question_id" : 99,
      "question" : "What is your name?"
    }, 
    "-Lf64AvZinbjvEQLMzGd" : {
      "question_id" : 200,
      "question" : "What do you do?"
    }
}

由于行数为 70,000(此数据的 JSON 文件为 110 MB);无法单独插入 Firebase。 所以我尝试了一种生成 70,000 GUID 并编辑 JSON 文件以在每个对象之前添加每个 GUID 的方法。但是,我在这两个地方都卡住了。我正在使用以下类 (PushId.php) 来生成 GUID -

<?php

/**
 * Fancy ID generator that creates 20-character string identifiers with the following properties:
 *
 * 1. They're based on timestamp so that they sort *after* any existing ids.
 * 2. They contain 72-bits of random data after the timestamp so that IDs won't collide with other clients' IDs.
 * 3. They sort *lexicographically* (so the timestamp is converted to characters that will sort properly).
 * 4. They're monotonically increasing.  Even if you generate more than one in the same timestamp, the
 *    latter ones will sort after the former ones.  We do this by using the previous random bits
 *    but "incrementing" them by 1 (only in the case of a timestamp collision).
 */
class PushId
{
    /**
     * Modeled after base64 web-safe chars, but ordered by ASCII.
     *
     * @var string
     */
    const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';

    /**
     * Timestamp of last push, used to prevent local collisions if you push twice in one ms.
     *
     * @var int
     */
    private static $lastPushTime = 0;

    /**
     * We generate 72-bits of randomness which get turned into 12 characters and appended to the
     * timestamp to prevent collisions with other clients.  We store the last characters we
     * generated because in the event of a collision, we'll use those same characters except
     * "incremented" by one.
     *
     * @var array
     */
    private static $lastRandChars = [];

    /**
     * @return string
     */
    public static function generate()
    {
        $now = (int) microtime(true) * 1000;
        $isDuplicateTime = ($now === static::$lastPushTime);
        static::$lastPushTime = $now;

        $timeStampChars = new SplFixedArray(8);
        for ($i = 7; $i >= 0; $i--) {
            $timeStampChars[$i] = substr(self::PUSH_CHARS, $now % 64, 1);
            // NOTE: Can't use << here because javascript will convert to int and lose the upper bits.
            $now = (int) floor($now / 64);
        }

        static::assert($now === 0, 'We should have converted the entire timestamp.');

        $id = implode('', $timeStampChars->toArray());

        if (!$isDuplicateTime) {
            for ($i = 0; $i < 12; $i++) {
                $lastRandChars[$i] = floor(rand(0, 64));
            }
        } else {
            // If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
            for ($i = 11; $i >= 0 && static::$lastRandChars[$i] === 63; $i--) {
                static::$lastRandChars[$i] = 0;
            }
            static::$lastRandChars[$i]++;
        }
        for ($i = 0; $i < 12; $i++) {
            $id .= substr(self::PUSH_CHARS, $lastRandChars[$i], 1);
        }

        static::assert(strlen($id) === 20, 'Length should be 20.');

        return $id;
    }

    /**
     * @param bool   $condition
     * @param string $message
     */
    private static function assert($condition, $message = '')
    {
        if ($condition !== true) {
            throw new RuntimeException($message);
        }
    }
}

以下是我为生成 70,000 个 GUID 而编写的 PHP 代码,但它显示错误(如果我只使用它生成 1 个 GUID,则相同的代码正在工作)

require_once('PushId.php');
$vars = new PushId(); 


$my_file = 'TheGUIDs.txt';
$handle = fopen($my_file, 'w') or die('Cannot open file:  '.$my_file);

$i=1;

while($i <= 70000){
    $data = $vars->generate();
    fwrite($handle, $data);
    echo $data;
    $i++;
}

fclose($handle);

编辑 -1 我在生成 GUID 时遇到的错误是 - Notice: Undefined offset: 11 in C:\wamp64\www\firebase-json\PushId.php on line 65

Notice: Undefined variable: lastRandChars in C:\wamp64\www\firebase-json\PushId.php on line 71

第一个 GUID 是完整的,例如在上次运行中我得到了-Lf8WPlkkNTUjYkIP4WT,但后来我得到了不完整的 GUID -Lf8WPlk------------

【问题讨论】:

    标签: php json firebase


    【解决方案1】:

    首先,您忘记在某些地方将static:: 添加到$lastRandChars:

    for ($i = 0; $i < 12; $i++) {
        $lastRandChars[$i] = floor(rand(0, 64)); // << here
    }
    
    for ($i = 0; $i < 12; $i++) {
        $id .= substr(self::PUSH_CHARS, $lastRandChars[$i], 1); // << and here
    }
    

    下一步: 在增加前一个 ID 时,您错过了不仅应该增加最后一个字符,还应该增加所有以前的字符(如果它们超过 63)。 样本 ID 序列:

    ...
    -Lf64AvZinbjvEQLMzGw
    -Lf64AvZinbjvEQLMzGx
    -Lf64AvZinbjvEQLMzGy
    -Lf64AvZinbjvEQLMzGz 
    -Lf64AvZinbjvEQLMzH- <<< on this step last char is reset, and previous one is incremented by one
    -Lf64AvZinbjvEQLMzH0
    -Lf64AvZinbjvEQLMzH1
    ...
    -Lf64AvZinbjvEQLMzzw
    -Lf64AvZinbjvEQLMzzx
    -Lf64AvZinbjvEQLMzzw
    -Lf64AvZinbjvEQLMzzz 
    -Lf64AvZinbjvEQLN--- <<< on this step last three chars are reset, and previous one is incremented by one
    -Lf64AvZinbjvEQLN--0
    -Lf64AvZinbjvEQLN--1
    ...
    

    修改后的递增逻辑:

    // If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
    for ($i = 11; $i >= 0; $i--) {
        $previousIncremented = false;
        for ($j = $i; $j > 0; $j--) {
            if (!$previousIncremented) {
                static::$lastRandChars[$j]++;
            }
            if (static::$lastRandChars[$j] == 64) {
                static::$lastRandChars[$j] = 0;
                static::$lastRandChars[$j - 1]++;
                $previousIncremented = true;
            } else {
                break 2;
            }
        }
    }
    

    【讨论】:

    • 非常感谢。我明白这两点。然而,即使在修改了增量逻辑之后,它有时在 5000 个 GUID 之后显示错误,有时在 30,000 个 GUID 之后显示错误。我能在随机的地方弄清楚为什么?
    • @Dr.AtulTiwari,我认为问题出在$lastRandChars[$i] = floor(rand(0, 64)); 线上。应该有rand(0, 63),因为我们不能使用位置64(我们只有63 字符)。
    猜你喜欢
    • 2011-09-10
    • 2019-02-05
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    • 1970-01-01
    • 2016-08-07
    • 1970-01-01
    • 2011-07-26
    相关资源
    最近更新 更多