Verzeichnisstruktur phpBB-3.1.0
- Veröffentlicht
- 27.10.2014
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
RedisProfilerStorage.php
001 <?php
002
003 /*
004 * This file is part of the Symfony package.
005 *
006 * (c) Fabien Potencier <fabien@symfony.com>
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 namespace Symfony\Component\HttpKernel\Profiler;
013
014 /**
015 * RedisProfilerStorage stores profiling information in Redis.
016 *
017 * @author Andrej Hudec <pulzarraider@gmail.com>
018 * @author Stephane PY <py.stephane1@gmail.com>
019 */
020 class RedisProfilerStorage implements ProfilerStorageInterface
021 {
022 const TOKEN_PREFIX = 'sf_profiler_';
023
024 const REDIS_OPT_SERIALIZER = 1;
025 const REDIS_OPT_PREFIX = 2;
026 const REDIS_SERIALIZER_NONE = 0;
027 const REDIS_SERIALIZER_PHP = 1;
028
029 protected $dsn;
030 protected $lifetime;
031
032 /**
033 * @var \Redis
034 */
035 private $redis;
036
037 /**
038 * Constructor.
039 *
040 * @param string $dsn A data source name
041 * @param string $username Not used
042 * @param string $password Not used
043 * @param int $lifetime The lifetime to use for the purge
044 */
045 public function __construct($dsn, $username = '', $password = '', $lifetime = 86400)
046 {
047 $this->dsn = $dsn;
048 $this->lifetime = (int) $lifetime;
049 }
050
051 /**
052 * {@inheritdoc}
053 */
054 public function find($ip, $url, $limit, $method, $start = null, $end = null)
055 {
056 $indexName = $this->getIndexName();
057
058 if (!$indexContent = $this->getValue($indexName, self::REDIS_SERIALIZER_NONE)) {
059 return array();
060 }
061
062 $profileList = array_reverse(explode("\n", $indexContent));
063 $result = array();
064
065 foreach ($profileList as $item) {
066 if ($limit === 0) {
067 break;
068 }
069
070 if ($item == '') {
071 continue;
072 }
073
074 list($itemToken, $itemIp, $itemMethod, $itemUrl, $itemTime, $itemParent) = explode("\t", $item, 6);
075
076 $itemTime = (int) $itemTime;
077
078 if ($ip && false === strpos($itemIp, $ip) || $url && false === strpos($itemUrl, $url) || $method && false === strpos($itemMethod, $method)) {
079 continue;
080 }
081
082 if (!empty($start) && $itemTime < $start) {
083 continue;
084 }
085
086 if (!empty($end) && $itemTime > $end) {
087 continue;
088 }
089
090 $result[] = array(
091 'token' => $itemToken,
092 'ip' => $itemIp,
093 'method' => $itemMethod,
094 'url' => $itemUrl,
095 'time' => $itemTime,
096 'parent' => $itemParent,
097 );
098 --$limit;
099 }
100
101 return $result;
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function purge()
108 {
109 // delete only items from index
110 $indexName = $this->getIndexName();
111
112 $indexContent = $this->getValue($indexName, self::REDIS_SERIALIZER_NONE);
113
114 if (!$indexContent) {
115 return false;
116 }
117
118 $profileList = explode("\n", $indexContent);
119
120 $result = array();
121
122 foreach ($profileList as $item) {
123 if ($item == '') {
124 continue;
125 }
126
127 if (false !== $pos = strpos($item, "\t")) {
128 $result[] = $this->getItemName(substr($item, 0, $pos));
129 }
130 }
131
132 $result[] = $indexName;
133
134 return $this->delete($result);
135 }
136
137 /**
138 * {@inheritdoc}
139 */
140 public function read($token)
141 {
142 if (empty($token)) {
143 return false;
144 }
145
146 $profile = $this->getValue($this->getItemName($token), self::REDIS_SERIALIZER_PHP);
147
148 if (false !== $profile) {
149 $profile = $this->createProfileFromData($token, $profile);
150 }
151
152 return $profile;
153 }
154
155 /**
156 * {@inheritdoc}
157 */
158 public function write(Profile $profile)
159 {
160 $data = array(
161 'token' => $profile->getToken(),
162 'parent' => $profile->getParentToken(),
163 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()),
164 'data' => $profile->getCollectors(),
165 'ip' => $profile->getIp(),
166 'method' => $profile->getMethod(),
167 'url' => $profile->getUrl(),
168 'time' => $profile->getTime(),
169 );
170
171 $profileIndexed = false !== $this->getValue($this->getItemName($profile->getToken()));
172
173 if ($this->setValue($this->getItemName($profile->getToken()), $data, $this->lifetime, self::REDIS_SERIALIZER_PHP)) {
174 if (!$profileIndexed) {
175 // Add to index
176 $indexName = $this->getIndexName();
177
178 $indexRow = implode("\t", array(
179 $profile->getToken(),
180 $profile->getIp(),
181 $profile->getMethod(),
182 $profile->getUrl(),
183 $profile->getTime(),
184 $profile->getParentToken(),
185 ))."\n";
186
187 return $this->appendValue($indexName, $indexRow, $this->lifetime);
188 }
189
190 return true;
191 }
192
193 return false;
194 }
195
196 /**
197 * Internal convenience method that returns the instance of Redis.
198 *
199 * @return \Redis
200 *
201 * @throws \RuntimeException
202 */
203 protected function getRedis()
204 {
205 if (null === $this->redis) {
206 $data = parse_url($this->dsn);
207
208 if (false === $data || !isset($data['scheme']) || $data['scheme'] !== 'redis' || !isset($data['host']) || !isset($data['port'])) {
209 throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Redis with an invalid dsn "%s". The minimal expected format is "redis://[host]:port".', $this->dsn));
210 }
211
212 if (!extension_loaded('redis')) {
213 throw new \RuntimeException('RedisProfilerStorage requires that the redis extension is loaded.');
214 }
215
216 $redis = new \Redis();
217 $redis->connect($data['host'], $data['port']);
218
219 if (isset($data['path'])) {
220 $redis->select(substr($data['path'], 1));
221 }
222
223 if (isset($data['pass'])) {
224 $redis->auth($data['pass']);
225 }
226
227 $redis->setOption(self::REDIS_OPT_PREFIX, self::TOKEN_PREFIX);
228
229 $this->redis = $redis;
230 }
231
232 return $this->redis;
233 }
234
235 /**
236 * Set instance of the Redis
237 *
238 * @param \Redis $redis
239 */
240 public function setRedis($redis)
241 {
242 $this->redis = $redis;
243 }
244
245 private function createProfileFromData($token, $data, $parent = null)
246 {
247 $profile = new Profile($token);
248 $profile->setIp($data['ip']);
249 $profile->setMethod($data['method']);
250 $profile->setUrl($data['url']);
251 $profile->setTime($data['time']);
252 $profile->setCollectors($data['data']);
253
254 if (!$parent && $data['parent']) {
255 $parent = $this->read($data['parent']);
256 }
257
258 if ($parent) {
259 $profile->setParent($parent);
260 }
261
262 foreach ($data['children'] as $token) {
263 if (!$token) {
264 continue;
265 }
266
267 if (!$childProfileData = $this->getValue($this->getItemName($token), self::REDIS_SERIALIZER_PHP)) {
268 continue;
269 }
270
271 $profile->addChild($this->createProfileFromData($token, $childProfileData, $profile));
272 }
273
274 return $profile;
275 }
276
277 /**
278 * Gets the item name.
279 *
280 * @param string $token
281 *
282 * @return string
283 */
284 private function getItemName($token)
285 {
286 $name = $token;
287
288 if ($this->isItemNameValid($name)) {
289 return $name;
290 }
291
292 return false;
293 }
294
295 /**
296 * Gets the name of the index.
297 *
298 * @return string
299 */
300 private function getIndexName()
301 {
302 $name = 'index';
303
304 if ($this->isItemNameValid($name)) {
305 return $name;
306 }
307
308 return false;
309 }
310
311 private function isItemNameValid($name)
312 {
313 $length = strlen($name);
314
315 if ($length > 2147483648) {
316 throw new \RuntimeException(sprintf('The Redis item key "%s" is too long (%s bytes). Allowed maximum size is 2^31 bytes.', $name, $length));
317 }
318
319 return true;
320 }
321
322 /**
323 * Retrieves an item from the Redis server.
324 *
325 * @param string $key
326 * @param int $serializer
327 *
328 * @return mixed
329 */
330 private function getValue($key, $serializer = self::REDIS_SERIALIZER_NONE)
331 {
332 $redis = $this->getRedis();
333 $redis->setOption(self::REDIS_OPT_SERIALIZER, $serializer);
334
335 return $redis->get($key);
336 }
337
338 /**
339 * Stores an item on the Redis server under the specified key.
340 *
341 * @param string $key
342 * @param mixed $value
343 * @param int $expiration
344 * @param int $serializer
345 *
346 * @return bool
347 */
348 private function setValue($key, $value, $expiration = 0, $serializer = self::REDIS_SERIALIZER_NONE)
349 {
350 $redis = $this->getRedis();
351 $redis->setOption(self::REDIS_OPT_SERIALIZER, $serializer);
352
353 return $redis->setex($key, $expiration, $value);
354 }
355
356 /**
357 * Appends data to an existing item on the Redis server.
358 *
359 * @param string $key
360 * @param string $value
361 * @param int $expiration
362 *
363 * @return bool
364 */
365 private function appendValue($key, $value, $expiration = 0)
366 {
367 $redis = $this->getRedis();
368 $redis->setOption(self::REDIS_OPT_SERIALIZER, self::REDIS_SERIALIZER_NONE);
369
370 if ($redis->exists($key)) {
371 $redis->append($key, $value);
372
373 return $redis->setTimeout($key, $expiration);
374 }
375
376 return $redis->setex($key, $expiration, $value);
377 }
378
379 /**
380 * Removes the specified keys.
381 *
382 * @param array $keys
383 *
384 * @return bool
385 */
386 private function delete(array $keys)
387 {
388 return (bool) $this->getRedis()->delete($keys);
389 }
390 }
391