/**
  * Securely downloads a file from the server.
  * All permission checks shall be made externally.
  * Files are downloaded from the application/media by default!
  *
  * @param   string  $fileName   Name of the file.
  * @param   string  $fileFolder Additional media subdirectory.
  * @return  bool
  */
 public static function downloadFile($fileName = '', $fileFolder = '')
 {
     if (Validate::validString($fileName) && Validate::validString($fileFolder)) {
         $fileFolder = empty($fileFolder) ? '' : $fileFolder . '/';
         if (file_exists(APP_MEDIA . $fileFolder . $fileName) && $fileName != '.' && $fileName != 'index.php' && !empty($fileName)) {
             $filePath = APP_MEDIA . $fileFolder . $fileName;
             $fileNameParts = explode('.', $fileName);
             // Determining the MIME type of the file.
             $fileInfoType = finfo_open(FILEINFO_MIME_TYPE);
             $fileMimeType = strtolower(finfo_file($fileInfoType, $filePath));
             // Determining the MIME encoding of the file.
             $fileInfoEncoding = finfo_open(FILEINFO_MIME_ENCODING);
             $fileMimeEncoding = finfo_file($fileInfoEncoding, $filePath);
             // Making sure the MIME type is valid.
             if (!isset(self::$downloadMimes[$fileMimeType])) {
                 // Log::logActivity('Invalid MIME type. File MIME type has to be valid. (' . $fileFolder . $fileName . ')', 'err', 'sys', __CLASS__, __METHOD__);
                 return false;
             } elseif (self::$downloadMimes[$fileMimeType] != end($fileNameParts)) {
                 // Log::logActivity('Invalid file extension. File extension has to correspond the MIME type. (' . $fileFolder . $fileName . ')', 'err', 'sys', __CLASS__, __METHOD__);
                 return false;
             }
             header('Content-Type: ' . $fileMimeType);
             header('Content-Transfer-Encoding: ' . $fileMimeEncoding);
             header('Content-Disposition: attachment; filename="' . $fileName . '"');
             header('Accept-Ranges: bytes');
             readfile($filePath);
             return true;
         } else {
             return false;
         }
     } else {
         // Log::logActivity('Invalid string provided. Expecting string or equivalent.', 'err', 'sys', __CLASS__, __METHOD__);
         return false;
     }
 }
 /**
  * Retrieves a user's browser and browser version.
  * A list of browsers is at the top of the class.
  *
  * @return  array   [browser, version]
  */
 public static function agentGetBrowser()
 {
     $agentBrowserEngine = '';
     $agentBrowserVersion = '';
     // Retrieving the Browser.
     foreach (self::$agentEngines as $agentEngine => $agentRealName) {
         if (preg_match('/' . $agentEngine . '/i', self::$agentString)) {
             $agentBrowserEngine = $agentEngine;
             self::$agentBrowser = $agentRealName;
         }
     }
     if ($agentBrowserEngine) {
         $bufferPos = strpos(self::$agentString, $agentBrowserEngine) + strlen($agentBrowserEngine) + 1;
         // Retrieving the Version.
         while ($bufferPos < strlen(self::$agentString)) {
             if (self::$agentString[$bufferPos] == '.' || Validate::validAlphanumeric(self::$agentString[$bufferPos])) {
                 $agentBrowserVersion .= self::$agentString[$bufferPos];
             } else {
                 break;
             }
             $bufferPos++;
         }
         self::$agentBrowserVersion = $agentBrowserVersion;
     } else {
         self::$agentBrowser = '';
         self::$agentBrowserVersion = '';
     }
     return array('browser' => self::$agentBrowser, 'version' => self::$agentBrowserVersion);
 }