util = new Util($app); $this->dataDir = $this->util->dataDir; } function run($db) { $db = $this->getSysConn(); set_time_limit(0); $this->trashSubdir = date('YmdHis'); $deleteCount = 0; $dir = opendir($this->dataDir); if ($dir) while ($collection = readdir($dir)) if (!in_array($collection, ['.', '..'])) { $info = $this->util->loadInfo($collection); $collectionPath = "{$this->dataDir}/$collection"; // Deletes unreferenced collections. if (!isset($info)) { $this->recycle($collection); continue; } // Deletes unreferenced sizes. $collectionDir = opendir($collectionPath); if ($collectionDir) while ($size = readdir($collectionDir)) if (!in_array($size, ['.', '..', 'full']) && !isset($info['sizes'][$size])) $this->recycle("$collection/$size"); // Deletes unreferenced images. try { $db->query('START TRANSACTION'); $res = $db->query( 'SELECT id, `name`, collectionFk FROM `image` WHERE nRefs = 0 AND collectionFk = #collection FOR UPDATE', ['collection' => $collection] ); if ($res->num_rows == 0) continue; echo "Deleting {$res->num_rows} from collection '$collection'.\n"; while ($image = $res->fetch_object()) if (!empty($image->name) && !in_array($image->name, ['.', '..'])) { $deleteCount++; $this->recycle("$collection/full/{$image->name}.png"); foreach ($info['sizes'] as $size => $i) $this->recycle("$collection/$size/{$image->name}.png"); $db->query( 'DELETE FROM `image` WHERE nRefs = 0 AND id = #id', ['id' => $image->id] ); } $res->free(); $db->query('COMMIT'); } catch(Exception $e) { $db->query('ROLLBACK'); throw $e; } } echo "Syncronization finished. $deleteCount images moved to trash.\n"; } /** * Moves data file to trash. * * @param string $file File or directory to move */ function recycle($file) { $filePath = "{$this->dataDir}/$file"; if (!file_exists($filePath)) return; $trashBasedir = "{$this->dataDir}/.trash/". $this->trashSubdir; $trashdir = "$trashBasedir/". dirname($file); if (!is_dir($trashdir)) mkdir($trashdir, 0775, TRUE); rename( "$filePath", "$trashBasedir/$file" ); } }