forked from alchemy-fr/Phlickr
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Cache.php
282 lines (267 loc) · 8.99 KB
/
Cache.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
<?php
/**
* @version $Id$
* @author Andrew Morton <[email protected]>
* @license http://opensource.org/licenses/lgpl-license.php
* GNU Lesser General Public License, Version 2.1
* @package Phlickr
*/
/**
* Phlickr_Api includes the core classes.
*/
require_once dirname(__FILE__) . '/Api.php';
/**
* The Phlickr_Cache stores responses to previous Flickr API calls.
*
* Sample usage:
* <code>
* <?php
* include_once '/Api.php';
*
* $cache = new Phlickr_Cache();
*
* // add a value to the cache.
* $cache->set('http://example.com/', 'sample response');
*
* // verify that it exists in the cache.
* print $cache->has('http://example.com/');
*
* // retrieve a value from the cache.
* print $cache->has('http://example.com/');
* ?>
* </code>
*
*
* Serialization Example:
* <code>
* <?php
* include_once '/Api.php';
* include_once '/User.php';
*
* // file to save the cache into
* define('FILENAME', '/tmp/phlickr.cache');
*
* $api = new Phlickr_Api(FLICKR_API_KEY, FLICKR_API_SECRET, FLICKR_TOKEN);
*
* // if there's a saved cache file load and unserialize it.
* $api->setCache(Phlickr_Cache::createFrom(FILENAME));
*
* // print out your 10 newest photos
* $user = new Phlickr_User($api, $api->getUserId());
* foreach ($user->getPhotoList()->getPhotos(10) as $photo) {
* // getting the tags causes a separate request. caching is a big help here.
* printf("Photo: %s\n\tTags: %s \n",
* $photo->getTitle(),
* implode(',', $photo->getTags())
* );
* }
*
* // serialize and save the cache file
* $api->getCache()->saveAs(FILENAME);
* ?>
* </code>
*
* This class is responsible for:
* - Associating a full request's URL with it's XML response. This means that
* separate users should be able to share a cache.
* - Tracking the expiration times of each URL so that older, possibly invalid
* data is removed from the cache.
* - Hashing URLs so minimize the risk of displaying passwords that are
* included as parameters.
* - Providing a single class to serialize to allow request results to be
* stored across sessions.
*
* There were two motivations behind the design of this class:
* - Allowing offline unit testing. This speeds up the time it takes to run the
* tests and allows me to use the real Phlickr classes instead of mocks or
* stubs.
* - Letting me run one large search for photos with a certain tag, then
* display a unique photo each time a webpage was displayed. I didn't want to
* wait for a request each time the page was loaded and wanted the the photos
* to be randomized.
*
* @package Phlickr
* @author Andrew Morton <[email protected]>
* @since 0.1.6
*/
class Phlickr_Cache {
/**
* By default a cache entry is valid for 1 hour or 3600 seconds.
*
* @var integer
* @see __construct(), getShelfLife()
*/
const DEFAULT_SHELF_LIFE = 3600;
/**
* Array of cached values. The key is the MD5 hash of the URL and the value
* is a string with the XML result.
*
* @var array
*/
private $_values;
/**
* Array of expiration timestamps. The key is the MD5 hash of the URL and
* the value is an integer timestamp when the entry expires.
*
* @var array
*/
private $_expires;
/**
* Default shelf life in seconds.
*
* @var integer
* @see getShelfLife(), setShelfLife(), DEFAULT_SHELF_LIFE
*/
private $_shelfLife;
/**
* Constructor.
*
* @param integer $shelfLife The default number of seconds to store an
* entry.
* @see getShelfLife(), DEFAULT_SHELF_LIFE
*/
public function __construct($shelfLife = self::DEFAULT_SHELF_LIFE) {
$this->_values = array();
$this->_expires = array();
$this->_shelfLife = (integer) $shelfLife;
}
/**
* Load a serialized cache object from a file.
*
* If the file does not exist, is invalid, or cannot be loaded, then a new,
* empty, cache object will be created and returned.
*
* @param string $fileName Name of the file containing the serialized
* cache object.
* @param integer $defaultShelfLife The default number of seconds to
* store an entry.
* @return object Phlickr_Cache
* @since 0.2.1
* @see saveAs()
*/
static public function createFrom($fileName, $shelfLife = self::DEFAULT_SHELF_LIFE) {
if (file_exists($fileName)) {
$cache = unserialize(file_get_contents($fileName));
if (!is_null($cache) && ($cache instanceof Phlickr_Cache)) {
$cache->setShelfLife($shelfLife);
return $cache;
}
}
return new Phlickr_Cache($shelfLife);
}
/**
* Attempt to retrieve a response from the cache.
*
* If there's a cached response, an XML string that is ready for use with
* a Phlickr_Response will be returned. if . If not, return null.
*
* @param string $url The Phlickr_Request's complete URL.
* @return string If there's a cached response, an XML string ready for
* use with a Phlickr_Response. If not, return null.
* @since 0.1.6
* @see has(), set()
*/
public function get($url) {
if ($this->has($url)) {
// use MD5 to obscure passwords in the urls
return $this->_values[md5($url)];
}
return null;
}
/**
* Get the default number of seconds a cached entry is considered valid.
*
* This value is used if none is specified when adding an entry with set().
* A negative return value indicates that entries will not expire. A return
* value of 0 indicates that no entries will be cached.
*
* @return integer
* @since 0.2.3
* @see __construct(), setShelfLife(), DEFAULT_SHELF_LIFE
*/
public function getShelfLife() {
return $this->_shelfLife;
}
/**
* Cache a URL/response pair.
*
* Setting the $shelfLife parameter to 0 is equivalent to removing an entry
* from the cache.
*
* @param string $url The Phlickr_Request's complete URL.
* @param mixed $response Typically this is a XML string that will be
* passed to a Phlickr_Response. Other datatypes are allowed, and
* preserved so that applications can use this object for caching.
* @param integer $shelfLife The number of seconds this response is
* considered valid. A value of 0 indicates it should not be
* cached, while a negative number indicates it should not expire.
* If this parameter is omitted, the value returned by
* getShelfLife() will be used in its place.
* @return void
* @since 0.1.6
* @see get(), has(), getShelfLife()
*/
public function set($url, $response, $shelfLife = null) {
// use MD5 to obscure passwords in the urls
$md5 = md5($url);
$shelfLife = (is_int($shelfLife)) ? $shelfLife : $this->getShelfLife();
if ($shelfLife == 0) {
// remove any existing values
unset($this->_values[$md5]);
unset($this->_expires[$md5]);
} else {
// if the shelf life is positive add it to the current time.
if ($shelfLife > 0) {
$this->_expires[$md5] = time() + $shelfLife;
}
$this->_values[$md5] = $response;
}
}
/**
* Set the default number of seconds a cached entry is considered valid.
*
* This value is used if none is specified when adding an entry with set().
* A negative return value indicates that entries will not expire. A return
* value of 0 indicates that no entries will be cached.
*
* @param integer $shelfLife Number of seconds
* @return void
* @since 0.2.3
* @see __construct(), getShelfLife(), DEFAULT_SHELF_LIFE
*/
public function setShelfLife($shelfLife) {
$this->_shelfLife = (integer) $shelfLife;
}
/**
* Return a boolean value indicating if the cache has a valid reponse for
* a given URL.
*
* @param string $url The URL.
* @return boolean
* @since 0.1.6
* @see get(), set()
*/
public function has($url) {
$md5 = md5($url);
// check if there is an expiration time, and if it has passed
if (isset($this->_expires[$md5]) && $this->_expires[$md5] < time()) {
unset($this->_values[$md5]);
unset($this->_expires[$md5]);
return false;
} else {
return isset($this->_values[$md5]);
}
}
/**
* Serialize this object and save it to a file.
*
* @param string $fileName The filename where the cache will be saved.
* @return void
* @since 0.2.1
* @see createFrom()
* @todo Add some code to remove expired entries before saving.
*/
public function saveAs($fileName) {
file_put_contents($fileName, serialize($this));
}
}