Deaktivieren Sie Warnungen, wenn Sie nicht wohlgeformtes HTML von DomDocument (PHP) laden.

79

Ich muss einige HTML-Dateien analysieren, sie sind jedoch nicht wohlgeformt und PHP druckt Warnungen aus. Ich möchte ein solches Debugging- / Warnverhalten programmgesteuert vermeiden. Bitte beraten. Vielen Dank!

Code:

// create a DOM document and load the HTML data
$xmlDoc = new DomDocument;
// this dumps out the warnings
$xmlDoc->loadHTML($fetchResult);

Dies:

@$xmlDoc->loadHTML($fetchResult)

kann die Warnungen unterdrücken, aber wie kann ich diese Warnungen programmgesteuert erfassen?

Viet
quelle
Versuchen Sie diese Lösung - scheint viel einfacher zu sein - stackoverflow.com/questions/6090667/…
Marcin
Das Konvertieren von miesen Eingaben in korrekte Ausgaben ist das, was die Rechnungen bezahlt;) Die Wiederherstellungsoption befindet sich im Handbuch . Es ist nur ein Boolescher Wert. Sie können einfach anrufen, $dom->saveHTML()um zu sehen, welche Art von Dokument libxml versucht, aus Ihrer $htmlEingabe zu machen . Normalerweise ist es ziemlich nah / ok.
Wrikken

Antworten:

13

Sie können einen temporären Fehlerbehandler mit installieren set_error_handler

class ErrorTrap {
  protected $callback;
  protected $errors = array();
  function __construct($callback) {
    $this->callback = $callback;
  }
  function call() {
    $result = null;
    set_error_handler(array($this, 'onError'));
    try {
      $result = call_user_func_array($this->callback, func_get_args());
    } catch (Exception $ex) {
      restore_error_handler();        
      throw $ex;
    }
    restore_error_handler();
    return $result;
  }
  function onError($errno, $errstr, $errfile, $errline) {
    $this->errors[] = array($errno, $errstr, $errfile, $errline);
  }
  function ok() {
    return count($this->errors) === 0;
  }
  function errors() {
    return $this->errors;
  }
}

Verwendung:

// create a DOM document and load the HTML data
$xmlDoc = new DomDocument();
$caller = new ErrorTrap(array($xmlDoc, 'loadHTML'));
// this doesn't dump out any warnings
$caller->call($fetchResult);
if (!$caller->ok()) {
  var_dump($caller->errors());
}
troelskn
quelle
10
Scheint viel übertrieben für die Situation. Beachten Sie die libxml2-Funktionen von PHP.
Thomasrutter
Guter Punkt, Thomas. Ich wusste nichts über diese Funktionen, als ich diese Antwort schrieb. Wenn ich mich nicht irre, macht es übrigens intern dasselbe.
troelskn
1
In diesem Fall hat es den gleichen Effekt: Ja, obwohl es auf einer anderen Ebene ausgeführt wird: Mit der obigen Lösung werden PHP-Fehler generiert, aber unterdrückt, aber mit meiner werden sie nicht zu PHP-Fehlern. Ich persönlich bin der Meinung, dass es der falsche Weg ist, PHP-Fehler entweder durch @ oder set_error_handler () zu unterdrücken. Das ist aber nur meine Meinung. Beachten Sie, dass PHP-Fehler und Ausnahmen eine völlig andere Sache sind - die Verwendung von try {} catch () {} ist in Ordnung.
Thomasrutter
2
Ich glaube, ich habe einige Fehlerberichte gesehen, die darauf hindeuten, dass sie sich libxml_use_internal_errorsan den Fehlerbehandler von PHP anschließen.
troelskn
Ähm, das ist irgendwie der Punkt. libxml_use_internal_errorsSteuert, ob libxml2 sich an den PHP-Fehlerbehandler anschließt oder nicht. An welche Fehler denkst du?
Thomasrutter
220

Anruf

libxml_use_internal_errors(true);

vor der Verarbeitung mit mit $xmlDoc->loadHTML()

Dies weist libxml2 an, keine Fehler und Warnungen an PHP zu senden . Um dann nach Fehlern zu suchen und diese selbst zu behandeln, können Sie libxml_get_last_error () und / oder libxml_get_errors () konsultieren, wenn Sie bereit sind.

thomasrutter
quelle
1
So viel einfacher als das Hinzufügen von 20 Codezeilen als die akzeptierte Antwort. Vielen Dank!
Brian Klug
92

Um die Warnungen auszublenden, müssen Sie spezielle Anweisungen geben, libxmldie intern für die Analyse verwendet werden:

libxml_use_internal_errors(true);
$dom->loadHTML($html);
libxml_clear_errors();

Das libxml_use_internal_errors(true)zeigt an, dass Sie die Fehler und Warnungen selbst behandeln und nicht möchten, dass sie die Ausgabe Ihres Skripts durcheinander bringen.

Dies ist nicht dasselbe wie der @Bediener. Die Warnungen werden hinter den Kulissen gesammelt und können anschließend abgerufen werden, indem Sie libxml_get_errors()für den Fall, dass Sie eine Protokollierung durchführen oder die Liste der Probleme an den Anrufer zurücksenden möchten, diese verwenden .

Unabhängig davon, ob Sie die gesammelten Warnungen verwenden oder nicht, sollten Sie die Warteschlange immer durch einen Anruf löschen libxml_clear_errors().

Den Staat erhalten

Wenn Sie anderen Code verwenden, der verwendet wird libxml, kann es sinnvoll sein, sicherzustellen, dass Ihr Code den globalen Status der Fehlerbehandlung nicht ändert . Dazu können Sie den Rückgabewert von verwenden libxml_use_internal_errors(), um den vorherigen Status zu speichern.

// modify state
$libxml_previous_state = libxml_use_internal_errors(true);
// parse
$dom->loadHTML($html);
// handle errors
libxml_clear_errors();
// restore
libxml_use_internal_errors($libxml_previous_state);
Jack
quelle
2
@Greeso: Es wird auf den vorherigen Wert gesetzt. Dies geschieht durch das Konzept, dass es möglicherweise für einen anderen Code konfiguriert wurde, der sich global von dem unterscheidet, FALSEund FALSEdass eine spätere Einstellung diese Einstellung zerstören würde. Durch die Verwendung des vorherigen Rückgabewerts werden $libxml_previous_statediese potenziellen Nebenwirkungen verhindert, da die ursprüngliche Konfiguration unabhängig von den Anforderungen dieses Ortes wiederhergestellt wurde. Die libxml_use_internal_errors()Einstellung ist global, daher lohnt es sich, vorsichtig zu sein.
hakre
Wenn bereits libxml-Fehler anstehen, werden sie dann nicht verschlungen?
CHao
@cHao ist es nicht vernünftig anzunehmen, dass Sie mit einer leeren Tafel beginnen? :)
Ja͢ck
@ Ja͢ck: Nein. Wenn etwas zuvor aufgerufen wurde libxml_use_internal_errors(true), wartet es möglicherweise darauf, die aufgetretenen Fehler zu behandeln.
CHao
20

Das Einstellen der Optionen "LIBXML_NOWARNING" und "LIBXML_NOERROR" funktioniert ebenfalls einwandfrei:

$dom->loadHTML($html, LIBXML_NOWARNING | LIBXML_NOERROR);
Joshua Ott
quelle