Recently, I was working on a game project where I needed to fetch quests from an XML database using PHP. Everything seemed to work fine until I realized the script only fetched data when the ID was “1”. Any other quest ID, like 2 or 3? The script just fell silent and threw annoying Undefined variable
notices.
So, I rolled up my sleeves, dove into the code, and here’s how I fixed it (and improved it). If you’re stuck with a similar issue, I hope this walk-through helps.
The Buggy Code I Started With
Here’s the original snippet I was using:
<?php
$xmlStringFile = '<?xml version="1.0" standalone="yes"?>
<quests>
<quest id="1">
<ID>1</ID>
<QUEST>Katakomby pod městem</QUEST>
<INFO>Asi nevÃte že pod naÅ¡Ãm krásným mÄ›stem je spousta tajných chodem...</INFO>
<TIME>780</TIME>
<ITEMS1></ITEMS1>
<XPMIN>180</XPMIN>
<MONEY>800</MONEY>
<LVL>1</LVL>
</quest>
<quest id="2">
<ID>2</ID>
<QUEST>Oprava zÅ™Ãceného mostu</QUEST>
<INFO>Před několika dny strhla záplava starý dřevěný most u radnice...</INFO>
<TIME>7200</TIME>
<ITEMS1></ITEMS1>
<XPMIN>250</XPMIN>
<MONEY>250</MONEY>
<LVL>4</LVL>
</quest>
</quests>';
$quests = new SimpleXMLElement($xmlStringFile);
// This only matches the FIRST <quest>, i.e., id="1"
if($_GET['quest'] == $quests->quest["id"]){
$quest2 = $quests->quest->QUEST;
$info_quest = $quests->quest->INFO;
$time_end = $quests->quest->TIME;
}
// Throws "Undefined variable" if condition is not met
echo $_GET['quest'] . $quest2 . $info_quest . $time_end;
?>
What Went Wrong
The line $quests->quest["id"]
is the core problem. It only accesses the first <quest>
element in the XML. So when I passed ?quest=2
via the URL, PHP didn’t find a match, the if
block didn’t run, and the variables weren’t initialized. That led to this classic PHP warning:
Notice: Undefined variable: quest2
Notice: Undefined variable: info_quest
Notice: Undefined variable: time_end
The Fix and Improve Version
Here’s the code I rewrote to loop through each <quest>
and find the one that matches the requested ID:
<?php
$xmlStringFile = '<?xml version="1.0" standalone="yes"?>
<quests>
<quest id="1">
<ID>1</ID>
<QUEST>Katakomby pod městem</QUEST>
<INFO>Asi nevÃte že pod naÅ¡Ãm krásným mÄ›stem je spousta tajných chodem...</INFO>
<TIME>780</TIME>
<ITEMS1></ITEMS1>
<XPMIN>180</XPMIN>
<MONEY>800</MONEY>
<LVL>1</LVL>
</quest>
<quest id="2">
<ID>2</ID>
<QUEST>Oprava zÅ™Ãceného mostu</QUEST>
<INFO>Před několika dny strhla záplava starý dřevěný most u radnice...</INFO>
<TIME>7200</TIME>
<ITEMS1></ITEMS1>
<XPMIN>250</XPMIN>
<MONEY>250</MONEY>
<LVL>4</LVL>
</quest>
</quests>';
$quests = new SimpleXMLElement($xmlStringFile);
$questId = $_GET['quest'] ?? null;
$found = false;
foreach ($quests->quest as $quest) {
if ((string)$quest['id'] === $questId) {
$quest2 = $quest->QUEST;
$info_quest = $quest->INFO;
$time_end = $quest->TIME;
$found = true;
break;
}
}
if ($found) {
echo "<h3>Quest ID: $questId</h3>";
echo "<p><strong>Quest:</strong> $quest2</p>";
echo "<p><strong>Info:</strong> $info_quest</p>";
echo "<p><strong>Time:</strong> $time_end seconds</p>";
} else {
echo " Quest with ID $questId not found.";
}
?>
And just like that problem solve.
Bonus Additional Feature I Added
While I was at it, I added a few more features for better usability and testing.
List All Quests
Now I can see which quests are available at any time:
echo "<h2>Available Quests</h2><ul>";
foreach ($quests->quest as $q) {
echo "<li><a href='?quest=" . $q['id'] . "'>Quest " . $q['id'] . ": " . $q->QUEST . "</a></li>";
}
echo "</ul>";
Display All Quest Details
And to make the interface friendlier, I included a detailed list of all quests:
echo "<hr><h3>All Quest Details</h3>";
foreach ($quests->quest as $q) {
echo "<div style='border:1px solid #ccc; margin-bottom:10px; padding:10px;'>";
echo "<h4>" . $q->QUEST . "</h4>";
echo "<p>" . $q->INFO . "</p>";
echo "<small>XP: {$q->XPMIN}, Money: {$q->MONEY}, Level: {$q->LVL}</small>";
echo "</div>";
}
Final Thought
If your PHP script only retrieves the first record from an XML file, chances are you’re mistakenly treating a collection of elements as a single object. To handle multiple XML nodes correctly, always use a foreach
loop to iterate through the child elements. It’s also crucial to validate that your data exists before trying to use it this helps avoid undefined variable notices that often point to deeper logic issues.