Search code examples
phpopencartopencart-3

How to verify OTP in PHP with SESSION or COOKIES (Opencart 3)


I'm just creating OTP verification system in Opencart. Everything works fine, but the only problem is number is not validating. I think I am doing something wrong. Every time I refresh the page, OTP also get changed. Does number should stay same for time of 3-4 minutes? Could you guys suggest me where I am wrong?

Here is the controller code:

<?php
class ControllerAccountOtpverify extends Controller {
private $error = array();

public function index() {
    if ($this->customer->getOtpverify() == 1) {
        $this->response->redirect($this->url->link('account/account', '', true));
    }

    $this->load->language('account/otp_verify');

    $this->document->setTitle($this->language->get('heading_title'));

    $this->load->model('account/customer');

    if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
        $this->model_account_customer->editOtpverify($this->request->post['otpverify']);

        $this->session->data['success'] = $this->language->get('text_success');

        $this->response->redirect($this->url->link('account/account', '', true));
    }

    $data['breadcrumbs'] = array();

    $data['breadcrumbs'][] = array(
        'text' => $this->language->get('text_home'),
        'href' => $this->url->link('common/home')
    );

    $data['breadcrumbs'][] = array(
        'text' => $this->language->get('text_account'),
        'href' => $this->url->link('account/account', '', true)
    );

    if (isset($this->error['otp'])) {
        $data['error_otp'] = $this->error['otp'];
    } else {
        $data['error_otp'] = '';
    }

    $data['otp'] = rand(1000, 9999);
    $_SESSION['otp'] = $data['otp'];

    $data['action'] = $this->url->link('account/otp_verify', '', true);

    $data['back'] = $this->url->link('account/login', '', true);


    $data['column_left'] = $this->load->controller('common/column_left');
    $data['column_right'] = $this->load->controller('common/column_right');
    $data['content_top'] = $this->load->controller('common/content_top');
    $data['content_bottom'] = $this->load->controller('common/content_bottom');
    $data['footer'] = $this->load->controller('common/footer');
    $data['header'] = $this->load->controller('common/header');

    $this->response->setOutput($this->load->view('account/otp_verify', $data));
}
private function validate() {
    if ((trim($this->request->post['otp'])) != $this->_SESSION['otp']) {
        $this->error['otp'] = $this->language->get('error_otp');
    }


    return !$this->error;
}
}

I am not familiar with session and cookies so can any one help me in this. Thank you.


Solution

  • Below is your sample code modified according to your comments. I have not tested it though, so look out for any errors / warnings:

    <?php
    class ControllerAccountVerify extends Controller {
        private $error = array();
        private $otp = array();
    
        public function index() {
            if ($this->customer->getPhoneverified() == 1) {
                $this->response->redirect($this->url->link('account/account', '', true));
            }
    
            $this->load->language('account/verify');
    
            $this->document->setTitle($this->language->get('heading_title'));
    
            $this->load->model('account/customer');
    
            if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
                $this->model_account_customer->editPhoneverified($this->request->post['phoneverified']);
    
                $this->session->data['success'] = $this->language->get('text_success');
    
                $this->response->redirect($this->url->link('account/account', '', true));
            }
    
            //$this->session->data['session_otp'] = '';
    
            if(isset($this->session->data['otp']) && $this->session->data['otp'] != '') {
                $this->otp = json_decode($this->session->data['otp']);
    
                // create a new OTP if it is expired
                if($this->otp->Expired) {
                    $this->createOTP();
                    $data['otp'] = $this->otp->Value;
                }
            } else {
                $this->createOTP();
                $data['otp'] = $this->otp->Value;
            }
    
            $data['debugTest'] = json_encode($this->session);
    
            $data['numberotp'] = $this->otp->Value;
    
            $data['breadcrumbs'] = array();
    
            $data['breadcrumbs'][] = array(
                'text' => $this->language->get('text_home'),
                'href' => $this->url->link('common/home')
            );
    
            $data['breadcrumbs'][] = array(
                'text' => $this->language->get('text_account'),
                'href' => $this->url->link('account/account', '', true)
            );
    
            if (isset($this->error['otp'])) {
                $data['error_otp'] = $this->error['otp'];
            } else {
                $data['error_otp'] = '';
            }
    
            $data['action'] = $this->url->link('account/verify', '', true);
    
            $data['back'] = $this->url->link('account/login', '', true);
    
            $data['column_left'] = $this->load->controller('common/column_left');
            $data['column_right'] = $this->load->controller('common/column_right');
            $data['content_top'] = $this->load->controller('common/content_top');
            $data['content_bottom'] = $this->load->controller('common/content_bottom');
            $data['footer'] = $this->load->controller('common/footer');
            $data['header'] = $this->load->controller('common/header');
    
            $this->response->setOutput($this->load->view('account/verify', $data));
        }
    
        private function validate() {
            if (!isset($this->request->post['otp'])) {
                $this->error['otp'] = $this->language->get('error_otp'); // No OTP posted to controller
            } else {
                $otp_value = $this->request->post['otp']; // set the posted value
            }
    
            // check that our session has a value
            if(!isset($this->session->data['otp'])) {
                $this->error['otp'] = $this->language->get('error_otp_session'); //  need to add an error message to handle if the session value is null
            } else {
                $this->otp = json_decode($this->session->data['otp']);
                // compare the posted otp to the value in session
                if(!$this->otp->Value == $otp_value) {
                    $this->error['otp'] = $this->language->get('error_otp_invalid'); //  need to add an error message to handle if the otp does not match
                } else {
                    // check if the otp has expired or not
                    $elapsed_time = date_diff(date('Y-m-d H:i:s'),$session_otp['ExpireDateTime']);
                    if(!$elapsed_time->mins < 5 ) {
                        $this->otp->Expired = true;
                        $this->error['otp'] = $this->language->get('error_otp_expired'); //  need to add an error message to handle if the otp expired
                    }
                }
            }
    
            return !$this->error;
        }
    
        // reset the OTP property and update the session
        private function createOTP() {
            $this->otp = array(
                "Value"             => rand(1000, 9999),
                "ExpireDateTime"    => date('Y-m-d H:i:s', strtotime("+5 min")),
                "Expired"           => false
            );
    
            $this->session->data['otp'] = json_encode($this->otp);
        }
    }