PHP - How to eval math with big integer result? - php

I have a problem like this
when i eval this
$a='820725059 + 35 * 4082615 + 6209777 - 6476390779 * 3376849 + 3 - 8089 * 3967379273 - 0 * 55111452';
eval('return ('.$a.');');
i got this result -2.1901884886788E+16
instead of -21901884886788304
i know about BCMath, but how to calculate multiple operation like this?
Note:
My problem is about print out as BIG INT

Check if you are using 32bit or 64bit PHP
echo PHP_INT_SIZE; //4 is 32bit, 8 is 64bit
32bit won't handle this integer, for 64bit the result is -21901884886788304
if you have to use 32bit, try using GMP, and parse the integer yourself (good luck...)
Another solution is to write very basic Python program (or any other language that handles large numbers easily) and send it as an argument with exec function and let the other language to parse it for you (Python can handle very large numbers easily)

I assume that the line "how to calculate multiple operation like this?" means "how to write a calculator for arbitrary user-submitted math expressions?", which is why you use eval in first place.
If you use eval over unsanitized user-submitted input, you fail, remember this as a rule of thumb.
You just can't solve this with eval anyway, you have to use BCMath operations if you want to work with bignums.
Proper solution is to tokenize the input and construct the tree of math operations, essentially writing an interpreter for simple language for describing math expressions.
Here is result of 5 seconds of googling for something already done before: https://github.com/michellesanver/Calculator You can take her work and replace usage of plain math operators in classes like Addition with BCMath methods.

Related

PHP Hex to Integer

I'm integrating a PHP application with an API that uses permissions in the form of 0x00000008, 0x20000000, etc. where each of these represents a given permission. Their API returned an integer. In PHP, how do I interpret something like 0x20000000 into an integer so I can utilize bitwise operators?
Another dev told me he thought these numbers were hex annotation, but googling that in PHP I'm finding limited results. What kind of numbers are these and how can I take an integer set of permissions and using bitwise operators determine if the user can 0x00000008.
As stated in the php documentation, much like what happens in the C language, this format is recognized in php as a native integer (in hexadecimal notation).
<?php
echo 0xDEADBEEF; // outputs 3735928559
Demo : https://3v4l.org/g1ggf
Ref : http://php.net/manual/en/language.types.integer.php#language.types.integer.syntax
Thus you could perform on them any bitwise operation since they are plain integers, with respect to the size of the registers on your server's processor (nowadays you are likely working on a 64-bit architecture, just saying in case it applies, you can confirm it with phpinfo() and through other means in doubt).
echo 0x00000001<<3; // 1*2*2*2, outputs 8
Demo : https://3v4l.org/AKv7H
Ref : http://php.net/manual/en/language.operators.bitwise.php
As suggested by #iainn and #SaltyPotato in their respective answer and comment, since you are reading the data from an API you might have to deal with these values obtained as strings instead of native integers. To overcome this you would just have to go through the hexdec function to convert them before use.
Ref : http://php.net/manual/en/function.hexdec.php
Since you are receiving it from an API php will interpret it as a string
echo hexdec('0x00000008');
returns the integer 8
This should work.

perl unary ~ gives not the expected result

I'm trying to port a php algorithm to perl but I struggle with one bit operator I'm not familiar with...
so the php code looks like this:
...
$var = '348492634';
print ~$var;
...
result: -348492635
doing the exact same thing in perl:
...
$var = '348492634';
print ~$var;
...
result: 18446744073361058981
I read a lot about the integer size depending on the architecture of the cpu, but I never found a working solution. Maybe I'm just using the wrong function in perl...
It's necessary for the logic to get same result as in the php script.
Thanks in advance
Seems that on your setup, PHP ints are 32bit signed while perl ints are 64bit unsigned.
This will probably do what you need on the given system but it is not guaranteed to work the same if you use it on another installation of perl.
$var = '348492634'; #hex!
print ~($var - 2**32) - 2**32;
The following will do for both $var='348492634' (which you claim to have) and $var=348492634 (which you did have):
unpack('l', ~pack('l', $var))
The quick and dirty conversion is:
print -($var+1); # like ~$var in PHP
If your perl is using 64-bit integers, this will only fail for $var=-18446744073709551616
(0x8000000000000000), which is a value you wouldn't use in 32-bit PHP anyway.

PHP equivalent for Excel's COMBIN(N,K) function?

I am aware that the function may be computed manually using factorials, the problem is that larger numbers will not calculate properly.
For example, if I input COMBIN(1500,5) in MS Excel it will return 62,860,358,437,800 as it should. But if I try to calculate it manually, even in Excel I will get a #NUM! error when I try to first find the factorial of 1500. The manual formula would be
1500!/5!(1500-5)!
I find it curious that Excel's COMBIN function calculates properly yet the manual way returns an error. In short, I am wondering if there is an equivalent of this function in PHP? I have already tried manually computing using gmp_fact and as with Excel, it returns error (NaN).
Thanks
Your calculation is failing because you're quickly overflowing the Integer data type, which is probably just 32-bits on your system. You could use the arbitrary precision math functions to get around that problem:
http://www.php.net/manual/en/ref.gmp.php
If gmp_fact(...) seems to be returning errors or bad results, you're probably passing it a bad value or assuming it's result is a basic numeric type. You'll want to use something like gmp_strval to convert the returned GMP resource into something readable when you're done performing calculations.
Example:
$a = gmp_fact(1500);
$b = gmp_fact(5);
$c = gmp_fact(1500-5);
$result = gmp_div($a,(gmp_mul($b,$c)));
echo gmp_strval($result);

Php rand vs Perl rand

I am trying to port a piece of code from perl to php. The perl code snippet is part of akamai's video on demand link generation script. The script generates seed based on the location / URL of the video file (which will always be constant for a single URL). And then it is used in generating serial ID for stream (which is basically a random number between 1 and 2000 using the seed). Here is the perl code.$seed=6718;
srand($seed);
print(int(rand(1999)) + 1); // return 442 every time And the converted PHP code is:$seed=6718;
srand($seed);
echo(rand(0, 1999) + 1); //returns 155 every time
Does php rand behaves differently than perl one?
Yes. You can't depend on their algorithms being the same. For perl, which rand is used depends on what platform your perl was built for.
You may have more luck using a particular algorithm; for instance, Mersenne Twister looks to be available for both PHP and Perl.
Update: trying it produces different results, so that one at least won't do the trick.
Update 2: From the perl numbers you show, your perl is using the drand48 library; I don't know whether that's available for PHP at all, and google isn't helping.
[clippy]It looks like your trying to hash a number, maybe you want to use a hash function?[/clippy]
Hash functions are designed to take an input and produce a consistently repeatable value, that is in appearance random. As a bonus they often have cross language implementations.
Using srand() with rand() to get what is basically a hash value is a fairly bad idea. Different languages use different algorithms, some just use system libraries. Changing (or upgrading) the OS, standard C library, or language can result in wildly different results.
Using SHA1 to get a number between 1 and 2000 is a bit overkill, but you can at least be sure that you could port the code to nearly any language and still get the same result.
use Digest::SHA1;
# get a integer hash value from $in between $min (inclusive) and $max (exclusive)
sub get_int_hash {
my ($in, $min, $max) = #_;
# calculate the SHA1 of $in, note $in is converted to a string.
my $sha = Digest::SHA1->new;
$sha->add( "$in" );
my $digest = $sha->hexdigest;
# use the last 7 characters of the digest (28 bits) for an effective range of 0 - 268,435,455.
my $value = hex substr $digest, -7;
# scale and shift the value to the desired range.
my $out = int( $value / 0x10000000 * ( $max - $min ) ) + $min;
return $out;
}
print get_int_hash(6718, 1, 2000); #this should print 812 for any SHA1 implementation.
Just seeing this snippet of code it is impossible to say if it is the same.
At first you need to knew that even a random generator like the rand() function is not really random. It calculates a new value with a mathematical formula from the previous number. With the srand() function you can set the start value.
Calling srand() with the same argument each time means that the program always returns the same numbers in the same order.
If you really want random numbers, in Perl you should remove the initialization of srand(). Because Perl automatically sets srand() to a better (random) value when you first call the rand() function.
If your program really wants random numbers, then it should also be okay for PHP. But even in PHP i would look if srand() is automatically set and set to a more random value.
If your program don't work with random numbers and instead really want a stream of numbers that is always the same, then the snipet of code are probably not identical. Even if you do the same initialization with srand() it could be that PHP uses another formula to calculate the next "random" number.
So you need to look at your surrounding code if you code really wants random numbers, if yes you can use this code. But even then you should look for a better initialization for srand().

Parse math operations with PHP

I am working on a project where I need to make a function that will parse the 4 default math operations (addition, subtraction, multiplication, division). It would be nice if the function could parse operations between brackets.
So, a must is that the function first check for multiplication and division operations (should check for that after it parser all operations between brackets if they exist, and that rule should apply for bracket operations [the biggest problem is that the brackets can contain brackets]). After doing all multiplication and division operations, it should do all addition and subtraction operations. The final number should be returned by functions.
Another nice addition would be a RegExp string that will check for math operations.
Thanks in advance!
This should be pretty secure:
function do_maths($expression) {
eval('$o = ' . preg_replace('/[^0-9\+\-\*\/\(\)\.]/', '', $expression) . ';');
return $o;
}
echo do_maths('1+1');
You could use eval() (WARNING: be sure what enters is a math operation and not some other arbitrary input or php code).
$input = "3 + (4 - 2 * 8) / 2";
eval('$result = ' . $input . ';');
echo "The result is $result";
there was a similar problem
How to evaluate formula passed as string in PHP?
you can try to use Class: Eval Math from php classes
http://www.phpclasses.org/package/2695-PHP-Safely-evaluate-mathematical-expressions.html
I can recommend https://github.com/andig/php-shunting-yard which is a PSR-0 compatible implementation of the Shunting Yard algorithm.
Regular expressions aren't the answer here; I suggest using an expression tree where all terminal nodes are constants or variables, and the rest of the nodes are operators. For example, 2 + 3 * 4 becomes:
+ --- 2
|
--- * --- 3
|
--- 4
Then, you evaluate the expression by using a depth-first traversal. In PHP it's sort of difficult to represent trees, but you could either use a built-in library as a commenter suggested or represent them using an associative array of arrays.
if you want a truly safe math parser, then eval won't do it. bcParserPHP can do it. It is implemented in PHP and does not use eval, thus it is very secure.

Categories