PHP Generate an unique hash from an IPADDRESS - php

I have a board and i want to disable registrations instead i want the users to be able to post freely with an unique ID based on their IPAddress
for example:
if "Joe" IP is 200.100.15.117, "Joe" nickname will become the hash function of 200.100.15.117
if "Joe" IP changes he will get another ID, that doesn't matter, i only want one unique ID per IPAddress
There are also two important things :
unique ID must be 8 characters long
hash should be secure, i don't want hackers be abble to crack my
users IPaddresses
I thought in using an MD5 function and then trim it to 8 chars, but how unique is that ? is there a better way ?

You can turn the ip address string to LONG(4 bytes) and do whatever you want next.
see the php function ip2long.

The thing with this is that you cant really diferentiate 2 persons on the same network, so if I post on there, and my dorm neighbour goes to the site, the site thinks he is me.
You should consider using cookies, these can easily be made unique, and AFAIK, can't be hacked remotely.
For the unique ID part, if you are storing the "users" in a database, you could just assign the primary key from your "user" table and use that in the cookie.
If it HAS to be 8 chars long, you could prepend 0's to the ID - e.g. 00000001, 00000002.... Atleast this way its unique, and 8 chars long-

EDIT According to OP comment on this answer.
Code below uses BC Math library to translate a MD5 hash into a Base-90 string. This converts a 32 char string into a 20 char one. This is far from desired 8 chars but it is the minimum string length using ASCII range (it is possible to increase the base to Base-94 by using chars ' " \ [space] but this does not affect to the string length and instead may cause problems while handling data).
$ip = '200.100.15.117';
$hash = md5($ip);
$chars16 = array(
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5,
'6' => 6, '7' => 7, '8' => 8, '9' => 9, 'a' => 10, 'b' => 11,
'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15
);
$base10 = '0';
for ($i = strlen($hash) - 1; $i > 0; $i--) {
$base10 = bcadd($base10, bcmul($chars16[$hash[$i]], bcpow(16, $i)));
}
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,;.:-_+*?!$%&##~^=/<>[](){}`';
$base = (string)strlen($chars);
$baseX = '';
while (bccomp($base10, $base) === 1 || bccomp($base10, $base) === 0) {
$baseX = substr($chars, bcmod($base10, $base), 1) . $baseX;
$base10 = preg_replace('/\.\d*$/', '', bcdiv($base10, $base));
}
$baseX = substr($chars, $base10, 1) . $baseX;
echo $baseX; // Shows: 1BS[JdZf/7J$J{ud&r5i

You can salt the ip address, e.g.
$salt = "e45re%$#";
$ip = "200.111.123.111";
$hash = md5($ip.$salt);
$hash = substr($hash,0,8);

Related

How I can generate the unique ID in laravel?

I’m working with my graduation project in Laravel, and want to generate small unique ID "9 char max" ... I don't need UUID because this will generate 36 char which is too long.
You can use PHP function like this:
function unique_code($limit)
{
return substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, $limit);
}
echo unique_code(9);
Output looks like:
s5s108dfc
Here the specifications:
base_convert – Convert a number between arbitrary bases.
sha1 – Calculate the sha1 hash of a string.
uniqid – Generate a
unique ID.
mt_rand – Generate a random value via the Mersenne Twister Random
Number Generator.
Or in Laravel you can use laravel Str library:
just use this:
use Illuminate\Support\Str;
$uniqid = Str::random(9);
You can generate a random string with this library:
use Illuminate\Support\Str;
$id = Str::random(9);
You can use this ,
$unique_id= echo floor(time()-999999999);
this is generating a 9 digit unique value based on time.
Generate custom Unique ID or Code (With Prefix or Suffix Or Both Or Only Unique Id) Or reset your ID after the change of Prefix or Suffix Or Both in laravel framework
Visit https://github.com/SirajCse/laravel-unique-id-generator
Example:
Inv-000001/12/21
UniqueIdGenerator::generate(['table' => 'invoices','field'=>'invoice_id','length' => 16,'prefix' => 'Inv-', 'suffix' => date('/m/y')]);
'table' => 'invoices' [sting table name]
'field'=>'invoice_id' [Default 'id'] [Optional][any string field name]
'length' => 12 [Integer value Id length]
'prefix'=>'Inv-' [Default ''] [Optional] [any string]
'suffix'=>date('/m/y') [Default ''] [Optional][any string]
'reset_on_change'=>false[ Default false] [Optional] [Options are 1.prefix , 2.suffix 3.both 4.false]
uniqueId=000001
in laravel create custom helper method
it will generate sequence random number based on condition
function generateSequenceNumber($tablename, array $conditions = [], string $prefix, int $length = 5): string
{
$model = \DB::table($tablename);
if (is_array($conditions) && count($conditions) > 0) {
$model = $model->where($conditions);
}
return $prefix . str_pad(
($model->count()) + 1,
$length,
'0',
STR_PAD_LEFT
);
}
generateSequenceNumber('tablename',[],'prefix-',5); //prefix-00001
generateSequenceNumber('users',['role' => 'admin'],'admin-',5); //admin-00005
generateSequenceNumber('users',['is_active' => 1,'role' => 'client'],'client-',8);
//client-00000008

Convert Gigabytes to Bytes

I am in the position where I am trying to convert gigabytes to bytes from a submit form. I have searched around and I am unable to find anything suitable.
Currently when converting bytes to gigabytes I use this method, which works perfectly.
public function byteFormat($bytes, $unit = "", $decimals = 2)
{
$units = array('B' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4,
'PB' => 5, 'EB' => 6, 'ZB' => 7, 'YB' => 8);
$value = 0;
if ($bytes > 0) {
// Generate automatic prefix by bytes
// If wrong prefix given
if (!array_key_exists($unit, $units)) {
$pow = floor(log($bytes)/log(1024));
$unit = array_search($pow, $units);
}
// Calculate byte value by prefix
$value = ($bytes/pow(1024,floor($units[$unit])));
}
// If decimals is not numeric or decimals is less than 0
// then set default value
if (!is_numeric($decimals) || $decimals < 0) {
$decimals = 2;
}
// Format output
return sprintf('%.' . $decimals . 'f '.$unit, $value);
}
There seems to be plenty of examples of bytes to other formats but not the other way around.
I have seen that I can convert the number 1.5 like so
round(($number[0] * 1073741824));
The result is 12992276070, however, when using the byteformat method shown above, I get the following 1610612736, this seems quite a difference between the two methods.
Can anyone suggest a more stable method for converting gigabytes to bytes.
Well there are two different unit symbol, decimal and binary.
As you can see here, decimal multiplication is by 1000 and binary by 1024.
so if you are using "B"(byte), just do something like:
$bytenumber=$giga*pow(1024,3);
if using "b"(bit) :
$bitnumber=$giga*pow(1000,3);
P.S:$giga is your giga number.
You can only get as accurate of a conversion as there are numbers after the decimal place. If you start with 1.29634 gigs you'll get a closer representation to it's actual byte value versus calling it 1.3 Gigs. Is that what you're after?
numberOfBytes = round (numberOfGb * 1073741824)
is the exact answer to your question. It seems, you have miscalculated. Try to check it on a calculator.
The other problem is that if you have the source number of 2 digits, it is incorrect to give an answer in more or less than 2 digits. The correct counting will be:
source: 1.5GB
counting: 1.5GB*1073741824 B/GB= 1610612736 B
rounding to the last significant digit: 1610612736 B ~= 1.6e9 B
answer: 1.6e9 B
But, of course, many clients do not really want the correct answer, they want THEIR answer. It is up to you to choose.

Splitting string by fixed length

I am looking for ways to split a string of a unicode alpha-numeric type to fixed lenghts.
for example:
992000199821376John Smith 20070603
and the array should look like this:
Array (
[0] => 99,
[1] => 2,
[2] => 00019982,
[3] => 1376,
[4] => "John Smith",
[5] => 20070603
)
array data will be split like this:
Array[0] - Account type - must be 2 characters long,
Array[1] - Account status - must be 1 character long,
Array[2] - Account ID - must be 8 characters long,
Array[3] - Account settings - must be 4 characters long,
Array[4] - User Name - must be 20 characters long,
Array[5] - Join Date - must be 8 characters long.
Or if you want to avoid preg:
$string = '992000199821376John Smith 20070603';
$intervals = array(2, 1, 8, 4, 20, 8);
$start = 0;
$parts = array();
foreach ($intervals as $i)
{
$parts[] = mb_substr($string, $start, $i);
$start += $i;
}
$s = '992000199821376Николай Шмидт 20070603';
if (preg_match('~(.{2})(.{1})(.{8})(.{4})(.{20})(.{8})~u', $s, $match))
{
list (, $type, $status, $id, $settings, $name, $date) = $match;
}
Using the substr function would do this quite easily.
$accountDetails = "992000199821376John Smith 20070603";
$accountArray = array(substr($accountDetails,0,2),substr($accountDetails,2,1),substr($accountDetails,3,8),substr($accountDetails,11,4),substr($accountDetails,15,20),substr($accountDetails,35,8));
Should do the trick, other than that regular expressions (as suggested by akond) is probably the way to go (and more flexible). (Figured this was still valid as an alternate option).
It is not possible to split a unicode string in a way you ask for.
Not possible without making the parts invalid.
Some code points have no way of standing out, for example: שׁ is 2 code points (and 4 bytes in UTF-8 and UTF-16) and you cannot split it because it is undefined.
When you work with unicode, "character" is a very slippery term. There are code points, glyphs, etc. See more at http://www.utf8everywhere.org, the part on "length of a string"

PHP Question about bitwise

I have a script like this
$job = array(
1 => 'User',
2 => 'Editor',
4 => 'Supervisor',
8 => 'Manager',
10 => 'President');
$value = 18;
foreach($job as $key => $val)
{
if($value & $key)
{
$job[] = $key;
echo $val.', ';
}
}
now what I want to achieve is that in the example above '18' system must only display the value as ' Manager, President, ' ( 10+8 = 18; )
But if you run the script, the system displays as Editor, President,
that's not all the arrays I've got, I have like 23 more array values
Sorry but I really can't explain it in english, hope you understand...
<?php
$flags = array(
1 => 'User', // 00000001 Note the place of the 1
2 => 'Editor', // 00000010
4 => 'Supervisor', // 00000100
8 => 'Manager', // 00001000
16 => 'President' // 00010000
);
// permission we're going for
$permissions = 16 + 8; // 00011000 again, note the 1's places.
$levels = array();
foreach ($flags as $level => $name)
{
if (($permissions & $level) == $level)
$levels[] = $name;
}
echo implode(', ', $levels);
Output:
Manager, President
You want your values in powers of 2 so that, in binary, the corresponding flag matches the permission you're specifying.
The bit-wise AND (&) is saying (when it reaches Manager):
$flags $Pemissions $flags
if (00001000 & 00011000) == 00001000
if (00001000) == 00001000 [true]
Basically, if the flag is set on both sides (both the value you're checking for and against) keep that bit. Then, make sure it still equals the value you're checking for. If it does, the user is set to that permission. An AND is only true when both the left and the right values have the bit(s) set.
The value for President is wrong. To use a bitfield all numbers must be powers of two, so President should be 16 and not 10.
Note that 16 (decimal) is 0x10 (hex) -- perhaps setting the President value to 10 (decimal) was a copy/paste error?
Your problem is that 10 is not a 2^y variable.
10 = 2+8 (2^1 and 2^3), and thus will match values 2 and 8 respectively.
If you want to allow bitwise selection like you do; you need to pick 2^y values for your indexes (1, 2, 4, 8, 16, 32, etc).
Then you can safely add those values as selectors (e.g. 16+4 (20), 2+32(34) etc).
you should change 10 to 16 (1,2,4,8,16,32, ..) or you may cannot understand some number. Is 10=10 or 10=2+8

Which data type is suitable for storing this situation?

For example, I have a user, and the user have different user right, for example, a user can have
-create file
-read file
-update file
-delete file
4 rights, I can use 4 BOOL to find the user right, but if the user have more right, I need create more and more BOOL to store the right. I don't think it is a good idea. And I think of getting a long integer for this... for example, the user can do all the stuff is 1111.
create file is 1000, read file is 100, update is 10, delete is 1. So, if the user only get read file right is 0100.
Is there any better ideas?? Thank you.
I suggest to convert privileges (rights) in binary-state-string and later, store it in database as long integer or hexadecimal string (VARCHAR; for storing a lot of rights).
Example
$privileges_list = array(
0 => 'create_file',
1 => 'read_file',
2 => 'update_file',
3 => 'delete_file',
4 => 'create_pool',
5 => 'vote_in_pool',
6 => 'create_gallery',
7 => 'upload_images',
8 => 'view_statistics'
);
So if you want to set create file, update file and view statistics rights to the user just put 1 on appropriate positions in string (0, 2, 8) and 0 for rest of them
$binary_string = "100000101";
Last character in this string is position 0, first is position 8.
Now you can convert this string to integer (261) or hex-number (105) and put it into database as privilege-set for that user (I prefer hex).
To convert this value back to privileges-list you can use something like this
function hexvalue2privileges($hexvalue, $plist) {
$res = array(); $res_assoc = array();
for ($i = strlen($hexvalue) - 1; $i >= 0; $i--) {
$bin = str_pad(decbin(hexdec(substr($hexvalue, $i, 1))), 4, '0', STR_PAD_LEFT);
$bin_array = array_reverse(str_split($bin, 1));
foreach ($bin_array as $bitstate) $res[] = $bitstate == '1' ? true : false;
}
foreach ($plist as $key => $id) {
$res_assoc[$id] = $res[$key];
}
return $res_assoc;
}
and call this function
print_r(hexvalue2privileges('105', $privileges_list));
Output will be
Array
(
[create_file] => 1 // true
[read_file] => // false
[update_file] => 1 // true
[delete_file] => // false
[create_pool] => // false
[vote_in_pool] => // false
[create_gallery] => // false
[upload_images] => // false
[view_statistics] => 1 // true
)
With every hexadecimal character you can store 4 rights so to calculate number of character needed use this formula
$chars_needed = floor((count($privileges_list)-1) / 4) + 1; // result 3
To get total length of binary-string
$binary_length = $chars_needed * 4; // result 12
To fix length of privileges set
$binary_string = "100000101";
$binary_string = str_pad($binary_string, $binary_length, '0', STR_PAD_LEFT);
// result '000100000101'
To convert $binary_string to hex
$binary_string = "000100000101";
$hexvalue = "";
$groups = str_split($binary_string, 4);
foreach ($groups as $group) $hexvalue .= dechex(bindec($group));
// result $hexvalue='105' (1=0001, 0=0000, 5=0101)
Also you can create groups of privileges and assign them to users by creating privileges-set for every group (administrators, moderators, guests, vip, etc).
Hope this helps
Use [flags CHAR(10) default '0000000000']
Whenever you need any digit, you can use it like
1st digit - New
2nd digit - Edit etc.
At the time of storing, you just need to change that bit and store like this 1100000000. That's it.

Categories