Check if cast to int will lose data - PHP - 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.

Related

PHP non-numeric value warning

I'm getting the following error:
Warning: A non-numeric value encountered
Does anyone have the solution? (I'm a beginner.)
EDIT:
Here is the code:
while($r = mysqli_fetch_row($result))
{
$items[] = $r;
}
$itemArray = array($items[0][0]=>array('Proid' => $items[0][0],
'name'=>$items[0][1], 'brand'=>$items[0][2], 'desc'=>$items[0][3],
'quan'=>$_POST["quantity"], 'price'=>$items[0][4], 'image'=> $items[0][5]));
$_SESSION['cart'] += $itemArray;
$i = $item['Proid'];
$tp = $item['quan'] * $item['price'];
$tp2 += $tp;
Probably some of your values are a string, not a integer or float.
To make sure, use
intval() to convert a string to integer
or
floatval() to convert a string to float.
This is just a warning, php will try to convert it behind the scenes, but if may not be accurate, for example, if you use , as decimal separator, or if you use some thousand separator.
Not sure which PHP version you are using but a Warning will be emitted if a non-numeric value is encountered. See this link.
so what you can do is before doing calculation make sure you check if the entity is numeric or not and for that you can use is_numeric() PHP function.
For example in your case :
if(is_numeric($item['quan']) && is_numeric($item['price'])){
$tp = $item['quan'] * $item['price'];
}

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

PHP Secure Hashing

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

PHP unique identy field in url

I have dilemma. I need unique string in my database table to show it in url (I don't show id in url).
I want generate in php unique string check it is unique in table if not generate new.
What do you think in terms of performance for a string with a length of 8 characters, and with a large number of rows (about 100,000 rows).
You can create a unique id in php using uniqid().
When generating a new ID, check the DB to see if it exists. If it does, create a new one. Assuming you set up an index on that column in the database, these checks will not be very expensive.
In pseudo(-ish) code :
while (true) {
$id = uniqid();
if (!id_exists_in_db($id)) // we have a unique id
break;
}
Instead of generating a unique key besides the id, you can also create a function that hashes or encodes the id to a string. For instance, you can convert the integer to an 8 character hexidecimal representation. You can make it a little more complex if you like, but still, it's fairly easy to write a function that uses a fixed formula to convert a number to 8 letters and vice versa. That way, you don't need to store this extra data, and you don't have to worry about the value being unique.
<?php
function translate($key, $back)
{
$key = str_pad($key, 8, '0', STR_PAD_LEFT);
$a = array('1','2','3','4','5','6','7','8','9','0');
$b = array('a','b','c','d','e','f','g','h','i','j');
if ($back) {$c = $b; $b = $a; $a = $c;}
return str_replace($a, $b, $key);
}
function encode_id($int)
{
return translate($int, false);
}
function decode_id($key)
{
return (int)translate($key, true);
}
$key = encode_id(40000);
$int = decode_id($key);
echo $key;
echo '<br>';
echo $int;

PHP: If number (with comma), convert it to right number format (with point)

I have an array of mixed values:
$row = array('Unspecified risk','Yes','8','3','2','13','none','-1,49','-2,51','-1,46','-1,54'); -1,94 -1,55
As you can see it contains text and both negative and positive comma-numbers.
I need to convert the numeric values to the right number format and leave the text values as is.
Now I'm looping over the values:
foreach ($row as $value) {
// If $value is numeric, convert it to the
// right number format for use with MySQL (decimal(10,2))
// If not, leave it be.
}
Two related questions I've investigated but cannot find a suitable solution.
Converting a number with comma as decimal point to float
I need php regular expression for numeric value including "-" and ","
Could anyone provide a practical example?
You don't need to use regular expressions.
use str_replace() as you need to replace the ',' for a '.', and then use intval() or floatval() functions to get the numeric value. You can also use strstr() to look for the '.' and decide if using intval() or floatval()
Example:
$row = array('Unspecified risk', 'Yes', '8', '3', '2', '13', 'none', '-1,49', '-2,51', '-1,46', '-1,54');
function toNumber($target){
$switched = str_replace(',', '.', $target);
if(is_numeric($target)){
return intval($target);
}elseif(is_numeric($switched)){
return floatval($switched);
} else {
return $target;
}
}
$row = array_map('toNumber', $row);
var_dump($row);
We use str_replace() to replace the dot for the comma, this way it's a international notation float, even if it's on string, this way later on we can check if it's numeric with is_numeric() <-- this function is awesome as it detects from a string if it's a number or not, no matter integer or float etc.
We use the is_numeric to check if the value is integer float or text and return the corresponding value using intval() or floatval() (the value without the replace applied will not return as a valid numeric, only after switching the , and . it will return true as numeric).
We use $row = array_map('toNumber', $row); to apply the changes to the array.
Profit xD
$row = array('Unspecified risk','Yes','8','3','2','13','none','-1,49','-2,51','-1,46','-1,54');
foreach($row as $key => $var) {
if(strstr($var, ",") && !is_numeric($var)) {
$var1 = str_replace(",","", $var);
if(is_numeric($var1)) {
$decimal = strstr($var, ',', TRUE);
$digits = str_replace($decimal, "", $var1);
$finalValue = $digits * pow(10,$decimal);
$row[$key] = $finalValue;
}
}
}
echo "<pre>"; print_r($row);
NOTE: This will work for php 5.3 or php 5.3+
I am responding so many years later because I dont find any of the provided solutions reliable enough.
This is a more rigid test if a string contains a float with a comma as decimal separator, and if yes, converts it. Also it removes spaces around the number if needed. It does not really test for malformed numbers.
if( preg_match('/^\s*[0-9\.]*,\d*\s*$/', $str))
return (float)str_replace(",",".",str_replace(".","",trim($str)));
else
return $str ;
If you know a numerical value ALWAYS has a European notation (so 1.234 without a comma should also be coverted to 1234), it should be:
if( preg_match('/^\s*[0-9\.]*,?\d*\s*$/', $str))
return (float)str_replace(",",".",str_replace(".","",trim($str)));
else
return $str ;
If you want a truly rigid test, no malformed numbers (like starting with a thousands separator), and that uses ONLY three digits between thousands separators (not all countries use three, though, like India!):
if( preg_match('/^\s*\d{0,3}((?<=\d)\.\d{3})*,?\d*\s*$/', $str))
return (float)str_replace(",",".",str_replace(".","",trim($str)));
else
return $str ;
And lastly if you want to go even more rigid and also do not want numbers to be able to begin or end with a comma ("1.234," or ",17", which in some cases are considered correct) it becomes
if( preg_match('/^\s*\d{1,3}((?<=\d)\.\d{3})*(,\d+)*\s*$/', $str))
return (float)str_replace(",",".",str_replace(".","",trim($str)));
else
return $str ;
Use is_numeric to test and number_format to format:
foreach ($row as &$value) {
$number = str_replace(',', '.', $value);
if (is_numeric($number)) {
$value = number_format($number, 2, '.', '');
}
}
unset($value);

Categories