644 lines
21 KiB
PHP
644 lines
21 KiB
PHP
<?php
|
|
|
|
/*
|
|
* @copyright Copyright (C) 2005-2010 Keyboard Monkeys Ltd. http://www.kb-m.com
|
|
* @license http://creativecommons.org/licenses/BSD/ BSD License
|
|
* @author Keyboard Monkeys Ltd.
|
|
* @since CommunityID 0.9
|
|
* @package CommunityID
|
|
* @packager Keyboard Monkeys
|
|
*/
|
|
|
|
|
|
class Users_Model_Users extends Monkeys_Db_Table_Gateway
|
|
{
|
|
const DIR_ASC = 0;
|
|
const DIR_DESC = 1;
|
|
|
|
protected $_name = 'users';
|
|
protected $_primary = 'id';
|
|
protected $_rowClass = 'Users_Model_User';
|
|
|
|
private $_user;
|
|
|
|
private $_sortFields = array(
|
|
'name' => array('firstname', 'lastname'),
|
|
'registration' => array('registration_date', 'firstname', 'lastname'),
|
|
'status' => array('accepted_eula', 'registration_date', 'firstname', 'lastname'),
|
|
);
|
|
|
|
public function createRow(array $data = array(), $defaultSource = null)
|
|
{
|
|
return parent::createRow(array(
|
|
'openid' => '',
|
|
'password_changed' => '0000-00-00',
|
|
'role' => Users_Model_User::ROLE_GUEST,
|
|
'passwordreset_token' => '',
|
|
));
|
|
}
|
|
|
|
/**
|
|
* In CID we chose from the beginning not to use SET NAMES, and instead leave the charset encodings configurations
|
|
* to remain in the database server side (my.cnf).
|
|
*
|
|
* CID's strings are UTF8. If character_set_client is not UTF8 but latin1 for example (unfortunatly that's the common case), non-latin1
|
|
* characters will appear garbled when manually browsing the db, but they should show OK in CID's web pages.
|
|
*
|
|
* When authenticating below, we use MySQL's MD5 function. From my tests, it looks like the argument of this function
|
|
* gets automatically converted to the charset of that field. Sorta like if we had implicitly MD5(CONVERT(arg using charset)).
|
|
* When the tables are build during setup, the charset of string fields are set accordingly to the my.cnf directives
|
|
* character-set-server and collation-server.
|
|
* If those directives don't match character_set_client, the conversion inside MD5 will in fact transform the string, and we'll
|
|
* get the MD5 of a different string than what we had intended (well, only if the string contains non-latin1 characters).
|
|
* For this reason we have to override that conversion, converting to the charset specified in character_set_client, as shown below.
|
|
*
|
|
* @return Zend_Auth_Result
|
|
*/
|
|
public function authenticate($identity, $password, $isOpenId = false, Zend_View $view = null, $bypassMarkSuccessfullLogin = false)
|
|
{
|
|
$config = Zend_Registry::get('config');
|
|
$useYubikey = false;
|
|
|
|
if ($isOpenId) {
|
|
if (!Zend_OpenId::normalize($identity)) {
|
|
return false;
|
|
}
|
|
|
|
if (!$this->_user = $this->getUserWithOpenId($identity)) {
|
|
return false;
|
|
}
|
|
|
|
$cn = $this->_user->username;
|
|
} else {
|
|
$cn = $identity;
|
|
$this->_user = $this->getUserWithUsername($identity, false, $view);
|
|
}
|
|
|
|
if ($this->_user
|
|
&& $config->yubikey->enabled
|
|
&& ($this->_user->auth_type == Users_Model_User::AUTH_YUBIKEY
|
|
|| $config->yubikey->force)) {
|
|
$parts = Yubico_Auth::parsePasswordOTP($password);
|
|
if (!$parts || $this->_user->yubikey_publicid != $parts['prefix']) {
|
|
return false;
|
|
}
|
|
$useYubikey = true;
|
|
}
|
|
|
|
$config = Zend_Registry::get('config');
|
|
$ldapConfig = $config->ldap;
|
|
if ($useYubikey) {
|
|
if (!@$config->yubikey->api_id || !@$config->yubikey->api_key) {
|
|
throw new Zend_Exception('Admin must set the yubikey configuration options before attempting to log in using this method');
|
|
}
|
|
|
|
$authAdapter = new Monkeys_Auth_Adapter_Yubikey(
|
|
array(
|
|
'api_id' => $config->yubikey->api_id,
|
|
'api_key' => $config->yubikey->api_key
|
|
),
|
|
$identity,
|
|
$password
|
|
);
|
|
} else if ($ldapConfig->enabled) {
|
|
$ldapOptions = $ldapConfig->toArray();
|
|
$ldapOptions['accountCanonicalForm'] = Zend_Ldap::ACCTNAME_FORM_USERNAME;
|
|
unset($ldapOptions['enabled']);
|
|
unset($ldapOptions['admin']);
|
|
unset($ldapOptions['fields']);
|
|
unset($ldapOptions['keepRecordsSynced']);
|
|
unset($ldapOptions['canChangePassword']);
|
|
unset($ldapOptions['passwordHashing']);
|
|
|
|
// we'll try to bind directly as the user to be authenticated, so we're unsetting
|
|
// the LDAP admin credentials
|
|
unset($ldapOptions['username']);
|
|
unset($ldapOptions['password']);
|
|
|
|
$username = "cn=$cn,{$ldapOptions['baseDn']}";
|
|
|
|
$authAdapter = new Zend_Auth_Adapter_Ldap(
|
|
array('server1' => $ldapOptions),
|
|
$username,
|
|
$password
|
|
);
|
|
} else {
|
|
$db = $this->getAdapter();
|
|
|
|
$result = $db->query("SHOW VARIABLES LIKE 'character_set_client'")->fetch();
|
|
$clientCharset = $result['Value'];
|
|
if ($isOpenId) {
|
|
$authAdapter = new Zend_Auth_Adapter_DbTable($db, 'users', 'openid', 'password',
|
|
'MD5(CONCAT(CONVERT(openid using ' . $clientCharset . '), CONVERT(? using ' . $clientCharset . ')))');
|
|
} else {
|
|
$authAdapter = new Zend_Auth_Adapter_DbTable($db, 'users', 'username', 'password',
|
|
'MD5(CONCAT(CONVERT(openid using ' . $clientCharset . '), CONVERT(? using ' . $clientCharset . ')))');
|
|
}
|
|
|
|
$authAdapter->setIdentity($identity);
|
|
$authAdapter->setCredential($password);
|
|
}
|
|
|
|
$auth = Zend_Auth::getInstance();
|
|
$result = $auth->authenticate($authAdapter);
|
|
|
|
if ($result->isValid()) {
|
|
if (!$isOpenId) {
|
|
try {
|
|
$this->_user = $this->getUserWithUsername($identity, true, $view);
|
|
} catch (Exception $e) {
|
|
// avoid leaving in the session an empty user object
|
|
Zend_Auth::getInstance()->clearIdentity();
|
|
Zend_Session::forgetMe();
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
if (!$bypassMarkSuccessfullLogin) {
|
|
$this->_user->markSuccessfullLogin();
|
|
}
|
|
$this->_user->save();
|
|
|
|
$auth->getStorage()->write($this->_user);
|
|
Zend_Registry::set('user', $this->_user);
|
|
|
|
return true;
|
|
}
|
|
|
|
// this is ugly, logging should be done in the controller, not here
|
|
$logger = Zend_Registry::get('logger');
|
|
$logger->log("Invalid authentication: " . implode(' - ', $result->getMessages()), Zend_Log::DEBUG);
|
|
if (is_a($authAdapter, 'Monkeys_Auth_Adapter_Yubikey')) {
|
|
$authOptions = $authAdapter->getOptions();
|
|
if ($yubi = @$authOptions['yubiClient']) {
|
|
$logger->log("Yubi request was: " . $yubi->getlastQuery(), Zend_Log::DEBUG);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function getUser()
|
|
{
|
|
return $this->_user;
|
|
}
|
|
|
|
public function getUsers($startIndex = false, $results = false, $sort = false, $dir = false, $where = false, $search = false)
|
|
{
|
|
$select = $this->select();
|
|
|
|
if ($startIndex !== false && $results !== false) {
|
|
$select = $select->limit($results, $startIndex);
|
|
}
|
|
|
|
if ($sort && isset($this->_sortFields[$sort])) {
|
|
$dir = ($dir == self::DIR_ASC? 'ASC' : 'DESC');
|
|
$sortSql = array();
|
|
foreach ($this->_sortFields[$sort] as $field) {
|
|
$sortSql[] = "$field $dir";
|
|
}
|
|
|
|
$select = $select->order($sortSql);
|
|
}
|
|
|
|
if ($where) {
|
|
$select = $select->where($where);
|
|
}
|
|
|
|
if ($search) {
|
|
$select = $select->where('firstname LIKE ? OR lastname LIKE ?', "%$search%", "%$search%");
|
|
}
|
|
|
|
return $this->fetchAll($select);
|
|
}
|
|
|
|
public function getNumUsers($where = false, $search = false)
|
|
{
|
|
$users = $this->getUsers(false, false, false, false, $where, $search);
|
|
|
|
return count($users);
|
|
}
|
|
|
|
public function getNumUnconfirmedUsers()
|
|
{
|
|
$users = $this->getUsers(false, false, false, false, "accepted_eula=0 AND role != '".Users_Model_User::ROLE_ADMIN."'");
|
|
|
|
return count($users);
|
|
}
|
|
|
|
public function getUserWithToken($token)
|
|
{
|
|
$select = $this->select()
|
|
->where('token=?', $token);
|
|
|
|
return $this->fetchRow($select);
|
|
}
|
|
|
|
public function getUserWithEmail($email)
|
|
{
|
|
$ldapOptions = Zend_Registry::get('config')->ldap;
|
|
if ($ldapOptions->enabled) {
|
|
$ldap = Monkeys_Ldap::getInstance();
|
|
try {
|
|
$ldapUserData = $ldap->search($ldapOptions->baseDn, 'mail', $email);
|
|
} catch (Exception $e) {
|
|
if ($e->getCode() == Monkeys_Ldap::EXCEPTION_GET_ENTRIES) {
|
|
return false;
|
|
}
|
|
|
|
throw $e;
|
|
}
|
|
|
|
$select = $this->select()
|
|
->where('username=?', $ldapUserData['cn'][0]);
|
|
$user = $this->fetchRow($select);
|
|
if (!$user) {
|
|
// user is registered in LDAP, but not in CID's db
|
|
$user = $this->createRow();
|
|
$user->registration_date = date('Y-m-d');
|
|
}
|
|
// this fields are always overridden from what comes from LDAP, because they might change
|
|
$user->overrideWithLdapData($ldapUserData);
|
|
} else {
|
|
$select = $this->select()
|
|
->where('email=?', $email);
|
|
$user = $this->fetchRow($select);
|
|
}
|
|
|
|
return $user;
|
|
}
|
|
|
|
public function getUserWithUsername($username, $generateNewIfMissing = false, Zend_View $view = null)
|
|
{
|
|
$select = $this->select()
|
|
->where('username=?', $username);
|
|
$user = $this->fetchRow($select);
|
|
|
|
$ldapOptions = Zend_Registry::get('config')->ldap;
|
|
if ($ldapOptions->enabled) {
|
|
$ldap = Monkeys_Ldap::getInstance();
|
|
try {
|
|
$ldapUserData = $ldap->get("cn=$username,{$ldapOptions->baseDn}");
|
|
} catch (Exception $e) {
|
|
if ($e->getCode() == Monkeys_Ldap::EXCEPTION_SEARCH) {
|
|
return false;
|
|
}
|
|
|
|
throw $e;
|
|
}
|
|
|
|
if ($user) {
|
|
// this fields are always overridden from what comes from LDAP, because they might change
|
|
$user->overrideWithLdapData($ldapUserData);
|
|
} else {
|
|
// user is registered in LDAP, but not in CID's db
|
|
$user = $this->createRow();
|
|
$user->registration_date = date('Y-m-d');
|
|
$user->overrideWithLdapData($ldapUserData);
|
|
|
|
if ($user->role != Users_Model_User::ROLE_ADMIN) {
|
|
preg_match('#(.*)/users/login/authenticate#', Zend_OpenId::selfURL(), $matches);
|
|
$user->generateOpenId($matches[1]);
|
|
}
|
|
|
|
if ($generateNewIfMissing) {
|
|
$user->save();
|
|
$profileId = $user->createDefaultProfile($view);
|
|
$user->generatePersonalInfo($ldapUserData, $profileId);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $user;
|
|
}
|
|
|
|
public function getUserWithOpenId($openid)
|
|
{
|
|
$select = $this->select()
|
|
->where('openid=?', $openid);
|
|
|
|
return $this->fetchRow($select);
|
|
}
|
|
|
|
public function getUnconfirmedUsers($olderThanDays)
|
|
{
|
|
$date = date('Y-m-d 23:59:59', strtotime("$olderThanDays days ago"));
|
|
$select = $this->select()
|
|
->where('accepted_eula=0')
|
|
->where('registration_date < ?', $date);
|
|
|
|
return $this->fetchAll($select);
|
|
}
|
|
|
|
public function deleteUser(Users_Model_User $user)
|
|
{
|
|
$where = $this->getAdapter()->quoteInto('id=?', $user->id);
|
|
$this->delete($where);
|
|
}
|
|
|
|
public function deleteTestEntries()
|
|
{
|
|
$this->delete('test=1');
|
|
}
|
|
|
|
public function deleteUnconfirmed($olderThanDays)
|
|
{
|
|
$olderThanDays = (int) $olderThanDays;
|
|
$date = date('Y-m-d', strtotime("$olderThanDays days ago"));
|
|
$this->delete("accepted_eula=0 AND role = '".Users_Model_User::ROLE_GUEST."' AND registration_date < '$date'");
|
|
}
|
|
|
|
protected $_metadata = array(
|
|
'id' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'id',
|
|
'COLUMN_POSITION' => 1,
|
|
'DATA_TYPE' => 'int',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => NULL,
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => true,
|
|
'PRIMARY_POSITION' => 1,
|
|
'IDENTITY' => true,
|
|
),
|
|
'test' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'test',
|
|
'COLUMN_POSITION' => 2,
|
|
'DATA_TYPE' => 'tinyint',
|
|
'DEFAULT' => '0',
|
|
'NULLABLE' => false,
|
|
'LENGTH' => NULL,
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'username' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'username',
|
|
'COLUMN_POSITION' => 3,
|
|
'DATA_TYPE' => 'varchar',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '50',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'openid' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'openid',
|
|
'COLUMN_POSITION' => 4,
|
|
'DATA_TYPE' => 'varchar',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '100',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'accepted_eula' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'accepted_eula',
|
|
'COLUMN_POSITION' => 5,
|
|
'DATA_TYPE' => 'tinyint',
|
|
'DEFAULT' => '0',
|
|
'NULLABLE' => false,
|
|
'LENGTH' => NULL,
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'registration_date' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'registration_date',
|
|
'COLUMN_POSITION' => 6,
|
|
'DATA_TYPE' => 'date',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => NULL,
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'last_login' =>
|
|
array(
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'last_login',
|
|
'COLUMN_POSITION' => 7,
|
|
'DATA_TYPE' => 'datetime',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => NULL,
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'auth_type' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'auth_type',
|
|
'COLUMN_POSITION' => 7,
|
|
'DATA_TYPE' => 'tinyint',
|
|
'DEFAULT' => '0',
|
|
'NULLABLE' => false,
|
|
'LENGTH' => NULL,
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'password' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'password',
|
|
'COLUMN_POSITION' => 7,
|
|
'DATA_TYPE' => 'char',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '40',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'password_changed' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'password_changed',
|
|
'COLUMN_POSITION' => 8,
|
|
'DATA_TYPE' => 'date',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => NULL,
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'yubikey_publicid' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'yubikey_publicid',
|
|
'COLUMN_POSITION' => 9,
|
|
'DATA_TYPE' => 'varchar',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '50',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'firstname' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'firstname',
|
|
'COLUMN_POSITION' => 9,
|
|
'DATA_TYPE' => 'varchar',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '50',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'lastname' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'lastname',
|
|
'COLUMN_POSITION' => 10,
|
|
'DATA_TYPE' => 'varchar',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '50',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'email' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'email',
|
|
'COLUMN_POSITION' => 11,
|
|
'DATA_TYPE' => 'varchar',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '50',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'role' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'role',
|
|
'COLUMN_POSITION' => 12,
|
|
'DATA_TYPE' => 'varchar',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '50',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'token' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'token',
|
|
'COLUMN_POSITION' => 13,
|
|
'DATA_TYPE' => 'char',
|
|
'DEFAULT' => NULL,
|
|
'NULLABLE' => false,
|
|
'LENGTH' => '32',
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
'reminders' =>
|
|
array (
|
|
'SCHEMA_NAME' => NULL,
|
|
'TABLE_NAME' => 'users',
|
|
'COLUMN_NAME' => 'reminders',
|
|
'COLUMN_POSITION' => 14,
|
|
'DATA_TYPE' => 'int',
|
|
'DEFAULT' => '0',
|
|
'NULLABLE' => false,
|
|
'LENGTH' => NULL,
|
|
'SCALE' => NULL,
|
|
'PRECISION' => NULL,
|
|
'UNSIGNED' => NULL,
|
|
'PRIMARY' => false,
|
|
'PRIMARY_POSITION' => NULL,
|
|
'IDENTITY' => false,
|
|
),
|
|
);
|
|
}
|