Platon Technologies
neprihlásený Prihlásiť Registrácia
SlovakEnglish
open source software development oslavujeme 10 rokov vývoja otvoreného softvéru! Sobota, 20. apríl 2024

Súbor: [Platon] / phpPlatonLib / Auth_AuthDB / AuthDB.php (stiahnutie)

Revízia 1.18, Wed Oct 14 11:45:40 2009 UTC (14 years, 6 months ago) by nepto


Zmeny od 1.17: +5 -1 [lines]

Disable domain in cookie if domain is "localhost"

<?php

/*
 * phpPlatonLib - Platon Group PHP library
 *
 * Auth/AuthDB.php - powerful authentification interface
 * ____________________________________________________________
 *
 * Developed by Ondrej Jombik <nepto@platon.sk>
 * Copyright (c) 2001-2007 Platon Group, http://platon.sk/
 * All rights reserved.
 *
 * See README file for more information about this software.
 * See COPYING file for license information.
 *
 * Download the latest version from
 * http://platon.sk/projects/phpPlatonLib/
 */

/* $Platon: phpPlatonLib/Auth_AuthDB/AuthDB.php,v 1.17 2008-05-01 14:15:57 nepto Exp $ */

/*
 * History:
 *
 * 2002-03-31 - initial release
 * 2002-05-13 - headers update
 * 2002-05-29 - code cleanup, little improvements
 *              (username and password moved to props array)
 * 2002-09-05 - expiration & timeout implementation
 *            - better HTTP_X_FORWARDED_FOR handling in authentification
 *            - extensive code cleanup
 * 2003-07-27 - support for authentification via another cooperative
 *              authentification interface
 * 2007-09-22 - configurable cookie name, path, domain
 *            - configurable username/password CGI form variable name
 * 2009-10-14 - disable domain in cookie if domain is "localhost"
 */

require_once 'DB.php';

define('AUTH_DB_COOKIE_NAME',    'AuthDB_session_id_cookie');
define('AUTH_DB_VAR_USERNAME',    'username');
define('AUTH_DB_VAR_PASSWORD',    'password');
define('AUTH_DB_UNDEFINED',         0);
define('AUTH_DB_NOT_LOGGED',    -1);
define('AUTH_DB_LOGGED_IN',         1);
define('AUTH_DB_LOGGED_OUT',    -2);
define('AUTH_DB_EXPIRED',        -3);
define('AUTH_DB_TIMEOUT',        -4);
define('AUTH_DB_FAILED',        -5);
//define('AUTH_DB_ERROR',        -6);


class AuthDB
{
    var $_status     = AUTH_DB_UNDEFINED;
    var $_options    = null;
    var $_db         = null;
    var $_logged_fnc = null;
    var $_props      = array(
            'username'   => null,
            'password'   => null,
            'session_id' => null,
            'user_agent' => null,
            'remote_ip'  => null
            );

    function AuthDB($options) /* {{{ */
    {
        $this->_options = $options;
        $this->_checkOptions();
    } /* }}} */

    function _checkOptions() /* {{{ */
    {
        if (! isset($this->_options['var']['username'])) {
            $this->_options['var']['username'] = AUTH_DB_VAR_USERNAME;
        }
        if (! isset($this->_options['var']['password'])) {
            $this->_options['var']['password'] = AUTH_DB_VAR_PASSWORD;
        }
        if (! isset($this->_options['cookie']['name'])) {
            $this->_options['cookie']['name'] = AUTH_DB_COOKIE_NAME;
        }
        if (! strcasecmp(trim($this->_options['cookie']['domain']), 'localhost')) {
            $this->_options['cookie']['domain'] = null;
        }
    } /* }}} */

    /**
     * Tells AuthDB, that particular user is already authentificated
     * via another cooperative authetification interface.
     *
     * @param    fncname        name of the function, which returns
     *                        username of already logged in user
     * @return    status
     */
    function setLoggedFunction($fncname) /* {{{ */
    {
        $this->_logged_fnc = $fncname;
    } /* }}} */

    function assignData() /* {{{ */
    {
        $username_var = $this->_options['var']['username'];
        $password_var = $this->_options['var']['password'];

        /* Empty passwords are allowed. Empty usernames not. */

        if (isset($_POST[$username_var]) && $_POST[$username_var] != '') {
            $this->_props['username'] = $_POST[$username_var];

            if (isset($_POST[$password_var])) {
                $this->_props['password'] = $_POST[$password_var];
            }
        }
    } /* }}} */

    /* PEAR Auth class compatibility */
    function getAuth() /* {{{ */
    {
        return $this->getStatus() == AUTH_DB_LOGGED_IN;
    } /* }}} */

    function getStatus() /* {{{ */
    {
        if ($this->_status != AUTH_DB_UNDEFINED)
            return $this->_status;

        $this->_status = $this->_processStatus();

        return $this->_status;
    } /* }}} */

    function _processStatus() /* {{{ */
    {
        if ($this->_logged_fnc != null && function_exists($this->_logged_fnc)) {
            $this->_props['username'] = call_user_func($this->_logged_fnc);
        }
        $this->_checkDB();
        $this->_DBupdateTimeout();

        $status = $this->_DBcheckLogin();
        
        /* If there is a defined login status returns it.
           Exception is, if we are in "logged" mode, which means we are
           authentificated via another cooperative authentification interface.
           In this case only LOGGED_IN and FAILED are returned.
           Other statuses purpously force login function again. */
        if ($status != AUTH_DB_UNDEFINED && ($this->_logged_fnc == null
                    || $status == AUTH_DB_FAILED
                    || $status == AUTH_DB_LOGGED_IN)) {
            if ($status != AUTH_DB_LOGGED_IN) {
                setcookie($this->_options['cookie']['name'],
                        '',                    /* empty string */
                        time() - 100000,    /* time in the past */
                        $this->_options['cookie']['path'],
                        $this->_options['cookie']['domain']);
            }
            return $status;
        }

        /* If not in "logged" mode, assign login data into variables. */
        $this->_logged_fnc != null || $this->assignData();
        $status = $this->login();

        if ($status == AUTH_DB_LOGGED_IN) {
            $this->_DBinsert();
            setcookie($this->_options['cookie']['name'],
                    $this->_getProperty('session_id'),
                    0, /* expires at the end of session */
                    $this->_options['cookie']['path'],
                    $this->_options['cookie']['domain']);
        } elseif ($status == AUTH_DB_FAILED) {
            $this->_DBlog();
        }

        return $status;
    } /* }}} */

    function login() /* {{{ */
    {
        $status = AUTH_DB_UNDEFINED;

        if (! empty($this->_props['username'])) {
            $password = $this->_DBgetPassword();
            if (isset($password)) {
                if ($this->_logged_fnc ||
                        ! strcmp($password, md5($this->_props['password']))) {
                    $status = AUTH_DB_LOGGED_IN;
                } else {
                    $status = AUTH_DB_FAILED;
                }
            } else {
                $status = AUTH_DB_FAILED;
            }
        } else {
            $status = AUTH_DB_NOT_LOGGED;
        }

        return $status;
    } /* }}} */

    function logout() /* {{{ */
    {
        if ($this->getAuth()) {
            $this->_DBlogout();
            $this->_status = AUTH_DB_LOGGED_OUT;
        }
        setcookie($this->_options['cookie']['name'],
                '',                    /* empty string */
                time() - 100000,    /* time in the past */
                $this->_options['cookie']['path'],
                $this->_options['cookie']['domain']);
    } /* }}} */

    function getUsername() /* {{{ */
    {
        return $this->_DBgetUsername();
    } /* }}} */

    function getUserInfo() /* {{{ */
    {
        if ($this->getAuth()) {
            $this->_props['username'] = $this->getUsername();
            return $this->_DBgetUserInfo();
        }

        return false;
    } /* }}} */


    // Private methods

    function _checkDB() /* {{{ */
    {
        if (! isset($this->_db)) {
            $this->_db = DB::connect($this->_options['dsn']);
            DB::isError($this->_db) && $this->_error($this->_db);
            $this->_db->setFetchMode(DB_FETCHMODE_ASSOC);
        }
    } /* }}} */

    function _error($error) /* {{{ */
    {
        die('AuthDB error: '.$error->getMessage());
        // sensitive!
        // $error->getDebugInfo();
    } /* }}} */

    function _getProperty($property) /* {{{ */
    {
        if (isset($this->_props[$property]))
            return $this->_props[$property];

        switch ($property) {
            case 'user_agent':
                $ret = @$_SERVER['HTTP_USER_AGENT'];
                $ret = substr(stripslashes($ret), 0, 255);
                break;

            case 'remote_ip':
                /* Sending HTTP_X_FORWARDED_FOR? OK, send anything you want,
                   but it must persist for the whole session. */
                $ret = array();
                foreach (array('REMOTE_ADDR', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP') as $key) {
                    if (isset($_SERVER[$key])) {
                        $ret[] = $_SERVER[$key];
                    }
                }
                $ret = array_unique($ret);
                $ret = join(' / ', $ret);
                break;

            default:
            case 'session_id':
                if (isset($_COOKIE[$this->_options['cookie']['name']])) {
                    $ret = $_COOKIE[$this->_options['cookie']['name']];
                    $ret = intval(stripslashes($ret));
                } else {
                    $ret = '';
                }
                break;
        }

        $this->_props[$property] = $ret;
        return $ret;
    } /* }}} */

    function _DBgetPassword() /* {{{ */
    {
        $query = sprintf('SELECT %s FROM %s WHERE %s = %s',
                $this->_options['users']['cols']['password'],
                $this->_options['users']['table'],
                $this->_options['users']['cols']['username'],
                $this->_db->quote($this->_props['username']));

        if (DB::isError($password = $this->_db->getOne($query)))
            $this->_error($password);

        return $password;
    } /* }}} */

    function _DBinsert() /* {{{ */
    {
        mt_srand((double) microtime() * 1000000);

        do {
            $session_id = mt_rand();
            $query = sprintf('SELECT session_id FROM %s'
                    . ' WHERE session_id = %s',
                    $this->_options['sessions']['table'],
                    $this->_db->quote($session_id));

            DB::isError($res = $this->_db->getOne($query))
                && $this->_error($res);
        } while (isset($res));

        $query = sprintf('INSERT INTO %s'
                .' (status, login, logout,'
                    .' username, session_id, ip, user_agent)'
                .' VALUES'
                .' ("online", sysdate(), sysdate(),'
                    .' %s, %s, %s, %s)',
                $this->_options['sessions']['table'],
                $this->_db->quote($this->_props['username']),
                $this->_db->quote($session_id),
                $this->_db->quote($this->_getProperty('remote_ip')),
                $this->_db->quote($this->_getProperty('user_agent')));

        DB::isError($res = $this->_db->query($query)) && $this->_error($res);
        $this->_props['session_id'] = $session_id;
    } /* }}} */

    function _DBlog() /* {{{ */
    {
        $query = sprintf('INSERT INTO %s'
                .' (status, login, logout,'
                    .' username, password, ip, user_agent)'
                .' VALUES'
                .' ("failed", sysdate(), sysdate(),'
                    .' %s, %s, %s, %s)',
                $this->_options['sessions']['table'],
                $this->_db->quote($this->_props['username']),
                $this->_db->quote($this->_props['password']),
                $this->_db->quote($this->_getProperty('remote_ip')),
                $this->_db->quote($this->_getProperty('user_agent')));

        DB::isError($res = $this->_db->query($query)) && $this->_error($res);
    } /* }}} */

    function _DBupdateTimeout() /* {{{ */
    {
        $timeout = intval($this->_options['timeout']);
        $expired = intval($this->_options['expired']);

        if ($timeout > 0) {
            $query = sprintf('UPDATE %s'
                    .' SET status   = "timeout"'
                    .' WHERE status = "online"'
                    .' AND UNIX_TIMESTAMP(SYSDATE())'
                    .' - UNIX_TIMESTAMP(logout) >= %s',
                    $this->_options['sessions']['table'],
                    $this->_db->quote($timeout));
            DB::isError($res = $this->_db->query($query)) && $this->_error($res);
        }
        if ($expired > 0) {
            $query = sprintf('UPDATE %s'
                    .' SET status   = "expired"'
                    .' WHERE status = "online"'
                    .' AND UNIX_TIMESTAMP(SYSDATE())'
                    .' - UNIX_TIMESTAMP(login) >= %s',
                    $this->_options['sessions']['table'],
                    $this->_db->quote($expired));
            DB::isError($res = $this->_db->query($query)) && $this->_error($res);
        }
    } /* }}} */

    // This method needs ISDN fastfix
    function _DBlogout() /* {{{ */
    {
        $query = sprintf('UPDATE %s'
                .' SET status = "logout", logout = sysdate() '
                .' WHERE status = "online"'
                .' AND session_id = %s'
                .' AND ip = %s'
                .' AND user_agent = %s',
                $this->_options['sessions']['table'],
                $this->_db->quote($this->_getProperty('session_id')),
                $this->_db->quote($this->_getProperty('remote_ip')),
                $this->_db->quote($this->_getProperty('user_agent')));

        DB::isError($res = $this->_db->query($query)) && $this->_error($res);
    } /* }}} */

    // This method needs ISDN fastfix
    function _DBupdateLogin() /* {{{ */
    {
        $query = sprintf('UPDATE %s'
                .' SET logout = sysdate()'
                .' WHERE status = "online"'
                .' AND session_id = %s'
                .' AND ip = %s'
                .' AND user_agent = %s',
                $this->_options['sessions']['table'],
                $this->_db->quote($this->_getProperty('session_id')),
                $this->_db->quote($this->_getProperty('remote_ip')),
                $this->_db->quote($this->_getProperty('user_agent')));

        DB::isError($res = $this->_db->query($query)) && $this->_error($res);
        return $this->_db->affectedRows() > 0 ? true : false;
    } /* }}} */

    // This method needs ISDN fastfix
    function _DBcheckLogin() /* {{{ */
    {
        if ($this->_DBupdateLogin() == true)
            return true;
        $query = sprintf('SELECT status FROM %s'
                .' WHERE session_id = %s'
                .' AND ip = %s'
                .' AND user_agent = %s',
                $this->_options['sessions']['table'],
                $this->_db->quote($this->_getProperty('session_id')),
                $this->_db->quote($this->_getProperty('remote_ip')),
                $this->_db->quote($this->_getProperty('user_agent')));

        DB::isError($res = $this->_db->getCol($query)) && $this->_error($res);
        $res = array_unique($res);

        /* Keep this in priority order. */
        if (in_array('logout',  $res)) return AUTH_DB_LOGGED_OUT;
        if (in_array('failed',  $res)) return AUTH_DB_FAILED;
        if (in_array('timeout', $res)) return AUTH_DB_TIMEOUT;
        if (in_array('expired', $res)) return AUTH_DB_EXPIRED;
        if (in_array('online',  $res)) return AUTH_DB_LOGGED_IN;
        return AUTH_DB_UNDEFINED;
    } /* }}} */

    // This method needs ISDN fastfix
    function _DBgetUsername() /* {{{ */
    {
        $query = sprintf('SELECT username FROM %s'
                .' WHERE status = "online"'
                .' AND session_id = %s'
                .' AND ip = %s'
                .' AND user_agent = %s',
                $this->_options['sessions']['table'],
                $this->_db->quote($this->_getProperty('session_id')),
                $this->_db->quote($this->_getProperty('remote_ip')),
                $this->_db->quote($this->_getProperty('user_agent')));

        DB::isError($res = $this->_db->getCol($query)) && $this->_error($res);
        return $res[0];
    } /* }}} */

    function _DBgetUserInfo() /* {{{ */
    {
        $select_cols = array();
        $select_tables = array();
        $select_where = array();

        foreach (array('sessions', 'users', 'groups') as $key) {
            $prefix = $this->_options[$key]['prefix'];
            $table = $this->_options[$key]['table'];
            $cols = $this->_options[$key]['info_cols'];

            if (! is_array($cols) || ! isset($table))
                continue;

            if (in_array('*', $cols) == true) {
                if (DB::isError($info = $this->_db->tableInfo($table)))
                    $this->_error($info);

                $cols = array();
                foreach ($info as $info_val)
                    $cols[] = $info_val['name'];
            }

            $select_tables[] = $table;

            foreach ($cols as $col_val)
                $select_cols[] = "$table.$col_val AS ".$prefix.$col_val;
        }

        if (count($select_tables) == 0 || count($select_cols) == 0)
            return false;

        if (is_array($this->_options['users']['info_cols'])
                && is_array($this->_options['groups']['info_cols'])) {
            $select_where[] = sprintf('%s.%s = %s.%s',
                    $this->_options['users']['table'],
                    $this->_options['users']['cols']['group_id'],
                    $this->_options['groups']['table'],
                    $this->_options['groups']['cols']['id']);
        }

        if (is_array($this->_options['users']['info_cols'])
                && is_array($this->_options['sessions']['info_cols'])) {
            $select_where[] = sprintf('%s.username = %s.%s',
                    $this->_options['sessions']['table'],
                    $this->_options['users']['table'],
                    $this->_options['users']['cols']['username']);
        }

        if (is_array($this->_options['users']['info_cols'])) {
            $select_where[] = sprintf('%s.username = %s',
                    $this->_options['users']['table'],
                    $this->_db->quote($this->_props['username']));
        }

        if (is_array($this->_options['sessions']['info_cols'])) {
            $select_where[] = sprintf('%s.session_id = %s',
                    $this->_options['sessions']['table'],
                    $this->_db->quote($this->_getProperty('session_id')));
        }

        $query = sprintf('SELECT %s FROM %s',
                join(', ', $select_cols),
                join(', ', $select_tables));

        if (count($select_where))
            $query .= ' WHERE ' . join(' AND ', $select_where);

        DB::isError($res = $this->_db->getRow($query)) && $this->_error($res);
        return $res;
    } /* }}} */

}

/* Modeline for ViM {{{
 * vim: set ts=4:
 * vim600: fdm=marker fdl=0 fdc=0:
 * }}} */

?>

Platon Group <platon@platon.sk> http://platon.sk/
Copyright © 2002-2006 Platon Group
Stránka používa redakčný systém Metafox
Na začiatok