Yaffs site version 1.1
[yaffs-website] / vendor / symfony / http-kernel / Profiler / BaseMemcacheProfilerStorage.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\HttpKernel\Profiler;
13
14 @trigger_error('The '.__NAMESPACE__.'\BaseMemcacheProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED);
15
16 /**
17  * Base Memcache storage for profiling information in a Memcache.
18  *
19  * @author Andrej Hudec <pulzarraider@gmail.com>
20  *
21  * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0.
22  *             Use {@link FileProfilerStorage} instead.
23  */
24 abstract class BaseMemcacheProfilerStorage implements ProfilerStorageInterface
25 {
26     const TOKEN_PREFIX = 'sf_profiler_';
27
28     protected $dsn;
29     protected $lifetime;
30
31     /**
32      * Constructor.
33      *
34      * @param string $dsn      A data source name
35      * @param string $username
36      * @param string $password
37      * @param int    $lifetime The lifetime to use for the purge
38      */
39     public function __construct($dsn, $username = '', $password = '', $lifetime = 86400)
40     {
41         $this->dsn = $dsn;
42         $this->lifetime = (int) $lifetime;
43     }
44
45     /**
46      * {@inheritdoc}
47      */
48     public function find($ip, $url, $limit, $method, $start = null, $end = null)
49     {
50         $indexName = $this->getIndexName();
51
52         $indexContent = $this->getValue($indexName);
53         if (!$indexContent) {
54             return array();
55         }
56
57         $profileList = explode("\n", $indexContent);
58         $result = array();
59
60         foreach ($profileList as $item) {
61             if ($limit === 0) {
62                 break;
63             }
64
65             if ($item == '') {
66                 continue;
67             }
68
69             $values = explode("\t", $item, 7);
70             list($itemToken, $itemIp, $itemMethod, $itemUrl, $itemTime, $itemParent) = $values;
71             $statusCode = isset($values[6]) ? $values[6] : null;
72
73             $itemTime = (int) $itemTime;
74
75             if ($ip && false === strpos($itemIp, $ip) || $url && false === strpos($itemUrl, $url) || $method && false === strpos($itemMethod, $method)) {
76                 continue;
77             }
78
79             if (!empty($start) && $itemTime < $start) {
80                 continue;
81             }
82
83             if (!empty($end) && $itemTime > $end) {
84                 continue;
85             }
86
87             $result[$itemToken] = array(
88                 'token' => $itemToken,
89                 'ip' => $itemIp,
90                 'method' => $itemMethod,
91                 'url' => $itemUrl,
92                 'time' => $itemTime,
93                 'parent' => $itemParent,
94                 'status_code' => $statusCode,
95             );
96             --$limit;
97         }
98
99         usort($result, function ($a, $b) {
100             if ($a['time'] === $b['time']) {
101                 return 0;
102             }
103
104             return $a['time'] > $b['time'] ? -1 : 1;
105         });
106
107         return $result;
108     }
109
110     /**
111      * {@inheritdoc}
112      */
113     public function purge()
114     {
115         // delete only items from index
116         $indexName = $this->getIndexName();
117
118         $indexContent = $this->getValue($indexName);
119
120         if (!$indexContent) {
121             return false;
122         }
123
124         $profileList = explode("\n", $indexContent);
125
126         foreach ($profileList as $item) {
127             if ($item == '') {
128                 continue;
129             }
130
131             if (false !== $pos = strpos($item, "\t")) {
132                 $this->delete($this->getItemName(substr($item, 0, $pos)));
133             }
134         }
135
136         return $this->delete($indexName);
137     }
138
139     /**
140      * {@inheritdoc}
141      */
142     public function read($token)
143     {
144         if (empty($token)) {
145             return false;
146         }
147
148         $profile = $this->getValue($this->getItemName($token));
149
150         if (false !== $profile) {
151             $profile = $this->createProfileFromData($token, $profile);
152         }
153
154         return $profile;
155     }
156
157     /**
158      * {@inheritdoc}
159      */
160     public function write(Profile $profile)
161     {
162         $data = array(
163             'token' => $profile->getToken(),
164             'parent' => $profile->getParentToken(),
165             'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()),
166             'data' => $profile->getCollectors(),
167             'ip' => $profile->getIp(),
168             'method' => $profile->getMethod(),
169             'url' => $profile->getUrl(),
170             'time' => $profile->getTime(),
171         );
172
173         $profileIndexed = false !== $this->getValue($this->getItemName($profile->getToken()));
174
175         if ($this->setValue($this->getItemName($profile->getToken()), $data, $this->lifetime)) {
176             if (!$profileIndexed) {
177                 // Add to index
178                 $indexName = $this->getIndexName();
179
180                 $indexRow = implode("\t", array(
181                     $profile->getToken(),
182                     $profile->getIp(),
183                     $profile->getMethod(),
184                     $profile->getUrl(),
185                     $profile->getTime(),
186                     $profile->getParentToken(),
187                     $profile->getStatusCode(),
188                 ))."\n";
189
190                 return $this->appendValue($indexName, $indexRow, $this->lifetime);
191             }
192
193             return true;
194         }
195
196         return false;
197     }
198
199     /**
200      * Retrieve item from the memcache server.
201      *
202      * @param string $key
203      *
204      * @return mixed
205      */
206     abstract protected function getValue($key);
207
208     /**
209      * Store an item on the memcache server under the specified key.
210      *
211      * @param string $key
212      * @param mixed  $value
213      * @param int    $expiration
214      *
215      * @return bool
216      */
217     abstract protected function setValue($key, $value, $expiration = 0);
218
219     /**
220      * Delete item from the memcache server.
221      *
222      * @param string $key
223      *
224      * @return bool
225      */
226     abstract protected function delete($key);
227
228     /**
229      * Append data to an existing item on the memcache server.
230      *
231      * @param string $key
232      * @param string $value
233      * @param int    $expiration
234      *
235      * @return bool
236      */
237     abstract protected function appendValue($key, $value, $expiration = 0);
238
239     private function createProfileFromData($token, $data, $parent = null)
240     {
241         $profile = new Profile($token);
242         $profile->setIp($data['ip']);
243         $profile->setMethod($data['method']);
244         $profile->setUrl($data['url']);
245         $profile->setTime($data['time']);
246         $profile->setCollectors($data['data']);
247
248         if (!$parent && $data['parent']) {
249             $parent = $this->read($data['parent']);
250         }
251
252         if ($parent) {
253             $profile->setParent($parent);
254         }
255
256         foreach ($data['children'] as $token) {
257             if (!$token) {
258                 continue;
259             }
260
261             if (!$childProfileData = $this->getValue($this->getItemName($token))) {
262                 continue;
263             }
264
265             $profile->addChild($this->createProfileFromData($token, $childProfileData, $profile));
266         }
267
268         return $profile;
269     }
270
271     /**
272      * Get item name.
273      *
274      * @param string $token
275      *
276      * @return string
277      */
278     private function getItemName($token)
279     {
280         $name = self::TOKEN_PREFIX.$token;
281
282         if ($this->isItemNameValid($name)) {
283             return $name;
284         }
285
286         return false;
287     }
288
289     /**
290      * Get name of index.
291      *
292      * @return string
293      */
294     private function getIndexName()
295     {
296         $name = self::TOKEN_PREFIX.'index';
297
298         if ($this->isItemNameValid($name)) {
299             return $name;
300         }
301
302         return false;
303     }
304
305     private function isItemNameValid($name)
306     {
307         $length = strlen($name);
308
309         if ($length > 250) {
310             throw new \RuntimeException(sprintf('The memcache item key "%s" is too long (%s bytes). Allowed maximum size is 250 bytes.', $name, $length));
311         }
312
313         return true;
314     }
315 }