Sfoglia il codice sorgente

moved mass-rename-v2.php to mass-rename.php + deprecate older script support.

Christopher 5 anni fa
parent
commit
4c75448c9b
2 ha cambiato i file con 542 aggiunte e 86 eliminazioni
  1. 395 0
      mass-rename-v1.php
  2. 147 86
      mass-rename.php

+ 395 - 0
mass-rename-v1.php

@@ -0,0 +1,395 @@
+<?php
+
+//	Copyright (c) 2020 DBMXPCA Technologies. All rights reserved.
+//	www.dbmxpca.com
+//	Date Created: May 18, 2020
+//	Last Updated: May 19, 2020
+//	     Version: 1.06
+
+//	====================================================================================
+//	--- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS ---
+//	====================================================================================
+
+//	If you are running through a large dataset that may consume a large amount
+//	of memory, adjust this as necessary.
+ini_set('memory_limit', -1);
+
+//	If true, the script will search for all possible occurrences of itself
+//	and remove it from the directory traversal so as to prevent any alter-
+//	ations to the script itself. This can be useful but for larger dir-
+//	ectory traversals can consume a significant amount of time. It is rec-
+//	ommended that this is enabled only for small datasets or if time is
+//	not of significant concern.
+$remove_self = false;
+
+//	If true, the script will show a preview of all discovered files and dir-
+//	ectories. See the setting "$max_preview_size" for maximum preview results.
+$enable_dir_scan_preview = true;
+
+//	If true, the script will spew the full command immediately prior to its
+//	execution during the final renaming process.
+$display_full_cmd = true;
+
+//	If true, the script will spew the progress during the rename operation.
+$display_progress = true;
+
+//	If true, directories will be skipped and thus will not be renamed.
+$skip_directories = true;
+
+//	Maximum results per preview.
+$max_preview_size = 100;
+
+//	Number of characters to limit the full path & file command preview. This
+//	must be a negative number in order to display the last N characters.
+$cmd_display_limit = -32;
+
+
+
+//	====================================================================================
+//	+++++++++++ DO NOT EDIT BEYOND THIS POINT +++++++++++ DO NOT EDIT BEYOND THIS POINT
+//	====================================================================================
+
+
+$dirToTraverse = -1;
+$regex_search = "";
+$replace_str = "";
+$thisFile = __DIR__ . "/" . $argv[0];
+
+$script_time_start = 0;
+$script_time_end = 0;
+
+function GET_DIR_CONTENTS($dir, &$results = array()) {
+    $files = scandir($dir);
+
+    foreach ($files as $key => $value) {
+        $path = realpath($dir . DIRECTORY_SEPARATOR . $value);
+        if (!is_dir($path)) {
+            $results[] = $path;
+        } else if ($value != "." && $value != "..") {
+            GET_DIR_CONTENTS($path, $results);
+            $results[] = $path;
+        }
+    }
+
+    return $results;
+}
+
+function ECHO_USAGE(){
+	
+	global $argv;
+	
+	echo "\n > Usage:\n";
+	echo "    \"php " . $argv[0] . " <t-dir> <search-regex> <replace-str>\"\n";
+	echo "       where <t-dir> is the directory to traverse and\n";
+	echo "       <search-regex> is the regular expression to\n";
+	echo "       search for, and <replace-str> is the raw string\n";
+	echo "       to replace the search-regex with. Note that\n";
+	echo "       <replace-str> is NOT a regular expression.\n";
+	echo "       If <replace-str> contains one or more whitespace\n";
+	echo "       character(s), it must be enclosed within double-\n";
+	echo "       quotation marks.\n";
+	
+	echo "\n > Examples:\n";
+	echo "   > \"php " . $argv[0] . " . /.[a-z]+/ .jpg\"\n";
+	echo "   > \"php " . $argv[0] . " . /.[a-zA-Z]+/ .jpg\"\n";
+	echo "   > \"php " . $argv[0] . " . /.[a-zA-Z0-9]+/ \".jpg\"\"\n";
+	
+}
+
+//	@BRIEF		Replace $search with $replace in $str. This performs a simple replace using PHP's str_replace().
+function REPLACE($str, $search, $replace){
+	
+	return str_replace($search, $replace, $str);
+}
+
+//	@BRIEF		Replace $search with $replace in $str. This expects a regular expression for $search and uses PHP's preg_replace().
+function REPLACE2($str, $search, $replace){
+	
+	return preg_replace($search, $replace, $str);
+}
+
+//	Returns true if both strings are the same. Performs a case-insensitive comparison unless third parameter is true.
+function ARE_STRINGS_EQUAL($str1, $str2, $case_sensitive = false){
+	
+	switch($case_sensitive){
+		case true:
+			if (strcmp($str1, $str2) == 0){
+				return true;
+			}
+			else{
+				return false;
+			}
+			break;
+		default:
+			if (strcasecmp($str1, $str2) == 0){
+				return true;
+			}
+			else{
+				return false;
+			}
+			break;
+	}
+	return false;	
+}
+
+//	======================================================================
+
+if (isset($argv[1])){
+	
+	$dirToTraverse = $argv[1];
+	echo " > Check passed; Traversal Directory = [" . $dirToTraverse . "]\n";
+}
+
+else{
+	
+	echo " > Check FAILED; Missing Traversal Directory!\n";
+	
+	ECHO_USAGE();
+	
+	echo "\n > Script terminated.\n";
+	exit(1);
+}
+
+if (isset($argv[2])){
+	
+	$regex_search = $argv[2];
+	echo " > Check passed; Search RegEx = \"" . $regex_search . "\"\n";
+}
+
+else{
+	
+	echo " > Check FAILED; Missing Search RegEx!\n";
+	
+	ECHO_USAGE();
+	
+	echo "\n > Script terminated.\n";
+	exit(1);
+}
+
+if (isset($argv[3])){
+	
+	$replace_str = $argv[3];
+	echo " > Check passed; Replacement String = \"" . $replace_str . "\"\n";
+}
+
+else{
+	
+	echo " > Check FAILED; Missing Search RegEx!\n";
+	
+	ECHO_USAGE();
+	
+	echo "\n > Script terminated.\n";
+	exit(1);
+}
+
+echo " > Performing initial directory traversal, please wait...\n";
+$script_time_start = microtime(true);
+
+$contents = array();
+GET_DIR_CONTENTS($dirToTraverse, $contents);
+
+if ($remove_self){
+	
+	while( ($found = array_search($thisFile, $contents)) !== false ){
+		
+		echo " > Removing this script from file listing.\n";
+		unset($contents[$found]);
+	}
+}
+
+// var_dump($contents);
+$script_time_end = microtime(true);
+$script_runtime = $script_time_end - $script_time_start;
+
+echo " > Initial directory traversal complete [" . $script_runtime . " ms].\n";
+
+$counter = 0;
+$stop_preview = false;
+
+if ($enable_dir_scan_preview){
+
+	echo " > ORIGINAL FILE AND DIRECTORY PREVIEW:\n ================================\n";
+	foreach ($contents as $c){
+		
+		if ($stop_preview)
+			break;
+		$counter++;
+		
+		if ($counter > $max_preview_size){
+			
+			echo " --------- (results truncated)\n";
+			$stop_preview = true;
+			break;
+		}
+		
+		echo "   " . $c . "\n";
+	}
+
+	echo " ================================\n";
+}
+
+$content_map = array();
+$content_map_new = array();
+
+//	Build a content map: array with path => filename format.
+foreach ($contents as $c){
+	
+	if (is_dir($c))
+		$filename = null;
+	else
+		$filename = basename($c);
+	
+	$content_map[$c] = $filename;
+}
+
+$content_map_new = $content_map;
+
+echo " > Creating new content map based on supplied search and replace settings, please wait...\n";
+
+// print_r($content_map);
+
+//	Build the replacement content map. This contains the same path => filename
+//	format but with the updated filename instead of the original.
+$script_time_start = microtime(true);
+foreach ($content_map_new as $p => $f){
+	
+	// REPLACE2($str, $search, $replace)
+	$filename_new = REPLACE2($f, $regex_search, $replace_str);
+	$path_new = REPLACE2($p, $regex_search, $replace_str);
+	$content_map_new[$p] = $filename_new;
+}
+
+$script_time_end = microtime(true);
+$script_runtime = $script_time_end - $script_time_start;
+
+echo " > Success: new content map created [" . $script_runtime . " ms].\n";
+
+echo " > FILE AND DIRECTORY PREVIEW:\n ================================\n";
+
+
+$counter = 0;
+$stop_preview = false;
+
+foreach ($content_map as $p => $f){
+	
+	if ($stop_preview)
+		break;
+	
+	if (!is_dir($p)){
+		
+		$counter++;
+		
+		if ($counter > $max_preview_size){
+			
+			echo " --------- (results truncated)\n";
+			$stop_preview = true;
+			break;
+		}
+		
+		$new_path = dirname($p) . "/" . $content_map_new[$p];
+		echo " [before]: " . $p . "\n";
+		echo "  [after]: " . $new_path . "\n\n";
+		
+	}
+	
+}
+
+
+echo " *** Please review above results carefully ***\n\n";
+echo "  - To begin operation (cannot be undone), type 'Y' and press ENTER/RETURN.\n";
+// echo " - To preview more results, type 'P'  and press ENTER/RETURN.\n";
+echo "  - To cancel script without making any changes, type 'N' and press ENTER/RETURN.\n";
+echo "\n  >> Begin operation? [Y/n]: ";
+$response = fgets(STDIN);
+$begin_operation = substr($response, 0, strlen($response) - 1);
+
+if (ARE_STRINGS_EQUAL($begin_operation, "Y", true)){
+	
+	echo "\n  > Operation started by user.\n";
+	$countdown_timer = 5;
+	while($countdown_timer > 0){
+		
+		echo "  > Operation starting in " . $countdown_timer . " second(s)...\n";
+		$countdown_timer--;
+		sleep(1);
+	}
+	
+	echo "\n  > Operation in progress, please wait...\n";
+	
+	$total_items = count($content_map) + 1;
+	$items_remaining = $total_items;
+	$curr_item = 0;
+	$progress_val = 0;
+	$script_time_start = microtime(true);
+	
+	foreach ($content_map as $p => $f){
+		
+		$curr_item++;
+		$progress_val = $curr_item / $total_items;
+		$progress_val *= 100;
+		$progress_val_d = number_format((float)$progress_val, 2, '.', '');
+		
+		//	TODO: Only perform this check if skip_directories is TRUE.
+		if (!is_dir($p)){
+			
+			
+			$new_path = dirname($p) . "/" . $content_map_new[$p];
+			//	Actual command to be executed.
+			$cmd = "mv \"" . $p . "\" \"" . $new_path . "\"";
+			//	Truncated command to be displayed.
+			$cmd_d = "-";
+			//	Make sure the strings are actually long enough to get truncated. If either are too short,
+			//	then just display the full command.
+			if (strlen($p) >= -$cmd_display_limit && strlen($new_path) >= -$cmd_display_limit){
+				$cmd_d = "mv \"..." . substr($p, $cmd_display_limit) . "\" \"..." . substr($new_path, $cmd_display_limit) . "\"";
+			}
+			else{
+				$cmd_d = $cmd;
+			}
+			
+			if (!$display_progress && !$display_full_cmd){		//00
+				//	print nothing
+			}
+			else if (!$display_progress && $display_full_cmd){	//01
+				echo " >>> [" . $cmd_d . "]\n";
+			}
+			else if ($display_progress && !$display_full_cmd){	//10
+				echo " >>> [Progress:  " . $progress_val_d . "%  (" . $curr_item . "/" . $total_items . ") | Items Remaining: " . $items_remaining . "]\n";
+			}
+			else if ($display_progress && $display_full_cmd){	//11
+				echo " >>> [Progress: " . $progress_val_d . "% (" . $curr_item . "/" . $total_items . ") | Remaining: " . $items_remaining . "] | [" . $cmd_d . "]\n";
+			}
+			
+			exec($cmd);
+		}
+		
+		$items_remaining--;
+		
+	}
+	
+	$script_time_end = microtime(true);
+	$script_runtime = $script_time_end - $script_time_start;
+	
+	echo "  > Operation complete. [" . $script_runtime . " ms].\n";
+	exit(0);
+	
+}
+
+echo "\n  > Operation cancelled by user.\n";
+exit(0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 147 - 86
mass-rename.php

@@ -4,7 +4,7 @@
 //	www.dbmxpca.com
 //	Date Created: May 18, 2020
 //	Last Updated: May 19, 2020
-//	     Version: 1.06
+//	     Version: 2.03
 
 //	====================================================================================
 //	--- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS ---
@@ -228,21 +228,54 @@ if ($enable_dir_scan_preview){
 	echo " ================================\n";
 }
 
+$total_items_original = count($contents);
+//	Account for zero-based indexing.
+if ($total_items_original > 0)
+	$total_items_original++;
+
+echo " > A total of " . $total_items_original . " files and directories were discovered.\n";
+
 $content_map = array();
 $content_map_new = array();
 
-//	Build a content map: array with path => filename format.
+echo " > Creating base content map, please wait...\n";
+$script_time_start = microtime(true);
+
+//	V2 Update: Build a content map with ONLY the path, while
+//	honoring the $skip_directory setting. The content map will
+//	be roughly the same if $skip_directories is false but should
+//	usually be shortened if the aforementioned setting is true.
 foreach ($contents as $c){
 	
-	if (is_dir($c))
-		$filename = null;
-	else
-		$filename = basename($c);
-	
-	$content_map[$c] = $filename;
+	switch($skip_directories){
+		
+		case true:
+			if (!is_dir($c)){
+				array_push($content_map, $c);
+			}
+			break;
+		default:
+			array_push($content_map, $c);
+			break;
+	}
 }
 
-$content_map_new = $content_map;
+$script_time_end = microtime(true);
+$script_runtime = $script_time_end - $script_time_start;
+
+//	Cleanup items no longer needed.
+$contents = null;
+
+echo " > Base content map creation complete [" . $script_runtime . " ms].\n";
+$total_items_old = count($content_map);
+//	Account for zero-based indexing.
+if ($total_items_old > 0)
+	$total_items_old++;
+
+echo " > A total of " . $total_items_old . " item(s) remain, after filtering based on script directory-skip settings.\n";
+
+//	Instead of copying the entire array, we'll add to it as necessary later.
+// $content_map_new = $content_map;
 
 echo " > Creating new content map based on supplied search and replace settings, please wait...\n";
 
@@ -251,26 +284,48 @@ echo " > Creating new content map based on supplied search and replace settings,
 //	Build the replacement content map. This contains the same path => filename
 //	format but with the updated filename instead of the original.
 $script_time_start = microtime(true);
-foreach ($content_map_new as $p => $f){
+// foreach ($content_map_new as $p => $f){
+	
+//	V2 Update: Build a new content map, with ONLY values that will be replaced,
+//	in key => value pairs as old_value => new_value.
+foreach ($content_map as $p){
+	
+	//	Keep track of old and new filenames.
+	$filename = $p;
+	$filename_new = $filename;
 	
-	// REPLACE2($str, $search, $replace)
-	$filename_new = REPLACE2($f, $regex_search, $replace_str);
-	$path_new = REPLACE2($p, $regex_search, $replace_str);
-	$content_map_new[$p] = $filename_new;
+	//	Perform the search & replacement.
+	$filename_new = REPLACE2($filename_new, $regex_search, $replace_str);
+	
+	//	If original and new filenames are different, then a replacement was made.
+	//	Add this to the new content map.
+	if (!ARE_STRINGS_EQUAL($filename, $filename_new)){
+		
+		$content_map_new[$filename] = $filename_new;
+	}
 }
 
+//	Record number of items for use later.
+$total_items = count($content_map_new);
+//	Account for zero-based indexing.
+if ($total_items > 0)
+	$total_items++;
+
 $script_time_end = microtime(true);
 $script_runtime = $script_time_end - $script_time_start;
 
-echo " > Success: new content map created [" . $script_runtime . " ms].\n";
+//	Cleanup items no longer needed.
+$content_map = null;
 
+echo " > Success: new content map created [" . $script_runtime . " ms].\n";
 echo " > FILE AND DIRECTORY PREVIEW:\n ================================\n";
 
 
 $counter = 0;
 $stop_preview = false;
 
-foreach ($content_map as $p => $f){
+//	Display preview of new content map.
+foreach ($content_map_new as $old => $new){
 	
 	if ($stop_preview)
 		break;
@@ -286,98 +341,104 @@ foreach ($content_map as $p => $f){
 			break;
 		}
 		
-		$new_path = dirname($p) . "/" . $content_map_new[$p];
-		echo " [before]: " . $p . "\n";
-		echo "  [after]: " . $new_path . "\n\n";
+		echo " [before]: " . $old . "\n";
+		echo "  [after]: " . $new . "\n\n";
 		
 	}
 	
 }
 
 
-echo " *** Please review above results carefully ***\n\n";
-echo "  - To begin operation (cannot be undone), type 'Y' and press ENTER/RETURN.\n";
-// echo " - To preview more results, type 'P'  and press ENTER/RETURN.\n";
-echo "  - To cancel script without making any changes, type 'N' and press ENTER/RETURN.\n";
-echo "\n  >> Begin operation? [Y/n]: ";
-$response = fgets(STDIN);
-$begin_operation = substr($response, 0, strlen($response) - 1);
+echo "\n >>> A total of " . $total_items . " item(s) will be renamed if you continue. <<<\n\n";
 
-if (ARE_STRINGS_EQUAL($begin_operation, "Y", true)){
-	
-	echo "\n  > Operation started by user.\n";
-	$countdown_timer = 5;
-	while($countdown_timer > 0){
+if ($total_items > 0){
+
+	echo " *** PLEASE REVIEW ABOVE PREVIEW RESULTS CAREFULLY BEFORE PROCEEDING. ***\n\n";
+	echo "  - To begin operation (cannot be undone), type 'Y' and press ENTER/RETURN.\n";
+	// echo " - To preview more results, type 'P'  and press ENTER/RETURN.\n";
+	echo "  - To cancel script without making any changes, type 'N' and press ENTER/RETURN.\n";
+	echo "\n  >> Begin operation? [Y/n]: ";
+	$response = fgets(STDIN);
+	$begin_operation = substr($response, 0, strlen($response) - 1);
+
+	if (ARE_STRINGS_EQUAL($begin_operation, "Y", true)){
 		
-		echo "  > Operation starting in " . $countdown_timer . " second(s)...\n";
-		$countdown_timer--;
-		sleep(1);
-	}
-	
-	echo "\n  > Operation in progress, please wait...\n";
-	
-	$total_items = count($content_map) + 1;
-	$items_remaining = $total_items;
-	$curr_item = 0;
-	$progress_val = 0;
-	$script_time_start = microtime(true);
-	
-	foreach ($content_map as $p => $f){
+		echo "\n  > Operation started by user.\n";
+		$countdown_timer = 5;
+		while($countdown_timer > 0){
+			
+			echo "  > Operation starting in " . $countdown_timer . " second(s)...\n";
+			$countdown_timer--;
+			sleep(1);
+		}
+		
+		echo "\n  > Operation in progress, please wait...\n";
 		
-		$curr_item++;
-		$progress_val = $curr_item / $total_items;
-		$progress_val *= 100;
-		$progress_val_d = number_format((float)$progress_val, 2, '.', '');
+		$items_remaining = $total_items;
+		$curr_item = 0;
+		$progress_val = 0;
+		$script_time_start = microtime(true);
 		
-		//	TODO: Only perform this check if skip_directories is TRUE.
-		if (!is_dir($p)){
+		foreach ($content_map_new as $old => $new){
 			
+			$curr_item++;
+			$progress_val = $curr_item / $total_items;
+			$progress_val *= 100;
+			$progress_val_d = number_format((float)$progress_val, 2, '.', '');
 			
-			$new_path = dirname($p) . "/" . $content_map_new[$p];
-			//	Actual command to be executed.
-			$cmd = "mv \"" . $p . "\" \"" . $new_path . "\"";
-			//	Truncated command to be displayed.
-			$cmd_d = "-";
-			//	Make sure the strings are actually long enough to get truncated. If either are too short,
-			//	then just display the full command.
-			if (strlen($p) >= -$cmd_display_limit && strlen($new_path) >= -$cmd_display_limit){
-				$cmd_d = "mv \"..." . substr($p, $cmd_display_limit) . "\" \"..." . substr($new_path, $cmd_display_limit) . "\"";
-			}
-			else{
-				$cmd_d = $cmd;
+			//	TODO: Only perform this check if skip_directories is TRUE.
+			if (!is_dir($p)){
+				
+				//	Actual command to be executed.
+				$cmd = "mv \"" . $old . "\" \"" . $new . "\"";
+				//	Truncated command to be displayed.
+				$cmd_d = "-";
+				//	Make sure the strings are actually long enough to get truncated. If either are too short,
+				//	then just display the full command.
+				if (strlen($old) >= -$cmd_display_limit && strlen($new) >= -$cmd_display_limit){
+					$cmd_d = "mv \"..." . substr($old, $cmd_display_limit) . "\" \"..." . substr($new, $cmd_display_limit) . "\"";
+				}
+				else{
+					$cmd_d = $cmd;
+				}
+				
+				if (!$display_progress && !$display_full_cmd){		//00
+					//	print nothing
+				}
+				else if (!$display_progress && $display_full_cmd){	//01
+					echo " >>> [" . $cmd_d . "]\n";
+				}
+				else if ($display_progress && !$display_full_cmd){	//10
+					echo " >>> [Progress:  " . $progress_val_d . "%  (" . $curr_item . "/" . $total_items . ") | Items Remaining: " . $items_remaining . "]\n";
+				}
+				else if ($display_progress && $display_full_cmd){	//11
+					echo " >>> [Progress: " . $progress_val_d . "% (" . $curr_item . "/" . $total_items . ") | Remaining: " . $items_remaining . "] | [" . $cmd_d . "]\n";
+				}
+				
+				exec($cmd);
 			}
 			
-			if (!$display_progress && !$display_full_cmd){		//00
-				//	print nothing
-			}
-			else if (!$display_progress && $display_full_cmd){	//01
-				echo " >>> [" . $cmd_d . "]\n";
-			}
-			else if ($display_progress && !$display_full_cmd){	//10
-				echo " >>> [Progress:  " . $progress_val_d . "%  (" . $curr_item . "/" . $total_items . ") | Items Remaining: " . $items_remaining . "]\n";
-			}
-			else if ($display_progress && $display_full_cmd){	//11
-				echo " >>> [Progress: " . $progress_val_d . "% (" . $curr_item . "/" . $total_items . ") | Remaining: " . $items_remaining . "] | [" . $cmd_d . "]\n";
-			}
+			$items_remaining--;
 			
-			exec($cmd);
 		}
 		
-		$items_remaining--;
+		$script_time_end = microtime(true);
+		$script_runtime = $script_time_end - $script_time_start;
+		
+		echo "  > Operation complete. [" . $script_runtime . " ms].\n";
+		exit(0);
 		
 	}
-	
-	$script_time_end = microtime(true);
-	$script_runtime = $script_time_end - $script_time_start;
-	
-	echo "  > Operation complete. [" . $script_runtime . " ms].\n";
+
+	echo "\n  > Operation cancelled by user.\n";
 	exit(0);
-	
 }
 
-echo "\n  > Operation cancelled by user.\n";
-exit(0);
-
+else{
+	
+	echo "\n  > Operation cancelled: there are no items to replace.\n";
+	exit(0);
+}