diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6373079
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+.DS_STORE
\ No newline at end of file
diff --git a/README.md b/README.md
index 3fb0cc3..a1973f7 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,12 @@
-# opencart
+# vQmod for OpenCart
This is a repository for the opencart vqmod core script files.
First download and install vQmod from the main repository, then install the script files from this repository for use with opencart
-1. Be sure you've installed the vQmod package first! This package only contains the opencart script files
-2. Upload the xml and install folder to your vqmod folder on your server.
-3. Overwrite any files that already exist
+Steps to install:
+1. Download the latest vQmod release from the releases page: https://github.com/vqmod/vqmod/releases
+2. Then checkout this repository.
+3. Upload the xml and install folder to your vqmod folder on your server.
+4. Overwrite any files that already exist
+5. Run the installer with https://yourstore.com/vqmod/install
-When done, you should see the following files on your server
- vqmod/xml/vqmod_opencart.xml
- vqmod/install/index.php
-
-4. Run the installer with https:/yourstore.com/vqmod/install
\ No newline at end of file
+Where yourstore.com is your domain name and where vqmod is the folder you installed vqmod to (ex: /vqmod/, /custom_vqmod/, /changes/ .... )
\ No newline at end of file
diff --git a/install/.htaccess b/install/.htaccess
new file mode 100644
index 0000000..2720bc4
--- /dev/null
+++ b/install/.htaccess
@@ -0,0 +1,2 @@
+Satisfy Any
+Allow From All
diff --git a/install/index.php b/install/index.php
index 1e1080a..4fbd8fd 100644
--- a/install/index.php
+++ b/install/index.php
@@ -34,29 +34,41 @@
if (!empty($_POST['admin_name'])) {
//$admin = 'admin';
- $admin = htmlspecialchars($_POST['admin_name']);
+ $admin = htmlspecialchars(trim($_POST['admin_name']));
// Counters
$changes = 0;
$writes = 0;
$files = [];
// Load class required for installation
- require('ugrsr.class.php');
+ $main_class = 'ugrsr.class.php';
+ if (!file_exists($main_class)) {
+ die('ERROR - UGRSR CLASS NOT FOUND - Please ensure you have uploaded the vQmod install files correctly');
+ }
+
+ require($main_class);
+
+ $vqmod_path = dirname(__FILE__, 2) . '/';
+
+ // Get the vqmod folder via the path
+ $vqmod_folder = basename($vqmod_path);
+
+ // OpenCart path
+ $opencart_path = dirname(__FILE__, 3) . '/';
- // Get directory two above installation directory
- $opencart_path = realpath(dirname(__FILE__) . '/../../') . '/';
-
// Verify path is correct
- if(empty($opencart_path)) die('ERROR - COULD NOT DETERMINE OPENCART PATH CORRECTLY - ' . dirname(__FILE__));
+ if(empty($opencart_path)) {
+ die('ERROR - COULD NOT DETERMINE OPENCART PATH CORRECTLY - ' . __DIR__);
+ }
$write_errors = array();
- if(!is_writeable($opencart_path . 'index.php')) {
+ if(!is_writable($opencart_path . 'index.php')) {
$write_errors[] = 'index.php not writeable';
}
- if(!is_writeable($opencart_path . $admin . '/index.php')) {
+ if(!is_writable($opencart_path . $admin . '/index.php')) {
$write_errors[] = 'Administrator index.php not writeable';
}
- if(!is_writeable($opencart_path . 'vqmod/pathReplaces.php')) {
+ if(!is_writable($opencart_path . $vqmod_folder . '/pathReplaces.php')) {
$write_errors[] = 'vQmod pathReplaces.php not writeable';
}
@@ -73,7 +85,7 @@
// Set file searching to off
$u->file_search = false;
- // Attempt upgrade if necessary. Otherwise just continue with normal install
+ // Attempt upgrade if necessary. Otherwise, just continue with normal install
$u->addFile('index.php');
$u->addFile($admin . '/index.php');
@@ -82,21 +94,18 @@
$result = $u->run();
- if($result['writes'] > 0) {
- if(file_exists('../mods.cache')) {
- unlink('../mods.cache');
- }
- //die('UPGRADE COMPLETE');
+ if(($result['writes'] > 0) && file_exists('../mods.cache')) {
+ unlink('../mods.cache');
}
$u->clearPatterns();
$u->resetFileList();
- // Add catalog index files to files to include
+ // Add catalog index files to include
$u->addFile('index.php');
// Pattern to add vqmod include
- $u->addPattern('~// Startup~', "// vQmod\nrequire_once('./vqmod/vqmod.php');\nVQMod::bootup();\n\n// VQMODDED Startup");
+ $u->addPattern('~// Startup~', "// vQmod\nrequire_once('./" . $vqmod_folder . "/vqmod.php');\nVQMod::bootup();\n\n// VQMODDED Startup");
$result = $u->run();
$writes += $result['writes'];
@@ -110,7 +119,7 @@
$u->addFile($admin . '/index.php');
// Pattern to add vqmod include
- $u->addPattern('~// Startup~', "//vQmod\nrequire_once('../vqmod/vqmod.php');\nVQMod::bootup();\n\n// VQMODDED Startup");
+ $u->addPattern('~// Startup~', "//vQmod\nrequire_once('../" . $vqmod_folder . "/vqmod.php');\nVQMod::bootup();\n\n// VQMODDED Startup");
$result = $u->run();
$writes += $result['writes'];
@@ -127,15 +136,15 @@
$writes += $result['writes'];
$changes += $result['changes'];
$files = array_merge($files, $result['files']);
-
+
$u->clearPatterns();
$u->resetFileList();
-
+
// 2022 - Qphoria
// pathReplaces install
-
+
// Add vqmod/pathReplaces.php file
- $u->addFile('vqmod/pathReplaces.php');
+ $u->addFile($vqmod_folder . '/pathReplaces.php');
// Pattern to add vqmod include
$u->addPattern('~// START REPLACES //~', "// VQMODDED START REPLACES //\nif (defined('DIR_CATALOG')) { \$replaces[] = array('~^admin\b~', basename(DIR_APPLICATION)); }");
@@ -157,10 +166,10 @@
// output result to user
die('VQMOD HAS BEEN INSTALLED ON YOUR SYSTEM!');
-} else {
- echo 'vQmod Installer for OpenCart
';
- echo '
';
-}
\ No newline at end of file
+}
+
+echo 'vQmod Installer for OpenCart
';
+echo '';
diff --git a/vqmod.php b/vqmod.php
new file mode 100644
index 0000000..c5c16ae
--- /dev/null
+++ b/vqmod.php
@@ -0,0 +1,1030 @@
+= self::$_lastModifiedTime && filemtime($cacheFile) >= $file_last_modified) {
+ return $cacheFile;
+ }
+
+ if(isset(self::$_filesModded[$sourcePath])) {
+ return self::$_filesModded[$sourcePath]['cached'] ? $cacheFile : $sourceFile;
+ }
+
+ $changed = false;
+ $fileHash = sha1_file($sourcePath);
+ $fileData = file_get_contents($sourcePath);
+
+ foreach(self::$_mods as $modObject) {
+ foreach($modObject->mods as $path => $mods) {
+ if(self::_checkMatch($path, $modificationsPath)) {
+ $modObject->applyMod($mods, $fileData);
+ }
+ }
+ }
+
+ if (sha1($fileData) != $fileHash) {
+ $writePath = $cacheFile;
+ if(!file_exists($writePath) || is_writable($writePath)) {
+ file_put_contents($writePath, $fileData, LOCK_EX);
+ $changed = true;
+ }
+ } else {
+ file_put_contents(self::path(self::$checkedCache, true), $stripped_filename . PHP_EOL, FILE_APPEND | LOCK_EX);
+
+ // Prevent checked.cache file from duplicating lines when checked folder is above vqmod directory - Thanks adrianolmedo
+ $lines = file(self::path(self::$checkedCache, true));
+ $lines = array_unique($lines);
+ file_put_contents(self::path(self::$checkedCache, true), implode($lines));
+
+ self::$_doNotMod[] = $sourcePath;
+ }
+
+ self::$_filesModded[$sourcePath] = array('cached' => $changed);
+ return $changed ? $writePath : $sourcePath;
+ }
+
+ /**
+ * VQMod::path()
+ *
+ * @param string $path File path
+ * @param bool $skip_real If true path is full not relative
+ * @return bool, string
+ * @description Returns the full true path of a file if it exists, otherwise false
+ */
+ public static function path($path, $skip_real = false) {
+ $tmp = self::$_cwd . $path;
+ $realpath = $skip_real ? $tmp : self::_realpath($tmp);
+ if(!$realpath) {
+ return false;
+ }
+ return $realpath;
+ }
+
+ /**
+ * VQMod::getCwd()
+ *
+ * @return string
+ * @description Returns current working directory
+ */
+ public static function getCwd() {
+ return self::$_cwd;
+ }
+
+ /**
+ * VQMod::dirCheck()
+ *
+ * @param string $path
+ * @return null
+ * @description Creates $path folder if it doesn't exist
+ */
+ public static function dirCheck($path) {
+ if(!is_dir($path)) {
+ if(!mkdir($path)) {
+ die('VQMod::dirCheck - CANNOT CREATE "' . $path . '" DIRECTORY');
+ }
+ }
+ }
+
+ /**
+ * VQMod::handleXMLError()
+ *
+ * @description Error handler for bad XML files
+ */
+ public static function handleXMLError($errno, $errstr, $errfile, $errline) {
+ if ($errno == E_WARNING && (substr_count($errstr, 'DOMDocument::load()') > 0)) {
+ throw new DOMException(str_replace('DOMDocument::load()', '', $errstr));
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param $pattern
+ * @param $flags
+ * @return array|false
+ */
+ private static function glob_recursive($pattern, $flags = 0)
+ {
+ $files = glob($pattern, $flags);
+
+ foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir)
+ {
+ $files = array_merge($files, self::glob_recursive($dir.'/'.basename($pattern), $flags));
+ }
+
+ return $files;
+ }
+
+
+ /**
+ * VQMod::_getMods()
+ *
+ * @return null
+ * @description Gets list of XML files in vqmod xml folder for processing
+ */
+ private static function _getMods() {
+
+ // Check and set folder
+ $vqmod_path = dirname(__FILE__, 1) . '/';
+
+ // Get the vqmod folder via the path
+ $vqmod_folder = basename($vqmod_path);
+
+ self::$_modFileList = self::glob_recursive(self::path($vqmod_folder . '/xml/', true) . '*.xml');
+
+ foreach(self::$_modFileList as $file) {
+ if(file_exists($file)) {
+ $lastMod = filemtime($file);
+ if($lastMod > self::$_lastModifiedTime){
+ self::$_lastModifiedTime = $lastMod;
+ }
+ }
+ }
+
+ $xml_folder_time = filemtime(self::path($vqmod_folder . '/xml'));
+ if($xml_folder_time > self::$_lastModifiedTime){
+ self::$_lastModifiedTime = $xml_folder_time;
+ }
+
+ $modCache = self::path(self::$modCache);
+ if(self::$_devMode || !file_exists($modCache)) {
+ self::$_lastModifiedTime = time();
+ } elseif(file_exists($modCache) && filemtime($modCache) >= self::$_lastModifiedTime) {
+ $mods = file_get_contents($modCache);
+ if(!empty($mods))
+ self::$_mods = unserialize($mods);
+ if(self::$_mods !== false) {
+ return;
+ }
+ }
+
+ // Clear checked cache if rebuilding
+ file_put_contents(self::path(self::$checkedCache, true), '', LOCK_EX);
+
+ if(self::$_modFileList) {
+ self::_parseMods();
+ } else {
+ self::$log->write('VQMod::_getMods - NO XML FILES READABLE IN XML FOLDER');
+ }
+ }
+
+ /**
+ * VQMod::_parseMods()
+ *
+ * @return null
+ * @description Loops through xml files and attempts to load them as VQModObject's
+ */
+ private static function _parseMods() {
+
+ set_error_handler(array('VQMod', 'handleXMLError'));
+
+ $dom = new DOMDocument('1.0', 'UTF-8');
+ foreach(self::$_modFileList as $modFileKey => $modFile) {
+ if(file_exists($modFile)) {
+ try {
+ $dom->load($modFile);
+ $mod = $dom->getElementsByTagName('modification')->item(0);
+ $vqmver = $mod->getElementsByTagName('vqmver')->item(0);
+
+ if($vqmver) {
+ $version_check = $vqmver->getAttribute('required');
+ if(strtolower($version_check) == 'true') {
+ if(version_compare(self::$_vqversion, $vqmver->nodeValue, '<')) {
+ self::$log->write('VQMod::_parseMods - FILE "' . $modFile . '" REQUIRES VQMOD "' . $vqmver->nodeValue . '" OR ABOVE AND HAS BEEN SKIPPED');
+ continue;
+ }
+ }
+ }
+
+ self::$_mods[] = new VQModObject($mod, $modFile);
+ } catch (Exception $e) {
+ self::$log->write('VQMod::_parseMods - INVALID XML FILE: ' . $e->getMessage());
+ }
+ } else {
+ self::$log->write('VQMod::_parseMods - FILE NOT FOUND: ' . $modFile);
+ }
+ }
+
+ restore_error_handler();
+
+ $modCache = self::path(self::$modCache, true);
+ $result = file_put_contents($modCache, serialize(self::$_mods), LOCK_EX);
+ if(!$result) {
+ die('VQMod::_parseMods - "'.self::$modCache.'" FILE NOT WRITEABLE');
+ }
+ }
+
+ /**
+ * VQMod::_loadProtected()
+ *
+ * @return null
+ * @description Loads protected list and adds them to _doNotMod array
+ */
+ private static function _loadProtected() {
+ $file = self::path(self::$protectedFilelist);
+ if($file && is_file($file)) {
+ $paths = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if(!empty($paths)) {
+ foreach($paths as $path) {
+ $fullPath = self::path($path);
+ if($fullPath && !in_array($fullPath, self::$_doNotMod)) {
+ self::$_doNotMod[] = $fullPath;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * VQMod::_loadChecked()
+ *
+ * @return null
+ * @description Loads already checked files and adds them to _doNotMod array
+ */
+ private static function _loadChecked() {
+ $file = self::path(self::$checkedCache);
+ if($file && is_file($file)) {
+ $paths = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if(!empty($paths)) {
+ foreach($paths as $path) {
+ $fullPath = self::path($path, true);
+ if($fullPath) {
+ self::$_doNotMod[] = $fullPath;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * VQMod::_cacheName()
+ *
+ * @param string $file Filename to be converted to cache filename
+ * @return string
+ * @description Returns cache file name for a path
+ */
+ private static function _cacheName($file) {
+ return self::$_cachePathFull . 'vq2-' . preg_replace('~[/\\\\]+~', '_', $file);
+ }
+
+ /**
+ * VQMod::_setCwd()
+ *
+ * @param string $path Path to be used as current working directory
+ * @return null
+ * @description Sets the current working directory variable
+ */
+ private static function _setCwd($path) {
+ self::$_cwd = self::_realpath($path);
+ }
+
+ /**
+ * VQMod::_realpath()
+ *
+ * @param string $file
+ * @return string
+ * @description Returns real path of any path, adding directory slashes if necessary
+ */
+ private static function _realpath($file) {
+ $path = realpath($file);
+ if(!$path) {
+ return false;
+ }
+
+ if(is_dir($path)) {
+ $path = rtrim($path, self::$directorySeparator) . self::$directorySeparator;
+ }
+
+ return $path;
+ }
+
+ /**
+ * VQMod::_checkMatch()
+ *
+ * @param string $modFilePath Modification path from a node
+ * @param string $checkFilePath File path
+ * @return bool
+ * @description Checks a modification path against a file path
+ */
+ private static function _checkMatch($modFilePath, $checkFilePath) {
+ $modFilePath = str_replace('\\', '/', $modFilePath);
+ $checkFilePath = str_replace('\\', '/', $checkFilePath);
+
+ if(self::$windows) {
+ $modFilePath = strtolower($modFilePath);
+ $checkFilePath = strtolower($checkFilePath);
+ }
+
+ if($modFilePath == $checkFilePath) {
+ $return = true;
+ } elseif(strpos($modFilePath, '*') !== false) {
+ $return = true;
+ $modParts = explode('/', $modFilePath);
+ $checkParts = explode('/', $checkFilePath);
+
+ if(count($modParts) !== count($checkParts)) {
+ $return = false;
+ } else {
+
+ $toCheck = array_diff_assoc($modParts, $checkParts);
+
+ foreach($toCheck as $k => $part) {
+ if($part === '*') {
+ continue;
+ } elseif(strpos($part, '*') !== false) {
+ $part = preg_replace_callback('~([^*]+)~', 'VQMod::_quotePath', $part);
+ $part = str_replace('*', '[^/]*', $part);
+ $part = (bool) preg_match('~^' . $part . '$~', $checkParts[$k]);
+
+ if($part) {
+ continue;
+ }
+ } elseif($part === $checkParts[$k]) {
+ continue;
+ }
+
+ $return = false;
+ break;
+ }
+
+ }
+ } else {
+ $return = false;
+ }
+
+ return $return;
+ }
+
+ /**
+ * VQMod::_quotePath()
+ *
+ * @param string $matches callback matches
+ * @return string
+ * @description apply's preg_quote to string from callback
+ */
+ private static function _quotePath($matches) {
+ return preg_quote($matches[1], '~');
+ }
+}
+
+/**
+ * VQModLog
+ * @description Object to log information to a file
+ */
+class VQModLog {
+ private $_sep;
+ private $_defhash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+ private $_logs = array();
+
+ /**
+ * VQModLog::__construct()
+ *
+ * @return null
+ * @description Object instantiation method
+ */
+ public function __construct() {
+ $this->_sep = str_repeat('-', 70);
+ }
+
+ /**
+ * VQModLog::__destruct()
+ *
+ * @return null
+ * @description Logs any messages to the log file just before object is destroyed
+ */
+ public function __destruct() {
+ if(empty($this->_logs) || VQMod::$logging == false) {
+ return;
+ }
+
+ $logPath = VQMod::path(VQMod::$logFolder . date('w_D') . '.log', true);
+
+ $txt = array();
+
+ $txt[] = str_repeat('-', 10) . ' Date: ' . date('Y-m-d H:i:s') . ' ~ IP : ' . (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'N/A') . ' ' . str_repeat('-', 10);
+ $txt[] = 'REQUEST URI : ' . $_SERVER['REQUEST_URI'];
+
+ foreach($this->_logs as $count => $log) {
+ if($log['obj']) {
+ $vars = get_object_vars($log['obj']);
+ $txt[] = 'MOD DETAILS:';
+ foreach($vars as $k => $v) {
+ if(is_string($v)) {
+ $txt[] = ' ' . str_pad($k, 10, ' ', STR_PAD_RIGHT) . ': ' . $v;
+ }
+ }
+
+ }
+
+ foreach($log['log'] as $msg) {
+ $txt[] = $msg;
+ }
+
+ if ($count > count($this->_logs)-1) {
+ $txt[] = '';
+ }
+ }
+
+ $txt[] = $this->_sep;
+ $txt[] = str_repeat(PHP_EOL, 2);
+ $append = true;
+
+ if(!file_exists($logPath)) {
+ $append = false;
+ } else {
+ $content = file_get_contents($logPath);
+ if(!empty($content) && strpos($content, ' Date: ' . date('Y-m-d ')) === false) {
+ $append = false;
+ }
+ }
+
+ $result = file_put_contents($logPath, implode(PHP_EOL, $txt), ($append ? FILE_APPEND | LOCK_EX : LOCK_EX));
+ if(!$result) {
+ die('VQModLog::__destruct - LOG FILE "' . $logPath . '" COULD NOT BE WRITTEN');
+ }
+ }
+
+ /**
+ * VQModLog::write()
+ *
+ * @param string $data Text to be added to log file
+ * @param VQModObject $obj Modification the error belongs to
+ * @return null
+ * @description Adds error to log object ready to be output
+ */
+ public function write($data, VQModObject $obj = NULL) {
+ if($obj) {
+ $hash = sha1($obj->id);
+ } else {
+ $hash = $this->_defhash;
+ }
+
+ if(empty($this->_logs[$hash])) {
+ $this->_logs[$hash] = array(
+ 'obj' => $obj,
+ 'log' => array()
+ );
+ }
+
+ if(VQMod::$fileModding) {
+ $this->_logs[$hash]['log'][] = PHP_EOL . 'File Name : ' . VQMod::$fileModding;
+ }
+
+ $this->_logs[$hash]['log'][] = $data;
+
+ }
+}
+
+/**
+ * VQModObject
+ * @description Object for the that orchestrates each applied modification
+ */
+class VQModObject {
+ public $modFile = '';
+ public $id = '';
+ public $version = '';
+ public $vqmver = '';
+ public $author = '';
+ public $mods = array();
+
+ private $_skip = false;
+
+ /**
+ * VQModObject::__construct()
+ *
+ * @param DOMNode $node node
+ * @param string $modFile File modification is from
+ * @return null
+ * @description Loads modification meta information
+ */
+ public function __construct(DOMNode $node, $modFile) {
+ if($node->hasChildNodes()) {
+ foreach($node->childNodes as $child) {
+ $name = (string) $child->nodeName;
+ if(isset($this->$name)) {
+ $this->$name = (string) $child->nodeValue;
+ }
+ }
+ }
+
+ $this->modFile = $modFile;
+ $this->_parseMods($node);
+ }
+
+ /**
+ * VQModObject::skip()
+ *
+ * @return bool
+ * @description Returns the skip status of a modification
+ */
+ public function skip() {
+ return $this->_skip;
+ }
+
+ /**
+ * VQModObject::applyMod()
+ *
+ * @param array $mods Array of search add nodes
+ * @param string $data File contents to be altered
+ * @return null
+ * @description Applies all modifications to the text data
+ */
+ public function applyMod($mods, &$data) {
+ if($this->_skip) return;
+ $tmp = $data;
+
+ foreach($mods as $mod) {
+ VQMod::$fileModding = $mod['fileToMod'] . '(' . $mod['opIndex'] . ')';
+ if(!empty($mod['ignoreif'])) {
+ if($mod['ignoreif']->regex == 'true') {
+ if (preg_match($mod['ignoreif']->getContent(), $tmp)) {
+ continue;
+ }
+ } else {
+ if (strpos($tmp, $mod['ignoreif']->getContent()) !== false) {
+ continue;
+ }
+ }
+ }
+
+ $indexCount = 0;
+
+ $tmp = $this->_explodeData($tmp);
+ $lineMax = count($tmp) - 1;
+
+ // tag attributes - Override attributes if set
+ foreach(array_keys((array)$mod['search']) as $key) {
+ if ($key == "\x0VQNode\x0_content") { continue; }
+ if ($key == "trim") { continue; }
+ if (isset($mod['add']->$key) && $mod['add']->$key) {
+ $mod['search']->$key = $mod['add']->$key;
+ }
+ }
+
+ switch($mod['search']->position) {
+ case 'top':
+ $tmp[$mod['search']->offset] = $mod['add']->getContent() . $tmp[$mod['search']->offset];
+ break;
+
+ case 'bottom':
+ $offset = $lineMax - $mod['search']->offset;
+ if($offset < 0){
+ $tmp[-1] = $mod['add']->getContent();
+ } else {
+ $tmp[$offset] .= $mod['add']->getContent();
+ }
+ break;
+
+ default:
+
+ $changed = false;
+ foreach($tmp as $lineNum => $line) {
+ if(strlen($mod['search']->getContent()) == 0) {
+ if($mod['error'] == 'log' || $mod['error'] == 'abort') {
+ VQMod::$log->write('VQModObject::applyMod - EMPTY SEARCH CONTENT ERROR', $this);
+ }
+ break;
+ }
+
+ if($mod['search']->regex == 'true') {
+ $pos = @preg_match($mod['search']->getContent(), $line);
+ if($pos === false) {
+ if($mod['error'] == 'log' || $mod['error'] == 'abort' ) {
+ VQMod::$log->write('VQModObject::applyMod - INVALID REGEX ERROR - ' . $mod['search']->getContent(), $this);
+ }
+ break 2;
+ } elseif($pos == 0) {
+ $pos = false;
+ }
+ } else {
+ $pos = strpos($line, $mod['search']->getContent());
+ }
+
+ if($pos !== false) {
+ $indexCount++;
+ $changed = true;
+
+ if(!$mod['search']->indexes() || ($mod['search']->indexes() && in_array($indexCount, $mod['search']->indexes()))) {
+
+ switch($mod['search']->position) {
+ case 'before':
+ $offset = ($lineNum - $mod['search']->offset < 0) ? -1 : $lineNum - $mod['search']->offset;
+ $tmp[$offset] = empty($tmp[$offset]) ? $mod['add']->getContent() : $mod['add']->getContent() . "\n" . $tmp[$offset];
+ break;
+
+ case 'after':
+ $offset = ($lineNum + $mod['search']->offset > $lineMax) ? $lineMax : $lineNum + $mod['search']->offset;
+ $tmp[$offset] = $tmp[$offset] . "\n" . $mod['add']->getContent();
+ break;
+
+ case 'ibefore':
+ $tmp[$lineNum] = str_replace($mod['search']->getContent(), $mod['add']->getContent() . $mod['search']->getContent(), $line);
+ break;
+
+ case 'iafter':
+ $tmp[$lineNum] = str_replace($mod['search']->getContent(), $mod['search']->getContent() . $mod['add']->getContent(), $line);
+ break;
+
+ default:
+ if(!empty($mod['search']->offset)) {
+ if($mod['search']->offset > 0) {
+ for($i = 1; $i <= $mod['search']->offset; $i++) {
+ if(isset($tmp[$lineNum + $i])) {
+ $tmp[$lineNum + $i] = '';
+ }
+ }
+ } elseif($mod['search']->offset < 0) {
+ for($i = -1; $i >= $mod['search']->offset; $i--) {
+ if(isset($tmp[$lineNum + $i])) {
+ $tmp[$lineNum + $i] = '';
+ }
+ }
+ }
+ }
+
+ if($mod['search']->regex == 'true') {
+ $tmp[$lineNum] = preg_replace($mod['search']->getContent(), $mod['add']->getContent(), $line);
+ } else {
+ $tmp[$lineNum] = str_replace($mod['search']->getContent(), $mod['add']->getContent(), $line);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if(!$changed) {
+ $skip = ($mod['error'] == 'skip' || $mod['error'] == 'log') ? ' (SKIPPED)' : ' (ABORTING MOD)';
+
+ if($mod['error'] == 'log' || $mod['error'] == 'abort') {
+ VQMod::$log->write('VQModObject::applyMod - SEARCH NOT FOUND' . $skip . ': ' . $mod['search']->getContent(), $this);
+ }
+
+ if($mod['error'] == 'abort') {
+ $this->_skip = true;
+ return;
+ }
+
+ }
+
+ break;
+ }
+ ksort($tmp);
+ $tmp = $this->_implodeData($tmp);
+ }
+
+ VQMod::$fileModding = false;
+
+ $data = $tmp;
+ }
+
+ /**
+ * VQModObject::_parseMods()
+ *
+ * @param DOMNode $node node to be parsed
+ * @return null
+ * @description Parses modifications in preparation for the applyMod method to work
+ */
+ private function _parseMods(DOMNode $node){
+ $files = $node->getElementsByTagName('file');
+
+ $replaces = VQMod::$replaces;
+
+ foreach($files as $file) {
+ $path = $file->getAttribute('path') ? $file->getAttribute('path') : '';
+ $filesToMod = explode(',', $file->getAttribute('name'));
+
+ foreach($filesToMod as $filename) {
+
+ $fileToMod = $path . $filename;
+ if(!empty($replaces)) {
+ foreach($replaces as $r) {
+ if(count($r) == 2) {
+ $fileToMod = preg_replace($r[0], $r[1], $fileToMod);
+ }
+ }
+ }
+
+ $error = ($file->hasAttribute('error')) ? $file->getAttribute('error') : 'log';
+ $fullPath = VQMod::path($fileToMod);
+
+ if(!$fullPath || !file_exists($fullPath)){
+ if(strpos($fileToMod, '*') !== false) {
+ $fullPath = VQMod::getCwd() . $fileToMod;
+ } else {
+ if ($error == 'log' || $error == 'abort') {
+ $skip = ($error == 'log') ? ' (SKIPPED)' : ' (ABORTING MOD)';
+ VQMod::$log->write('VQModObject::parseMods - Could not resolve path for [' . $fileToMod . ']' . $skip, $this);
+ }
+
+ if ($error == 'log' || $error == 'skip') {
+ continue;
+ } elseif ($error == 'abort') {
+ return false;
+ }
+ }
+ }
+
+ $operations = $file->getElementsByTagName('operation');
+
+ foreach($operations as $opIndex => $operation) {
+ VQMod::$fileModding = $fileToMod . '(' . $opIndex . ')';
+ $skipOperation = false;
+
+ $error = ($operation->hasAttribute('error')) ? $operation->getAttribute('error') : 'abort';
+ $ignoreif = $operation->getElementsByTagName('ignoreif')->item(0);
+
+ if($ignoreif) {
+ $ignoreif = new VQSearchNode($ignoreif);
+ } else {
+ $ignoreif = false;
+ }
+
+ $search = $operation->getElementsByTagName('search')->item(0);
+ $add = $operation->getElementsByTagName('add')->item(0);
+
+ if(!$search) {
+ VQMod::$log->write('Operation tag missing', $this);
+ $skipOperation = true;
+ }
+
+ if(!$add) {
+ VQMod::$log->write('Operation tag missing', $this);
+ $skipOperation = true;
+ }
+
+ if(!$skipOperation) {
+ $this->mods[$fullPath][] = array(
+ 'search' => new VQSearchNode($search),
+ 'add' => new VQAddNode($add),
+ 'ignoreif' => $ignoreif,
+ 'error' => $error,
+ 'fileToMod' => $fileToMod,
+ 'opIndex' => $opIndex,
+ );
+ }
+ }
+ VQMod::$fileModding = false;
+ }
+ }
+ }
+
+ /**
+ * VQModObject::_explodeData()
+ *
+ * @param string $data file contents
+ * @return string
+ * @description Splits a file into an array of individual lines
+ */
+ private function _explodeData($data) {
+ return explode("\n", $data);
+ }
+
+ /**
+ * VQModObject::_implodeData()
+ *
+ * @param array $data Array of lines
+ * @return string
+ * @description Joins an array of lines back into a text file
+ */
+ private function _implodeData($data) {
+ return implode("\n", $data);
+ }
+}
+
+/**
+ * VQNode
+ * @description Basic node object blueprint
+ */
+class VQNode {
+ public $regex = 'false';
+ public $trim = 'false';
+ private $_content = '';
+
+ /**
+ * VQNode::__construct()
+ *
+ * @param DOMNode $node Search/add node
+ * @return null
+ * @description Parses the node attributes and sets the node property
+ */
+ public function __construct(DOMNode $node) {
+ $this->_content = $node->nodeValue;
+
+ if($node->hasAttributes()) {
+ foreach($node->attributes as $attr) {
+ $name = $attr->nodeName;
+ if(isset($this->$name)) {
+ $this->$name = $attr->nodeValue;
+ }
+ }
+ }
+ }
+
+ /**
+ * VQNode::getContent()
+ *
+ * @return string
+ * @description Returns the content, trimmed if applicable
+ */
+ public function getContent() {
+ $content = ($this->trim == 'true') ? trim($this->_content) : $this->_content;
+ return $content;
+ }
+}
+
+/**
+ * VQSearchNode
+ * @description Object for the xml tags
+ */
+class VQSearchNode extends VQNode {
+ public $position = 'replace';
+ public $offset = 0;
+ public $index = 'false';
+ public $regex = 'false';
+ public $trim = 'true';
+
+ /**
+ * VQSearchNode::indexes()
+ *
+ * @return bool, array
+ * @description Returns the index values to use the search on, or false if none
+ */
+ public function indexes() {
+ if($this->index == 'false') {
+ return false;
+ }
+ $tmp = explode(',', $this->index);
+ foreach($tmp as $k => $v) {
+ if(!is_int($v)) {
+ unset($k);
+ }
+ }
+ $tmp = array_unique($tmp);
+ return empty($tmp) ? false : $tmp;
+ }
+}
+
+/**
+ * VQAddNode
+ * @description Object for the xml tags
+ */
+class VQAddNode extends VQNode {
+ public $position = false;
+ public $offset = false;
+ public $index = false;
+ public $regex = false;
+ public $trim = 'false';
+}
diff --git a/xml/vqmod_opencart.xml b/xml/vqmod_opencart.xml
index e48d450..f9ed816 100644
--- a/xml/vqmod_opencart.xml
+++ b/xml/vqmod_opencart.xml
@@ -1,59 +1,59 @@
-
-
- VQMOD CORE FOR OPENCART - DO NOT REMOVE
- 1.4.x and above
- 2.6.7
- vqmod.com
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- root) + 1);
- ]]>
-
-
-
+
+
+ VQMOD CORE FOR OPENCART - DO NOT REMOVE
+ 1.4.x and above
+ 2.6.7
+ vqmod.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ root) + 1);
+ ]]>
+
+
+
\ No newline at end of file