/vendor/symfony/src/Symfony/Component/HttpKernel/Profiler/PdoProfilerStorage.php

https://github.com/proclamo/txinbometro · PHP · 230 lines · 140 code · 35 blank · 55 comment · 8 complexity · 4b488bd1e60f01ba3893ab09e1b7e0ff MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpKernel\Profiler;
  11. use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
  12. /**
  13. * Base PDO storage for profiling information in a PDO database.
  14. *
  15. * @author Fabien Potencier <fabien@symfony.com>
  16. * @author Jan Schumann <js@schumann-it.com>
  17. */
  18. abstract class PdoProfilerStorage implements ProfilerStorageInterface
  19. {
  20. protected $dsn;
  21. protected $username;
  22. protected $password;
  23. protected $lifetime;
  24. protected $db;
  25. /**
  26. * Constructor.
  27. *
  28. * @param string $dsn A data source name
  29. * @param string $username The username for the database
  30. * @param string $password The password for the database
  31. * @param integer $lifetime The lifetime to use for the purge
  32. */
  33. public function __construct($dsn, $username = '', $password = '', $lifetime = 86400)
  34. {
  35. $this->dsn = $dsn;
  36. $this->username = $username;
  37. $this->password = $password;
  38. $this->lifetime = (int) $lifetime;
  39. }
  40. /**
  41. * {@inheritdoc}
  42. */
  43. public function find($ip, $url, $limit)
  44. {
  45. list($criteria, $args) = $this->buildCriteria($ip, $url, $limit);
  46. $criteria = $criteria ? 'WHERE '.implode(' AND ', $criteria) : '';
  47. $db = $this->initDb();
  48. $tokens = $this->fetch($db, 'SELECT token, ip, url, time, parent FROM sf_profiler_data '.$criteria.' ORDER BY time DESC LIMIT '.((integer) $limit), $args);
  49. $this->close($db);
  50. return $tokens;
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. public function read($token)
  56. {
  57. $db = $this->initDb();
  58. $args = array(':token' => $token);
  59. $data = $this->fetch($db, 'SELECT data, parent, ip, url, time FROM sf_profiler_data WHERE token = :token LIMIT 1', $args);
  60. $this->close($db);
  61. if (isset($data[0]['data'])) {
  62. return $this->createProfileFromData($token, $data[0]);
  63. }
  64. return null;
  65. }
  66. /**
  67. * {@inheritdoc}
  68. */
  69. public function write(Profile $profile)
  70. {
  71. $db = $this->initDb();
  72. $args = array(
  73. ':token' => $profile->getToken(),
  74. ':parent' => $profile->getParent() ? $profile->getParent()->getToken() : '',
  75. ':data' => base64_encode(serialize($profile->getCollectors())),
  76. ':ip' => $profile->getIp(),
  77. ':url' => $profile->getUrl(),
  78. ':time' => $profile->getTime(),
  79. ':created_at' => time(),
  80. );
  81. try {
  82. $this->exec($db, 'INSERT INTO sf_profiler_data (token, parent, data, ip, url, time, created_at) VALUES (:token, :parent, :data, :ip, :url, :time, :created_at)', $args);
  83. $this->cleanup();
  84. $status = true;
  85. } catch (\Exception $e) {
  86. $status = false;
  87. }
  88. $this->close($db);
  89. return $status;
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public function purge()
  95. {
  96. $db = $this->initDb();
  97. $this->exec($db, 'DELETE FROM sf_profiler_data');
  98. $this->close($db);
  99. }
  100. /**
  101. * Build SQL criteria to fetch records by ip and url
  102. *
  103. * @param string $ip The IP
  104. * @param string $url The URL
  105. * @param string $limit The maximum number of tokens to return
  106. *
  107. * @return array An array with (criteria, args)
  108. */
  109. abstract protected function buildCriteria($ip, $url, $limit);
  110. /**
  111. * Initializes the database
  112. *
  113. * @throws \RuntimeException When the requested database driver is not installed
  114. */
  115. abstract protected function initDb();
  116. protected function cleanup()
  117. {
  118. $db = $this->initDb();
  119. $this->exec($db, 'DELETE FROM sf_profiler_data WHERE created_at < :time', array(':time' => time() - $this->lifetime));
  120. $this->close($db);
  121. }
  122. protected function exec($db, $query, array $args = array())
  123. {
  124. $stmt = $this->prepareStatement($db, $query);
  125. foreach ($args as $arg => $val) {
  126. $stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
  127. }
  128. $success = $stmt->execute();
  129. if (!$success) {
  130. throw new \RuntimeException(sprintf('Error executing query "%s"', $query));
  131. }
  132. }
  133. protected function prepareStatement($db, $query)
  134. {
  135. try {
  136. $stmt = $db->prepare($query);
  137. } catch (\Exception $e) {
  138. $stmt = false;
  139. }
  140. if (false === $stmt) {
  141. throw new \RuntimeException('The database cannot successfully prepare the statement');
  142. }
  143. return $stmt;
  144. }
  145. protected function fetch($db, $query, array $args = array())
  146. {
  147. $stmt = $this->prepareStatement($db, $query);
  148. foreach ($args as $arg => $val) {
  149. $stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
  150. }
  151. $stmt->execute();
  152. $return = $stmt->fetchAll(\PDO::FETCH_ASSOC);
  153. return $return;
  154. }
  155. protected function close($db)
  156. {
  157. }
  158. protected function createProfileFromData($token, $data, $parent = null)
  159. {
  160. $profile = new Profile($token);
  161. $profile->setIp($data['ip']);
  162. $profile->setUrl($data['url']);
  163. $profile->setTime($data['time']);
  164. $profile->setCollectors(unserialize(base64_decode($data['data'])));
  165. if (!$parent && isset($data['parent']) && $data['parent']) {
  166. $parent = $this->read($data['parent']);
  167. }
  168. if ($parent) {
  169. $profile->setParent($parent);
  170. }
  171. $profile->setChildren($this->readChildren($token, $parent));
  172. return $profile;
  173. }
  174. /**
  175. * Reads the child profiles for the given token.
  176. *
  177. * @param string $token The parent token
  178. *
  179. * @return array An array of Profile instance
  180. */
  181. protected function readChildren($token, $parent)
  182. {
  183. $db = $this->initDb();
  184. $data = $this->fetch($db, 'SELECT token, data, ip, url, time FROM sf_profiler_data WHERE parent = :token', array(':token' => $token));
  185. $this->close($db);
  186. if (!$data) {
  187. return array();
  188. }
  189. $profiles = array();
  190. foreach ($data as $d) {
  191. $profiles[] = $this->createProfileFromData($d['token'], $d, $parent);
  192. }
  193. return $profiles;
  194. }
  195. }