PHP Secure Hashing - php

So I have a small issue over PHP. I think I've messed the foreach loops a bit. Here's the code:
<?php
error_reporting(0);
class Hash{
public function hashing($password,$hashsum)
{
$iter = date('sh');
$poyl = array($iter,strrev($iter));
foreach ($poyl as $key) {
$itg = array('1','2','3','4','5'); # if == any array element
foreach($itg as $v){
if ($key == $v){ # has to be checked here
$algo = 'TIGER128,3';
} elseif ($key == rand(31,60)){
$algo = 'HAVAL128,4';
} # else
}
} # foreach
return hash($algo,$password.strtok($password,'7'));
}
}
$obj = new Hash();
print $obj->hashing('text',hash($algo,$password.strtok($password,'7')));
What I aim to achieve here is the following: this is supposed to be a class that would calculate semi-polymorphic hash values. In order for this kinda false polymorphism to work, I need to at least have two different hashing algorithms. (establishing dependency and correlation with a database would be considered afterwards).
So my problem is that I need to perform a check that would determine whether the first character (integer in this case) is equal to any of the elements in the $itg array (or if it's equal to any number ranging 1-30). If so, the algorithm will be TIGER128,3; if not (and first character of the date variable is equal to any value ranging 31-60) then algorithm applied should be HAVAL128,4.
The code is totally messed up. I'm using the date function to generate integers and compare them afterwards because I couldn't think of anything that fast (means this will defo be changed).

if you just want to compare what is in that array you could use in_array()
$array = array(1,2,3,4);
$str = '1abcdef';
in_array($str[0], $array) // Returns TRUE;
http://uk1.php.net/in_array

Related

How to determine if an array contains anything but a specific value?

Given the below array of values, what is the best way to determine if the array contains anything other than the value 4?
$values = [1,2,3,4,5,6];
For clarity, I don't want to check that 4 simply doesn't exist, as 4 is still allowed to be in the array. I want to check the existence of any other number.
The only way I can think to do it is with a function, something like the below:
function checkOtherValuesExist(array $values, $search) {
foreach ($values as $value) {
if ($value !== $search)
return TRUE;
}
}
}
Simply do array_diff to get array without 4's
$diff = array_diff($values, [4]);
if (!empty($diff)) {
echo "Array contains illegal values! "
. "Legal values: 4; Illegal values: " . implode(', ', $diff);
} else {
echo "All good!";
}
TBH - I think your current version is the most optimal. It will potentially only involve 1 test, find a difference and then return.
The other solutions (so far) will always process the entire array and then check if the result is empty. So they will always process every element.
You should add a return FALSE though to make the function correct.

Why does `array_diff_ukey` call the compare function so many times?

I executed the following code and its result made me confused!
I pass two arrays and a function named "myfunction" as arguments to the array_diff_ukey function. I see that myfunction is called 13 times (while it should be called at most 9 times). Even more amazing is that it compares the keys of the same array too! In both columns of the output, I see the key "e", while only the second array has it (the same is true for some other keys).
function myfunction($a,$b) {
echo $a . " ".$b."<br>";
if ($a===$b) {
return 0;
}
return ($a>$b)?1:-1;
}
$a1=array("a"=>"green","b"=>"blue","c"=>"red");
$a2=array("d"=>"blue","e"=>"black","f"=>"blue");
$result=array_diff_ukey($a1,$a2,"myfunction");
print_r($result);
Output:
a b
b c
d e
e f
a d
a e
a f
b d
b e
b f
c d
c e
c f
Array
(
[a] => green
[b] => blue
[c] => red
)
See it run on eval.in.
Why does the array_diff_ukey perform that many unnecessary calls to the compare function?
Nice question. Indeed the implemented algorithm is not the most efficient.
The C-source for PHP array functions can be found github. The implementation for array_diff_ukey uses a C-function php_array_diff which is also used by the implementations of array_udiff, array_diff_uassoc, and array_udiff_uassoc.
As you can see there, that function has this C-code:
for (i = 0; i < arr_argc; i++) {
//...
zend_sort((void *) lists[i], hash->nNumOfElements,
sizeof(Bucket), diff_key_compare_func, (swap_func_t)zend_hash_bucket_swap);
//...
}
...which means each input array is sorted using the compare function, explaining the first series of output you get, where keys of the same array are compared, and the first column can list other keys than the those of the first array.
Then it has a loop on the elements of the first array, a nested loop on the other arrays, and -- nested in that -- a loop on the elements of each of those:
while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) {
//...
for (i = 1; i < arr_argc; i++) {
//...
while (Z_TYPE(ptr->val) != IS_UNDEF &&
(0 != (c = diff_key_compare_func(ptrs[0], ptr)))) {
ptr++;
}
//...
}
//...
}
Evidently, the sorting that is done on each of the arrays does not really contribute to anything in this algorithm, since still all keys of the first array are compared to potentially all the keys of the other array(s) with a plain 0 != comparison. The algorithm is thus O(klogk + nm), where n is the size of the first array, and m is the sum of the sizes of the other arrays, and k is the size of the largest array. Often the nm term will be the most significant.
One can only guess why this inefficient algorithm was chosen, but it looks like the main reason is code reusability: as stated above, this C code is used by other PHP functions as well, where it may make more sense. Still, it does not really sound like a good excuse.
A simple implementation of this (inefficient) array_diff_ukey algorithm in PHP (excluding all type checking, border conditions, etc) could look like this mimic_array_diff_ukey function :
function mimic_array_diff_ukey(...$args) {
$key_compare_func = array_pop($args);
foreach ($args as $arr) uksort($arr, $key_compare_func);
$first = array_shift($args);
return array_filter($first, function ($key) use($key_compare_func, $args) {
foreach ($args as $arr) {
foreach ($arr as $otherkey => $othervalue) {
if ($key_compare_func($key, $otherkey) == 0) return false;
}
}
return true;
}, ARRAY_FILTER_USE_KEY);
}
A more efficient algorithm would use sorting, but then would also take benefit from that and step through the keys of the first arrays while at the same time stepping through the keys of the other arrays in ascending order, in tandem -- never having to step back. This would make the algorithm O(nlogn + mlogm + n+m) = O(nlogn + mlogm).
Here is a possible implementation of that improved algorithm in PHP:
function better_array_diff_ukey(...$args) {
$key_compare_func = array_pop($args);
$first = array_shift($args);
$rest = [];
foreach ($args as $arr) $rest = $rest + $arr;
$rest = array_keys($rest);
uksort($first, $key_compare_func);
usort($rest, $key_compare_func);
$i = 0;
return array_filter($first, function ($key) use($key_compare_func, $rest, &$i) {
while ($i < count($rest) && ($cmp = $key_compare_func($rest[$i], $key)) < 0) $i++;
return $i >= count($rest) || $cmp > 0;
}, ARRAY_FILTER_USE_KEY);
}
Of course, this algorithm would need to be implemented in C if taken on board for improving array_diff_ukey, and to get a fair runtime comparison.
See the comparisons that are made -- on a slightly different input than in your question -- by the three functions (array_diff_ukey, mimic_array_diff_ukey and better_array_diff_ukey) on eval.in.
array_diff_ukey runs in two stages:
Sort the array keys
Compare key by key
This would probably explain why the callback is expected to return a sort value rather than a boolean "is equal".
I expect this is probably done for performance reasons, but if that's the case I would have thought that it can use this to say "well this key is bigger than all keys in the other array, so I shouldn't bother testing if these other, bigger keys are also bigger because they must be", but this doesn't seem to be the case: it compares them dutifully anyway.
I can only assume it's because the function cannot prove itself to be deterministic (and indeed in this case produces side-effects) so it can't be optimised like that. Perhaps array_diff_key (without user-defined function) does this optimisation just fine.
But anyway, that's what happens under the hood, and why you see more than just 9 comparisons. It could probably be made better in the core...

How to get the highest version number / tag in PHP

Because the Bitbucket API doesn't provide a method to get the latest tag for a repository I find myself having to get it from an array of all tags.
How do you do it?
I have tried max but it doesn't work for certain numbers e.g.
max(['1.0.8', '1.0.9', '1.0.10']);
returns '1.0.9'.
I know the tags will only ever be three numbers a.b.c they won't have other semver accepted strings like alpha etc. because of the way we do tags for our repos.
So how do you do it?
$versions = ['1.0.8', '1.0.9', '1.0.10'];
usort($versions, 'version_compare');
echo end($versions);
See http://php.net/version_compare
If you don't feel like modifying the array:
echo array_reduce($versions, function ($highest, $current) {
return version_compare($highest, $current, '>') ? $highest : $current;
});
By using the version_compare function:
function maxVersion($array)
{
$max = null;
foreach ($array as $version) {
if (version_compare($max, $version) === -1) {
$max = $version;
}
}
return $max;
}
print(maxVersion(['1.0.8', '1.0.9', '1.0.10']));
// returns "1.0.10"
Because you are dealing with Strings here rather than numbers, you will not get the result you require. You could try the following:
$version_numbers = str_replace(".","",['1.0.8', '1.0.9', '1.0.10']);
$max = max($version_numbers);
If you are always dealing with a fixed a.b.c structure then by replacing the decimal point you will get a series of integers that will let you determine the maximum relatively easily

Check if cast to int will lose data - PHP

I have this piece of code:
$result = new stdClass();
foreach ($array as $index => $value) {
if(is_numeric($value)){
$int = (int)$value;
$double = (double)$value;
if($int == $double)
$value = $int;
else
$value = $double;
}
$index = strtolower($index);
$result->$index = $value;
}
And it worked for ages. Now I got a problem with it. I have a column in my database that has numbers (big numbers) in it. But they're not numbers, they're varchar and those numbers are not for mathematical purpose. Unfortunately, since the column is fully filled with numbers only, it passes the is_numeric test, but since it's a giant number, it loses data due to memory limitation (4 billions, I think).
Anyway, how can I check if after the cast I lost data or not to my variable?
Thanks.
if($value<=PHP_INT_MAX) ... // safe to convert
else // not safe
Convert it back and see if it gives the same value as the source.

Knowing keys type of array?

is there a command to know if an array has their keys as string or plain int?
Like:
$array1 = array('value1','value2','value3');
checkArr($array1); //> Returns true because there aren't keys as string
And:
$array2 = array('key1'=>'value1','key2'=>'value2','value3');
checkArr($array2); //> Returns false because there are keys as string
Note: I know I can parse all the array to check it.
The "compact" version to test this is:
$allnumeric =
array_sum(array_map("is_numeric", array_keys($array))) == count($array);
#Gumbo's suggestion is 1 letter shorter and could very well be a bit speedier for huge arrays:
count(array_filter(array_keys($array), "is_numeric")) == count($array);
You can use array_keys to obtain the keys for the array and then analyse the resultant array.
look at array_keys() if values are int - you got ints if strings -> strings
If you want to check the array's keys, it would be probably better to use something like this:
reset($array);
while (($key = key($array)) !== null) {
// check the key, for example:
if (is_string($key)) {
// ...
}
next($array);
}
This will be most performant, as there are no extraneous copies made of variables that you are not going to use.
On the other hand, this way is probably the most readable and makes the intent crystal clear:
$keys = array_keys($array);
foreach($keys as $key) {
// check the key, for example:
if (is_string($key)) {
// ...
}
}
Take your pick.
Important note:
Last time I checked, PHP would not let you have keys which are string representations of integers. For example:
$array = array();
$array["5"] = "foo";
echo $array[5]; // You might think this will not work, but it will
So keep that in mind when you are checking what the types of such keys are: they might have been created as strings, but PHP will have converted them to integers behind the scenes.

Categories