=head1 NAME TUWF::Misc - Miscellaneous utility functions and methods for TUWF =head1 DESCRIPTION This module provides a few methods for the main TUWF object and optionally exports a few handy functions. The methods can be used from within any TUWF website without requiring any additional magic, TUWF automatically loads this module at initialization. The exported functions can be imported through TUWF (C) or by using this module directly (C). The latter form is useful if you wish to use a function outside of the TUWF framework. =head1 METHODS =head2 formValidate(@fields) Shorthand for calling C with the following sources: Name TUWF Method post reqPosts() get reqGets() param reqParams() cookie reqCookie() The L configuration setting is passed as the I option. =head2 compile($schema) I Short-hand for calling L with the L option. For example: TUWF::set('custom_validations')->{username} = { length => [ 3, 32 ] }; my $val = tuwf->compile({ username => 1 })->validate('this is a username')->data; =head2 validate(what, @args) I Validate and return request data using L. The first argument must be the source of the data to validate, the following sources are supported: Argument Source post reqPosts() get reqGets() param reqParams() json reqJSON() This method takes several different forms for the further arguments (the examples below will perhaps make this more clear): =over =item Single value (C<< tuwf->validate($source, $param_name, $schema)> >>) In this form, only a single value is validated and returned. =item Hash value (C<< tuwf->validate($source, $schema) >>) In this form, the source is converted into a hash table and then validated. The C<$schema> then validates the entire hash. =item Multiple values (C<< tuwf->validate($source, $param1, $schema1, $param2, $schema2, ..) >>) This form uses the syntax of the I form to validate multiple values. It is a convenient short-hand for the I form. =back The C<$schema> argument in the above description can be either a bare or compiled schema. A bare schema will be compiled with the L setting. The C source only supports the I form. Using the C source is discouraged, as it is slower than using the C or C source directly. And in almost all cases you only need to accept the data from either the query string or the POST data, not both. If a get/post/param parameter has multiple values, it is represented in the source data as an array. To handle parameters that may occur any number of times, use a C<< {type => 'array', scalar => 1} >> schema. Some examples: # JSON, with custom error handling my $validation_result = tuwf->validate(json => { type => 'hash', keys => { username => { length => [ 3, 32 ] }, password => { }, } }); if($validation_result) { my $data = $validation_result->data; check_login($data->{username}, $data->{password}); } else { show_error(); } # Single value my $page_number = tuwf->validate(get => page => { uint => 1, max => 1000 })->data; # Same, with a pre-compiled scheme (this is faster) state $c = tuwf->compile({ uint => 1, max => 1000 }); my $page_number = tuwf->validate(get => page => $c)->data; # Multiple values my $data = tuwf->validate(post => username => { length => [ 3, 32 ] }, password => { }, )->data; # Same, using the "Hash value" form my $data = tuwf->validate(post => { type => 'hash', keys => { username => { length => [ 3, 32 ] }, password => { }, } })->data; =head2 mail(body, header => value, ..) Very simple email sending function. The C header defaults to C, and the C header to the L configuration setting. The mail is sent using the sendmail program configured with L, you should make sure both that option is correct and the server is configured to allow using the sendmail program to actually send mail. =head1 FUNCTIONS =head2 uri_escape(string) Percent-encodes the given string and returns a string suitable for use as a parameter value in a URI. The given string is assumed to be in Perls native unicode format, and the escaped string will have UTF-8 encoded percent-escaping. This function is equivalent to C provided by L, and the C function in JavaScript. =head2 kv_validate(sources, templates, fields) Validates a set of key/value pairs against a list of constraints and data definitions. Returns the (optionally modified) key/value pairs and, if a field did not validate, an error indication. This function was designed to validate form input data, and can as such also validate keys (or I) which represent multiple values. This function is rarely used directly, C does everything you need when validating common input data. I is a hashref explaining where the values should be fetched from. Each key in the hash represents the I of the source, and its value is a subroutine reference. This subroutine should accept one argument: the name of the field, and is expected return a list of values, or an empty list if there are no values with that key. The following example defines a source by the name "param", and tells C to fetch the values using L. kv_validate( { param => sub { $TUWF::OBJ->reqParams(shift) } }, .. ); The I argument should be reference to a (possibly empty) hash providing templates for commonly used constraints and data definitions. The I argument should be an arrayref, where each item in the array represents a single field. Each field should be a hashref with options. The following options are accepted: =over =item => String, indicates from which source the field should be fetched, and which name to use. Note that even though C accepts validating data from multiple sources, each field should only have one source option, and there should not be a field from a different source with the same name. Using the I example above, specifying C 'foo'> as field option tells C to fetch the value(s) for this field from C. =item required 0/1. Indicates whether the field is required or not. Default: 1. =item default Specifies the default value to return when the field is not present or left empty. Only makes sense for fields that are not required. =item rmwhitespace 0/1. Removes any whitespace before and after the value before doing any other validation. All occurences of C<\r> are also removed from the value. Default: 1. =item maxlength Number. Maximum length (in number of characters) of the value. =item minlength Number. Minimum length of the value. =item enum Arrayref. The value must be equal to any of the strings in the array. Note that even though a string comparison is used, this works fine numbers as well. =item regex Validate the value against a regular expression. For identification, this option can also be set to an arrayref, of which the first item contains the regular expression. All other elements in the array are ignored by C, but are still returned in the error structure and can therefore be used in your code. =item func Subroutine reference. Validate the value against a function. The subroutine is passed two arguments: The value, and a hash reference with the I in the scope that the I is defined. The subroutine should return false if the value is invalid, true otherwise. The value argument is passed as a reference, and may be modified in-place to perform normalization. This option can also be set to an arrayref, which works the same as with the I option. This constraint is only executed after the other constraints have been validated. So the subroutine is not called if, for example, the value is empty and the I flag is set. The extra I argument can be used to read additional information for validation. For example, { func => sub { $_[0] =~ /^$_[1]{prefix}/ }, prefix => 'hello' } The subroutine verifies that the value is prefixed by the value of the I field, which is passed to the subroutine as second argument. =item template String, refers to a key in the I hash. Validates the value against the options in I<%{$templates{$string}}>, which may contain any of the above mentioned options (except ). When a template contains a I field, the fields that are passed to the subroutine only include the fields that are specified in the template options. Using the example above, the following will not work as expected: $templates{prefix} = { func => sub { $_[0] =~ /^$_[1]{prefix} } }; # In the field definitions { template => 'prefix', prefix => 'hello' } In this example, the only field that is passed to the subroutine is the 'func' field that is in the template definition itself. The subroutine has no access to 'prefix' field that is defined outside of the template. To work around this issue, a special I option exists to allow the template to inherit certain fields from the parent scope. The template definition can be changed as follows: $templates{prefix} = { func => sub { $_[0] =~ /^$_[1]{prefix} }, inherit => ['prefix'], }; This causes the 'prefix' field from the user of the template to be passed into the context of the template itself, so the subroutine can access it. =item multi 0/1, indicates whether there should be only one value or multiple values. If this option is disabled (as is the default), only the first value will be validated and returned. Otherwise, each value is validated separately against the above options and an arrayref with values is returned. Validating this field is stopped when one value does not match. The I and I options are also evaluated per-value: if required is true, each value should be non-empty. Empty values are set to the default. =item maxcount Number. When I is true, specifies the maximum number of values to be present. Whether they are empty or not is ignored in this count. =item mincount Number. See I. =back C returns a hashref with field name to value mappings. When one or more fields did not validate, a special C<_err> field is added. Its value is an arrayref where each item represents an invalid field. Each invalid field is represented again by an arrayref containing three items: the name of the field, the option that caused it to fail and the value of that option. The following templates are provided by default. These templates can be safely overridden with the I argument to C or removed completely by setting the template to C. =over =item num The value must be a (JSON-like) number. Two extra fields are available when this template is used: I to specify the lower bound on the number, and I the upper bound. This template automatically coorces the value into a Perl number. =item int Similar to the I template, except the value must be a whole number, no fractions or exponents are allowed. =item uint Similar to the I template, but the number must be positive. =item ascii The value must consist entirely of printable ASCII characters. =item email The value must be a valid e-mail address. Note that this is just simple validation using a regular expression. A valid e-mail address in this context does not imply that the email exists, or that all mail clients or servers will accept it. For more precise validation, there's always L and L. =item weburl The value must be a valid HTTP or HTTPS URL. =back Usage example: my $r = kv_validate( # sources { param => sub { $TUWF::OBJ->reqParams(shift) } }, # templates { crc32_hex => { regex => qr/^[0-9a-f]+$/i, maxlength => 8, minlength => 8, } }, # field definitions [ { param => 'name', maxlength => 100 }, { param => 'age', min => 18, max => 120 }, { param => 'crc', required => 0, template => 'crc32_hex' }, ], ); # Depending on the input, $r may look something like: { name => 'John Doe', age => 28, crc => 'This does not look like a CRC32 string', _err => [ [ 'crc', 'template', 'crc32_hex' ] ] } =head1 SEE ALSO L, L. =head1 COPYRIGHT Copyright (c) 2008-2018 Yoran Heling. This module is part of the TUWF framework and is free software available under the liberal MIT license. See the COPYING file in the TUWF distribution for the details. =head1 AUTHOR Yoran Heling =cut