How to create a unique order identifier (only for user display) with the actual order identifier?

EDIT AGAIN: I do not want to create another question, so please here. I have the same situation. But this time I need an algorithm in C. Can someone help me.

I have the following table.

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 ; 

I want to generate a unique order identifier (just show it to the user) so that the user cannot figure out what the next order identifier will be.

How can I get this unique random order Id from the original order If

and return the original order id from this random order id?

EDIT: I do not want to create any other field.

+7
source share
7 answers

If your requirements:

  • It should be reversible (that is, given just a "random" identifier, you can find the original order_id)
  • No extra columns
  • You do not want to show the source / internal order_id to the user at all

then I would recommend some kind of two-way encryption. Hashing will not work as you cannot find the original value from the hash.

I also add that it should be convenient for a person, for example. someone can call you

I am going to use a very simple two-way encryption class located here , which was written by Tony Marston.

We want the solution to be convenient for people, so remove some of the scrambling symbols. I left only uppercase characters, numbers and space and hatching characters. All of them can be easily transmitted using the standard phonetic alphabet, and the forced use of uppercase eliminates any confusion as to what character.

These are the scrambling strings that I used (I used this online scrambler instead of trying to cross the string myself):

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

So the code to create our friendly person order 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; ?> 

(You need to download and save the * encryption_class * file locally and enable it).

I ran this code from the command line and got the following output:

 Original: 123456789 Encrypted: 2UD5UIK9S Decrypted: 123456789 

We now have a short, user-friendly order_id that can be used in a URL such as http://myapp.example.com/order/view/2UD5UIK9S , and you never need to display or pass an internal order_id for your users .

Notes:

The encrypted code will be unique if your order_id is unique (since it will be PK)

This should not be used as a password encryption / decryption procedure - do not store passwords, store hashes.

Make sure your secret key is random, complex, and contains only characters in your $ scramble variables.

It only confuses order_id.

Edit:

Although padding the input line (order_id) creates a certain amount of ramdomness, you can combine this with @biakaveron's answer to create a url like http://myapp.example.com/order/view/5cc46aea44e898c3b4e1303eb18d8161302cd367/2UD5UIK9S

+9
source
  • Create your private key (any line) and save it in your configuration files (or in the DB configuration).
  • Create a unique identifier: $newId = hash_hmac('sha1', $orderId, $secret_key).'-'.$orderId; . Thus, your order pages will look like http://example.com/order/show/123456...absdef-123 .
  • You can quickly get the original order ID and check it:
  list($hash, $original) = explode($newId, '-', 2); if (hash_hmac('sha1', $original, $secret_key).'-'.$original === $hash) { // its a correct ID } else { // wrong hash, ignore it! } 

This source identifier is publicly available, but the user cannot replace it with the site address due to an unknown hashed string (the first part of the unique identifier).

+9
source

First of all, you should save your order_id as a physical identifier in your database: this field is an integer, it works well (your code is designed to use this - and integers give better results than string ones).

But you can add another field that will act as an identifier for the user :

  • A varchar(something) or char(something) that would get a better display and would be harder to guess
  • It will be displayed to the user,
  • It will have a UNIQUE pointer,
  • But this will not make any technical sense to your code.


A GUID may be an idea - but I have a function that may be too long ...

What about something based on the first letter of the username, date, and some random number?
It would be hard to guess, and still makes little sense to the user ...

Of course, you cannot calculate order_id from this string identifier, but if this is a unique, simple request, and you will return order_id:

 select order_id from your_table where nice_looking_id = '...'; 
+2
source

You may be curious, but I would totally recommend adding another column. This is how I will do it with 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; 

So, if your actual order ID is 489 and the current timestamp is 1300778794, you get an order ID that looks like 418390. If your customer then uses this order ID for something, you just need to break it down:

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

This is not a very complicated approach and is not 100% impeccable. But in order to cautiously confuse your order identifiers, I think that it does this job enough.

Edit: as soon as possible, you can use a different method to generate some semi-random number to fill in an id other than time() . For example, you could do rand(pow(10, log10($orderId)), pow(10, log10($orderId)+1)) , which would always return a random number that has the same length as orderId.

0
source

Another really simple method is to base64 encode OrderID. You pass the base64 encoded identifier to the client instead of the actual identifier, and then decode the identifier when it returns. I would recommend removing the equal signs from the end of the encoded string.

Benefits:

  • Really fast and easy obfuscation of the actual identifier

Disadvantages:

  • You must remember to decode it.
  • A smart user could easily understand this from
0
source

$ original_id = [whatever];

 $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 five digits long $checksum = "0" . $checksum; $user_facing_id = $checksum . $original_id; // Prepend original with checksum 

You can return the original identifier with substr ($ user_facing_id, 5), and you can even check if it is a valid order identifier without polling your database by checking the equality between dechex (substr ($ user_facing_id, 0, 5)) and substr (md5 (substr ($ user_facing_id, 5). $ salt).

0
source

As others have said, you can simply generate a hash of the order ID with a known salt - while on computers it doesn't matter if the order number

854bf1176798d77ecaf6b66cbe71a8fc1b0c1847

or

36698

There is a big difference when it comes to wetware.

so that the user canโ€™t guess what will be the next order identifier.

What are you really trying to avoid here? I would think that you just want to prevent users from seeing other people's orders - in this case, you just need to use a combination of the order ID and user ID to select orders.

Of course, the total volume of orders can be considered confidential information - in this case, just use the serial number associated with the user ID. Although you have not explicitly indicated which DBMS you are using, I assume that it is mysql or a derivative based on the engine, but the following applies to most relational DBMSs:

If you add a column to the table describing users with a default value of 0, you can add triggers to the order table to automatically retrieve, increase and update this value for each insert in the order table - i.e. no changes are required to the code elsewhere, with the exception of supporting the "external" link to the order. Of course, you need to sow this value with the corresponding number of already placed orders - something like ....

 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); 

(note, I suspect that the above will not work directly in MySQL, it does not look like subsamples in the same table as update / delete - you need to deploy the logic into the procedure)

and....

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

All Articles