PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/PhpFastCache/Drivers/sqlite.php

https://gitlab.com/webbroteam/satisfaction-mvc
PHP | 484 lines | 301 code | 59 blank | 124 comment | 55 complexity | af31c5ce7b1e5483824f7b65db9eb8b1 MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * This file is part of phpFastCache.
  5. *
  6. * @license MIT License (MIT)
  7. *
  8. * For full copyright and license information, please see the docs/CREDITS.txt file.
  9. *
  10. * @author Khoa Bui (khoaofgod) <khoaofgod@gmail.com> http://www.phpfastcache.com
  11. * @author Georges.L (Geolim4) <contact@geolim4.com>
  12. *
  13. */
  14. namespace phpFastCache\Drivers;
  15. use phpFastCache\Core\DriverAbstract;
  16. use PDO;
  17. use PDOException;
  18. use phpFastCache\Exceptions\phpFastCacheDriverException;
  19. /**
  20. * Class sqlite
  21. * @package phpFastCache\Drivers
  22. */
  23. class sqlite extends DriverAbstract
  24. {
  25. /**
  26. *
  27. */
  28. const SQLITE_DIR = 'sqlite';
  29. /**
  30. *
  31. */
  32. const INDEXING_FILE = 'indexing';
  33. /**
  34. * @var int
  35. */
  36. public $max_size = 10; // 10 mb
  37. /**
  38. * @var array
  39. */
  40. public $instant = array();
  41. /**
  42. * @var null
  43. */
  44. public $indexing = null;
  45. /**
  46. * @var string
  47. */
  48. public $path = '';
  49. /**
  50. * @var int
  51. */
  52. public $currentDB = 1;
  53. /**
  54. * Init Main Database & Sub Database
  55. * phpFastCache_sqlite constructor.
  56. * @param array $config
  57. * @throws phpFastCacheDriverException
  58. */
  59. public function __construct($config = array())
  60. {
  61. /**
  62. * init the path
  63. */
  64. $this->setup($config);
  65. if (!$this->checkdriver()) {
  66. throw new phpFastCacheDriverException('SQLITE is not installed, cannot continue.');
  67. }
  68. if (!file_exists($this->getPath() . '/' . self::SQLITE_DIR)) {
  69. if (!mkdir($this->getPath() . '/' . self::SQLITE_DIR,
  70. $this->__setChmodAuto())
  71. ) {
  72. $this->fallback = true;
  73. }
  74. }
  75. $this->path = $this->getPath() . '/' . self::SQLITE_DIR;
  76. }
  77. /**
  78. * INIT NEW DB
  79. * @param \PDO $db
  80. */
  81. public function initDB(PDO $db)
  82. {
  83. $db->exec('drop table if exists "caching"');
  84. $db->exec('CREATE TABLE "caching" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "keyword" VARCHAR UNIQUE, "object" BLOB, "exp" INTEGER)');
  85. $db->exec('CREATE UNIQUE INDEX "cleanup" ON "caching" ("keyword","exp")');
  86. $db->exec('CREATE INDEX "exp" ON "caching" ("exp")');
  87. $db->exec('CREATE UNIQUE INDEX "keyword" ON "caching" ("keyword")');
  88. }
  89. /**
  90. * INIT Indexing DB
  91. * @param \PDO $db
  92. */
  93. public function initIndexing(PDO $db)
  94. {
  95. // delete everything before reset indexing
  96. $dir = opendir($this->path);
  97. while ($file = readdir($dir)) {
  98. if ($file != '.' && $file != '..' && $file != 'indexing' && $file != 'dbfastcache') {
  99. unlink($this->path . '/' . $file);
  100. }
  101. }
  102. $db->exec('drop table if exists "balancing"');
  103. $db->exec('CREATE TABLE "balancing" ("keyword" VARCHAR PRIMARY KEY NOT NULL UNIQUE, "db" INTEGER)');
  104. $db->exec('CREATE INDEX "db" ON "balancing" ("db")');
  105. $db->exec('CREATE UNIQUE INDEX "lookup" ON "balancing" ("keyword")');
  106. }
  107. /**
  108. * INIT Instant DB
  109. * Return Database of Keyword
  110. * @param $keyword
  111. * @return int
  112. */
  113. public function indexing($keyword)
  114. {
  115. if ($this->indexing == null) {
  116. $createTable = false;
  117. if (!file_exists($this->path . '/indexing')) {
  118. $createTable = true;
  119. }
  120. $PDO = new PDO("sqlite:" . $this->path . '/' . self::INDEXING_FILE);
  121. $PDO->setAttribute(PDO::ATTR_ERRMODE,
  122. PDO::ERRMODE_EXCEPTION);
  123. if ($createTable == true) {
  124. $this->initIndexing($PDO);
  125. }
  126. $this->indexing = $PDO;
  127. unset($PDO);
  128. $stm = $this->indexing->prepare("SELECT MAX(`db`) as `db` FROM `balancing`");
  129. $stm->execute();
  130. $row = $stm->fetch(PDO::FETCH_ASSOC);
  131. if (!isset($row[ 'db' ])) {
  132. $db = 1;
  133. } elseif ($row[ 'db' ] <= 1) {
  134. $db = 1;
  135. } else {
  136. $db = $row[ 'db' ];
  137. }
  138. // check file size
  139. $size = file_exists($this->path . '/db' . $db) ? filesize($this->path . '/db' . $db) : 1;
  140. $size = round($size / 1024 / 1024, 1);
  141. if ($size > $this->max_size) {
  142. $db = $db + 1;
  143. }
  144. $this->currentDB = $db;
  145. }
  146. // look for keyword
  147. $stm = $this->indexing->prepare("SELECT * FROM `balancing` WHERE `keyword`=:keyword LIMIT 1");
  148. $stm->execute(array(
  149. ':keyword' => $keyword,
  150. ));
  151. $row = $stm->fetch(PDO::FETCH_ASSOC);
  152. if (isset($row[ 'db' ]) && $row[ 'db' ] != '') {
  153. $db = $row[ 'db' ];
  154. } else {
  155. /*
  156. * Insert new to Indexing
  157. */
  158. $db = $this->currentDB;
  159. $stm = $this->indexing->prepare("INSERT INTO `balancing` (`keyword`,`db`) VALUES(:keyword, :db)");
  160. $stm->execute(array(
  161. ':keyword' => $keyword,
  162. ':db' => $db,
  163. ));
  164. }
  165. return $db;
  166. }
  167. /**
  168. * @param $keyword
  169. * @param bool $reset
  170. * @return mixed
  171. */
  172. public function db($keyword, $reset = false)
  173. {
  174. /**
  175. * Default is fastcache
  176. */
  177. $instant = $this->indexing($keyword);
  178. /**
  179. * init instant
  180. */
  181. if (!isset($this->instant[ $instant ])) {
  182. // check DB Files ready or not
  183. $createTable = false;
  184. if (!file_exists($this->path . '/db' . $instant) || $reset == true) {
  185. $createTable = true;
  186. }
  187. $PDO = new PDO('sqlite:' . $this->path . '/db' . $instant);
  188. $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  189. if ($createTable == true) {
  190. $this->initDB($PDO);
  191. }
  192. $this->instant[ $instant ] = $PDO;
  193. unset($PDO);
  194. }
  195. return $this->instant[ $instant ];
  196. }
  197. /**
  198. * @return bool
  199. */
  200. public function checkdriver()
  201. {
  202. if (extension_loaded('pdo_sqlite') && is_writable($this->getPath())) {
  203. return true;
  204. }
  205. $this->fallback = true;
  206. return false;
  207. }
  208. /**
  209. * @param $keyword
  210. * @param string $value
  211. * @param int $time
  212. * @param array $option
  213. * @return bool
  214. */
  215. public function driver_set(
  216. $keyword,
  217. $value = '',
  218. $time = 300,
  219. $option = array()
  220. ) {
  221. $skipExisting = isset($option[ 'skipExisting' ]) ? $option[ 'skipExisting' ] : false;
  222. $toWrite = true;
  223. // check in cache first
  224. $in_cache = $this->get($keyword, $option);
  225. if ($skipExisting == true) {
  226. if ($in_cache == null) {
  227. $toWrite = true;
  228. } else {
  229. $toWrite = false;
  230. }
  231. }
  232. if ($toWrite == true) {
  233. try {
  234. $stm = $this->db($keyword)
  235. ->prepare("INSERT OR REPLACE INTO `caching` (`keyword`,`object`,`exp`) values(:keyword,:object,:exp)");
  236. $stm->execute(array(
  237. ':keyword' => $keyword,
  238. ':object' => $this->encode($value),
  239. ':exp' => time() + (int)$time,
  240. ));
  241. return true;
  242. } catch (\PDOException $e) {
  243. try {
  244. $stm = $this->db($keyword, true)
  245. ->prepare("INSERT OR REPLACE INTO `caching` (`keyword`,`object`,`exp`) values(:keyword,:object,:exp)");
  246. $stm->execute(array(
  247. ':keyword' => $keyword,
  248. ':object' => $this->encode($value),
  249. ':exp' => time() + (int)$time,
  250. ));
  251. } catch (PDOException $e) {
  252. return false;
  253. }
  254. }
  255. }
  256. return false;
  257. }
  258. /**
  259. * @param $keyword
  260. * @param array $option
  261. * @return mixed|null
  262. */
  263. public function driver_get($keyword, $option = array())
  264. {
  265. // return null if no caching
  266. // return value if in caching
  267. try {
  268. $stm = $this->db($keyword)
  269. ->prepare("SELECT * FROM `caching` WHERE `keyword`=:keyword LIMIT 1");
  270. $stm->execute(array(
  271. ':keyword' => $keyword,
  272. ));
  273. $row = $stm->fetch(PDO::FETCH_ASSOC);
  274. } catch (PDOException $e) {
  275. try {
  276. $stm = $this->db($keyword, true)
  277. ->prepare("SELECT * FROM `caching` WHERE `keyword`=:keyword LIMIT 1");
  278. $stm->execute(array(
  279. ':keyword' => $keyword,
  280. ));
  281. $row = $stm->fetch(PDO::FETCH_ASSOC);
  282. } catch (PDOException $e) {
  283. return null;
  284. }
  285. }
  286. if ($this->isExpired($row)) {
  287. $this->deleteRow($row);
  288. return null;
  289. }
  290. if (isset($row[ 'id' ])) {
  291. $data = $this->decode($row[ 'object' ]);
  292. return $data;
  293. }
  294. return null;
  295. }
  296. /**
  297. * @param $row
  298. * @return bool
  299. */
  300. public function isExpired($row)
  301. {
  302. if (isset($row[ 'exp' ]) && time() >= $row[ 'exp' ]) {
  303. return true;
  304. }
  305. return false;
  306. }
  307. /**
  308. * @param $row
  309. * @return bool
  310. */
  311. public function deleteRow($row)
  312. {
  313. try {
  314. $stm = $this->db($row[ 'keyword' ])
  315. ->prepare("DELETE FROM `caching` WHERE (`id`=:id) OR (`exp` <= :U) ");
  316. $stm->execute(array(
  317. ':id' => $row[ 'id' ],
  318. ':U' => time(),
  319. ));
  320. } catch (PDOException $e) {
  321. return false;
  322. }
  323. }
  324. /**
  325. * @param $keyword
  326. * @param array $option
  327. * @return bool
  328. */
  329. public function driver_delete($keyword, $option = array())
  330. {
  331. try {
  332. $stm = $this->db($keyword)
  333. ->prepare("DELETE FROM `caching` WHERE (`keyword`=:keyword) OR (`exp` <= :U)");
  334. $stm->execute(array(
  335. ':keyword' => $keyword,
  336. ':U' => time(),
  337. ));
  338. } catch (PDOException $e) {
  339. return false;
  340. }
  341. }
  342. /**
  343. * Return total cache size + auto removed expired entries
  344. * @param array $option
  345. * @return array
  346. */
  347. public function driver_stats($option = array())
  348. {
  349. $res = array(
  350. 'info' => '',
  351. 'size' => '',
  352. 'data' => '',
  353. );
  354. $total = 0;
  355. $optimized = 0;
  356. $dir = opendir($this->path);
  357. while ($file = readdir($dir)) {
  358. if ($file != '.' && $file != '..') {
  359. $file_path = $this->path . "/" . $file;
  360. $size = filesize($file_path);
  361. $total = $total + $size;
  362. try {
  363. $PDO = new PDO("sqlite:" . $file_path);
  364. $PDO->setAttribute(PDO::ATTR_ERRMODE,
  365. PDO::ERRMODE_EXCEPTION);
  366. $stm = $PDO->prepare("DELETE FROM `caching` WHERE `exp` <= :U");
  367. $stm->execute(array(
  368. ':U' => date('U'),
  369. ));
  370. $PDO->exec('VACUUM;');
  371. $size = filesize($file_path);
  372. $optimized = $optimized + $size;
  373. } catch (PDOException $e) {
  374. $size = 0;
  375. $optimized = 0;
  376. }
  377. }
  378. }
  379. $res[ 'size' ] = $optimized;
  380. $res[ 'info' ] = array(
  381. 'total before removing expired entries [bytes]' => $total,
  382. 'optimized after removing expired entries [bytes]' => $optimized,
  383. );
  384. return $res;
  385. }
  386. /**
  387. * @param array $option
  388. * @return void
  389. */
  390. public function driver_clean($option = array())
  391. {
  392. // close connection
  393. $this->instant = array();
  394. $this->indexing = null;
  395. // delete everything before reset indexing
  396. $dir = opendir($this->path);
  397. while ($file = readdir($dir)) {
  398. if ($file != '.' && $file != '..') {
  399. unlink($this->path . '/' . $file);
  400. }
  401. }
  402. }
  403. /**
  404. * @param $keyword
  405. * @return bool
  406. */
  407. public function driver_isExisting($keyword)
  408. {
  409. try {
  410. $stm = $this->db($keyword)
  411. ->prepare("SELECT COUNT(`id`) as `total` FROM `caching` WHERE `keyword`=:keyword");
  412. $stm->execute(array(
  413. ':keyword' => $keyword,
  414. ));
  415. $data = $stm->fetch(PDO::FETCH_ASSOC);
  416. if ($data[ 'total' ] >= 1) {
  417. return true;
  418. } else {
  419. return false;
  420. }
  421. } catch (PDOException $e) {
  422. return false;
  423. }
  424. }
  425. }