1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file
|
5
|
* Contains the FlagCookieStorage class.
|
6
|
*/
|
7
|
|
8
|
/**
|
9
|
* Utility class to handle cookies.
|
10
|
*
|
11
|
* Cookies are used to record flaggings for anonymous users on cached pages.
|
12
|
*
|
13
|
* This class contains only two instance methods. Usage example:
|
14
|
* @code
|
15
|
* $storage = FlagCookieStorage::factory($flag);
|
16
|
* $storage->flag(145);
|
17
|
* $storage->unflag(17);
|
18
|
* @endcode
|
19
|
*
|
20
|
* You may delete all the cookies with <code>FlagCookieStorage::drop()</code>.
|
21
|
*/
|
22
|
abstract class FlagCookieStorage {
|
23
|
|
24
|
/**
|
25
|
* Returns the actual storage object compatible with the flag.
|
26
|
*/
|
27
|
static function factory($flag) {
|
28
|
if ($flag->global) {
|
29
|
return new FlagGlobalCookieStorage($flag);
|
30
|
}
|
31
|
else {
|
32
|
return new FlagNonGlobalCookieStorage($flag);
|
33
|
}
|
34
|
}
|
35
|
|
36
|
function __construct($flag) {
|
37
|
$this->flag = $flag;
|
38
|
}
|
39
|
|
40
|
/**
|
41
|
* "Flags" an item.
|
42
|
*
|
43
|
* It just records this fact in a cookie.
|
44
|
*/
|
45
|
abstract function flag($entity_id);
|
46
|
|
47
|
/**
|
48
|
* "Unflags" an item.
|
49
|
*
|
50
|
* It just records this fact in a cookie.
|
51
|
*/
|
52
|
abstract function unflag($entity_id);
|
53
|
|
54
|
/**
|
55
|
* Deletes all the cookies.
|
56
|
*
|
57
|
* (Etymology: "drop" as in "drop database".)
|
58
|
*/
|
59
|
static function drop() {
|
60
|
FlagGlobalCookieStorage::drop();
|
61
|
FlagNonGlobalCookieStorage::drop();
|
62
|
}
|
63
|
}
|
64
|
|
65
|
/**
|
66
|
* Storage handler for global flags.
|
67
|
*/
|
68
|
class FlagGlobalCookieStorage extends FlagCookieStorage {
|
69
|
|
70
|
function flag($entity_id) {
|
71
|
$cookie_key = $this->cookie_key($entity_id);
|
72
|
setcookie($cookie_key, 1, REQUEST_TIME + $this->get_lifetime(), base_path());
|
73
|
$_COOKIE[$cookie_key] = 1;
|
74
|
}
|
75
|
|
76
|
function unflag($entity_id) {
|
77
|
$cookie_key = $this->cookie_key($entity_id);
|
78
|
setcookie($cookie_key, 0, REQUEST_TIME + $this->get_lifetime(), base_path());
|
79
|
$_COOKIE[$cookie_key] = 0;
|
80
|
}
|
81
|
|
82
|
// Global flags persist for the length of the minimum cache lifetime.
|
83
|
protected function get_lifetime() {
|
84
|
$cookie_lifetime = variable_get('cache', 0) ? variable_get('cache_lifetime', 0) : -1;
|
85
|
// Do not let the cookie lifetime be 0 (which is the no cache limit on
|
86
|
// anonymous page caching), since it would expire immediately. Usually
|
87
|
// the no cache limit means caches are cleared on cron, which usually runs
|
88
|
// at least once an hour.
|
89
|
if ($cookie_lifetime == 0) {
|
90
|
$cookie_lifetime = 3600;
|
91
|
}
|
92
|
return $cookie_lifetime;
|
93
|
}
|
94
|
|
95
|
protected function cookie_key($entity_id) {
|
96
|
return 'flag_global_' . $this->flag->name . '_' . $entity_id;
|
97
|
}
|
98
|
|
99
|
/**
|
100
|
* Deletes all the global cookies.
|
101
|
*/
|
102
|
static function drop() {
|
103
|
foreach ($_COOKIE as $key => $value) {
|
104
|
if (strpos($key, 'flag_global_') === 0) {
|
105
|
setcookie($key, FALSE, 0, base_path());
|
106
|
unset($_COOKIE[$key]);
|
107
|
}
|
108
|
}
|
109
|
}
|
110
|
}
|
111
|
|
112
|
/**
|
113
|
* Storage handler for non-global flags.
|
114
|
*/
|
115
|
class FlagNonGlobalCookieStorage extends FlagCookieStorage {
|
116
|
|
117
|
// The anonymous per-user flaggings are stored in a single cookie, so that
|
118
|
// all of them persist as long as the Drupal cookie lifetime.
|
119
|
|
120
|
function __construct($flag) {
|
121
|
parent::__construct($flag);
|
122
|
$this->flaggings = isset($_COOKIE['flags']) ? explode(' ', $_COOKIE['flags']) : array();
|
123
|
}
|
124
|
|
125
|
function flag($entity_id) {
|
126
|
if (!$this->is_flagged($entity_id)) {
|
127
|
$this->flaggings[] = $this->cookie_key($entity_id);
|
128
|
$this->write();
|
129
|
}
|
130
|
}
|
131
|
|
132
|
function unflag($entity_id) {
|
133
|
if (($index = $this->index_of($entity_id)) !== FALSE) {
|
134
|
unset($this->flaggings[$index]);
|
135
|
$this->write();
|
136
|
}
|
137
|
}
|
138
|
|
139
|
protected function get_lifetime() {
|
140
|
return min((int) ini_get('session.cookie_lifetime'), (int) ini_get('session.gc_maxlifetime'));
|
141
|
}
|
142
|
|
143
|
protected function cookie_key($entity_id) {
|
144
|
return $this->flag->name . '_' . $entity_id;
|
145
|
}
|
146
|
|
147
|
protected function write() {
|
148
|
$serialized = implode(' ', array_filter($this->flaggings));
|
149
|
setcookie('flags', $serialized, REQUEST_TIME + $this->get_lifetime(), base_path());
|
150
|
$_COOKIE['flags'] = $serialized;
|
151
|
}
|
152
|
|
153
|
protected function is_flagged($entity_id) {
|
154
|
return $this->index_of($entity_id) !== FALSE;
|
155
|
}
|
156
|
|
157
|
protected function index_of($entity_id) {
|
158
|
return array_search($this->cookie_key($entity_id), $this->flaggings);
|
159
|
}
|
160
|
|
161
|
/**
|
162
|
* Deletes the cookie.
|
163
|
*/
|
164
|
static function drop() {
|
165
|
if (isset($_COOKIE['flags'])) {
|
166
|
setcookie('flags', FALSE, 0, base_path());
|
167
|
unset($_COOKIE['flags']);
|
168
|
}
|
169
|
}
|
170
|
}
|