Browse Source

Merge pull request #8584 from cakephp/issue-postlink-isolation

Port FormHelper fixes in #8388 to 3.x
Mark Story 10 years ago
parent
commit
a680fb2894
2 changed files with 41 additions and 4 deletions
  1. 12 4
      src/View/Helper/FormHelper.php
  2. 29 0
      tests/TestCase/View/Helper/FormHelperTest.php

+ 12 - 4
src/View/Helper/FormHelper.php

@@ -552,18 +552,20 @@ class FormHelper extends Helper
      *    generating the hash, else $this->fields is being used.
      * @param array $secureAttributes will be passed as HTML attributes into the hidden
      *    input elements generated for the Security Component.
-     * @return string|null A hidden input field with a security hash
+     * @return string A hidden input field with a security hash, or empty string when
+     *   secured forms are not in use.
      */
     public function secure(array $fields = [], array $secureAttributes = [])
     {
         if (empty($this->request['_Token'])) {
-            return null;
+            return '';
         }
         $debugSecurity = Configure::read('debug');
         if (isset($secureAttributes['debugSecurity'])) {
             $debugSecurity = $debugSecurity && $secureAttributes['debugSecurity'];
             unset($secureAttributes['debugSecurity']);
         }
+        $secureAttributes['secure'] = static::SECURE_SKIP;
 
         $tokenData = $this->_buildFieldToken(
             $this->_lastAction,
@@ -1678,7 +1680,9 @@ class FormHelper extends Helper
         }
         $templater = $this->templater();
 
+        $restoreAction = $this->_lastAction;
         $this->_lastAction($url);
+
         $action = $templater->formatAttributes([
             'action' => $this->Url->build($url),
             'escape' => false
@@ -1687,19 +1691,23 @@ class FormHelper extends Helper
         $out = $this->formatTemplate('formStart', [
             'attrs' => $templater->formatAttributes($formOptions) . $action
         ]);
-        $out .= $this->hidden('_method', ['value' => $requestMethod]);
+        $out .= $this->hidden('_method', [
+            'value' => $requestMethod,
+            'secure' => static::SECURE_SKIP
+        ]);
         $out .= $this->_csrfField();
 
         $fields = [];
         if (isset($options['data']) && is_array($options['data'])) {
             foreach (Hash::flatten($options['data']) as $key => $value) {
                 $fields[$key] = $value;
-                $out .= $this->hidden($key, ['value' => $value]);
+                $out .= $this->hidden($key, ['value' => $value, 'secure' => static::SECURE_SKIP]);
             }
             unset($options['data']);
         }
         $out .= $this->secure($fields);
         $out .= $this->formatTemplate('formEnd', []);
+        $this->_lastAction = $restoreAction;
 
         if ($options['block']) {
             if ($options['block'] === true) {

+ 29 - 0
tests/TestCase/View/Helper/FormHelperTest.php

@@ -6979,6 +6979,35 @@ class FormHelperTest extends TestCase
     }
 
     /**
+     * Test that postLink doesn't modify the fields in the containing form.
+     *
+     * postLink() calls inside open forms should not modify the field list
+     * for the form.
+     *
+     * @return void
+     */
+    public function testPostLinkSecurityHashBlockMode()
+    {
+        $hash = Security::hash(
+            '/posts/delete/1' .
+            serialize([]) .
+            '' .
+            Security::salt()
+        );
+        $hash .= '%3A';
+        $this->Form->request->params['_Token']['key'] = 'test';
+
+        $this->Form->create('Post', ['url' => ['action' => 'add']]);
+        $this->Form->input('title');
+        $this->Form->postLink('Delete', '/posts/delete/1', ['block' => true]);
+        $result = $this->View->fetch('postLink');
+
+        $this->assertEquals(['title'], $this->Form->fields);
+        $this->assertContains($hash, $result, 'Should contain the correct hash.');
+        $this->assertAttributeEquals('/articles/add', '_lastAction', $this->Form, 'lastAction was should be restored.');
+    }
+
+    /**
      * Test that security does not include debug token if debug is false.
      *
      * @return void