Skip to content
Browse files

Add support for multi-file upload via the file input tag's 'multiple'…

… attribute

Bug fix for long-standing folder creation bug where 'continue' was used outside of loop context
Various code cleanup
  • Loading branch information...
1 parent 10aa20f commit df20ba4b151ef2f21393755bce4e5eec5f7580cd @okonomiyaki3000 committed Apr 5, 2012
View
271 administrator/components/com_media/controllers/file.php
@@ -19,37 +19,68 @@
*/
class MediaControllerFile extends JController
{
+ /*
+ * The folder we are uploading into
+ */
+ protected $folder = '';
+
/**
* Upload a file
*
* @since 1.5
*/
- function upload()
+ public function upload()
{
// Check for request forgeries
- JSession::checkToken('request') or jexit(JText::_('JINVALID_TOKEN'));
-
- // Get the user
- $user = JFactory::getUser();
+ JRequest::checkToken('request') or jexit(JText::_('JINVALID_TOKEN'));
// Get some data from the request
- $file = JRequest::getVar('Filedata', '', 'files', 'array');
- $folder = JRequest::getVar('folder', '', '', 'path');
- $return = JRequest::getVar('return-url', null, 'post', 'base64');
+ $files = JRequest::getVar('Filedata', '', 'files', 'array');
+ $return = JRequest::getVar('return-url', null, 'post', 'base64');
+ $this->folder = JRequest::getVar('folder', '', '', 'path');
+ // Set the redirect
+ if ($return)
+ {
+ $this->setRedirect(base64_decode($return) . '&folder=' . $this->folder);
+ }
- // Set FTP credentials, if given
- JClientHelper::setCredentialsFromRequest('ftp');
+ // Authorize the user
+ if (!$this->authoriseUser('create'))
+ {
+ return false;
+ }
- // Set the redirect
- if ($return) {
- $this->setRedirect(base64_decode($return).'&folder='.$folder);
+ // Input is in the form of an associative array containing numerically indexed arrays
+ // We want a numerically indexed array containing associative arrays
+ $files = array_map( array($this, 'reformatFilesArray'),
+ $files['name'], $files['type'], $files['tmp_name'], $files['error'], $files['size']
+ );
+
+ // Perform basic checks on file info before attempting anything
+ foreach ($files as &$file)
+ {
+ if (JFile::exists($file['filepath']))
+ {
+ // A file with this name already exists
+ JError::raiseWarning(100, JText::_('COM_MEDIA_ERROR_FILE_EXISTS'));
+ return false;
+ }
+
+ if (!isset($file['name']))
+ {
+ // No filename (after the name was cleaned by JFile::makeSafe)
+ $this->setRedirect('index.php', JText::_('COM_MEDIA_INVALID_REQUEST'), 'error');
+ return false;
+ }
}
- // Make the filename safe
- $file['name'] = JFile::makeSafe($file['name']);
+ // Set FTP credentials, if given
+ JClientHelper::setCredentialsFromRequest('ftp');
+ JPluginHelper::importPlugin('content');
+ $dispatcher = JDispatcher::getInstance();
- if (isset($file['name']))
+ foreach ($files as &$file)
{
// The request is valid
$err = null;
@@ -60,33 +91,15 @@ function upload()
return false;
}
- $filepath = JPath::clean(COM_MEDIA_BASE . '/' . $folder . '/' . strtolower($file['name']));
-
// Trigger the onContentBeforeSave event.
- JPluginHelper::importPlugin('content');
- $dispatcher = JDispatcher::getInstance();
$object_file = new JObject($file);
- $object_file->filepath = $filepath;
$result = $dispatcher->trigger('onContentBeforeSave', array('com_media.file', &$object_file));
- if (in_array(false, $result, true)) {
+ if (in_array(false, $result, true))
+ {
// There are some errors in the plugins
JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_SAVE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
return false;
}
- $file = (array) $object_file;
-
- if (JFile::exists($file['filepath']))
- {
- // File exists
- JError::raiseWarning(100, JText::_('COM_MEDIA_ERROR_FILE_EXISTS'));
- return false;
- }
- elseif (!$user->authorise('core.create', 'com_media'))
- {
- // File does not exist and user is not authorised to create
- JError::raiseWarning(403, JText::_('COM_MEDIA_ERROR_CREATE_NOT_PERMITTED'));
- return false;
- }
if (!JFile::upload($file['tmp_name'], $file['filepath']))
{
@@ -99,113 +112,157 @@ function upload()
// Trigger the onContentAfterSave event.
$dispatcher->trigger('onContentAfterSave', array('com_media.file', &$object_file, true));
$this->setMessage(JText::sprintf('COM_MEDIA_UPLOAD_COMPLETE', substr($file['filepath'], strlen(COM_MEDIA_BASE))));
- return true;
}
}
- else
+
+ return true;
+ }
+
+ /**
+ * Used as a callback for array_map, turns the multi-file input array into a sensible array of files
+ * Also, removes illegal characters from the 'name' and sets a 'filepath' as the final destination of the file
+ *
+ * @param string - file name ($files['name'])
+ * @param string - file type ($files['type'])
+ * @param string - temporary name ($files['tmp_name'])
+ * @param string - error info ($files['error'])
+ * @param string - file size ($files['size'])
+ *
+ * @return array
+ * @access protected
+ */
+ protected function reformatFilesArray($name, $type, $tmp_name, $error, $size)
+ {
+ $name = JFile::makeSafe($name);
+ return array(
+ 'name' => $name,
+ 'type' => $type,
+ 'tmp_name' => $tmp_name,
+ 'error' => $error,
+ 'size' => $size,
+ 'filepath' => JPath::clean(implode(DS, array(COM_MEDIA_BASE, $this->folder, $name)))
+ );
+ }
+
+ /**
+ * Check that the user is authorized to perform this action
+ *
+ * @param string $action - the action to be peformed (create or delete)
+ *
+ * @return boolean
+ * @access protected
+ */
+ protected function authoriseUser($action)
+ {
+ if (!JFactory::getUser()->authorise('core.' . strtolower($action), 'com_media'))
{
- $this->setRedirect('index.php', JText::_('COM_MEDIA_INVALID_REQUEST'), 'error');
+ // User is not authorised
+ JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_' . strtoupper($action) . '_NOT_PERMITTED'));
return false;
}
+
+ return true;
}
/**
* Deletes paths from the current path
*
- * @param string $listFolder The image directory to delete a file from
* @since 1.5
*/
- function delete()
+ public function delete()
{
- JSession::checkToken('request') or jexit(JText::_('JINVALID_TOKEN'));
- $app = JFactory::getApplication();
- $user = JFactory::getUser();
+ JRequest::checkToken('request') or jexit(JText::_('JINVALID_TOKEN'));
// Get some data from the request
$tmpl = JRequest::getCmd('tmpl');
$paths = JRequest::getVar('rm', array(), '', 'array');
$folder = JRequest::getVar('folder', '', '', 'path');
- if ($tmpl == 'component') {
+ $redirect = 'index.php?option=com_media&folder=' . $folder;
+ if ($tmpl == 'component')
+ {
// We are inside the iframe
- $this->setRedirect('index.php?option=com_media&view=mediaList&folder='.$folder.'&tmpl=component');
- } else {
- $this->setRedirect('index.php?option=com_media&folder='.$folder);
+ $redirect .= '&view=mediaList&tmpl=component';
}
+ $this->setRedirect($redirect);
- if (!$user->authorise('core.delete', 'com_media'))
+ // Nothing to delete
+ if (empty($paths))
+ {
+ return true;
+ }
+
+ // Authorize the user
+ if (!$this->authoriseUser('delete'))
{
- // User is not authorised to delete
- JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'));
return false;
}
- else
+
+ // Set FTP credentials, if given
+ JClientHelper::setCredentialsFromRequest('ftp');
+
+ JPluginHelper::importPlugin('content');
+ $dispatcher = JDispatcher::getInstance();
+
+ // Initialise variables.
+ $ret = true;
+ foreach ($paths as $path)
{
- // Set FTP credentials, if given
- JClientHelper::setCredentialsFromRequest('ftp');
+ if ($path !== JFile::makeSafe($path))
+ {
+ // filename is not safe
+ $filename = htmlspecialchars($path, ENT_COMPAT, 'UTF-8');
+ JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FILE_WARNFILENAME', substr($filename, strlen(COM_MEDIA_BASE))));
+ continue;
+ }
+
+ $fullPath = JPath::clean(implode(DS, array(COM_MEDIA_BASE, $folder, $path)));
+ $object_file = new JObject(array('filepath' => $fullPath));
+ if (is_file($fullPath))
+ {
+ // Trigger the onContentBeforeDelete event.
+ $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.file', &$object_file));
+ if (in_array(false, $result, true))
+ {
+ // There are some errors in the plugins
+ JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
+ continue;
+ }
- // Initialise variables.
- $ret = true;
+ $ret &= JFile::delete($fullPath);
- if (count($paths))
+ // Trigger the onContentAfterDelete event.
+ $dispatcher->trigger('onContentAfterDelete', array('com_media.file', &$object_file));
+ $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($fullPath, strlen(COM_MEDIA_BASE))));
+ }
+ elseif (is_dir($fullPath))
{
- JPluginHelper::importPlugin('content');
- $dispatcher = JDispatcher::getInstance();
- foreach ($paths as $path)
+ $contents = JFolder::files($fullPath, '.', true, false, array('.svn', 'CVS', '.DS_Store', '__MACOSX', 'index.html'));
+ if (empty($contents))
{
- if ($path !== JFile::makeSafe($path))
+ // Trigger the onContentBeforeDelete event.
+ $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.folder', &$object_file));
+ if (in_array(false, $result, true))
{
- // filename is not safe
- $filename = htmlspecialchars($path, ENT_COMPAT, 'UTF-8');
- JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FILE_WARNFILENAME', substr($filename, strlen(COM_MEDIA_BASE))));
+ // There are some errors in the plugins
+ JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
continue;
}
- $fullPath = JPath::clean(COM_MEDIA_BASE . '/' . $folder . '/' . $path);
- $object_file = new JObject(array('filepath' => $fullPath));
- if (is_file($fullPath))
- {
- // Trigger the onContentBeforeDelete event.
- $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.file', &$object_file));
- if (in_array(false, $result, true)) {
- // There are some errors in the plugins
- JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
- continue;
- }
-
- $ret &= JFile::delete($fullPath);
-
- // Trigger the onContentAfterDelete event.
- $dispatcher->trigger('onContentAfterDelete', array('com_media.file', &$object_file));
- $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($fullPath, strlen(COM_MEDIA_BASE))));
- }
- elseif (is_dir($fullPath))
- {
- if (count(JFolder::files($fullPath, '.', true, false, array('.svn', 'CVS', '.DS_Store', '__MACOSX'), array('index.html', '^\..*', '.*~'))) == 0)
- {
- // Trigger the onContentBeforeDelete event.
- $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.folder', &$object_file));
- if (in_array(false, $result, true)) {
- // There are some errors in the plugins
- JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
- continue;
- }
-
- $ret &= JFolder::delete($fullPath);
-
- // Trigger the onContentAfterDelete event.
- $dispatcher->trigger('onContentAfterDelete', array('com_media.folder', &$object_file));
- $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($fullPath, strlen(COM_MEDIA_BASE))));
- }
- else
- {
- //This makes no sense...
- JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_NOT_EMPTY', substr($fullPath, strlen(COM_MEDIA_BASE))));
- }
- }
+ $ret &= JFolder::delete($fullPath);
+
+ // Trigger the onContentAfterDelete event.
+ $dispatcher->trigger('onContentAfterDelete', array('com_media.folder', &$object_file));
+ $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($fullPath, strlen(COM_MEDIA_BASE))));
+ }
+ else
+ {
+ // This makes no sense...
+ JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_NOT_EMPTY', substr($fullPath, strlen(COM_MEDIA_BASE))));
}
}
- return $ret;
}
+
+ return $ret;
}
}
View
133 administrator/components/com_media/controllers/folder.php
@@ -23,10 +23,9 @@ class MediaControllerFolder extends JController
/**
* Deletes paths from the current path
*
- * @param string $listFolder The image directory to delete a file from
* @since 1.5
*/
- function delete()
+ public function delete()
{
JSession::checkToken('request') or jexit(JText::_('JINVALID_TOKEN'));
@@ -37,11 +36,17 @@ function delete()
$paths = JRequest::getVar('rm', array(), '', 'array');
$folder = JRequest::getVar('folder', '', '', 'path');
+ $redirect = 'index.php?option=com_media&folder=' . $folder;
if ($tmpl == 'component') {
// We are inside the iframe
- $this->setRedirect('index.php?option=com_media&view=mediaList&folder='.$folder.'&tmpl=component');
- } else {
- $this->setRedirect('index.php?option=com_media&folder='.$folder);
+ $redirect .= '&view=mediaList&tmpl=component';
+ }
+ $this->setRedirect($redirect);
+
+ // Just return if there's nothing to do
+ if (!empty($paths))
+ {
+ return true;
}
if (!$user->authorise('core.delete', 'com_media'))
@@ -50,68 +55,68 @@ function delete()
JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'));
return false;
}
- else
+
+ // Set FTP credentials, if given
+ JClientHelper::setCredentialsFromRequest('ftp');
+
+ // Initialise variables.
+ $ret = true;
+
+ JPluginHelper::importPlugin('content');
+ $dispatcher = JDispatcher::getInstance();
+ foreach ($paths as $path)
{
- // Set FTP credentials, if given
- JClientHelper::setCredentialsFromRequest('ftp');
+ if ($path !== JFile::makeSafe($path))
+ {
+ $dirname = htmlspecialchars($path, ENT_COMPAT, 'UTF-8');
+ JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_WARNDIRNAME', substr($dirname, strlen(COM_MEDIA_BASE))));
+ continue;
+ }
+
+ $fullPath = JPath::clean(implode(DS, array(COM_MEDIA_BASE, $folder, $path)));
+ $object_file = new JObject(array('filepath' => $fullPath));
+ if (is_file($fullPath))
+ {
+ // Trigger the onContentBeforeDelete event.
+ $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.file', &$object_file));
+ if (in_array(false, $result, true)) {
+ // There are some errors in the plugins
+ JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
+ continue;
+ }
- // Initialise variables.
- $ret = true;
+ $ret &= JFile::delete($fullPath);
- if (count($paths)) {
- JPluginHelper::importPlugin('content');
- $dispatcher = JDispatcher::getInstance();
- foreach ($paths as $path) {
- if ($path !== JFile::makeSafe($path)) {
- $dirname = htmlspecialchars($path, ENT_COMPAT, 'UTF-8');
- JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_WARNDIRNAME', substr($dirname, strlen(COM_MEDIA_BASE))));
+ // Trigger the onContentAfterDelete event.
+ $dispatcher->trigger('onContentAfterDelete', array('com_media.file', &$object_file));
+ $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($fullPath, strlen(COM_MEDIA_BASE))));
+ }
+ elseif (is_dir($fullPath))
+ {
+ $contents = JFolder::files($fullPath, '.', true, false, array('.svn', 'CVS', '.DS_Store', '__MACOSX', 'index.html'));
+ if (empty($contents))
+ {
+ // Trigger the onContentBeforeDelete event.
+ $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.folder', &$object_file));
+ if (in_array(false, $result, true)) {
+ // There are some errors in the plugins
+ JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
continue;
}
- $fullPath = JPath::clean(COM_MEDIA_BASE . '/' . $folder . '/' . $path);
- $object_file = new JObject(array('filepath' => $fullPath));
- if (is_file($fullPath))
- {
- // Trigger the onContentBeforeDelete event.
- $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.file', &$object_file));
- if (in_array(false, $result, true)) {
- // There are some errors in the plugins
- JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
- continue;
- }
-
- $ret &= JFile::delete($fullPath);
-
- // Trigger the onContentAfterDelete event.
- $dispatcher->trigger('onContentAfterDelete', array('com_media.file', &$object_file));
- $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($fullPath, strlen(COM_MEDIA_BASE))));
- }
- elseif (is_dir($fullPath))
- {
- if (count(JFolder::files($fullPath, '.', true, false, array('.svn', 'CVS', '.DS_Store', '__MACOSX'), array('index.html', '^\..*', '.*~'))) == 0)
- {
- // Trigger the onContentBeforeDelete event.
- $result = $dispatcher->trigger('onContentBeforeDelete', array('com_media.folder', &$object_file));
- if (in_array(false, $result, true)) {
- // There are some errors in the plugins
- JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_DELETE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
- continue;
- }
-
- $ret &= !JFolder::delete($fullPath);
-
- // Trigger the onContentAfterDelete event.
- $dispatcher->trigger('onContentAfterDelete', array('com_media.folder', &$object_file));
- $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($fullPath, strlen(COM_MEDIA_BASE))));
- }
- else
- {
- //This makes no sense...
- JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_NOT_EMPTY', substr($fullPath, strlen(COM_MEDIA_BASE))));
- }
- }
+ $ret &= !JFolder::delete($fullPath);
+
+ // Trigger the onContentAfterDelete event.
+ $dispatcher->trigger('onContentAfterDelete', array('com_media.folder', &$object_file));
+ $this->setMessage(JText::sprintf('COM_MEDIA_DELETE_COMPLETE', substr($fullPath, strlen(COM_MEDIA_BASE))));
+ }
+ else
+ {
+ //This makes no sense...
+ JError::raiseWarning(100, JText::sprintf('COM_MEDIA_ERROR_UNABLE_TO_DELETE_FOLDER_NOT_EMPTY', substr($fullPath, strlen(COM_MEDIA_BASE))));
}
}
+
return $ret;
}
}
@@ -122,7 +127,7 @@ function delete()
* @param string $path Path of the folder to create
* @since 1.5
*/
- function create()
+ public function create()
{
// Check for request forgeries
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
@@ -149,7 +154,8 @@ function create()
JRequest::setVar('folder', $parent);
- if (($folderCheck !== null) && ($folder !== $folderCheck)) {
+ if (($folderCheck !== null) && ($folder !== $folderCheck))
+ {
$this->setMessage(JText::_('COM_MEDIA_ERROR_UNABLE_TO_CREATE_FOLDER_WARNDIRNAME'));
return false;
}
@@ -162,10 +168,11 @@ function create()
JPluginHelper::importPlugin('content');
$dispatcher = JDispatcher::getInstance();
$result = $dispatcher->trigger('onContentBeforeSave', array('com_media.folder', &$object_file));
- if (in_array(false, $result, true)) {
+ if (in_array(false, $result, true))
+ {
// There are some errors in the plugins
JError::raiseWarning(100, JText::plural('COM_MEDIA_ERROR_BEFORE_SAVE', count($errors = $object_file->getErrors()), implode('<br />', $errors)));
- continue;
+ return false;
}
JFolder::create($path);
View
2 administrator/components/com_media/views/images/tmpl/default.php
@@ -82,7 +82,7 @@
<legend><?php echo $this->config->get('upload_maxsize')=='0' ? JText::_('COM_MEDIA_UPLOAD_FILES_NOLIMIT') : JText::sprintf('COM_MEDIA_UPLOAD_FILES', $this->config->get('upload_maxsize')); ?></legend>
<fieldset id="upload-noflash" class="actions">
<label for="upload-file" class="hidelabeltxt"><?php echo JText::_('COM_MEDIA_UPLOAD_FILE'); ?></label>
- <input type="file" id="upload-file" name="Filedata" />
+ <input type="file" id="upload-file" name="Filedata[]" multiple />
<label for="upload-submit" class="hidelabeltxt"><?php echo JText::_('COM_MEDIA_START_UPLOAD'); ?></label>
<input type="submit" id="upload-submit" value="<?php echo JText::_('COM_MEDIA_START_UPLOAD'); ?>"/>
</fieldset>
View
2 administrator/components/com_media/views/media/tmpl/default.php
@@ -65,7 +65,7 @@
<legend><?php echo $this->config->get('upload_maxsize')=='0' ? JText::_('COM_MEDIA_UPLOAD_FILES_NOLIMIT') : JText::sprintf('COM_MEDIA_UPLOAD_FILES', $this->config->get('upload_maxsize')); ?></legend>
<fieldset id="upload-noflash" class="actions">
<label for="upload-file" class="hidelabeltxt"><?php echo JText::_('COM_MEDIA_UPLOAD_FILE'); ?></label>
- <input type="file" id="upload-file" name="Filedata" />
+ <input type="file" id="upload-file" name="Filedata[]" multiple />
<label for="upload-submit" class="hidelabeltxt"><?php echo JText::_('COM_MEDIA_START_UPLOAD'); ?></label>
<input type="submit" id="upload-submit" value="<?php echo JText::_('COM_MEDIA_START_UPLOAD'); ?>"/>
</fieldset>

0 comments on commit df20ba4

Please sign in to comment.
Something went wrong with that request. Please try again.