Development

/branches/1.1/lib/validator/sfValidatorSchema.class.php

You must first sign up to be able to contribute.

root/branches/1.1/lib/validator/sfValidatorSchema.class.php

Revision 16274, 8.9 kB (checked in by fabien, 6 years ago)

[1.1, 1.2, 1.3] fixed form submissions when posted data exceeds post_max_size (closes #6081 - oh yes, I sometimes really hate you PHP!)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * sfValidatorSchema represents an array of fields.
13  *
14  * A field is a named validator.
15  *
16  * @package    symfony
17  * @subpackage validator
18  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
19  * @version    SVN: $Id$
20  */
21 class sfValidatorSchema extends sfValidatorBase implements ArrayAccess
22 {
23   protected
24     $fields        = array(),
25     $preValidator  = null,
26     $postValidator = null;
27
28   /**
29    * Constructor.
30    *
31    * The first argument can be:
32    *
33    *  * null
34    *  * an array of named sfValidatorBase instances
35    *
36    * @param mixed $fields    Initial fields
37    * @param array $options   An array of options
38    * @param array $messages  An array of error messages
39    *
40    * @see sfValidatorBase
41    */
42   public function __construct($fields = null, $options = array(), $messages = array())
43   {
44     if (is_array($fields))
45     {
46       foreach ($fields as $name => $validator)
47       {
48         $this[$name] = $validator;
49       }
50     }
51     else if (!is_null($fields))
52     {
53       throw new InvalidArgumentException('sfValidatorSchema constructor takes an array of sfValidatorBase objects.');
54     }
55
56     parent::__construct($options, $messages);
57   }
58
59   /**
60    * Configures the validator.
61    *
62    * Available options:
63    *
64    *  * allow_extra_fields:  if false, the validator adds an error if extra fields are given in the input array of values (default to false)
65    *  * filter_extra_fields: if true, the validator filters extra fields from the returned array of cleaned values (default to true)
66    *
67    * Available error codes:
68    *
69    *  * extra_fields
70    *
71    * @param array $options   An array of options
72    * @param array $messages  An array of error messages
73    *
74    * @see sfValidatorBase
75    */
76   protected function configure($options = array(), $messages = array())
77   {
78     $this->addOption('allow_extra_fields', false);
79     $this->addOption('filter_extra_fields', true);
80
81     $this->addMessage('extra_fields', 'Unexpected extra form field named "%field%".');
82     $this->addMessage('post_max_size', 'The form submission cannot be processed. It probably means that you have uploaded a file that is too big.');
83   }
84
85   /**
86    * @see sfValidatorBase
87    */
88   public function clean($values)
89   {
90     return $this->doClean($values);
91   }
92
93   /**
94    * @see sfValidatorBase
95    */
96   protected function doClean($values)
97   {
98     if (is_null($values))
99     {
100       $values = array();
101     }
102
103     if (!is_array($values))
104     {
105       throw new InvalidArgumentException('You must pass an array parameter to the clean() method');
106     }
107
108     $clean  = array();
109     $unused = array_keys($this->fields);
110     $errorSchema = new sfValidatorErrorSchema($this);
111
112     // check that post_max_size has not been reached
113     if (isset($_SERVER['CONTENT_LENGTH']) && (int) $_SERVER['CONTENT_LENGTH'] > $this->getBytes(ini_get('post_max_size')))
114     {
115       $errorSchema->addError(new sfValidatorError($this, 'post_max_size'));
116
117       throw $errorSchema;
118     }
119
120     // pre validator
121     try
122     {
123       $this->preClean($values);
124     }
125     catch (sfValidatorErrorSchema $e)
126     {
127       $errorSchema->addErrors($e);
128     }
129     catch (sfValidatorError $e)
130     {
131       $errorSchema->addError($e);
132     }
133
134     // validate given values
135     foreach ($values as $name => $value)
136     {
137       // field exists in our schema?
138       if (!array_key_exists($name, $this->fields))
139       {
140         if (!$this->options['allow_extra_fields'])
141         {
142           $errorSchema->addError(new sfValidatorError($this, 'extra_fields', array('field' => $name)));
143         }
144         else if (!$this->options['filter_extra_fields'])
145         {
146           $clean[$name] = $value;
147         }
148
149         continue;
150       }
151
152       unset($unused[array_search($name, $unused, true)]);
153
154       // validate value
155       try
156       {
157         $clean[$name] = $this->fields[$name]->clean($value);
158       }
159       catch (sfValidatorError $e)
160       {
161         $clean[$name] = null;
162
163         $errorSchema->addError($e, (string) $name);
164       }
165     }
166
167     // are non given values required?
168     foreach ($unused as $name)
169     {
170       // validate value
171       try
172       {
173         $clean[$name] = $this->fields[$name]->clean(null);
174       }
175       catch (sfValidatorError $e)
176       {
177         $clean[$name] = null;
178
179         $errorSchema->addError($e, (string) $name);
180       }
181     }
182
183     // post validator
184     try
185     {
186       $clean = $this->postClean($clean);
187     }
188     catch (sfValidatorErrorSchema $e)
189     {
190       $errorSchema->addErrors($e);
191     }
192     catch (sfValidatorError $e)
193     {
194       $errorSchema->addError($e);
195     }
196
197     if (count($errorSchema))
198     {
199       throw $errorSchema;
200     }
201
202     return $clean;
203   }
204
205   /**
206    * Cleans the input values.
207    *
208    * This method is the first validator executed by doClean().
209    *
210    * It executes the validator returned by getPreValidator()
211    * on the global array of values.
212    *
213    * @param  array $values  The input values
214    *
215    * @throws sfValidatorError
216    */
217   public function preClean($values)
218   {
219     if (is_null($validator = $this->getPreValidator()))
220     {
221       return;
222     }
223
224     $validator->clean($values);
225   }
226
227   /**
228    * Cleans the input values.
229    *
230    * This method is the last validator executed by doClean().
231    *
232    * It executes the validator returned by getPostValidator()
233    * on the global array of cleaned values.
234    *
235    * @param  array $values  The input values
236    *
237    * @throws sfValidatorError
238    */
239   public function postClean($values)
240   {
241     if (is_null($validator = $this->getPostValidator()))
242     {
243       return $values;
244     }
245
246     return $validator->clean($values);
247   }
248
249   /**
250    * Sets the pre validator.
251    *
252    * @param sfValidatorBase $validator  An sfValidatorBase instance
253    */
254   public function setPreValidator(sfValidatorBase $validator)
255   {
256     $this->preValidator = clone $validator;
257   }
258
259   /**
260    * Returns the pre validator.
261    *
262    * @return sfValidatorBase A sfValidatorBase instance
263    */
264   public function getPreValidator()
265   {
266     return $this->preValidator;
267   }
268
269   /**
270    * Sets the post validator.
271    *
272    * @param sfValidatorBase $validator  An sfValidatorBase instance
273    */
274   public function setPostValidator(sfValidatorBase $validator)
275   {
276     $this->postValidator = clone $validator;
277   }
278
279   /**
280    * Returns the post validator.
281    *
282    * @return sfValidatorBase An sfValidatorBase instance
283    */
284   public function getPostValidator()
285   {
286     return $this->postValidator;
287   }
288
289   /**
290    * Returns true if the schema has a field with the given name (implements the ArrayAccess interface).
291    *
292    * @param  string  $name  The field name
293    *
294    * @return bool true if the schema has a field with the given name, false otherwise
295    */
296   public function offsetExists($name)
297   {
298     return isset($this->fields[$name]);
299   }
300
301   /**
302    * Gets the field associated with the given name (implements the ArrayAccess interface).
303    *
304    * @param  string $name  The field name
305    *
306    * @return sfValidatorBase The sfValidatorBase instance associated with the given name, null if it does not exist
307    */
308   public function offsetGet($name)
309   {
310     return isset($this->fields[$name]) ? $this->fields[$name] : null;
311   }
312
313   /**
314    * Sets a field (implements the ArrayAccess interface).
315    *
316    * @param string          $name       The field name
317    * @param sfValidatorBase $validator  An sfValidatorBase instance
318    */
319   public function offsetSet($name, $validator)
320   {
321     if (!$validator instanceof sfValidatorBase)
322     {
323       throw new InvalidArgumentException('A field must be an instance of sfValidatorBase.');
324     }
325
326     $this->fields[$name] = clone $validator;
327   }
328
329   /**
330    * Removes a field by name (implements the ArrayAccess interface).
331    *
332    * @param string $name
333    */
334   public function offsetUnset($name)
335   {
336     unset($this->fields[$name]);
337   }
338
339   /**
340    * Returns an array of fields.
341    *
342    * @return sfValidatorBase An array of sfValidatorBase instances
343    */
344   public function getFields()
345   {
346     return $this->fields;
347   }
348
349   /**
350    * @see sfValidatorBase
351    */
352   public function asString($indent = 0)
353   {
354     throw new Exception('Unable to convert a sfValidatorSchema to string.');
355   }
356
357   public function __clone()
358   {
359     foreach ($this->fields as $name => $field)
360     {
361       $this->fields[$name] = clone $field;
362     }
363
364     if (!is_null($this->preValidator))
365     {
366       $this->preValidator = clone $this->preValidator;
367     }
368
369     if (!is_null($this->postValidator))
370     {
371       $this->postValidator = clone $this->postValidator;
372     }
373   }
374
375   protected function getBytes($value)
376   {
377     $value = trim($value);
378     switch (strtolower($value[strlen($value) - 1]))
379     {
380       // The 'G' modifier is available since PHP 5.1.0
381       case 'g':
382         $value *= 1024;
383       case 'm':
384         $value *= 1024;
385       case 'k':
386         $value *= 1024;
387     }
388
389     return $value;
390   }
391 }
392
Note: See TracBrowser for help on using the browser.