Undefined Offset? What does that mean?

Jaxel

Well-known member
I built a wiki-like template system onto my CMS. The way it works is actually pretty simple... If I put the following code into a page, it will replace it with the appropriate pre-defined template:
Code:
[template=charBig]
| name = Cassandra Alexandra
| debut = Soulcalibur II
| voiceE = Debra Jean Rogers
| voiceJ = Reiko Takagi
[/template]

The way it works, is when it is building the page, it sends the content of the page to a model:
Code:
<?php

class EWRporta_Model_Templates extends XenForo_Model
{
	public function parseTemplates($text)
	{
		$templates = $this->fetchAllKeyed("
			SELECT template_name AS name, template_content AS content
				FROM EWRporta_templates
		", 'name');

		$codePattern = '/\[template=([\w]+)\](.*?)\[\/template\]/si';
		$dataPattern = '/([\w\s]+)=(.+)/';

		if (preg_match_all($codePattern, $text, $codeMatches))
		{
			foreach ($codeMatches AS $key => $codeMatch)
			{
				if (isset($templates[$codeMatches[1][$key]]))
				{
					$matches = explode("|", $codeMatches[2][$key]);
					$replaceText = $templates[$codeMatches[1][$key]]['content'];

					foreach ($matches AS $match)
					{
						if (preg_match($dataPattern, $match, $dataMatch))
						{
							$replaceText = str_replace("{{{".trim($dataMatch[1])."}}}", trim($dataMatch[2]), $replaceText);
						}
					}

					echo $replaceText;

					$text = str_replace($codeMatches[0][$key], $replaceText, $text);					
				}
			}
		}

		return $text;
	}
}

Allow me to try to explain how this code works:
  1. parseTemplate recieves original content as $text
  2. database fetches existing templates and stores them into $templates, keyed by the name
  3. defines regular expression matching patterns
  4. if regular expression match collects any results in $codeMatches, continue
  5. for each result stored in the match, continue as $codeMatch
  6. if template['name of match'] actually exists, continue, otherwise ignore
  7. the rest is parsing of the results and replacement text, which I dont need to get into for this discussion. needless to say, I know it all works because "echo $replaceText" actually works and displays the proper results
This code works great, the replacement text is gathered correctly... and the system even echos the $replaceText out! However, the rest of XenForo then fails with the following error and trace stack:

Server Error​
Undefined offset: 2​
  1. XenForo_Application::handlePhpError() in EWRporta/Model/Templates.php at line 19
  2. EWRporta_Model_Templates->parseTemplates() in EWRporta/ControllerPublic/Index.php at line 104
  3. EWRporta_ControllerPublic_Index->actionPages() in XenForo/FrontController.php at line 303
  4. XenForo_FrontController->dispatch() in XenForo/FrontController.php at line 132
  5. XenForo_FrontController->run() in /home/eightway/public_xen1/index.php at line 15

Line 19 is the following code:
Code:
if (isset($templates[$codeMatches[1][$key]]));

However, like I said, I know there is nothing wrong with my code, since the IF does process correctly and it does then go onto ECHO which is within the IF, and the results of the echo are correct.
 
You are referring to an array element that does not exist. You should use array_key_exists() function instead of checking isset($template[$index-of-non-existing-element]).
 
g0rn, thats not the issue... even using array_key_exists(), I get the same error...

You can see that the function I wrote works by going here:
http://xen1.8wayrun.com/portal/cassandra

The replacement text is a table which was automatically generated at the top (the result of "echo $replaceText;"). But then the forum itself stops working. The function I wrote works fine, but then XenForo's php error handler claims there was an error is brings everything to a halt... even though there was no error.

On another note, in this case, isset() is preferred because its faster and there are no worries about NULL values.
 
Okay... I figured it out...
Code:
foreach ($codeMatches AS $key => $codeMatch)

Because each element in the $codeMatches array each had a sub array with 3 more elements... the foreach always assumed there were a total of 3 elements. For some reason foreach is iterating on itself down to the deepest nest, instead of the next. So I changed the code to:

Code:
foreach ($codeMatches[1] AS $key => $codeMatch)
 
Top Bottom