$scope, 'cursor' => $cursor, 'next_cursor' => $cursor + count($slice) < count($files) ? $cursor + count($slice) : null, 'total' => count($files), 'files' => $slice, ); } private static function scan(string $root): array { if (!is_dir($root) || !is_readable($root)) { return array(); } $result = array(); $iterator = new RecursiveIteratorIterator( new RecursiveCallbackFilterIterator( new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS), function (SplFileInfo $current): bool { return !in_array($current->getFilename(), self::EXCLUDED_PARTS, true) && !$current->isLink(); } ), RecursiveIteratorIterator::LEAVES_ONLY ); foreach ($iterator as $file) { if (!$file->isFile() || !$file->isReadable()) { continue; } $absolute = $file->getPathname(); $relative = ltrim(str_replace('\\', '/', substr($absolute, strlen($root))), '/'); $result[] = array( 'path' => $relative, 'bytes' => $file->getSize(), 'modified' => $file->getMTime(), 'sha256' => hash_file('sha256', $absolute), ); } usort($result, fn(array $a, array $b): int => strcmp($a['path'], $b['path'])); return $result; } }