[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\Installer\Adapter; 11 12 use Joomla\CMS\Filesystem\File; 13 use Joomla\CMS\Filesystem\Folder; 14 use Joomla\CMS\Installer\Installer; 15 use Joomla\CMS\Installer\InstallerAdapter; 16 use Joomla\CMS\Installer\Manifest\LibraryManifest; 17 use Joomla\CMS\Language\Text; 18 use Joomla\CMS\Log\Log; 19 use Joomla\CMS\Table\Table; 20 use Joomla\CMS\Table\Update; 21 use Joomla\Database\ParameterType; 22 23 // phpcs:disable PSR1.Files.SideEffects 24 \defined('JPATH_PLATFORM') or die; 25 // phpcs:enable PSR1.Files.SideEffects 26 27 /** 28 * Library installer 29 * 30 * @since 3.1 31 */ 32 class LibraryAdapter extends InstallerAdapter 33 { 34 /** 35 * Method to check if the extension is present in the filesystem, flags the route as update if so 36 * 37 * @return void 38 * 39 * @since 3.4 40 * @throws \RuntimeException 41 */ 42 protected function checkExtensionInFilesystem() 43 { 44 if ($this->currentExtensionId) { 45 // Already installed, can we upgrade? 46 if ($this->parent->isOverwrite() || $this->parent->isUpgrade()) { 47 // We can upgrade, so uninstall the old one 48 49 // We don't want to compromise this instance! 50 $installer = new Installer(); 51 $installer->setDatabase($this->getDatabase()); 52 $installer->setPackageUninstall(true); 53 $installer->uninstall('library', $this->currentExtensionId); 54 55 // Clear the cached data 56 $this->currentExtensionId = null; 57 $this->extension = Table::getInstance('Extension', 'JTable', array('dbo' => $this->getDatabase())); 58 59 // From this point we'll consider this an update 60 $this->setRoute('update'); 61 } else { 62 // Abort the install, no upgrade possible 63 throw new \RuntimeException(Text::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_ALREADY_INSTALLED')); 64 } 65 } 66 } 67 68 /** 69 * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file 70 * 71 * @return void 72 * 73 * @since 3.4 74 * @throws \RuntimeException 75 */ 76 protected function copyBaseFiles() 77 { 78 if ($this->parent->parseFiles($this->getManifest()->files, -1) === false) { 79 throw new \RuntimeException(Text::sprintf('JLIB_INSTALLER_ABORT_LIB_COPY_FILES', $this->element)); 80 } 81 } 82 83 /** 84 * Method to finalise the installation processing 85 * 86 * @return void 87 * 88 * @since 3.4 89 * @throws \RuntimeException 90 */ 91 protected function finaliseInstall() 92 { 93 // Clobber any possible pending updates 94 /** @var Update $update */ 95 $update = Table::getInstance('update'); 96 $uid = $update->find( 97 array( 98 'element' => $this->element, 99 'type' => $this->type, 100 ) 101 ); 102 103 if ($uid) { 104 $update->delete($uid); 105 } 106 107 // Lastly, we will copy the manifest file to its appropriate place. 108 if ($this->route !== 'discover_install') { 109 $manifest = array(); 110 $manifest['src'] = $this->parent->getPath('manifest'); 111 $manifest['dest'] = JPATH_MANIFESTS . '/libraries/' . $this->element . '.xml'; 112 113 $destFolder = \dirname($manifest['dest']); 114 115 if (!is_dir($destFolder) && !@mkdir($destFolder)) { 116 // Install failed, rollback changes 117 throw new \RuntimeException( 118 Text::sprintf( 119 'JLIB_INSTALLER_ABORT_COPY_SETUP', 120 Text::_('JLIB_INSTALLER_' . strtoupper($this->route)) 121 ) 122 ); 123 } 124 125 if (!$this->parent->copyFiles(array($manifest), true)) { 126 // Install failed, rollback changes 127 throw new \RuntimeException( 128 Text::sprintf( 129 'JLIB_INSTALLER_ABORT_COPY_SETUP', 130 Text::_('JLIB_INSTALLER_' . strtoupper($this->route)) 131 ) 132 ); 133 } 134 135 // If there is a manifest script, let's copy it. 136 if ($this->manifest_script) { 137 $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script; 138 $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script; 139 140 if ($this->parent->isOverwrite() || !file_exists($path['dest'])) { 141 if (!$this->parent->copyFiles(array($path))) { 142 // Install failed, rollback changes 143 throw new \RuntimeException( 144 Text::sprintf( 145 'JLIB_INSTALLER_ABORT_MANIFEST', 146 Text::_('JLIB_INSTALLER_' . strtoupper($this->route)) 147 ) 148 ); 149 } 150 } 151 } 152 } 153 } 154 155 /** 156 * Method to finalise the uninstallation processing 157 * 158 * @return boolean 159 * 160 * @since 4.0.0 161 * @throws \RuntimeException 162 */ 163 protected function finaliseUninstall(): bool 164 { 165 $extensionId = $this->extension->extension_id; 166 167 $db = $this->getDatabase(); 168 169 // Remove the schema version 170 $query = $db->getQuery(true) 171 ->delete('#__schemas') 172 ->where('extension_id = :extension_id') 173 ->bind(':extension_id', $extensionId, ParameterType::INTEGER); 174 $db->setQuery($query); 175 $db->execute(); 176 177 // Clobber any possible pending updates 178 $update = Table::getInstance('update'); 179 $uid = $update->find( 180 [ 181 'element' => $this->extension->element, 182 'type' => $this->type, 183 ] 184 ); 185 186 if ($uid) { 187 $update->delete($uid); 188 } 189 190 $this->extension->delete(); 191 192 return true; 193 } 194 195 /** 196 * Get the filtered extension element from the manifest 197 * 198 * @param string $element Optional element name to be converted 199 * 200 * @return string The filtered element 201 * 202 * @since 3.4 203 */ 204 public function getElement($element = null) 205 { 206 if (!$element) { 207 $element = (string) $this->getManifest()->libraryname; 208 } 209 210 return $element; 211 } 212 213 /** 214 * Custom loadLanguage method 215 * 216 * @param string $path The path where to find language files. 217 * 218 * @return void 219 * 220 * @since 3.1 221 */ 222 public function loadLanguage($path = null) 223 { 224 $source = $this->parent->getPath('source'); 225 226 if (!$source) { 227 $this->parent->setPath('source', JPATH_PLATFORM . '/' . $this->getElement()); 228 } 229 230 $extension = 'lib_' . str_replace('/', '_', $this->getElement()); 231 $librarypath = (string) $this->getManifest()->libraryname; 232 $source = $path ?: JPATH_PLATFORM . '/' . $librarypath; 233 234 $this->doLoadLanguage($extension, $source, JPATH_SITE); 235 } 236 237 /** 238 * Method to parse optional tags in the manifest 239 * 240 * @return void 241 * 242 * @since 3.4 243 */ 244 protected function parseOptionalTags() 245 { 246 $this->parent->parseLanguages($this->getManifest()->languages); 247 $this->parent->parseMedia($this->getManifest()->media); 248 } 249 250 /** 251 * Prepares the adapter for a discover_install task 252 * 253 * @return void 254 * 255 * @since 3.4 256 */ 257 public function prepareDiscoverInstall() 258 { 259 $manifestPath = JPATH_MANIFESTS . '/libraries/' . $this->extension->element . '.xml'; 260 $this->parent->manifest = $this->parent->isManifest($manifestPath); 261 $this->parent->setPath('manifest', $manifestPath); 262 $this->setManifest($this->parent->getManifest()); 263 } 264 265 /** 266 * Removes this extension's files 267 * 268 * @return void 269 * 270 * @since 4.0.0 271 * @throws \RuntimeException 272 */ 273 protected function removeExtensionFiles() 274 { 275 $this->parent->removeFiles($this->getManifest()->files, -1); 276 File::delete(JPATH_MANIFESTS . '/libraries/' . $this->extension->element . '.xml'); 277 278 // @todo: Change this so it walked up the path backwards so we clobber multiple empties 279 // If the folder is empty, let's delete it 280 if (Folder::exists($this->parent->getPath('extension_root'))) { 281 if (is_dir($this->parent->getPath('extension_root'))) { 282 $files = Folder::files($this->parent->getPath('extension_root')); 283 284 if (!\count($files)) { 285 Folder::delete($this->parent->getPath('extension_root')); 286 } 287 } 288 } 289 290 $this->parent->removeFiles($this->getManifest()->media); 291 $this->parent->removeFiles($this->getManifest()->languages); 292 293 $elementParts = explode('/', $this->extension->element); 294 295 // Delete empty vendor folders 296 if (2 === \count($elementParts)) { 297 $folders = Folder::folders(JPATH_PLATFORM . '/' . $elementParts[0]); 298 299 if (empty($folders)) { 300 Folder::delete(JPATH_MANIFESTS . '/libraries/' . $elementParts[0]); 301 Folder::delete(JPATH_PLATFORM . '/' . $elementParts[0]); 302 } 303 } 304 } 305 306 /** 307 * Method to do any prechecks and setup the install paths for the extension 308 * 309 * @return void 310 * 311 * @since 3.4 312 * @throws \RuntimeException 313 */ 314 protected function setupInstallPaths() 315 { 316 $group = (string) $this->getManifest()->libraryname; 317 318 if (!$group) { 319 throw new \RuntimeException(Text::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_NOFILE')); 320 } 321 322 // Don't install libraries which would override core folders 323 $restrictedFolders = array('php-encryption', 'phpass', 'src', 'vendor'); 324 325 if (in_array($group, $restrictedFolders)) { 326 throw new \RuntimeException(Text::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_CORE_FOLDER')); 327 } 328 329 $this->parent->setPath('extension_root', JPATH_PLATFORM . '/' . implode(DIRECTORY_SEPARATOR, explode('/', $group))); 330 } 331 332 /** 333 * Method to do any prechecks and setup the uninstall job 334 * 335 * @return void 336 * 337 * @since 4.0.0 338 */ 339 protected function setupUninstall() 340 { 341 $manifestFile = JPATH_MANIFESTS . '/libraries/' . $this->extension->element . '.xml'; 342 343 // Because libraries may not have their own folders we cannot use the standard method of finding an installation manifest 344 if (!file_exists($manifestFile)) { 345 // Remove this row entry since its invalid 346 $this->extension->delete($this->extension->extension_id); 347 348 throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_INVALID_NOTFOUND_MANIFEST')); 349 } 350 351 $manifest = new LibraryManifest($manifestFile); 352 353 // Set the library root path 354 $this->parent->setPath('extension_root', JPATH_PLATFORM . '/' . $manifest->libraryname); 355 356 // Set the source path to the library root, the manifest script may be found 357 $this->parent->setPath('source', $this->parent->getPath('extension_root')); 358 359 $xml = simplexml_load_file($manifestFile); 360 361 // If we cannot load the XML file return null 362 if (!$xml) { 363 throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_LOAD_MANIFEST')); 364 } 365 366 // Check for a valid XML root tag. 367 if ($xml->getName() !== 'extension') { 368 throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_INVALID_MANIFEST')); 369 } 370 371 $this->setManifest($xml); 372 373 // Attempt to load the language file; might have uninstall strings 374 $this->loadLanguage(); 375 } 376 377 /** 378 * Method to store the extension to the database 379 * 380 * @return void 381 * 382 * @since 3.4 383 * @throws \RuntimeException 384 */ 385 protected function storeExtension() 386 { 387 // Discover installs are stored a little differently 388 if ($this->route === 'discover_install') { 389 $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); 390 391 $this->extension->manifest_cache = json_encode($manifest_details); 392 $this->extension->state = 0; 393 $this->extension->name = $manifest_details['name']; 394 $this->extension->enabled = 1; 395 $this->extension->params = $this->parent->getParams(); 396 397 if (!$this->extension->store()) { 398 // Install failed, roll back changes 399 throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_LIB_DISCOVER_STORE_DETAILS')); 400 } 401 402 return; 403 } 404 405 $this->extension->name = $this->name; 406 $this->extension->type = 'library'; 407 $this->extension->element = $this->element; 408 $this->extension->changelogurl = $this->changelogurl; 409 410 // There is no folder for libraries 411 $this->extension->folder = ''; 412 $this->extension->enabled = 1; 413 $this->extension->protected = 0; 414 $this->extension->access = 1; 415 $this->extension->client_id = 0; 416 $this->extension->params = $this->parent->getParams(); 417 418 // Update the manifest cache for the entry 419 $this->extension->manifest_cache = $this->parent->generateManifestCache(); 420 421 if (!$this->extension->store()) { 422 // Install failed, roll back changes 423 throw new \RuntimeException( 424 Text::sprintf( 425 'JLIB_INSTALLER_ABORT_LIB_INSTALL_ROLLBACK', 426 $this->extension->getError() 427 ) 428 ); 429 } 430 431 // Since we have created a library item, we add it to the installation step stack 432 // so that if we have to rollback the changes we can undo it. 433 $this->parent->pushStep(array('type' => 'extension', 'id' => $this->extension->extension_id)); 434 } 435 436 /** 437 * Custom discover method 438 * 439 * @return array Extension list of extensions available 440 * 441 * @since 3.1 442 */ 443 public function discover() 444 { 445 $results = array(); 446 447 $mainFolder = JPATH_MANIFESTS . '/libraries'; 448 $folder = new \RecursiveDirectoryIterator($mainFolder); 449 $iterator = new \RegexIterator( 450 new \RecursiveIteratorIterator($folder), 451 '/\.xml$/i', 452 \RecursiveRegexIterator::GET_MATCH 453 ); 454 455 foreach ($iterator as $file => $pattern) { 456 $element = str_replace(array($mainFolder . DIRECTORY_SEPARATOR, '.xml'), '', $file); 457 $manifestCache = Installer::parseXMLInstallFile($file); 458 459 $extension = Table::getInstance('extension'); 460 $extension->set('type', 'library'); 461 $extension->set('client_id', 0); 462 $extension->set('element', $element); 463 $extension->set('folder', ''); 464 $extension->set('name', $element); 465 $extension->set('state', -1); 466 $extension->set('manifest_cache', json_encode($manifestCache)); 467 $extension->set('params', '{}'); 468 $results[] = $extension; 469 } 470 471 return $results; 472 } 473 474 /** 475 * Refreshes the extension table cache 476 * 477 * @return boolean Result of operation, true if updated, false on failure 478 * 479 * @since 3.1 480 */ 481 public function refreshManifestCache() 482 { 483 // Need to find to find where the XML file is since we don't store this normally 484 $manifestPath = JPATH_MANIFESTS . '/libraries/' . $this->parent->extension->element . '.xml'; 485 $this->parent->manifest = $this->parent->isManifest($manifestPath); 486 $this->parent->setPath('manifest', $manifestPath); 487 488 $manifest_details = Installer::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 try { 493 return $this->parent->extension->store(); 494 } catch (\RuntimeException $e) { 495 Log::add(Text::_('JLIB_INSTALLER_ERROR_LIB_REFRESH_MANIFEST_CACHE'), Log::WARNING, 'jerror'); 496 497 return false; 498 } 499 } 500 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |