/Lib/Base/Service/User.php
PHP | 3618 lines | 2415 code | 501 blank | 702 comment | 469 complexity | 4367631cc482a0023f323c15ae1d1730 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- <?php
- class Base_Service_User
- {
- const BAN_COOKIE_NAME = 'f_ubx';
- const COOKIE_CHECKSUM = 27;
- const USER_GENDER_FEMALE = 0;
- const USER_GENDER_MALE = 1;
- const USER_GENDER_UNKNOWN = 2;
- const SALT_TYPE_COOKIE = 'cookie';
- const SALT_TYPE_COOKIE_OLD = 'cookie_old';
- const SALT_TYPE_EMAIL = 'email';
- const SALT_TYPE_PASSWORD = 'password';
- /* Bitwise online/offline statuses */
- const SOURCE_OFFLINE = 0;
- // Online on site
- const SOURCE_FS_ONLINE = 1;
- const SOURCE_FS_AWAY = 2;
- // Online in messenger
- const SOURCE_FSM_ONLINE = 4;
- const SOURCE_FSM_AWAY = 8;
- // Online from mibile version of FS
- const SOURCE_MOBILE_ONLINE = 16;
- const SOURCE_MOBILE_AWAY = 32;
- // Online from iPhone
- const SOURCE_IPHONE_ONLINE = 64;
- const SOURCE_IPHONE_AWAY = 128;
- // Тут внимание! Добвлять новые сурсы можно но мы ограничены 16 битами (8 из которых уже заняты)
- const ONLINE_BIT_SHIFT = 16; // x bit shift
- const ONLINE_MAX_ONLINE_TIME = 86400; //24 * 60 * 60 - максимальное время онлайна
- const ONLINE_TIMEOUT_UPDATE = 180; // 3 * 60 - тамймаут, когда записывать юзера в up
- /*Sources*/
- const ONLINE_SOURCE_FS = 1;
- const ONLINE_SOURCE_FSM = 2;
- const ONLINE_SOURCE_MOBILE = 3;
- const ONLINE_SOURCE_IPHONE = 4;
- /*statuses*/
- const ONLINE_STATUS_ONLINE = 1;
- const ONLINE_STATUS_UPDATE = 2;
- const ONLINE_STATUS_OFFLINE = 3;
- const ACTIVITY_GROUP_ERROR = 5;
- const ACTIVITY_GROUP_NEWUSER = 1;
- const ACTIVITY_GROUP_ACTIVE = 2;
- const ACTIVITY_GROUP_INACTIVE = 3;
- const ACTIVITY_GROUP_LOST = 4;
- const M_GROUP_AGE_KID = 1;
- const M_GROUP_AGE_ADULT = 4;
- const M_GROUP_AGE_NO_AGE = 6;
- // const M_GROUP_AGE_TEEN = 2;
- // const M_GROUP_AGE_YOUNG = 3;
- // const M_GROUP_AGE_AGED = 5;
- const M_GROUP_MALE = 1;
- const M_GROUP_FEMALE = 2;
- const F_ACT_GROUP = 1;
- const F_AGE_GROUP = 2;
- const F_SEX_GROUP = 3;
- const ZODIAC_ARIES = 1; // Овен
- const ZODIAC_TAURUS = 2; // Телец
- const ZODIAC_GEMINI = 3; // Близнецы
- const ZODIAC_CANCER = 4; // Рак
- const ZODIAC_LEO = 5; // Лев
- const ZODIAC_VIRGO = 6; // Дева
- const ZODIAC_LIBRA = 7; // Весы
- const ZODIAC_SCORPIO = 8; // Скорпион
- const ZODIAC_SAGITTARIUS = 9; // Стрелец
- const ZODIAC_CAPRICORN = 10; // Козерог
- const ZODIAC_AQUARIUS = 11; // Водолей
- const ZODIAC_PISCES = 12; // Рыбы
- public static $zodiacs = array(
- self::ZODIAC_ARIES => array(
- 'name' => 'Овен',
- 'range' => array(321, 420),
- 'suitable_signs' => array(self::ZODIAC_GEMINI, self::ZODIAC_LEO, self::ZODIAC_CAPRICORN, self::ZODIAC_AQUARIUS, self::ZODIAC_PISCES),
- ),
- self::ZODIAC_TAURUS => array(
- 'name' => 'Телец',
- 'range' => array(421, 520),
- 'suitable_signs' => array(self::ZODIAC_CANCER, self::ZODIAC_LEO, self::ZODIAC_VIRGO, self::ZODIAC_LIBRA, self::ZODIAC_CAPRICORN, self::ZODIAC_PISCES),
- ),
- self::ZODIAC_GEMINI => array(
- 'name' => 'Близнецы',
- 'range' => array(521, 621),
- 'suitable_signs' => array(self::ZODIAC_ARIES, self::ZODIAC_LEO, self::ZODIAC_LIBRA, self::ZODIAC_AQUARIUS, self::ZODIAC_PISCES),
- ),
- self::ZODIAC_CANCER => array(
- 'name' => 'Рак',
- 'range' => array(622, 722),
- 'suitable_signs' => array(self::ZODIAC_ARIES, self::ZODIAC_LEO, self::ZODIAC_LIBRA, self::ZODIAC_AQUARIUS, self::ZODIAC_PISCES),
- ),
- self::ZODIAC_LEO => array(
- 'name' => 'Лев',
- 'range' => array(723, 823),
- 'suitable_signs' => array(self::ZODIAC_ARIES, self::ZODIAC_TAURUS, self::ZODIAC_GEMINI, self::ZODIAC_CANCER, self::ZODIAC_LEO, self::ZODIAC_LIBRA, self::ZODIAC_SAGITTARIUS),
- ),
- self::ZODIAC_VIRGO => array(
- 'name' => 'Дева',
- 'range' => array(824, 923),
- 'suitable_signs' => array(self::ZODIAC_TAURUS, self::ZODIAC_CANCER, self::ZODIAC_VIRGO, self::ZODIAC_SCORPIO, self::ZODIAC_CAPRICORN, self::ZODIAC_AQUARIUS),
- ),
- self::ZODIAC_LIBRA => array(
- 'name' => 'Весы',
- 'range' => array(924, 1022),
- 'suitable_signs' => array(self::ZODIAC_TAURUS, self::ZODIAC_GEMINI, self::ZODIAC_LEO, self::ZODIAC_LIBRA, self::ZODIAC_SAGITTARIUS, self::ZODIAC_AQUARIUS),
- ),
- self::ZODIAC_SCORPIO => array(
- 'name' => 'Скорпион',
- 'range' => array(1023, 1122),
- 'suitable_signs' => array(self::ZODIAC_CANCER, self::ZODIAC_VIRGO, self::ZODIAC_CAPRICORN, self::ZODIAC_PISCES),
- ),
- self::ZODIAC_SAGITTARIUS => array(
- 'name' => 'Стрелец',
- 'range' => array(1123, 1221),
- 'suitable_signs' => array(self::ZODIAC_LEO, self::ZODIAC_LIBRA, self::ZODIAC_AQUARIUS),
- ),
- self::ZODIAC_CAPRICORN => array(
- 'name' => 'Козерог',
- 'range' => array(1222, 120),
- 'suitable_signs' => array(self::ZODIAC_ARIES, self::ZODIAC_TAURUS, self::ZODIAC_VIRGO, self::ZODIAC_SCORPIO, self::ZODIAC_CAPRICORN, self::ZODIAC_PISCES),
- ),
- self::ZODIAC_AQUARIUS => array(
- 'name' => 'Водолей',
- 'range' => array(121, 219),
- 'suitable_signs' => array(self::ZODIAC_ARIES, self::ZODIAC_GEMINI, self::ZODIAC_VIRGO, self::ZODIAC_LIBRA, self::ZODIAC_SAGITTARIUS, self::ZODIAC_AQUARIUS),
- ),
- self::ZODIAC_PISCES => array(
- 'name' => 'Рыбы',
- 'range' => array(220, 320),
- 'suitable_signs' => array(self::ZODIAC_ARIES, self::ZODIAC_TAURUS, self::ZODIAC_GEMINI, self::ZODIAC_CANCER, self::ZODIAC_SCORPIO, self::ZODIAC_CAPRICORN),
- ),
- );
- /* Time outs by source */
- private static $onlineAwayTimeout = array(
- // online type => timeout in seconds
- self::SOURCE_FS_ONLINE => 900, // 60 * 15
- self::SOURCE_FSM_ONLINE => 900, // 60 * 15
- self::SOURCE_MOBILE_ONLINE => 900, // 60 * 15
- self::SOURCE_IPHONE_ONLINE => 900, // 60 * 15
- );
- private static $_systemUsersIds = array(
- 1, // Фотострана
- 2, // Служба поддержки
- 3, // Служба модерации
- 57267704, // Служба Поддержки ФотоЧата
- 63760510, // Тематические новости в ньюсфиде
- 63760585, // Тематические новости в ньюсфиде
- 63760651, // Тематические новости в ньюсфиде
- 63760698, // Тематические новости в ньюсфиде
- 63760742, // Тематические новости в ньюсфиде
- 63760791, // Тематические новости в ньюсфиде
- 63760836, // Тематические новости в ньюсфиде
- 63760932, // Тематические новости в ньюсфиде
- 65396826, // Социальные таргетинговые объявления
- 70388414, // Бот Новости Фотостраны
- );
- private static function getSalt($type)
- {
- $saltConfig = Base_Application::getInstance()->config['passwd']['salt'];
- return !empty($saltConfig[$type]) ? $saltConfig[$type] : '';
- }
- public static function getUserProfileUrl($user, $native = false)
- {
- if ($native) {
- $project = $user->getNativeProject();
- } else {
- $project = Base_Project_Manager::getProject();
- }
- $domain = $project->getDomain();
- if (Base_Service_Common::isStage(false)) {
- $domain = 'stage.' . $domain;
- }
- $isRambler = Base_Project_Manager::getProject()->isRamblerWL() || $project->isRamblerWl();
- // костыль для letitbit и pet.rambler.ru
- if (!Base_Project_Manager::isOurDomainId($project->getDomainModel()->getId()) ||
- $isRambler) {
- return 'http://' . $domain . '/user/' . $user['user_id'] . '/';
- }
- if (!isset($user['user_id']) || !$user['user_id']) {
- return 'http://' . $domain . '/user/deleteduser/';
- }
- if (PetApp_Base_Service_Project::isPetAppProject($project->getType())) {
- return $user['user_pet_id'] ? 'http://' . $domain . '/pet/' . $user['user_pet_id'] . '/' :
- 'http://' . $domain . '/user/'. $user['user_id'] .'/';
- }
- if (isset($user['user_pagename']) && $user['user_pagename']) {
- if (Base_Project_Fotostrana::fotostrana2Enabled()) {
- // для определения ссылок на пользователей в фс 2.0 добавляем /u/. для аякс-переходов
- // @todo найти нормальное решение, не требующее изменения урлов.
- return 'http://' . $domain . '/u/' . $user['user_pagename'] . '/';
- }
- return 'http://' . $domain . '/' . $user['user_pagename'] . '/';
- } else {
- return 'http://' . $domain . '/user/' . $user['user_id'] . '/';
- }
- }
- public static function getInterestPeople($user)
- {
- $userId = $user->getId();
- $cachedId = Base_Service_Memcache::get(Base_Dao_User::MC_USER_INTERESTPEOPLE.$userId, __METHOD__);
- if($cachedId!==false) {
- $result = Base_Dao_User::getUsersByIds($cachedId);
- } else {
- if(!($user instanceof Base_Model_User) || !$user) {
- return array();
- }
- $periods = array(Base_Service_Interest_Tracker::USERS_PERIOD_DAY, //0
- Base_Service_Interest_Tracker::USERS_PERIOD_WEEK, //1
- Base_Service_Interest_Tracker::USERS_PERIOD_MONTH); //2
- $result = array();
- $userFriendsIds = Friends_Service_New::getFriends($userId, 50, 0, true);
- $userFavIds = Usercontact_Dao_Favorite::getRight($userId, 10);
- $t = Base_Dao_User::getUsersByIds(array_unique($userFavIds[2]));
- $userFavs = array();
- foreach($t as $u){
- if ($u->isPetAppUser()) {
- Base_Service_Counter_Social::getInstance()->increment($u, 'test_stat_pet_only_in_favorite_left', 1);
- Base_Service_Counter_Social::getInstance()->increment($user, 'test_stat_pet_only_in_favorite_right', 1);
- }
- if($u->isOnline()) {
- $userFavs[] = $u;
- }
- }
- if(count($userFavs)==0 || count($userFriendsIds)==0) {
- $interests = array(15,10,5);
- } else {
- $interests = array(15,5,5);
- }
- $userInterestIds = array();
- foreach($periods as $p) {
- $t = Base_Service_Interest_Tracker::getUserContactsPopular($userId, $p, $interests[$p]);
- if(is_array($t)) {
- foreach($t as $u=>$c) {
- if($c>2 && $u!=0) {
- $userInterestIds[] = $u;
- }
- }
- }
- }
- $userInterest = Base_Dao_User::getUsersByIds(array_unique($userInterestIds));
- $userFriendsIds = array_diff($userFriendsIds, $userInterestIds, $userFavIds);
- $userFriends = Base_Dao_User::getUsersByIds($userFriendsIds);
- $users = array_merge($userInterest, $userFavs, $userFriends);
- //$usersIds = array_merge($userInterestIds, $userFavIds[2], $userFriendsIds);
- $resIds = array();
- foreach($users as $u) {
- if($u->hasMainPhoto() && $u->getId()>1 && !in_array($u, $result)) {
- $result[] = $u;
- $resIds[] = $u->getId();
- }
- if(count($result)>=20) break;
- }
- Base_Service_Memcache::set(Base_Dao_User::MC_USER_INTERESTPEOPLE . $userId, $resIds);
- }
- return $result;
- }
- public static function generateUserEmailHash($userOrEmail)
- {
- $salt = self::getSalt('email');
- if ($userOrEmail instanceof Base_Model_User) {
- return md5($userOrEmail->getEmail() . $salt);
- } else {
- return md5($userOrEmail . $salt);
- }
- }
- /**
- * convert user birthday to age
- *
- * @param $userBirthday
- * @param bool $asString
- * @param bool $baseTime
- *
- * @return bool|int|string
- */
- public static function getUserAge($userBirthday, $asString = false, $baseTime = false)
- {
- if (!$userBirthday || $userBirthday == '0000-00-00') {
- return false;
- }
- $baseTime = ($baseTime === false) ? TIME : $baseTime;
- list($year, $month, $day) = explode('-', $userBirthday);
- $yearDiff = date('Y', ($baseTime)) - $year;
- $monthDiff = date('m', ($baseTime)) - $month;
- $dayDiff = date('d', ($baseTime)) - $day;
- if ($monthDiff < 0) {
- $yearDiff--;
- } elseif (($monthDiff == 0) && ($dayDiff < 0)) {
- $yearDiff--;
- }
- return $asString ? _f('{plural|%d год|%d года|%d лет|%d лет}', $yearDiff) : $yearDiff;
- }
- /**
- * Получть хеш пароля из пароля. Он хранится в бд
- */
- public static function getPasswordHash($password)
- {
- return md5($password . self::getSalt(self::SALT_TYPE_PASSWORD));
- }
- public static function getPasswordCrypt($password)
- {
- $secretKey = Base_Application::getInstance()->config['passwd']['user']['crypt_key'];
- return Base_Service_Crypt::crypt($password, true, $secretKey);
- }
- public static function getPasswordDecrypt($password)
- {
- if(Base_Mailer_Service_Config::isPreviewMode()) {
- return 'password_hidden';
- }
- $secretKey = Base_Application::getInstance()->config['passwd']['user']['crypt_key'];
- return Base_Service_Crypt::decrypt($password, true, $secretKey);
- }
- /**
- * Получить хеш для авторизации
- *
- * @param $userId ID пользователя
- * @param $userEmail e-mail пользователя
- * @param $userPasswordHash хеш пароля пользователя
- * @param bool $includeASCode включать ли в хеш провайдера
- * @param bool $oldSalt использовать ли старую соль (для переходного периода)
- *
- * @return string
- */
- public static function getAuthHash($userId, $userEmail, $userPasswordHash, $includeASCode = false, $oldSalt = false)
- {
- $salt = self::getSalt($oldSalt ? self::SALT_TYPE_COOKIE_OLD : self::SALT_TYPE_COOKIE);
- $provider = '';
- if ($includeASCode) {
- $ip = Base_Service_Common::getRealIp();
- $location = Base_Dao_Geo::getLocationByIp($ip);
- if (!empty($location['provider'])) {
- $provider = crc32(Utf::trim($location['provider']));
- }
- }
- return md5($userEmail . $userPasswordHash . $provider . $salt) . $userId % self::COOKIE_CHECKSUM;
- }
- /**
- * @deprecated use Base_Service_User::getAuthHash
- */
- public static function getUserPasswordSalt($userId, $userEmail, $userPassword, $newEmail = '')
- {
- return md5($userEmail . $userPassword . $newEmail . self::getSalt(self::SALT_TYPE_COOKIE_OLD)) . $userId % self::COOKIE_CHECKSUM;
- }
- /**
- * Упрощенная авторизация. Используется там, где не нужна повышенная безопасность
- *
- * @param $userId
- * @param $cookieSecretWord
- *
- * @return bool
- */
- public static function checkPasswordHash($userId, $cookieSecretWord)
- {
- $uidHash = $userId % Base_Service_User::COOKIE_CHECKSUM;
- return ($uidHash == Utf::substr($cookieSecretWord, -Utf::strlen($uidHash), Utf::strlen($uidHash)));
- }
- /**
- * Авторизует пользователя на сайте
- *
- * @param Base_Model_User $user
- *
- * @return bool
- */
- public static function logIn($user)
- {
- if (!$user) {
- return false;
- }
- Service_Base::setCookie(
- 'uid',
- $user->getId(),
- 100, '/', true, 2
- );
- Service_Base::setCookie(
- 'hw',
- Base_Service_User::getAuthHash($user->getId(), $user->getEmail(), $user->getPasswordHash(), false),
- 100, '/', true, 2
- );
- Antispam_Service_Token::setToken();
- $trace = Base_Service_Log::getTrace(3);
- Pet_Dao_Trace::log($user->getId(), 'lgn: ' . implode(',', $trace));
- return true;
- }
- public static function logout()
- {
- Service_Base::setCookie('hw', '', -1, '/', true, 2);
- Service_Base::setCookie('uid', '', -1, '/', true, 2);
- }
- /**
- * @param Base_Model_User $user
- *
- * @return boolean
- */
- public static function checkUserNeedsActivation($user)
- {
- if (!$user) {
- return false;
- }
- if (!$user->getRefId() && !$user->isEmailApproved() && $user->isFsUser()) {
- return true;
- }
- return false;
- }
- /**
- * Check User for ban
- *
- * @param Base_Model_User $user
- *
- * @return bool
- */
- public static function checkUserBanCookie($user)
- {
- return;
- // if (!$user->isBanned() && isset($_COOKIE[self::BAN_COOKIE_NAME])) {
- // Service_Base::setCookie(self::BAN_COOKIE_NAME, '');
- // } elseif ($user->isBanned() && $user->isBanned() != Db_Moders::BAN_REASON_NEED_APPROVE_EMAIL && !isset($_COOKIE[self::BAN_COOKIE_NAME])) {
- // Service_Base::setCookie(self::BAN_COOKIE_NAME, 1, 1);
- // }
- }
- /**
- * Проверям, может ли юзер стать претендентом в эксперты
- *
- * @param Base_Model_User $user пользователь
- * @param $type (expert, moder, petgid, guide)
- * @param $reason Возвращает причину отказа (в виде кода)
- *
- * @return bool
- */
- public static function canBeExpert($user, $type, &$reason = '')
- {
- $reason = '';
- assert(in_array($type, array('expert', 'moder', 'petgid', 'guide')));
- if (!($user instanceof Base_Model_User)) {
- trigger_error("Please pass Base_Model_User, not an array", E_USER_WARNING);
- $user = Base_Dao_User::getUserById($user['user_id']);
- }
- /*if(!$user['user_identity_approved']) {
- if($type != 'petgid') {
- $reason = 'need_identity_approved';
- return false;
- }
- }*/
- if ($type == 'petgid' && $user->hasProfession()) {
- $reason = 'has_profession';
- return false;
- }
- // Требуем наличия подтвержденного телефона
- if ($user->getUserClass() !== Db_User::USER_CLASS_CITIZEN) {
- $reason = 'must_be_citizen';
- return false;
- }
- if(self::getUserAge($user['user_birthday'])<18 && $type!='petgid'){
- $reason = 'must_be_18';
- return false;
- }
- if ($type=='petgid') {
- if (self::getUserAge($user['user_birthday'])<16) {
- $reason = 'must_be_16';
- return false;
- }
- $pet = $user->getPet();
- if (!$pet) {
- $reason = 'no_pet';
- return false;
- }
- if ($pet->getDaltLevel() < 10) {
- $reason = 'pet_dalt_10';
- return false;
- }
- }
- $dbModers = new Admin_Dao_User();
- $bans = $dbModers->getUsersViolations(array($user['user_id']),'adminban',true);
- if(!empty($bans)) {
- $reason = 'has_bans';
- return false;
- }
- if(Support_Dao_Base::getExpertRequestByUserId($user['user_id'],$type)) {
- $reason = 'already_applied';
- return false;
- }
- return true;
- }
- /**
- * Возвращает HTML-текст с сообщением об ошибке для данного кода ошибки.
- */
- public static function getErrorText($errorCode)
- {
- $simpleCodes = array(
- 'need_identity_approved' => _g('Чтобы получить профессию, надо сначала подтвердить свою личность.'),
- 'need_more_reputation' => _g('У тебя пока недостаточно репутации, чтобы получить профессию.'), // deprecated
- 'must_be_18' => _g('Тебе должно быть не меньше 18 лет!'),
- 'must_be_16' => _g('Тебе должно быть не меньше 16 лет!'),
- 'has_profession' => _g('У тебя уже есть профессия на сайте!'),
- 'no_pet' => _g('У тебя нет питомца.'),
- 'pet_dalt_10' => _g('У твоего питомца недостаточно способностей.'),
- 'has_bans' => _g('Ты был наказан за нарушения.'),
- 'already_applied' => _g('Ты уже подавал заявку на получение профессии. Дождись ее рассмотрения.'),
- 'must_be_citizen' => _g('Тебе необходимо подтвердить свой номер телефона.')
- );
- if ($errorCode == '') {
- // No error
- return '';
- }
- if (isset($simpleCodes[$errorCode])) {
- return $simpleCodes[$errorCode];
- }
- throw new Base_Exception("Invalid error code: '$errorCode'");
- }
- public static function canBeWriter($user)
- {
- return false; // профессия выключена для всех
- if (Event_Service_Editor::userInBan($user['user_id'])) {
- return false;
- }
- return
- !$user['user_is_volunteer']
- && $user['user_class'] == Db_User::USER_CLASS_CITIZEN;
- }
- public static function getDeletedUserInto(&$user)
- {
- $user['is_deleted'] = true;
- $user['user_name'] = _g('Удаленный житель');
- $user['user_pagename'] = null;
- $user['user_phone'] = null;
- $user['user_phone_approved'] = '0';
- $user['user_sex'] = 'm';
- $user['user_inserted'] = '2009-01-01 00:00:00';
- $user['user_updated'] = '2009-01-01 00:00:00';
- $user['user_email'] = 'deleted@fotostrana.ru';
- $user['password_hash'] = '';
- $user['user_email_approved'] = null;
- $user['user_ip'] = null;
- $user['user_id_from'] = null;
- $user['user_about'] = null;
- $user['user_city'] = null;
- $user['user_last_mail'] = '2009-01-01 00:00:00';
- $user['user_is_hidden'] = null;
- $user['user_is_volunteer'] = null;
- $user['user_source'] = null;
- $user['user_source_result'] = null;
- $user['user_not_activated'] = null;
- $user['user_country_id'] = 0;
- $user['user_city_id'] = 0;
- $user['user_region_id'] = 0;
- $user['user_birthday'] = null;
- $user['user_ref_id'] = null;
- $user['user_ref_pa'] = '0';
- $user['user_deviz'] = null;
- $user['user_why'] = null;
- $user['user_galleries'] = null;
- $user['user_status'] = null;
- $user['user_bans'] = null;
- $user['user_warn'] = null;
- $user['user_cash'] = '0.00';
- $user['user_hold'] = '0.00';
- $user['user_class'] = '0';
- $user['terms_agree'] = '1';
- $user['time_in'] = 1;
- $user['time_out'] = 1;
- $user['user_pet_id'] = 0;
- $user['user_photo_id'] = -1;
- return $user;
- }
- public static function getDeletedUser($userId)
- {
- $user = array();
- $user['user_id'] = $userId;
- self::getDeletedUserInto($user);
- return new Base_Model_User($user);
- }
- public static function validateEmail($email)
- {
- return Utf::preg_match('/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/', $email);
- }
- /**
- * исправить ошибки в написании пароля:
- * убирает пробелы на краях и заменяет русские символы транслитом
- * (если забыл сменить язык)
- */
- public static function correctPassword($pswd)
- {
- $pswd = trim($pswd);
- // strtr получается в 4е раза быстрее чем str_replace
- return strtr($pswd, 'ёйцукенгшщзфывапролдячсмитьЁЙЦУКЕНГШЩЗФЫВАПРОЛДЯЧСМИТЬ', '`qwertyuiopasdfghjklzxcvbnm~QWERTYUIOPASDFGHJKLZXCVBNM');
- }
- /**
- * Валидатор для имени пользователя
- *
- * @param $name
- * @param string $error
- * @return bool
- */
- public static function validateUsername($name, &$error = '', &$debug = '')
- {
- // если нужно заблочить смешанное имя (кириллица + латиница),
- // можно добавлять в любой массив
- // разделение массивов сделано для увеличения производительности в
- // ф-циях preg_match
- if (Base_Service_Common::isOurIp()) {
- return true;
- }
- $name = str_replace(chr(173), '', $name);
- // stop words in Antifraud_Service_Badwords
- $cyrStopWords = Antifraud_Service_Badwords::getWords(Antifraud_Service_Badwords::CYR_NAMES);
- $latStopWords = Antifraud_Service_Badwords::getWords(Antifraud_Service_Badwords::LAT_NAMES);
- array_walk($cyrStopWords, function (&$value, $key) {
- $value = preg_quote($value);
- });
- array_walk($latStopWords, function (&$value, $key) {
- $value = preg_quote($value);
- });
- $error = '';
- $toCyrName = strtr($name, 'aA6cCeETmHoOpPkKxXBMbryYUunl3gt', 'аАбсСеЕТтНоОрРкКхХВМьгуУИип1Здт'); // переводим имя в кириллицу
- $toLatName = strtr($name, 'аАбсСеЕТтНоОрРкКхХВМьгуУИип1Здт', 'aA6cCeETmHoOpPkKxXBMbryYUunl3gt'); // переводим имя в латиницу
- $name = Utf::trim(mb_strtolower($name));
- $toCyrName = Utf::trim(mb_strtolower($toCyrName));
- $toLatName = Utf::trim(mb_strtolower($toLatName));
- // первый этап проверки, если юзер меняет на что-то вроде админ или admin (т.е. не использует замены символов на похожие)
- if (!$error && Utf::preg_match('/(' . implode('|', array_merge($cyrStopWords, $latStopWords)) . ')/', $name)) {
- $error = 'stop_word';
- $debug = 'lat_or_cyr_stop_word';
- }
- // второй этап, если юзер ввел имя, используя замену кириллических символов на похожие латинские
- if (!$error && Utf::preg_match('/(' . implode('|', $cyrStopWords) . ')/', $toCyrName)) {
- $error = 'stop_word';
- $debug = 'cyr_to_lat_change';
- }
- // третий этап, если юзер ввел имя, используя замену латинских символов на похожие кириллические
- if (!$error && Utf::preg_match('/(' . implode('|', $latStopWords) . ')/', $toLatName)) {
- $error = 'stop_word';
- $debug = 'lat_to_cyr_change';
- }
- // normalize urls
- $toLatName = str_replace(' ', '', $toLatName);
- $toLatName = preg_replace('#[.]+#', '.', $toLatName);
- if (!$error && Utf::preg_match(Base_Util_String::getUrlPreg(), $toLatName) > 0) {
- $error = 'stop_word';
- $debug = 'url_preg';
- }
- $statsClient = new Base_Service_Counter_Main();
- $defaultUser = Base_Dao_User::getUserById(1);
- $statsClient->increment($defaultUser, 'signup_time_name_check', 1);
- if ($error) {
- $statsClient->increment($defaultUser, 'signup_time_name_block', 1);
- return false;
- }
- return true;
- }
- public static function getRemainingDeleteRequestTime($userId)
- {
- $requestTime = Base_Dao_User::getDeleteRequestTime($userId);
- if (!$requestTime) {
- return false;
- }
- $requestTimeEnd = $requestTime + 60*60*24;
- $timeRemaining = $requestTimeEnd - time();
- // Пользователь за 5 дней не подтвердил желание удалиться, удаляем заявку
- $user = Base_Dao_User::getUserById($userId);
- if($timeRemaining < -60*60*24*5 && $user['user_is_hidden'] != Db_Moders::DELAYED_DELETED){
- Base_Dao_User::cancelDeleteRequest($userId);
- return false;
- }
- if ($timeRemaining < 0) {
- return -1;
- }
- $hours = (int)($timeRemaining / (60*60));
- $minutes = (int)($timeRemaining % (60*60) /60);
- $hoursStr = _f('{plural|%d час|%d часа|%d часов}', $hours);
- $minutesStr = _f('{plural|%d минуту|%d минуты|%d минут}', $minutes);
- return $hoursStr . ' ' . $minutesStr;
- }
- public static function getRemainingDeleteTime($userId)
- {
- $requestTime = Base_Dao_User::getDeleteRequestTime($userId);
- if (!$requestTime) {
- return false;
- }
- $deleteTime = $requestTime + 60*60*24*30;
- $timeRemaining = $deleteTime - time();
- if ($timeRemaining < 0) {
- return _g('еще одного дня');
- }
- $days = (int)($timeRemaining / (60*60*24));
- if ($days == 0) {
- $days = 1;
- }
- return _f('{plural|%d дня|%d дней|%d дней}', $days);
- }
- public static function getDeleteConfirmHash($user, $oldSalt = false)
- {
- $salt = self::getSalt($oldSalt ? self::SALT_TYPE_COOKIE_OLD : self::SALT_TYPE_COOKIE);
- return md5($user['user_inserted'] . $salt);
- }
- public static function processDelayedDelete()
- {
- $db = Base_Context::getInstance()->getDbConnection();
- $dbUser = new Db_User();
- $query = '
- SELECT user_id, reason
- FROM
- user_delete_request
- WHERE
- DATE_SUB(NOW(), INTERVAL 30 DAY) > request_time
- LIMIT 200';
- $usersData = $db->fetchAssoc($query, __METHOD__);
- if ($usersData) {
- $userIds = Base_Util_Array::extract($usersData, 'user_id');
- $usersToDelete = Base_Dao_User::getUsersByIds($userIds);
- foreach ($usersToDelete as $userToDelete) {
- if ($userToDelete->isHidden() != Db_Moders::DELAYED_DELETED) {
- continue;
- }
- $reason = isset($usersData[$userToDelete->getId()]) ? $usersData[$userToDelete->getId()]['reason'] : '';
- $dbUser->deleteUser($userToDelete, $reason);
- $userToDelete->getNativeProject()->getStatisticClient()->increment($userToDelete, 'delete_user', 1);
- // @analytics stats
- $analytics = new Base_Service_Counter_Analytics();
- $analytics->increment($userToDelete, 'delete_user', 1);
- sleep(1);
- }
- $db->delete('user_delete_request', $db->qq('user_id IN ('.join(',',$userIds).')'), __METHOD__);
- }
- // предупреждаем тех, кому осталось 3 дня до удаления
- $query = '
- SELECT user_id
- FROM
- user_delete_request
- WHERE
- DATE_SUB(NOW(), INTERVAL 60*24*27-10 MINUTE) > request_time
- AND DATE_SUB(NOW(), INTERVAL 60*24*27 MINUTE) <= request_time';
- $usersToNotifyIds = $db->fetchCol($query, __METHOD__);
- if ($usersToNotifyIds) {
- $usersToNotify = Base_Dao_User::getUsersByIds($usersToNotifyIds);
- foreach ($usersToNotify as $userToNotify) {
- if ($userToNotify->isHidden() != Db_Moders::DELAYED_DELETED || !$userToNotify->isEmailSet() ) {
- continue;
- }
- /* @var $userToNotify Base_Model_User */
- Base_Mailer_Base::addImmediateMail($userToNotify, Base_Mailer_NewTypes::TYPE_DELETE_NOTIFY, __METHOD__, array('subject' => _f('Удаление с {string}', $userToNotify->getNativeProject()->getTitle(2))));
- }
- }
- }
- /**
- * @param Base_Model_User $user
- * @param string $wLetter
- * @param string $mLetter
- *
- * @return string
- */
- public static function getSexLetter($user, $wLetter = 'а', $mLetter = '')
- {
- return $user->isFemale() ? $wLetter : $mLetter;
- }
- /**
- * Проверяет, кто из списка айдишников онлайн
- *
- * @param array $ids массив айдишников пользователй для проверки
- * @param bool $keepOffline
- *
- * @return array|bool массив с ключами $ids и значениями 1|0 (онлайн/офлайн)
- */
- public static function getAutoOnlineUsers(array $ids, $keepOffline = true)
- {
- if(!is_array($ids)){
- return false;
- }
- $db = Base_Context::getInstance()->getDbConnection();
- $select = $db->select()->from('auto_online','user_id')->where('user_id IN (?)', $ids);
- $result = $db->fetchCol($select, __METHOD__);
- $online = $keepOffline ? array_fill_keys($ids, 0) : array();
- foreach($result as $id){
- $online[$id]=1;
- }
- return $online;
- }
- /**
- * По прошествию 4-х дней переносятся все пользователи кроме:
- * 1) забанен и не имеет фин активности
- * 2) не имеет подтвержденного е-мела
- * в таблицу user. Остальные пользователи удаляются.
- */
- public static function moveNewUsers()
- {
- $date4Day = date('Y-m-d H:i:s', time() - 86400 * 4);
- /**
- * Если мы в окружении для тестирования, необходимо
- * скопировать пользователей которые были добавлены через modelFactory
- */
- if (defined('TESTING') && constant('TESTING') === true) {
- // $whereNotActive = "user_email = '".Db_User::DEFAULT_EMAIL."'";
- // $whereActive = "user_email != '".Db_User::DEFAULT_EMAIL."'";
- $whereActive = "1=1";
- } else {
- // $whereNotActive = "user_inserted < '$date4Day' AND user_email = '".Db_User::DEFAULT_EMAIL."'";
- // $whereActive = "user_inserted < '$date4Day' AND user_email != '".Db_User::DEFAULT_EMAIL."'";
- $whereActive = "user_inserted < '$date4Day'";
- }
- /* ---------------------------------------------------------------------------------------------------------- */
- $db = Base_Context::getInstance()->getDbConnection();
- /* $countNew = (int) $db->fetchOne("SELECT COUNT(*) FROM `user_new` WHERE $whereActive", __METHOD__);
- $countBefore = (int) $db->fetchOne("SELECT COUNT(*) FROM `user`", __METHOD__);
- $query = "INSERT INTO `user` (SELECT * FROM `user_new` WHERE $whereActive) ON DUPLICATE KEY UPDATE user.user_email = user_new.user_email, user.user_is_hidden = user_new.user_is_hidden, user.user_not_activated = user_new.user_not_activated";
- $db->writequery('user', $query, __METHOD__);
- $countAfter = $db->fetchOneMaster("SELECT COUNT(*) FROM `user`", __METHOD__);
- if ($countAfter >= $countBefore + $countNew) {
- $queryDelete = "DELETE FROM `user_new` WHERE $whereActive";
- Driver_Db::writequery('user_new', $queryDelete, __METHOD__);
- }*/
- // получим активных пользователей, для переноса
- $activeIds = $db->fetchCol("SELECT `user_id` FROM `user_new` WHERE $whereActive", __METHOD__);
- $activeTotal = count($activeIds);
- foreach (array_chunk($activeIds, 5000) as $idsPack) {
- $activeIdsImploded = implode(', ', $idsPack);
- // перенесем их в `users` табличку
- $query = "
- INSERT INTO `user` (SELECT * FROM `user_new` WHERE `user_id` IN($activeIdsImploded))
- ON DUPLICATE KEY UPDATE
- `user`.`user_email` = `user_new`.`user_email`,
- `user`.`user_is_hidden` = `user_new`.`user_is_hidden`,
- `user`.`user_not_activated` = `user_new`.`user_not_activated`
- ";
- $db->writequery('user', $query, __METHOD__);
- // уберем перенесенных из `user_new`
- $db->writequery('user_new', "DELETE FROM `user_new` WHERE `user_id` IN($activeIdsImploded)", __METHOD__);
- }
- unset($activeIds, $activeIdsImploded);
- /* ---------------------------------------------------------------------------------------------------------- */
- // полюбому удаляем, тех, кто были незабанены :)
- $dbUser = new Db_User();
- $dbUser->getTb(1, true); // обновляем кеш по ид на данном сервере.
- $usersToDelete = array(); // $db->fetchAll($db->select()->from('user_new')->where($whereNotActive), __METHOD__);
- $phonesToBlacklist = array();
-
- // foreach ($usersToDelete as $user) {
- // // забанен, не платил, номер телефона активирован
- //// if($user['user_is_hidden'] >= 1 && $user['user_cash'] === null && $user['user_phone_approved'] == 1 && $user['user_phone']){
- //// $phonesToBlacklist[] = $user['user_phone'];
- //// }
- //
- // /**
- // * Слишком долго выполняется в тестах
- // */
- // if (!defined('TESTING')) {
- // $dbUser->deleteUser($user, "not-active-4day");
- // }
- // }
- //
- // // добавляем телефоны в blacklist. Отключено по просьбе Германова Евгения.
- //// $blacklistDao = Antifraud_Dao_Blacklist::getInstance();
- //// foreach($phonesToBlacklist as $phone){
- //// $blacklistDao->addToBlackList(Antifraud_Dao_Blacklist::TYPE_PHONE, $phone, 'not-active-4day-banned');
- //// }
- //
- // $dbUser->getTb(1, true);
- return array(
- 'transferred' => $activeTotal, //$countNew,
- 'deleted' => count($usersToDelete),
- 'phonesToBlacklist' => count($phonesToBlacklist)
- );
- }
- /**
- * @depracated - оставлю для истории. Сейчас этот крон работает в демоне. Код портировали с небольшими измениями.
- *
- * Обновления онлайн. Запускается раз в 1 минуту.
- *
- * Как эта хренота работает:
- * - забираем юзеров из SQ, туда записываются из разных мест массивчики вида
- array(
- 'user_id' => id юзера, который произвёл действие,
- 'time' => время, когда это действие было совершено,
- 'r_id' => реферрер - откуда пришёл юзер,
- 'r_data' => что-то (не вкурсе, присутствовало в старом кроне),
- 'src_id' => сурс - с какого типа ФС юзер вышел онлайн (FS, FSm, Mobile version, iPhone app, ...)
- );
- * - группируем эти действия по user_id и src_id
- * - берём время последнего действия для каждого типа
- * - достаём все записи из auto_online
- * - путём нехитрых манипуляций вычисляем по time_update юзеров, которые проэкспайрились
- * - исходя из данных из SQ определяем юзеров которые только что стали онлайн (тоесть отсутствуют в auto_online)
- * и тех, кто уже был онлайн на момент запуска крона (присутствуют в auto_online)
- * - и затем апдейтим группы этих юзеров
- * ... В общем коллективный разум нам подсказал сложную и интересную реализацию онлайнов.
- * В табличках user и user_new у нас есть (появилось) поле online_mask, которое содержит в себе побитовую маску
- * сурсов, в которых юзер онлайн/оффлайн. Битики лежат в константах этого класса (с префиксом SOURCE_*).
- * Масочка может принимать значение 0 - когда юзер вообще оффлайн или иметь установленные битики онлайн/эвэй для каждого их сурсов.
- * Под каждый сурс занято 2 бита - бит online и бит away (это когда юзер ещё где-то онлайн, но по данному сурсу уже оффлайн),
- * выглядит это как-то так (на момент запуска - 16 бит, определяется константой ONLINE_BIT_SHIFT):
- * |0|0|0|0|0|0|0|0|
- * | | | | FS: away, online
- * | | | FSm: away, online
- * | | Mobile: away, online
- * | iPhone: away, online
- * Если юзер не имеет ни одного установленного бита online - ему вставляется 0.
- * Апдейтится эта штука так: создаётся маска, имеющая 32 бит:
- * 16 младших бит - это те биты, которые мы хотим сбросить
- * 16 старших бит - это те биты, которые мы хотим поставить
- * Весь апдейт происходит сбрасыванием полной маски, и установкой со сдвигом маски на 16 бит вправо
- * Собственно вот :)
- * - и соответственно апдейтим мемкэш для этих юзеров
- * - удаляем юзеров из auto_online
- * Тут ещё есть немного кода, который был перенесён из старого крона, и коммент соответсвенно для него:
- * в) статистика логинов для Gameleads
- *
- */
- public static function updateAutoOnline($qnum)
- {
- $timeNow = time();
- $currDayTS = strtotime(date('Y-m-d 00:00:00'));
- $prevDayTS = strtotime(date('Y-m-d 00:00:00', strtotime('-1 day')));
- // забираем все из очереди
- if (PRODUCTION) {
- $queueNum = ($qnum == 1) ? Base_Service_SharedQueue::INDEX_ONLINE : Base_Service_SharedQueue::INDEX_ONLINE_EVEN;
- $sqData = Base_Service_SharedQueue::popAll($queueNum);
- } else {
- if ($qnum != 1) {
- return true;
- }
- $sqData = array_merge(
- Base_Service_SharedQueue::popAll(Base_Service_SharedQueue::INDEX_ONLINE),
- Base_Service_SharedQueue::popAll(Base_Service_SharedQueue::INDEX_ONLINE_EVEN)
- );
- }
- // берём время последнего действия с группировкой по юзеру и сурсу
- $byUserSrc = array();
- $usersLocation = array();
- /*$loggedOutUsers = array();*/
- foreach ($sqData as $k => $item) {
- if (!empty($item['from_logout'])) {
- /*$loggedOutUsers[$item['user_id']] = 1;*/
- continue;
- }
- // временная затычка, на время перехода со старого крона на новый
- if (!isset($item['src_id'])) {
- $item['src_id'] = self::SOURCE_FS_ONLINE;
- }
- /* Example
- $item = array(
- 'user_id' => $userId,
- 'time' => $timeNow,
- 'r_id' => $referrerId,
- 'r_data' => $returnData,
- 'src_id' => $sourceId
- );
- */
- // отсеиваем события старше таймаута для данного сурса (ибо нахх не нужны)
- if (($timeNow - $item['time']) > Base_Service_User::$onlineAwayTimeout[$item['src_id']]) {
- continue;
- }
- //Сохраним ip и время для обновления счетчиков логинов
- if (isset($item['long_ip'])) {
- $usersLocation[$item['user_id']] = $item['long_ip'];
- }
- if (!isset($byUserSrc[$item['user_id']])) {
- $byUserSrc[$item['user_id']] = array();
- } elseif (!isset($byUserSrc[$item['user_id']][$item['src_id']])) {
- $byUserSrc[$item['user_id']][$item['src_id']] = array();
- }
- // сделаем ссылочку, для более удобной работы с элементом массива
- $link = &$byUserSrc[$item['user_id']][$item['src_id']];
- // обновляем время последнего действия
- if (!isset($link['time']) || $item['time'] > $link['time']) {
- $link['time'] = $item['time'];
- }
- // Записываем только первый refererId для юзера
- if (!empty($item['r_id']) && !isset($link['r_id'])) {
- $link['r_id'] = $item['r_id'];
- }
- if (!empty($item['r_data']) && empty($link['r_data'])) {
- $link['r_data'] = $item['r_data'];
- }
- unset($link);
- }
- unset($sqData);
- $_new = $_up = $_off = array();
- // выбираем пользователей которые были онлайн
- $autoOnlineByUser = array();
- $db = Base_Context::getInstance()->getDbConnection();
- $autoOnlineData = $db->selectAll('auto_online', "SELECT user_id, source_id, time_update, time_in FROM auto_online", __METHOD__);
- foreach ($autoOnlineData as $k => $row) {
- // фильтруем чётные / нечётные
- if (PRODUCTION && (($qnum == 1 && $row['user_id'] % 2 == 0) || ($qnum == 2 && $row['user_id'] % 2 != 0))) {
- continue;
- }
- $timeOut = Base_Service_User::$onlineAwayTimeout[$row['source_id']];
- if (!isset($autoOnlineByUser[$row['user_id']])) {
- $autoOnlineByUser[$row['user_id']] = array();
- }
- $autoOnlineByUser[$row['user_id']][$row['source_id']] = array(
- 'time_update' => $row['time_update'],
- 'time_in' => $row['time_in']
- );
- /* Вынес условия в переменные, иначе код нечитаемый */
- // если юзер проэкспайрился по табличке
- $dbTimeout = ($timeNow - $row['time_update']) > $timeOut;
- // отсутствует в SQ или имеет в SQ проэкспайреное время
- $sqTimeout = (!isset($byUserSrc[$row['user_id']][$row['source_id']]) || ($timeNow - $byUserSrc[$row['user_id']][$row['source_id']]['time']) > self::ONLINE_TIMEOUT_UPDATE);
- // если юзер олайн больше чем максимальное время онлайна
- $maxTimeout = ($timeNow - $row['time_in']) > self::ONLINE_MAX_ONLINE_TIME;
- if…
Large files files are truncated, but you can click here to view the full file