SHARE
TWEET

Untitled

a guest Mar 20th, 2016 55 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2.  
  3. /**
  4.  * User class
  5.  */
  6.  
  7. class User
  8. {
  9.  
  10.   public $errors;
  11.  
  12.  
  13.   /**
  14.    * Magic getter - read data from a property that isn't set yet
  15.    *
  16.    * @param string $name  Property name
  17.    * @return mixed
  18.    */
  19.    public function __get($name)
  20.    {
  21.    }
  22.  
  23.  
  24.   /**
  25.    * Get a page of user records and the previous and next page (if there are any)
  26.    *
  27.    * @param string $page  Page number
  28.    * @return array        Previous page, next page and user data. Page elements are null if there isn't a previous or next page.
  29.    */
  30.   public static function paginate($page)
  31.   {
  32.     $data = [];
  33.     $users_per_page = 5;
  34.  
  35.     // Calculate the total number of pages
  36.     $total_users = static::_getTotalUsers();
  37.     $total_pages = (int) ceil($total_users / $users_per_page);
  38.      
  39.  
  40.     // Make sure the current page is valid
  41.     $page = (int) $page;
  42.  
  43.     if ($page < 1) {
  44.       $page = 1;
  45.     } elseif ($page > $total_pages) {
  46.       $page = $total_pages;
  47.     }
  48.  
  49.  
  50.     // Calculate the next and previous pages
  51.     $data['previous'] = $page == 1 ? null : $page - 1;
  52.     $data['next'] = $page == $total_pages ? null : $page + 1;
  53.  
  54.  
  55.     // Get the page of users
  56.     try {
  57.  
  58.       $db = Database::getInstance();
  59.  
  60.       $offset = ($page - 1) * $users_per_page;
  61.  
  62.       $data['users'] = $db->query("SELECT * FROM users ORDER BY email LIMIT $users_per_page OFFSET $offset")->fetchAll();
  63.  
  64.     } catch(PDOException $exception) {
  65.  
  66.       error_log($exception->getMessage());
  67.  
  68.       $data['users'] = [];
  69.     }
  70.  
  71.     return $data;
  72.   }
  73.  
  74.  
  75.   /**
  76.    * Authenticate a user by email and password
  77.    *
  78.    * @param string $email     Email address
  79.    * @param string $password  Password
  80.    * @return mixed            User object if authenticated correctly, null otherwise
  81.    */
  82.   public static function authenticate($email, $password)
  83.   {
  84.     $user = static::findByEmail($email);
  85.  
  86.     if ($user !== null) {
  87.  
  88.       // Check the user has been activated
  89.       if ($user->is_active) {
  90.  
  91.         // Check the hashed password stored in the user record matches the supplied password
  92.         if (Hash::check($password, $user->password)) {
  93.           return $user;
  94.         }
  95.       }
  96.     }
  97.   }
  98.  
  99.  
  100.   /**
  101.    * Find the user with the specified ID
  102.    *
  103.    * @param string $id  ID
  104.    * @return mixed      User object if found, null otherwise
  105.    */
  106.   public static function findByID($id)
  107.   {
  108.     try {
  109.  
  110.       $db = Database::getInstance();
  111.  
  112.       $stmt = $db->prepare('SELECT * FROM users WHERE id = :id LIMIT 1');
  113.       $stmt->execute([':id' => $id]);
  114.       $user = $stmt->fetchObject('User');
  115.  
  116.       if ($user !== false) {
  117.         return $user;
  118.       }
  119.  
  120.     } catch(PDOException $exception) {
  121.  
  122.       error_log($exception->getMessage());
  123.     }
  124.   }
  125.  
  126.  
  127.   /**
  128.    * Get the user by ID or display a 404 Not Found page if not found.
  129.    *
  130.    * @param array $data  $_GET data
  131.    * @return mixed       User object if found, null otherwise
  132.    */
  133.   public static function getByIDor404($data)
  134.   {
  135.     if (isset($data['id'])) {
  136.       $user = static::findByID($data['id']);
  137.  
  138.       if ($user !== null) {
  139.         return $user;
  140.       }
  141.     }
  142.  
  143.     Util::showNotFound();
  144.   }
  145.  
  146.  
  147.   /**
  148.    * Find the user with the specified email address
  149.    *
  150.    * @param string $email  email address
  151.    * @return mixed         User object if found, null otherwise
  152.    */
  153.   public static function findByEmail($email)
  154.   {
  155.     try {
  156.  
  157.       $db = Database::getInstance();
  158.  
  159.       $stmt = $db->prepare('SELECT * FROM users WHERE email = :email LIMIT 1');
  160.       $stmt->execute([':email' => $email]);
  161.       $user = $stmt->fetchObject('User');
  162.  
  163.       if ($user !== false) {
  164.         return $user;
  165.       }
  166.  
  167.     } catch(PDOException $exception) {
  168.  
  169.       error_log($exception->getMessage());
  170.     }
  171.   }
  172.  
  173.  
  174.   /**
  175.    * Signup a new user
  176.    *
  177.    * @param array $data  POST data
  178.    * @return User
  179.    */
  180.   public static function signup($data)
  181.   {
  182.     // Create a new user model and set the attributes
  183.     $user = new static();
  184.  
  185.     $user->name = $data['name'];
  186.     $user->surname = $data['surname'];
  187.     $user->email = $data['email'];
  188.     $user->password = $data['password'];
  189.  
  190.     if ($user->isValid()) {
  191.  
  192.       // Generate a random token for activation and base64 encode it so it's URL safe
  193.       $token = base64_encode(uniqid(rand(), true));
  194.       $hashed_token = sha1($token);
  195.  
  196.       try {
  197.  
  198.         $db = Database::getInstance();
  199.  
  200.         $stmt = $db->prepare('INSERT INTO users (name, surname, email, password, activation_token) VALUES (:name, :surname, :email, :password, :token)');
  201.         $stmt->bindParam(':name', $user->name);
  202.         $stmt->bindParam(':surname', $user->surname);
  203.         $stmt->bindParam(':email', $user->email);
  204.         $stmt->bindParam(':password', Hash::make($user->password));
  205.         $stmt->bindParam(':token', $hashed_token);
  206.          
  207.  
  208.         $stmt->execute();
  209.  
  210.         // Send activation email
  211.         $user->_sendActivationEmail($token);
  212.  
  213.       } catch(PDOException $exception) {
  214.  
  215.         // Log the exception message
  216.         error_log($exception->getMessage());
  217.       }
  218.     }
  219.  
  220.     return $user;
  221.   }
  222.  
  223.  
  224.   /**
  225.    * Find the user by remember token
  226.    *
  227.    * @param string $token  token
  228.    * @return mixed         User object if found, null otherwise
  229.    */
  230.   public static function findByRememberToken($token)
  231.   {
  232.     try {
  233.  
  234.       $db = Database::getInstance();
  235.  
  236.       $stmt = $db->prepare('SELECT u.* FROM users u JOIN remembered_logins r ON u.id = r.user_id WHERE token = :token');
  237.       $stmt->execute([':token' => $token]);
  238.       $user = $stmt->fetchObject('User');
  239.  
  240.       if ($user !== false) {
  241.         return $user;
  242.       }
  243.  
  244.     } catch(PDOException $exception) {
  245.  
  246.       error_log($exception->getMessage());
  247.     }
  248.   }
  249.  
  250.  
  251.   /**
  252.    * Deleted expired remember me tokens
  253.    *
  254.    * @return integer  Number of tokens deleted
  255.    */
  256.   public static function deleteExpiredTokens()
  257.   {
  258.     try {
  259.  
  260.       $db = Database::getInstance();
  261.  
  262.       $stmt = $db->prepare("DELETE FROM remembered_logins WHERE expires_at < '" . date('Y-m-d H:i:s') . "'");
  263.       $stmt->execute();
  264.  
  265.       return $stmt->rowCount();
  266.  
  267.     } catch(PDOException $exception) {
  268.  
  269.       // Log the detailed exception
  270.       error_log($exception->getMessage());
  271.     }
  272.  
  273.     return 0;
  274.   }
  275.  
  276.  
  277.   /**
  278.    * Find the user for password reset, by the specified token and check the token hasn't expired
  279.    *
  280.    * @param string $token  Reset token
  281.    * @return mixed         User object if found and the token hasn't expired, null otherwise
  282.    */
  283.   public static function findForPasswordReset($token)
  284.   {
  285.     $hashed_token = sha1($token);
  286.  
  287.     try {
  288.  
  289.       $db = Database::getInstance();
  290.  
  291.       $stmt = $db->prepare('SELECT * FROM users WHERE password_reset_token = :token LIMIT 1');
  292.       $stmt->execute([':token' => $hashed_token]);
  293.       $user = $stmt->fetchObject('User');
  294.  
  295.       if ($user !== false) {
  296.  
  297.         // Check the token hasn't expired
  298.         $expiry = DateTime::createFromFormat('Y-m-d H:i:s', $user->password_reset_expires_at);
  299.  
  300.         if ($expiry !== false) {
  301.           if ($expiry->getTimestamp() > time()) {
  302.             return $user;
  303.           }
  304.         }
  305.       }
  306.  
  307.     } catch(PDOException $exception) {
  308.  
  309.       error_log($exception->getMessage());
  310.     }
  311.   }
  312.  
  313.  
  314.   /**
  315.    * Activate the user account, nullifying the activation token and setting the is_active flag
  316.    *
  317.    * @param string $token  Activation token
  318.    * @return void
  319.    */
  320.   public static function activateAccount($token)
  321.   {
  322.     $hashed_token = sha1($token);
  323.  
  324.     try {
  325.  
  326.       $db = Database::getInstance();
  327.  
  328.       $stmt = $db->prepare('UPDATE users SET activation_token = NULL, is_active = TRUE WHERE activation_token = :token');
  329.       $stmt->execute([':token' => $hashed_token]);
  330.  
  331.     } catch(PDOException $exception) {
  332.  
  333.       // Log the detailed exception
  334.       error_log($exception->getMessage());
  335.     }
  336.   }
  337.  
  338.  
  339.   /**
  340.    * Delete the user.
  341.    *
  342.    * @return void
  343.    */
  344.   public function delete()
  345.   {
  346.     try {
  347.  
  348.       $db = Database::getInstance();
  349.  
  350.       $stmt = $db->prepare('DELETE FROM users WHERE id = :id');
  351.       $stmt->bindParam(':id', $this->id, PDO::PARAM_INT);
  352.       $stmt->execute();
  353.  
  354.     } catch(PDOException $exception) {
  355.  
  356.       // Log the detailed exception
  357.       error_log($exception->getMessage());
  358.     }
  359.   }
  360.    
  361.    
  362.    
  363.     /**
  364.    * Select schools fro drop down in sign up page
  365.    */
  366.   public function selectschool()
  367.   {
  368.     try {
  369.  
  370.       $db = Database::getInstance();
  371.  
  372.         $sql= "SELECT id, name FROM schools";
  373.         $stmt = $pdo->query($sql);
  374.         $schools = $stmt->fetchAll(PDO::FETCH_ASSOC);
  375.         $stmt->execute();
  376.  
  377.     }
  378.   }
  379.  
  380.  
  381.   /**
  382.    * Update or insert the user's details based on the data. Data is validated and $this->errors is set if
  383.    * if any values are invalid.
  384.    *
  385.    * @param array $data  Data ($_POST array)
  386.    * @return boolean     True if the values were updated / inserted successfully, false otherwise.
  387.    */
  388.   public function save($data)
  389.   {
  390.     $this->name = $data['name'];
  391.       $this->surname = $data['surname'];
  392.     $this->email = $data['email'];
  393.  
  394.     // If editing a user, only validate and update the password if a value provided
  395.     if (isset($this->id) && empty($data['password'])) {
  396.       unset($this->password);
  397.     } else {
  398.       $this->password = $data['password'];
  399.     }
  400.  
  401.     // Convert values of the checkboxes to boolean
  402.     $this->is_active = isset($data['is_active']) && ($data['is_active'] == '1');
  403.     $this->is_admin = isset($data['is_admin']) && ($data['is_admin'] == '1');
  404.  
  405.     if ($this->isValid()) {
  406.  
  407.       try {
  408.  
  409.         $db = Database::getInstance();
  410.  
  411.         // Prepare the SQL: Update the existing record if editing, or insert new if adding
  412.         if (isset($this->id)) {
  413.  
  414.           $sql = 'UPDATE users SET name = :name, surname = :surname,  email = :email, is_active = :is_active, is_admin = :is_admin';
  415.  
  416.           if (isset($this->password)) {  // only update password if set
  417.             $sql .= ', password = :password';
  418.           }
  419.  
  420.           $sql .= ' WHERE id = :id';
  421.  
  422.         } else {
  423.  
  424.           $sql = 'INSERT INTO users (name, surname, email, password, is_active, is_admin) VALUES (:name, :surname, :email, :password, :is_active, :is_admin)';
  425.         }
  426.  
  427.         // Bind the parameters
  428.         $stmt = $db->prepare($sql);
  429.         $stmt->bindParam(':name', $this->name);
  430.         $stmt->bindParam(':surname', $this->surname);
  431.         $stmt->bindParam(':email', $this->email);
  432.         $stmt->bindParam(':is_active', $this->is_active);
  433.         $stmt->bindParam(':is_admin', $this->is_admin);
  434.  
  435.         if (isset($this->id)) {
  436.           if (isset($this->password)) {  // only update password if set
  437.             $stmt->bindParam(':password', Hash::make($this->password));
  438.           }
  439.  
  440.           $stmt->bindParam(':id', $this->id, PDO::PARAM_INT);
  441.  
  442.         } else {
  443.           $stmt->bindParam(':password', Hash::make($this->password));
  444.         }
  445.  
  446.         $stmt->execute();
  447.  
  448.         // Set the ID if a new record
  449.         if ( ! isset($this->id)) {
  450.           $this->id = $db->lastInsertId();
  451.         }
  452.  
  453.         return true;
  454.  
  455.       } catch(PDOException $exception) {
  456.  
  457.         // Set generic error message and log the detailed exception
  458.         $this->errors = ['error' => 'A database error occurred.'];
  459.         error_log($exception->getMessage());
  460.       }
  461.     }
  462.  
  463.     return false;
  464.   }
  465.  
  466.  
  467.   /**
  468.    * Remember the login by storing a unique token associated with the user ID
  469.    *
  470.    * @param integer $expiry  Expiry timestamp
  471.    * @return mixed           The token if remembered successfully, false otherwise
  472.    */
  473.   public function rememberLogin($expiry)
  474.   {
  475.    
  476.     // Generate a unique token
  477.     $token = uniqid($this->email, true);
  478.  
  479.     try {
  480.  
  481.       $db = Database::getInstance();
  482.  
  483.       $stmt = $db->prepare('INSERT INTO remembered_logins (token, user_id, expires_at) VALUES (:token, :user_id, :expires_at)');
  484.       $stmt->bindParam(':token', sha1($token));  // store a hash of the token
  485.       $stmt->bindParam(':user_id', $this->id, PDO::PARAM_INT);
  486.       $stmt->bindParam(':expires_at', date('Y-m-d H:i:s', $expiry));
  487.       $stmt->execute();
  488.  
  489.       if ($stmt->rowCount() == 1) {
  490.         return $token;
  491.       }
  492.  
  493.     } catch(PDOException $exception) {
  494.  
  495.       // Log the detailed exception
  496.       error_log($exception->getMessage());
  497.     }
  498.  
  499.     return false;
  500.   }
  501.  
  502.  
  503.   /**
  504.    * Forget the login based on the token value
  505.    *
  506.    * @param string $token  Remember token
  507.    * @return void
  508.    */
  509.   public function forgetLogin($token)
  510.   {
  511.     if ($token !== null) {
  512.  
  513.       try {
  514.  
  515.         $db = Database::getInstance();
  516.  
  517.         $stmt = $db->prepare('DELETE FROM remembered_logins WHERE token = :token');
  518.         $stmt->bindParam(':token', $token);
  519.         $stmt->execute();
  520.  
  521.       } catch(PDOException $exception) {
  522.  
  523.         // Log the detailed exception
  524.         error_log($exception->getMessage());
  525.       }
  526.     }
  527.   }
  528.  
  529.  
  530.   /**
  531.    * Start the password reset process by generating a unique token and expiry and saving them in the user model
  532.    *
  533.    * @return boolean  True if the user model was updated successfully, false otherwise
  534.    */
  535.   public function startPasswordReset()
  536.   {
  537.     // Generate a random token and base64 encode it so it's URL safe
  538.     $token = base64_encode(uniqid(rand(), true));
  539.     $hashed_token = sha1($token);
  540.  
  541.     // Set the token to expire in one hour
  542.     $expires_at = date('Y-m-d H:i:s', time() + 60 * 60);
  543.    
  544.     try {
  545.  
  546.       $db = Database::getInstance();
  547.  
  548.       $stmt = $db->prepare('UPDATE users SET password_reset_token = :token, password_reset_expires_at = :expires_at WHERE id = :id');
  549.       $stmt->bindParam(':token', $hashed_token);
  550.       $stmt->bindParam(':expires_at', $expires_at);
  551.       $stmt->bindParam(':id', $this->id, PDO::PARAM_INT);
  552.       $stmt->execute();
  553.  
  554.       if ($stmt->rowCount() == 1) {
  555.         $this->password_reset_token = $token;
  556.         $this->password_reset_expires_at = $expires_at;
  557.  
  558.         return true;
  559.       }
  560.  
  561.     } catch(PDOException $exception) {
  562.  
  563.       // Log the detailed exception
  564.       error_log($exception->getMessage());
  565.     }
  566.  
  567.     return false;
  568.   }
  569.  
  570.  
  571.   /**
  572.    * Reset the password
  573.    *
  574.    * @return boolean  true if the password was changed successfully, false otherwise
  575.    */
  576.   public function resetPassword()
  577.   {
  578.     $password_error = $this->_validatePassword();
  579.  
  580.     if ($password_error === null) {
  581.  
  582.       try {
  583.  
  584.         $db = Database::getInstance();
  585.  
  586.         $stmt = $db->prepare('UPDATE users SET password = :password, password_reset_token = NULL, password_reset_expires_at = NULL WHERE id = :id');
  587.         $stmt->bindParam(':password', Hash::make($this->password));
  588.         $stmt->bindParam(':id', $this->id, PDO::PARAM_INT);
  589.         $stmt->execute();
  590.  
  591.         if ($stmt->rowCount() == 1) {
  592.           return true;
  593.         }
  594.  
  595.       } catch(PDOException $exception) {
  596.  
  597.         // Set generic error message and log the detailed exception
  598.         $this->errors = ['error' => 'A database error occurred.'];
  599.         error_log($exception->getMessage());
  600.       }
  601.      
  602.     } else {
  603.       $this->errors['password'] = $password_error;
  604.     }
  605.  
  606.     return false;
  607.   }
  608.  
  609.  
  610.   /**
  611.    * Validate the properties and set $this->errors if any are invalid
  612.    *
  613.    * @return boolean  true if valid, false otherwise
  614.    */
  615.   public function isValid()
  616.   {
  617.     $this->errors = [];
  618.  
  619.     //
  620.     // name
  621.     //
  622.     if ($this->name == '') {
  623.       $this->errors['name'] = 'Please enter a valid name';
  624.     }
  625.  
  626.     //
  627.     // email address
  628.     //
  629.     if (filter_var($this->email, FILTER_VALIDATE_EMAIL) === false) {
  630.       $this->errors['email'] = 'Please enter a valid email address';
  631.     }
  632.  
  633.     if ($this->_emailTaken($this->email)) {
  634.       $this->errors['email'] = 'That email address is already taken';
  635.     }
  636.  
  637.     //
  638.     // password
  639.     //
  640.     $password_error = $this->_validatePassword();
  641.     if ($password_error !== null) {
  642.       $this->errors['password'] = $password_error;
  643.     }
  644.  
  645.     return empty($this->errors);
  646.   }
  647.  
  648.  
  649.   /**
  650.    * Get the total number of users
  651.    *
  652.    * @return integer
  653.    */
  654.   private static function _getTotalUsers()
  655.   {
  656.     try {
  657.  
  658.       $db = Database::getInstance();
  659.       $count = (int) $db->query('SELECT COUNT(*) FROM users')->fetchColumn();
  660.  
  661.     } catch(PDOException $exception) {
  662.  
  663.       error_log($exception->getMessage());
  664.       $count = 0;
  665.     }
  666.  
  667.     return $count;
  668.   }
  669.  
  670.  
  671.   /**
  672.    * See if the email address is taken (already exists), ignoring the current user if already saved.
  673.    *
  674.    * @param string $email  Email address
  675.    * @return boolean       True if the email is taken, false otherwise
  676.    */
  677.   private function _emailTaken($email)
  678.   {
  679.     $isTaken = false;
  680.     $user = $this->findByEmail($email);
  681.  
  682.     if ($user !== null) {
  683.  
  684.       if (isset($this->id)) {  // existing user
  685.  
  686.         if ($this->id != $user->id) {  // different user
  687.           $isTaken = true;
  688.         }
  689.  
  690.       } else {  // new user
  691.         $isTaken = true;
  692.       }
  693.     }
  694.  
  695.     return $isTaken;
  696.   }
  697.  
  698.  
  699.   /**
  700.    * Validate the password
  701.    *
  702.    * @return mixed  The first error message if invalid, null otherwise
  703.    */
  704.   private function _validatePassword()
  705.   {
  706.     if (isset($this->password) && (strlen($this->password) < 5)) {
  707.       return 'Please enter a longer password';
  708.     }
  709.  
  710.     if (isset($this->password_confirmation) && ($this->password != $this->password_confirmation)) {
  711.       return 'Please enter the same password';
  712.     }
  713.   }
  714.  
  715.  
  716.   /**
  717.    * Send activation email to the user based on the token
  718.    *
  719.    * @param string $token  Activation token
  720.    * @return mixed         User object if authenticated correctly, null otherwise
  721.    */
  722.   private function _sendActivationEmail($token)
  723.   {
  724.     // Note hardcoded protocol
  725.     $url = 'http://'.$_SERVER['HTTP_HOST'].'/activate_account.php?token=' . $token;
  726.  
  727.     $body = <<<EOT
  728.  
  729. <p>Please click on the following link to activate your account.</p>
  730.  
  731. <p><a href="$url">$url</a></p>
  732.  
  733. EOT;
  734.  
  735.     Mail::send($this->name, $this->email, 'Activate account', $body);
  736.   }
  737.  
  738. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top