/** * Validates the uploaded image. Returns the temporary name of the uploaded file. */ public function validateUpload($InputName, $ThrowError = true) { if (!function_exists('gd_info')) { throw new Exception(T('The uploaded file could not be processed because GD is not installed.')); } // Make sure that all standard file upload checks are performed. $TmpFileName = parent::validateUpload($InputName, $ThrowError); // Now perform image-specific checks. if ($TmpFileName) { $Size = getimagesize($TmpFileName); if ($Size === false) { throw new Exception(T('The uploaded file was not an image.')); } } return $TmpFileName; }
/** * * * @param PostController $Sender * @param array $Args */ public function postController_editorUpload_create($Sender, $Args = array()) { // @Todo Move to a library/functions file. require 'generate_thumbnail.php'; // Grab raw upload data ($_FILES), essentially. It's only needed // because the methods on the Upload class do not expose all variables. $fileData = Gdn::request()->getValueFrom(Gdn_Request::INPUT_FILES, $this->editorFileInputName, false); $discussionID = $Sender->Request->post('DiscussionID') ? $Sender->Request->post('DiscussionID') : ''; // JSON payload of media info will get sent back to the client. $json = array('error' => 1, 'feedback' => 'There was a problem.', 'errors' => array(), 'payload' => array()); // New upload instance $Upload = new Gdn_Upload(); // This will validate, such as size maxes, file extensions. Upon doing // this, $_FILES is set as a protected property, so all the other Gdn_Upload methods work on it. $tmpFilePath = $Upload->validateUpload($this->editorFileInputName); // Get base destination path for editor uploads $this->editorBaseUploadDestinationDir = $this->getBaseUploadDestinationDir(); // Pass path, if doesn't exist, will create, and determine if valid. $canUpload = Gdn_Upload::canUpload($this->editorBaseUploadDestinationDir); if ($tmpFilePath && $canUpload) { $fileExtension = strtolower($Upload->getUploadedFileExtension()); $fileName = $Upload->getUploadedFileName(); list($tmpwidth, $tmpheight, $imageType) = getimagesize($tmpFilePath); // This will return the absolute destination path, including generated // filename based on md5_file, and the full path. It // will create a filename, with extension, and check if its dir can be writable. $absoluteFileDestination = $this->getAbsoluteDestinationFilePath($tmpFilePath, $fileExtension); // Save original file to uploads, then manipulate from this location if // it's a photo. This will also call events in Vanilla so other plugins can tie into this. if (empty($imageType)) { $filePathParsed = $Upload->saveAs($tmpFilePath, $absoluteFileDestination, array('source' => 'content')); } else { $filePathParsed = Gdn_UploadImage::saveImageAs($tmpFilePath, $absoluteFileDestination, '', '', array('SaveGif' => true)); $tmpwidth = $filePathParsed['Width']; $tmpheight = $filePathParsed['Height']; } // Determine if image, and thus requires thumbnail generation, or simply saving the file. // Not all files will be images. $thumbHeight = ''; $thumbWidth = ''; $imageHeight = ''; $imageWidth = ''; $thumbPathParsed = array('SaveName' => ''); $thumbUrl = ''; // This is a redundant check, because it's in the thumbnail function, // but there's no point calling it blindly on every file, so just check here before calling it. $generate_thumbnail = false; if (in_array($fileExtension, array('jpg', 'jpeg', 'gif', 'png', 'bmp', 'ico'))) { $imageHeight = $tmpheight; $imageWidth = $tmpwidth; $generate_thumbnail = true; } // Save data to database using model with media table $Model = new Gdn_Model('Media'); // Will be passed to model for database insertion/update. All thumb vars will be empty. $Media = array('Name' => $fileName, 'Type' => $fileData['type'], 'Size' => $fileData['size'], 'ImageWidth' => $imageWidth, 'ImageHeight' => $imageHeight, 'ThumbWidth' => $thumbWidth, 'ThumbHeight' => $thumbHeight, 'InsertUserID' => Gdn::session()->UserID, 'DateInserted' => date('Y-m-d H:i:s'), 'StorageMethod' => 'local', 'Path' => $filePathParsed['SaveName'], 'ThumbPath' => $thumbPathParsed['SaveName']); // Get MediaID and pass it to client in payload. $MediaID = $Model->save($Media); $Media['MediaID'] = $MediaID; if ($generate_thumbnail) { $thumbUrl = url('/utility/mediathumbnail/' . $MediaID, true); } $payload = array('MediaID' => $MediaID, 'Filename' => htmlspecialchars($fileName), 'Filesize' => $fileData['size'], 'FormatFilesize' => Gdn_Format::bytes($fileData['size'], 1), 'type' => $fileData['type'], 'Thumbnail' => '', 'FinalImageLocation' => '', 'Parsed' => $filePathParsed, 'Media' => (array) $Media, 'original_url' => $Upload->url($filePathParsed['SaveName']), 'thumbnail_url' => $thumbUrl, 'original_width' => $imageWidth, 'original_height' => $imageHeight); $json = array('error' => 0, 'feedback' => 'Editor received file successfully.', 'payload' => $payload); } // Return JSON payload echo json_encode($json); }
/** * Banner management screen. * * @since 2.0.0 * @access public */ public function banner() { $this->permission('Garden.Community.Manage'); $this->addSideMenu('dashboard/settings/banner'); $this->title(t('Banner')); $Validation = new Gdn_Validation(); $ConfigurationModel = new Gdn_ConfigurationModel($Validation); $ConfigurationModel->setField(array('Garden.HomepageTitle' => c('Garden.Title'), 'Garden.Title', 'Garden.Description')); // Set the model on the form. $this->Form->setModel($ConfigurationModel); // Get the current logo. $Logo = c('Garden.Logo'); if ($Logo) { $Logo = ltrim($Logo, '/'); // Fix the logo path. if (stringBeginsWith($Logo, 'uploads/')) { $Logo = substr($Logo, strlen('uploads/')); } $this->setData('Logo', $Logo); } // Get the current mobile logo. $MobileLogo = c('Garden.MobileLogo'); if ($MobileLogo) { $MobileLogo = ltrim($MobileLogo, '/'); // Fix the logo path. if (stringBeginsWith($MobileLogo, 'uploads/')) { $MobileLogo = substr($MobileLogo, strlen('uploads/')); } $this->setData('MobileLogo', $MobileLogo); } // Get the current favicon. $Favicon = c('Garden.FavIcon'); $this->setData('Favicon', $Favicon); $ShareImage = c('Garden.ShareImage'); $this->setData('ShareImage', $ShareImage); // If seeing the form for the first time... if (!$this->Form->authenticatedPostBack()) { // Apply the config settings to the form. $this->Form->setData($ConfigurationModel->Data); } else { $SaveData = array(); if ($this->Form->save() !== false) { $Upload = new Gdn_Upload(); try { // Validate the upload $TmpImage = $Upload->validateUpload('Logo', false); if ($TmpImage) { // Generate the target image name $TargetImage = $Upload->generateTargetName(PATH_UPLOADS); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); // Delete any previously uploaded images. if ($Logo) { $Upload->delete($Logo); } // Save the uploaded image $Parts = $Upload->SaveAs($TmpImage, $ImageBaseName); $ImageBaseName = $Parts['SaveName']; $SaveData['Garden.Logo'] = $ImageBaseName; $this->setData('Logo', $ImageBaseName); } $TmpMobileImage = $Upload->validateUpload('MobileLogo', false); if ($TmpMobileImage) { // Generate the target image name $TargetImage = $Upload->generateTargetName(PATH_UPLOADS); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); // Delete any previously uploaded images. if ($MobileLogo) { $Upload->delete($MobileLogo); } // Save the uploaded image $Parts = $Upload->saveAs($TmpMobileImage, $ImageBaseName); $ImageBaseName = $Parts['SaveName']; $SaveData['Garden.MobileLogo'] = $ImageBaseName; $this->setData('MobileLogo', $ImageBaseName); } $ImgUpload = new Gdn_UploadImage(); $TmpFavicon = $ImgUpload->validateUpload('Favicon', false); if ($TmpFavicon) { $ICOName = 'favicon_' . substr(md5(microtime()), 16) . '.ico'; if ($Favicon) { $Upload->delete($Favicon); } // Resize the to a png. $Parts = $ImgUpload->SaveImageAs($TmpFavicon, $ICOName, 16, 16, array('OutputType' => 'ico', 'Crop' => true)); $SaveData['Garden.FavIcon'] = $Parts['SaveName']; $this->setData('Favicon', $Parts['SaveName']); } $TmpShareImage = $Upload->ValidateUpload('ShareImage', false); if ($TmpShareImage) { $TargetImage = $Upload->GenerateTargetName(PATH_UPLOADS, false); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); if ($ShareImage) { $Upload->delete($ShareImage); } $Parts = $Upload->SaveAs($TmpShareImage, $ImageBaseName); $SaveData['Garden.ShareImage'] = $Parts['SaveName']; $this->setData('ShareImage', $Parts['SaveName']); } } catch (Exception $ex) { $this->Form->addError($ex); } // If there were no errors, save the path to the logo in the config if ($this->Form->errorCount() == 0) { saveToConfig($SaveData); } $this->informMessage(t("Your settings have been saved.")); } } $this->render(); }
/** * Handle form upload of an addon zip archive. * * @return array */ protected function handleAddonUpload() { $Upload = new Gdn_Upload(); $Upload->allowFileExtension(null); $Upload->allowFileExtension('zip'); $AnalyzedAddon = []; try { // Validate the upload. $TmpFile = $Upload->validateUpload('File'); $Extension = pathinfo($Upload->getUploadedFileName(), PATHINFO_EXTENSION); // Generate the target name. $TargetFile = $Upload->generateTargetName('addons', $Extension); $TargetPath = PATH_UPLOADS . '/' . $TargetFile; if (!file_exists(dirname($TargetPath))) { mkdir(dirname($TargetPath), 0777, true); } // Save the file to a temporary location for parsing. if (!move_uploaded_file($TmpFile, $TargetPath)) { throw new Exception("We couldn't save the file you uploaded. Please try again later.", 400); } $AnalyzedAddon = UpdateModel::analyzeAddon($TargetPath, true); // If the long description is blank, load up the readme if it exists $formDescription = $this->Form->getFormValue('Description2', ''); if ($formDescription == '') { $Readme = $this->parseReadme($TargetPath); if ($Readme) { $AnalyzedAddon['Description2'] = $Readme; } } else { $AnalyzedAddon['Description2'] = $formDescription; } // Get an icon if one exists. $Icon = $this->extractIcon($TargetPath, val('Icon', $AnalyzedAddon, '')); if ($Icon) { // Overwrite info array value with the path to the saved file. $AnalyzedAddon['Icon'] = $Icon; } // Set the filename for the CDN. $Upload->EventArguments['OriginalFilename'] = AddonModel::slug($AnalyzedAddon, true) . '.zip'; // Save the uploaded file. After this, we no longer have a local copy to analyze. $Parsed = $Upload->saveAs($TargetPath, $TargetFile); $AnalyzedAddon['File'] = $Parsed['SaveName']; unset($AnalyzedAddon['Path']); trace($AnalyzedAddon, 'Analyzed Addon'); $this->Form->formValues($AnalyzedAddon); } catch (Exception $ex) { $this->Form->addError($ex); // Delete the erroneous file. try { if (isset($AnalyzedAddon) && isset($AnalyzedAddon['File'])) { $Upload->delete($AnalyzedAddon['File']); } } catch (Exception $Ex2) { } } if (isset($TargetPath) && file_exists($TargetPath)) { unlink($TargetPath); } return $AnalyzedAddon; }
/** * Editing a category. * * @since 2.0.0 * @access public * * @param int $CategoryID Unique ID of the category to be updated. */ public function editCategory($CategoryID = '') { // Check permission $this->permission('Garden.Community.Manage'); // Set up models $RoleModel = new RoleModel(); $PermissionModel = Gdn::permissionModel(); $this->Form->setModel($this->CategoryModel); if (!$CategoryID && $this->Form->authenticatedPostBack()) { if ($ID = $this->Form->getFormValue('CategoryID')) { $CategoryID = $ID; } } // Get category data $this->Category = $this->CategoryModel->getID($CategoryID); if (!$this->Category) { throw notFoundException('Category'); } $this->Category->CustomPermissions = $this->Category->CategoryID == $this->Category->PermissionCategoryID; // Set up head $this->addJsFile('jquery.alphanumeric.js'); $this->addJsFile('categories.js'); $this->addJsFile('jquery.gardencheckboxgrid.js'); $this->title(t('Edit Category')); $this->addSideMenu('vanilla/settings/managecategories'); // Make sure the form knows which item we are editing. $this->Form->addHidden('CategoryID', $CategoryID); $this->setData('CategoryID', $CategoryID); // Load all roles with editable permissions $this->RoleArray = $RoleModel->getArray(); $this->fireEvent('AddEditCategory'); if ($this->Form->authenticatedPostBack()) { $this->setupDiscussionTypes($this->Category); $Upload = new Gdn_Upload(); $TmpImage = $Upload->validateUpload('PhotoUpload', false); if ($TmpImage) { // Generate the target image name $TargetImage = $Upload->generateTargetName(PATH_UPLOADS); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); // Save the uploaded image $Parts = $Upload->saveAs($TmpImage, $ImageBaseName); $this->Form->setFormValue('Photo', $Parts['SaveName']); } $this->Form->setFormValue('CustomPoints', (bool) $this->Form->getFormValue('CustomPoints')); if ($this->Form->save()) { $Category = CategoryModel::categories($CategoryID); $this->setData('Category', $Category); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { redirect('vanilla/settings/managecategories'); } } } else { $this->Form->setData($this->Category); $this->setupDiscussionTypes($this->Category); $this->Form->setValue('CustomPoints', $this->Category->PointsCategoryID == $this->Category->CategoryID); } // Get all of the currently selected role/permission combinations for this junction. $Permissions = $PermissionModel->getJunctionPermissions(array('JunctionID' => $CategoryID), 'Category', '', array('AddDefaults' => !$this->Category->CustomPermissions)); $Permissions = $PermissionModel->unpivotPermissions($Permissions, true); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { $this->setData('PermissionData', $Permissions, true); } // Render default view $this->render(); }
/** * Editing a category. * * @since 2.0.0 * @param int|string $CategoryID Unique ID of the category to be updated. * @throws Exception when category cannot be found. */ public function editCategory($CategoryID = '') { // Check permission $this->permission(['Garden.Community.Manage', 'Garden.Settings.Manage'], false); // Set up models $RoleModel = new RoleModel(); $PermissionModel = Gdn::permissionModel(); $this->Form->setModel($this->CategoryModel); if (!$CategoryID && $this->Form->authenticatedPostBack()) { if ($ID = $this->Form->getFormValue('CategoryID')) { $CategoryID = $ID; } } // Get category data $this->Category = CategoryModel::categories($CategoryID); if (!$this->Category) { throw notFoundException('Category'); } // Category data is expected to be in the form of an object. $this->Category = (object) $this->Category; $this->Category->CustomPermissions = $this->Category->CategoryID == $this->Category->PermissionCategoryID; $displayAsOptions = categoryModel::getDisplayAsOptions(); // Restrict "Display As" types based on parent. $parentCategory = $this->CategoryModel->getID($this->Category->ParentCategoryID); $parentDisplay = val('DisplayAs', $parentCategory); if ($parentDisplay === 'Flat') { unset($displayAsOptions['Heading']); } // Set up head $this->addJsFile('jquery.alphanumeric.js'); $this->addJsFile('manage-categories.js'); $this->addJsFile('jquery.gardencheckboxgrid.js'); $this->title(t('Edit Category')); $this->setHighlightRoute('vanilla/settings/categories'); // Make sure the form knows which item we are editing. $this->Form->addHidden('CategoryID', $CategoryID); $this->setData('CategoryID', $CategoryID); // Load all roles with editable permissions $this->RoleArray = $RoleModel->getArray(); $this->fireAs('SettingsController'); $this->fireEvent('AddEditCategory'); if ($this->Form->authenticatedPostBack()) { $this->setupDiscussionTypes($this->Category); $Upload = new Gdn_Upload(); $TmpImage = $Upload->validateUpload('PhotoUpload', false); if ($TmpImage) { // Generate the target image name $TargetImage = $Upload->generateTargetName(PATH_UPLOADS); $ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME); // Save the uploaded image $Parts = $Upload->saveAs($TmpImage, $ImageBaseName); $this->Form->setFormValue('Photo', $Parts['SaveName']); } $this->Form->setFormValue('CustomPoints', (bool) $this->Form->getFormValue('CustomPoints')); // Enforces tinyint values on boolean fields to comply with strict mode $this->Form->setFormValue('HideAllDiscussions', forceBool($this->Form->getFormValue('HideAllDiscussions'), '0', '1', '0')); $this->Form->setFormValue('Archived', forceBool($this->Form->getFormValue('Archived'), '0', '1', '0')); $this->Form->setFormValue('AllowFileUploads', forceBool($this->Form->getFormValue('AllowFileUploads'), '0', '1', '0')); if ($parentDisplay === 'Flat' && $this->Form->getFormValue('DisplayAs') === 'Heading') { $this->Form->addError('Cannot display as a heading when your parent category is displayed flat.', 'DisplayAs'); } if ($this->Form->save()) { $Category = CategoryModel::categories($CategoryID); $this->setData('Category', $Category); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { $destination = $this->categoryPageByParent($parentCategory); redirect($destination); } elseif ($this->deliveryType() === DELIVERY_TYPE_DATA && method_exists($this, 'getCategory')) { $this->Data = []; $this->getCategory($CategoryID); return; } } } else { $this->Form->setData($this->Category); $this->setupDiscussionTypes($this->Category); $this->Form->setValue('CustomPoints', $this->Category->PointsCategoryID == $this->Category->CategoryID); } // Get all of the currently selected role/permission combinations for this junction. $Permissions = $PermissionModel->getJunctionPermissions(array('JunctionID' => $CategoryID), 'Category', '', array('AddDefaults' => !$this->Category->CustomPermissions)); $Permissions = $PermissionModel->unpivotPermissions($Permissions, true); if ($this->deliveryType() == DELIVERY_TYPE_ALL) { $this->setData('PermissionData', $Permissions, true); } // Render default view $this->setData('Operation', 'Edit'); $this->setData('DisplayAsOptions', $displayAsOptions); $this->render(); }