Example #1
0
 private function _listS3Contents($path = null)
 {
     static $lastDirectory = null;
     static $lastListing = array();
     $directory = substr($path, 5);
     if ($lastDirectory != $directory) {
         if ($directory == '/') {
             $directory = null;
         } else {
             $directory = trim($directory, '/') . '/';
         }
         $s3 = AmazonS3::getInstance();
         $lastListing = $s3->getBucket('', $directory, null, null, '/', true);
     }
     return $lastListing;
 }
Example #2
0
 public function check()
 {
     $this->assertNotEmpty($this->title, 'COM_ARS_CATEGORY_ERR_NEEDS_TITLE');
     // If the alias is missing, auto-create a new one
     if (!$this->alias) {
         \JLoader::import('joomla.filter.input');
         $alias = str_replace(' ', '-', strtolower($this->title));
         $this->alias = (string) preg_replace('/[^A-Z0-9_-]/i', '', $alias);
     }
     // If no alias could be auto-generated, fail
     $this->assertNotEmpty($this->alias, 'COM_ARS_CATEGORY_ERR_NEEDS_SLUG');
     // Check alias for uniqueness
     $db = $this->getDBO();
     $query = $db->getQuery(true)->select($db->qn('alias'))->from($db->qn('#__ars_categories'));
     if ($this->id) {
         $query->where('NOT(' . $db->qn('id') . ' = ' . $db->q($this->id) . ')');
     }
     $db->setQuery($query);
     $aliases = $db->loadColumn();
     $this->assertNotInArray($this->alias, $aliases, 'COM_ARS_CATEGORY_ERR_NEEDS_UNIQUE_SLUG');
     // Check directory
     \JLoader::import('joomla.filesystem.folder');
     $this->directory = rtrim($this->directory, '/');
     if ($this->directory == 's3:') {
         $this->directory = 's3://';
     }
     $check = trim($this->directory);
     $this->assertNotEmpty($check, 'COM_ARS_CATEGORY_ERR_NEEDS_DIRECTORY');
     $potentialPrefix = substr($check, 0, 5);
     $potentialPrefix = strtolower($potentialPrefix);
     if ($potentialPrefix == 's3://') {
         $check = substr($check, 5);
         if (!empty($check)) {
             $check .= '/';
         }
         $s3 = AmazonS3::getInstance();
         $items = $s3->getBucket('', $check);
         $this->assertNotEmpty($items, 'COM_ARS_CATEGORY_ERR_S3_DIRECTORY_NOT_EXISTS');
     } else {
         if (!\JFolder::exists($this->directory)) {
             $directory = JPATH_SITE . '/' . $this->directory;
             $this->assert(\JFolder::exists($directory), 'COM_ARS_CATEGORY_ERR_DIRECTORY_NOT_EXISTS');
         }
     }
     // Automaticaly fix the type
     if (!in_array($this->type, array('normal', 'bleedingedge'))) {
         $this->type = 'normal';
     }
     // Set the access to registered if there are subscriptions groups defined
     if (empty($this->access)) {
         $this->access = 1;
     }
     if (!empty($this->groups) && $this->access == 1) {
         $this->access = 2;
     }
     if (empty($this->published) && $this->published !== 0) {
         $this->published = 0;
     }
     parent::check();
     return $this;
 }
Example #3
0
 function delete()
 {
     $folder = $this->getCategoryFolder();
     $file = $this->getState('file', '');
     if (empty($file)) {
         return '';
     }
     $potentialPrefix = substr($folder, 0, 5);
     $potentialPrefix = strtolower($potentialPrefix);
     $useS3 = $potentialPrefix == 's3://';
     if ($useS3) {
         $folder = trim(substr($folder, 5), '/');
         if (!empty($folder)) {
             $folder .= '/';
         }
         $filepath = $folder . $file;
     } else {
         $filepath = $folder . '/' . $file;
     }
     if (!$useS3) {
         \JLoader::import('joomla.filesystem.file');
         if (!\JFile::exists($filepath)) {
             return false;
         }
     }
     /** @var Items $itemsModel */
     $itemsModel = $this->container->factory->model('Items')->tmpInstance();
     $files = $itemsModel->category($this->getState('category', 0))->filename($this->getState('file', ''))->get(true);
     if ($files->count()) {
         // Unpublish entries
         /** @var Items $item */
         foreach ($files as $item) {
             $item->unpublish();
         }
     }
     if ($useS3) {
         $s3 = AmazonS3::getInstance();
         return $s3->deleteObject($filepath);
     } else {
         return \JFile::delete($filepath);
     }
 }
Example #4
0
 public function doDownload(Items $item)
 {
     // If it's a link we just have to redirect users
     if ($item->type == 'link') {
         if (@ob_get_length() !== false) {
             @ob_end_clean();
         }
         $this->logoutUser();
         \JFactory::getApplication()->redirect($item->url, false);
         return;
     }
     \JLoader::import('joomla.filesystem.folder');
     \JLoader::import('joomla.filesystem.file');
     $folder = $item->release->category->directory;
     $potentialPrefix = substr($folder, 0, 5);
     $potentialPrefix = strtolower($potentialPrefix);
     $useS3 = $potentialPrefix == 's3://';
     if ($useS3) {
         $filename = substr($folder, 5) . '/' . $item->filename;
         $s3 = AmazonS3::getInstance();
         $url = $s3->getAuthenticatedURL($filename);
         if (@ob_get_length() !== false) {
             @ob_end_clean();
         }
         $this->logoutUser();
         \JFactory::getApplication()->redirect($url, false);
         return;
     }
     if (!\JFolder::exists($folder)) {
         $folder = JPATH_ROOT . '/' . $folder;
         if (!\JFolder::exists($folder)) {
             $this->logoutUser();
             throw new \RuntimeException('Not found', 404);
         }
     }
     $filename = $folder . '/' . $item->filename;
     if (!\JFile::exists($filename)) {
         $this->logoutUser();
         throw new \RuntimeException('Not found', 404);
     }
     $basename = @basename($filename);
     $filesize = @filesize($filename);
     $mime_type = null;
     if (class_exists('finfo')) {
         $fInfo = new \finfo(FILEINFO_MIME_TYPE);
         $mime_type = $fInfo->file($filename);
     }
     if (empty($mime_type)) {
         $mime_type = $this->get_mime_type($filename);
     }
     if (empty($mime_type)) {
         $mime_type = 'application/octet-stream';
     }
     // Clear cache
     while (@ob_end_clean()) {
         // Make sure no junk will come before out content – to the extent we have a say on this...
     }
     // Fix IE bugs
     if (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
         $header_file = preg_replace('/\\./', '%2e', $basename, substr_count($basename, '.') - 1);
         if (ini_get('zlib.output_compression')) {
             ini_set('zlib.output_compression', 'Off');
         }
     } else {
         $header_file = $basename;
     }
     // Import ARS plugins
     \JLoader::import('joomla.plugin.helper');
     \JPluginHelper::importPlugin('ars');
     // Call any plugins to post-process the download file parameters
     $object = array('rawentry' => $item, 'filename' => $filename, 'basename' => $basename, 'header_file' => $header_file, 'mimetype' => $mime_type, 'filesize' => $filesize);
     $app = \JFactory::getApplication();
     $retArray = $app->triggerEvent('onARSBeforeSendFile', array($object));
     if (!empty($retArray)) {
         foreach ($retArray as $ret) {
             if (empty($ret) || !is_array($ret)) {
                 continue;
             }
             $ret = (object) $ret;
             $filename = $ret->filename;
             $basename = $ret->basename;
             $header_file = $ret->header_file;
             $mime_type = $ret->mimetype;
             $filesize = $ret->filesize;
         }
     }
     @clearstatcache();
     // Disable caching
     header("Pragma: public");
     header("Expires: 0");
     header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
     header("Cache-Control: public", false);
     // Send MIME headers
     header("Content-Description: File Transfer");
     header('Content-Type: ' . $mime_type);
     header("Accept-Ranges: bytes");
     header('Content-Disposition: attachment; filename="' . $header_file . '"');
     header('Content-Transfer-Encoding: binary');
     header('Connection: close');
     error_reporting(0);
     if (!ini_get('safe_mode')) {
         set_time_limit(0);
     }
     // Support resumable downloads
     $isResumable = false;
     $seek_start = 0;
     $seek_end = $filesize - 1;
     if (isset($_SERVER['HTTP_RANGE'])) {
         list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
         if ($size_unit == 'bytes') {
             //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
             list($range, $extra_ranges) = explode(',', $range_orig, 2);
         } else {
             $range = '';
         }
     } else {
         $range = '';
     }
     if ($range) {
         // Figure out download piece from range (if set)
         list($seek_start, $seek_end) = explode('-', $range, 2);
         // Set start and end based on range (if set), else set defaults. Also checks for invalid ranges.
         $seek_end = empty($seek_end) ? $filesize - 1 : min(abs(intval($seek_end)), $filesize - 1);
         $seek_start = empty($seek_start) || $seek_end < abs(intval($seek_start)) ? 0 : max(abs(intval($seek_start)), 0);
         $isResumable = true;
     }
     // Use 1M chunks for echoing the data to the browser
     $chunksize = 1024 * 1024;
     //1M chunks
     $handle = @fopen($filename, 'rb');
     if ($handle !== false) {
         if ($isResumable) {
             //Only send partial content header if downloading a piece of the file (IE workaround)
             if ($seek_start > 0 || $seek_end < $filesize - 1) {
                 header('HTTP/1.1 206 Partial Content');
             }
             // Necessary headers
             $totalLength = $seek_end - $seek_start + 1;
             header('Content-Range: bytes ' . $seek_start . '-' . $seek_end . '/' . $filesize);
             header('Content-Length: ' . $totalLength);
             // Seek to start
             fseek($handle, $seek_start);
         } else {
             $isResumable = false;
             // Notify of filesize, if this info is available
             if ($filesize > 0) {
                 header('Content-Length: ' . (int) $filesize);
             }
         }
         $read = 0;
         while (!feof($handle) && $chunksize > 0) {
             if ($isResumable) {
                 if ($totalLength - $read < $chunksize) {
                     $chunksize = $totalLength - $read;
                     if ($chunksize < 0) {
                         continue;
                     }
                 }
             }
             $buffer = fread($handle, $chunksize);
             if ($isResumable) {
                 $read += strlen($buffer);
             }
             echo $buffer;
             @ob_flush();
             flush();
         }
         @fclose($handle);
     } else {
         // Notify of filesize, if this info is available
         if ($filesize > 0) {
             header('Content-Length: ' . (int) $filesize);
         }
         @readfile($filename);
     }
     // Call any plugins to post-process the file download
     $object = array('rawentry' => $item, 'filename' => $filename, 'basename' => $basename, 'header_file' => $header_file, 'mimetype' => $mime_type, 'filesize' => $filesize, 'resumable' => $isResumable, 'range_start' => $seek_start, 'range_end' => $seek_end);
     $ret = $app->triggerEvent('onARSAfterSendFile', array($object));
     if (!empty($ret)) {
         foreach ($ret as $r) {
             if (!empty($r)) {
                 echo $r;
             }
         }
     }
     $this->logoutUser();
 }
Example #5
0
 /**
  * Returns a list of select options which will let the user pick a file for a release. Files already used in other
  * items of the same category will not be listed to prevent the list getting too long.
  *
  * @param   int  $release_id  The numeric ID of the release selected by the user
  * @param   int  $item_id     The numeric ID of the current item. Leave 0 if it's a new item.
  *
  * @return  array  Array of JHtml options.
  */
 public function getFilesOptions($release_id, $item_id = 0)
 {
     $options = array();
     $options[] = JHTML::_('select.option', '', '- ' . JText::_('LBL_ITEMS_FILENAME_SELECT') . ' -');
     // Try to figure out a directory
     $directory = null;
     if (empty($release_id)) {
         return $options;
     }
     /** @var Releases $releaseModel */
     $releaseModel = $this->container->factory->model('Releases')->tmpInstance();
     // Get the release
     $release = $releaseModel->find((int) $release_id);
     // Get which directory to use
     $directory = $release->category->directory;
     $potentialPrefix = substr($directory, 0, 5);
     $potentialPrefix = strtolower($potentialPrefix);
     $useS3 = $potentialPrefix == 's3://';
     if ($useS3) {
         $directory = substr($directory, 5);
         if ($directory === false) {
             $directory = '';
         }
         $s3 = AmazonS3::getInstance();
         $items = $s3->getBucket('', $directory . '/');
         if (empty($items)) {
             $directory = null;
         }
         if (empty($directory)) {
             $directory = '/';
         }
     } else {
         \JLoader::import('joomla.filesystem.folder');
         if (!\JFolder::exists($directory)) {
             $directory = JPATH_ROOT . '/' . $directory;
             if (!\JFolder::exists($directory)) {
                 $directory = null;
             }
         }
     }
     if (empty($directory)) {
         return $options;
     }
     // Get a list of files already used in this category (so as not to show them again, he he!)
     $files = array();
     $itemsModel = $this->tmpInstance();
     $items = $itemsModel->category($release->category_id)->release('false')->get(true);
     if (!empty($items)) {
         // Walk through the list and find the currently selected filename
         $currentFilename = '';
         foreach ($items as $item) {
             if ($item->id == $item_id) {
                 $currentFilename = $item->filename;
                 break;
             }
         }
         // Remove already used filenames except the currently selected filename
         reset($items);
         foreach ($items as $item) {
             if ($item->filename != $currentFilename && !empty($item->filename)) {
                 $files[] = $item->filename;
             }
         }
         $files = array_unique($files);
     }
     // Produce a list of files and remove the items in the $files array
     $useFiles = array();
     if ($useS3) {
         $s3 = Amazons3::getInstance();
         $allFiles = $s3->getBucket('', $directory, null, null, null, true);
         if (!empty($allFiles)) {
             foreach ($allFiles as $aFile => $info) {
                 $aFile = ltrim(substr($aFile, strlen($directory)), '/');
                 if (in_array($aFile, $files)) {
                     continue;
                 }
                 $useFiles[] = $aFile;
             }
         }
     } else {
         $allFiles = \JFolder::files($directory, '.', 3, true);
         $root = str_replace('\\', '/', $directory);
         if (!empty($allFiles)) {
             foreach ($allFiles as $aFile) {
                 $aFile = str_replace('\\', '/', $aFile);
                 $aFile = ltrim(substr($aFile, strlen($root)), '/');
                 if (in_array($aFile, $files)) {
                     continue;
                 }
                 $useFiles[] = $aFile;
             }
         }
     }
     if (empty($useFiles)) {
         return $options;
     }
     foreach ($useFiles as $file) {
         $options[] = JHTML::_('select.option', $file, $file);
     }
     return $options;
 }
Example #6
0
 /**
  * Create a new folder
  */
 public function newFolder()
 {
     if (!$this->checkACL('core.create')) {
         throw new \RuntimeException(\JText::_('JERROR_ALERTNOAUTHOR'), 403);
     }
     $this->csrfProtection();
     $categoryId = $this->input->getInt('id', 0);
     $folder = $this->input->getString('folder', '');
     $file = $this->input->getString('file', '');
     /** @var \Akeeba\ReleaseSystem\Admin\Model\Upload $model */
     $model = $this->getModel();
     $model->setState('category', (int) $categoryId);
     $model->setState('folder', $folder);
     $model->setState('file', $file);
     $parent = $model->getCategoryFolder();
     $potentialPrefix = substr($parent, 0, 5);
     $potentialPrefix = strtolower($potentialPrefix);
     $useS3 = $potentialPrefix == 's3://';
     if ($useS3) {
         $trimmedParent = $parent;
         if (substr($parent, 0, 5) == 's3://') {
             $trimmedParent = substr($parent, 5);
         }
         $newFolder = $trimmedParent . '/' . $file;
         $newFolder = trim($newFolder, '/') . '/';
         $s3 = AmazonS3::getInstance();
         $status = $s3->putObject('$folder$', $newFolder, true);
     } else {
         \JLoader::import('joomla.filesystem.folder');
         $newFolder = $parent . '/' . \JFolder::makeSafe($file);
         $status = \JFolder::create($newFolder);
     }
     $url = 'index.php?option=com_ars&view=upload&task=category&id=' . (int) $categoryId . '&folder=' . urlencode($this->input->getString('folder')) . '&' . \JFactory::getSession()->getFormToken(true) . '=1';
     if ($status) {
         $this->setRedirect($url, \JText::_('MSG_FOLDER_CREATED'));
         return;
     }
     $this->setRedirect($url, JText::_('MSG_FOLDER_NOT_CREATED'), 'error');
 }