Skip to content
Snippets Groups Projects
Select Git revision
  • 74cde461f8dd1b0b83ea9e031822603e9c280b56
  • main default protected
  • step-3263
  • feature/plugins-cli
  • feature/vite
  • step-2484-peerreview
  • biest/issue-5051
  • tests/simplify-jsonapi-tests
  • fix/typo-in-1a70031
  • feature/broadcasting
  • database-seeders-and-factories
  • feature/peer-review-2
  • feature-feedback-jsonapi
  • feature/peerreview
  • feature/balloon-plus
  • feature/stock-images-unsplash
  • tic-2588
  • 5.0
  • 5.2
  • biest/unlock-blocks
  • biest-1514
21 results

functions.php

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    FileRef.php 22.52 KiB
    <?php
    /**
     * FileRef.php
     * model class for table file_refs
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License as
     * published by the Free Software Foundation; either version 2 of
     * the License, or (at your option) any later version.
     *
     * @author      André Noack <noack@data-quest.de>
     * @copyright   2016 Stud.IP Core-Group
     * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
     * @category    Stud.IP
     *
     *
     * @property string id database column
     * @property string file_id database column
     * @property string folder_id database column
     * @property string user_id database column
     * @property string name database column
     * @property string downloads database column
     * @property string description database column
     * @property string license database column
     * @property string content_terms_of_use_id database column
     * @property string mkdate database column
     * @property string chdate database column
     * @property SimpleORMap file belongs_to File
     * @property SimpleORMap folder belongs_to Folder
     * @property SimpleORMap owner belongs_to User
     * @property SimpleORMap terms_of_use belongs_to ContentTermsOfUse
     */
    class FileRef extends SimpleORMap implements PrivacyObject, FeedbackRange
    {
        protected static function configure($config = [])
        {
            $config['db_table'] = 'file_refs';
    
            $config['belongs_to']['file'] = [
                'class_name'  => File::class,
                'foreign_key' => 'file_id',
            ];
            $config['belongs_to']['folder'] = [
                'class_name'  => Folder::class,
                'foreign_key' => 'folder_id',
            ];
            $config['belongs_to']['owner'] = [
                'class_name'  => User::class,
                'foreign_key' => 'user_id',
            ];
    
            $config['belongs_to']['terms_of_use'] = [
                'class_name' => ContentTermsOfUse::class,
                'foreign_key' => 'content_terms_of_use_id',
                'assoc_func' => 'findOrBuild'
            ];
    
            $config['additional_fields']['size'] = ['file', 'size'];
            $config['additional_fields']['mime_type'] = ['file', 'mime_type'];
            $config['additional_fields']['download_url']['set'] = 'setDownloadURL';
            $config['additional_fields']['download_url']['get'] = 'getDownloadURL';
            $config['additional_fields']['author_name']['get'] = 'getAuthorName';
            $config['additional_fields']['is_link']['get'] = 'isLink';
            $config['additional_fields']['foldertype']['set'] = 'setFolderType';
            $config['additional_fields']['foldertype']['get'] = 'getFolderType';
    
            $config['registered_callbacks']['after_delete'][] = 'cbRemoveFileIfOrphaned';
            $config['registered_callbacks']['after_delete'][] = 'cbRemoveFeedbackElements';
            $config['registered_callbacks']['before_store'][] = 'cbMakeUniqueFilename';
    
            parent::configure($config);
        }
    
        protected $folder_type;
        protected $download_url;
        public $path_to_blob;
    
        /**
         * This callback is called after deleting a FileRef.
         * It removes the File object that is associated with the FileRef,
         * if the File is not referenced by any other FileRef object.
         */
        public function cbRemoveFileIfOrphaned()
        {
            if (!self::countBySql('file_id = ?', [$this->file_id])) {
                File::deleteBySQL("id = ?", [$this->file_id]);
            }
        }
    
        /**
         * This callback is called after deleting a FileRef.
         * It removes feedback elements that are associated with the FileRef.
         */
        public function cbRemoveFeedbackElements()
        {
            FeedbackElement::deleteBySQL("range_id = ? AND range_type = 'FileRef'", [$this->id]);
        }
    
        /**
         * This callback is called before storing a FileRef object.
         * In case the name field is changed this callback assures that the
         * name of the FileRef is unique inside the folder where
         * the FileRef is placed.
         */
        public function cbMakeUniqueFilename()
        {
            if (isset($this->folder) && $this->isFieldDirty('name')) {
                $this->name = $this->folder->getUniqueName($this->name);
            }
            if ($this->isFieldDirty('folder_id')) {
                //We have moved the file ref. $this->folder may not work directly
                //so we have to load the folder manually:
                $folder = Folder::find($this->folder_id);
                if ($folder) {
                    $this->name = $folder->getUniqueName($this->name);
                }
            }
        }
    
        /**
         * Overrides the usual download url that this file_ref would get by the system (sendfile.php...)
         * Use this method by cloud plugins.
         * If you set download URL to null, the normal sendfile.php will be set as default download URL.
         * @param $url : string as URL or null to set URL to sendfile.php-URL
         */
        public function setDownloadURL($field, $url) {
            $this->download_url = $url;
        }
    
        /**
         * Returns the download-URL for the FileRef.
         *
         * @param string $dltype The download type: 'normal', 'zip', 'force' or 'force_download'.
         *
         * @return string The URL for the FileRef.
         */
        public function getDownloadURL($dltype = 'normal')
        {
            if ($this->download_url) {
                return $this->download_url;
            }
            $mode = Config::get()->SENDFILE_LINK_MODE ?: 'normal';
            $link = [];
            $params = [];
            $type = '0';
            $file_name = $this->file->name ?: $this->name;
            $file_id = $this->id;
    
            switch($mode) {
                case 'rewrite':
                    $link[] = 'download/';
                    switch ($dltype) {
                        case 'zip':
                            $link[] = 'zip/';
                            break;
                        case 'force':
                        case 'force_download':
                            $link[] = 'force_download/';
                            break;
                        default:
                            $link[] = 'normal/';
                    }
                    $link[] = $type . '/' . $file_id . '/' . $file_name;
                    break;
                default:
                    $link[] = 'sendfile.php';
                    if ($dltype == 'zip') {
                        $params['zip'] = 1;
                    } elseif (in_array($dltype,  ['force_download', 'force'])) {
                        $params['force_download'] = 1;
                    }
                    $params['type'] = $type;
                    $params['file_id'] = $file_id;
                    $params['file_name'] = $file_name;
            }
            return URLHelper::getScriptURL(implode('', $link), $params);
        }
    
        /**
         * Returns the name of the FileRef's author.
         *
         * @return string The name of the FileRef's author.
         */
        public function getAuthorName()
        {
            if (isset($this->owner)) {
                return $this->owner->getFullName('no_title_rev');
            }
            return $this->file->author_name;
        }
    
        /**
         * This method increments the download counter of the FileRef.
         *
         * @return int The number of rows of the file_refs table that have been altered.
         */
        public function incrementDownloadCounter()
        {
            $this->downloads += 1;
            if (!$this->isNew()) {
                $where_query = join(' AND ' , $this->getWhereQuery());
                $query = "UPDATE `{$this->db_table}`
                          SET `downloads` = `downloads` + 1
                          WHERE {$where_query}";
                return DBManager::get()->exec($query);
            }
    
            return 0;
        }
    
        /**
         * Returns the license object for this file.
         *
         * @return Object (to be specified!)
         */
        public function getLicenseObject()
        {
            if (class_exists($this->license)) {
                return new $this->license();
            }
            throw new UnexpectedValueException("class: {$this->license} not found");
        }
    
        /**
         * Determines whether this FileRef is a link or not.
         * @deprecated
         * @return bool True, if the FileRef references a link, false otherwise.
         */
        public function isLink()
        {
            return false;
        }
    
        public function setFolderType($field, FolderType $folder_type)
        {
            $this->folder_type = $folder_type;
        }
    
        public function getFolderType()
        {
            if ($this->folder_type) {
                return $this->folder_type;
            } elseif($this->folder) {
                return $this->folder->getTypedFolder();
            }
        }
    
        /**
         * Determines if the FileRef references an image file.
         *
         * @return bool True, if the referenced file is an image file, false otherwise.
         */
        public function isImage()
        {
            return mb_strpos($this->mime_type, 'image/') === 0;
        }
    
        /**
         * Determines if the FileRef references an audio file.
         *
         * @return bool True, if the referenced file is an audio file, false otherwise.
         */
        public function isAudio()
        {
            return mb_strpos($this->mime_type, 'audio/') === 0;
        }
    
    
        /**
         * Determines if the FileRef references a video file.
         *
         * @return bool True, if the referenced file is a video file, false otherwise.
         */
        public function isVideo()
        {
            return mb_strpos($this->mime_type, 'video/') === 0;
        }
    
        /**
         * Export available data of a given user into a storage object
         * (an instance of the StoredUserData class) for that user.
         *
         * @param StoredUserData $storage object to store data into
         */
        public static function exportUserData(StoredUserData $storage)
        {
            $sorm = self::findBySQL("user_id = ?", [$storage->user_id]);
            if ($sorm) {
                $field_data = [];
                foreach ($sorm as $row) {
                    $field_data[] = $row->toRawArray();
                }
                if ($field_data) {
                    $storage->addTabularData(_('Dateien'), 'file_refs', $field_data);
                }
            }
        }
    
        /**
         * @returns FileType
         */
        public function getFileType()
        {
            $filetype = $this->file->filetype;
            if (class_exists($filetype) && is_subclass_of($filetype, 'FileType')) {
                return new $filetype($this);
            } else {
                return new UnknownFileType($this);
            }
        }
    
        public function getRangeName()
        {
            return $this->name;
        }
    
        public function getRangeIcon($role)
        {
            return FileManager::getIconForFileRef($this, $role);
        }
    
        public function getRangeUrl()
        {
            return 'course/files/index/' . $this->foldertype->getId();
        }
    
        public function getRangeCourseId()
        {
            return $this->foldertype->range_id;
        }
    
        public function isRangeAccessible(string $user_id = null): bool
        {
            $user_id = $user_id ?? $GLOBALS['user']->id;
    
            return $this->foldertype->isFileDownloadable($this->id, $user_id);
        }
    
    
        /**
         * This is a helper method to generate the SQL query for the
         * findAll and countAll methods. Relevant FileRef objects for these methods
         * can be limited by a time range and a specific course. The amount
         * and the offset of the FileRef objects to be retrieved can also be set.
         *
         * @param string $user_id The ID of the user that is used to count or
         *     retrieve FileRef objects.
         *
         * @param DateTime|null $begin The begin of the time range.
         *
         * @param DateTime|null $end The end of the time range.
         *
         * @param string $course_id The ID of the course from which FileRef objects
         *     shall be retrieved.
         *
         * @param int $file_limit The maximum amount of FileRef objects to be
         *     retrieved.
         *
         * @param int $file_offset The offset in the FileRef data from which to
         *     start retrieving objects.
         *
         * @returns mixed[] An array with two indexes:
         *     - sql: The SQL query string.
         *     - params: An array with SQL query parameters.
         */
        protected static function getAllSql($user_id, $begin = null, $end = null, $course_id = '', $file_limit = 0, $file_offset = 0)
        {
            $sql = '';
            $sql_params = [];
            if ($course_id) {
                //Limit the result for a specific course.
                $sql = 'INNER JOIN `folders`
                    ON `file_refs`.`folder_id` = `folders`.`id`
                    WHERE `folders`.`range_id` =  :course_id ';
                $sql_params['course_id'] = $course_id;
                if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
                    $sql .= 'AND `file_refs`.`chdate` BETWEEN :begin AND :end ';
                    $sql_params['begin'] = $begin->getTimestamp();
                    $sql_params['end'] = $end->getTimestamp();
                }
            } else {
                if ($GLOBALS['perm']->have_perm('root', $user_id)) {
                    //This is easy: Get all recent files ordered by chdate.
                    if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
                        $sql = 'chdate BETWEEN :begin AND :end ';
                        $sql_params['begin'] = $begin->getTimestamp();
                        $sql_params['end'] = $end->getTimestamp();
                    } else {
                        $sql = 'TRUE ';
                    }
                } else {
                    //Get the folders (all folders) of the user first and then
                    //check for new files. This means getting all folders of courses
                    //and institutes where the user has access to.
    
                    $range_ids = FileManager::getRangeIdsForFolders($user_id, true);
    
                    //Now get all file refs:
                    $sql = 'INNER JOIN `folders`
                        ON `file_refs`.`folder_id` = `folders`.`id`
                        WHERE `folders`.`range_id` IN ( :range_ids ) ';
                    $sql_params['range_ids'] = $range_ids;
    
                    if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
                        $sql .= 'AND `file_refs`.`chdate` BETWEEN :begin AND :end ';
                        $sql_params['begin'] = $begin->getTimestamp();
                        $sql_params['end'] = $end->getTimestamp();
                    }
                }
            }
            $sql .= ' ORDER BY `file_refs`.`chdate` DESC, `file_refs`.`mkdate` DESC, `file_refs`.`name` ASC';
            if ($file_limit > 0) {
                $sql .= ' LIMIT :limit';
                $sql_params['limit'] = $file_limit;
                if ($file_offset > 0) {
                    $sql .= ' OFFSET :offset';
                    $sql_params['offset'] = $file_offset;
                }
            }
            return ['sql' => $sql, 'params' => $sql_params];
        }
    
    
        /**
         * This method retrieves the FileRef objects a user has access to.
         *
         * @see FileRef::getAllSql for the parameter description.
         *
         * @returns FileRef[] A list of FileRef objects.
         */
        public static function findAll($user_id, $begin = null, $end = null, $course_id = null, $file_limit = 0, $file_offset = 0)
        {
            $sql_data = self::getAllSql($user_id, $begin, $end, $course_id, $file_limit, $file_offset);
            return FileRef::findBySql($sql_data['sql'], $sql_data['params']);
        }
    
    
        /**
         * This method counts all the FileRef objects a user has access to.
         *
         * @see FileRef::getAllSql for the parameter description.
         *
         * @returns int The amount of found FileRef rows.
         */
        public static function countAll($user_id, $begin = null, $end = null, $course_id = null)
        {
            $sql_data = self::getAllSql($user_id, $begin, $end, $course_id);
            return FileRef::countBySql($sql_data['sql'], $sql_data['params']);
        }
    
    
        /**
         * This is a helper method to generate the SQL query for the
         * findPublicFiles and countPublicFiles methods. Relevant FileRef objects
         * for these methods can be limited by a time range. The amount
         * and the offset of the FileRef objects to be retrieved can also be set.
         *
         * @param string $user_id The ID of the user that is used to count or
         *     retrieve FileRef objects in public folders.
         *
         * @param DateTime|null $begin The begin of the time range.
         *
         * @param DateTime|null $end The end of the time range.
         *
         * @param int $file_limit The maximum amount of FileRef objects to be
         *     retrieved from public folders.
         *
         * @param int $file_offset The offset in the FileRef data from which to
         *     start retrieving objects from public folders.
         *
         * @returns mixed[] An array with two indexes:
         *     - sql: The SQL query string.
         *     - params: An array with SQL query parameters.
         */
        protected static function getPublicFilesSql($user_id, $begin = null, $end = null, $file_limit = 0, $file_offset = 0)
        {
            $sql = "INNER JOIN `folders`
                ON `file_refs`.`folder_id` = `folders`.`id`
                WHERE `folders`.`folder_type` = 'PublicFolder'
                AND `folders`.`range_type` = 'user' ";
            $sql_params = [];
            if ($user_id) {
                $sql .= " AND `folders`.`user_id` = :user_id";
                $sql_params['user_id'] = $user_id;
            }
            if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
                $sql .= ' AND `file_refs`.`chdate` BETWEEN :begin AND :end';
                $sql_params['begin'] = $begin->getTimestamp();
                $sql_params['end'] = $end->getTimestamp();
            }
            $sql .= " ORDER BY `file_refs`.`chdate` DESC";
            if ($file_limit > 0) {
                $sql .= " LIMIT :file_limit";
                $sql_params['file_limit'] = $file_limit;
            }
            if ($file_offset > 0) {
                $sql .= " OFFSET :file_offset";
                $sql_params['file_offset'] = $file_offset;
            }
            return ['sql' => $sql, 'params' => $sql_params];
        }
    
    
        /**
         * This method retrieves the FileRef objects in public folders which
         * can be accessed by a user.
         *
         * @see FileRef::getPublicFilesSql for the parameter description.
         *
         * @returns FileRef[] A list of FileRef objects.
         */
        public static function findPublicFiles($user_id, $begin = null, $end = null, $file_limit = 0, $file_offset = 0)
        {
            $sql_data = self::getPublicFilesSql($user_id, $begin, $end, $file_limit, $file_offset);
            return self::findBySql($sql_data['sql'], $sql_data['params']);
        }
    
    
        /**
         * This method counts the FileRef objects in public folders which
         * can be accessed by a user.
         *
         * @see FileRef::getPublicFilesSql for the parameter description.
         *
         * @returns int The amount of found FileRef rows.
         */
        public static function countPublicFiles($user_id, $begin = null, $end = null)
        {
            $sql_data = self::getPublicFilesSql($user_id, $begin, $end);
            return self::countBySql($sql_data['sql'], $sql_data['params']);
        }
    
    
        /**
         * This is a helper method to generate the SQL query for the
         * findUploadedFiles and countUploadedFiles methods. Relevant FileRef
         * objects for these methods can be limited by a time range and a specified
         * course. Furthermore, it is possible to limit the search to FileRef
         * objects without a license set or with the "unknown" license set.
         * The amount and the offset of the FileRef objects to be retrieved can also
         * be set.
         *
         * @param string $user_id The ID of the user whose uploaded files shall be
         *     retrieved or counted.
         *
         * @param DateTime|null $begin The begin of the time range.
         *
         * @param DateTime|null $end The end of the time range.
         *
         * @param string $course_id The ID of the course from which FileRef objects
         *     shall be retrieved.
         *
         * @param bool $unknown_license_only Whether to only query for FileRef
         *     objects without a license or with the "unknown" license set
         *     (true) or to query all uploaded FileRef objects (false).
         *     Defaults to false.
         *
         * @param int $file_limit The maximum amount of FileRef objects to be
         *     retrieved from public folders.
         *
         * @param int $file_offset The offset in the FileRef data from which to
         *     start retrieving objects from public folders.
         *
         * @returns mixed[] An array with two indexes:
         *     - sql: The SQL query string.
         *     - params: An array with SQL query parameters.
         */
        protected static function getUploadedFilesSql($user_id, $begin = null, $end = null, $course_id = '', $unknown_license_only = false, $file_limit = 0, $file_offset = 0)
        {
            $sql = '';
            if ($course_id) {
                $sql = 'INNER JOIN `folders`
                    ON `file_refs`.`folder_id` = `folders`.`id`
                    WHERE ';
            }
            $sql .= "`file_refs`.`user_id` = :user_id";
            $sql_params = [
                'user_id' => $user_id
            ];
            if ($unknown_license_only) {
                $sql .= " AND (
                    `file_refs`.`content_terms_of_use_id` IN ('', 'UNDEF_LICENSE')
                    OR
                    `file_refs`.`content_terms_of_use_id` IS NULL
                )";
            }
    
            if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
                $active_sidebar_filters[] = 'course';
                $sql .= ' AND `file_refs`.`chdate` BETWEEN :begin AND :end ';
                $sql_params['begin'] = $begin->getTimestamp();
                $sql_params['end'] = $end->getTimestamp();
            }
            if ($course_id) {
                $sql .= ' AND `folders`.`range_id` = :course_id';
                $sql_params['course_id'] = $course_id;
            }
            $sql .= " ORDER BY `file_refs`.`chdate` DESC";
            if ($file_limit > 0) {
                $sql .= " LIMIT :file_limit";
                $sql_params['file_limit'] = $file_limit;
            }
            if ($file_offset > 0) {
                $sql .= " OFFSET :file_offset";
                $sql_params['file_offset'] = $file_offset;
            }
            return ['sql' => $sql, 'params' => $sql_params];
        }
    
    
        /**
         * Retrieves all uploaded files a user has uploaded.
         *
         * @see FileRef::getUploadedFilesSql for the parameter description.
         *
         * @returns FileRef[] A list of FileRef objects for files the user uploaded.
         */
        public static function findUploadedFiles($user_id, $begin = null, $end = null, $course_id = '', $unknown_license_only = false, $file_limit = 0, $file_offset = 0)
        {
            $sql_data = self::getUploadedFilesSql($user_id, $begin, $end, $course_id, $unknown_license_only, $file_limit, $file_offset);
            return self::findBySql($sql_data['sql'], $sql_data['params']);
        }
    
    
        /**
         * Counts all uploaded files a user has uploaded.
         *
         * @see FileRef::getUploadedFilesSql for the parameter description.
         *
         * @returns int The amount of files the user uploaded.
         */
        public static function countUploadedFiles($user_id, $begin = null, $end = null, $course_id = '', $unknown_license_only = false)
        {
            $sql_data = self::getUploadedFilesSql($user_id, $begin, $end, $course_id, $unknown_license_only);
            return self::countBySql($sql_data['sql'], $sql_data['params']);
        }
    }