File indexing completed on 2024-12-22 05:33:07
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 }