fix txt export (paragraph problems)

This commit is contained in:
mirivlad 2025-12-06 22:29:20 +03:00
parent 18a338c2ce
commit 9294399517
2 changed files with 118 additions and 62 deletions

View File

@ -555,67 +555,123 @@ class ExportController extends BaseController {
}
function exportTXT($book, $chapters, $is_public, $author_name) {
$content = "=" . str_repeat("=", 80) . "=\n";
$content .= str_pad($book['title'], 80, " ", STR_PAD_BOTH) . "\n";
$content .= str_pad($author_name, 80, " ", STR_PAD_BOTH) . "\n";
$content .= "=" . str_repeat("=", 80) . "=\n\n";
if (!empty($book['genre'])) {
$content .= "Жанр: " . $book['genre'] . "\n\n";
}
if (!empty($book['description'])) {
$content .= "ОПИСАНИЕ:\n";
// Обрабатываем описание
$descriptionText = strip_tags($book['description']);
$content .= wordwrap($descriptionText, 144) . "\n\n";
}
// Оглавление
if (!empty($chapters)) {
$content .= "ОГЛАВЛЕНИЕ:\n";
$content .= str_repeat("-", 60) . "\n";
foreach ($chapters as $index => $chapter) {
$chapter_number = $index + 1;
$content .= "{$chapter_number}. {$chapter['title']}\n";
}
$content .= "\n";
}
$content .= str_repeat("-", 144) . "\n\n";
foreach ($chapters as $index => $chapter) {
$content .= $chapter['title'] . "\n";
$content .= str_repeat("-", 60) . "\n\n";
// Получаем очищенный текст
$cleanContent = strip_tags($chapter['content']);
$paragraphs = $this->htmlToPlainTextParagraphs($cleanContent);
foreach ($paragraphs as $paragraph) {
if (!empty(trim($paragraph))) {
$content .= wordwrap($paragraph, 144) . "\n\n";
}
}
if ($index < count($chapters) - 1) {
$content .= str_repeat("-", 144) . "\n\n";
}
}
$content .= "\n" . str_repeat("=", 144) . "\n";
$content .= "Экспортировано из " . APP_NAME . " - " . date('d.m.Y H:i') . "\n";
$content .= "Автор: " . $author_name . " | Всего глав: " . count($chapters) . " | Всего слов: " . array_sum(array_column($chapters, 'word_count')) . "\n";
$content .= str_repeat("=", 144) . "\n";
$filename = cleanFilename($book['title']) . '.txt';
header('Content-Type: text/plain; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
echo $content;
exit;
}
$content = "=" . str_repeat("=", 80) . "=\n";
$content .= str_pad($book['title'], 80, " ", STR_PAD_BOTH) . "\n";
$content .= str_pad($author_name, 80, " ", STR_PAD_BOTH) . "\n";
$content .= "=" . str_repeat("=", 80) . "=\n\n";
if (!empty($book['genre'])) {
$content .= "Жанр: " . $book['genre'] . "\n\n";
}
if (!empty($book['description'])) {
$content .= "ОПИСАНИЕ:\n";
// Обрабатываем описание, сохраняя абзацы
$descriptionText = $this->htmlToPlainText($book['description']);
$descriptionLines = explode("\n", $descriptionText);
foreach ($descriptionLines as $line) {
if (trim($line) !== '') {
$content .= wordwrap(trim($line), 144) . "\n";
}
}
$content .= "\n";
}
// Оглавление
if (!empty($chapters)) {
$content .= "ОГЛАВЛЕНИЕ:\n";
$content .= str_repeat("-", 60) . "\n";
foreach ($chapters as $index => $chapter) {
$chapter_number = $index + 1;
$content .= "{$chapter_number}. {$chapter['title']}\n";
}
$content .= "\n";
}
$content .= str_repeat("-", 144) . "\n\n";
foreach ($chapters as $index => $chapter) {
$content .= $chapter['title'] . "\n";
$content .= str_repeat("-", 60) . "\n\n";
// Используем новый метод для преобразования HTML в текст с сохранением абзацев
$plainText = $this->htmlToPlainText($chapter['content']);
$paragraphs = explode("\n", $plainText);
foreach ($paragraphs as $paragraph) {
$trimmed = trim($paragraph);
if (!empty($trimmed)) {
// Оборачиваем текст с учетом ширины строки
$wrapped = wordwrap($trimmed, 144);
$content .= $wrapped . "\n\n";
}
}
if ($index < count($chapters) - 1) {
$content .= str_repeat("-", 144) . "\n\n";
}
}
$content .= "\n" . str_repeat("=", 144) . "\n";
$content .= "Экспортировано из " . APP_NAME . " - " . date('d.m.Y H:i') . "\n";
$content .= "Автор: " . $author_name . " | Всего глав: " . count($chapters) . " | Всего слов: " . array_sum(array_column($chapters, 'word_count')) . "\n";
$content .= str_repeat("=", 144) . "\n";
$filename = cleanFilename($book['title']) . '.txt';
header('Content-Type: text/plain; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
echo $content;
exit;
}
private function htmlToPlainText($html) {
if (empty($html)) {
return '';
}
// Заменяем HTML-сущности
$text = html_entity_decode($html, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// Сохраняем структуру абзацев
// Заменяем теги <p> и <div> на переносы строк
$text = preg_replace('/<(p|div)[^>]*>/i', "\n", $text);
$text = str_replace(['</p>', '</div>'], "\n", $text);
// Заменяем <br> и <br/> на переносы строк
$text = preg_replace('/<br\s*\/?>/i', "\n", $text);
// Заменяем HTML списки на текстовые
$text = preg_replace('/<li[^>]*>/i', "", $text);
$text = str_replace('</li>', "\n", $text);
$text = str_replace(['<ul>', '</ul>', '<ol>', '</ol>'], "\n", $text);
// Заменяем заголовки
$text = preg_replace('/<h[1-6][^>]*>/i', "\n", $text);
$text = preg_replace('/<\/h[1-6]>/i', "\n\n", $text);
// Удаляем все остальные теги
$text = strip_tags($text);
// Удаляем лишние пробелы
$text = preg_replace('/[ \t]+/', ' ', $text);
// Удаляем лишние переносы строк (более 2 подряд)
$text = preg_replace('/\n{3,}/', "\n\n", $text);
// Удаляем пробелы в начале и конце строк
$lines = explode("\n", $text);
$lines = array_map('trim', $lines);
// Фильтруем пустые строки
$lines = array_filter($lines, function($line) {
return $line !== '';
});
// Объединяем обратно
$text = implode("\n", $lines);
return trim($text);
}
// Функция для разбивки HTML на абзацы
function htmlToParagraphs($html) {
// Убираем HTML теги и нормализуем пробелы

View File

@ -37,7 +37,7 @@ class Chapter {
VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW())
");
$word_count = str_word_count(strip_tags($data['content']));
$word_count = $this->countWords($data['content']);
return $stmt->execute([
$data['book_id'],