/vendor/tedivm/stash/src/Stash/Driver/Sub/SqlitePdo.php
PHP | 290 lines | 147 code | 32 blank | 111 comment | 9 complexity | 0d3bb41c63cec1c18c2827c63d7fb077 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, AGPL-3.0, MPL-2.0-no-copyleft-exception
- <?php
- /*
- * This file is part of the Stash package.
- *
- * (c) Robert Hafner <tedivm@tedivm.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Stash\Driver\Sub;
- /**
- * Class SqlitePDO
- *
- * This SQLite subdriver uses PDO and the latest version of SQLite.
- *
- * @internal
- * @package Stash
- * @author Robert Hafner <tedivm@tedivm.com>
- */
- class SqlitePdo
- {
- /**
- * Directory where the SQLite databases are stored.
- *
- * @var string
- */
- protected $path;
- /**
- * Output of buildDriver, used to interact with the relevant SQLite extension.
- *
- * @var \PDO
- */
- protected $driver;
- /**
- * PDO driver string, used to distinguish between SQLite versions.
- *
- * @var string
- */
- protected static $pdoDriver = 'sqlite';
- /**
- * The SQLite query used to generate the database.
- *
- * @var string
- */
- protected $creationSql = 'CREATE TABLE cacheStore (
- key TEXT UNIQUE ON CONFLICT REPLACE,
- expiration INTEGER,
- encoding TEXT,
- data BLOB
- );
- CREATE INDEX keyIndex ON cacheStore (key);';
- /**
- * File permissions of new SQLite databases.
- *
- * @var string
- */
- protected $filePermissions;
- /**
- * File permissions of new directories leading to SQLite databases.
- *
- * @var string
- */
- protected $dirPermissions;
- /**
- * Amounts of time to wait for the SQLite engine before timing out.
- *
- * @var int milliseconds
- */
- protected $busyTimeout;
- /**
- * The appropriate response code to use when retrieving data.
- *
- * @var int
- */
- protected $responseCode;
- /**
- * @param string $path
- * @param string $directoryPermission
- * @param string $filePermission
- * @param int $busyTimeout
- */
- public function __construct($path, $directoryPermission, $filePermission, $busyTimeout)
- {
- $this->path = $path;
- $this->filePermissions = $filePermission;
- $this->dirPermissions = $directoryPermission;
- $this->busyTimeout = $busyTimeout;
- $this->responseCode = \PDO::FETCH_ASSOC;
- }
- /**
- * Clear out driver, closing file sockets.
- */
- public function __destruct()
- {
- $this->driver = null;
- }
- /**
- * Retrieves data from cache store.
- *
- * @param string $key
- * @return bool|mixed
- */
- public function get($key)
- {
- $driver = $this->getDriver();
- $query = $driver->query("SELECT * FROM cacheStore WHERE key LIKE '{$key}'");
- if ($query === false) {
- return false;
- }
- if ($resultArray = $query->fetch($this->responseCode)) {
- return unserialize(base64_decode($resultArray['data']));
- }
- return false;
- }
- /**
- * Stores data in sqlite database.
- *
- * @param string $key
- * @param mixed $value
- * @param int $expiration
- * @return bool
- */
- public function set($key, $value, $expiration)
- {
- $driver = $this->getDriver();
- $data = base64_encode(serialize($value));
- $contentLength = strlen($data);
- if ($contentLength > 100000) {
- $this->setTimeout($this->busyTimeout * (ceil($contentLength / 100000))); // .5s per 100k
- }
- $driver->query("INSERT INTO cacheStore (key, expiration, data)
- VALUES ('{$key}', '{$expiration}', '{$data}')");
- return true;
- }
- /**
- * Clears data from database. If a key is defined only it and it's children are removed. If everything is set to be
- * cleared then the database itself is deleted off disk.
- *
- * @param null|string $key
- * @return bool
- */
- public function clear($key = null)
- {
- // return true if the cache is already empty
- try {
- $driver = $this->getDriver();
- } catch (RuntimeException $e) {
- return true;
- }
- if (!isset($key)) {
- unset($driver);
- $this->driver = null;
- $this->driver = false;
- \Stash\Utilities::deleteRecursive($this->path);
- } else {
- $driver->query("DELETE FROM cacheStore WHERE key LIKE '{$key}%'");
- }
- return true;
- }
- /**
- * Old data is removed and the "vacuum" operation is run.
- *
- * @return bool
- */
- public function purge()
- {
- $driver = $this->getDriver();
- $driver->query('DELETE FROM cacheStore WHERE expiration < ' . time());
- $driver->query('VACUUM');
- return true;
- }
- /**
- * Checks that PDO extension is present and has the appropriate SQLite driver.
- *
- */
- public static function isAvailable()
- {
- if (!class_exists('\PDO', false)) {
- return false;
- }
- $drivers = \PDO::getAvailableDrivers();
- return in_array(static::$pdoDriver, $drivers);
- }
- /**
- * Tells the SQLite driver how long to wait for data to be written.
- *
- * @param int $milliseconds
- * @return bool
- */
- protected function setTimeout($milliseconds)
- {
- $driver = $this->getDriver();
- $timeout = ceil($milliseconds / 1000);
- $driver->setAttribute(\PDO::ATTR_TIMEOUT, $timeout);
- }
- /**
- * Retrieves the relevant SQLite driver, creating the database file if necessary.
- *
- * @return \SQLiteDatabase
- * @throws \Stash\Exception\RuntimeException
- */
- protected function getDriver()
- {
- if (isset($this->driver) && $this->driver !== false) {
- return $this->driver;
- }
- if (!file_exists($this->path)) {
- $dir = $this->path;
- // Since PHP will understand paths with mixed slashes- both the windows \ and unix / variants- we have
- // to test for both and see which one is the last in the string.
- $pos1 = strrpos($this->path, '/');
- $pos2 = strrpos($this->path, '\\');
- if ($pos1 || $pos2) {
- $pos = $pos1 >= $pos2 ? $pos1 : $pos2;
- $dir = substr($this->path, 0, $pos);
- }
- if (!is_dir($dir)) {
- mkdir($dir, $this->dirPermissions, true);
- }
- $runInstall = true;
- } else {
- $runInstall = false;
- }
- $db = $this->buildDriver();
- if ($runInstall && !$db->query($this->creationSql)) {
- unlink($this->path);
- throw new RuntimeException('Unable to set SQLite: structure');
- }
- if (!$db) {
- throw new RuntimeException('SQLite driver failed to load');
- }
- $this->driver = $db;
- // prevent the cache from getting hungup waiting on a return
- $this->setTimeout($this->busyTimeout);
- return $db;
- }
- /**
- * Creates the actual database driver itself.
- *
- * @return \SQLiteDatabase
- * @throws \Stash\Exception\RuntimeException
- */
- protected function buildDriver()
- {
- $db = new \PDO(static::$pdoDriver . ':' . $this->path);
- return $db;
- }
- }