Problems, need help? Have a tip or advice? Post it here.
6 posts Page 1 of 1
Hi everyone,

Here I am again with a couch "validator" regex problem. These are the regex used inside the template tag to validate user input for field values.

I have 2 simple regex that are not working for me as couch validators, but which are valid regex expressions. I checked them using php's preg_match() from the command line. However, when used as couch input validators, they always report a regex mismatch. I am using the default pipe character (|) as "separator".

validator='regex=/^([A-Z]{2}=\d,){59}$/'
This validator should accept exactly 59 US states zone definitions,of the form "AA=8". Here are the first 7:
AA=8,AE=8,AP=8,AL=5,AK=8,AS=8,AZ=6,

validator='regex=/^([A-Z]{2},)+$/'
This validator should match a list of US states (2 digit states codes) of indeterminate length:
AA,AE,AP,AL,AK,

This similar regex works for me:
/^(\d+\.?\d*,){8}$/
(validates a comma separated list of list of exactly 8 prices, which may contain a decimal)
This makes me think the problem is probably the square brackets. I'll bet they're being sanitized by couch.
@KK, I still believe that user-provided validators must be treated as-is by default. This topic is a perfect example that Couch should not intervene unless specifically instructed.

OP, create a substitute validator that will use unmodified regex :)
I strongly agree with trendoman. At least, Couch should not mangle user-supplied regex expressions.

Trendoman kindly pointed out to me that Couch lowercases the argument to the "validator" attribute. I think this happens both for the "editable" tag as well as the "validate" tag.

I understand that it is possible to specify a custom validator. Is that possible for the "editable" tag? If so, I don't think it is documented. Can someone please point me to some information on this?
lstandish wrote: I understand that it is possible to specify a custom validator. Is that possible for the "editable" tag? If so, I don't think it is documented. Can someone please point me to some information on this?


Whatever is passed in validator='' parameter of cms:editable can be considered 'custom', because it is a name of a php function, sitting somewhere and waiting to be called (can be in kfunctions.php - user-defined funcs or in native CouchCMS code - documented validators). I sent a PM with a link to another topic discussing the matter with example from KK. There are tons of examples in forum.
Thanks trendoman, that should be all the information I need.
Validators can be simple PHP functions and don't need to be registered.

For example, if my editable region is defined this way -
Code: Select all
<cms:editable name='email' label='Email' validator='email | no_duplicate_mail' type='text' />  

- there are two validators being used above. The first one 'email' is registered in Couch but the second one is not so Couch will see if a PHP function by that name is available.
If it is, it will be called with the field being validated (and any arguments that may be set); if not found, it will display an error.

So the function must be put somewhere where it is available to Couch - the kfunctions.php file is a good place for this.
Also, as highlighted in the line above, the function must accept as its parameters the field and the arguments (if applicable).

If you take a look in couch/functions.php, you'll find many functions named validate_* e.g.
Code: Select all
static function validate_numeric( $field ){
    $val = trim( $field->get_data() );
    if( !is_numeric($val) ){
        return KFuncs::raise_error( "Invalid characters (only numeric values allowed)" );
    }
}

Each will accept a $field as its first parameter and some may also accept a second param e.g.
Code: Select all
static function validate_min_len( $field, $args ){ ..

We'll continue with validate_numeric as our example.
The $field is actually the editable region being validated so we need to first get the value being inputted in that editable region. That is what this line does.
Code: Select all
$val = trim( $field->get_data() ); 

Next we do whatever validation we desire on that value.
If our validations pass, the function silently returns (i.e no news is good news).
If it fails, we return a KFuncs::raise_error like this -
Code: Select all
return KFuncs::raise_error( "Invalid characters (only numeric values allowed)" );  

And those are the only two essential things for any validator - get the value from the editable region and test it and return an error object if validation fails.

I suggest you take a look at the following core validators that use regex (something that you are interested in) -
Code: Select all
static function validate_email( $field ){
    if( !preg_match("/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,10}$/i", trim($field->get_data())) ){
        return KFuncs::raise_error( "Invalid email address" );
    }
}

static function validate_url( $field ){
    // Pattern from http://mathiasbynens.be/demo/url-regex
    $pattern = "/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iuS";
    if( !preg_match($pattern, trim($field->get_data())) ){
        return KFuncs::raise_error( "Invalid URL" );
    }
}

static function validate_regex( $field, $args ){
    if( !preg_match(trim($args), trim($field->get_data())) ){
        return KFuncs::raise_error( "Does not match pattern" );
    }
}

Notice how each uses the two points I mentioned.

All the examples above are registered validators (and so are invoked by some easier names) but any custom validator will be exactly the same.
As one last example, remember the custom validator (no_duplicate_email) we used in the very first code example above?
Code: Select all
<cms:editable name='email' label='Email' validator='email | no_duplicate_mail' type='text' />   

Here is the actual code for the function behind it -
Code: Select all
// custom email validator placed in kfunctions.php
function no_duplicate_mail( $field ){
    global $FUNCS, $CTX;

    $email = trim( $field->get_data() );
    $current_page_id = $field->page->id;

    if( strlen($email) ){

         // Create Couch script..
        $html = "<cms:pages masterpage='contact.php' id='NOT {$current_page_id}' custom_field='email=={$email}' show_future_entries='1' count_only='1' />";

        // Pass on the code to Couch for execution using the 'embed' function
        $count = $FUNCS->embed( $html, $is_code=1 );
        if( $count ){
            return KFuncs::raise_error( "Email already exists" );
        }
    }
}

As you can see, it is just a normal PHP function and uses the same steps as used by the registered core validators.

Hope this is sufficient info for you to code your own validator.
6 posts Page 1 of 1
cron