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 }