【问题标题】:How to generate Unique Order Id (just to show touser) with actual Order Id?如何使用实际订单 ID 生成唯一订单 ID(仅向用户展示)?
【发布时间】:2011-07-20 06:05:58
【问题描述】:

再次编辑:我不想创建另一个问题,所以在这里问。我也有同样的情况。但是这次我需要C语言的算法。任何人都可以帮助我。

我有下表。

CREATE TABLE IF NOT EXISTS `j741_order` (
  `order_id` int(11) NOT NULL AUTO_INCREMENT,
  `buyer_id` int(11) NOT NULL,
  `subtotal` decimal(15,5) DEFAULT '0.00000',
  `discount` decimal(15,5) NOT NULL DEFAULT '0.00000',
  `shipping` decimal(15,5) DEFAULT '0.00000',
  `tax` decimal(15,5) DEFAULT '0.00000',
  `total` decimal(15,5) NOT NULL DEFAULT '0.00000',
  `currency` char(3) DEFAULT NULL,
  `status` int(11) NOT NULL DEFAULT '0',
  `created_date` datetime NOT NULL,
  `modified_date` datetime NOT NULL,
  PRIMARY KEY (`order_id`),
  KEY `idx_buyer_id` (`buyer_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

我想生成一个唯一的 Order Id,(只是为了显示给用户)这样用户就无法猜测下一个 Order Id 是什么。

如何获得唯一的随机顺序 来自原始 Order If 的 ID

并从中取回原始订单 ID 那个随机顺序 ID?

编辑:我不想创建任何其他字段。

【问题讨论】:

  • 如果给定的用户只能看到他们的订单,那么猜测下一个 OrderId 应该不是问题。如果所有订单都是公开的,那么从性能、维护和工作量的角度来看,您最好简单地添加一个采用随机值的唯一列,或者至少将随机值的映射表添加到 OrderIds。为什么最简单最明显的解决方案不在桌面上?
  • 您的编辑大大改变了问题。如果您在用另一种语言实现算法时遇到问题,您应该发布一个问题,询问您已经取得的任何进展。

标签: php c algorithm encryption


【解决方案1】:

如果您的要求是:

  • 它必须是可逆的(即只需“随机”ID,您可以找到原始order_id)
  • 没有额外的列
  • 您根本不想向用户显示原始/内部 order_id

那么我会推荐某种双向加密。哈希不起作用,因为您无法从哈希中找到原始值。

我还要补充一点,它应该是人性化的,例如有人可以通过电话告诉你

我将使用由 Tony Marston 编写的位于 here 的非常简单的双向加密类。

我们希望解决方案对人类友好,所以让我们删除一些加扰字符。我只留下了大写字符、数字以及空格和破折号。所有这些都可以使用标准拼音字母表轻松传达,强制使用大写字母可以消除任何关于字符是什么的混淆。

这些是我使用的打乱字符串(我使用this online word scrambler,而不是自己尝试打乱字符串):

    $this->scramble1 = '0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
    $this->scramble2 = 'UKAH652LMOQ FBDIEG03JT17N4C89XPV-WRSYZ';

因此,创建人性化订单 ID 的代码是:

<?php

include 'encryption_class.php';

$crypt = new encryption_class();

$key = "A-COMPLETELY-RANDOM-KEY-THAT-I-HAVE-USED";
// Min length of 8 for encrypted string
$min_length = 8;

$order_id = 123456789;

print "Original: " . $order_id . PHP_EOL;

$encrypt_result = $crypt->encrypt($key, $order_id, $min_length); 

print "Encrypted: " . $encrypt_result . PHP_EOL;

// DECRYPT
$decrypt_result = $crypt->decrypt($key, $encrypt_result);

print "Decrypted: " . $decrypt_result . PHP_EOL;

?>

(您需要在本地下载并保存 *encryption_class* 文件,并包含它)。

我从命令行运行该代码并收到以下输出:

Original: 123456789
Encrypted: 2UD5UIK9S
Decrypted: 123456789

现在我们有了简短、人性化的 order_id,可以在诸如 http://myapp.example.com/order/view/2UD5UIK9S 之类的 URL 中使用,您无需向用户显示或传达内部 order_id。

注意事项:

一旦您的 order_id 是唯一的,加密代码将是唯一的(因为它是一个 PK)

这不应用作密码加密/解密例程 - 不要存储密码、存储哈希值。

确保您的密钥是随机的、复杂的并且只包含 $scramble 变量中的字符。

它只会混淆 order_id。

编辑:

虽然填充输入字符串 (order_id) 会产生一定程度的随机性,但您可以将其与@biakaveron 的答案结合起来创建一个类似http://myapp.example.com/order/view/5cc46aea44e898c3b4e1303eb18d8161302cd367/2UD5UIK9S 的 URL

【讨论】:

  • 它真的很有帮助。很抱歉,没有选择或恢复奖励的赏金。
  • 你知道C中类似的算法吗
  • 恐怕不行。我已经有一段时间没有用 C 进行任何认真的编程了
  • $crypt->encrypt($key, $order_id, $min_length);这对我没有任何意义..有什么想法吗?
【解决方案2】:
  1. 创建您的密钥(任何字符串)并保存在您的配置文件(或数据库配置)中。
  2. 创建唯一 ID:$newId = hash_hmac('sha1', $orderId, $secret_key).'-'.$orderId;。因此,您的订单页面将类似于http://example.com/order/show/123456...absdef-123
  3. 您可以快速获取原始订单ID并查看:
 list($hash, $original) = explode($newId, '-', 2);
 if (hash_hmac('sha1', $original, $secret_key).'-'.$original === $hash)
 {
    // its a correct ID
 }
 else
 {
    // wrong hash, ignore it!
 }

这种方式原始ID是公开的,但由于未知的哈希字符串(唯一ID的第一部分),用户无法在站点地址中替换它。

【讨论】:

  • 您还可以将用户特定的数据(如 USER-AGENT)添加到 $secret_key,因此生成的链接将无法在另一台计算机上使用。
  • +1 用于使用 HMAC,因此即使用户猜测下一个 orderId 哈希方法,他/她也无法生成不透明代码并伪装另一个请求订单号。很好的答案。
【解决方案3】:

首先,您应该将 order_id 作为物理标识符保留在数据库中:该字段是一个整数,它工作得很好(您的代码旨在使用它 - - 并且整数比字符串键有更好的性能).

但您可以添加另一个字段,作为用户的标识符

  • varchar(something)char(something) 字段,这样会获得更好的显示效果并且更难猜,
  • 它将显示给用户,
  • 上面会有一个UNIQUE 索引,
  • 但它对您的代码没有技术意义。


GUID 可能是一个想法——但我觉得它可能有点太长了......

基于用户名的第一个字母、日期和一些随机数的东西呢?
这很难猜,对用户来说还是有点意思的……

当然,您将无法根据该字符串标识符计算 order_id - 但如果该标识符是唯一的,则只需简单查询即可获得 order_id:

select order_id from your_table where nice_looking_id = '...';

【讨论】:

  • 我不想在我的表中添加另一列。
  • @Gaurav:如果没有表格栏祝你好运,没有其他方法可以有效地做到这一点
  • @Gaurav 你真的应该:从技术角度来看,保持整数主键是好的。
【解决方案4】:

您可以捏造它,但我完全建议添加另一列。下面是我使用 PHP 的方法。

// do your insert

// Retrieve last insert id
$orderId = mysql_insert_id();

// get the current timestamp
$time = time();

// Intersperse the $orderId into the $time to get a new "hash"
$orderId = explode("", (string)$orderId);
$time = explode("", (string)$time);

$orderIdLength = sizeof($orderId);
$newOrderId = "";
for ($i = 0; $i < $orderIdLength; ++$i) {
    $newOrderId .= $orderId[$i] . $time[$i];
}
$newOrderId = (int)$newOrderId;

因此,如果您的实际订单 ID 是 489,而当前时间戳是 1300778794,那么您最终会得到一个看起来像 418390 的订单 ID。如果您的客户随后将该订单 ID 用于任何事情,您只需将其拆开下:

$newOrderId = explode("", (string)$newOrderId);
$length = sizeof($newOrderId);
$oldOrderId = "";
for ($i = 0; $i < $length; $i = $i + 2) {
    $oldOrderId .= $newOrderId[$i];
}
$oldOrderId = (int)$oldOrderId;

这不是一种非常复杂的方法,也不是 100% 万无一失的。但是为了温和地混淆您的订单 ID,我认为它足以完成这项工作。

编辑: 顺便说一句,除了time() 之外,您还可以使用其他一些方法来生成一些半随机数来填充 id。例如,您可以使用rand(pow(10, log10($orderId)), pow(10, log10($orderId)+1)),它总是会返回一些与 orderId 长度相同的随机数。

【讨论】:

  • 这个解决方案对用户并不友好,因为每次 time() 的值发生变化时,输出的订单 ID 都会不同。虽然在计算上可以逆转混淆,但如果订单 ID 一直在变化,它会使用户感到困惑。
  • @Rinuwise:然后使用 UNIX_TIMESTAMP(created_date)。出于某种原因,我想象他正在为仅交付一次的打印发票生成订单 ID。我不知道我为什么这么想。 :)
【解决方案5】:

另一个非常简单的方法是对 OrderID 进行 base64 编码。您将 base64 编码的 ID 而非实际 ID 传递给客户端,然后在 ID 返回时对其进行解码。我建议从编码字符串的末尾删除等号。

优点:

  • 真正快速简单的混淆 的实际 ID

缺点:

  • 你必须记得解码它
  • 聪明的用户会很容易理解它 出去

【讨论】:

  • 高兴地投反对票,但请说出原因。特别是因为这个解决方案,尽管它可能很糟糕,但确实满足了问题的要求。
  • 没有为您的答案投票,但 base64 并不安全,因为高级用户可以计算每个 OrderID 的编码值并(可能)访问它。
【解决方案6】:

$original_id = [随便];

$salt = [very big private number/string/value];

$checksum = hexdec(substr(md5($original_id . $salt)), 0, 4);   // Generate 16 bit checksum

while(strlen($checksum) < 5)        // make sure it's five digits long
   $checksum = "0" . $checksum;

$user_facing_id = $checksum . $original_id; // Prepend original with checksum

您可以使用 substr($user_facing_id, 5) 取回原始 ID,您甚至可以通过检查 dechex(substr($user_facing_id, 0, 5)) 之间的相等性来检查它是否是有效的订单 ID 而无需询问您的数据库和 substr(md5(substr($user_facing_id, 5) . $salt)。

【讨论】:

    【解决方案7】:

    正如其他人所说,您可以简单地使用已知的盐生成订单 ID 的哈希值 - 而计算机并不真正关心订单号是否为

    854bf1176798d77ecaf6b66cbe71a8fc1b0c1847

    36698

    在湿件方面有很大的不同。

    这样用户就无法猜测下一个订单 ID 是什么。

    您在这里真正想避免什么?我原以为您只是想阻止用户看到其他人的订单 - 在这种情况下,您只需要使用订单 ID 和用户标识符的组合来选择订单。

    当然,订单总量可能被视为敏感信息 - 在这种情况下,只需使用与用户 ID 相关联的序列号。虽然您没有明确说明您使用的是哪个 DBMS,但我认为它是 mysql 或基于引擎的衍生产品 - 但以下内容也适用于大多数关系 DBMS:

    如果您向表中添加一个默认值为 0 的描述用户的列,那么您可以在订单表上添加触发器以自动获取、递增和更新订单表上每个插入的该值 - 即无需更改到其他地方的代码,除了支持“外部”订单参考。当然,您需要使用已下订单的相关数量来播种此值 - 类似于....

    ALTER TABLE buyers ADD COLUMN buy_ref_last INTEGER DEFAULT 0;
    ALTER TABLE orders ADD COLUMN buyer_order_ref INTEGER;
    UPDATE orders o SET buyer_order_ref = (SELECT COUNT(*)
        FROM orders r WHERE r.buyer_id=o.buyer_id
        AND r.order_id<o.order_id);
    

    (注意我怀疑上面不会直接在 MySQL 中运行,它不喜欢在同一个表上进行子选择作为更新/删除 - 你需要将逻辑展开到一个过程中)

    和....

    UPDATE buyers b SET buy_ref_last=(SELECT MAX(buyer_order_ref)
         FROM orders o WHERE o.buyer_id=b.id);
    

    【讨论】:

      猜你喜欢
      • 2014-03-12
      • 2023-04-03
      • 2014-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-19
      • 1970-01-01
      • 2021-02-13
      相关资源
      最近更新 更多