Example #1
0
 /**
  * @internal
  *
  * @todo get rid of registerClass
  */
 public function __construct()
 {
     parent::__construct();
     self::$defaultConfig['compile_dir'] = Application::$FILE_ROOT . 'tmp/smarty_compile';
     self::$defaultConfig['cache_dir'] = Application::$FILE_ROOT . 'tmp/smarty_cache';
     $config = Config::get('smarty', self::$defaultConfig);
     $this->setTemplateDir(dirname(dirname(__DIR__)) . '/template/html');
     $this->addTemplateDir(dirname(Application::$WEB_ROOT) . '/template');
     $this->addPluginsDir(__DIR__ . '/smarty_plugins/');
     $this->error_reporting = E_ALL & ~E_NOTICE;
     $this->_file_perms = $config['file_perms'];
     $this->_dir_perms = $config['dir_perms'];
     // cache dir
     FileUtil::makedir($config['cache_dir'], $config['dir_perms']);
     $this->setCacheDir($config['cache_dir']);
     // compile dir
     FileUtil::makedir($config['compile_dir'], $config['dir_perms']);
     $this->setCompileDir($config['compile_dir']);
     // add classes for usage in templates
     $this->registerClass('Session', 'FeM\\sPof\\Session');
     $this->registerClass('Group', 'FeM\\sPof\\model\\Group');
     $this->registerClass('DBConnection', 'FeM\\sPof\\model\\DBConnection');
     $this->registerClass('SessionRegister', 'FeM\\sPof\\model\\SessionRegister');
     $this->registerClass('Config', 'FeM\\sPof\\Config');
     $this->registerClass('Authorization', 'FeM\\sPof\\Authorization');
     $this->registerClass('Auth', 'FeM\\sPof\\Authorization');
 }
Example #2
0
 /**
  * Download a file.
  *
  * @internal
  */
 public function download()
 {
     // get and check sid
     if (empty($this->sid) || strlen($this->sid) > 32) {
         self::sendNotFound();
     }
     $db = DBConnection::getInstance();
     $db->beginTransaction();
     // get file details
     $stmt = $db->prepare("\n            SELECT\n                id,\n                content_oid,\n                mimetype,\n                size,\n                name,\n                to_char(modify,'Dy, DD Mon YYYY HH24:MI:SS TZ') AS modify\n            FROM tbl_file\n            WHERE\n                sid=:sid\n                AND visible IS TRUE\n                AND disabled IS FALSE\n            ");
     $stmt->bindParam('sid', $this->sid, \PDO::PARAM_INT);
     $stmt->execute();
     if ($stmt->rowCount() == 0) {
         self::sendNotFound();
     }
     $file = $stmt->fetch(\PDO::FETCH_ASSOC);
     // set path to unprocessed cache file
     $path_cachefile = sprintf(Application::$CACHE_ROOT . 'files/%s/%s.file', $this->sid[0], $this->sid);
     // load file from database if cache file doesn't exist
     $handle = false;
     if (file_exists($path_cachefile) === false) {
         // open db handle if no cached file available
         $handle = $db->pgsqlLOBOpen($file['content_oid'], 'r');
         if (feof($handle)) {
             self::sendNotFound();
         }
         // try to create cache
         if (!FileUtil::makedir(dirname($path_cachefile))) {
             error_log('cache' . $path_cachefile . ' not writeable');
         } else {
             // create cache file
             $fcache = fopen($path_cachefile, 'w');
             stream_copy_to_stream($handle, $fcache);
             fclose($fcache);
             // close db handle
             fclose($handle);
             $handle = false;
         }
     }
     // check wether path_sendfile is set explicitly
     if (!empty($this->path_sendfile)) {
         // update stat data if exists
         if (is_readable($this->path_sendfile)) {
             $stat = stat($this->path_sendfile);
             $file['modify'] = $stat['mtime'];
             $file['size'] = $stat['size'];
         } elseif (isset($this->processing) && method_exists($this, 'processCachefile')) {
             // check for processing
             $file['cachefile'] = $path_cachefile;
             $this->processCachefile($file);
         } else {
             self::sendNotFound();
         }
     } else {
         $this->path_sendfile = $path_cachefile;
     }
     if (!is_readable($this->path_sendfile) && !is_resource($handle)) {
         self::sendNotFound();
     }
     // check wether stats_disable is set
     if ($this->stats_disable === false) {
         // insert statistics
         $stmt = $db->prepare("\n                    INSERT INTO tbl_statistic_file (user_id, ip, file_id)\n                    VALUES (:user_id, :ip, :file_id)\n                ");
         if (is_null(Session::getUserId())) {
             $stmt->bindValue('user_id', null, \PDO::PARAM_NULL);
         } else {
             $stmt->bindValue('user_id', Session::getUserId(), \PDO::PARAM_INT);
         }
         $stmt->bindValue('ip', Request::getIp(), \PDO::PARAM_STR);
         $stmt->bindValue('file_id', $file['id'], \PDO::PARAM_INT);
         $stmt->execute();
     }
     $db->commit();
     // there is nothing to write, tell the session it is no longer needed (and thus no longer blocking output
     // flushing)
     session_write_close();
     // check if http_range is sent by browser
     if (isset($_SERVER['HTTP_RANGE'])) {
         $unit = explode('=', $_SERVER['HTTP_RANGE'])[0];
         if ($unit == 'bytes') {
             $range_list = explode('=', $_SERVER['HTTP_RANGE'], 2)[1];
             // multiple ranges could be specified at the same time, but for simplicity only serve the first range
             // http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
             $ranges = explode(',', $range_list);
             foreach ($ranges as $range) {
                 $seek_start = explode('-', $range)[0];
                 $seek_end = explode('-', $range)[1];
                 // set valid and in range for seek end
                 if (empty($seek_end)) {
                     $seek_end = $file['size'] - 1;
                 } else {
                     $seek_end = min(abs($seek_end), $file['size'] - 1);
                 }
                 // set valid and in range for seek start
                 if (empty($seek_start) || $seek_end < abs($seek_start)) {
                     $seek_start = 0;
                 } else {
                     $seek_start = max(abs($seek_start), 0);
                 }
                 if (!is_resource($handle)) {
                     $handle = fopen($path_cachefile, 'rb');
                 }
                 // seek to start of missing part
                 if (($seek_start > 0 || $seek_end < $file['size'] - 1) && fseek($handle, $seek_start) !== -1) {
                     $length = $seek_end - $seek_start + 1;
                     header('HTTP/1.1 206 Partial Content');
                     header('Accept-Ranges: bytes');
                     header('Content-Range: bytes ' . $seek_start . '-' . $seek_end . '/' . $file['size']);
                     header('Content-Type: ' . $file['mimetype']);
                     header('Content-Disposition: attachment; filename="' . $file['name'] . '"');
                     header('Content-Length: ' . $length);
                     // start buffered download of 8 KB chunks while the connection is alive
                     $transfered = 0;
                     while (!feof($handle) && connection_status() == CONNECTION_NORMAL && $transfered < $length) {
                         // reset time limit for big files
                         set_time_limit(0);
                         // @codingStandardsIgnoreStart
                         echo fread($handle, 8192);
                         // @codingStandardsIgnoreEnd
                         $transfered += 8192;
                         flush();
                         ob_flush();
                     }
                     // while
                     fclose($handle);
                     exit;
                 }
                 // if fseek
             }
             // foreach ranges
         }
         // if unit bytes
     }
     // if http_range
     // prepare headers
     header('Last-Modified: ' . $file['modify']);
     header('Accept-Ranges: bytes');
     header('Content-Type: ' . $file['mimetype']);
     header('Content-Length: ' . $file['size']);
     header('Content-Transfer-Encoding: binary');
     session_cache_limiter(false);
     if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= strtotime($file['modify'])) {
         header('HTTP/1.0 304 Not Modified');
         exit;
     }
     if (is_resource($handle)) {
         // write to output buffer in small chunks to bypass memory limit of large files (which fpassthru would
         // exceed)
         while (!feof($handle) && connection_status() == CONNECTION_NORMAL) {
             // reset time limit for big files
             set_time_limit(0);
             // @codingStandardsIgnoreStart
             echo fread($handle, 8192);
             // @codingStandardsIgnoreEnd
             flush();
             ob_flush();
         }
         // while
         fclose($handle);
     } elseif (Config::get('use_sendfile') && in_array('mod_xsendfile', apache_get_modules())) {
         header('X-Sendfile: ' . $this->path_sendfile);
     } else {
         readfile($this->path_sendfile);
         exit;
     }
 }
Example #3
0
 /**
  * Generating thumbnail from cached file of matching sid
  *
  * If global variable $path_sendfile is set and variable $processing is true
  * download.php will call this function with a file info array with metadata.
  *
  * Afterwards download.php checks existance and updates metadata of file at $path_sendfile.
  *
  * @api
  *
  * @param array   $file database entry and cachefile path of file matching the sid
  */
 protected function processCachefile($file)
 {
     if (isset($file['mimetype']) && ($file['mimetype'] !== 'image/jpeg' && $file['mimetype'] !== 'image/png')) {
         self::sendInternalError();
     }
     if (!FileUtil::makedir(dirname($this->path_sendfile))) {
         self::sendInternalError();
     }
     if (!ImageUtil::resize($file['cachefile'], $this->path_sendfile, $this->width, $this->height, $this->cropimage)) {
         self::sendInternalError();
     }
 }
Example #4
0
 /**
  * This function generates a new .js file from the existing files (if anything new happen to them or does not
  * exist). The name of the new file will be returned.
  *
  * @api
  *
  * @param array $files
  *
  * @return string|false false on error or nothing
  */
 public static function combine(array $files)
 {
     if (empty($files)) {
         return false;
     }
     $target = self::getTargetPath();
     $source = self::getSourcePath();
     // identify file combinations by hash
     $jsHash = md5(serialize($files));
     $targetfile = $target . $jsHash . '.js';
     // check if any source file was modified
     $needUpdate = false;
     if (file_exists($targetfile)) {
         $hashtime = filemtime($targetfile);
         foreach ($files as $file) {
             if (substr($file['name'], 0, 1) === '/') {
                 $filename = $file['name'];
             } elseif ($file['relative']) {
                 // relative to public/js
                 $filename = $target . $file['name'] . '.js';
             } else {
                 // use javascript folder
                 $filename = $source . $file['name'] . '.js.tpl';
             }
             if ($hashtime < filemtime($filename)) {
                 $needUpdate = true;
                 break;
             }
         }
     } else {
         // file does not exist, so we need an update anyway
         $needUpdate = true;
     }
     // we can abort if no update is required
     if ($needUpdate === false) {
         return $jsHash;
     }
     // make sure, that the target directory exists
     if (!is_dir($target)) {
         FileUtil::makedir($target);
     }
     // combine file contents
     $content = '';
     foreach ($files as $file) {
         try {
             if (substr($file['name'], 0, 1) === '/') {
                 if (strpos($file['name'], '.tpl') > 0) {
                     $nextcontent = JavascriptTemplate::getInstance()->fetch($file['name']);
                 } else {
                     $nextcontent = file_get_contents($file['name']);
                 }
             } elseif ($file['relative']) {
                 $nextcontent = file_get_contents($target . $file['name'] . '.js');
             } else {
                 $nextcontent = JavascriptTemplate::getInstance()->fetch($source . $file['name'] . '.js.tpl');
             }
             // do not double minify
             if (strpos($file['name'], '.min') > 0 || strpos($file['name'], '.pack') > 0 || !method_exists('\\JShrink\\Minifier', 'minify')) {
                 $content .= $nextcontent . "\n";
             } else {
                 $content .= \JShrink\Minifier::minify($nextcontent) . "\n";
             }
         } catch (\ErrorException $exception) {
             Logger::getInstance()->exception($exception);
         }
     }
     // foreach file
     // write minified version
     $success = file_put_contents($targetfile, $content);
     // adjust file permissions for webserver
     if ($success) {
         chmod($targetfile, Config::getDetail('smarty', 'file_perms', self::$defaultConfig));
     }
     // foreach scssFiles
     return $jsHash;
 }
Example #5
0
 /**
  * This function generates new .css files from the .scss files in the stylesheet folder under the condition, that
  * the .scss files are newer or possible dependencies are updated. Files that begin with underscore (_) are not
  * transformed and are only used for defining parts of rules.
  *
  * @api
  */
 public static function update()
 {
     $sourcePath = self::getSourcePath();
     $targetPath = self::getTargetPath();
     if (!is_dir($targetPath)) {
         FileUtil::makedir($targetPath);
     }
     // check if source has changed
     $updated = Cache::fetch('style.update');
     if ($updated !== false && $updated > filemtime($sourcePath)) {
         // check all files in the source folder for modifications
         if (Config::getDetail('stylesheet', 'check_file_level', self::$defaultConfig)) {
             $needUpdate = false;
             $dir = new \DirectoryIterator($sourcePath);
             foreach ($dir as $file) {
                 /** @var \DirectoryIterator $file */
                 $filename = $file->getFilename();
                 // ignore dirs
                 if ($file->isDot() || $file->isDir() || strpos($filename, '.#') === 0) {
                     continue;
                 }
                 if ($updated < filemtime($sourcePath . $filename)) {
                     $needUpdate = true;
                     break;
                 }
             }
             // foreach dir
             if (!$needUpdate) {
                 return;
             }
         } else {
             return;
         }
     }
     $dir = new \DirectoryIterator($sourcePath);
     // remember last update (begin with this file as dependency)
     $lastDependencyUpdate = filemtime(__FILE__);
     // list of files to generate
     $scssFiles = [];
     // first step: generate list of files and get last updated dependency file
     foreach ($dir as $file) {
         /** @var \DirectoryIterator $file */
         $filename = $file->getFilename();
         // ignore dirs
         if ($file->isDot() || $file->isDir() || strpos($filename, '.#') === 0) {
             continue;
         }
         if (strpos($filename, '_') === 0) {
             $lastDependencyUpdate = max($lastDependencyUpdate, filemtime($sourcePath . $filename));
         } else {
             $scssFiles[] = $filename;
         }
     }
     // foreach dir
     foreach ($scssFiles as $filename) {
         // does target exist? does it have an older timestamp?
         $savefile = $targetPath . str_replace('.scss', '.css', $filename);
         if (file_exists($savefile)) {
             $modified = filemtime($savefile);
             if (filemtime($sourcePath . $filename) <= $modified && $lastDependencyUpdate <= $modified) {
                 continue;
             }
         }
         // save and set file permissions
         /*require_once "vendor/leafo/scssphp/scss.inc.php";
                     $scss = new \scssc();
                     $scss->addImportPath(function ($path) {
                         if (!file_exists('stylesheet/'.$path)) {
                             return null;
                         }
                         return 'stylesheet/'.$path;
                     });
         */
         try {
             // will import `stylesheets/vanilla.css'
             //              file_put_contents($savefile, $scss->compile('@import "'.$filename.'"'));
             file_put_contents($savefile, self::getParser()->toCss(file_get_contents($sourcePath . $filename), false));
             chmod($savefile, Config::getDetail('stylesheet', 'file_perms', self::$defaultConfig));
         } catch (\Exception $exception) {
             Logger::getInstance()->exception($exception);
         }
     }
     // foreach scssFiles
     Cache::store('style.update', time());
 }