/lib/Flux/LoginServer.php
PHP | 547 lines | 386 code | 76 blank | 85 comment | 63 complexity | aa21a4641ddec487b269a76a4600241a MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, BSD-3-Clause
- <?php
- require_once 'Flux/BaseServer.php';
- require_once 'Flux/RegisterError.php';
- /**
- * Represents an eAthena Login Server.
- */
- class Flux_LoginServer extends Flux_BaseServer {
- /**
- * Connection to the MySQL server.
- *
- * @access public
- * @var Flux_Connection
- */
- public $connection;
-
- /**
- * Login server database.
- *
- * @access public
- * @var string
- */
- public $loginDatabase;
-
- /**
- * Logs database. (is not set until setConnection() is called.)
- *
- * @access public
- * @var string
- */
- public $logsDatabase;
-
- /**
- * Overridden to add custom properties.
- *
- * @access public
- */
- public function __construct(Flux_Config $config)
- {
- parent::__construct($config);
- $this->loginDatabase = $config->getDatabase();
- }
-
- /**
- * Set the connection object to be used for this LoginServer instance.
- *
- * @param Flux_Connection $connection
- * @return Flux_Connection
- * @access public
- */
- public function setConnection(Flux_Connection $connection)
- {
- $this->connection = $connection;
- $this->logsDatabase = $connection->logsDbConfig->getDatabase();
-
- return $connection;
- }
-
- /**
- * Validate credentials against the login server's database information.
- *
- * @param string $username Ragnarok account username.
- * @param string $password Ragnarok account password.
- * @return bool True/false if valid or invalid.
- * @access public
- */
- public function isAuth($username, $password)
- {
- if ($this->config->get('UseMD5')) {
- $password = Flux::hashPassword($password);
- }
-
- if (trim($username) == '' || trim($password) == '') {
- return false;
- }
-
- $sql = "SELECT userid FROM {$this->loginDatabase}.login WHERE sex != 'S' AND level >= 0 ";
- if ($this->config->getNoCase()) {
- $sql .= 'AND LOWER(userid) = LOWER(?) ';
- }
- else {
- $sql .= 'AND CAST(userid AS BINARY) = ? ';
- }
- $sql .= "AND user_pass = ? LIMIT 1";
- $sth = $this->connection->getStatement($sql);
- $sth->execute(array($username, $password));
-
- $res = $sth->fetch();
- if ($res) {
- return true;
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function register($username, $password, $confirmPassword, $email, $gender, $birthDate, $securityCode)
- {
- if (strlen($username) < Flux::config('MinUsernameLength')) {
- throw new Flux_RegisterError('Username is too short', Flux_RegisterError::USERNAME_TOO_SHORT);
- }
- elseif (strlen($username) > Flux::config('MaxUsernameLength')) {
- throw new Flux_RegisterError('Username is too long', Flux_RegisterError::USERNAME_TOO_LONG);
- }
- elseif (strlen($password) < Flux::config('MinPasswordLength')) {
- throw new Flux_RegisterError('Password is too short', Flux_RegisterError::PASSWORD_TOO_SHORT);
- }
- elseif (strlen($password) > Flux::config('MaxPasswordLength')) {
- throw new Flux_RegisterError('Password is too long', Flux_RegisterError::PASSWORD_TOO_LONG);
- }
- elseif ($password !== $confirmPassword) {
- throw new Flux_RegisterError('Passwords do not match', Flux_RegisterError::PASSWORD_MISMATCH);
- }
- elseif (!preg_match('/(.+?)@(.+?)/', $email)) {
- throw new Flux_RegisterError('Invalid e-mail address', Flux_RegisterError::INVALID_EMAIL_ADDRESS);
- }
- elseif (!in_array(strtoupper($gender), array('M', 'F'))) {
- throw new Flux_RegisterError('Invalid gender', Flux_RegisterError::INVALID_GENDER);
- }
- elseif ($birthDate > date('Y-m-d')) {
- throw new Flux_RegisterError('Invalid Birth date', Flux_RegisterError::INVALID_BIRTH_DATE);
- }
- elseif (Flux::config('UseCaptcha')) {
- if (Flux::config('EnableReCaptcha')) {
- require_once 'recaptcha/recaptchalib.php';
- $resp = recaptcha_check_answer(
- Flux::config('ReCaptchaPrivateKey'),
- $_SERVER['REMOTE_ADDR'],
- // Checks POST fields.
- $_POST['recaptcha_challenge_field'],
- $_POST['recaptcha_response_field']);
-
- if (!$resp->is_valid) {
- throw new Flux_RegisterError('Invalid security code', Flux_RegisterError::INVALID_SECURITY_CODE);
- }
- }
- elseif (strtolower($securityCode) !== strtolower(Flux::$sessionData->securityCode)) {
- throw new Flux_RegisterError('Invalid security code', Flux_RegisterError::INVALID_SECURITY_CODE);
- }
- }
-
- $sql = "SELECT userid FROM {$this->loginDatabase}.login WHERE ";
- if ($this->config->getNoCase()) {
- $sql .= 'LOWER(userid) = LOWER(?) ';
- }
- else {
- $sql .= 'BINARY userid = ? ';
- }
- $sql .= 'LIMIT 1';
- $sth = $this->connection->getStatement($sql);
- $sth->execute(array($username));
-
- $res = $sth->fetch();
- if ($res) {
- throw new Flux_RegisterError('Username is already taken', Flux_RegisterError::USERNAME_ALREADY_TAKEN);
- }
-
- if (!Flux::config('AllowDuplicateEmails')) {
- $sql = "SELECT email FROM {$this->loginDatabase}.login WHERE email = ? LIMIT 1";
- $sth = $this->connection->getStatement($sql);
- $sth->execute(array($email));
- $res = $sth->fetch();
- if ($res) {
- throw new Flux_RegisterError('E-mail address is already in use', Flux_RegisterError::EMAIL_ADDRESS_IN_USE);
- }
- }
-
- if ($this->config->getUseMD5()) {
- $password = Flux::hashPassword($password);
- }
-
- $sql = "INSERT INTO {$this->loginDatabase}.login (userid, user_pass, email, sex, birthdate) VALUES (?, ?, ?, ?, ?)";
- $sth = $this->connection->getStatement($sql);
- $res = $sth->execute(array($username, $password, $email, $gender, $birthDate));
-
- if ($res) {
- $idsth = $this->connection->getStatement("SELECT LAST_INSERT_ID() AS account_id");
- $idsth->execute();
-
- $idres = $idsth->fetch();
- $createTable = Flux::config('FluxTables.AccountCreateTable');
-
- $sql = "INSERT INTO {$this->loginDatabase}.{$createTable} (account_id, userid, user_pass, sex, email, reg_date, reg_ip, confirmed) ";
- $sql .= "VALUES (?, ?, ?, ?, ?, NOW(), ?, 1)";
- $sth = $this->connection->getStatement($sql);
-
- $sth->execute(array($idres->account_id, $username, $password, $gender, $email, $_SERVER['REMOTE_ADDR']));
- return $idres->account_id;
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function temporarilyBan($bannedBy, $banReason, $accountID, $until)
- {
- $info = $this->getBanInfo($accountID);
- $table = Flux::config('FluxTables.AccountBanTable');
-
- if (!$info || $info->ban_type !== '1') {
- $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) ";
- $sql .= "VALUES (?, ?, 1, ?, NOW(), ?)";
- $sth = $this->connection->getStatement($sql);
- $res = $sth->execute(array($accountID, $bannedBy, $until, $banReason));
-
- $ts = strtotime($until);
- $sql = "UPDATE {$this->loginDatabase}.login SET state = 0, unban_time = '$ts' WHERE account_id = ?";
- $sth = $this->connection->getStatement($sql);
- return $sth->execute(array($accountID));
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function permanentlyBan($bannedBy, $banReason, $accountID)
- {
- $info = $this->getBanInfo($accountID);
- $table = Flux::config('FluxTables.AccountBanTable');
-
- if (!$info || $info->ban_type !== '2') {
- $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) ";
- $sql .= "VALUES (?, ?, 2, '0000-00-00 00:00:00', NOW(), ?)";
- $sth = $this->connection->getStatement($sql);
- $res = $sth->execute(array($accountID, $bannedBy, $banReason));
-
- if ($res) {
- $sql = "UPDATE {$this->loginDatabase}.login SET state = 5, unban_time = 0 WHERE account_id = ?";
- $sth = $this->connection->getStatement($sql);
- return $sth->execute(array($accountID));
- }
- else {
- return false;
- }
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function unban($unbannedBy, $unbanReason, $accountID)
- {
- //$info = $this->getBanInfo($accountID);
- $table = Flux::config('FluxTables.AccountBanTable');
- $createTable = Flux::config('FluxTables.AccountCreateTable');
-
- //if (!$info || !$info->ban_type) {
- $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) ";
- $sql .= "VALUES (?, ?, 0, '0000-00-00 00:00:00', NOW(), ?)";
- $sth = $this->connection->getStatement($sql);
- $res = $sth->execute(array($accountID, $unbannedBy, $unbanReason));
-
- if ($res) {
- $sql = "UPDATE {$this->loginDatabase}.$createTable SET confirmed = 1, confirm_expire = NULL WHERE account_id = ?";
- $sth = $this->connection->getStatement($sql);
- $sth->execute(array($accountID));
-
- $sql = "UPDATE {$this->loginDatabase}.login SET state = 0, unban_time = 0 WHERE account_id = ?";
- $sth = $this->connection->getStatement($sql);
- return $sth->execute(array($accountID));
- }
- else {
- return false;
- }
- //}
- //else {
- //return false;
- //}
- }
-
- /**
- *
- */
- public function getBanInfo($accountID)
- {
- $table = Flux::config('FluxTables.AccountBanTable');
- $col = "$table.id, $table.account_id, $table.banned_by, $table.ban_type, ";
- $col .= "$table.ban_until, $table.ban_date, $table.ban_reason, login.userid";
- $sql = "SELECT $col FROM {$this->loginDatabase}.$table ";
- $sql .= "LEFT OUTER JOIN {$this->loginDatabase}.login ON login.account_id = $table.banned_by ";
- $sql .= "WHERE $table.account_id = ? ORDER BY $table.ban_date DESC ";
- $sth = $this->connection->getStatement($sql);
- $res = $sth->execute(array($accountID));
-
- if ($res) {
- $ban = $sth->fetchAll();
- return $ban;
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function hasCreditsRecord($accountID)
- {
- $creditsTable = Flux::config('FluxTables.CreditsTable');
-
- $sql = "SELECT COUNT(account_id) AS hasRecord FROM {$this->loginDatabase}.$creditsTable WHERE account_id = ?";
- $sth = $this->connection->getStatement($sql);
-
- $sth->execute(array($accountID));
-
- if ($sth->fetch()->hasRecord) {
- return true;
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function depositCredits($targetAccountID, $credits, $donationAmount = null)
- {
- $sql = "SELECT COUNT(account_id) AS accountExists FROM {$this->loginDatabase}.login WHERE account_id = ?";
- $sth = $this->connection->getStatement($sql);
-
- if (!$sth->execute(array($targetAccountID)) || !$sth->fetch()->accountExists) {
- return false; // Account doesn't exist.
- }
-
- $creditsTable = Flux::config('FluxTables.CreditsTable');
-
- if (!$this->hasCreditsRecord($targetAccountID)) {
- $fields = 'account_id, balance';
- $values = '?, ?';
-
- if (!is_null($donationAmount)) {
- $fields .= ', last_donation_date, last_donation_amount';
- $values .= ', NOW(), ?';
- }
-
- $sql = "INSERT INTO {$this->loginDatabase}.$creditsTable ($fields) VALUES ($values)";
- $sth = $this->connection->getStatement($sql);
- $vals = array($targetAccountID, $credits);
-
- if (!is_null($donationAmount)) {
- $vals[] = $donationAmount;
- }
-
- return $sth->execute($vals);
- }
- else {
- $vals = array();
- $sql = "UPDATE {$this->loginDatabase}.$creditsTable SET balance = balance + ? ";
- if (!is_null($donationAmount)) {
- $sql .= ", last_donation_date = NOW(), last_donation_amount = ? ";
- }
-
- $vals[] = $credits;
- if (!is_null($donationAmount)) {
- $vals[] = $donationAmount;
- }
- $vals[] = $targetAccountID;
-
- $sql .= "WHERE account_id = ?";
- $sth = $this->connection->getStatement($sql);
-
- return $sth->execute($vals);
- }
- }
-
- /**
- *
- */
- public function getPrefs($accountID, array $prefs = array())
- {
- $sql = "SELECT account_id FROM {$this->loginDatabase}.`login` WHERE account_id = ? LIMIT 1";
- $sth = $this->connection->getStatement($sql);
-
- if ($sth->execute(array($accountID)) && ($char=$sth->fetch())) {
- $accountPrefsTable = Flux::config('FluxTables.AccountPrefsTable');
-
- $pref = array();
- $bind = array($accountID);
- $sql = "SELECT name, value FROM {$this->loginDatabase}.$accountPrefsTable ";
- $sql .= "WHERE account_id = ?";
-
- if ($prefs) {
- foreach ($prefs as $p) {
- $pref[] = "name = ?";
- $bind[] = $p;
- }
- $sql .= sprintf(' AND (%s)', implode(' OR ', $pref));
- }
-
- $sth = $this->connection->getStatement($sql);
-
- if ($sth->execute($bind)) {
- $prefsArray = array();
- foreach ($sth->fetchAll() as $p) {
- $prefsArray[$p->name] = $p->value;
- }
-
- return new Flux_Config($prefsArray);
- }
- else {
- return false;
- }
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function setPrefs($accountID, array $prefsArray)
- {
- $sql = "SELECT account_id FROM {$this->loginDatabase}.`login` WHERE account_id = ? LIMIT 1";
- $sth = $this->connection->getStatement($sql);
-
- if ($sth->execute(array($accountID)) && ($char=$sth->fetch())) {
- $accountPrefsTable = Flux::config('FluxTables.AccountPrefsTable');
-
- $pref = array();
- $bind = array($accountID);
- $sql = "SELECT id, name, value FROM {$this->loginDatabase}.$accountPrefsTable ";
- $sql .= "WHERE account_id = ?";
-
- if ($prefsArray) {
- foreach ($prefsArray as $prefName => $prefValue) {
- $pref[] = "name = ?";
- $bind[] = $prefName;
- }
- $sql .= sprintf(' AND (%s)', implode(' OR ', $pref));
- }
-
- $sth = $this->connection->getStatement($sql);
-
- if ($sth->execute($bind)) {
- $prefs = $sth->fetchAll();
- $update = array();
-
- $usql = "UPDATE {$this->loginDatabase}.$accountPrefsTable ";
- $usql .= "SET value = ? WHERE id = ?";
- $usth = $this->connection->getStatement($usql);
-
- $isql = "INSERT INTO {$this->loginDatabase}.$accountPrefsTable ";
- $isql .= "(account_id, name, value, create_date) ";
- $isql .= "VALUES (?, ?, ?, NOW())";
- $isth = $this->connection->getStatement($isql);
-
- foreach ($prefs as $p) {
- $update[$p->name] = $p->id;
- }
-
- foreach ($prefsArray as $pref => $value) {
- if (array_key_exists($pref, $update)) {
- $id = $update[$pref];
- $usth->execute(array($value, $id));
- }
- else {
- $isth->execute(array($accountID, $pref, $value));
- }
- }
-
- return true;
- }
- else {
- return false;
- }
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function getPref($accountID, $pref)
- {
- $prefs = $this->getPrefs($accountID, array($pref));
- if ($prefs instanceOf Flux_Config) {
- return $prefs->get($pref);
- }
- else {
- return false;
- }
- }
-
- /**
- *
- */
- public function setPref($accountID, $pref, $value)
- {
- return $this->setPrefs($accountID, array($pref => $value));
- }
-
- /**
- *
- */
- public function isIpBanned($ip = null)
- {
- if (is_null($ip)) {
- $ip = $_SERVER['REMOTE_ADDR'];
- }
-
- $ip = trim($ip);
- if (!preg_match('/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $ip, $m)) {
- // Invalid IP.
- return false;
- }
-
- $sql = "SELECT list FROM {$this->loginDatabase}.ipbanlist WHERE ";
- $sql .= "rtime > NOW() AND (list = ? OR list = ? OR list = ? OR list = ?) LIMIT 1";
- $sth = $this->connection->getStatement($sql);
-
- $list = array(
- sprintf('%u.*.*.*', $m[1]),
- sprintf('%u.%u.*.*', $m[1], $m[2]),
- sprintf('%u.%u.%u.*', $m[1], $m[2], $m[3]),
- sprintf('%u.%u.%u.%u', $m[1], $m[2], $m[3], $m[4])
- );
-
- $sth->execute($list);
- $ipban = $sth->fetch();
-
- if ($ipban) {
- return true;
- }
- else {
- return false;
- }
- }
- }
- ?>