modification.php (24643B)
1 <?php 2 /** 3 * Modifcation XML Documentation can be found here: 4 * 5 * https://github.com/opencart/opencart/wiki/Modification-System 6 */ 7 class ControllerMarketplaceModification extends Controller { 8 private $error = array(); 9 10 public function index() { 11 $this->load->language('marketplace/modification'); 12 13 $this->document->setTitle($this->language->get('heading_title')); 14 15 $this->load->model('setting/modification'); 16 17 $this->getList(); 18 } 19 20 public function delete() { 21 $this->load->language('marketplace/modification'); 22 23 $this->document->setTitle($this->language->get('heading_title')); 24 25 $this->load->model('setting/modification'); 26 27 if (isset($this->request->post['selected']) && $this->validate()) { 28 foreach ($this->request->post['selected'] as $modification_id) { 29 $this->model_setting_modification->deleteModification($modification_id); 30 } 31 32 $this->session->data['success'] = $this->language->get('text_success'); 33 34 $url = ''; 35 36 if (isset($this->request->get['sort'])) { 37 $url .= '&sort=' . $this->request->get['sort']; 38 } 39 40 if (isset($this->request->get['order'])) { 41 $url .= '&order=' . $this->request->get['order']; 42 } 43 44 if (isset($this->request->get['page'])) { 45 $url .= '&page=' . $this->request->get['page']; 46 } 47 48 $this->response->redirect($this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . $url, true)); 49 } 50 51 $this->getList(); 52 } 53 54 public function refresh($data = array()) { 55 $this->load->language('marketplace/modification'); 56 57 $this->document->setTitle($this->language->get('heading_title')); 58 59 $this->load->model('setting/modification'); 60 61 if ($this->validate()) { 62 // Just before files are deleted, if config settings say maintenance mode is off then turn it on 63 $maintenance = $this->config->get('config_maintenance'); 64 65 $this->load->model('setting/setting'); 66 67 $this->model_setting_setting->editSettingValue('config', 'config_maintenance', true); 68 69 //Log 70 $log = array(); 71 72 // Clear all modification files 73 $files = array(); 74 75 // Make path into an array 76 $path = array(DIR_MODIFICATION . '*'); 77 78 // While the path array is still populated keep looping through 79 while (count($path) != 0) { 80 $next = array_shift($path); 81 82 foreach (glob($next) as $file) { 83 // If directory add to path array 84 if (is_dir($file)) { 85 $path[] = $file . '/*'; 86 } 87 88 // Add the file to the files to be deleted array 89 $files[] = $file; 90 } 91 } 92 93 // Reverse sort the file array 94 rsort($files); 95 96 // Clear all modification files 97 foreach ($files as $file) { 98 if ($file != DIR_MODIFICATION . 'index.html') { 99 // If file just delete 100 if (is_file($file)) { 101 unlink($file); 102 103 // If directory use the remove directory function 104 } elseif (is_dir($file)) { 105 rmdir($file); 106 } 107 } 108 } 109 110 // Begin 111 $xml = array(); 112 113 // Load the default modification XML 114 $xml[] = file_get_contents(DIR_SYSTEM . 'modification.xml'); 115 116 // This is purly for developers so they can run mods directly and have them run without upload after each change. 117 $files = glob(DIR_SYSTEM . '*.ocmod.xml'); 118 119 if ($files) { 120 foreach ($files as $file) { 121 $xml[] = file_get_contents($file); 122 } 123 } 124 125 // Get the default modification file 126 $results = $this->model_setting_modification->getModifications(); 127 128 foreach ($results as $result) { 129 if ($result['status']) { 130 $xml[] = $result['xml']; 131 } 132 } 133 134 $modification = array(); 135 136 foreach ($xml as $xml) { 137 if (empty($xml)){ 138 continue; 139 } 140 141 $dom = new DOMDocument('1.0', 'UTF-8'); 142 $dom->preserveWhiteSpace = false; 143 $dom->loadXml($xml); 144 145 // Log 146 $log[] = 'MOD: ' . $dom->getElementsByTagName('name')->item(0)->textContent; 147 148 // Wipe the past modification store in the backup array 149 $recovery = array(); 150 151 // Set the a recovery of the modification code in case we need to use it if an abort attribute is used. 152 if (isset($modification)) { 153 $recovery = $modification; 154 } 155 156 $files = $dom->getElementsByTagName('modification')->item(0)->getElementsByTagName('file'); 157 158 foreach ($files as $file) { 159 $operations = $file->getElementsByTagName('operation'); 160 161 $files = explode('|', $file->getAttribute('path')); 162 163 foreach ($files as $file) { 164 $path = ''; 165 166 // Get the full path of the files that are going to be used for modification 167 if ((substr($file, 0, 7) == 'catalog')) { 168 $path = DIR_CATALOG . substr($file, 8); 169 } 170 171 if ((substr($file, 0, 5) == 'admin')) { 172 $path = DIR_APPLICATION . substr($file, 6); 173 } 174 175 if ((substr($file, 0, 6) == 'system')) { 176 $path = DIR_SYSTEM . substr($file, 7); 177 } 178 179 if ($path) { 180 $files = glob($path, GLOB_BRACE); 181 182 if ($files) { 183 foreach ($files as $file) { 184 // Get the key to be used for the modification cache filename. 185 if (substr($file, 0, strlen(DIR_CATALOG)) == DIR_CATALOG) { 186 $key = 'catalog/' . substr($file, strlen(DIR_CATALOG)); 187 } 188 189 if (substr($file, 0, strlen(DIR_APPLICATION)) == DIR_APPLICATION) { 190 $key = 'admin/' . substr($file, strlen(DIR_APPLICATION)); 191 } 192 193 if (substr($file, 0, strlen(DIR_SYSTEM)) == DIR_SYSTEM) { 194 $key = 'system/' . substr($file, strlen(DIR_SYSTEM)); 195 } 196 197 // If file contents is not already in the modification array we need to load it. 198 if (!isset($modification[$key])) { 199 $content = file_get_contents($file); 200 201 $modification[$key] = preg_replace('~\r?\n~', "\n", $content); 202 $original[$key] = preg_replace('~\r?\n~', "\n", $content); 203 204 // Log 205 $log[] = PHP_EOL . 'FILE: ' . $key; 206 } 207 208 foreach ($operations as $operation) { 209 $error = $operation->getAttribute('error'); 210 211 // Ignoreif 212 $ignoreif = $operation->getElementsByTagName('ignoreif')->item(0); 213 214 if ($ignoreif) { 215 if ($ignoreif->getAttribute('regex') != 'true') { 216 if (strpos($modification[$key], $ignoreif->textContent) !== false) { 217 continue; 218 } 219 } else { 220 if (preg_match($ignoreif->textContent, $modification[$key])) { 221 continue; 222 } 223 } 224 } 225 226 $status = false; 227 228 // Search and replace 229 if ($operation->getElementsByTagName('search')->item(0)->getAttribute('regex') != 'true') { 230 // Search 231 $search = $operation->getElementsByTagName('search')->item(0)->textContent; 232 $trim = $operation->getElementsByTagName('search')->item(0)->getAttribute('trim'); 233 $index = $operation->getElementsByTagName('search')->item(0)->getAttribute('index'); 234 235 // Trim line if no trim attribute is set or is set to true. 236 if (!$trim || $trim == 'true') { 237 $search = trim($search); 238 } 239 240 // Add 241 $add = $operation->getElementsByTagName('add')->item(0)->textContent; 242 $trim = $operation->getElementsByTagName('add')->item(0)->getAttribute('trim'); 243 $position = $operation->getElementsByTagName('add')->item(0)->getAttribute('position'); 244 $offset = $operation->getElementsByTagName('add')->item(0)->getAttribute('offset'); 245 246 if ($offset == '') { 247 $offset = 0; 248 } 249 250 // Trim line if is set to true. 251 if ($trim == 'true') { 252 $add = trim($add); 253 } 254 255 // Log 256 $log[] = 'CODE: ' . $search; 257 258 // Check if using indexes 259 if ($index !== '') { 260 $indexes = explode(',', $index); 261 } else { 262 $indexes = array(); 263 } 264 265 // Get all the matches 266 $i = 0; 267 268 $lines = explode("\n", $modification[$key]); 269 270 for ($line_id = 0; $line_id < count($lines); $line_id++) { 271 $line = $lines[$line_id]; 272 273 // Status 274 $match = false; 275 276 // Check to see if the line matches the search code. 277 if (stripos($line, $search) !== false) { 278 // If indexes are not used then just set the found status to true. 279 if (!$indexes) { 280 $match = true; 281 } elseif (in_array($i, $indexes)) { 282 $match = true; 283 } 284 285 $i++; 286 } 287 288 // Now for replacing or adding to the matched elements 289 if ($match) { 290 switch ($position) { 291 default: 292 case 'replace': 293 $new_lines = explode("\n", $add); 294 295 if ($offset < 0) { 296 array_splice($lines, $line_id + $offset, abs($offset) + 1, array(str_replace($search, $add, $line))); 297 298 $line_id -= $offset; 299 } else { 300 array_splice($lines, $line_id, $offset + 1, array(str_replace($search, $add, $line))); 301 } 302 break; 303 case 'before': 304 $new_lines = explode("\n", $add); 305 306 array_splice($lines, $line_id - $offset, 0, $new_lines); 307 308 $line_id += count($new_lines); 309 break; 310 case 'after': 311 $new_lines = explode("\n", $add); 312 313 array_splice($lines, ($line_id + 1) + $offset, 0, $new_lines); 314 315 $line_id += count($new_lines); 316 break; 317 } 318 319 // Log 320 $log[] = 'LINE: ' . $line_id; 321 322 $status = true; 323 } 324 } 325 326 $modification[$key] = implode("\n", $lines); 327 } else { 328 $search = trim($operation->getElementsByTagName('search')->item(0)->textContent); 329 $limit = $operation->getElementsByTagName('search')->item(0)->getAttribute('limit'); 330 $replace = trim($operation->getElementsByTagName('add')->item(0)->textContent); 331 332 // Limit 333 if (!$limit) { 334 $limit = -1; 335 } 336 337 // Log 338 $match = array(); 339 340 preg_match_all($search, $modification[$key], $match, PREG_OFFSET_CAPTURE); 341 342 // Remove part of the the result if a limit is set. 343 if ($limit > 0) { 344 $match[0] = array_slice($match[0], 0, $limit); 345 } 346 347 if ($match[0]) { 348 $log[] = 'REGEX: ' . $search; 349 350 for ($i = 0; $i < count($match[0]); $i++) { 351 $log[] = 'LINE: ' . (substr_count(substr($modification[$key], 0, $match[0][$i][1]), "\n") + 1); 352 } 353 354 $status = true; 355 } 356 357 // Make the modification 358 $modification[$key] = preg_replace($search, $replace, $modification[$key], $limit); 359 } 360 361 if (!$status) { 362 // Abort applying this modification completely. 363 if ($error == 'abort') { 364 $modification = $recovery; 365 // Log 366 $log[] = 'NOT FOUND - ABORTING!'; 367 break 5; 368 } 369 // Skip current operation or break 370 elseif ($error == 'skip') { 371 // Log 372 $log[] = 'NOT FOUND - OPERATION SKIPPED!'; 373 continue; 374 } 375 // Break current operations 376 else { 377 // Log 378 $log[] = 'NOT FOUND - OPERATIONS ABORTED!'; 379 break; 380 } 381 } 382 } 383 } 384 } 385 } 386 } 387 } 388 389 // Log 390 $log[] = '----------------------------------------------------------------'; 391 } 392 393 // Log 394 $ocmod = new Log('ocmod.log'); 395 $ocmod->write(implode("\n", $log)); 396 397 // Write all modification files 398 foreach ($modification as $key => $value) { 399 // Only create a file if there are changes 400 if ($original[$key] != $value) { 401 $path = ''; 402 403 $directories = explode('/', dirname($key)); 404 405 foreach ($directories as $directory) { 406 $path = $path . '/' . $directory; 407 408 if (!is_dir(DIR_MODIFICATION . $path)) { 409 @mkdir(DIR_MODIFICATION . $path, 0777); 410 } 411 } 412 413 $handle = fopen(DIR_MODIFICATION . $key, 'w'); 414 415 fwrite($handle, $value); 416 417 fclose($handle); 418 } 419 } 420 421 // Maintance mode back to original settings 422 $this->model_setting_setting->editSettingValue('config', 'config_maintenance', $maintenance); 423 424 // Do not return success message if refresh() was called with $data 425 $this->session->data['success'] = $this->language->get('text_success'); 426 427 $url = ''; 428 429 if (isset($this->request->get['sort'])) { 430 $url .= '&sort=' . $this->request->get['sort']; 431 } 432 433 if (isset($this->request->get['order'])) { 434 $url .= '&order=' . $this->request->get['order']; 435 } 436 437 if (isset($this->request->get['page'])) { 438 $url .= '&page=' . $this->request->get['page']; 439 } 440 441 $this->response->redirect($this->url->link(!empty($data['redirect']) ? $data['redirect'] : 'marketplace/modification', 'user_token=' . $this->session->data['user_token'] . $url, true)); 442 } 443 444 $this->getList(); 445 } 446 447 public function clear() { 448 $this->load->language('marketplace/modification'); 449 450 $this->document->setTitle($this->language->get('heading_title')); 451 452 $this->load->model('setting/modification'); 453 454 if ($this->validate()) { 455 $files = array(); 456 457 // Make path into an array 458 $path = array(DIR_MODIFICATION . '*'); 459 460 // While the path array is still populated keep looping through 461 while (count($path) != 0) { 462 $next = array_shift($path); 463 464 foreach (glob($next) as $file) { 465 // If directory add to path array 466 if (is_dir($file)) { 467 $path[] = $file . '/*'; 468 } 469 470 // Add the file to the files to be deleted array 471 $files[] = $file; 472 } 473 } 474 475 // Reverse sort the file array 476 rsort($files); 477 478 // Clear all modification files 479 foreach ($files as $file) { 480 if ($file != DIR_MODIFICATION . 'index.html') { 481 // If file just delete 482 if (is_file($file)) { 483 unlink($file); 484 485 // If directory use the remove directory function 486 } elseif (is_dir($file)) { 487 rmdir($file); 488 } 489 } 490 } 491 492 $this->session->data['success'] = $this->language->get('text_success'); 493 494 $url = ''; 495 496 if (isset($this->request->get['sort'])) { 497 $url .= '&sort=' . $this->request->get['sort']; 498 } 499 500 if (isset($this->request->get['order'])) { 501 $url .= '&order=' . $this->request->get['order']; 502 } 503 504 if (isset($this->request->get['page'])) { 505 $url .= '&page=' . $this->request->get['page']; 506 } 507 508 $this->response->redirect($this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . $url, true)); 509 } 510 511 $this->getList(); 512 } 513 514 public function enable() { 515 $this->load->language('marketplace/modification'); 516 517 $this->document->setTitle($this->language->get('heading_title')); 518 519 $this->load->model('setting/modification'); 520 521 if (isset($this->request->get['modification_id']) && $this->validate()) { 522 $this->model_setting_modification->enableModification($this->request->get['modification_id']); 523 524 $this->session->data['success'] = $this->language->get('text_success'); 525 526 $url = ''; 527 528 if (isset($this->request->get['sort'])) { 529 $url .= '&sort=' . $this->request->get['sort']; 530 } 531 532 if (isset($this->request->get['order'])) { 533 $url .= '&order=' . $this->request->get['order']; 534 } 535 536 if (isset($this->request->get['page'])) { 537 $url .= '&page=' . $this->request->get['page']; 538 } 539 540 $this->response->redirect($this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . $url, true)); 541 } 542 543 $this->getList(); 544 } 545 546 public function disable() { 547 $this->load->language('marketplace/modification'); 548 549 $this->document->setTitle($this->language->get('heading_title')); 550 551 $this->load->model('setting/modification'); 552 553 if (isset($this->request->get['modification_id']) && $this->validate()) { 554 $this->model_setting_modification->disableModification($this->request->get['modification_id']); 555 556 $this->session->data['success'] = $this->language->get('text_success'); 557 558 $url = ''; 559 560 if (isset($this->request->get['sort'])) { 561 $url .= '&sort=' . $this->request->get['sort']; 562 } 563 564 if (isset($this->request->get['order'])) { 565 $url .= '&order=' . $this->request->get['order']; 566 } 567 568 if (isset($this->request->get['page'])) { 569 $url .= '&page=' . $this->request->get['page']; 570 } 571 572 $this->response->redirect($this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . $url, true)); 573 } 574 575 $this->getList(); 576 } 577 578 public function clearlog() { 579 $this->load->language('marketplace/modification'); 580 581 $this->document->setTitle($this->language->get('heading_title')); 582 583 $this->load->model('setting/modification'); 584 585 if ($this->validate()) { 586 $handle = fopen(DIR_LOGS . 'ocmod.log', 'w+'); 587 588 fclose($handle); 589 590 $this->session->data['success'] = $this->language->get('text_success'); 591 592 $url = ''; 593 594 if (isset($this->request->get['sort'])) { 595 $url .= '&sort=' . $this->request->get['sort']; 596 } 597 598 if (isset($this->request->get['order'])) { 599 $url .= '&order=' . $this->request->get['order']; 600 } 601 602 if (isset($this->request->get['page'])) { 603 $url .= '&page=' . $this->request->get['page']; 604 } 605 606 $this->response->redirect($this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . $url, true)); 607 } 608 609 $this->getList(); 610 } 611 612 protected function getList() { 613 if (isset($this->request->get['sort'])) { 614 $sort = $this->request->get['sort']; 615 } else { 616 $sort = 'name'; 617 } 618 619 if (isset($this->request->get['order'])) { 620 $order = $this->request->get['order']; 621 } else { 622 $order = 'ASC'; 623 } 624 625 if (isset($this->request->get['page'])) { 626 $page = $this->request->get['page']; 627 } else { 628 $page = 1; 629 } 630 631 $url = ''; 632 633 if (isset($this->request->get['sort'])) { 634 $url .= '&sort=' . $this->request->get['sort']; 635 } 636 637 if (isset($this->request->get['order'])) { 638 $url .= '&order=' . $this->request->get['order']; 639 } 640 641 if (isset($this->request->get['page'])) { 642 $url .= '&page=' . $this->request->get['page']; 643 } 644 645 $data['breadcrumbs'] = array(); 646 647 $data['breadcrumbs'][] = array( 648 'text' => $this->language->get('text_home'), 649 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true) 650 ); 651 652 $data['breadcrumbs'][] = array( 653 'text' => $this->language->get('heading_title'), 654 'href' => $this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'], true) 655 ); 656 657 $data['refresh'] = $this->url->link('marketplace/modification/refresh', 'user_token=' . $this->session->data['user_token'] . $url, true); 658 $data['clear'] = $this->url->link('marketplace/modification/clear', 'user_token=' . $this->session->data['user_token'] . $url, true); 659 $data['delete'] = $this->url->link('marketplace/modification/delete', 'user_token=' . $this->session->data['user_token'] . $url, true); 660 661 $data['modifications'] = array(); 662 663 $filter_data = array( 664 'sort' => $sort, 665 'order' => $order, 666 'start' => ($page - 1) * $this->config->get('config_limit_admin'), 667 'limit' => $this->config->get('config_limit_admin') 668 ); 669 670 $modification_total = $this->model_setting_modification->getTotalModifications(); 671 672 $results = $this->model_setting_modification->getModifications($filter_data); 673 674 foreach ($results as $result) { 675 $data['modifications'][] = array( 676 'modification_id' => $result['modification_id'], 677 'name' => $result['name'], 678 'author' => $result['author'], 679 'version' => $result['version'], 680 'status' => $result['status'] ? $this->language->get('text_enabled') : $this->language->get('text_disabled'), 681 'date_added' => date($this->language->get('date_format_short'), strtotime($result['date_added'])), 682 'link' => $result['link'], 683 'enable' => $this->url->link('marketplace/modification/enable', 'user_token=' . $this->session->data['user_token'] . '&modification_id=' . $result['modification_id'], true), 684 'disable' => $this->url->link('marketplace/modification/disable', 'user_token=' . $this->session->data['user_token'] . '&modification_id=' . $result['modification_id'], true), 685 'enabled' => $result['status'] 686 ); 687 } 688 689 $data['user_token'] = $this->session->data['user_token']; 690 691 if (isset($this->error['warning'])) { 692 $data['error_warning'] = $this->error['warning']; 693 } else { 694 $data['error_warning'] = ''; 695 } 696 697 if (isset($this->session->data['success'])) { 698 $data['success'] = $this->session->data['success']; 699 700 unset($this->session->data['success']); 701 } else { 702 $data['success'] = ''; 703 } 704 705 if (isset($this->request->post['selected'])) { 706 $data['selected'] = (array)$this->request->post['selected']; 707 } else { 708 $data['selected'] = array(); 709 } 710 711 $url = ''; 712 713 if ($order == 'ASC') { 714 $url .= '&order=DESC'; 715 } else { 716 $url .= '&order=ASC'; 717 } 718 719 if (isset($this->request->get['page'])) { 720 $url .= '&page=' . $this->request->get['page']; 721 } 722 723 $data['sort_name'] = $this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . '&sort=name' . $url, true); 724 $data['sort_author'] = $this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . '&sort=author' . $url, true); 725 $data['sort_version'] = $this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . '&sort=version' . $url, true); 726 $data['sort_status'] = $this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . '&sort=status' . $url, true); 727 $data['sort_date_added'] = $this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . '&sort=date_added' . $url, true); 728 729 $url = ''; 730 731 if (isset($this->request->get['sort'])) { 732 $url .= '&sort=' . $this->request->get['sort']; 733 } 734 735 if (isset($this->request->get['order'])) { 736 $url .= '&order=' . $this->request->get['order']; 737 } 738 739 $pagination = new Pagination(); 740 $pagination->total = $modification_total; 741 $pagination->page = $page; 742 $pagination->limit = $this->config->get('config_limit_admin'); 743 $pagination->url = $this->url->link('marketplace/modification', 'user_token=' . $this->session->data['user_token'] . $url . '&page={page}', true); 744 745 $data['pagination'] = $pagination->render(); 746 747 $data['results'] = sprintf($this->language->get('text_pagination'), ($modification_total) ? (($page - 1) * $this->config->get('config_limit_admin')) + 1 : 0, ((($page - 1) * $this->config->get('config_limit_admin')) > ($modification_total - $this->config->get('config_limit_admin'))) ? $modification_total : ((($page - 1) * $this->config->get('config_limit_admin')) + $this->config->get('config_limit_admin')), $modification_total, ceil($modification_total / $this->config->get('config_limit_admin'))); 748 749 $data['sort'] = $sort; 750 $data['order'] = $order; 751 752 // Log 753 $file = DIR_LOGS . 'ocmod.log'; 754 755 if (file_exists($file)) { 756 $data['log'] = htmlentities(file_get_contents($file, FILE_USE_INCLUDE_PATH, null)); 757 } else { 758 $data['log'] = ''; 759 } 760 761 $data['clear_log'] = $this->url->link('marketplace/modification/clearlog', 'user_token=' . $this->session->data['user_token'], true); 762 763 $data['header'] = $this->load->controller('common/header'); 764 $data['column_left'] = $this->load->controller('common/column_left'); 765 $data['footer'] = $this->load->controller('common/footer'); 766 767 $this->response->setOutput($this->load->view('marketplace/modification', $data)); 768 } 769 770 protected function validate() { 771 if (!$this->user->hasPermission('modify', 'marketplace/modification')) { 772 $this->error['warning'] = $this->language->get('error_permission'); 773 } 774 775 return !$this->error; 776 } 777 }