We help IT Professionals succeed at work.

PHP Coding - Undefined Variable error

Wanda Marston
on
High Priority
166 Views
Last Modified: 2019-10-29
I am getting this message with the following code:

"Undefined variable: id"

if (array_key_exists("id",$_POST)) $id = mysqli_real_escape_string($db,$_POST['id']);

$q = "SELECT notices.users_id, notices.organization, notices.amount, notices.currency, notices.timeframe, notices.location, notices.description, users.email FROM notices INNER JOIN users ON notices.users_id =users. id WHERE notices.id=$id" ;

Open in new window

Comment
Watch Question

gr8gonzoConsultant
CERTIFIED EXPERT

Commented:
This code:
if(condition) 
line of code #1
line of code #2

Open in new window


...is the same as this:
if(condition) 
{
    line of code #1
}
line of code #2

Open in new window


Basically, when you leave out the { } braces, then PHP assumes the condition only applies for the next line of code. So this code:

if (array_key_exists("id",$_POST)) $id = mysqli_real_escape_string($db,$_POST['id']);

$q = "SELECT notices.users_id, notices.organization, notices.amount, notices.currency, notices.timeframe, notices.location, notices.description, users.email FROM notices INNER JOIN users ON notices.users_id =users. id WHERE notices.id=$id"

Open in new window


...actually executes like this:
if (array_key_exists("id",$_POST))
{
    $id = mysqli_real_escape_string($db,$_POST['id']);
}

$q = "SELECT notices.users_id, notices.organization, notices.amount, notices.currency, notices.timeframe, notices.location, notices.description, users.email FROM notices INNER JOIN users ON notices.users_id =users. id WHERE notices.id=$id"

Open in new window


That said, if $_POST does NOT contain an "id" value, then the $id variable will never be set. So in that scenario, when you go and try to use $id in your $q variable, it's telling you that the variable doesn't exist.
Dave BaldwinFixer of Problems
CERTIFIED EXPERT
Most Valuable Expert 2014

Commented:
Also you have a extra space in this section:

notices.users_id =users. id

Open in new window

CERTIFIED EXPERT
Most Valuable Expert 2017
Distinguished Expert 2019
Commented:
Suggestion: Use prepared statement instead
(My preference is PDO as it makes binding much easier - but here is a mysqli version)
$id = isset($_POST['id']) ? $id : false; 
if ($id) {
   $query = <<< QUERY
SELECT notices.users_id, notices.organization, notices.amount, notices.currency, notices.timeframe, notices.location, notices.description, users.email 
FROM notices INNER JOIN users ON notices.users_id =users. id
WHERE notices.id=?
QUERY;
    $stmt = mysqli_prepare($db, $query);
    // Assumes id is numeric - if not change "d" to "s"
    mysqli_stmt_bind_param($stmt, "d", $id);
    mysqli_stmt_execute($stmt);
    $stmt->bind_result($user_id, $organization, $amount, $currency, $timeframe, $location, $description, $email);
    while (mysqli_stmt_fetch($stmt)) {
      /// 
    }
}

Open in new window


With PDO - much easier
$id = isset($_POST['id']) ? $id : false; 
if ($id) {
   $query = <<< QUERY
SELECT notices.users_id, notices.organization, notices.amount, notices.currency, notices.timeframe, notices.location, notices.description, users.email 
FROM notices INNER JOIN users ON notices.users_id =users. id
WHERE notices.id=?
QUERY;
  $stmt = $pdo->prepare($query);
  $stmt->execute([$id]);
  $rows = $stmt->fetchAll(PDO::FETCH_OBJ);
}

Open in new window


UPDATE: Fixed spelling error in query ('F missing from FROM')

UPDATE2: The first line of the above to scripts is incorrect. It should be
$id = isset($_POST['id']) ? $_POST['id'] : false

Open in new window

Thanks to Chris for pointing it out
Wanda MarstonCreative Director

Author

Commented:
Thanks. The above PDO coding works (there is an F missing from in front of ROM) but none of the information shows up.

// Create the form:
echo '<form action="ContactPoster.php" method="post">

<p>Company: ' . $row[1] . '</p>

<p>Amount: ' . $row[2] . '</p>

<p>Currency: ' . $row[3] . '</p>
		
<p>Timeframe: ' . $row[4] . '</p>

<p>Location: ' . $row[5] . '</p>

<p>Description: ' . $row[6] . '</p>

<input type="hidden" name="toemail" value="'.$row[7].' " >';

?>

Open in new window

CERTIFIED EXPERT
Most Valuable Expert 2017
Distinguished Expert 2019

Commented:
Thanks for the note on the spelling error - I have fixed.

If you are only fetching one row then you can simply do this on line 10 of the second listing

 $row = $stmt->fetch(PDO::FETCH_OBJ);

Open in new window


The code in my post uses fetchAll which will return an array of records - so either use the above fetch() or reference the first element in the array

$rows[0]

Also you are using numeric indices in your code

$row[1], $row[2] etc

In my example I supplied the PDO::FETCH_OBJ which means $rows is an array of objects - not arrays.

Option 1 - use object notation (assuming you used fetch and not fetchAll)
$row->organization (instead of $row[1])
$row->amount (instead of $row[2])

Open in new window

If using fetchAll then
$rows[0]->organization;

Open in new window


If you don't want to use object notation then you must change the fetch style attribute in your fetch

$row = $db->fetch(); // same as $db->fetch(PDO::FETCH_BOTH);

Open in new window


This will return an array that contains both numeric indices (zero based) and associative names.

You can then use $row[1] as you have it in your code. [Personally I prefer the object notation - it is more expressive than numeric indicies and neater than associative array]

You can read more about this here https://www.php.net/manual/en/pdostatement.fetch.php
gr8gonzoConsultant
CERTIFIED EXPERT

Commented:
If there are follow-up questions about how to use PDO, they should probably go into another question. The original question was answered right away and the conversation is veering more into questions about the PDO suggestion (which is a good one, don't get me wrong).
Wanda MarstonCreative Director

Author

Commented:
Yes, I wondered about that. Sometimes the solution for a question in itself will trigger another question. Also, Experts Exchange and changed their way of doing things about three times since I joined and now I am paying on a monthly basis.

BUT I don't have any problem with entering another question. I can see how that would be a problem with the people that are answering.

Thanks
gr8gonzoConsultant
CERTIFIED EXPERT

Commented:
To me, it's mostly for the benefit of others later on. If one person asks a question, then there are probably 10 or 100 other people out there who will eventually have the same type of question. But if they don't see the question being asked near the top of the page, they might leave instead of reading through the page.

So by separating follow-up questions into their own questions, it usually just helps others who have those same questions. :)
Wanda MarstonCreative Director

Author

Commented:
Yes, didn't think of that. The information should be easy and straight forward to obtain.
gr8gonzoConsultant
CERTIFIED EXPERT

Commented:
Is there a reason you selected Julian's comment as the answer? I provided you with the answer and the explanation to your original question...
Wanda MarstonCreative Director

Author

Commented:
gr8gonzo - I tried your code a few times and it just wasn't working.

The code I posted was used several times on other sites and there was never any problem. This time, for some reason I was getting that error message.

With Julian's code the error messages were gone. BUT the information was not showing up which is why I though that this was really a two part question as I am getting the data but I need to know that I can display it.
gr8gonzoConsultant
CERTIFIED EXPERT

Commented:
The code I showed you wasn't a fix (nor was it intended to be a fix), because the root problem isn't in the code itself. The code I showed you was just explaining why you were getting the error. The technical reason here is very straightforward. The root cause for all of it is what I explained at the end of my first comment:

That said, if $_POST does NOT contain an "id" value, then the $id variable will never be set.

If you don't POST an ID value, then you won't get any data, regardless of which option you go with. The answer you selected won't actually fix the root problem - it just wraps the query code so you don't see an error (which is still a good thing). The problem is still that you're not sending over an ID value. Without doing that, there is no code that will fix the problem.

You could keep the code you originally had and it would work -IF- you sent over an ID value to this script.

Think of it this way - you are sent by your boss to go pull a special folder from the filing cabinets in the basement. He doesn't tell you which folder it is, though, but still sends you on your way. So you arrive in the basement and you ask the filing guy, "Hey, can you give me the folder labeled..." and then you stop. The guy looks at you for a moment and asks, "Which file?" You say, "I don't know! My boss never told me!"

That's what's happening here. The browser is getting to this script/page but it is getting there without a POST-ed ID value, so when you go to try and put together a query using that value, PHP is yelling, "I don't know what ID you're talking about!"

If you wrap all of the code in an if() block, then it's like you are getting to the basement but since you still don't have the folder name, you just don't even bother talking to the filing guy. Instead, you just stand there silent for a moment, then turn around and leave. So there's no yelling, but you're still not getting the folder your boss wants.

So the ONLY way to fix it is for your boss to send you WITH the name of the folder he wants.

So in terms of PHP, you have to look at the originating script and figure out why it's not sending over the ID value.

Explore More ContentExplore courses, solutions, and other research materials related to this topic.