session.php 8.52 KB
Newer Older
1 2
<?php
/**
Francois Marier's avatar
Francois Marier committed
3
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
4 5
 * Copyright (C) 2006-2009 Catalyst IT Ltd and others; see:
 *                         http://wiki.mahara.org/Contributors
6
 *
Francois Marier's avatar
Francois Marier committed
7 8 9 10
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
11
 *
Francois Marier's avatar
Francois Marier committed
12 13 14 15
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
16
 *
Francois Marier's avatar
Francois Marier committed
17 18
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 20
 *
 * @package    mahara
Nigel McNie's avatar
Nigel McNie committed
21
 * @subpackage core
22
 * @author     Catalyst IT Ltd
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
24
 * @copyright  (C) 2006-2009 Catalyst IT Ltd http://catalyst.net.nz
25 26 27 28 29
 *
 */

defined('INTERNAL') || die();

30 31 32
//
// Set session settings
//
33
session_name(get_config('cookieprefix') . 'mahara');
34 35 36 37 38 39 40
ini_set('session.save_path', '3;' . get_config('dataroot') . 'sessions');
ini_set('session.gc_divisor', 1000);
// Session timeout is stored in minutes in the database
ini_set('session.gc_maxlifetime', get_config('session_timeout') * 60);
ini_set('session.use_only_cookies', true);
ini_set('session.cookie_path', get_mahara_install_subdirectory());
ini_set('session.cookie_httponly', 1);
41
ini_set('session.hash_bits_per_character', 4);
42
ini_set('session.hash_function', 0);
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63


// TEMPORARY: this will be REMOVED after the session path changing
// has been around for a bit.
// Attempt to create session directories
$sessionpath = get_config('dataroot') . 'sessions';
if (!is_dir("$sessionpath/0")) {
    // Create three levels of directories, named 0-9, a-f
    $characters = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
    foreach ($characters as $c1) {
        check_dir_exists("$sessionpath/$c1");
        foreach ($characters as $c2) {
            check_dir_exists("$sessionpath/$c1/$c2");
            foreach ($characters as $c3) {
                check_dir_exists("$sessionpath/$c1/$c2/$c3");
            }
        }
    }
}


64
/**
65
 * The session class handles session data and messages.
66
 *
67 68 69 70
 * This class stores information across page loads, using only a cookie to
 * remember the info. User information is stored in the session so it does
 * not have to be requested each time the page is loaded, however any other
 * information can also be stored using this class.
71 72 73 74
 *
 * This class also is smart about giving out sessions - if a visitor
 * has not logged in (e.g. they are a guest, searchbot or a simple
 * 'curl' request), a session will not be created for them.
75
 *
76 77
 * Messages are stored in the session and are displayed the next time
 * a page is displayed to a user, even over multiple requests.
78 79 80
 */
class Session {

81
    /**
82
     * Resumes an existing session, only if there is one
83
     */
84
    private function __construct() {
85
        // Resume an existing session if required
86
        if (isset($_COOKIE[session_name()])) {
87
            @session_start();
88 89 90
        }
    }

91 92 93 94 95 96 97 98 99 100 101 102
    /**
     * Singelton function keeps us from generating multiple instances of this
     * class
     *
     * @return object   The class instance
     * @access public
     */
    public static function singleton() {
        //single instance
        static $instance;

        //if we don't have the single instance, create one
103
        if (!isset($instance)) {
104 105 106 107 108
            $instance = new Session();
        }
        return($instance);
    }

109 110 111 112 113 114 115 116 117 118
    /**
     * Gets the session property keyed by $key.
     *
     * @param string $key The key to get the value of
     * @return mixed
     */
    public function get($key) {
        if (isset($_SESSION[$key])) {
            return $_SESSION[$key];
        }
Penny Leach's avatar
Penny Leach committed
119 120 121
        return null;
    }

122 123 124 125 126 127 128
    /**
     * Sets the session property keyed by $key.
     *
     * @param string $key   The key to set.
     * @param string $value The value to set for the key
     */
    public function set($key, $value) {
129
        $this->ensure_session();
130
        $_SESSION[$key] = $value;
131 132
    }

Martyn Smith's avatar
Martyn Smith committed
133 134 135 136 137
    /**
     * Clears the session property keyed by $key (by setting it to null).
     *
     * @param string $key   The key to set.
     */
Martyn Smith's avatar
Martyn Smith committed
138
    public function clear($key) {
Martyn Smith's avatar
Martyn Smith committed
139 140 141 142
        $this->ensure_session();
        $_SESSION[$key] = null;
    }

143 144 145 146 147 148 149
    /**
     * Adds a message that indicates something was successful
     *
     * @param string $message The message to add
     * @param boolean $escape Whether to HTML escape the message
     */
    public function add_ok_msg($message, $escape=true) {
150
        $this->ensure_session();
151
        if ($escape) {
152
            $message = self::escape_message($message);
153 154 155 156 157 158 159 160 161 162 163
        }
        $_SESSION['messages'][] = array('type' => 'ok', 'msg' => $message);
    }

    /**
     * Adds a message that indicates an informational message
     *
     * @param string $message The message to add
     * @param boolean $escape Whether to HTML escape the message
     */
    public function add_info_msg($message, $escape=true) {
164
        $this->ensure_session();
165
        if ($escape) {
166
            $message = self::escape_message($message);
167 168 169 170 171 172 173 174 175 176
        }
        $_SESSION['messages'][] = array('type' => 'info', 'msg' => $message);
    }

    /**
     * Adds a message that indicates a failure to do something
     *
     * @param string $message The message to add
     * @param boolean $escape Whether to HTML escape the message
     */
177
    public function add_error_msg($message, $escape=true) {
178
        $this->ensure_session();
179
        if ($escape) {
180
            $message = self::escape_message($message);
181
        }
182
        $_SESSION['messages'][] = array('type' => 'error', 'msg' => $message);
183 184 185 186 187 188 189 190 191 192 193 194 195
    }

    /**
     * Builds HTML that represents all of the messages and returns it.
     *
     * This is designed to let smarty templates hook in any session messages.
     *
     * Calling this function will destroy the session messages that were
     * rendered, so they do not inadvertently get displayed again.
     *
     * @return string The HTML representing all of the session messages.
     */
    public function render_messages() {
196
        global $THEME;
197
        $result = '<div id="messages">';
198 199
        if (isset($_SESSION['messages'])) {
            foreach ($_SESSION['messages'] as $data) {
200
                $result .= '<div class="' . $data['type'] . '">';
201
                $result .= '<div class="fr"><a href="" onclick="removeElement(this.parentNode.parentNode);return false;">';
202
                $result .= '<img src="' . $THEME->get_url('images/icon_close.gif') . '" alt="[X]"></a></div>';
203
                $result .= $data['msg'] . '</div>';
204
            }
205
            $_SESSION['messages'] = array();
206
        }
207
        $result .= '</div>';
208 209 210
        return $result;
    }

211
    /**
212
     * Create a session, by initialising the $_SESSION array.
213
     */
214 215 216
    private function ensure_session() {
        if (empty($_SESSION)) {
            if (!session_id()) {
217
                @session_start();
218 219 220 221
            }
            $_SESSION = array(
                'messages' => array()
            );
222
        }
223 224
    }

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
    /**
     * Destroy a session
     */
    public function destroy_session() {
        if ($this->is_live()) {
            $_SESSION = array();
            if (isset($_COOKIE[session_name()])) {
                setcookie(session_name(), '', time() - 65536,
                    ini_get('session.cookie_path'),
                    ini_get('session.cookie_domain'),
                    ini_get('session.cookie_secure'),
                    ini_get('session.cookie_httponly')
                );
            }
            session_destroy();
        }
    }

243 244 245 246 247 248 249 250 251 252
    /**
     * Find out if the session has been started yet
     */
    public function is_live() {
        if ("" == session_id()) {
            return false;
        }
        return true;
    }

253 254 255 256 257 258 259 260 261 262
    /**
     * Escape a message for HTML output
     * 
     * @param string $message The message to escape
     * @return string         The message, escaped for output as HTML
     */
    private static function escape_message($message) {
        $message = hsc($message);
        $message = str_replace('  ', '&nbsp; ', $message);
        return $message;
263
    }
264

265 266 267 268 269 270 271 272 273 274 275 276 277
}

/**
 * A smarty callback to insert page messages
 *
 * @return string The HTML represening all of the session messages.
 */
function insert_messages() {
    global $SESSION;
    return $SESSION->render_messages();
}

?>