requireLogin(); $user_id = $_SESSION['user_id']; $bookModel = new Book($this->pdo); $chapterModel = new Chapter($this->pdo); $book = $bookModel->findById($book_id); if (!$book || $book['user_id'] != $user_id) { $_SESSION['error'] = "Доступ запрещен"; $this->redirect('/books'); } // Для автора - все главы $chapters = $chapterModel->findByBook($book_id); // Получаем информацию об авторе $author_name = $this->getAuthorName($book['user_id']); $this->handleExport($book, $chapters, false, $author_name, $format); } public function exportShared($share_token, $format = 'pdf') { $bookModel = new Book($this->pdo); $chapterModel = new Chapter($this->pdo); $book = $bookModel->findByShareToken($share_token); if (!$book) { $_SESSION['error'] = "Книга не найдена"; $this->redirect('/'); } // Для публичного доступа - только опубликованные главы $chapters = $bookModel->getPublishedChapters($book['id']); // Получаем информацию об авторе $author_name = $this->getAuthorName($book['user_id']); $this->handleExport($book, $chapters, true, $author_name, $format); } private function getAuthorName($user_id) { $stmt = $this->pdo->prepare("SELECT display_name, username FROM users WHERE id = ?"); $stmt->execute([$user_id]); $author_info = $stmt->fetch(PDO::FETCH_ASSOC); if ($author_info && $author_info['display_name'] != "") { return $author_info['display_name']; } elseif ($author_info) { return $author_info['username']; } return "Неизвестный автор"; } private function handleExport($book, $chapters, $is_public, $author_name, $format) { switch ($format) { case 'pdf': $this->exportPDF($book, $chapters, $is_public, $author_name); break; case 'docx': $this->exportDOCX($book, $chapters, $is_public, $author_name); break; case 'html': $this->exportHTML($book, $chapters, $is_public, $author_name); break; case 'txt': $this->exportTXT($book, $chapters, $is_public, $author_name); break; default: $_SESSION['error'] = "Неверный формат экспорта"; $redirect_url = $is_public ? "/book/{$book['share_token']}" : "/books/{$book['id']}/edit"; $this->redirect($redirect_url); } } function exportPDF($book, $chapters, $is_public, $author_name) { $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); // Устанавливаем метаданные документа $pdf->SetCreator(APP_NAME); $pdf->SetAuthor($author_name); $pdf->SetTitle($book['title']); $pdf->SetSubject($book['genre'] ?? ''); // Устанавливаем margins $pdf->SetMargins(15, 25, 15); $pdf->SetHeaderMargin(10); $pdf->SetFooterMargin(10); // Устанавливаем авто разрыв страниц $pdf->SetAutoPageBreak(TRUE, 15); // Добавляем страницу $pdf->AddPage(); // Устанавливаем шрифт с поддержкой кириллицы $pdf->SetFont('dejavusans', '', 12); // Заголовок книги $pdf->SetFont('dejavusans', 'B', 18); $pdf->Cell(0, 10, $book['title'], 0, 1, 'C'); $pdf->Ln(2); // Автор $pdf->SetFont('dejavusans', 'I', 14); $pdf->Cell(0, 10, $author_name, 0, 1, 'C'); $pdf->Ln(5); // Обложка книги if (!empty($book['cover_image'])) { $cover_path = COVERS_PATH . $book['cover_image']; if (file_exists($cover_path)) { list($width, $height) = getimagesize($cover_path); $max_width = 80; $ratio = $width / $height; $new_height = $max_width / $ratio; $x = (210 - $max_width) / 2; $pdf->Image($cover_path, $x, $pdf->GetY(), $max_width, $new_height, '', '', 'N', false, 300, '', false, false, 0, false, false, false); $pdf->Ln($new_height + 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', '', 11); $pdf->MultiCell(0, 6, $book['description'], 0, 'J'); $pdf->Ln(10); } // Интерактивное оглавление $chapterLinks = []; if (!empty($chapters)) { $pdf->SetFont('dejavusans', 'B', 14); $pdf->Cell(0, 10, 'Оглавление', 0, 1, 'C'); $pdf->Ln(5); $toc_page = $pdf->getPage(); $pdf->SetFont('dejavusans', '', 11); foreach ($chapters as $index => $chapter) { $chapter_number = $index + 1; $link = $pdf->AddLink(); $chapterLinks[$chapter['id']] = $link; // Сохраняем ссылку для этой главы $pdf->Cell(0, 6, "{$chapter_number}. {$chapter['title']}", 0, 1, 'L', false, $link); } $pdf->Ln(10); } // Разделитель $pdf->Line(15, $pdf->GetY(), 195, $pdf->GetY()); $pdf->Ln(10); // Главы с закладками и правильными ссылками foreach ($chapters as $index => $chapter) { // Добавляем новую страницу для каждой главы $pdf->AddPage(); // УСТАНАВЛИВАЕМ ЯКОРЬ ДЛЯ ССЫЛКИ if (isset($chapterLinks[$chapter['id']])) { $pdf->SetLink($chapterLinks[$chapter['id']]); } // Устанавливаем закладку для этой главы $pdf->Bookmark($chapter['title'], 0, 0, '', 'B', array(0, 0, 0)); // Название главы $pdf->SetFont('dejavusans', 'B', 14); $pdf->Cell(0, 8, $chapter['title'], 0, 1); $pdf->Ln(2); // Контент главы $pdf->SetFont('dejavusans', '', 11); $htmlContent = $chapter['content']; $pdf->writeHTML($htmlContent, true, false, true, false, ''); $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, 'Автор: ' . $author_name . ' | Всего глав: ' . 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, $author_name) { $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(1); // Автор $section->addText($author_name, ['italic' => true, 'size' => 14], ['alignment' => 'center']); $section->addTextBreak(2); // Обложка книги if (!empty($book['cover_image'])) { $cover_path = COVERS_PATH . $book['cover_image']; if (file_exists($cover_path)) { $section->addImage($cover_path, [ 'width' => 150, 'height' => 225, 'alignment' => 'center' ]); $section->addTextBreak(2); } } // Жанр if (!empty($book['genre'])) { $section->addText('Жанр: ' . $book['genre'], ['italic' => true], ['alignment' => 'center']); $section->addTextBreak(1); } // Описание if (!empty($book['description'])) { $descriptionParagraphs = $this->htmlToParagraphs($book['description']); foreach ($descriptionParagraphs as $paragraph) { if (!empty(trim($paragraph))) { $section->addText($paragraph); } } $section->addTextBreak(2); } // Интерактивное оглавление if (!empty($chapters)) { $section->addText('Оглавление', ['bold' => true, 'size' => 14], ['alignment' => 'center']); $section->addTextBreak(1); foreach ($chapters as $index => $chapter) { $chapter_number = $index + 1; // Создаем гиперссылку на заголовок главы $section->addLink("chapter_{$chapter['id']}", "{$chapter_number}. {$chapter['title']}", null, null, true); $section->addTextBreak(1); } $section->addTextBreak(2); } // Разделитель $section->addPageBreak(); // Главы с закладками foreach ($chapters as $index => $chapter) { // Добавляем закладку для главы $section->addBookmark("chapter_{$chapter['id']}"); // Заголовок главы $section->addText($chapter['title'], ['bold' => true, 'size' => 14]); $section->addTextBreak(1); // Получаем очищенный текст и разбиваем на абзацы $cleanContent = strip_tags($chapter['content']); $paragraphs = $this->htmlToParagraphs($chapter['content']); // Добавляем каждый абзац foreach ($paragraphs as $paragraph) { if (!empty(trim($paragraph))) { $section->addText($paragraph); $section->addTextBreak(1); } } // Добавляем разрыв страницы между главами (кроме последней) 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('Автор: ' . $author_name . ' | Всего глав: ' . 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 exportHTML($book, $chapters, $is_public, $author_name) { $html = '