I want to evaluate a mathematical operations inside the string after I get it in that string.
Here is the string
$string = "Add this two numbers [4+2+2]. And [5*3/2] will result to?"
I already get those numbers:
$f_number = "4+2+2";
$s_number = "5*3/2";
How can I evaluate this automatically using any function?
Sample:
echo anyfunction($f_number);//will result to 8
echo anyfunction($s_number);//will result to 7.5
because if I will echo directly it will just output like this:
echo $f_number;//will result to 4+2+2
echo a$s_number;//will result to 5*3/2
You can use eval. It's probably the easiest way out. Mind though that it can also be used for other expressions, because it basically executes any PHP code that is in the string.
But by wrapping it in a function, like you intended, you can at least black box it, and add safety measures later if you need to, or even switch to a different expression evaluator, without having to change all your code.
A simple safety measure would be to check if the string only contains numeric values, whitespace and allowed operators. That way it should be impossible to secretly inject actual code.
function anyfunction($expr)
{
// Optional: check if $expr contains only numerics and operators
// actual evaluation. The code in $expre should contain a return
// statement if you want it to return something.
return eval("return $expr;");
}
echo anyfunction($f_number);
Related
I should firstly apologize for my probably rookie question, but I've just got no clue how to achieve that relatively complex task being a complete newbie regarding regex. What I need is to specify a validation pattern for a string input and perform separate checks on the separate segments of that pattern. So let's begin with the task itself. I'm working with php7.0 on laravel 5.4 (which should genuinely not make any difference) and I need to somehow produce a matching pattern for a string input, which pattern is the following:
header1: expression1; header2: expression2; header3: expression3 //etc...
What I'd need here is to check if each header is present and if it's present in a special validation list of available headers. So I'd need to extract each header.
Furthermore the expressions are built as follows
expression1 = (a1 + a2)*(a3-a1)
expression2 = b1*(b2 - b3)/b4
//etc...
The point is that each expression contains some numeric parameters which should form a valid arithmetic calculation. Those parameters should also be contained in a special list of available parameter placeholders, so I'd need to check them too. So, is there a simple efficient way (using regex and string analysis in pure php) to specify that strict structure or should I do everything step by step with exploding and try-catching?
An optimal solution would be a shorthand logic (or regex expression?) of a kind like:
$value->match("^n(header: expression)")
->delimitedBy(';')
->where(in_array($header, $allowed_headers))
->where(strtr($expression, array_fill_keys($available_param_placeholders, 0))->isValidArithmeticExpression())
I hope you can follow my logic. The code above would read as: Match N repetitions of the pattern "header: expression", delimited by ';', where 'header' (given that $header is its value) is in an array and where 'expression' (given that $expression is its value) forms a valid arithmetic expression when all available parameter placeholders have been replaced by 0. That's it all. Each deviation of that strict pattern should return false.
As an alternative I'm currently thinking of something like firstly exploding the string by the main delimiter (the semicolon) and then analysing each part separately. So I'll then have to check if there is a colon present, then if everything to the left of the colon matches a valid header name and if everythin to the right of the column forms a valid arithmetic expression when all param names from the list are replaced by a random value (like 0, just to check if the code executes, which I also don't know how to do). Anyway, that way seems like an overkill and I'm sure there should be a smoother way to specify the needed pattern.
I hope I've explained everything good enough and sorry if I'm being to messy explaining my problem. Thanks in advance for each piece of advice/help! Greatly appreciated!
Using eval() must always be Plan Z. With my understanding of your input string, this method may sufficiently validate the headers and expressions (if not, I think it should sufficiently sanitize the string for arithmetic parsing). I don't code in Laravel, so if this can be converted to Laravel syntax I'll leave that job for you.
Code: (Demo)
$test = "header1: (a1 + a2)*(a3-a1); header2: b1*(b2 - b3)/b4; header3: c1 * (((c2); header4: ((a1 * (a2 - b1))/(a3-a1))+b2";
$allowed_headers=['header1','header3','header4'];
$pairs=explode('; ',$test);
foreach($pairs as $pair){
list($header,$expression)=explode(': ',$pair,2);
if(!in_array($header,$allowed_headers)){
echo "$header is not permitted.";
}elseif(!preg_match('~^((?:[-+*/ ]+|[a-z]\d+|\((?1)\))*)$~',$expression)){ // based on https://stackoverflow.com/a/562729/2943403
echo "Invalid expression # $header: $expression";
}else{
echo "$header passed.";
}
echo "\n---\n";
}
Output:
header1 passed.
---
header2 is not permitted.
---
Invalid expression # header3: c1 * (((c2)
---
header4 passed.
---
I will admit the above pattern will match (+ )( +) so it is not the breast best pattern. So perhaps your question may be a candidate for using eval(). Although you may want to consider/research some of the github creations / plugins / parsers that can parse/tokenize an arithmetic expressions first.
Perhaps:
calculate math expression from a string using eval
How to evaluate formula passed as string in PHP?
Parse math operations with PHP
How to mathematically evaluate a string like "2-1" to produce "1"?
Any $pair that gets past the if and the elseif can move onto the evaluation process in the else.
I'll give you a headstart/hint about some general handling, but I'll shy away from giving any direct instruction to avoid the wrath of a certain population of critics.
}else{
// replace all variables with 0
//$expression=preg_replace('/[a-z]\d+/','0',$expression);
// or replace each unique variable with a whole number
$expression=preg_match_all('/[a-z]\d+/',$expression,$out)?strtr($expression,array_flip($out[0])):$expression; // variables become incremented whole numbers
// ... from here use $expression with eval() in a style/intent of your choosing.
// ... set a battery of try and catch statements to handle unsavory outcomes.
// https://www.sitepoint.com/a-crash-course-of-changes-to-exception-handling-in-php-7/
}
$test = "header1: (a1 + a2)*(a3-a1); header2: b1*(b2 - b3)/b4; header3: expression3";
$pairs = explode(';', $test);
$headers = [];
$expressions = [];
foreach ($pairs as $p) {
$he = explode(':', $p);
$headers[] = trim($he[0]);
$expressions[] = trim($he[1]);
}
foreach ($headers as $h) {
if (!in_array($h, $allowed_headers)) {
return false;
}
}
foreach ($expressions as $e) {
preg_match_all('/[a-z0-9]+/', $e, $matches);
foreach ($matches as $m) {
if (param_fails($m)) {
echo "Expression $e contains forbidden param $m.";
}
}
}
Regex appeared to be not as complicated as I thought when posting that question, so I've managed to achieve the pattern in its complete form by myself with the initial headstart owed to #mickmackusa. What I have finally come up with is that here, explained to you by regex101 itself: https://regex101.com/r/UHMrqL/1
The logic whic it's based on is described in the initial question. The only thing missing is the verification of the values of the headers and the names of the params, but that's easy to match afterwards with preg_match_all and verify with pure php checks. Thanks again for the attention and the help! :)
I'm very new to php .I want to convert the string to integer value.
I used following code to convert
$val='(100*2)';
echo (int)($val); //This will showing output as 0
But echo (int)((100*2)); /This will showing output as 200
Please help me any one to solve this .Thanks advance
(int)($val) evaluates to 0 because $val's value is not a numeric string (ie one that can be directly cast to a number).
If you really need this kind of functionality, try eval():
$val='(100*2)';
echo (int)($val); //This will showing output as 0
eval('$newval='.$val.';');
echo $newval;
But be warned: eval() can be dangerous!
From http://php.net/manual/en/function.eval.php:
Caution
The eval() language construct is very dangerous because it allows
execution of arbitrary PHP code. Its use thus is discouraged. If you
have carefully verified that there is no other option than to use this
construct, pay special attention not to pass any user provided data
into it without properly validating it beforehand.
EDIT: Added .';' to eval parameter to make it a legit php instruction.
The most common suggestion will be - evaluate your string as PHP code, like:
$val = '(100*2)';
eval('$val = '.$val.';');
-but that's unsafe, eval should be avoided as long as possible.
Alternatively, there is bcParser for PHP, which can solve such issues. That's more safe than eval.
Finally, I doubt that you really need do such things - it seems you're solving some problem with wrong method (see XY-problem description)
You can do it using php eval function.
For that first you have to check for special characters and equation characters.
$val='(100*2)';
echo matheval($val);
function matheval($equation)
{
$equation = preg_replace("/[^0-9+\-.*\/()%]/","",$equation);
// fix percentage calcul when percentage value < 10
$equation = preg_replace("/([+-])([0-9]{1})(%)/","*(1\$1.0\$2)",$equation);
// calc percentage
$equation = preg_replace("/([+-])([0-9]+)(%)/","*(1\$1.\$2)",$equation);
// you could use str_replace on this next line
// if you really, really want to fine-tune this equation
$equation = preg_replace("/([0-9]+)(%)/",".\$1",$equation);
if ( $equation == "" )
{
$return = 0;
}
else
{
eval("\$return=" . $equation . ";" );
}
return $return;
}
I not recommended this, but you can use eval to suit your need
eval('$val = (100*2)');
echo intval($val);
Why not just:
$x=intval(100);// <- or an other value from the cleaned user input
$y=intval(2);
$val=$x*$y;
echo $val;
You are not giving a goal.
I can just explain why your code works like it does.
'(100*2)' is a String that cannot be converted to int, since it does contain other chars than numbers. Every String that cannot be converted will result in 0.
echo (int)(100*2) will work, because you use numbers and no strings. No need to convert, either, would work without the cast, just echo (100*2);
Remember PHP use loose typing. You will almost never need to convert types. This scenario is very set up.
My issue is a bit haywire, I must admit before I carry on. So please do not ask me why I need this. Here goes:
Suppose I have an anonymous function of this sort:
$_ = function(){return true;};
What I aim to achieve is to alter the syntax using the XOR operator as follows:
$_ = ("&"^"#").('*'^'_').("."^"#").('<'^'_').("+"^"_").("#"^")").("/"^"#").("."^"#").(){return true;};
This is met as invalid syntax by PHP. Same goes if I try to append the value of the string 'function' to a variable and then use it as shown below:
$__ = ("&"^"#").('*'^'_').("."^"#").('<'^'_').("+"^"_").("#"^")").("/"^"#").("."^"#")
$_ = $__(){return true;}
Therefore, my question is how could I possibly approach this case and use a XORed value of the keyword 'function'. I know it is possible but fail to perceive how it's being realised.
Thank you in advance for any solutions/guidelines/answers!
Unfortunately for you, PHP doesn't allow you to use a calculated value as a keyword. To over-simplify, PHP has three stages: lexing, parsing, and execution. Keywords are used during the parsing process, and your XORs are calculated during execution. To use your calculated value as a keyword, you'd have to redo the parsing process.
Fortunately for you, in PHP, that's possible using eval, although it has to be a whole new piece of code rather than, say, a single function token. eval needs a whole chunk of code, so you'll need to assemble the whole thing into a string:
$myKeyword = 'function'; // XORs don't matter; the problem is it's calculated
$code = '$myResult = ' . $myKeyword . '() { return true; };';
Then you can pass that to eval:
eval($code); // you could, of course, bypass the intermediate $code variable
Your function is now in $myResult:
$myResult(); // => true
Of course, you'd never want to use this in code you intend to be readable, but I'm almost certain you're just trying to obfuscate your code, in which case readability is intended to be poor.
This is annoying me. In theory it should be easy but I don't live in theory.
Basically, I have an option to set a custom algorithm to make a 'code' that is either string or int.
This is user generated, and I then call that.
I have attempted to execute it using this code:
$code = eval('return($custalg);');
but that returns the actual algorithm entered, and not the value it would produce.
So my question is, how would I manage to execute the string in $custalg as php and then save the result into a variable?
It looks you are not aware of difference between single quoted ' and double quoted " strings in PHP. You should use:
$code = eval("return($custalg);");
if you want $custalog to be expanded:
The most important feature of double-quoted strings is the fact that
variable names will be expanded. See string parsing for details.
See more in docs.
So basically correct syntax depends on what $custalg is and where it is assigned. In your case I guess your $custalg is assigned in main code so you do not want substitution. Use code like this then:
$code = eval("return \$custalg;");
You can get an echoed output with using the PHP output control functions:
ob_start();
eval("echo $custalg;");
$tmp = ob_get_contents();
ob_end_clean();
$evalOutput = $tmp;
Or you just assign the return value to a global variable.
Perhaps this is a petty question, but consider the following PHP code:
$a = "foo1"; $b = "foo2"; $c = "foo3";
echo $a, $b, $c;
echo $a . $b . $c;
echo "$a$b$c";
aren't these three statements equivalent. What's the difference.
What if one cannot decide whether to use one or the other?
The first one simply echoes out 3 values in a single call. The other two do string concatenations and output the result of that operation. In other words, if you were doing this a few zillion times in a row, the first version would probably be slightly faster, because there's less string operations going on.
That being said, even if you reduce string operations in PHP, the output produced by the echo statements will still be tacked onto the end of an output buffer, and stuffing in a single larger string may be more efficient than multiple smaller strings.
In the grand scheme of things, there'll probably be very little difference between any of those versions, so go with the one that makes the most sense to you, and is easiest for maintenance down the road.
They are mostly equivalent, I would assume that the only real difference would be on performance of how it executes. This may become insignificant or nonexistent if you use a php optimizer.
If I was to guess, I would say that echo #1 is fastest, followed by echo #2, and lastly echo #3.
Why I say this?:
echo #1:
plays directly off of the language construct that it is and simply spits out the variables.
echo #2:
must first concat the strings together and then echo it out
echo #3:
Must first search through the string and replace what it finds with what the variable is. Which would most likely be the most expensive operaion to handle.
Additional note:
You should ALWAYS use single quotes when putting strings into variables unless you explicitly want variables replaced on the inside. Thus your first line:
$a = "foo1"; $b = "foo2"; $c = "foo3";
Should be:
$a = 'foo1'; $b = 'foo2'; $c = 'foo3';
Just a note about the third method:
When using variables in double quotes, I am in the habit of using curly brackets because they escape array-based variables:
echo "{$a}{$b}{$c}";
If $c were an associative array and you wanted to output some element of it, the statement would then be:
echo "{$a}{$b}{$c['foo']}";
Sometimes this results in neater string formatting than concatenating variables and strings together for output.