Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
blog
/
data
/
sessions
:
strays-20261027093400-20261027165048.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php // Finds and moves stray copies from a blog folder. Run it from the command line, from inside the blog folder: // php find-strays.php lists what it would move (changes nothing) // php find-strays.php --move moves the strays into a folder named _strays (nothing is deleted) // // What it looks for: files with a timestamp added to their name (like admin-20261026155027.php), and copies of // the blog's files that ended up in the wrong folder (for example lib/admin.php sitting in the blog folder, or in // tools). Your posts, settings, pictures and the real files in their real places are never touched. if (PHP_SAPI !== 'cli') { http_response_code(403); exit; } $root = getcwd(); $move = in_array('--move', $argv, true); $manifest = json_decode(<<<'JSON' [".gitignore", ".htaccess", ".user.ini", "README.md", "assets/admin/admin-theme.js", "assets/admin/admin.css", "assets/admin/analytics.js", "assets/admin/auth-init.js", "assets/admin/comments.js", "assets/admin/editor.js", "assets/admin/fa/fa.css", "assets/admin/fa/webfonts/fa-solid-900.woff2", "assets/admin/ipcard.js", "assets/admin/jquery.min.js", "assets/admin/list.js", "assets/admin/probe.js", "assets/admin/prompts.js", "assets/admin/settings-ui.js", "assets/admin/settings.js", "assets/admin/themestrap/namespace.js", "assets/admin/themestrap/themestrap.plugin.auth.js", "assets/admin/themestrap/themestrap.plugin.calendar.js", "assets/admin/themestrap/themestrap.plugin.dialog.js", "assets/admin/themestrap/themestrap.plugin.hovercard.js", "assets/admin/themestrap/themestrap.plugin.markdown.js", "assets/admin/themestrap/themestrap.plugin.markdowneditor.js", "assets/admin/themestrap/themestrap.plugin.numberinput.js", "assets/admin/themestrap/themestrap.plugin.richeditor.js", "assets/admin/themestrap/themestrap.plugin.select.js", "assets/admin/themestrap/themestrap.plugin.tagsinput.js", "assets/admin/themestrap/themestrap.plugin.timepicker.js", "assets/admin/themestrap/themestrap.plugin.toolbar.js", "assets/admin/update.js", "assets/track.js", "config.sample.php", "docs/analytics.md", "docs/architecture.md", "docs/comments.md", "docs/configuration.md", "docs/deployment.md", "docs/getting-started.md", "docs/security.md", "docs/storage.md", "docs/themes.md", "docs/troubleshooting.md", "docs/updates.md", "docs/writing.md", "index.php", "lib/admin.php", "lib/analytics.php", "lib/app.php", "lib/comments.php", "lib/compat.php", "lib/front.php", "lib/markdown.php", "lib/media.php", "lib/settings.php", "lib/store.php", "lib/update.php", "lib/vendor/sodium_compat/LICENSE", "lib/vendor/sodium_compat/autoload.php", "lib/vendor/sodium_compat/composer.json", "lib/vendor/sodium_compat/lib/namespaced.php", "lib/vendor/sodium_compat/lib/php72compat.php", "lib/vendor/sodium_compat/lib/php72compat_const.php", "lib/vendor/sodium_compat/lib/php84compat.php", "lib/vendor/sodium_compat/lib/php84compat_const.php", "lib/vendor/sodium_compat/lib/ristretto255.php", "lib/vendor/sodium_compat/lib/stream-xchacha20.php", "lib/vendor/sodium_compat/namespaced/Compat.php", "lib/vendor/sodium_compat/namespaced/Core/BLAKE2b.php", "lib/vendor/sodium_compat/namespaced/Core/ChaCha20.php", "lib/vendor/sodium_compat/namespaced/Core/ChaCha20/Ctx.php", "lib/vendor/sodium_compat/namespaced/Core/ChaCha20/IetfCtx.php", "lib/vendor/sodium_compat/namespaced/Core/Curve25519.php", "lib/vendor/sodium_compat/namespaced/Core/Curve25519/Fe.php", "lib/vendor/sodium_compat/namespaced/Core/Curve25519/Ge/Cached.php", "lib/vendor/sodium_compat/namespaced/Core/Curve25519/Ge/P1p1.php", "lib/vendor/sodium_compat/namespaced/Core/Curve25519/Ge/P2.php", "lib/vendor/sodium_compat/namespaced/Core/Curve25519/Ge/P3.php", "lib/vendor/sodium_compat/namespaced/Core/Curve25519/Ge/Precomp.php", "lib/vendor/sodium_compat/namespaced/Core/Curve25519/H.php", "lib/vendor/sodium_compat/namespaced/Core/Ed25519.php", "lib/vendor/sodium_compat/namespaced/Core/HChaCha20.php", "lib/vendor/sodium_compat/namespaced/Core/HSalsa20.php", "lib/vendor/sodium_compat/namespaced/Core/Poly1305.php", "lib/vendor/sodium_compat/namespaced/Core/Poly1305/State.php", "lib/vendor/sodium_compat/namespaced/Core/Salsa20.php", "lib/vendor/sodium_compat/namespaced/Core/SipHash.php", "lib/vendor/sodium_compat/namespaced/Core/Util.php", "lib/vendor/sodium_compat/namespaced/Core/X25519.php", "lib/vendor/sodium_compat/namespaced/Core/XChaCha20.php", "lib/vendor/sodium_compat/namespaced/Core/Xsalsa20.php", "lib/vendor/sodium_compat/namespaced/Crypto.php", "lib/vendor/sodium_compat/namespaced/File.php", "lib/vendor/sodium_compat/src/Compat.php", "lib/vendor/sodium_compat/src/Core/AEGIS/State128L.php", "lib/vendor/sodium_compat/src/Core/AEGIS/State256.php", "lib/vendor/sodium_compat/src/Core/AEGIS128L.php", "lib/vendor/sodium_compat/src/Core/AEGIS256.php", "lib/vendor/sodium_compat/src/Core/AES.php", "lib/vendor/sodium_compat/src/Core/AES/Block.php", "lib/vendor/sodium_compat/src/Core/AES/Expanded.php", "lib/vendor/sodium_compat/src/Core/AES/KeySchedule.php", "lib/vendor/sodium_compat/src/Core/BLAKE2b.php", "lib/vendor/sodium_compat/src/Core/Base64/Original.php", "lib/vendor/sodium_compat/src/Core/Base64/UrlSafe.php", "lib/vendor/sodium_compat/src/Core/ChaCha20.php", "lib/vendor/sodium_compat/src/Core/ChaCha20/Ctx.php", "lib/vendor/sodium_compat/src/Core/ChaCha20/IetfCtx.php", "lib/vendor/sodium_compat/src/Core/Curve25519.php", "lib/vendor/sodium_compat/src/Core/Curve25519/Fe.php", "lib/vendor/sodium_compat/src/Core/Curve25519/Ge/Cached.php", "lib/vendor/sodium_compat/src/Core/Curve25519/Ge/P1p1.php", "lib/vendor/sodium_compat/src/Core/Curve25519/Ge/P2.php", "lib/vendor/sodium_compat/src/Core/Curve25519/Ge/P3.php", "lib/vendor/sodium_compat/src/Core/Curve25519/Ge/Precomp.php", "lib/vendor/sodium_compat/src/Core/Curve25519/H.php", "lib/vendor/sodium_compat/src/Core/Curve25519/README.md", "lib/vendor/sodium_compat/src/Core/Ed25519.php", "lib/vendor/sodium_compat/src/Core/HChaCha20.php", "lib/vendor/sodium_compat/src/Core/HSalsa20.php", "lib/vendor/sodium_compat/src/Core/Poly1305.php", "lib/vendor/sodium_compat/src/Core/Poly1305/State.php", "lib/vendor/sodium_compat/src/Core/Ristretto255.php", "lib/vendor/sodium_compat/src/Core/Salsa20.php", "lib/vendor/sodium_compat/src/Core/SecretStream/State.php", "lib/vendor/sodium_compat/src/Core/SipHash.php", "lib/vendor/sodium_compat/src/Core/Util.php", "lib/vendor/sodium_compat/src/Core/X25519.php", "lib/vendor/sodium_compat/src/Core/XChaCha20.php", "lib/vendor/sodium_compat/src/Core/XSalsa20.php", "lib/vendor/sodium_compat/src/Crypto.php", "lib/vendor/sodium_compat/src/File.php", "lib/vendor/sodium_compat/src/SodiumException.php", "lib/version.php", "lib/views/analytics.php", "lib/views/comments.php", "lib/views/edit.php", "lib/views/layout.php", "lib/views/list.php", "lib/views/login.php", "lib/views/settings.php", "theme/default/404.php", "theme/default/alerts.js", "theme/default/comments.js", "theme/default/home.php", "theme/default/layout.php", "theme/default/post.js", "theme/default/post.php", "theme/default/reading.js", "theme/default/style.css", "theme/default/tags.php", "theme/default/theme.js", "theme/default/vendor/jquery.min.js", "theme/default/vendor/namespace.js", "theme/default/vendor/themestrap.plugin.alert.js", "theme/default/vendor/themestrap.plugin.scrollshadow.js", "theme/themestrap/404.php", "theme/themestrap/alerts.js", "theme/themestrap/comments.js", "theme/themestrap/functions.php", "theme/themestrap/home.php", "theme/themestrap/layout.php", "theme/themestrap/post.js", "theme/themestrap/post.php", "theme/themestrap/reading.js", "theme/themestrap/style.css", "theme/themestrap/tags.php", "theme/themestrap/theme.js", "theme/themestrap/vendor/jquery.min.js", "theme/themestrap/vendor/namespace.js", "theme/themestrap/vendor/themestrap.plugin.alert.js", "theme/themestrap/vendor/themestrap.plugin.scrollshadow.js", "tools/build-release.php", "tools/migrate.php"] JSON, true); $real = array_flip($manifest); $byName = []; foreach ($manifest as $rel) $byName[basename($rel)][] = dirname($rel) === '.' ? '' : dirname($rel); $dataLike = '/^\.gitkeep$|(\.md\.php|\.md|\.cache\.php|\.db|\.tmp)$|^(hits-\d{4}-\d{2}|settings|state|admin|log|ipinfo|comments|index\.cache)\.php$/i'; $stamp = '/-\d{14}(?=\.|$|-\d{14})/'; if (!is_file($root . '/index.php') || !is_dir($root . '/lib')) { fwrite(STDERR, "This does not look like the blog folder (no index.php and lib folder here). Run it from inside the blog folder.\n"); exit(1); } // If the blog is set up to keep its data in this very folder, data-like files here are real, so leave them $cfgFile = is_file($root . '/config.php') ? @include $root . '/config.php' : []; $cfgFile = is_array($cfgFile) ? $cfgFile : []; $dataHere = false; foreach (['data_dir', 'content_dir'] as $k) if (!empty($cfgFile[$k]) && realpath((string) $cfgFile[$k]) !== false && in_array(realpath((string) $cfgFile[$k]), [realpath($root), realpath($root . '/tools')], true)) $dataHere = true; $strays = []; // Walk the folder, skipping the ones that are not ours to look at (private session files, git, pictures) and // any folder this account is not allowed to open $skipDirs = ['_strays', '.git', 'uploads', 'data/sessions']; $skipped = []; $filter = new RecursiveCallbackFilterIterator(new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS), function ($f) use ($root, $skipDirs, &$skipped) { if (!$f->isDir() || $f->isLink()) return true; $rel = str_replace('\\', '/', substr($f->getPathname(), strlen($root) + 1)); if (in_array($rel, $skipDirs, true)) return false; if (!is_readable($f->getPathname()) || !is_executable($f->getPathname())) { $skipped[] = $rel; return false; } return true; }); $it = new RecursiveIteratorIterator($filter, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD); foreach ($it as $f) { if (!$f->isFile() || $f->isLink()) continue; $rel = str_replace('\\', '/', substr($f->getPathname(), strlen($root) + 1)); $top = explode('/', $rel)[0]; if (in_array($top, ['_strays', '.git', 'uploads'], true)) continue; if (isset($real[$rel])) continue; $dir = dirname($rel) === '.' ? '' : dirname($rel); $name = basename($rel); $why = ''; if (preg_match($stamp, $name)) $why = 'name has a timestamp added'; elseif (($dir === '' || $dir === 'tools') && $name !== 'config.php') { if (isset($byName[$name]) && !in_array($dir, $byName[$name], true)) $why = 'a copy of ' . ltrim($byName[$name][0] . '/' . $name, '/'); elseif (!$dataHere && preg_match($dataLike, $name)) $why = 'a data file that belongs in data or content'; } if ($why !== '') $strays[$rel] = $why; } ksort($strays); $missing = array_values(array_filter($manifest, fn($m) => !is_file($root . '/' . $m))); if ($skipped) echo "Skipped folders this account cannot open: " . implode(", ", $skipped) . "\n"; printf("%d stray file(s) found.\n", count($strays)); foreach ($strays as $rel => $why) printf(" %-70s %s\n", $rel, $why); if ($missing) { printf("\n%d of the blog's own files are missing from their proper place (an update or a fresh upload will restore them):\n", count($missing)); foreach ($missing as $m) echo " $m\n"; } else { echo "\nEvery one of the blog's own files is in its proper place.\n"; } if (!$strays) exit(0); if (!$move) { echo "\nNothing was changed. Run again with --move to put these in the _strays folder.\n"; exit(0); } $moved = 0; foreach ($strays as $rel => $why) { $dest = $root . '/_strays/' . $rel; if (!is_dir(dirname($dest)) && !@mkdir(dirname($dest), 0775, true)) { echo "Could not create a folder for $rel\n"; continue; } $n = 1; $base = $dest; while (file_exists($dest)) $dest = $base . '.' . $n++; if (@rename($root . '/' . $rel, $dest)) $moved++; else echo "Could not move $rel\n"; } @file_put_contents($root . '/_strays/.htaccess', "Require all denied\n"); @file_put_contents($root . '/_strays/index.html', ''); echo "\nMoved $moved file(s) into _strays. Check the blog, then delete that folder when you are happy.\n";