Convert string of variable names to real variables

Hi all,
This should be easy but I’m having trouble wrapping my head around the solution.
In a nutshell, here it is,


$bindres = '$id,$email,$password,$salt,$userlevel';
. . . .

$stmt->bind_result($bindres);
echo '<br>bind_result '.$bindres.'<br>';


Obviously $bindres is a string, is there an easy way to convert the string variables to real variables?
Eval() appears to do that but many say it is evil.
Do prepared statements remove the evil from eval?
Thanks for looking and helping.

Never eval a user-touchable piece of content. It’s just begging for hacking.

You want the variable VALUES, or variable references?

If you want the values, turn your single quotes into double quotes and bindres will contain the evaluated values instead of variable names.
I’m thinking you might be able to do something funky with a preg_replace (something like "Find anything ‘$(lettersandnumbers)’, replace with "${($1)}), but failing that (as i’m unable to do testing at the moment), a simple str_replace will do the task.

Can you give us some background on this problem? Why do you have a list of variable names in a string? Are they provided by a user, third party, something else? Is it hard coded in code? Usually when I see a question like this, my first thought is, you choose a bad design for your project and you need to re-think it, but without knowing what is happening, I can’t say if that’s the truth or not for this situation.

I am getting the error,
Number of bind variables doesn’t match number of fields in prepared statement on line 99.
with both of these.


$bindres = "$id,$email,$password,$salt,$userlevel";
$bindres = '$id,$email,$password,$salt,$userlevel';

if I change (line 99),


$stmt->bind_result($bindres);
// to
$stmt->bind_result($id,$email,$password,$salt,$userlevel);

it works perfectly. I’m building my own dynamic PDO function and am hung up on this bit.
Thanks.
BTW, I even tried exploding $bindres into an array, print_r looked great but still no joy with bind_result. I read somewhere bind_result will work with an array

Well my first impulse is to say: Dont use bind_result if you want this set of fields to change. I’d be using a fetchAll like device. If you still needed them sharded out into individual variables at that point, walk the array.
Assuming you’re trying to make this dynamic…
take the string, remove the $'s.
explode on ,. This is now your identifier set.
foreach numeric-indexed row in result set:
foreach element of exploded string (capturing key)
${$expstring[$key]} = $resultrow[$key];

least, thats how it works in my head. As cpradio said, this is an odd sort of behavior to be looking to use, and may be a sign your project flow needs a rethink.

Okay, so now that I know what you are attempting to do, I’ll tell you how I implemented something similar a while back. I used Prepared Statements (yes, it has a bit of a performance hit in most scenarios, but it wasn’t enough to really affect my application).

$stmt = $this->connection->prepare($query);
$result = $stmt->execute($arrayOfArgs);

The execute takes an array, so you can use the ? or :name syntax in your query and so long as your array contains the correct number of arguments, it will execute the query.

Granted, I’m sure there is a way to make it work with bind_result, but as I previously stated, I didn’t bother going that route for the sake that prepared statements didn’t impact my application in a negative way.

I appreciate you time and thank you,
I really don’t need bind_result and am used to working with $row.
This is almost there. In the following code I have $stmt->bind_result($id,$email,$password,$salt,$userlevel); hardcoded and the query works.
If I comment out that line I dont get anything out of the database.
All I am looking for now is to get values for $row.
No mater what I try print_ is always 1 (??)

Here is the entire code.


$name = 'dave';

$select = 'id
, email
, password
, salt
, userlevel
';

$wherearr = array(username => $name);

foreach ($wherearr as $key => $value) {
    if (is_numeric($value)) {
        $bind1 .= 'n';
    } else {
        $bind1 .= 's';
    }
	$bind2 .= $value ;
	$where = $key.'= ?';
}

$q = "SELECT ".$select." FROM members WHERE $where LIMIT 1";
echo '<br>'.$q.'<br>'; // SELECT id , email , password , salt , userlevel FROM members WHERE username= ? LIMIT 1

$stmt = $mysqli->prepare($q);
$stmt->bind_param($bind1, $bind2); // Bind "$email" to parameter.
echo '<br>bind_param '.$bind1.', '. $bind2.'<br>'; // s, dave

$stmt->execute();
$stmt->store_result();
$stmt->bind_result($id,$email,$password,$salt,$userlevel);

while($row = $stmt->fetch()) {
	echo'<pre>row'; print_r($row); echo '</pre>'; // only displays 1
}

if($stmt->num_rows == 0) { // If the user exists
	echo 'got nothing';	
}
else{
	echo $email.' got something '.$stmt->num_rows; // works fine if bind_result

}


Thank you so much, I intend to move away from mysql for good.

Well, if you’re comfortable statically defining the fields;

when you do a fetch(), $id,$email,$password,$salt,$userlevel will be filled with the current row’s values.

Take a look at Example #1 on PHP Manual’s page for Fetch()

I got the entire code figured out.
I need to roll it into a function but its pretty slick. Just fill out the three variables and you have a solid query.
Order by and limit will be easy to add but for now I am very happy that it works.
My only concern and I’m sure it will come back and bite me is that I have two variables eg. $row[‘email’] (good) and $email (hmm).

Thanks for the help, appreciated. I have been reading a ton of information.

Take a look at Example #1 on PHP Manual’s page for Fetch()

I saw it but just want to enter data one time and have the “is,id,email” added automatically.
Cheers.


$from = 'members';

$select = 'id
, email
, password
, salt
, userlevel
';

$wherearr = array(username => $name
, userlevel => $userlevel
, email => $email
);

$i = 1;
$len = count($wherearr);
foreach ($wherearr as $key => $value) {
	if ($len == 1 || $len == $i) {
		$and = '';
	}
	else{
		$and = ' AND ';
	}

    if (is_numeric($value)) {
        $bind .= 'i';
    } else {
        $bind .= 's';
    }

	$where .= $key.'= ?'.$and;
	$i++;
}
array_unshift($wherearr, $bind);

$q = "SELECT $select FROM $from WHERE $where";
echo '<br>'.$q.'<br>';

$stmt = $mysqli->prepare($q);
call_user_func_array(array($stmt,'bind_param'),$wherearr);
$stmt->execute();
$stmt->store_result();

$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) { 
	$var = $field->name; 
	$$var = null; 
	$row[$var] = &$$var; 
}
call_user_func_array(array($stmt,'bind_result'),$row);

while ($stmt->fetch()){
	echo $row['email'];
}
	echo "<pre>final";
    print_r($row);
    echo "</pre>";

if($stmt->num_rows == 0) { // If the user exists
	echo 'got nothing';	
}
else{
	echo $email.' '.$salt.' got something '.$stmt->num_rows;

}