如何使用实际订单ID生成唯一订单ID(仅显示touser)?

时间:2011-03-22 06:51:15

标签: php c algorithm encryption

再次编辑:我不想再创建另一个问题,所以问这里。我有同样的情况。但是这次我需要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 ;

我想生成一个唯一的订单ID,(只是向用户显示),以便用户无法猜出下一个订单ID。

  

如何获得该唯一随机顺序   来自原始订单的ID

     

并从中获取原始订单ID   随机订单ID?

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

7 个答案:

答案 0 :(得分:9)

  1. 创建您的密钥(任何字符串)并保存在配置文件(或DB配置)中。
  2. 创建唯一ID:$newId = hash_hmac('sha1', $orderId, $secret_key).'-'.$orderId;。因此,您的订单页面将显示为http://example.com/order/show/123456...absdef-123
  3. 您可以快速获取原始订单ID并进行检查:
  4.  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的第一部分),用户无法在站点地址中替换它。

答案 1 :(得分:9)

如果您的要求是:

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

然后我会推荐某种双向加密。哈希将无法正常工作,因为您无法从哈希中找到原始值。

我还补充说它应该是人性化的,例如有人可以通过电话给你打电话

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

我们希望解决方案对人类友好,所以让我们删除一些争夺字符。我只留下大写字母,数字以及空格和短划线符号。所有这些都可以使用标准的拼音字母轻松传达,强制使用大写可以消除任何关于角色的混淆。

这些是我使用的争夺字符串(我使用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等网址中使用,您永远不需要向用户显示或传达内部order_id。

备注:

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

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

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

它仅对order_id进行模糊处理。

修改

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

答案 2 :(得分:2)

首先,您应该将 order_id 作为数据库中的物理标识符:该字段是一个整数,它运行良好(您的代码旨在使用那个 - 和整数比字符串键提供更好的表现)

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

  • varchar(something)char(something)字段,可以更好地显示,并且更难猜测,
  • 将向用户显示
  • 上面会有一个UNIQUE索引,
  • 但它对你的代码没有任何技术意义。


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

根据用户姓名的第一个字母,日期和一些随机数,该怎么办?
很难猜测,对用户来说仍然有一点意义......

当然,您将无法从该字符串标识符计算order_id - 但如果该字符串标识符是唯一的,那么您将获得一个简单的查询,然后您将获得order_id:

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

答案 3 :(得分:0)

你可以捏造它,但我完全建议添加另一列。这是我用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长度相同的随机数。

答案 4 :(得分:0)

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

优点:

  • 真正快速而简单的混淆 实际身份证件

缺点:

  • 你必须记住解码它
  • 聪明的用户很容易想到它 出

答案 5 :(得分:0)

$ 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)。

答案 6 :(得分:0)

正如其他人所说,您只需使用已知的盐生成订单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);