_config, 'database', NULL); if ($database === NULL) { throw new Cache_Exception('Database path not available in Kohana Cache configuration'); } // Load new Sqlite DB $this->_db = new PDO('sqlite:'.$database); // Test for existing DB $result = $this->_db->query("SELECT * FROM sqlite_master WHERE name = 'caches' AND type = 'table'")->fetchAll(); // If there is no table, create a new one if (0 == count($result)) { $database_schema = Arr::get($this->_config, 'schema', NULL); if ($database_schema === NULL) { throw new Cache_Exception('Database schema not found in Kohana Cache configuration'); } try { // Create the caches table $this->_db->query(Arr::get($this->_config, 'schema', NULL)); } catch (PDOException $e) { throw new Cache_Exception('Failed to create new SQLite caches table with the following error : :error', [':error' => $e->getMessage()]); } } } /** * Retrieve a value based on an id * * @param string $id id * @param string $default default [Optional] Default value to return if id not found * @return mixed * @throws Cache_Exception */ public function get($id, $default = NULL) { // Prepare statement $statement = $this->_db->prepare('SELECT id, expiration, cache FROM caches WHERE id = :id LIMIT 0, 1'); // Try and load the cache based on id try { $statement->execute([':id' => $this->_sanitize_id($id)]); } catch (PDOException $e) { throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', [':error' => $e->getMessage()]); } if ( ! $result = $statement->fetch(PDO::FETCH_OBJ)) { return $default; } // If the cache has expired if ($result->expiration != 0 and $result->expiration <= time()) { // Delete it and return default value $this->delete($id); return $default; } // Otherwise return cached object else { // Return the valid cache data $data = @unserialize($result->cache); // Return the resulting data return $data; } } /** * Set a value based on an id. Optionally add tags. * * @param string $id id * @param mixed $data data * @param integer $lifetime lifetime [Optional] * @return boolean */ public function set($id, $data, $lifetime = NULL) { return (bool) $this->set_with_tags($id, $data, $lifetime); } /** * Delete a cache entry based on id * * @param string $id id * @return boolean * @throws Cache_Exception */ public function delete($id) { // Prepare statement $statement = $this->_db->prepare('DELETE FROM caches WHERE id = :id'); // Remove the entry try { $statement->execute([':id' => $this->_sanitize_id($id)]); } catch (PDOException $e) { throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', [':error' => $e->getMessage()]); } return (bool) $statement->rowCount(); } /** * Delete all cache entries * * @return boolean */ public function delete_all() { // Prepare statement $statement = $this->_db->prepare('DELETE FROM caches'); // Remove the entry try { $statement->execute(); } catch (PDOException $e) { throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', [':error' => $e->getMessage()]); } return (bool) $statement->rowCount(); } /** * Set a value based on an id. Optionally add tags. * * @param string $id id * @param mixed $data data * @param integer $lifetime lifetime [Optional] * @param array $tags tags [Optional] * @return boolean * @throws Cache_Exception */ public function set_with_tags($id, $data, $lifetime = NULL, array $tags = NULL) { // Serialize the data $data = serialize($data); // Normalise tags $tags = (NULL === $tags) ? NULL : ('<'.implode('>,<', $tags).'>'); // Setup lifetime if ($lifetime === NULL) { $lifetime = (0 === Arr::get($this->_config, 'default_expire', NULL)) ? 0 : (Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE) + time()); } else { $lifetime = (0 === $lifetime) ? 0 : ($lifetime + time()); } // Prepare statement // $this->exists() may throw Cache_Exception, no need to catch/rethrow $statement = $this->exists($id) ? $this->_db->prepare('UPDATE caches SET expiration = :expiration, cache = :cache, tags = :tags WHERE id = :id') : $this->_db->prepare('INSERT INTO caches (id, cache, expiration, tags) VALUES (:id, :cache, :expiration, :tags)'); // Try to insert try { $statement->execute([':id' => $this->_sanitize_id($id), ':cache' => $data, ':expiration' => $lifetime, ':tags' => $tags]); } catch (PDOException $e) { throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', [':error' => $e->getMessage()]); } return (bool) $statement->rowCount(); } /** * Delete cache entries based on a tag * * @param string $tag tag * @return boolean * @throws Cache_Exception */ public function delete_tag($tag) { // Prepare the statement $statement = $this->_db->prepare('DELETE FROM caches WHERE tags LIKE :tag'); // Try to delete try { $statement->execute([':tag' => "%<{$tag}>%"]); } catch (PDOException $e) { throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', [':error' => $e->getMessage()]); } return (bool) $statement->rowCount(); } /** * Find cache entries based on a tag * * @param string $tag tag * @return array * @throws Cache_Exception */ public function find($tag) { // Prepare the statement $statement = $this->_db->prepare('SELECT id, cache FROM caches WHERE tags LIKE :tag'); // Try to find try { if ( ! $statement->execute([':tag' => "%<{$tag}>%"])) { return []; } } catch (PDOException $e) { throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', [':error' => $e->getMessage()]); } $result = []; while ($row = $statement->fetchObject()) { $result[$row->id] = @unserialize($row->cache); } return $result; } /** * Garbage collection method that cleans any expired * cache entries from the cache. * * @return void */ public function garbage_collect() { // Create the sequel statement $statement = $this->_db->prepare('DELETE FROM caches WHERE expiration < :expiration'); try { $statement->execute([':expiration' => time()]); } catch (PDOException $e) { throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', [':error' => $e->getMessage()]); } } /** * Tests whether an id exists or not * * @param string $id id * @return boolean * @throws Cache_Exception */ protected function exists($id) { $statement = $this->_db->prepare('SELECT id FROM caches WHERE id = :id'); try { $statement->execute([':id' => $this->_sanitize_id($id)]); } catch (PDOExeption $e) { throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', [':error' => $e->getMessage()]); } return (bool) $statement->fetchAll(); } }