namespace App\Console\Commands;
-use App\Util\FluidbookFarm;
+use App\Fluidbook\Farm;
use Cubist\Backpack\Console\Commands\CubistCommand;
public function handle()
{
- FluidbookFarm::ping(true, $this->option('force', false));
+ Farm::ping(true, $this->option('force', false));
}
}
--- /dev/null
+<?php
+
+namespace App\Fluidbook;
+
+use Cubist\Util\Files\Files;
+use hollodotme\FastCGI\Client;
+use hollodotme\FastCGI\Requests\PostRequest;
+use hollodotme\FastCGI\SocketConnections\NetworkSocket;
+use function App\Util\is_countable;
+
+class Farm
+{
+ protected static $_farmServers = [
+ ['name' => 'alphaville', 'host' => 'fluidbook-processfarm', 'port' => 9000, 'weight' => 24],
+ ['name' => 'brazil', 'host' => 'brazil.cubedesigners.com', 'weight' => 6],
+ ['name' => 'clockwork', 'host' => 'clockwork.cubedesigners.com', 'weight' => 2],
+ ['name' => 'dracula', 'host' => 'dracula.cubedesigners.com', 'weight' => 3],
+ ['name' => 'elephantman', 'host' => 'elephantman.cubedesigners.com', 'weight' => 1],
+ ['name' => 'fastandfurious', 'host' => 'fastandfurious.cubedesigners.com', 'weight' => 1],
+ ['name' => 'godzilla', 'host' => 'godzilla.cubedesigners.com', 'weight' => 3],
+ ['name' => 'her', 'host' => 'her2.cubedesigners.com', 'weight' => 4],
+ ['name' => 'isleofdogs', 'host' => 'paris.cubedesigners.com', 'port' => 9458, 'weight' => 2],
+ ['name' => 'jumanji', 'host' => 'paris.cubedesigners.com', 'port' => 9459, 'weight' => 2],
+ ];
+
+ protected static function _pingCache()
+ {
+ return Files::mkdir(storage_path('fluidbookfarm')) . '/pings';
+ }
+
+ protected static function _serversCache()
+ {
+ return Files::mkdir(storage_path('fluidbookfarm')) . '/servers';
+ }
+
+ public static function getServers()
+ {
+ return self::$_farmServers;
+ }
+
+ public static function pickOneServer()
+ {
+ $hat = [];
+ $pingCache = self::_pingCache();
+ if (!file_exists($pingCache)) {
+ self::ping(false);
+ }
+ $pings = json_decode(file_get_contents(self::_pingCache()));
+
+ foreach (self::$_farmServers as $k => $farmServer) {
+ if (!isset($pings[$k]) || !$pings[$k]) {
+ continue;
+ }
+ for ($i = 0; $i < $farmServer['weight']; $i++) {
+ $hat[] = $k;
+ }
+ }
+ shuffle($hat);
+ $i = array_pop($hat);
+ return self::$_farmServers[$i];
+ }
+
+ public static function getFCGIConnexion(array $farm, $timeout = 240): NetworkSocket
+ {
+ $timeout *= 1000;
+ return new NetworkSocket($farm['host'], $farm['port'] ?? 9457, $timeout, $timeout);
+ }
+
+ public static function sendRequest($farmer, $url, $params = [], $timeout = 240)
+ {
+ set_time_limit(0);
+ $client = new Client();
+ $response = $client->sendRequest(self::getFCGIConnexion($farmer, $timeout), new PostRequest($url, http_build_query($params)));
+ return trim($response->getBody());
+ }
+
+ public static function getFile($page, $format, $resolution, $withText, $withGraphics, $version, $resolutionRatio, $mobileFirstRatio, $path, $force = false)
+ {
+ $start = microtime(true);
+ $farmer = self::pickOneServer();
+
+ $params = ['page' => $page, 'format' => $format, 'resolution' => $resolution, 'withText' => $withText, 'withGraphics' => $withGraphics, 'version' => $version, 'force' => $force, 'out' => $path, 'resolutionRatio' => $resolutionRatio, 'mobileRatio' => $mobileFirstRatio];
+
+ $output = self::sendRequest($farmer, 'process.php', $params);
+ if (preg_match('|/data1/extranet/www/[^\s]+|', $output, $matches)) {
+ $o = $matches[0];
+ } else {
+ $o = $output;
+ }
+
+ if (file_exists($o)) {
+ $res = $o;
+ } else {
+ echo $o;
+ $res = false;
+ }
+
+ $time = round(microtime(true) - $start, 4);
+ $log = '[' . $farmer['name'] . ']' . "\t" . date('Y-m-d H:i:s') . "\t" . $time . "\t$page|$format|$resolution|$withText|$withGraphics|$version\t$res\t" . $output . "\n";
+
+ error_log($log);
+
+ return $res;
+ }
+
+ public static function ping($echo = true, $force = false)
+ {
+ $cache = self::_pingCache();
+ $servers = self::getServers();
+ $pings = [];
+ if (file_exists($cache)) {
+ $cached = json_decode(file_get_contents($cache));
+ if (is_countable($cached) && count($cached) === count($servers)) {
+ $pings = $cached;
+ }
+ }
+
+ foreach ($servers as $id => $farmer) {
+ if ($echo) {
+ echo $farmer['name'] . ' (' . $id . ') || ';
+ }
+ if (isset($pings[$id]) && !$pings[$id]) {
+ // If ping failed recently, we wait a bit before trying again.
+ if (!$force && rand(0, 9) != 5) {
+ if ($echo) {
+ echo 'Skipped, will try again soon' . "\n";
+ }
+ continue;
+ }
+ }
+ try {
+ $res = self::sendRequest($farmer, 'ping.php', [], 5);
+ $ok = $res == '1';
+ } catch (\Exception $e) {
+ $res = $e->getMessage();
+ $ok = false;
+ }
+
+ if ($echo) {
+ echo ($ok ? 'OK' : 'KO') . ' : ' . trim($res) . "\n";
+ }
+
+ $pings[$id] = $ok;
+ }
+ file_put_contents($cache, json_encode($pings));
+ file_put_contents(self::_serversCache(), json_encode($servers));
+ }
+}
--- /dev/null
+<?php
+
+namespace App\Fluidbook;
+
+use App\Models\User;
+use App\Util\wsDAOBook;
+use App\Util\wsDocument;
+use Cubist\Util\Files\Files;
+use Cubist\Util\Str;
+use Fluidbook\Tools\Links\Link;
+use PhpOffice\PhpSpreadsheet\Cell\DataType;
+use PhpOffice\PhpSpreadsheet\Exception;
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Style\Alignment;
+use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
+use function App\Util\utf8_encode;
+
+class Links
+{
+ protected static $_testLinkCache = null;
+ protected static $_linksKey = null;
+
+ /**
+ * @throws Exception
+ */
+ public static function linksToExcel($links, $rulers, $pages = null)
+ {
+ set_time_limit(0);
+
+ $cols = array(
+ 'uid' => __('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 Spreadsheet();
+ $s = $xls->setActiveSheetIndex(0);
+ $s->setTitle('Links');
+
+ // Labels
+ $i = 1;
+ foreach ($cols as $id => $label) {
+ $s->setCellValueByColumnAndRow($i, 1, $id);
+ $s->getColumnDimensionByColumn($i)->setAutoSize(true);
+ $s->getStyleByColumnAndRow($i, 1)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
+ $i++;
+ }
+
+ // Links
+ self::_correctImageSpecialLinks($links);
+ $j = 2;
+ foreach ($links as $l) {
+ $i = 1;
+ 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(DataType::TYPE_STRING)->getStyle()->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT);
+ }
+ $value = $l[$id];
+ } else {
+ $value = '';
+ }
+ }
+
+ $s->setCellValueExplicitByColumnAndRow($i, $j, $value, DataType::TYPE_STRING);
+ $i++;
+ }
+ $j++;
+ }
+ // Rulers
+ $s = $xls->createSheet();
+ $s->setTitle('Rulers');
+
+ $rcols = array('page', 'type', 'pos');
+ $i = 1;
+ // Labels
+ foreach ($rcols as $id) {
+ $s->setCellValueByColumnAndRow($i, 1, $id);
+ $s->getColumnDimensionByColumn($i)->setAutoSize(true);
+ $i++;
+ }
+
+ // Contents
+ $j = 2;
+ foreach ($rulers as $r) {
+ $i = 1;
+ 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(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 . '.links3.gz';
+ if ($time === 'latest' && !file_exists($file)) {
+ $versions = self::getLinksVersions($book_id);
+ foreach ($versions as $version => $m) {
+ copy(Files::firstThatExists($dir . '/' . $version . '.links3.gz', $dir . '/' . $version . '.links.gz'), $dir . '/latest.links3.gz');
+ copy(Files::firstThatExists($dir . '/' . $version . '.meta3.gz', $dir . '/' . $version . '.meta.gz'), $dir . '/latest.meta3.gz');
+ break;
+ }
+ }
+ if (!file_exists($file)) {
+ $links = [];
+ $rulers = [];
+ return;
+ }
+
+ $r = json_decode(gzdecode(file_get_contents($file)), true);
+ $links = self::_UID($r['links']);
+ $rulers = self::_UID($r['rulers']);
+ if (can('fluidbook-publication:links:edit-animations')) {
+ $links = Link::decryptLinks($links);
+ }else{
+ $links = Link::encryptLinks($links);
+ }
+
+ self::_correctImageSpecialLinks($links);
+ }
+
+ protected static function _UID($items)
+ {
+ $res = [];
+ foreach ($items as $item) {
+ if (!isset($item['uid'])) {
+ $item['uid'] = self::uid();
+ }
+ $res[$item['uid']] = $item;
+ }
+ return $res;
+ }
+
+ protected static function uid()
+ {
+ return Str::lower(Str::random(12));
+ }
+
+ 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 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.links3.gz';
+ $latestMeta = self::getLinksDir($book_id) . '/latest.meta3.gz';
+ file_put_contents($base . '.meta3.gz', gzencode(json_encode($meta)));
+ file_put_contents($base . '.links3.gz', gzencode(json_encode($lr)));
+ copy($base . '.links3.gz', $latestLinks);
+ copy($base . '.meta3.gz', $latestMeta);
+ }
+
+
+ public static function getLinksDir($book_id)
+ {
+ return Files::mkdir('/data/extranet/www/fluidbook/books/links/' . $book_id);
+ }
+
+ public static function getLinksVersions($book_id)
+ {
+ $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[1] !== 'meta3.gz') || $e[0] === 'latest') {
+ continue;
+ }
+
+ $updates[$e[0]] = self::getMeta($book_id, $e[0]);
+ }
+ krsort($updates);
+
+
+ $res = [];
+ foreach ($updates as $timestamp => $u) {
+ try {
+ $u['name'] = User::find($u['user'])->name;
+ } catch (\Exception $e) {
+ $u['name'] = '-';
+ }
+ $u['date'] = date('Y-m-d H:i:s', $timestamp);
+ $u['timestamp'] = $timestamp;
+ $res[] = $u;
+ }
+
+ return $res;
+ }
+
+ public static function getMeta($book_id, $update = 'latest')
+ {
+ return json_decode(gzdecode(file_get_contents(Files::firstThatExists(self::getLinksDir($book_id) . '/' . $update . '.meta3.gz', 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));
+
+ $k = 0;
+ foreach ($l as $item) {
+ $item['id'] = $k + 1;
+ if (!isset($item['to'])) {
+ $item['to'] = '';
+ }
+ $finalLinks[] = $item;
+ $k++;
+ }
+
+ self::_correctImageSpecialLinks($finalLinks);
+
+ return ['links' => Link::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, []);
+ }
+
+ public static function getLinksAndRulersFromExcelFile($path, &$links, &$rulers)
+ {
+ $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
+ $xls = $reader->load($path);
+ Links::getLinksFromExcel($xls, $links, $rulers);
+ }
+
+ public static function generateUID()
+ {
+ $characters = '0123456789abcdefghijklmnopqrstuvwxyz';
+ $randstring = '';
+ for ($i = 0; $i < 12; $i++) {
+ $randstring = $characters[rand(0, 35)];
+ }
+ return $randstring;
+ }
+}
--- /dev/null
+<?php
+
+namespace App\Fluidbook\Packager;
+
+use Cubist\Util\CommandLine;
+use Cubist\Util\PHP;
+
+class Base extends \App\Jobs\Base
+{
+
+ protected $dir;
+ protected $vdir;
+ public $book;
+ protected $pages;
+ protected $theme;
+ protected $version;
+ protected $book_id;
+ protected $themeRoot;
+ protected $daoBook;
+ protected $zip;
+ protected $workingDir;
+ protected $whole = true;
+ protected $_clean = true;
+ protected $_compileOnConstruct = false;
+ public $cleanOnDestruct = true;
+
+ public static function package($book_id, $version, $zip = true, $cleanOnDestruct = true, $options = [])
+ {
+ global $packager;
+
+ PHP::neverStop();
+
+
+ if ($version === 'html') {
+ $packager = new Online($book_id, null, true, $options);
+ } else if ($version === 'scorm') {
+ $packager = new SCORM($book_id, null, true, $options);
+ } else if ($version === 'sharepoint') {
+ $packager = new Sharepoint($book_id, null, true, $options);
+ } elseif ($version === 'win_html') {
+ $packager = new OfflineHTML($book_id, null, true, $options);
+ } else if ($version === 'win_exe_html') {
+ $packager = new WindowsZIP($book_id, $options);
+ } else if ($version === 'mac_exe_html') {
+ $packager = new MacOS($book_id, $options);
+ } else if ($version === 'win_ins_html') {
+ $packager = new WindowsInstaller($book_id, $options);
+ } else if ($version === 'win_inss_html') {
+ $packager = new WindowsEXE($book_id, $options);
+ } else if ($version === 'win_cd_html') {
+ $packager = new USBKey($book_id, $options);
+ } else if ($version === 'precompiled') {
+ $packager = new Precompiled($book_id, null, true, $options);
+ } else if ($version === 'chromeos') {
+ $packager = new ChromeOS($book_id, null, true, $options);
+ }
+ $packager->cleanOnDestruct = $packager->cleanOnDestruct && $cleanOnDestruct;
+
+ return $packager->makePackage($zip);
+ }
+
+ public function __construct($book_id, $vdir = null, $whole = true, $options = [])
+ {
+
+ $this->_clean = (null === $vdir);
+
+ $this->book_id = $book_id;
+
+ $this->vdir = $vdir;
+ $this->dir = ROOT . '/fluidbook/packager/' . $book_id . '/';
+ $this->whole = $whole;
+
+ if (!file_exists($this->dir)) {
+ mkdir($this->dir, 0777, true);
+ }
+
+ $this->daoBook = new wsDAOBook($core->con);
+ $this->book = $this->daoBook->selectById($book_id);
+ $forceCompile = false;
+ if (count($options)) {
+ $options['forceCompileOnDownload'] = true;
+ }
+ foreach ($options as $k => $v) {
+ $this->book->parametres->$k = $v;
+ }
+
+ $this->pages = $this->daoBook->getPagesOfBook($book_id, false);
+
+ $daoTheme = new wsDAOTheme($core->con);
+ $this->theme = $daoTheme->getThemeOfBook($book_id, true);
+ $this->themeRoot = WS_THEMES . '/' . $this->theme->theme_id . '/';
+
+ $this->workingDir = $this->book->getAssetDir();
+
+ if ($this->_compileOnConstruct) {
+ $this->compile($forceCompile);
+ }
+ }
+
+
+ protected function compile($forceCompile = false)
+ {
+ $this->daoBook->compile($this->book_id, '2', false, $this->book->parametres->forceCompileOnDownload || $forceCompile, false, $this->book);
+ }
+
+ protected function preparePackage()
+ {
+ $this->initTempDir();
+ }
+
+ public function makePackage($zip)
+ {
+ $this->preparePackage();
+ }
+
+ protected function replaceContents($str, $toReplace)
+ {
+ $res = $str;
+ foreach ($toReplace as $k => $v) {
+ if (is_null($v)) {
+ return;
+ }
+ $res = str_replace('$' . $k, $v, $res);
+ }
+ return $res;
+ }
+
+ protected function copyFluidbookFiles()
+ {
+ // Copie du FB vers un répertoire temporaire
+ $cp = new CommandLine('cp');
+ $cp->setArg('R');
+ $cp->setArg('p');
+ $cp->setArg(null, WS_BOOKS . '/final/' . $this->book->book_id . '/*');
+ $cp->setArg(null, $this->vdir);
+ $cp->execute();
+ }
+
+ protected function copyOtherFiles($files)
+ {
+ foreach ($files as $source => $dest) {
+ if (is_int($source)) {
+ $source = $dest;
+ }
+
+ $s = WS_COMPILE_ASSETS . '/' . $source;
+ if (is_file($s) && !file_exists($this->vdir . $dest)) {
+ $this->copy($s, $this->vdir . $dest);
+ } else if (is_dir($s)) {
+ $cp = new CommandLine('cp');
+ $cp->setArg('R');
+ $cp->setArg('p');
+ $cp->setArg(null, $s);
+ $cp->setArg(null, $this->vdir);
+ $cp->execute();
+
+ $mv = new CommandLine('mv');
+ $mv->setArg($this->vdir . '/' . $source);
+ $mv->setArg($this->vdir . '/' . $dest);
+ $mv->execute();
+ }
+ }
+ }
+
+ protected function getBaseFile()
+ {
+ return $this->version . '-' . date('Ymdhis') . '-' . $this->escapeTitle();
+ }
+
+ protected function escapeTitle()
+ {
+ $res = cubeText::str2URL($this->book->parametres->title);
+ if ($res == '') {
+ $res = 'fluidbook';
+ }
+ return $res;
+ }
+
+ protected function getRelativeBase()
+ {
+ return '/packager/download/' . $this->getBaseFile();
+ }
+
+ protected function getURLBase($ext = '')
+ {
+ $res = '/fluidbook' . $this->getRelativeBase();
+ if ($ext != '') {
+ $res .= '.' . $ext;
+ }
+ return $res;
+ }
+
+ protected function getPathBase($ext = '')
+ {
+ $res = WS_FILES . $this->getRelativeBase();
+ if ($ext != '') {
+ $res .= '.' . $ext;
+ }
+
+ return $res;
+ }
+
+ protected function zip($zipfile = null)
+ {
+ if (!$this->whole) {
+ return;
+ }
+ $url = $this->getURLBase('zip');
+ $final = $this->getPathBase('zip');
+ $rename = false;
+ if (is_null($zipfile)) {
+ $zipfile = $final;
+ } else {
+ $rename = true;
+ }
+
+ $dir = $this->getFinalPackageDir();
+ if (file_exists($dir)) {
+ $zip = new CommandLine('zip');
+ $zip->cd($dir);
+ $zip->setArg(null, $zipfile);
+ $zip->setArg('symlinks');
+ $zip->setArg('0');
+ $zip->setArg('r');
+ $zip->setArg('u');
+ $zip->setArg(null, '.');
+ $zip->setManualArg('-x "*/\.*"');
+ $zip->execute();
+ $zip->debug();
+ }
+
+ if (!file_exists(WS_FILES . '/packager/download')) {
+ mkdir(WS_FILES . '/packager/download', 0777, true);
+ }
+
+ if ($rename) {
+ rename($zipfile, $final);
+ }
+ return $url;
+ }
+
+ public function getFinalPackageDir()
+ {
+ $dir = $this->vdir;
+ $dir .= '/m/';
+ return $dir;
+ }
+
+ protected function initTempDir()
+ {
+ if (is_null($this->vdir)) {
+ $this->vdir = $this->dir . $this->version . '/';
+ }
+ $this->cleanVdir();
+ if (!file_exists($this->vdir . '/data')) {
+ mkdir($this->vdir . '/data', 0777, true);
+ }
+ }
+
+ protected function cleanVdir()
+ {
+ if (!$this->_clean) {
+ return;
+ }
+ if (file_exists($this->vdir)) {
+ // Suppression du répertoire si il existe
+ $rm = new CommandLine('rm');
+ $rm->setArg('r');
+ $rm->setArg('f');
+ $rm->setArg(null, $this->vdir);
+ $rm->execute();
+ }
+ }
+
+ protected function postPackage()
+ {
+
+ }
+
+ public function __destruct()
+ {
+ if ($this->whole && $this->cleanOnDestruct) {
+ $this->cleanVdir();
+ }
+ }
+
+ public function copy($source, $dest)
+ {
+ if (!file_exists($source)) {
+ return;
+ }
+ copy($source, $dest);
+ touch($dest, filemtime($source));
+ }
+}
--- /dev/null
+<?php
+
+namespace App\Fluidbook\Packager;
+
+use Cubist\Util\CommandLine;
+
+class ChromeOS extends Online
+{
+ public function __construct($book_id, $vdir = null, $whole = true, $options = [])
+ {
+ parent::__construct($book_id, $vdir, $whole, $options);
+ $this->version = 'chromeos';
+ $this->cleanOnDestruct = true;
+ }
+
+ protected function preparePackage()
+ {
+ $res = parent::preparePackage();
+ $manifest = ['name' => $this->book->parametres->offlineTitle == '' ? $this->book->parametres->title : $this->book->parametres->offlineTitle,
+ 'version' => '1.0.' . time(),
+ 'manifest_version' => 3,
+ //'default_locale' => $this->book->lang,
+ //'icons' => [],
+ 'permissions' => [
+ 'webview',
+ ]
+ ];
+// $sizes=[128,64,32,16];
+// $pngFile = WS_THEMES . '/' . $this->theme->theme_id . '/' . $this->theme->parametres->favicon;
+// foreach ($sizes as $size) {
+//
+// }
+
+ file_put_contents($this->vdir . '/m/manifest.json', json_encode($manifest));
+ return $res;
+ }
+
+ public function makePackage($zip)
+ {
+ $this->preparePackage();
+
+ $chrome = new CommandLine('crx3');
+ $chrome->setArg('o', WS_PACKAGER . '/download/' . $this->getBaseFile() . '.crx');
+ $chrome->setArg(null, $this->vdir . '/m/');
+ $chrome->execute();
+ $chrome->debug();
+
+ return $this->getURLBase('crx');
+ }
+}
--- /dev/null
+<?php
+namespace App\Fluidbook\Packager;
+use Cubist\Util\CommandLine;
+
+class MacOS extends Offline
+{
+ protected $nwplatform = 'osx64';
+ protected $nwversion = '0.49.2';
+ protected $node_platform = 'mac';
+ protected $exenameMaxlength = 28;
+
+ public function __construct($book_id, $options = [])
+ {
+ parent::__construct($book_id, $options);
+ $this->version = 'mac_exe_html';
+ }
+
+ public function makePackage($zip)
+ {
+ $this->preparePackage();
+ $toDelete = ['chromedriver', 'credits.html', 'minidump_stackwalk', 'nwjc', 'payload', 'v8_context_snapshot.bin', 'natives_blob.bin', 'libffmpeg.dylib'];
+ foreach ($toDelete as $item) {
+ $p = $this->getFinalPackageDir() . '/' . $item;
+ `rm -rf "$p"`;
+ }
+ if ($zip) {
+ $res = $this->zip(null);
+ } else {
+ $res = $this->getFinalPackageDir();
+ }
+ $this->postPackage();
+ return $res;
+ }
+
+ public function getAppPath()
+ {
+ return $this->getFinalPackageDir() . '/' . $this->exeName . '.app';
+ }
+
+ public function getFinalPackageDir()
+ {
+ $res = parent::getFinalPackageDir();
+ return $res;
+ }
+
+ protected function preparePackage()
+ {
+ $this->initTempDir();
+ $this->copyFluidbookFiles();
+ $this->makeJSON();
+
+ $this->buildPath = WS_PACKAGER . '/nwbuild/' . $this->version . '/' . $this->book_id;
+ if (!file_exists($this->buildPath)) {
+ mkdir($this->buildPath, 0777, true);
+ }
+
+ $cl = new CommandLine('nwbuild');
+ $cl->setPath(CONVERTER_PATH);
+ $cl->setArg('p', $this->nwplatform);
+ $cl->setArg('o', $this->buildPath);
+ $cl->setArg('v', $this->nwversion);
+ $cl->setArg('winIco', $this->vdir . '/icon.ico');
+ $cl->setArg('macIcns', $this->vdir . '/icon.icns');
+ $cl->setArg(null, $this->vdir);
+ $cl->execute();
+ $cl->debug();
+
+ $this->replaceFFMpeg();
+ if(!file_exists($this->getAppPath())){
+ die('Error while building mac app : '.$cl->commande.' // '.$cl->output);
+ }
+
+ $this->signApp();
+ }
+
+ function replaceFFMpeg()
+ {
+ copy(WS_COMPILE_ASSETS . '/_exehtml/_ffmpeg/libffmpeg.dylib', $this->getAppPath() . '/Contents/Frameworks/nwjs Framework.framework/Versions/Current/libffmpeg.dylib');
+ }
+
+ protected function signApp()
+ {
+ self::_signApp($this->getAppPath());
+ }
+
+ public static function _signApp($appPath, $back = true)
+ {
+ $local_root = '/Users/vincent/Sign/';
+ $dist_root = '/mnt/sshfs/macparis' . $local_root;
+
+ $f = 'tmp_' . md5(rand(0, 1000000)) . ".app";
+ $path = $dist_root . $f;
+
+ // Copy app to mac
+ $cp = new CommandLine('cp');
+ $cp->setArg('r');
+ $cp->setArg(null, $appPath);
+ $cp->setArg(null, $path);
+ $cp->execute();
+ $cp->debug();
+
+ // Sign app
+ $cl = new CommandLine($local_root . 'sign');
+ $cl->setSSH(wsExporter::VINCENT, 'vincent', 'atacama', 22022);
+ $cl->setArg(null, $local_root . $f);
+ $cl->execute();
+ $cl->debug();
+ $res = $cl->output;
+
+ if ($back) {
+ // Copy back signed
+ $cp = new CommandLine('rsync');
+ $cp->setArg('r');
+ $cp->setArg('l');
+ $cp->setArg('p');
+ $cp->setArg('D');
+ $cp->setArg('v');
+ $cp->setArg(null, $path . '/');
+ $cp->setArg(null, $appPath . '/');
+ $cp->setArg('delete');
+ $cp->execute();
+ $cp->debug();
+ }
+
+ // `rm -rf $path`;
+ return $res;
+ }
+}
--- /dev/null
+<?php
+
+namespace App\Fluidbook\Packager;
+
+class OfflineHTML extends Online {
+ protected $_allowNetworking = 'internal';
+
+ protected function copyFluidbookFiles() {
+ parent::copyFluidbookFiles();
+ unlink($this->vdir . '/index.swf');
+ unlink($this->vdir . '/player.swf');
+ copy(WS_COMPILE_ASSETS . '/offline.swf', $this->vdir . '/index.swf');
+ }
+}
--- /dev/null
+<?php
+
+namespace App\Fluidbook\Packager;
+
+use Cubist\Util\CommandLine;
+
+class Online extends Base
+{ protected $origHTML;
+ protected $_labels = array();
+ protected $_allowNeworking = 'all';
+ protected $_ext = 'html';
+ protected $_disableScorm = true;
+ protected $_compileOnConstruct = false;
+
+ public function __construct($book_id, $vdir = null, $whole = true, $options = [])
+ {
+ parent::__construct($book_id, $vdir, $whole, $options);
+ $this->version = 'html';
+ }
+
+ protected function preparePackage()
+ {
+ parent::preparePackage();
+
+ if ($this->_disableScorm) {
+ $this->book->parametres->scorm_enable = false;
+ }
+
+ $this->_ext = $this->book->parametres->htmlExtension;
+ $this->book->parametres->actualHtmlExtension = $this->_ext;
+
+ $this->copyFluidbookFiles();
+ $this->mergeJavascript();
+
+// $others = array('fluidbook.js', 'getflash.gif', 'index.html', 'style.css');
+// $others = array_merge($others, $this->getSWFFiles());
+//
+// $this->copyOtherFiles($others);
+
+ if (!file_exists($this->vdir . '/pages')) {
+ mkdir($this->vdir . '/pages/', 0777, true);
+ }
+
+ $ga = '';
+ if ($this->book->parametres->googleAnalyticsCustom) {
+ $ga = $this->book->parametres->googleAnalyticsCustom;
+ } elseif ($this->book->parametres->googleAnalytics != '') {
+ $variables = array('Language' => array('value' => 'getLang()', 'valueAsJS' => true, 'scope' => 2));
+ $ga = cubePage::googleAnalytics(explode(',', $this->book->parametres->googleAnalytics), true, $variables);
+ }
+
+ $statsfooter = '';
+ if ($this->book->parametres->statsCustom != '') {
+ $statsfooter = $this->book->parametres->statsCustom;
+ }
+
+ $facebook = '';
+ if ($this->book->parametres->facebook) {
+ if ($this->book->parametres->facebook_title != '') {
+ $facebook .= '<meta property="og:title" content="' . self::escape($this->book->parametres->facebook_title) . '" />';
+ } else {
+ $facebook .= '<meta property="og:title" content="' . self::escape($this->book->parametres->title) . '" />';
+ }
+ if ($this->book->parametres->facebook_description != '') {
+ $facebook .= '<meta property="og:description" content="' . self::escape($this->book->parametres->facebook_description) . '" />';
+ }
+ $t = 'https://workshop.fluidbook.com/services/facebook_thumbnail?cid=' . $this->book->cid . '&j=' . time();
+ $dim = getimagesize($t);
+ $facebook .= '<meta property="og:image" content="' . $t . '" />';
+ $facebook .= '<meta property="og:image:width" content="' . $dim[0] . '" />';
+ $facebook .= '<meta property="og:image:height" content="' . $dim[1] . '" />';
+ }
+
+ $favicon = '';
+
+ if ($this->theme->parametres->favicon != '') {
+ $favicon = '<link rel="shortcut icon" href="data/fluidbook.ico">';
+ }
+
+ $redirectPDF = 'redirectPDF();';
+ if ($this->book->parametres->mobileVersion == 'pdf') {
+ $redirectMobile = $redirectPDF;
+ } else {
+ $redirectMobile = 'redirectMobile();';
+ $this->prepareHTML5();
+ }
+
+ $seoVersion = true;
+ if (isset($this->book->parametres->seoVersion)) {
+ $seoVersion = $this->book->parametres->seoVersion;
+ }
+
+ $seoRobot = true;
+ if (isset($this->book->parametres->seoRobots)) {
+ $seoRobot = $this->book->parametres->seoRobots;
+ }
+
+ $robots = '';
+ if (!$seoRobot) {
+ $robots = '<meta name="robots" content="noindex, nofollow">';
+ }
+
+ $keywords = '';
+ if ($this->book->parametres->seoKeywords) {
+ $keywords = '<meta name="keywords" content="' . self::escape($this->book->parametres->seoKeywords) . '">';
+ }
+
+ $alwaysHTML5 = true;
+ $html5priority = true;
+
+
+ // Stuffs to replace in html
+ $toReplace = array('lang' => strtolower($this->book->lang),
+ 'ga' => $ga,
+ 'statsfooter' => $statsfooter,
+ 'facebook' => $facebook,
+ 'bgcolor' => $this->theme->parametres->loadingBackColor,
+ 'junk' => TIME,
+ 'robots' => $robots,
+ 'favicon' => $favicon,
+ 'alwaysHTML5' => $alwaysHTML5,
+ 'keywords' => $keywords,
+ );
+
+ $this->origHTML = $this->book->parametres->htmlPrepend;
+ $h = $this->vdir . '/index.html';
+ if (file_exists($h)) {
+ $this->origHTML .= file_get_contents($h);
+ unlink($h);
+ }
+ $this->origHTML = $this->replaceHTML($toReplace);
+
+ $nav1 = $this->makeHTMLNav(true);
+ $nav = $this->makeHTMLNav(false);
+ $footer = $this->makeHTMLFooter();
+
+
+ foreach ($this->pages as $page => $infos) {
+ $pathToIndex = 'index.swf';
+ $pathToGetflash = 'getflash.gif';
+ $redirectScript = '';
+ if ($page == 1) {
+ $dest = 'index.' . $this->_ext;
+ $title = $this->book->parametres->title;
+ $sp = '';
+ } else {
+ $label = $this->_getLabelOfPage($page);
+ $title = $label . ' - ' . $this->book->parametres->title;
+ $dest = 'pages/' . $page . '-' . mb_strtolower(cubeText::str2URL($label)) . '.' . $this->_ext;
+ $pathToIndex = '../index.swf';
+ $pathToGetflash = '../getflash.gif';
+ $sp = '../';
+ $redirectScript = '<script type="text/javascript">window.location=\'../index.' . $this->_ext . '#/' . $page . '\';</script>';
+ }
+ $alt = '';
+
+// if ($seoVersion && CubeIT_Util_Gzip::file_exists($htmlfile)) {
+// $html = CubeIT_Util_Gzip::file_get_contents($htmlfile);
+// $alt .= "\n" . $html . "\n";
+//
+// if ($page == 1) {
+// $alt .= $nav1;
+// } else {
+// $alt .= $nav;
+// }
+// }
+
+ $alt .= $footer;
+
+ $base = '';
+ if ($this->book->parametres->baseUrl) {
+ $base = '<base href="' . $this->book->parametres->baseUrl . '" />';
+ }
+
+ if ($page == 1 && $this->book->parametres->seoDescription) {
+ $description = $this->book->parametres->seoDescription;
+ } else {
+ $textfile = wsDocument::getDir($infos['document_id']) . 'ph' . $infos['document_page'] . '.txt';
+ if (file_exists($textfile)) {
+ $description = mb_substr(file_get_contents($textfile), 0, 150);
+ } else {
+ $description = '';
+ }
+ }
+
+ $data = str_replace('$alt', $alt, $this->origHTML);
+ $data = str_replace('$base', $base, $data);
+ $data = str_replace('$pathToIndex', $pathToIndex, $data);
+ $data = str_replace('$title', $this->escape($title), $data);
+ $data = str_replace('$pathToGetflash', $pathToGetflash, $data);
+ $data = str_replace('$redirectScript', $redirectScript, $data);
+ $data = str_replace('$sp', $sp, $data);
+ $data = str_replace('$index_ext', $this->_ext, $data);
+ $data = str_replace('$description', '<meta name="description" content="' . self::escape($description, true) . '">', $data);
+
+ file_put_contents($this->vdir . $dest, $data);
+
+ if (!$seoVersion) {
+ break;
+ }
+ }
+ }
+
+ protected function getFlashvars()
+ {
+ return array();
+ }
+
+ public function prepareHTML5()
+ {
+ if (!$this->whole) {
+ return;
+ }
+ $dest = $this->vdir . 'm';
+
+ $mfid = $this->book->parametres->mobilefirstFluidbookId;
+ if ($mfid != '' && (int)$mfid > 0) {
+ $mfbook = $this->daoBook->selectById($mfid);
+ $this->_compileHTML5($this->book_id, $this->book, $dest . '/d', true);
+ $vars = wsDAOBook::$lastHTML5Compiler->getIndexVars();
+ $this->_compileHTML5($mfid, $mfbook, $dest . '/mf', true);
+
+ $hybrid = file_get_contents(WS_COMPILE_ASSETS . '/hybrid/index.html');
+ $replace = [
+ 'titre' => $vars['<!-- $titre -->'],
+ 'breakpoint' => $this->book->parametres->mobilefirstBreakpoint . 'px',
+ 'bgcolor' => $this->theme->parametres->loadingBackColor,
+ 'description' => $vars['<!-- $description -->'],
+ 'twittercard' => $vars['<!-- $twittercard -->'],
+ 'opengraph' => $vars['<!-- $opengraph -->'],
+ 'credits' => $vars['<!-- $credits -->'],
+ ];
+ foreach ($replace as $var => $value) {
+ $hybrid = str_replace('$' . $var, $value, $hybrid);
+ }
+ file_put_contents($dest . '/index.html', $hybrid);
+ } else {
+ $this->_compileHTML5($this->book_id, $this->book, $dest);
+ }
+
+ }
+
+ protected function _compileHTML5($bookId, $book, $dest, $hybrid = false)
+ {
+
+ $this->daoBook->compile($bookId, 'html5', false, $book->parametres->forceCompileOnDownload, false, $book, true, false, $hybrid);
+
+ if (!file_exists($dest)) {
+ mkdir($dest, 0777, true);
+ }
+
+ $cp = new CommandLine('cp');
+ $cp->setPath(CONVERTER_PATH);
+ $cp->setArg('r');
+ $cp->setArg('p');
+ $cp->setArg(null, WS_BOOKS . '/html5/' . $bookId . '/*');
+ $cp->setArg(null, $dest);
+ $cp->execute();
+
+ $filesToAdd = array();
+ foreach ($filesToAdd as $f) {
+ $this->copy(WS_COMPILE_ASSETS . '/_html5/' . $f, $dest . '/' . $f);
+ }
+
+ $filesToDelete = array('indext.html', 'indexu.html');
+
+ $htmlFiles = array('index');
+
+ foreach ($htmlFiles as $name) {
+ $html = $book->parametres->htmlPrepend . file_get_contents($dest . '/' . $name . '.html');
+ file_put_contents($dest . '/' . $name . '.' . $this->_ext, $html);
+ if ($this->_ext != 'html') {
+ $filesToDelete[] = $name . '.html';
+ }
+ }
+
+ $rm = new CommandLine('rm');
+ $rm->setPath(CONVERTER_PATH);
+ foreach ($filesToDelete as $f) {
+ $rm->setArg(null, $dest . '/' . $f);
+ }
+ $rm->execute();
+
+ if ($this->_ext !== 'html') {
+ $e = $this->_ext;
+ `find $dest -type f -name "*.html" -exec rename 's/\.html$/.$e/' '{}' \;`;
+
+ }
+ }
+
+ public function makePackage($zip)
+ {
+ parent::makePackage($zip);
+ if ($zip) {
+ return $this->zip();
+ }
+ return $this->getFinalPackageDir();
+ }
+
+ protected function makeHTMLNav($root)
+ {
+ $res = '<nav>';
+ foreach ($this->pages as $page => $infos) {
+ $label = $this->_getLabelOfPage($page);
+ if ($page == 1) {
+ if ($root) {
+ $url = 'index.' . $this->_ext;
+ } else {
+ $url = '../index.' . $this->_ext;
+ }
+ } else {
+ if ($root) {
+ $url = 'pages/' . $page . '-' . mb_strtolower(cubeText::str2URL($label)) . '.' . $this->_ext;
+ } else {
+ $url = $page . '-' . mb_strtolower(cubeText::str2URL($label)) . '.' . $this->_ext;
+ }
+ }
+ $res .= '<a href="' . $url . '">' . $label . '</a>';
+ }
+ $res .= '</nav>';
+ return $res;
+ }
+
+ protected function _getLabelOfPage($page)
+ {
+ if (!isset($this->_chapters)) {
+ $this->_chapters = $this->book->chapters;
+ }
+
+
+ if (isset($this->_labels[$page])) {
+ return $this->_labels[$page];
+ }
+
+
+ if ($page == 1) {
+ $this->_labels[1] = $this->book->parametres->title;
+
+ return $this->_labels[1];
+ }
+
+
+ $virtual = $this->_getVirtualPage($page);
+
+ $candidates = array();
+ foreach ($this->_chapters as $c) {
+ if ($c->page == $virtual) {
+ $candidates[] = $c;
+ }
+ }
+ if (!count($candidates)) {
+ $this->_labels[$page] = $this->_getLabelOfPage($page - 1);
+ return $this->_labels[$page];
+ }
+
+ usort($candidates, array($this, '_sortCandidates'));
+ $c = array_shift($candidates);
+
+ $this->_labels[$page] = $c->label;
+ return $this->_labels[$page];
+ }
+
+ protected function _sortCandidates($a, $b)
+ {
+ if ($a->level > $b->level) {
+ return 1;
+ } else if ($a->level < $b->level) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ protected function _getVirtualPage($page)
+ {
+ $num = explode(',', $this->book->numerotation);
+ if (isset($num[$page - 1])) {
+ return $num[$page - 1];
+ }
+ return 1;
+ }
+
+ protected function escape($txt, $replaceNewLines = false)
+ {
+ $res = htmlentities($txt, ENT_COMPAT, 'UTF-8');
+ if ($replaceNewLines) {
+ $res = str_replace("\n", ' ', $res);
+ $res = str_replace("\r", '', $res);
+ }
+ return $res;
+ }
+
+ protected function makeHTMLFooter()
+ {
+ $res = '<footer>';
+ $res .= '<h2><a href="https://www.fluidbook.com">Fluidbook : Solution de catalogues interactifs et brochures en ligne</a></h2>';
+ $res .= '</footer>';
+ return $res;
+ }
+
+ protected function replaceHTML($toReplace)
+ {
+ return $this->replaceContents($this->origHTML, $toReplace);
+ }
+
+ protected function mergeJavascript()
+ {
+ $dest = WS_COMPILE_ASSETS . '/fluidbook.js';
+ $orig = WS_COMPILE_ASSETS . '/_js/';
+ $files = array('log4js.js' => false, 'esapi.js' => false, 'resources/i18n/ESAPI_Standard_en_US.properties.js' => false, 'resources/Base.esapi.properties.js' => false, 'swfobject.js' => false, 'swfaddress.js' => true, 'fluidbook.js' => true);
+
+ $refresh = false;
+ if (file_exists($dest)) {
+ $mtime = filemtime($dest);
+ foreach ($files as $file => $min) {
+ if (filemtime($orig . $file) > $mtime) {
+ $refresh = true;
+ break;
+ }
+ }
+ } else {
+ $refresh = true;
+ }
+ if (!$refresh) {
+ return;
+ }
+
+ $minjs = "\n\n";
+ foreach ($files as $file => $min) {
+ $c = file_get_contents($orig . $file);
+ if ($min) {
+ $c = JSMin::minify($c);
+ }
+
+ $minjs .= $c . "\n\n";
+ }
+ file_put_contents($dest, $minjs);
+ }
+
+
+}
--- /dev/null
+<?php
+
+namespace App\Fluidbook\Packager;
+
+class Precompiled extends Online
+{
+ public function __construct($book_id, $vdir = null, $whole = true,$options=[])
+ {
+ parent::__construct($book_id, $vdir, $whole,$options);
+ $this->version = 'precompiled';
+ $this->book->parametres->embedAllLibraries = true;
+ }
+
+
+ public function prepareHTML5()
+ {
+ $res = parent::prepareHTML5();
+ $dest = $this->vdir . 'm';
+
+ // Copy styles
+ $source = wsHTML5::getSourcesPath($this->book->parametres->mobileLVersion);
+ $styles = $source . '/style';
+ $destLess = $dest . '/_less';
+ $cmd = "cp -R $styles $destLess";
+ `$cmd`;
+
+ // Copy theme assets
+ $theme = WS_THEMES . '/' . $this->book->theme . '/';
+ $destTheme = $dest . '/_theme';
+ $cmd = "cp -R -L $theme $destTheme";
+ `$cmd`;
+
+ // Cleanup
+ $clean = ['data/thumbnails', 'data/background', 'data/contents', 'data/*.pdf', 'data/style', 'style'];
+ foreach ($clean as $item) {
+ $path = $dest . '/' . $item;
+ if (strstr($item, '.')) {
+ `rm -f $path`;
+ } else {
+ `rm -rf $path`;
+ }
+ }
+
+ return $res;
+ }
+
+
+}
--- /dev/null
+<?php
+namespace App\Fluidbook\Packager;
+class Scorm extends Online
+{
+ public function __construct($book_id, $vdir = null, $whole = true, $options = [])
+ {
+ parent::__construct($book_id, $vdir, $whole, $options);
+ $this->version = 'scorm';
+ $this->_disableScorm = false;
+ }
+
+ protected function preparePackage()
+ {
+ $res = parent::preparePackage();
+ $manifests = $this->vdir . '/m/data/links/*/imsmanifest.xml';
+ $cmd = "rm $manifests";
+ `$cmd`;
+ return $res;
+ }
+}
--- /dev/null
+<?php
+
+namespace App\Fluidbook\Packager;
+
+class Sharepoint extends Online
+{
+ public function __construct($book_id, $vdir = null, $whole = true, $options = [])
+ {
+ parent::__construct($book_id, $vdir, $whole, $options);
+ $this->version = 'sharepoint';
+ $this->book->parametres->seoVersion = false;
+ $this->book->parametres->maxResolution = 150;
+ $this->book->parametres->htmlExtension = 'aspx';
+ }
+}
--- /dev/null
+<?php
+namespace App\Fluidbook\Packager;
+class USBKey extends MacOS
+{
+
+ public function __construct($book_id,$options=[])
+ {
+ parent::__construct($book_id,$options);
+ $this->version = 'win_cd_html';
+ }
+
+ protected function preparePackage()
+ {
+ parent::preparePackage();
+ $this->replaceAutorun();
+
+ // Package mac app
+ $win = ROOT . Base::package($this->book_id, 'win_inss_html', false, false);
+
+ $dest = $this->getFinalPackageDir() . "/" . $this->exeName . '.exe';
+ $cp = "cp $win $dest";
+ `$cp`;
+ }
+
+ public function replaceAutorun()
+ {
+ $inf = file_get_contents(WS_COMPILE_ASSETS . '/autorun-html.inf');
+ $toReplace = array('title' => $this->book->parametres->title, 'exe' => $this->exeName . '.exe', 'nwplatform' => $this->nwplatform);
+ $inf = $this->replaceContents($inf, $toReplace);
+ file_put_contents($this->getFinalPackageDir() . '/autorun.inf', utf8_decode($inf));
+ }
+
+
+ protected function postPackage()
+ {
+
+ }
+
+}
--- /dev/null
+<?php
+namespace App\Fluidbook\Packager;
+class WindowsEXE extends WindowsInstaller
+{
+
+ protected $nsifile = 'html-silent';
+
+ public function __construct($book_id, $options = [])
+ {
+ parent::__construct($book_id, $options);
+ $this->version = 'win_inss_html';
+ }
+}
--- /dev/null
+<?php
+namespace App\Fluidbook\Packager;
+class WindowsInstaller extends WindowsZIP
+{
+
+ protected $nsi;
+ protected $nsifile = 'html';
+
+ public function __construct($book_id, $options = [])
+ {
+ parent::__construct($book_id, $options);
+ $this->version = 'win_ins_html';
+ }
+
+ protected function preparePackage()
+ {
+ parent::preparePackage();
+
+ $this->makeNSI();
+ }
+
+ protected function makeNSI()
+ {
+ global $core;
+
+ $winvdir = $this->getFinalPackageDir();
+
+ $daoLang = new wsDAOLang($core->con);
+ $lang = $daoLang->selectById($this->book->lang);
+
+ if ($lang->nsis == 'Arabic') {
+ $lang->nsis = 'English';
+ }
+
+ if (!file_exists(WS_FILES . '/packager/download')) {
+ mkdir(WS_FILES . '/packager/download', 0777, true);
+ }
+
+ $fname = $this->exeName;
+ $title = $this->appName;
+
+ $nsi = file_get_contents(WS_COMPILE_ASSETS . '/' . $this->nsifile . '.nsi');
+ $nsi = str_replace('$name', $title, $nsi);
+ $nsi = str_replace('$htmldir', WS_COMPILE_ASSETS, $nsi);
+ $nsi = str_replace('$fname', $fname, $nsi);
+ $nsi = str_replace('$fdir', $winvdir, $nsi);
+ $nsi = str_replace('$titre', $title, $nsi);
+ $nsi = str_replace('$lang', $lang->nsis, $nsi);
+ $nsi = str_replace('$nwplatform', $this->nwplatform, $nsi);
+ $nsi = str_replace('$nsisdir', '/usr/local/share/nsis', $nsi);
+ $nsi = str_replace('$output', $this->getPathBase('exe'), $nsi);
+ $favicon = $this->vdir . 'data/favicon.ico';
+ if ($this->theme->parametres->favicon == '') {
+ $this->copy(WS_COMPILE_ASSETS . '/fluidbook.ico', $favicon);
+ } else if (!file_exists($favicon)) {
+ $pngFile = WS_THEMES . '/' . $this->theme->theme_id . '/' . $this->theme->parametres->favicon;
+ $icoFile = WS_THEMES . '/' . $this->theme->theme_id . '/favicon.ico';
+ if (!file_exists($icoFile) || filemtime($icoFile) < filemtime($pngFile) || filemtime(__FILE__) > filemtime($icoFile)) {
+ $tmp = CubeIT_Files::tempnam() . '.png';
+ $convert = "convert $pngFile -resize 64x64^ -gravity center $tmp";
+ `$convert`;
+
+ $icotool = new CommandLine('icotool');
+ $icotool->setArg('c');
+ $icotool->setArg('o', $icoFile);
+ $icotool->setArg(null, $tmp);
+ $icotool->execute();
+
+ unlink($tmp);
+ }
+ $this->copy($icoFile, $favicon);
+ if (!file_exists($favicon)) {
+ $this->copy(WS_COMPILE_ASSETS . '/fluidbook.ico', $favicon);
+ }
+ }
+ $nsi = str_replace('$favicon', $favicon, $nsi);
+
+ $this->nsi = $nsi;
+ }
+
+ public function makePackage($zip)
+ {
+ $this->preparePackage();
+
+ $tmp = cubeFiles::tempnam() . '.nsi';
+ file_put_contents($tmp, $this->nsi);
+ $makensis = new CommandLine('makensis');
+ $makensis->setArg(null, '-V4');
+ $makensis->setArg(null, $tmp);
+ $makensis->execute();
+ $makensis->debug();
+ if (!file_exists($this->getPathBase('exe'))) {
+ die('Error while building the installer : ' . $this->getPathBase('exe') . ' // ' . $makensis->commande . ' // ' . $makensis->output);
+ }
+
+ $this->signInstaller();
+
+ if (!file_exists($this->getPathBase('exe'))) {
+ die('Error during the signing process : ' . $this->getPathBase('exe'));
+ }
+
+ return $this->getURLBase('exe');
+ }
+
+ public function signInstaller()
+ {
+ $this->_sign($this->getPathBase('exe'));
+ }
+
+ public function __destruct()
+ {
+
+ }
+
+}
--- /dev/null
+<?php
+
+namespace App\Fluidbook\Packager;
+
+use Cubist\Net\SSH2;
+use Cubist\Util\CommandLine;
+
+class WindowsZIP extends Base
+{
+ protected $exeName;
+ protected $appName;
+ protected $buildPath;
+ protected $nwplatform = 'windows-x64';
+ protected $nwversion = '0.55.0';
+ protected $appversion = '';
+ protected $node_platform = 'win';
+ protected $exenameMaxlength = 30;
+ protected $_compileOnConstruct = true;
+
+ public function __construct($book_id, $options = [])
+ {
+ parent::__construct($book_id, null, true, $options);
+ $this->version = 'win_exe_html';
+ $this->appName = '';
+ $this->appversion = '1.0.' . time();
+ $this->_clean = false;
+
+ if ($this->book->parametres->offlineTitle == "") {
+ $this->exeName = $this->book->book_id . '-' . trim(cubeText::str2URL(mb_substr($this->book->parametres->title, 0, $this->exenameMaxlength - 6)), '-');
+ $this->appName = $this->book->parametres->title;
+ } else {
+ $this->exeName = trim(cubeText::str2URL(mb_substr($this->book->parametres->offlineTitle, 0, $this->exenameMaxlength)), '-');
+ $this->appName = $this->book->parametres->offlineTitle;
+ }
+
+ if ($this->exeName === '') {
+ $this->exeName = $book_id . '-fluidbook';
+ }
+ }
+
+ protected function preparePackage()
+ {
+
+ parent::preparePackage();
+
+ $this->copyFluidbookFiles();
+ $this->makeJSON();
+
+ $this->buildPath = WS_PACKAGER . '/nwbuild/' . $this->version . '/' . $this->book_id;
+
+ `umask 0000;rm -rf $this->buildPath;mkdir -p 0777 $this->buildPath;chmod -R 777 $this->vdir;mkdir -p 0777 /application/tmp;chmod -R 777 /application/tmp`;
+
+ $cl = new CommandLine('/usr/local/web2exe/web2exe-linux');
+ $cl->setSudo(true);
+ $cl->setEnv('TMPDIR', '/application/tmp');
+ $cl->setLongArgumentSeparator(' ');
+ $cl->setArg('export-to', $this->nwplatform);
+ $cl->setArg('uncompressed-folder');
+ $cl->setArg('title', $this->appName);
+ $cl->setArg('output-dir', $this->buildPath);
+ $cl->setArg('nw-version', $this->nwversion);
+ //$cl->setArg('sdk-build');
+ $cl->setArg('main', 'index.html');
+ $cl->setArg('name', $this->exeName);
+ $cl->setArg('mac-icon', $this->vdir . 'icon.icns');
+ $cl->setArg('exe-icon', $this->vdir . 'icon.ico');
+ $cl->setArg('icon', $this->vdir . 'icon.png');
+ $cl->setArg('width', 1024);
+ $cl->setArg('height', 768);
+ $cl->setArg('app-name', $this->exeName);
+ $cl->setArg('version', $this->appversion);
+ $cl->setArg('id', 'com.fluidbook.' . $this->book_id);
+ $cl->setArg('verbose');
+ $cl->setArg(null, $this->vdir);
+ $cl->execute();
+ $cl->debug();
+
+ `sudo chown -R extranet:www-data $this->buildPath`;
+
+ if (!file_exists($this->buildPath)) {
+ die('Error while making exe : ' . $cl->commande . ' // ' . $cl->output);
+ }
+
+ $this->replaceFFMpeg();
+
+ $this->signExe();
+ }
+
+ function signExe()
+ {
+ $exe = $this->buildPath . '/' . $this->exeName . '/' . $this->nwplatform . '/' . $this->exeName . '.exe';
+ $this->_sign($exe);
+ }
+
+ function _sign($exe)
+ {
+ $rand = 'sign-' . rand(1000000, 9999999) . '.exe';
+ copy($exe, '/mnt/sshfs/codesign/' . $rand);
+ $cli = new CommandLine('C:/Program Files (x86)/Windows Kits/10/bin/10.0.18362.0/x64/signtool.exe');
+ $cli->setManualArg("sign /f C:/Users/vince/Documents/Cubedesigners.cer /csp \"eToken Base Cryptographic Provider\" /k \"[SafeNet Token JC 0{{TYWjZacq%hAH98}}]=54C3F1B91759268A\" /tr http://timestamp.sectigo.com /td sha256 /fd sha256 /a C:/Sign/$rand");
+ $cli->execute(new SSH2('paris.cubedesigners.com', 'vince', 'Y@mUC9mY2DOYWXkN', '22422'));
+ $cli->debug();
+ sleep(2);
+ copy('/mnt/sshfs/codesign/' . $rand, $exe);
+ unlink('/mnt/sshfs/codesign/' . $rand);
+ }
+
+ function replaceFFMpeg()
+ {
+ copy(WS_COMPILE_ASSETS . '/_exehtml/_ffmpeg/' . $this->nwplatform . '-ffmpeg.dll', $this->getFinalPackageDir() . '/ffmpeg.dll');
+ }
+
+ function makeJSON()
+ {
+ $data = ['app_name' => $this->appName, 'main' => 'index.html', 'name' => $this->exeName, 'version' => '1.0.' . time(),
+ 'webkit' => [],
+ 'window' => ['height' => 768, 'width' => 1024, 'title' => $this->appName, 'id' => 'main', 'icon' => 'icon.png', 'mac_icon' => 'icon.icns'],
+ 'dependencies' => ['child_process' => "^1.0.2",
+ 'fs' => '0.0.1-security',
+ 'path' => '^0.12.7'],
+ ];
+
+ if ($this->book->parametres->offlineWindowsProfilePath != '') {
+ $datadir = str_replace('%title%', $this->exeName, $this->book->parametres->offlineWindowsProfilePath);
+ $data['chromium-args'] = '--crash-dumps-dir=\'' . $datadir . '\' --user-data-dir=\'' . $datadir . '\'';
+ }
+
+
+ $pngIcon = $this->vdir . '/icon.png';
+ $winIcon = $this->vdir . '/icon.ico';
+
+ $png = WS_COMPILE_ASSETS . '/fluidbook.png';
+ $ico = WS_COMPILE_ASSETS . '/fluidbook.ico';
+
+ if ($this->theme->parametres->favicon != '') {
+ if (file_exists($this->vdir . '/data/favicon.png')) {
+ $png = $this->vdir . '/data/favicon.png';
+ }
+ if (file_exists($this->vdir . '/data/favicon.ico')) {
+ $ico = $this->vdir . '/data/favicon.ico';
+ }
+ }
+
+ $icns = $this->vdir . '/icon.icns';
+ $this->copy($png, $pngIcon);
+ $this->copy($ico, $winIcon);
+ commonTools::pngToIcns($png, $icns);
+
+
+ file_put_contents($this->vdir . '/package.json', json_encode($data));
+ }
+
+ public function makePackage($zip)
+ {
+ parent::makePackage($zip);
+ $res = $this->zip();
+ $this->postPackage();
+ return $res;
+ }
+
+ public function getFinalPackageDir()
+ {
+ return $this->buildPath . '/' . $this->exeName . '/' . $this->nwplatform;
+ }
+
+ protected function compile($forceCompile = false)
+ {
+ // For exe version, force to export only the html5 version
+ // No need to export pages with texts for this version, we are certain that svg is supported if enabled
+ if ($this->book->parametres->mobileVersion == 'html5-desktop') {
+ $this->book->parametres->mobileVersion = 'html5';
+ }
+ $this->book->parametres->seoVersion = false;
+
+ $this->daoBook->compile($this->book_id, 'html5', false, $this->book->parametres->forceCompileOnDownload, false, $this->book);
+ }
+
+ protected function copyFluidbookFiles()
+ {
+ // Copie du FB vers un répertoire temporaire
+ $cp = new CommandLine('cp');
+ $cp->setArg('R');
+ $cp->setArg('p');
+ $cp->setArg(null, WS_BOOKS . '/html5/' . $this->book->book_id . '/*');
+ $cp->setArg(null, $this->vdir);
+ $cp->execute();
+
+ $this->copyExtras();
+ $this->copyNodeModules();
+ }
+
+ protected function copyExtras()
+ {
+
+ if ($this->book->parametres->form == 'bourbon') {
+
+ $dest = $this->vdir . '/exe';
+ if (!file_exists($dest)) {
+ mkdir($dest, 0777, true);
+ }
+ $this->copy(WS_FILES . '/bourbon/sendemail.exe', $dest . '/sendemail.exe');
+ }
+ }
+
+ protected function copyNodeModules()
+ {
+ $dest = $this->vdir . '/node_modules';
+ if (!file_exists($dest)) {
+ mkdir($dest, 0777, true);
+ }
+ $cp = new CommandLine('cp');
+ $cp->setArg('R');
+ $cp->setArg('p');
+ $cp->setArg(null, WS_COMPILE_ASSETS . '/_exehtml/_node_modules_' . $this->node_platform . '/*');
+ $cp->setArg(null, $dest);
+ $cp->execute();
+ }
+}
namespace App\Http\Controllers\Admin\Operations\FluidbookPublication;
-use App\Models\FluidbookDocument;
+use App\Fluidbook\Links;
use App\Models\FluidbookPublication;
-use App\Util\FluidbookLinks;
use Cubist\Backpack\Http\Controllers\Base\XSendFileController;
use Cubist\Util\Files\Files;
use Illuminate\Http\UploadedFile;
abort(401);
}
- FluidbookLinks::saveLinksInFile($fluidbook_id,
+ Links::saveLinksInFile($fluidbook_id,
backpack_user()->id,
request('message'),
json_decode(request('links', '[]'), true),
);
$fb = FluidbookPublication::find($fluidbook_id);
- return response()->json(['assets' => $fb->getLinksAssetsDimensions(), 'versions' => FluidbookLinks::getLinksVersions($fluidbook_id)]);
+ return response()->json(['assets' => $fb->getLinksAssetsDimensions(), 'versions' => Links::getLinksVersions($fluidbook_id)]);
}
protected function moveLinks($fluidbook_id)
$width = $fb->getPageWidth();
$isOnePage = $fb->isOnePage();
- FluidbookLinks::getLinksAndRulers($fluidbook_id, $links, $rulers);
+ Links::getLinksAndRulers($fluidbook_id, $links, $rulers);
$rlinks = array();
foreach ($links as $k => $link) {
$rrulers[$k] = $ruler;
}
- FluidbookLinks::saveLinksInFile($fluidbook_id, backpack_user()->id, __('Décalage de :nb pages à partir de la page :page', ['nb' => $offset, 'page' => $from]), $rlinks, $rrulers);
+ Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __('Décalage de :nb pages à partir de la page :page', ['nb' => $offset, 'page' => $from]), $rlinks, $rrulers);
return response()->json(['success' => 'ok']);
}
if (!FluidbookPublication::hasPermission($fluidbook_id)) {
abort(401);
}
- $links = FluidbookLinks::getLinksVersions($fluidbook_id);
+ $links = Links::getLinksVersions($fluidbook_id);
return response()->json($links);
}
if (!FluidbookPublication::hasPermission($fluidbook_id)) {
abort(401);
}
- FluidbookLinks::getLinksAndRulers($fluidbook_id, $links, $rulers, $version);
- $xlsx = FluidbookLinks::linksToExcel($links, $rulers);
+ Links::getLinksAndRulers($fluidbook_id, $links, $rulers, $version);
+ $xlsx = Links::linksToExcel($links, $rulers);
$tmpfile = Files::tempnam() . '.xlsx';
$writer = new Xlsx($xlsx);
$writer->save($tmpfile);
abort(401);
}
- FluidbookLinks::getLinksAndRulers($fluidbook_id, $links, $rulers, $version);
- FluidbookLinks::saveLinksInFile($fluidbook_id, backpack_user()->id, __('Restaurer la sauvegarde des liens :date', ['date' => date('Y-m-d H:i:s', $version)]), $links, $rulers, [], []);
+ Links::getLinksAndRulers($fluidbook_id, $links, $rulers, $version);
+ Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __('Restaurer la sauvegarde des liens :date', ['date' => date('Y-m-d H:i:s', $version)]), $links, $rulers, [], []);
return response()->json(['success' => 'ok']);
}
/** @var UploadedFile $uploadedFile */
$uploadedFile = request()->file('file');
- FluidbookLinks::getLinksAndRulersFromExcelFile($uploadedFile->getPathname(), $links, $rulers);
- FluidbookLinks::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Remplacer les liens à partir du fichier :file", ['file' => $uploadedFile->getClientOriginalName()]), $links, $rulers, [], []);
+ Links::getLinksAndRulersFromExcelFile($uploadedFile->getPathname(), $links, $rulers);
+ Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Remplacer les liens à partir du fichier :file", ['file' => $uploadedFile->getClientOriginalName()]), $links, $rulers, [], []);
return response()->json(['success' => 'ok']);
}
/** @var UploadedFile $uploadedFile */
$uploadedFile = request()->file('file');
- FluidbookLinks::getLinksAndRulers($fluidbook_id, $merged_links, $merged_rulers);
- FluidbookLinks::getLinksAndRulersFromExcelFile($uploadedFile->getPathname(), $links, $rulers);
+ Links::getLinksAndRulers($fluidbook_id, $merged_links, $merged_rulers);
+ Links::getLinksAndRulersFromExcelFile($uploadedFile->getPathname(), $links, $rulers);
$existing_uids = [];
foreach ($merged_links as $merged_link) {
$existing_uids[$merged_link['uid']] = true;
foreach ($links as $link) {
if (isset($existing_uids[$link['uid']])) {
- $link['uid'] = FluidbookLinks::generateUID();
+ $link['uid'] = Links::generateUID();
$existing_uids[$link['uid']] = true;
}
$merged_links[] = $link;
$merged_rulers = array_merge($merged_rulers, $rulers);
- FluidbookLinks::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Ajouter les liens à partir du fichier :file", ['file' => $uploadedFile->getClientOriginalName()]) . ' ', $merged_links, $merged_rulers, [], []);
+ Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Ajouter les liens à partir du fichier :file", ['file' => $uploadedFile->getClientOriginalName()]) . ' ', $merged_links, $merged_rulers, [], []);
return response()->json(['success' => 'ok']);
}
namespace App\Jobs;
+use App\Fluidbook\Links;
+use App\Fluidbook\Link\Link;
use App\Fluidbook\PDF;
-use App\Http\Controllers\Admin\Operations\FluidbookPublication\Services\SocialImageOperation;
-use App\Http\Controllers\Admin\Operations\Tools\Favicon;
-use App\Models\Signature;
use App\Fluidbook\SearchIndex;
use App\Fluidbook\SEO\Document;
+use App\Http\Controllers\Admin\Operations\FluidbookPublication\Services\SocialImageOperation;
+use App\Http\Controllers\Admin\Operations\Tools\Favicon;
use App\Models\FluidbookPublication;
use App\Models\FluidbookTheme;
use App\Models\FluidbookTranslate;
+use App\Models\Signature;
use App\Models\Traits\FluidbookPlayerBranches;
-use App\Util\FluidbookLinks;
use Cubist\Backpack\Magic\Fields\Checkbox;
use Cubist\Excel\ExcelToArray;
use Cubist\Locale\Country;
use DOMDocument;
use DOMElement;
use DOMXPath;
-use Faker\Provider\File;
use Fluidbook\Tools\Compiler\CompilerInterface;
use Fluidbook\Tools\Links\AnchorLink;
use Fluidbook\Tools\Links\ContentLink;
-use App\Fluidbook\Link\Link;
use Fluidbook\Tools\SVG\SVGTools;
use Illuminate\Console\Command;
use SimpleXMLElement;
$file = $cdir . $this->fluidbookSettings->basketReferences;
$this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file);
- FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
+ Links::getLinksAndRulers($this->book_id, $links, $rulers);
foreach ($links as $link) {
if ($link['type'] == '12') {
$file = $cdir . $this->fluidbookSettings->basketReferences;
$this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file);
- FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
+ Links::getLinksAndRulers($this->book_id, $links, $rulers);
foreach ($this->config->basketReferences as $ref => $data) {
$source = $cdir . '/' . $data['Image'];
$this->vdir->copy($cdir . $f, 'data/commerce/' . $f);
}
- FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
+ Links::getLinksAndRulers($this->book_id, $links, $rulers);
}
public function writeGrandPavoisCart()
$file = $cdir . $this->fluidbookSettings->basketReferences;
$this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file);
- FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
+ Links::getLinksAndRulers($this->book_id, $links, $rulers);
}
$this->config->eanReferences = ExcelToArray::excelToArrayIndexKeyVars($eanFile);
}
- FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
+ Links::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';
$this->vdir->copyDirectory($d['dir'], $d['fdir']);
}
- FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
+ Links::getLinksAndRulers($this->book_id, $links, $rulers);
if ($this->fluidbookSettings->basketManager === 'Puma') {
foreach ($links as $k => $init) {
$anchorExists[$linkData['to']] = $linkData;
}
if ($linkData['type'] == 35 || $linkData['type'] == 15 || $linkData['type'] == 39) {
- $linkData = FluidbookLinks::decryptLink($linkData);
+ $linkData = Links::decryptLink($linkData);
$animations = ContentLink::parseAnimations($linkData['image_rollover']);
foreach ($animations as $animation) {
if (isset($animation['backgroundcolor']) && $animation['backgroundcolor'] !== 'transparent') {
namespace App\Models;
+use App\Fluidbook\Farm;
use App\Jobs\FluidbookDocumentFileProcess;
use App\Jobs\FluidbookDocumentUpload;
use App\Models\Base\ToolboxModel;
-use App\Util\FluidbookFarm;
use Cubist\Backpack\Magic\Fields\Integer;
use Cubist\Backpack\Magic\Fields\Text;
use Cubist\Backpack\Magic\Fields\Textarea;
public function _getFile($page, $format = 'jpg', $resolution = 150, $withText = true, $withGraphics = true, $version = 'html')
{
if (!$this->hasFile($page, $format, $resolution, $withText, $withGraphics, $version)) {
- return FluidbookFarm::getFile($page, $format, $resolution, $withText, $withGraphics, $version, $this->getResolutionRatio(), $this->getMobileFirstRatio(), $this->path());
+ return Farm::getFile($page, $format, $resolution, $withText, $withGraphics, $version, $this->getResolutionRatio(), $this->getMobileFirstRatio(), $this->path());
}
$path = $this->_getPath($page, $format, $resolution, $withText, $withGraphics, $version);
use App\Fields\FluidbookComposition;
use App\Fields\FluidbookLocale;
use App\Fields\User;
+use App\Fluidbook\Links;
use App\Http\Controllers\Admin\Operations\FluidbookPublication\CompositionOperation;
use App\Http\Controllers\Admin\Operations\FluidbookPublication\DeletefbOperation;
use App\Http\Controllers\Admin\Operations\FluidbookPublication\DownloadOperation;
+use App\Http\Controllers\Admin\Operations\FluidbookPublication\EditOperation;
use App\Http\Controllers\Admin\Operations\FluidbookPublication\PreviewOperation;
use App\Http\Controllers\Admin\Operations\FluidbookPublication\StatsOperation;
-use App\Http\Controllers\Admin\Operations\FluidbookPublication\EditOperation;
use App\Jobs\FluidbookImagesPreprocess;
use App\Models\Base\ToolboxSettingsModel;
use App\Models\Traits\PublicationSettings;
use App\Models\Traits\SCORMVersionTrait;
-use App\Util\FluidbookLinks;
use Backpack\CRUD\app\Http\Controllers\Operations\CloneOperation;
use Backpack\CRUD\app\Library\Widget;
use Cubist\Backpack\Magic\Fields\FormBigSection;
public function getLinksAndRulers(&$links, &$rulers)
{
- FluidbookLinks::getLinksAndRulers($this->id, $links, $rulers);
+ Links::getLinksAndRulers($this->id, $links, $rulers);
}
public function getLinksAssetsDimensions()
+++ /dev/null
-<?php
-
-namespace App\Util;
-
-use Cubist\Util\Files\Files;
-use hollodotme\FastCGI\Client;
-use hollodotme\FastCGI\Requests\PostRequest;
-use hollodotme\FastCGI\SocketConnections\NetworkSocket;
-
-class FluidbookFarm
-{
- protected static $_farmServers = [
- ['name' => 'alphaville', 'host' => 'fluidbook-processfarm', 'port' => 9000, 'weight' => 24],
- ['name' => 'brazil', 'host' => 'brazil.cubedesigners.com', 'weight' => 6],
- ['name' => 'clockwork', 'host' => 'clockwork.cubedesigners.com', 'weight' => 2],
- ['name' => 'dracula', 'host' => 'dracula.cubedesigners.com', 'weight' => 3],
- ['name' => 'elephantman', 'host' => 'elephantman.cubedesigners.com', 'weight' => 1],
- ['name' => 'fastandfurious', 'host' => 'fastandfurious.cubedesigners.com', 'weight' => 1],
- ['name' => 'godzilla', 'host' => 'godzilla.cubedesigners.com', 'weight' => 3],
- ['name' => 'her', 'host' => 'her2.cubedesigners.com', 'weight' => 4],
- ['name' => 'isleofdogs', 'host' => 'paris.cubedesigners.com', 'port' => 9458, 'weight' => 2],
- ['name' => 'jumanji', 'host' => 'paris.cubedesigners.com', 'port' => 9459, 'weight' => 2],
- ];
-
- protected static function _pingCache()
- {
- return Files::mkdir(storage_path('fluidbookfarm')) . '/pings';
- }
-
- protected static function _serversCache()
- {
- return Files::mkdir(storage_path('fluidbookfarm')) . '/servers';
- }
-
- public static function getServers()
- {
- return self::$_farmServers;
- }
-
- public static function pickOneServer()
- {
- $hat = [];
- $pingCache = self::_pingCache();
- if (!file_exists($pingCache)) {
- self::ping(false);
- }
- $pings = json_decode(file_get_contents(self::_pingCache()));
-
- foreach (self::$_farmServers as $k => $farmServer) {
- if (!isset($pings[$k]) || !$pings[$k]) {
- continue;
- }
- for ($i = 0; $i < $farmServer['weight']; $i++) {
- $hat[] = $k;
- }
- }
- shuffle($hat);
- $i = array_pop($hat);
- return self::$_farmServers[$i];
- }
-
- public static function getFCGIConnexion(array $farm, $timeout = 240): NetworkSocket
- {
- $timeout *= 1000;
- return new NetworkSocket($farm['host'], $farm['port'] ?? 9457, $timeout, $timeout);
- }
-
- public static function sendRequest($farmer, $url, $params = [], $timeout = 240)
- {
- set_time_limit(0);
- $client = new Client();
- $response = $client->sendRequest(self::getFCGIConnexion($farmer, $timeout), new PostRequest($url, http_build_query($params)));
- return trim($response->getBody());
- }
-
- public static function getFile($page, $format, $resolution, $withText, $withGraphics, $version, $resolutionRatio, $mobileFirstRatio, $path, $force = false)
- {
- $start = microtime(true);
- $farmer = self::pickOneServer();
-
- $params = ['page' => $page, 'format' => $format, 'resolution' => $resolution, 'withText' => $withText, 'withGraphics' => $withGraphics, 'version' => $version, 'force' => $force, 'out' => $path, 'resolutionRatio' => $resolutionRatio, 'mobileRatio' => $mobileFirstRatio];
-
- $output = self::sendRequest($farmer, 'process.php', $params);
- if (preg_match('|/data1/extranet/www/[^\s]+|', $output, $matches)) {
- $o = $matches[0];
- } else {
- $o = $output;
- }
-
- if (file_exists($o)) {
- $res = $o;
- } else {
- echo $o;
- $res = false;
- }
-
- $time = round(microtime(true) - $start, 4);
- $log = '[' . $farmer['name'] . ']' . "\t" . date('Y-m-d H:i:s') . "\t" . $time . "\t$page|$format|$resolution|$withText|$withGraphics|$version\t$res\t" . $output . "\n";
-
- error_log($log);
-
- return $res;
- }
-
- public static function ping($echo = true, $force = false)
- {
- $cache = self::_pingCache();
- $servers = self::getServers();
- $pings = [];
- if (file_exists($cache)) {
- $cached = json_decode(file_get_contents($cache));
- if (is_countable($cached) && count($cached) === count($servers)) {
- $pings = $cached;
- }
- }
-
- foreach ($servers as $id => $farmer) {
- if ($echo) {
- echo $farmer['name'] . ' (' . $id . ') || ';
- }
- if (isset($pings[$id]) && !$pings[$id]) {
- // If ping failed recently, we wait a bit before trying again.
- if (!$force && rand(0, 9) != 5) {
- if ($echo) {
- echo 'Skipped, will try again soon' . "\n";
- }
- continue;
- }
- }
- try {
- $res = self::sendRequest($farmer, 'ping.php', [], 5);
- $ok = $res == '1';
- } catch (\Exception $e) {
- $res = $e->getMessage();
- $ok = false;
- }
-
- if ($echo) {
- echo ($ok ? 'OK' : 'KO') . ' : ' . trim($res) . "\n";
- }
-
- $pings[$id] = $ok;
- }
- file_put_contents($cache, json_encode($pings));
- file_put_contents(self::_serversCache(), json_encode($servers));
- }
-}
+++ /dev/null
-<?php
-
-namespace App\Util;
-
-use App\Models\FluidbookPublication;
-use App\Models\User;
-use Cubist\Util\ArrayUtil;
-use Cubist\Util\Crypt;
-use Cubist\Util\Files\Files;
-use Cubist\Util\ObjectUtil;
-use Cubist\Util\Str;
-use Fluidbook\Tools\Links\Link;
-use PhpOffice\PhpSpreadsheet\Cell\DataType;
-use PhpOffice\PhpSpreadsheet\Exception;
-use PhpOffice\PhpSpreadsheet\Spreadsheet;
-use PhpOffice\PhpSpreadsheet\Style\Alignment;
-use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
-use SodiumException;
-
-class FluidbookLinks
-{
- protected static $_testLinkCache = null;
- protected static $_linksKey = null;
-
- /**
- * @throws Exception
- */
- public static function linksToExcel($links, $rulers, $pages = null)
- {
- set_time_limit(0);
-
- $cols = array(
- 'uid' => __('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 Spreadsheet();
- $s = $xls->setActiveSheetIndex(0);
- $s->setTitle('Links');
-
- // Labels
- $i = 1;
- foreach ($cols as $id => $label) {
- $s->setCellValueByColumnAndRow($i, 1, $id);
- $s->getColumnDimensionByColumn($i)->setAutoSize(true);
- $s->getStyleByColumnAndRow($i, 1)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
- $i++;
- }
-
- // Links
- self::_correctImageSpecialLinks($links);
- $j = 2;
- foreach ($links as $l) {
- $i = 1;
- 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(DataType::TYPE_STRING)->getStyle()->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT);
- }
- $value = $l[$id];
- } else {
- $value = '';
- }
- }
-
- $s->setCellValueExplicitByColumnAndRow($i, $j, $value, DataType::TYPE_STRING);
- $i++;
- }
- $j++;
- }
- // Rulers
- $s = $xls->createSheet();
- $s->setTitle('Rulers');
-
- $rcols = array('page', 'type', 'pos');
- $i = 1;
- // Labels
- foreach ($rcols as $id) {
- $s->setCellValueByColumnAndRow($i, 1, $id);
- $s->getColumnDimensionByColumn($i)->setAutoSize(true);
- $i++;
- }
-
- // Contents
- $j = 2;
- foreach ($rulers as $r) {
- $i = 1;
- 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(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 . '.links3.gz';
- if ($time === 'latest' && !file_exists($file)) {
- $versions = self::getLinksVersions($book_id);
- foreach ($versions as $version => $m) {
- copy(Files::firstThatExists($dir . '/' . $version . '.links3.gz', $dir . '/' . $version . '.links.gz'), $dir . '/latest.links3.gz');
- copy(Files::firstThatExists($dir . '/' . $version . '.meta3.gz', $dir . '/' . $version . '.meta.gz'), $dir . '/latest.meta3.gz');
- break;
- }
- }
- if (!file_exists($file)) {
- $links = [];
- $rulers = [];
- return;
- }
-
- $r = json_decode(gzdecode(file_get_contents($file)), true);
- $links = self::_UID($r['links']);
- $rulers = self::_UID($r['rulers']);
- if (can('fluidbook-publication:links:edit-animations')) {
- $links = Link::decryptLinks($links);
- }else{
- $links = Link::encryptLinks($links);
- }
-
- self::_correctImageSpecialLinks($links);
- }
-
- protected static function _UID($items)
- {
- $res = [];
- foreach ($items as $item) {
- if (!isset($item['uid'])) {
- $item['uid'] = self::uid();
- }
- $res[$item['uid']] = $item;
- }
- return $res;
- }
-
- protected static function uid()
- {
- return Str::lower(Str::random(12));
- }
-
- 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 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.links3.gz';
- $latestMeta = self::getLinksDir($book_id) . '/latest.meta3.gz';
- file_put_contents($base . '.meta3.gz', gzencode(json_encode($meta)));
- file_put_contents($base . '.links3.gz', gzencode(json_encode($lr)));
- copy($base . '.links3.gz', $latestLinks);
- copy($base . '.meta3.gz', $latestMeta);
- }
-
-
- public static function getLinksDir($book_id)
- {
- return Files::mkdir('/data/extranet/www/fluidbook/books/links/' . $book_id);
- }
-
- public static function getLinksVersions($book_id)
- {
- $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[1] !== 'meta3.gz') || $e[0] === 'latest') {
- continue;
- }
-
- $updates[$e[0]] = self::getMeta($book_id, $e[0]);
- }
- krsort($updates);
-
-
- $res = [];
- foreach ($updates as $timestamp => $u) {
- try {
- $u['name'] = User::find($u['user'])->name;
- } catch (\Exception $e) {
- $u['name'] = '-';
- }
- $u['date'] = date('Y-m-d H:i:s', $timestamp);
- $u['timestamp'] = $timestamp;
- $res[] = $u;
- }
-
- return $res;
- }
-
- public static function getMeta($book_id, $update = 'latest')
- {
- return json_decode(gzdecode(file_get_contents(Files::firstThatExists(self::getLinksDir($book_id) . '/' . $update . '.meta3.gz', 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));
-
- $k = 0;
- foreach ($l as $item) {
- $item['id'] = $k + 1;
- if (!isset($item['to'])) {
- $item['to'] = '';
- }
- $finalLinks[] = $item;
- $k++;
- }
-
- self::_correctImageSpecialLinks($finalLinks);
-
- return ['links' => Link::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, []);
- }
-
- public static function getLinksAndRulersFromExcelFile($path, &$links, &$rulers)
- {
- $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
- $xls = $reader->load($path);
- FluidbookLinks::getLinksFromExcel($xls, $links, $rulers);
- }
-
- public static function generateUID()
- {
- $characters = '0123456789abcdefghijklmnopqrstuvwxyz';
- $randstring = '';
- for ($i = 0; $i < 12; $i++) {
- $randstring = $characters[rand(0, 35)];
- }
- return $randstring;
- }
-}