modification.php (25672B)
1 <?php 2 /* 3 * location: admin/model/extension/d_opencart_patch/modification.php 4 * 5 */ 6 7 class ModelExtensionDOpencartPatchModification extends Model { 8 9 /* 10 * Ocmod: turn on or off 11 */ 12 13 public function setModification($xml, $status = 1){ 14 //finding file 15 16 //by full path. 17 $file = str_replace("system/", "", DIR_SYSTEM).$xml; 18 if (!file_exists($file)) { 19 $file = DIR_SYSTEM.'library/d_shopunity/install/'.$xml; 20 } 21 22 //old format - depricated 23 if (!file_exists($file)) { 24 $file = DIR_SYSTEM.'mbooth/install/'.$xml; 25 } 26 27 if (!file_exists($file)) { 28 return false; 29 } 30 31 $json = array(); 32 if(VERSION >= '3.0.0.0'){ 33 $this->load->model('setting/modification'); 34 }else{ 35 $this->load->model('extension/modification'); 36 } 37 38 if($status){ 39 40 41 // If xml file just put it straight into the DB 42 $xml = file_get_contents($file); 43 44 if ($xml) { 45 try { 46 $dom = new DOMDocument('1.0', 'UTF-8'); 47 $dom->loadXml($xml); 48 49 $name = $dom->getElementsByTagName('name')->item(0); 50 51 if ($name) { 52 $name = $name->nodeValue; 53 } else { 54 $name = ''; 55 } 56 57 $code = $dom->getElementsByTagName('code')->item(0); 58 59 if ($code) { 60 $code = $code->nodeValue; 61 62 // Check to see if the modification is already installed or not. 63 if(VERSION <= '2.0.0.0'){ 64 $modification_info = $this->getModificationByName($name); 65 }else{ 66 $modification_info = $this->getModificationByCode($code); 67 } 68 69 if ($modification_info) { 70 $json['error'] = sprintf($this->language->get('error_exists'), $modification_info['name']); 71 } 72 } else { 73 $json['error'] = $this->language->get('error_code'); 74 } 75 76 $author = $dom->getElementsByTagName('author')->item(0); 77 78 if ($author) { 79 $author = $author->nodeValue; 80 } else { 81 $author = ''; 82 } 83 84 $version = $dom->getElementsByTagName('version')->item(0); 85 86 if ($version) { 87 $version = $version->nodeValue; 88 } else { 89 $version = ''; 90 } 91 92 $link = $dom->getElementsByTagName('link')->item(0); 93 94 if ($link) { 95 $link = $link->nodeValue; 96 } else { 97 $link = ''; 98 } 99 100 $modification_data = array( 101 'name' => $name, 102 'code' => $code, 103 'author' => $author, 104 'version' => $version, 105 'link' => $link, 106 'xml' => $xml, 107 'status' => 1 108 ); 109 110 if (!$json) { 111 $this->addModification($modification_data); 112 } 113 } catch(Exception $exception) { 114 return false; 115 } 116 } 117 }else{ 118 $modification_id = $this->getModificationId($xml); 119 if($modification_id){ 120 if(VERSION >= '3.0.0.0'){ 121 $this->model_setting_modification->deleteModification($modification_id); 122 }else{ 123 $this->model_extension_modification->deleteModification($modification_id); 124 } 125 } 126 } 127 return false; 128 } 129 130 public function refreshCache(){ 131 if(VERSION >= '3.0.0.0'){ 132 $this->load->language('marketplace/modification'); 133 }else{ 134 $this->load->language('extension/modification'); 135 } 136 137 138 if(VERSION >= '3.0.0.0'){ 139 $this->load->model('setting/modification'); 140 }else{ 141 $this->load->model('extension/modification'); 142 } 143 144 //remove conflict with third-pary extensions; 145 if(file_exists(DIR_MODIFICATION.'admin/controller/extension/modification.php')){ 146 unlink(DIR_MODIFICATION.'admin/controller/extension/modification.php'); 147 } 148 149 // Just before files are deleted, if config settings say maintenance mode is off then turn it on 150 // $maintenance = $this->config->get('config_maintenance'); 151 152 // $this->load->model('setting/setting'); 153 154 // $this->model_setting_setting->editSettingValue('config', 'config_maintenance', true); 155 156 //Log 157 $log = array(); 158 159 // Clear all modification files 160 $files = array(); 161 162 // Make path into an array 163 $path = array(DIR_MODIFICATION . '*'); 164 165 // While the path array is still populated keep looping through 166 while (count($path) != 0) { 167 $next = array_shift($path); 168 169 foreach (glob($next) as $file) { 170 // If directory add to path array 171 if (is_dir($file)) { 172 $path[] = $file . '/*'; 173 } 174 175 // Add the file to the files to be deleted array 176 $files[] = $file; 177 } 178 } 179 180 // Reverse sort the file array 181 rsort($files); 182 183 // Clear all modification files 184 foreach ($files as $file) { 185 if ($file != DIR_MODIFICATION . 'index.html') { 186 // If file just delete 187 if (is_file($file)) { 188 unlink($file); 189 190 // If directory use the remove directory function 191 } elseif (is_dir($file)) { 192 rmdir($file); 193 } 194 } 195 } 196 197 // Begin 198 $xml = array(); 199 200 // Load the default modification XML 201 $xml[] = file_get_contents(DIR_SYSTEM . 'modification.xml'); 202 203 // This is purly for developers so they can run mods directly and have them run without upload sfter each change. 204 $files = glob(DIR_SYSTEM . '*.ocmod.xml'); 205 206 if ($files) { 207 foreach ($files as $file) { 208 $xml[] = file_get_contents($file); 209 } 210 } 211 212 // Get the default modification file 213 if(VERSION >= '3.0.0.0'){ 214 $results = $this->model_setting_modification->getModifications(); 215 }else{ 216 $results = $this->model_extension_modification->getModifications(); 217 } 218 219 foreach ($results as $result) { 220 if ($result['status']) { 221 if(VERSION <= '2.0.0.0'){ 222 $xml[] = $result['code']; 223 }else{ 224 $xml[] = $result['xml']; 225 } 226 227 } 228 } 229 230 $modification = array(); 231 232 foreach ($xml as $xml) { 233 if(empty($xml)){ 234 continue; 235 } 236 $dom = new DOMDocument('1.0', 'UTF-8'); 237 $dom->preserveWhiteSpace = false; 238 $dom->loadXml($xml); 239 240 // Log 241 $log[] = 'MOD: ' . $dom->getElementsByTagName('name')->item(0)->textContent; 242 243 // Wipe the past modification store in the backup array 244 $recovery = array(); 245 246 // Set the a recovery of the modification code in case we need to use it if an abort attribute is used. 247 if (isset($modification)) { 248 $recovery = $modification; 249 } 250 251 $files = $dom->getElementsByTagName('modification')->item(0)->getElementsByTagName('file'); 252 253 foreach ($files as $file) { 254 $operations = $file->getElementsByTagName('operation'); 255 if(VERSION >= "2.0.2.0" && VERSION < "2.1.0.0" ){ 256 $files = explode(',', $file->getAttribute('path')); 257 }else{ 258 $files = explode('|', $file->getAttribute('path')); 259 } 260 261 foreach ($files as $file) { 262 $path = ''; 263 264 // Get the full path of the files that are going to be used for modification 265 if (substr($file, 0, 7) == 'catalog') { 266 $path = DIR_CATALOG . str_replace('../', '', substr($file, 8)); 267 } 268 269 if (substr($file, 0, 5) == 'admin') { 270 $path = DIR_APPLICATION . str_replace('../', '', substr($file, 6)); 271 } 272 273 if (substr($file, 0, 6) == 'system') { 274 $path = DIR_SYSTEM . str_replace('../', '', substr($file, 7)); 275 } 276 277 if ($path) { 278 $files = glob($path, GLOB_BRACE); 279 280 if ($files) { 281 foreach ($files as $file) { 282 // Get the key to be used for the modification cache filename. 283 if (substr($file, 0, strlen(DIR_CATALOG)) == DIR_CATALOG) { 284 $key = 'catalog/' . substr($file, strlen(DIR_CATALOG)); 285 } 286 287 if (substr($file, 0, strlen(DIR_APPLICATION)) == DIR_APPLICATION) { 288 $key = 'admin/' . substr($file, strlen(DIR_APPLICATION)); 289 } 290 291 if (substr($file, 0, strlen(DIR_SYSTEM)) == DIR_SYSTEM) { 292 $key = 'system/' . substr($file, strlen(DIR_SYSTEM)); 293 } 294 295 // If file contents is not already in the modification array we need to load it. 296 if (!isset($modification[$key])) { 297 $content = file_get_contents($file); 298 299 $modification[$key] = preg_replace('~\r?\n~', "\n", $content); 300 $original[$key] = preg_replace('~\r?\n~', "\n", $content); 301 302 // Log 303 $log[] = 'FILE: ' . $key; 304 } 305 306 foreach ($operations as $operation) { 307 $error = $operation->getAttribute('error'); 308 309 // Ignoreif 310 $ignoreif = $operation->getElementsByTagName('ignoreif')->item(0); 311 312 if ($ignoreif) { 313 if ($ignoreif->getAttribute('regex') != 'true') { 314 if (strpos($modification[$key], $ignoreif->textContent) !== false) { 315 continue; 316 } 317 } else { 318 if (preg_match($ignoreif->textContent, $modification[$key])) { 319 continue; 320 } 321 } 322 } 323 324 $status = false; 325 326 // Search and replace 327 if ($operation->getElementsByTagName('search')->item(0)->getAttribute('regex') != 'true') { 328 // Search 329 $search = $operation->getElementsByTagName('search')->item(0)->textContent; 330 $trim = $operation->getElementsByTagName('search')->item(0)->getAttribute('trim'); 331 $index = $operation->getElementsByTagName('search')->item(0)->getAttribute('index'); 332 333 // Trim line if no trim attribute is set or is set to true. 334 if (!$trim || $trim == 'true') { 335 $search = trim($search); 336 } 337 338 // Add 339 $add = $operation->getElementsByTagName('add')->item(0)->textContent; 340 $trim = $operation->getElementsByTagName('add')->item(0)->getAttribute('trim'); 341 $position = $operation->getElementsByTagName('add')->item(0)->getAttribute('position'); 342 $offset = $operation->getElementsByTagName('add')->item(0)->getAttribute('offset'); 343 344 if ($offset == '') { 345 $offset = 0; 346 } 347 348 // Trim line if is set to true. 349 if ($trim == 'true') { 350 $add = trim($add); 351 } 352 353 // Log 354 $log[] = 'CODE: ' . $search; 355 356 // Check if using indexes 357 if ($index !== '') { 358 $indexes = explode(',', $index); 359 } else { 360 $indexes = array(); 361 } 362 363 // Get all the matches 364 $i = 0; 365 366 $lines = explode("\n", $modification[$key]); 367 368 for ($line_id = 0; $line_id < count($lines); $line_id++) { 369 $line = $lines[$line_id]; 370 371 // Status 372 $match = false; 373 374 // Check to see if the line matches the search code. 375 if (stripos($line, $search) !== false) { 376 // If indexes are not used then just set the found status to true. 377 if (!$indexes) { 378 $match = true; 379 } elseif (in_array($i, $indexes)) { 380 $match = true; 381 } 382 383 $i++; 384 } 385 386 // Now for replacing or adding to the matched elements 387 if ($match) { 388 switch ($position) { 389 default: 390 case 'replace': 391 $new_lines = explode("\n", $add); 392 393 if ($offset < 0) { 394 array_splice($lines, $line_id + $offset, abs($offset) + 1, array(str_replace($search, $add, $line))); 395 396 $line_id -= $offset; 397 } else { 398 array_splice($lines, $line_id, $offset + 1, array(str_replace($search, $add, $line))); 399 } 400 401 break; 402 case 'before': 403 $new_lines = explode("\n", $add); 404 405 array_splice($lines, $line_id - $offset, 0, $new_lines); 406 407 $line_id += count($new_lines); 408 break; 409 case 'after': 410 $new_lines = explode("\n", $add); 411 412 array_splice($lines, ($line_id + 1) + $offset, 0, $new_lines); 413 414 $line_id += count($new_lines); 415 break; 416 } 417 418 // Log 419 $log[] = 'LINE: ' . $line_id; 420 421 $status = true; 422 } 423 } 424 425 $modification[$key] = implode("\n", $lines); 426 } else { 427 $search = trim($operation->getElementsByTagName('search')->item(0)->textContent); 428 $limit = $operation->getElementsByTagName('search')->item(0)->getAttribute('limit'); 429 $replace = trim($operation->getElementsByTagName('add')->item(0)->textContent); 430 431 // Limit 432 if (!$limit) { 433 $limit = -1; 434 } 435 436 // Log 437 $match = array(); 438 439 preg_match_all($search, $modification[$key], $match, PREG_OFFSET_CAPTURE); 440 441 // Remove part of the the result if a limit is set. 442 if ($limit > 0) { 443 $match[0] = array_slice($match[0], 0, $limit); 444 } 445 446 if ($match[0]) { 447 $log[] = 'REGEX: ' . $search; 448 449 for ($i = 0; $i < count($match[0]); $i++) { 450 $log[] = 'LINE: ' . (substr_count(substr($modification[$key], 0, $match[0][$i][1]), "\n") + 1); 451 } 452 453 $status = true; 454 } 455 456 // Make the modification 457 $modification[$key] = preg_replace($search, $replace, $modification[$key], $limit); 458 } 459 460 if (!$status) { 461 // Log 462 $log[] = 'NOT FOUND!'; 463 464 // Abort applying this modification completely. 465 if ($error == 'abort') { 466 $modification = $recovery; 467 468 // Log 469 $log[] = 'ABORTING!'; 470 471 break 5; 472 } 473 474 // Skip current operation or break 475 if ($error == 'skip') { 476 continue; 477 } else { 478 break; 479 } 480 } 481 } 482 } 483 } 484 } 485 } 486 } 487 488 // Log 489 $log[] = '----------------------------------------------------------------'; 490 } 491 492 // Log 493 $ocmod = new Log('ocmod.log'); 494 $ocmod->write(implode("\n", $log)); 495 496 // Write all modification files 497 foreach ($modification as $key => $value) { 498 // Only create a file if there are changes 499 if ($original[$key] != $value) { 500 $path = ''; 501 502 $directories = explode('/', dirname($key)); 503 504 foreach ($directories as $directory) { 505 $path = $path . '/' . $directory; 506 507 if (!is_dir(DIR_MODIFICATION . $path)) { 508 @mkdir(DIR_MODIFICATION . $path, 0777); 509 } 510 } 511 512 $handle = fopen(DIR_MODIFICATION . $key, 'w'); 513 514 fwrite($handle, $value); 515 516 fclose($handle); 517 } 518 } 519 520 // Maintance mode back to original settings 521 //$this->model_setting_setting->editSettingValue('config', 'config_maintenance', $maintenance); 522 523 return false; 524 } 525 526 public function getModificationId($xml){ 527 //by full path. 528 $file = str_replace("system/", "", DIR_SYSTEM).$xml; 529 if (!file_exists($file)) { 530 $file = DIR_SYSTEM.'library/d_shopunity/install/'.$xml; 531 } 532 533 //old format - depricated 534 if (!file_exists($file)) { 535 $file = DIR_SYSTEM.'mbooth/install/'.$xml; 536 } 537 538 if (!file_exists($file)) { 539 return false; 540 } 541 542 $xml = file_get_contents($file); 543 544 $dom = new DOMDocument('1.0', 'UTF-8'); 545 $dom->loadXml($xml); 546 547 $code = $dom->getElementsByTagName('code')->item(0); 548 $name = $dom->getElementsByTagName('name')->item(0); 549 if ($name) { 550 $name = $name->nodeValue; 551 } else { 552 $name = ''; 553 } 554 555 if ($code) { 556 $code = $code->nodeValue; 557 } else { 558 $code = ''; 559 } 560 561 if ($code || $name) { 562 if(VERSION <= '2.0.0.0'){ 563 $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "modification WHERE name = '" . $this->db->escape($name) . "'"); 564 }else{ 565 $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "modification WHERE code = '" . $this->db->escape($code) . "'"); 566 } 567 568 if(isset($query->row['modification_id'])){ 569 return $query->row['modification_id']; 570 } 571 } 572 } 573 574 public function getModificationByCode($code) { 575 $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "modification WHERE code = '" . $this->db->escape($code) . "'"); 576 577 return $query->row; 578 } 579 580 public function getModificationByName($name) { 581 $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "modification WHERE name = '" . $this->db->escape($name) . "'"); 582 583 return $query->row; 584 } 585 586 public function addModification($data) { 587 588 if(VERSION <= '2.0.0.0'){ 589 $this->db->query("INSERT INTO " . DB_PREFIX . "modification SET name = '" . $this->db->escape($data['name']) . "', author = '" . $this->db->escape($data['author']) . "', version = '" . $this->db->escape($data['version']) . "', link = '" . $this->db->escape($data['link']) . "', code = '" . $this->db->escape($data['xml']) . "', status = '" . (int)$data['status'] . "', date_added = NOW()"); 590 }else{ 591 $this->db->query("INSERT INTO " . DB_PREFIX . "modification SET code = '" . $this->db->escape($data['code']) . "', name = '" . $this->db->escape($data['name']) . "', author = '" . $this->db->escape($data['author']) . "', version = '" . $this->db->escape($data['version']) . "', link = '" . $this->db->escape($data['link']) . "', xml = '" . $this->db->escape($data['xml']) . "', status = '" . (int)$data['status'] . "', date_added = NOW()"); 592 } 593 } 594 }