where('id', '>', $lastId) ->where('storage', 'local') ->order('id asc') ->limit($batchSize) ->field('id,url,filename,is_del,mimetype') ->select(); if (empty($rows)) { break; } foreach ($rows as $row) { $row = is_array($row) ? $row : $row->toArray(); $lastId = (int)$row['id']; $checked++; $url = trim((string)($row['url'] ?? '')); if ($url === '') { $exists = false; } elseif (preg_match('#^https?://#i', $url)) { // 外链不做本地存在性检查 continue; } else { $relative = '/' . ltrim(str_replace('\\', '/', $url), '/'); $file = $publicPath . str_replace('/', DIRECTORY_SEPARATOR, $relative); $exists = is_file($file); } if ($exists) { continue; } $missing++; $name = $row['filename'] ?? ''; $delFlag = !empty($row['is_del']) ? ' [已在回收站]' : ''; echo "[缺失] id={$row['id']} url={$url} filename={$name}{$delFlag}\n"; if ($dryRun) { continue; } if ($softDelete) { Db::name('attachment')->where('id', $row['id'])->update([ 'is_del' => 1, 'updatetime' => $now, ]); } else { Db::name('attachment')->where('id', $row['id'])->delete(); } } } echo "\n完成:共检查 {$checked} 条本地附件,发现缺失 {$missing} 条"; echo $dryRun ? '(预览,未修改数据库)' : '(已清理)'; echo "\n";