v7‰PNG
IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ±üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0AºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT
Databased.php 0000644 00000076012 15210162164 0007131 0 ustar 00 Return example:
*
* array( 'db' => 'MYSQL_DBNAME',
* 'user' => 'MYSQL_USER',
* 'prefix'=> 'MYSQL_PREFIX'
* )
*/
abstract class Am_Protect_Databased extends Am_Protect_Abstract implements Am_Protect_SingleLogin
{
const USER_NEED_SETPASS = 'user_need_setpass';
protected $_tableClass = "Am_Protect_Table";
/** @var Am_Protect_Table */
public $_table = null;
/** @var DbSimple_Mysql */
public $_db;
/** @var IntegrationTable */
public $_integrationTable;
/** @var UserTable */
public $_userTable;
/** @var Am_Protect_SessionTable */
public $_sessionTable;
/** @var string table name without prefix */
protected $guessTablePattern = null;
/** @var array of several fieldnames in the table */
protected $guessFieldsPattern = array(
);
protected $groupMode = self::GROUP_NONE;
const GROUP_NONE = 0;
const GROUP_SINGLE = 1;
const GROUP_MULTI = 2;
public $sqlDebug = false;
protected $skipAfterLogin = false;
protected $skipCheckUniqLogin = false;
/** @var array group => priority, must be built on first access */
protected $_priority = null;
public function __construct(Am_Di $di, array $config)
{
parent::__construct($di, $config);
if ($this->_tableClass === null)
$this->_tableClass = get_class($this) . "_Table";
}
/** @return IntegrationTable */
public function getIntegrationTable()
{
if (!$this->_integrationTable)
$this->_integrationTable = $this->getDi()->integrationTable;
return $this->_integrationTable;
}
/** @return UserTable */
public function getUserTable()
{
if (!$this->_userTable)
$this->_userTable = $this->getDi()->userTable;
return $this->_userTable;
}
public function _getTableClass()
{
return $this->_tableClass;
}
function onSetupForms(Am_Event_SetupForms $event)
{
$f = new Am_Form_Setup_ProtectDatabased($this);
if($plugin_readme = $this->getReadme())
{
$plugin_readme = str_replace(
array('%root_url%', '%root_surl%', '%root_dir%'),
array($this->getDi()->rurl(''), $this->getDi()->surl(''),
$this->getDi()->root_dir),
$plugin_readme);
$f->addEpilog('
');
}
$event->addForm($f);
// addConfigItems will be called when necessary
}
function afterAddConfigItems(Am_Form_Setup_ProtectDatabased $form)
{
}
function guessDbPrefix(DbSimple_Interface $db, $database=null, $prefix=null)
{
$res = array();
foreach ($dbs = $db->selectCol("SHOW DATABASES") as $dbname)
{
try {
$tables = $db->selectCol("SHOW TABLES FROM ?# LIKE '%$this->guessTablePattern'", $dbname);
} catch (Am_Exception_Db $e) {
continue;
}
if (is_array($tables))
foreach ($tables as $t)
{
// check fields here
$info = $db->select("SHOW COLUMNS FROM `$dbname`.$t");
$infostr = "";
if (is_array($info))
foreach ($info as $k => $v)
$infostr .= join(';', $v) . "\n";
$wrong = 0;
foreach ($this->guessFieldsPattern as $pat)
{
if (!preg_match('|^' . $pat . '|m', $infostr))
$wrong++;
}
if ($wrong)
continue;
$res[] = $dbname . '.' . substr($t, 0, -strlen($this->guessTablePattern));
}
}
return $res;
}
/** @return bool true if plugin is able to create customers without signup */
public function canAutoCreate()
{
return false;
}
/** @return bool true if plugin is able to create customers without signup using current user's groups from integrated script */
public function canAutoCreateFromGroups()
{
return false;
}
function configCheckDbSettings(array $config)
{
$class = get_class($this);
$np = new $class($this->getDi(), $config);
try
{
$db = $np->getDb();
} catch (Am_Exception_PluginDb $e)
{
return ___('Cannot connect to database. Check hostname, username and password settings') . ' ' . $e->getMessage();
}
try
{
$table = $this->guessTablePattern;
$fields = join(',', $this->guessFieldsPattern);
$db->query("SELECT $fields FROM ?_{$table} LIMIT 1");
} catch (Am_Exception_PluginDb $e)
{
$defaultDb = $this->getDi()->getParameter('db');
$defaultDb = $defaultDb['mysql']['db'];
$dbname = $config['db'] ? $config['db'] : $defaultDb;
$prefix = $config['prefix'];
return ___('Database name or prefix is wrong - could not find table [%s] with fields [%s] inside database [%s]:', $prefix.$table, $fields, $dbname) . ' ' .
$e->getMessage();
}
return $np->configDbChecksAdditional($db);
}
function configDbChecksAdditional()
{
}
function dbErrorHandler($message, $info)
{
$class = 'Am_Exception_PluginDb';
$e = new $class("$message({$info['code']}) in query: {$info['query']}", @$info['code']);
throw $e;
}
function getConfigPageId()
{
return get_first($this->defaultTitle, $this->getId(true));
}
public function isConfigured()
{
return $this->getConfig('db') || $this->getConfig('prefix');
}
function getGroupMode()
{
return $this->groupMode;
}
function getAdminGroups()
{
return array_filter(array_map('trim', $this->getConfig('admin_groups', array())));
}
function getBannedGroups()
{
return array_filter(array_map('trim', $this->getConfig('banned_groups', array())));
}
function getLockedGroup()
{
return $this->getConfig('locked_group');
}
/**
* Return plugin groups that must be set according to
* aMember user subscriptions and aMember configuration
* @param User $user if null, defaul group returned
* @return array of int third-party group ids, or int for single-group, or true/false for GROUP_NONE
*/
function calculateGroups(User $user = null, $addDefault = false)
{
// we have got no user so search does not make sense, return default group if configured
$groups = array();
if ($user && $user->pk())
{
foreach ($this->getIntegrationTable()->getAllowedResources($user, $this->getId()) as $integration)
{
$vars = unserialize($integration->vars);
$groups[] = $vars;
}
if ($this->groupMode == self::GROUP_NONE)
return (bool) $groups;
} else
{
if ($this->groupMode == self::GROUP_NONE)
return false;
}
$groups = $this->chooseGroups($groups, $user);
if ($addDefault && !$groups)
{
$ret = $this->getConfig('default_group', null);
if (($this->groupMode == self::GROUP_MULTI) && (!is_array($ret)))
$ret = array($ret);
return $ret;
} else
return $groups;
}
/** Compare groups based on priority list */
function _compareGroups($a, $b)
{
$pa = array_key_exists($a, $this->_priority) ? $this->_priority[$a] : 100001;
$pb = array_key_exists($b, $this->_priority) ? $this->_priority[$b] : 100000;
return $pa - $pb;
}
/**
*
* @param type $groups
* @param User|Am_record $user
* @return type
*/
function addSuperGroups($groups, $user=null){
$super = $this->getConfig('super_groups');
if(!$super||!$user)
return $groups;
if($user instanceof User)
$record = $this->getTable()->findByAmember($user);
else
$record = $user;
if(!$record)
return $groups;
$old_groups = (array) $this->getTable()->getGroups($record);
if(!$old_groups)
return $groups;
$intact = array_intersect($super, $old_groups);
if(!$intact)
return $groups;
return array_unique(array_filter(array_merge((array)$groups, $intact)));
}
/**
*
* @param type $groups array of configs from ?_integration table
* @return array of int|int return sorted array or most suitable single int
*/
function chooseGroups($groups, User $user = null)
{
$ret = array();
foreach ($groups as $config)
$ret[] = $config['gr'];
if($user && $user->isLocked() && ($locked = $this->getLockedGroup()))
return ($this->groupMode == self::GROUP_SINGLE ? $locked : array($locked));
$ret = $this->addSuperGroups($ret, $user);
if ($this->_priority === null)
$this->_initPriority();
usort($ret, array($this, '_compareGroups'));
if ($this->groupMode == self::GROUP_SINGLE)
return $ret ? array_shift($ret) : null;
else
return $ret;
}
protected function _initPriority()
{
$this->_priority = array_flip($this->getConfig('priority', array()));
}
function getDb()
{
if (!$this->_db)
{
$dsn = array();
$dsn['scheme'] = 'mysql';
$dsn['path'] = $this->getConfig('db');
if ($this->getConfig('other_db') == "1")
{
$dsn = array_merge($dsn, array(
'host' => $this->getConfig('host'),
'user' => $this->getConfig('user'),
'pass' => $this->getConfig('pass'),
));
} else
{
$appOptions = $this->getDi()->getParameters();
$dbConfig = $appOptions['db']['mysql'];
$dsn = array_merge($dsn, array(
'host' => $dbConfig['host'],
'user' => $dbConfig['user'],
'pass' => $dbConfig['pass']
));
if(isset($dbConfig['port']) && $dbConfig['port'])
$dsn['port'] = $dbConfig['port'];
}
if($dsn['host'] && (strpos($dsn['host'], ':') !== false) && preg_match('/\:(\d+)$/',$dsn['host']))
list($dsn['host'], $dsn['port']) = explode(':', $dsn['host']);
$this->_db = Am_Db::connect($dsn, true);
$this->_db->setErrorHandler(array($this, 'dbErrorHandler'));
$this->_db->setIdentPrefix($this->getConfig('prefix'));
$this->_db->query("USE ?#", $dsn['path']);
$this->_db->query("SET NAMES utf8");
$this->_db->query("SET SESSION sql_mode=''");
}
if ($this->sqlDebug)
{
if (!empty($this->getDi()->db->_logger))
$this->_db->setLogger($this->getDi()->db->_logger);
}
return $this->_db;
}
function _setDb($db) { $this->_db = $db; }
/** lazy-load the table
* @return Am_Protect_Table */
function getTable()
{
if (!$this->_table)
$this->_table = $this->createTable()->setDi($this->getDi());
return $this->_table;
}
/**
* create table
* you can (in fact you must) override this function to fine-tune
* @return Am_Protect_Table
*/
function createTable()
{
return new $this->_tableClass($this, $this->getDb());
}
/**
* create session table if applicable
* @return Am_Protect_SingleLogin|null
*/
function createSessionTable()
{
return null;
}
/**
* get session table if applicable
* @return Am_Protect_SingleLogin|null
*/
function getSessionTable()
{
if(!$this->_sessionTable)
$this->_sessionTable = $this->createSessionTable();
if(!is_null($this->_sessionTable)) $this->_sessionTable->setDi($this->getDi());
return $this->_sessionTable;
}
/**
* @param Am_Event_SubscriptionChanged $event
* @param User $oldUser presents if called from onUserLoginChanged
*/
function onSubscriptionChanged(Am_Event_SubscriptionChanged $event, User $oldUser = null)
{
if ($oldUser === null) $oldUser = $event->getUser();
$user = $event->getUser();
$found = $this->getTable()->findByAmember($oldUser);
if ($found)
{
if($this->canUpdate($found)){
$this->getTable()->updateFromAmember($found, $user, $this->calculateGroups($user, true));
$pass = $this->findPassword($user, true);
if ($pass) $this->getTable()->updatePassword($found, $pass);
}
} elseif ($groups = $this->calculateGroups($user, false))
{ // we will only insert record if it makes sense - there are groups
$this->getTable()->insertFromAmember($user, $this->findPassword($user, true), $groups);
}
}
function onUserAfterUpdate(Am_Event_UserAfterUpdate $event)
{
$e = new Am_Event_SubscriptionChanged($event->getUser(), array(), array());
return $this->onSubscriptionChanged($e, $event->getOldUser());
}
function onUserAfterDelete(Am_Event_UserAfterDelete $event)
{
$found = $this->getTable()->findByAmember($event->getUser());
if (!$found || !$this->canRemove($found))
return;
if ($this->getConfig('remove_users'))
{
$this->_table->removeRecord($found);
} elseif (!$this->isBanned($found)) {
$this->_table->disableRecord($found, $this->calculateGroups(null, true));
}
}
function onSetPassword(Am_Event_SetPassword $event)
{
$user = $event->getUser();
$found = $this->getTable()->findByAmember($user);
if ($found && $this->canUpdate($found))
{
$this->_table->updatePassword($found, $event->getSaved($this->getPasswordFormat()));
$user->data()->set(self::USER_NEED_SETPASS, null)->update();
}
}
/**
* Return Object that will handle single login. If SessionTable is not created return $this
* @return Am_Protect_SingleLogin
*/
function getSingleLoginObject(){
return is_null($sessionTable = $this->getSessionTable()) ? $this : $sessionTable;
}
function onAuthCheckLoggedIn(Am_Event_AuthCheckLoggedIn $event)
{
$record = $this->getSingleLoginObject()->getLoggedInRecord();
if (!$record || !$this->canLogin($record))
return;
$user = $this->getTable()->findAmember($record);
if (!$user)
return;
if($user->isLocked())
return;
if ($this->getTable()->checkPassword($record, $user))
{
$event->setSuccessAndStop($user);
$this->skipAfterLogin = true;
}
}
function onAuthAfterLogin(Am_Event_AuthAfterLogin $event)
{
if ($this->skipAfterLogin)
return;
if($event->getUser()->isLocked())
return;
// there we handled situation when user was added without knowledge of password
// @todo implement situation when we have found there is not password
// in related user record during login
if ($event->getPassword() && $event->getUser()->data()->get(self::USER_NEED_SETPASS))
{
$user = $event->getUser();
$user->setPass($event->getPassword());
$user->save();
$user->data()->set(self::USER_NEED_SETPASS, null)->update();
}
$record = $this->getTable()->findByAmember($event->getUser());
if (!$record || !$this->canLogin($record))
return;
if (!$this->getTable()->checkPassword($record, $event->getUser(), $event->getPassword()))
return;
$this->getSingleLoginObject()->loginUser($record, $event->getPassword());
}
function onAuthAfterLogout(Am_Event_AuthAfterLogout $event)
{
$this->getSingleLoginObject()->logoutUser($event->getUser());
}
function onAuthSessionRefresh(Am_Event_AuthSessionRefresh $event){
$afterLoginEvent = new Am_Event_AuthAfterLogin($event->getUser());
$this->onAuthAfterLogin($afterLoginEvent);
}
function onCheckUniqLogin(Am_Event_CheckUniqLogin $event)
{
$table = $this->getTable();
if ($table->getIdType() != Am_Protect_Table::BY_LOGIN) return;
if ($table->findFirstByLogin($event->getLogin()))
$event->setFailureAndStop();
}
function onCheckUniqEmail(Am_Event_CheckUniqEmail $event)
{
$table = $this->getTable();
if ($table->getIdType() != Am_Protect_Table::BY_EMAIL) return;
if ($event->getUserId()) {
$user = $this->getDi()->userTable->load($event->getUserId());
} else {
$user = $this->getDi()->userRecord;
$user->email = $event->getEmail();
}
$record = $table->findByAmember($user);
if ($record) {
$user = $table->findAmember($record);
if ($user && $user->pk()!=$event->getUserId())
$event->setFailureAndStop();
}
}
public function onAuthTryLogin(Am_Event_AuthTryLogin $event)
{
if (!$this->getConfig('auto_create'))
return;
//in case several plugins are using auto_create option
if($event->isCreated())
return;
$login = $event->getLogin();
$isEmail = preg_match('/^.+@.+\..+$/', $login);
$found = !$isEmail ?
$this->getTable()->findFirstByLogin($login) :
$this->getTable()->findFirstByEmail($login);
/* @var $found Am_Record */
if (!$found || !$this->canLogin($found))
return;
// now create fake user for checkPassword
$user = $this->getDi()->userTable->createRecord();
if ($isEmail)
$user->email = $login; else
$user->login = $login;
$user->toggleFrozen(true);
if (!$this->getTable()->checkPassword($found, $user, $event->getPassword()))
return;
// all checked, now create user in aMember
$user = $this->getDi()->userRecord;
$this->getTable()->createAmember($user, $found);
if (!$user->login)
{
$this->skipCheckUniqLogin = true;
$user->generateLogin();
$this->skipCheckUniqLogin = false;
}
$user->setPass($event->getPassword());
$user->insert();
if ($p_b = $this->getConfig('auto_create_billing_plan'))
{
try{
if($p_b == -1)
{
if($this->canAutoCreateFromGroups())
{
$arr = array();
foreach($this->getConfig() as $k => $v)
if(preg_match("/^auto_create_bpgroups_(.*)/",$k,$m))
$arr[$m[1]] = $v;
$arr_keys = array_keys($arr);
foreach($this->getTable()->getGroups($found) as $gr_id)
if(in_array($gr_id, $arr_keys))
$access = $this->addAccessAfterCreate($arr[$gr_id], $user);
}
}
else
{
$access = $this->addAccessAfterCreate($p_b, $user);
}
// send 1-day autoresponders if supposed to
$this->getDi()->emailTemplateTable->sendZeroAutoresponders($user, $access);
}
catch (Exception $e)
{
//just log
$this->getDi()->errorLogTable->logException($e);
};
}
$event->setCreated($user);
}
function addAccessAfterCreate($p_b,$user)
{
list($product_id,$billing_plan_id) = explode('_', $p_b);
$invoice = $this->getDi()->invoiceRecord;
$invoice->setUser($user);
$product = $this->getDi()->productTable->load($product_id);
$product->setBillingPlan($billing_plan_id);
$invoice->add($product);
$begin_date = $product->calculateStartDate($this->getDi()->sqlDate, $invoice);
$p = new Am_Period($product->getBillingPlan()->first_period);
$expire_date = $p->addTo($begin_date);
$access = $this->getDi()->accessRecord;
$access->begin_date = $begin_date;
$access->expire_date = $expire_date;
$access->user_id = $user->user_id;
$access->product_id = $product_id;
$access->comment = ___('Added during user creation by demand from plugin [%s]', $this->getId());
return $access->insert();
}
function getLoggedInRecord()
{
return null;
}
function loginUser(Am_Record $record, $password)
{
return false;
}
function logoutUser(User $user)
{
}
/**
* If there is a saved password, return it
* If user has plaintext pass set, encrypt it, save and return
* if second paramter is true, it will return dummy record
* and mark user for password update on next login
* @return SavedPass|null
*/
public function findPassword(User $user, $returnNoPass = false)
{
// try find password
$saved = $this->getDi()->savedPassTable->findSaved($user, $this->getPasswordFormat());
if ($saved)
return $saved;
/// else encrypt it again
$pass = $user->getPlaintextPass();
if ($pass)
{
$saved = $this->getDi()->savedPassRecord;
$saved->user_id = $user->user_id;
$saved->format = $this->getPasswordFormat();
$saved->salt = null;
$saved->pass = $this->cryptPassword($pass, $saved->salt, $user);
$saved->insert();
return $saved;
}
// nothing
if ($returnNoPass)
{
$pass = $this->getDi()->savedPassRecord;
$pass->pass = '-nopass-' . uniqid();
$pass->salt = 'NNN';
if ($user->isLoaded())
$user->data()->set(self::USER_NEED_SETPASS, 1)->update();
return $pass;
}
}
public function isAdmin(Am_Record $record)
{
if ($this->getGroupMode() == Am_Protect_Databased::GROUP_NONE)
return false;
return (bool)array_intersect(
(array)$this->_table->getGroups($record),
$this->getAdminGroups()
);
}
public function isBanned(Am_Record $record)
{
if ($this->getGroupMode() == Am_Protect_Databased::GROUP_NONE)
return false;
return (bool)array_intersect(
(array)$this->_table->getGroups($record),
$this->getBannedGroups()
);
}
/**
* Return true if we can edit this record, and false if we can not -
* for example if it is admin record or a banned record
* @return bool
*/
function canUpdate(Am_Record $record)
{
return !$this->isAdmin($record) && !$this->isBanned($record);
}
function canRemove(Am_Record $record)
{
return !$this->isAdmin($record);
}
function canLogin(Am_Record $record)
{
return !$this->isAdmin($record) && !$this->isBanned($record);
}
function deinstall()
{
}
/**
* @see getAvailableUserGroupsSql
* @see getManagedUserGroups
* @return array Am_Protect_Databased_Usergroup
*/
function getAvailableUserGroups()
{
$ret = array();
if ($this->groupMode == self::GROUP_NONE) {
$g = new Am_Protect_Databased_Usergroup(array(
'id'=>1,
'title'=>'Registered',
'isAdmin'=>0,
'isBanned'=>0
));
$ret[$g->getId()] = $g;
return $ret;
}
foreach ($this->getDb()->select($this->getAvailableUserGroupsSql()) as $r)
{
try {
$g = new Am_Protect_Databased_Usergroup($r);
} catch (Am_Exception_PluginDb $e){ // to log errors with groups in integrated script
$this->getDi()->errorLogTable->logException($e);
throw $e;
}
$ret[$g->getId()] = $g;
}
return $ret;
}
function getAvailableUserGroupsSql()
{
throw new Am_Exception_NotImplemented("getAvailableUserGroupsSql or getAvailableUserGroups must be redefined");
}
/**
* return only list of user groups the script must manage:
* excluding for example Banned and Admin user groups
*/
function getManagedUserGroups()
{
$groups = $this->getAvailableUserGroups();
foreach ($groups as $k => $group)
if (in_array($group->getId(), $this->getConfig('admin_groups', array())) || in_array($group->getId(), $this->getConfig('banned_groups', array())))
unset($groups[$k]);
return $groups;
}
public function getIntegrationFormElements(HTML_QuickForm2_Container $container)
{
$groups = $this->getManagedUserGroups();
$options = array();
foreach ($groups as $g)
$options[$g->getId()] = $g->getTitle();
$container
->addSelect('gr', array(), array('options' => $options))
->setLabel($this->getTitle() . ' usergroup');
}
public function getIntegrationSettingDescription(array $config)
{
$groups = array_combine((array) $config['gr'], (array) $config['gr']);
try
{
foreach ($this->getAvailableUserGroups() as $g)
{
$id = $g->getId();
if (!empty($groups[$id]))
$groups[$id] = '[' . $g->getTitle() . ']';
}
} catch (Am_Exception_PluginDb $e)
{
}
return ___('Assign Group') . ' ' . implode(",", array_values($groups));
}
public function onRebuild(Am_Event_Rebuild $event)
{
$batch = new Am_BatchProcessor(array($this, 'batchProcess'));
$context = $event->getDoneString();
$this->_rebuildName = $this->getId();
$this->_sessionId = Zend_Session::getId();
if ($batch->run($context))
{
$event->setDone();
$this->getDi()->storeRebuild->deleteByNameAndSession($this->_rebuildName, $this->_sessionId);
} else
{
$event->setDoneString($context);
}
}
public function batchProcess(&$context, Am_BatchProcessor $batch)
{
@list($step, $start) = explode('-', $context);
$pageCount = 30;
switch ($step)
{
case 0:
$q = new Am_Query($this->getTable());
$count = 0;
$updated = array();
foreach ($q->selectPageRecords($start / $pageCount, $pageCount) as $r)
{
$count++;
if (!$this->canUpdate($r))
continue;
/* @var $r Am_Record */
$user = $this->_table->findAmember($r);
if (!$user)
{
// no such records in aMember, disable user record ?
$this->_table->disableRecord($r, $this->calculateGroups(null, true));
} else
{
$updated[] = $user->user_id;
$this->getTable()->updateFromAmember($r, $user, $this->calculateGroups($user, true));
$pass = $this->getDi()->savedPassTable->findSaved($user, $this->getPasswordFormat());
if ($pass) $this->getTable()->updatePassword($r, $pass);
}
}
if (!$count)
{
$step++;
$context = "$step-0";
}else{
$store = array();
foreach ($updated as $v)
$store[] = $v;
$this->getDi()->storeRebuild->setArray($this->_rebuildName, $this->_sessionId, $store, '+3 hour');
$start += $count;
$context = "$step-$start";
}
break;
case 1:
/// now select aMember users not exists in plugin db
$count = 0;
$records = array();
$db = $this->getDi()->db;
$r = $db->queryResultOnly("SELECT t.* from ?_user t left join ?_store_rebuild s on s.user_id = t.user_id and s.rebuild_name = ? and s.session_id = ?
WHERE s.user_id is null LIMIT ?d , ?d", $this->_rebuildName, $this->_sessionId, $start , $pageCount);
while ($row = $db->fetchRow($r))
{
$records[] = $this->getDi()->userTable->createRecord($row);
}
foreach ($records as $user)
{
$count++;
/* @var $user User */
$this->onSubscriptionChanged(new Am_Event_SubscriptionChanged($user, array(), array()));
}
if (!$count)
{
$context = null;
return true;
}
$start += $count;
$context = "$step-$start";
break;
default:
throw new Am_Exception_InputError(___('Wrong step'));
}
}
}
class Am_Protect_Databased_Usergroup
{
protected $id;
protected $title;
protected $isAdmin = false;
protected $isBanned = false;
function __construct($row)
{
$this->id = $row['id'];
$this->title = $row['title'];
$this->isAdmin = (bool) @$row['is_admin'];
$this->isBanned = (bool) @$row['is_banned'];
if (!$this->id)
throw new Am_Exception_PluginDb("Wrong group record passed - id is empty");
if (empty($this->title))
throw new Am_Exception_PluginDb("Wrong group #{$this->id} record passed - title is empty");
}
function isBanned()
{
return $this->isBanned;
}
function isAdmin()
{
return $this->isAdmin;
}
function getId()
{
return $this->id;
}
function getTitle()
{
return $this->title;
}
} Table.php 0000644 00000037771 15210162164 0006321 0 ustar 00 plugin-field
* mapping MUST return at least one mapping for FIELD_EMAIL, FIELD_LOGIN and FIELD_PASS
* Can also accept callbacks and constants as amember-user-field
* constants should have : as first char, functions @, object methods should be passed as array()
* Pass $user object to callbacks.
* examples:
* array(':value', 'field') - field will be set to value
* array('!value', 'field') - field will be set to eval(value)
* array('@func', 'field') - func($user) will be executed, value returned by function will be assigned to field
* array(array($this, "func"), 'field') - $this->func($user) will be executed, value returned by function will be assigned to field
*
* */
protected $_fieldsMapping = array();
/** @var Am_Protect_Databased */
protected $_plugin;
protected $_groupMode = null;
// you do not need to touch these values - it is handled automatically
// based on @see $_fieldsMapping in constructor
public $_passField;
public $_saltField;
public $_loginField;
public $_emailField;
/** it will be automatically changed to e-mail if there is no login field in mapping */
public $_idType = self::BY_LOGIN;
/** Config of group table where groups are saved as separate records
* a sample for drupal
* array(self::GROUP_TABLE => '?_users_roles', self::GROUP_UID => 'uid', self::GROUP_GID => 'rid')
*/
protected $_groupTableConfig = array();
public function __construct(Am_Protect_Databased $plugin, $db = null, $table = null, $recordClass = null, $key = null)
{
$this->_plugin = $plugin;
$this->_groupMode = $plugin->getGroupMode();
parent::__construct($db, $table, $recordClass, $key);
if ($this->_fieldsMapping)
$this->setFieldsMapping($this->_fieldsMapping);
}
public function getIdType()
{
return $this->_idType;
}
function setFieldsMapping(array $mapping)
{
$this->_fieldsMapping = $mapping;
foreach ($this->_fieldsMapping as $a)
{
list($k, $v) = $a;
if (!$this->_loginField && ($k == self::FIELD_LOGIN))
$this->_loginField = $v;
if (!$this->_emailField && ($k == self::FIELD_EMAIL))
$this->_emailField = $v;
if (!$this->_passField && ($k == self::FIELD_PASS))
$this->_passField = $v;
if (!$this->_saltField && ($k == self::FIELD_SALT))
$this->_saltField = $v;
}
if (!$this->_loginField && $this->_emailField)
$this->_idType = self::BY_EMAIL;
}
function setGroupsTableConfig(array $config)
{
$this->_groupTableConfig = $config;
}
function getFieldsMapping()
{
return $this->_fieldsMapping;
}
/** @return Am_Protect_Databased */
public function getPlugin()
{
return $this->_plugin;
}
public function findFirstByLogin($login)
{
$ret = $this->findFirstBy(array($this->_loginField => $login));
return $ret;
}
public function findFirstByEmail($email)
{
$ret = $this->findFirstBy(array($this->_emailField => $email));
return $ret;
}
/** @return Am_Record|null */
public function findByAmember(User $user)
{
return $this->_idType == self::BY_EMAIL ?
$this->findFirstByEmail($user->email) :
$this->findFirstByLogin($user->login);
}
/** Insert record based on aMember records
* automatically fills fields from the @see getFieldsMapping()
* @return Am_Record
*/
function createFromAmember(User $user, SavedPass $pass, $groups)
{
$record = $this->createRecord();
foreach ($this->_fieldsMapping as $a)
{
list($k, $v) = $a;
switch ($k)
{
case self::FIELD_PASS:
$record->set($v, $pass->pass);
break;
case self::FIELD_SALT:
$record->set($v, $pass->salt);
break;
case self::FIELD_ADDED_SQL:
$record->set($v, $user->added);
break;
case self::FIELD_ADDED_STAMP:
$record->set($v, strtotime($user->added));
break;
case self::FIELD_NAME:
$record->set($v, $user->getName());
break;
default:
if (is_callable($k))
$val = call_user_func($k, $user, $record, $this);
elseif ($k[0] == ':')
$val = substr($k, 1);
elseif ($k[0] == '!')
$val = eval(substr($k, 1));
elseif ($k[0] != '_')
$val = $user->get($k);
else
break;
$record->set($v, is_null($val) ? "" : $val);
}
}
return $record;
}
/** Update record based on updated aMember record
* automatically fills fields from the @see getFieldsMapping()
*/
function refreshFromAmember(Am_Record $record, User $user, $groups)
{
foreach ($this->getFieldsMapping() as $a)
{
list($k, $v) = $a;
// Do not update field if it is primary key for record.
// Some plugins like drupal will set primary key on their own.
if($v == $this->_key) continue;
switch ($k)
{
case self::FIELD_PASS:
case self::FIELD_SALT:
case self::FIELD_ADDED_SQL:
case self::FIELD_ADDED_STAMP:
break;
case self::FIELD_NAME:
$record->set($v, $user->getName());
break;
case self::FIELD_LOGIN:
case self::FIELD_EMAIL:
$record->set($v, $user->get($k));
break;
default:
if (is_callable($k))
$val = call_user_func($k, $user, $record, $this);
elseif ($k[0] == ':')
break;
elseif ($k[0] == '!')
$val = eval(substr($k, 1));
elseif ($k[0] != '_')
$val = $user->get($k);
else
break;
$record->set($v, is_null($val) ? "" : $val);
}
}
}
/**
* Insert record to plugin based on amember record
* @param User $user
* @param SavedPass $pass
* @param int|array|bool $groups - type depends on plugin groupsType
* @return Am_Record
*/
function insertFromAmember(User $user, SavedPass $pass, $groups)
{
$record = $this->createFromAmember($user, $pass, $groups);
$record->insert();
$this->setGroups($record, $groups);
return $record;
}
public function updateFromAmember(Am_Record $record, User $user, $groups)
{
$this->refreshFromAmember($record, $user, $groups);
$record->update();
$this->setGroups($record, $groups);
}
public function delete($key)
{
parent::delete($key);
if ($this->_groupTableConfig)
{
$table = $this->_groupTableConfig[Am_Protect_Table::GROUP_TABLE];
$uidField = $this->_groupTableConfig[Am_Protect_Table::GROUP_UID];
$this->_db->query("DELETE FROM {$table} WHERE ?#=?", $uidField, $key);
}
}
public function updatePassword(Am_Record $record, SavedPass $saved)
{
if (!$this->_passField)
throw new Am_Exception_NotImplemented (get_class($this) . "->updatePassword() is not implemented");
$arr = array( $this->_passField => $saved->pass );
if ($this->_saltField)
$arr[ $this->_saltField ] = $saved->salt;
$record->updateQuick($arr);
}
public function removeRecord(Am_Record $record)
{
$record->delete();
}
/** Set record to "default" or "disabled' state depending on config
* it is exists when no related aMember record is exist in database
*/
public function disableRecord(Am_Record $record, $groups)
{
if($this->getPlugin()->getConfig('super_groups'))
{
$groups = $this->getPlugin()->addSuperGroups($groups, $record);
}
$this->setGroups($record, $groups);
}
/** Find related amember user based on current record login
* Do not check password or groups here
* @return User
*/
function findAmember(Am_Record $record)
{
return $this->_idType == Am_Protect_Table::BY_EMAIL ?
$this->getDi()->userTable->findFirstByEmail($record->get($this->_emailField)) :
$this->getDi()->userTable->findFirstByLogin($record->get($this->_loginField));
}
/** Create amember record based on the current plugin record
* automatically fills fields from the @see getFieldsMapping()
* @return User returns not-inserted user
*/
function createAmember(User $user, Am_Record $record)
{
foreach ($this->getFieldsMapping() as $a)
{
list($k, $v) = $a;
if (is_callable($k) || ($k[0] == ':') || ($k[0] == '!') || ($k[0] == '_') || $k == self::FIELD_NAME)
continue;
if (($vv = $record->get($v)) && !$user->get($k))
$user->set($k, $vv);
}
$user->data()->set("created-by-plugin", $this->_plugin->getId());
}
/**
* Update amember record based on the current plugin record
*/
function updateAmember(User $user)
{
}
/**
* Check if plaintextPass or saved password of amember user matches password
* of current record
* @param User $user
* @return bool true if password matches
*/
function checkPassword(Am_Record $record, User $user, $plaintextPass = null)
{
if (!$this->_passField)
throw new Am_Exception_NotImplemented(get_class($this) . "->checkPassword() is not implemented");
if ($plaintextPass)
{
$salt = $this->_saltField ? $record->get($this->_saltField) : $record->get($this->_passField);
return $this->_plugin->cryptPassword($plaintextPass, $salt, $user) === $record->get($this->_passField);
} else {
$saved = $this->_plugin->findPassword($user);
if (!$saved) return false;
if ($record->get($this->_passField) != $saved->pass) return false;
if ($this->_saltField && ($record->get($this->_saltField) != $saved->salt)) return false;
return true;
}
}
function getGroups(Am_Record $record)
{
switch ($this->_groupMode)
{
case Am_Protect_Databased::GROUP_NONE: return null;
case Am_Protect_Databased::GROUP_MULTI:
if ($this->_groupTableConfig)
{
$table = $this->_groupTableConfig[Am_Protect_Table::GROUP_TABLE];
$uidField = $this->_groupTableConfig[Am_Protect_Table::GROUP_UID];
$gidField = $this->_groupTableConfig[Am_Protect_Table::GROUP_GID];
return $this->_db->selectCol("SELECT $gidField FROM $table WHERE $uidField=?", $record->pk());
}
break;
case Am_Protect_Databased::GROUP_SINGLE:
/// may be a field set
$field = null;
foreach ($this->_fieldsMapping as $a)
{
list($k, $v) = $a;
if ($k == Am_Protect_Table::FIELD_GROUP_ID)
{
$field = $v;
break;
}
}
if ($field)
{
$v = $record->get($field);
return $v;
}
break;
}
throw new Am_Exception_NotImplemented(get_class($this) . "->getGroups() is not implemented");
}
function setGroups(Am_Record $record, $groups)
{
switch ($this->_groupMode)
{
case Am_Protect_Databased::GROUP_NONE: return null;
case Am_Protect_Databased::GROUP_MULTI:
if ($this->_groupTableConfig)
{
$this->_setTableGroups($record, $groups);
return $this;
}
break;
case Am_Protect_Databased::GROUP_SINGLE:
foreach ($this->getFieldsMapping() as $a)
{
list($k, $v) = $a;
if ($k == Am_Protect_Table::FIELD_GROUP_ID)
{
$record->updateQuick($v, $groups);
return $this;
}
}
break;
}
throw new Am_Exception_NotImplemented(get_class($this) . "->setGroups() is not implemented");
}
/**
* For usage within $this->setGroups() when $_groupTableConfig defined
* @param array $groups - just ids to set
*/
protected function _setTableGroups(Am_Record $record, $groups)
{
$table = $this->_groupTableConfig[Am_Protect_Table::GROUP_TABLE];
$uidField = $this->_groupTableConfig[Am_Protect_Table::GROUP_UID];
$gidField = $this->_groupTableConfig[Am_Protect_Table::GROUP_GID];
$fields = empty($this->_groupTableConfig[Am_Protect_Table::GROUP_ADDITIONAL_FIELDS]) ?
array() : $this->_groupTableConfig[Am_Protect_Table::GROUP_ADDITIONAL_FIELDS];
// update groups
$oldGroups = $this->getGroups($record);
$added = array_unique(array_diff($groups, $oldGroups));
$deleted = array_unique(array_diff($oldGroups, $groups));
if ($deleted)
$this->_db->query("DELETE FROM $table WHERE $uidField=? AND $gidField IN (?a)", $record->pk(), $deleted);
$sql = array();
$fk = $fv = '';
if(!empty($fields)){
$field_keys = array_keys($fields);
$field_values = array_values($fields);
array_walk($field_values, function(&$value, $key, $db) {$value = $db->escape($value);}, $this->_db);
if(!empty($field_keys)){
$fk = ", ".join(", ", $field_keys);
$fv = ", ".join(", ", $field_values);
}
}
foreach ($added as $group)
if(!is_null($group)) $sql[] = "('$group', " . $record->pk() . $fv.")";
if ($sql)
$this->_db->query("INSERT INTO $table ($gidField, $uidField$fk) VALUES " . join(",", $sql));
}
}
Abstract.php 0000644 00000003023 15210162164 0007014 0 ustar 00 $v) $ret[] = "$k: $v";
return join('; ', $ret);
}
/**
* @return string|null - null if no password necessary
* @see SavedPass constants
*/
abstract public function getPasswordFormat();
/**
* Crypt password for the plugin. Default implementation calls
* SavedPass::crypt() method according to @see getPasswordFormat()
* @see SavedPass::crypt
* @return string
* @param type $password
* @param type $salt
* @param User $user
*/
public function cryptPassword($pass, & $salt = null, User $user = null)
{
if ($this->getPasswordFormat() !== null)
return $this->getDi()->savedPassTable->crypt($pass, $this->getPasswordFormat(), $salt, $user);
}
}
SessionTable.php 0000644 00000024655 15210162164 0007662 0 ustar 00 value, 'path' => value,
* 'expires' => value, 'secure'=>value,
* 'exact_domain' =>true|false)
* All parameters to be passed to Am_Cookie::set();
*/
const COOKIE_PARAMS = '_cookie_params';
const COOKIE_PARAM_DOMAIN = 'domain';
const COOKIE_PARAM_PATH = 'path';
const COOKIE_PARAM_EXPIRES = 'expires';
const COOKIE_PARAM_EXACT_DOMAIN = 'exact_domain';
const COOKIE_PARAM_SECORE = 'secure';
/* Additional fields that should be set in database when session created: array('field_name'=>$field_value or callback) */
const FIELDS_ADDITIONAL = '_additional';
/* Additional fields that should be set in database when session created: array('cookie_name' => $value or callback)) */
const COOKIES_ADDITIONAL = '_cookies_additional';
protected $_recordClass = 'Am_Protect_SessionTable_Record';
protected $_plugin = null;
protected $_sessionTableConfig = null;
protected $_cookie = null;
protected $_sid = null;
protected $_uid = null;
protected $_ip = null;
protected $_ua = null;
protected $_created = null;
protected $_changed = null;
protected $_cookie_params = null;
protected $_additional = null;
protected $_cookies_additional = null;
protected $_keyIsInt = false;
protected $_defaultCookieParams = array(
'expires' => 0,
'path' => '/',
'domain' => null,
'secure' => false,
'exact_domain' => false
);
function __construct(Am_Protect_Databased $plugin, $db = null, $table = null, $key = null, $recordClass = null)
{
$this->_plugin = $plugin;
parent::__construct($db, $table, $key, $recordClass);
}
/**
* Define configuration for Session table.
* @param Array $config - array of configuration values.
* Example:
* array(
* Am_Protect_SessionTable::FIELD_UID => 'uid',
* Am_Protect_SessionTable::SESSION_COOKIE => 'cookie_name'
* );
*
*
*/
function setTableConfig(Array $config)
{
$this->_sessionTableConfig = $config;
foreach ($this->_sessionTableConfig as $k => $v)
{
if (property_exists($this, $k))
$this->$k = $v;
else
throw new Am_Exception_Configuration("Unknown config field: $k");
}
if (is_null($this->_uid) || is_null($this->_sid))
throw new Am_Exception_Configuration("Both SID and UID fields must be set in session table configuration");
}
/**
* Return session cookie name;
* @return string
*/
function getSessionCookieName()
{
return $this->_cookie;
}
/**
* Generate new session ID.
* by default session_id will be generated this way: md5(uniqid())
* @return string
*/
function createSessionId()
{
return md5(uniqid());
}
/**
* Get Session ID from Cookie;
* @return string
*/
function getSessionIdFromCookie()
{
return (($session_id = filterId($this->getDi()->request->getCookie($this->getSessionCookieName()))) ? $session_id : null);
}
/**
* Return user agent of current visitor (to be stored in session table)
* @return string
*/
function getUserAgent()
{
return $this->getDi()->request->getServer('HTTP_USER_AGENT');
}
/**
* Return IP address of current visitor (to be stored in session table)
* @return string
*/
function getUserIp()
{
return $this->getDi()->request->getClientIp();
}
/**
* Return time to store in session table;
* @return time
*/
function getCreateTime()
{
return time();
}
/**
* Return time to store in session table;
* @return time
*/
function getChangeTime()
{
return time();
}
function getUid(Am_Protect_SessionTable_Record $record)
{
return $record->get($this->_uid);
}
function setUid(Am_Protect_SessionTable_Record $record, Am_Record $user)
{
return $record->set($this->_uid, $user->pk());
}
/**
* Make sure that session is valid. Will check session IP and UserAgent
* Return true if UserAgent and IP are the same as for current user.
* @param Am_Record $session
* @return true|false
*
*/
function sessionIsValid(Am_Record $session)
{
// If session have different User Agent or IP do not login user into aMember.
if (!is_null($this->_ua) && $session->get($this->_ua) && ($session->get($this->_ua) != $this->getUserAgent()))
return false;
if (!is_null($this->_ip) && $session->get($this->_ip) && ($session->get($this->_ip) != $this->getUserIp()))
return false;
return true;
}
/**
* Load session from database;
* @param $sid - session _id returned by Am_Protect_SessionTable::getSessionId
* @return Am_Record|null
*/
function loadSession($sid)
{
$r = $this->findFirstBy(array($this->_sid => $sid));
if (!$r)
return null;
if ($this->sessionIsValid($r))
return $r;
return null;
}
/**
* Set cookie depends on _cookie_params
* @param type $name - cookie name
* @param type $value - cookie value
*/
function setCookie($name, $value)
{
$params = array($name, $value);
if (!is_null($this->_cookie_params))
foreach (array('expires', 'path', 'domain', 'secure', 'exact_domain') as $k)
$params[] = array_key_exists($k, $this->_cookie_params) && isset($this->_cookie_params[$k]) ? $this->_cookie_params[$k] : $this->_defaultCookieParams[$k];
call_user_func_array(array("Am_Cookie", "set"), $params);
}
/**
* Delete Cookie.
* @param type $name - cookie name;
*/
function delCookie($name)
{
$params = array($name, '', time() - 24 * 3600);
if (!is_null($this->_cookie_params))
foreach (array('path', 'domain', 'secure', 'exact_domain') as $k)
$params[] = array_key_exists($k, $this->_cookie_params) && isset($this->_cookie_params[$k]) ? $this->_cookie_params[$k] : $this->_defaultCookieParams[$k];
call_user_func_array(array("Am_Mvc_Controller", "setCookie"), $params);
}
/**
* Delete all cookies set by plugin
*/
function deleteAllCookies()
{
$this->delCookie($this->getSessionCookieName());
if (!is_null($this->_cookies_additional))
foreach ($this->_cookies_additional as $k => $v)
$this->delCookie($k);
}
function getLoggedInRecord()
{
$sid = $this->getSessionIdFromCookie();
if (is_null($sid))
return null;
$session = $this->loadSession($sid);
if (is_null($session))
return null;
$uid = $this->getUid($session);
if (!$uid)
return null;
return $this->_plugin->getTable()->load($uid);
}
function loginUser(Am_Record $record, $password)
{
$sid = $this->getSessionIdFromCookie();
if (is_null($sid))
{
do
{
$sid = $this->createSessionId();
}
while ($this->loadRow($sid, false));
}
$session = $this->load($sid, false);
if (is_null($session))
{
$session = new Am_Protect_SessionTable_Record($this);
$session->set($this->_sid, $sid);
if (!is_null($this->_created))
$session->set($this->_created, $this->getCreateTime());
if (!is_null($this->_ip))
$session->set($this->_ip, $this->getUserIp());
if (!is_null($this->_ua))
$session->set($this->_ua, $this->getUserAgent());
}
else if (!$this->sessionIsValid($session))
{
return false;
}
$this->setUid($session, $record);
if (!is_null($this->_changed))
$session->set($this->_changed, $this->getChangeTime());
if (!is_null($this->_additional))
{
foreach ($this->_additional as $k => $v)
{
$session->set($k, is_callable($v) ? call_user_func($v, $record, $session) : $v);
}
}
$session->save();
$this->setSessionCookie($sid, $record, $session);
return true;
}
function setSessionCookie($sid, $record, $session){
// Update Cookies.
$this->setCookie($this->getSessionCookieName(), $sid);
if (!is_null($this->_cookies_additional))
foreach ($this->_cookies_additional as $k => $v)
{
$this->setCookie($k, is_callable($v) ? call_user_func($v, $record, $session) : $v);
}
}
function logoutUser(User $user)
{
$sid = $this->getSessionIdFromCookie();
if (is_null($sid))
return;
$this->deleteAllCookies();
$session = $this->loadSession($sid);
if (is_null($session))
return;
$session->delete();
}
}
class Am_Protect_SessionTable_Record extends Am_Record
{
// Must be able to insert record with primary key already set.
protected $_disableInsertPkCheck = true;
protected $_isLoaded = false;
function __construct(Am_Table $table)
{
parent::__construct($table);
}
function isLoaded()
{
return $this->_isLoaded;
}
function fromRow(array $vars)
{
$this->_isLoaded = true;
return parent::fromRow($vars);
}
function save()
{
$this->isLoaded() ? $this->update() : $this->insert(false)->refresh();
return $this;
}
}
SingleLogin.php 0000644 00000001532 15210162164 0007466 0 ustar 00