Отключить предупреждения при загрузке некорректного HTML с помощью DomDocument (PHP)


79

Мне нужно проанализировать некоторые файлы HTML, однако они не имеют правильного формата, и PHP выводит предупреждения для них. Я хочу программно избежать такого поведения отладки / предупреждения. Пожалуйста, порекомендуйте. Спасибо!

Код:

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

Этот:

@$xmlDoc->loadHTML($fetchResult)

можно подавить предупреждения, но как я могу записать эти предупреждения программно?


Попробуйте это решение - кажется, намного проще - stackoverflow.com/questions/6090667/…
— Marcin

Преобразование паршивого ввода в надлежащий вывод - вот что оплачивает счета;) Вариант восстановления указан в руководстве . это просто логическое значение. Вы можете просто позвонить, $dom->saveHTML()чтобы посмотреть, какой тип документа libxml пытается сделать из вашего $htmlввода, обычно это довольно близко / хорошо.
— Wrikken 09

Ответы:


13

Вы можете установить временный обработчик ошибок с помощью 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;
  }
}

Применение:

// 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
Похоже, что для этой ситуации много лишнего. Обратите внимание на функции PHP libxml2.
— thomasrutter

Хорошее замечание, Томас. Я не знал об этих функциях, когда писал этот ответ. Если я не ошибаюсь, внутри он делает то же самое.
— troelskn

1
В этом случае он имеет тот же эффект, да, хотя это делается на другом уровне: с помощью вышеупомянутого решения ошибки PHP генерируются, но подавляются, но в моем случае они не становятся ошибками PHP. Я лично считаю, что если что-то связано с подавлением ошибок PHP с помощью @ или set_error_handler (), то это неправильный способ. Но это только мое мнение. Обратите внимание, что ошибки и исключения PHP - это совсем другое дело - можно использовать try {} catch () {}.
— thomasrutter

2
Я думаю, что видел несколько отчетов об ошибках, которые предполагают, что libxml_use_internal_errorsподключается к обработчику ошибок php.
— troelskn

Я надеюсь, что люди прокрутят этот ответ до лучших ответов ниже.
— thomasrutter

222

Вызов

libxml_use_internal_errors(true);

до обработки с $xmlDoc->loadHTML()

Это указывает libxml2 не отправлять ошибки и предупреждения в PHP. Затем, чтобы проверить ошибки и обработать их самостоятельно, вы можете обратиться к libxml_get_last_error () и / или libxml_get_errors (), когда будете готовы.


1
Намного проще, чем добавить 20 строк кода, как это делает принятый ответ. Благодаря!
— Брайан Клуг

94

Чтобы скрыть предупреждения, вы должны дать специальные инструкции, libxmlкоторые используются внутри для выполнения синтаксического анализа:

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

Значок libxml_use_internal_errors(true)указывает, что вы собираетесь самостоятельно обрабатывать ошибки и предупреждения и не хотите, чтобы они испортили вывод вашего скрипта.

Это не то же самое, что @оператор. Предупреждения собираются за кулисами, и впоследствии вы можете получить их, используя, libxml_get_errors()если вы хотите выполнить регистрацию или вернуть список проблем вызывающему.

Независимо от того, используете ли вы собранные предупреждения, вы всегда должны очищать очередь, позвонив libxml_clear_errors().

Сохранение государства

Если у вас есть другой код, который использует, libxmlвозможно, стоит убедиться, что ваш код не изменяет глобальное состояние обработки ошибок; для этого вы можете использовать возвращаемое значение, libxml_use_internal_errors()чтобы сохранить предыдущее состояние.

// 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: установлено предыдущее значение. Это сделано с учетом того, что он мог быть настроен для какого-то другого кода, глобально отличного от того, FALSEи установка его FALSEвпоследствии разрушила бы этот параметр. Использование предыдущего возвращаемого значения $libxml_previous_stateпредотвращает эти потенциальные побочные эффекты, поскольку исходная конфигурация была восстановлена ​​независимо от потребностей этого места. libxml_use_internal_errors()Установка является глобальной, так что стоит взять какую - то помощь.
— hakre

Если уже есть ожидающие ошибки libxml, разве это их не съест?
— cHao

@cHao разве не разумно предположить, что вы начинаете с чистого листа? :)
— Ja͢ck

@ Як: Нет. Если что-то ранее вызывалось libxml_use_internal_errors(true), то оно может ожидать обработки возникших ошибок.
— cHao

23

Установка параметров "LIBXML_NOWARNING" и "LIBXML_NOERROR" тоже отлично работает:

$dom->loadHTML($html, LIBXML_NOWARNING | LIBXML_NOERROR);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.