/** * Fetch an element of $arr array using "complex" key $name. * * $name can be in form of "zzz[aaa][bbb]", * it means $arr[zzz][aaa][bbb]. * * If $name contain auto-indexed parts (e.g. a[b][]), replace * it by corresponding indexes. * * $name may be scalar name or array (already splitted name, * see _splitMultiArray() method). * * @param array &$arr Array to fetch from. * @param mixed &$name Complex form-field name. * @param array &$autoindexes Container to hold auto-indexes * @return found value, or false if $name is not found. */ function _deepFetch(&$arr, &$name, &$autoindexes) { if (is_scalar($name) && strpos($name, '[') === false) { // Fast fetch. return isset($arr[$name]) ? $arr[$name] : false; } // Else search into deep. $parts = HTML_FormPersister::_splitMultiArray($name); $leftPrefix = ''; foreach ($parts as $i => $k) { if (!strlen($k)) { // Perform auto-indexing. if (!isset($autoindexes[$leftPrefix])) { $autoindexes[$leftPrefix] = 0; } $parts[$i] = $k = $autoindexes[$leftPrefix]++; } if (!is_array($arr)) { // Current container is not array. return false; } if (!array_key_exists($k, $arr)) { // No such element. return false; } $arr =& $arr[$k]; $leftPrefix = strlen($leftPrefix) ? $leftPrefix . "[{$k}]" : $k; } if (!is_scalar($name)) { $name = $parts; } else { $name = $leftPrefix; } return $arr; }
/** * Convert plain metadata to multidimension array (as in $_GET and $_POST). * Used for forms with complex field names: a[b][c][] etc. * Called usually ONLY on POST form processing, not each time page loaded. * Also check if field values are consistent with metadata (e.g. hidden * field is unchanged manually and "select" value is present in <option>'s). * Each resulting elements will have the following structure: * elementName => array( * 'type' => text | action | single | multiple, * 'label' => corresponding <label>...</label> content * 'value' => entered value (if MF_USE_VALUES is true) * 'name' => full name of form element (e.g. field[key1][key2]) * 'original' => original value of the element (for hidden fields and forms) * 'items' => array(items of selects, checkboxes etc.) * ); */ function _decodeFormMeta($metas, $valuesArray) { require_once 'HTML/FormPersister.php'; // Second pass: make meta tree. $flatMetas = $metas['items']; $treeMetas = $autoindexes = $values = array(); foreach ($flatMetas as $k => $meta) { // Get name structure. $name = $meta['name']; $nameParts = HTML_FormPersister::_splitMultiArray($name); // may be modified later! // Set values. if ($this->MF_USE_VALUES) { $value = null; // Fetch the value. if ($meta['type'] == "action" && count($nameParts) == 1) { // This is possibly <input type="image" name="aaa"> field. E.g., // $_GET contains "aaa_x" and "aaa_y" fieds. if (is_numeric($x = @$valuesArray["{$name}_x"]) && is_numeric($y = @$valuesArray["{$name}_y"])) { $value = array($x, $y); } } if ($value === null) { // This is not "image" field, or "image" with [] parts // (PHP always ignores .x and .y after [] part, so - remain only "y" coord). if (($v = HTML_FormPersister::_deepFetch($valuesArray, $nameParts, $autoindexes)) !== false) { $value = $v; } } // For multi-selects value is ALWAYS array. if ($value === null && $meta['type'] == "multiple") { $value = array(); } // Single select with size>1 and set of radio-buttons without // checked item ALSO could generate NULL in value. But we must // process such cases via meta:dynamic attribute. // Flag-based checkbox may need correction. if ($meta['type'] == 'flag') { if ($meta['key'] === null) { // If checkbox has no 'value' attribute - completely // boolean element (browser sends "on"). $value = intval(!!$value); } unset($meta['key']); } // Make values array ("trusted $_POST"). $curValue =& $values; foreach ($nameParts as $part) { $curValue =& $curValue[$part]; } $curValue = $value; // Save new value back to meta. $meta['value'] = $value; } // Make deep (tree-like) array. $curTree =& $treeMetas; foreach ($nameParts as $part) { if (!strlen($part)) { break; } $curTree =& $curTree[$part]; } $curTree = $meta; // Save modified meta back to array. $flatMetas[$k] = $meta; } // Create resulting metadata. $metas['items'] = $flatMetas; $metas['tree'] = $treeMetas; if ($this->MF_USE_VALUES) { $metas['value'] = $values; } // Return full meta-information. return $metas; }