Artifact 5f84090ade0dbce7d6add10fab76c93701809c6c0d39509424a4922b1ad9cfac:


<?php

namespace Garradin\Files\Storage;

use Garradin\Entities\Files\File;

use Garradin\Static_Cache;
use Garradin\DB;

use KD2\DB\EntityManager as EM;

use const Garradin\{DB_FILE, DATA_ROOT};

class SQLite implements StorageInterface
{
	static public function configure(?string $config): void
	{
	}

	/**
	 * Renvoie le chemin vers le fichier local en cache, et le crée s'il n'existe pas
	 * @return string Chemin local
	 */
	static protected function _getFilePathFromCache(File $file): string
	{
		$cache_id = 'files.' . $file->pathHash();

		if (!Static_Cache::exists($cache_id))
		{
			$db = DB::getInstance();

			try {
				$blob = $db->openBlob('files_contents', 'content', $file->id());
			}
			catch (\Exception $e) {
				if (!strstr($e->getMessage(), 'no such rowid')) {
					throw $e;
				}

				throw new \RuntimeException('File does not exist in DB: ' . $file->pathname());
			}

			Static_Cache::storeFromPointer($cache_id, $blob);
			fclose($blob);
		}

		return Static_Cache::getPath($cache_id);
	}

	static public function storePath(File $file, string $source_path): bool
	{
		return self::store($file, $source_path, null);
	}

	static public function storeContent(File $file, string $source_content): bool
	{
		return self::store($file, null, $source_content);
	}

	static protected function store(File $file, ?string $source_path, ?string $source_content): bool
	{
		if (!isset($source_path) && !isset($source_content)) {
			throw new \InvalidArgumentException('Either source_path or source_content must be supplied');
		}

		$db = DB::getInstance();

		$db->preparedQuery('INSERT OR REPLACE INTO files_contents (id, content) VALUES (?, zeroblob(?));',
			$file->id(), $file->size);

		$blob = $db->openBlob('files_contents', 'content', $file->id(), 'main', \SQLITE3_OPEN_READWRITE);

		if (null !== $source_content) {
			fwrite($blob, $source_content);
		}
		else {
			fwrite($blob, file_get_contents($source_path));
		}

		fclose($blob);

		$cache_id = 'files.' . $file->pathHash();
		Static_Cache::remove($cache_id);

		return true;
	}

	static public function getFullPath(File $file): ?string
	{
		return self::_getFilePathFromCache($file);
	}

	static public function display(File $file): void
	{
		readfile(self::getFullPath($file));
	}

	static public function fetch(File $file): string
	{
		return file_get_contents(self::getFullPath($file));
	}

	static public function modified(File $file): ?int
	{
		return $file->modified ?? time();
	}

	static public function exists(string $path): bool
	{
		return DB::getInstance()->test('files', 'path = ? AND name = ?', dirname($path), basename($path));
	}

	static public function delete(File $file): bool
	{
		$db = DB::getInstance();

		$cache_id = 'files.' . $file->pathHash();
		Static_Cache::remove($cache_id);

		return $db->delete('files_contents', 'id = ?', $file->id());
	}

	static public function move(File $file, string $new_path): bool
	{
		return true;
	}

	static public function mkdir(File $file): bool
	{
		return true;
	}

	static public function getTotalSize(): int
	{
		return (int) DB::getInstance()->firstColumn('SELECT SUM(LENGTH(content)) FROM files_contents;');
	}

	/**
	 * @see https://www.crazyws.fr/dev/fonctions-php/fonction-disk-free-space-et-disk-total-space-pour-ovh-2JMH9.html
	 * @see https://github.com/jdel/sspks/commit/a890e347f32e9e3e50a0dd82398947633872bf38
	 */
	static public function getQuota(): int
	{
		$quota = @disk_total_space(DATA_ROOT);
		return $quota === false ? \PHP_INT_MAX : (int) $quota;
	}

	static public function truncate(): void
	{
		$db = DB::getInstance();
		$db->exec('DELETE FROM files_contents; VACUUM;');
	}

	static public function lock(): void
	{
		DB::getInstance()->exec('INSERT INTO files (name, path) VALUES (\'.lock\', \'.lock\');');
	}

	static public function unlock(): void
	{
		DB::getInstance()->exec('DELETE FROM files WHERE path = \'.lock\';');
	}

	static public function checkLock(): void
	{
		$lock = DB::getInstance()->firstColumn('SELECT 1 FROM files WHERE path = \'.lock\';');

		if ($lock) {
			throw new \RuntimeException('File storage is locked');
		}
	}

	/**
	 * We don't need to do anything there as everything is already in DB
	 */
	static public function sync(?string $path): void
	{
		return;
	}

	static public function update(File $file): ?File
	{
		return $file;
	}
}