File indexing completed on 2024-04-28 17:09:56

0001 <?php
0002 /** @noinspection PhpUndefinedFieldInspection */
0003 /** @noinspection PhpUnused */
0004 
0005 /**
0006  * file server - part of Opendesktop.org platform project <https://www.opendesktop.org>.
0007  *
0008  * Copyright (c) 2016 pling GmbH.
0009  *
0010  * This program is free software: you can redistribute it and/or modify
0011  * it under the terms of the GNU Affero General Public License as
0012  * published by the Free Software Foundation, either version 3 of the
0013  * License, or (at your option) any later version.
0014  *
0015  * This program is distributed in the hope that it will be useful,
0016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0018  * GNU Affero General Public License for more details.
0019  *
0020  * You should have received a copy of the GNU Affero General Public License
0021  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
0022  */
0023 class Comics extends BaseController
0024 {
0025     /**
0026      * @return void
0027      * @throws Flooer_Exception
0028      */
0029     public function getExtractcomic()
0030     {
0031         $id = null;
0032         if (!empty($this->request->id)) {
0033             $id = $this->request->id;
0034         }
0035 
0036         if ($id) {
0037             $id = $this->models->files->getFileId($id);
0038         }
0039 
0040         $file = $this->models->files->$id;
0041 
0042         if (!$file) {
0043             $this->response->setStatus(404);
0044             throw new Flooer_Exception('Not found', LOG_NOTICE);
0045         }
0046 
0047         $this->log->log("Start Extract comic book (file: $file->id;)", LOG_NOTICE);
0048 
0049 
0050         $collectionId = $file->collection_id;
0051 
0052         if (!$collectionId) {
0053             $this->response->setStatus(404);
0054             throw new Flooer_Exception('Collection not found', LOG_NOTICE);
0055         }
0056 
0057         $testPath = $this->appConfig->general['comicsDir'] . '/' . $collectionId;
0058 
0059         $this->log->log("Create folders (collection: $testPath;)", LOG_NOTICE);
0060 
0061         if (!is_dir($this->appConfig->general['comicsDir'] . '/' . $collectionId) && !mkdir($this->appConfig->general['comicsDir'] . '/' . $collectionId)) {
0062             $this->response->setStatus(500);
0063             throw new Flooer_Exception('Failed to create collection folder', LOG_ALERT);
0064         }
0065 
0066         if (!is_dir($this->appConfig->general['comicsDir'] . '/' . $collectionId . '/' . $file->id) && !mkdir($this->appConfig->general['comicsDir'] . '/' . $collectionId . '/' . $file->id)) {
0067             $this->response->setStatus(500);
0068             throw new Flooer_Exception('Failed to create comic folder', LOG_ALERT);
0069         }
0070 
0071         $filePath = $this->appConfig->general['filesDir'] . '/' . $collectionId . '/';
0072 
0073         $comicPath = $this->appConfig->general['comicsDir'] . '/' . $collectionId . '/' . $file->id . '/';
0074 
0075         $this->log->log("Comic-Path: $comicPath;)", LOG_NOTICE);
0076 
0077 
0078         if ($this->endsWith($file->name, ".cbz")) {
0079             $zip = new ZipArchive();
0080 
0081             if ($zip->open($filePath . $file->name) === true) {
0082                 for ($i = 0; $i < $zip->numFiles; $i++) {
0083                     $filename = $zip->getNameIndex($i);
0084                     $fileinfo = pathinfo($filename);
0085 
0086                     $folderName = $fileinfo['dirname'];
0087                     if ($folderName == '.') {
0088                         $folderName = '';
0089                     }
0090                     $folderName = $this->normalizeString($folderName);
0091 
0092                     //$this->log->log("Comic-Page-Path: ".$filename, LOG_NOTICE);
0093 
0094                     if ($this->endsWith($zip->getNameIndex($i), '.jpg') || $this->endsWith($zip->getNameIndex($i), '.gif') || $this->endsWith($zip->getNameIndex($i), '.png') || $this->endsWith($zip->getNameIndex($i), '.webp')) {
0095 
0096                         copy("zip://" . $filePath . $file->name . "#" . $filename, $comicPath . $folderName . $fileinfo['basename']);
0097                     }
0098 
0099                 }
0100                 $zip->close();
0101             }
0102         } else {
0103             if ($this->endsWith($file->name, ".cbr")) {
0104 
0105                 exec('rar e ' . $filePath . $file->name . ' ' . $comicPath);
0106 
0107             }
0108         }
0109 
0110         //normalize file names
0111         foreach (new DirectoryIterator($comicPath) as $fn) {
0112 
0113             $nameString = $fn->getFilename();
0114             if ($this->endsWith($nameString, '.jpg') || $this->endsWith($nameString, '.gif') || $this->endsWith($nameString, '.png') || $this->endsWith($nameString, '.webp')) {
0115                 if ($nameString != $this->normalizeString($nameString)) {
0116                     $cmd = 'mv ' . '\'' . $comicPath . $nameString . '\'' . ' ' . '\'' . $comicPath . $this->normalizeString($nameString) . '\'';
0117                     //$this->log->log("Rename file: ".$cmd, LOG_NOTICE);
0118 
0119                     exec($cmd);
0120 
0121                     $nameString = $this->normalizeString($nameString);
0122                 }
0123 
0124                 //Convert webp to png
0125                 if ($this->endsWith($nameString, '.webp')) {
0126                     $cmd = 'dwebp ' . '\'' . $comicPath . $nameString . '\'' . ' -o ' . '\'' . $comicPath . $nameString . '.png\'';
0127                     //$this->log->log("Rename file: ".$cmd, LOG_NOTICE);
0128 
0129                     exec($cmd);
0130 
0131                     unlink($comicPath . $nameString);
0132 
0133                 }
0134 
0135             }
0136 
0137         }
0138 
0139         $this->log->log("Extract: Done", LOG_NOTICE);
0140 
0141         $this->_setResponseContent('success');
0142         exit;
0143     }
0144 
0145     /**
0146      * @param $haystack
0147      * @param $needle
0148      *
0149      * @return bool
0150      */
0151     private function endsWith($haystack, $needle): bool
0152     {
0153         return $needle === "" || substr(strtolower($haystack), -strlen($needle)) === strtolower($needle);
0154     }
0155 
0156     /**
0157      * @param string $str
0158      *
0159      * @return array|string|string[]
0160      */
0161     public static function normalizeString(string $str = '')
0162     {
0163         $str = strip_tags($str);
0164         $str = preg_replace('/[\r\n\t ]+/', ' ', $str);
0165         $str = preg_replace('/[\"\*\/\:\<\>\?\'\|]+/', ' ', $str);
0166         //$str = strtolower($str);
0167         $str = html_entity_decode($str, ENT_QUOTES, "utf-8");
0168         $str = htmlentities($str, ENT_QUOTES, "utf-8");
0169         $str = preg_replace("/(&)([a-z])([a-z]+;)/i", '$2', $str);
0170         $str = str_replace(' ', '-', $str);
0171         $str = rawurlencode($str);
0172 
0173         return str_replace('%', '-', $str);
0174     }
0175 
0176     /**
0177      * @return void
0178      * @throws Flooer_Exception
0179      */
0180     public function getExtractebook()
0181     {
0182         $id = null;
0183         if (!empty($this->request->id)) {
0184             $id = $this->request->id;
0185         }
0186 
0187         if ($id) {
0188             $id = $this->models->files->getFileId($id);
0189         }
0190 
0191         $file = $this->models->files->$id;
0192 
0193         if (!$file) {
0194             $this->response->setStatus(404);
0195             throw new Flooer_Exception('Not found', LOG_NOTICE);
0196         }
0197 
0198         $this->log->log("Start Extract ebook (file: $file->id;)", LOG_NOTICE);
0199 
0200 
0201         $collectionId = $file->collection_id;
0202 
0203         if (!$collectionId) {
0204             $this->response->setStatus(404);
0205             throw new Flooer_Exception('Collection not found', LOG_NOTICE);
0206         }
0207 
0208         $testPath = $this->appConfig->general['ebooksDir'] . '/' . $collectionId;
0209 
0210         $this->log->log("Create folders (collection: $testPath;)", LOG_NOTICE);
0211 
0212         if (!is_dir($this->appConfig->general['ebooksDir'] . '/' . $collectionId) && !mkdir($this->appConfig->general['ebooksDir'] . '/' . $collectionId, 0777)) {
0213             $this->response->setStatus(500);
0214             throw new Flooer_Exception('Failed to create collection folder', LOG_ALERT);
0215         }
0216 
0217         if (!is_dir($this->appConfig->general['ebooksDir'] . '/' . $collectionId . '/' . $file->id) && !mkdir($this->appConfig->general['ebooksDir'] . '/' . $collectionId . '/' . $file->id)) {
0218             $this->response->setStatus(500);
0219             throw new Flooer_Exception('Failed to create ebooks folder', LOG_ALERT);
0220         }
0221 
0222         $filePath = $this->appConfig->general['filesDir'] . '/' . $collectionId . '/';
0223 
0224         $ebookPath = $this->appConfig->general['ebooksDir'] . '/' . $collectionId . '/' . $file->id . '/';
0225 
0226         $this->log->log("Ebook-Path: $ebookPath;)", LOG_NOTICE);
0227 
0228 
0229         if ($this->endsWith($file->name, ".epub")) {
0230             $zip = new ZipArchive();
0231 
0232             if ($zip->open($filePath . $file->name) === true) {
0233                 $zip->extractTo($ebookPath);
0234                 $zip->close();
0235             }
0236         }
0237 
0238         $this->log->log("Extract: Done", LOG_NOTICE);
0239 
0240         $this->_setResponseContent('success');
0241         exit;
0242     }
0243 
0244     /**
0245      * @return void
0246      * @throws Flooer_Exception
0247      */
0248     public function getToc()
0249     {
0250         $id = null;
0251         if (!empty($this->request->id)) {
0252             $id = $this->request->id;
0253         }
0254 
0255         if ($id) {
0256             $id = $this->models->files->getFileId($id);
0257         }
0258 
0259         $file = $this->models->files->$id;
0260 
0261         if (!$file) {
0262             $this->response->setStatus(404);
0263             throw new Flooer_Exception('Not found', LOG_NOTICE);
0264         }
0265 
0266         $this->log->log("Start get comic book toc (file: $file->id;)", LOG_NOTICE);
0267 
0268 
0269         $collectionId = $file->collection_id;
0270 
0271         if (!$collectionId) {
0272             $this->response->setStatus(404);
0273             throw new Flooer_Exception('Collection not found', LOG_NOTICE);
0274         }
0275 
0276         //ebook or epub?
0277         if ($this->endsWith($file->name, '.epub')) {
0278             $ebook = new EPubReader();
0279             $comicPath = $this->appConfig->general['ebooksDir'] . '/' . $collectionId . '/' . $file->id;
0280             $ebook->init($comicPath);
0281 
0282             //$this->log->log("Ebook Object:" . print_r($ebook, true), LOG_NOTICE);
0283 
0284             $toc = $ebook->getTOC();
0285 
0286         } else {
0287             $comicPath = $this->appConfig->general['comicsDir'] . '/' . $collectionId . '/' . $file->id;
0288 
0289             $this->log->log("Comic-Path: $comicPath;)", LOG_NOTICE);
0290 
0291             $tocFile = $comicPath . '/toc.txt';
0292 
0293             if (file_exists($tocFile)) {
0294                 //Retrieve the data from our text file.
0295                 $fileContents = file_get_contents($tocFile);
0296 
0297                 //Convert the JSON string back into an array.
0298                 $toc = json_decode($fileContents, true);
0299 
0300                 $this->log->log("Read from Toc-File: $tocFile", LOG_NOTICE);
0301             } else {
0302                 $toc = array();
0303 
0304                 foreach (new DirectoryIterator($comicPath) as $fn) {
0305 
0306                     $nameString = $fn->getFilename();
0307                     if ($this->endsWith($nameString, '.jpg') || $this->endsWith($nameString, '.gif') || $this->endsWith($nameString, '.png') || $this->endsWith($nameString, '.webp')) {
0308                         $toc[] = $nameString;
0309                     }
0310                 }
0311 
0312                 natcasesort($toc);
0313                 $toc = array_values($toc);
0314 
0315 
0316                 //Encode the array into a JSON string.
0317                 $encodedString = json_encode($toc);
0318 
0319                 //Save the JSON string to a text file.
0320                 file_put_contents($tocFile, $encodedString);
0321 
0322                 $this->log->log("Read from Folder", LOG_NOTICE);
0323             }
0324 
0325 
0326             $this->log->log("Done, found " . count($toc) . " pages", LOG_NOTICE);
0327         }
0328 
0329 
0330         $this->_setResponseContent('success', array('files' => $toc));
0331     }
0332 
0333     /**
0334      * @return void
0335      * @throws Flooer_Exception
0336      */
0337     public function getPage()
0338     {
0339         $id = null;
0340         if (!empty($this->request->id)) {
0341             $id = $this->request->id;
0342         }
0343 
0344         $filename = null;
0345         if (!empty($this->request->filename)) {
0346             $filename = $this->request->filename;
0347         }
0348 
0349         if ($id) {
0350             $id = $this->models->files->getFileId($id);
0351         }
0352 
0353         $file = $this->models->files->$id;
0354 
0355         if (!$file) {
0356             $this->response->setStatus(404);
0357             throw new Flooer_Exception('Not found', LOG_NOTICE);
0358         }
0359 
0360         $this->log->log("Start show book page (file: $file->id;)", LOG_NOTICE);
0361 
0362 
0363         $collectionId = $file->collection_id;
0364 
0365         if (!$collectionId) {
0366             $this->response->setStatus(404);
0367             throw new Flooer_Exception('Collection not found', LOG_NOTICE);
0368         }
0369 
0370 
0371         //ebook or epub?
0372         if ($this->endsWith($file->name, '.epub')) {
0373             $ebook = new EPubReader();
0374             $comicPath = $this->appConfig->general['ebooksDir'] . '/' . $collectionId . '/' . $file->id . '/';
0375             $ebook->init($comicPath);
0376 
0377             //$this->log->log("Ebook Object:" . print_r($ebook, true), LOG_NOTICE);
0378             $pagePath = $comicPath . $ebook->getOPFDir() . '/' . $filename;
0379 
0380             $page = fopen($pagePath, 'rb');
0381 
0382             if (!$page) {
0383                 $this->log->log("Page not found:" . $pagePath, LOG_NOTICE);
0384             } else {
0385 
0386                 //$serverUri = $this->appConfig->general['ebookUri'] . '/api/files/pageitem?id=' . $file->id . '&filename=' . $filename . '/';
0387 
0388                 //replace href links with links to /api/files/pageitem?FILE_ID&filename=FILENAME
0389                 /*$result = "";
0390                 # read the contents in
0391                 $file_contents = fgets($page, filesize($pagePath));
0392 
0393                 while ($file_contents) {
0394                     # apply the translation
0395                     $result .= str_replace(" href='", " href='".$serverUri, $file_contents);
0396                 }*/
0397 
0398                 header('Content-type: text/html');
0399                 header('Access-Control-Allow-Origin: *');
0400                 fpassthru($page);
0401                 //print_r($result);
0402             }
0403 
0404         } else {
0405 
0406             $comicPath = $this->appConfig->general['comicsDir'] . '/' . $collectionId . '/' . $file->id . '/';
0407 
0408             $this->log->log("Comic-Path: " . $comicPath . $filename, LOG_NOTICE);
0409 
0410             $page = fopen($comicPath . $filename, 'rb');
0411 
0412             if ($this->endsWith($filename, ".jpg")) {
0413                 //file_put_contents($saveName,$zip->getFromIndex(0));
0414                 //imagejpeg($zip->getStream($page), "cache/test.jpg", 75);
0415                 header('Content-type: image/jpeg');
0416                 fpassthru($page);
0417             } else {
0418                 if ($this->endsWith($filename, ".png")) {
0419                     //imagepng(($zip->getStream($page), $saveName);
0420                     header('Content-type: image/png');
0421                     fpassthru($page);
0422                 } else {
0423                     if ($this->endsWith($filename, ".gif")) {
0424                         //imagegif($zip->getStream($page), $saveName);
0425                         header('Content-type: image/gif');
0426                         fpassthru($page);
0427                     } else {
0428                         if ($this->endsWith($filename, ".webp")) {
0429                             //imagegif($zip->getStream($page), $saveName);
0430                             header('Content-type: image/webp');
0431                             fpassthru($page);
0432                         }
0433                     }
0434                 }
0435             }
0436             $this->log->log("Done", LOG_NOTICE);
0437 
0438             $this->_setResponseContent('success');
0439         }
0440         exit;
0441     }
0442 
0443     /**
0444      * @return void
0445      * @throws Flooer_Exception
0446      */
0447     public function getPageitem()
0448     {
0449         $id = null;
0450         if (!empty($this->request->id)) {
0451             $id = $this->request->id;
0452         }
0453 
0454         $filename = null;
0455         if (!empty($this->request->filename)) {
0456             $filename = $this->request->filename;
0457         }
0458 
0459         if ($id) {
0460             $id = $this->models->files->getFileId($id);
0461         }
0462 
0463         $file = $this->models->files->$id;
0464 
0465         if (!$file) {
0466             $this->response->setStatus(404);
0467             throw new Flooer_Exception('Not found', LOG_NOTICE);
0468         }
0469 
0470         $this->log->log("Start show book page item (file: $file->id, filename: $filename)", LOG_NOTICE);
0471 
0472 
0473         $collectionId = $file->collection_id;
0474 
0475         if (!$collectionId) {
0476             $this->response->setStatus(404);
0477             throw new Flooer_Exception('Collection not found', LOG_NOTICE);
0478         }
0479 
0480 
0481         //ebook or epub?
0482         if ($this->endsWith($file->name, '.epub')) {
0483             $ebook = new EPubReader();
0484             $comicPath = $this->appConfig->general['ebooksDir'] . '/' . $collectionId . '/' . $file->id . '/';
0485             $ebook->init($comicPath);
0486 
0487             //$this->log->log("Ebook Object:" . print_r($ebook, true), LOG_NOTICE);
0488             $pagePath = $comicPath . $ebook->getOPFDir() . '/' . $filename;
0489 
0490             $page = fopen($pagePath, 'rb');
0491 
0492             if (!$page) {
0493                 $this->log->log("Page Item not found:" . $pagePath, LOG_NOTICE);
0494             } else {
0495                 header('Content-type: ' . mime_content_type($pagePath));
0496                 fpassthru($page);
0497             }
0498         }
0499 
0500         exit;
0501     }
0502 
0503     /**
0504      * @param $baseDir
0505      * @param $dir
0506      * @param $fileNameList
0507      *
0508      * @return mixed|void
0509      */
0510     protected function listFolderFiles($baseDir, $dir, $fileNameList)
0511     {
0512         $ffs = scandir($baseDir . '/' . $dir);
0513 
0514         unset($ffs[array_search('.', $ffs, true)]);
0515         unset($ffs[array_search('..', $ffs, true)]);
0516 
0517         // prevent empty ordered elements
0518         if (count($ffs) < 1) {
0519             return;
0520         }
0521 
0522         foreach ($ffs as $ff) {
0523             $nameString = $ff;
0524             if ($this->endsWith($nameString, '.jpg') || $this->endsWith($nameString, '.gif') || $this->endsWith($nameString, '.png') || $this->endsWith($nameString, '.webp')) {
0525                 $fileNameList[] = $dir . '/' . $ff;
0526             }
0527 
0528 
0529             if (is_dir($baseDir . '/' . $dir . '/' . $ff)) {
0530                 $fileNameList = $this->listFolderFiles($baseDir, $dir . '/' . $ff, $fileNameList);
0531             }
0532         }
0533 
0534         return $fileNameList;
0535     }
0536 
0537 }