]> _ Git - cubeextranet.git/commitdiff
(no commit message)
authorvincent@cubedesigners.com <vincent@cubedesigners.com@f5622870-0f3c-0410-866d-9cb505b7a8ef>
Mon, 20 Jan 2014 10:36:58 +0000 (10:36 +0000)
committervincent@cubedesigners.com <vincent@cubedesigners.com@f5622870-0f3c-0410-866d-9cb505b7a8ef>
Mon, 20 Jan 2014 10:36:58 +0000 (10:36 +0000)
inc/ws/Controlleur/class.ws.services.php
inc/ws/DAO/class.ws.dao.book.php

index 302331732904494c4ed5d419b38f6de0c7d52c0b..894e70c9a4084769c43665a3ccdb68dd6054e9f5 100644 (file)
-<?php\r
-\r
-class wsServices extends cubeFlashGateway {\r
-\r
-       const CNAME = __CLASS__;\r
-\r
-       public static function in($args) {\r
-               global $core;\r
-               $args = cubePage::getArgs($args);\r
-               $n = self::CNAME;\r
-               $gateway = new $n($core->con, $args);\r
-       }\r
-\r
-       public function sendEmail() {\r
-               if (!$this->_checkHash()) {\r
-                       return;\r
-               }\r
-               // Send the email\r
-               $mail = new cubeMail();\r
-               $mail->returnPath = 'postmaster@fluidbook.com';\r
-               $mail->acknowledge = isset($this->args['askAcknowledge']) && $this->args['askAcknowledge'];\r
-               $mail->charset = 'UTF-8';\r
-               $mail->to = $this->args['email'];\r
-               $mail->from = $this->args['fromname'] . '<' . $this->args['fromemail'] . '>';\r
-               $mail->subject = $this->args['subject'];\r
-               $mail->body = $this->args['body'];\r
-               $this->xml->addChild('ok', $mail->send() ? '1' : '0');\r
-       }\r
-\r
-       protected function _checkHash() {\r
-               // Check protection hash\r
-               $hash = md5(substr($this->args['fromemail'], 2, 6) . substr($this->args['email'], 3, 5) . 'SFGHF566!S' . $this->args['id']);\r
-               if ($hash != $this->args['hash']) {\r
-                       $this->xml->addChild('hashOK', '0');\r
-                       $this->xml->addChild('ok', '0');\r
-                       return false;\r
-               }\r
-               $this->xml->addChild('hashOK', '1');\r
-               return true;\r
-       }\r
-\r
-       public function sendBookmarks() {\r
-               if (!$this->_checkHash()) {\r
-                       return;\r
-               }\r
-\r
-               $bookmarks = json_decode(base64_decode($this->args['bookmarks']), true);\r
-               $files = array();\r
-               foreach ($bookmarks as $b) {\r
-                       $range = $b['page'];\r
-                       if ($b['nb'] > 1) {\r
-                               $range.='-' . ($b['page'] + $b['nb'] - 1);\r
-                       }\r
-\r
-                       $file = $this->getPDFComplex($this->args['id'], $range);\r
-                       $files[] = array('name' => $b['name'], 'file' => $file['file']);\r
-               }\r
-\r
-               $limit = 5 * 1024 * 1024 * 0.8;\r
-               $groups = array();\r
-               $group = array();\r
-               $groupsize = 0;\r
-               foreach ($files as $f) {\r
-                       $size = filesize($f['file']);\r
-\r
-                       if ($groupsize + $size > $limit) {\r
-                               if (count($group)) {\r
-                                       $groups[] = $group;\r
-                                       $group = array();\r
-                                       $groupsize = 0;\r
-                               }\r
-\r
-                               $group[] = $f;\r
-                               $groupsize = $size;\r
-\r
-                               if ($groupsize > $limit) {\r
-                                       $groups[] = $group;\r
-                                       $group = array();\r
-                                       $groupsize = 0;\r
-                               }\r
-                       } else {\r
-                               $group[] = $f;\r
-                               $groupsize+=$size;\r
-                       }\r
-               }\r
-\r
-               if (count($group)) {\r
-                       $groups[] = $group;\r
-               }\r
-\r
-\r
-               $total = count($groups);\r
-               foreach ($groups as $i => $g) {\r
-                       $s = '';\r
-                       if ($total > 1) {\r
-                               $s = ' (' . ($i + 1) . '/' . $total . ')';\r
-                       }\r
-\r
-                       // Send the email\r
-                       $mail = new cubeMail();\r
-                       $mail->returnPath = 'postmaster@fluidbook.com';\r
-                       $mail->acknowledge = isset($this->args['askAcknowledge']) && $this->args['askAcknowledge'];\r
-                       $mail->charset = 'UTF-8';\r
-                       $mail->to = $this->args['email'];\r
-                       $mail->from = $this->args['fromname'] . '<' . $this->args['fromemail'] . '>';\r
-                       $mail->subject = $this->args['subject'] . $s;\r
-                       $mail->body = $this->args['body'];\r
-                       foreach ($g as $f) {\r
-                               $mail->addFile($f['name'] . '.pdf', $f['file']);\r
-                       }\r
-                       $this->xml->addChild('ok', $mail->send() ? '1' : '0');\r
-               }\r
-       }\r
-\r
-       protected function shortenURL($url, $id) {\r
-               $bitLyUser = 'fluidbook';\r
-               $bitLyKey = 'R_3858dd1c9884d5c6a5fe386d7e95cf1d';\r
-               // Recherche dans le cache\r
-               $r = $this->con->select('SELECT * FROM book_short_url WHERE long_url=\'' . $this->con->escape($url) . '\' LIMIT 1');\r
-               if ($r->count() > 0) {\r
-                       return $r->short_url;\r
-               }\r
-               // Si pas dans le cache, on le recherche\r
-               $short_url = cubeURLShortener::bitLy($url, $bitLyUser, $bitLyKey);\r
-               if (is_null($short_url) || empty($short_url) || !$short_url) {\r
-                       $short_url = cubeURLShortener::tinyURL($url);\r
-               }\r
-               $short_url = trim($short_url);\r
-\r
-               $c = $this->con->openCursor('book_short_url');\r
-               $c->long_url = $url;\r
-               $c->book_id = $id;\r
-               $c->short_url = $short_url;\r
-               $c->insert();\r
-\r
-               return $short_url;\r
-       }\r
-\r
-       /**\r
-        * wsServices::facebook_thumbnail()\r
-        *\r
-        * @return\r
-        */\r
-       public function facebook_thumbnail() {\r
-               $this->outputXML = false;\r
-               $dao = new wsDAOBook($this->con);\r
-\r
-               $book = $dao->selectById($this->args['id']);\r
-\r
-\r
-               if (isset($book->parametres->facebook_image) && $book->parametres->facebook_image != '') {\r
-                       $c = WS_BOOKS . '/working/' . $this->args['id'] . '/' . $book->parametres->facebook_image;\r
-                       if (file_exists($c)) {\r
-                               $cover = $c;\r
-                       }\r
-               }\r
-               if (!isset($cover)) {\r
-                       $pages = $dao->getPagesOfBook($this->args['id']);\r
-                       $cover = WS_DOCS . '/' . $pages[1]['document_id'] . '/html/t36-' . $pages[1]['document_page'] . '.jpg';\r
-                       if (!file_exists($cover)) {\r
-                               $cover = WS_DOCS . '/' . $pages[1]['document_id'] . '/p' . $pages[1]['document_page'] . '.jpg';\r
-                       }\r
-               }\r
-               cubeHTTP::relayFile($cover);\r
-               exit;\r
-       }\r
-\r
-       public function facebookShare() {\r
-               http::redirect('http://www.facebook.com/sharer/sharer.php?u=' . urlencode($this->args['url']));\r
-               exit;\r
-       }\r
-\r
-       public function googleplusShare() {\r
-               http::redirect('https://plus.google.com/share?url=' . urlencode($this->args['url']) . "&sgp=1");\r
-               exit;\r
-       }\r
-\r
-       public function linkedinShare() {\r
-               http::redirect('https://www.linkedin.com/cws/share?url=' . urlencode($this->args['url']) . '&isFramed=true&_ts=' . microtime(true));\r
-       }\r
-\r
-       public function viadeoShare() {\r
-               http::redirect('http://www.viadeo.com/shareit/share/?url=' . urlencode($this->args['url']));\r
-       }\r
-\r
-       public function twitterShare() {\r
-               $url = $this->shortenURL($this->args['url'], $this->args['id']);\r
-\r
-               $post = str_replace('%short%', $url, $this->args['post']);\r
-               $post = rawurlencode($post);\r
-\r
-               http::redirect('http://twitter.com/intent/tweet?source=webclient&text=' . $post);\r
-               exit;\r
-       }\r
-\r
-       public function searchHints() {\r
-               $index = Zend_Search_Lucene::open(WS_BOOKS . '/search/' . $this->args['id']);\r
-\r
-               $charsLimit = 2;\r
-\r
-               $terms = $this->getTerms($this->args['term']);\r
-               $term = array_pop($terms);\r
-\r
-               if (strlen($term) < $charsLimit) {\r
-                       $this->xml->addChild('hints', '{}');\r
-                       return;\r
-               }\r
-\r
-               $term = new Zend_Search_Lucene_Index_Term($term . '*', 'contents');\r
-               $query = new Zend_Search_Lucene_Search_Query_Wildcard($term);\r
-               $query->setMinPrefixLength($charsLimit);\r
-\r
-               $index->find($query);\r
-               $terms = $query->getQueryTerms();\r
-               $res = array();\r
-               foreach ($terms as $t) {\r
-                       $res[$t->text] = array_sum($index->termFreqs($t));\r
-               }\r
-               arsort($res);\r
-               $res = array_slice($res, 0, 10, true);\r
-               $this->xml->addChild('hints', json_encode($res));\r
-       }\r
-\r
-       public function searchResults() {\r
-               $index = Zend_Search_Lucene::open(WS_BOOKS . '/search/' . $this->args['id']);\r
-\r
-               $terms = $this->getTerms($this->args['term']);\r
-\r
-               $query = new Zend_Search_Lucene_Search_Query_MultiTerm();\r
-               foreach ($terms as $term) {\r
-                       $query->addTerm(new Zend_Search_Lucene_Index_Term($term, 'contents'), null);\r
-               }\r
-\r
-               $hits = $index->find($query);\r
-               $res = array();\r
-               $terms = array();\r
-               foreach ($query->getQueryTerms() as $t) {\r
-                       $terms[] = $t->text;\r
-                       foreach ($index->termFreqs($t) as $doc_id => $f) {\r
-                               $page = trim($index->getDocument($doc_id)->getField('url')->getUtf8Value(), "#");\r
-                               if (!isset($res[$page])) {\r
-                                       $res[$page] = 0;\r
-                               }\r
-                               $res[$page]+=$f;\r
-                       }\r
-               }\r
-               $this->xml->addChild('results', json_encode($res));\r
-               $this->xml->addChild('terms', implode(',', $terms));\r
-       }\r
-\r
-       protected function getTerms($term) {\r
-               $term = trim($term, '*? ');\r
-               $term = mb_strtolower($term);\r
-               $term = cubeText::removeAccents($term);\r
-               $terms = explode(' ', $term);\r
-               return $terms;\r
-       }\r
-\r
-       public function printpdf() {\r
-               $this->outputXML = false;\r
-               $this->exportpdf(true);\r
-       }\r
-\r
-       protected function getPDFComplex($book, $range) {\r
-               global $core;\r
-\r
-               $daoBook = new wsDAOBook($core->con);\r
-\r
-               if (is_int($book) || is_string($book)) {\r
-                       $book = $daoBook->selectById($book);\r
-               }\r
-\r
-               if (is_null($book)) {\r
-                       return;\r
-               }\r
-\r
-               // Normalize range\r
-               $range = cubeArray::parseRange($range);\r
-\r
-               if ($k = array_search(0, $range)) {\r
-                       $range[$k] = 1;\r
-               }\r
-               if ($k = array_search($book->parametres->pages + 1, $range)) {\r
-                       $range[$k] = $r->pages;\r
-               }\r
-\r
-               if (!count($range)) {\r
-                       return;\r
-               }\r
-               // Paths init\r
-               $baseDocument = WS_BOOKS . '/final/' . $book->book_id . '/data/' . $book->parametres->pdfName;\r
-               if (!file_exists($baseDocument)) {\r
-                       return;\r
-               }\r
-               $destDir = WS_CACHE . '/exportpdf/' . $book->cid;\r
-               if (!file_exists($destDir)) {\r
-                       mkdir($destDir, 0777, true);\r
-               }\r
-               $fname = md5(implode(',%ù', $range)) . '.pdf';\r
-               $destFile = $destDir . '/' . $fname;\r
-               $destURL = '/fluidbook/cache/exportpdf/' . $book->cid . '/' . $fname;\r
-               // If result exists, don't make the pdf again\r
-               if (file_exists($destFile) && filemtime($destFile) > filemtime($baseDocument)) {\r
-                       \r
-               } else {\r
-                       // Prepare the command line\r
-                       $l = array('A=' . $baseDocument, 'cat');\r
-                       foreach ($range as $page) {\r
-                               if ($page < 1 || $page > $book->parametres->pages) {\r
-                                       continue;\r
-                               }\r
-                               $l[] = 'A' . $page;\r
-                       }\r
-                       $l[] = 'output';\r
-                       $l[] = $destFile;\r
-\r
-                       $args = implode(' ', $l);\r
-                       // Execute the command line\r
-                       $pdftk = new cubeCommandLine('pdftk');\r
-                       $pdftk->setPath(CONVERTER_PATH);\r
-                       $pdftk->setManualArg($args);\r
-                       $pdftk->execute();\r
-               }\r
-\r
-               return array('url' => $destURL, 'file' => $destFile);\r
-       }\r
-\r
-       public function e() {\r
-               $this->args['cid'] = $this->callArgs[0];\r
-               $this->args['range'] = $this->callArgs[1];\r
-               return $this->exportpdf();\r
-       }\r
-\r
-       public function p() {\r
-               $this->args['cid'] = $this->callArgs[0];\r
-               $this->args['range'] = $this->callArgs[1];\r
-               return $this->exportpdf(true);\r
-       }\r
-\r
-       public function exportpdf($print = false) {\r
-               global $core;\r
-\r
-               $dao = new wsDAOBook($core->con);\r
-               if (isset($this->args['cid'])) {\r
-                       $book = $dao->selectByCid($this->args['cid']);\r
-               } else if ($this->args['id'] < 11202) {\r
-                       $book = $dao->selectById($this->args['id']);\r
-               }\r
-\r
-               $dest = $this->getPDFComplex($book, $this->args['range']);\r
-\r
-               if (!$print) {\r
-                       // Return the url of the resulting pdf\r
-                       http::redirect($dest['url']);\r
-                       exit;\r
-               } else {\r
-                       $this->outputXML = false;\r
-                       $res = '<!DOCTYPE html><html><head>\r
-                               <meta http-equiv="X-UA-Compatible" content="IE=8" />                            \r
-                               <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script>\r
-                               <script type="text/javascript" src="/js/pdfprint.js"></script>\r
-                               <link rel="stylesheet" type="text/css" href="/style/ws/printpdf.css" />\r
-                               </head>\r
-                               <body>\r
-                               <iframe id="pdf" name="pdff" src="' . $dest['url'] . '" width="100%" height="100%"></iframe>\r
-                               </body>\r
-                               </html>';\r
-                       ob_end_clean();\r
-                       echo $res;\r
-                       exit;\r
-               }\r
-       }\r
-\r
-       public function bulle() {\r
-               global $core;\r
-               $e = explode('-', $this->args['catalogue'], 2);\r
-               if (count($e) == 2) {\r
-                       $catalogue = $e[1];\r
-               } else {\r
-                       $catalogue = $e[0];\r
-               }\r
-\r
-               $c = $core->con->openCursor('bulle');\r
-               $c->prenom = trim($this->args['prenom']);\r
-               $c->nom = trim($this->args['nom']);\r
-               $c->catalogue = trim($catalogue);\r
-               $c->email = trim($this->args['email']);\r
-               $c->date = TIME;\r
-               $c->insert();\r
-       }\r
-\r
-       public function getBulleList() {\r
-               $user = 'bulle';\r
-               $pass = '23bu1l300';\r
-               $this->outputXML = false;\r
-               $ok = (isset($_SERVER['PHP_AUTH_USER']) && $_SERVER['PHP_AUTH_USER'] == $user && isset($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_PW'] == $pass);\r
-               if (!$ok) {\r
-                       header('WWW-Authenticate: Basic realm="Protected access"');\r
-                       header('HTTP/1.0 401 Unauthorized');\r
-                       ob_end_clean();\r
-                       header('Content-type: text/html');\r
-                       echo '<h1>Forbidden</h1>';\r
-                       exit;\r
-               } else {\r
-                       global $core;\r
-                       header('Content-type: text/csv');\r
-                       header('Content-Disposition: attachment; filename="inscriptions.csv"');\r
-                       $r = $core->con->select('SELECT * FROM bulle ORDER BY date');\r
-                       ob_end_clean();\r
-                       echo utf8_decode('"Prénom";"Nom";"E-mail";"Catalogue";"Date"') . "\n";\r
-                       while ($r->fetch()) {\r
-                               echo utf8_decode('"' . $r->prenom . '";"' . $r->nom . '";"' . $r->email . '";"' . $r->catalogue . '";"' . date('Y-m-d H:i', $r->date) . '"') . "\n";\r
-                       }\r
-                       exit;\r
-               }\r
-       }\r
-\r
-       public function grdfValidForm() {\r
-               $notempty = array('civilite', 'prenom', 'nom', 'adresse', 'codepostal', 'ville', 'telephone', 'optin', 'connu', 'energie');\r
-               $error = false;\r
-               $errors = array();\r
-               foreach ($notempty as $f) {\r
-                       if (!isset($this->args[$f]) || is_null($this->args[$f]) || $this->args[$f] == 'null' || trim($this->args[$f]) == '') {\r
-                               $error = true;\r
-                               $errors[] = $f;\r
-                       }\r
-               }\r
-\r
-               /* if (!cubeMail::isEmail($this->args['email'])) {\r
-                 $error = true;\r
-                 $errors[] = 'email_valid';\r
-                 } */\r
-\r
-               $this->xml->addChild('ok', $error ? '0' : '1');\r
-               $this->xml->addChild('errors', implode(',', $errors));\r
-       }\r
-\r
-       public function grdfSendForm() {\r
-               global $core;\r
-\r
-               $fields = array('Civilité' => 'civilite', 'Prénom' => 'prenom', 'Nom' => 'nom',\r
-                       'E-mail' => 'email', 'Adresse' => 'adresse', 'Code postal' => 'codepostal', 'Ville' => 'ville',\r
-                       'Téléphone' => 'telephone', 'Connu par' => 'connu', 'Energie' => 'energie',\r
-                       'Optin' => 'optin', 'Coupons sélectionnés' => 'reflist');\r
-\r
-               $mail = new cubeMail();\r
-               $mail->charset = 'UTF-8';\r
-               $mail->subject = '[Chéquier avantages] Validation de coupon';\r
-               $mail->from = 'noreply@chequieravantages.fr';\r
-               $mail->replyTo = 'noreply@chequiavantages.fr';\r
-               $mail->to = 'projetrenogaz@grdf.fr';\r
-               $mail->bcc = 'test@cubedesigners.com';\r
-               $body = '';\r
-\r
-               foreach ($fields as $k => $f) {\r
-                       $body.=$k . ' : ' . $this->args[$f] . "\r\n";\r
-                       $datas[$f] = $this->args[$f];\r
-               }\r
-               $datas['date'] = TIME;\r
-\r
-               $c = $core->con->openCursor('grdf2013');\r
-               $c->datas = json_encode($datas);\r
-               $c->insert();\r
-\r
-               $mail->body = $body;\r
-               $mail->send();\r
-       }\r
-\r
-       public function grdfCoupon() {\r
-               $this->outputXML = false;\r
-               $couponsRoot = WS_BOOKS . '/working/11222/commerce/';\r
-\r
-               $xml = simplexml_load_file($couponsRoot . 'references.xml');\r
-               // Check hash\r
-               $hash = md5('ae' . $_GET['nom'] . '25' . $_GET['ref']);\r
-               if ($hash != $_GET['h']) {\r
-                       exit;\r
-               }\r
-               $refs = explode(',', $_GET['ref']);\r
-               $pdf = new FPDI();\r
-               foreach ($refs as $ref) {\r
-\r
-                       foreach ($xml->xpath('//item[@reference=\'' . $ref . '\']') as $item) {\r
-                               $code = (string) $item['code'];\r
-                       }\r
-\r
-                       $file = $couponsRoot . $ref . '.pdf';\r
-\r
-                       $pdf->setSourceFile($file);\r
-                       $idx = $pdf->importPage(1);\r
-                       $pdf->AddPage();\r
-                       $pdf->useTemplate($idx);\r
-                       $pdf->SetXY(11, 12);\r
-                       $pdf->SetFont('Helvetica', '', 12);\r
-                       $pdf->SetTextColor(0, 0, 0);\r
-                       $pdf->Cell(180, 10, utf8_decode(trim($_GET['civilite'] . ' ' . $_GET['prenom'] . ' ' . $_GET['nom']) . ','));\r
-                       $pdf->SetXY(143, 203);\r
-                       $pdf->SetFont('Helvetica', 'B', 18);\r
-                       $pdf->Cell(33, 15, $code);\r
-               }\r
-               $pdf->Output('coupon.pdf', 'I');\r
-       }\r
-\r
-       public function grdfExcel12568() {\r
-               global $core;\r
-               $this->outputXML = false;\r
-\r
-\r
-               $couponsRoot = WS_BOOKS . '/working/11222/commerce/';\r
-\r
-               $xml = simplexml_load_file($couponsRoot . 'references.xml');\r
-\r
-               $cols = array('Date' => 'date', 'Civilité' => 'civilite', 'Prénom' => 'prenom', 'Nom' => 'nom',\r
-                       'E-mail' => 'email', 'Adresse' => 'adresse', 'Code postal' => 'codepostal', 'Ville' => 'ville',\r
-                       'Téléphone' => 'telephone', 'Connu par' => 'connu', 'Energie' => 'energie',\r
-                       'Optin' => 'optin');\r
-               $refs = array();\r
-               foreach ($xml->xpath('//item') as $i) {\r
-                       $refs[(string) $i['reference']] = $i['name'];\r
-               }\r
-\r
-               // \r
-               $h = '<table>';\r
-               $h.='<tr>';\r
-               foreach ($cols as $l => $k) {\r
-                       $h.='<th>' . utf8_decode($l) . '</th>';\r
-               }\r
-               foreach ($refs as $k => $l) {\r
-                       $h.='<th>' . utf8_decode($l) . '</th>';\r
-               }\r
-               $h.='</tr>';\r
-\r
-               $r = $core->con->select('SELECT * FROM grdf2013');\r
-               while ($r->fetch()) {\r
-                       $d = json_decode($r->datas);\r
-                       $rl = explode(',', $d->reflist);\r
-                       $h.='<tr>';\r
-                       foreach ($cols as $l => $k) {\r
-                               $v = $d->$k;\r
-                               if ($k == 'date') {\r
-                                       $v = date('Y-m-d H:i', $v);\r
-                               }\r
-                               $h.='<td>' . utf8_decode($v) . '</td>';\r
-                       }\r
-                       foreach ($refs as $k => $l) {\r
-                               $v = in_array($k, $rl) ? '1' : '0';\r
-                               $h.='<td>' . utf8_decode($v) . '</td>';\r
-                       }\r
-                       $h.='</tr>';\r
-               }\r
-\r
-               $h.='</table>';\r
-\r
-               if (!file_exists(ROOT . '/cache/12568/')) {\r
-                       mkdir(ROOT . '/cache/12568/', 0777, true);\r
-               }\r
-               file_put_contents(ROOT . '/cache/12568/chequieravantage.xls', $h);\r
-               http::redirect('/cache/12568/chequieravantage.xls');\r
-               exit;\r
-       }\r
-\r
-       public function proxy() {\r
-               ob_end_clean();\r
-               fb(netHttp::quickGet($_GET['u'], 'php://output'));\r
-               $this->outputXML = false;\r
-       }\r
-\r
-       public function wescoRef() {\r
-               global $core;\r
-\r
-               $ref = ltrim(substr($this->args['ref'], 4), '0');\r
-\r
-               $r = $core->con->select('SELECT url FROM wescoref WHERE ref="' . $core->con->escape($ref) . '"');\r
-               if ($r->count()) {\r
-                       header('Location: ' . $r->url);\r
-                       exit;\r
-               }\r
-               $cache = ROOT . '/cache/wesco/' . $this->args['ref'];\r
-               if (file_exists($cache)) {\r
-                       header('Location: ' . file_get_contents($cache));\r
-                       exit;\r
-               }\r
-               $url = 'http://www.wesco-eshop.fr/catalogsearch/result/?q=' . $ref;\r
-               $doc = new DOMDocument();\r
-               $doc->loadHTML(file_get_contents($url));\r
-               $x = simplexml_import_dom($doc);\r
-               $xpath = $x->xpath('//a[@class="product-image"]');\r
-               if (count($xpath) > 0) {\r
-                       $r = $xpath[0]['href'];\r
-                       file_put_contents($cache, $r);\r
-                       header('Location: ' . $r);\r
-                       exit;\r
-               }\r
-               header('Location: http://www.wesco-eshop.fr');\r
-       }\r
-\r
-       public function flfRef() {\r
-               global $core;\r
-\r
-               $r = $core->con->select('SELECT url FROM flfref WHERE ref="' . $core->con->escape($this->args['ref']) . '"');\r
-               if ($r->count()) {\r
-                       header('Location: http://www.flf.fr' . $r->url);\r
-                       exit;\r
-               }\r
-       }\r
-\r
-       public function collection() {\r
-               global $core;\r
-               $id = $this->callArgs[0];\r
-               $os = $this->callArgs[1];\r
-               $resolution = $this->callArgs[2];\r
-               $local = (isset($this->callArgs[3])) ? $this->callArgs[3] : null;\r
-\r
-               if ($id == 4) {\r
-                       $resolution = 150;\r
-               }\r
-\r
-               $this->outputXML = false;\r
-               header('Content-type: application/json');\r
-\r
-               $cache = WS_COLLECTIONS . '/ws/' . $id . '.' . $os . '.' . $resolution . '.json';\r
-               $update = WS_COLLECTIONS . '/ws/' . $id . '.' . $os . '.' . $resolution . '.update';\r
-\r
-               if (file_exists($update) && filemtime(__FILE__) > filemtime($update)) {\r
-                       unlink($update);\r
-               }\r
-\r
-               if (!is_null($local) && file_exists($update) && file_get_contents($update) == $local) {\r
-                       echo 'false';\r
-                       exit;\r
-               }\r
-\r
-               $limit = TIME - 72000;\r
-               if (!file_exists($cache) || !file_exists($update) || filemtime($cache) < $limit) {\r
-                       $r = $core->con->select('SELECT * FROM book_collection_compile WHERE online_' . $os . '=1 AND collection_id=\'' . $core->con->escape($id) . '\'');\r
-                       $r->fetch();\r
-                       $version = $r->compile_date;\r
-\r
-                       $daoCollection = new wsDAOCollection($core->con);\r
-                       $collection = $daoCollection->selectById($id);\r
-\r
-                       $ns = $collection->settings['namespace'];\r
-\r
-\r
-                       $vcompo = WS_COLLECTIONS . '/versions/' . $id . '/' . $version . '/composition.json';\r
-                       $composition = json_decode(file_get_contents($vcompo));\r
-\r
-                       $couvertures = array();\r
-                       $vroot = WS_COLLECTIONS . '/versions/' . $id . '/' . $version . '/' . $os . '/';\r
-\r
-                       $publications = array();\r
-                       $langs = array();\r
-\r
-                       foreach ($composition as $k => $g) {\r
-                               foreach ($g->publications as $l => $p) {\r
-                                       $publications[] = $p->id;\r
-                               }\r
-                       }\r
-\r
-                       $daoBook = new wsDAOBook($core->con);\r
-                       $books = $daoBook->selectByIds($publications);\r
-\r
-                       $langsnames = array();\r
-                       foreach ($composition as $k => $g) {\r
-                               foreach ($g->publications as $l => $p) {\r
-                                       $book = $books[$p->id];\r
-                                       $root = WS_COLLECTIONS . '/versions/' . $id . '/' . $version . '/' . $os . '/' . $p->id;\r
-                                       $couv = $root . '/cover.jpg';\r
-                                       $couvertures[$p->id] = base64_encode(file_get_contents($couv));\r
-                                       $composition[$k]->publications[$l]->width = $book->parametres->width;\r
-                                       $composition[$k]->publications[$l]->height = $book->parametres->height;\r
-                                       $composition[$k]->publications[$l]->lang = $book->lang;\r
-                                       $langs[] = $book->lang;\r
-                               }\r
-                       }\r
-\r
-                       $langs = array_unique($langs);\r
-\r
-                       $w2h = new wiki2xhtml();\r
-                       $w2h->setOpt('active_pre', 0);\r
-\r
-                       $contents = $collection->contents;\r
-                       foreach ($langs as $lang) {\r
-                               $langsnames[$lang] = cubeLang::getNameByCode($lang);\r
-                               $contents[$lang]['apropos'] = $w2h->transform($contents[$lang]['apropos']);\r
-                       }\r
-\r
-\r
-                       $traductions = array();\r
-                       $r = $core->con->select('SELECT traductions,lang_id FROM langues WHERE lang_id IN(\'' . implode('\',\'', $langs) . '\')');\r
-                       while ($r->fetch()) {\r
-                               $traductions[$r->lang_id] = json_decode($r->traductions);\r
-                       }\r
-\r
-                       $d = array('id' => $id, 'res' => $resolution, 'ns' => $ns, 'langs' => $langs, 'langnames' => $langsnames, 'time' => $version, 'datas' => $composition, 'couvertures' => $couvertures, 'traductions' => $traductions, 'contents' => $contents);\r
-                       $d = array_merge($d, $this->_getManifest($publications, '/fluidbook/collections/versions/' . $id . '/' . $version . '/' . $os, $books, $resolution));\r
-\r
-                       $dao = new wsDAOCollection($core->con);\r
-                       $col = $dao->selectById($id);\r
-\r
-                       $json = json_encode($d);\r
-                       file_put_contents($cache, $json);\r
-                       file_put_contents($update, $version);\r
-               } else {\r
-                       $d = json_decode(file_get_contents($cache), true);\r
-               }\r
-\r
-               $force = false;\r
-               if (!is_null($local)) {\r
-                       $lcompo = WS_COLLECTIONS . '/versions/' . $id . '/' . $local . '/composition.json';\r
-                       if (!file_exists($lcompo)) {\r
-                               $force = true;\r
-                       }\r
-               }\r
-\r
-               $d['forceUpdate'] = $force;\r
-               echo json_encode($d);\r
-               exit;\r
-       }\r
-\r
-       protected function _getManifest($publications, $dir, $books, $resolution) {\r
-               global $core;\r
-               $res = array();\r
-               $res['manifest'] = array('assetRoot' => 'http://workshop.fluidbook.com' . $dir . '/', 'autoDownload' => false);\r
-               $res['manifestPub'] = array();\r
-\r
-               $bundles = array();\r
-\r
-               $removeFromRelative = realpath(ROOT . '/' . $dir) . '/';\r
-               $daoTheme = new wsDAOTheme($core->con);\r
-\r
-               foreach ($publications as $p) {\r
-                       $res['manifestPub'][$p] = array('assetRoot' => 'http://workshop.fluidbook.com' . $dir . '/', 'autoDownload' => true);\r
-\r
-                       $r = $p . '/';\r
-                       $iterator = CubeIT_Files::getRecursiveDirectoryIterator(ROOT . $dir . '/' . $p);\r
-                       $book = $books[$p];\r
-                       $reso = $resolution;\r
-\r
-                       $theme = $daoTheme->selectById($book->theme);\r
-                       $orders = $this->_getBundles($book);\r
-                       $regexp = $this->_getRegExpManifest($r, $book, $theme, $reso);\r
-                       $reg = $regexp['reg'];\r
-                       $exclude = $regexp['exclude'];\r
-\r
-                       $b = array();\r
-\r
-                       foreach ($iterator as $k => $f) {\r
-                               if ($f->isDir()) {\r
-                                       continue;\r
-                               }\r
-                               $path = str_replace($removeFromRelative, '', $k);\r
-\r
-                               foreach ($exclude as $e) {\r
-                                       if (preg_match('|' . $e . '|', $path)) {\r
-                                               continue 2;\r
-                                       }\r
-                               }\r
-\r
-                               $order = $this->_inFirstManifest($path, $orders, $reg);\r
-\r
-                               if (!isset($b[$order])) {\r
-                                       $b[$order] = array();\r
-                               }\r
-\r
-                               $b[$order][] = $path;\r
-                       }\r
-\r
-                       $bundles[] = array('name' => 'p_' . $p, 'contents' => $b['loading']);\r
-                       $res['manifestPub'][$p]['bundles'] = array();\r
-\r
-                       foreach ($b as $name => $contents) {\r
-                               if ($name == 'loading') {\r
-                                       continue;\r
-                               }\r
-                               $k = array_search($name, $orders);\r
-                               $res['manifestPub'][$p]['bundles'][$k] = array('name' => $name, 'contents' => $contents);\r
-                       }\r
-                       ksort($res['manifestPub'][$p]['bundles']);\r
-                       $res['manifestPub'][$p]['bundles'] = array_values($res['manifestPub'][$p]['bundles']);\r
-               }\r
-\r
-               $res['manifest']['bundles'] = $bundles;\r
-               return $res;\r
-       }\r
-\r
-       protected function _getRegExpManifest($r, $book, $theme, $resolution) {\r
-               $reg = array();\r
-               $reg['loading'] = array('^' . $r . 'style/(.*).css$', '^' . $r . 'index.html$', '^' . $r . 'data/style/(.*)$', '^' . $r . 'data/(.*).js$', '^' . $r . 'data/images/' . $theme->parametres->logoLoader . '$', '^' . $r . 'style/fonts/(.*).ttf$', '^' . $r . 'data/images/interface-down.svg$', '^' . $r . 'plugins/(.*)$');\r
-               $reg['extras'] = array('^' . $r . 'data/links/(.*).mp4$', '^' . $r . 'data/links/(.*).ogv$', '^' . $r . 'data/links/(.*).webm$', '^' . $r . 'data/(.*).pdf$', '^' . $r . 'cover.jpg$');\r
-               $reg['thumbnails'] = array('^' . $r . 'data/thumbnails/p(\d+).jpg$');\r
-               for ($i = 1; $i <= $book->parametres->pages; $i++) {\r
-                       $var = 'content_' . $i;\r
-                       $reg[$var] = array('^' . $r . 'data/background/\d+/t' . $i . '.jpg$', '^' . $r . 'data/contents/p' . $i . '.svg$');\r
-               }\r
-               $reg['urgents'] = array('^' . $r . 'images/(.*)$', '^' . $r . 'data/images/(.*)$', '^' . $r . 'data/links/(.*).jpg$', '^' . $r . 'data/links/(.*).png$');\r
-               $reg['loading'] = array_merge($reg['loading'], $reg['urgents']);\r
-\r
-\r
-               $exclude = array();\r
-               if ($resolution == 150) {\r
-                       $er = 300;\r
-               } else {\r
-                       $er = 150;\r
-               }\r
-               $exclude[] = '^' . $r . 'data/background/' . $er . '/t\d+.jpg$';\r
-               return array('reg' => $reg, 'exclude' => $exclude);\r
-       }\r
-\r
-       protected function _inFirstManifest($p, $orders, $reg) {\r
-               foreach ($orders as $list) {\r
-                       foreach ($reg[$list] as $v) {\r
-                               if (preg_match('|' . $v . '|', $p)) {\r
-                                       return $list;\r
-                               }\r
-                       }\r
-               }\r
-               return $list;\r
-       }\r
-\r
-       protected function _getBundles($book) {\r
-               $res = array(0 => 'loading', 20001 => 'extras', 20000 => 'thumbnails', 1 => 'urgents');\r
-               for ($i = 1; $i <= $book->parametres->pages; $i++) {\r
-                       $k = 2 + $i;\r
-                       $res[$k] = 'content_' . $i;\r
-               }\r
-               return $res;\r
-       }\r
-\r
-       public function collectionPushRegister() {\r
-               global $core;\r
-\r
-               $c = $core->con->openCursor('book_collection_push');\r
-               $c->collection_id = $_POST['id'];\r
-               $c->token = $_POST['token'];\r
-               $c->datas = $_POST['datas'];\r
-               $c->platform = $_POST['platform'];\r
-               $c->locale = $_POST['locale'];\r
-               $c->last_visit = TIME;\r
-               try {\r
-                       $c->insert();\r
-               } catch (Exception $e) {\r
-                       $c->update('WHERE collection_id=\'' . $core->con->escape($_POST['id']) . '\' AND token=\'' . $core->con->escape($_POST['token']) . '\'');\r
-               }\r
-       }\r
-\r
-}\r
-\r
+<?php
+
+class wsServices extends cubeFlashGateway {
+
+       const CNAME = __CLASS__;
+
+       public static function in($args) {
+               global $core;
+               $args = cubePage::getArgs($args);
+               $n = self::CNAME;
+               $gateway = new $n($core->con, $args);
+       }
+
+       public function sendEmail() {
+               if (!$this->_checkHash()) {
+                       return;
+               }
+               // Send the email
+               $mail = new cubeMail();
+               $mail->returnPath = 'postmaster@fluidbook.com';
+               $mail->acknowledge = isset($this->args['askAcknowledge']) && $this->args['askAcknowledge'];
+               $mail->charset = 'UTF-8';
+               $mail->to = $this->args['email'];
+               $mail->from = $this->args['fromname'] . '<' . $this->args['fromemail'] . '>';
+               $mail->subject = $this->args['subject'];
+               $mail->body = $this->args['body'];
+               $this->xml->addChild('ok', $mail->send() ? '1' : '0');
+       }
+
+       protected function _checkHash() {
+               // Check protection hash
+               $hash = md5(substr($this->args['fromemail'], 2, 6) . substr($this->args['email'], 3, 5) . 'SFGHF566!S' . $this->args['id']);
+               if ($hash != $this->args['hash']) {
+                       $this->xml->addChild('hashOK', '0');
+                       $this->xml->addChild('ok', '0');
+                       return false;
+               }
+               $this->xml->addChild('hashOK', '1');
+               return true;
+       }
+
+       public function sendBookmarks() {
+               if (!$this->_checkHash()) {
+                       return;
+               }
+
+               $bookmarks = json_decode(base64_decode($this->args['bookmarks']), true);
+               $files = array();
+               foreach ($bookmarks as $b) {
+                       $range = $b['page'];
+                       if ($b['nb'] > 1) {
+                               $range.='-' . ($b['page'] + $b['nb'] - 1);
+                       }
+
+                       $file = $this->getPDFComplex($this->args['id'], $range);
+                       $files[] = array('name' => $b['name'], 'file' => $file['file']);
+               }
+
+               $limit = 5 * 1024 * 1024 * 0.8;
+               $groups = array();
+               $group = array();
+               $groupsize = 0;
+               foreach ($files as $f) {
+                       $size = filesize($f['file']);
+
+                       if ($groupsize + $size > $limit) {
+                               if (count($group)) {
+                                       $groups[] = $group;
+                                       $group = array();
+                                       $groupsize = 0;
+                               }
+
+                               $group[] = $f;
+                               $groupsize = $size;
+
+                               if ($groupsize > $limit) {
+                                       $groups[] = $group;
+                                       $group = array();
+                                       $groupsize = 0;
+                               }
+                       } else {
+                               $group[] = $f;
+                               $groupsize+=$size;
+                       }
+               }
+
+               if (count($group)) {
+                       $groups[] = $group;
+               }
+
+
+               $total = count($groups);
+               foreach ($groups as $i => $g) {
+                       $s = '';
+                       if ($total > 1) {
+                               $s = ' (' . ($i + 1) . '/' . $total . ')';
+                       }
+
+                       // Send the email
+                       $mail = new cubeMail();
+                       $mail->returnPath = 'postmaster@fluidbook.com';
+                       $mail->acknowledge = isset($this->args['askAcknowledge']) && $this->args['askAcknowledge'];
+                       $mail->charset = 'UTF-8';
+                       $mail->to = $this->args['email'];
+                       $mail->from = $this->args['fromname'] . '<' . $this->args['fromemail'] . '>';
+                       $mail->subject = $this->args['subject'] . $s;
+                       $mail->body = $this->args['body'];
+                       foreach ($g as $f) {
+                               $mail->addFile($f['name'] . '.pdf', $f['file']);
+                       }
+                       $this->xml->addChild('ok', $mail->send() ? '1' : '0');
+               }
+       }
+
+       protected function shortenURL($url, $id) {
+               $bitLyUser = 'fluidbook';
+               $bitLyKey = 'R_3858dd1c9884d5c6a5fe386d7e95cf1d';
+               // Recherche dans le cache
+               $r = $this->con->select('SELECT * FROM book_short_url WHERE long_url=\'' . $this->con->escape($url) . '\' LIMIT 1');
+               if ($r->count() > 0) {
+                       return $r->short_url;
+               }
+               // Si pas dans le cache, on le recherche
+               $short_url = cubeURLShortener::bitLy($url, $bitLyUser, $bitLyKey);
+               if (is_null($short_url) || empty($short_url) || !$short_url) {
+                       $short_url = cubeURLShortener::tinyURL($url);
+               }
+               $short_url = trim($short_url);
+
+               $c = $this->con->openCursor('book_short_url');
+               $c->long_url = $url;
+               $c->book_id = $id;
+               $c->short_url = $short_url;
+               $c->insert();
+
+               return $short_url;
+       }
+
+       /**
+        * wsServices::facebook_thumbnail()
+        *
+        * @return
+        */
+       public function facebook_thumbnail() {
+               $this->outputXML = false;
+               $dao = new wsDAOBook($this->con);
+
+               $book = $dao->selectById($this->args['id']);
+
+
+               if (isset($book->parametres->facebook_image) && $book->parametres->facebook_image != '') {
+                       $c = WS_BOOKS . '/working/' . $this->args['id'] . '/' . $book->parametres->facebook_image;
+                       if (file_exists($c)) {
+                               $cover = $c;
+                       }
+               }
+               if (!isset($cover)) {
+                       $pages = $dao->getPagesOfBook($this->args['id']);
+                       $cover = WS_DOCS . '/' . $pages[1]['document_id'] . '/html/t36-' . $pages[1]['document_page'] . '.jpg';
+                       if (!file_exists($cover)) {
+                               $cover = WS_DOCS . '/' . $pages[1]['document_id'] . '/p' . $pages[1]['document_page'] . '.jpg';
+                       }
+               }
+               cubeHTTP::relayFile($cover);
+               exit;
+       }
+
+       public function facebookShare() {
+               http::redirect('http://www.facebook.com/sharer/sharer.php?u=' . urlencode($this->args['url']));
+               exit;
+       }
+
+       public function googleplusShare() {
+               http::redirect('https://plus.google.com/share?url=' . urlencode($this->args['url']) . "&sgp=1");
+               exit;
+       }
+
+       public function linkedinShare() {
+               http::redirect('https://www.linkedin.com/cws/share?url=' . urlencode($this->args['url']) . '&isFramed=true&_ts=' . microtime(true));
+       }
+
+       public function viadeoShare() {
+               http::redirect('http://www.viadeo.com/shareit/share/?url=' . urlencode($this->args['url']));
+       }
+
+       public function twitterShare() {
+               $url = $this->shortenURL($this->args['url'], $this->args['id']);
+
+               $post = str_replace('%short%', $url, $this->args['post']);
+               $post = rawurlencode($post);
+
+               http::redirect('http://twitter.com/intent/tweet?source=webclient&text=' . $post);
+               exit;
+       }
+
+       public function searchHints() {
+               $index = Zend_Search_Lucene::open(WS_BOOKS . '/search/' . $this->args['id']);
+
+               $charsLimit = 2;
+
+               $terms = $this->getTerms($this->args['term']);
+               $term = array_pop($terms);
+
+               if (strlen($term) < $charsLimit) {
+                       $this->xml->addChild('hints', '{}');
+                       return;
+               }
+
+               $term = new Zend_Search_Lucene_Index_Term($term . '*', 'contents');
+               $query = new Zend_Search_Lucene_Search_Query_Wildcard($term);
+               $query->setMinPrefixLength($charsLimit);
+
+               $index->find($query);
+               $terms = $query->getQueryTerms();
+               $res = array();
+               foreach ($terms as $t) {
+                       $res[$t->text] = array_sum($index->termFreqs($t));
+               }
+               arsort($res);
+               $res = array_slice($res, 0, 10, true);
+               $this->xml->addChild('hints', json_encode($res));
+       }
+
+       public function searchResults() {
+               $index = Zend_Search_Lucene::open(WS_BOOKS . '/search/' . $this->args['id']);
+
+               $terms = $this->getTerms($this->args['term']);
+
+               $query = new Zend_Search_Lucene_Search_Query_MultiTerm();
+               foreach ($terms as $term) {
+                       $query->addTerm(new Zend_Search_Lucene_Index_Term($term, 'contents'), null);
+               }
+
+               $hits = $index->find($query);
+               $res = array();
+               $terms = array();
+               foreach ($query->getQueryTerms() as $t) {
+                       $terms[] = $t->text;
+                       foreach ($index->termFreqs($t) as $doc_id => $f) {
+                               $page = trim($index->getDocument($doc_id)->getField('url')->getUtf8Value(), "#");
+                               if (!isset($res[$page])) {
+                                       $res[$page] = 0;
+                               }
+                               $res[$page]+=$f;
+                       }
+               }
+               $this->xml->addChild('results', json_encode($res));
+               $this->xml->addChild('terms', implode(',', $terms));
+       }
+
+       protected function getTerms($term) {
+               $term = trim($term, '*? ');
+               $term = mb_strtolower($term);
+               $term = cubeText::removeAccents($term);
+               $terms = explode(' ', $term);
+               return $terms;
+       }
+
+       public function printpdf() {
+               $this->outputXML = false;
+               $this->exportpdf(true);
+       }
+
+       public function getPDFComplex($book = null, $range = null) {
+               global $core;
+
+               if (is_null($book)) {
+                       $book = $this->callArgs[0];
+                       $range = $this->callArgs[1];
+               }
+
+               $daoBook = new wsDAOBook($core->con);
+
+               if (is_int($book) || is_string($book)) {
+                       $book = $daoBook->selectById($book);
+               }
+
+               if (is_null($book)) {
+                       return;
+               }
+
+               // Normalize range
+               $range = cubeArray::parseRange($range);
+
+               if ($k = array_search(0, $range)) {
+                       $range[$k] = 1;
+               }
+               if ($k = array_search($book->parametres->pages + 1, $range)) {
+                       $range[$k] = $r->pages;
+               }
+
+               if (!count($range)) {
+                       return;
+               }
+               // Paths init
+               $baseDocument = $this->getPDFComplexBaseDocument($book);
+               if (!file_exists($baseDocument)) {
+                       return;
+               }
+               $destDir = WS_CACHE . '/exportpdf/' . $book->cid;
+               if (!file_exists($destDir)) {
+                       mkdir($destDir, 0777, true);
+               }
+               $fname = md5(implode(',%ù', $range)) . '.pdf';
+               $destFile = $destDir . '/' . $fname;
+               $destURL = '/fluidbook/cache/exportpdf/' . $book->cid . '/' . $fname;
+               // If result exists, don't make the pdf again
+               if (file_exists($destFile) && filemtime($destFile) > filemtime($baseDocument)) {
+
+               } else {
+                       // Prepare the command line
+                       $l = array('A=' . $baseDocument, 'cat');
+                       foreach ($range as $page) {
+                               if ($page < 1 || $page > $book->parametres->pages) {
+                                       continue;
+                               }
+                               $l[] = 'A' . $page;
+                       }
+                       $l[] = 'output';
+                       $l[] = $destFile;
+
+                       $args = implode(' ', $l);
+                       // Execute the command line
+                       $pdftk = new cubeCommandLine('pdftk');
+                       $pdftk->setPath(CONVERTER_PATH);
+                       $pdftk->setManualArg($args);
+                       $pdftk->execute();
+               }
+
+               return array('url' => $destURL, 'file' => $destFile);
+       }
+
+       public function getPDFComplexBaseDocument($book) {
+               $normal = WS_BOOKS . '/pdf/' . $book->book_id . '/original.pdf';
+
+               if ($book->parametres->pdfReplace != '' && file_exists($normal)) {
+                       $this->xml->addChild('normal', $normal);
+                       return $normal;
+               }
+               return WS_BOOKS . '/final/' . $book->book_id . '/data/' . $book->parametres->pdfName;
+       }
+
+       public function e() {
+               $this->args['cid'] = $this->callArgs[0];
+               $this->args['range'] = $this->callArgs[1];
+               return $this->exportpdf();
+       }
+
+       public function p() {
+               $this->args['cid'] = $this->callArgs[0];
+               $this->args['range'] = $this->callArgs[1];
+               return $this->exportpdf(true);
+       }
+
+       public function exportpdf($print = false) {
+               global $core;
+
+               $dao = new wsDAOBook($core->con);
+               if (isset($this->args['cid'])) {
+                       $book = $dao->selectByCid($this->args['cid']);
+               } else if ($this->args['id'] < 11202) {
+                       $book = $dao->selectById($this->args['id']);
+               }
+
+               $dest = $this->getPDFComplex($book, $this->args['range']);
+
+               if (!$print) {
+                       // Return the url of the resulting pdf
+                       http::redirect($dest['url']);
+                       exit;
+               } else {
+                       $this->outputXML = false;
+                       $res = '<!DOCTYPE html><html><head>
+                               <meta http-equiv="X-UA-Compatible" content="IE=8" />
+                               <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
+                               <script type="text/javascript" src="/js/pdfprint.js"></script>
+                               <link rel="stylesheet" type="text/css" href="/style/ws/printpdf.css" />
+                               </head>
+                               <body>
+                               <iframe id="pdf" name="pdff" src="' . $dest['url'] . '" width="100%" height="100%"></iframe>
+                               </body>
+                               </html>';
+                       ob_end_clean();
+                       echo $res;
+                       exit;
+               }
+       }
+
+       public function bulle() {
+               global $core;
+               $e = explode('-', $this->args['catalogue'], 2);
+               if (count($e) == 2) {
+                       $catalogue = $e[1];
+               } else {
+                       $catalogue = $e[0];
+               }
+
+               $c = $core->con->openCursor('bulle');
+               $c->prenom = trim($this->args['prenom']);
+               $c->nom = trim($this->args['nom']);
+               $c->catalogue = trim($catalogue);
+               $c->email = trim($this->args['email']);
+               $c->date = TIME;
+               $c->insert();
+       }
+
+       public function getBulleList() {
+               $user = 'bulle';
+               $pass = '23bu1l300';
+               $this->outputXML = false;
+               $ok = (isset($_SERVER['PHP_AUTH_USER']) && $_SERVER['PHP_AUTH_USER'] == $user && isset($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_PW'] == $pass);
+               if (!$ok) {
+                       header('WWW-Authenticate: Basic realm="Protected access"');
+                       header('HTTP/1.0 401 Unauthorized');
+                       ob_end_clean();
+                       header('Content-type: text/html');
+                       echo '<h1>Forbidden</h1>';
+                       exit;
+               } else {
+                       global $core;
+                       header('Content-type: text/csv');
+                       header('Content-Disposition: attachment; filename="inscriptions.csv"');
+                       $r = $core->con->select('SELECT * FROM bulle ORDER BY date');
+                       ob_end_clean();
+                       echo utf8_decode('"Prénom";"Nom";"E-mail";"Catalogue";"Date"') . "\n";
+                       while ($r->fetch()) {
+                               echo utf8_decode('"' . $r->prenom . '";"' . $r->nom . '";"' . $r->email . '";"' . $r->catalogue . '";"' . date('Y-m-d H:i', $r->date) . '"') . "\n";
+                       }
+                       exit;
+               }
+       }
+
+       public function grdfValidForm() {
+               $notempty = array('civilite', 'prenom', 'nom', 'adresse', 'codepostal', 'ville', 'telephone', 'optin', 'connu', 'energie');
+               $error = false;
+               $errors = array();
+               foreach ($notempty as $f) {
+                       if (!isset($this->args[$f]) || is_null($this->args[$f]) || $this->args[$f] == 'null' || trim($this->args[$f]) == '') {
+                               $error = true;
+                               $errors[] = $f;
+                       }
+               }
+
+               /* if (!cubeMail::isEmail($this->args['email'])) {
+                 $error = true;
+                 $errors[] = 'email_valid';
+                 } */
+
+               $this->xml->addChild('ok', $error ? '0' : '1');
+               $this->xml->addChild('errors', implode(',', $errors));
+       }
+
+       public function grdfSendForm() {
+               global $core;
+
+               if ($this->args['id'] == 11222) {
+                       $annee = 2013;
+               } else if ($this->args['id'] == 12235) {
+                       $annee = 2014;
+               }
+
+               $fields = array('Civilité' => 'civilite', 'Prénom' => 'prenom', 'Nom' => 'nom',
+                       'E-mail' => 'email', 'Adresse' => 'adresse', 'Code postal' => 'codepostal', 'Ville' => 'ville',
+                       'Téléphone' => 'telephone', 'Connu par' => 'connu', 'Energie' => 'energie',
+                       'Optin' => 'optin', 'Coupons sélectionnés' => 'reflist');
+
+               $mail = new cubeMail();
+               $mail->charset = 'UTF-8';
+               $mail->subject = '[Chéquier avantages] Validation de coupon';
+               $mail->from = 'noreply@chequieravantages.fr';
+               $mail->replyTo = 'noreply@chequiavantages.fr';
+               $mail->to = 'projetrenogaz@grdf.fr';
+               $mail->bcc = 'test@cubedesigners.com';
+               $body = '';
+
+               foreach ($fields as $k => $f) {
+                       $body.=$k . ' : ' . $this->args[$f] . "\r\n";
+                       $datas[$f] = $this->args[$f];
+               }
+               $datas['date'] = TIME;
+
+               $c = $core->con->openCursor('grdf' . $annee);
+               $c->datas = json_encode($datas);
+               $c->insert();
+
+               $mail->body = $body;
+               $mail->send();
+       }
+
+       public function grdfCoupon() {
+               $id = $this->args['id'];
+
+               $this->outputXML = false;
+               $couponsRoot = WS_BOOKS . '/working/' . $id . '/commerce/';
+
+               $xml = simplexml_load_file($couponsRoot . 'references.xml');
+               // Check hash
+               $hash = md5('ae' . $_GET['nom'] . '25' . $_GET['ref']);
+               if ($hash != $_GET['h']) {
+                       exit;
+               }
+               $refs = explode(',', $_GET['ref']);
+               $pdf = new FPDI();
+               foreach ($refs as $ref) {
+
+                       foreach ($xml->xpath('//item[@reference=\'' . $ref . '\']') as $item) {
+                               $code = (string) $item['code'];
+                       }
+
+                       $file = $couponsRoot . $ref . '.pdf';
+
+                       $pdf->setSourceFile($file);
+                       $idx = $pdf->importPage(1);
+                       $pdf->AddPage();
+                       $pdf->useTemplate($idx);
+                       $pdf->SetXY(11, 12);
+                       $pdf->SetFont('Helvetica', '', 12);
+                       $pdf->SetTextColor(0, 0, 0);
+                       $pdf->Cell(180, 10, utf8_decode(trim($_GET['civilite'] . ' ' . $_GET['prenom'] . ' ' . $_GET['nom']) . ','));
+                       $pdf->SetXY(135, 203);
+                       $pdf->SetFont('Helvetica', 'B', 16);
+                       $pdf->Cell(50, 15, $code, 0, 1, "C");
+               }
+               $pdf->Output('coupon.pdf', 'I');
+       }
+
+       public function grdfExcel12568() {
+               global $core;
+               $this->outputXML = false;
+
+               if (!isset($_GET['annee'])) {
+                       $_GET['annee'] = 2013;
+               }
+               $annee = $_GET['annee'];
+
+               if ($annee == 2013) {
+                       $id = 11222;
+               } elseif ($annee == 2014) {
+                       $id = 12235;
+               }
+
+
+               $couponsRoot = WS_BOOKS . '/working/' . $id . '/commerce/';
+
+               $xml = simplexml_load_file($couponsRoot . 'references.xml');
+
+               $cols = array('Date' => 'date', 'Civilité' => 'civilite', 'Prénom' => 'prenom', 'Nom' => 'nom',
+                       'E-mail' => 'email', 'Adresse' => 'adresse', 'Code postal' => 'codepostal', 'Ville' => 'ville',
+                       'Téléphone' => 'telephone', 'Connu par' => 'connu', 'Energie' => 'energie',
+                       'Optin' => 'optin');
+               $refs = array();
+               foreach ($xml->xpath('//item') as $i) {
+                       $refs[(string) $i['reference']] = $i['name'];
+               }
+
+               //
+               $h = '<table>';
+               $h.='<tr>';
+               foreach ($cols as $l => $k) {
+                       $h.='<th>' . utf8_decode($l) . '</th>';
+               }
+               foreach ($refs as $k => $l) {
+                       $h.='<th>' . utf8_decode($l) . '</th>';
+               }
+               $h.='</tr>';
+
+               $r = $core->con->select('SELECT * FROM grdf' . $annee);
+               while ($r->fetch()) {
+                       $d = json_decode($r->datas);
+                       $rl = explode(',', $d->reflist);
+                       $h.='<tr>';
+                       foreach ($cols as $l => $k) {
+                               $v = $d->$k;
+                               if ($k == 'date') {
+                                       $v = date('Y-m-d H:i', $v);
+                               }
+                               $h.='<td>' . utf8_decode($v) . '</td>';
+                       }
+                       foreach ($refs as $k => $l) {
+                               $v = in_array($k, $rl) ? '1' : '0';
+                               $h.='<td>' . utf8_decode($v) . '</td>';
+                       }
+                       $h.='</tr>';
+               }
+
+               $h.='</table>';
+
+               if (!file_exists(ROOT . '/cache/12568/')) {
+                       mkdir(ROOT . '/cache/12568/', 0777, true);
+               }
+               file_put_contents(ROOT . '/cache/12568/chequieravantage.xls', $h);
+               http::redirect('/cache/12568/chequieravantage.xls');
+               exit;
+       }
+
+       public function proxy() {
+               ob_end_clean();
+               fb(netHttp::quickGet($_GET['u'], 'php://output'));
+               $this->outputXML = false;
+       }
+
+       public function wescoRef() {
+               global $core;
+
+               $ref = ltrim(substr($this->args['ref'], 4), '0');
+
+               $r = $core->con->select('SELECT url FROM wescoref WHERE ref="' . $core->con->escape($ref) . '"');
+               if ($r->count()) {
+                       header('Location: ' . $r->url);
+                       exit;
+               }
+               $cache = ROOT . '/cache/wesco/' . $this->args['ref'];
+               if (file_exists($cache)) {
+                       header('Location: ' . file_get_contents($cache));
+                       exit;
+               }
+               $url = 'http://www.wesco-eshop.fr/catalogsearch/result/?q=' . $ref;
+               $doc = new DOMDocument();
+               $doc->loadHTML(file_get_contents($url));
+               $x = simplexml_import_dom($doc);
+               $xpath = $x->xpath('//a[@class="product-image"]');
+               if (count($xpath) > 0) {
+                       $r = $xpath[0]['href'];
+                       file_put_contents($cache, $r);
+                       header('Location: ' . $r);
+                       exit;
+               }
+               header('Location: http://www.wesco-eshop.fr');
+       }
+
+       public function flfRef() {
+               global $core;
+
+               $r = $core->con->select('SELECT url FROM flfref WHERE ref="' . $core->con->escape($this->args['ref']) . '"');
+               if ($r->count()) {
+                       header('Location: http://www.flf.fr' . $r->url);
+                       exit;
+               }
+       }
+
+       public function collection() {
+               global $core;
+               $id = $this->callArgs[0];
+               $os = $this->callArgs[1];
+               $resolution = $this->callArgs[2];
+               $local = (isset($this->callArgs[3])) ? $this->callArgs[3] : null;
+
+               if ($id == 4) {
+                       $resolution = 150;
+               }
+
+               $this->outputXML = false;
+               header('Content-type: application/json');
+
+               $cache = WS_COLLECTIONS . '/ws/' . $id . '.' . $os . '.' . $resolution . '.json';
+               $update = WS_COLLECTIONS . '/ws/' . $id . '.' . $os . '.' . $resolution . '.update';
+
+               if (file_exists($update) && filemtime(__FILE__) > filemtime($update)) {
+                       unlink($update);
+               }
+
+               if (!is_null($local) && file_exists($update) && file_get_contents($update) == $local) {
+                       echo 'false';
+                       exit;
+               }
+
+               $limit = TIME - 72000;
+               if (!file_exists($cache) || !file_exists($update) || filemtime($cache) < $limit) {
+                       $r = $core->con->select('SELECT * FROM book_collection_compile WHERE online_' . $os . '=1 AND collection_id=\'' . $core->con->escape($id) . '\'');
+                       $r->fetch();
+                       $version = $r->compile_date;
+
+                       $daoCollection = new wsDAOCollection($core->con);
+                       $collection = $daoCollection->selectById($id);
+
+                       $ns = $collection->settings['namespace'];
+
+
+                       $vcompo = WS_COLLECTIONS . '/versions/' . $id . '/' . $version . '/composition.json';
+                       $composition = json_decode(file_get_contents($vcompo));
+
+                       $couvertures = array();
+                       $vroot = WS_COLLECTIONS . '/versions/' . $id . '/' . $version . '/' . $os . '/';
+
+                       $publications = array();
+                       $langs = array();
+
+                       foreach ($composition as $k => $g) {
+                               foreach ($g->publications as $l => $p) {
+                                       $publications[] = $p->id;
+                               }
+                       }
+
+                       $daoBook = new wsDAOBook($core->con);
+                       $books = $daoBook->selectByIds($publications);
+
+                       $langsnames = array();
+                       foreach ($composition as $k => $g) {
+                               foreach ($g->publications as $l => $p) {
+                                       $book = $books[$p->id];
+                                       $root = WS_COLLECTIONS . '/versions/' . $id . '/' . $version . '/' . $os . '/' . $p->id;
+                                       $couv = $root . '/cover.jpg';
+                                       $couvertures[$p->id] = base64_encode(file_get_contents($couv));
+                                       $composition[$k]->publications[$l]->width = $book->parametres->width;
+                                       $composition[$k]->publications[$l]->height = $book->parametres->height;
+                                       $composition[$k]->publications[$l]->lang = $book->lang;
+                                       $langs[] = $book->lang;
+                               }
+                       }
+
+                       $langs = array_unique($langs);
+
+                       $w2h = new wiki2xhtml();
+                       $w2h->setOpt('active_pre', 0);
+
+                       $contents = $collection->contents;
+                       foreach ($langs as $lang) {
+                               $langsnames[$lang] = cubeLang::getNameByCode($lang);
+                               $contents[$lang]['apropos'] = $w2h->transform($contents[$lang]['apropos']);
+                       }
+
+
+                       $traductions = array();
+                       $r = $core->con->select('SELECT traductions,lang_id FROM langues WHERE lang_id IN(\'' . implode('\',\'', $langs) . '\')');
+                       while ($r->fetch()) {
+                               $traductions[$r->lang_id] = json_decode($r->traductions);
+                       }
+
+                       $d = array('id' => $id, 'res' => $resolution, 'ns' => $ns, 'langs' => $langs, 'langnames' => $langsnames, 'time' => $version, 'datas' => $composition, 'couvertures' => $couvertures, 'traductions' => $traductions, 'contents' => $contents);
+                       $d = array_merge($d, $this->_getManifest($publications, '/fluidbook/collections/versions/' . $id . '/' . $version . '/' . $os, $books, $resolution));
+
+                       $dao = new wsDAOCollection($core->con);
+                       $col = $dao->selectById($id);
+
+                       $json = json_encode($d);
+                       file_put_contents($cache, $json);
+                       file_put_contents($update, $version);
+               } else {
+                       $d = json_decode(file_get_contents($cache), true);
+               }
+
+               $force = false;
+               if (!is_null($local)) {
+                       $lcompo = WS_COLLECTIONS . '/versions/' . $id . '/' . $local . '/composition.json';
+                       if (!file_exists($lcompo)) {
+                               $force = true;
+                       }
+               }
+
+               $d['forceUpdate'] = $force;
+               echo json_encode($d);
+               exit;
+       }
+
+       protected function _getManifest($publications, $dir, $books, $resolution) {
+               global $core;
+               $res = array();
+               $res['manifest'] = array('assetRoot' => 'http://workshop.fluidbook.com' . $dir . '/', 'autoDownload' => false);
+               $res['manifestPub'] = array();
+
+               $bundles = array();
+
+               $removeFromRelative = realpath(ROOT . '/' . $dir) . '/';
+               $daoTheme = new wsDAOTheme($core->con);
+
+               foreach ($publications as $p) {
+                       $res['manifestPub'][$p] = array('assetRoot' => 'http://workshop.fluidbook.com' . $dir . '/', 'autoDownload' => true);
+
+                       $r = $p . '/';
+                       $iterator = CubeIT_Files::getRecursiveDirectoryIterator(ROOT . $dir . '/' . $p);
+                       $book = $books[$p];
+                       $reso = $resolution;
+
+                       $theme = $daoTheme->selectById($book->theme);
+                       $orders = $this->_getBundles($book);
+                       $regexp = $this->_getRegExpManifest($r, $book, $theme, $reso);
+                       $reg = $regexp['reg'];
+                       $exclude = $regexp['exclude'];
+
+                       $b = array();
+
+                       foreach ($iterator as $k => $f) {
+                               if ($f->isDir()) {
+                                       continue;
+                               }
+                               $path = str_replace($removeFromRelative, '', $k);
+
+                               foreach ($exclude as $e) {
+                                       if (preg_match('|' . $e . '|', $path)) {
+                                               continue 2;
+                                       }
+                               }
+
+                               $order = $this->_inFirstManifest($path, $orders, $reg);
+
+                               if (!isset($b[$order])) {
+                                       $b[$order] = array();
+                               }
+
+                               $b[$order][] = $path;
+                       }
+
+                       $bundles[] = array('name' => 'p_' . $p, 'contents' => $b['loading']);
+                       $res['manifestPub'][$p]['bundles'] = array();
+
+                       foreach ($b as $name => $contents) {
+                               if ($name == 'loading') {
+                                       continue;
+                               }
+                               $k = array_search($name, $orders);
+                               $res['manifestPub'][$p]['bundles'][$k] = array('name' => $name, 'contents' => $contents);
+                       }
+                       ksort($res['manifestPub'][$p]['bundles']);
+                       $res['manifestPub'][$p]['bundles'] = array_values($res['manifestPub'][$p]['bundles']);
+               }
+
+               $res['manifest']['bundles'] = $bundles;
+               return $res;
+       }
+
+       protected function _getRegExpManifest($r, $book, $theme, $resolution) {
+               $reg = array();
+               $reg['loading'] = array('^' . $r . 'style/(.*).css$', '^' . $r . 'index.html$', '^' . $r . 'data/style/(.*)$', '^' . $r . 'data/(.*).js$', '^' . $r . 'data/images/' . $theme->parametres->logoLoader . '$', '^' . $r . 'style/fonts/(.*).ttf$', '^' . $r . 'data/images/interface-down.svg$', '^' . $r . 'plugins/(.*)$');
+               $reg['extras'] = array('^' . $r . 'data/links/(.*).mp4$', '^' . $r . 'data/links/(.*).ogv$', '^' . $r . 'data/links/(.*).webm$', '^' . $r . 'data/(.*).pdf$', '^' . $r . 'cover.jpg$');
+               $reg['thumbnails'] = array('^' . $r . 'data/thumbnails/p(\d+).jpg$');
+               for ($i = 1; $i <= $book->parametres->pages; $i++) {
+                       $var = 'content_' . $i;
+                       $reg[$var] = array('^' . $r . 'data/background/\d+/t' . $i . '.jpg$', '^' . $r . 'data/contents/p' . $i . '.svg$');
+               }
+               $reg['urgents'] = array('^' . $r . 'images/(.*)$', '^' . $r . 'data/images/(.*)$', '^' . $r . 'data/links/(.*).jpg$', '^' . $r . 'data/links/(.*).png$');
+               $reg['loading'] = array_merge($reg['loading'], $reg['urgents']);
+
+
+               $exclude = array();
+               if ($resolution == 150) {
+                       $er = 300;
+               } else {
+                       $er = 150;
+               }
+               $exclude[] = '^' . $r . 'data/background/' . $er . '/t\d+.jpg$';
+               return array('reg' => $reg, 'exclude' => $exclude);
+       }
+
+       protected function _inFirstManifest($p, $orders, $reg) {
+               foreach ($orders as $list) {
+                       foreach ($reg[$list] as $v) {
+                               if (preg_match('|' . $v . '|', $p)) {
+                                       return $list;
+                               }
+                       }
+               }
+               return $list;
+       }
+
+       protected function _getBundles($book) {
+               $res = array(0 => 'loading', 20001 => 'extras', 20000 => 'thumbnails', 1 => 'urgents');
+               for ($i = 1; $i <= $book->parametres->pages; $i++) {
+                       $k = 2 + $i;
+                       $res[$k] = 'content_' . $i;
+               }
+               return $res;
+       }
+
+       public function collectionPushRegister() {
+               global $core;
+
+               $c = $core->con->openCursor('book_collection_push');
+               $c->collection_id = $_POST['id'];
+               $c->token = $_POST['token'];
+               $c->datas = $_POST['datas'];
+               $c->platform = $_POST['platform'];
+               $c->locale = $_POST['locale'];
+               $c->last_visit = TIME;
+               try {
+                       $c->insert();
+               } catch (Exception $e) {
+                       $c->update('WHERE collection_id=\'' . $core->con->escape($_POST['id']) . '\' AND token=\'' . $core->con->escape($_POST['token']) . '\'');
+               }
+       }
+
+}
+
 ?>
\ No newline at end of file
index 133f51d05e668d9cf69421b338af32e45dfb0b2a..bd263961dcc84e22de49e186f5c5b6837dbb6fcf 100644 (file)
-<?php\r
-\r
-class wsDAOBook extends commonDAO {\r
-\r
-       /**\r
-        * wsDAOBook::singleton()\r
-        *\r
-        * @param mixed $r\r
-        * @return\r
-        */\r
-       protected function singleton($r) {\r
-               $book = new wsBook();\r
-               $book->book_id = $r->book_id;\r
-               $book->cid = $r->cid;\r
-               $book->nom = $r->nom;\r
-               $book->lang = $r->lang;\r
-               $book->theme = $r->theme;\r
-               $book->proprietaire = $r->proprietaire_nom;\r
-               $book->proprietaire_id = $r->proprietaire_id;\r
-               $book->proprietaire_utilisateur = $r->proprietaire_utilisateur;\r
-               $book->hash = $r->hash;\r
-               $book->compteur_visites = $r->compteur_visites;\r
-               $book->status = $r->status;\r
-               $book->date_status = $r->date_status;\r
-               $book->date = $r->date;\r
-               $book->pages = array();\r
-               $book->chapters = $r->chapters;\r
-               $book->traductions = $r->traductions;\r
-               $book->specialLinks = $r->specialLinks;\r
-               $book->specialRulers = $r->specialRulers;\r
-               $book->parametres = $r->parametres;\r
-               $book->extras = $r->extras;\r
-               $book->numerotation = $r->numerotation;\r
-               $book->changedate = $r->changedate;\r
-               $book->compiledate = $r->compiledate;\r
-               $book->compile1date = $r->compile1date;\r
-               $book->compilehtml5date = $r->compilehtml5date;\r
-               $book->facturable = $r->facturable;\r
-               $book->facturable_id = $r->facturable_id;\r
-               $book->tache = $r->tache;\r
-               if (isset($r->projet)) {\r
-                       $book->projet = $r->projet;\r
-               }\r
-               $book->version = $r->version;\r
-               $book->composition_update = $r->composition_update;\r
-               $book->dir_references = $r->dir_references;\r
-               $book->dir_hosting = $r->dir_hosting;\r
-               $book->dir_macbook_phonegap_ios = $r->dir_macbook_phonegap_ios;\r
-               $book->dir_phonegap_android = $r->dir_phonegap_android;\r
-               $book->dir_external = $r->dir_external;\r
-               $book->demo_counter = $r->demo_counter;\r
-               $book->exportdatas = $r->exportdatas;\r
-\r
-               return $book;\r
-       }\r
-\r
-       protected function cree($r) {\r
-               $book = new wsBook();\r
-               $book->book_id = 'new';\r
-               $book->nom = '';\r
-               $book->cid = null;\r
-               $book->lang = 'fr';\r
-               $book->theme = 1;\r
-               $book->proprietaire = '';\r
-               $book->proprietaire_id = 0;\r
-               $book->hash = '';\r
-               $book->compteur_visites = 20;\r
-               $book->status = 0;\r
-               $book->date_status = TIME;\r
-               $book->date = TIME;\r
-               $book->composition_update = TIME;\r
-               $book->chapters = json_encode(array());\r
-               $book->parametres = new wsBookParametres();\r
-               $book->tache = 0;\r
-               $book->pages = array();\r
-               $book->version = 2;\r
-               return $book;\r
-       }\r
-\r
-       protected function getNextId() {\r
-               $r = $this->con->select('SELECT MAX(book_id) AS book_id FROM books');\r
-               if ($r->book_id < 10000) {\r
-                       return 10000;\r
-               }\r
-               return $r->book_id + 1;\r
-       }\r
-\r
-       public function saveExportDatas($book_id, $datas) {\r
-               $c = $this->con->openCursor('books');\r
-               $c->exportdatas = json_encode($datas);\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function addDemoCount($book_id) {\r
-\r
-               $r = $this->con->select('SELECT demo_counter,nom FROM books WHERE book_id=\'' . $book_id . '\'');\r
-               $m = 20;\r
-               if ($r->demo_counter > 0 && $r->demo_counter % $m == 0) {\r
-                       $mail = new cubeMail();\r
-                       $mail->charset = 'UTF-8';\r
-                       $mail->from = 'contact@fluidbook.com';\r
-                       $mail->to = 'tech@fluidbook.com';\r
-                       $mail->subject = '[Fluidbook Workshop] Fluidbook consulté via l\'url publique';\r
-                       $mail->body = 'Le fluidbook suivant a été consulté ' . $m . ' fois (et ' . $r->demo_counter . ' au total) via l\'url publique : ' . "\r\n" .\r
-                                       'Fluidbook # ' . $book_id . ' - ' . $r->nom;\r
-                       $mail->send();\r
-               }\r
-\r
-               $this->con->select('UPDATE books SET demo_counter=demo_counter+1 WHERE book_id=\'' . $book_id . '\'');\r
-       }\r
-\r
-       public function selectByIds($book_ids = array(), $simple = false) {\r
-               if ($simple) {\r
-                       $table = 'books';\r
-               } else {\r
-                       $table = 'books_vue';\r
-               }\r
-               $sql = 'SELECT * FROM ' . $table . ' WHERE book_id IN (' . implode(',', $book_ids) . ')';\r
-               $books = $this->factory($this->con->select($sql));\r
-               $res = array();\r
-               foreach ($books as $book) {\r
-                       $res[$book->book_id] = $book;\r
-               }\r
-               return $res;\r
-       }\r
-\r
-       public function selectById($book_id = null, $simple = false) {\r
-               if (is_null($book_id)) {\r
-                       return $this->cree();\r
-               }\r
-               if ($simple) {\r
-                       $table = 'books';\r
-               } else {\r
-                       $table = 'books_vue';\r
-               }\r
-               $sql = 'SELECT * FROM ' . $table . ' WHERE book_id=\'' . $this->con->escape($book_id) . '\' LIMIT 1';\r
-               $r = $this->con->select($sql);\r
-               return $this->singleton($r);\r
-       }\r
-\r
-       public function selectByCid($cid = null, $simple = false) {\r
-               if ($simple) {\r
-                       $table = 'books';\r
-               } else {\r
-                       $table = 'books_vue';\r
-               }\r
-\r
-               $sql = 'SELECT * FROM ' . $table . ' WHERE cid LIKE BINARY \'' . $this->con->escape($cid) . '\' LIMIT 1';\r
-               $r = $this->con->select($sql);\r
-               return $this->singleton($r);\r
-       }\r
-\r
-       public function selectLuceneToDo() {\r
-               $sql = 'SELECT * FROM books_vue WHERE lucene_time<composition_update AND version=2 ORDER BY book_id ASC LIMIT 1';\r
-               $r = $this->con->select($sql);\r
-               return $this->factory($r);\r
-       }\r
-\r
-       public function selectLuceneTimeNotSet() {\r
-               $sql = 'SELECT * FROM books_vue WHERE lucene_time=0 AND version=2';\r
-               $r = $this->con->select($sql);\r
-               return $this->factory($r);\r
-       }\r
-\r
-       /**\r
-        * wsDAOBook::sauve()\r
-        *\r
-        * @param mixed $createur\r
-        * @param mixed $data\r
-        * @return\r
-        */\r
-       public function sauve($createur, $data) {\r
-               $c = $this->con->openCursor('books');\r
-               if (isset($data['nom'])) {\r
-                       $c->nom = $data['nom'];\r
-               }\r
-               if (isset($data['lang'])) {\r
-                       $c->lang = $data['lang'];\r
-               }\r
-               if (isset($data['theme'])) {\r
-                       $c->theme = $data['theme'];\r
-               }\r
-               if (isset($data['proprietaire'])) {\r
-                       $c->proprietaire = $data['proprietaire'];\r
-               }\r
-\r
-               if ($data['book_id'] == 'new' || $data['book_id'] == '') {\r
-                       $c->date = TIME;\r
-                       $c->hash = md5(rand(0, 123456789365469));\r
-                       $c->compteur_visites = 20;\r
-                       $c->parametres = serialize(new wsParametres());\r
-                       $c->changedate = TIME;\r
-                       $book_id = $c->book_id = $this->getNextId();\r
-\r
-                       $c->insert();\r
-               } else {\r
-                       $c->changedate = TIME;\r
-                       $book_id = $data['book_id'];\r
-                       $c->update('WHERE book_id=\'' . $this->con->escape($data['book_id']) . '\'');\r
-               }\r
-\r
-               return $this->selectById($book_id);\r
-       }\r
-\r
-       public function duplicate($book_id, $createur, $nom, $pages = false) {\r
-               $r = $this->con->select('SELECT * FROM books_vue WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-\r
-               $old_id = $book_id;\r
-\r
-               $parametres = unserialize($r->parametres);\r
-               $parametres->setParent($this);\r
-               $parametres->title = $nom;\r
-\r
-               $c = $this->con->openCursor('books');\r
-               $c->proprietaire = $createur;\r
-               $c->date = TIME;\r
-               $c->hash = md5(rand(0, 1234567893));\r
-               $c->cid = $this->generateCID();\r
-               $c->compteur_visites = 20;\r
-               $c->status = -1;\r
-               $c->date_status = TIME;\r
-               $c->lang = $r->lang;\r
-               $c->parametres = serialize($parametres);\r
-               $c->nom = $nom;\r
-               $c->theme = $r->theme;\r
-               $c->changedate = TIME;\r
-               $c->compiledate = 0;\r
-               $c->version = 2;\r
-               $c->traductions = $r->traductions;\r
-               $c->specialLinks = $r->specialLinks;\r
-               $c->specialRulers = $r->specialRulers;\r
-               $c->composition_update = TIME;\r
-               $book_id = $c->book_id = $this->getNextId();\r
-               if ($pages) {\r
-                       $c->numerotation = $r->numerotation;\r
-                       $c->chapters = $r->chapters;\r
-                       $this->con->execute('INSERT INTO book_pages SELECT ' . $book_id . ' AS book_id,book_page,document_id,document_page FROM book_pages WHERE book_id=' . $old_id);\r
-               }\r
-               $c->insert();\r
-               $this->saveCompositionVersion($book_id);\r
-\r
-               return $this->selectById($book_id);\r
-       }\r
-\r
-       public function creeEmpty($createur, $lang, $nom) {\r
-               $c = $this->con->openCursor('books');\r
-\r
-               $parametres = new wsBookParametres($this);\r
-               $parametres->title = $nom;\r
-\r
-               $c->proprietaire = $createur;\r
-               $c->cid = $this->generateCID();\r
-               $c->nom = $nom;\r
-               $c->date = TIME;\r
-               $c->hash = md5(rand(0, 1234567893));\r
-               $c->compteur_visites = 20;\r
-               $c->status = -1;\r
-               $c->date_status = TIME;\r
-               $c->parametres = serialize($parametres);\r
-\r
-               $c->theme = 1;\r
-               $c->lang = $lang;\r
-               $c->changedate = TIME;\r
-               $c->compiledate = 0;\r
-               $c->version = 2;\r
-               $c->composition_update = TIME;\r
-               $book_id = $c->book_id = $this->getNextId();\r
-               $c->insert();\r
-               return $this->selectById($book_id);\r
-       }\r
-\r
-       public function supprime($book_id) {\r
-               $this->con->execute('DELETE FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-               return $this->con->execute('DELETE FROM books WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function count($limitedToUserRights = false) {\r
-               $filters = $this->makeWhereFromFiltres();\r
-               if ($filters == '1=1') {\r
-                       $table = 'books';\r
-               } else {\r
-                       $table = 'books_vue';\r
-               }\r
-\r
-               $where = '(' . $filters . ')';\r
-               $where .= $this->limitToUserRights($limitedToUserRights);\r
-               $r = $this->con->select('SELECT COUNT(*) AS nb FROM ' . $table . ' WHERE ' . $where);\r
-               return $r->nb;\r
-       }\r
-\r
-       public function getPagesOfBookAt($book_id, $time) {\r
-               $r = $this->con->select('SELECT * FROM book_pages_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\' ORDER BY `update`');\r
-               if (!$r->count()) {\r
-                       return $this->getPagesOfBook($book_id);\r
-               }\r
-               if ($r->count() == 1) {\r
-                       $pages = unserialize($r->composition);\r
-                       if (!count($pages)) {\r
-                               return $this->getPagesOfBook($book_id);\r
-                       }\r
-                       return $pages;\r
-               }\r
-               $pages = null;\r
-               while ($r->fetch()) {\r
-                       if ($r->update > $time) {\r
-                               if (is_null($pages)) {\r
-                                       return $this->getPagesOfBook($book_id);\r
-                               }\r
-                               return unserialize($pages);\r
-                       }\r
-                       $pages = $r->composition;\r
-               }\r
-               return unserialize($pages);\r
-       }\r
-\r
-       public function getDocumentsToUpdate($book_id) {\r
-               $res = array();\r
-               $r = $this->con->select('SELECT DISTINCT d.document_id FROM book_pages b,documents d WHERE b.book_id=\'' . $this->con->escape($book_id) . '\' AND d.version=1 AND b.document_id=d.document_id');\r
-               while ($r->fetch()) {\r
-                       $res[] = $r->document_id;\r
-               }\r
-               return $res;\r
-       }\r
-\r
-       public function getPagesOfBook($book_id, $conversion = true) {\r
-               $pages = array();\r
-\r
-               $sql = 'SELECT b.*,d.numberSections AS num,d.conversionInfos AS conversion,d.pages AS doc_pages,d.version AS version FROM book_pages b JOIN documents d ON d.document_id=b.document_id WHERE b.book_id=\'' . $this->con->escape($book_id) . '\' ORDER BY book_page';\r
-\r
-               $r = $this->con->select($sql);\r
-               while ($r->fetch()) {\r
-                       $n = explode(',', $r->num);\r
-\r
-                       if (isset($n[$r->document_page - 1])) {\r
-                               $num = $n[$r->document_page - 1];\r
-                       } else {\r
-                               $num = '';\r
-                       }\r
-                       $pages[$r->book_page] = array('document_id' => $r->document_id,\r
-                               'document_page' => $r->document_page,\r
-                               'version' => $r->version,\r
-                               'defaultNum' => $num,\r
-                               'nb_pages' => $r->doc_pages\r
-                       );\r
-\r
-                       if ($conversion) {\r
-                               if ($r->conversion != '') {\r
-                                       $c = unserialize($r->conversion);\r
-                                       $c = $c->pages[$r->document_page];\r
-                               }\r
-                               $qp = array('resolution', 'method', 'quality', 'objects');\r
-                               foreach ($qp as $p) {\r
-                                       if (isset($c) && isset($c->$p)) {\r
-                                               $pages[$r->book_page][$p] = $c->$p;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               return $pages;\r
-       }\r
-\r
-       public function appendDocument($book_id, $document_id) {\r
-               $r = $this->con->select('SELECT MAX(book_page) AS book_page FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-               $lastPage = is_null($r->book_page) ? 0 : $r->book_page;\r
-               $this->insertDocument($book_id, $lastPage, $document_id);\r
-       }\r
-\r
-       public function removePage($book_id, $book_page) {\r
-               // Supprime la page\r
-               $this->con->execute('DELETE FROM book_pages WHERE book_page=\'' . $this->con->escape($book_page) . '\' AND book_id=\'' . $this->con->escape($book_id) . '\'');\r
-               // Décale les pages suivantes vers le haut\r
-               $this->decalePages($book_id, $book_page, -1);\r
-       }\r
-\r
-       public function insertPage($book_id, $after_page, $document_id, $document_page) {\r
-               // Décale les pages vers le bas\r
-               $this->decalePages($book_id, $after_page, 1);\r
-               // Insère la page\r
-               $c = $this->con->openCursor('book_pages');\r
-               $c->book_id = $book_id;\r
-               $c->book_page = $after_page + 1;\r
-               $c->document_id = $document_id;\r
-               $c->document_page = $document_page;\r
-               $c->insert();\r
-       }\r
-\r
-       public function insertDocument($book_id, $after_page, $document_id) {\r
-               // Obtiens le book\r
-               $book = $this->selectById($book_id);\r
-               $num = explode(',', $book->numerotation);\r
-               // Obtiens le nombre de pages\r
-               $r = $this->con->select('SELECT pages,numberSections FROM documents WHERE document_id=\'' . $this->con->escape($document_id) . '\'');\r
-               // Décale les pages vers le bas\r
-               if ($after_page > 0) {\r
-                       $this->decalePages($book_id, $after_page, $r->pages);\r
-               }\r
-               // Insère les pages\r
-               $c = $this->con->openCursor('book_pages');\r
-               $c->book_id = $book_id;\r
-               $c->document_id = $document_id;\r
-               for ($i = 1; $i <= $r->pages; $i++) {\r
-                       $c->document_page = $i;\r
-                       $c->book_page = $after_page + $i;\r
-                       $c->insert();\r
-               }\r
-               // Mets à jour la liste des numéros des pages\r
-               $before = array_slice($num, 0, $after_page);\r
-               $after = array_slice($num, $after_page, count($num) - $after_page);\r
-\r
-               $newnum = $r->numberSections;\r
-               if (trim($newnum, ',') == '') {\r
-                       // If no number detected, we create a numeric list from 1\r
-                       $between = range(1, $r->pages);\r
-               } else {\r
-                       // Else, we use numbers detected at conversion\r
-                       $between = explode(',', $r->numberSections);\r
-               }\r
-               $num = array_merge($before, $between, $after);\r
-               // Mets à jour la numerotation de la publication\r
-               $c = $this->con->openCursor('books');\r
-               $c->numerotation = implode(',', $num);\r
-               $c->composition_update = TIME;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-\r
-               $this->saveCompositionVersion($book_id);\r
-       }\r
-\r
-       protected function decalePages($book_id, $after_page, $decalage) {\r
-               $decalage = ($decalage >= 0) ? '+' . $decalage : $decalage;\r
-               $this->con->execute('UPDATE book_pages SET book_page=book_page' . $decalage . ' WHERE book_page>' . $this->con->escape($after_page) . ' AND book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function getListe($orderby = null, $sens = null, $limit = null, $limitedToUserRights = false) {\r
-               if (!is_null($this->q)) {\r
-                       $where = '(';\r
-                       if ($this->search_id) {\r
-                               $where .= ' book_id=\'' . $this->con->escape($this->q) . '\' OR ';\r
-                       }\r
-\r
-                       if (!cubeMath::is_int($this->q)) {\r
-                               $where .= 'nom LIKE \'%' . $this->con->escape($this->q) . '%\'';\r
-                               $daoClient = new commonDAOClient($this->con);\r
-                               $where .= ' OR proprietaire_id IN(' . $daoClient->querySearchByName($this->q) . ') OR ';\r
-                       }\r
-                       $limit = null;\r
-                       $where .= '1=2)';\r
-               } else {\r
-                       $where = '(' . $this->makeWhereFromFiltres() . ')';\r
-               }\r
-               $where .= $this->limitToUserRights($limitedToUserRights);\r
-\r
-               $orderby = is_null($orderby) ? 'book_id' : $orderby;\r
-               $sens = is_null($sens) ? 'DESC' : $sens;\r
-               $limit = is_null($limit) ? '' : $this->con->limit($limit);\r
-\r
-               $sql = 'SELECT * FROM books_vue WHERE ' . $where . ' ORDER BY ' . $orderby . ' ' . $sens . ' ' . $limit;\r
-               $r = $this->con->select($sql);\r
-               return $this->factory($r);\r
-       }\r
-\r
-       protected function limitToUserRights($utilisateur) {\r
-               if ($utilisateur) {\r
-                       if (wsDroits::admin()) {\r
-                               return '';\r
-                       }\r
-                       return ' AND proprietaire IN (' . $utilisateur->ws_rights . ')';\r
-               }\r
-               return '';\r
-       }\r
-\r
-       protected function makeWhereFromFiltres() {\r
-               if (!is_null($this->filtres)) {\r
-                       $w = array('1=1');\r
-                       if (commonFiltre::test('admin_book', $this->filtres)) {\r
-                               $w[] = 'super_admin IN (' . implode(',', array_keys($this->filtres['admin_book'])) . ')';\r
-                       }\r
-                       if (commonFiltre::test('status_book', $this->filtres)) {\r
-                               $w[] = 'status IN(' . implode(',', array_keys($this->filtres['status_book'])) . ')';\r
-                       }\r
-                       if (commonFiltre::test('revendeur_book', $this->filtres)) {\r
-                               $v = array_keys($this->filtres['revendeur_book']);\r
-                               $values = array();\r
-                               foreach ($v as $r) {\r
-                                       $values[] = $this->con->escape($r);\r
-                               }\r
-\r
-\r
-                               $w[] = 'facturable IN(\'' . implode('\',\'', $values) . '\')';\r
-                       }\r
-                       return implode(' AND ', $w);\r
-               } else {\r
-                       return '1=1';\r
-               }\r
-       }\r
-\r
-       public function setChapters($book_id, $json) {\r
-               $chapters = json_decode($json, TRUE);\r
-               $res = array();\r
-\r
-               foreach ($chapters as $c) {\r
-                       $c['label'] = trim($c['label']);\r
-                       $n = (string) $c['page'];\r
-                       $c['label'] = trim(preg_replace('|\s+' . $n . '$|iu', '', $c['label']));\r
-                       $res[] = $c;\r
-               }\r
-\r
-               $c = $this->con->openCursor('books');\r
-               $c->chapters = json_encode($res);\r
-               $c->changedate = TIME;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function setSpecialLinksAndRulers($book_id, $links, $rulers) {\r
-               $c1 = $this->con->openCursor('special_links_versions');\r
-               $c = $this->con->openCursor('books');\r
-\r
-               if (is_string($links)) {\r
-                       $links = json_encode(json_decode($links, false));\r
-               }\r
-               if (is_string($rulers)) {\r
-                       $rulers = json_encode(json_decode($rulers, false));\r
-               }\r
-\r
-               if (is_array($links)) {\r
-                       $links = json_encode($links);\r
-               }\r
-               if (is_array($rulers)) {\r
-                       $rulers = json_encode($rulers);\r
-               }\r
-\r
-\r
-\r
-               $c1->links = $c->specialLinks = $links;\r
-               $c1->rulers = $c->specialRulers = $rulers;\r
-               $c1->update = $c->changedate = TIME;\r
-               $c1->book_id = $book_id;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-               try {\r
-                       $c1->insert();\r
-               } catch (Exception $e) {\r
-                       $c1->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\' AND `update`=' . TIME);\r
-               }\r
-       }\r
-\r
-       public function setTheme($book_id, $theme) {\r
-               $c = $this->con->openCursor('books');\r
-               $c->theme = $theme;\r
-               $c->changedate = TIME;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function setStatus($book_id, $status) {\r
-               $c = $this->con->openCursor('books');\r
-               if ($status < 2) {\r
-                       $c->tache = 0;\r
-               }\r
-               $c->status = $status;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-               return $this->selectById($book_id);\r
-       }\r
-\r
-       public function setChaptersFromOldFluidbook($book_id) {\r
-               $book = $this->selectById($book_id);\r
-               $n = explode(',', $book->numerotation);\r
-\r
-               $xml = simplexml_load_file('http://ws.fluidbook.com/books/' . $book_id . '/data/links.xml');\r
-               $res = array();\r
-               $chapters = $xml->xpath('//chapters');\r
-               foreach ($chapters as $ch) {\r
-                       $c = array();\r
-                       $c['label'] = (string) $ch->txt;\r
-\r
-                       $p = intval((string) $ch->page);\r
-                       if ($p <= 0) {\r
-                               continue;\r
-                       }\r
-                       $c['page'] = $n[$p];\r
-                       $c['level'] = intval((string) $ch->level);\r
-                       $res[] = $c;\r
-               }\r
-\r
-               $c = $this->con->openCursor('books');\r
-               $c->chapters = json_encode($res);\r
-               $c->changedate = TIME;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function saveCompositionVersion($book_id, $time = null) {\r
-\r
-               $time = is_null($time) ? TIME : $time;\r
-\r
-               $pages = $this->getPagesOfBook($book_id);\r
-\r
-               $c = $this->con->openCursor('book_pages_versions');\r
-               $c->update = $time;\r
-               $c->book_id = $book_id;\r
-               $c->composition = serialize($pages);\r
-               $c->insert();\r
-       }\r
-\r
-       public function setLang($book_id, $base, $traductions) {\r
-               // Cleanup user translations\r
-               $traductions = json_decode($traductions, true);\r
-               foreach ($traductions as $k => $v) {\r
-                       $traductions[$k] = trim($v);\r
-               }\r
-\r
-               $daoLang = new wsDAOLang($this->con);\r
-               $lang = $daoLang->selectById($base);\r
-               // Cleanup base translations\r
-               $baseTraductions = $lang->traductions;\r
-               foreach ($baseTraductions as $k => $v) {\r
-                       $baseTraductions[$k] = trim($v);\r
-               }\r
-               // Then compare them. If there is no differences, we don't save translations in the book\r
-               if ($traductions == $baseTraductions) {\r
-                       $t = '';\r
-               } else {\r
-                       $t = json_encode($traductions);\r
-               }\r
-\r
-               $c = $this->con->openCursor('books');\r
-               $c->lang = $base;\r
-               $c->traductions = $t;\r
-               $c->changedate = TIME;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function setSettings($book_id, $settings) {\r
-               $book = $this->selectById($book_id);\r
-               $parametres = $book->parametres;\r
-               $new = $settings;\r
-               foreach ($new as $k => $v) {\r
-                       if ($k == '_empty_') {\r
-                               continue;\r
-                       }\r
-                       $parametres->$k = $v;\r
-               }\r
-\r
-               $ip = array();\r
-               if (isset($parametres->stats_exclude_ip) && trim($parametres->stats_exclude_ip) != '') {\r
-                       $list = $parametres->stats_exclude_ip;\r
-                       $list = str_replace("\r", "\n", $list);\r
-                       $e = explode("\n", $list);\r
-                       foreach ($e as $i) {\r
-                               $i = trim($i);\r
-                               if ($i == '') {\r
-                                       continue;\r
-                               }\r
-                               $long = ip2long($i);\r
-                               if ($long !== false) {\r
-                                       $ip[] = $long;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               $file = '/home/stats/www/exclude/' . $book_id;\r
-\r
-               if (count($ip)) {\r
-                       file_put_contents($file, implode(',', $ip));\r
-                       chmod($file, 0777);\r
-                       chown($file, 'stats');\r
-               } else if (file_exists($file)) {\r
-                       unlink($file);\r
-               }\r
-\r
-               $c = $this->con->openCursor('books');\r
-               $c->nom = $parametres->title;\r
-               $c->parametres = serialize($parametres);\r
-               $c->changedate = TIME;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function setProprietaire($book_id, $proprietaire_id) {\r
-               $c = $this->con->openCursor('books');\r
-               $c->proprietaire = $proprietaire_id;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function setTache($book_id, $tache) {\r
-               $c = $this->con->openCursor('books');\r
-               $c->tache = $tache;\r
-               $c->status = 2;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function setVersion($book_id, $version) {\r
-               $c = $this->con->openCursor('books');\r
-               $c->version = $version;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function touch($book_id) {\r
-               $c = $this->con->openCursor('books');\r
-               $c->changedate = TIME;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function touchCompile($book_id, $version = 'all') {\r
-               $c = $this->con->openCursor('books');\r
-               if ($version == '2') {\r
-                       $c->compiledate = TIME;\r
-               } elseif ($version == '1') {\r
-                       $c->compile1date = TIME;\r
-               } elseif ($version == 'html5') {\r
-                       $c->compilehtml5date = TIME;\r
-               } else {\r
-                       $c->compiledate = TIME;\r
-                       $c->compile1date = TIME;\r
-                       $c->compilehtml5date = TIME;\r
-               }\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function isUpToDate($book, $version) {\r
-               $version = (string) $version;\r
-               if ($version == '2') {\r
-                       if (!file_exists(WS_BOOKS . '/final/' . $book->book_id)) {\r
-                               return false;\r
-                       }\r
-                       if ($book->compiledate < $book->changedate) {\r
-                               return false;\r
-                       }\r
-               } else if ($version == '1') {\r
-                       // V1\r
-                       if (!file_exists(WS_BOOKS . '/finalv1/' . $book->book_id . '/index.swf')) {\r
-                               return false;\r
-                       }\r
-                       if ($book->compile1date < $book->changedate) {\r
-                               return false;\r
-                       }\r
-               } else if ($version == 'html5') {\r
-                       // HTML5\r
-                       $checks = array($book->changedate, cubeFiles::filemtimeRecursive(WS_BOOKS . '/working/' . $book->book_id), cubeFiles::filemtimeRecursive(WS_COMPILE_ASSETS . '/_html5'), cubeFiles::filemtimeRecursive(ROOT . '/inc/ws/Util/html5'));\r
-                       foreach ($checks as $check) {\r
-                               if ($check > $book->compilehtml5date) {\r
-                                       return false;\r
-                               }\r
-                       }\r
-               }\r
-               return true;\r
-       }\r
-\r
-       public function setComposition($book_id, $pages) {\r
-               $numerotation = array();\r
-               $nb_pages = 0;\r
-               foreach ($pages as $p) {\r
-                       $numerotation[] = $p->virtual;\r
-                       $nb_pages++;\r
-               }\r
-\r
-               $book = $this->selectById($book_id);\r
-               $parametres = $book->parametres;\r
-               $parametres->pages = $nb_pages;\r
-\r
-               $c = $this->con->openCursor('books');\r
-               $c->parametres = serialize($parametres);\r
-               $c->numerotation = implode(',', $numerotation);\r
-               $c->changedate = TIME;\r
-\r
-               // Check if composition need to be updated\r
-               $r = $this->con->select('SELECT * FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-               $tab = array();\r
-               $now = array();\r
-               while ($r->fetch()) {\r
-                       $ref[$r->book_page] = array((int) $r->document_id, (int) $r->document_page);\r
-               }\r
-               $i = 1;\r
-               foreach ($pages as $p) {\r
-                       $now[$i] = array((int) $p->document_id, (int) $p->document_page);\r
-                       $i++;\r
-               }\r
-               if ($now != $ref) {\r
-                       $this->con->execute('DELETE FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-\r
-                       $c1 = $this->con->openCursor('book_pages');\r
-                       $c1->book_id = $book_id;\r
-                       $i = 1;\r
-                       foreach ($pages as $p) {\r
-                               $c1->document_id = $p->document_id;\r
-                               $c1->document_page = $p->document_page;\r
-                               $c1->book_page = $i;\r
-                               $c1->insert();\r
-                               $i++;\r
-                       }\r
-                       $c->composition_update = TIME;\r
-                       $this->saveCompositionVersion($book_id);\r
-               }\r
-\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function setInstallDir($book_id, $dir, $server) {\r
-               $col = 'dir_' . $server;\r
-\r
-               $c = $this->con->openCursor('books');\r
-               $c->$col = $dir;\r
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');\r
-       }\r
-\r
-       public function makeTextsIndexes($book, $pages, &$index, &$textes) {\r
-\r
-               $prefix = '';\r
-               if ($book->parametres->textExtraction == 'poppler') {\r
-                       $prefix = 'p';\r
-               }\r
-\r
-\r
-               $dir = WS_BOOKS . '/index/' . $book->book_id;\r
-               if ($book->parametres->ignoreSearchSeparators != '') {\r
-                       $dir.='/' . sha1($book->parametres->ignoreSearchSeparators);\r
-               }\r
-               if (!file_exists($dir)) {\r
-                       mkdir($dir, 0777, true);\r
-               }\r
-\r
-               $ifilec = $dir . '/' . $prefix . 'index.json';\r
-               $tfilec = $dir . '/' . $prefix . 'textes.json';\r
-\r
-               if (file_exists($ifilec) && file_exists($tfilec) && (min(filemtime($ifilec), filemtime($tfilec)) >= $book->composition_update)) {\r
-                       $index = file_get_contents($ifilec);\r
-                       $textes = file_get_contents($tfilec);\r
-                       return;\r
-               }\r
-\r
-               if ($book->parametres->ignoreSearchSeparators != "") {\r
-                       $docs = array();\r
-                       foreach ($pages as $p => $i) {\r
-                               $docs[] = $i['document_id'];\r
-                       }\r
-                       $docs = array_unique($docs);\r
-\r
-                       foreach ($docs as $doc) {\r
-                               $out = WS_DOCS . '/' . $doc . '/';\r
-\r
-                               $fwstk = new cubeCommandLine('fwstk');\r
-                               $fwstk->setPath(CONVERTER_PATH);\r
-                               $fwstk->setArg('--input ' . $out . '/crop.pdf');\r
-                               $fwstk->setArg('--extractTexts ' . $out . '%s%d.txt');\r
-                               $fwstk->setArg('--ignoreSeparators ' . $book->parametres->ignoreSearchSeparators);\r
-                               $fwstk->execute();\r
-                       }\r
-               }\r
-\r
-               $index = array();\r
-               $textes = array();\r
-               foreach ($pages as $book_page => $infos) {\r
-                       $tfile = WS_DOCS . '/' . $infos['document_id'] . '/' . $prefix . 'p' . $infos['document_page'] . '.txt';\r
-                       $ifile = WS_DOCS . '/' . $infos['document_id'] . '/' . $prefix . 'i' . $infos['document_page'] . '.txt';\r
-                       $text = file_get_contents($tfile);\r
-                       $ipage = file_get_contents($ifile);\r
-\r
-                       $this->fillIndexWithWords($index, $book_page, $ipage);\r
-                       $textes[$book_page] = $text;\r
-               }\r
-               ksort($index);\r
-\r
-\r
-               $textes = json_encode($textes);\r
-               $index = json_encode($index);\r
-\r
-               file_put_contents($tfilec, $textes);\r
-               file_put_contents($ifilec, $index);\r
-       }\r
-\r
-       protected function fillIndexWithWords(&$index, $page, $ipage) {\r
-               $twords = explode("\n", trim($ipage));\r
-\r
-               foreach ($twords as $woadata) {\r
-                       $w1 = explode(',', trim($woadata));\r
-                       if (count($w1) <= 1) {\r
-                               continue;\r
-                       }\r
-                       list($woa, $worddata) = $w1;\r
-                       $e = explode("\t", $worddata, 2);\r
-                       if (count($e) < 2) {\r
-                               continue;\r
-                       }\r
-                       list($total, $wordslist) = $e;\r
-\r
-                       if ($woa == '') {\r
-                               continue;\r
-                       }\r
-\r
-                       if (!isset($index[$woa])) {\r
-                               $index[$woa] = array('t' => 0, 'w' => array());\r
-                       }\r
-                       $index[$woa]['t'] += $total;\r
-\r
-                       $words = explode("\t", $wordslist);\r
-\r
-                       foreach ($words as $word) {\r
-                               list($wordwa, $count) = explode('$', $word, 2);\r
-                               if (!isset($index[$woa]['w'][$wordwa])) {\r
-                                       $index[$woa]['w'][$wordwa] = array('t' => 0, 'p' => array());\r
-                               }\r
-                               if (!isset($index[$woa]['w'][$wordwa]['p'][$page])) {\r
-                                       $index[$woa]['w'][$wordwa]['p'][$page] = 0;\r
-                               }\r
-                               $index[$woa]['w'][$wordwa]['t'] += $count;\r
-                               $index[$woa]['w'][$wordwa]['p'][$page] += $count;\r
-                       }\r
-               }\r
-       }\r
-\r
-       public function getNumerotationFromDocs($book_id) {\r
-               $pages = $this->getPagesOfBook($book_id);\r
-       }\r
-\r
-       public function compileTemp($book_id, $version, $dir) {\r
-               if ($version == 'ha' || $version == 'hi') {\r
-                       if ($version == 'ha') {\r
-                               $os = 'android';\r
-                       } elseif ($version == 'hi') {\r
-                               $os = 'ios';\r
-                       }\r
-                       $packager = new wsPackagerPhonegap($book_id, $dir, false, true, $os);\r
-                       $packager->makePackage(false);\r
-               }\r
-       }\r
-\r
-       public function compile($book_id, $version = 'all', $complete = false, $force = false) {\r
-               if (is_null($book_id) || !$book_id) {\r
-                       return;\r
-               }\r
-\r
-               $v1 = $v2 = $html5 = false;\r
-\r
-               if ($version == 'all') {\r
-                       $v1 = $v2 = $html5 = true;\r
-               } else if ($version == '1') {\r
-                       $v1 = true;\r
-               } else if ($version == '2') {\r
-                       $v2 = true;\r
-               } elseif ($version == 'html5') {\r
-                       $html5 = true;\r
-               }\r
-\r
-               $book = $this->selectById($book_id);\r
-               $pages = $this->getPagesOfBook($book_id);\r
-\r
-               if (!$force) {\r
-\r
-                       $v1 = $v1 && !$this->isUpToDate($book, 1);\r
-                       $v2 = $v2 && !$this->isUpToDate($book, 2);\r
-                       $html5 = $html5 && !$this->isUpToDate($book, 'html5');\r
-               } else {\r
-                       $v1 = false;\r
-                       $html5 = false;\r
-                       $v2 = true;\r
-               }\r
-\r
-\r
-\r
-               $res = '';\r
-               if ($v1) {\r
-                       fb(time(), 'Compile V1');\r
-                       $res.=$this->compile1($book_id, $book, $pages);\r
-                       $this->touchCompile($book_id, '1');\r
-               }\r
-               if ($v2) {\r
-                       fb(time(), 'Compile V2');\r
-                       $res .= $this->compile3($book_id, $complete, $book, $pages);\r
-                       $this->touchCompile($book_id, '2');\r
-               }\r
-               if ($html5) {\r
-                       fb(time(), 'Compile HTML5');\r
-                       $res.=$this->compileHTML5($book_id, $book);\r
-                       $this->touchCompile($book_id, 'html5');\r
-               }\r
-               if ($v1 || $v2) {\r
-                       fb(time(), 'Compile PDF & Widget');\r
-                       $this->compilePDF($book, $pages);\r
-                       $this->compileWidget($book, $pages);\r
-               }\r
-\r
-               fb(time(), 'End Compile');\r
-               return $res;\r
-       }\r
-\r
-       public function compile1($book_id, $book, $pages) {\r
-               $finalDir = WS_BOOKS . '/finalv1/' . $book_id . '/';\r
-               $packager = new wsPackagerV1($book_id, $finalDir, false);\r
-               $packager->makePackage(false);\r
-       }\r
-\r
-       public function compile3($book_id, $complete, $book, $pages) {\r
-               $res = '';\r
-\r
-               $compilerDir = WS_BOOKS . '/datasCompiler/' . $book_id . '/';\r
-               $finalDir = WS_BOOKS . '/final/' . $book_id . '/';\r
-\r
-               $rm = new cubeCommandLine('rm');\r
-               $rm->setArg('r');\r
-               $rm->setArg('f');\r
-               $rm->setArg(null, $finalDir);\r
-               $rm->execute();\r
-               mkdir($finalDir, 0777, true);\r
-\r
-               $flex = new cubeFlexCompiler('FluidbookDatas', $compilerDir, 'flash.display.Sprite', explode(';', AS3_SOURCES), MXMLC_PATH, 10);\r
-               $flexLight = new cubeFlexCompiler('FluidbookDatasLight', $compilerDir, 'flash.display.Sprite', explode(';', AS3_SOURCES), MXMLC_PATH, 10);\r
-\r
-               $filesToCopy = array();\r
-               $this->compileFlex($book_id, $complete, $compilerDir, $finalDir, $filesToCopy, $book, $pages, $flex, $flexLight);\r
-\r
-               $res .= $flex->compile() . "\n\n-------------------\n\n";\r
-               $flexLight->addVariable('datasSize', filesize($compilerDir . '/FluidbookDatas.swf'));\r
-               $res .= $flexLight->compile();\r
-\r
-               $filesToCopy['data/fd.swf'] = $compilerDir . '/FluidbookDatas.swf';\r
-               $filesToCopy['data/fdl.swf'] = $compilerDir . '/FluidbookDatasLight.swf';\r
-\r
-               // Copy of files\r
-               // Check if dest dir exists\r
-               if (!file_exists($finalDir . 'data')) {\r
-                       mkdir($finalDir . 'data', 0777, true);\r
-               }\r
-\r
-               foreach ($filesToCopy as $local => $source) {\r
-                       $localPath = $finalDir . $local;\r
-                       if (!file_exists($localPath) || filemtime($localPath) < filemtime($source) || filesize($localPath) != filesize($source) || filemtime($localPath) < $book->composition_update) {\r
-                               if (is_dir($source)) {\r
-                                       continue;\r
-                               }\r
-                               $this->copy($source, $localPath);\r
-                       }\r
-               }\r
-\r
-               $workingDir = WS_BOOKS . '/working/' . $book_id . '/';\r
-               if (file_exists($workingDir . 'media')) {\r
-                       $cp = new cubeCommandLine('cp');\r
-                       $cp->setPath(CONVERTER_PATH);\r
-                       $cp->setArg('r');\r
-                       $cp->setArg('p');\r
-                       $cp->setArg(null, $workingDir . 'media');\r
-                       $cp->setArg(null, $finalDir . 'data');\r
-                       $cp->execute();\r
-               }\r
-\r
-               return $res;\r
-       }\r
-\r
-       public function copy($source, $dest) {\r
-               copy($source, $dest);\r
-               touch($dest, filemtime($source));\r
-       }\r
-\r
-       public function compileAir($book_id) {\r
-               $compilerDir = WS_BOOKS . '/air/' . $book_id . '/compiler';\r
-               $finalDir = WS_BOOKS . '/air/' . $book_id . '/';\r
-\r
-               $book = $this->selectById($book_id);\r
-               $pages = $this->getPagesOfBook($book_id);\r
-\r
-               $src = AS3_FLUIDBOOK_SOURCES . '/_src/';\r
-               $lib10 = AS3_FLUIDBOOK_SOURCES . '/lib10/';\r
-               $libs = array(\r
-                       $src,\r
-                       $lib10,\r
-                       AS3_SOURCES,\r
-                       $src . 'lib/fluidbook3dLibrary.swc',\r
-                       $src . 'lib/mdm.swc',\r
-                       $lib10 . 'flash.swc',\r
-                       $lib10 . 'flex.swc',\r
-                       $lib10 . 'framework.swc',\r
-               );\r
-\r
-               wsSVN::updateToLastRevision();\r
-\r
-               $swf = 'FluidbookAirProjector' . $book_id;\r
-               $flex = new cubeFlexCompiler($swf, $compilerDir, 'com.fluidbook.player.AIRMain', $libs, '/usr/local/flex/bin/mxmlc', 'air', 45, 800, 600, true);\r
-\r
-               $this->compileFlex($book_id, true, $compilerDir, $finalDir, $filesToCopy, $book, $pages, $flex, $flex);\r
-               $res = $flex->compile();\r
-\r
-               $air = new cubeAIRCompiler($swf . '.swf', '/usr/local/flex/bin', $compilerDir, '2.0');\r
-               $air->setApplicationDatas('com.fluidbook' . $book_id, $book->parametres->title, $book->parametres->title, cubeText::str2URL($book->parametres->title), $book->lang);\r
-               $air->setInitialWindow($book->parametres->title);\r
-               $res.=$air->compile();\r
-\r
-               return $res;\r
-       }\r
-\r
-       public function compileFlex($book_id, $complete, $compilerDir, $finalDir, &$filesToCopy, $book, $pages, $flex, $flexLight) {\r
-               cubePHP::neverStop();\r
-               /* @var $flex cubeFlexCompiler */\r
-\r
-               $workingDir = WS_BOOKS . '/working/' . $book_id . '/';\r
-\r
-               $res = '';\r
-\r
-               $daoDoc = new wsDAODocument($this->con);\r
-               $firstDoc = $daoDoc->selectById($pages[1]['document_id']);\r
-               $size = $firstDoc->generalInfos['size'];\r
-\r
-               $daoLang = new wsDAOLang($this->con);\r
-               $lang = $daoLang->selectById($book->lang);\r
-\r
-               $langs = $daoLang->selectAll();\r
-\r
-               $daoTheme = new wsDAOTheme($this->con);\r
-               $theme = $daoTheme->getThemeOfBook($book_id, true);\r
-\r
-               $daoSignature = new wsDAOSignature($this->con);\r
-               $signature = $daoSignature->selectById($book->parametres->signature);\r
-\r
-               $exportSignature = array('main' => $signature->main,\r
-                       'mainLink' => $signature->mainLink,\r
-                       'partner' => $signature->partner,\r
-                       'partnerLink' => $signature->partnerLink);\r
-\r
-               $index = '';\r
-               $textes = '';\r
-\r
-               $hash = $book_id;\r
-               $hash .= 'kjgl!az4.';\r
-               $hash .= count($pages);\r
-               $hash .= round($size[0], 3);\r
-\r
-               $hash = sha1($hash);\r
-\r
-               $this->makeTextsIndexes($book, $pages, $index, $textes);\r
-\r
-               $daoDoc->getLinksAndRulers($book_id, $links, $rulers);\r
-\r
-               $imagesassets = array();\r
-               $id = 1;\r
-               foreach ($links as $id => $link) {\r
-                       $links[$id]['id'] = $id;\r
-                       if ($link['type'] == 15) {\r
-                               if (isset($imagesassets[$id])) {\r
-                                       continue;\r
-                               }\r
-                               if ($link['page'] <= 1) {\r
-                                       $flexLight->addBitmap($workingDir . '/' . $link['to'], 'link_datas_' . $id);\r
-                               } else {\r
-                                       $flex->addBitmap($workingDir . '/' . $link['to'], 'link_datas_' . $id);\r
-                               }\r
-                               $imagesassets[$id] = true;\r
-                       } else if (in_array($link['type'], array(4, 6, 7, 9, 16, 17))) {\r
-                               $workingFile = $workingDir . '/' . $link['to'];\r
-                               if (file_exists($workingFile)) {\r
-                                       $filesToCopy['data/' . $link['to']] = $workingFile;\r
-                               }\r
-\r
-                               if ($link['type'] == 4) {\r
-                                       $poster = $link['to'];\r
-                                       $e = explode('.', $poster);\r
-                                       array_pop($e);\r
-                                       array_push($e, 'jpg');\r
-                                       $poster = implode('.', $e);\r
-\r
-                                       $workingFile = $workingDir . '/' . $poster;\r
-                                       if (file_exists($workingFile)) {\r
-                                               $filesToCopy['data/' . $poster] = $workingFile;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               $externalsOptions = array('ongletsSWF', 'tabs2DSWF', 'externalChapters', 'externalArchives');\r
-               foreach ($externalsOptions as $e) {\r
-                       if (isset($book->parametres->$e) && $book->parametres->$e != '') {\r
-                               $f = $workingDir . '/' . $book->parametres->$e;\r
-                               if (file_exists($f)) {\r
-                                       $filesToCopy['data/' . $book->parametres->$e] = $f;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               $flex->addVariable('links', $links, false, true, 'JSONObject');\r
-\r
-               $flex->addVariable('signature', $exportSignature, false, true, 'JSONObject');\r
-               $flexLight->addVariable('datas', $book->parametres->toStandardObject(), false, true, 'JSONObject');\r
-               $flexLight->addVariable('id', $book_id, false, true, 'uint');\r
-               $flexLight->addVariable('cid', $book->cid, false, true, 'String');\r
-\r
-               $traductions = (!count($book->traductions)) ? $lang->traductions : $book->traductions;\r
-               $allTraductions = array();\r
-               foreach ($langs as $l) {\r
-                       $allTraductions[$l->lang_id] = $l->traductions;\r
-               }\r
-\r
-               $flex->addVariable('traductions', $traductions, false, true, 'JSONObject', false);\r
-               $flex->addVariable('allTraductions', $allTraductions, false, true, 'JSONObject');\r
-               $flex->addVariable('chapters', $book->chapters, false, true, 'JSONObject');\r
-               $flex->addVariable('extras', '<extras>' . $book->extras . '</extras>', false, true, 'XML');\r
-               $flex->addVariable('numerotation', $book->numerotation, false, true, 'String');\r
-               $flexLight->addVariable('theme', $theme->parametres->toStandardObject(), false, true, 'JSONObject');\r
-               $flexLight->addVariable('pages', $book->parametres->pages);\r
-               $flexLight->addVariable('fwidth', round($size[0], 4), false, true, 'Number');\r
-               $flexLight->addVariable('fheight', round($size[1], 4), false, true, 'Number');\r
-               $flexLight->addVariable('pagesInDatas', $complete, false, true, 'Boolean');\r
-               $flex->addVariable('index', $index, false, true, 'JSONObject', false, false);\r
-               $flex->addVariable('textes', $textes, false, true, 'JSONObject', false, false);\r
-\r
-               $rasterized = array();\r
-               $sizes = array();\r
-\r
-               foreach ($pages as $i => $infos) {\r
-                       $base = WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'];\r
-                       $baset = WS_DOCS . '/' . $infos['document_id'] . '/t' . $infos['document_page'];\r
-                       $swffile = $base . '.swf';\r
-                       if (file_exists($swffile)) {\r
-                               $fsize = filesize($swffile);\r
-                       } else {\r
-                               $fsize = 0;\r
-                       }\r
-\r
-                       if ($complete) {\r
-                               $flex->addSWF($swffile, 'page' . $i);\r
-                       } else {\r
-                               $filesToCopy['data/p' . $i . '.swf'] = $swffile;\r
-                               if ($infos['method'] >= wsDocument::BARBARE_PNM) {\r
-                                       $rasterized[$i] = true;\r
-                                       $filesToCopy['data/t' . $i . '.swf'] = $baset . '.swf';\r
-                               } else {\r
-                                       $rasterized[$i] = false;\r
-                               }\r
-                       }\r
-\r
-                       if ($i == 1) {\r
-                               $flexLight->addBitmap($base . '.jpg', 'thumb1');\r
-                       } else {\r
-                               $flex->addBitmap($base . '.jpg', 'thumb' . $i);\r
-                       }\r
-                       $sizes[$i] = $fsize;\r
-               }\r
-\r
-               $flexLight->addVariable('rasterized', $rasterized, false, true, 'JSONObject');\r
-               $flexLight->addVariable('sizes', $sizes, false, true, 'JSONObject');\r
-\r
-               if ($book->parametres->soundTheme != '') {\r
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/corner-drag.mp3', 'soundDragCorner');\r
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/corner-release.mp3', 'soundReleaseCorner');\r
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/page-flip-1.mp3', 'soundPage0');\r
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/page-flip-2.mp3', 'soundPage1');\r
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/cover-flip.mp3', 'soundCover0');\r
-               }\r
-               // Theme assets\r
-               $themeRoot = WS_THEMES . '/' . $theme->theme_id . '/';\r
-\r
-               if ($theme->parametres->backgroundImage != '') {\r
-                       $flexLight->addBitmap($themeRoot . $theme->parametres->backgroundImage, 'background');\r
-               }\r
-               if ($theme->parametres->menuImage != '') {\r
-                       $flex->addBitmap($themeRoot . $theme->parametres->menuImage, 'menu');\r
-               }\r
-               if ($theme->parametres->logoLoader != '') {\r
-                       $flexLight->addBitmap($themeRoot . $theme->parametres->logoLoader, 'logoLoader');\r
-               }\r
-               if ($theme->parametres->topBar != '') {\r
-                       $flexLight->addBitmap($themeRoot . $theme->parametres->topBar, 'topBar');\r
-               }\r
-               if ($theme->parametres->logo != '') {\r
-                       $flex->addBitmap($themeRoot . $theme->parametres->logo, 'logo');\r
-               }\r
-               if ($theme->parametres->afterSearch != '') {\r
-                       $flex->addBitmap($themeRoot . $theme->parametres->afterSearch, 'aftersearch');\r
-               }\r
-               if ($theme->parametres->favicon != '') {\r
-                       $filesToCopy['data/fluidbook.ico'] = $themeRoot . 'fluidbook.ico';\r
-               }\r
-\r
-               // Icons assets\r
-               $iconsRoot = WS_ICONS . '/' . $theme->parametres->iconSet . '/';\r
-               foreach (wsIcone::$files as $file) {\r
-                       $flex->addBitmap($iconsRoot . 'nav-' . $file . '.png', 'nav_' . $file);\r
-               }\r
-               // Share icons\r
-               $iconsRoot = WS_ICONS . '/share/';\r
-               foreach (wsIcone::$share as $file) {\r
-                       $flex->addBitmap($iconsRoot . 'share-' . $file . '.png', 'share_' . $file);\r
-               }\r
-\r
-               // Multilang\r
-               if (trim($book->parametres->multilang) != '') {\r
-                       $m = str_replace("\r", "\n", trim($book->parametres->multilang));\r
-                       $langs = explode("\n", $m);\r
-                       $langNames = array();\r
-                       $countryNames = array();\r
-                       $iso = l10n::getISOcodes();\r
-                       $chars = '()';\r
-                       $vuFlags = array();\r
-                       foreach ($langs as $l) {\r
-                               list($mlang, $flag, $url) = explode(',', trim($l), 3);\r
-                               if (!isset($vuFlags[$flag])) {\r
-                                       $flex->addBitmap(cubeMedia::getFlagFile($flag), 'flag_' . $flag);\r
-                                       $vuFlags[$flag] = true;\r
-                               }\r
-                               $n = cubeText::ucfirst($iso[$mlang]);\r
-                               $langNames[$mlang] = $n;\r
-                               $cn = cubeCountry::getCountryName($flag, $mlang);\r
-                               $countryNames[$mlang . '_' . $flag] = $cn;\r
-                               $chars.=$n . $cn;\r
-                       }\r
-\r
-                       $chars = preg_split('/(?<!^)(?!$)/u', $chars);\r
-                       $chars = array_unique($chars);\r
-\r
-                       $flex->addFont(WS_FILES . '/fonts/FluidbookMultilang.ttf', 'MultilangFont', $chars);\r
-                       $flex->addVariable('langNames', $langNames, false, true, 'JSONObject');\r
-                       $flex->addVariable('countryNames', $countryNames, false, true, 'JSONObject');\r
-               }\r
-               $flexLight->addVariable('lang', $book->lang);\r
-\r
-               // Basket\r
-               if ($book->parametres->basket) {\r
-                       $formats = array('jpg', 'png', 'jpeg');\r
-                       $referencesFile = $workingDir . 'commerce/' . $book->parametres->basketReferences;\r
-\r
-                       if (file_exists($referencesFile)) {\r
-                               $xml = simplexml_load_file($referencesFile);\r
-                               $i = 0;\r
-                               $allref = array();\r
-                               foreach ($xml->item as $item) {\r
-                                       $ref = (string) $item['reference'];\r
-                                       if (isset($allref[$ref])) {\r
-                                               continue;\r
-                                       }\r
-                                       $allref[$ref] = true;\r
-                                       foreach ($formats as $f) {\r
-                                               $refimage = $workingDir . 'commerce/' . $ref . '.' . $f;\r
-                                               if (file_exists($refimage)) {\r
-                                                       $flex->addBitmap($refimage, "basket_image_" . $ref);\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-                                       $i++;\r
-                               }\r
-                       }\r
-                       if (isset($xml)) {\r
-                               $flex->addVariable('basketReferences', cubeXML::condense($xml->asXML()), false, true, "String");\r
-                       }\r
-                       if ($book->parametres->basketPDFBackground != '') {\r
-                               $flex->addByteArray($workingDir . 'commerce/' . $book->parametres->basketPDFBackground, 'basket_pdf_background');\r
-                       }\r
-               }\r
-               // Fonts\r
-               if ($theme->parametres->fontKit == 'auto') {\r
-                       if ($lang->font != 'system') {\r
-                               $flex->addFont(FONT_PATH . '/' . $lang->font, 'BoldFont', $lang->charset);\r
-                               $flex->addFont(FONT_PATH . '/' . $lang->font, 'GeneralFont', $lang->charset);\r
-                       }\r
-                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');\r
-                       $flexLight->addFont(FONT_PATH . '/FluidbookLoader.ttf', 'LoaderFont', 'Numerals');\r
-               } else if ($theme->parametres->fontKit == 'vagrounded') {\r
-                       $flex->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Bold.otf', 'BoldFont', $lang->charset);\r
-                       $flex->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Light.otf', 'GeneralFont', $lang->charset);\r
-                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');\r
-                       $flexLight->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Bold.otf', 'LoaderFont', 'Numerals');\r
-               } else if ($theme->parametres->fontKit == 'gill') {\r
-                       $flex->addFont(FONT_PATH . '/gill/gill.ttf', 'BoldFont', $lang->charset);\r
-                       $flex->addFont(FONT_PATH . '/gill/gill.ttf', 'GeneralFont', $lang->charset);\r
-                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');\r
-                       $flexLight->addFont(FONT_PATH . '/gill/gill.ttf', 'LoaderFont', 'Numerals');\r
-               }\r
-\r
-               $flexLight->addVariable('checksum', $hash, false, true, 'String');\r
-       }\r
-\r
-       public function compileWidget($book, $pages) {\r
-               if (!$book->parametres->widget) {\r
-                       return;\r
-               }\r
-\r
-               global $core;\r
-\r
-               $finalDir = WS_BOOKS . '/final/' . $book->book_id . '/widget/';\r
-               $finalWidget = $finalDir . 'miniFluidbook.swf';\r
-\r
-               if (!file_exists($finalDir)) {\r
-                       mkdir($finalDir, 0777, true);\r
-               }\r
-\r
-               if ($book->parametres->widgetCover) {\r
-                       $file = 'miniFluidbookCouv.swf';\r
-               } else {\r
-                       $file = 'miniFluidbook.swf';\r
-               }\r
-               $mini = WS_COMPILE_ASSETS . '/_widget/' . $file;\r
-\r
-               $from = max(1, $book->parametres->widgetStart);\r
-               $to = min($book->parametres->widgetEnd, count($pages));\r
-\r
-               $swfcombine = new cubeCommandLine('swfcombine');\r
-               $swfcombine->setPath(CONVERTER_PATH);\r
-               $swfcombine->setArg('merge');\r
-               $swfcombine->setArg('stack1');\r
-               $swfcombine->setArg('z');\r
-               $swfcombine->setArg('o', $finalWidget);\r
-               $swfcombine->setArg(null, $mini);\r
-\r
-               $tempimage = array();\r
-               $tempswf = array();\r
-               $timg = array();\r
-\r
-               for ($i = $from; $i <= $to; $i++) {\r
-                       $page = $pages[$i];\r
-\r
-                       $timg[$i] = $tempimage[$i] = cubeFiles::tempnam();\r
-                       $tempswf[$i] = cubeFiles::tempnam();\r
-\r
-                       $it = new imageTools();\r
-                       $image = WS_DOCS . '/' . $page['document_id'] . '/html/t150-' . $page['document_page'] . '.jpg';\r
-\r
-                       try {\r
-                               $it->loadImage($image);\r
-                               $it->resize($book->parametres->widgetSize, 10000);\r
-                               $it->output('jpeg', $tempimage[$i], 100);\r
-                       } catch (Exception $e) {\r
-                               $tempimage[$i] = $image;\r
-                       }\r
-                       $jpg2swf = new cubeCommandLine('jpeg2swf');\r
-                       $jpg2swf->setEnv('PATH', '/bin:/usr/bin:/usr/local/bin');\r
-                       $jpg2swf->setArg('q', $book->parametres->widgetQuality);\r
-                       $jpg2swf->setArg('o', $tempswf[$i]);\r
-                       $jpg2swf->setArg(null, $tempimage[$i]);\r
-                       $jpg2swf->execute();\r
-\r
-                       $swfcombine->setArg(null, $tempswf[$i]);\r
-               }\r
-               $swfcombine->execute();\r
-\r
-               foreach ($timg as $t) {\r
-                       if (file_exists($t)) {\r
-                               unlink($t);\r
-                       }\r
-               }\r
-               foreach ($tempswf as $t) {\r
-                       unlink($t);\r
-               }\r
-       }\r
-\r
-       public function compileHTML5($book_id, $book) {\r
-               $htmlCompiler = wsHTML5Compiler::factory($book_id, $book->parametres->mobileLVersion);\r
-               $htmlCompiler->compile();\r
-       }\r
-\r
-       public function indexPDF($book, $pages) {\r
-               $indexPath = WS_BOOKS . '/search/' . $book->book_id;\r
-\r
-               Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive());\r
-\r
-               if (file_exists($indexPath)) {\r
-                       files::deltree($indexPath);\r
-               }\r
-               $index = Zend_Search_Lucene::create($indexPath);\r
-\r
-               foreach ($pages as $i => $infos) {\r
-                       $doc = new Zend_Search_Lucene_Document();\r
-                       $doc->addField(Zend_Search_Lucene_Field::Text('url', '#' . $i));\r
-                       $doc->addField(Zend_Search_Lucene_Field::UnStored('contents', file_get_contents(WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'] . '.txt')));\r
-                       $index->addDocument($doc);\r
-               }\r
-\r
-               $c = $this->con->openCursor('books');\r
-               $c->lucene_time = TIME;\r
-               $c->update('WHERE book_id=' . $book->book_id);\r
-       }\r
-\r
-       public function compilePDF($book, $pages) {\r
-               if(substr($book->parametres->pdfName,0,4)=='http'){\r
-                       return;\r
-               }\r
-               if (isset($book->parametres->pdfName) && $book->parametres->pdfName != '') {\r
-                       $pdfName = $book->parametres->pdfName;\r
-               }\r
-\r
-               $cacheDir = WS_BOOKS . '/pdf/' . $book->book_id;\r
-               if (!file_exists($cacheDir)) {\r
-                       mkdir($cacheDir);\r
-               }\r
-\r
-               $normalPDF = $cacheDir . '/normal.pdf';\r
-               $compressedPDF = $cacheDir . '/compressed.pdf';\r
-\r
-               if ($book->parametres->pdfReplace) {\r
-                       $replace = WS_BOOKS . '/working/' . $book->book_id . '/' . $book->parametres->pdfReplace;\r
-                       if (file_exists($replace)) {\r
-                               if (!file_exists($normalPDF) || filemtime($normalPDF) < filemtime($replace) || filesize($normalPDF) != filesize($replace)) {\r
-                                       $this->copy($replace, $normalPDF);\r
-                               }\r
-                       }\r
-               } else {\r
-\r
-                       if (file_exists($normalPDF)) {\r
-                               $fmtime = filemtime($normalPDF);\r
-                               if ($fmtime >= $book->composition_update) {\r
-                                       $invalid = false;\r
-                                       foreach ($pages as $i => $infos) {\r
-                                               $doc = WS_DOCS . '/' . $infos['document_id'] . '/crop.pdf';\r
-                                               if (filemtime($doc) > $fmtime) {\r
-                                                       $invalid = true;\r
-                                               }\r
-                                       }\r
-                               } else {\r
-                                       $invalid = true;\r
-                               }\r
-                       } else {\r
-                               $invalid = true;\r
-                       }\r
-\r
-                       fb($invalid, 'invalid ?');\r
-\r
-                       if ($invalid) {\r
-                               $pdfList = array();\r
-                               $pagesList = array();\r
-                               $nb_pages = array();\r
-                               $j = 0;\r
-                               $k = 0;\r
-                               $original = true;\r
-\r
-                               foreach ($pages as $i => $infos) {\r
-                                       if (!isset($firstDoc)) {\r
-                                               $firstDoc = $infos['document_id'];\r
-                                       }\r
-\r
-                                       $doc = WS_DOCS . '/' . $infos['document_id'] . '/crop.pdf';\r
-                                       if (!isset($pdfList[$doc])) {\r
-                                               $pdfList[$doc] = $j;\r
-                                               $nb_pages[$doc] = $infos['nb_pages'];\r
-                                               $k = $j;\r
-                                               $j++;\r
-                                       } else {\r
-                                               $k = $pdfList[$doc];\r
-                                       }\r
-                                       $pagesList[$i] = array($k, $infos['document_page']);\r
-\r
-                                       if ($i != $infos['document_page'] || $infos['document_id'] != $firstDoc) {\r
-                                               $original = false;\r
-                                       }\r
-                               }\r
-\r
-                               if ($original) {\r
-                                       fb($normalPDF, 'original');\r
-                                       $this->copy(WS_DOCS . '/' . $firstDoc . '/crop.pdf', $normalPDF);\r
-                               } else {\r
-                                       $args = '';\r
-                                       foreach ($pdfList as $doc => $index) {\r
-                                               $lettre = cubeMath::toPDFLetter($index, true);\r
-                                               $args .= $lettre . '=' . $doc . ' ';\r
-                                       }\r
-\r
-                                       $args .= ' cat ';\r
-\r
-                                       $ranges = array();\r
-                                       $currentRange = null;\r
-\r
-                                       foreach ($pagesList as $p) {\r
-                                               $lettre = cubeMath::toPDFLetter($p[0], true);\r
-                                               $page = $p[1];\r
-\r
-                                               // Initialise l'intervale\r
-                                               if (is_null($currentRange)) {\r
-                                                       $currentRange = array('lettre' => $lettre, 'start' => $page, 'end' => $page);\r
-                                                       continue;\r
-                                               }\r
-\r
-                                               // Poursuit le remplissage si la lettre est identique et si la page suivante est bien la page suivante dans le document\r
-                                               if ($currentRange['lettre'] == $lettre && $currentRange['end'] + 1 == $page) {\r
-                                                       $currentRange['end'] = $page;\r
-                                                       continue;\r
-                                               }\r
-\r
-                                               // Ajoute l'intervale à la liste finale\r
-                                               $ranges[] = $currentRange;\r
-\r
-                                               // Réinitialise l'intervale suivant\r
-                                               $currentRange = array('lettre' => $lettre, 'start' => $page, 'end' => $page);\r
-                                       }\r
-\r
-                                       // Ajoute la dernière\r
-                                       if (!is_null($currentRange)) {\r
-                                               $ranges[] = $currentRange;\r
-                                       }\r
-                                       // Si le pdf final est constitué du document complet d'un document\r
-                                       if (count($ranges) == 1 && $ranges[0]['start'] == 1) {\r
-                                               $alldocs = array_keys($pdfList);\r
-                                               $doc = array_pop($alldocs);\r
-                                               if ($nb_pages[$doc] == $ranges[0]['end']) {\r
-                                                       $this->copy($doc, $normalPDF);\r
-                                                       return;\r
-                                               }\r
-                                       }\r
-\r
-                                       foreach ($ranges as $range) {\r
-                                               $args .= ' ' . $range['lettre'] . $range['start'];\r
-                                               if ($range['start'] == $range['end']) {\r
-                                                       continue;\r
-                                               }\r
-                                               $args .= '-' . $range['end'];\r
-                                       }\r
-\r
-                                       $hash = sha1($args);\r
-\r
-                                       $args .= ' output ' . $normalPDF;\r
-\r
-                                       $cached = WS_BOOKS . '/pdf/' . $hash . '.pdf';\r
-\r
-                                       if (file_exists($cached)) {\r
-                                               $this->copy($cached, $normalPDF);\r
-                                       } else {\r
-                                               $pdftk = new cubeCommandLine('pdftk');\r
-                                               $pdftk->setPath(CONVERTER_PATH);\r
-                                               $pdftk->setManualArg($args);\r
-                                               $pdftk->execute();\r
-                                               $this->copy($normalPDF, $cached);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               $finalPDF = WS_BOOKS . '/final/' . $book->book_id . '/data/' . $book->parametres->pdfName;\r
-\r
-               if ($book->parametres->pdfCompress) {\r
-                       if (!file_exists($compressedPDF) || filemtime($compressedPDF) < filemtime($normalPDF)) {\r
-                               $gs = new cubeCommandLine('gs', null, true);\r
-                               $gs->setPath(CONVERTER_PATH);\r
-                               $gs->setEnv('GS_FONTPATH', '/home/ws/fonts');\r
-                               $gs->setArg('-dBATCH');\r
-                               $gs->setArg('-dNOPAUSE');\r
-                               $gs->setArg('-dNOPROMPT');\r
-                               $gs->setArg('-sOutputFile=' . $compressedPDF);\r
-                               $gs->setArg('-sDEVICE=pdfwrite');\r
-                               $gs->setArg('-dPDFSETTINGS=/ebook');\r
-                               $gs->setArg('-dColorImageResolution=72');\r
-                               $gs->setArg('-dAutoRotatePages=/None');\r
-                               $gs->setArg('-dColorConversionStrategy=/LeaveColorUnchanged');\r
-                               $gs->setArg(null, $normalPDF);\r
-                               $gs->execute();\r
-                       }\r
-                       copy($compressedPDF, $finalPDF);\r
-               } else {\r
-                       copy($normalPDF, $finalPDF);\r
-               }\r
-       }\r
-\r
-       public function generateCID() {\r
-\r
-               do {\r
-                       $res = '';\r
-                       for ($i = 0; $i < 8; $i++) {\r
-                               $j = rand(0, 61);\r
-                               $res.=$this->base62($j);\r
-                       }\r
-                       $r = $this->con->select('SELECT book_id FROM books WHERE cid=\'' . $res . '\'');\r
-                       if ($r->count() == 0) {\r
-                               return $res;\r
-                       }\r
-               } while (true);\r
-       }\r
-\r
-       protected function base62($val) {\r
-               $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\r
-               $base = strlen($chars);\r
-               $str = '';\r
-               do {\r
-                       $i = $val % $base;\r
-                       $str = $chars[$i] . $str;\r
-                       $val = ($val - $i) / $base;\r
-               } while ($val > 0);\r
-               return $str;\r
-       }\r
-\r
-}\r
-\r
+<?php
+
+class wsDAOBook extends commonDAO {
+
+       /**
+        * wsDAOBook::singleton()
+        *
+        * @param mixed $r
+        * @return
+        */
+       protected function singleton($r) {
+               $book = new wsBook();
+               $book->book_id = $r->book_id;
+               $book->cid = $r->cid;
+               $book->nom = $r->nom;
+               $book->lang = $r->lang;
+               $book->theme = $r->theme;
+               $book->proprietaire = $r->proprietaire_nom;
+               $book->proprietaire_id = $r->proprietaire_id;
+               $book->proprietaire_utilisateur = $r->proprietaire_utilisateur;
+               $book->hash = $r->hash;
+               $book->compteur_visites = $r->compteur_visites;
+               $book->status = $r->status;
+               $book->date_status = $r->date_status;
+               $book->date = $r->date;
+               $book->pages = array();
+               $book->chapters = $r->chapters;
+               $book->traductions = $r->traductions;
+               $book->specialLinks = $r->specialLinks;
+               $book->specialRulers = $r->specialRulers;
+               $book->parametres = $r->parametres;
+               $book->extras = $r->extras;
+               $book->numerotation = $r->numerotation;
+               $book->changedate = $r->changedate;
+               $book->compiledate = $r->compiledate;
+               $book->compile1date = $r->compile1date;
+               $book->compilehtml5date = $r->compilehtml5date;
+               $book->facturable = $r->facturable;
+               $book->facturable_id = $r->facturable_id;
+               $book->tache = $r->tache;
+               if (isset($r->projet)) {
+                       $book->projet = $r->projet;
+               }
+               $book->version = $r->version;
+               $book->composition_update = $r->composition_update;
+               $book->dir_references = $r->dir_references;
+               $book->dir_hosting = $r->dir_hosting;
+               $book->dir_macbook_phonegap_ios = $r->dir_macbook_phonegap_ios;
+               $book->dir_phonegap_android = $r->dir_phonegap_android;
+               $book->dir_external = $r->dir_external;
+               $book->demo_counter = $r->demo_counter;
+               $book->exportdatas = $r->exportdatas;
+
+               return $book;
+       }
+
+       protected function cree($r) {
+               $book = new wsBook();
+               $book->book_id = 'new';
+               $book->nom = '';
+               $book->cid = null;
+               $book->lang = 'fr';
+               $book->theme = 1;
+               $book->proprietaire = '';
+               $book->proprietaire_id = 0;
+               $book->hash = '';
+               $book->compteur_visites = 20;
+               $book->status = 0;
+               $book->date_status = TIME;
+               $book->date = TIME;
+               $book->composition_update = TIME;
+               $book->chapters = json_encode(array());
+               $book->parametres = new wsBookParametres();
+               $book->tache = 0;
+               $book->pages = array();
+               $book->version = 2;
+               return $book;
+       }
+
+       protected function getNextId() {
+               $r = $this->con->select('SELECT MAX(book_id) AS book_id FROM books');
+               if ($r->book_id < 10000) {
+                       return 10000;
+               }
+               return $r->book_id + 1;
+       }
+
+       public function saveExportDatas($book_id, $datas) {
+               $c = $this->con->openCursor('books');
+               $c->exportdatas = json_encode($datas);
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function addDemoCount($book_id) {
+
+               $r = $this->con->select('SELECT demo_counter,nom FROM books WHERE book_id=\'' . $book_id . '\'');
+               $m = 20;
+               if ($r->demo_counter > 0 && $r->demo_counter % $m == 0) {
+                       $mail = new cubeMail();
+                       $mail->charset = 'UTF-8';
+                       $mail->from = 'contact@fluidbook.com';
+                       $mail->to = 'tech@fluidbook.com';
+                       $mail->subject = '[Fluidbook Workshop] Fluidbook consulté via l\'url publique';
+                       $mail->body = 'Le fluidbook suivant a été consulté ' . $m . ' fois (et ' . $r->demo_counter . ' au total) via l\'url publique : ' . "\r\n" .
+                                       'Fluidbook # ' . $book_id . ' - ' . $r->nom;
+                       $mail->send();
+               }
+
+               $this->con->select('UPDATE books SET demo_counter=demo_counter+1 WHERE book_id=\'' . $book_id . '\'');
+       }
+
+       public function selectByIds($book_ids = array(), $simple = false) {
+               if ($simple) {
+                       $table = 'books';
+               } else {
+                       $table = 'books_vue';
+               }
+               $sql = 'SELECT * FROM ' . $table . ' WHERE book_id IN (' . implode(',', $book_ids) . ')';
+               $books = $this->factory($this->con->select($sql));
+               $res = array();
+               foreach ($books as $book) {
+                       $res[$book->book_id] = $book;
+               }
+               return $res;
+       }
+
+       public function selectById($book_id = null, $simple = false) {
+               if (is_null($book_id)) {
+                       return $this->cree();
+               }
+               if ($simple) {
+                       $table = 'books';
+               } else {
+                       $table = 'books_vue';
+               }
+               $sql = 'SELECT * FROM ' . $table . ' WHERE book_id=\'' . $this->con->escape($book_id) . '\' LIMIT 1';
+               $r = $this->con->select($sql);
+               return $this->singleton($r);
+       }
+
+       public function selectByCid($cid = null, $simple = false) {
+               if ($simple) {
+                       $table = 'books';
+               } else {
+                       $table = 'books_vue';
+               }
+
+               $sql = 'SELECT * FROM ' . $table . ' WHERE cid LIKE BINARY \'' . $this->con->escape($cid) . '\' LIMIT 1';
+               $r = $this->con->select($sql);
+               return $this->singleton($r);
+       }
+
+       public function selectLuceneToDo() {
+               $sql = 'SELECT * FROM books_vue WHERE lucene_time<composition_update AND version=2 ORDER BY book_id ASC LIMIT 1';
+               $r = $this->con->select($sql);
+               return $this->factory($r);
+       }
+
+       public function selectLuceneTimeNotSet() {
+               $sql = 'SELECT * FROM books_vue WHERE lucene_time=0 AND version=2';
+               $r = $this->con->select($sql);
+               return $this->factory($r);
+       }
+
+       /**
+        * wsDAOBook::sauve()
+        *
+        * @param mixed $createur
+        * @param mixed $data
+        * @return
+        */
+       public function sauve($createur, $data) {
+               $c = $this->con->openCursor('books');
+               if (isset($data['nom'])) {
+                       $c->nom = $data['nom'];
+               }
+               if (isset($data['lang'])) {
+                       $c->lang = $data['lang'];
+               }
+               if (isset($data['theme'])) {
+                       $c->theme = $data['theme'];
+               }
+               if (isset($data['proprietaire'])) {
+                       $c->proprietaire = $data['proprietaire'];
+               }
+
+               if ($data['book_id'] == 'new' || $data['book_id'] == '') {
+                       $c->date = TIME;
+                       $c->hash = md5(rand(0, 123456789365469));
+                       $c->compteur_visites = 20;
+                       $c->parametres = serialize(new wsParametres());
+                       $c->changedate = TIME;
+                       $book_id = $c->book_id = $this->getNextId();
+
+                       $c->insert();
+               } else {
+                       $c->changedate = TIME;
+                       $book_id = $data['book_id'];
+                       $c->update('WHERE book_id=\'' . $this->con->escape($data['book_id']) . '\'');
+               }
+
+               return $this->selectById($book_id);
+       }
+
+       public function duplicate($book_id, $createur, $nom, $pages = false) {
+               $r = $this->con->select('SELECT * FROM books_vue WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+
+               $old_id = $book_id;
+
+               $parametres = unserialize($r->parametres);
+               $parametres->setParent($this);
+               $parametres->title = $nom;
+
+               $c = $this->con->openCursor('books');
+               $c->proprietaire = $createur;
+               $c->date = TIME;
+               $c->hash = md5(rand(0, 1234567893));
+               $c->cid = $this->generateCID();
+               $c->compteur_visites = 20;
+               $c->status = -1;
+               $c->date_status = TIME;
+               $c->lang = $r->lang;
+               $c->parametres = serialize($parametres);
+               $c->nom = $nom;
+               $c->theme = $r->theme;
+               $c->changedate = TIME;
+               $c->compiledate = 0;
+               $c->version = 2;
+               $c->traductions = $r->traductions;
+               $c->specialLinks = $r->specialLinks;
+               $c->specialRulers = $r->specialRulers;
+               $c->composition_update = TIME;
+               $book_id = $c->book_id = $this->getNextId();
+               if ($pages) {
+                       $c->numerotation = $r->numerotation;
+                       $c->chapters = $r->chapters;
+                       $this->con->execute('INSERT INTO book_pages SELECT ' . $book_id . ' AS book_id,book_page,document_id,document_page FROM book_pages WHERE book_id=' . $old_id);
+               }
+               $c->insert();
+               $this->saveCompositionVersion($book_id);
+
+               return $this->selectById($book_id);
+       }
+
+       public function creeEmpty($createur, $lang, $nom) {
+               $c = $this->con->openCursor('books');
+
+               $parametres = new wsBookParametres($this);
+               $parametres->title = $nom;
+
+               $c->proprietaire = $createur;
+               $c->cid = $this->generateCID();
+               $c->nom = $nom;
+               $c->date = TIME;
+               $c->hash = md5(rand(0, 1234567893));
+               $c->compteur_visites = 20;
+               $c->status = -1;
+               $c->date_status = TIME;
+               $c->parametres = serialize($parametres);
+
+               $c->theme = 1;
+               $c->lang = $lang;
+               $c->changedate = TIME;
+               $c->compiledate = 0;
+               $c->version = 2;
+               $c->composition_update = TIME;
+               $book_id = $c->book_id = $this->getNextId();
+               $c->insert();
+               return $this->selectById($book_id);
+       }
+
+       public function supprime($book_id) {
+               $this->con->execute('DELETE FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+               return $this->con->execute('DELETE FROM books WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function count($limitedToUserRights = false) {
+               $filters = $this->makeWhereFromFiltres();
+               if ($filters == '1=1') {
+                       $table = 'books';
+               } else {
+                       $table = 'books_vue';
+               }
+
+               $where = '(' . $filters . ')';
+               $where .= $this->limitToUserRights($limitedToUserRights);
+               $r = $this->con->select('SELECT COUNT(*) AS nb FROM ' . $table . ' WHERE ' . $where);
+               return $r->nb;
+       }
+
+       public function getPagesOfBookAt($book_id, $time) {
+               $r = $this->con->select('SELECT * FROM book_pages_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\' ORDER BY `update`');
+               if (!$r->count()) {
+                       return $this->getPagesOfBook($book_id);
+               }
+               if ($r->count() == 1) {
+                       $pages = unserialize($r->composition);
+                       if (!count($pages)) {
+                               return $this->getPagesOfBook($book_id);
+                       }
+                       return $pages;
+               }
+               $pages = null;
+               while ($r->fetch()) {
+                       if ($r->update > $time) {
+                               if (is_null($pages)) {
+                                       return $this->getPagesOfBook($book_id);
+                               }
+                               return unserialize($pages);
+                       }
+                       $pages = $r->composition;
+               }
+               return unserialize($pages);
+       }
+
+       public function getDocumentsToUpdate($book_id) {
+               $res = array();
+               $r = $this->con->select('SELECT DISTINCT d.document_id FROM book_pages b,documents d WHERE b.book_id=\'' . $this->con->escape($book_id) . '\' AND d.version=1 AND b.document_id=d.document_id');
+               while ($r->fetch()) {
+                       $res[] = $r->document_id;
+               }
+               return $res;
+       }
+
+       public function getPagesOfBook($book_id, $conversion = true) {
+               $pages = array();
+
+               $sql = 'SELECT b.*,d.numberSections AS num,d.conversionInfos AS conversion,d.pages AS doc_pages,d.version AS version FROM book_pages b JOIN documents d ON d.document_id=b.document_id WHERE b.book_id=\'' . $this->con->escape($book_id) . '\' ORDER BY book_page';
+
+               $r = $this->con->select($sql);
+               while ($r->fetch()) {
+                       $n = explode(',', $r->num);
+
+                       if (isset($n[$r->document_page - 1])) {
+                               $num = $n[$r->document_page - 1];
+                       } else {
+                               $num = '';
+                       }
+                       $pages[$r->book_page] = array('document_id' => $r->document_id,
+                               'document_page' => $r->document_page,
+                               'version' => $r->version,
+                               'defaultNum' => $num,
+                               'nb_pages' => $r->doc_pages
+                       );
+
+                       if ($conversion) {
+                               if ($r->conversion != '') {
+                                       $c = unserialize($r->conversion);
+                                       $c = $c->pages[$r->document_page];
+                               }
+                               $qp = array('resolution', 'method', 'quality', 'objects');
+                               foreach ($qp as $p) {
+                                       if (isset($c) && isset($c->$p)) {
+                                               $pages[$r->book_page][$p] = $c->$p;
+                                       }
+                               }
+                       }
+               }
+               return $pages;
+       }
+
+       public function appendDocument($book_id, $document_id) {
+               $r = $this->con->select('SELECT MAX(book_page) AS book_page FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+               $lastPage = is_null($r->book_page) ? 0 : $r->book_page;
+               $this->insertDocument($book_id, $lastPage, $document_id);
+       }
+
+       public function removePage($book_id, $book_page) {
+               // Supprime la page
+               $this->con->execute('DELETE FROM book_pages WHERE book_page=\'' . $this->con->escape($book_page) . '\' AND book_id=\'' . $this->con->escape($book_id) . '\'');
+               // Décale les pages suivantes vers le haut
+               $this->decalePages($book_id, $book_page, -1);
+       }
+
+       public function insertPage($book_id, $after_page, $document_id, $document_page) {
+               // Décale les pages vers le bas
+               $this->decalePages($book_id, $after_page, 1);
+               // Insère la page
+               $c = $this->con->openCursor('book_pages');
+               $c->book_id = $book_id;
+               $c->book_page = $after_page + 1;
+               $c->document_id = $document_id;
+               $c->document_page = $document_page;
+               $c->insert();
+       }
+
+       public function insertDocument($book_id, $after_page, $document_id) {
+               // Obtiens le book
+               $book = $this->selectById($book_id);
+               $num = explode(',', $book->numerotation);
+               // Obtiens le nombre de pages
+               $r = $this->con->select('SELECT pages,numberSections FROM documents WHERE document_id=\'' . $this->con->escape($document_id) . '\'');
+               // Décale les pages vers le bas
+               if ($after_page > 0) {
+                       $this->decalePages($book_id, $after_page, $r->pages);
+               }
+               // Insère les pages
+               $c = $this->con->openCursor('book_pages');
+               $c->book_id = $book_id;
+               $c->document_id = $document_id;
+               for ($i = 1; $i <= $r->pages; $i++) {
+                       $c->document_page = $i;
+                       $c->book_page = $after_page + $i;
+                       $c->insert();
+               }
+               // Mets à jour la liste des numéros des pages
+               $before = array_slice($num, 0, $after_page);
+               $after = array_slice($num, $after_page, count($num) - $after_page);
+
+               $newnum = $r->numberSections;
+               if (trim($newnum, ',') == '') {
+                       // If no number detected, we create a numeric list from 1
+                       $between = range(1, $r->pages);
+               } else {
+                       // Else, we use numbers detected at conversion
+                       $between = explode(',', $r->numberSections);
+               }
+               $num = array_merge($before, $between, $after);
+               // Mets à jour la numerotation de la publication
+               $c = $this->con->openCursor('books');
+               $c->numerotation = implode(',', $num);
+               $c->composition_update = TIME;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+
+               $this->saveCompositionVersion($book_id);
+       }
+
+       protected function decalePages($book_id, $after_page, $decalage) {
+               $decalage = ($decalage >= 0) ? '+' . $decalage : $decalage;
+               $this->con->execute('UPDATE book_pages SET book_page=book_page' . $decalage . ' WHERE book_page>' . $this->con->escape($after_page) . ' AND book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function getListe($orderby = null, $sens = null, $limit = null, $limitedToUserRights = false) {
+               if (!is_null($this->q)) {
+                       $where = '(';
+                       if ($this->search_id) {
+                               $where .= ' book_id=\'' . $this->con->escape($this->q) . '\' OR ';
+                       }
+
+                       if (!cubeMath::is_int($this->q)) {
+                               $where .= 'nom LIKE \'%' . $this->con->escape($this->q) . '%\'';
+                               $daoClient = new commonDAOClient($this->con);
+                               $where .= ' OR proprietaire_id IN(' . $daoClient->querySearchByName($this->q) . ') OR ';
+                       }
+                       $limit = null;
+                       $where .= '1=2)';
+               } else {
+                       $where = '(' . $this->makeWhereFromFiltres() . ')';
+               }
+               $where .= $this->limitToUserRights($limitedToUserRights);
+
+               $orderby = is_null($orderby) ? 'book_id' : $orderby;
+               $sens = is_null($sens) ? 'DESC' : $sens;
+               $limit = is_null($limit) ? '' : $this->con->limit($limit);
+
+               $sql = 'SELECT * FROM books_vue WHERE ' . $where . ' ORDER BY ' . $orderby . ' ' . $sens . ' ' . $limit;
+               $r = $this->con->select($sql);
+               return $this->factory($r);
+       }
+
+       protected function limitToUserRights($utilisateur) {
+               if ($utilisateur) {
+                       if (wsDroits::admin()) {
+                               return '';
+                       }
+                       return ' AND proprietaire IN (' . $utilisateur->ws_rights . ')';
+               }
+               return '';
+       }
+
+       protected function makeWhereFromFiltres() {
+               if (!is_null($this->filtres)) {
+                       $w = array('1=1');
+                       if (commonFiltre::test('admin_book', $this->filtres)) {
+                               $w[] = 'super_admin IN (' . implode(',', array_keys($this->filtres['admin_book'])) . ')';
+                       }
+                       if (commonFiltre::test('status_book', $this->filtres)) {
+                               $w[] = 'status IN(' . implode(',', array_keys($this->filtres['status_book'])) . ')';
+                       }
+                       if (commonFiltre::test('revendeur_book', $this->filtres)) {
+                               $v = array_keys($this->filtres['revendeur_book']);
+                               $values = array();
+                               foreach ($v as $r) {
+                                       $values[] = $this->con->escape($r);
+                               }
+
+
+                               $w[] = 'facturable IN(\'' . implode('\',\'', $values) . '\')';
+                       }
+                       return implode(' AND ', $w);
+               } else {
+                       return '1=1';
+               }
+       }
+
+       public function setChapters($book_id, $json) {
+               $chapters = json_decode($json, TRUE);
+               $res = array();
+
+               foreach ($chapters as $c) {
+                       $c['label'] = trim($c['label']);
+                       $n = (string) $c['page'];
+                       $c['label'] = trim(preg_replace('|\s+' . $n . '$|iu', '', $c['label']));
+                       $res[] = $c;
+               }
+
+               $c = $this->con->openCursor('books');
+               $c->chapters = json_encode($res);
+               $c->changedate = TIME;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function setSpecialLinksAndRulers($book_id, $links, $rulers) {
+               $c1 = $this->con->openCursor('special_links_versions');
+               $c = $this->con->openCursor('books');
+
+               if (is_string($links)) {
+                       $links = json_encode(json_decode($links, false));
+               }
+               if (is_string($rulers)) {
+                       $rulers = json_encode(json_decode($rulers, false));
+               }
+
+               if (is_array($links)) {
+                       $links = json_encode($links);
+               }
+               if (is_array($rulers)) {
+                       $rulers = json_encode($rulers);
+               }
+
+
+
+               $c1->links = $c->specialLinks = $links;
+               $c1->rulers = $c->specialRulers = $rulers;
+               $c1->update = $c->changedate = TIME;
+               $c1->book_id = $book_id;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+               try {
+                       $c1->insert();
+               } catch (Exception $e) {
+                       $c1->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\' AND `update`=' . TIME);
+               }
+       }
+
+       public function setTheme($book_id, $theme) {
+               $c = $this->con->openCursor('books');
+               $c->theme = $theme;
+               $c->changedate = TIME;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function setStatus($book_id, $status) {
+               $c = $this->con->openCursor('books');
+               if ($status < 2) {
+                       $c->tache = 0;
+               }
+               $c->status = $status;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+               return $this->selectById($book_id);
+       }
+
+       public function setChaptersFromOldFluidbook($book_id) {
+               $book = $this->selectById($book_id);
+               $n = explode(',', $book->numerotation);
+
+               $xml = simplexml_load_file('http://ws.fluidbook.com/books/' . $book_id . '/data/links.xml');
+               $res = array();
+               $chapters = $xml->xpath('//chapters');
+               foreach ($chapters as $ch) {
+                       $c = array();
+                       $c['label'] = (string) $ch->txt;
+
+                       $p = intval((string) $ch->page);
+                       if ($p <= 0) {
+                               continue;
+                       }
+                       $c['page'] = $n[$p];
+                       $c['level'] = intval((string) $ch->level);
+                       $res[] = $c;
+               }
+
+               $c = $this->con->openCursor('books');
+               $c->chapters = json_encode($res);
+               $c->changedate = TIME;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function saveCompositionVersion($book_id, $time = null) {
+
+               $time = is_null($time) ? TIME : $time;
+
+               $pages = $this->getPagesOfBook($book_id);
+
+               $c = $this->con->openCursor('book_pages_versions');
+               $c->update = $time;
+               $c->book_id = $book_id;
+               $c->composition = serialize($pages);
+               $c->insert();
+       }
+
+       public function setLang($book_id, $base, $traductions) {
+               // Cleanup user translations
+               $traductions = json_decode($traductions, true);
+               foreach ($traductions as $k => $v) {
+                       $traductions[$k] = trim($v);
+               }
+
+               $daoLang = new wsDAOLang($this->con);
+               $lang = $daoLang->selectById($base);
+               // Cleanup base translations
+               $baseTraductions = $lang->traductions;
+               foreach ($baseTraductions as $k => $v) {
+                       $baseTraductions[$k] = trim($v);
+               }
+               // Then compare them. If there is no differences, we don't save translations in the book
+               if ($traductions == $baseTraductions) {
+                       $t = '';
+               } else {
+                       $t = json_encode($traductions);
+               }
+
+               $c = $this->con->openCursor('books');
+               $c->lang = $base;
+               $c->traductions = $t;
+               $c->changedate = TIME;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function setSettings($book_id, $settings) {
+               $book = $this->selectById($book_id);
+               $parametres = $book->parametres;
+               $new = $settings;
+               foreach ($new as $k => $v) {
+                       if ($k == '_empty_') {
+                               continue;
+                       }
+                       $parametres->$k = $v;
+               }
+
+               $ip = array();
+               if (isset($parametres->stats_exclude_ip) && trim($parametres->stats_exclude_ip) != '') {
+                       $list = $parametres->stats_exclude_ip;
+                       $list = str_replace("\r", "\n", $list);
+                       $e = explode("\n", $list);
+                       foreach ($e as $i) {
+                               $i = trim($i);
+                               if ($i == '') {
+                                       continue;
+                               }
+                               $long = ip2long($i);
+                               if ($long !== false) {
+                                       $ip[] = $long;
+                               }
+                       }
+               }
+
+               $file = '/home/stats/www/exclude/' . $book_id;
+
+               if (count($ip)) {
+                       file_put_contents($file, implode(',', $ip));
+                       chmod($file, 0777);
+                       chown($file, 'stats');
+               } else if (file_exists($file)) {
+                       unlink($file);
+               }
+
+               $c = $this->con->openCursor('books');
+               $c->nom = $parametres->title;
+               $c->parametres = serialize($parametres);
+               $c->changedate = TIME;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function setProprietaire($book_id, $proprietaire_id) {
+               $c = $this->con->openCursor('books');
+               $c->proprietaire = $proprietaire_id;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function setTache($book_id, $tache) {
+               $c = $this->con->openCursor('books');
+               $c->tache = $tache;
+               $c->status = 2;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function setVersion($book_id, $version) {
+               $c = $this->con->openCursor('books');
+               $c->version = $version;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function touch($book_id) {
+               $c = $this->con->openCursor('books');
+               $c->changedate = TIME;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function touchCompile($book_id, $version = 'all') {
+               $c = $this->con->openCursor('books');
+               if ($version == '2') {
+                       $c->compiledate = TIME;
+               } elseif ($version == '1') {
+                       $c->compile1date = TIME;
+               } elseif ($version == 'html5') {
+                       $c->compilehtml5date = TIME;
+               } else {
+                       $c->compiledate = TIME;
+                       $c->compile1date = TIME;
+                       $c->compilehtml5date = TIME;
+               }
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function isUpToDate($book, $version) {
+               $version = (string) $version;
+               if ($version == '2') {
+                       if (!file_exists(WS_BOOKS . '/final/' . $book->book_id)) {
+                               return false;
+                       }
+                       if ($book->compiledate < $book->changedate) {
+                               return false;
+                       }
+               } else if ($version == '1') {
+                       // V1
+                       if (!file_exists(WS_BOOKS . '/finalv1/' . $book->book_id . '/index.swf')) {
+                               return false;
+                       }
+                       if ($book->compile1date < $book->changedate) {
+                               return false;
+                       }
+               } else if ($version == 'html5') {
+                       // HTML5
+                       $checks = array($book->changedate, cubeFiles::filemtimeRecursive(WS_BOOKS . '/working/' . $book->book_id), cubeFiles::filemtimeRecursive(WS_COMPILE_ASSETS . '/_html5'), cubeFiles::filemtimeRecursive(ROOT . '/inc/ws/Util/html5'));
+                       foreach ($checks as $check) {
+                               if ($check > $book->compilehtml5date) {
+                                       return false;
+                               }
+                       }
+               }
+               return true;
+       }
+
+       public function setComposition($book_id, $pages) {
+               $numerotation = array();
+               $nb_pages = 0;
+               foreach ($pages as $p) {
+                       $numerotation[] = $p->virtual;
+                       $nb_pages++;
+               }
+
+               $book = $this->selectById($book_id);
+               $parametres = $book->parametres;
+               $parametres->pages = $nb_pages;
+
+               $c = $this->con->openCursor('books');
+               $c->parametres = serialize($parametres);
+               $c->numerotation = implode(',', $numerotation);
+               $c->changedate = TIME;
+
+               // Check if composition need to be updated
+               $r = $this->con->select('SELECT * FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+               $tab = array();
+               $now = array();
+               while ($r->fetch()) {
+                       $ref[$r->book_page] = array((int) $r->document_id, (int) $r->document_page);
+               }
+               $i = 1;
+               foreach ($pages as $p) {
+                       $now[$i] = array((int) $p->document_id, (int) $p->document_page);
+                       $i++;
+               }
+               if ($now != $ref) {
+                       $this->con->execute('DELETE FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+
+                       $c1 = $this->con->openCursor('book_pages');
+                       $c1->book_id = $book_id;
+                       $i = 1;
+                       foreach ($pages as $p) {
+                               $c1->document_id = $p->document_id;
+                               $c1->document_page = $p->document_page;
+                               $c1->book_page = $i;
+                               $c1->insert();
+                               $i++;
+                       }
+                       $c->composition_update = TIME;
+                       $this->saveCompositionVersion($book_id);
+               }
+
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function setInstallDir($book_id, $dir, $server) {
+               $col = 'dir_' . $server;
+
+               $c = $this->con->openCursor('books');
+               $c->$col = $dir;
+               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+       }
+
+       public function makeTextsIndexes($book, $pages, &$index, &$textes) {
+
+               $prefix = '';
+               if ($book->parametres->textExtraction == 'poppler') {
+                       $prefix = 'p';
+               }
+
+
+               $dir = WS_BOOKS . '/index/' . $book->book_id;
+               if ($book->parametres->ignoreSearchSeparators != '') {
+                       $dir.='/' . sha1($book->parametres->ignoreSearchSeparators);
+               }
+               if (!file_exists($dir)) {
+                       mkdir($dir, 0777, true);
+               }
+
+               $ifilec = $dir . '/' . $prefix . 'index.json';
+               $tfilec = $dir . '/' . $prefix . 'textes.json';
+
+               if (file_exists($ifilec) && file_exists($tfilec) && (min(filemtime($ifilec), filemtime($tfilec)) >= $book->composition_update)) {
+                       $index = file_get_contents($ifilec);
+                       $textes = file_get_contents($tfilec);
+                       return;
+               }
+
+               if ($book->parametres->ignoreSearchSeparators != "") {
+                       $docs = array();
+                       foreach ($pages as $p => $i) {
+                               $docs[] = $i['document_id'];
+                       }
+                       $docs = array_unique($docs);
+
+                       foreach ($docs as $doc) {
+                               $out = WS_DOCS . '/' . $doc . '/';
+
+                               $fwstk = new cubeCommandLine('fwstk');
+                               $fwstk->setPath(CONVERTER_PATH);
+                               $fwstk->setArg('--input ' . $out . '/crop.pdf');
+                               $fwstk->setArg('--extractTexts ' . $out . '%s%d.txt');
+                               $fwstk->setArg('--ignoreSeparators ' . $book->parametres->ignoreSearchSeparators);
+                               $fwstk->execute();
+                       }
+               }
+
+               $index = array();
+               $textes = array();
+               foreach ($pages as $book_page => $infos) {
+                       $tfile = WS_DOCS . '/' . $infos['document_id'] . '/' . $prefix . 'p' . $infos['document_page'] . '.txt';
+                       $ifile = WS_DOCS . '/' . $infos['document_id'] . '/' . $prefix . 'i' . $infos['document_page'] . '.txt';
+                       $text = file_get_contents($tfile);
+                       $ipage = file_get_contents($ifile);
+
+                       $this->fillIndexWithWords($index, $book_page, $ipage);
+                       $textes[$book_page] = $text;
+               }
+               ksort($index);
+
+
+               $textes = json_encode($textes);
+               $index = json_encode($index);
+
+               file_put_contents($tfilec, $textes);
+               file_put_contents($ifilec, $index);
+       }
+
+       protected function fillIndexWithWords(&$index, $page, $ipage) {
+               $twords = explode("\n", trim($ipage));
+
+               foreach ($twords as $woadata) {
+                       $w1 = explode(',', trim($woadata));
+                       if (count($w1) <= 1) {
+                               continue;
+                       }
+                       list($woa, $worddata) = $w1;
+                       $e = explode("\t", $worddata, 2);
+                       if (count($e) < 2) {
+                               continue;
+                       }
+                       list($total, $wordslist) = $e;
+
+                       if ($woa == '') {
+                               continue;
+                       }
+
+                       if (!isset($index[$woa])) {
+                               $index[$woa] = array('t' => 0, 'w' => array());
+                       }
+                       $index[$woa]['t'] += $total;
+
+                       $words = explode("\t", $wordslist);
+
+                       foreach ($words as $word) {
+                               list($wordwa, $count) = explode('$', $word, 2);
+                               if (!isset($index[$woa]['w'][$wordwa])) {
+                                       $index[$woa]['w'][$wordwa] = array('t' => 0, 'p' => array());
+                               }
+                               if (!isset($index[$woa]['w'][$wordwa]['p'][$page])) {
+                                       $index[$woa]['w'][$wordwa]['p'][$page] = 0;
+                               }
+                               $index[$woa]['w'][$wordwa]['t'] += $count;
+                               $index[$woa]['w'][$wordwa]['p'][$page] += $count;
+                       }
+               }
+       }
+
+       public function getNumerotationFromDocs($book_id) {
+               $pages = $this->getPagesOfBook($book_id);
+       }
+
+       public function compileTemp($book_id, $version, $dir) {
+               if ($version == 'ha' || $version == 'hi') {
+                       if ($version == 'ha') {
+                               $os = 'android';
+                       } elseif ($version == 'hi') {
+                               $os = 'ios';
+                       }
+                       $packager = new wsPackagerPhonegap($book_id, $dir, false, true, $os);
+                       $packager->makePackage(false);
+               }
+       }
+
+       public function compile($book_id, $version = 'all', $complete = false, $force = false) {
+               if (is_null($book_id) || !$book_id) {
+                       return;
+               }
+
+               $v1 = $v2 = $html5 = false;
+
+               if ($version == 'all') {
+                       $v1 = $v2 = $html5 = true;
+               } else if ($version == '1') {
+                       $v1 = true;
+               } else if ($version == '2') {
+                       $v2 = true;
+               } elseif ($version == 'html5') {
+                       $html5 = true;
+               }
+
+               $book = $this->selectById($book_id);
+               $pages = $this->getPagesOfBook($book_id);
+
+               if (!$force) {
+
+                       $v1 = $v1 && !$this->isUpToDate($book, 1);
+                       $v2 = $v2 && !$this->isUpToDate($book, 2);
+                       $html5 = $html5 && !$this->isUpToDate($book, 'html5');
+               } else {
+                       $v1 = false;
+                       $html5 = false;
+                       $v2 = true;
+               }
+
+
+
+               $res = '';
+               if ($v1) {
+                       fb(time(), 'Compile V1');
+                       $res.=$this->compile1($book_id, $book, $pages);
+                       $this->touchCompile($book_id, '1');
+               }
+               if ($v2) {
+                       fb(time(), 'Compile V2');
+                       $res .= $this->compile3($book_id, $complete, $book, $pages);
+                       $this->touchCompile($book_id, '2');
+               }
+               if ($html5) {
+                       fb(time(), 'Compile HTML5');
+                       $res.=$this->compileHTML5($book_id, $book);
+                       $this->touchCompile($book_id, 'html5');
+               }
+               if ($v1 || $v2) {
+                       fb(time(), 'Compile PDF & Widget');
+                       $this->compilePDF($book, $pages);
+                       $this->compileWidget($book, $pages);
+               }
+
+               fb(time(), 'End Compile');
+               return $res;
+       }
+
+       public function compile1($book_id, $book, $pages) {
+               $finalDir = WS_BOOKS . '/finalv1/' . $book_id . '/';
+               $packager = new wsPackagerV1($book_id, $finalDir, false);
+               $packager->makePackage(false);
+       }
+
+       public function compile3($book_id, $complete, $book, $pages) {
+               $res = '';
+
+               $compilerDir = WS_BOOKS . '/datasCompiler/' . $book_id . '/';
+               $finalDir = WS_BOOKS . '/final/' . $book_id . '/';
+
+               $rm = new cubeCommandLine('rm');
+               $rm->setArg('r');
+               $rm->setArg('f');
+               $rm->setArg(null, $finalDir);
+               $rm->execute();
+               mkdir($finalDir, 0777, true);
+
+               $flex = new cubeFlexCompiler('FluidbookDatas', $compilerDir, 'flash.display.Sprite', explode(';', AS3_SOURCES), MXMLC_PATH, 10);
+               $flexLight = new cubeFlexCompiler('FluidbookDatasLight', $compilerDir, 'flash.display.Sprite', explode(';', AS3_SOURCES), MXMLC_PATH, 10);
+
+               $filesToCopy = array();
+               $this->compileFlex($book_id, $complete, $compilerDir, $finalDir, $filesToCopy, $book, $pages, $flex, $flexLight);
+
+               $res .= $flex->compile() . "\n\n-------------------\n\n";
+               $flexLight->addVariable('datasSize', filesize($compilerDir . '/FluidbookDatas.swf'));
+               $res .= $flexLight->compile();
+
+               $filesToCopy['data/fd.swf'] = $compilerDir . '/FluidbookDatas.swf';
+               $filesToCopy['data/fdl.swf'] = $compilerDir . '/FluidbookDatasLight.swf';
+
+               // Copy of files
+               // Check if dest dir exists
+               if (!file_exists($finalDir . 'data')) {
+                       mkdir($finalDir . 'data', 0777, true);
+               }
+
+               foreach ($filesToCopy as $local => $source) {
+                       $localPath = $finalDir . $local;
+                       if (!file_exists($localPath) || filemtime($localPath) < filemtime($source) || filesize($localPath) != filesize($source) || filemtime($localPath) < $book->composition_update) {
+                               if (is_dir($source)) {
+                                       continue;
+                               }
+                               $this->copy($source, $localPath);
+                       }
+               }
+
+               $workingDir = WS_BOOKS . '/working/' . $book_id . '/';
+               if (file_exists($workingDir . 'media')) {
+                       $cp = new cubeCommandLine('cp');
+                       $cp->setPath(CONVERTER_PATH);
+                       $cp->setArg('r');
+                       $cp->setArg('p');
+                       $cp->setArg(null, $workingDir . 'media');
+                       $cp->setArg(null, $finalDir . 'data');
+                       $cp->execute();
+               }
+
+               return $res;
+       }
+
+       public function copy($source, $dest) {
+               copy($source, $dest);
+               touch($dest, filemtime($source));
+       }
+
+       public function compileAir($book_id) {
+               $compilerDir = WS_BOOKS . '/air/' . $book_id . '/compiler';
+               $finalDir = WS_BOOKS . '/air/' . $book_id . '/';
+
+               $book = $this->selectById($book_id);
+               $pages = $this->getPagesOfBook($book_id);
+
+               $src = AS3_FLUIDBOOK_SOURCES . '/_src/';
+               $lib10 = AS3_FLUIDBOOK_SOURCES . '/lib10/';
+               $libs = array(
+                       $src,
+                       $lib10,
+                       AS3_SOURCES,
+                       $src . 'lib/fluidbook3dLibrary.swc',
+                       $src . 'lib/mdm.swc',
+                       $lib10 . 'flash.swc',
+                       $lib10 . 'flex.swc',
+                       $lib10 . 'framework.swc',
+               );
+
+               wsSVN::updateToLastRevision();
+
+               $swf = 'FluidbookAirProjector' . $book_id;
+               $flex = new cubeFlexCompiler($swf, $compilerDir, 'com.fluidbook.player.AIRMain', $libs, '/usr/local/flex/bin/mxmlc', 'air', 45, 800, 600, true);
+
+               $this->compileFlex($book_id, true, $compilerDir, $finalDir, $filesToCopy, $book, $pages, $flex, $flex);
+               $res = $flex->compile();
+
+               $air = new cubeAIRCompiler($swf . '.swf', '/usr/local/flex/bin', $compilerDir, '2.0');
+               $air->setApplicationDatas('com.fluidbook' . $book_id, $book->parametres->title, $book->parametres->title, cubeText::str2URL($book->parametres->title), $book->lang);
+               $air->setInitialWindow($book->parametres->title);
+               $res.=$air->compile();
+
+               return $res;
+       }
+
+       public function compileFlex($book_id, $complete, $compilerDir, $finalDir, &$filesToCopy, $book, $pages, $flex, $flexLight) {
+               cubePHP::neverStop();
+               /* @var $flex cubeFlexCompiler */
+
+               $workingDir = WS_BOOKS . '/working/' . $book_id . '/';
+
+               $res = '';
+
+               $daoDoc = new wsDAODocument($this->con);
+               $firstDoc = $daoDoc->selectById($pages[1]['document_id']);
+               $size = $firstDoc->generalInfos['size'];
+
+               $daoLang = new wsDAOLang($this->con);
+               $lang = $daoLang->selectById($book->lang);
+
+               $langs = $daoLang->selectAll();
+
+               $daoTheme = new wsDAOTheme($this->con);
+               $theme = $daoTheme->getThemeOfBook($book_id, true);
+
+               $daoSignature = new wsDAOSignature($this->con);
+               $signature = $daoSignature->selectById($book->parametres->signature);
+
+               $exportSignature = array('main' => $signature->main,
+                       'mainLink' => $signature->mainLink,
+                       'partner' => $signature->partner,
+                       'partnerLink' => $signature->partnerLink);
+
+               $index = '';
+               $textes = '';
+
+               $hash = $book_id;
+               $hash .= 'kjgl!az4.';
+               $hash .= count($pages);
+               $hash .= round($size[0], 3);
+
+               $hash = sha1($hash);
+
+               $this->makeTextsIndexes($book, $pages, $index, $textes);
+
+               $daoDoc->getLinksAndRulers($book_id, $links, $rulers);
+
+               $imagesassets = array();
+               $id = 1;
+               foreach ($links as $id => $link) {
+                       $links[$id]['id'] = $id;
+                       if ($link['type'] == 15) {
+                               if (isset($imagesassets[$id])) {
+                                       continue;
+                               }
+                               if ($link['page'] <= 1) {
+                                       $flexLight->addBitmap($workingDir . '/' . $link['to'], 'link_datas_' . $id);
+                               } else {
+                                       $flex->addBitmap($workingDir . '/' . $link['to'], 'link_datas_' . $id);
+                               }
+                               $imagesassets[$id] = true;
+                       } else if (in_array($link['type'], array(4, 6, 7, 9, 16, 17))) {
+                               $workingFile = $workingDir . '/' . $link['to'];
+                               if (file_exists($workingFile)) {
+                                       $filesToCopy['data/' . $link['to']] = $workingFile;
+                               }
+
+                               if ($link['type'] == 4) {
+                                       $poster = $link['to'];
+                                       $e = explode('.', $poster);
+                                       array_pop($e);
+                                       array_push($e, 'jpg');
+                                       $poster = implode('.', $e);
+
+                                       $workingFile = $workingDir . '/' . $poster;
+                                       if (file_exists($workingFile)) {
+                                               $filesToCopy['data/' . $poster] = $workingFile;
+                                       }
+                               }
+                       }
+               }
+
+               $externalsOptions = array('ongletsSWF', 'tabs2DSWF', 'externalChapters', 'externalArchives');
+               foreach ($externalsOptions as $e) {
+                       if (isset($book->parametres->$e) && $book->parametres->$e != '') {
+                               $f = $workingDir . '/' . $book->parametres->$e;
+                               if (file_exists($f)) {
+                                       $filesToCopy['data/' . $book->parametres->$e] = $f;
+                               }
+                       }
+               }
+
+               $flex->addVariable('links', $links, false, true, 'JSONObject');
+
+               $flex->addVariable('signature', $exportSignature, false, true, 'JSONObject');
+               $flexLight->addVariable('datas', $book->parametres->toStandardObject(), false, true, 'JSONObject');
+               $flexLight->addVariable('id', $book_id, false, true, 'uint');
+               $flexLight->addVariable('cid', $book->cid, false, true, 'String');
+
+               $traductions = (!count($book->traductions)) ? $lang->traductions : $book->traductions;
+               $allTraductions = array();
+               foreach ($langs as $l) {
+                       $allTraductions[$l->lang_id] = $l->traductions;
+               }
+
+               $flex->addVariable('traductions', $traductions, false, true, 'JSONObject', false);
+               $flex->addVariable('allTraductions', $allTraductions, false, true, 'JSONObject');
+               $flex->addVariable('chapters', $book->chapters, false, true, 'JSONObject');
+               $flex->addVariable('extras', '<extras>' . $book->extras . '</extras>', false, true, 'XML');
+               $flex->addVariable('numerotation', $book->numerotation, false, true, 'String');
+               $flexLight->addVariable('theme', $theme->parametres->toStandardObject(), false, true, 'JSONObject');
+               $flexLight->addVariable('pages', $book->parametres->pages);
+               $flexLight->addVariable('fwidth', round($size[0], 4), false, true, 'Number');
+               $flexLight->addVariable('fheight', round($size[1], 4), false, true, 'Number');
+               $flexLight->addVariable('pagesInDatas', $complete, false, true, 'Boolean');
+               $flex->addVariable('index', $index, false, true, 'JSONObject', false, false);
+               $flex->addVariable('textes', $textes, false, true, 'JSONObject', false, false);
+
+               $rasterized = array();
+               $sizes = array();
+
+               foreach ($pages as $i => $infos) {
+                       $base = WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'];
+                       $baset = WS_DOCS . '/' . $infos['document_id'] . '/t' . $infos['document_page'];
+                       $swffile = $base . '.swf';
+                       if (file_exists($swffile)) {
+                               $fsize = filesize($swffile);
+                       } else {
+                               $fsize = 0;
+                       }
+
+                       if ($complete) {
+                               $flex->addSWF($swffile, 'page' . $i);
+                       } else {
+                               $filesToCopy['data/p' . $i . '.swf'] = $swffile;
+                               if ($infos['method'] >= wsDocument::BARBARE_PNM) {
+                                       $rasterized[$i] = true;
+                                       $filesToCopy['data/t' . $i . '.swf'] = $baset . '.swf';
+                               } else {
+                                       $rasterized[$i] = false;
+                               }
+                       }
+
+                       if ($i == 1) {
+                               $flexLight->addBitmap($base . '.jpg', 'thumb1');
+                       } else {
+                               $flex->addBitmap($base . '.jpg', 'thumb' . $i);
+                       }
+                       $sizes[$i] = $fsize;
+               }
+
+               $flexLight->addVariable('rasterized', $rasterized, false, true, 'JSONObject');
+               $flexLight->addVariable('sizes', $sizes, false, true, 'JSONObject');
+
+               if ($book->parametres->soundTheme != '') {
+                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/corner-drag.mp3', 'soundDragCorner');
+                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/corner-release.mp3', 'soundReleaseCorner');
+                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/page-flip-1.mp3', 'soundPage0');
+                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/page-flip-2.mp3', 'soundPage1');
+                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/cover-flip.mp3', 'soundCover0');
+               }
+               // Theme assets
+               $themeRoot = WS_THEMES . '/' . $theme->theme_id . '/';
+
+               if ($theme->parametres->backgroundImage != '') {
+                       $flexLight->addBitmap($themeRoot . $theme->parametres->backgroundImage, 'background');
+               }
+               if ($theme->parametres->menuImage != '') {
+                       $flex->addBitmap($themeRoot . $theme->parametres->menuImage, 'menu');
+               }
+               if ($theme->parametres->logoLoader != '') {
+                       $flexLight->addBitmap($themeRoot . $theme->parametres->logoLoader, 'logoLoader');
+               }
+               if ($theme->parametres->topBar != '') {
+                       $flexLight->addBitmap($themeRoot . $theme->parametres->topBar, 'topBar');
+               }
+               if ($theme->parametres->logo != '') {
+                       $flex->addBitmap($themeRoot . $theme->parametres->logo, 'logo');
+               }
+               if ($theme->parametres->afterSearch != '') {
+                       $flex->addBitmap($themeRoot . $theme->parametres->afterSearch, 'aftersearch');
+               }
+               if ($theme->parametres->favicon != '') {
+                       $filesToCopy['data/fluidbook.ico'] = $themeRoot . 'fluidbook.ico';
+               }
+
+               // Icons assets
+               $iconsRoot = WS_ICONS . '/' . $theme->parametres->iconSet . '/';
+               foreach (wsIcone::$files as $file) {
+                       $flex->addBitmap($iconsRoot . 'nav-' . $file . '.png', 'nav_' . $file);
+               }
+               // Share icons
+               $iconsRoot = WS_ICONS . '/share/';
+               foreach (wsIcone::$share as $file) {
+                       $flex->addBitmap($iconsRoot . 'share-' . $file . '.png', 'share_' . $file);
+               }
+
+               // Multilang
+               if (trim($book->parametres->multilang) != '') {
+                       $m = str_replace("\r", "\n", trim($book->parametres->multilang));
+                       $langs = explode("\n", $m);
+                       $langNames = array();
+                       $countryNames = array();
+                       $iso = l10n::getISOcodes();
+                       $chars = '()';
+                       $vuFlags = array();
+                       foreach ($langs as $l) {
+                               list($mlang, $flag, $url) = explode(',', trim($l), 3);
+                               if (!isset($vuFlags[$flag])) {
+                                       $flex->addBitmap(cubeMedia::getFlagFile($flag), 'flag_' . $flag);
+                                       $vuFlags[$flag] = true;
+                               }
+                               $n = cubeText::ucfirst($iso[$mlang]);
+                               $langNames[$mlang] = $n;
+                               $cn = cubeCountry::getCountryName($flag, $mlang);
+                               $countryNames[$mlang . '_' . $flag] = $cn;
+                               $chars.=$n . $cn;
+                       }
+
+                       $chars = preg_split('/(?<!^)(?!$)/u', $chars);
+                       $chars = array_unique($chars);
+
+                       $flex->addFont(WS_FILES . '/fonts/FluidbookMultilang.ttf', 'MultilangFont', $chars);
+                       $flex->addVariable('langNames', $langNames, false, true, 'JSONObject');
+                       $flex->addVariable('countryNames', $countryNames, false, true, 'JSONObject');
+               }
+               $flexLight->addVariable('lang', $book->lang);
+
+               // Basket
+               if ($book->parametres->basket) {
+                       $formats = array('jpg', 'png', 'jpeg');
+                       $referencesFile = $workingDir . 'commerce/' . $book->parametres->basketReferences;
+
+                       if (file_exists($referencesFile)) {
+                               $xml = simplexml_load_file($referencesFile);
+                               $i = 0;
+                               $allref = array();
+                               foreach ($xml->item as $item) {
+                                       $ref = (string) $item['reference'];
+                                       if (isset($allref[$ref])) {
+                                               continue;
+                                       }
+                                       $allref[$ref] = true;
+                                       foreach ($formats as $f) {
+                                               $refimage = $workingDir . 'commerce/' . $ref . '.' . $f;
+                                               if (file_exists($refimage)) {
+                                                       $flex->addBitmap($refimage, "basket_image_" . $ref);
+                                                       break;
+                                               }
+                                       }
+                                       $i++;
+                               }
+                       }
+                       if (isset($xml)) {
+                               $flex->addVariable('basketReferences', cubeXML::condense($xml->asXML()), false, true, "String");
+                       }
+                       if ($book->parametres->basketPDFBackground != '') {
+                               $flex->addByteArray($workingDir . 'commerce/' . $book->parametres->basketPDFBackground, 'basket_pdf_background');
+                       }
+               }
+               // Fonts
+               if ($theme->parametres->fontKit == 'auto') {
+                       if ($lang->font != 'system') {
+                               $flex->addFont(FONT_PATH . '/' . $lang->font, 'BoldFont', $lang->charset);
+                               $flex->addFont(FONT_PATH . '/' . $lang->font, 'GeneralFont', $lang->charset);
+                       }
+                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
+                       $flexLight->addFont(FONT_PATH . '/FluidbookLoader.ttf', 'LoaderFont', 'Numerals');
+               } else if ($theme->parametres->fontKit == 'vagrounded') {
+                       $flex->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Bold.otf', 'BoldFont', $lang->charset);
+                       $flex->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Light.otf', 'GeneralFont', $lang->charset);
+                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
+                       $flexLight->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Bold.otf', 'LoaderFont', 'Numerals');
+               } else if ($theme->parametres->fontKit == 'gill') {
+                       $flex->addFont(FONT_PATH . '/gill/gill.ttf', 'BoldFont', $lang->charset);
+                       $flex->addFont(FONT_PATH . '/gill/gill.ttf', 'GeneralFont', $lang->charset);
+                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
+                       $flexLight->addFont(FONT_PATH . '/gill/gill.ttf', 'LoaderFont', 'Numerals');
+               }
+
+               $flexLight->addVariable('checksum', $hash, false, true, 'String');
+       }
+
+       public function compileWidget($book, $pages) {
+               if (!$book->parametres->widget) {
+                       return;
+               }
+
+               global $core;
+
+               $finalDir = WS_BOOKS . '/final/' . $book->book_id . '/widget/';
+               $finalWidget = $finalDir . 'miniFluidbook.swf';
+
+               if (!file_exists($finalDir)) {
+                       mkdir($finalDir, 0777, true);
+               }
+
+               if ($book->parametres->widgetCover) {
+                       $file = 'miniFluidbookCouv.swf';
+               } else {
+                       $file = 'miniFluidbook.swf';
+               }
+               $mini = WS_COMPILE_ASSETS . '/_widget/' . $file;
+
+               $from = max(1, $book->parametres->widgetStart);
+               $to = min($book->parametres->widgetEnd, count($pages));
+
+               $swfcombine = new cubeCommandLine('swfcombine');
+               $swfcombine->setPath(CONVERTER_PATH);
+               $swfcombine->setArg('merge');
+               $swfcombine->setArg('stack1');
+               $swfcombine->setArg('z');
+               $swfcombine->setArg('o', $finalWidget);
+               $swfcombine->setArg(null, $mini);
+
+               $tempimage = array();
+               $tempswf = array();
+               $timg = array();
+
+               for ($i = $from; $i <= $to; $i++) {
+                       $page = $pages[$i];
+
+                       $timg[$i] = $tempimage[$i] = cubeFiles::tempnam();
+                       $tempswf[$i] = cubeFiles::tempnam();
+
+                       $it = new imageTools();
+                       $image = WS_DOCS . '/' . $page['document_id'] . '/html/t150-' . $page['document_page'] . '.jpg';
+
+                       try {
+                               $it->loadImage($image);
+                               $it->resize($book->parametres->widgetSize, 10000);
+                               $it->output('jpeg', $tempimage[$i], 100);
+                       } catch (Exception $e) {
+                               $tempimage[$i] = $image;
+                       }
+                       $jpg2swf = new cubeCommandLine('jpeg2swf');
+                       $jpg2swf->setEnv('PATH', '/bin:/usr/bin:/usr/local/bin');
+                       $jpg2swf->setArg('q', $book->parametres->widgetQuality);
+                       $jpg2swf->setArg('o', $tempswf[$i]);
+                       $jpg2swf->setArg(null, $tempimage[$i]);
+                       $jpg2swf->execute();
+
+                       $swfcombine->setArg(null, $tempswf[$i]);
+               }
+               $swfcombine->execute();
+
+               foreach ($timg as $t) {
+                       if (file_exists($t)) {
+                               unlink($t);
+                       }
+               }
+               foreach ($tempswf as $t) {
+                       unlink($t);
+               }
+       }
+
+       public function compileHTML5($book_id, $book) {
+               $htmlCompiler = wsHTML5Compiler::factory($book_id, $book->parametres->mobileLVersion);
+               $htmlCompiler->compile();
+       }
+
+       public function indexPDF($book, $pages) {
+               $indexPath = WS_BOOKS . '/search/' . $book->book_id;
+
+               Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive());
+
+               if (file_exists($indexPath)) {
+                       files::deltree($indexPath);
+               }
+               $index = Zend_Search_Lucene::create($indexPath);
+
+               foreach ($pages as $i => $infos) {
+                       $doc = new Zend_Search_Lucene_Document();
+                       $doc->addField(Zend_Search_Lucene_Field::Text('url', '#' . $i));
+                       $doc->addField(Zend_Search_Lucene_Field::UnStored('contents', file_get_contents(WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'] . '.txt')));
+                       $index->addDocument($doc);
+               }
+
+               $c = $this->con->openCursor('books');
+               $c->lucene_time = TIME;
+               $c->update('WHERE book_id=' . $book->book_id);
+       }
+
+       public function compilePDF($book, $pages) {
+               if (substr($book->parametres->pdfName, 0, 4) == 'http') {
+                       return;
+               }
+               if (isset($book->parametres->pdfName) && $book->parametres->pdfName != '') {
+                       $pdfName = $book->parametres->pdfName;
+               }
+
+               $cacheDir = WS_BOOKS . '/pdf/' . $book->book_id;
+               if (!file_exists($cacheDir)) {
+                       mkdir($cacheDir);
+               }
+
+               $normalPDF = $cacheDir . '/normal.pdf';
+               $originalPDF = $cacheDir . '/original.pdf';
+               $compressedPDF = $cacheDir . '/compressed.pdf';
+
+
+
+
+               if (file_exists($originalPDF)) {
+                       $fmtime = filemtime($originalPDF);
+                       if ($fmtime >= $book->composition_update) {
+                               $invalid = false;
+                               foreach ($pages as $i => $infos) {
+                                       $doc = WS_DOCS . '/' . $infos['document_id'] . '/crop.pdf';
+                                       if (filemtime($doc) > $fmtime) {
+                                               $invalid = true;
+                                       }
+                               }
+                       } else {
+                               $invalid = true;
+                       }
+               } else {
+                       $invalid = true;
+               }
+
+
+               if ($invalid) {
+                       $pdfList = array();
+                       $pagesList = array();
+                       $nb_pages = array();
+                       $j = 0;
+                       $k = 0;
+                       $original = true;
+
+                       foreach ($pages as $i => $infos) {
+                               if (!isset($firstDoc)) {
+                                       $firstDoc = $infos['document_id'];
+                               }
+
+                               $doc = WS_DOCS . '/' . $infos['document_id'] . '/crop.pdf';
+                               if (!isset($pdfList[$doc])) {
+                                       $pdfList[$doc] = $j;
+                                       $nb_pages[$doc] = $infos['nb_pages'];
+                                       $k = $j;
+                                       $j++;
+                               } else {
+                                       $k = $pdfList[$doc];
+                               }
+                               $pagesList[$i] = array($k, $infos['document_page']);
+
+                               if ($i != $infos['document_page'] || $infos['document_id'] != $firstDoc) {
+                                       $original = false;
+                               }
+                       }
+
+                       if ($original) {
+
+                               $this->copy(WS_DOCS . '/' . $firstDoc . '/crop.pdf', $originalPDF);
+                       } else {
+                               $args = '';
+                               foreach ($pdfList as $doc => $index) {
+                                       $lettre = cubeMath::toPDFLetter($index, true);
+                                       $args .= $lettre . '=' . $doc . ' ';
+                               }
+
+                               $args .= ' cat ';
+
+                               $ranges = array();
+                               $currentRange = null;
+
+                               foreach ($pagesList as $p) {
+                                       $lettre = cubeMath::toPDFLetter($p[0], true);
+                                       $page = $p[1];
+
+                                       // Initialise l'intervale
+                                       if (is_null($currentRange)) {
+                                               $currentRange = array('lettre' => $lettre, 'start' => $page, 'end' => $page);
+                                               continue;
+                                       }
+
+                                       // Poursuit le remplissage si la lettre est identique et si la page suivante est bien la page suivante dans le document
+                                       if ($currentRange['lettre'] == $lettre && $currentRange['end'] + 1 == $page) {
+                                               $currentRange['end'] = $page;
+                                               continue;
+                                       }
+
+                                       // Ajoute l'intervale à la liste finale
+                                       $ranges[] = $currentRange;
+
+                                       // Réinitialise l'intervale suivant
+                                       $currentRange = array('lettre' => $lettre, 'start' => $page, 'end' => $page);
+                               }
+
+                               // Ajoute la dernière
+                               if (!is_null($currentRange)) {
+                                       $ranges[] = $currentRange;
+                               }
+                               // Si le pdf final est constitué du document complet d'un document
+                               if (count($ranges) == 1 && $ranges[0]['start'] == 1) {
+                                       $alldocs = array_keys($pdfList);
+                                       $doc = array_pop($alldocs);
+                                       if ($nb_pages[$doc] == $ranges[0]['end']) {
+                                               $this->copy($doc, $originalPDF);
+                                               return;
+                                       }
+                               }
+
+                               foreach ($ranges as $range) {
+                                       $args .= ' ' . $range['lettre'] . $range['start'];
+                                       if ($range['start'] == $range['end']) {
+                                               continue;
+                                       }
+                                       $args .= '-' . $range['end'];
+                               }
+
+                               $hash = sha1($args);
+
+                               $args .= ' output ' . $originalPDF;
+
+                               $cached = WS_BOOKS . '/pdf/' . $hash . '.pdf';
+
+                               if (file_exists($cached)) {
+                                       $this->copy($cached, $originalPDF);
+                               } else {
+                                       $pdftk = new cubeCommandLine('pdftk');
+                                       $pdftk->setPath(CONVERTER_PATH);
+                                       $pdftk->setManualArg($args);
+                                       $pdftk->execute();
+                                       $this->copy($normalPDF, $cached);
+                               }
+                       }
+               }
+
+
+
+
+               if ($book->parametres->pdfReplace) {
+                       $replace = WS_BOOKS . '/working/' . $book->book_id . '/' . $book->parametres->pdfReplace;
+                       if (file_exists($replace)) {
+                               if (!file_exists($normalPDF) || filemtime($normalPDF) < filemtime($replace) || filesize($normalPDF) != filesize($replace)) {
+                                       $this->copy($replace, $normalPDF);
+                               }
+                       }
+               } else {
+                       $this->copy($originalPDF, $normalPDF);
+               }
+               $finalPDF = WS_BOOKS . '/final/' . $book->book_id . '/data/' . $book->parametres->pdfName;
+
+               if ($book->parametres->pdfCompress) {
+                       if (!file_exists($compressedPDF) || filemtime($compressedPDF) < filemtime($normalPDF)) {
+                               $gs = new cubeCommandLine('gs', null, true);
+                               $gs->setPath(CONVERTER_PATH);
+                               $gs->setEnv('GS_FONTPATH', '/home/ws/fonts');
+                               $gs->setArg('-dBATCH');
+                               $gs->setArg('-dNOPAUSE');
+                               $gs->setArg('-dNOPROMPT');
+                               $gs->setArg('-sOutputFile=' . $compressedPDF);
+                               $gs->setArg('-sDEVICE=pdfwrite');
+                               $gs->setArg('-dPDFSETTINGS=/ebook');
+                               $gs->setArg('-dColorImageResolution=72');
+                               $gs->setArg('-dAutoRotatePages=/None');
+                               $gs->setArg('-dColorConversionStrategy=/LeaveColorUnchanged');
+                               $gs->setArg(null, $normalPDF);
+                               $gs->execute();
+                       }
+                       copy($compressedPDF, $finalPDF);
+               } else {
+                       copy($normalPDF, $finalPDF);
+               }
+       }
+
+       public function generateCID() {
+
+               do {
+                       $res = '';
+                       for ($i = 0; $i < 8; $i++) {
+                               $j = rand(0, 61);
+                               $res.=$this->base62($j);
+                       }
+                       $r = $this->con->select('SELECT book_id FROM books WHERE cid=\'' . $res . '\'');
+                       if ($r->count() == 0) {
+                               return $res;
+                       }
+               } while (true);
+       }
+
+       protected function base62($val) {
+               $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+               $base = strlen($chars);
+               $str = '';
+               do {
+                       $i = $val % $base;
+                       $str = $chars[$i] . $str;
+                       $val = ($val - $i) / $base;
+               } while ($val > 0);
+               return $str;
+       }
+
+}
+
 ?>
\ No newline at end of file