Tắt cảnh báo khi tải HTML không được định dạng tốt bởi DomDocument (PHP)


79

Tôi cần phân tích cú pháp một số tệp HTML, tuy nhiên, chúng không được định dạng tốt và PHP in ra các cảnh báo. Tôi muốn tránh hành vi gỡ lỗi / cảnh báo như vậy theo chương trình. Xin hãy tư vấn. Cảm ơn bạn!

Mã:

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

Điều này:

@$xmlDoc->loadHTML($fetchResult)

có thể ngăn chặn các cảnh báo nhưng làm thế nào tôi có thể nắm bắt các cảnh báo đó theo chương trình?


Hãy thử giải pháp này - có vẻ dễ dàng hơn nhiều - stackoverflow.com/questions/6090667/…
Marcin

Chuyển đổi đầu vào tệ hại thành đầu ra thích hợp là những gì thanh toán các hóa đơn;) Tùy chọn khôi phục có trong sách hướng dẫn . nó chỉ là một boolean. Bạn chỉ có thể gọi $dom->saveHTML()để xem loại nếu tài liệu libxml đang cố gắng thực hiện $htmlđầu vào của bạn , thường thì nó khá gần / ok.
Wrikken

Câu trả lời:


13

Bạn có thể cài đặt trình xử lý lỗi tạm thời với 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;
  }
}

Sử dụng:

// 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
Có vẻ như rất nhiều mức cần thiết cho tình hình. Lưu ý các hàm libxml2 của PHP.
thomasrutter

Tốt, Thomas. Tôi không biết về các chức năng này khi tôi viết câu trả lời này. Nếu tôi không nhầm, nó làm điều tương tự trong nội bộ btw.
troelskn

1
Nó có tác dụng tương tự trong trường hợp này là có, mặc dù nó được thực hiện ở một cấp độ khác: với giải pháp trên, các lỗi PHP được tạo ra nhưng bị loại bỏ nhưng với của tôi, chúng không trở thành lỗi PHP. Cá nhân tôi cảm thấy rằng nếu làm điều gì đó liên quan đến việc ngăn chặn các lỗi PHP thông qua @ hoặc set_error_handler (), thì đó là cách làm sai. Đó chỉ là ý kiến ​​của tôi. Lưu ý rằng các lỗi và ngoại lệ PHP hoàn toàn khác - sử dụng try {} catch () {} là được.
thomasrutter

2
Tôi nghĩ rằng tôi đã thấy một số báo cáo lỗi, điều đó cho thấy rằng libxml_use_internal_errorskết nối với trình xử lý lỗi của php.
troelskn

Ừm, đó là một vấn đề. libxml_use_internal_errorskiểm soát xem libxml2 có kết nối với trình xử lý lỗi của PHP hay không. Bạn đang nghĩ đến lỗi nào?
thomasrutter

220

Gọi

libxml_use_internal_errors(true);

trước khi xử lý với $xmlDoc->loadHTML()

Điều này cho biết libxml2 không gửi lỗi và cảnh báo tới PHP. Sau đó, để kiểm tra lỗi và tự xử lý, bạn có thể tham khảo libxml_get_last_error () và / hoặc libxml_get_errors () khi bạn đã sẵn sàng.


1
Vì vậy, dễ dàng hơn nhiều sau đó thêm 20 dòng mã như câu trả lời được chấp nhận. Cảm ơn!
Brian Klug

92

Để ẩn các cảnh báo, bạn phải đưa ra các hướng dẫn đặc biệt libxmlđược sử dụng nội bộ để thực hiện phân tích cú pháp:

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

Dấu libxml_use_internal_errors(true)hiệu cho biết rằng bạn sẽ tự xử lý các lỗi và cảnh báo và bạn không muốn chúng làm rối đầu ra của tập lệnh của mình.

Điều này không giống với @toán tử. Các cảnh báo được thu thập ở hậu trường và sau đó bạn có thể lấy chúng bằng cách sử dụng libxml_get_errors()trong trường hợp bạn muốn thực hiện ghi nhật ký hoặc trả lại danh sách các vấn đề cho người gọi.

Cho dù bạn có đang sử dụng các cảnh báo đã thu thập hay không, bạn phải luôn xóa hàng đợi bằng cách gọi libxml_clear_errors().

Bảo tồn trạng thái

Nếu bạn có mã khác mà sử dụng libxmlnó có thể là đáng giá để đảm bảo mã của bạn không làm thay đổi toàn cầu trạng việc xử lý lỗi; đối với điều này, bạn có thể sử dụng giá trị trả về của libxml_use_internal_errors()để lưu trạng thái trước đó.

// 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: Nó được đặt thành giá trị trước đó . Điều đó được thực hiện bởi khái niệm rằng nó có thể đã được cấu hình cho một số mã khác trên toàn cầu FALSEvà việc đặt nó thành FALSEsau đó sẽ phá hủy cài đặt đó. Bằng cách sử dụng giá trị trả về trước đó, $libxml_previous_statenhững tác dụng phụ tiềm ẩn đó sẽ được ngăn chặn vì cấu hình ban đầu đã được khôi phục độc lập với nhu cầu của địa điểm này. Các libxml_use_internal_errors()thiết lập là toàn cầu, vì vậy nó có giá trị để có một số dịch vụ chăm sóc.
hakre

Nếu đã có lỗi libxml đang chờ xử lý, điều này sẽ không ăn chúng?
cHao

@cHao không hợp lý khi cho rằng bạn đang bắt đầu với một phương tiện trống? :)
Ja͢ck

@ Ja͢ck: Không. Nếu một cái gì đó đã được gọi trước đó libxml_use_internal_errors(true), thì nó có thể đang chờ xử lý bất kỳ lỗi nào phát sinh.
cHao

20

Việc đặt các tùy chọn "LIBXML_NOWARNING" & "LIBXML_NOERROR" cũng hoạt động hoàn toàn tốt:

$dom->loadHTML($html, LIBXML_NOWARNING | LIBXML_NOERROR);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.