Max output of crypt() function - php

Back when I used MD5 I used to create a varchar(32) column in the datebase.
However, I started using crypt(), and as I understand the output length is variable.
So which length should I set to the varchar?

The maximum number of characters returned is 123 characters. http://php.net/manual/en/function.crypt.php

For those wondering, like I did, what the maximum length of the
returned hash can be for the purpose of storing it in a database, the
answer is:
123 characters.
This is the top User Contributed Note from the PHP: crypt Manual page

Related

How to convert string to integer in PHP?

(This question is not about PHP type-casting.)
I have read in couple of questions what it is best not to show record id to users, but use another value, which doesn't give out any information about howmany record there is in the database, etc. I wanted to implement this, and after searching on google, surprisingly no solution was found.
So, my question is, is it possible to convert a (long, for example) sequence of strings to unique (or unique enough for at least million converts) sequence of numbers, is there any options available which I have no idea of?
Just to show you an example:
$uName = $this->newUsername;
$publicId = $this->strToInt(somecomplexstring); // Outputs something like 13272992
// Or feed with username
$publicId = $this->strToInt($uName);
You might considering using something like a slug. So your user will have an unique id in the database but also an unique slug (random string, ex. TGqJItemU5TGqJItemU5f6S5VaCr2n). You can then use this slug instead of the id when presenting data to the browser.
As stated in a comment, you can use uniquid to get a unique string. this function will return an hexadecimal string.
If you need only numbers, you just have to convert the hex to a decimal number with this hexdec.
The final code will look like this :
hexdec(uniqid());
An other way to get an integer from a string is to use md5. This function also returns a hex string so you will have to use hexdec to get a decimal number
Please note that a md5 is not a unique string, there is a (very small) probability of accidental collision (1 in 340 undecillion, see How many random elements before MD5 produces collisions ? for more info)
You can use:
md5(uniqid(rand(), true))

PHP Murmurhash3 and MySql Murmurhash3 sometimes don't match

I'm using Murmurhash3 to create unique hashes for text entries. When text entries are created, I'm using this php implementation, which returns a 32 bit hash integer, to get the hash value. The hash is stored in a BINARY(16) database column. I also need to update our existing database so I'm using this MySql implementation to update the database. In order to match the php created hash, I'm base converting it and lower-casing it.
UPDATE column SET hash=LOWER(CONV(murmur_hash_v3(CONCAT(column1, column2), 0), 10, 32));
It matches the php version about 80% of the time, which obviously isn't going to cut it. For example, hashing the string 'engtest' creates 15d15m in php and 3uqiuqa in MySql. However, the string 'engtest sentence' creates the same hash in both. What could I be doing wrong?
Figured it out. PHP's integer type is signed and occasionally Murmurhash was producing negative hash values that didnt match the always positive MySql values. The solution was to format php's hash value using sprintf with format set to "%u" before the base conversion.
$hash = murmurhash3_int($text);
return base_convert(sprintf("%u\n", $hash), 10, 32);
See the php crc32 docs for more info.

PHP md5() gives different output then MySQL md5

I'm trying to set up a login system, but I can't solve one problem:
PHP is giving me an other output with md5(); than MySQL...
For example, in PHP:
$password = md5("brickmasterj");
return $password;
Returns:
3aa7b18f304e2e2a088cfd197351cfa8
But the MySQL equivalent gives me a shorter version:
3aa7b18f304e2e2a08
What's the problem? And how do I work with this while checking passwords?
I guess the problem in the length of column of your table, set the length of password field to at least 32
No way MySQL returns it of a length of < 32. If you would do a simple query like SELECT md5('brickmasterj'), you would see. Now you are most likely inserting the value into a column which is not wide enough.
Is your database field 32 characters long? Are you writing to the database using mysql's md5?
The hash size if always fixed. In your case the hash size is 128 bits. When converted to a ascii string it would be a 32 character string that contains only hexadecimal digits.
so if you are storing variable character the length should be atleast 32
example:password varchar(32)
should go in mysql table then you can call using php using
select password from table where password =md5($password);

Generating an int within a certain range based on two variables

I'm making an anonymous commenting system for my blog. I need the users to have a randomly picked username from an array I have made, it has 600 usernames. I can't just make it random because then people wouldn't know if it was the same person posting a reply, so I have given each post a randomly generated key between 1-9999, using the key and the users ID I want to do some sort of calculation so that number will stay consistent through that particular post. The result has to be within 1-600.
something like:
user_id x foo(1-9999) = bar(1-600)
Thanks.
What you're probably looking for is a hash function. To quote Wikipedia:
A hash function is any algorithm or subroutine that maps large data sets of variable length, called keys, to smaller data sets of a fixed length.
So you can use a standard hash function, plus modular arithmetic to further map the output of that hash function to your username range, like so:
function anonymise($username, $post_key) {
$hash = hash("adler32", "$username/$post_key");
$hash_decimal = base_convert($hash, 16, 10);
$anonymised_id = $hash_decimal % 600;
return $usernames[$anonymised_id];
}
So, what you really want is a unique identifier for every poster?
Why not use http://php.net/ip2long modded 600?
of course, you'll have to do some collision detection with that too.
You can try using md5 on the concatinated id and post key. it gives you a consistent 32 byte hash of that. And it is actually a hexadecimal string, so you can actually covet it to a number easily by doing a hex to int conversion.
Edit: Based on your feedback. you can take the generated int and modulas it by 600.

How to store hashes in MySQL databases without using text fields

I'm storing unique user-agents in a MySQL MyISAM table so when I have to look if it exists in the table, I check the md5 hash that is stored next to the TEXT field.
User-Agents
{
id - INT
user-agent - TEXT
hash - VARCHAR(32) // md5
}
There is any way to do the same but using a 32-bit integer and not a text hash? Maybe the md5 in raw format will be faster? That will requiere a binary search.
[EDIT]
MySQL don't handle hash searches for complete case-sensitive strings?
Store the UNHEX(MD5($value)) in a BINARY(16).
You could do this instead:
User-Agents
{
id - INT
user-agent - TEXT
hash - UNSIGNED INT (CRC32, indexed)
}
$crc32 = sprintf("%u", crc32($user_agent));
SELECT * FROM user_agents WHERE hash=$crc32 AND user_agent='$user_agent';
It's unlikely that you'll get collisions with crc32 for this kind of data.
To guarantee that collisions will not cause problems, add a secondary search parameter. MySQL will be able to use the index to quickly find the record. Then it can do a simple string search to guarantee that match is correct.
PS: The sprintf() is there to work around signed 32-bit integers. Should be unnecessary on 64-bit systems.
Let MySQL do the hard work for you. Use a CHAR column and create an index on that column. You could convert and store the hash as an integer, but there's absolutely no benefit, and it may actually cause problems.
try MurmurHash. Its a fast hashing algo thats been translated to multiple languages. It takes your input and translates it into a 32/64 bit integer hash.
You can't store an MD5 hash in a 32-bit int: it simply won't fit. (It's 32 characters when written in hex, but it's 128-bits of data)
You could look at MySQL's BINARY and VARBINARY types. See http://dev.mysql.com/doc/refman/5.1/en/binary-varbinary.html. These types store binary data. In your case, BINARY(16) or VARBINARY(16), but since MD5 hashes are always 16 bytes, the latter seems a bit pointless.
You can store MD5 hash in char(32) which is a bit faster than varchar(32).
It's also possible to make two BIGINT fields and keep first half of md5 hash in first field and second part in second field.
Are you REALLY sure the hashes are only 32-bit? MD5 is 128-bit. Cropping the hash to first 4 or 8 bytes would greatly increase risk of collisions.
If your field hash is always an MD5 value generated by PHP, then you can safely set it to CHAR(32). This should not impact the response time to your queries, unless you plan to have millions+ of rows, or even worst! JOIN other tables with this field. The bottom line is that fixed width column is better than variable ones, so if you can optimize do it.
Regarding changing MD5 into int values, see this question; the conclusion to this is that if you really want to change your MD5 into a 128-bit int value, you might as well use a random number instead of an MD5!
Have you tried creating a BINARY(16) field, and storing the result of md5($plaintext, true); in it? That might work, make sure you index that field as well.
Because trying to fit a 128-bit value in 32 bits doesn't make any sense...

Categories