diff --git a/lib/Horde/Form/Type.php b/lib/Horde/Form/Type.php index 89305ed..4c7a0a7 100644 --- a/lib/Horde/Form/Type.php +++ b/lib/Horde/Form/Type.php @@ -183,6 +183,7 @@ public function isValid($var, $vars, $value, $message) } $message = Horde_Form_Translation::t("This field must be a valid number."); + $this->message = $message; return false; } diff --git a/src/V3/AddressType.php b/src/V3/AddressType.php new file mode 100644 index 0000000..790f906 --- /dev/null +++ b/src/V3/AddressType.php @@ -0,0 +1,110 @@ + 'uk', 'zip' => $addressParts[3]]; + if (!empty($addressParts[1])) { + $info['street'] = $addressParts[1]; + } + if (!empty($addressParts[2])) { + $info['city'] = $addressParts[2]; + } + } elseif (preg_match('/\b' . $aus_state_regex . '\b/', $address)) { + /* Australian state detected. */ + /* Split out the address, line-by-line. */ + $addressLines = preg_split('/\r?\n/', $address); + $info = ['country' => 'au']; + for ($i = 0; $i < count($addressLines); $i++) { + /* See if it's the street number & name. */ + if (preg_match('/(\d+\s*\/\s*)?(\d+|\d+[a-zA-Z])\s+([a-zA-Z ]*)/', $addressLines[$i], $lineParts)) { + $info['street'] = $addressLines[$i]; + $info['streetNumber'] = $lineParts[2]; + $info['streetName'] = $lineParts[3]; + } + /* Look for "Suburb, State". */ + if (preg_match('/([a-zA-Z ]*),?\s+(' . $aus_state_regex . ')/', $addressLines[$i], $lineParts)) { + $info['city'] = $lineParts[1]; + $info['state'] = $lineParts[2]; + } + /* Look for "State <4 digit postcode>". */ + if (preg_match('/(' . $aus_state_regex . ')\s+(\d{4})/', $addressLines[$i], $lineParts)) { + $info['state'] = $lineParts[1]; + $info['zip'] = $lineParts[2]; + } + } + } elseif (preg_match('/(?s)(.*?)(?-s)\r?\n(.*)\s*,\s*(\w+)\.?\s+(\d+|[a-zA-Z]\d[a-zA-Z]\s?\d[a-zA-Z]\d)/', $address, $addressParts)) { + /* American/Canadian address style. */ + $info = ['country' => 'us']; + if (!empty($addressParts[4]) && + preg_match('|[a-zA-Z]\d[a-zA-Z]\s?\d[a-zA-Z]\d|', $addressParts[4])) { + $info['country'] = 'ca'; + } + if (!empty($addressParts[1])) { + $info['street'] = $addressParts[1]; + } + if (!empty($addressParts[2])) { + $info['city'] = $addressParts[2]; + } + if (!empty($addressParts[3])) { + $info['state'] = $addressParts[3]; + } + if (!empty($addressParts[4])) { + $info['zip'] = $addressParts[4]; + } + } elseif (preg_match('/(?:(?s)(.*?)(?-s)(?:\r?\n|,\s*))?(?:([A-Z]{1,3})-)?(\d{4,5})\s+(.*)(?:\r?\n(.*))?/i', $address, $addressParts)) { + /* European address style. */ + $info = []; + if (!empty($addressParts[1])) { + $info['street'] = $addressParts[1]; + } + if (!empty($addressParts[2])) { + include 'Horde/Nls/Carsigns.php'; + $country = array_search(Horde_String::upper($addressParts[2]), $carsigns); + if ($country) { + $info['country'] = $country; + } + } + if (!empty($addressParts[5])) { + include 'Horde/Nls/Countries.php'; + $country = array_search($addressParts[5], $countries); + if ($country) { + $info['country'] = Horde_String::lower($country); + } elseif (!isset($info['street'])) { + $info['street'] = trim($addressParts[5]); + } else { + $info['street'] .= "\n" . $addressParts[5]; + } + } + if (!empty($addressParts[3])) { + $info['zip'] = $addressParts[3]; + } + if (!empty($addressParts[4])) { + $info['city'] = trim($addressParts[4]); + } + } + + return $info; + } + + /** + * Return info about field type. + */ + public function about():array + { + return [ + 'name' => Horde_Form_Translation::t("Address"), + 'params' => [ + 'rows' => ['label' => Horde_Form_Translation::t("Number of rows"), + 'type' => 'int'], + 'cols' => ['label' => Horde_Form_Translation::t("Number of columns"), + 'type' => 'int']]]; + } +} \ No newline at end of file diff --git a/src/V3/AddresslinkType.php b/src/V3/AddresslinkType.php new file mode 100644 index 0000000..823c7df --- /dev/null +++ b/src/V3/AddresslinkType.php @@ -0,0 +1,19 @@ + Horde_Form_Translation::t("Address Link")]; + } + +} \ No newline at end of file diff --git a/src/V3/CellphoneType.php b/src/V3/CellphoneType.php new file mode 100644 index 0000000..5937566 --- /dev/null +++ b/src/V3/CellphoneType.php @@ -0,0 +1,16 @@ + Horde_Form_Translation::t("Mobile phone number"), + 'params' => [ + 'size' => ['label' => Horde_Form_Translation::t("Size"), + 'type' => 'int'], + ], + ]; + } +} \ No newline at end of file diff --git a/src/V3/CountedtextType.php b/src/V3/CountedtextType.php new file mode 100644 index 0000000..ba485b4 --- /dev/null +++ b/src/V3/CountedtextType.php @@ -0,0 +1,58 @@ +_chars = $chars; + } + + public function isValid($var, Horde_Variables|array $vars, $value) + { + $valid = true; + + $length = Horde_String::length(trim($value)); + + if ($var->isRequired() && $length <= 0) { + $valid = false; + $message = Horde_Form_Translation::t("This field is required."); + + } elseif ($length > $this->_chars) { + $valid = false; + $message = sprintf(Horde_Form_Translation::ngettext("There are too many characters in this field. You have entered %d character; ", "There are too many characters in this field. You have entered %d characters; ", $length), $length) + . sprintf(Horde_Form_Translation::t("you must enter less than %d."), $this->_chars); + } + + $this->message = (string)$message; + return $valid; + } + + /** + * Return info about field type. + */ + public function about():array + { + return [ + 'name' => Horde_Form_Translation::t("Counted text"), + 'params' => [ + 'rows' => ['label' => Horde_Form_Translation::t("Number of rows"), + 'type' => 'int'], + 'cols' => ['label' => Horde_Form_Translation::t("Number of columns"), + 'type' => 'int'], + 'chars' => ['label' => Horde_Form_Translation::t("Number of characters"), + 'type' => 'int']]]; + } + +} \ No newline at end of file diff --git a/src/V3/IntType.php b/src/V3/IntType.php new file mode 100644 index 0000000..61830a3 --- /dev/null +++ b/src/V3/IntType.php @@ -0,0 +1,28 @@ +isRequired() && empty($value) && ((string) (int) $value !== $value)) { + $this->message = Horde_Form_Translation::t("This field is required."); + return false; + } + + if (empty($value) || preg_match('/^[0-9]+$/', $value)) { + return true; + } + + $this->message = Horde_Form_Translation::t("This field may only contain integers."); + return false; + } + + /** + * Return info about field type. + */ + public function about():array + { + return ['name' => Horde_Form_Translation::t("Integer")]; + } +} diff --git a/src/V3/IntlistType.php b/src/V3/IntlistType.php new file mode 100644 index 0000000..8cbcbf3 --- /dev/null +++ b/src/V3/IntlistType.php @@ -0,0 +1,32 @@ +isRequired()) { + $message = Horde_Form_Translation::t("This field is required."); + $this->message = $message; + return false; + } + + if (empty($value) || preg_match('/^[0-9 ,]+$/', $value)) { + return true; + } + + $message = Horde_Form_Translation::t("This field must be a comma or space separated list of integers"); + $this->message = $message; + return false; + + } + + /** + * Return info about field type. + */ + public function about():array + { + return ['name' => Horde_Form_Translation::t("Integer list")]; + } + +} \ No newline at end of file diff --git a/src/V3/Ip6address.php b/src/V3/Ip6address.php new file mode 100644 index 0000000..1225e23 --- /dev/null +++ b/src/V3/Ip6address.php @@ -0,0 +1,35 @@ + 0) { + $valid = @inet_pton($value); + + if ($valid === false) { + $message = Horde_Form_Translation::t("Please enter a valid IP address."); + $this->message = $message; + + } + } elseif ($var->isRequired()) { + $valid = false; + $message = Horde_Form_Translation::t("This field is required."); + $this->message = $message; + } + // Looks like a bug. Shouldn't we return $valid here? + return true; + } + + /** + * Return info about field type. + */ + public function about():array + { + return ['name' => Horde_Form_Translation::t("IPv6 address")]; + } + +} \ No newline at end of file diff --git a/src/V3/IpadressType.php b/src/V3/IpadressType.php new file mode 100644 index 0000000..df91079 --- /dev/null +++ b/src/V3/IpadressType.php @@ -0,0 +1,44 @@ + 0) { + $ip = explode('.', $value); + $valid = (count($ip) == 4); + if ($valid) { + foreach ($ip as $part) { + if (!is_numeric($part) || + $part > 255 || + $part < 0) { + $valid = false; + break; + } + } + } + + if (!$valid) { + $message = Horde_Form_Translation::t("Please enter a valid IP address."); + } + } elseif ($var->isRequired()) { + $valid = false; + $message = Horde_Form_Translation::t("This field is required."); + $this->message = $message; + } + + return $valid; + } + + /** + * Return info about field type. + */ + public function about():array + { + return ['name' => Horde_Form_Translation::t("IP address")]; + } + +} \ No newline at end of file diff --git a/src/V3/LongtextType.php b/src/V3/LongtextType.php new file mode 100644 index 0000000..cd8114d --- /dev/null +++ b/src/V3/LongtextType.php @@ -0,0 +1,88 @@ +isRequired() && empty($value) && ((string) (int) $value !== $value)) { + $this->message = Horde_Form_Translation::t("This field is required."); + return false; + } + + if (empty($value) || preg_match('/^[0-7]+$/', $value)) { + return true; + } + + $this->message = Horde_Form_Translation::t("This field may only contain octal values."); + return false; + } + + /** + * Initialize a Longtext field type + * + * @param $rows = $params[0] ?? 8; + * @param $cols = $params[1] ?? 80; + * @param $helper = $params[2] ?? array(); + */ + public function init(...$params) + { + $rows = $params[0] ?? 8; + $cols = $params[1] ?? 80; + $helper = $params[2] ?? []; + + if (!is_array($helper)) { + $helper = [$helper]; + } + + $this->_rows = $rows; + $this->_cols = $cols; + $this->_helper = $helper; + } + + public function getRows() + { + return $this->_rows; + } + + public function getCols() + { + return $this->_cols; + } + + public function hasHelper($option = '') + { + if (empty($option)) { + /* No option specified, check if any helpers have been + * activated. */ + return !empty($this->_helper); + } elseif (empty($this->_helper)) { + /* No helpers activated at all, return false. */ + return false; + } else { + /* Check if given helper has been activated. */ + return in_array($option, $this->_helper); + } + } + + + /** + * Return info about field type. + */ + public function about():array + { + return [ + 'name' => Horde_Form_Translation::t("Long text"), + 'params' => [ + 'rows' => ['label' => Horde_Form_Translation::t("Number of rows"), + 'type' => 'int'], + 'cols' => ['label' => Horde_Form_Translation::t("Number of columns"), + 'type' => 'int'], + 'helper' => ['label' => Horde_Form_Translation::t("Helpers"), + 'type' => 'stringarray']]]; + } + +} \ No newline at end of file diff --git a/src/V3/NumberType.php b/src/V3/NumberType.php new file mode 100644 index 0000000..1560007 --- /dev/null +++ b/src/V3/NumberType.php @@ -0,0 +1,87 @@ +_fraction = $params[0] ?? null; + } + + public function isValid($var, Horde_Variables|array $vars, $value): bool + { + if ($var->isRequired() && empty($value) && ((string) (float) $value !== $value)) { + $this->message = Horde_Form_Translation::t("This field is required."); + return false; + } elseif (empty($value)) { + return true; + } + + /* If matched, then this is a correct numeric value. */ + if (preg_match($this->_getValidationPattern(), $value)) { + return true; + } + + $this->message = Horde_Form_Translation::t("This field must be a valid number."); + return false; + } + + public function _getValidationPattern() + { + static $pattern = ''; + if (!empty($pattern)) { + return $pattern; + } + + /* Get current locale information. */ + $linfo = Horde_Nls::getLocaleInfo(); + + /* Build the pattern. */ + $pattern = '(-)?'; + + /* Only check thousands separators if locale has any. */ + if (!empty($linfo['mon_thousands_sep'])) { + /* Regex to check for correct thousands separators (if any). */ + $pattern .= '((\d+)|((\d{0,3}?)([' . $linfo['mon_thousands_sep'] . ']\d{3})*?))'; + } else { + /* No locale thousands separator, check for only digits. */ + $pattern .= '(\d+)'; + } + /* If no decimal point specified default to dot. */ + if (empty($linfo['mon_decimal_point'])) { + $linfo['mon_decimal_point'] = '.'; + } + /* Regex to check for correct decimals (if any). */ + if (empty($this->_fraction)) { + $fraction = '*'; + } else { + $fraction = '{0,' . $this->_fraction . '}'; + } + $pattern .= '([' . $linfo['mon_decimal_point'] . '](\d' . $fraction . '))?'; + + /* Put together the whole regex pattern. */ + $pattern = '/^' . $pattern . '$/'; + + return $pattern; + } + + public function getInfo($vars, $var) + { + $value = $vars->get($var->getVarName()); + $linfo = Horde_Nls::getLocaleInfo(); + $value = str_replace($linfo['mon_thousands_sep'], '', $value); + $info = str_replace($linfo['mon_decimal_point'], '.', $value); + return $info; + } + + /** + * Return info about field type. + */ + public function about(): array + { + return ['name' => Horde_Form_Translation::t("Number")]; + } +} + diff --git a/src/V3/OctalType.php b/src/V3/OctalType.php new file mode 100644 index 0000000..0834a76 --- /dev/null +++ b/src/V3/OctalType.php @@ -0,0 +1,29 @@ +isRequired() && empty($value) && ((string) (int) $value !== $value)) { + $this->message = Horde_Form_Translation::t("This field is required."); + return false; + } + + if (empty($value) || preg_match('/^[0-7]+$/', $value)) { + return true; + } + + $this->message = Horde_Form_Translation::t("This field may only contain octal values."); + return false; + } + + /** + * Return info about field type. + */ + public function about():array + { + return ['name' => Horde_Form_Translation::t("Octal")]; + } + +} \ No newline at end of file diff --git a/src/V3/PhoneType.php b/src/V3/PhoneType.php new file mode 100644 index 0000000..4cc27b2 --- /dev/null +++ b/src/V3/PhoneType.php @@ -0,0 +1,61 @@ +_size = $params[0] ?? 15; + } + + public function isValid($var, Horde_Variables|array $vars, $value) + { + if (!strlen(trim($value))) { + if ($var->isRequired()) { + $message = Horde_Form_Translation::t("This field is required."); + $this->message = $message; + return false; + } + } elseif (!preg_match('/^\+?[\d()\-\/.\s]*$/u', $value)) { + $message = Horde_Form_Translation::t("You must enter a valid phone number, digits only with an optional '+' for the international dialing prefix."); + $this->message = $message; + return false; + } + + return true; + } + + public function getSize() + { + return $this->_size; + } + + public function getChars() + { + return $this->_chars; + } + + /** + * Return info about field type. + */ + public function about():array + { + return [ + 'name' => Horde_Form_Translation::t("Phone number"), + 'params' => [ + 'size' => ['label' => Horde_Form_Translation::t("Size"), + 'type' => 'int'], + ], + ]; + } +} \ No newline at end of file diff --git a/src/V3/StringarrayType.php b/src/V3/StringarrayType.php new file mode 100644 index 0000000..f5e9b17 --- /dev/null +++ b/src/V3/StringarrayType.php @@ -0,0 +1,28 @@ +get($var->getVarName()))); + } + + /** + * Return info about field type. + */ + public function about():array + { + return [ + 'name' => Horde_Form_Translation::t("String list returning an array"), + 'params' => [ + 'regex' => ['label' => Horde_Form_Translation::t("Regex"), + 'type' => 'text'], + 'size' => ['label' => Horde_Form_Translation::t("Size"), + 'type' => 'int'], + 'maxlength' => ['label' => Horde_Form_Translation::t("Maximum length"), + 'type' => 'int']], + ]; + } + +} \ No newline at end of file diff --git a/src/V3/StringlistType.php b/src/V3/StringlistType.php new file mode 100644 index 0000000..9bdfc43 --- /dev/null +++ b/src/V3/StringlistType.php @@ -0,0 +1,25 @@ + Horde_Form_Translation::t("String list"), + 'params' => [ + 'regex' => ['label' => Horde_Form_Translation::t("Regex"), + 'type' => 'text'], + 'size' => ['label' => Horde_Form_Translation::t("Size"), + 'type' => 'int'], + 'maxlength' => ['label' => Horde_Form_Translation::t("Maximum length"), + 'type' => 'int']], + ]; + } + +} \ No newline at end of file diff --git a/src/V3/TablesetType.php b/src/V3/TablesetType.php new file mode 100644 index 0000000..92ec9f7 --- /dev/null +++ b/src/V3/TablesetType.php @@ -0,0 +1,62 @@ +_values = $params[0]; + $this->_header = $params[1]; + } + + public function isValid($var, Horde_Variables|array $vars, $value): bool + { + if (count($this->_values) == 0 || count($value) == 0) { + return true; + } + foreach ($value as $item) { + if (!isset($this->_values[$item])) { + $error = true; + break; + } + } + if (!isset($error)) { + return true; + } + + $message = Horde_Form_Translation::t("Invalid data submitted."); + $this->message = $message; + return false; + } + + public function getHeader() + { + return $this->_header; + } + + public function getValues() + { + return $this->_values; + } + + /** + * Return info about field type. + */ + public function about(): array + { + return [ + 'name' => Horde_Form_Translation::t("Table Set"), + 'params' => [ + 'values' => ['label' => Horde_Form_Translation::t("Values"), + 'type' => 'stringlist'], + 'header' => ['label' => Horde_Form_Translation::t("Headers"), + 'type' => 'stringlist']], + ]; + } +} diff --git a/src/V3/TextType.php b/src/V3/TextType.php new file mode 100644 index 0000000..b6bbbb3 --- /dev/null +++ b/src/V3/TextType.php @@ -0,0 +1,91 @@ +_regex = $params[0] ?? ''; + $this->_size = $params[1] ?? 40; + $this->_maxlength = $params[2] ?? null; + } + + public function isValid($var, Horde_Variables|array $vars, $value) + { + $valid = true; + + if (!empty($this->_maxlength) && Horde_String::length($value) > $this->_maxlength) { + $valid = false; + $message = sprintf(Horde_Form_Translation::t("Value is over the maximum length of %d."), $this->_maxlength); + $this->message = $message; + } elseif ($var->isRequired() && empty($this->_regex)) { + $valid = strlen(trim($value)) > 0; + + if (!$valid) { + $message = Horde_Form_Translation::t("This field is required."); + $this->message = $message; + } + } elseif (!empty($this->_regex)) { + $valid = preg_match($this->_regex, $value); + + if (!$valid) { + $message = Horde_Form_Translation::t("You must enter a valid value."); + $this->message = $message; + } + } + + return $valid; + + } + public function getSize() + { + return $this->_size; + } + + public function getMaxLength() + { + return $this->_maxlength; + } + + /** + * Return info about field type. + */ + public function about():array + { + return [ + 'name' => Horde_Form_Translation::t("Text"), + 'params' => [ + 'regex' => ['label' => Horde_Form_Translation::t("Regex"), + 'type' => 'text'], + 'size' => ['label' => Horde_Form_Translation::t("Size"), + 'type' => 'int'], + 'maxlength' => ['label' => Horde_Form_Translation::t("Maximum length"), + 'type' => 'int']]]; + } + +} \ No newline at end of file