PHP - How to exit an if - php

My code is showing an error in the line commented below saying:
ErrorException A non-numeric value encountered
The input variable receives an asterisk character and runs through my if instead of stopping at the first iteration. Could you help me find out the reason for the error or tell me the command to exit if after the first if iteration?
$minute = '*';
$pos1 = strpos($minute, '*');
$pos2 = strpos($minute, ',');
$pos3 = strpos($minute, '-');
$pos4 = strpos($minute, '/');
if (true == $pos1) {
$operator = '*';
} elseif (true == $pos2) {
$operator = ',';
} elseif (true == $pos3) {
$operator = '-';
} elseif (true == $pos4) {
$operator = '/';
} else {
$minute_atual = Carbon::now->format('i');
if ($minute < $minute_current) {
$minute = 60 - ($minute_current - $minute); // The error message says it is on that line
$operator = $ minute;
} elseif ($minute_current == $minute) {
$minute = '0';
$operator = $minute;
} else {
$minute = $minute - $minute_current;
$operator = $minute;
}
}

strpos is notorious for that error.
Indeed
$minute = "*";
$pos1 = strpos($minute, '*');
var_dump($pos1);
// 0 because this is the first (0th) character
so the test true == 0 fails
Use strict inequality $pos0 !== false instead
Function reference : https://www.php.net/manual/en/function.strpos
See the warning in the "return value" section.

$minute = '*';
This is a string. And php can't apply numeric operations over it. I don't see if you are assigning a numeric value to it before the subtraction.
Basically you are trying to do "number - (number - string)". Probably you are missing some part of your logic.
Also you don't need to set priority over the operations if they are subtraction or addition.
60 - $minute_current - $minute
Will give you the same result. Of course if $minute is integer.
And also I strongly recommend to avoid weak comparison, use ===, !== instead. So you know exactly what you are doing

Related

I cannot use a given symbol in the char type, as a mathematical symbol [duplicate]

I want to calculate math expression from a string. I have read that the solution to this is to use eval(). But when I try to run the following code:
<?php
$ma ="2+10";
$p = eval($ma);
print $p;
?>
It gives me the following error:
Parse error: syntax error, unexpected $end in
C:\xampp\htdocs\eclipseWorkspaceWebDev\MandatoryHandinSite\tester.php(4)
: eval()'d code on line 1
Does someone know the solution to this problem.
While I don't suggest using eval for this (it is not the solution), the problem is that eval expects complete lines of code, not just fragments.
$ma ="2+10";
$p = eval('return '.$ma.';');
print $p;
Should do what you want.
A better solution would be to write a tokenizer/parser for your math expression. Here's a very simple regex-based one to give you an example:
$ma = "2+10";
if(preg_match('/(\d+)(?:\s*)([\+\-\*\/])(?:\s*)(\d+)/', $ma, $matches) !== FALSE){
$operator = $matches[2];
switch($operator){
case '+':
$p = $matches[1] + $matches[3];
break;
case '-':
$p = $matches[1] - $matches[3];
break;
case '*':
$p = $matches[1] * $matches[3];
break;
case '/':
$p = $matches[1] / $matches[3];
break;
}
echo $p;
}
Take a look at this..
I use this in an accounting system where you can write math expressions in amount input fields..
Examples
$Cal = new Field_calculate();
$result = $Cal->calculate('5+7'); // 12
$result = $Cal->calculate('(5+9)*5'); // 70
$result = $Cal->calculate('(10.2+0.5*(2-0.4))*2+(2.1*4)'); // 30.4
Code
class Field_calculate {
const PATTERN = '/(?:\-?\d+(?:\.?\d+)?[\+\-\*\/])+\-?\d+(?:\.?\d+)?/';
const PARENTHESIS_DEPTH = 10;
public function calculate($input){
if(strpos($input, '+') != null || strpos($input, '-') != null || strpos($input, '/') != null || strpos($input, '*') != null){
// Remove white spaces and invalid math chars
$input = str_replace(',', '.', $input);
$input = preg_replace('[^0-9\.\+\-\*\/\(\)]', '', $input);
// Calculate each of the parenthesis from the top
$i = 0;
while(strpos($input, '(') || strpos($input, ')')){
$input = preg_replace_callback('/\(([^\(\)]+)\)/', 'self::callback', $input);
$i++;
if($i > self::PARENTHESIS_DEPTH){
break;
}
}
// Calculate the result
if(preg_match(self::PATTERN, $input, $match)){
return $this->compute($match[0]);
}
// To handle the special case of expressions surrounded by global parenthesis like "(1+1)"
if(is_numeric($input)){
return $input;
}
return 0;
}
return $input;
}
private function compute($input){
$compute = create_function('', 'return '.$input.';');
return 0 + $compute();
}
private function callback($input){
if(is_numeric($input[1])){
return $input[1];
}
elseif(preg_match(self::PATTERN, $input[1], $match)){
return $this->compute($match[0]);
}
return 0;
}
}
I recently created a PHP package that provides a math_eval helper function. It does exactly what you need, without the need to use the potentially unsafe eval function.
You just pass in the string version of the mathematical expression and it returns the result.
$two = math_eval('1 + 1');
$three = math_eval('5 - 2');
$ten = math_eval('2 * 5');
$four = math_eval('8 / 2');
You can also pass in variables, which will be substituted if needed.
$ten = math_eval('a + b', ['a' => 7, 'b' => 3]);
$fifteen = math_eval('x * y', ['x' => 3, 'y' => 5]);
Link: https://github.com/langleyfoxall/math_eval
Using eval function is very dangerous when you can't control the string argument.
Try Matex for safe Mathematical formulas calculation.
Solved!
<?php
function evalmath($equation)
{
$result = 0;
// sanitize imput
$equation = preg_replace("/[^a-z0-9+\-.*\/()%]/","",$equation);
// convert alphabet to $variabel
$equation = preg_replace("/([a-z])+/i", "\$$0", $equation);
// convert percentages to decimal
$equation = preg_replace("/([+-])([0-9]{1})(%)/","*(1\$1.0\$2)",$equation);
$equation = preg_replace("/([+-])([0-9]+)(%)/","*(1\$1.\$2)",$equation);
$equation = preg_replace("/([0-9]{1})(%)/",".0\$1",$equation);
$equation = preg_replace("/([0-9]+)(%)/",".\$1",$equation);
if ( $equation != "" ){
$result = #eval("return " . $equation . ";" );
}
if ($result == null) {
throw new Exception("Unable to calculate equation");
}
echo $result;
// return $equation;
}
$a = 2;
$b = 3;
$c = 5;
$f1 = "a*b+c";
$f1 = str_replace("a", $a, $f1);
$f1 = str_replace("b", $b, $f1);
$f1 = str_replace("c", $c, $f1);
evalmath($f1);
/*if ( $equation != "" ){
$result = #eval("return " . $equation . ";" );
}
if ($result == null) {
throw new Exception("Unable to calculate equation");
}
echo $result;*/
?>
This method has two major drawbacks:
Security, php script is being evaluated by the eval function. This is bad,
especially when the user wants to inject malicious code.
Complexity
I created this, check it out: Formula Interpreter
How does it work ?
First, create an instance of FormulaInterpreter with the formula and its parameters
$formulaInterpreter = new FormulaInterpreter("x + y", ["x" => 10, "y" => 20]);
Use the execute() method to interpret the formula. It will return the result:
echo $formulaInterpreter->execute();
in a single line
echo (new FormulaInterpreter("x + y", ["x" => 10, "y" => 20]))->execute();
Examples
# Formula: speed = distance / time
$speed = (new FormulaInterpreter("distance/time", ["distance" => 338, "time" => 5]))->execute() ;
echo $speed;
#Venezuela night overtime (ordinary_work_day in hours): (normal_salary * days_in_a_work_month)/ordinary_work_day
$parameters = ["normal_salary" => 21000, "days_in_a_work_month" => 30, "ordinary_work_day" => 8];
$venezuelaLOTTTArt118NightOvertime = (new FormulaInterpreter("(normal_salary/days_in_a_work_month)/ordinary_work_day", $parameters))->execute();
echo $venezuelaLOTTTArt118NightOvertime;
#cicle area
$cicleArea = (new FormulaInterpreter("3.1416*(radio*radio)", ["radio" => 10]))->execute();
echo $cicleArea;
About the formulas
It must contain at least two operands and an operator.
Operands' name could be in upper or lower case.
By now, math functions as sin, cos, pow… are not included. I'm working to include them.
If your formula is not valid, you will get an error message like: Error, your formula (single_variable) is not valid.
Parameters' values must be numeric.
You can improve it if you want to!
eval Evaluates the given code as PHP. Meaning that it will execute the given paremeter as a PHP piece of code.
To correct your code, use this :
$ma ="print (2+10);";
eval($ma);
Using eval function
protected function getStringArthmeticOperation($value, $deduct)
{
if($value > 0){
$operator = '-';
}else{
$operator = '+';
}
$mathStr = '$value $operator $deduct';
eval("\$mathStr = \"$mathStr\";");
$userAvailableUl = eval('return '.$mathStr.';');
return $userAvailableUl;
}
$this->getStringArthmeticOperation(3, 1); //2
Finding a sweetspot between the dangers of eval and the limitless calculation possibilities I suggest checking the input for only numbers, operators and brackets:
if (preg_match('/^[0-9\+\-\*\/\(\)\.]+$/', $mathString)) {
$value = eval('return
' . $mathString . ';');
} else {
throw new \Exception('Invalid calc() value: ' . $mathString);
}
It's still easy to use yet relatively save. And it can handle any basic math calulation like (10*(1+0,2)) which isn't possible with most of the mentioned solutions here.
An eval'd expression should end with ";"
Try this :
$ma ="2+10;";
$p = eval($ma);
print $p;
By the way, this is out of scope but the 'eval' function won't return the value of the expression. eval('2+10') won't return 12.
If you want it to return 12, you should eval('return 2+10;');

Catch true statement from if condition with multiple statements

Is there a way to get the true statement from $this if condition:
$a = 1;
$b = 3;
$c = 7;
if ($a == 3 || $b == 4 || $c == 7) {
echo "The true statement was: ";
}
I expect to get this output:
The true statement was: 7
Is it possible to do this in PHP?
Or better to say how can i check which statement has triggered the if condition?
You can't without multiple conditions. Whatever answer you will get here eg:
Inline if statements
Wrap in a function
Condition result assignment in the condition
Switch
Loops
etc. Will always require you to have multiple conditions.
If you don't mind multiple conditions and just looking for most elegant way to write it, thats another question and we can help.
This can only ever show 1 true statement because of how the if works:
$a = 1;
$b = 3;
$c = 7;
if (($t = $a) ==3 || ($t = $b) == 4 || ($t=$c) == 7) {
echo "The true statement was: $t";
}
What happens here is it sets $t to each variable and then checks if the assignment result (which is the value) was successful. Since this is an || then it stops at the first success and so $t will have the last compared value.
Try this.
<?php
$day = 1;
$month = 3;
$year = 2017;
$str = "The true statements are: " . ($day == 3 ? "$day, " : "") . ($month == 4 ? "$month, " : "") . ($year == 2017 ? "$year, " : "");
echo substr($str, 0, strlen($str) - 2);
?>
If I understand correctly, this should work.
The strlen($str) -2 is to remove the trailing ", ".
Here is a solution with boolean variables:
$day = 1;
$month = 3;
$year = 2017;
$cday = $day == 3;
$cmonth = $month == 4;
$cyear = $year == 2017;
if ($cday || $cmonth || $cyear) {
echo "The true statements are: ";
if($cday) echo "$day<br>\n";
if($cmonth) echo "$month<br>\n";
if($cyear) echo "$year<br>\n";
}
This might help -
// actual values
$day = 1;
$month = 3;
$year = 2017;
// values & variable names to check
$checks = array(
'day' => 1,
'month' => 4,
'year' => 2017,
);
// Loop through the checks
foreach($checks as $check => $value) {
// compare values
if($$check == $value) {
// output and stop looping
echo "The true statement was: $check -> $value";
break;
}
}
Demo

Division by zero warning when divisor is "0.0"

I'm reading data from a text file and performing some basic math. This is how things should work:
// no warning, expected result N/A
$dividend = 100;
$divisor = 0.0;
if (!empty($dividend) && !empty($divisor))
{
$quotient = $dividend/$divisor;
} else {
$quotient = 'N/A';
}
echo $quotient;
This is how things are actually happening.
// yeilds division by zero warning
$dividend = 100;
$divisor = '0.0';
if (!empty($dividend) && !empty($divisor))
{
$quotient = $dividend/$divisor;
} else {
$quotient = 'N/A';
}
echo $quotient;
I'm getting a division by zero warning when a value in the text file is read as '0.0', which empty() sees as non-empty, when it actually empty.
What's the best way to test that '0.0' is actually 0?
Typecast $divisor to float: $divisor = (float)'0.0';
You'll want to cast to float (or use floatval()) in your condition statement. This leaves your values untouched in case you need other data from your variables, such as trailing text:
$dividend = 100;
$divisor = '0.0';
if ((float)$dividend && (float)$divisor) //both are non-zero
{
$quotient = $dividend/$divisor;
} else { //one or the other are zero
$quotient = 'N/A';
}
echo $quotient;
However consider only checking $divisor for zero.
Cast it to an int;
$divisor = (int) '0.0';
i think quotient should be zero if divisior is zero.
So you get a result in the following operations instead a N/A.
I always resolve it like this:
$quotient = ($divisor == 0) ? 0 : ($divident/$divisor);
it should work for "0.0", too.

How to calculate answer from variables? [duplicate]

I want to calculate math expression from a string. I have read that the solution to this is to use eval(). But when I try to run the following code:
<?php
$ma ="2+10";
$p = eval($ma);
print $p;
?>
It gives me the following error:
Parse error: syntax error, unexpected $end in
C:\xampp\htdocs\eclipseWorkspaceWebDev\MandatoryHandinSite\tester.php(4)
: eval()'d code on line 1
Does someone know the solution to this problem.
While I don't suggest using eval for this (it is not the solution), the problem is that eval expects complete lines of code, not just fragments.
$ma ="2+10";
$p = eval('return '.$ma.';');
print $p;
Should do what you want.
A better solution would be to write a tokenizer/parser for your math expression. Here's a very simple regex-based one to give you an example:
$ma = "2+10";
if(preg_match('/(\d+)(?:\s*)([\+\-\*\/])(?:\s*)(\d+)/', $ma, $matches) !== FALSE){
$operator = $matches[2];
switch($operator){
case '+':
$p = $matches[1] + $matches[3];
break;
case '-':
$p = $matches[1] - $matches[3];
break;
case '*':
$p = $matches[1] * $matches[3];
break;
case '/':
$p = $matches[1] / $matches[3];
break;
}
echo $p;
}
Take a look at this..
I use this in an accounting system where you can write math expressions in amount input fields..
Examples
$Cal = new Field_calculate();
$result = $Cal->calculate('5+7'); // 12
$result = $Cal->calculate('(5+9)*5'); // 70
$result = $Cal->calculate('(10.2+0.5*(2-0.4))*2+(2.1*4)'); // 30.4
Code
class Field_calculate {
const PATTERN = '/(?:\-?\d+(?:\.?\d+)?[\+\-\*\/])+\-?\d+(?:\.?\d+)?/';
const PARENTHESIS_DEPTH = 10;
public function calculate($input){
if(strpos($input, '+') != null || strpos($input, '-') != null || strpos($input, '/') != null || strpos($input, '*') != null){
// Remove white spaces and invalid math chars
$input = str_replace(',', '.', $input);
$input = preg_replace('[^0-9\.\+\-\*\/\(\)]', '', $input);
// Calculate each of the parenthesis from the top
$i = 0;
while(strpos($input, '(') || strpos($input, ')')){
$input = preg_replace_callback('/\(([^\(\)]+)\)/', 'self::callback', $input);
$i++;
if($i > self::PARENTHESIS_DEPTH){
break;
}
}
// Calculate the result
if(preg_match(self::PATTERN, $input, $match)){
return $this->compute($match[0]);
}
// To handle the special case of expressions surrounded by global parenthesis like "(1+1)"
if(is_numeric($input)){
return $input;
}
return 0;
}
return $input;
}
private function compute($input){
$compute = create_function('', 'return '.$input.';');
return 0 + $compute();
}
private function callback($input){
if(is_numeric($input[1])){
return $input[1];
}
elseif(preg_match(self::PATTERN, $input[1], $match)){
return $this->compute($match[0]);
}
return 0;
}
}
I recently created a PHP package that provides a math_eval helper function. It does exactly what you need, without the need to use the potentially unsafe eval function.
You just pass in the string version of the mathematical expression and it returns the result.
$two = math_eval('1 + 1');
$three = math_eval('5 - 2');
$ten = math_eval('2 * 5');
$four = math_eval('8 / 2');
You can also pass in variables, which will be substituted if needed.
$ten = math_eval('a + b', ['a' => 7, 'b' => 3]);
$fifteen = math_eval('x * y', ['x' => 3, 'y' => 5]);
Link: https://github.com/langleyfoxall/math_eval
Using eval function is very dangerous when you can't control the string argument.
Try Matex for safe Mathematical formulas calculation.
Solved!
<?php
function evalmath($equation)
{
$result = 0;
// sanitize imput
$equation = preg_replace("/[^a-z0-9+\-.*\/()%]/","",$equation);
// convert alphabet to $variabel
$equation = preg_replace("/([a-z])+/i", "\$$0", $equation);
// convert percentages to decimal
$equation = preg_replace("/([+-])([0-9]{1})(%)/","*(1\$1.0\$2)",$equation);
$equation = preg_replace("/([+-])([0-9]+)(%)/","*(1\$1.\$2)",$equation);
$equation = preg_replace("/([0-9]{1})(%)/",".0\$1",$equation);
$equation = preg_replace("/([0-9]+)(%)/",".\$1",$equation);
if ( $equation != "" ){
$result = #eval("return " . $equation . ";" );
}
if ($result == null) {
throw new Exception("Unable to calculate equation");
}
echo $result;
// return $equation;
}
$a = 2;
$b = 3;
$c = 5;
$f1 = "a*b+c";
$f1 = str_replace("a", $a, $f1);
$f1 = str_replace("b", $b, $f1);
$f1 = str_replace("c", $c, $f1);
evalmath($f1);
/*if ( $equation != "" ){
$result = #eval("return " . $equation . ";" );
}
if ($result == null) {
throw new Exception("Unable to calculate equation");
}
echo $result;*/
?>
This method has two major drawbacks:
Security, php script is being evaluated by the eval function. This is bad,
especially when the user wants to inject malicious code.
Complexity
I created this, check it out: Formula Interpreter
How does it work ?
First, create an instance of FormulaInterpreter with the formula and its parameters
$formulaInterpreter = new FormulaInterpreter("x + y", ["x" => 10, "y" => 20]);
Use the execute() method to interpret the formula. It will return the result:
echo $formulaInterpreter->execute();
in a single line
echo (new FormulaInterpreter("x + y", ["x" => 10, "y" => 20]))->execute();
Examples
# Formula: speed = distance / time
$speed = (new FormulaInterpreter("distance/time", ["distance" => 338, "time" => 5]))->execute() ;
echo $speed;
#Venezuela night overtime (ordinary_work_day in hours): (normal_salary * days_in_a_work_month)/ordinary_work_day
$parameters = ["normal_salary" => 21000, "days_in_a_work_month" => 30, "ordinary_work_day" => 8];
$venezuelaLOTTTArt118NightOvertime = (new FormulaInterpreter("(normal_salary/days_in_a_work_month)/ordinary_work_day", $parameters))->execute();
echo $venezuelaLOTTTArt118NightOvertime;
#cicle area
$cicleArea = (new FormulaInterpreter("3.1416*(radio*radio)", ["radio" => 10]))->execute();
echo $cicleArea;
About the formulas
It must contain at least two operands and an operator.
Operands' name could be in upper or lower case.
By now, math functions as sin, cos, pow… are not included. I'm working to include them.
If your formula is not valid, you will get an error message like: Error, your formula (single_variable) is not valid.
Parameters' values must be numeric.
You can improve it if you want to!
eval Evaluates the given code as PHP. Meaning that it will execute the given paremeter as a PHP piece of code.
To correct your code, use this :
$ma ="print (2+10);";
eval($ma);
Using eval function
protected function getStringArthmeticOperation($value, $deduct)
{
if($value > 0){
$operator = '-';
}else{
$operator = '+';
}
$mathStr = '$value $operator $deduct';
eval("\$mathStr = \"$mathStr\";");
$userAvailableUl = eval('return '.$mathStr.';');
return $userAvailableUl;
}
$this->getStringArthmeticOperation(3, 1); //2
Finding a sweetspot between the dangers of eval and the limitless calculation possibilities I suggest checking the input for only numbers, operators and brackets:
if (preg_match('/^[0-9\+\-\*\/\(\)\.]+$/', $mathString)) {
$value = eval('return
' . $mathString . ';');
} else {
throw new \Exception('Invalid calc() value: ' . $mathString);
}
It's still easy to use yet relatively save. And it can handle any basic math calulation like (10*(1+0,2)) which isn't possible with most of the mentioned solutions here.
An eval'd expression should end with ";"
Try this :
$ma ="2+10;";
$p = eval($ma);
print $p;
By the way, this is out of scope but the 'eval' function won't return the value of the expression. eval('2+10') won't return 12.
If you want it to return 12, you should eval('return 2+10;');

How to get modulo from float

I have:
$value = 0.57;
$step = 0.01;
I want to check if $value/$step is integer. Additionally sometimes $value is negative.
What I get is:
$value/$step -> 57
is_int($value/$step) -> false
and the best one:
floor($value/$step) -> 56 (I assume that 57 is really 56.9999999(9) )
$a - $b * floor($a / $b) -> 0.0099999(9)
($value/$step)%1 -> 0 (ok, but % doesn't work if it is really a float)
fmod($value/$step) -> 0.999999999(9)
any idea?
other possibility: float as string modulo :-)
function float_modulo($value, $step) {
$str_value = strval($value);
$float_part_value = substr($str_value, strpos($str_value, ".") + 1);
$str_step = strval($step);
$float_part_step = substr($str_step, strpos($str_step, ".") + 1);
return intval($float_part_value) % intval($float_part_step);
}
OP solution
public static function isZero($number, $precision = 0.0000000001)
{
$precision = abs($precision);
return -$precision < (float)$number && (float)$number < $precision;
}
public static function isEqual($number1, $number2)
{
return self::isZero($number1 - $number2);
}
public static function fmod($number1, $number2)
{
//$rest = self::sfmod($number1, $number2);
if ($number2<0)
{
$rest = $number1 - $number2 * ceil($number1/$number2);
}
else if ($number2>0)
{
$rest = $number1-$number2*floor($number1/$number2);
}
if (self::isEqual($rest, $number2)) {
return 0.0;
}
if (mb_strpos($number1, ".") === false) {
$decimals1 = 0;
} else {
$decimals1 = mb_strlen($number1) - mb_strpos($number1, ".") - 1;
}
if (mb_strpos($number2, ".") === false) {
$decimals2 = 0;
} else {
$decimals2 = mb_strlen($number2) - mb_strpos($number2, ".") - 1;
}
return (float)round($rest, max($decimals1, $decimals2));
}
I don't know if it's helpful enough but i think you can subtract the division result from its rounded value and compare it to an epsilon value, like this:
$value = 0.57;
$step = 0.01;
$epsilon = 0.00000001; // less decimals means lower precision
var_dump(abs(round($value/$step) - $value/$step) < $epsilon);
Wrap it in a function and call it test_integer or however you want and see if it's working for you.
LE: Added abs() to make it work for negative numbers.

Categories