|
|
@@ -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);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|