Alex: strpos EOF Problem

Hallo,

ich hoffe auf Hilfe bei einem Problem mit der strpos Funktion in php.
Ich versuche per PHP eine xml-Datei einzulesen (file_get_contents) und dann aus deren Inhalt (der einen HTML-ähnlichen Aufbau hat) alle Tabellen nach bestimmten Markern (z.B: <Tablelle>Ihnalt</Tabelle>) auszulesen, einige Einfügungen und Ersetzungen durchzuführen und das Ganze dann in eine neue xml-Datei zu speichern.
Dabei verwende ich die strpos-Funktion um den Inhalt der xml Blockweise abzuarbeiten bzw. die Tabellenelemente auszulesen.
Das Problem ist nun, dass strpos dabei in einer for-Schleife laufen muss.

Nun hat sich das Script immer aufgehängt. Mit einigen Versuchen konnte ich feststellen, dass strpos das Ende der XML-Datei bzw. des Content-Strings (EOF) nicht erkennt (https://bugs.php.net/bug.php?id=25781).

Ich habe nun versucht das Script abzubrechen indem ich am Ende und am Anfang der for-Schleife prüfe ob ich über EOF hinaus wieder am Anfang des Content-Strings angelangt bin. Ich erhalte aber immernoch aus einer 120 KB Quelldatei eine 10 MB Ausgabedatei. Ich hoffe es kann mir jemand hierzu einen Rat geben.

Hier ein Beispielcode:

  
<?php  
  
/*  
In $xml_content stehen Elemente wie:  
<Tabelle tag="100" anderertag="20">Inhalt</Tabelle>  
*/  
function makeNewXML($xml_content){  
  
// die Länge des Content-Strings  
$imaxxml = strlen($xml_content);  
  
$istop = 0;  
$lastj = -1;  
$j=0;  
  
for($j=0;$j<$imaxxml;$j++){  
		  
		// echo $j." ".$imaxxml."\r\n";  
		if($lastj > $j){  
		break;  
		}  
		$lastj = $j;  
		  
	$findatable = strpos($xml_content,"<Tabelle",$istop);  
	  
	if($findatable !== false){  // Tabelle gefunden  
			  
			$istart = $findatable;  
			$iendtag = strpos($xml_content,">",$istart); 					  
			$string = substr($xml_content,$istart,$iendtag-$istart); 		  
  
			$newXMLContent .= substr($xml_content,$istop,$istart-$istop); // Das XML vor der gefunden Tabelle übernehmen	  
			$istop = strpos($xml_content,"</Tabelle>",$istart)+strlen("</Tabelle>"); 	  
			  
			  
			// hier folgt dann das Auswerten und Umformen dieser Tabelle  
			// ...  
			// ...  
			$j = $istop;  
			  
	}else{ // keine Tabelle gefunden  
	  
		$newXMLContent .= substr($xml_content,$istop,$imaxxml-$istop); // den Rest des XML mitnehmen  
		$j = $imaxxml; // break		  
		  
	}  
  
}  
  
return $newXMLContent;  
  
};  
  
?>  

Vielen Dank für die Hilfe,
Alex

  1. Hallo nachmal,

    ich konnte das Problem selbst lösen. Eigentlich simpel.

    Ich prüfe jetzt am Anfang der for-Schleife ob das <root>-Element des XML im aktuell ausgelesenen xml-Teilcontent vorkommt. Wenn es zum zweiten Mal vorkommt, beende ich die Funktion bzw. gehe direkt zum return ...

    Viele Grüße
    Alex

  2. Tach!

    Ich versuche per PHP eine xml-Datei einzulesen (file_get_contents) und dann aus deren Inhalt [etwas] auszulesen, einige Einfügungen und Ersetzungen durchzuführen und das Ganze dann in eine neue xml-Datei zu speichern.

    Nun, zunächst hast du nach dem file_get_contents() nur noch einen String vorliegen und keine Datei. Also liest du im Folgenden aus dem String und nicht aus einer Datei.

    Mit einigen Versuchen konnte ich feststellen, dass strpos das Ende der XML-Datei bzw. des Content-Strings (EOF) nicht erkennt (https://bugs.php.net/bug.php?id=25781).

    Da du strpos nicht auf eine Datei anwendeun kannst sondern nur auf Strings, kann das Ende einer Datei keine Rolle spielen. In dem Bug-Report wird es auch nur auf Strings angewendet. Der dortige Fehler ist, dass beim Erhöhen von $my_position anschließend nicht geprüft wird, ob tatsächlich im Array ein Eintrag unter $file_line[$my_position] existiert. Bei E_ALL gesetztem error_reporting sollte dieser Zugriff ins Nichts gemeldet werden. Das "Nichts" wird von PHP als Leerstring angesehen und strpos() findet darin nichts, weswegen das Ergebnis false ist und nun die Schleife endlos läuft. Die Abbruchbedingung beziehungsweise der Programmablauf an sich muss also mindestens noch die Existenz des $file_line-Eintrags berücksichtigen.

    Ich habe nun versucht das Script abzubrechen indem ich am Ende und am Anfang der for-Schleife prüfe ob ich über EOF hinaus wieder am Anfang des Content-Strings angelangt bin. Ich erhalte aber immernoch aus einer 120 KB Quelldatei eine 10 MB Ausgabedatei. Ich hoffe es kann mir jemand hierzu einen Rat geben.

    Auf den ersten Blick sehe ich den Fehler in deinem Code nicht. Mein allgemeiner Rat ist, error_reporting auf E_ALL (und display_errors auf on) zu stellen und etwaige Meldungen zu beachten. Der zweite Rat ist, prüfe mit Kontrollausgaben (und vielleicht einer ganz kurzen Datei, bei der der Fehler auch auftritt), an welcher Stelle Wunsch und Wirklichkeit auseinanderlaufen. Damit lassen sich noch am ehesten logische Fehler im Ablauf eingrenzen. Und der dritte Rat ist, kommentiere deinen Code in der Form, dass du hinschreibst, was du bezweckst. Was der Code tut, sieh man ja aus ihm, nur nicht, was er eigentlich tun soll.

    dedlfix.