PageRenderTime 1559ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/vqmod/install/ugrsr.class.php

https://bitbucket.org/MSambrook/dsgi-opencart-site
PHP | 494 lines | 228 code | 99 blank | 167 comment | 40 complexity | 1213285ec574e47b69a1a9195fd8c8fd MD5 | raw file
  1. <?php
  2. /**
  3. * UGRSR
  4. *
  5. * @package Universal Global RegEx Search/Replace
  6. * @author Qphoria - http://theqdomain.com/ & Jay Gilford - http://jaygilford.com/
  7. * @copyright Qphoria & Jay Gilford 2011
  8. * @version 0.2
  9. * @access public
  10. *
  11. * @information
  12. * This class will perform mass search and replace actions
  13. * based on regex pattern matching. It recursively grabs all files
  14. * below it's given path and applies the specified change(s)
  15. *
  16. * @license
  17. * Permission is hereby granted, free of charge, to any person to
  18. * use, copy, modify, distribute, sublicense, and/or sell copies
  19. * of the Software, subject to the following conditions:
  20. *
  21. * The above copyright notice and this permission notice shall be
  22. * included in all copies or substantial portions of the Software
  23. *
  24. * @warning
  25. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. * EXPRESSED OR IMPLIED.
  27. *
  28. */
  29. class UGRSR {
  30. public $debug = false; // Show debug messages switch
  31. public $flags = 0; // Flags for the file recursive glob
  32. public $pattern = '*.php'; // File pattern to match with glob
  33. public $recursive = true; // Recursion into subdirectories switch
  34. public $test_mode = false; // Test mode only switch
  35. public $file_search = true; // Search for files switch
  36. private $_regexes = array(); // Array for regex patterns and replaces
  37. private $_path = ''; // Path to directory to work with
  38. private $_protected = array(); // Array of protected files
  39. private $_files = array(); // Array of manually added file locations
  40. /**
  41. * UGRSR::__construct()
  42. *
  43. * @param string $path
  44. * @return null
  45. */
  46. function __construct($path = '') {
  47. // Use current working directory if none given as a parameter
  48. if(empty($path)) {
  49. $path = getcwd();
  50. }
  51. // Apply path to var
  52. $this->setPath($path);
  53. // Check to make sure the script calling the class is set to be protected
  54. if(!isset($_SERVER['SCRIPT_FILENAME'])) {
  55. DIE('SCRIPT FILENAME COULD NOT BE DETERMINED');
  56. }
  57. // Set default file protections
  58. $this->resetProtected();
  59. }
  60. /**
  61. * UGRSR::addPattern()
  62. *
  63. * @param string $pattern
  64. * @param string $replace
  65. * @return bool
  66. */
  67. public function addPattern($pattern, $replace) {
  68. // If pattern is empty throw error
  69. if(empty($pattern)) {
  70. $this->_dbg('PATTERN EMPTY');
  71. return false;
  72. }
  73. // Add regex pattern and replace vars to _regexes array
  74. $this->_regexes[] = array(
  75. 'pattern' => $pattern,
  76. 'replace' => $replace
  77. );
  78. return true;
  79. }
  80. /**
  81. * UGRSR::mergePatterns()
  82. *
  83. * @param array $pattern_array
  84. * @return bool
  85. */
  86. public function mergePatterns($pattern_array) {
  87. // If the param is not an array throw error
  88. if(!is_array($pattern_array)) {
  89. $this->_dbg('PARAM IS NOT AN ARRAY');
  90. return false;
  91. }
  92. //Loop through pattern array
  93. foreach($pattern_array as $data) {
  94. // If pattern or replace keys not set throw error and continue loop
  95. if(!isset($data['pattern']) || !isset($data['replace'])) {
  96. $this->_dbg('ARRAY KEYS NOT SET');
  97. continue;
  98. }
  99. // Add regex and replace
  100. $this->addPattern($data['pattern'], $data['replace']);
  101. }
  102. return true;
  103. }
  104. /**
  105. * UGRSR::clearPatterns()
  106. *
  107. * @return null
  108. */
  109. public function clearPatterns() {
  110. // Set regexes var to empty array
  111. $this->_regexes = array();
  112. }
  113. /**
  114. * UGRSR::addFile()
  115. *
  116. * @param string $filename
  117. * @param bool
  118. * @return bool
  119. */
  120. public function addFile($filename, $omit_path = false) {
  121. $file = $omit_path ? $filename : $this->_path . $filename;
  122. // If the protection isnt for a file throw an error
  123. if(!is_file($file)) {
  124. $this->_dbg('FILE [' . $file . '] IS NOT A FILE');
  125. return false;
  126. }
  127. // Get real full path to file
  128. $real_filename = realpath($file);
  129. // If real path for file can't be found throw error
  130. if(!$real_filename) {
  131. $this->_dbg('FILE [' . $file . '] IS NOT A FILE');
  132. return false;
  133. }
  134. // Don't add file if it's already in the file list
  135. if(in_array($real_filename, $this->_files)) {
  136. $this->_dbg('FILE [' . $file . '] ALREADY IN FILE LIST');
  137. return false;
  138. }
  139. // Add filename to file list
  140. $this->_dbg('FILE [' . $real_filename . '] ADDED TO FILE LIST');
  141. $this->_files[] = $real_filename;
  142. return true;
  143. }
  144. /**
  145. * UGRSR::resetFileList()
  146. *
  147. * @return true
  148. */
  149. public function resetFileList() {
  150. // Clear file list
  151. $this->_files = array();
  152. $this->_dbg('FILE LIST RESET');
  153. return true;
  154. }
  155. /**
  156. * UGRSR::addProtected()
  157. *
  158. * @param string $filename
  159. * @return bool
  160. */
  161. public function addProtected($filename) {
  162. // If the protection isnt for a file throw an error
  163. if(!is_file($filename)) {
  164. $this->_dbg('FILE [' . $filename . '] IS NOT A FILE');
  165. return false;
  166. }
  167. // Get real full path to file
  168. $real_filename = realpath($filename);
  169. // If real path for file can't be found throw error
  170. if(!$real_filename) {
  171. $this->_dbg('FILE [' . $filename . '] IS NOT A FILE');
  172. return false;
  173. }
  174. // Add filename to protected list
  175. $this->_dbg('FILE [' . $filename . '] ADDED TO PROTECTED LIST');
  176. $this->_protected[] = $real_filename;
  177. return true;
  178. }
  179. /**
  180. * UGRSR::resetProtected()
  181. *
  182. * @return true
  183. */
  184. public function resetProtected() {
  185. // Clear protected list
  186. $this->_protected = array();
  187. $this->_dbg('PROTECTED FILES RESET');
  188. //Add this class to protected list
  189. $this->_protected[] = realpath(__FILE__);
  190. // Add script that called the class to protected list
  191. $this->_protected[] = realpath($_SERVER['SCRIPT_FILENAME']);
  192. return true;
  193. }
  194. /**
  195. * UGRSR::setPath()
  196. *
  197. * @param string $path
  198. * @return bool
  199. */
  200. public function setPath($path) {
  201. // Get full real path to given path
  202. $realpath = realpath($path);
  203. // If path can't be found or isn't a directory throw an error
  204. if(!$realpath || !is_dir($realpath)) {
  205. $this->_dbg('INVALID PATH [' . $realpath . ']');
  206. return false;
  207. }
  208. // Add trailing slash to path name
  209. $realpath .= '/';
  210. // Set path to new value
  211. $this->_dbg('NEW PATH SET [' . $realpath . ']');
  212. $this->_path = $realpath;
  213. return true;
  214. }
  215. /**
  216. * UGRSR::run()
  217. *
  218. * @return bool
  219. */
  220. public function run() {
  221. // If regexes array is empty throw an error
  222. if(empty($this->_regexes)) {
  223. $this->_dbg('REGEX LIST IS EMPTY');
  224. return false;
  225. }
  226. $this->_dbg('STARTING RUN');
  227. $this->_dbg();
  228. // Set files to list of manually added files
  229. $files = $this->_files;
  230. // Check if file searching is enabled
  231. if($this->file_search) {
  232. $this->_dbg('GETTING FILE LIST');
  233. // Get a list of files under defined path
  234. $found = array_merge($this->_rglob());
  235. $this->_dbg(count($found) . ' FILES FOUND');
  236. $this->_dbg();
  237. // merge list of files with manually added file list
  238. $files = array_merge($files, $found);
  239. }
  240. // Check files found or throw error and return
  241. if(count($files) == 0) {
  242. $this->_dbg('NO FILES TO BE PROCESSED');
  243. return false;
  244. }
  245. $this->_dbg('STARTING FILE PROCESSING');
  246. // Var for total regex matches throughout files
  247. $global_change_count = 0;
  248. // Var to hold
  249. $global_write_count = 0;
  250. // Var to hold number of bytes saved
  251. $bytes_saved = 0;
  252. // Loop through files one at a time
  253. foreach($files as $filename) {
  254. // Var for total regex matches in current file
  255. $file_change_count = 0;
  256. // Load file contents
  257. $content = $original_content = file_get_contents($filename);
  258. // If content couldn't be loaded throw error
  259. if($content === FALSE) {
  260. $this->_dbg('COULD NOT OPEN [' . $filename . ']');
  261. continue;
  262. }
  263. // If file length is 0 throw error
  264. if(strlen($content) == 0) {
  265. $this->_dbg('EMPTY FILE SKIPPED [' . $filename . ']');
  266. continue;
  267. }
  268. // Loop through _regexes array applying changes to content
  269. foreach($this->_regexes as $regex) {
  270. // Var for total regex matches for individual pattern
  271. $change_count = 0;
  272. // Try replacing content
  273. $content = preg_replace($regex['pattern'], $regex['replace'], $content, -1, $change_count);
  274. // If regex operation fails throw error and abort all operations
  275. if($content === NULL) {
  276. $this->_dbg('REGEX PATTERN ERROR <strong>' . $regex['pattern'] . '</strong>');
  277. $this->_dbg('ABORTING ALL OPERATIONS');
  278. break 2;
  279. }
  280. // Add individual pattern change count to file change count
  281. $file_change_count += $change_count;
  282. $this->_dbg('REGEX <strong>' . $regex['pattern'] . '</strong> FOUND ' . ($change_count ? $change_count : 'NO') . ' MATCHES IN [' . $filename . ']');
  283. }
  284. // If not in test mode and content has changed attempt to write back to file
  285. if($content !== $original_content && !$this->test_mode) {
  286. $this->_dbg('ATTEMPTING TO WRITE TO FILE [' . $filename . ']');
  287. // If file isn't writeable throw error
  288. if(!is_writeable($filename)) {
  289. $this->_dbg('CANNOT WRITE TO [' . $filename . ']');
  290. } else {
  291. // Write file data back to file and show result
  292. $result = file_put_contents($filename, $content);
  293. if($result) {
  294. $this->_dbg('SUCCESSFULLY WROTE ' . $result . ' BYTES TO [' . $filename . ']');
  295. $global_write_count++;
  296. } else {
  297. $this->_dbg('WRITE OPERATION FAILED IN [' . $filename . ']');
  298. }
  299. }
  300. }
  301. // Add byte difference to $bytes_saved
  302. $bytes_saved += (strlen($original_content) - strlen($content));
  303. // Add total file changes count to global file changes count
  304. $global_change_count += $file_change_count;
  305. $this->_dbg('TOTAL NUMBER OF FILE CHANGES: ' . $file_change_count);
  306. $this->_dbg();
  307. }
  308. $this->_dbg();
  309. $this->_dbg('FINISHED FILE PROCESSING');
  310. $this->_dbg('TOTAL CHANGES APPLIED ACROSS ALL FILES: <strong>' . $global_change_count . '</strong>');
  311. $this->_dbg('TOTAL BYTES SAVED ACROSS ALL FILES: <strong>' . $bytes_saved . '</strong>');
  312. $this->_dbg();
  313. $this->_dbg('FINISHED RUN');
  314. $this->_dbg();
  315. // Pass back the number of changes and writes matched
  316. return array(
  317. 'changes' => $global_change_count,
  318. 'writes' => $global_write_count
  319. );
  320. }
  321. /**
  322. * UGRSR::_dbg()
  323. *
  324. * @param string $message
  325. * @return NULL;
  326. */
  327. private function _dbg($message = '') {
  328. // If in debug mode show output
  329. if($this->debug) {
  330. // Set mode type
  331. $mode = $this->test_mode ? 'TEST MODE' : 'LIVE MODE';
  332. // If there's a message echo that otherwise echo some whitespace for formatting
  333. if(!empty($message)) {
  334. echo $mode . ': *** ' . $message . " ***<br />\r\n";
  335. } else {
  336. echo str_repeat("<br />\r\n", 2);
  337. }
  338. }
  339. }
  340. /**
  341. * UGRSR::_rglob()
  342. *
  343. * @param string $path
  344. * @return array
  345. */
  346. private function _rglob($path = NULL) {
  347. // If the path isn't supplied use the one stored in _path
  348. if($path === NULL) $path = $this->_path;
  349. $this->_dbg('SEARCHING PATH [' . $path .']');
  350. // Get list of files under current directory
  351. $files = glob($path . $this->pattern, $this->flags);
  352. // Loop through all files
  353. foreach($files as $key => &$file) {
  354. // Flag to allow file to be kept in file array
  355. $remove_file = false;
  356. // Get full path of file
  357. $realfile = realpath($file);
  358. // Report if file path can't be resolved
  359. if($realfile === FALSE) {
  360. $this->_dbg('REAL PATH OF FILE [' . $file . '] COULD NOT BE RESOLVED');
  361. $remove_file = true;
  362. }
  363. // Report if file path is in the protected list
  364. if($realfile && in_array($realfile, $this->_protected)) {
  365. $this->_dbg('PROTECTED FILE [' . $realfile . '] REMOVED FROM FILES LIST');
  366. $remove_file = true;
  367. }
  368. // Report if file path is in the protected list
  369. if($realfile && in_array($realfile, $this->_files)) {
  370. $this->_dbg('FILE [' . $realfile . '] SKIPPED. ALREADY IN FILE LIST');
  371. $remove_file = true;
  372. }
  373. // Report if write access cannot be granted for file
  374. if($realfile && !is_writeable($realfile)) {
  375. $this->_dbg('FILE [' . $file . '] SKIPPED AS CANNOT WRITE TO IT');
  376. $remove_file = true;
  377. }
  378. // Remove from file list if any issues
  379. if($remove_file) {
  380. unset($files[$key]);
  381. }
  382. }
  383. // If recursion is set get files in subdirectories
  384. if($this->recursive) {
  385. // Get list of directories under current path
  386. $paths = glob($path . '*', GLOB_MARK|GLOB_ONLYDIR|GLOB_NOSORT);
  387. // Loop through subdirectories and merge files into directory list
  388. foreach($paths as $p) {
  389. $files = array_merge($files, $this->_rglob($p));
  390. }
  391. }
  392. // Pass file array back
  393. return $files;
  394. }
  395. }