Wyłącz ostrzeżenia podczas ładowania nieprawidłowego kodu HTML przez DomDocument (PHP)


79

Muszę przeanalizować niektóre pliki HTML, jednak nie są one poprawnie sformułowane i PHP wyświetla ostrzeżenia w formacie. Chcę programowo uniknąć takiego debugowania / ostrzegania. Proszę doradź. Dziękuję Ci!

Kod:

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

To:

@$xmlDoc->loadHTML($fetchResult)

można pominąć ostrzeżenia, ale jak mogę programowo przechwytywać te ostrzeżenia?


Wypróbuj to rozwiązanie - wydaje się być znacznie łatwiejsze - stackoverflow.com/questions/6090667/ ...
Marcin

Przeliczenie marnego wejścia na właściwe wyjście jest tym, co opłaca rachunki;) Opcja odzyskiwania znajduje się w instrukcji . to tylko wartość logiczna. Możesz po prostu zadzwonić, $dom->saveHTML()aby zobaczyć, jakiego rodzaju, jeśli dokument libxml próbuje wprowadzić twoje $htmldane wejściowe, zwykle jest dość blisko / ok.
Wrikken,

Odpowiedzi:


13

Możesz zainstalować tymczasową obsługę błędów z 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;
  }
}

Stosowanie:

// 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());
}

10
Wydaje się, że to przesada w tej sytuacji. Zwróć uwagę na funkcje PHP libxml2.
thomasrutter

Słuszna uwaga, Thomas. Nie wiedziałem o tych funkcjach, kiedy pisałem tę odpowiedź. Jeśli się nie mylę, wewnętrznie robi to samo.
troelskn

1
W tym przypadku ma to ten sam efekt, chociaż odbywa się to na innym poziomie: w powyższym rozwiązaniu błędy PHP są generowane, ale pomijane, ale w moim przypadku nie stają się błędami PHP. Osobiście uważam, że jeśli robienie czegoś wiąże się z tłumieniem błędów PHP za pomocą @ lub set_error_handler (), to jest to niewłaściwy sposób. To tylko moja opinia. Zauważ, że błędy i wyjątki PHP to zupełnie co innego - użycie try {} catch () {} jest w porządku.
thomasrutter

2
Myślę, że widziałem kilka raportów o błędach, które sugerują, że libxml_use_internal_errorspodłącza się do programu obsługi błędów php.
troelskn

Mam nadzieję, że ludzie przewijają tę odpowiedź do lepszych odpowiedzi poniżej.
thomasrutter


94

Aby ukryć ostrzeżenia, musisz podać specjalne instrukcje, libxmlktóre są używane wewnętrznie do wykonywania analizy:

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

Symbol libxml_use_internal_errors(true)wskazuje, że sam poradzisz sobie z błędami i ostrzeżeniami i nie chcesz, aby zepsuły wyniki Twojego skryptu.

To nie to samo, co @operator. Ostrzeżenia są zbierane za kulisami, a następnie możesz je odzyskać, używając libxml_get_errors()w przypadku, gdy chcesz wykonać rejestrację lub zwrócić listę problemów dzwoniącemu.

Niezależnie od tego, czy używasz zebranych ostrzeżeń, czy nie, zawsze powinieneś wyczyścić kolejkę, dzwoniąc libxml_clear_errors().

Ochrona państwa

Jeśli masz inny kod, który używa libxml, warto upewnić się, że Twój kod nie zmienia globalnego stanu obsługi błędów; w tym celu możesz użyć zwracanej wartości, libxml_use_internal_errors()aby zapisać poprzedni stan.

// 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);

2
@Greeso: jest ustawiona na poprzednią wartość. Jest to spowodowane koncepcją, że mógł zostać skonfigurowany dla jakiegoś innego globalnie innego kodu, FALSEa ustawienie go FALSEpóźniej zniszczyłoby to ustawienie. Używając poprzedniej wartości zwracanej, $libxml_previous_statezapobiega się tym potencjalnym skutkom ubocznym, ponieważ oryginalna konfiguracja została przywrócona niezależnie od potrzeb tego miejsca. libxml_use_internal_errors()Ustawienie jest globalny, więc warto poświęcić trochę opieki.
hakre

Jeśli są już oczekujące błędy libxml, czy to ich nie zje?
cHao

@cHao, czy nie rozsądnie jest zakładać, że zaczynasz od czystej karty? :)
Ja͢ck

@ Ja͢ck: Nie. Jeśli coś zostało wcześniej nazwane libxml_use_internal_errors(true), może czekać, aby obsłużyć wszelkie pojawiające się błędy.
cHao

23

Ustawienie opcji „LIBXML_NOWARNING” i „LIBXML_NOERROR” również działa doskonale:

$dom->loadHTML($html, LIBXML_NOWARNING | LIBXML_NOERROR);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.