diff --git a/public/main/inc/ajax/lp.ajax.php b/public/main/inc/ajax/lp.ajax.php index c07b8ca2a2b..534e28b7a37 100644 --- a/public/main/inc/ajax/lp.ajax.php +++ b/public/main/inc/ajax/lp.ajax.php @@ -30,6 +30,44 @@ $sessionId = api_get_session_id(); switch ($action) { + case 'get_lp_export_items': + $lpItems = []; + if ($lp) { + $items = learnpath::get_flat_ordered_items_list($lp); + $lpItemRepo = Container::getLpItemRepository(); + $documentRepo = Container::getDocumentRepository(); + foreach ($items as $itemId) { + $item = $lpItemRepo->find($itemId); + + if ('document' !== $item->getItemType()) { + continue; + } + + $document = $documentRepo->find((int) $item->getPath()); + if (!$document instanceof CDocument) { + continue; + } + + // Only export if it's a valid HTML file + try { + $content = $documentRepo->getResourceFileContent($document); + if (!is_string($content) || !preg_match('/^\s*<(?!!--|!doctype|html|body)/i', $content)) { + continue; + } + + $lpItems[] = [ + 'id' => $item->getIid(), + 'title' => $item->getTitle(), + ]; + } catch (\Throwable $e) { + // Skip silently + } + } + } + + header('Content-Type: application/json'); + echo json_encode(['items' => $lpItems]); + exit; case 'get_lp_list_by_course': $course_id = (isset($_GET['course_id']) && !empty($_GET['course_id'])) ? (int) $_GET['course_id'] : 0; $session_id = (isset($_GET['session_id']) && !empty($_GET['session_id'])) ? (int) $_GET['session_id'] : 0; diff --git a/public/main/inc/lib/pdf.lib.php b/public/main/inc/lib/pdf.lib.php index 68f70d906ee..f88ee0e5fa8 100644 --- a/public/main/inc/lib/pdf.lib.php +++ b/public/main/inc/lib/pdf.lib.php @@ -243,46 +243,45 @@ public function html_to_pdf( $counter = 1; foreach ($htmlFileArray as $file) { - //Add a page break per file - $pageBreak = ''; - if ($counter == count($htmlFileArray)) { - $pageBreak = ''; - } - - //if the array provided contained subarrays with 'title' entry, - // then print the title in the PDF - if (is_array($file) && isset($file['title'])) { - $htmlTitle = $file['title']; - $file = $file['path']; + $pageBreak = ($counter === count($htmlFileArray)) ? '' : ''; + $htmlTitle = ''; + $filePath = null; + $content = null; + + if (is_array($file)) { + $htmlTitle = $file['title'] ?? ''; + $content = $file['content'] ?? null; + $filePath = $file['path'] ?? null; } else { - //we suppose we've only been sent a file path + $filePath = $file; $htmlTitle = basename($file); } - $counter++; + if ($counter === 1 && !empty($mainTitle)) { + $this->pdf->WriteHTML('

'.$mainTitle.'

'); + } - if (empty($file) && !empty($htmlTitle)) { - // this is a chapter, print title & skip the rest - if (2 === $counter && !empty($mainTitle)) { - $this->pdf->WriteHTML( - '

'.$mainTitle.'

' - ); - } - if ($printTitle) { - $this->pdf->WriteHTML( - '

'.$htmlTitle.'

'.$pageBreak - ); + // New support for direct HTML content + if (!empty($content)) { + if ($printTitle && !empty($htmlTitle)) { + $this->pdf->WriteHTML('

'.$htmlTitle.'

', 2); } + $this->pdf->WriteHTML($content.$pageBreak, 2); + $counter++; continue; - } else { - if (2 === $counter && !empty($mainTitle)) { - $this->pdf->WriteHTML( - '

'.$mainTitle.'

' - ); + } + + // Original logic for physical files + if (empty($filePath)) { + if ($printTitle && !empty($htmlTitle)) { + $this->pdf->WriteHTML('

'.$htmlTitle.'

'.$pageBreak); } + $counter++; + continue; } - if (!file_exists($file)) { + if (!file_exists($filePath)) { + $counter++; continue; } @@ -292,28 +291,21 @@ public function html_to_pdf( $this->pdf->WriteHTML($css, 1); } - //it's not a chapter but the file exists, print its title - if ($printTitle) { + if ($printTitle && !empty($htmlTitle)) { $this->pdf->WriteHTML('

'.$htmlTitle.'

', 2); } - $file_info = pathinfo($file); + $file_info = pathinfo($filePath); $extension = $file_info['extension']; if (in_array($extension, ['html', 'htm'])) { $dirName = $file_info['dirname']; - $filename = $file_info['basename']; - $filename = str_replace('_', ' ', $filename); - - if ('html' === $extension) { - $filename = basename($filename, '.html'); - } elseif ('htm' === $extension) { - $filename = basename($filename, '.htm'); - } + $filename = str_replace('_', ' ', $file_info['basename']); + $filename = basename($filename, '.'.$extension); $webPath = api_get_path(WEB_PATH); - $documentHtml = @file_get_contents($file); + $documentHtml = @file_get_contents($filePath); $documentHtml = preg_replace($clean_search, '', $documentHtml); $crawler = new Crawler($documentHtml); @@ -342,25 +334,17 @@ public function html_to_pdf( ); } - //$documentHtml = self::fixImagesPaths($documentHtml, $courseInfo, $dirName); - // The library mPDF expects UTF-8 encoded input data. api_set_encoding_html($documentHtml, 'UTF-8'); - // TODO: Maybe it is better idea the title to be passed through - $title = api_get_title_html($documentHtml, 'UTF-8', 'UTF-8'); - // $_GET[] too, as it is done with file name. - // At the moment the title is retrieved from the html document itself. - if (empty($title)) { - $title = $filename; // Here file name is expected to contain ASCII symbols only. - } if (!empty($documentHtml)) { $this->pdf->WriteHTML($documentHtml.$pageBreak, 2); } } elseif (in_array($extension, ['jpg', 'jpeg', 'png', 'gif'])) { - // Images - $image = Display::img($file); + $image = Display::img($filePath); $this->pdf->WriteHTML(''.$image.''.$pageBreak, 2); } + + $counter++; } $outputFile = 'pdf_'.api_get_local_time().'.pdf'; diff --git a/public/main/lp/ScormExport.php b/public/main/lp/ScormExport.php index 636a8ad7df8..1ffcf9949fe 100644 --- a/public/main/lp/ScormExport.php +++ b/public/main/lp/ScormExport.php @@ -3,6 +3,7 @@ /* For licensing terms, see /license.txt */ use Chamilo\CoreBundle\Framework\Container; +use Chamilo\CourseBundle\Entity\CDocument; use Chamilo\CourseBundle\Entity\CLp; use Chamilo\CourseBundle\Entity\CLpItem; use Symfony\Component\Filesystem\Filesystem; @@ -1002,84 +1003,95 @@ public static function export(learnpath $lp) DocumentManager::file_send_for_download($temp_zip_file, true, $name); } - public static function exportToPdf($lp_id, $courseInfo) + /** + * Export selected learning path items to a PDF. + */ + public static function exportToPdf(int $lpId, array $courseInfo, array $selectedItems = []): ?bool { - // @todo fix exportToPdf - $lp_id = (int) $lp_id; /** @var CLp $lp */ - $lp = Container::getLpRepository()->find($lp_id); + $lp = Container::getLpRepository()->find($lpId); + if (!$lp || empty($courseInfo)) { + return false; + } $lpItemRepo = Container::getLpItemRepository(); + $documentRepo = Container::getDocumentRepository(); + $filesToExport = []; + $courseCode = $courseInfo['code']; + $scormPath = null; - $files_to_export = []; + $orderedItemIds = learnpath::get_flat_ordered_items_list($lp); - $sessionId = api_get_session_id(); - $courseCode = $courseInfo['code']; - $scorm_path = null; - - if (!empty($courseInfo)) { - //$scorm_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/scorm/'.$this->path; - $list = learnpath::get_flat_ordered_items_list($lp); - if (!empty($list)) { - foreach ($list as $item_id) { - /** @var CLpItem $item */ - $item = $lpItemRepo->find($item_id); - $type = $item->getItemType(); - switch ($type) { - case 'document': - // Getting documents from a LP with chamilo documents - $file_data = DocumentManager::get_document_data_by_id($item->getPath(), $courseCode); - // Try loading document from the base course. - if (empty($file_data) && !empty($sessionId)) { - $file_data = DocumentManager::get_document_data_by_id( - $item->getPath(), - $courseCode, - false, - 0 - ); - } - $file_path = api_get_path(SYS_COURSE_PATH).$courseCode['path'].'/document'.$file_data['path']; - if (file_exists($file_path)) { - $files_to_export[] = [ - 'title' => $item->get_title(), - 'path' => $file_path, - ]; - } - break; - case 'asset': //commes from a scorm package generated by chamilo - case 'sco': - $file_path = $scorm_path.'/'.$item->getPath(); - if (file_exists($file_path)) { - $files_to_export[] = [ - 'title' => $item->get_title(), - 'path' => $file_path, - ]; - } - break; - case 'dir': - $files_to_export[] = [ - 'title' => $item->get_title(), - 'path' => null, - ]; + foreach ($orderedItemIds as $itemId) { + if (!empty($selectedItems) && !in_array($itemId, $selectedItems)) { + continue; + } + + /** @var CLpItem $item */ + $item = $lpItemRepo->find($itemId); + $type = $item->getItemType(); + + switch ($type) { + case 'document': + $document = $documentRepo->find((int) $item->getPath()); + if (!$document instanceof CDocument) { + break; + } + + $fileType = $document->getFiletype(); + $resourceNode = $document->getResourceNode(); + + if ($fileType !== 'file' || !$resourceNode->hasResourceFile()) { + break; + } + + try { + $content = $documentRepo->getResourceFileContent($document); + + if (!is_string($content) || !preg_match('/^\s*<(?!!--|!doctype|html|body)/i', $content)) { break; + } + + $filesToExport[] = [ + 'title' => $item->getTitle(), + 'content' => $content, + ]; + } catch (\Throwable) { + break; } - } - } - $pdf = new PDF(); - $result = $pdf->html_to_pdf( - $files_to_export, - $lp->getTitle(), - $courseCode, - true, - true, - true, - $lp->getTitle() - ); + break; - return $result; + case 'asset': + case 'sco': + $filePath = $scormPath.'/'.$item->getPath(); + if (file_exists($filePath)) { + $filesToExport[] = [ + 'title' => $item->getTitle(), + 'path' => $filePath, + ]; + } + break; + + case 'dir': + $filesToExport[] = [ + 'title' => $item->getTitle(), + 'path' => null, + ]; + break; + } } - return false; + $pdf = new PDF(); + + return $pdf->html_to_pdf( + $filesToExport, + $lp->getTitle(), + $courseCode, + true, + true, + true, + $lp->getTitle() + ); } } diff --git a/public/main/lp/lp_controller.php b/public/main/lp/lp_controller.php index 4f9c2757fb3..a449a27deed 100644 --- a/public/main/lp/lp_controller.php +++ b/public/main/lp/lp_controller.php @@ -716,7 +716,8 @@ if (!$lp_found) { require 'lp_list.php'; } else { - $result = ScormExport::exportToPdf($lpId, $courseInfo); + $selectedItems = isset($_GET['items']) ? explode(',', $_GET['items']) : []; + $result = ScormExport::exportToPdf($lpId, $courseInfo, $selectedItems); if (!$result) { require 'lp_list.php'; } diff --git a/public/main/lp/lp_list.php b/public/main/lp/lp_list.php index 91cfcc4f67a..2b4fd9a387c 100644 --- a/public/main/lp/lp_list.php +++ b/public/main/lp/lp_list.php @@ -2,9 +2,11 @@ /* For licensing terms, see /license.txt */ +use Chamilo\CoreBundle\Component\Utils\ActionIcon; use Chamilo\CoreBundle\Framework\Container; use Chamilo\CourseBundle\Entity\CLpCategory; use ChamiloSession as Session; +require_once __DIR__.'/../inc/global.inc.php'; /** * This file was originally the copy of document.php, but many modifications happened since then ; @@ -20,14 +22,12 @@ exit; } -require_once __DIR__.'/../inc/global.inc.php'; - api_protect_course_script(); // Extra javascript functions for in html head: $htmlHeadXtra[] = "
{% for lp_data in data %}