Obfuscating database ID to customer facing number - php

I'm using mysql database auto-increment as an order ID. When I display the order ID to the user, I want to somehow mask/obfuscate it.
Why?
So at first glance, it is obvious to admin users what the number
refers to (orders start with 10, customers start with 20 etc)
To hide, at first glance, that this is only my 4th order.
Based on this this answer, I want the masked/obfuscated order id to:
Be only numbers
Consistent length (if possible)
Not cause collisions
Be reversible so I can decode it and get the original ID
How would I acheive this in PHP? It doesn't have to be very complex, just so at first glance it's not obvious.

I think you can use XOR operator to hide "at first glance" for example (MySQL example):
(id*121) ^ 2342323
Where 2342323 and 121 are "magic" numbers - templates for the order number.
To reverse:
(OrderNum ^ 2342323)/121
Additional advantage in this case - you can validate OrderNumber (to avoid spam or something like this in online form) if (OrderNum ^ 2342323) is divided by 121 with no remainder.
SQLFiddle demo

A little bit late, but Optimus (https://github.com/jenssegers/optimus) does exactly what is here asked for.
$encoded = $optimus->encode(20); // 1535832388
$original = $optimus->decode(1535832388); // 20
Only the initial setup is a bit weird (generate primenumbers)

Probably the simplest way is to just generate a long random string and use it instead of the auto-increment ID. Or maybe use it alongside the auto-increment ID. If the string is long enough and random enough, it will be unique for every record (think of GUIDs). Then you can display these to the user and not worry about anything.

Can it help?
echo hexdec(uniqid());
Off course you should store this value at db, at the same row with order id.

Just converting a ID into something like HEX might not give you the result what you like. Moreover its still easy 'guessable'
I would a a extra ID column (i.e. order_id). Set a unqi. index. Then on_creation use one of the following mysql functions:
SHA1(contcat('ORDER', id))
MD5(contcat('ORDER', id))
SHA1(contcat('ORDER', id, customer_id))
MD5(contcat('ORDER', id, customer_id))
UUID()
// try this in your mysql console
SELECT UUID(), SHA(CONCAT('ORDER',10)), SHA1(1);
You could (as in the example), add a simple text prefix like 'order'. Or even combine them. However i think UUID() would be easiest.
Implementation depends a bit on what you prefer you could use a stored procedure) or incorporate it in your model.

Related

Generatinge Unique Id on the fly Mysql + PHP

I am trying to come up with a solution to generate a Unique Id preferably on the Fly. Usage scope could be Order, Product or Plan Id, where there is no security involved.
I don't like idea of generating a random number and then querying the db to check its uniqueness and repeating the process if it is not in this case where security isn't an issue.
Also I don't prefer using Auto Increment id since it looks so simple.
My initial thought is to use a combination of Auto Increment id + timestamp converting the decimal value to hex so it looks like a random string. And then finally prefixing and suffixing it with 2 digit random string.
function generateUID($num){
$str = dechex(time()+ intval($num));
$prefix = dechex(rand(1,15));
$suffix = dechex(rand(1,15));
return strtoupper($suffix.$str.$prefix);
}
Where $num is the auto_increment id
Returns something like E53D42A046
Is this the right way to go about doing this, are there collision issues ?
I thank all responses..!
I acknowledge the usefulness of uniqid() but in this context to be genuinely unique Auto_Increment need to play a significant part so how will it do so in uniqid. Passing it as a prefix would result in a Product id which vary greatly in size. (153d432da861fe, 999999953d432f439bc0).
To expand the scope further, Ideally we want a unique code which looks random with fairly consistent length and could be reversed to the auto_increment id from which it was created.
Such a function already exists - uniqid()
http://php.net/manual/en/function.uniqid.php
It works based on the timestamp down to the microsecond - you can add a prefix based on the process ID to further refine it. There are a couple more robust versions out there as well - see PHP function to generate v4 UUID

Regenerate "random" MySQL query

I have a database with more than a million records. I'm trying to get the records in a randomized order. The database is filled with links to images and each image has an unique number. So I should be able to recreate the same "random" order for the next and previous buttons on the pictures?
Is there a way to come up with a query and save it on a cookie or session and reuse that to regenerate my random order?
Overall is it efficient because I don't want the load time to go high?
Any suggestion is awesome.
The easiest way for this is, put in another column in your database, index it properly, and give it a random integer. Then you can ORDER your table on this, and have it be stable. This will make all users have the same, but random, sequence.
EDIT: If you want each user to have their own sequence, this too is simple enough, as Alma Do said:
SELECT * FROM records ORDER BY RAND(17)
will always have the same ordering (as long as you don't change the database), and different from
SELECT * FROM records ORDER BY RAND(2308)
But it will not be fast.
The only alternative I can think of would use a lot of space: when you calculate a sequence for a user, store it in a table. This would require a two-column table of million rows per user.
According to MySQL manual page, you can specify parameter for RAND() function and so it will return random, but repeatable sequence:
If a constant integer argument N is specified, it is used as the seed
value, which produces a repeatable sequence of column values.
That means, you'll be able to have random order, but still same order across your prev-next pages.

Counting items or incrementing a number?

From someone with more experience than myself, would it be a better idea to simply count the number of items in a table (such as counting the number of topics in a category) or to keep a variable that holds that value and just increment and call it (an extra field in the category table)?
Is there a significant difference between the two or is it just very slight, and even if it is slight, would one method still be better than the other? It's not for any one particular project, so please answer generally (if that makes sense) rather than based on something like the number of users.
Thank you.
To get the number of items (rows in a table), you'd use standard SQL and do it on demand
SELECT COUNT(*) FROM MyTable
Note, in case I've missed something, each item (row) in the table has some unique identifier, whether it's a part number, some code, or an auto-increment. So adding a new row could trigger the "auto-increment" of a column.
This is unrelated to "counting rows". Because of DELETEs or ROLLBACK, numbers may not be contiguous.
Trying to maintain row counts separately will end in tears and/or disaster. Trying to use COUNT(*)+1 or MAX(id)+1 to generate a new row identifier is even worse
I think there is some confusion about your question. My interpretation is whether you want to do a select count(*) or a column where you track your actual count.
I would not add such a column, if you don't have reasons to do so. This is premature optimization and you complicate your software design.
Also, you want to avoid having the same information stored in different places. Counting is a trivial task, so you actually duplicating information, which is a bad idea.
I'd go with just counting. If you notice a performance issue, you can consider other options, but as soon as you keep a value that's separate, you have to do some work to make sure it's always correct. Using COUNT() you always get the actual number "straight from the horse's mouth" so to speak.
Basically, don't start optimizing until you have to. If everything works fine and fast using COUNT(), then do that. Otherwise, store the count somewhere, but rather than adding/subtracting to update the stored value, run COUNT() when needed to get the new number of items
In my forum I count the sub-threads in a forum like this:
SELECT COUNT(forumid) AS count FROM forumtable
As long as you're using an identifier that is the same to specify what forum and/or sub-section, and the column has an index key, it's very fast. So there's no reason to add more columns than you need to.

Custom Unique ID

Is there any way I could make my model ID (primary key) generated into random unique 8 digits containing only numbers instead of the default auto increment?
A client requested this specific 8-digits-number-only feature, so I can't argue much about the reasons.
I want to use the PHP uniqid but it's 13 digits and contains alphabets as well.
Any idea?
Thanks.
Update
I forgot to tell that I need the ID randomly generated each new record being saved.
Just want to ask the mechanism on generating the ID and then saving the ID (also the attributes). Do I have to check the database first for the randomly generated ID whether another same key already exists and then save the attributes or what?
Why dont you keep the auto increment but set it to start from 10000000 on your primary key instead of 1?
ALTER TABLE some_table AUTO_INCREMENT=10000000
Yes you can. I assume you are on MySQL, when talking about AI. Just do not set it as auto increment and insert the value as for the other columns. You can create a function or method, which will take up to 8 numbers randomly or in specific order (algorithm).
INSERT INTO model (id, name, value, etc) VALUES (87654321, 'My selected name', 'some price or text', 'etc').
Consider that INT(11) value may accept from -2147483648 to 2147483647. Which will fit you for numbers with 8 digits. If at later time the client request bigger numbers you may need to switch to BIGINT.
I use to set the Primary Keys as unsigned, which allows you to fit numbers between 0 and 4294967295.
For php function - generator of 8 digits:
<?php
mt_srand();
$id = mt_rand(10000000, 99999999);
?>
You can read more about mt_srand() and mt_rand() on php documentation. It is said that they are better than the srand() and rand().
Keep the ID, but pad it.
$id = 6;
$padded_id = sprintf("%013d", $id);
// This will print 0000000000006
That'll pad the $id so that it's 13 digits long.
Every time you need to display the ID use a function to convert it, like this.
function padId($id){
return sprintf("%013d", $id);
}
Or you could make a row in your table called pad-id, then run this function when you create a record (along with mysql_insert_id (to get the ID just inserted)).
The best approach depends on a subtle aspect of your client's randomness requirement --
When they say random do they mean completely unpredictable or just hard to predict? I don't mean to sound like Clinton at the Lewinski trial, but what your client intends when they say random affects whether it will even be possible for you to meet the requirement.
If the client wants to hide user IDs (for some perceived security benefit) and make them virtually impossible to predict or reverse-engineer, then that is very difficult. If the client would be satisfied with just "hard" to predict (which I suspect), then you can do something simple, similar to the md5 approach (#Dotty). But md5 is not collision resistant. And even with the best, provably unique hash algorithms (which md5 is not), you'll have a collision problem if the number of users is large compared to the number of digits you are allowed for user ID's (8). You have about 27 bits to work with in the 8 decimal digits allowed. Which means you're likely to get a collision after 2^N/2 = 2^(27/2) which is about 10K users. So if your client's user list approaches 10K users, then even the best hash algorithm will spend a lot of time filtering out all the collisions.
To solve this without filters and nondeterministic algorithms, just use a simple "Full Cycle" algorithm. Some will produce pseudo-random numbers (PRNs) that are guaranteed to be unique and guaranteed to fully span whatever range you're trying to cover (e.g., the set of all 8-digit positive integers). And if you ever need to reverse engineer the user registration sequence just rerun the full cycle PRN generator again with whatever initial value you used. And you can keep this initial value a secret, like a private key, if your client wants to make it slightly more difficult than easy for a hacker to reverse-engineer your user ID sequence.
Another question for your client is whether leading zeros are allowed in the user id. If so, (and the client's randomness requirements are liberal) then the simple Full Cycle algorithm on Wikipedia will work nicely for you. It could be distilled to 2 lines of PHP.
Whatever algorithm you use, it might be good to actually generate the list of official 8-digit semi-random user IDs in a separate table, and then just "pop" the value from the top of the table (deleting that row) whenever you add a new user. The database memory requirements shouldn't be prohibitive and it will streamline the user experience, eliminating any delays and memory gobbling caused by sophisticated, nondeterministic, random number generators and uniqueness filters. Trying to create the user ID online, live, it's conceivable you could get into a perpetual loop with some hash algorithms stalling your user registration indefinitely. And this stall (due to perpetual collision) might not occur until user 1000 or 10000. In contrast, with the offline lookup table approach, you can easily add additional client-prescribed filters like eliminating IDs with leading zeros; in case the client never wants to see a user with the ID 1 (00000001). And you'd know in advance whether everything is going to always work, without any hangs.

php unique alpha numeric id

I have seen a few post on this, but nothing that would work entirely for what I'm trying to do. Pretty much I want to generate a new id for clients in this script. What I want to do is add a new entry to my database, get the id, and then multiply by say A1A1, or something like that. So it would be like
A1A1 - 1st id
A1A2 - 2nd id
A1A3 - 3rd id
(so on and so fort).
Anyone got any ideas where I should start with that?
Just increment your string:
$id = 'A1A1';
$new_id = ++ $id; // $new_id is now A1A2
See it on Ideone
Not sure if this would work, but typically generates somewhat sequential hexdecimal numbers based on the current microsecond.
uniqid();
http://www.php.net/manual/en/function.uniqid.php
If you are using a SQL database, I would highly suggest checking out auto increment. For example, here is auto-increment for mysql.
You may split the whole id into alphabets and numerals. Then increment the corresponding numeral and concatenate back. If you have to make record deletion, take care of the re-arranging the sequence.

Categories