Skip to content

Instantly share code, notes, and snippets.

@mejta
Last active April 7, 2022 23:42
Show Gist options
  • Select an option

  • Save mejta/162c54ef859801d5dff8d2b01a91153f to your computer and use it in GitHub Desktop.

Select an option

Save mejta/162c54ef859801d5dff8d2b01a91153f to your computer and use it in GitHub Desktop.
Script that cleans unused files in WordPress uploads folder
<?php
/**
* Find WordPress wp-blog-header.php file.
*
* @param string $folder
*
* @return string
*/
function find_blog_header( string $folder ): string {
$folder = rtrim( $folder, '/' );
$count = 0;
while ( $count < 20 ) {
if ( file_exists( $folder . '/wp-blog-header.php' ) ) {
return $folder . '/wp-blog-header.php';
}
if ( file_exists( $folder . '/wp/wp-blog-header.php' ) ) {
return $folder . '/wp/wp-blog-header.php';
}
$folder = dirname( $folder );
$count ++;
}
return '';
}
/**
* Find uploads folder.
*
* @return string
*/
function find_uploads_folder(): string {
$upload_dir = wp_upload_dir();
return $upload_dir['basedir'];
}
/**
* Get the SQL dump from the database.
*
* @return string
*/
function get_sql_dump(): string {
$destination = sys_get_temp_dir() . '/' . wp_generate_uuid4() . '.sql';
if ( file_exists( $destination ) ) {
unlink( $destination );
}
exec( "mysqldump --user=" . DB_USER . " --password=" . DB_PASSWORD . " --host=" . DB_HOST . " " . DB_NAME . " > " . $destination );
$dump = file_get_contents( $destination );
unlink( $destination );
return $dump;
}
/**
* Get the file count in folder.
*
* @param $path
*
* @return int
*/
function get_file_count( $path ): int {
$size = 0;
$ignore = array( '.', '..', '.DS_Store' );
$files = scandir( $path );
foreach ( $files as $t ) {
if ( in_array( $t, $ignore ) ) {
continue;
} elseif ( is_dir( rtrim( $path, '/' ) . '/' . $t ) ) {
$size += get_file_count( rtrim( $path, '/' ) . '/' . $t );
} else {
$size ++;
}
}
return $size;
}
/**
* Removes empty folders recursively.
*
* @param $path
*
* @return bool
*/
function remove_empty_folders( $path ): bool {
$empty = true;
foreach ( glob( $path . DIRECTORY_SEPARATOR . '*' ) as $file ) {
if ( is_dir( $file ) ) {
if ( ! remove_empty_folders( $file ) ) {
$empty = false;
}
} else {
$empty = false;
}
}
if ( $empty ) {
@rmdir( $path );
}
return $empty;
}
/**
* Walk through the uploads folder and run callback on each file.
*
* @param string $dir
* @param callable $callback
*/
function walk_all_files( string $dir, callable $callback ): void {
$root = scandir( $dir );
foreach ( $root as $value ) {
if ( $value === '.' || $value === '..' ) {
continue;
}
if ( is_file( $dir . DIRECTORY_SEPARATOR . $value ) ) {
$callback( $dir . DIRECTORY_SEPARATOR . $value, $dir );
continue;
}
walk_all_files( $dir . DIRECTORY_SEPARATOR . $value, $callback );
}
}
$blog_header = find_blog_header( __DIR__ );
if ( empty( $blog_header ) ) {
die( "Could not find WordPress root folder." );
}
const WP_USE_THEMES = false;
$_SERVER['HTTP_HOST'] = null;
$_SERVER['REQUEST_METHOD'] = 'GET';
echo "\nIncluding WordPress...\n";
require $blog_header;
echo "\nRequesting database dump...\n";
$dump = get_sql_dump();
$uploads = find_uploads_folder();
echo "\nProcessing files...\n";
$file_count = get_file_count( $uploads );
$process = 0;
$percent = $process / $file_count * 100;
$width = 50;
$bar = floor( $width / 100 * $percent );
$deleted = 0;
echo "[ " . str_repeat( "=", $bar ) . ">" . str_repeat( " ", $width - $bar ) . " ] " . round( $percent, 2 ) . "% (" . $process . "/" . $file_count . ")";
walk_all_files( $uploads, function ( string $file ) use ( $uploads, $dump, &$process, $width, &$bar, &$percent, $file_count, &$deleted ) {
$process ++;
$percent = $process / $file_count * 100;
$bar = floor( $width / 100 * $percent );
echo "\033[0G\033[2K[ " . str_repeat( "=", $bar ) . ">" . str_repeat( " ", $width - $bar ) . " ] " . round( $percent, 2 ) . "% (" . $process . "/" . $file_count . ")";
if ( preg_match( "~[0-9]{4}/[0-9]{2}/(?<filename>[^/]+$)~m", $file, $matches ) ) {
if ( mb_strpos( $dump, $matches['filename'] ) === false ) {
if ( unlink( $file ) ) {
$deleted ++;
} else {
echo " > could not remove " . $file . "\n";
}
}
}
} );
echo "\033[0G\033[2K > deleted " . $deleted . " files\n";
echo "\nRemoving empty folders...\n";
remove_empty_folders( $uploads );
echo "\nFinished!\n";
@mejta
Copy link
Author

mejta commented Apr 7, 2022

Usage: php clean-wordpress-uploads.php

@mejta
Copy link
Author

mejta commented Apr 7, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment