File indexing completed on 2024-12-22 05:33:07

0001 <?php /** @noinspection PhpUndefinedFieldInspection */
0002 
0003 /**
0004  * ocs-fileserver
0005  *
0006  * Copyright 2016 by pling GmbH.
0007  *
0008  * This file is part of ocs-fileserver.
0009  *
0010  * ocs-fileserver is free software: you can redistribute it and/or modify
0011  * it under the terms of the GNU Affero General Public License as published by
0012  * the Free Software Foundation, either version 3 of the License, or
0013  * (at your option) any later version.
0014  *
0015  * ocs-fileserver 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
0022  **/
0023 
0024 /**
0025  * Class BaseController
0026  *
0027  * @property RedisCache redisCache
0028  * @property object appConfig
0029  * @property Flooer_Log log
0030  * @property Flooer_Http_Response response
0031  * @property ModelContainer models
0032  * @property OcsModel modelOcs
0033  * @property Flooer_Http_Request request
0034  *
0035  */
0036 class BaseController extends Flooer_Controller
0037 {
0038 
0039     protected function _sendFile($filepath, $filename, $type, $size, $attachment = false, $headeronly = false)
0040     {
0041         $rangeBegin = 0;
0042         $rangeEnd = $size - 1; // Content-Range: bytes 0-1023/1024
0043         $disposition = 'inline';
0044         if ($attachment) {
0045             $disposition = 'attachment';
0046         }
0047 
0048         $this->response->setHeader('Access-Control-Allow-Headers', 'Range');
0049         $this->response->setHeader(
0050             'Access-Control-Expose-Headers',
0051             'Accept-Ranges, Content-Length, Content-Range'
0052         );
0053         $this->response->setHeader('Accept-Ranges', 'bytes');
0054         $this->response->setHeader('Cache-Control', 'public, must-revalidate, max-age=0');
0055         $this->response->setHeader('Pragma', 'no-cache');
0056         $this->response->setHeader('Last-Modified', date('r', filemtime($filepath)));
0057         $this->response->setHeader('Content-Type', $type);
0058         $this->response->setHeader('Content-Length', $size);
0059         $this->response->setHeader(
0060             'Content-Disposition',
0061             $disposition . '; filename="' . $filename . '"'
0062         );
0063 
0064         if (isset($this->server->HTTP_RANGE)) {
0065             if (preg_match(
0066                 '/bytes=\h*(\d+)-(\d*)[\D.*]?/i',
0067                 $this->server->HTTP_RANGE,
0068                 $matches
0069             )) {
0070                 $rangeBegin = (int) $matches[1];
0071                 if (!empty($matches[2])) {
0072                     $rangeEnd = (int) $matches[2];
0073                 }
0074             }
0075             $this->response->setStatus(206);
0076             $this->response->setHeader(
0077                 'Content-Range',
0078                 'bytes ' . $rangeBegin . '-' . $rangeEnd . '/' . $size
0079             );
0080             $this->response->setHeader(
0081                 'Content-Length',
0082                 $rangeEnd - $rangeBegin + 1
0083             );
0084         }
0085 
0086         $this->response->send();
0087 
0088         if (!$headeronly) {
0089             if (ob_get_level()) {
0090                 ob_end_flush();
0091             }
0092             $length = 1024 * 512; // Please do not specify an extremely large size
0093             $cur = $rangeBegin;
0094             $end = $rangeEnd + 1;
0095             $fp = fopen($filepath, 'rb');
0096             fseek($fp, $cur, 0);
0097             while (!feof($fp)
0098                 && $cur < $end
0099                 && connection_status() == 0
0100             ) {
0101                 echo fread($fp, min($length, $end - $cur));
0102                 $cur += $length;
0103                 ob_flush();
0104                 flush();
0105             }
0106             fclose($fp);
0107         }
0108 
0109         if (php_sapi_name() == 'fpm-fcgi') {
0110             fastcgi_finish_request();
0111         }
0112 
0113         exit;
0114     }
0115 
0116     protected function _setResponseContent($status, array $data = null)
0117     {
0118         $status = strtolower($status);
0119         if (!in_array($status, array('success', 'error', 'failure'))) {
0120             $status = 'unknown';
0121         }
0122 
0123         $content = array('status' => $status);
0124         if ($data) {
0125             $content += $data;
0126         }
0127 
0128         $format = $this->appConfig->general['format'];
0129         if (!empty($this->request->format)) {
0130             $format = $this->request->format;
0131         }
0132 
0133         if (!empty($this->request->ignore_status_code)) {
0134             $this->response->setStatus(200);
0135         }
0136 
0137         switch (strtolower($format)) {
0138             case 'json':
0139                 $this->view->content = json_encode($content);
0140                 if (!empty($this->request->callback)) {
0141                     $this->view->jsonpCallback = htmlspecialchars(
0142                         $this->request->callback,
0143                         ENT_QUOTES
0144                     );
0145                     $this->view->setFile('content.js');
0146                     break;
0147                 }
0148                 $this->view->setFile('content.json');
0149                 break;
0150             case 'xml':
0151                 // Continue to default
0152             default:
0153                 $this->view->content = $this->_convertXmlDom($content, 'response')->saveXML();
0154                 $this->view->setFile('content.xml');
0155                 break;
0156         }
0157     }
0158 
0159     protected function _convertXmlDom($values, $tagName = 'data', DOMNode &$dom = null, DOMElement &$element = null)
0160     {
0161         if (!$dom) {
0162             $dom = new DomDocument(
0163                 '1.0',
0164                 $this->dispatch->getApplication()->getConfig('encoding')
0165             );
0166         }
0167 
0168         if (!$element) {
0169             $element = $dom->appendChild($dom->createElement($tagName));
0170         }
0171 
0172         if (is_array($values) || is_object($values)) {
0173             foreach ($values as $key => $value) {
0174                 if (ctype_digit((string) $key)) {
0175                     $key = $element->tagName . '_' . $key;
0176                 }
0177                 $childElement = $element->appendChild($dom->createElement($key));
0178                 $this->_convertXmlDom($value, $key, $dom, $childElement);
0179             }
0180         }
0181         else {
0182             $element->appendChild($dom->createTextNode($values));
0183         }
0184 
0185         return $dom;
0186     }
0187 
0188     protected function _getDownloadSecret($clientId)
0189     {
0190         $clients = parse_ini_file('configs/clients.ini', true);
0191         if (isset($clients[$clientId])) {
0192             return $clients[$clientId]['downloadSecret'];
0193         }
0194         return '';
0195     }
0196 
0197     protected function _isAllowedAccess()
0198     {
0199         if (!empty($this->request->client_id)
0200             && !empty($this->request->secret)
0201         ) {
0202             $clients = parse_ini_file('configs/clients.ini', true);
0203             if (isset($clients[$this->request->client_id])
0204                 && $clients[$this->request->client_id]['secret'] === $this->request->secret
0205             ) {
0206                 return true;
0207             }
0208         }
0209         return false;
0210     }
0211 
0212     protected function _isValidUri($uri)
0213     {
0214         return Flooer_Utility_Validation::isUri($uri);
0215     }
0216 
0217     protected function _isValidEmail($email)
0218     {
0219         return Flooer_Utility_Validation::isEmail($email);
0220     }
0221 
0222     protected function _isValidPerpageNumber($number)
0223     {
0224         if (Flooer_Utility_Validation::isDigit($number)
0225             && $number > 0
0226             && $number <= $this->appConfig->general['perpageMax']
0227         ) {
0228             return true;
0229         }
0230         return false;
0231     }
0232 
0233     protected function _isValidPageNumber($number)
0234     {
0235         if (Flooer_Utility_Validation::isDigit($number) && $number > 0) {
0236             return true;
0237         }
0238         return false;
0239     }
0240 
0241     protected function _getFavoriteIds($clientId, $userId)
0242     {
0243         $ids = array();
0244 
0245         $favoriteOwners = $this->models->favorites->getFavoriteOwners(
0246             $clientId,
0247             $userId
0248         );
0249         if ($favoriteOwners) {
0250             $ids['ownerIds'] = array();
0251             foreach ($favoriteOwners as $favoriteOwner) {
0252                 $ids['ownerIds'][] = $favoriteOwner->owner_id;
0253             }
0254         }
0255 
0256         $favoriteCollections = $this->models->favorites->getFavoriteCollections(
0257             $clientId,
0258             $userId
0259         );
0260         if ($favoriteCollections) {
0261             $ids['collectionIds'] = array();
0262             foreach ($favoriteCollections as $favoriteCollection) {
0263                 $ids['collectionIds'][] = $favoriteCollection->collection_id;
0264             }
0265         }
0266 
0267         $favoriteFiles = $this->models->favorites->getFavoriteFiles(
0268             $clientId,
0269             $userId
0270         );
0271         if ($favoriteFiles) {
0272             $ids['fileIds'] = array();
0273             foreach ($favoriteFiles as $favoriteFile) {
0274                 $ids['fileIds'][] = $favoriteFile->file_id;
0275             }
0276         }
0277 
0278         return $ids;
0279     }
0280 
0281     protected function _generateArchive($source, $archive)
0282     {
0283         exec('tar'
0284             . ' -czf "' . $archive . '"'
0285             . ' "' . $source . '"'
0286         );
0287     }
0288 
0289     protected function _generateZsync($source, $zsync, $uri)
0290     {
0291         exec('zsyncmake'
0292             . ' -u "' . $uri . '"'
0293             . ' -o "' . $zsync . '"'
0294             . ' "' . $source . '"'
0295         );
0296     }
0297 
0298     protected function _detectLinkInTags($tagsString)
0299     {
0300         $link = '';
0301         $tags = explode(',', $tagsString);
0302         foreach ($tags as $tag) {
0303             $tag = trim($tag);
0304             if (strpos($tag, 'link##') === 0) {
0305                 $link = urldecode(str_replace('link##', '', $tag));
0306                 break;
0307             }
0308         }
0309         return $link;
0310     }
0311 
0312     protected function _detectMimeTypeFromUri($uri)
0313     {
0314         $mimeTypes = array(
0315           'txt'  => 'text/plain',
0316           'htm'  => 'text/html',
0317           'html' => 'text/html',
0318           'php'  => 'text/html',
0319           'css'  => 'text/css',
0320           'js'   => 'application/javascript',
0321           'json' => 'application/json',
0322           'xml'  => 'application/xml',
0323           'swf'  => 'application/x-shockwave-flash',
0324           // images
0325           'png'  => 'image/png',
0326           'jpe'  => 'image/jpeg',
0327           'jpeg' => 'image/jpeg',
0328           'jpg'  => 'image/jpeg',
0329           'gif'  => 'image/gif',
0330           'bmp'  => 'image/bmp',
0331           'ico'  => 'image/vnd.microsoft.icon',
0332           'tiff' => 'image/tiff',
0333           'tif'  => 'image/tiff',
0334           'svg'  => 'image/svg+xml',
0335           'svgz' => 'image/svg+xml',
0336           // archives
0337           'tar'  => 'application/x-tar',
0338           'tgz'  => 'application/tar+gzip',
0339           'gz'   => 'application/x-gzip',
0340           'bz2'   => 'application/x-bzip2',
0341           'xz'   => 'application/x-xz',
0342           'zip'  => 'application/zip',
0343           '7z'   => 'application/x-7z-compressed',
0344           'rar'  => 'application/x-rar-compressed',
0345           'exe'  => 'application/x-msdownload',
0346           'msi'  => 'application/x-msdownload',
0347           'cab'  => 'application/vnd.ms-cab-compressed',
0348           // audio/video
0349           'aac'  => 'audio/aac',
0350           'm4a'  => 'audio/mp4',
0351           'mp3'  => 'audio/mpeg',
0352           'qt'   => 'video/quicktime',
0353           'mov'  => 'video/quicktime',
0354           'mp4'  => 'video/mp4',
0355           'm4v'  => 'video/mp4',
0356           'ogv'  => 'video/ogg',
0357           'flv'  => 'video/x-flv',
0358           // adobe
0359           'pdf'  => 'application/pdf',
0360           'psd'  => 'image/vnd.adobe.photoshop',
0361           'ai'   => 'application/postscript',
0362           'eps'  => 'application/postscript',
0363           'ps'   => 'application/postscript',
0364           // ms office
0365           'doc'  => 'application/msword',
0366           'rtf'  => 'application/rtf',
0367           'xls'  => 'application/vnd.ms-excel',
0368           'ppt'  => 'application/vnd.ms-powerpoint',
0369           // open office
0370           'odt'  => 'application/vnd.oasis.opendocument.text',
0371           'ods'  => 'application/vnd.oasis.opendocument.spreadsheet'
0372         );
0373 
0374         $uriParts = explode('.', $uri);
0375         $ext = strtolower(array_pop($uriParts));
0376 
0377         if (array_key_exists($ext, $mimeTypes)) {
0378             return $mimeTypes[$ext];
0379         }
0380         else {
0381             $ch = curl_init($uri);
0382             curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
0383             curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
0384             curl_setopt($ch, CURLOPT_HEADER, 1);
0385             curl_setopt($ch, CURLOPT_NOBODY, 1);
0386             curl_exec($ch);
0387             return curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
0388         }
0389     }
0390 
0391     protected function _detectFilesizeFromUri($uri)
0392     {
0393         static $regex = '/^Content-Length: *+\K\d++$/im';
0394         if (!$fp = @fopen($uri, 'rb')) {
0395             return false;
0396         }
0397         if (isset($http_response_header)
0398             && preg_match($regex, implode("\n", $http_response_header), $matches)
0399         ) {
0400             return (int)$matches[0] > 0 ? (int)$matches[0] : 1;
0401         }
0402         return strlen(stream_get_contents($fp));
0403     }
0404 
0405     protected function getRemoteFileInfo($url) {
0406         $ch = curl_init($url);
0407         curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
0408         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
0409         curl_setopt($ch, CURLOPT_HEADER, TRUE);
0410         curl_setopt($ch, CURLOPT_NOBODY, TRUE);
0411         $data = curl_exec($ch);
0412         $fileSize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
0413         $fileType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
0414         $httpResponseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
0415         curl_close($ch);
0416 
0417         return [
0418             'fileExists' => (int)$httpResponseCode == 200,
0419             'fileSize'   => (int)$fileSize,
0420             'fileType'   => $fileType,
0421         ];
0422     }
0423 
0424     protected function getHost()
0425     {
0426         $host = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null);
0427         $host = isset($host) ? $host : $_SERVER['SERVER_NAME'];
0428 
0429         return mb_strimwidth($host,0,255);
0430     }
0431 
0432     protected function getScheme()
0433     {
0434         $scheme = isset($_SERVER['HTTP_X_FORWARDED_PROTO']) ? $_SERVER['HTTP_X_FORWARDED_PROTO'] : null;
0435         $scheme = isset($scheme) ? $scheme : (isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : null);
0436         $scheme = isset($scheme) ? $scheme : (isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : null);
0437         $scheme = isset($scheme) ? $scheme : (isset($_SERVER['SERVER_PORT']) AND $_SERVER['SERVER_PORT'] == '443' ? 'https' : 'http');
0438 
0439         return mb_strimwidth($scheme,0,5);
0440     }
0441 
0442     protected function getIpAddress() {
0443         $ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']) : $_SERVER['REMOTE_ADDR'];
0444 
0445         if (is_array($ip)) {
0446             return mb_strimwidth($ip[0],0,39);
0447         }
0448 
0449         if (false === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
0450             return null;
0451         }
0452         return mb_strimwidth($ip,0,39);
0453     }
0454 
0455     protected function getRequestId() {
0456         $request_id = $_SERVER['UNIQUE_ID'] ?? ($_SERVER['HTTP_X_REQUEST_ID'] ?? null);
0457 
0458         return mb_strimwidth($request_id, 0, 25);
0459     }
0460 
0461     protected function logWithRequestId($message, $priority = null) {
0462         return $this->log->log($message . "; request id: {$this->getRequestId()}", $priority);
0463     }
0464 
0465     protected function _generateWaveForm($src, $target)
0466     {
0467         $output = array();
0468         $code = 0;
0469         $this->log->log(__METHOD__ . ' :: system(\'' . '/usr/local/bin/audiowaveform -i "' . $src . '" -o "' . $target . '" --pixels-per-second 20 --bits 8\')');
0470         $output = system('/bin/bash -c \'/usr/local/bin/audiowaveform -i "' . $src . '" -o "' . $target . '" --pixels-per-second 20 --bits 8 2>&1\'', $code);
0471         $this->log->log(__METHOD__ . ' :: ' . $output . '(' . $code . ')');
0472 
0473         return $code;
0474     }
0475 }