Completed
Push — stable13 ( c99529...4ff6ea )
by Morris
58:12 queued 30:27
created

Internal::regenerateId()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 18
nop 2
dl 0
loc 33
rs 8.7697
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author cetra3 <[email protected]>
7
 * @author Christoph Wurst <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Thomas Müller <[email protected]>
12
 * @author Victor Dubiniuk <[email protected]>
13
 *
14
 * @license AGPL-3.0
15
 *
16
 * This code is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License, version 3,
18
 * as published by the Free Software Foundation.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License, version 3,
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
27
 *
28
 */
29
30
namespace OC\Session;
31
32
use OC\Authentication\Exceptions\InvalidTokenException;
33
use OC\Authentication\Token\IProvider;
34
use OC\SystemConfig;
35
use OCP\IConfig;
36
use OCP\Session\Exceptions\SessionNotAvailableException;
37
38
/**
39
 * Class Internal
40
 *
41
 * wrap php's internal session handling into the Session interface
42
 *
43
 * @package OC\Session
44
 */
45
class Internal extends Session {
46
	/**
47
	 * @param string $name
48
	 * @throws \Exception
49
	 */
50
	public function __construct($name) {
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
51
		set_error_handler(array($this, 'trapError'));
52
		$this->invoke('session_name', [$name]);
53
		try {
54
			$this->invoke('session_start');
55
		} catch (\Exception $e) {
56
			setcookie($this->invoke('session_name'), null, -1, \OC::$WEBROOT ?: '/');
57
		}
58
		restore_error_handler();
59
		if (!isset($_SESSION)) {
60
			throw new \Exception('Failed to start session');
61
		}
62
	}
63
64
	/**
65
	 * @param string $key
66
	 * @param integer $value
67
	 */
68
	public function set($key, $value) {
0 ignored issues
show
Coding Style introduced by
set uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
69
		$this->validateSession();
70
		$_SESSION[$key] = $value;
71
	}
72
73
	/**
74
	 * @param string $key
75
	 * @return mixed
76
	 */
77
	public function get($key) {
0 ignored issues
show
Coding Style introduced by
get uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
78
		if (!$this->exists($key)) {
79
			return null;
80
		}
81
		return $_SESSION[$key];
82
	}
83
84
	/**
85
	 * @param string $key
86
	 * @return bool
87
	 */
88
	public function exists($key) {
0 ignored issues
show
Coding Style introduced by
exists uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
89
		return isset($_SESSION[$key]);
90
	}
91
92
	/**
93
	 * @param string $key
94
	 */
95
	public function remove($key) {
0 ignored issues
show
Coding Style introduced by
remove uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
96
		if (isset($_SESSION[$key])) {
97
			unset($_SESSION[$key]);
98
		}
99
	}
100
101
	public function clear() {
0 ignored issues
show
Coding Style introduced by
clear uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
102
		$this->invoke('session_unset');
103
		$this->regenerateId();
104
		$this->invoke('session_start', [], true);
105
		$_SESSION = [];
106
	}
107
108
	public function close() {
109
		$this->invoke('session_write_close');
110
		parent::close();
111
	}
112
113
	/**
114
	 * Wrapper around session_regenerate_id
115
	 *
116
	 * @param bool $deleteOldSession Whether to delete the old associated session file or not.
117
	 * @param bool $updateToken Wheater to update the associated auth token
118
	 * @return void
119
	 */
120
	public function regenerateId($deleteOldSession = true, $updateToken = false) {
121
		$oldId = null;
122
123
		if ($updateToken) {
124
			// Get the old id to update the token
125
			try {
126
				$oldId = $this->getId();
127
			} catch (SessionNotAvailableException $e) {
128
				// We can't update a token if there is no previous id
129
				$updateToken = false;
130
			}
131
		}
132
133
		try {
134
			@session_regenerate_id($deleteOldSession);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
135
		} catch (\Error $e) {
0 ignored issues
show
Bug introduced by
The class Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
136
			$this->trapError($e->getCode(), $e->getMessage());
137
		}
138
139
		if ($updateToken) {
140
			// Get the new id to update the token
141
			$newId = $this->getId();
142
143
			/** @var IProvider $tokenProvider */
144
			$tokenProvider = \OC::$server->query(IProvider::class);
145
146
			try {
147
				$tokenProvider->renewSessionToken($oldId, $newId);
148
			} catch (InvalidTokenException $e) {
149
				// Just ignore
150
			}
151
		}
152
	}
153
154
	/**
155
	 * Wrapper around session_id
156
	 *
157
	 * @return string
158
	 * @throws SessionNotAvailableException
159
	 * @since 9.1.0
160
	 */
161
	public function getId() {
162
		$id = $this->invoke('session_id', [], true);
163
		if ($id === '') {
164
			throw new SessionNotAvailableException();
165
		}
166
		return $id;
167
	}
168
169
	/**
170
	 * @throws \Exception
171
	 */
172
	public function reopen() {
173
		throw new \Exception('The session cannot be reopened - reopen() is ony to be used in unit testing.');
174
	}
175
176
	/**
177
	 * @param int $errorNumber
178
	 * @param string $errorString
179
	 * @throws \ErrorException
180
	 */
181
	public function trapError($errorNumber, $errorString) {
182
		throw new \ErrorException($errorString);
183
	}
184
185
	/**
186
	 * @throws \Exception
187
	 */
188
	private function validateSession() {
189
		if ($this->sessionClosed) {
190
			throw new SessionNotAvailableException('Session has been closed - no further changes to the session are allowed');
191
		}
192
	}
193
194
	/**
195
	 * @param string $functionName the full session_* function name
196
	 * @param array $parameters
197
	 * @param bool $silence whether to suppress warnings
198
	 * @throws \ErrorException via trapError
199
	 * @return mixed
200
	 */
201
	private function invoke($functionName, array $parameters = [], $silence = false) {
202
		try {
203
			if($silence) {
204
				return @call_user_func_array($functionName, $parameters);
205
			} else {
206
				return call_user_func_array($functionName, $parameters);
207
			}
208
		} catch(\Error $e) {
0 ignored issues
show
Bug introduced by
The class Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
209
			$this->trapError($e->getCode(), $e->getMessage());
210
		}
211
	}
212
}
213