File: /home/assibfaf/public_html/prox-classes/User/Customer.php
<?php
/**
* @package Proxim
* @author Davison Pro <davisonpro.coder@gmail.com>
* @copyright 2019 Proxim
* @version 1.0.0
* @since File available since Release 1.0.0
*/
namespace Proxim\User;
use Db;
use Proxim\Application;
use Proxim\Database\DbQuery;
use Proxim\Cache\Cache;
use Proxim\Configuration;
use Proxim\ObjectModel;
use Proxim\Tools;
use Proxim\Validate;
use Proxim\Util\DateUtils;
use Proxim\Crypto\Hashing;
use Proxim\Hook;
/**
* Customer
*/
class Customer extends ObjectModel {
/** @var $id Customer ID */
public $id;
public $google_analytics_id;
public $email;
public $name;
public $phone;
public $country_id;
public $site_id = PROX_SITE_ID;
public $password;
public $new_password;
public $reset_password_token;
public $reset_password_validity;
public $last_passwd_gen;
public $secure_key;
public $policy_accepted = 0;
public $policy_accepted_at;
public $total_spent = 0;
public $referrer_id;
public $affiliate_used = 0;
public $affiliate_balance = 0;
public $last_academic_level;
public $last_payment_method;
public $is_subscribed = 0;
public $is_test = 0;
public $is_banned = 0;
public $push_notifications = 0;
public $last_login;
public $last_activity;
public $reg_date;
/** @var bool is the user logged in */
public $logged = false;
/**
* @see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'customer',
'primary' => 'customer_id',
'fields' => array(
'google_analytics_id' => array('type' => self::TYPE_STRING, 'size' => 255),
'email' => array('type' => self::TYPE_STRING, 'validate' => 'isEmail', 'required' => true, 'size' => 255),
'name' => array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => false, 'size' => 255),
'phone' => array('type' => self::TYPE_STRING, 'validate' => 'isPhoneNumber', 'required' => false, 'size' => 50),
'country_id' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'site_id' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'password' => array('type' => self::TYPE_STRING, 'validate' => 'isPasswd', 'required' => true, 'size' => 255),
'new_password' => array('type' => self::TYPE_STRING, 'validate' => 'isPasswd', 'required' => true, 'size' => 255),
'reset_password_token' => array('type' => self::TYPE_STRING, 'validate' => 'isSha1', 'size' => 40),
'reset_password_validity' => array('type' => self::TYPE_DATE, 'validate' => 'isDateOrNull'),
'last_passwd_gen' => array('type' => self::TYPE_DATE, 'validate' => 'isDateOrNull'),
'secure_key' => array('type' => self::TYPE_STRING, 'validate' => 'isMd5'),
'policy_accepted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'policy_accepted_at' => array('type' => self::TYPE_DATE, 'validate' => 'isDateOrNull'),
'total_spent' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'referrer_id' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'affiliate_used' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'affiliate_balance' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice'),
'last_academic_level' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'last_payment_method' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
'is_subscribed' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'is_test' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'is_banned' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'push_notifications' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'last_login' => array('type' => self::TYPE_DATE, 'validate' => 'isDateOrNull'),
'last_activity' => array('type' => self::TYPE_DATE, 'validate' => 'isDateOrNull'),
'reg_date' => array('type' => self::TYPE_DATE, 'validate' => 'isDate')
)
);
/**
* constructor.
*
* @param null $id
*/
public function __construct($id = null)
{
parent::__construct($id);
}
public function add($autoDate = true, $nullValues = true)
{
$this->secure_key = md5(uniqid(rand(), true));
$this->last_passwd_gen = DateUtils::now();
if ( !$this->getNextCustomerId() ) {
$this->id = 452441;
} else {
$next_customer_id = Db::getInstance()->getValue('SELECT MAX(`customer_id`)+2 FROM `' . PROX_DB_PREFIX . 'customer`');
$this->id = $next_customer_id;
}
$this->force_id = true;
$success = parent::add($autoDate, $nullValues);
return $success;
}
/**
* Return user instance from its e-mail (optionally check password).
*
* @param string $email e-mail
* @param string $plaintextPassword Password is also checked if specified
*
* @return bool|User User instance
*/
public function getByEmail($email, $plaintextPassword = null, $siteId = null )
{
if (!Validate::isEmail($email) || ($plaintextPassword && !Validate::isPasswd($plaintextPassword))) {
return false;
}
if(\is_null($siteId) && !Configuration::get('SHARED_AUTH')) {
$siteId = PROX_SITE_ID;
}
$sql = new DbQuery();
$sql->select('c.*');
$sql->from('customer', 'c');
$sql->where('c.`email` = \'' . pSQL($email) . '\'');
if ($siteId) {
$sql->where('c.`site_id` = \'' . (int) $siteId . '\'');
}
$result = Db::getInstance()->getRow($sql);
if (!$result) {
return false;
}
$crypto = new Hashing();
$passwordHash = $result['password'];
$shouldCheckPassword = !is_null($plaintextPassword);
if ($shouldCheckPassword && !$crypto->checkHash($plaintextPassword, $passwordHash)) {
return false;
}
$this->id = $result['customer_id'];
foreach ($result as $key => $value) {
if (property_exists($this, $key)) {
$this->{$key} = $value;
}
}
if ($shouldCheckPassword && !$crypto->isFirstHash($plaintextPassword, $passwordHash)) {
$this->password = $crypto->hash($plaintextPassword);
$this->update();
}
return $this;
}
/**
* Check user information and return user validity.
*
* @return bool user validity
*/
public function isLogged()
{
/* Customer is valid only if it can be load and if session is active */
return $this->logged == 1 && (int) $this->id && Customer::checkPassword($this->id, $this->password);
}
/**
* Soft logout, delete everything that links to the user
*
* @since 1.0.0
*/
public function logout() {
Hook::exec('actionCustomerLogoutBefore', ['customer' => $this]);
// remove auth cookie
if (isset(Application::getInstance()->container->cookie)) {
Application::getInstance()->container->cookie->logout();
}
Hook::exec('actionCustomerLogoutAfter', ['customer' => $this]);
$this->logged = false;
}
/**
* Check if customer password is the right one.
*
* @param int $customer_id Customer ID
* @param string $passwordHash Hashed password
*
* @return bool result
*/
public static function checkPassword($customer_id, $passwordHash)
{
if (!Validate::isUnsignedId($customer_id)) {
die(Tools::displayError());
}
$cacheId = 'Customer::checkPassword' . (int) $customer_id . '-' . $passwordHash;
if (!Cache::isStored($cacheId)) {
$sql = new DbQuery();
$sql->select('c.`customer_id`');
$sql->from('customer', 'c');
$sql->where('c.`customer_id` = ' . (int) $customer_id);
$sql->where('c.`password` = \'' . pSQL($passwordHash) . '\'');
$result = (bool) Db::getInstance(PROX_USE_SQL_SLAVE)->getValue($sql);
Cache::store($cacheId, $result);
return $result;
}
return Cache::retrieve($cacheId);
}
/**
* Fill Reset password unique token with random sha1 and its validity date. For forgot password feature.
*/
public function stampResetPasswordToken()
{
$salt = $this->id . '-' . $this->secure_key;
$this->reset_password_token = sha1(time() . $salt);
$this->reset_password_validity = date('Y-m-d H:i:s', strtotime('+' . 1440 . ' minutes'));
}
/**
* Test if a reset password token is present and is recent enough to avoid creating a new one (in case of customer triggering the forgot password link too often).
*/
public function hasRecentResetPasswordToken()
{
if (!$this->reset_password_token || $this->reset_password_token == '') {
return false;
}
// TODO maybe use another 'recent' value for this test. For instance, equals password validity value.
if (!$this->reset_password_validity || strtotime($this->reset_password_validity) < time()) {
return false;
}
return true;
}
/**
* Returns the valid reset password token if it validity date is > now().
*/
public function getValidResetPasswordToken()
{
if (!$this->reset_password_token || $this->reset_password_token == '') {
return false;
}
if (!$this->reset_password_validity || strtotime($this->reset_password_validity) < time()) {
return false;
}
return $this->reset_password_token;
}
/**
* Delete reset password token data.
*/
public function removeResetPasswordToken()
{
$this->reset_password_token = null;
$this->reset_password_validity = null;
}
/**
* This method return the ID of the next customer.
*
* @since 1.0.0
*
* @return int
*/
public function getNextCustomerId()
{
return Db::getInstance()->getValue('
SELECT customer_id
FROM ' . PROX_DB_PREFIX . 'customer
WHERE customer_id > ' . (int) $this->id . '
ORDER BY customer_id ASC');
}
}