Use string value as if/else expression - php

This is probably the dumbest question out there and the answer is probably NO, but...
Is it possible to use the value of a string in the expression of an if statement? For example, say I pass
'if strcasecmp("hello", "Hello") == 0'
to a function and call it $string, could I then use that value as the conditional evaluation of an if statement?
if (the value of $string) {}
I know eval() will execute a string as if it was PHP code, but actually executes it and returns null/false, rather than just allowing the PHP surrounding the string to deal with the contents of string. I also know you can use variable variables by using ${$varname} that will tell php to use the value of $varname as the name of a a variable.
So I guess what I'm looking for is kind of like 'variable code' instead of 'variable variables'.

I must guess a bit, maybe you want to return from eval?
if (eval('return strcasecmp("hello", "Hello") == 0;')) {}
Also, there are closures that might add a bit more fluidity:
$if = function($string) {
return eval(sprintf('return (%s);', $string));
}
$string = 'strcasecmp("hello", "Hello") == 0';
if ($if($string)) {
...
}

The if statement does not return anything, so your example won't work. However, you can store the expression as a string and eval it later:
$expr = 'strcasecmp("hello", "Hello") == 0';
$val = eval($expr);
Now, keep in mind that using eval is extremely discouraged, as it can lead to serious security problems.

if( eval("return ({$string});") ):
...
endif;
Though what you're trying to do is very bad.

Related

While loop: only Variables can be passed by reference error

I am running into a "Only variables should be passed by reference" error, because on the code I am using there is a line that does not put the explode() result into a variable. As required when using strict PHP standards.
However because the explode() function is used in a While loop I can't think of a appropriate solution.
My code looks like
function user_exists($username) {
rewind($this->fp);
while(!feof($this->fp) && trim($lusername = array_shift(explode(":",$line = rtrim(fgets($this->fp)))))) {
if($lusername == $username)
return 1;
}
return 0;
}
Any suggestions on how to solve this?
I think maybe you need to sit back and break your code apart a bit and take a look at what is happening.
First, condition is while !feof($this->fp)
From the manual:
feof — Tests for end-of-file on a file pointer
One thing you will notice here is that feof() is only a test which returns true or false. It does not advance the pointer position while looping over, so while using this function, somewhere else in your while loop there needs to be something that advances the pointer or else you will have an infinite loop.
Second condition is:
trim($lusername = array_shift(explode(":",$line = rtrim(fgets($this->fp)))))
First function from left to right is trim(), which returns a string. From our handy dandy comparison table we see that when doing if ((String) $var) it evaluates to false if and only if the string is empty ("") or the number zero as a string ("0"), otherwise it returns true. Personally I tend to really hate using if ((String) $var) (first because it's slightly unclear to newbies unless you know your comparison table well and second because 99% of the time people are doing that they are actually checking for string length, in which case I would want it to return true for the string "0"). So assuming that you don't need it to return false for "0" we could change this to strlen($var) > 0 and then manipulate the variable within the loop. That should greatly simplify things here.
So now we have:
while (!feof($this->fp) && strlen($var) > 0) { /*...*/ }
This will loop over until either we are at the end of the file or $var is an empty line. Everything else can be offloaded into the body of the while loop, so it is much easier to break apart.
So this is what we have now:
$line = rtrim(fgets($this->fp));
$lusername = array_shift(explode(":",$line)));
Uh-oh! There's that "nasty" error:
Strict Standards: Only variables should be passed by reference in /path/to/file.php on line x.
So we can see from here, the part producing the error is not explode(), but array_shift(). See also: Strict Standards: Only variables should be passed by reference
What this means is that since array_shift() modifies the array, it requires it to be by reference. Since you are not passing an actual variable but instead the result of a function, PHP is unable to modify it. It's similar to doing something like function($var) = 3;. Of course you can't do that. Instead you need to save the value to a temporary variable. So now we have:
$line = rtrim(fgets($this->fp));
$split = explode(":",$line);
$lusername = array_shift($split);
Woo hoo! No more warning message.
So putting this together, we now have:
while (!feof($this->fp) && strlen($lusername) > 0) {
$line = rtrim(fgets($this->fp));
$split = explode(":",$line);
$lusername = array_shift($split);
if($lusername == $username) {
return 1;
}
}
Also, as mentioned earlier, the fgets() will advance the pointer, which allows the !feof($this->fp) part in the while statement to vary.

How to dynamically pass condition of if statement

I am in a situation where I'll get comparison string in a variable, and I want to use that variable in IF
$xyz = '$abc<200'; // Dummy Dynamic Text
if($xyz) { // It should execute like if($abc<200)
echo 'you are dynamic';
}
In the example above the comparison string coming dynamically in $xyz variable and I want to put that variable in if condition, How do I do that?
You cannot use quotes as it is making the string out of it. Do it this way:
$xyz=($abc<200); //or, as well, $xyz=$abc<200
if($xyz) {
echo 'you are dynamic';
}
If however you want to keep that condition text in string, you could use eval:
$xyz='$abc<200';
if(eval("return $xyz;")) {
echo 'you are dynamic';
}
Eval is sometimes disabled. This is for security reasons. Often with suhosin. Eval can be evil! Think about code injections.
You could try to use an anonymous function.
<?php
$func = function($abc) {
return $abc<200;
};
if ($func($abc)) {
// great
}

In this case can I use # to avoid useless isset()?

Basically I need to create a string with $_GET['param'], something like:
$myString = $_GET['param'] . 'abc';
When $_GET['param'] isn't isset i am perfectly fine with $myString being just ='abc'
So I can do something like this:
$myString = #$_GET['param'] . 'abc';
Or use the standard way with isset:
if (!isset($_GET['param']))
$_GET['param'] = '';
$myString = $_GET['param'] . 'abc';
In this case using the # suppresser is considering such a bad pratice?
The most elegant thing IMHO would be to wrap that in a nice getter function, something like:
function _getParam($param, $default = '') {
if (!isset($_GET[$param]))
return $default;
return $_GET[$param];
}
$myString = _getParam('param').'abc';
yes123 note:
As dvir said having a getter function for input variables in your framework can be handy. But this _getParam suffers of this problem:
Let's see we make a typo in our code, we want to access $_GET['param'] and istead of it we type:
_getParam('parm')
Our code will work without generting any problems and we will have hard time finding the error.
So I thought we could modify the function presented to something like:
function _get() {
$key = func_get_arg(0);
if (func_num_args()==2) {
if (!isset($_GET[$key]))
return func_get_arg(1);
}
return $_GET[$key];
}
This ensures that when we typo it with _get('parm') we will get a notice throwed normally. But when we use it with 2 param we get out default value:
_get('param','myDefaultValue');
You can avoid using # like this:
$myString = ( isset($_GET['param']) ? $_GET['param'] : '' ) . 'abc';
In this case using the # suppresser is considering such a bad pratice?
Generally from the developer perspective it is good idea to avoid using # operator because it may hide errors that may be useful when debugging a particular problem. Other than that, it is very slow and for that reason, in the future version of PHP, # won't be supported in ini_set calls.
It's not extremely elegant in my opinion (although it is short). I think the worst thing you have going here may be writing to the $_GET superglobal directly in your "standard" approach.
if (!isset($_GET['param'])) $_GET['param'] = '';
Maybe I'm being paranoid, but another unrelated script could run afterwards that checks for isset($_GET['param']), and now it will return TRUE because you injected '' into it.
So, yes - you can safely use error suppression here (there's not much you're going to miss), but there's no reason to avoid isset() either:
$myString = isset($_GET['param']) ? $_GET['param'] : '' . 'abc';

Why doesn't my code to test an email address against a specific domain work?

I wanted to allow only specific email domain. Actually I did it. What i wanted to ask why my first code did not work at all.
I am just trying to learn PHP so that the question may seem silly, sorry for that.
Here is my code:
function check_email_address($email) {
$checkmail = print_r (explode("#",$email));
$container = $checkmail[1];
if(strcmp($container, "gmail.com")) {
return true;
}else {
return false;
}
}
Check out the documentation for strcmp() , it will return 0 of the two strings are the same, so that's the check you want to be doing. Also, you're using print_r() when you shouldn't be, as mentioned by the other answerers.
Anyway, here's how I would have done the function - it's much simpler and uses only one line of code:
function check_email_address($email) {
return (strtolower(strstr($email, '#')) == 'gmail.com');
}
It uses the strstr() function and the strtolower() function to get the domain name and change it to lower case, and then it checks if it is gmail.com or not. It then returns the result of that comparison.
It's because you're using print_r. It doesn't do what you seem to expect from it at all. Remove it:
$checkmail = explode("#", $email);
You can find the docs about print_r here:
http://php.net/print_r
Besides that, you can just use the following (it's much shorter):
$parts = explode("#", $email);
return (strcmp($parts[1], "gmail.com") == 0);
The following row doesn't work as you think it does:
$checkmail = print_r (explode("#",$email));
This means that you're trying to assign the return value from print_r() into $checkmail, but it doesn't actually return anything (if you don't supply the second, optional parameter with the value true).
Even then, it would've gotten a string containing the array structure, and your $container would have taken the value r, as it's the second letter in Array.
Bottom line: if your row would've been without the call to print_r(), it would've been working as planned (as long as you made sure to compare the strcmp() versus 0, as it means that the strings are identical).
Edit:
Interesting enough, I just realized that this could be achieved with the use of substr() too:
<?php
//Did we find #gmail.com at the end?
if( strtolower(substr($email, -10)) == '#gmail.com' ) {
//Do something since it's an gmail.com-address
} else {
//Error handling here
}
?>
You want:
if(strcmp($container, "gmail.com")==0)
instead of
if(strcmp($container, "gmail.com"))
Oh! And no inlined print_r() of course.
Even better:
return strcmp($container, "gmail.com")==0;
No need for the print_r; explode returns a list. And in terms of style (at least, my style) no need to assign the Nth element of that list to another variable unless you intend to use it a lot elsewhere. Thus,
$c = explode('#',$mail);
if(strcmp($c[1],'gmail.com') == 0) return true;
return false;

PHP GET Question: How do I set a variable value only if it's not in the query string?

I know how to get the value from the query string if the parameter exists:
$hop = $_GET['hop'];
But I also need to set a default value IF it's not in the query string. I tried this and it didn't work:
$hop = $_GET['hop'];
if ($hop = " ") {
$hop = 'hardvalue';
};
Please help me handle the case where the query string has and does not have the "hop" parameter, and if it's present but not defined:
example.com/?hop=xyz
&
example.com/
&
example.com/?hop=
PS I don't know what I'm doing, so if you explain to me, please also include the exact code for me to add to my PHP page.
use array_key_exists
if (array_key_exists('hop', $_GET))
{
// the key hop was passed on the query string.
// NOTE it still can be empty if it was passed as ?hop=&nextParam=1
}
else
{
//the key hop was not passed on the query string.
}
Thought about it a bit more and decided it should be a bit more robust:
$hop = 'hardvalue';
if (array_key_exists('hop', $_GET)) {
if (!empty($_GET['hop'])) { $hop = $_GET['hop']; }
}
You already got the fiddly solutions. When working with URL or form parameters, you often want to treat the empty string or zeros as absent values too. Then you can use this alternative syntax:
$hop = $_GET["hop"] or $hop = "hardvalue";
It works because of the higher precedence of = over or, and is easier to read with extra spaces.
Starting from PHP 5.3 it's also possible to use:
$hop = $_GET["hop"] ?: "hardvalue";
The advantage here is that this syntax doesn't slurp up php notices, which are useful for debugging.
Actually, I would use
$hop = !empty($_GET['hop']) ? $_GET['hop'] : 'default';
Using empty() instead of isset() takes care of your third scenario, where the parameter is present but not defined.
Also, in if ($hop = " ") the = would need to be changed to ==. = assigns, == tests equality. The way you have it, the if-statement will always run, no matter what $hop equaled.

Categories