Yaffs site version 1.1
[yaffs-website] / vendor / symfony / http-kernel / Profiler / PdoProfilerStorage.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__.'\PdoProfilerStorage class is deprecated since Symfony 2.8 and will be removed in 3.0. Use FileProfilerStorage instead.', E_USER_DEPRECATED);
15
16 /**
17  * Base PDO storage for profiling information in a PDO database.
18  *
19  * @author Fabien Potencier <fabien@symfony.com>
20  * @author Jan Schumann <js@schumann-it.com>
21  *
22  * @deprecated Deprecated since Symfony 2.8, to be removed in Symfony 3.0.
23  *             Use {@link FileProfilerStorage} instead.
24  */
25 abstract class PdoProfilerStorage implements ProfilerStorageInterface
26 {
27     protected $dsn;
28     protected $username;
29     protected $password;
30     protected $lifetime;
31     protected $db;
32
33     /**
34      * Constructor.
35      *
36      * @param string $dsn      A data source name
37      * @param string $username The username for the database
38      * @param string $password The password for the database
39      * @param int    $lifetime The lifetime to use for the purge
40      */
41     public function __construct($dsn, $username = '', $password = '', $lifetime = 86400)
42     {
43         $this->dsn = $dsn;
44         $this->username = $username;
45         $this->password = $password;
46         $this->lifetime = (int) $lifetime;
47     }
48
49     /**
50      * {@inheritdoc}
51      */
52     public function find($ip, $url, $limit, $method, $start = null, $end = null)
53     {
54         if (null === $start) {
55             $start = 0;
56         }
57
58         if (null === $end) {
59             $end = time();
60         }
61
62         list($criteria, $args) = $this->buildCriteria($ip, $url, $start, $end, $limit, $method);
63
64         $criteria = $criteria ? 'WHERE '.implode(' AND ', $criteria) : '';
65
66         $db = $this->initDb();
67         $tokens = $this->fetch($db, 'SELECT token, ip, method, url, time, parent, status_code FROM sf_profiler_data '.$criteria.' ORDER BY time DESC LIMIT '.((int) $limit), $args);
68         $this->close($db);
69
70         return $tokens;
71     }
72
73     /**
74      * {@inheritdoc}
75      */
76     public function read($token)
77     {
78         $db = $this->initDb();
79         $args = array(':token' => $token);
80         $data = $this->fetch($db, 'SELECT data, parent, ip, method, url, time FROM sf_profiler_data WHERE token = :token LIMIT 1', $args);
81         $this->close($db);
82         if (isset($data[0]['data'])) {
83             return $this->createProfileFromData($token, $data[0]);
84         }
85     }
86
87     /**
88      * {@inheritdoc}
89      */
90     public function write(Profile $profile)
91     {
92         $db = $this->initDb();
93         $args = array(
94             ':token' => $profile->getToken(),
95             ':parent' => $profile->getParentToken(),
96             ':data' => base64_encode(serialize($profile->getCollectors())),
97             ':ip' => $profile->getIp(),
98             ':method' => $profile->getMethod(),
99             ':url' => $profile->getUrl(),
100             ':time' => $profile->getTime(),
101             ':created_at' => time(),
102             ':status_code' => $profile->getStatusCode(),
103         );
104
105         try {
106             if ($this->has($profile->getToken())) {
107                 $this->exec($db, 'UPDATE sf_profiler_data SET parent = :parent, data = :data, ip = :ip, method = :method, url = :url, time = :time, created_at = :created_at, status_code = :status_code WHERE token = :token', $args);
108             } else {
109                 $this->exec($db, 'INSERT INTO sf_profiler_data (token, parent, data, ip, method, url, time, created_at, status_code) VALUES (:token, :parent, :data, :ip, :method, :url, :time, :created_at, :status_code)', $args);
110             }
111             $this->cleanup();
112             $status = true;
113         } catch (\Exception $e) {
114             $status = false;
115         }
116
117         $this->close($db);
118
119         return $status;
120     }
121
122     /**
123      * {@inheritdoc}
124      */
125     public function purge()
126     {
127         $db = $this->initDb();
128         $this->exec($db, 'DELETE FROM sf_profiler_data');
129         $this->close($db);
130     }
131
132     /**
133      * Build SQL criteria to fetch records by ip and url.
134      *
135      * @param string $ip     The IP
136      * @param string $url    The URL
137      * @param string $start  The start period to search from
138      * @param string $end    The end period to search to
139      * @param string $limit  The maximum number of tokens to return
140      * @param string $method The request method
141      *
142      * @return array An array with (criteria, args)
143      */
144     abstract protected function buildCriteria($ip, $url, $start, $end, $limit, $method);
145
146     /**
147      * Initializes the database.
148      *
149      * @throws \RuntimeException When the requested database driver is not installed
150      */
151     abstract protected function initDb();
152
153     protected function cleanup()
154     {
155         $db = $this->initDb();
156         $this->exec($db, 'DELETE FROM sf_profiler_data WHERE created_at < :time', array(':time' => time() - $this->lifetime));
157         $this->close($db);
158     }
159
160     protected function exec($db, $query, array $args = array())
161     {
162         $stmt = $this->prepareStatement($db, $query);
163
164         foreach ($args as $arg => $val) {
165             $stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
166         }
167         $success = $stmt->execute();
168         if (!$success) {
169             throw new \RuntimeException(sprintf('Error executing query "%s"', $query));
170         }
171     }
172
173     protected function prepareStatement($db, $query)
174     {
175         try {
176             $stmt = $db->prepare($query);
177         } catch (\Exception $e) {
178             $stmt = false;
179         }
180
181         if (false === $stmt) {
182             throw new \RuntimeException('The database cannot successfully prepare the statement');
183         }
184
185         return $stmt;
186     }
187
188     protected function fetch($db, $query, array $args = array())
189     {
190         $stmt = $this->prepareStatement($db, $query);
191
192         foreach ($args as $arg => $val) {
193             $stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
194         }
195         $stmt->execute();
196
197         return $stmt->fetchAll(\PDO::FETCH_ASSOC);
198     }
199
200     protected function close($db)
201     {
202     }
203
204     protected function createProfileFromData($token, $data, $parent = null)
205     {
206         $profile = new Profile($token);
207         $profile->setIp($data['ip']);
208         $profile->setMethod($data['method']);
209         $profile->setUrl($data['url']);
210         $profile->setTime($data['time']);
211         $profile->setCollectors(unserialize(base64_decode($data['data'])));
212
213         if (!$parent && !empty($data['parent'])) {
214             $parent = $this->read($data['parent']);
215         }
216
217         if ($parent) {
218             $profile->setParent($parent);
219         }
220
221         $profile->setChildren($this->readChildren($token, $profile));
222
223         return $profile;
224     }
225
226     /**
227      * Reads the child profiles for the given token.
228      *
229      * @param string $token  The parent token
230      * @param string $parent The parent instance
231      *
232      * @return Profile[] An array of Profile instance
233      */
234     protected function readChildren($token, $parent)
235     {
236         $db = $this->initDb();
237         $data = $this->fetch($db, 'SELECT token, data, ip, method, url, time FROM sf_profiler_data WHERE parent = :token', array(':token' => $token));
238         $this->close($db);
239
240         if (!$data) {
241             return array();
242         }
243
244         $profiles = array();
245         foreach ($data as $d) {
246             $profiles[] = $this->createProfileFromData($d['token'], $d, $parent);
247         }
248
249         return $profiles;
250     }
251
252     /**
253      * Returns whether data for the given token already exists in storage.
254      *
255      * @param string $token The profile token
256      *
257      * @return string
258      */
259     protected function has($token)
260     {
261         $db = $this->initDb();
262         $tokenExists = $this->fetch($db, 'SELECT 1 FROM sf_profiler_data WHERE token = :token LIMIT 1', array(':token' => $token));
263         $this->close($db);
264
265         return !empty($tokenExists);
266     }
267 }