user3918443 user3918443 - 1 month ago 13
PHP Question

associative array to string conversion issue

First off when answering please try and explain simply as possible as I am fairly new to php. Anyway my problem is is that I do not understand why my associative array to string conversion is not working. I am basically using the same model as described here: PHP 5 arrays Scroll down to see example for associative arrays. Anyway the output I always get is this when I submit "Adam" into the textbox:

Notice: Undefined index:
queryStr in C:\xampp\htdocs\practice\src\fetchigndatausingpdo.php on line 24
PID = 80 = 8 AND FirstName = adam AND 1 = adam AND LastName = preston AND 2 = preston AND Age = 17 AND 3 = 17 AND

Below is the code if you have any suggestions please notify me, thankyou :). Also $user and $pass have been deliberately blanked for security reasons.

<form action="fetchigndatausingpdo.php" method="post">
<input type="text" name="name">
<input type="submit" name="submit" value="submit">
</form>

<?php

$user = "adam";
$pass = "**********";


if(isset($_POST['name'])){
try{
$dbh = new PDO('mysql:host=localhost;dbname=my_db', $user, $pass, array(PDO::ATTR_PERSISTENT=>true));

$stmt = $dbh->prepare("SELECT * FROM persons WHERE FirstName LIKE ?");
$stmt->execute(array($_POST['name']));
if($stmt->rowCount() > 0){
$result = $stmt->fetchAll();
$terms = count($result);
foreach($result as $person){
foreach ($person AS $field => $value){
$terms--;
$GLOBALS['queryStr'].= $field.' = '.$value;
if($terms){
$GLOBALS['queryStr'].=' AND ';
}
}
}
echo $queryStr;
}

}catch(PDOException $e){
echo $e->getMessage();
}
}

?>

Answer

If you will be only receiving exactly one row from your query, you can change your $result = $stmt->fetchAll(); row to use the fetch() method of your database handler instead. That will give you exactly one array for your $result variable. That way, you'll like not have to make any further changes.

Change is required, because fetchAll() will put arrays into your $result variable (even if there's only one result). If you don't change the fetchAll() to fetch(), then you could try changing your foreach($result as $field => $value){ and below part to something like this:

..
foreach($result as $person){
    foreach ($person AS $field => $value){
         $terms--;
        $GLOBALS['queryStr'].= $field.' = '.$value;
        if($terms){
            $GLOBALS['queryStr'].=' AND ';
        }
        echo $queryStr;
    }        
}
..

Please elaborate if this is the desired effect.

Some additional comments on the code:

You are already using the PDO library and its prepare method for efficient and safe use of queries. As you are using parameterbinding, it is not necessary to do manual sanitization of the received data, as PDO will handle that for you. Talking about this line here:

$name = mysql_real_escape_string($_POST['name']);

and this one:

$stmt->execute(array($name))

You could change the execute part to

$stmt->execute(array($_POST['name']))

instead. Also, regular way of checking if any results were returned when using PDO would be the rowCount() method of the statement you're executing. PDO would return true even if there weren't any matches in your query resultset. The above all combined, you would have that part of your code look like this:

..

if(isset($_POST['name'])){
    try{
        $dbh = new PDO('mysql:host=localhost;dbname=my_db', $user, $pass, array(PDO::ATTR_PERSISTENT=>true));

        $stmt = $dbh->prepare("SELECT * FROM persons WHERE FirstName LIKE ?");
        $stmt->execute(array($_POST['name']));
        $resultsSize = $stmt->rowCount();
        if($resultsSize > 0){
            $queryStr = '';

            $result = $stmt->fetchAll();
            foreach($result as $person){
                $terms  = sizeof(array_keys($person));    
                foreach ($person AS $field => $value){
                    $terms--;
                    $queryStr .= $field.' = '.$value;
                    if($terms){
                        $queryStr .=' AND ';
                    }
                $queryStr .= '<br/>'; // easier HTML visual evaluation
               }        
            }
            echo $queryStr;
        }

    }catch(PDOException $e){
        echo $e->getMessage();
    }
}

With the above refactoring (you are first checking if the $_POST['name'] is set) you are avoiding the extra resources allocated to the database connection (even if you are not using it). Putting your connection initialization along with your other executed code is not a problem in this case, you're good with one catch block handling your errors (as in this case they would be of similar nature, either problematic connection to the database.

Changes made to the query: when comparing string values, the equals sign (=) would result in a byte-by-byte comparison for exact value, while the LIKE operator would give the advantage of not stumbling upon any encoding fancyness - and using LIKE is the normally accepted way of comparing string values (also, with LIKE you could make use of wildcards (% character, etc.)).

**Edit:

I've updated the above code based on your comment - I've also moved the output of the string after the outer foreach loop (so it will print when all of the returned rows have been processed). I've changed your variable from the $GLOBALS superglobal variable to a local one (current context doesn't imply you would need access to it outside this file or page generation, if so, look into the possibility of using the $_SESSION variable).

Comments