mass-rename.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <?php
  2. // Copyright (c) 2020 DBMXPCA Technologies. All rights reserved.
  3. // www.dbmxpca.com
  4. // Date Created: May 18, 2020
  5. // Last Updated: May 18, 2020
  6. // Version: 1.1
  7. // ====================================================================================
  8. // --- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS --- SETTINGS ---
  9. // ====================================================================================
  10. // If true, the script will search for all possible occurrences of itself
  11. // and remove it from the directory traversal so as to prevent any alter-
  12. // ations to the script itself. This can be useful but for larger dir-
  13. // ectory traversals can consume a significant amount of time. It is rec-
  14. // ommended that this is enabled only for small datasets or if time is
  15. // not of significant concern.
  16. $remove_self = false;
  17. // If true, directories will be skipped and thus will not be renamed.
  18. $skip_directories = true;
  19. // Maximum results per preview group.
  20. $count_group_size = 100;
  21. // ====================================================================================
  22. // +++++++++++ DO NOT EDIT BEYOND THIS POINT +++++++++++ DO NOT EDIT BEYOND THIS POINT
  23. // ====================================================================================
  24. $dirToTraverse = -1;
  25. $regex_search = "";
  26. $replace_str = "";
  27. $thisFile = __DIR__ . "/" . $argv[0];
  28. function GET_DIR_CONTENTS($dir, &$results = array()) {
  29. $files = scandir($dir);
  30. foreach ($files as $key => $value) {
  31. $path = realpath($dir . DIRECTORY_SEPARATOR . $value);
  32. if (!is_dir($path)) {
  33. $results[] = $path;
  34. } else if ($value != "." && $value != "..") {
  35. GET_DIR_CONTENTS($path, $results);
  36. $results[] = $path;
  37. }
  38. }
  39. return $results;
  40. }
  41. function ECHO_USAGE(){
  42. global $argv;
  43. echo "\n > Usage:\n";
  44. echo " \"php " . $argv[0] . " <t-dir> <search-regex> <replace-str>\"\n";
  45. echo " where <t-dir> is the directory to traverse and\n";
  46. echo " <search-regex> is the regular expression to\n";
  47. echo " search for, and <replace-str> is the raw string\n";
  48. echo " to replace the search-regex with. Note that\n";
  49. echo " <replace-str> is NOT a regular expression.\n";
  50. echo " If <replace-str> contains one or more whitespace\n";
  51. echo " character(s), it must be enclosed within double-\n";
  52. echo " quotation marks.\n";
  53. echo "\n > Examples:\n";
  54. echo " > \"php " . $argv[0] . " . /.[a-z]+/ .jpg\"\n";
  55. echo " > \"php " . $argv[0] . " . /.[a-zA-Z]+/ .jpg\"\n";
  56. echo " > \"php " . $argv[0] . " . /.[a-zA-Z0-9]+/ \".jpg\"\"\n";
  57. }
  58. // @BRIEF Replace $search with $replace in $str. This performs a simple replace using PHP's str_replace().
  59. function REPLACE($str, $search, $replace){
  60. return str_replace($search, $replace, $str);
  61. }
  62. // @BRIEF Replace $search with $replace in $str. This expects a regular expression for $search and uses PHP's preg_replace().
  63. function REPLACE2($str, $search, $replace){
  64. return preg_replace($search, $replace, $str);
  65. }
  66. // Returns true if both strings are the same. Performs a case-insensitive comparison unless third parameter is true.
  67. function ARE_STRINGS_EQUAL($str1, $str2, $case_sensitive = false){
  68. switch($case_sensitive){
  69. case true:
  70. if (strcmp($str1, $str2) == 0){
  71. return true;
  72. }
  73. else{
  74. return false;
  75. }
  76. break;
  77. default:
  78. if (strcasecmp($str1, $str2) == 0){
  79. return true;
  80. }
  81. else{
  82. return false;
  83. }
  84. break;
  85. }
  86. return false;
  87. }
  88. // ======================================================================
  89. if (isset($argv[1])){
  90. $dirToTraverse = $argv[1];
  91. echo " > Check passed; Traversal Directory = [" . $dirToTraverse . "]\n";
  92. }
  93. else{
  94. echo " > Check FAILED; Missing Traversal Directory!\n";
  95. ECHO_USAGE();
  96. echo "\n > Script terminated.\n";
  97. exit(1);
  98. }
  99. if (isset($argv[2])){
  100. $regex_search = $argv[2];
  101. echo " > Check passed; Search RegEx = \"" . $regex_search . "\"\n";
  102. }
  103. else{
  104. echo " > Check FAILED; Missing Search RegEx!\n";
  105. ECHO_USAGE();
  106. echo "\n > Script terminated.\n";
  107. exit(1);
  108. }
  109. if (isset($argv[3])){
  110. $replace_str = $argv[3];
  111. echo " > Check passed; Replacement String = \"" . $replace_str . "\"\n";
  112. }
  113. else{
  114. echo " > Check FAILED; Missing Search RegEx!\n";
  115. ECHO_USAGE();
  116. echo "\n > Script terminated.\n";
  117. exit(1);
  118. }
  119. $contents = array();
  120. GET_DIR_CONTENTS($dirToTraverse, $contents);
  121. if ($remove_self){
  122. while( ($found = array_search($thisFile, $contents)) !== false ){
  123. echo " > Removing this script from file listing.\n";
  124. unset($contents[$found]);
  125. }
  126. }
  127. // var_dump($contents);
  128. echo " > FILE AND DIRECTORY LIST:\n ================================\n";
  129. foreach ($contents as $c){
  130. echo " " . $c . "\n";
  131. }
  132. echo " ================================\n";
  133. $content_map = array();
  134. $content_map_new = array();
  135. // Build a content map: array with path => filename format.
  136. foreach ($contents as $c){
  137. if (is_dir($c))
  138. $filename = null;
  139. else
  140. $filename = basename($c);
  141. $content_map[$c] = $filename;
  142. }
  143. $content_map_new = $content_map;
  144. // print_r($content_map);
  145. // Build the replacement content map. This contains the same path => filename
  146. // format but with the updated filename instead of the original.
  147. foreach ($content_map_new as $p => $f){
  148. // REPLACE2($str, $search, $replace)
  149. $filename_new = REPLACE2($f, $regex_search, $replace_str);
  150. $path_new = REPLACE2($p, $regex_search, $replace_str);
  151. $content_map_new[$p] = $filename_new;
  152. }
  153. echo " > New content map created. See below for preview.\n";
  154. echo " > FILE AND DIRECTORY PREVIEW:\n ================================\n";
  155. $counter = 0;
  156. $stop_preview = false;
  157. foreach ($content_map as $p => $f){
  158. if ($stop_preview)
  159. break;
  160. if (!is_dir($p)){
  161. $counter++;
  162. if ($counter > $count_group_size){
  163. echo " --------- (results truncated)\n";
  164. $stop_preview = true;
  165. break;
  166. }
  167. $new_path = dirname($p) . "/" . $content_map_new[$p];
  168. echo " [before]: " . $p . "\n";
  169. echo " [after]: " . $new_path . "\n\n";
  170. }
  171. }
  172. echo " *** Please review above results carefully ***\n\n";
  173. echo " - To begin operation (cannot be undone), type 'Y' and press ENTER/RETURN.\n";
  174. // echo " - To preview more results, type 'P' and press ENTER/RETURN.\n";
  175. echo " - To cancel script without making any changes, type 'N' and press ENTER/RETURN.\n";
  176. echo "\n >> Begin operation? [Y/n]: ";
  177. $response = fgets(STDIN);
  178. $begin_operation = substr($response, 0, strlen($response) - 1);
  179. if (ARE_STRINGS_EQUAL($begin_operation, "Y", true)){
  180. echo "\n > Operation started by user.\n";
  181. $countdown_timer = 5;
  182. while($countdown_timer > 0){
  183. echo " > Operation starting in " . $countdown_timer . " second(s)...\n";
  184. $countdown_timer--;
  185. sleep(1);
  186. }
  187. foreach ($content_map as $p => $f){
  188. if (!is_dir($p)){
  189. $new_path = dirname($p) . "/" . $content_map_new[$p];
  190. $cmd = "mv \"" . $p . "\" \"" . $new_path . "\"";
  191. echo " >>> " . $cmd . "\n";
  192. exec($cmd);
  193. }
  194. }
  195. echo " > Operation complete.\n";
  196. exit(0);
  197. }
  198. echo "\n > Operation cancelled by user.\n";
  199. exit(0);