PdoProfilerStorage.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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 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 findChildren($token)
  56. {
  57. $db = $this->initDb();
  58. $args = array(':token' => $token);
  59. $tokens = $this->fetch($db, 'SELECT token FROM data WHERE parent = :token LIMIT 1', $args);
  60. $this->close($db);
  61. return $tokens;
  62. }
  63. /**
  64. * {@inheritdoc}
  65. */
  66. public function read($token)
  67. {
  68. $db = $this->initDb();
  69. $args = array(':token' => $token);
  70. $data = $this->fetch($db, 'SELECT data, parent, ip, url, time FROM data WHERE token = :token LIMIT 1', $args);
  71. $this->close($db);
  72. if (isset($data[0]['data'])) {
  73. return array($data[0]['data'], $data[0]['parent'], $data[0]['ip'], $data[0]['url'], $data[0]['time']);
  74. }
  75. return false;
  76. }
  77. /**
  78. * {@inheritdoc}
  79. */
  80. public function write($token, $parent, $data, $ip, $url, $time)
  81. {
  82. $db = $this->initDb();
  83. $args = array(
  84. ':token' => $token,
  85. ':parent' => $parent,
  86. ':data' => $data,
  87. ':ip' => $ip,
  88. ':url' => $url,
  89. ':time' => $time,
  90. ':created_at' => time(),
  91. );
  92. try {
  93. $this->exec($db, 'INSERT INTO data (token, parent, data, ip, url, time, created_at) VALUES (:token, :parent, :data, :ip, :url, :time, :created_at)', $args);
  94. $this->cleanup();
  95. $status = true;
  96. } catch (\Exception $e) {
  97. $status = false;
  98. }
  99. $this->close($db);
  100. return $status;
  101. }
  102. /**
  103. * {@inheritdoc}
  104. */
  105. public function purge()
  106. {
  107. $db = $this->initDb();
  108. $this->exec($db, 'DELETE FROM data');
  109. $this->close($db);
  110. }
  111. /**
  112. * Build SQL criteria to fetch records by ip and url
  113. *
  114. * @param string $ip The IP
  115. * @param string $url The URL
  116. * @param string $limit The maximum number of tokens to return
  117. *
  118. * @return array An array with (creteria, args)
  119. */
  120. abstract protected function buildCriteria($ip, $url, $limit);
  121. /**
  122. * Initializes the database
  123. *
  124. * @throws \RuntimeException When the requeted database driver is not installed
  125. */
  126. abstract protected function initDb();
  127. protected function cleanup()
  128. {
  129. $db = $this->initDb();
  130. $this->exec($db, 'DELETE FROM data WHERE created_at < :time', array(':time' => time() - $this->lifetime));
  131. $this->close($db);
  132. }
  133. protected function exec($db, $query, array $args = array())
  134. {
  135. $stmt = $this->prepareStatement($db, $query);
  136. foreach ($args as $arg => $val) {
  137. $stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
  138. }
  139. $success = $stmt->execute();
  140. if (!$success) {
  141. throw new \RuntimeException(sprintf('Error executing query "%s"', $query));
  142. }
  143. }
  144. protected function prepareStatement($db, $query)
  145. {
  146. try {
  147. $stmt = $db->prepare($query);
  148. } catch (\Exception $e) {
  149. $stmt = false;
  150. }
  151. if (false === $stmt) {
  152. throw new \RuntimeException('The database cannot successfully prepare the statement');
  153. }
  154. return $stmt;
  155. }
  156. protected function fetch($db, $query, array $args = array())
  157. {
  158. $return = array();
  159. $stmt = $this->prepareStatement($db, $query);
  160. foreach ($args as $arg => $val) {
  161. $stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR);
  162. }
  163. $stmt->execute();
  164. $return = $stmt->fetchAll(\PDO::FETCH_ASSOC);
  165. return $return;
  166. }
  167. protected function close($db)
  168. {
  169. }
  170. }