Skip to main content

I wanted something similar to form validation for validating url segments. Basically to be able to use any form validation function, helper, php or callback functions to validate passed data.
I have seen countless programmers not check data passed via the url and leading to broken CI pages...for example if they don't check that they actually got a database result when using an id passed via the url that is not what was expected.
It's handy for times you want to check that a passed user id is the current logged in user. Any function you want to use you can...you can even use the 2nd argument like match[1]. You can also pass FALSE as the site url and it will return the FALSE result.
In this example I immediately redirect with an error if one of the checks fails but it uses my set_message() function. So just take that out or add your own function for setting the user message.
This could be further enhanced to use the validation language capabilities and maybe added to the url class and allow you to save rules in a config file.

<?php

/**
 * CodeIgniter Helper function to validate data passed in
 * the URI by segment number.
 *
 * Redirects on fail to specified site url or returns result
 * if the passed $site_url param is bool FALSE. Returns the
 * segment data on success or returns the formatted data if
 * a prepping function was used.
 *
 * @param number $segment The URI segment position to validate.
 * @param string $rules A pipe delimeted string of functions
 *                      to apply against the segment value.
 * @param string $site_url Redirects on fail to specified site
 *                         url or returns result if the passed
 *                         $site_url param is bool FALSE.
 * @return mixed Returns the segment data on success or returns
 *               the formatted data if a prepping function
 *               was used.
 */
function validate_segment($segment, $rules, $site_url = TRUE)
{
    $CI = &get_instance();
    $CI->load->library('form_validation');
    $data = $CI->uri->segment($segment);

    $rules = explode('|', $rules);

    if (! in_array('required', $rules) && $data == '')
    {
        return $data;
    }

    if (in_array('required', $rules) and $data == '')
    {
        set_message('The url has missing data.', 'error');

        if ($site_url)
        {
            $site_url = is_string($site_url) ? $site_url : '';
            redirect($site_url);
        }
    }

    //
    // Cycle through each rule and run it:
    foreach ($rules as $rule)
    {
        if ($rule == 'required')
        {
            continue;
        }

        // Is the rule a callback?
        $callback = FALSE;
        if (substr($rule, 0, 9) == 'callback_')
        {
            $rule = substr($rule, 9);
            $callback = TRUE;
        }

        //
        // Strip the parameter (if exists) from the rule
        // Rules can contain a parameter: max_length[5]
        $match = NULL;
        $param = FALSE;
        if (preg_match('/(.*?)\[(.*?)\]/', $rule, $match))
        {
            $rule = $match[1];
            $param = $match[2];
        }

        //
        // Call the function that corresponds to the rule:
        if ($callback === TRUE)
        {
            if (! method_exists($CI, $rule))
            {
                $validates = FALSE;
            }

            if ($param)
            {
                $result = $CI->$rule($data, $param);
            }
            else
            {
                $result = $CI->$rule($data);
            }
        }
        else
        {
            if (! method_exists($CI->form_validation, $rule))
            {
                // If our own wrapper function doesn't exist,
                // see if a native PHP function exists.
                // Users can use any native PHP function
                // call that has one param:
                if (function_exists($rule))
                {
                    if ($param)
                    {
                        $result = $rule($data, $param);
                    }
                    else
                    {
                        $result = $rule($data);
                    }
                }
            }
            else
            {
                if ($param)
                {
                    $result = $CI->form_validation->$rule($data, $param);
                }
                else
                {
                    $result = $CI->form_validation->$rule($data);
                }
            }
        }

        //
        // Is it a bool or did the function change the data
        // and send it back:
        $data = (is_bool($result)) ? $data : $result;

        //
        // Did the rule test negatively? If so, grab the error:
        if (is_bool($result) && $result === FALSE)
        {
            if ($site_url)
            {
                $site_url = is_string($site_url) ? $site_url : '';
                set_message('The url has incorrect data.', 'error');
                redirect($site_url);
            }

            return $data;
        }
    }

    return $data;
}

//
// Usage

$id = validate_segment(3, 'required|is_natural_no_zero');
$user_id = validate_segment(4, 'required|is_natural_no_zero|is_admin|is_current_user');
$page_name = validate_segment(5, 'alpha_dash');