Apache Zeta Components Manual :: File Source for input_form.php

Source for file input_form.php

Documentation is available at input_form.php

  1. <?php
  2. /**
  3.  *
  4.  * Licensed to the Apache Software Foundation (ASF) under one
  5.  * or more contributor license agreements.  See the NOTICE file
  6.  * distributed with this work for additional information
  7.  * regarding copyright ownership.  The ASF licenses this file
  8.  * to you under the Apache License, Version 2.0 (the
  9.  * "License"); you may not use this file except in compliance
  10.  * with the License.  You may obtain a copy of the License at
  11.  * 
  12.  *   http://www.apache.org/licenses/LICENSE-2.0
  13.  * 
  14.  * Unless required by applicable law or agreed to in writing,
  15.  * software distributed under the License is distributed on an
  16.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17.  * KIND, either express or implied.  See the License for the
  18.  * specific language governing permissions and limitations
  19.  * under the License.
  20.  *
  21.  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  22.  * @version //autogentag//
  23.  * @filesource
  24.  * @package UserInput
  25.  */
  26.  
  27. /**
  28.  * Provides access to form variables.
  29.  *
  30.  * This class allows you to retrieve input variables from the request in a safe
  31.  * way, by applying filters to allow only wanted data into your application. It
  32.  * works by passing an array that describes your form definition to the
  33.  * constructor of the class. The constructor will then initialize the class
  34.  * with properties that contain the value of your request's input fields.
  35.  *
  36.  * Example:
  37.  * <code>
  38.  * <?php
  39.  * if ( ezcInputForm::hasGetData() )
  40.  * {
  41.  *     $definition = array(
  42.  *        'fieldname'  => new ezcInputFormDefinitionElement(
  43.  *                            ezcInputFormDefinitionElement::REQUIRED, 'filtername'
  44.  *                        ),
  45.  *        'textfield'  => new ezcInputFormDefinitionElement(
  46.  *                            ezcInputFormDefinitionElement::OPTIONAL, 'string'
  47.  *                        ),
  48.  *        'integer1'   => new ezcInputFormDefinitionElement(
  49.  *                            ezcInputFormDefinitionElement::REQUIRED, 'int',
  50.  *                            array( 'min_range' => 0, 'max_range' => 42 )
  51.  *                        ),
  52.  *        'xmlfield'   => new ezcInputFormDefinitionElement(
  53.  *                            ezcInputFormDefinitionElement::REQUIRED, 'unsafe_raw'
  54.  *                        ),
  55.  *        'special'    => new ezcInputFormDefinitionElement(
  56.  *                            ezcInputFormDefinitionElement::OPTIONAL, 'callback',
  57.  *                            array( 'ezcInputFilter', 'special' )
  58.  *                        ),
  59.  *     );
  60.  *     $form = new ezcInputForm( INPUT_GET, $definition );
  61.  *     if ( $form->hasInputField( 'textfield' ) ) // check for optional field
  62.  *     {
  63.  *         $text = $form->textfield;
  64.  *     }
  65.  * 
  66.  *     try
  67.  *     {
  68.  *         $xml = $form->xmlfield; // Uses dynamic properties through __get().
  69.  *         $field = $form->fieldname;
  70.  *         $int = $form->integer1;
  71.  *     }
  72.  *     catch ( ezcInputFormException $e )
  73.  *     {
  74.  *         // one of the required fields didn't have valid data.
  75.  *         $invalidProperties = $form->getInvalidProperties();
  76.  * 
  77.  *         // Retrieve RAW data for invalid properties so that we can fill in the
  78.  *         // forms online with this RAW data again - Make sure to escape it on
  79.  *         // output though, but that should be done for all data anyway.
  80.  *         if ( in_array( 'xmlfield', $invalidProperties ) )
  81.  *         {
  82.  *             $xml = $form->getUnsafeRawData( 'xmlfield' );
  83.  *         }
  84.  *     }
  85.  * 
  86.  *     // Checking optional fields
  87.  *     foreach ( $form->getOptionalProperties() as $property )
  88.  *     {
  89.  *         $name = "property_{$property}";
  90.  *         if ( $form->hasValidData( $property ) )
  91.  *         {
  92.  *             $$name = $form->$property;
  93.  *         }
  94.  *     }
  95.  * }
  96.  * ?>
  97.  * </code>
  98.  *
  99.  * @property-read string $formFields 
  100.  *                 There is a read-only property for each field that is defined
  101.  *                 as input field.
  102.  *
  103.  * @package UserInput
  104.  * @version //autogentag//
  105.  * @mainclass
  106.  */
  107. {
  108.     /**
  109.      * @var VALID is used in the $properties array to record whether the data
  110.      *             in a specific input variable contained valid data according
  111.      *             to the filter.
  112.      */
  113.     const VALID 0;
  114.  
  115.     /**
  116.      * @var INVALID is used in the $properties array to record whether the data
  117.      *               in a specific input variable contained valid data according
  118.      *               to the filter.
  119.      */
  120.     const INVALID 1;
  121.  
  122.     const DEF_NO_ARRAY                      1;
  123.     const DEF_EMPTY                         2;
  124.     const DEF_ELEMENT_NO_DEFINITION_ELEMENT 3;
  125.     const DEF_NOT_REQUIRED_OR_OPTIONAL      5;
  126.     const DEF_WRONG_FLAGS_TYPE              6;
  127.     const DEF_UNSUPPORTED_FILTER            7;
  128.     const DEF_FIELD_NAME_BROKEN             8;
  129.  
  130.     /**
  131.      * Contains the definition for this form (as passed in the constructor).
  132.      * @var array(string=>ezcInputFormDefinitionElement) 
  133.      */
  134.     private $definition;
  135.  
  136.     /**
  137.      * Contains a list of all retrieved properties and their status.  The key
  138.      * for each array element is the field name, and the value associated with
  139.      * this key is one of the constants VALID or INVALID.
  140.      * @var array 
  141.      */
  142.     private $properties;
  143.  
  144.     /**
  145.      * Contains the values of the input variables.  The key for each array
  146.      * element is the field name, and the value associated with this key is the
  147.      * property's value. This array does not have an entry for input fields
  148.      * that do not have valid data.
  149.      * @var array 
  150.      */
  151.     protected $propertyValues;
  152.  
  153.     /**
  154.      * Contains the input source to be used.
  155.      * @var int 
  156.      */
  157.     private $inputSource;
  158.  
  159.     /**
  160.      * Whether all the input elements are valid
  161.      */
  162.     private $allElementsValid;
  163.  
  164.     /**
  165.      * Constructs a new ezcInputForm for $inputSource with $definition.
  166.      *
  167.      * This method constructs a new ezcInputForm with three parameters. The
  168.      * $inputSource parameter selects the input source and should be one of the
  169.      * constants INPUT_GET, INPUT_POST or INPUT_COOKIE. The $definition
  170.      * parameter is an array of ezcInputFormDefinitionElement items and
  171.      * determines which input variables make up this form (see the example at
  172.      * the top of this class). The last parameter, $characterEncoding is the
  173.      * character encoding to use while retrieving input variable data. This
  174.      * parameter has currently no function as it will depend on PHP 6
  175.      * functionality which does not exist yet in the input filter extension.
  176.      *
  177.      * @throws ezcInputFormVariableMissingException when one of the required
  178.      *          input variables is missing.
  179.      * @throws ezcInputFormInvalidDefinitionException when the definition array
  180.      *          is invalid or when the input source was invalid.
  181.      *
  182.      * @param int $inputSource 
  183.      * @param array(ezcInputFormDefinitionElement) $definition 
  184.      * @param string $characterEncoding 
  185.      */
  186.     public function __construct$inputSource$definition$characterEncoding null )
  187.     {
  188.         if ( ( $returnValue ezcInputForm::validateDefinition$definition ) ) !== true )
  189.         {
  190.             throw new ezcInputFormInvalidDefinitionException$returnValue[1);
  191.         }
  192.         $this->definition $definition;
  193.         $this->inputSource $inputSource;
  194.  
  195.         $this->parseInput();
  196.     }
  197.  
  198.     /**
  199.      * Returns whether there is GET data available
  200.      *
  201.      * @return bool True if there is GET data available
  202.      */
  203.     static public function hasGetData()
  204.     {
  205.         return count$_GET 0;
  206.     }
  207.  
  208.     /**
  209.      * Returns whether there is POST data available
  210.      *
  211.      * @return bool True if there is POST data available
  212.      */
  213.     static public function hasPostData()
  214.     {
  215.         return count$_POST 0;
  216.     }
  217.  
  218.     /**
  219.      * Parses the input according to the definition array.
  220.      *
  221.      * @throws ezcInputFormInvalidDefinitionException when one of the required
  222.      *          input variables is missing or when the input source was invalid.
  223.       */
  224.     private function parseInput()
  225.     {
  226.         $this->allElementsValid true;
  227.  
  228.         if (  !in_array$this->inputSourcearrayINPUT_GETINPUT_POSTINPUT_COOKIE ) ) )
  229.         {
  230.             throw new ezcInputFormWrongInputSourceException$this->inputSource );
  231.         }
  232.  
  233.         foreach $this->definition as $elementName => $inputElement )
  234.         {
  235.             $hasVariable filter_has_var$this->inputSource$elementName );
  236.             if $hasVariable )
  237.             {
  238.                 if $inputElement->type === ezcInputFormDefinitionElement::REQUIRED )
  239.                 {
  240.                     throw new ezcInputFormVariableMissingException$elementName );
  241.                 }
  242.                 else
  243.                 {
  244.                     $this->properties[$elementNameezcInputForm::INVALID;
  245.                     $this->allElementsValid false;
  246.                     continue;
  247.                 }
  248.             }
  249.  
  250.             $flags FILTER_NULL_ON_FAILURE $inputElement->flags;
  251.             $value filter_input$this->inputSource$elementNamefilter_id$inputElement->filterName )array'options' => $inputElement->options'flags' => $flags ) );
  252.  
  253.             if $value !== null )
  254.             {
  255.                 $this->properties[$elementNameezcInputForm::VALID;
  256.                 $this->propertyValues[$elementName$value;
  257.             }
  258.             else
  259.             {
  260.                 $this->properties[$elementNameezcInputForm::INVALID;
  261.                 $this->allElementsValid false;
  262.             }
  263.         }
  264.     }
  265.  
  266.     /**
  267.      * Validates the definition array $definition.
  268.      *
  269.      * Before reading the values from the input source, the definition array
  270.      * can be validated by this method to check whether all necessary
  271.      * elements are correctly formed.
  272.      *
  273.      * With the following code you can check whether the definition is valid:
  274.      * <code>
  275.      * <?php
  276.      * if ( ( $returnValue = ezcInputForm::validateDefinition( $definition ) ) !== true )
  277.      * {
  278.      *     // do something with the error type and error message in $returnValue
  279.      * }
  280.      * else
  281.      * {
  282.      *     // the definition was correct
  283.      * }
  284.      * ?>
  285.      * </code>
  286.      *
  287.      * @param array $definition 
  288.      * @return array|boolIf the definition is correct the method returns
  289.      *                     boolean true. When an error is found the function
  290.      *                     returns an array where the first element is the type,
  291.      *                     and the second element the error message.
  292.      */
  293.     static public function validateDefinition$definition )
  294.     {
  295.         // The definition parameter should be an array
  296.         if !is_array$definition ) )
  297.         {
  298.             return arrayezcInputForm::DEF_NO_ARRAY"The definition array is not an array" );
  299.         }
  300.  
  301.         // There should be atleast one element
  302.         if count$definition === )
  303.         {
  304.             return arrayezcInputForm::DEF_EMPTY"The definition array is empty" );
  305.         }
  306.  
  307.         foreach $definition as $name => $element )
  308.         {
  309.             // Each element should be an ezcInputFormDefinitionElement
  310.             if !$element instanceof ezcInputFormDefinitionElement )
  311.             {
  312.                 return arrayezcInputForm::DEF_ELEMENT_NO_DEFINITION_ELEMENT"The definition for element '{$name}' is not an ezcInputFormDefinitionElement);
  313.             }
  314.  
  315.             // The first value in an element should be REQUIRED or OPTIONAL
  316.             if !in_array$element->typearrayezcInputFormDefinitionElement::OPTIONALezcInputFormDefinitionElement::REQUIRED )true ) )
  317.             {
  318.                 return arrayezcInputForm::DEF_NOT_REQUIRED_OR_OPTIONAL"The first element definition for element '{$name}' is not ezcInputFormDefinitionElement::OPTIONAL or ezcInputFormDefinitionElement::REQUIRED);
  319.             }
  320.  
  321.             // The options should either be an array, a string, or an int
  322.             if $element->options !== null )
  323.             {
  324.                 $filterOptionsType gettype$element->options );
  325.                 if !in_array$filterOptionsTypearray'integer''string''array' ) ) )
  326.                 {
  327.                     return arrayezcInputForm::DEF_WRONG_FLAGS_TYPE"The options to the definition for element '{$name}' is not of type integer, string or array);
  328.                 }
  329.  
  330.                 // A callback filter should have the form "string" or "array(string, string)"
  331.                 if $element->filterName == 'callback' )
  332.                 {
  333.                     if $filterOptionsType == 'integer' )
  334.                     {
  335.                         return arrayezcInputForm::DEF_WRONG_FLAGS_TYPE"The callback filter for element '{$name}' should not be an integer);
  336.                     }
  337.                     if $filterOptionsType == 'array' )
  338.                     {
  339.                         if count$element->options != )
  340.                         {
  341.                             return arrayezcInputForm::DEF_WRONG_FLAGS_TYPE"The array parameter for the callback filter for element '{$name}' should have exactly two elements);
  342.                         }
  343.                         if gettype$element->options[0!= 'string' || gettype$element->options[1!= 'string' )
  344.                         {
  345.                             return arrayezcInputForm::DEF_WRONG_FLAGS_TYPE"The array elements for the callback filter for element '{$name}' should both be a string);
  346.                         }
  347.                     }
  348.                 }
  349.             }
  350.  
  351.             // The options should either be an int
  352.             if $element->flags !== null )
  353.             {
  354.                 if gettype$element->flags !== 'integer' )
  355.                 {
  356.                     return arrayezcInputForm::DEF_WRONG_FLAGS_TYPE"The flags to the definition for element '{$name}' is not of type integer, string or array);
  357.                 }
  358.             }
  359.  
  360.             // The filter should be an existing filter
  361.             if !in_array$element->filterNamefilter_list() ) )
  362.             {
  363.                 $filters join', 'filter_list() );
  364.                 return arrayezcInputForm::DEF_UNSUPPORTED_FILTER"The filter '{$element->filterName}' for element '{$name}' does not exist. Pick one of: $filters);
  365.             }
  366.  
  367.             // The input field name should have a sane format
  368.             if gettype$name != 'string' )
  369.             {
  370.                 return arrayezcInputForm::DEF_FIELD_NAME_BROKEN"The element name '{$name}' is not a string);
  371.             }
  372.             if (preg_match'@^[a-z][a-z0-9_]*$@i'$name ) )
  373.             {
  374.                 return arrayezcInputForm::DEF_FIELD_NAME_BROKEN"The element name '{$name}' has an unsupported format. It should start with an a-z and followed by a-z0-9_);
  375.             }
  376.  
  377.         }
  378.         return true;
  379.     }
  380.  
  381.     /**
  382.      * This function is called when a variable is assigned to a magic property.
  383.      *
  384.      * When the value of a property is requested this function checks with the
  385.      * $properties array whether it contains valid data or not. If there is no
  386.      * valid data, the UserInputInValidData exception is thrown, otherwise the
  387.      * function returns the value associated with the input variable.
  388.      *
  389.      * @throws ezcInputFormInvalidDataException when trying to read a property
  390.      *          which has no valid data.
  391.      * @throws ezcInputFormUnknownFieldException when a property is being
  392.      *          accessed which is not defined in the definition array.
  393.      *
  394.      * @param string $propertyName 
  395.      * @return mixed The value of the input variable.
  396.      * @ignore
  397.      */
  398.     public function __get$propertyName )
  399.     {
  400.         if isset$this->properties[$propertyName) )
  401.         {
  402.             if $this->properties[$propertyName=== ezcInputForm::VALID )
  403.             {
  404.                 return $this->propertyValues[$propertyName];
  405.             }
  406.             else
  407.             {
  408.                 throw new ezcInputFormNoValidDataException$propertyName );
  409.             }
  410.         }
  411.         throw new ezcInputFormUnknownFieldException$propertyName );
  412.     }
  413.  
  414.     /**
  415.      * Returns whether a magic property was is used on a magic property.
  416.      *
  417.      * This method checks whether a magic property exists and returns true of
  418.      * it does and false if it doesn't. The list of properties which exist is
  419.      * determined by the $definition array that was passed to the constructor.
  420.      *
  421.      * @param string $propertyName 
  422.      * @return bool  Whether the $propertyName exists or not.
  423.      * @ignore
  424.      */
  425.     public function __isset$propertyName )
  426.     {
  427.         return isset$this->properties[$propertyName);
  428.     }
  429.  
  430.     /**
  431.      * Sets a new magic property.
  432.      *
  433.      * This function is called when one of the magic properties was assigned a
  434.      * new value.  As all magic properties are read-only for this class, all
  435.      * that this function does is return the exception
  436.      * ezcBasePropertyReadOnlyException.
  437.      *
  438.      * @throws ezcBasePropertyPermissionException for every call to this
  439.      *          function.
  440.      * @param string $propertyName 
  441.      * @param mixed  $newValue 
  442.      * @ignore
  443.      */
  444.     public function __set$propertyName$newValue )
  445.     {
  446.         throw new ezcBasePropertyPermissionException$propertyNameezcBasePropertyPermissionException::READ );
  447.     }
  448.  
  449.     /**
  450.      * Returns whether the optional field $fieldName exists.
  451.      *
  452.      * @param string $fieldName 
  453.      * @return bool true if the input field was available and false otherwise.
  454.      */
  455.     public function hasInputField$fieldName )
  456.     {
  457.         if isset$this->properties[$fieldName) )
  458.         {
  459.             return true;
  460.         }
  461.         return false;
  462.     }
  463.  
  464.     /**
  465.      * Returns whether the filters for required field $fieldName returned valid data.
  466.      *
  467.      * @param string $fieldName 
  468.      * @return bool true if the input field was available and false otherwise.
  469.      */
  470.     public function hasValidData$fieldName )
  471.     {
  472.         if isset$this->properties[$fieldName&& $this->properties[$fieldName=== ezcInputForm::VALID )
  473.         {
  474.             return true;
  475.         }
  476.         return false;
  477.     }
  478.  
  479.     /**
  480.      * Returns RAW input variable values for invalid field $fieldName.
  481.      *
  482.      * The return value of this function can be used to prefill forms on the
  483.      * next request. It will only work for invalid input fields, as for valid
  484.      * input fields you should never have to get to the original RAW data. In
  485.      * the case a $fieldName is passed that has valid data, an
  486.      * ezcInputFormException will be thrown.
  487.      *
  488.      * @throws ezcInputFormValidDataException when trying to get unsafe raw
  489.      *          data from a input field with valid data.
  490.      * @throws ezcInputFormFieldNotFoundException when trying to get data from a
  491.      *          property that does not exist.
  492.      * @param string $fieldName 
  493.      * @return string The original RAW data of the specified input field.
  494.      */
  495.     public function getUnsafeRawData$fieldName )
  496.     {
  497.         if isset$this->properties[$fieldName) )
  498.         {
  499.             if $this->properties[$fieldName=== ezcInputForm::VALID )
  500.             {
  501.                 throw new ezcInputFormValidDataAvailableException$fieldName );
  502.             }
  503.             else
  504.             {
  505.                 if filter_has_var$this->inputSource$fieldName ) )
  506.                 {
  507.                     return filter_input$this->inputSource$fieldNameFILTER_UNSAFE_RAW );
  508.                 }
  509.                 else
  510.                 {
  511.                     throw new ezcInputFormFieldNotFoundException$fieldName );
  512.                 }
  513.             }
  514.         }
  515.         throw new ezcInputFormUnknownFieldException$fieldName );
  516.     }
  517.  
  518.     /**
  519.      * Returns a list with all optional properties.
  520.      * @return array(string) 
  521.      */
  522.     public function getOptionalProperties()
  523.     {
  524.         $properties array();
  525.         foreach $this->definition as $fieldName => $fieldDefinition )
  526.         {
  527.             if $fieldDefinition->type === ezcInputFormDefinitionElement::OPTIONAL )
  528.             {
  529.                 $properties[$fieldName;
  530.             }
  531.         }
  532.         return $properties;
  533.     }
  534.  
  535.     /**
  536.      * Returns a list with all required properties.
  537.      * @return array(string) 
  538.      */
  539.     public function getRequiredProperties()
  540.     {
  541.         $properties array();
  542.         foreach $this->definition as $fieldName => $fieldDefinition )
  543.         {
  544.             if $fieldDefinition->type === ezcInputFormDefinitionElement::REQUIRED )
  545.             {
  546.                 $properties[$fieldName;
  547.             }
  548.         }
  549.         return $properties;
  550.     }
  551.  
  552.     /**
  553.      * Returns a list with all properties that have valid data.
  554.      * @return array(string) 
  555.      */
  556.     public function getValidProperties()
  557.     {
  558.         $properties array();
  559.         foreach $this->properties as $fieldName => $fieldStatus )
  560.         {
  561.             if $fieldStatus === ezcInputForm::VALID )
  562.             {
  563.                 $properties[$fieldName;
  564.             }
  565.         }
  566.         return $properties;
  567.     }
  568.  
  569.     /**
  570.      * Returns a list with all properties having invalid data.
  571.      * @return array(string) 
  572.      */
  573.     public function getInvalidProperties()
  574.     {
  575.         $properties array();
  576.         foreach $this->properties as $fieldName => $fieldStatus )
  577.         {
  578.             if $fieldStatus === ezcInputForm::INVALID )
  579.             {
  580.                 $properties[$fieldName;
  581.             }
  582.         }
  583.         return $properties;
  584.     }
  585.  
  586.     /**
  587.      * Returns whether all the input elements were valid or not.
  588.      *
  589.      * @return bool 
  590.      */
  591.     public function isValid()
  592.     {
  593.         return $this->allElementsValid;
  594.     }
  595. }
  596. ?>
Documentation generated by phpDocumentor 1.4.3