/** * Find the given folder or create it as a database record * * @param string $folderPath Directory path relative to assets root * @return Folder|null */ public static function find_or_make($folderPath) { // replace leading and trailing slashes $folderPath = preg_replace('/^\\/?(.*)\\/?$/', '$1', trim($folderPath)); $parts = explode("/", $folderPath); $parentID = 0; $item = null; $filter = FileNameFilter::create(); foreach ($parts as $part) { if (!$part) { continue; // happens for paths with a trailing slash } // Ensure search includes folders with illegal characters removed, but // err in favour of matching existing folders if $folderPath // includes illegal characters itself. $partSafe = $filter->filter($part); $item = Folder::get()->filter(array('ParentID' => $parentID, 'Name' => array($partSafe, $part)))->first(); if (!$item) { $item = new Folder(); $item->ParentID = $parentID; $item->Name = $partSafe; $item->Title = $part; $item->write(); } $parentID = $item->ID; } return $item; }
/** * Description * @return string */ protected function determineFolderName() { // Grab paths $paths = Config::inst()->get(__CLASS__, 'upload_paths'); // Grab ancestry from top-down $className = get_class($this->record); $classes = array_reverse(ClassInfo::ancestry($className)); $path = $className; // Loop over ancestry and break out if we have a match foreach ($classes as $class) { if (array_key_exists($class, $paths)) { $path = $paths[$class]; break; } } // If there are any parameters which require matching, search for them $matches = array(); preg_match_all('/\\$[a-zA-Z0-9]+?/U', $path, $matches); // Replace with field values foreach ($matches[0] as $match) { $field = str_replace("\$", "", $match); $value = FileNameFilter::create()->filter($this->record->getField($field)); $path = str_replace($match, $value, $path); } $this->folderName = $path; return $path; }
public function onBeforeWrite() { parent::onBeforeWrite(); $this->Title = FileNameFilter::create()->filter($this->Title); if (strlen($this->ContentFile)) { $templates = $this->fileBasedTemplates(); if (!isset($templates[$this->ContentFile])) { $this->ContentFile = ''; } } }
/** * Save an file passed from a form post into this object. * * @param $tmpFile array Indexed array that PHP generated for every file it uploads. * @param $folderPath string Folder path relative to /assets * @return Boolean|string Either success or error-message. */ public function load($tmpFile, $folderPath = false) { if (!$folderPath) { $folderPath = Config::inst()->get('Upload', 'uploads_folder'); } // @TODO This puts a HUGE limitation on files especially when lots // have been uploaded. $base = Director::baseFolder(); $parentFolder = Folder::find_or_make($folderPath); // Generate default filename $fileArray = explode('/', $tmpFile); $fileName = $fileArray[count($fileArray) - 1]; $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($fileName); $fileName = basename($file); $relativeFilePath = ASSETS_DIR . "/" . $folderPath . "/{$fileName}"; // if filename already exists, version the filename (e.g. test.gif to test1.gif) while (file_exists("{$base}/{$relativeFilePath}")) { $i = isset($i) ? $i + 1 : 2; $oldFilePath = $relativeFilePath; // make sure archives retain valid extensions if (substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.gz')) == '.tar.gz' || substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.bz2')) == '.tar.bz2') { $relativeFilePath = preg_replace('/[0-9]*(\\.tar\\.[^.]+$)/', $i . '\\1', $relativeFilePath); } else { if (strpos($relativeFilePath, '.') !== false) { $relativeFilePath = preg_replace('/[0-9]*(\\.[^.]+$)/', $i . '\\1', $relativeFilePath); } else { if (strpos($relativeFilePath, '_') !== false) { $relativeFilePath = preg_replace('/_([^_]+$)/', '_' . $i, $relativeFilePath); } else { $relativeFilePath .= '_' . $i; } } } if ($oldFilePath == $relativeFilePath && $i > 2) { user_error("Couldn't fix {$relativeFilePath} with {$i} tries", E_USER_ERROR); } } if (file_exists($tmpFile) && copy($tmpFile, $base . "/" . $relativeFilePath)) { $this->owner->ParentID = $parentFolder->ID; // This is to prevent it from trying to rename the file $this->owner->Name = basename($relativeFilePath); $this->owner->write(); return true; } else { return false; } }
public function getPdfPreviewImage() { $pdfFile = Director::getAbsFile($this->owner->getFileName()); $pathInfo = pathinfo($pdfFile); if (strtolower($pathInfo['extension']) != 'pdf') { //@Todo if dev then exception? else fail silently return null; } $fileName = $pathInfo['filename']; $savePath = __DIR__ . '/../../'; $saveImage = $this->imagePrefix . '-' . $fileName . '.jpg'; // Fix illegal characters $filter = FileNameFilter::create(); $saveImage = $filter->filter($saveImage); $saveTo = $savePath . $this->folderToSave . $saveImage; $image = DataObject::get_one('Image', "`Name` = '{$saveImage}'"); if (!$image) { $folderObject = DataObject::get_one("Folder", "`Filename` = '{$this->folderToSave}'"); if ($folderObject) { if ($this->generator->generatePreviewImage($pdfFile, $saveTo)) { $image = new Image(); $image->ParentID = $folderObject->ID; $image->setName($saveImage); $image->write(); } } } else { //check LastEdited to update $cacheInValid = false; if (strtotime($image->LastEdited) < strtotime($this->owner->LastEdited)) { $cacheInValid = true; } if ($cacheInValid) { $this->generator->generatePreviewImage($pdfFile, $saveTo); $image->setName($saveImage); $image->write(false, false, true); } } return $image; }
public function createPdf() { $storeIn = $this->getStorageFolder(); $name = FileNameFilter::create()->filter($this->Title); $name .= '.pdf'; if (!$name) { throw new Exception("Must have a name!"); } if (!$this->Template) { throw new Exception("Please specify a template before rendering."); } $file = new ComposedPdfFile(); $file->ParentID = $storeIn->ID; $file->SourceID = $this->ID; $file->Title = $this->Title; $file->setName($name); $file->write(); $content = $this->renderPdf(); $filename = singleton('PdfRenditionService')->render($content); if (file_exists($filename)) { copy($filename, $file->getFullPath()); unlink($filename); } }
/** * Setter function for Name. Automatically sets a default title, * and removes characters that might be invalid on the filesystem. * Also adds a suffix to the name if the filename already exists * on the filesystem, and is associated to a different {@link File} database record * in the same folder. This means "myfile.jpg" might become "myfile-1.jpg". * * Does not change the filesystem itself, please use {@link write()} for this. * * @param String $name */ function setName($name) { $oldName = $this->Name; // It can't be blank, default to Title if (!$name) { $name = $this->Title; } // Fix illegal characters $filter = FileNameFilter::create(); $name = $filter->filter($name); // We might have just turned it blank, so check again. if (!$name) { $name = 'new-folder'; } // If it's changed, check for duplicates if ($oldName && $oldName != $name) { $base = pathinfo($name, PATHINFO_BASENAME); $ext = self::get_file_extension($name); $suffix = 1; while (DataObject::get_one("File", "\"Name\" = '" . Convert::raw2sql($name) . "' AND \"ParentID\" = " . (int) $this->ParentID)) { $suffix++; $name = "{$base}-{$suffix}{$ext}"; } } // Update title if (!$this->getField('Title')) { $this->__set('Title', str_replace(array('-', '_'), ' ', preg_replace('/\\.[^.]+$/', '', $name))); } // Update actual field value $this->setField('Name', $name); // Ensure that the filename is updated as well (only in-memory) // Important: Circumvent the getter to avoid infinite loops $this->setField('Filename', $this->getRelativePath()); return $this->getField('Name'); }
/** * Given a temporary file and upload path, validate the file and determine the * value of the 'Filename' tuple that should be used to store this asset. * * @param array $tmpFile * @param string $folderPath * @return string|false Value of filename tuple, or false if invalid */ protected function getValidFilename($tmpFile, $folderPath = null) { if (!is_array($tmpFile)) { throw new InvalidArgumentException("Upload::load() Not passed an array. Most likely, the form hasn't got the right enctype"); } // Validate $this->clearErrors(); $valid = $this->validate($tmpFile); if (!$valid) { return false; } // Clean filename if (!$folderPath) { $folderPath = $this->config()->uploads_folder; } $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($tmpFile['name']); $filename = basename($file); if ($folderPath) { $filename = File::join_paths($folderPath, $filename); } return $filename; }
/** * Save an file passed from a form post into this object. * File names are filtered through {@link FileNameFilter}, see class documentation * on how to influence this behaviour. * * @param $tmpFile array Indexed array that PHP generated for every file it uploads. * @param $folderPath string Folder path relative to /assets * @return Boolean|string Either success or error-message. */ public function load($tmpFile, $folderPath = false) { if (!is_array($tmpFile)) { throw new InvalidArgumentException("Upload::load() Not passed an array. Most likely, the form hasn't got the right enctype"); } // Validate $this->clearErrors(); $valid = $this->validate($tmpFile); if (!$valid) { return false; } // Clean filename if (!$folderPath) { $folderPath = $this->config()->uploads_folder; } $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($tmpFile['name']); $filename = basename($file); if ($folderPath) { $filename = File::join_paths($folderPath, $filename); } // Validate filename $filename = $this->resolveExistingFile($filename); // Save file into backend $conflictResolution = $this->replaceFile ? AssetStore::CONFLICT_OVERWRITE : AssetStore::CONFLICT_RENAME; $this->file->setFromLocalFile($tmpFile['tmp_name'], $filename, null, null, $conflictResolution); // Save changes to underlying record (if it's a DataObject) if ($this->file instanceof DataObject) { $this->file->write(); } //to allow extensions to e.g. create a version after an upload $this->file->extend('onAfterUpload'); $this->extend('onAfterLoad', $this->file); return true; }
/** * Save an file passed from a form post into this object. * File names are filtered through {@link FileNameFilter}, see class documentation * on how to influence this behaviour. * * @param $tmpFile array Indexed array that PHP generated for every file it uploads. * @param $folderPath string Folder path relative to /assets * @return Boolean|string Either success or error-message. */ public function load($tmpFile, $folderPath = false) { $this->clearErrors(); if (!$folderPath) { $folderPath = $this->config()->uploads_folder; } if (!is_array($tmpFile)) { user_error("Upload::load() Not passed an array. Most likely, the form hasn't got the right enctype", E_USER_ERROR); } if (!$tmpFile['size']) { $this->errors[] = _t('File.NOFILESIZE', 'Filesize is zero bytes.'); return false; } $valid = $this->validate($tmpFile); if (!$valid) { return false; } // @TODO This puts a HUGE limitation on files especially when lots // have been uploaded. $base = Director::baseFolder(); $parentFolder = Folder::find_or_make($folderPath); // Generate default filename $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($tmpFile['name']); $fileName = basename($file); $relativeFolderPath = $parentFolder ? $parentFolder->getRelativePath() : ASSETS_DIR . '/'; $relativeFilePath = $relativeFolderPath . $fileName; // Create a new file record (or try to retrieve an existing one) if (!$this->file) { $fileClass = File::get_class_for_file_extension(pathinfo($tmpFile['name'], PATHINFO_EXTENSION)); $this->file = new $fileClass(); } if (!$this->file->ID && $this->replaceFile) { $fileClass = $this->file->class; $file = File::get()->filter(array('ClassName' => $fileClass, 'Name' => $fileName, 'ParentID' => $parentFolder ? $parentFolder->ID : 0))->First(); if ($file) { $this->file = $file; } } // if filename already exists, version the filename (e.g. test.gif to test2.gif, test2.gif to test3.gif) if (!$this->replaceFile) { $fileSuffixArray = explode('.', $fileName); $fileTitle = array_shift($fileSuffixArray); $fileSuffix = !empty($fileSuffixArray) ? '.' . implode('.', $fileSuffixArray) : null; // make sure files retain valid extensions $oldFilePath = $relativeFilePath; $relativeFilePath = $relativeFolderPath . $fileTitle . $fileSuffix; if ($oldFilePath !== $relativeFilePath) { user_error("Couldn't fix {$relativeFilePath}", E_USER_ERROR); } while (file_exists("{$base}/{$relativeFilePath}")) { $i = isset($i) ? $i + 1 : 2; $oldFilePath = $relativeFilePath; $pattern = '/([0-9]+$)/'; if (preg_match($pattern, $fileTitle)) { $fileTitle = preg_replace($pattern, $i, $fileTitle); } else { $fileTitle .= $i; } $relativeFilePath = $relativeFolderPath . $fileTitle . $fileSuffix; if ($oldFilePath == $relativeFilePath && $i > 2) { user_error("Couldn't fix {$relativeFilePath} with {$i} tries", E_USER_ERROR); } } } else { //reset the ownerID to the current member when replacing files $this->file->OwnerID = Member::currentUser() ? Member::currentUser()->ID : 0; } if (file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], "{$base}/{$relativeFilePath}")) { $this->file->ParentID = $parentFolder ? $parentFolder->ID : 0; // This is to prevent it from trying to rename the file $this->file->Name = basename($relativeFilePath); $this->file->write(); $this->file->onAfterUpload(); $this->extend('onAfterLoad', $this->file); //to allow extensions to e.g. create a version after an upload return true; } else { $this->errors[] = _t('File.NOFILESIZE', 'Filesize is zero bytes.'); return false; } }
/** * Adds a new image to the given product. * * @param SilvercartProduct $product Product to add image to * @param string $filename Filename * @param string $description Description * @param int $consecutiveNumber Consecutive number */ protected function addNewImage(SilvercartProduct $product, $filename, $description, $consecutiveNumber) { $fileEnding = strrev(substr(strrev($filename), 0, strpos(strrev($filename), '.'))); $nameFilter = FileNameFilter::create(); $targetFilename = $product->ProductNumberShop . '-' . $nameFilter->filter($product->Title) . '-' . $consecutiveNumber . '.' . $fileEnding; $originalFile = self::get_absolute_upload_folder() . '/' . $filename; $targetFile = self::get_absolute_product_image_folder() . '/' . $targetFilename; $parentFolder = Folder::find_or_make('Uploads/product-images'); rename($originalFile, $targetFile); $image = new Image(); $image->Name = basename($targetFilename); $image->ParentID = $parentFolder->ID; $image->write(); $silvercartImage = new SilvercartImage(); $silvercartImage->ImageID = $image->ID; $silvercartImage->Title = $description; $silvercartImage->write(); $product->SilvercartImages()->add($silvercartImage); }
public function EnquiryForm() { if (!Email::validEmailAddress($this->EmailTo) || !Email::validEmailAddress($this->EmailFrom)) { return false; } if (!$this->EmailSubject) { $this->EmailSubject = 'Website Enquiry'; } $elements = $this->EnquiryFormFields(); /* empty form, return nothing */ if ($elements->count() == 0) { return false; } /* Build the fieldlist */ $fields = FieldList::create(); $validator = RequiredFields::create(); $jsValidator = array(); /* Create filter for possible $_GET parameters / pre-population */ $get_param_filter = FileNameFilter::create(); foreach ($elements as $el) { $key = $this->keyGen($el->FieldName, $el->SortOrder); $field = false; $type = false; if ($el->FieldType == 'Text') { if ($el->FieldOptions == 1) { $field = TextField::create($key, htmlspecialchars($el->FieldName)); } else { $field = TextareaField::create($key, htmlspecialchars($el->FieldName)); $field->setRows($el->FieldOptions); } } elseif ($el->FieldType == 'Email') { $field = EmailField::create($key, htmlspecialchars($el->FieldName)); } elseif ($el->FieldType == 'Select') { $options = preg_split('/\\n\\r?/', $el->FieldOptions, -1, PREG_SPLIT_NO_EMPTY); if (count($options) > 0) { $tmp = array(); foreach ($options as $o) { $tmp[trim($o)] = trim($o); } $field = DropdownField::create($key, htmlspecialchars($el->FieldName), $tmp); $field->setEmptyString('[ Please Select ]'); } } elseif ($el->FieldType == 'Checkbox') { $options = preg_split('/\\n\\r?/', $el->FieldOptions, -1, PREG_SPLIT_NO_EMPTY); if (count($options) > 0) { $tmp = array(); foreach ($options as $o) { $tmp[trim($o)] = trim($o); } $field = CheckboxSetField::create($key, htmlspecialchars($el->FieldName), $tmp); } } elseif ($el->FieldType == 'Radio') { $options = preg_split('/\\n\\r?/', $el->FieldOptions, -1, PREG_SPLIT_NO_EMPTY); if (count($options) > 0) { $tmp = array(); foreach ($options as $o) { $tmp[trim($o)] = trim($o); } $field = OptionsetField::create($key, htmlspecialchars($el->FieldName), $tmp); } } elseif ($el->FieldType == 'Header') { if ($el->FieldOptions) { $field = LiteralField::create(htmlspecialchars($el->FieldName), '<h4>' . htmlspecialchars($el->FieldName) . '</h4> <p class="note">' . nl2br(htmlspecialchars($el->FieldOptions)) . '</p>'); } else { $field = HeaderField::create(htmlspecialchars($el->FieldName), 4); } } elseif ($el->FieldType == 'Note') { if ($el->FieldOptions) { $field = LiteralField::create(htmlspecialchars($el->FieldName), '<p class="note">' . nl2br(htmlspecialchars($el->FieldOptions)) . '</p>'); } else { $field = LiteralField::create(htmlspecialchars($el->FieldName), '<p class="note">' . htmlspecialchars($el->FieldName) . '</p>'); } } if ($field) { /* Allow $_GET parameters to pre-populate fields */ $request = $this->request; $get_var = $get_param_filter->filter($el->FieldName); if (!$request->isPOST() && !$field->Value() && null != $request->getVar($get_var)) { $field->setValue($request->getVar($get_var)); } if ($el->RequiredField == 1) { $field->addExtraClass('required'); /* Add "Required" next to field" */ $validator->addRequiredField($key); $jsValidator[$key] = $el->FieldType; } if ($el->PlaceholderText) { $field->setAttribute('placeholder', $el->PlaceholderText); } $fields->push($field); } } if ($this->AddCaptcha) { $label = $this->CaptchaLabel; $field = CaptchaField::create('CaptchaImage', $label); $field->addExtraClass('required'); $validator->addRequiredField('CaptchaImage'); $jsValidator['CaptchaImage'] = 'Text'; if ($this->CaptchaHelp) { $field->setRightTitle('<span id="CaptchaHelp">' . htmlspecialchars($this->CaptchaHelp) . '</span>'); } $fields->push($field); } $actions = FieldList::create(FormAction::create('SendEnquiryForm', $this->EmailSubmitButtonText)); if (Config::inst()->get('EnquiryPage', 'js_validation')) { Requirements::customScript('var EnquiryFormValidator=' . json_encode($jsValidator) . ';'); Requirements::javascript(basename(dirname(dirname(__FILE__))) . '/javascript/enquiryform.js'); } $form = Form::create($this, 'EnquiryForm', $fields, $actions, $validator); return $form; }
/** * Get the sanitised log path. * @return string */ public function getSanitisedLogFilePath() { return $this->basePath . '/' . strtolower(FileNameFilter::create()->filter($this->logFile)); }
/** * Determines if a specified file exists * * @param SS_HTTPRequest $request */ public function fileexists(SS_HTTPRequest $request) { // Check both original and safely filtered filename $originalFile = $request->requestVar('filename'); $nameFilter = FileNameFilter::create(); $filteredFile = basename($nameFilter->filter($originalFile)); // check if either file exists $folder = $this->getFolderName(); $exists = false; foreach (array($originalFile, $filteredFile) as $file) { if (file_exists(ASSETS_PATH . "/{$folder}/{$file}")) { $exists = true; break; } } // Encode and present response $response = new SS_HTTPResponse(Convert::raw2json(array('exists' => $exists))); $response->addHeader('Content-Type', 'application/json'); return $response; }
/** * Take a file uploaded via a POST form, and save it inside this folder. * File names are filtered through {@link FileNameFilter}, see class documentation * on how to influence this behaviour. */ function addUploadToFolder($tmpFile) { if(!is_array($tmpFile)) { user_error("Folder::addUploadToFolder() Not passed an array. Most likely, the form hasn't got the right enctype", E_USER_ERROR); } if(!isset($tmpFile['size'])) { return; } $base = BASE_PATH; // $parentFolder = Folder::findOrMake("Uploads"); // Generate default filename $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($tmpFile['name']); while($file[0] == '_' || $file[0] == '.') { $file = substr($file, 1); } $file = $this->RelativePath . $file; Filesystem::makeFolder(dirname("$base/$file")); $doubleBarrelledExts = array('.gz', '.bz', '.bz2'); $ext = ""; if(preg_match('/^(.*)(\.[^.]+)$/', $file, $matches)) { $file = $matches[1]; $ext = $matches[2]; // Special case for double-barrelled if(in_array($ext, $doubleBarrelledExts) && preg_match('/^(.*)(\.[^.]+)$/', $file, $matches)) { $file = $matches[1]; $ext = $matches[2] . $ext; } } $origFile = $file; $i = 1; while(file_exists("$base/$file$ext")) { $i++; $oldFile = $file; if(strpos($file, '.') !== false) { $file = preg_replace('/[0-9]*(\.[^.]+$)/', $i . '\\1', $file); } elseif(strpos($file, '_') !== false) { $file = preg_replace('/_([^_]+$)/', '_' . $i, $file); } else { $file .= '_'.$i; } if($oldFile == $file && $i > 2) user_error("Couldn't fix $file$ext with $i", E_USER_ERROR); } if (move_uploaded_file($tmpFile['tmp_name'], "$base/$file$ext")) { // Update with the new image return $this->constructChild(basename($file . $ext)); } else { if(!file_exists($tmpFile['tmp_name'])) user_error("Folder::addUploadToFolder: '$tmpFile[tmp_name]' doesn't exist", E_USER_ERROR); else user_error("Folder::addUploadToFolder: Couldn't copy '$tmpFile[tmp_name]' to '$base/$file$ext'", E_USER_ERROR); return false; } }
/** * Folder name sanitizer. * Checks for valid names and sanitizes * against directory traversal. * * @param string $foldername * @return string */ public static function sanitize_folder_name($foldername) { //return $foldername; return FileNameFilter::create()->filter(basename($foldername)); }
/** * File names are filtered through {@link FileNameFilter}, see class documentation * on how to influence this behaviour. * * @deprecated 3.2 */ public function loadUploadedImage($tmpFile) { Deprecation::notice('3.2', 'Use the Upload::loadIntoFile()'); if (!is_array($tmpFile)) { user_error("Image::loadUploadedImage() Not passed an array. Most likely, the form hasn't got the right" . "enctype", E_USER_ERROR); } if (!$tmpFile['size']) { return; } $class = $this->class; // Create a folder if (!file_exists(ASSETS_PATH)) { mkdir(ASSETS_PATH, Config::inst()->get('Filesystem', 'folder_create_mask')); } if (!file_exists(ASSETS_PATH . "/{$class}")) { mkdir(ASSETS_PATH . "/{$class}", Config::inst()->get('Filesystem', 'folder_create_mask')); } // Generate default filename $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($tmpFile['name']); if (!$file) { $file = "file.jpg"; } $file = ASSETS_PATH . "/{$class}/{$file}"; while (file_exists(BASE_PATH . "/{$file}")) { $i = $i ? $i + 1 : 2; $oldFile = $file; $file = preg_replace('/[0-9]*(\\.[^.]+$)/', $i . '\\1', $file); if ($oldFile == $file && $i > 2) { user_error("Couldn't fix {$file} with {$i}", E_USER_ERROR); } } if (file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], BASE_PATH . "/{$file}")) { // Remove the old images $this->deleteFormattedImages(); return true; } }
/** * Save an file passed from a form post into this object. * File names are filtered through {@link FileNameFilter}, see class documentation * on how to influence this behaviour. * * @param $tmpFile array Indexed array that PHP generated for every file it uploads. * @param $folderPath string Folder path relative to /assets * @return Boolean|string Either success or error-message. */ function load($tmpFile, $folderPath = false) { $this->clearErrors(); if(!$folderPath) $folderPath = self::$uploads_folder; if(!$this->file) { $fileClass = File::get_class_for_file_extension(pathinfo($tmpFile['name'], PATHINFO_EXTENSION)); $this->file = new $fileClass(); } if(!is_array($tmpFile)) { user_error("Upload::load() Not passed an array. Most likely, the form hasn't got the right enctype", E_USER_ERROR); } if(!$tmpFile['size']) { $this->errors[] = _t('File.NOFILESIZE', 'Filesize is zero bytes.'); return false; } $valid = $this->validate($tmpFile); if(!$valid) return false; // @TODO This puts a HUGE limitation on files especially when lots // have been uploaded. $base = Director::baseFolder(); $parentFolder = Folder::find_or_make($folderPath); // Create a folder for uploading. if(!file_exists(ASSETS_PATH)){ mkdir(ASSETS_PATH, Filesystem::$folder_create_mask); } if(!file_exists(ASSETS_PATH . "/" . $folderPath)){ mkdir(ASSETS_PATH . "/" . $folderPath, Filesystem::$folder_create_mask); } // Generate default filename $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($tmpFile['name']); $fileName = basename($file); $relativeFilePath = ASSETS_DIR . "/" . $folderPath . "/$fileName"; // if filename already exists, version the filename (e.g. test.gif to test1.gif) while(file_exists("$base/$relativeFilePath")) { $i = isset($i) ? ($i+1) : 2; $oldFilePath = $relativeFilePath; // make sure archives retain valid extensions if(substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.gz')) == '.tar.gz' || substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.bz2')) == '.tar.bz2') { $relativeFilePath = preg_replace('/[0-9]*(\.tar\.[^.]+$)/', $i . '\\1', $relativeFilePath); } else if (strpos($relativeFilePath, '.') !== false) { $relativeFilePath = preg_replace('/[0-9]*(\.[^.]+$)/', $i . '\\1', $relativeFilePath); } else if (strpos($relativeFilePath, '_') !== false) { $relativeFilePath = preg_replace('/_([^_]+$)/', '_'.$i, $relativeFilePath); } else { $relativeFilePath .= '_'.$i; } if($oldFilePath == $relativeFilePath && $i > 2) user_error("Couldn't fix $relativeFilePath with $i tries", E_USER_ERROR); } if(file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], "$base/$relativeFilePath")) { $this->file->ParentID = $parentFolder->ID; // This is to prevent it from trying to rename the file $this->file->Name = basename($relativeFilePath); $this->file->write(); return true; } else { $this->errors[] = _t('File.NOFILESIZE', 'Filesize is zero bytes.'); return false; } }
/** * Returns a path unique to a specific transfer, including project/environment details. * Does not create the path on the filesystem. Can be used to store files related to this transfer. * * @param DNDataTransfer * @return String Absolute file path */ public function generateFilepath(DNDataTransfer $dataTransfer) { $data = DNData::inst(); $transferDir = $data->getDataTransferDir(); $filter = FileNameFilter::create(); return sprintf('%s/%s/%s/transfer-%s/', $transferDir, $filter->filter(strtolower($this->OriginalEnvironment()->Project()->Name)), $filter->filter(strtolower($this->OriginalEnvironment()->Name)), $dataTransfer->ID); }
/** * Generates an actual report file. * * @param string $format */ public function generateReport($format = 'html') { $field = strtoupper($format) . 'FileID'; $storeIn = $this->getReportFolder(); // SS hates spaces in here :( $name = preg_replace('/ +/', '-', trim($this->Title)); $name = $name . '.' . $format; $name = FileNameFilter::create()->filter($name); $childId = $storeIn->constructChild($name); $file = DataObject::get_by_id('File', $childId); // it's a new file, so trigger the onAfterUpload method for extensions that expect it if (method_exists($file, 'onAfterUpload')) { $file->onAfterUpload(); } // okay, now we should copy across... right? $file->setName($name); $file->write(); // create the raw report file $output = $this->createReport($format, true); if (is_object($output)) { if (file_exists($output->filename)) { if ($this->config()->store_file_content) { $file->Content = base64_encode(file_get_contents($output->filename)); $file->write(); } else { copy($output->filename, $file->getFullPath()); } } } // make sure to set the appropriate ID $this->{$field} = $file->ID; $this->write(); }
/** * Save an file passed from a form post into this object. * File names are filtered through {@link FileNameFilter}, see class documentation * on how to influence this behaviour. * * @param $tmpFile array Indexed array that PHP generated for every file it uploads. * @param $folderPath string Folder path relative to /assets * @return Boolean|string Either success or error-message. */ public function load($tmpFile, $folderPath = false) { $this->clearErrors(); if (!$folderPath) { $folderPath = $this->config()->uploads_folder; } if (!is_array($tmpFile)) { user_error("Upload::load() Not passed an array. Most likely, the form hasn't got the right enctype", E_USER_ERROR); } if (!$tmpFile['size']) { $this->errors[] = _t('File.NOFILESIZE', 'Filesize is zero bytes.'); return false; } $valid = $this->validate($tmpFile); if (!$valid) { return false; } // @TODO This puts a HUGE limitation on files especially when lots // have been uploaded. $base = Director::baseFolder(); $parentFolder = Folder::find_or_make($folderPath); // Create a folder for uploading. if (!file_exists(ASSETS_PATH . "/" . $folderPath)) { Filesystem::makeFolder(ASSETS_PATH . "/" . $folderPath); } // Generate default filename $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($tmpFile['name']); $fileName = basename($file); $relativeFilePath = ASSETS_DIR . "/" . $folderPath . "/{$fileName}"; // Create a new file record (or try to retrieve an existing one) if (!$this->file) { $fileClass = File::get_class_for_file_extension(pathinfo($tmpFile['name'], PATHINFO_EXTENSION)); if ($this->replaceFile) { $this->file = File::get()->filter(array('Name' => $fileName, 'ParentID' => $parentFolder ? $parentFolder->ID : 0))->First(); } if (!$this->file) { $this->file = new $fileClass(); } } // if filename already exists, version the filename (e.g. test.gif to test1.gif) if (!$this->replaceFile) { while (file_exists("{$base}/{$relativeFilePath}")) { $i = isset($i) ? $i + 1 : 2; $oldFilePath = $relativeFilePath; // make sure archives retain valid extensions if (substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.gz')) == '.tar.gz' || substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.bz2')) == '.tar.bz2') { $relativeFilePath = preg_replace('/[0-9]*(\\.tar\\.[^.]+$)/', $i . '\\1', $relativeFilePath); } else { if (strpos($relativeFilePath, '.') !== false) { $relativeFilePath = preg_replace('/[0-9]*(\\.[^.]+$)/', $i . '\\1', $relativeFilePath); } else { if (strpos($relativeFilePath, '_') !== false) { $relativeFilePath = preg_replace('/_([^_]+$)/', '_' . $i, $relativeFilePath); } else { $relativeFilePath .= '_' . $i; } } } if ($oldFilePath == $relativeFilePath && $i > 2) { user_error("Couldn't fix {$relativeFilePath} with {$i} tries", E_USER_ERROR); } } } else { //reset the ownerID to the current member when replacing files $this->file->OwnerID = Member::currentUser() ? Member::currentUser()->ID : 0; } if (file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], "{$base}/{$relativeFilePath}")) { $this->file->ParentID = $parentFolder ? $parentFolder->ID : 0; // This is to prevent it from trying to rename the file $this->file->Name = basename($relativeFilePath); $this->file->write(); $this->extend('onAfterLoad', $this->file); //to allow extensions to e.g. create a version after an upload return true; } else { $this->errors[] = _t('File.NOFILESIZE', 'Filesize is zero bytes.'); return false; } }
/** * Find the given folder or create it both as {@link Folder} database record * and on the filesystem. If necessary, creates parent folders as well. If it's * unable to find or make the folder, it will return null (as /assets is unable * to be represented by a Folder {@link DataObject}). * * @param string $folderPath Absolute or relative path to the file. * If path is relative, it's interpreted relative * to the "assets/" directory. * @return Folder | null */ public static function find_or_make_secured($folderPath) { // Create assets directory, if it is missing if (!file_exists(ASSETS_PATH)) { Filesystem::makeFolder(ASSETS_PATH); } $folderPath = trim(Director::makeRelative($folderPath)); // replace leading and trailing slashes $folderPath = preg_replace('/^\\/?(.*)\\/?$/', '$1', $folderPath); $parts = explode("/", $folderPath); $parentID = 0; $item = null; $filter = FileNameFilter::create(); foreach ($parts as $part) { if (!$part) { continue; // happens for paths with a trailing slash } // Ensure search includes folders with illegal characters removed, but // err in favour of matching existing folders if $folderPath // includes illegal characters itself. $partSafe = $filter->filter($part); $item = Folder::get()->filter(array('ParentID' => $parentID, 'Name' => array($partSafe, $part), 'CanViewType' => 'Anyone', 'CanEditType' => 'LoggedInUsers'))->first(); if (!$item) { $item = new Folder(); $item->ParentID = $parentID; $item->Name = $partSafe; $item->Title = $part; $item->Secured = true; $item->write(); // when initial the secured root folder, set its CanViewType to be if (!$parentID) { $item->CanViewType = 'Anyone'; $item->CanEditType = 'LoggedInUsers'; } } if (!file_exists($item->getFullPath())) { Filesystem::makeFolder($item->getFullPath()); } $parentID = $item->ID; } return $item; }
/** * Check if file exists, both checking filtered filename and exact filename * * @param string $originalFile Filename * @return bool */ protected function checkFileExists($originalFile) { // Check both original and safely filtered filename $nameFilter = FileNameFilter::create(); $filteredFile = $nameFilter->filter($originalFile); // Resolve expected folder name $folderName = $this->getFolderName(); $folder = Folder::find_or_make($folderName); $parentPath = $folder ? BASE_PATH . "/" . $folder->getFilename() : ASSETS_PATH . "/"; // check if either file exists return file_exists($parentPath . $originalFile) || file_exists($parentPath . $filteredFile); }
/** * Returns the location of the projects key dir if one exists. * * @return string|null */ public function getKeyDir() { $keyDir = $this->DNData()->getKeyDir(); if (!$keyDir) { return null; } $filter = FileNameFilter::create(); $name = $filter->filter($this->Name); return $this->DNData()->getKeyDir() . '/' . $name; }
/** * Setter function for Name. Automatically sets a default title, * and removes characters that might be invalid on the filesystem. * Also adds a suffix to the name if the filename already exists * on the filesystem, and is associated to a different {@link File} database record * in the same folder. This means "myfile.jpg" might become "myfile-1.jpg". * * Does not change the filesystem itself, please use {@link write()} for this. * * @param String $name */ public function setName($name) { $oldName = $this->Name; // It can't be blank, default to Title if (!$name) { $name = $this->Title; } // Fix illegal characters $filter = FileNameFilter::create(); $name = $filter->filter($name); // We might have just turned it blank, so check again. if (!$name) { $name = 'new-folder'; } // If it's changed, check for duplicates if ($oldName && $oldName != $name) { $base = pathinfo($name, PATHINFO_FILENAME); $ext = self::get_file_extension($name); $suffix = 1; while (File::get()->filter(array('Name' => $name, 'ParentID' => (int) $this->ParentID))->exclude(array('ID' => $this->ID))->first()) { $suffix++; $name = "{$base}-{$suffix}.{$ext}"; } } // Update actual field value $this->setField('Name', $name); // Ensure that the filename is updated as well (only in-memory) // Important: Circumvent the getter to avoid infinite loops $this->setField('Filename', $this->getRelativePath()); // Update title if (!$this->Title) { $this->Title = str_replace(array('-', '_'), ' ', preg_replace('/\\.[^.]+$/', '', $name)); } return $name; }
/** * Handles media objects from kapost * @param {mixed} $blog_id Site Config related to this content object * @param {array} $content Content object to be handled * @return {xmlrpcresp} XML-RPC Response object */ protected function newMediaObject($blog_id, $content) { $fileName = $content['name']; $validator = new Upload_Validator(array('name' => $fileName)); $validator->setAllowedExtensions(File::config()->allowed_extensions); //Verify we have a valid extension if ($validator->isValidExtension() == false) { return $this->httpError(403, _t('KapostService.FILE_NOT_ALLOWED', '_File extension is not allowed')); } //Generate default filename $nameFilter = FileNameFilter::create(); $file = $nameFilter->filter($fileName); while ($file[0] == '_' || $file[0] == '.') { $file = substr($file, 1); } $doubleBarrelledExts = array('.gz', '.bz', '.bz2'); $ext = ""; if (preg_match('/^(.*)(\\.[^.]+)$/', $file, $matches)) { $file = $matches[1]; $ext = $matches[2]; // Special case for double-barrelled if (in_array($ext, $doubleBarrelledExts) && preg_match('/^(.*)(\\.[^.]+)$/', $file, $matches)) { $file = $matches[1]; $ext = $matches[2] . $ext; } } $origFile = $file; //Find the kapost media folder $kapostMediaFolder = Folder::find_or_make($this->config()->kapost_media_folder); if (file_exists($kapostMediaFolder->getFullPath() . '/' . $file . $ext)) { if (self::config()->duplicate_assets == 'overwrite') { $obj = File::get()->filter('Filename', Convert::raw2sql($kapostMediaFolder->Filename . $file . $ext))->first(); if (!empty($obj) && $obj !== false && $obj->ID > 0) { //Update the Title for the image $obj->Title = !empty($content['alt']) ? $content['alt'] : str_replace(array('-', '_'), ' ', preg_replace('/\\.[^.]+$/', '', $obj->Name)); $obj->write(); //Write the file to the file system $f = fopen($kapostMediaFolder->getFullPath() . '/' . $file . $ext, 'w'); fwrite($f, $content['bits']); fclose($f); return array('id' => $obj->ID, 'url' => $obj->getAbsoluteURL()); } return $this->httpError(404, _t('KapostService.FILE_NOT_FOUND', '_File not found')); } else { if (self::config()->duplicate_assets == 'ignore') { return $this->httpError(409, _t('KapostService.DUPLICATE_FILE', '_Duplicate file detected, please rename the file and try again')); } else { if (self::config()->duplicate_assets == 'smart_rename' && file_exists($kapostMediaFolder->getFullPath() . '/' . $file . $ext)) { $obj = File::get()->filter('Filename', Convert::raw2sql($kapostMediaFolder->Filename . $file . $ext))->first(); if (!empty($obj) && $obj !== false && $obj->ID > 0) { $fileHash = sha1_file($kapostMediaFolder->getFullPath() . '/' . $file . $ext); if ($fileHash == sha1($content['bits'])) { return array('id' => $obj->ID, 'url' => $obj->getAbsoluteURL()); } } } $i = 1; while (file_exists($kapostMediaFolder->getFullPath() . '/' . $file . $ext)) { $i++; $oldFile = $file; if (strpos($file, '.') !== false) { $file = preg_replace('/[0-9]*(\\.[^.]+$)/', $i . '\\1', $file); } else { if (strpos($file, '_') !== false) { $file = preg_replace('/_([^_]+$)/', '_' . $i, $file); } else { $file .= '_' . $i; } } if ($oldFile == $file && $i > 2) { return $this->httpError(500, _t('KapostService.FILE_RENAME_FAIL', '_Could not fix {filename} with {attempts} attempts', array('filename' => $file . $ext, 'attempts' => $i))); } } //Write the file to the file system $f = fopen($kapostMediaFolder->getFullPath() . '/' . $file . $ext, 'w'); fwrite($f, $content['bits']); fclose($f); //Write the file to the database $className = File::get_class_for_file_extension(substr($ext, 1)); $obj = new $className(); $obj->Name = $file . $ext; $obj->Title = !empty($content['alt']) ? $content['alt'] : str_replace(array('-', '_'), ' ', preg_replace('/\\.[^.]+$/', '', $obj->Name)); $obj->FileName = $kapostMediaFolder->getRelativePath() . '/' . $file . $ext; $obj->ParentID = $kapostMediaFolder->ID; //If subsites is enabled add it to the correct subsite if (File::has_extension('FileSubsites')) { $obj->SubsiteID = $blog_id; } $obj->write(); $this->extend('updateNewMediaAsset', $blog_id, $content, $obj); return array('id' => $obj->ID, 'url' => $obj->getAbsoluteURL()); } } } else { //Write the file to the file system $f = fopen($kapostMediaFolder->getFullPath() . '/' . $file . $ext, 'w'); fwrite($f, $content['bits']); fclose($f); //Write the file to the database $className = File::get_class_for_file_extension(substr($ext, 1)); $obj = new $className(); $obj->Name = $file . $ext; $obj->Title = !empty($content['alt']) ? $content['alt'] : str_replace(array('-', '_'), ' ', preg_replace('/\\.[^.]+$/', '', $obj->Name)); $obj->FileName = $kapostMediaFolder->getRelativePath() . '/' . $file . $ext; $obj->ParentID = $kapostMediaFolder->ID; //If subsites is enabled add it to the correct subsite if (File::has_extension('FileSubsites')) { $obj->SubsiteID = $blog_id; } $obj->write(); $this->extend('updateNewMediaAsset', $blog_id, $content, $obj); return array('id' => $obj->ID, 'url' => $obj->getAbsoluteURL()); } }