From: Vincent Vanwaelscappel Date: Fri, 19 Aug 2022 18:14:35 +0000 (+0200) Subject: wip #5399 @1 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=74c91bd282c6fd6bddb970f70b97155f6caba6cf;p=fluidbook-toolbox.git wip #5399 @1 --- diff --git a/app/Jobs/FluidbookCompiler.php b/app/Jobs/FluidbookCompiler.php index 5a8470c68..9be23c04f 100644 --- a/app/Jobs/FluidbookCompiler.php +++ b/app/Jobs/FluidbookCompiler.php @@ -5,6 +5,7 @@ namespace App\Jobs; use App\Models\FluidbookPublication; use App\Models\FluidbookTheme; use App\Models\Traits\FluidbookPlayerBranches; +use App\Util\FluidbookLinks; use Cubist\Util\ArrayUtil; use Cubist\Util\CommandLine; use Cubist\Util\Files\Files; @@ -13,6 +14,7 @@ use Cubist\Util\Graphics\Color; use Cubist\Util\Graphics\Image; use Cubist\Util\ObjectUtil; use Cubist\Util\PHP; +use Cubist\Util\Text; use Cubist\Util\Url; use DOMDocument; use DOMElement; @@ -533,7 +535,7 @@ class FluidbookCompiler extends Base continue; } - $e = CubeIT_Text::multiExplode('_-.', mb_strtolower($file->getFilename())); + $e = Text::multiExplode('_-.', mb_strtolower($file->getFilename())); $ean = $this->findEAN($e); if (!$ean) { continue; @@ -604,7 +606,7 @@ class FluidbookCompiler extends Base $file = $cdir . $this->fluidbookSettings->basketReferences; $this->config->basketReferences = wsUtil::excelToArrayKeyVars($file); - wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers); + FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers); foreach ($links as $link) { if ($link['type'] == '12') { @@ -635,14 +637,14 @@ class FluidbookCompiler extends Base $file = $cdir . $this->fluidbookSettings->basketReferences; $this->config->basketReferences = wsUtil::excelToArrayKeyVars($file); - wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers); + FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers); foreach ($this->config->basketReferences as $ref => $data) { $source = $cdir . '/' . $data['Image']; if (!file_exists($source)) { continue; } - $d = CubeIT_Text::str2URL($ref) . '.jpg'; + $d = Text::str2URL($ref) . '.jpg'; $dest = $odir . '/' . $d; if (!file_exists($dest) || !filesize($dest) || filemtime($dest) < filemtime($source)) { $convert = new Image_Resizer_ImageMagick(); @@ -717,7 +719,7 @@ class FluidbookCompiler extends Base $this->vdir->copy($cdir . $f, 'data/commerce/' . $f); } - wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers); + FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers); } public function writeGrandPavoisCart() @@ -737,7 +739,7 @@ class FluidbookCompiler extends Base $file = $cdir . $this->fluidbookSettings->basketReferences; $this->config->basketReferences = wsUtil::excelToArrayKeyVars($file); - wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers); + FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers); } @@ -758,7 +760,7 @@ class FluidbookCompiler extends Base $this->config->eanReferences = wsUtil::excelToArrayIndexKeyVars($eanFile); } - wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers); + FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers); foreach ($links as $link) { if ($link['type'] == '12' && isset($this->config->basketReferences[$link['to']])) { $this->config->basketReferences[$link['to']]['zoom_image'] = 'data/links/zoom_' . $link['uid'] . '.jpg'; @@ -1012,7 +1014,6 @@ class FluidbookCompiler extends Base public function writeGPUDatabase() { - global $core; $r = $core->con->select('SELECT gpu,rgpu,score FROM gpu'); $gpu = []; while ($r->fetch()) { @@ -1079,15 +1080,16 @@ class FluidbookCompiler extends Base public function getResolutions() { - return self::getBookResolutions($this->book); + return self::getBookResolutions($this->getFluidbook()); } + public static function getBookResolutions($book) { - $maxRes = min(300, $book->parametres->maxResolution); + $maxRes = min(self::MAX_RES, $book->settings['maxResolution']); $res = []; - if ($maxRes == 300) { - $res = [150, 300]; + if ($maxRes == self::MAX_RES) { + $res = [150, self::MAX_RES]; } else if ($maxRes <= 150) { $res = [$maxRes]; } @@ -1121,7 +1123,7 @@ class FluidbookCompiler extends Base $this->log('Start compile process'); // Raw copy of some directories - $directories = array('style/fonts/OpenSans', 'images', 'sound', 'video'); + $directories = array('style/fonts/OpenSans', 'images', 'sound'); foreach ($directories as $directory) { $from = $this->assets . '/' . $directory; $this->vdir->copyDirectory($from, $directory); @@ -1196,7 +1198,6 @@ class FluidbookCompiler extends Base protected function writeStats() { - global $core; if ($this->fluidbookSettings->stats) { $this->config->statsMatomo = $this->book_id; @@ -1272,7 +1273,6 @@ height="0" width="0" style="display:none;visibility:hidden"> protected function _labelToPage($k) { - global $core; $k = trim($k, '#/'); $k = str_replace('page/page', 'page', $k); @@ -1281,7 +1281,7 @@ height="0" width="0" style="display:none;visibility:hidden"> } if (preg_match('/^page\/(.+)$/', $k, $matches)) { - $matches[1] = CubeIT_Util_Text::removeAccents($matches[1]); + $matches[1] = Text::removeAccents($matches[1]); $matches[1] = mb_strtolower($matches[1]); if (isset($this->pageLabels[$matches[1]])) { return 'page/' . $this->pageLabels[$matches[1]]; @@ -1292,8 +1292,8 @@ height="0" width="0" style="display:none;visibility:hidden"> protected function writeSecure() { - if ($this->fluidbookSettings->secureClientSidePassword !== '') { - $credentials = CubeIT_Text::explodeNewLines($this->fluidbookSettings->secureClientSidePasswordCredentials); + if ($this->fluidbookSettings->secureClientSidePassword) { + $credentials = Text::explodeNewLines($this->fluidbookSettings->secureClientSidePasswordCredentials); $credentials[] = 'fluidbook:LatacaM4##*'; $users = []; foreach ($credentials as $credential) { @@ -1330,7 +1330,6 @@ height="0" width="0" style="display:none;visibility:hidden"> }); });', $secure); $this->vdir->file_put_contents('secure.html', $secure); - $this->config->secureClientSidePasswordCredentials = $users; } @@ -1467,7 +1466,7 @@ height="0" width="0" style="display:none;visibility:hidden"> $text = trim($text); $text = str_replace(array_keys($replace), array_values($replace), $text); - $text = CubeIT_Text::cleanUTF8($text, ''); + $text = Text::cleanUTF8($text, ''); if ($this->fluidbookSettings->audiodescriptionVoice) { $hash = hash('sha256', $this->fluidbookSettings->audiodescriptionVoice . '_^_' . $text); @@ -1589,7 +1588,6 @@ height="0" width="0" style="display:none;visibility:hidden"> public function getIndexVars() { if (null === $this->_indexVars) { - global $core; $titre = $this->fluidbookSettings->title; @@ -1831,7 +1829,7 @@ height="0" width="0" style="display:none;visibility:hidden"> $symbols = array_merge($symbols, $this->_getSVGSymbols($svgfile)); } $symbols = array_merge($symbols, $this->_svgSymbols); - return '' . str_replace('> <', '><', CubeIT_Util_Text::removeNewLines(implode('', $symbols))) . ''; + return '' . str_replace('> <', '><', Text::removeNewLines(implode('', $symbols))) . ''; } protected function _getSVGSymbols($svg) @@ -1920,7 +1918,7 @@ height="0" width="0" style="display:none;visibility:hidden"> public function addContentLock($page, $unlockConditions = '') { $this->config->hasContentLock = true; - $unlockConditions = CubeIT_Text::explodeNewLines($unlockConditions); + $unlockConditions = Text::explodeNewLines($unlockConditions); $conditions = []; foreach ($unlockConditions as $unlockCondition) { $e = explode(',', $unlockCondition); @@ -1969,7 +1967,7 @@ height="0" width="0" style="display:none;visibility:hidden"> { $variables = []; $f = str_replace("\r", "\n", $f); - $e = CubeIT_Text::explodeNewLines($f); + $e = Text::explodeNewLines($f); foreach ($e as $item) { $item = trim($item); if ($item == '') { @@ -1991,7 +1989,7 @@ height="0" width="0" style="display:none;visibility:hidden"> if (!$this->config->pdfName) { $this->config->pdfName = 'document.pdf'; } - $this->config->pdfName = CubeIT_Text::removeAccents($this->config->pdfName); + $this->config->pdfName = Text::removeAccents($this->config->pdfName); if (mb_strtolower(substr($this->config->pdfName, -4)) !== '.pdf') { $this->config->pdfName .= '.pdf'; } @@ -2035,7 +2033,6 @@ height="0" width="0" style="display:none;visibility:hidden"> protected function writeLangs() { - global $core; $daoLang = new wsDAOLang($core->con); $lang = $daoLang->selectById($this->getFluidbook()->lang); $langs = $daoLang->selectAll(); @@ -2126,7 +2123,6 @@ height="0" width="0" style="display:none;visibility:hidden"> protected function writeLinks() { - global $core; switch ($this->fluidbookSettings->customLinkClass) { case 'WescoSalesLink': @@ -2158,13 +2154,13 @@ height="0" width="0" style="display:none;visibility:hidden"> if ($this->fluidbookSettings->externalChaptersHTML != '') { $d = $this->unzipFile($this->fluidbookSettings->externalChaptersHTML, false, 'data/chapters/'); $meta = $this->getConfigZIP($d['dir']); - $this->config->externalChaptersSize = new stdClass(); + $this->config->externalChaptersSize = new \stdClass(); $this->config->externalChaptersSize->width = $meta['width']; $this->config->externalChaptersSize->height = $meta['height']; $this->vdir->copyDirectory($d['dir'], $d['fdir']); } - wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers); + FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers); if ($this->fluidbookSettings->basketManager === 'Puma') { foreach ($links as $k => $init) { @@ -2260,7 +2256,7 @@ height="0" width="0" style="display:none;visibility:hidden"> $anchorExists[$linkData['to']] = $linkData; } if ($linkData['type'] == 35 || $linkData['type'] == 15 || $linkData['type'] == 39) { - $linkData = wsLinks::decryptLink($linkData); + $linkData = FluidbookLinks::decryptLink($linkData); $animations = contentLink::parseAnimations($linkData['image_rollover']); foreach ($animations as $animation) { if (isset($animation['backgroundcolor']) && $animation['backgroundcolor'] !== 'transparent') { @@ -2346,7 +2342,7 @@ height="0" width="0" style="display:none;visibility:hidden"> $aliases = []; $anchors = []; for ($i = 0; $i <= 2; $i++) { - $lines = CubeIT_Util_Text::explodeNewLines(file_get_contents($this->fluidbookSettings->anchorsAliases)); + $lines = Text::explodeNewLines(file_get_contents($this->fluidbookSettings->anchorsAliases)); foreach ($lines as $line) { $e = explode("\t", $line); $from = anchorLink::normalizeAnchor($e[0]); @@ -2547,7 +2543,7 @@ height="0" width="0" style="display:none;visibility:hidden"> public function addSEOArticle($page, $title, $intro, $image, $id = null, $url = null, $content = '') { if (null === $url) { - $url = CubeIT_Text::str2URL($title) . '.html'; + $url = Text::str2URL($title) . '.html'; } if (null === $id) { $id = $title; @@ -2749,7 +2745,7 @@ height="0" width="0" style="display:none;visibility:hidden"> $js .= file_get_contents($f); $js .= ";\n\n"; } - $tmp = cubeFiles::tempnam(); + $tmp = Files::tempnam(); file_put_contents($tmp, $js); if (file_exists($minimized)) { @@ -2862,10 +2858,6 @@ height="0" width="0" style="display:none;visibility:hidden"> protected function writeImages() { - global $core; - - wsBook::precompileImages($this->book_id); - switch ($this->fluidbookSettings->mobileVersion) { case 'html5-desktop': $this->backgroundsPrefix = array(true, false); @@ -2900,7 +2892,7 @@ height="0" width="0" style="display:none;visibility:hidden"> foreach ($thisbackgroundPrefix as $backgroundsPrefix) { $source = $this->getFluidbook()->getFile($page, $this->imageFormat, $r, $backgroundsPrefix, true, $imdir); if ($r === $this->maxRes) { - $this->getPageDimension($infos, $page); + $this->getPageDimension($page); } $this->vdir->copy($source, 'data/background/' . $r . '/' . ($backgroundsPrefix ? 't' : 'p') . $page . '.' . $this->imageFormat); } @@ -2913,54 +2905,52 @@ height="0" width="0" style="display:none;visibility:hidden"> , 'data/contents/p' . $page . '.svg'); } - $this->vdir->copy($this->getFluidbook()->getThumbFile($page, $this->imageFormat), 'data/thumbnails/p' . $page . '.' . $this->imageFormat); + $this->vdir->copy($this->getFluidbook()->getFile($page, $this->imageFormat, 'thumb'), 'data/thumbnails/p' . $page . '.' . $this->imageFormat); $this->log('Made image page ' . $page); } + $this->_makeCover($this->getFluidbook()->getFile(1, 'jpg', 150, true, true)); + $this->log('Made cover for apps'); $this->log('Made images'); } - protected function getPageDimension($infos, $page) + protected function getPageDimension($page) { - global $core; - if (!isset($this->_docDimensions[$infos['document_id']])) { - $daoDoc = new wsDAODocument($core->con); - $firstDoc = $daoDoc->selectById($infos['document_id']); - $this->_docDimensions[$infos['document_id']] = $firstDoc->generalInfos['page']; - } - $d = $this->_docDimensions[$infos['document_id']][$infos['document_page']]['size']; + $d = $this->getFluidbook()->getDocumentSize($page); $this->config->pagesDimensions[$page] = array($this->cssWidth, $d[1] * ($this->cssWidth / $d[0])); } protected function _makeCover($orig) { - $size = Image::getimagesize($orig); - $w = $size[0]; - $h = $size[1]; + $cached = $this->wdir . '/_cover.jpg'; - $tmp = cubeFiles::tempnam() . '.png'; + if (!file_exists($cached) || filemtime($cached) < filemtime($orig)) { + $size = Image::getimagesize($orig); + $w = $size[0]; + $h = $size[1]; - $c = new CommandLine('convert'); - $c->setArg(null, ROOT . '/images/ws/shade-cover-app.png'); - $c->setManualArg('-resize ' . round($w / 3) . 'x' . $h); - $c->setArg(null, $tmp); - $c->execute(); + $tmp = Files::tempnam() . '.png'; - $res = cubeFiles::tempnam() . '.jpg'; + $c = new CommandLine('convert'); + $c->setArg(null, resource_path('fluidbookpublication/cover/shade-cover-app.png')); + $c->setManualArg('-resize ' . round($w / 3) . 'x' . $h); + $c->setArg(null, $tmp); + $c->execute(); - $convert = new CommandLine('composite'); - $cmd = '-compose Multiply '; - $cmd .= $tmp . ' ' . $orig . ' '; - $cmd .= $res; - $convert->setManualArg($cmd); - $convert->execute(); + $convert = new CommandLine('composite'); + $cmd = '-compose Multiply '; + $cmd .= $tmp . ' ' . $orig . ' '; + $cmd .= $cached; + $convert->setManualArg($cmd); + $convert->execute(); - $this->vdir->copy($res, 'cover.jpg', true); + unlink($tmp); + } + $this->vdir->copy($cached, 'cover.jpg', true); - unlink($tmp); } protected function _lessBoolean($val) @@ -3665,119 +3655,120 @@ height="0" width="0" style="display:none;visibility:hidden"> public function writeXMLArticles() { $f = $this->fluidbookSettings->articlesFile; + if (!$f || !file_exists($this->wdir . '/' . $f) || !is_file($this->wdir . '/' . $f)) { + return; + } + $this->lessVariables['articles-title-color'] = '#000000'; $this->lessVariables['articles-font'] = 'Open Sans'; - if ($f !== '' && file_exists($this->wdir . '/' . $f)) { - $f = $this->wdir . '/' . $f; + $f = $this->wdir . '/' . $f; - $mapFonts = ['OpenSans' => 'Open Sans']; - $this->addLess('articles'); - if ($this->fluidbookSettings->articlesStyle !== 'default') { - $this->lessVariables['articles-styles'] = $this->fluidbookSettings->articlesStyle; - } - $this->lessVariables['articles-font'] = $mapFonts[$this->fluidbookSettings->articlesFont] ?? $this->fluidbookSettings->articlesFont; - $fontPath = $this->addFontKit($this->fluidbookSettings->articlesFont); + $mapFonts = ['OpenSans' => 'Open Sans']; + $this->addLess('articles'); + if ($this->fluidbookSettings->articlesStyle !== 'default') { + $this->lessVariables['articles-styles'] = $this->fluidbookSettings->articlesStyle; + } + $this->lessVariables['articles-font'] = $mapFonts[$this->fluidbookSettings->articlesFont] ?? $this->fluidbookSettings->articlesFont; + $fontPath = $this->addFontKit($this->fluidbookSettings->articlesFont); - $list = $this->config->articlesList ?? []; + $list = $this->config->articlesList ?? []; - $this->lessVariables['articles-title-color'] = '#565657'; + $this->lessVariables['articles-title-color'] = '#565657'; - $svg = ' + $svg = ' '; - $x = simplexml_load_string(file_get_contents($f)); - foreach ($x->xpath('/articles/article') as $k => $a) { - $dir = isset($a['dir']) ? (string)$a['dir'] : null; - $url = (string)$a['url']; - $id = (string)$a['id']; - $color = (string)$a['color']; - if (!$color) { - $color = '#000'; - } + $x = simplexml_load_string(file_get_contents($f)); + foreach ($x->xpath('/articles/article') as $k => $a) { + $dir = isset($a['dir']) ? (string)$a['dir'] : null; + $url = (string)$a['url']; + $id = (string)$a['id']; + $color = (string)$a['color']; + if (!$color) { + $color = '#000'; + } - $specificStyles = '## h3, ## figure figcaption{background-color:' . $color . '}'; - $specificStyles .= '## .chapo, ## blockquote, ## a{color:' . $color . ';}'; + $specificStyles = '## h3, ## figure figcaption{background-color:' . $color . '}'; + $specificStyles .= '## .chapo, ## blockquote, ## a{color:' . $color . ';}'; - $inner = '
'; - $inner .= '
'; - if ($this->fluidbookSettings->articlesShare && $this->fluidbookSettings->share) { - $inner .= ''; - } - $inner .= ''; - $inner .= '
'; + $inner = '
'; + $inner .= '
'; + if ($this->fluidbookSettings->articlesShare && $this->fluidbookSettings->share) { + $inner .= ''; + } + $inner .= ''; + $inner .= '
'; - $inner .= '
'; + $inner .= '
'; - $title = ''; - $lead = ''; - $image = ''; + $title = ''; + $lead = ''; + $image = ''; - $first = true; + $first = true; - foreach ($a->children() as $child) { - if ($first) { - $first = false; - if ($child->getName() !== 'category') { - $inner .= '

 

'; - } + foreach ($a->children() as $child) { + if ($first) { + $first = false; + if ($child->getName() !== 'category') { + $inner .= '

 

'; } - $inner .= $this->_articleToHTML($child, $title, $lead, $image, $dir); } - $inner .= '
'; + $inner .= $this->_articleToHTML($child, $title, $lead, $image, $dir); + } + $inner .= ''; - if (!$title) { - $title = 'Article sans titre ' . $k; - } + if (!$title) { + $title = 'Article sans titre ' . $k; + } - if (!$id) { - $id = CubeIT_Text::str2URL($title); - } + if (!$id) { + $id = Text::str2URL($title); + } - if (!$url) { - $url = $id . '.html'; - } + if (!$url) { + $url = $id . '.html'; + } - $inner = str_replace(array('$id', '$url'), array($id, $url), $inner); + $inner = str_replace(array('$id', '$url'), array($id, $url), $inner); - $article = ['id' => $id, - 'url' => $url, - 'color' => $color, - 'contents' => '', - 'type' => 'xml']; + $article = ['id' => $id, + 'url' => $url, + 'color' => $color, + 'contents' => '', + 'type' => 'xml']; - $article['contents'] = $inner; - $content = ''; - $content .= ''; - $content .= ''; - $content .= ''; - $content .= ''; - $content .= ''; - $content .= $svg; - $content .= $inner; - $content .= ''; - $article['print'] = $content; - $list[] = $article; + $article['contents'] = $inner; + $content = ''; + $content .= ''; + $content .= ''; + $content .= ''; + $content .= ''; + $content .= ''; + $content .= $svg; + $content .= $inner; + $content .= ''; + $article['print'] = $content; + $list[] = $article; - $this->addSEOArticle('#/article/' . $article['url'], $title, $lead, $image, $article['id'], $article['url'], $inner); - } + $this->addSEOArticle('#/article/' . $article['url'], $title, $lead, $image, $article['id'], $article['url'], $inner); } if (isset($list)) { $this->config->articlesList = $list; } - } public function findArticleById($id) diff --git a/app/Util/Excel.php b/app/Util/Excel.php new file mode 100644 index 000000000..83ef90f2f --- /dev/null +++ b/app/Util/Excel.php @@ -0,0 +1,8 @@ + __('Identifiant unique'), + 'page' => __('Page de la publication'), 'left' => __('x'), 'top' => __('y'), 'width' => __('Largeur'), 'height' => __('Hauteur'), 'rot' => __('Rotation'), + 'type' => __('Type'), 'to' => __('Destination'), 'target' => __('Cible'), + 'infobulle' => __('Infobulle'), 'numerotation' => __('Numérotation'), + 'display_area' => __('Activer la surbrillance'), + 'video_loop' => __('Video : boucle'), 'video_auto_start' => __('Video : démarrage automatique'), 'video_controls' => __('Vidéo : afficher les contrôles'), 'video_sound_on' => __('Vidéo : activer le son'), + 'inline' => __('Vidéo : afficher dans la page'), 'video_width' => __('Vidéo : Largeur du popup'), 'video_height' => __('Vidéo : Hauteur du popup'), + 'interactive' => __('Interactivité'), 'video_service' => __('Webvideo : service'), + 'extra' => __('Paramètre supplémentaire'), + 'alternative' => __('Alternative'), + 'read_mode' => __('Mode de lecture'), + 'image' => __('Image'), 'image_rollover' => __('Animation au survol'), + 'animation' => __('Animation'), + 'group' => __('Groupe'), + 'zindex' => __('Profondeur'), + ); + + $comments = array(); + + $xls = new PHPExcel(); + $s = $xls->setActiveSheetIndex(0); + $s->setTitle('Links'); + + // Labels + $i = 0; + foreach ($cols as $id => $label) { + $s->setCellValueByColumnAndRow($i, 1, $id); + $s->getColumnDimensionByColumn($i)->setAutoSize(true); + $s->getStyleByColumnAndRow($i, 1)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER); + $i++; + } + + // Links + self::_correctImageSpecialLinks($links); + $j = 2; + foreach ($links as $l) { + $i = 0; + foreach ($cols as $id => $label) { + if (($id == 'document_id' || $id == 'document_page')) { + if (!is_null($pages)) { + $infos = $pages[$l['page']]; + $value = $infos[$id]; + } else { + $value = ''; + } + } else { + + if (isset($l[$id])) { + if (is_bool($l[$id])) { + $l[$id] = $l[$id] ? '1' : '0'; + } + if ($id === 'numerotation') { + if ($l[$id] === 'false') { + $l[$id] = 'physical'; + } + } + if ($id === 'to') { + $s->getCellByColumnAndRow($i, $j)->setDataType(PHPExcel_Cell_DataType::TYPE_STRING)->getStyle()->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_TEXT); + } + $value = $l[$id]; + } else { + $value = ''; + } + } + + $s->setCellValueExplicitByColumnAndRow($i, $j, $value); + $i++; + } + $j++; + } + // Rulers + $s = $xls->createSheet(); + $s->setTitle('Rulers'); + + $rcols = array('page', 'type', 'pos'); + $i = 0; + // Labels + foreach ($rcols as $id) { + $s->setCellValueByColumnAndRow($i, 1, $id); + $s->getColumnDimensionByColumn($i)->setAutoSize(true); + $i++; + } + + // Contents + $j = 2; + foreach ($rulers as $r) { + $i = 0; + foreach ($rcols as $id) { + if (!is_null($pages) && ($id == 'document_id' || $id == 'document_page')) { + $infos = $pages[$r['page']]; + $value = $infos[$id]; + } else { + $value = $r[$id]; + } + $s->setCellValueByColumnAndRow($i, $j, $value); + $s->getStyleByColumnAndRow($i, $j)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT); + $i++; + } + $j++; + } + + $xls->setActiveSheetIndex(0); + return $xls; + } + + + public static function getLinksAndRulers($book_id, &$links, &$rulers, $time = 'latest') + { + if (null === $time) { + $time = 'latest'; + } + $dir = self::getLinksDir($book_id); + + $file = $dir . '/' . $time . '.links.gz'; + if ($time === 'latest' && !file_exists($file)) { + $versions = self::getLinksVersions($book_id); + foreach ($versions as $version => $m) { + copy($dir . '/' . $version . '.links.gz', $dir . '/latest.links.gz'); + copy($dir . '/' . $version . '.meta.gz', $dir . '/latest.meta.gz'); + break; + } + } + if (!file_exists($file)) { + $links = []; + $rulers = []; + return; + } + + $r = json_decode(gzdecode(file_get_contents($file)), true); + $links = $r['links']; + $rulers = $r['rulers']; + + self::_correctImageSpecialLinks($links); + } + + protected static function _correctImageSpecialLinks(&$links) + { + foreach ($links as $k => $link) { + if (preg_match('/^link_(.*)$/', $link['page'], $matches) && strlen($matches[1]) !== 32) { + $uid = $matches[1]; + foreach ($links as $l) { + if ($l['uid'] === $uid && $l['alternative']) { + $links[$k]['page'] = 'link_' . md5($l['alternative']); + break; + } + } + } else if (preg_match('/^([0-9a-f]{32})$/', $link['page'], $matches)) { + $links[$k]['page'] = 'link_' . $matches[1]; + } + } + } + + public static function getLinksFromExcel($xls, &$links, &$rulers) + { + $s = $xls->setActiveSheetIndexByName('Links'); + $i = 0; + $links = array(); + foreach ($s->getRowIterator() as $row) { + $cellIterator = $row->getCellIterator(); + $cellIterator->setIterateOnlyExistingCells(false); + if ($i == 0) { + $cols = array(); + foreach ($cellIterator as $cell) { + $cols[] = $cell->getValue(); + } + } else { + $link = array(); + $j = 0; + foreach ($cellIterator as $cell) { + $link[$cols[$j]] = $cell->getValue(); + $j++; + } + if ($link['display_area'] == '' || !$link['display_area']) { + $link['display_area'] = '0'; + } + if (trim($link['infobulle']) == '') { + $link['infobulle'] = ''; + } + $links[] = $link; + } + + $i++; + } + + $i = 0; + $rulers = array(); + $s = $xls->setActiveSheetIndexByName('Rulers'); + foreach ($s->getRowIterator() as $row) { + $cellIterator = $row->getCellIterator(); + $cellIterator->setIterateOnlyExistingCells(false); + if ($i == 0) { + $cols = array(); + foreach ($cellIterator as $cell) { + $cols[] = $cell->getValue(); + } + } else { + $link = array(); + $j = 0; + foreach ($cellIterator as $cell) { + $ruler[$cols[$j]] = $cell->getValue(); + $j++; + } + + $rulers[] = $ruler; + } + $i++; + } + + self::_correctImageSpecialLinks($links); + } + + public static function getLinksFromAutobookmarkText($txt, &$links, &$rulers) + { + $links = array(); + $rulers = array(); + + $lines = explode("\n", $txt); + + $protocols = array('mailto' => 3, 'custom' => 7, 'cart' => 12, 'pagelabel' => 26); + + foreach ($lines as $line) { + $line = trim($line); + if ($line == '') { + continue; + } + if (strpos('#', $line) === 0) { + continue; + } + $target = $numerotation = ''; + list($page, $left, $top, $width, $height, $type, $to) = explode(';', $line); + if ($type <= 2) { + $target = '_blank'; + } elseif ($type == 5) { + $numerotation = 'physical'; + } + + $links[] = array( + 'page' => $page, + 'left' => $left, 'top' => $top, 'width' => $width, 'height' => $height, 'rot' => '', + 'type' => $type, 'to' => $to, 'target' => $target, + 'infobulle' => '', 'numerotation' => $numerotation, 'display_area' => '1'); + } + + self::_correctImageSpecialLinks($links); + } + + public static function _getLinkKey() + { + if (self::$_linksKey === null) { + self::$_linksKey = base64_decode('o2p2yYGI8yMEHf+Y5/e6NdTINbbXg3NIo8BODgdhPxI='); + } + return self::$_linksKey; + } + + public static function encryptLinks($links) + { + $res = []; + foreach ($links as $key => $link) { + $res[$key] = self::encryptLinkAttrs($link); + } + return $res; + } + + /** + * @throws SodiumException + */ + public static function encryptLinkAttrs($link) + { + if (is_array($link)) { + $link = ObjectUtil::asObject($link); + } + + $crypted = [13, 14, 35]; + + if (!in_array($link->type, $crypted)) { + return $link; + } + + $attrs = ['image_rollover']; + foreach ($attrs as $attr) { + if (!isset($link->$attr)) { + continue; + } + $link->$attr = trim($link->$attr); + if (strpos($link->$attr, '///') === 0 || $link->$attr == '') { + continue; + } + $link->$attr = '///' . Crypt::safeEncrypt($link->uid . '|||' . $link->$attr, self::_getLinkKey()); + } + return $link; + } + + /** + * @throws SodiumException + */ + public static function decryptLink($link) + { + $array = false; + if (is_array($link)) { + $array = true; + $link = ObjectUtil::asObject($link); + } + + foreach ($link as $attr => $item) { + if (strpos($item, '///') !== 0) { + continue; + } + $v = Crypt::safeDecrypt(substr($item, 3), self::_getLinkKey()); + $e = explode('|||', $v); + if ($e[0] === $link->uid) { + $link->$attr = $e[1]; + } else { + $link->$attr = ''; + } + } + if (!$array) { + return $link; + } + return ArrayUtil::asArray($link); + } + + /** + * @throws SodiumException + */ + public static function decryptLinks($links) + { + $res = []; + foreach ($links as $key => $link) { + $res[$key] = self::decryptLink($link); + } + return $res; + } + + public static function saveLinksInFile($book_id, $user_id, $comments, $links, $rulers = [], $specialLinks = [], $specialRulers = []) + { + $lr = self::mergeLinksAndRulers($links, $rulers, $specialLinks, $specialRulers); + $meta = ['links' => count($lr['links']), 'rulers' => count($lr['rulers']), 'comments' => $comments, 'user' => $user_id]; + $base = self::getLinksDir($book_id) . '/' . time(); + $latestLinks = self::getLinksDir($book_id) . '/latest.links.gz'; + $latestMeta = self::getLinksDir($book_id) . '/latest.meta.gz'; + file_put_contents($base . '.meta.gz', gzencode(json_encode($meta))); + file_put_contents($base . '.links.gz', gzencode(json_encode($lr))); + copy($base . '.links.gz', $latestLinks); + copy($base . '.meta.gz', $latestMeta); + } + + + public static function getLinksDir($book_id) + { + return Files::mkdir('/data1/extranet/www/fluidbook/books/links/' . $book_id); + } + + public static function getLinksVersions($book_id, $withLinks = false) + { + $dir = self::getLinksDir($book_id); + $dr = opendir($dir); + $updates = []; + while ($f = readdir($dr)) { + if ($f === '.' || $f === '..') { + continue; + } + $e = explode('.', $f, 2); + if ($e[1] !== 'meta.gz' || $e[0] === 'latest') { + continue; + } + + $updates[$e[0]] = self::getMeta($book_id, $e[0]); + } + krsort($updates); + + return $updates; + } + + public static function getMeta($book_id, $update = 'latest') + { + return json_decode(gzdecode(file_get_contents(self::getLinksDir($book_id) . '/' . $update . '.meta.gz')), true); + } + + public static function mergeLinksAndRulers($links, $rulers, $specialLinks, $specialRulers) + { + $finalLinks = []; + $l = array_merge(self::_getAsArray($links), self::_getAsArray($specialLinks)); + foreach ($l as $k => $item) { + $item['id'] = $k + 1; + if (!isset($item['to'])) { + $item['to'] = ''; + } + $finalLinks[] = $item; + } + + self::_correctImageSpecialLinks($finalLinks); + + return ['links' => self::encryptLinks($finalLinks), 'rulers' => array_merge(self::_getAsArray($rulers), self::_getAsArray($specialRulers))]; + } + + protected static function _getAsArray($v) + { + if (is_array($v)) { + return $v; + } + return json_decode($v, true); + } + + public static function addLinksFromPDF($book_id) + { + global $core; + + $daoBook = new wsDAOBook($core->con); + $pages = $daoBook->getPagesOfBook($book_id); + + $booleans = array('video_loop', 'video_auto_start', 'video_controls', 'video_sound_on'); + $numbers = ['left', 'top', 'width', 'height']; + + $links = []; + + foreach ($pages as $page => $info) { + $csv = wsDocument::getDir($info['document_id']) . '/p' . $info['document_page'] . '.csv'; + if (!file_exists($csv) && file_exists($csv . '.gz')) { + $csv = 'compress.zlib://' . $csv . '.gz'; + } elseif (!file_exists($csv)) { + continue; + } + + $newformat = (filemtime($csv) > 1363685416); + + $fp = fopen($csv, 'rb'); + + while (true) { + $line = fgetcsv($fp, 512, ';', '"'); + // End of file + if (!$line) { + break; + } + // Commentaire || ligne vide + if (substr($line[0], 0, 1) == '#' || is_null($line[0])) { + continue; + } + + $link = []; + if ($newformat) { + $cols = array('page' => '', 'left' => '', 'top' => '', 'width' => '', 'height' => '', 'type' => '', 'to' => '', 'target' => '_blank', 'video_loop' => true, 'video_auto_start' => true, 'video_controls' => true, 'video_sound_on' => true, 'infobulle' => '', 'numerotation' => 'physical', "inline" => true); + } else { + $cols = array('page' => '', 'type' => '', 'to' => '', 'left' => '', 'top' => '', 'width' => '', 'height' => '', 'target' => '_blank', 'video_loop' => true, 'video_auto_start' => true, 'video_controls' => true, 'video_sound_on' => true, 'infobulle' => '', 'numerotation' => 'physical'); + } + + + $k = 0; + foreach ($cols as $col => $default) { + if (isset($line[$k])) { + if (in_array($k, $numbers)) { + $link[$col] = (float)str_replace(',', '.', $line[$k]); + } else if (in_array($k, $booleans)) { + $link[$col] = ($line[$k] == '1'); + } else { + $link[$col] = utf8_encode($line[$k]); + } + } else { + $link[$col] = $default; + } + $k++; + } + + if ($link['type'] == 18) { + $link['infobulle'] = $link['to']; + $link['to'] = ''; + } + + $link['display_area'] = '1'; + $link['page'] = $page; + $links[] = $link; + } + + } + + self::saveLinksInFile($book_id, $core->user->utilisateur_id, 'Links imported from PDF', $links, []); + } +} diff --git a/composer.json b/composer.json index 0c8b1c75d..02e8da463 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,8 @@ "ext-simplexml": "*", "ext-tidy": "*", "ext-zip": "*", + "ext-zlib": "*", + "ext-sodium": "*", "ahmadshah/lucy": "dev-master", "cubedesigners/userdatabase": "dev-master", "cubist/azuretts": "dev-master", diff --git a/resources/fluidbookpublication/cover/shade-cover-app.png b/resources/fluidbookpublication/cover/shade-cover-app.png new file mode 100644 index 000000000..f96319b35 Binary files /dev/null and b/resources/fluidbookpublication/cover/shade-cover-app.png differ