Source for file Login.php

Documentation is available at Login.php

  1. <?php
  2.  
  3. /**
  4.  * The Login Module
  5.  *
  6.  * This module can be used by other modules as follows:-
  7.  * - Copy module file to module directory
  8.  * - Adjust configuration file as needed (see further below on configuration file requirements)
  9.  * - In any action that requires the user to be logged in, run:
  10.  * - $this->exec_module_action('Login', 'check_login')
  11.  *
  12.  * After login and logout, the module executes the default action specified in the configuration.
  13.  *
  14.  * The Login module requires the following entries in the configuration file.
  15.  *
  16.  * [login]
  17.  * mode = database or file : Authenticate against a 'database' or 'file'
  18.  * key_field = key_field_name : Name of the field that contains the primary key
  19.  * user_field = user_field_name    : Name of the field that contains the user name
  20.  * pass_field = password_field_name : Name of the field that contains the password (encrypted using PASSWORD())
  21.  *
  22.  * table = login_table_name    : Name of the table in the database that contains login information
  23.  * 
  24.  * file = path/to/file : Location of the password file
  25.  * type = ini : Type of password file
  26.  *
  27.  * The defaults are as below:
  28.  * [login]
  29.  * mode = database
  30.  * key_field = user_id
  31.  * user_field = email
  32.  * pass_field = password
  33.  * 
  34.  * table = user
  35.  * 
  36.  * file = "ini/password.ini"
  37.  * type = ini
  38.  * 
  39.  * This module requires the Config module when file based authentication is used.
  40.  */
  41. class Login extends Module {
  42.     /**
  43.      * @var string $mode Authentication mode: 'database' or 'file'
  44.      *
  45.      *  Default: 'database'
  46.      */
  47.     var $mode = 'database';
  48.  
  49.     /**
  50.      * @var string $table Name of the field that contains the primary key
  51.      *
  52.      *  Default: 'user_id'
  53.      */
  54.     var $key_field = 'user_id';
  55.  
  56.     /**
  57.      * @var string $table Name of the field that contains the user name
  58.      *
  59.      *  Default: 'email'
  60.      */
  61.     var $user_field = 'email';
  62.  
  63.     /**
  64.      * @var string $table Name of the field that contains the password (encrypted using PASSWORD())
  65.      *
  66.      *  Default: 'password'
  67.      */
  68.     var $pass_field = 'password';
  69.     
  70.     /**
  71.      * @var string $table Name of the table in the database that contains login information
  72.      *
  73.      *  Default: 'user'
  74.      */
  75.     var $table = 'user';
  76.  
  77.     /**
  78.      * @var string $file Location of the password file.
  79.      *
  80.      *  Default: 'ini/password.ini'
  81.      */
  82.     var $file = 'ini/password.ini';
  83.  
  84.     /**
  85.      * @var string $type Type of password file: 'ini'
  86.      *
  87.      *  Default: 'ini'
  88.      */
  89.     var $type = 'ini';
  90.  
  91.     /**
  92.      * Constructor for Login module
  93.      *
  94.      * Register exceptions in the constructor
  95.      */
  96.     function Login({
  97.         $this->register_exception('login_user_form');
  98.         $this->register_error('ERROR_LOGIN_NEW_PASSWORD_MISMATCH'
  99.             "New passwords do not match. Please try again.""ERROR");
  100.         $this->register_error('ERROR_LOGIN_CURRENT_PASSWORD_INCORRECT'
  101.             "Current password incorrect. Please try again.""ERROR");
  102.         $this->register_error('ERROR_LOGIN_NEW_PASSWORD_TOO_SHORT'
  103.             "Your new password is too short. At least 8 characters are required. Please try again.""ERROR");
  104.         $this->register_error('ERROR_LOGIN_PASSWORD_FILE_DOES_NOT_EXIST',
  105.             "Password file does not exist: '%s'.""ERROR");
  106.         $this->register_error('ERROR_LOGIN_PASSWORD_FILE_EMPTY',
  107.             "Password file is empty: '%s'.""ERROR");
  108.         $this->disable_template_library();
  109.     }
  110.     
  111.     /**
  112.      * Get the configuration from the config file
  113.      */
  114.     function get_configuration({
  115.         // Load values from config file if applicable
  116.         if (isset($this->application->config['login'])) {
  117.             $keys explode(' ''mode key_field user_field pass_field table file type');
  118.             foreach ($keys as $key)
  119.                 if (isset_and_non_empty($this->application->config['login'][$key]))
  120.                     $this->$key $this->application->config['login'][$key];
  121.         }
  122.         
  123.         // Check if password file exists if mode = 'file'
  124.         if (($this->mode == 'file'&& (!file_exists($this->file)))
  125.             $this->error->display_error('ERROR_LOGIN_PASSWORD_FILE_DOES_NOT_EXIST'$this->file);
  126.     }
  127.     
  128.     /**
  129.      * Login the user
  130.      * 
  131.      * Use the following parameters if login processing is invoked from another
  132.      * module action.
  133.      * 
  134.      * @param string $module Name of the module to process the login form (default: Login)
  135.      * @param string $action Name of the action to process the login form (default: login_user)
  136.      * @param string $params Parameters required for this module:action combination in "param=value&param=value" format. (default: '')
  137.      * 
  138.      * @return mixed If a module:action is specified, this action returns true (for login success) or the login form HTML (for login failure)
  139.      */
  140.     function login_user($module='Login'$action='login_user'$params='')
  141.     {
  142.         // Load the configuration
  143.         $this->get_configuration();
  144.         
  145.         // Check if login form was filled
  146.         if (isset_and_non_empty($_POST[$this->user_field]&& isset($_POST[$this->pass_field])) {
  147.             if ($this->mode == 'database'{
  148.                 // Check if login/password matches
  149.                 $rows =$this->sql->select_query('SQL_SELECT'
  150.                     $this->table"where ".$this->user_field."='".$_POST[$this->user_field]."' and ".
  151.                     $this->pass_field."=PASSWORD('".$_POST[$this->pass_field]."')");
  152.                 if (count($rows!= 1{
  153.                     sleep(5);    // Sleep to avoid abuse
  154.                     return $this->login_user_form($module$action$paramstrue);
  155.                 }
  156.                 $row $rows[0];
  157.             
  158.                 // Save some of the values in the PHP session
  159.                 $_SESSION['session_user_id'$row[$this->key_field];
  160.                 $_SESSION['session_user'$_POST[$this->user_field];
  161.                 $_SESSION['session_authenticated'1;
  162.             else if ($this->mode == 'file'{
  163.                 // Load passwords from file
  164.                 $passwords $this->exec_module_action('Config''read_ini_file'$this->file);
  165.                 if (!count($passwords))
  166.                     $this->error->display_error('ERROR_LOGIN_PASSWORD_FILE_EMPTY'$this->file);
  167.                     
  168.                 // Check if login/password matches
  169.                 foreach ($passwords as $password{
  170.                     if (($password[$this->user_field== $_POST[$this->user_field]&&
  171.                         ($password[$this->pass_field== md5($_POST[$this->pass_field]))) {
  172.                         $_SESSION['session_user_id'$password[$this->key_field];
  173.                         $_SESSION['session_user'$_POST[$this->user_field];
  174.                         $_SESSION['session_authenticated'1;
  175.                         break;
  176.                     }
  177.                 }
  178.                 if ($this->check_login(false== false{
  179.                     sleep(5)// Sleep to avoid abuse
  180.                     return $this->login_user_form($module$action$paramstrue);
  181.                 }
  182.             }
  183.  
  184.             // Disable output
  185.             $this->disable_render();
  186.         
  187.             // Execute default action or return
  188.             if ($module == 'Login' && $action == 'login_user'{
  189.                 // Run the default action
  190.                 $_SERVER['QUERY_STRING''';
  191.                 $this->controller->execute();
  192.             else {
  193.                     return true;
  194.             }
  195.         else {
  196.             return $this->login_user_form($module$action$params);
  197.         }
  198.     }
  199.  
  200.     /**
  201.      * Log out the current user. This is done by deleting the session
  202.      * 
  203.      * The default or the specified module:action is executed after logging out.
  204.      * 
  205.      * @param string $module Name of the module to execute after logout
  206.      * @param string $action Name of the action to execute after logout
  207.      * @param string $params Parameters required for this module:action combination in "param=value&param=value" format. (default: '')
  208.      */
  209.     function logout_user($module=''$action=''$params='')
  210.     {
  211.         // Delete all the saved session data
  212.         $_SESSION array();
  213.     
  214.         // Disable output
  215.         $this->disable_render();
  216.  
  217.         if ($module == '' && $action == ''{
  218.             // Run the default action
  219.             $_SERVER['QUERY_STRING''';
  220.         else {
  221.             // Run specified action
  222.             $_SERVER['QUERY_STRING'"module=$module&action=$action";
  223.             if ($params != '')
  224.                 $_SERVER['QUERY_STRING'.= $params;
  225.         }
  226.         $this->controller->execute();
  227.     }
  228.  
  229.     /**
  230.      * Display login form
  231.      *
  232.      * @param string $module Name of the module to process the login form
  233.      * @param string $action Name of the action to process the login form
  234.      * @param string $params Parameters required for this module:action combination in "param=value&param=value" format. (default: '')
  235.      * @param bool $failed Set to true if previous login attempt failed.
  236.      */
  237.     function login_user_form($module$action$params=''$failed=false{
  238.         // Load the configuration
  239.         $this->get_configuration();
  240.         
  241.         // Header
  242.         $view new View("Login");
  243.         $view->h2();
  244.         $view->nl();
  245.         $view->center();
  246.         $this->output .= $view->get_data();
  247.         
  248.         // User label
  249.         $view->set_data("User name:");
  250.         $view->label($this->user_field);
  251.         $user_label $view->get_data();
  252.         
  253.         // User text box
  254.         $view->reset_data();
  255.         $view->set_properties(array("size" => 33"maxlength" => 60"required" => "required"));
  256.         $view->input_text($this->user_field);
  257.         $user_textbox $view->get_data();
  258.         
  259.         // Pass label
  260.         $view->set_data("Password:");
  261.         $view->label($this->pass_field);
  262.         $pass_label $view->get_data();
  263.         
  264.         // Pass text box
  265.         $view->reset_data();
  266.         $view->set_properties(array("required" => "required"));
  267.         $view->input_password($this->pass_field);
  268.         $pass_textbox $view->get_data();
  269.         
  270.         // Submit and cancel buttons
  271.         $view->reset_data();
  272.         $view->input_submit();
  273.         $view->sp();
  274.         $view->push();
  275.         $view->input_cancel();
  276.         $view->pop_prepend();
  277.         $buttons $view->data;
  278.  
  279.         // Create table
  280.         $view->set_data(array(
  281.             $user_label => $user_textbox,
  282.             $pass_label => $pass_textbox,
  283.             ' ' => $buttons));
  284.         $view->table_two_column_associative();
  285.         $view->set_properties(array(
  286.             "action" => $this->controller->encode_url($module$action$params),
  287.             "method" => "POST",
  288.             "onsubmit" => "javascript: return form.validate(this);"));
  289.         $view->form("login");
  290.         $view->center();
  291.         
  292.         $this->output .= $view->get_data();
  293.         
  294.         // Print failed message
  295.         if ($failed{
  296.             $view->set_data("Login failed!");
  297.             $view->set_properties(array("color" => "red"));
  298.             $view->font();
  299.             $view->nl();
  300.             $view->center();
  301.             $this->output .= $view->get_data();
  302.         }
  303.         
  304.         // Return the output
  305.         return $this->output;
  306.     }
  307.  
  308.     /**
  309.     * Check if a user is logged in
  310.     *
  311.     * @param bool $forward Forward the user to the login form if true (default: true)
  312.     */
  313.     function check_login($forward=true{
  314.         // Load the configuration
  315.         $this->get_configuration();
  316.         
  317.         if (!isset($_SESSION|| 
  318.             !isset($_SESSION['session_authenticated']|| 
  319.             $_SESSION['session_authenticated'!= 1{
  320.             if ($forward == true{
  321.                 $this->login_user();
  322.                 $this->render();
  323.                 exit;
  324.             }
  325.             else return false;
  326.         }
  327.     
  328.         return true;
  329.     }
  330.     
  331.     /*
  332.      * This function updates the login of the currently logged in user
  333.      * 
  334.      * Function requires the user to be logged in in order to change their login. It changes the login of the
  335.      * active user.
  336.      *
  337.      * @param string $new_login A string containing the updated login. String is escaped by the function using addslashes()
  338.      */
  339.     function update_login($new_login{
  340.         // Verify that we are logged in
  341.         $this->check_login();
  342.         
  343.         // Escape the provided string
  344.         $new_login addslashes($new_login);
  345.         
  346.         // Update login only if it has changed
  347.         if ($new_login != $_SESSION['session_user']{
  348.             if ($this->mode == 'database'{
  349.                 // Update the database row
  350.                 $this->database->sql->update_query(
  351.                     'SQL_UPDATE'$this->table
  352.                     $this->user_field."='".$new_login."'"
  353.                     $this->user_field."='".$_SESSION['session_user']."'""nocheck");
  354.             else if ($this->mode == 'file'{
  355.                 // Get passwords from file
  356.                 $passwords $this->exec_module_action('Config''read_ini_file'$this->file);
  357.                 if (!count($passwords))
  358.                     $this->error->display_error('ERROR_LOGIN_PASSWORD_FILE_EMPTY'$this->file);
  359.                 
  360.                 // Update login
  361.                 foreach ($passwords as $user => $password{
  362.                     if ($passwords[$user][$this->user_field== $_SESSION['session_user']{
  363.                         $passwords[$user][$this->user_field$new_login;
  364.                         break;
  365.                     }
  366.                 }
  367.                 
  368.                 // Write to file
  369.                 $this->exec_module_action('Config''write_ini_file'$this->file$passwords);
  370.             }
  371.                 
  372.             // Update the session variable
  373.             $_SESSION['session_user'$new_login;
  374.         }
  375.     }
  376.     
  377.     /*
  378.      * This function creates a form to update the password of the currently logged in user
  379.      *
  380.      * Function requires the user to be logged in in order to change their login. It changes the login of the
  381.      * active user. It should be directly invoked.
  382.      */
  383.     function change_password({
  384.         // Verify that we are logged in
  385.         $this->check_login();
  386.  
  387.         if (isset_and_non_empty($_POST['current_password']&& 
  388.             isset_and_non_empty($_POST['new_password']&& 
  389.             isset_and_non_empty($_POST['new_password_repeat'])) {
  390.             $current_password addslashes($_POST['current_password']);
  391.             $new_password addslashes($_POST['new_password']);
  392.             $new_password_repeat addslashes($_POST['new_password_repeat']);
  393.             
  394.             // Check if current password is correct
  395.             $rows =$this->sql->select_query('SQL_SELECT'
  396.                 $this->table"where ".$this->user_field."='".$_SESSION['session_user']."' and ".
  397.                 $this->pass_field."=PASSWORD('".$current_password."')");
  398.             if (count($rows!= 1{
  399.                 sleep(5);    // Sleep to avoid abuse
  400.                 unset($_POST['current_password']);
  401.                 unset($_POST['new_password']);
  402.                 unset($_POST['new_password_repeat']);
  403.                 $this->change_password();
  404.                 $this->error->display_error('ERROR_LOGIN_CURRENT_PASSWORD_INCORRECT');
  405.             }
  406.  
  407.             // Check new passwords
  408.             if ($new_password != $new_password_repeat{
  409.                 unset($_POST['current_password']);
  410.                 unset($_POST['new_password']);
  411.                 unset($_POST['new_password_repeat']);
  412.                 $this->change_password();
  413.                 $this->error->display_error('ERROR_LOGIN_NEW_PASSWORD_MISMATCH');
  414.             }
  415.             
  416.             // Check password length
  417.             if (strlen($new_password8{
  418.                 unset($_POST['current_password']);
  419.                 unset($_POST['new_password']);
  420.                 unset($_POST['new_password_repeat']);
  421.                 $this->change_password();
  422.                 $this->error->display_error('ERROR_LOGIN_NEW_PASSWORD_TOO_SHORT');
  423.             }
  424.             
  425.             // Update the password field
  426.             $this->sql->update_query('SQL_UPDATE'$this->table,
  427.                 $this->pass_field."=PASSWORD('".$new_password."')",
  428.                 $this->user_field."='".$_SESSION['session_user']."'""nocheck");
  429.                 
  430.             // Run the default action
  431.             $_SERVER['QUERY_STRING''';
  432.             $this->controller->execute();
  433.         else {
  434.             // Display the change password form
  435.             
  436.             // Create the labels
  437.             $view new View("Current password");
  438.             $view->label("current_password");
  439.             $label_op $view->get_data();
  440.             
  441.             $view->set_data("New password");
  442.             $view->label("new_password");
  443.             $label_np $view->get_data();
  444.  
  445.             $view->set_data("New password (repeat)");
  446.             $view->label("new_password_repeat");
  447.             $label_npr $view->get_data();
  448.             
  449.             // Create the password fields
  450.             $view->reset_data();
  451.             $view->set_properties(array('required' => 'required'));
  452.             $view->input_password("current_password");
  453.             $op_data $view->data;
  454.  
  455.             $view->reset_data();
  456.             $view->set_properties(array('required' => 'required'));
  457.             $view->input_password("new_password");
  458.             $np_data $view->data;
  459.  
  460.             $view->reset_data();
  461.             $view->set_properties(array('required' => 'required'));
  462.             $view->input_password("new_password_repeat");
  463.             $npr_data $view->data;
  464.  
  465.             // Create submit button
  466.             $view->input_submit();
  467.             $view->sp();
  468.             $view->push();
  469.  
  470.             // Create cancel button
  471.             $view->input_ca