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?

Viet
źródło
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());
}
troelskn
źródło
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
222

Połączenie

libxml_use_internal_errors(true);

przed przetworzeniem w $xmlDoc->loadHTML()

To mówi libxml2, aby nie wysyłał błędów i ostrzeżeń do PHP. Następnie, aby sprawdzić błędy i zająć się nimi samodzielnie, możesz skonsultować się z libxml_get_last_error () i / lub libxml_get_errors (), kiedy będziesz gotowy.

thomasrutter
źródło
1
O wiele łatwiejsze niż dodanie 20 linii kodu, jak robi to zaakceptowana odpowiedź. Dzięki!
Brian Klug
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);
Jacek
źródło
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);
Joshua Ott
źródło