1

View:

<div class="container">
    <div class="row">
        <div class="col-md-3">
        </div>
        <div class="col-md-6">
        <form method="post" action="<?php echo base_url();?>account/register">
        <?php $form_error = $this->session->flashdata('error'); ?>
          <div class="form-group">
            <label for="username">Username</label>
            <input class="form-control" id="username" name="username" type="input">
            <div id="form_error"><?php echo $form_error['username']; ?></div>
          </div>
          <div class="form-group">
            <label for="password">Password</label>
            <input class="form-control" id="password" name="password" type="password">
            <div id="form_error"><?php echo $form_error['password']; ?></div>
          </div>
          <div class="form-group">
            <label for="confirm_password">Confirm Password</label>
            <input class="form-control" id="confirm_password" name="confirm_password" type="password">
          <div id="form_error"><?php echo $form_error['confirm_password']; ?></div>
          </div>
          <div class="form-group">
            <label for="gender">Gender</label>
            <select class="form-control" id="gender" name="gender">
                <option disabled selected value="">select a gender</option>
                <option value="Male">Male</option>
                <option value="Female">Female</option>
                <option value="Other">Other</option>
            </select>
            <div id="form_error"><?php echo $form_error['gender']; ?></div>
          </div>
          <div class="form-group">
            <label for="birthdate">Birthdate</label>
            <input class="form-control" id="birthdate" name="birthdate" type="date">
            <div id="form_error"><?php echo $form_error['birthdate']; ?></div>
          </div>



          <button type="submit" class="btn btn-primary btn-block">Submit</button>
        </form>
        <div class="text-center">
        <a class="d-block small mt-3" href="<?php echo base_url();?>pages/login_user">Already have an account?</a>
        </div>
        </div>
        <div class="col-md-3">
        </div>
    </div>
</div>
</body>

Account Controller:

public function register(){
$this->form_validation->set_rules('username', 'Username', 'trim|required|is_unique[users.username]');
$this->form_validation->set_rules('password', 'Password', 'trim|required|min_length[8]|max_length[20]');
$this->form_validation->set_rules('confirm_password', 'Confirm Password', 'trim|required|matches[password]');
$this->form_validation->set_rules('gender', 'Gender', 'trim|required|in_list[Male,Female,Other]');
$this->form_validation->set_rules('birthdate', 'Birthdate', 'trim|required|valid_date');

if($this->form_validation->run() == FALSE){
$form_error = array('username' => form_error('username'),
        'password' => form_error('password'),
        'confirm_password' => form_error('confirm_password'),
        'gender' => form_error('gender'),
        'birthdate' => form_error('birthdate'));
$this->session->set_flashdata('error', $form_error);
redirect('pages/register_user');
}else{ 
$data = array('username' => $this->input->post('username'),
            'password' => password_hash($this->input->post('password'),PASSWORD_BCRYPT),
            'gender' => $this->input->post('gender'),
            'birthdate' => $this->input->post('birthdate'),
            'date_created' => mdate('%Y-%m-%d',time()),
            'last_login' => mdate('%Y-%m-%d',time()));
if($this->account_model->create_account($data)){
$this->session->set_flashdata('message','Registration Successful');
redirect('pages/login_user');
}else{
$this->session->set_flashdata('message','Registration Failed');
redirect('pages/register_user');}}
}

//form_validation callback
public function valid_date($birthdate){
    echo 'aw';
if(date('YYYY-MM-DD',strtotime($birthdate))){
return TRUE; }else{
    echo $birthdate;
$this->form_validation->set_message('valid_date', 'Invalid Birthdate');
$form_error['birthdate'] = form_error('valid_date');
$this->session->set_flashdata('error',$form_error);
return FALSE; }
}

Pages Controller:

public function login_user(){
    $data['title'] = 'Login';
    $this->load->view('template/header',$data);
    $this->load->view('template/navbar');
    $this->load->view('pages/login');
    $this->load->view('template/footer');
    }

    public function register_user(){
    $data['title'] = 'Register';
    $this->load->view('template/header',$data);
    $this->load->view('template/navbar');
    $this->load->view('pages/registration');
    $this->load->view('template/footer');
    }

I tried setting flashdata inside the callback function but this is my first time using a callback function to check the validity of the birthdate given. I tested out the input and you can't input any alphabets but you can go over the maximum length. For example the format should be 'YYYY-MM-DD' you can input something like this: 555555-55-55.

All my other error prints out successfully but the valid_date callback function prints an error:

Unable to access an error message corresponding to your field name Birthdate.(valid_date)

If what i'm asking for is impossible/wrong then i'll just add a min_length[10] and max_length[10] and just edit its error to 'invalid date'.

EDIT: Taking inspiration from my statement above about the max and min length, i also added a custom error for the valid_date there and what do you know it works.

Heres my updated controller:

public function register(){
    $this->form_validation->set_rules('username', 'Username', 'trim|required|is_unique[users.username]');
    $this->form_validation->set_rules('password', 'Password', 'trim|required|min_length[8]|max_length[20]');
    $this->form_validation->set_rules('confirm_password', 'Confirm Password', 'trim|required|matches[password]');
    $this->form_validation->set_rules('gender', 'Gender', 'trim|required|in_list[Male,Female,Other]');
    $this->form_validation->set_rules('birthdate', 'Birthdate', 'trim|required|valid_date',
    array('valid_date' => 'Invalid Date of birth'));

    if($this->form_validation->run() == FALSE){
    $form_error = array('username' => form_error('username'),
            'password' => form_error('password'),
            'confirm_password' => form_error('confirm_password'),
            'gender' => form_error('gender'),
            'birthdate' => form_error('birthdate'));
    $this->session->set_flashdata('error', $form_error);
    redirect('pages/register_user');
    }else{ 
    $data = array('username' => $this->input->post('username'),
                'password' => password_hash($this->input->post('password'),PASSWORD_BCRYPT),
                'gender' => $this->input->post('gender'),
                'birthdate' => $this->input->post('birthdate'),
                'date_created' => mdate('%Y-%m-%d',time()),
                'last_login' => mdate('%Y-%m-%d',time()));
    if($this->account_model->create_account($data)){
    $this->session->set_flashdata('message','Registration Successful');
    redirect('pages/login_user');
    }else{
    $this->session->set_flashdata('message','Registration Failed');
    redirect('pages/register_user');}}
    }

    //form_validation callback
    public function valid_date($birthdate){
    if(date('YYYY-MM-DD',strtotime($birthdate))){
    return TRUE; }else{return FALSE; }
    }

I'm still not sure if it really works or just by fluke.

John
  • 33
  • 4
  • 11
  • Usually only see that message when `set_message()` isn't defined or doesn't directly reference the function name. Weird. Why are you doing this in the callback? Doesn't make sense... Callbacks should just return not define any other app logic. – Alex Feb 10 '18 at 07:10
  • Also I'm not sure about your method for checking if a date is valid. Try this instead: https://stackoverflow.com/questions/19271381/correctly-determine-if-date-string-is-a-valid-date-in-that-format – Alex Feb 10 '18 at 07:11
  • The method i used is from date helper from codeigniter. If its a valid date format then it will convert if not then its not valid. I tried to set_message inside the callback since that's how most of the callback examples ive seen so i never gave it thought to just simply override it inside the set_rules() 4th parameter. – John Feb 10 '18 at 07:15
  • Indeed the set message way is the way I do it too, but I was referencing the session message in there. Glad you found a solution, still unsure why set_message() wasnt working: https://codeigniter.com/user_guide/libraries/form_validation.html#callbacks-your-own-validation-methods – Alex Feb 10 '18 at 07:16
  • My problem now is if im doing my callback function correctly. I can't seem to access my callback. I've echoed something in there and i've commented(//) my codes that loads the view. I keep getting invalid date even if its correct but i can't fix this if i can't access my callback T_T – John Feb 10 '18 at 07:22
  • Well your syntax is wrong for adding a message like that. Look at the docs under: "using anything as a rule"... also I'm having a problem getting your date function to properly work in terms of validating a date... it seems as though whatever I throw at it always gives me a valid date... – Alex Feb 10 '18 at 07:23
  • https://3v4l.org/mKZOZ – Alex Feb 10 '18 at 07:26
  • Yes, i noticed. I simply gave up accessing it through the form validation and simply directly accessed it through url and i keep throwing wrong formats at it and it keeps converting them. – John Feb 10 '18 at 07:26
  • I've tried using date helper but it keeps converting into time unix even though its a wrong format. I found an answer here but idk if i should just copy paste it. – John Feb 10 '18 at 07:33
  • What kindof date do you want to evaluate as valid? `2018-12-01`? – Alex Feb 10 '18 at 07:40

3 Answers3

1

Register code:

public function register() {
    $this->form_validation->set_rules('username', 'Username', 'trim|required|is_unique[users.username]');
    $this->form_validation->set_rules('password', 'Password', 'trim|required|min_length[8]|max_length[20]');
    $this->form_validation->set_rules('confirm_password', 'Confirm Password', 'trim|required|matches[password]');
    $this->form_validation->set_rules('gender', 'Gender', 'trim|required|in_list[Male,Female,Other]');
    $this->form_validation->set_rules('birthdate', 'Birthdate', 'trim|required|callback_valid_date');

    if ($this->form_validation->run() == FALSE) {
        // let's see what's going on under the hood...
        print_r($this->form_validation->error_array());
        exit;
        $form_error = array('username' => form_error('username'),
            'password' => form_error('password'),
            'confirm_password' => form_error('confirm_password'),
            'gender' => form_error('gender'),
            'birthdate' => form_error('birthdate'));
        $this->session->set_flashdata('error', $form_error);
        redirect('pages/register_user');
    } else {
        $data = array('username' => $this->input->post('username'),
            'password' => password_hash($this->input->post('password'), PASSWORD_BCRYPT),
            'gender' => $this->input->post('gender'),
            'birthdate' => $this->input->post('birthdate'),
            'date_created' => mdate('%Y-%m-%d', time()),
            'last_login' => mdate('%Y-%m-%d', time()));
        if ($this->account_model->create_account($data)) {
            $this->session->set_flashdata('message', 'Registration Successful');
            redirect('pages/login_user');
        } else {
            $this->session->set_flashdata('message', 'Registration Failed');
            redirect('pages/register_user');
        }
    }
}

Referencing a callback necessitates the function be called via callback_func_name.

Revised callback:

Note: item does not start with callback_

See: Correctly determine if date string is a valid date in that format (read: test cases)

public function valid_date($date) {
    $format = 'Y-m-d';
    $d = DateTime::createFromFormat($format, $date);
    if ($d && $d->format($format) == $date) {
        return TRUE;
    } else {
        $this->form_validation->set_message('valid_date', 'Invalid Birthdate.');
        return FALSE;
    }
}

Doing date('YYYY-MM-DD') is wrong as it yields: 2018201820182018-FebFeb-SatSat. See date docs.

Alex
  • 9,215
  • 8
  • 39
  • 82
  • Doesn't this only check if the format is valid and not the date itself? I'm reading the php manual for checkdate(). It checks if the date is valid. – John Feb 10 '18 at 07:47
  • Like if the date actually exists? It does that `2018-01-32` yields invalid. In any case, is the callback working? If you put in `2018-01-02` into the birthdate field does it validate? If you put in `blah` does it give you `Invalid Birthdate` in the error_array that I am print_r'ing in the above controller? – Alex Feb 10 '18 at 07:50
  • public function valid_date(){ $birthdate = '2001-02-29'; $temp = explode('-',$birthdate); $year = $temp[0]; $month = $temp[1]; $day = $temp[2]; if(checkdate($month,$day,$year)){ echo 'valid';} else{ echo 'invalid';} } If i put in 2001-02-29 the date doesnt exist so it prints invalid but if i try to add more number to the year for example 20011 it will print valid. im so confused. For example if the year was this : $birthdate = '20012-02-26'; it will still print valid. – John Feb 10 '18 at 07:52
  • Ah, i forgot to reread the manual and it says: The year is between 1 and 32767 inclusive. I guess i was too involved in the 4 digit years. – John Feb 10 '18 at 07:55
  • I've never heard or used that function so I can't say. `DateTime` is newer so I don't touch the old stuff. And when you have upwards of 260 answer upvotes on that method I tend to go with it. – Alex Feb 10 '18 at 07:55
  • I'll accept your answer but ill just use checkdate since its easier for me to understand. I never used shortcut like the datetime:: part. For example ive seen codes of if statements with question marks and i know it still works but for now since im still on the early phase of relearning php ill stick to the easier to follow route. – John Feb 10 '18 at 07:59
  • I get you, but datetime is pretty easy if you take the time to go through the docs. Thanks for the accept ;) – Alex Feb 10 '18 at 08:01
  • Its also kind of funny. The input type="date"; itself doesnt accept invalid dates. I tried testing my callback and tried inputting 02-29-2001 but it wont let me. Still the input type lets me input as many numbers to my years so the callback is still needed. – John Feb 10 '18 at 08:03
  • Yea I mean you can probably use standard bootstrap datepicker and a regular input and you can set your desired date format there. but as a general rule, as you must know as you are doing the right things with form validation on the backend, never trust browser validation of any kind. – Alex Feb 10 '18 at 08:08
0

hey try this to use callback

$this->form_validation->set_rules('birthdate', 'Birthdate', 'trim|required|callback_validdate',

//form_validation callback
public function validdate($birthdate){

    $birthdate = $this->input->post('birthdate');

    if( date('YYYY-MM-DD',strtotime($birthdate)) )
    {
        return true;
    }

    $this->form_validation->set_message('validdate','Check the birthday input to match a format like this YYYY-MM-DD');
    return false;

}

Callbacks: Your own Validation Methods

The validation system supports callbacks to your own validation methods. This permits you to extend the validation class to meet your needs. For example, if you need to run a database query to see if the user is choosing a unique username, you can create a callback method that does that

More Detail read https://codeigniter.com/user_guide/libraries/form_validation.html#callbacks-your-own-validation-methods

Bhupesh
  • 883
  • 7
  • 16
0

You should call this way:

$this->form_validation->set_rules('birthdate', 'Birthdate', 'trim|required|callback_valid_date');
  • I already changed my code to that. I haven't updated the question because it is already answered. Sorry for the confusion. – John Feb 10 '18 at 09:06