1 <?php
2 3 4 5 6 7 8
9
10 defined('JPATH_PLATFORM') or die;
11
12 use Joomla\Utilities\ArrayHelper;
13
14 jimport('joomla.filesystem.folder');
15
16 17 18 19 20
21 class JInstallerAdapterModule extends JInstallerAdapter
22 {
23 24 25 26 27 28
29 protected $clientId;
30
31 32 33 34 35 36
37 protected $scriptElement = null;
38
39 40 41 42 43 44 45 46
47 protected function checkExistingExtension()
48 {
49 try
50 {
51 $this->currentExtensionId = $this->extension->find(
52 array(
53 'element' => $this->element,
54 'type' => $this->type,
55 'client_id' => $this->clientId,
56 )
57 );
58 }
59 catch (RuntimeException $e)
60 {
61
62 throw new RuntimeException(
63 JText::sprintf(
64 'JLIB_INSTALLER_ABORT_ROLLBACK',
65 JText::_('JLIB_INSTALLER_' . $this->route),
66 $e->getMessage()
67 ),
68 $e->getCode(),
69 $e
70 );
71 }
72 }
73
74 75 76 77 78 79 80 81
82 protected function copyBaseFiles()
83 {
84
85 if ($this->parent->parseFiles($this->getManifest()->files, -1) === false)
86 {
87 throw new RuntimeException(JText::_('JLIB_INSTALLER_ABORT_MOD_COPY_FILES'));
88 }
89
90
91 if ($this->manifest_script)
92 {
93 $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script;
94 $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script;
95
96 if ($this->parent->isOverwrite() || !file_exists($path['dest']))
97 {
98 if (!$this->parent->copyFiles(array($path)))
99 {
100
101 throw new RuntimeException(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_MANIFEST'));
102 }
103 }
104 }
105 }
106
107 108 109 110 111 112 113 114
115 protected function finaliseInstall()
116 {
117
118 $update = JTable::getInstance('update');
119 $uid = $update->find(
120 array(
121 'element' => $this->element,
122 'type' => 'module',
123 'client_id' => $this->clientId,
124 )
125 );
126
127 if ($uid)
128 {
129 $update->delete($uid);
130 }
131
132
133 if ($this->route !== 'discover_install')
134 {
135 if (!$this->parent->copyManifest(-1))
136 {
137
138 throw new RuntimeException(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_COPY_SETUP'));
139 }
140 }
141 }
142
143 144 145 146 147 148 149 150 151
152 public function getElement($element = null)
153 {
154 if (!$element)
155 {
156 if (count($this->getManifest()->files->children()))
157 {
158 foreach ($this->getManifest()->files->children() as $file)
159 {
160 if ((string) $file->attributes()->module)
161 {
162 $element = strtolower((string) $file->attributes()->module);
163
164 break;
165 }
166 }
167 }
168 }
169
170 return $element;
171 }
172
173 174 175 176 177 178 179 180 181
182 public function loadLanguage($path = null)
183 {
184 $source = $this->parent->getPath('source');
185 $client = $this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE;
186
187 if (!$source)
188 {
189 $this->parent->setPath('source', $client . '/modules/' . $this->parent->extension->element);
190 }
191
192 $this->setManifest($this->parent->getManifest());
193
194 if ($this->getManifest()->files)
195 {
196 $extension = $this->getElement();
197
198 if ($extension)
199 {
200 $source = $path ?: ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $extension;
201 $folder = (string) $this->getManifest()->files->attributes()->folder;
202
203 if ($folder && file_exists($path . '/' . $folder))
204 {
205 $source = $path . '/' . $folder;
206 }
207
208 $client = (string) $this->getManifest()->attributes()->client;
209 $this->doLoadLanguage($extension, $source, constant('JPATH_' . strtoupper($client)));
210 }
211 }
212 }
213
214 215 216 217 218 219 220
221 protected function parseOptionalTags()
222 {
223
224 $this->parent->parseMedia($this->getManifest()->media, $this->clientId);
225 $this->parent->parseLanguages($this->getManifest()->languages, $this->clientId);
226 }
227
228 229 230 231 232 233 234
235 public function prepareDiscoverInstall()
236 {
237 $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
238 $manifestPath = $client->path . '/modules/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml';
239 $this->parent->manifest = $this->parent->isManifest($manifestPath);
240 $this->parent->setPath('manifest', $manifestPath);
241 $this->setManifest($this->parent->getManifest());
242 }
243
244 245 246 247 248 249 250 251
252 protected function setupInstallPaths()
253 {
254
255 $cname = (string) $this->getManifest()->attributes()->client;
256
257 if ($cname)
258 {
259
260 $client = JApplicationHelper::getClientInfo($cname, true);
261
262 if ($client === false)
263 {
264 throw new RuntimeException(
265 JText::sprintf(
266 'JLIB_INSTALLER_ABORT_MOD_UNKNOWN_CLIENT',
267 JText::_('JLIB_INSTALLER_' . $this->route),
268 $client->name
269 )
270 );
271 }
272
273 $basePath = $client->path;
274 $this->clientId = $client->id;
275 }
276 else
277 {
278
279 $basePath = JPATH_SITE;
280 $this->clientId = 0;
281 }
282
283
284 if (empty($this->element))
285 {
286 throw new RuntimeException(
287 JText::sprintf(
288 'JLIB_INSTALLER_ABORT_MOD_INSTALL_NOFILE',
289 JText::_('JLIB_INSTALLER_' . $this->route)
290 )
291 );
292 }
293
294 $this->parent->setPath('extension_root', $basePath . '/modules/' . $this->element);
295 }
296
297 298 299 300 301 302 303 304
305 protected function storeExtension()
306 {
307
308 if ($this->route === 'discover_install')
309 {
310 $manifest_details = JInstaller::parseXMLInstallFile($this->parent->getPath('manifest'));
311
312 $this->extension->manifest_cache = json_encode($manifest_details);
313 $this->extension->state = 0;
314 $this->extension->name = $manifest_details['name'];
315 $this->extension->enabled = 1;
316 $this->extension->params = $this->parent->getParams();
317
318 if (!$this->extension->store())
319 {
320
321 throw new RuntimeException(JText::_('JLIB_INSTALLER_ERROR_MOD_DISCOVER_STORE_DETAILS'));
322 }
323
324 return;
325 }
326
327
328 if ($this->currentExtensionId)
329 {
330 if (!$this->parent->isOverwrite())
331 {
332
333 throw new RuntimeException(
334 JText::sprintf(
335 'JLIB_INSTALLER_ABORT_MOD_INSTALL_ALLREADY_EXISTS',
336 JText::_('JLIB_INSTALLER_' . $this->route),
337 $this->name
338 )
339 );
340 }
341
342
343 $this->extension->load($this->currentExtensionId);
344
345
346 $this->extension->name = $this->name;
347
348
349 $this->extension->manifest_cache = $this->parent->generateManifestCache();
350
351 if (!$this->extension->store())
352 {
353
354 throw new RuntimeException(
355 JText::sprintf(
356 'JLIB_INSTALLER_ABORT_MOD_ROLLBACK',
357 JText::_('JLIB_INSTALLER_' . $this->route),
358 $this->extension->getError()
359 )
360 );
361 }
362 }
363 else
364 {
365 $this->extension->name = $this->name;
366 $this->extension->type = 'module';
367 $this->extension->element = $this->element;
368
369
370 $this->extension->folder = '';
371 $this->extension->enabled = 1;
372 $this->extension->protected = 0;
373 $this->extension->access = $this->clientId == 1 ? 2 : 0;
374 $this->extension->client_id = $this->clientId;
375 $this->extension->params = $this->parent->getParams();
376
377
378 $this->extension->custom_data = '';
379 $this->extension->system_data = '';
380 $this->extension->manifest_cache = $this->parent->generateManifestCache();
381
382 if (!$this->extension->store())
383 {
384
385 throw new RuntimeException(
386 JText::sprintf(
387 'JLIB_INSTALLER_ABORT_MOD_ROLLBACK',
388 JText::_('JLIB_INSTALLER_' . $this->route),
389 $this->extension->getError()
390 )
391 );
392 }
393
394
395
396 $this->parent->pushStep(
397 array(
398 'type' => 'extension',
399 'extension_id' => $this->extension->extension_id,
400 )
401 );
402
403
404 $name = preg_replace('#[\*?]#', '', JText::_($this->name));
405
406
407 $module = JTable::getInstance('module');
408 $module->title = $name;
409 $module->content = '';
410 $module->module = $this->element;
411 $module->access = '1';
412 $module->showtitle = '1';
413 $module->params = '';
414 $module->client_id = $this->clientId;
415 $module->language = '*';
416
417 $module->store();
418 }
419 }
420
421 422 423 424 425 426 427
428 public function discover()
429 {
430 $results = array();
431 $site_list = JFolder::folders(JPATH_SITE . '/modules');
432 $admin_list = JFolder::folders(JPATH_ADMINISTRATOR . '/modules');
433 $site_info = JApplicationHelper::getClientInfo('site', true);
434 $admin_info = JApplicationHelper::getClientInfo('administrator', true);
435
436 foreach ($site_list as $module)
437 {
438 if (file_exists(JPATH_SITE . "/modules/$module/$module.xml"))
439 {
440 $manifest_details = JInstaller::parseXMLInstallFile(JPATH_SITE . "/modules/$module/$module.xml");
441 $extension = JTable::getInstance('extension');
442 $extension->set('type', 'module');
443 $extension->set('client_id', $site_info->id);
444 $extension->set('element', $module);
445 $extension->set('folder', '');
446 $extension->set('name', $module);
447 $extension->set('state', -1);
448 $extension->set('manifest_cache', json_encode($manifest_details));
449 $extension->set('params', '{}');
450 $results[] = clone $extension;
451 }
452 }
453
454 foreach ($admin_list as $module)
455 {
456 if (file_exists(JPATH_ADMINISTRATOR . "/modules/$module/$module.xml"))
457 {
458 $manifest_details = JInstaller::parseXMLInstallFile(JPATH_ADMINISTRATOR . "/modules/$module/$module.xml");
459 $extension = JTable::getInstance('extension');
460 $extension->set('type', 'module');
461 $extension->set('client_id', $admin_info->id);
462 $extension->set('element', $module);
463 $extension->set('folder', '');
464 $extension->set('name', $module);
465 $extension->set('state', -1);
466 $extension->set('manifest_cache', json_encode($manifest_details));
467 $extension->set('params', '{}');
468 $results[] = clone $extension;
469 }
470 }
471
472 return $results;
473 }
474
475 476 477 478 479 480 481
482 public function refreshManifestCache()
483 {
484 $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
485 $manifestPath = $client->path . '/modules/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml';
486 $this->parent->manifest = $this->parent->isManifest($manifestPath);
487 $this->parent->setPath('manifest', $manifestPath);
488 $manifest_details = JInstaller::parseXMLInstallFile($this->parent->getPath('manifest'));
489 $this->parent->extension->manifest_cache = json_encode($manifest_details);
490 $this->parent->extension->name = $manifest_details['name'];
491
492 if ($this->parent->extension->store())
493 {
494 return true;
495 }
496 else
497 {
498 JLog::add(JText::_('JLIB_INSTALLER_ERROR_MOD_REFRESH_MANIFEST_CACHE'), JLog::WARNING, 'jerror');
499
500 return false;
501 }
502 }
503
504 505 506 507 508 509 510 511 512
513 public function uninstall($id)
514 {
515 $retval = true;
516 $db = $this->db;
517
518
519
520 if (!$this->extension->load((int) $id) || $this->extension->element === '')
521 {
522 JLog::add(JText::_('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_ERRORUNKOWNEXTENSION'), JLog::WARNING, 'jerror');
523
524 return false;
525 }
526
527
528
529 if ($this->extension->protected)
530 {
531 JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_WARNCOREMODULE', $this->extension->name), JLog::WARNING, 'jerror');
532
533 return false;
534 }
535
536 537 538 539
540 if ($this->extension->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($this->extension->package_id))
541 {
542 JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $this->extension->name), JLog::WARNING, 'jerror');
543
544 return false;
545 }
546
547
548 $element = $this->extension->element;
549 $client = JApplicationHelper::getClientInfo($this->extension->client_id);
550
551 if ($client === false)
552 {
553 $this->parent->abort(
554 JText::sprintf(
555 'JLIB_INSTALLER_ERROR_MOD_UNINSTALL_UNKNOWN_CLIENT',
556 $this->extension->client_id
557 )
558 );
559
560 return false;
561 }
562
563 $this->parent->setPath('extension_root', $client->path . '/modules/' . $element);
564
565 $this->parent->setPath('source', $this->parent->getPath('extension_root'));
566
567
568
569 $this->parent->findManifest();
570 $this->setManifest($this->parent->getManifest());
571
572
573 $this->loadLanguage(($this->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $element);
574
575
576 $this->scriptElement = $this->getManifest()->scriptfile;
577 $manifestScript = (string) $this->getManifest()->scriptfile;
578
579 if ($manifestScript)
580 {
581 $manifestScriptFile = $this->parent->getPath('extension_root') . '/' . $manifestScript;
582
583
584 $classname = $element . 'InstallerScript';
585
586 JLoader::register($classname, $manifestScriptFile);
587
588 if (class_exists($classname))
589 {
590
591 $this->parent->manifestClass = new $classname($this);
592
593
594 $this->set('manifest_script', $manifestScript);
595 }
596 }
597
598 try
599 {
600 $this->triggerManifestScript('uninstall');
601 }
602 catch (RuntimeException $e)
603 {
604
605 }
606
607 if (!($this->getManifest() instanceof SimpleXMLElement))
608 {
609
610 JFolder::delete($this->parent->getPath('extension_root'));
611 JLog::add(JText::_('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_INVALID_NOTFOUND_MANIFEST'), JLog::WARNING, 'jerror');
612
613 return false;
614 }
615
616
617 try
618 {
619 $this->parseQueries();
620 }
621 catch (RuntimeException $e)
622 {
623
624 JLog::add($e->getMessage(), JLog::WARNING, 'jerror');
625 $retval = false;
626 }
627
628
629 $query = $db->getQuery(true)
630 ->delete('#__schemas')
631 ->where('extension_id = ' . $this->extension->extension_id);
632 $db->setQuery($query);
633 $db->execute();
634
635
636 $this->parent->removeFiles($this->getManifest()->media);
637 $this->parent->removeFiles($this->getManifest()->languages, $this->extension->client_id);
638
639
640 $query->clear()
641 ->select($db->quoteName('id'))
642 ->from($db->quoteName('#__modules'))
643 ->where($db->quoteName('module') . ' = ' . $db->quote($this->extension->element))
644 ->where($db->quoteName('client_id') . ' = ' . (int) $this->extension->client_id);
645 $db->setQuery($query);
646
647 try
648 {
649 $modules = $db->loadColumn();
650 }
651 catch (RuntimeException $e)
652 {
653 $modules = array();
654 }
655
656
657 if (count($modules))
658 {
659
660 $modules = ArrayHelper::toInteger($modules);
661 $modID = implode(',', $modules);
662
663
664 $query = $db->getQuery(true)
665 ->delete($db->quoteName('#__modules_menu'))
666 ->where($db->quoteName('moduleid') . ' IN (' . $modID . ')');
667 $db->setQuery($query);
668
669 try
670 {
671 $db->execute();
672 }
673 catch (RuntimeException $e)
674 {
675 JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_EXCEPTION', $db->stderr(true)), JLog::WARNING, 'jerror');
676 $retval = false;
677 }
678
679
680
681 $module = JTable::getInstance('Module');
682
683 foreach ($modules as $modInstanceId)
684 {
685 $module->load($modInstanceId);
686
687 if (!$module->delete())
688 {
689 JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_EXCEPTION', $module->getError()), JLog::WARNING, 'jerror');
690 $retval = false;
691 }
692 }
693 }
694
695
696 $this->extension->delete($this->extension->extension_id);
697 $query = $db->getQuery(true)
698 ->delete($db->quoteName('#__modules'))
699 ->where($db->quoteName('module') . ' = ' . $db->quote($this->extension->element))
700 ->where($db->quote('client_id') . ' = ' . $this->extension->client_id);
701 $db->setQuery($query);
702
703 try
704 {
705
706 $db->execute();
707 }
708 catch (RuntimeException $e)
709 {
710
711 }
712
713
714 if (!JFolder::delete($this->parent->getPath('extension_root')))
715 {
716
717 $retval = false;
718 }
719
720 return $retval;
721 }
722
723 724 725 726 727 728 729 730 731 732
733 protected function ($arg)
734 {
735
736 $db = $this->parent->getDbo();
737
738
739 $query = $db->getQuery(true)
740 ->delete($db->quoteName('#__modules_menu'))
741 ->where($db->quoteName('moduleid') . ' = ' . (int) $arg['id']);
742 $db->setQuery($query);
743
744 try
745 {
746 return $db->execute();
747 }
748 catch (RuntimeException $e)
749 {
750 return false;
751 }
752 }
753
754 755 756 757 758 759 760 761 762 763
764 protected function _rollback_module($arg)
765 {
766
767 $db = $this->parent->getDbo();
768
769
770 $query = $db->getQuery(true)
771 ->delete($db->quoteName('#__modules'))
772 ->where($db->quoteName('id') . ' = ' . (int) $arg['id']);
773 $db->setQuery($query);
774
775 try
776 {
777 return $db->execute();
778 }
779 catch (RuntimeException $e)
780 {
781 return false;
782 }
783 }
784 }
785
786 787 788 789 790 791 792
793 class JInstallerModule extends JInstallerAdapterModule
794 {
795 }
796