Простая проблема с памятью HTML DOM

Я пытаюсь использовать PHP Simple HTML Dom Parser для анализа некоторой информации из результатов SQL-запроса. Но похоже, что с ним ОГРОМНАЯ проблема с памятью. Я создаю html-таблицу, используя результаты SQL-запроса, а затем экспортирую html-таблицу в файл csv. Я действительно новичок в этом, поэтому мой код не самый эффективный. Когда результаты моего запроса малы, файл csv создается успешно. Но когда результаты запроса велики, экспортированный CSV-файл не имеет результатов sql и вместо этого показывает следующее:

Неустранимая ошибка: вызов функции-члена find() для логического значения в /opt/lampp/htdocs/test.php в строке 101

Это моя функция, которая принимает результат sqlresult и создает таблицу html, а затем экспортирует ее в файл csv:

 echo sql_to_html_table($sqlresult, $delim="\n" );

function sql_to_html_table($sqlresult, $delim="\n") {
// starting table
include_once('simple_html_dom.php');
$htmltable =  "<table>" . $delim ;
$counter   = 0 ;
// putting in lines
//while( $row = $sqlresult->mysqli_fetch_assoc()  ){
while($row = mysqli_fetch_assoc($sqlresult)) {
if ( $counter===0 ) {
// table header
$htmltable .=   "<tr>"  . $delim;
foreach ($row as $key => $value ) {
      $htmltable .=   "<th>" . $key . "</th>"  . $delim ;
  }
  $htmltable .=   "</tr>"  . $delim ;
  $counter = 22;
 }
  // table body
  $htmltable .=   "<tr>"  . $delim ;
  foreach ($row as $key => $value ) {
      $htmltable .=   "<td>" . $value . "</td>"  . $delim ;
  }
  $htmltable .=   "</tr>"   . $delim ;
 }
 // closing table

$htmltable .=   "</table>"   . $delim ;
 // return
//return( $htmltable ) ;
$html = str_get_html($htmltable);

header('Content-type: application/ms-excel');
header('Content-Disposition: attachment; filename=sample.csv');

$fp = fopen("php://output", "w");

foreach($html->find('tr') as $element)
{
$td = array();
foreach( $element->find('th') as $row)
{
    $td [] = $row->plaintext;
}
fputcsv($fp, $td);
$td = array();
foreach( $element->find('td') as $row)
{
    $td [] = $row->plaintext;
}
fputcsv($fp, $td);
}
fclose($fp);
} 

Я попытался создать исключение после $html = str_get_html($htmltable); как это:

if (!str_get_html($htmltable)) {
throw new exception('exception') ; 
}

и когда я пытаюсь запустить код, мой браузер выдает мне эту ошибку:

Неустранимая ошибка: необработанное исключение «Исключение» с сообщением «исключение» в /opt/lampp/htdocs/test.php:96 Трассировка стека: #0 /opt/lampp/htdocs/test.php(62): sql_to_html_table(Object(mysqli_result ), '\n') #1 {main} добавлено в /opt/lampp/htdocs/test.php в строке 96


person Ahmad Aziz    schedule 25.06.2015    source источник
comment
Почему вы переходите с sql на html на csv? Почему бы не использовать встроенную в mysql функцию экспорта csv?   -  person Liam Sorsby    schedule 25.06.2015
comment
Я в основном разрабатываю интерфейс, используя php. Поэтому мне нужно выбрать SQL-запрос из раскрывающегося меню, а затем нажать кнопку, чтобы сгенерировать и сохранить файл csv. Я знаю, как использовать функцию экспорта в формате csv для сохранения файла, но мой начальник хочет сохранить его с помощью всплывающего окна.   -  person Ahmad Aziz    schedule 25.06.2015
comment
Ну, ваша ошибка нигде не означает, что есть какие-либо проблемы с памятью. В нем говорится, что вы пытаетесь вызвать функцию find() для логического значения в строке 101. Я предполагаю, что это следующая строка: foreach($html->find('tr') as $element), если да, то что содержит $html, Я бы напечатал_r($html); чтобы найти содержимое, чтобы увидеть, является ли это строкой или логическим значением, и перейти оттуда   -  person Liam Sorsby    schedule 25.06.2015
comment
Но я упоминал ранее, что когда я запускаю сценарий SQL, в результате которого есть несколько строк, он работает отлично. Эта проблема возникает только тогда, когда я использую сценарий sql, который имеет большое количество строк в своем результате. Вы все еще думаете, что нет проблем с памятью?   -  person Ahmad Aziz    schedule 25.06.2015
comment
Я шел к тому, что никакой ошибки памяти не было. Большинство загрузчиков DOM будут загружать строки в память одну за другой. О каких результатах мы говорим? Какую ошибку памяти вы получаете?   -  person Liam Sorsby    schedule 25.06.2015
comment
Я не получаю никакой ошибки памяти. Прошу прощения за путаницу. Здесь речь идет о 46000 строк. Когда я пытаюсь распечатать результат в браузере, он на некоторое время зависает и начинает отображать строки, что также приводит к задержке в браузере.   -  person Ahmad Aziz    schedule 25.06.2015
comment
Да, у вас наверняка возникнут проблемы с памятью и производительностью при вызовах 46000 str_get_html. Мой совет: переключиться на это, а также провести рефакторинг кода, убрать включение из функции, потому что это просто странно, и я убираю вещи, чтобы сделать их более читабельными.   -  person pguardiario    schedule 26.06.2015


Ответы (2)


Глядя на копию simple_html_dom.php из SourceForge, это звучит как ожидаемое поведение для достаточно большой строки HTML. Я вижу, что str_get_html() имеет проверку, которая заставит ее вернуть false, если размер строки больше, чем MAX_FILE_SIZE. И MAX_FILE_SIZE определяется с помощью:

define('MAX_FILE_SIZE', 600000);

Таким образом, похоже, что simple_html_dom не будет обрабатывать строки размером более 600 КБ. Поскольку это встроенное ограничение, я предполагаю, что вы можете либо попытаться изменить ограничение и посмотреть, что произойдет, либо использовать другую библиотеку.

Кроме того, вы можете просто пропустить часть HTML. Если вам нужно сгенерировать HTML для других целей, это нормально, но нет никаких причин, по которым вы не можете обойти эту проблему, просто создав CSV непосредственно из результатов базы данных, а не из HTML.

person Peter Geer    schedule 25.06.2015
comment
Я действительно новичок в этом, и я понятия не имею, как получить результаты CSV непосредственно из базы данных, а не HTML. не могли бы вы немного помочь мне в этом? - person Ahmad Aziz; 25.06.2015
comment
Что ж, просто используйте то, что у вас уже есть, для создания HTML. Прямо сейчас вы получаете данные из MySQL, конвертируете их в HTML и конвертируете HTML в CSV. Это одни и те же данные, поэтому нет никаких причин, по которым вы не могли бы просто выполнить fputcsv() непосредственно с результатом базы данных, когда вы просматриваете их. HTML совершенно не нужен для создания CSV. - person Peter Geer; 25.06.2015

Может быть, это немного легче понять:

function sql_to_csv($sqlresult, $delim = "\n") {

    // Loop each result into a csv row string
    while($row = mysqli_fetch_assoc($sqlresult)) {

        // Create/reset a var to hold the csv row content
        $csvRow = '';

        // Append each column value comma separated
        // Be warned of column values containing commas
        foreach ($row AS $columnValue) {
            $csvRow .= $columnValue . ',';
        }

        // Remove the trailing comma from the final column
        rtrim($csvRow, ',');

        // Send your CSV row to the browser
        echo $csvRow . $delim;
    }

    header('Content-type: text/csv');
    header('Content-Disposition: attachment; filename=sample.csv');
}

Существуют различные проблемы с этим подходом, не ограничиваясь большими буферами вывода, столбцами с несколькими запятыми и т. Д. Я признаю эти проблемы, но хотел дать ранний подход к решению вместо большого блока текста.

Самый простой способ отлаживать PHP-код — запускать его с выводом отладки ошибок. Следующее может помочь вам, если предыдущее бесполезно:

var_dump($variable);
exit;

Это позволит вам видеть содержимое переменной во время выполнения и может лучше указать ваше исключение, учитывая номер строки в ваших исключениях.

Удачи.

person Dan Belden    schedule 26.06.2015