diff --git a/forms/Form.php b/forms/Form.php index cea8d311d..403195fe5 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -355,8 +355,21 @@ class Form extends RequestHandler { $vars = $request->requestVars(); } + // construct an array of allowed fields that can be populated from request data. + // readonly or disabled fields should not be loading data from requests + $allowedFields = array(); + $dataFields = $this->Fields()->dataFields(); + if ($dataFields) { + /** @var FormField $field */ + foreach ($this->Fields()->dataFields() as $name => $field) { + if (!$field->isReadonly() && !$field->isDisabled()) { + $allowedFields[] = $name; + } + } + } + // Populate the form - $this->loadDataFrom($vars, true); + $this->loadDataFrom($vars, true, $allowedFields); // Protection against CSRF attacks $token = $this->getSecurityToken(); diff --git a/forms/FormField.php b/forms/FormField.php index eab6bcca0..d791ac432 100644 --- a/forms/FormField.php +++ b/forms/FormField.php @@ -164,6 +164,14 @@ class FormField extends RequestHandler { */ protected $attributes = array(); + /** + * @config + * @var array + */ + private static $casting = array( + 'Value' => 'Text', + ); + /** * Takes a field name and converts camelcase to spaced words. Also resolves combined field * names with dot syntax to spaced words. diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php index 8960a8d7a..db815feb6 100644 --- a/forms/HtmlEditorField.php +++ b/forms/HtmlEditorField.php @@ -26,6 +26,14 @@ class HtmlEditorField extends TextareaField { */ private static $sanitise_server_side = false; + /** + * @config + * @var array + */ + private static $casting = array( + 'Value' => 'HTMLText', + ); + protected $rows = 30; /** diff --git a/forms/ReadonlyField.php b/forms/ReadonlyField.php index 856d1cc11..6c68d4302 100644 --- a/forms/ReadonlyField.php +++ b/forms/ReadonlyField.php @@ -53,10 +53,28 @@ class ReadonlyField extends FormField { } public function Value() { - if($this->value) return $this->dontEscape ? $this->value : Convert::raw2xml($this->value); + if($this->value) return $this->value; else return '(' . _t('FormField.NONE', 'none') . ')'; } + /** + * This is a legacy fix to ensure that the `dontEscape` flag has an impact on readonly fields + * now that we've moved to casting template values more rigidly + * + * @param string $field + * @return string + */ + public function castingHelper($field) { + if ( + (strcasecmp($field, 'Value') === 0) + && ($this->dontEscape || empty($this->value)) + ) { + // Value is either empty, or unescaped + return 'HTMLText'; + } + return parent::castingHelper($field); + } + public function getAttributes() { return array_merge( parent::getAttributes(), diff --git a/forms/TextareaField.php b/forms/TextareaField.php index 876138e2b..7b9df32a6 100644 --- a/forms/TextareaField.php +++ b/forms/TextareaField.php @@ -18,6 +18,11 @@ * @subpackage fields-basic */ class TextareaField extends FormField { + + private static $casting = array( + 'Value' => 'HTMLText', + ); + /** * Visible number of text lines. * diff --git a/security/CMSSecurity.php b/security/CMSSecurity.php index ffd967797..851be1d49 100644 --- a/security/CMSSecurity.php +++ b/security/CMSSecurity.php @@ -213,7 +213,7 @@ PHP '

Login success. If you are not automatically redirected '. 'click here

', 'Login message displayed in the cms popup once a user has re-authenticated themselves', - array('link' => $backURL) + array('link' => Convert::raw2att($backURL)) ) )); diff --git a/tests/forms/FormTest.php b/tests/forms/FormTest.php index ebe740bb3..18aadaf7e 100644 --- a/tests/forms/FormTest.php +++ b/tests/forms/FormTest.php @@ -64,6 +64,33 @@ class FormTest extends FunctionalTest { $this->assertEquals($fields->fieldByName('othernamespace[key5][key6][key7]')->Value(), 'val7'); } + public function testSubmitReadonlyFields() { + $this->get('FormTest_Controller'); + + // Submitting a value for a readonly field should be ignored + $response = $this->post( + 'FormTest_Controller/Form', + array( + 'Email' => 'invalid', + 'Number' => '888', + 'ReadonlyField' => '' + // leaving out "Required" field + ) + ); + + // Number field updates its value + $this->assertContains('getBody()); + + + // Readonly field remains + $this->assertContains( + 'getBody() + ); + + $this->assertNotContains('hacxzored', $response->getBody()); + } + public function testLoadDataFromUnchangedHandling() { $form = new Form( new Controller(), @@ -755,7 +782,10 @@ class FormTest_Controller extends Controller implements TestOnly { new EmailField('Email'), new TextField('SomeRequiredField'), new CheckboxSetField('Boxes', null, array('1'=>'one','2'=>'two')), - new NumericField('Number') + new NumericField('Number'), + TextField::create('ReadonlyField') + ->setReadonly(true) + ->setValue('This value is readonly') ), new FieldList( new FormAction('doSubmit') diff --git a/tests/forms/TextareaFieldTest.php b/tests/forms/TextareaFieldTest.php index 1bd733dd3..d635574c1 100644 --- a/tests/forms/TextareaFieldTest.php +++ b/tests/forms/TextareaFieldTest.php @@ -2,16 +2,6 @@ class TextareaFieldTest extends SapphireTest { - /** - * Quick smoke test to ensure that text is being encoded properly. - */ - public function testTextEncoding() { - $inputText = "These are some unicodes: äöü"; - $field = new TextareaField("Test", "Test"); - $field->setValue($inputText); - $this->assertContains('These are some unicodes: äöü', $field->Field()); - } - /** * Quick smoke test to ensure that text with unicodes is being displayed properly in readonly fields. */