Problem in retrieving database entry for website registrants

I am a PHP newbie who has just studied Sitepoint’s ‘PHP & MySQL Novice to Ninja’ (5th Ed 2012) by Kevin Yank. I am trying to put it all into practice by building a member-only site.

My php code starts off by offering a login page with a link to a registration page. The registration page has a form of 9 fields in which visitors enter their personal information, which then writes the values to a single 9-column table in the database using a prepared statement. I want to be able to say, “You registered with the following details:…”, and then list them with perhaps the opportunity to edit any mistypes.

However I’ve hit a problem in trying to perform a retrieval of the entered values and present them back to the visitor after registration.
I am trying to use code similar to Kevin Yank’s in Chapter 4 with a SELECT database query to retrieve the values (he was retrieving rows of one field for many entries, I am retrieving all the fields for one row/entry for the most recent id entry), then using the query method to return a result set as a PDOStatement object ($results), which should contain all the fields for the last registrant. There is then a while loop and a call to the fetch method, which should return all the fields as an array called $regdetails. Then I direct to the output file (as an include) which should use a foreach loop to output the elements in the array.

However I keep getting an ‘undefined variable regdetails’ notice and an ‘invalid argument supplied for foreach’ for the following line every time it reaches the included output file.

<?php foreach ($regdetails as $item): ?>

Can anybody suggest where the problem might be, please?

I don’t know how did you got the PDOStatement object $regdetails,but I think you can try it like this:
$regdetails = $db->query(
“SELECT * FROM ‘your table name’ LIMIT 1”,
PDO::FETCH_ASSOC
);
foreach ($regdetails as $row) {
echo $row[‘column_0’];
echo $row[‘column_1’];
… //Insert other code here.
}

Could you please post the code that you’re using?

Hi SpacePhoenix. Yes here’s the code:


try
{
  $sql =  'SELECT firstname, lastname, jobtitle, organisation, country, landline, cellphone, email, password 
          FROM tablename   //substituted with real table name
          WHERE id = LAST_INSERT_ID ()';

  $results = $pdo->query($sql);
}
catch (PDOException $e)
{
  $output = 'Error fetching registration information:'.$e->getMessage();
  include 'output.html.php';
  exit();
}
while ($row = $results->fetch())
{
  $regdetails[] = array('firstname' => $row['firstname'],
  'lastname' => ['lastname'],
  'jobtitle' => ['jobtitle'],
  'organisation' => ['organisation'],
  'country' => ['country'],
  'landline' => ['landline'],
   'cellphone'=> ['cellphone'],
   'email' => ['email'],
   'password' => ['password']);
}

  include 'registrationdetails.html.php';

and then the include that should display is:


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Registration Details</title>
  </head>
  <body>
    <p>You are now registered with the following details:</p>
    <?php foreach ($regdetails as $item): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($item, ENT_QUOTES, 'UTF-8');?>
        </p>
      </blockquote>
    <?php endforeach; ?>
  </body>
</html>

Then I get the ‘undefined variable $regdetails…’ and an ‘invalid argument supplied for foreach…’ for the line <?php foreach ($regdetails as $item): ?>in the included file.

Thanks for the alternative code, blue_sky, although I’d like to understand what I’m doing wrong with my own code.

Well,I have found two problems in your code.
First,You have omitted the variable name here.

'lastname' => ['lastname'],
  'jobtitle' => ['jobtitle'],
  'organisation' => ['organisation'],
  'country' => ['country'],
  'landline' => ['landline'],
   'cellphone'=> ['cellphone'],
   'email' => ['email'],
   'password' => ['password']);

then,the variable ‘$item’ in

 <?php foreach ($regdetails as $item): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($item, ENT_QUOTES, 'UTF-8');?>
        </p>
      </blockquote>
    <?php endforeach; ?>

is an array type,You should use it like

<?php echo htmlspecialchars($item['firstname']); ?>

Hope this helpful for you.

I still don’t understand. My intention was to create an array variable called $regdetails with this:


{
  $regdetails[] = array('firstname' => $row['firstname'],
  'lastname' => ['lastname'],
  'jobtitle' => ['jobtitle'],
  'organisation' => ['organisation'],
  'country' => ['country'],
  'landline' => ['landline'],
   'cellphone'=> ['cellphone'],
   'email' => ['email'],
   'password' => ['password']);
}

and then to use foreach (in the included ‘regdetails.html.php’) on that array to pull out each element and output them one by one as a variable $item ($item is not intended itself to be an array)

What blue_sky is saying is that you’ve omitted the $row in most of your entries:


  $regdetails[] = array('firstname' => $row['firstname'],
  'lastname' => <HERE>['lastname'],
  'jobtitle' => <HERE>['jobtitle'],
  'organisation' => <HERE>['organisation'],
  'country' => <HERE>['country'],
  'landline' => <HERE>['landline'],
   'cellphone'=> <HERE>['cellphone'],
   'email' => <HERE>['email'],
   'password' => <HERE>['password']);
}

PHP has no idea what array you’re trying to reference in those locations, you have to tell it you mean $row.

The foreach is looping through each item, but each item is an array of values. so echoing $item will just return the word “Array” (thats what the array.toString method returns). If you want actual data from the array, you need to echo the piece of data you want ($item[‘name’] or whatever).

Thank you. I see now what was wrong with the creation of the $regdetails array variable. I have now changed this to:


while ($row = $results->fetch())
{
  $regdetails[] = array('firstname' => $row['firstname'],
  'lastname' => $row['lastname'],
  'jobtitle' => $row['jobtitle'],
  'organisation' => $row['organisation'],
  'country' => $row['country'],
  'landline' => $row['landline'],
   'cellphone'=> $row['cellphone'],
   'email' => $row['email'],
   'password' => $row['password']);
}

  include 'registrationdetails.html.php';

however the problem with ‘registrationdetails.html.php’ is still not clear to me, and I am still getting the same ‘undefined variable’ and ‘invalid argument supplied for foreach()’ notices, which both refer to the foreach line in:


<p>You are now registered with the following details:</p>
    <?php foreach ($regdetails as $item): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($item, ENT_QUOTES, 'UTF-8');?>
        </p>
      </blockquote>
    <?php endforeach; ?>

The intention is that foreach acts upon the $regdetails array to pull out each element one at a time as $item and echo them to create the list.

I’m confused because I modeled this on the database of jokes example in Kevin Yank’s Novice to Ninja book, Chapter 4:


// extract
while ($row = $result->fetch())
{
  $jokes[] = array('id' => $row['id'],
  'text' => $row['joketext'],
  'name' => $row['name'],
   'email' => $row['email']);
}

include 'jokes.html.php';


followed by jokes.html.php:


// extract
<p>Here are all the jokes in the database:</p>
    <?php foreach ($jokes as $joke): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($joke, ENT_QUOTES, 'UTF-8'); ?>
        </p>
      </blockquote>
    <?php endforeach; ?>

Incidentally I don’t understand the ‘array.toString’ reference because I’ve never come across that.

This appears correct.

however the problem with ‘registrationdetails.html.php’ is still not clear to me, and I am still getting the same ‘undefined variable’ and ‘invalid argument supplied for foreach()’ notices, which both refer to the foreach line in:


<p>You are now registered with the following details:</p>
    <?php foreach ($regdetails as $item): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($item, ENT_QUOTES, 'UTF-8');?>
        </p>
      </blockquote>
    <?php endforeach; ?>

The intention is that foreach acts upon the $regdetails array to pull out each element one at a time as $item and echo them to create the list.

This implies that the regdetails array is nonexistant. are you certain that your query is returning results? (Returning 0 results is not an error, so it wont be caught by try-catch exception handling!)

var_dump($regdetails) right before you do your foreach, that will tell you what PHP thinks is in the regdetails array (or if it even exists).

Incidentally I don’t understand the ‘array.toString’ reference because I’ve never come across that.

.toString (or __toString) is a magical function that automatically gets called whenever you try and echo an object. It basically asks the object “What should your string representation be?”. In the case of arrays, the answer received is always “Array”, regardless of the contents of said array.

For getting the details of the registered people that the query found you could use PDO’s fetchall method.

Thanks Star Lion,

Having inserted var_dump($regdetails) into the code directly before foreach I now get ‘syntax error, unexpected ‘foreach’ (T_FOREACH)’ instead of the previous notices. Therefore I reckon that the variable doesn’t exist, as you say. Here’s the code where the trouble must lie (it must be here because I know that the previous code is writing entries to the database successfully):


try
{
  $sql =  'SELECT firstname, lastname, jobtitle, organisation, country, landline, cellphone, email, password 
          FROM table name                                                                                                                                    // table name substituted here
          WHERE id = LAST_INSERT_ID ()';

  $results = $pdo->query($sql);
}
catch (PDOException $e)
{
  $output = 'Error fetching registration information:'.$e->getMessage();
  include 'output.html.php';
  exit();
}
while ($row = $results->fetch())
{
  $regdetails[] = array('firstname' => $row['firstname'],
  'lastname' => $row['lastname'],
  'jobtitle' => $row['jobtitle'],
  'organisation' => $row['organisation'],
  'country' => $row['country'],
  'landline' => $row['landline'],
   'cellphone'=> $row['cellphone'],
   'email' => $row['email'],
   'password' => $row['password']);
}

  include 'registrationdetails.html.php';

I tried substituting LAST_INSERT_ID() for 7 which is an id number that I know exists…this resulted in some improvement…I now get 'Warning: htmlspecialchars() expects parameter 1 to be string, array given in // path to the include '.

I tried substituting LAST_INSERT_ID() for 7 which is an id number that I know exists…this resulted in some improvement…I now get 'Warning: htmlspecialchars() expects parameter 1 to be string, array given in // path to the include '.

Because the regdetails is a multidimensional array,so when you use foreach (in the included ‘regdetails.html.php’) on the array to pull out each element, each element is an array type too(eg. $item).There are some mistakes in you reference code.


    <?php foreach ($regdetails as $item): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($item, ENT_QUOTES, 'UTF-8');?>
        </p>
      </blockquote>
    <?php endforeach; ?>

If you want to output $item,you must do it like this,

<?php echo htmlspecialchars($item['firstname'], ENT_QUOTES, 'UTF-8');?>
<?php echo htmlspecialchars($item['lastname'], ENT_QUOTES, 'UTF-8');?>
... //and so on

actually that means you forgot the semicolon on the end of the var_dump line.

Or you could nest another foreach inside the outer one if you didn’t want to hard-code the key names.

StarLion

Okay, thanks, I put the semicolon in and with WHERE id = 7 in the sql query (an entry that I am certain exists) I got confirmation via var_dump($regdetails) that the $regdetails variable existed as an array with details from the id 7 entry.
I also got the “htmlspecialchars expects parameter 1 to be string…” error message,

However I tried again with WHERE id = LAST_INSERT_ID() and it came back with ‘undefined variable’ again, as well as ‘invalid argument for foreach()’

LAST_INSERT_ID() seems valid, so I’m puzzled why it isn’t producing a variable like id=7 does.

I’m using MAMP for my offline development, and after executing the script I can only make the new entry appear in the database by clicking ‘refresh’ for the table in phpmyadmin, but at least I know it is being written to the database.

I don’t understand why I can seem to retrieve a numbered id but not the latest id.

blue_sky and Mittineague

Thanks for the comments about the foreach method. Kevin Yank uses foreach to loop through his array, rather then specifying each element’s index in his example in the manual. This is his code that I’m trying to replicate:


<p>Here are all the jokes in the database:</p>
    <?php foreach ($jokes as $joke): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($joke, ENT_QUOTES, 'UTF-8'); ?>
        </p>

I’m open to different ways of doing things, but having studied Yank’s manual I want to make that approach work and prove to myself that I’ve understood it.

I think you should learn more about the PHP data type and the usage of the basics PHP method(eg. foreach).You can read more details from PHP manual.
If your code is a complete copy from Yank’s manual,I think his code has some errors.You can try to run the Yank’s code if you can’t agree with me.
At last,I have noticed that there was a redundant space within the function LAST_INSERT_ID().

 $sql =  'SELECT firstname, lastname, jobtitle, organisation, country, landline, cellphone, email, password 
          FROM tablename   //substituted with real table name
          WHERE id = [COLOR="#FF0000"]LAST_INSERT_ID ()[/COLOR]';

I’m not sure whether it brings affect or not,because I don’t have a test.You can remove that space and try it again.Good luck.

Is there an autoincrementing field in the table? Otherwise the query will be rejected.

You can also achieve this effect with ORDER BY <id field> DESC LIMIT 1.

Hi StarLion, Yes the id field is definitely auto-incrementing. I’ve checked in phpmyadmin. The new database entries are being written successfully each time, with an incrementing id number. If I specify an id then it creates an array, as proven with the var_dump command, (but the foreach problem still remains). Using LAST_INSERT_ID() doesn’t produce an array, but substituting that term with an existant id number does.


try
{
  $sql =  'SELECT firstname, lastname, jobtitle, organisation, country, landline, cellphone, email, password 
          FROM tablename                                  //substituted with the real table name
          WHERE id = LAST_INSERT_ID()';

  $results = $pdo->query($sql);
}
catch (PDOException $e)
{
  $output = 'Error fetching registration information:'.$e->getMessage();
  include 'output.html.php';
  exit();
}
while ($row = $results->fetch())
{
  $regdetails[] = array('firstname' => $row['firstname'],
  'lastname' => $row['lastname'],
  'jobtitle' => $row['jobtitle'],
  'organisation' => $row['organisation'],
  'country' => $row['country'],
  'landline' => $row['landline'],
   'cellphone'=> $row['cellphone'],
   'email' => $row['email'],
   'password' => $row['password']);
}

  include 'registrationdetails.html.php';

followed by


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Registration Details</title>
  </head>
  <body>
    <p>You are now registered with the following details:</p>
    <?php var_dump($regdetails);
foreach ($regdetails as $item): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($item, ENT_QUOTES, 'UTF-8');?>
        </p>
      </blockquote>
    <?php endforeach; ?>
  </body>
</html>

Hi blue_sky, Sorry for quoting incorrectly with that redundant space. The code I am testing with now doesn’t have that space, so that it isn’t the problem. Yank’s code definitely works as I can run it and produce the list of jokes. My own code is very similar, but I have changed the names of the variables. He isn’t specifying the array indexes when outputting, but he is able to use a single foreach command to loop through the array and output the elements as a list.


try
{
  $sql = 'SELECT joke.id, joketext, name, email
   FROM joke inner join author
   on authorid = author.id';
  $result = $pdo->query($sql);
}
catch (PDOException $e)
{
  $error = 'Error fetching jokes: ' . $e->getMessage();
  include 'error.html.php';
  exit();
}

while ($row = $result->fetch())
{
  $jokes[] = array('id' => $row['id'],
  'text' => $row['joketext'],
  'name' => $row['name'],
   'email' => $row['email']);
}

include 'jokes.html.php';

followed by


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>List of Jokes</title>
  </head>
  <body>
    <p>Here are all the jokes in the database:</p>
    <?php foreach ($jokes as $joke): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($joke, ENT_QUOTES, 'UTF-8'); ?>
        </p>
      </blockquote>
    <?php endforeach; ?>
  </body>
</html>

Sorry, these are real puzzlers, aren’t they?


  $result = $pdo->query($sql);

=>


  $result = $pdo->query($sql);
  print_r($result->errorInfo());

Thanks, StarLion
The variable is actually $results and not $result.
Okay, having inserted the print_r($results->errorInfo()); line the code following a db connection is now:


try
{
  $sql =  'SELECT firstname, lastname, jobtitle, organisation, country, landline, cellphone, email, password 
          FROM tablename                                //sustituting the relevant table name
          WHERE id = LAST_INSERT_ID()';     //OR WHERE id = 85 in second example

  $results = $pdo->query($sql);
  print_r($results->errorInfo());
}
catch (PDOException $e)
{
  $output = 'Error fetching registration information:'.$e->getMessage();
  include 'output.html.php';
  exit();
}
while ($row = $results->fetch())
{
  $regdetails[] = array('firstname' => $row['firstname'],
  'lastname' => $row['lastname'],
  'jobtitle' => $row['jobtitle'],
  'organisation' => $row['organisation'],
  'country' => $row['country'],
  'landline' => $row['landline'],
   'cellphone'=> $row['cellphone'],
   'email' => $row['email'],
   'password' => $row['password']);
}

  include 'registrationdetails.html.php';

along with the include:


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Registration Details</title>
  </head>
  <body>
    <p>You are now registered with the following details:</p>
    <?php var_dump($regdetails);
foreach ($regdetails as $item): ?>
      <blockquote>
        <p>
          <?php echo htmlspecialchars($item, ENT_QUOTES, 'UTF-8');?>
        </p>
      </blockquote>
    <?php endforeach; ?>
  </body>
</html>

Running the code with LAST_INSERT_ID() gives:

Array ( [0] => 00000 [1] => [2] => )

You are now registered with the following details:

Notice: Undefined variable: regdetails in //pathway to the foreach line
NULL
Notice: Undefined variable: regdetails in //pathway to the foreach line
Warning: Invalid argument supplied for foreach() in //pathway to the foreach line

However running the code with WHERE id = 85 //(this is an id for an existent example entry in the db) gives:

Array ( [0] => 00000 [1] => [2] => )

You are now registered with the following details:
array(1) { [0]=> array(9) { [“firstname”]=> string(4) “Fred” [“lastname”]=> string(6) “Bloggs” [“jobtitle”]=> string(6) “Editor” [“organisation”]=> string(12) “Daily Gossip” [“country”]=> string(2) “UK” [“landline”]=> string(13) “0111 222 3333” [“cellphone”]=> string(13) “07777 888 999” [“email”]=> string(18) “fred@blahblah.blah” [“password”]=> string(8) “********” } }

Warning: htmlspecialchars() expects parameter 1 to be string, array given in      //the pathway to that line