/** * Handle a form submission. GET and POST requests behave identically. * Populates the form with {@link loadDataFrom()}, calls {@link validate()}, * and only triggers the requested form action/method * if the form is valid. * * @param HTTPRequest $request * @throws HTTPResponse_Exception */ public function httpSubmission($request) { // Strict method check if ($this->strictFormMethodCheck) { // Throws an error if the method is bad... if ($this->formMethod != $request->httpMethod()) { $response = Controller::curr()->getResponse(); $response->addHeader('Allow', $this->formMethod); $this->httpError(405, _t("Form.BAD_METHOD", "This form requires a " . $this->formMethod . " submission")); } // ...and only uses the variables corresponding to that method type $vars = $this->formMethod == 'GET' ? $request->getVars() : $request->postVars(); } else { $vars = $request->requestVars(); } // Populate the form $this->loadDataFrom($vars, true); // Protection against CSRF attacks $token = $this->getSecurityToken(); if (!$token->checkRequest($request)) { $securityID = $token->getName(); if (empty($vars[$securityID])) { $this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE", "There seems to have been a technical problem. Please click the back button, " . "refresh your browser, and try again.")); } else { // Clear invalid token on refresh $data = $this->getData(); unset($data[$securityID]); Session::set("FormInfo.{$this->FormName()}.data", $data); Session::set("FormInfo.{$this->FormName()}.errors", array()); $this->sessionMessage(_t("Form.CSRF_EXPIRED_MESSAGE", "Your session has expired. Please re-submit the form."), "warning"); return $this->controller->redirectBack(); } } // Determine the action button clicked $funcName = null; foreach ($vars as $paramName => $paramVal) { if (substr($paramName, 0, 7) == 'action_') { // Break off querystring arguments included in the action if (strpos($paramName, '?') !== false) { list($paramName, $paramVars) = explode('?', $paramName, 2); $newRequestParams = array(); parse_str($paramVars, $newRequestParams); $vars = array_merge((array) $vars, (array) $newRequestParams); } // Cleanup action_, _x and _y from image fields $funcName = preg_replace(array('/^action_/', '/_x$|_y$/'), '', $paramName); break; } } // If the action wasn't set, choose the default on the form. if (!isset($funcName) && ($defaultAction = $this->defaultAction())) { $funcName = $defaultAction->actionName(); } if (isset($funcName)) { $this->setButtonClicked($funcName); } // Permission checks (first on controller, then falling back to form) if ($this->controller->hasMethod($funcName) && !$this->controller->checkAccessAction($funcName) && !$this->buttonClicked()) { return $this->httpError(403, sprintf('Action "%s" not allowed on controller (Class: %s)', $funcName, get_class($this->controller))); } elseif ($this->hasMethod($funcName) && !$this->checkAccessAction($funcName)) { return $this->httpError(403, sprintf('Action "%s" not allowed on form (Name: "%s")', $funcName, $this->name)); } // TODO : Once we switch to a stricter policy regarding allowed_actions (meaning actions must be set // explicitly in allowed_actions in order to run) // Uncomment the following for checking security against running actions on form fields /* else { // Try to find a field that has the action, and allows it $fieldsHaveMethod = false; foreach ($this->Fields() as $field){ if ($field->hasMethod($funcName) && $field->checkAccessAction($funcName)) { $fieldsHaveMethod = true; } } if (!$fieldsHaveMethod) { return $this->httpError( 403, sprintf('Action "%s" not allowed on any fields of form (Name: "%s")', $funcName, $this->Name()) ); } }*/ // Validate the form if (!$this->validate()) { return $this->getValidationErrorResponse(); } // First, try a handler method on the controller (has been checked for allowed_actions above already) if ($this->controller->hasMethod($funcName)) { return $this->controller->{$funcName}($vars, $this, $request); // Otherwise, try a handler method on the form object. } elseif ($this->hasMethod($funcName)) { return $this->{$funcName}($vars, $this, $request); } elseif ($field = $this->checkFieldsForAction($this->Fields(), $funcName)) { return $field->{$funcName}($vars, $this, $request); } return $this->httpError(404); }
/** * Creates a single folder, within an optional parent folder. * * @param HTTPRequest $request * @return HTTPRequest|HTTPResponse */ public function apiCreateFolder(HTTPRequest $request) { $data = $request->postVars(); $class = 'SilverStripe\\Assets\\Folder'; // CSRF check $token = SecurityToken::inst(); if (empty($data[$token->getName()]) || !$token->check($data[$token->getName()])) { return new HTTPResponse(null, 400); } // check addchildren permissions /** @var Folder $parentRecord */ $parentRecord = null; if (!empty($data['ParentID']) && is_numeric($data['ParentID'])) { $parentRecord = DataObject::get_by_id($class, $data['ParentID']); } $data['Parent'] = $parentRecord; $data['ParentID'] = $parentRecord ? (int) $parentRecord->ID : 0; // Build filename $baseFilename = isset($data['Name']) ? basename($data['Name']) : _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.NEWFOLDER', "NewFolder"); if ($parentRecord && $parentRecord->ID) { $baseFilename = $parentRecord->getFilename() . '/' . $baseFilename; } // Ensure name is unique $nameGenerator = $this->getNameGenerator($baseFilename); $filename = null; foreach ($nameGenerator as $filename) { if (!File::find($filename)) { break; } } $data['Name'] = basename($filename); // Create record /** @var Folder $record */ $record = Injector::inst()->create($class); // check create permissions if (!$record->canCreate(null, $data)) { return (new HTTPResponse(null, 403))->addHeader('Content-Type', 'application/json'); } $record->ParentID = $data['ParentID']; $record->Name = $record->Title = basename($data['Name']); $record->write(); $result = $this->getObjectFromData($record); return (new HTTPResponse(json_encode($result)))->addHeader('Content-Type', 'application/json'); }