再次编辑:我不想再创建另一个问题,所以问这里。我有同样的情况。但是这次我需要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?
编辑:我不想创建任何其他字段。
答案 0 :(得分:9)
$newId = hash_hmac('sha1', $orderId, $secret_key).'-'.$orderId;
。因此,您的订单页面将显示为http://example.com/order/show/123456...absdef-123
。 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)
如果您的要求是:
然后我会推荐某种双向加密。哈希将无法正常工作,因为您无法从哈希中找到原始值。
我还补充说它应该是人性化的,例如有人可以通过电话给你打电话
我将使用一个非常简单的双向加密类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);