findByShareToken($share_token); // Для публичного доступа - только опубликованные главы $chapters = $bookModel->getPublishedChapters($book['id']); $is_public = true; } elseif ($book_id && $user_id) { $book = $bookModel->findById($book_id); if (!$book || $book['user_id'] != $user_id) { $_SESSION['error'] = "Доступ запрещен"; redirect('books.php'); } // Для автора - все главы $chapters = $chapterModel->findByBook($book_id); $is_public = false; } else { $_SESSION['error'] = "Книга не найдена"; redirect('books.php'); } if (!$book) { $_SESSION['error'] = "Книга не найдена"; redirect('books.php'); } // Функция для очистки имени файла // function cleanFilename($filename) { // return preg_replace('/[^a-zA-Z0-9_\-]/', '_', $filename); // } // Функция для преобразования Markdown в чистый текст с форматированием абзацев function markdownToPlainText($markdown) { // Обрабатываем диалоги (заменяем - на —) $markdown = preg_replace('/^- (.+)$/m', "— $1", $markdown); // Убираем Markdown разметку $text = $markdown; // Убираем заголовки $text = preg_replace('/^#+\s+/m', '', $text); // Убираем жирный и курсив $text = preg_replace('/\*\*(.*?)\*\*/', '$1', $text); $text = preg_replace('/\*(.*?)\*/', '$1', $text); $text = preg_replace('/__(.*?)__/', '$1', $text); $text = preg_replace('/_(.*?)_/', '$1', $text); // Убираем зачеркивание $text = preg_replace('/~~(.*?)~~/', '$1', $text); // Убираем код $text = preg_replace('/`(.*?)`/', '$1', $text); $text = preg_replace('/```.*?\n(.*?)```/s', '$1', $text); // Убираем ссылки $text = preg_replace('/\[(.*?)\]\(.*?\)/', '$1', $text); // Обрабатываем списки $text = preg_replace('/^[\*\-+]\s+/m', '', $text); $text = preg_replace('/^\d+\.\s+/m', '', $text); // Обрабатываем цитаты $text = preg_replace('/^>\s+/m', '', $text); return $text; } // Функция для форматирования текста с сохранением абзацев и диалогов function formatPlainText($text) { $lines = explode("\n", $text); $formatted = []; $in_paragraph = false; foreach ($lines as $line) { $line = trim($line); if (empty($line)) { if ($in_paragraph) { $formatted[] = ''; // Пустая строка для разделения абзацев $in_paragraph = false; } continue; } // Диалоги начинаются с — if (str_starts_with($line, '—')) { if ($in_paragraph) { $formatted[] = ''; // Разделяем абзацы перед диалогом } $formatted[] = $line; $formatted[] = ''; // Пустая строка после диалога $in_paragraph = false; } else { // Обычный текст $formatted[] = $line; $in_paragraph = true; } } return implode("\n", array_filter($formatted, function($line) { return $line !== '' || !empty($line); })); } // Обработка экспорта switch ($format) { case 'pdf': exportPDF($book, $chapters, $is_public); break; case 'docx': exportDOCX($book, $chapters, $is_public); break; case 'odt': exportODT($book, $chapters, $is_public); break; case 'html': exportHTML($book, $chapters, $is_public); break; case 'txt': exportTXT($book, $chapters, $is_public); break; default: $_SESSION['error'] = "Неверный формат экспорта"; redirect($share_token ? "view_book.php?share_token=$share_token" : "book_edit.php?id=$book_id"); } function exportPDF($book, $chapters, $is_public) { global $Parsedown; $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); // Устанавливаем метаданные документа $pdf->SetCreator(APP_NAME); $pdf->SetAuthor($is_public ? 'Автор' : ($_SESSION['display_name'] ?? 'Автор')); $pdf->SetTitle($book['title']); $pdf->SetSubject($book['genre'] ?? ''); // Устанавливаем margins $pdf->SetMargins(15, 20, 15); $pdf->SetHeaderMargin(10); $pdf->SetFooterMargin(10); // Устанавливаем авто разрыв страниц $pdf->SetAutoPageBreak(TRUE, 15); // Добавляем страницу $pdf->AddPage(); // Устанавливаем шрифт с поддержкой кириллицы $pdf->SetFont('dejavusans', '', 12); // Заголовок книги $pdf->SetFont('dejavusans', 'B', 16); $pdf->Cell(0, 10, $book['title'], 0, 1, 'C'); $pdf->Ln(5); // Жанр if (!empty($book['genre'])) { $pdf->SetFont('dejavusans', 'I', 12); $pdf->Cell(0, 10, 'Жанр: ' . $book['genre'], 0, 1, 'C'); $pdf->Ln(5); } // Описание if (!empty($book['description'])) { $pdf->SetFont('dejavusans', '', 12); $pdf->MultiCell(0, 8, $book['description'], 0, 'J'); $pdf->Ln(10); } // Разделитель $pdf->Line(15, $pdf->GetY(), 195, $pdf->GetY()); $pdf->Ln(10); // Главы foreach ($chapters as $index => $chapter) { $pdf->SetFont('dejavusans', '', 12); // Название главы $pdf->SetFont('dejavusans', 'B', 14); $pdf->Cell(0, 8, $chapter['title'], 0, 1); $pdf->Ln(2); // Контент главы (форматированный HTML) $pdf->SetFont('dejavusans', '', 11); $htmlContent = $Parsedown->text($chapter['content']); $pdf->writeHTML($htmlContent, true, false, true, false, ''); $pdf->Ln(8); // Разделитель между главами (кроме последней) if ($index < count($chapters) - 1) { $pdf->Line(15, $pdf->GetY(), 195, $pdf->GetY()); $pdf->Ln(8); } } // Футер с информацией $pdf->SetY(-25); $pdf->SetFont('dejavusans', 'I', 8); $pdf->Cell(0, 6, 'Экспортировано из ' . APP_NAME . ' - ' . date('d.m.Y H:i'), 0, 1, 'C'); $pdf->Cell(0, 6, 'Всего глав: ' . count($chapters) . ' | Всего слов: ' . array_sum(array_column($chapters, 'word_count')), 0, 1, 'C'); // Отправляем файл $filename = cleanFilename($book['title']) . '.pdf'; $pdf->Output($filename, 'D'); exit; } function exportDOCX($book, $chapters, $is_public) { global $Parsedown; $phpWord = new PhpWord(); // Стили документа $phpWord->setDefaultFontName('Times New Roman'); $phpWord->setDefaultFontSize(12); // Секция документа $section = $phpWord->addSection(); // Заголовок книги $section->addText($book['title'], ['bold' => true, 'size' => 16], ['alignment' => 'center']); $section->addTextBreak(2); // Жанр if (!empty($book['genre'])) { $section->addText('Жанр: ' . $book['genre'], ['italic' => true], ['alignment' => 'center']); $section->addTextBreak(1); } // Описание if (!empty($book['description'])) { $section->addText($book['description']); $section->addTextBreak(2); } // Разделитель $section->addText('СОДЕРЖАНИЕ', ['bold' => true, 'size' => 14], ['alignment' => 'center']); $section->addTextBreak(2); // Главы foreach ($chapters as $index => $chapter) { // Заголовок главы $section->addText($chapter['title'], ['bold' => true, 'size' => 14]); // Контент главы (форматированный HTML) $htmlContent = $Parsedown->text($chapter['content']); // Упрощенное добавление HTML контента $plainContent = strip_tags($htmlContent); $paragraphs = explode("\n\n", $plainContent); foreach ($paragraphs as $paragraph) { if (trim($paragraph)) { $section->addText($paragraph); } } // Разрыв страницы между главами (кроме последней) if ($index < count($chapters) - 1) { $section->addPageBreak(); } } // Футер $section->addTextBreak(2); $section->addText('Экспортировано из ' . APP_NAME . ' - ' . date('d.m.Y H:i'), ['italic' => true, 'size' => 9]); $section->addText('Всего глав: ' . count($chapters) . ' | Всего слов: ' . array_sum(array_column($chapters, 'word_count')), ['italic' => true, 'size' => 9]); // Сохраняем и отправляем $filename = cleanFilename($book['title']) . '.docx'; header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document'); header('Content-Disposition: attachment; filename="' . $filename . '"'); $objWriter = IOFactory::createWriter($phpWord, 'Word2007'); $objWriter->save('php://output'); exit; } function exportODT($book, $chapters, $is_public) { global $Parsedown; $phpWord = new PhpWord(); // Стили документа $phpWord->setDefaultFontName('Liberation Serif'); $phpWord->setDefaultFontSize(12); // Секция документа $section = $phpWord->addSection(); // Заголовок книги $section->addText($book['title'], ['bold' => true, 'size' => 16], ['alignment' => 'center']); $section->addTextBreak(2); // Жанр if (!empty($book['genre'])) { $section->addText('Жанр: ' . $book['genre'], ['italic' => true], ['alignment' => 'center']); $section->addTextBreak(1); } // Описание if (!empty($book['description'])) { $section->addText($book['description']); $section->addTextBreak(2); } // Главы foreach ($chapters as $index => $chapter) { // Заголовок главы $section->addText($chapter['title'], ['bold' => true, 'size' => 14]); // Контент главы (форматированный HTML) $htmlContent = $Parsedown->text($chapter['content']); $plainContent = strip_tags($htmlContent); $paragraphs = explode("\n\n", $plainContent); foreach ($paragraphs as $paragraph) { if (trim($paragraph)) { $section->addText($paragraph); } } $section->addTextBreak(2); } // Футер $section->addTextBreak(2); $section->addText('Экспортировано из ' . APP_NAME . ' - ' . date('d.m.Y H:i'), ['italic' => true, 'size' => 9]); $section->addText('Всего глав: ' . count($chapters) . ' | Всего слов: ' . array_sum(array_column($chapters, 'word_count')), ['italic' => true, 'size' => 9]); // Сохраняем и отправляем $filename = cleanFilename($book['title']) . '.odt'; header('Content-Type: application/vnd.oasis.opendocument.text'); header('Content-Disposition: attachment; filename="' . $filename . '"'); $objWriter = IOFactory::createWriter($phpWord, 'ODText'); $objWriter->save('php://output'); exit; } function exportHTML($book, $chapters, $is_public) { global $Parsedown; $html = '