/** * Mastercook can produce concatenated XML files, and they may possibly have different encoding * So we need to split the input into separate XML chunks and process each separately */ private function mastercook() { $content = @file_get_contents($this->filePath); /** * Clean up whitespace */ $content = str_replace("\r", "\n", $content); $content = preg_replace('/\\n\\n+/', "\n", $content); $content = trim($content); $xml = array(); $nFiles = 1; $xml[0] = -1; while (($xml[] = strpos($content, '<?xml', $xml[$nFiles - 1] + 1)) !== false) { $nFiles++; } if ($nFiles < 2) { $this->result->error = "There are no recipes in this file"; return; } /** * Get each XML chunk */ $files = array(); for ($i = 1; $i < $nFiles; $i++) { $length = $xml[$i + 1] ? $xml[$i + 1] - $xml[$i] : strlen($content) - $xml[$i]; $files[] = substr($content, $xml[$i], $length); } $recipes = array(); /** * Process each xml chunk separately */ while (count($files) > 0) { $content = array_pop($files); /** * Get the encoding and remove the original XML tag * Not all mx2 files have an encoding specified - assume UTF-8 if none */ $endXML = strpos($content, '?>') + 2; $xmlString = substr($content, 0, $endXML); $content = substr($content, $endXML); if (preg_match('/(?:encoding="([^"]+)").*/i', $xmlString, $regs)) { $encoding = strtoupper($regs[1]); } else { $encoding = 'UTF-8'; } /** * Make a new XML tag that DOMDocument will accept * DOMDocument doesn't recognise some attributes that may be present in the original (e.g. standalone) */ $xmlString = "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>"; $dom = new EasyRecipePlusDOMDocument("", false); if (!@$dom->loadXML($xmlString . $content)) { $error = libxml_get_last_error(); $line = $error ? $error->line : 0; $msg = $error ? $error->message : "Unknown error"; $this->result->error = "Error on line {$line}: {$msg}"; continue; } $recipeElements = $dom->getElementsByTagName("RcpE"); if ($recipeElements->length == 0) { $this->result->error = "There are no recipes in this file"; continue; } foreach ($recipeElements as $recipe) { $recipes[] = $this->parseMastercookRecipe($recipe); } /** * Try to salvage some memory - this process is very memory intensive */ $content = null; $recipeElements = null; $dom = null; } $this->writeTemp($recipes); }