Вимкнути попередження під час завантаження неправильно сформованого 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

Відповіді:


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
Здається, це надмірна ситуація. Зверніть увагу на функції libxml2 PHP.
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

@ 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.