|
<?php |
|
/** |
|
* VQCopy |
|
* @description 'Publish' VQModded files. |
|
* VQCopy copies a VQmodded directory to another directory at the same level. |
|
* It will then recursively copy the contents of a subfolder with the same name in the 'vqmod/vqcopy' directory. This step is required to remove the VQMod changes from index.php files and can be useful if other files also need to be copied to the 'live' directory (e.g. config files with different database connection details). |
|
* WISHLIST: Offer the option to copy all files, not just modded ones |
|
* WISHLIST: Offer to delete *all* files in the destination folder before copying |
|
* TODO: Needs to respect whatever this is: 'vqmod/vqprotect.txt' |
|
* TODO: Consider optionally uninstalling VQMod from index.php rather than requiring files to be copied |
|
* Installation: |
|
* 1. Copy this file to the VQMod directory. |
|
* 2. In the VQMod directory, create a directory called 'vqcopy' |
|
* 3. In the vqcopy directory, create a directory with the same name as the |
|
* Usage: |
|
* php vqcopy.php target MIN/MAX |
|
* Where: |
|
* 'target' is the name of a directory at the same level as the directory that contains the VQMod directory. |
|
* There should also be a directory with the same name as 'target' in the vqmod/vqcopy directory. |
|
* This directory *must* contain index.php and admin/index.php, it can optionally contain any other files. |
|
* 'MIN/MAX' is one of MIN or MAX |
|
* MIN: Copy only files that were modified (and the files in 'vqcopy/target'). |
|
* MAX: Copy the entire directory (and the files in 'vqcopy/target'). |
|
*/ |
|
error_reporting(E_ALL); |
|
// http://stackoverflow.com/a/2050909/957246 |
|
function recurseCopy($src,$dst) { |
|
$dir = opendir($src); |
|
if(!is_dir($dst)) if(!@mkdir($dst)) die('Error creating directory: ' . $dst); |
|
while(false !== ($file = readdir($dir))) { |
|
if(($file != '.') && ($file != '..')) { |
|
if(is_dir($src . DIRECTORY_SEPARATOR . $file)) { |
|
recurseCopy($src . DIRECTORY_SEPARATOR . $file,$dst . DIRECTORY_SEPARATOR . $file); |
|
} |
|
else { |
|
if(!@copy($src . DIRECTORY_SEPARATOR . $file,$dst . DIRECTORY_SEPARATOR . $file)) die('Error copying file: ' . $file); |
|
// copy($src . DIRECTORY_SEPARATOR . $file,$dst . DIRECTORY_SEPARATOR . $file); |
|
} |
|
} |
|
} |
|
closedir($dir); |
|
} |
|
|
|
function MD5Dir($directory) { |
|
if (!is_dir($directory)) return false; |
|
$files = array(); |
|
$dir = dir($directory); |
|
while (false !== ($file = $dir->read())) { |
|
if ($file != '.' and $file != '..') { |
|
if (is_dir($directory . '/' . $file)) $files[] = MD5Dir($directory . '/' . $file); |
|
else $files[] = md5_file($directory . '/' . $file); |
|
} |
|
} |
|
$dir->close(); |
|
return md5(implode('', $files)); |
|
} |
|
|
|
function fixPath($path) { |
|
$path = str_replace('\\',DIRECTORY_SEPARATOR,$path); |
|
$path = str_replace('/',DIRECTORY_SEPARATOR,$path); |
|
return $path; |
|
} |
|
|
|
$ignore_mods = array('vqmod_opencart.xml'); // Mods in this list will not be applied |
|
$ignore_dirs = array('vqmod','cache'); // Dirs named in this list will not be copied |
|
$copy_mode = 'MIN'; // $copy_mode is one of MIN (just the modified files), MAX (the entire, modified Opencart folder, excluding the VQMod subfolder) |
|
$path = dirname(dirname(__FILE__)); |
|
$vqmod_path = dirname(__FILE__); |
|
$pathlen = strlen($path); |
|
$parent = basename($path); |
|
$affected = array(); |
|
$wildcards = array(); |
|
$output_dir = $argv[1]; |
|
if(isset($argv[2]) AND in_array($argv[2],array('MIN','MAX'))) $copy_mode = $argv[2]; |
|
$input_path = $path; |
|
$output_path = dirname($path) . DIRECTORY_SEPARATOR . $output_dir; |
|
define('VC_LD',"====================================================================="); |
|
$log = array(VC_LD); |
|
$log[] = date("D M j Y, G:i:s"); |
|
$log[] = "Ignoring directories: " . implode(', ',$ignore_dirs); |
|
$log[] = "Path: " . $path; |
|
$log[] = "VQMod Path: " . $vqmod_path; |
|
$log[] = "Parent: " . $parent; |
|
$log[] = VC_LD; |
|
$log[] = "Copying from $input_path to $output_path"; |
|
$log[] = VC_LD; |
|
// Suppress potential REQUEST_URI error from VQMod |
|
if(!isset($_SERVER['REQUEST_URI'])) $_SERVER['REQUEST_URI'] = 'vqcopy'; |
|
// Temporarily rename ignored files so that VQMod doesn't parse them |
|
foreach($ignore_mods as $mod) { |
|
$mpath = fixPath("$vqmod_path//xml//$mod"); |
|
if(file_exists($mpath)) rename($mpath,$mpath . '__'); |
|
$log[] = "Renaming $mpath to $mpath" ."__."; |
|
} |
|
require_once(fixPath("$vqmod_path//vqmod.php")); |
|
include_once(fixPath("$vqmod_path//pathReplaces.php")); // Populates $replaces |
|
VQMod::bootup(); |
|
// This assumes it's a subdir, it might not be |
|
$vqmod_log_folder = $path . DIRECTORY_SEPARATOR . VQMod::$logFolder; |
|
if (!is_dir($vqmod_log_folder)) mkdir($vqmod_log_folder, 0777, true); |
|
|
|
// TODO: We should look at vqmod's log before we start - then again afterwards to check if anything's been added. if it has then say so. |
|
// Get log details |
|
// TODO: This doesn't work. The logsum is the same at the end. |
|
$log_sum = MD5Dir($vqmod_log_folder); |
|
$log[] = "Log sum: " . $log_sum; |
|
// Clear cache |
|
$log[] = 'Deleting cache.'; |
|
@unlink($path . DIRECTORY_SEPARATOR . VQMod::$modCache); |
|
@unlink($path . DIRECTORY_SEPARATOR . VQMod::$checkedCache); |
|
foreach(glob(fixPath("$path\\vqmod\\vqcache\\*")) as $d) if(is_file($d)) unlink($d); |
|
// Go through each mod and build a list of affected names |
|
// TODO: would there be an advantage if we got this list from VQMod itself? Can we do that? |
|
foreach(glob(fixPath("$path\\vqmod\\xml\\*.xml")) as $xml_file) { |
|
$log[] = "Processing mod: $xml_file."; |
|
$xml = simplexml_load_file($xml_file); |
|
foreach($xml->file as $files) { |
|
$x = array(); |
|
$p = null; |
|
foreach($files->attributes() as $k => $v) { |
|
if($k == 'name') { // 'name' is a comma-delimited list of files, which can contain wildcards (*). |
|
$x = (array) $v; // Cast object to array (which will only contain 1 element) |
|
$unmodified_x[] = $x[0]; |
|
if(strpos($x[0],',')) { // Explode 'name' if it's a comma-delimited list |
|
$x = explode(',',$x[0]); |
|
$x = array_map('trim', $x); |
|
} |
|
} |
|
if($k == 'path') { // 'path' is a prefix to apply to 'name', which can probably contain wildcards (*). |
|
$p = (array) $v; // Convert object to array (which will only contain 1 element) |
|
$p = trim($p[0]); |
|
} |
|
} |
|
if($p) foreach($x as $xk => $xv) $x[$xk] = $p.trim($xv); // Prefix names with path |
|
foreach($x as $xk => $xv) if(!in_array($xv,$affected)) $affected[] = $xv; // Add names to list |
|
} |
|
} |
|
|
|
// For each name, we should have an expanded list of files |
|
$unmodified_affected = $affected; |
|
sort($unmodified_affected); |
|
// Expand wildcards and de-dupe the list of affected files |
|
foreach($affected as $xk => $x) { // Expand wildcards |
|
$x = str_replace('/',DIRECTORY_SEPARATOR,$x); // Fix slashes for Windows |
|
if(!empty($replaces) AND is_array($replaces)) foreach($replaces as $r) if(count($r) == 2) $x = preg_replace($r[0], $r[1], $x); // Apply replaces |
|
$affected[$xk] = $x; |
|
if(strpos($x,'*')) { |
|
unset($affected[$xk]); |
|
$log[] = "Expanding path: " . fixPath($path . DIRECTORY_SEPARATOR . $x); |
|
$y = glob(fixPath($path . DIRECTORY_SEPARATOR . $x)); |
|
foreach($y as $z) { |
|
$log[] = "Adding path: " . substr($z,$pathlen+1); |
|
$wildcards[] = substr($z,$pathlen+1); |
|
} |
|
} |
|
} |
|
foreach($wildcards as $w) if(!in_array($w,$affected)) $affected[] = $w; |
|
sort($affected); |
|
$log[] = "Files to be processed:"; |
|
$log[] = "\r\n\t".implode("\r\n\t",$affected); |
|
foreach($affected as $target) { |
|
if(strpos($target,'*')) $log[] = "Handling: " . $target; |
|
$target = $path . DIRECTORY_SEPARATOR . $target; |
|
$cache_file = VQMod::modCheck($target); // This needs to be getting the de-replaced path |
|
$push_target = preg_replace("~$parent~","$output_dir",$target,1); |
|
if(!file_exists(dirname($push_target))) mkdir(dirname($push_target), 0777, true); |
|
copy($cache_file,$push_target); |
|
} |
|
$admin_index = 'admin' . DIRECTORY_SEPARATOR . 'index.php'; |
|
if(!empty($replaces)) foreach($replaces as $r) if(count($r) == 2) $admin_index = preg_replace($r[0], $r[1], $admin_index); // Apply replaces to admin path |
|
$tpath = str_replace($parent,$output_dir,$path); |
|
$admin_index = $tpath . DIRECTORY_SEPARATOR . $admin_index; |
|
$root_index = $tpath . DIRECTORY_SEPARATOR . 'index.php'; |
|
// Restore ignored files |
|
foreach($ignore_mods as $mod) { |
|
$mpath = fixPath("$vqmod_path//xml//$mod"); |
|
if(file_exists($mpath . '__')) rename($mpath . '__',$mpath); |
|
$log[] = "Renaming $mpath" ."__ back to $mpath."; |
|
} |
|
|
|
// Check log details - TODO/BUG: this comparison doesn't work, it's looking at the file as it was when this script started. |
|
$new_log_sum = MD5Dir($vqmod_log_folder); |
|
$log[] = "New log sum: " . $new_log_sum; |
|
if($new_log_sum != $log_sum) $log = array_merge($log,array(VC_LD,"!!! WARNING: Not all mods were fully processed! Check VQMod logs. !!!",VC_LD)); |
|
|
|
// Copy other files |
|
if($copy_mode != 'MIN') { |
|
$file_list = array(); |
|
$copied_file_list = array(); |
|
$source_files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(realpath($path))); |
|
// Build list of files, removing anything in ignored dirs |
|
foreach($source_files as $file => $object) { |
|
if((substr($file,-1) !== '.')) { |
|
$include_flag = true; |
|
foreach($ignore_dirs as $i) if(strpos($file,DIRECTORY_SEPARATOR . $i . DIRECTORY_SEPARATOR) == true) $include_flag = false; |
|
if($include_flag) $file_list[] = $file; |
|
} |
|
} |
|
$copied_files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(realpath(dirname($path) . DIRECTORY_SEPARATOR . $output_dir))); |
|
foreach($copied_files as $file => $object) { |
|
if((substr($file,-1) !== '.')) { |
|
$include_flag = true; |
|
foreach($ignore_dirs as $i) if(strpos($file,DIRECTORY_SEPARATOR . $i . DIRECTORY_SEPARATOR) == true) $include_flag = false; |
|
if($include_flag) $copied_file_list[] = $file; |
|
} |
|
} |
|
// Strip path prefixes from copies of the lists so that they can be compared |
|
$compare_file_list = array(); |
|
$strip = strlen($input_path); |
|
foreach($file_list as $k => $v) $compare_file_list[$k] = substr($v,$strip); |
|
$compare_copied_file_list = array(); |
|
$strip = strlen($output_path); |
|
foreach($copied_file_list as $k => $v) $compare_copied_file_list[$k] = substr($v,$strip); |
|
// Remove anything from the source list that's already in the target list |
|
$files_listed_to_copy = array_diff($compare_file_list,$compare_copied_file_list); |
|
foreach($files_listed_to_copy as $filename) { |
|
$copy_target = $output_path.$filename; |
|
if(!file_exists(dirname($copy_target))) mkdir(dirname($copy_target), 0777, true); |
|
copy($input_path.$filename,$output_path.$filename); |
|
} |
|
} |
|
|
|
// Copy extras |
|
recurseCopy($vqmod_path . DIRECTORY_SEPARATOR . 'vqcopy' . DIRECTORY_SEPARATOR . $output_dir ,$output_path); |
|
print_r(implode("\r\n",$log)); |
|
// EOF |