1
|
|
|
<?php |
|
|
|
|
2
|
|
|
|
3
|
|
|
require_once(dirname(dirname(dirname(__FILE__))).'/view/TemplateGlobalProvider.php'); |
4
|
|
|
require_once(dirname(dirname(dirname(__FILE__))).'/control/Director.php'); |
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* A chain of confirmation tokens to be validated on each request. This allows the application to |
8
|
|
|
* check multiple tokens at once without having to potentially redirect the user for each of them |
9
|
|
|
* |
10
|
|
|
* @internal This class is designed specifically for use pre-startup and may change without warning |
11
|
|
|
*/ |
12
|
|
|
class ConfirmationTokenChain |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* @var array |
16
|
|
|
*/ |
17
|
|
|
protected $tokens = array(); |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @param AbstractConfirmationToken $token |
21
|
|
|
*/ |
22
|
|
|
public function pushToken(AbstractConfirmationToken $token) { |
23
|
|
|
$this->tokens[] = $token; |
24
|
|
|
} |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Collect all tokens that require a redirect |
28
|
|
|
* |
29
|
|
|
* @return array |
30
|
|
|
*/ |
31
|
|
|
protected function filteredTokens() { |
32
|
|
|
$result = array(); |
33
|
|
|
foreach ($this->tokens as $token) { |
34
|
|
|
if ($token->reloadRequired()) { |
35
|
|
|
$result[] = $token; |
36
|
|
|
} |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
return $result; |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @return bool |
44
|
|
|
*/ |
45
|
|
|
public function suppressionRequired() { |
46
|
|
|
return (count($this->filteredTokens()) !== 0); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Suppress URLs & GET vars from tokens that require a redirect |
51
|
|
|
*/ |
52
|
|
|
public function suppressTokens() { |
53
|
|
|
foreach ($this->filteredTokens() as $token) { |
54
|
|
|
$token->suppress(); |
55
|
|
|
} |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @return bool |
60
|
|
|
*/ |
61
|
|
|
public function reloadRequired() { |
62
|
|
|
foreach ($this->tokens as $token) { |
63
|
|
|
if ($token->reloadRequired()) { |
64
|
|
|
return true; |
65
|
|
|
} |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
return false; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @return bool |
73
|
|
|
*/ |
74
|
|
|
public function reloadRequiredIfError() { |
75
|
|
|
foreach ($this->tokens as $token) { |
76
|
|
|
if ($token->reloadRequiredIfError()) { |
77
|
|
|
return true; |
78
|
|
|
} |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
return false; |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @param bool $includeToken |
86
|
|
|
* @return array |
87
|
|
|
*/ |
88
|
|
|
public function params($includeToken = true) { |
89
|
|
|
$params = array(); |
90
|
|
|
foreach ($this->tokens as $token) { |
91
|
|
|
$params = array_merge($params, $token->params($includeToken)); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
return $params; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Fetch the URL we want to redirect to, excluding query string parameters. This may |
99
|
|
|
* be the same URL (with a token to be added outside this method), or to a different |
100
|
|
|
* URL if the current one has been suppressed |
101
|
|
|
* |
102
|
|
|
* @return string |
103
|
|
|
*/ |
104
|
|
|
public function getRedirectUrlBase() { |
105
|
|
|
// URLConfirmationTokens may alter the URL to suppress the URL they're protecting, |
106
|
|
|
// so we need to ensure they're inspected last and therefore take priority |
107
|
|
|
$tokens = $this->filteredTokens(); |
108
|
|
|
usort($tokens, function ($a, $b) { |
|
|
|
|
109
|
|
|
return ($a instanceof URLConfirmationToken) ? 1 : 0; |
110
|
|
|
}); |
111
|
|
|
|
112
|
|
|
$urlBase = Director::baseURL(); |
113
|
|
|
foreach ($tokens as $token) { |
114
|
|
|
$urlBase = $token->getRedirectUrlBase(); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
return $urlBase; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Collate GET vars from all token providers that need to apply a token |
122
|
|
|
* |
123
|
|
|
* @return array |
124
|
|
|
*/ |
125
|
|
|
public function getRedirectUrlParams() { |
126
|
|
|
$params = array(); |
127
|
|
|
foreach ($this->filteredTokens() as $token) { |
128
|
|
|
$params = array_merge($params, $token->getRedirectUrlParams()); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
return $params; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @return string |
136
|
|
|
*/ |
137
|
|
|
protected function redirectURL() { |
138
|
|
|
$params = http_build_query($this->getRedirectUrlParams()); |
139
|
|
|
return $this->getRedirectUrlBase() . '?' . $params; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Forces a reload of the request with the applicable tokens included |
144
|
|
|
*/ |
145
|
|
|
public function reloadWithToken() { |
146
|
|
|
require_once(dirname(dirname(__FILE__)).'/Convert.php'); |
147
|
|
|
$location = $this->redirectURL(); |
148
|
|
|
$locationJS = Convert::raw2js($location); |
149
|
|
|
$locationATT = Convert::raw2att($location); |
150
|
|
|
|
151
|
|
|
if (headers_sent()) { |
152
|
|
|
echo " |
153
|
|
|
<script>location.href='{$locationJS}';</script> |
154
|
|
|
<noscript><meta http-equiv='refresh' content='0; url={$locationATT}'></noscript> |
155
|
|
|
You are being redirected. If you are not redirected soon, <a href='{$locationATT}'>click here to continue</a> |
156
|
|
|
"; |
157
|
|
|
} else { |
158
|
|
|
header("location: {$location}", true, 302); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
die; |
|
|
|
|
162
|
|
|
} |
163
|
|
|
} |
164
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.