[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package Joomla.Administrator 5 * @subpackage com_installer 6 * 7 * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> 8 * @license GNU General Public License version 2 or later; see LICENSE.txt 9 */ 10 11 namespace Joomla\Component\Installer\Administrator\Helper; 12 13 use Exception; 14 use Joomla\CMS\Factory; 15 use Joomla\CMS\HTML\HTMLHelper; 16 use Joomla\CMS\Language\Text; 17 use Joomla\CMS\Object\CMSObject; 18 use Joomla\Database\DatabaseDriver; 19 use Joomla\Database\ParameterType; 20 use SimpleXMLElement; 21 22 // phpcs:disable PSR1.Files.SideEffects 23 \defined('_JEXEC') or die; 24 // phpcs:enable PSR1.Files.SideEffects 25 26 /** 27 * Installer helper. 28 * 29 * @since 1.6 30 */ 31 class InstallerHelper 32 { 33 /** 34 * Get a list of filter options for the extension types. 35 * 36 * @return array An array of \stdClass objects. 37 * 38 * @since 3.0 39 */ 40 public static function getExtensionTypes() 41 { 42 $db = Factory::getDbo(); 43 $query = $db->getQuery(true) 44 ->select('DISTINCT ' . $db->quoteName('type')) 45 ->from($db->quoteName('#__extensions')); 46 $db->setQuery($query); 47 $types = $db->loadColumn(); 48 49 $options = array(); 50 51 foreach ($types as $type) { 52 $options[] = HTMLHelper::_('select.option', $type, Text::_('COM_INSTALLER_TYPE_' . strtoupper($type))); 53 } 54 55 return $options; 56 } 57 58 /** 59 * Get a list of filter options for the extension types. 60 * 61 * @return array An array of \stdClass objects. 62 * 63 * @since 3.0 64 */ 65 public static function getExtensionGroups() 66 { 67 $nofolder = ''; 68 $db = Factory::getDbo(); 69 $query = $db->getQuery(true) 70 ->select('DISTINCT ' . $db->quoteName('folder')) 71 ->from($db->quoteName('#__extensions')) 72 ->where($db->quoteName('folder') . ' != :folder') 73 ->bind(':folder', $nofolder) 74 ->order($db->quoteName('folder')); 75 $db->setQuery($query); 76 $folders = $db->loadColumn(); 77 78 $options = array(); 79 80 foreach ($folders as $folder) { 81 $options[] = HTMLHelper::_('select.option', $folder, $folder); 82 } 83 84 return $options; 85 } 86 87 /** 88 * Get a list of filter options for the application clients. 89 * 90 * @return array An array of \JHtmlOption elements. 91 * 92 * @since 3.5 93 */ 94 public static function getClientOptions() 95 { 96 // Build the filter options. 97 $options = array(); 98 $options[] = HTMLHelper::_('select.option', '0', Text::_('JSITE')); 99 $options[] = HTMLHelper::_('select.option', '1', Text::_('JADMINISTRATOR')); 100 $options[] = HTMLHelper::_('select.option', '3', Text::_('JAPI')); 101 102 return $options; 103 } 104 105 /** 106 * Get a list of filter options for the application statuses. 107 * 108 * @return array An array of \JHtmlOption elements. 109 * 110 * @since 3.5 111 */ 112 public static function getStateOptions() 113 { 114 // Build the filter options. 115 $options = array(); 116 $options[] = HTMLHelper::_('select.option', '0', Text::_('JDISABLED')); 117 $options[] = HTMLHelper::_('select.option', '1', Text::_('JENABLED')); 118 $options[] = HTMLHelper::_('select.option', '2', Text::_('JPROTECTED')); 119 $options[] = HTMLHelper::_('select.option', '3', Text::_('JUNPROTECTED')); 120 121 return $options; 122 } 123 124 /** 125 * Get a list of filter options for extensions of the "package" type. 126 * 127 * @return array 128 * @since 4.2.0 129 */ 130 public static function getPackageOptions(): array 131 { 132 $options = []; 133 134 /** @var DatabaseDriver $db The application's database driver object */ 135 $db = Factory::getContainer()->get(DatabaseDriver::class); 136 $query = $db->getQuery(true) 137 ->select( 138 $db->quoteName( 139 [ 140 'extension_id', 141 'name', 142 'element', 143 ] 144 ) 145 ) 146 ->from($db->quoteName('#__extensions')) 147 ->where($db->quoteName('type') . ' = ' . $db->quote('package')); 148 $extensions = $db->setQuery($query)->loadObjectList() ?: []; 149 150 if (empty($extensions)) { 151 return $options; 152 } 153 154 $language = Factory::getApplication()->getLanguage(); 155 $arrayKeys = array_map( 156 function (object $entry) use ($language): string { 157 $language->load($entry->element, JPATH_ADMINISTRATOR); 158 159 return Text::_($entry->name); 160 }, 161 $extensions 162 ); 163 $arrayValues = array_map( 164 function (object $entry): int { 165 return $entry->extension_id; 166 }, 167 $extensions 168 ); 169 170 $extensions = array_combine($arrayKeys, $arrayValues); 171 ksort($extensions); 172 173 foreach ($extensions as $label => $id) { 174 $options[] = HTMLHelper::_('select.option', $id, $label); 175 } 176 177 return $options; 178 } 179 180 /** 181 * Get a list of filter options for the application statuses. 182 * 183 * @param string $element element of an extension 184 * @param string $type type of an extension 185 * @param integer $clientId client_id of an extension 186 * @param string $folder folder of an extension 187 * 188 * @return SimpleXMLElement 189 * 190 * @since 4.0.0 191 */ 192 public static function getInstallationXML( 193 string $element, 194 string $type, 195 int $clientId = 1, 196 ?string $folder = null 197 ): ?SimpleXMLElement { 198 $path = [0 => JPATH_SITE, 1 => JPATH_ADMINISTRATOR, 3 => JPATH_API][$clientId] ?? JPATH_SITE; 199 200 switch ($type) { 201 case 'component': 202 $path .= '/components/' . $element . '/' . substr($element, 4) . '.xml'; 203 break; 204 case 'plugin': 205 $path .= '/plugins/' . $folder . '/' . $element . '/' . $element . '.xml'; 206 break; 207 case 'module': 208 $path .= '/modules/' . $element . '/' . $element . '.xml'; 209 break; 210 case 'template': 211 $path .= '/templates/' . $element . '/templateDetails.xml'; 212 break; 213 case 'library': 214 $path = JPATH_ADMINISTRATOR . '/manifests/libraries/' . $element . '.xml'; 215 break; 216 case 'file': 217 $path = JPATH_ADMINISTRATOR . '/manifests/files/' . $element . '.xml'; 218 break; 219 case 'package': 220 $path = JPATH_ADMINISTRATOR . '/manifests/packages/' . $element . '.xml'; 221 break; 222 case 'language': 223 $path .= '/language/' . $element . '/install.xml'; 224 } 225 226 if (file_exists($path) === false) { 227 return null; 228 } 229 230 $xmlElement = simplexml_load_file($path); 231 232 return ($xmlElement !== false) ? $xmlElement : null; 233 } 234 235 /** 236 * Get the download key of an extension going through their installation xml 237 * 238 * @param CMSObject $extension element of an extension 239 * 240 * @return array An array with the prefix, suffix and value of the download key 241 * 242 * @since 4.0.0 243 */ 244 public static function getDownloadKey(CMSObject $extension): array 245 { 246 $installXmlFile = self::getInstallationXML( 247 $extension->get('element'), 248 $extension->get('type'), 249 $extension->get('client_id'), 250 $extension->get('folder') 251 ); 252 253 if (!$installXmlFile) { 254 return [ 255 'supported' => false, 256 'valid' => false, 257 ]; 258 } 259 260 if (!isset($installXmlFile->dlid)) { 261 return [ 262 'supported' => false, 263 'valid' => false, 264 ]; 265 } 266 267 $prefix = (string) $installXmlFile->dlid['prefix']; 268 $suffix = (string) $installXmlFile->dlid['suffix']; 269 $value = substr($extension->get('extra_query'), strlen($prefix)); 270 271 if ($suffix) { 272 $value = substr($value, 0, -strlen($suffix)); 273 } 274 275 $downloadKey = [ 276 'supported' => true, 277 'valid' => $value ? true : false, 278 'prefix' => $prefix, 279 'suffix' => $suffix, 280 'value' => $value 281 ]; 282 283 return $downloadKey; 284 } 285 286 /** 287 * Get the download key of an extension given enough information to locate it in the #__extensions table 288 * 289 * @param string $element Name of the extension, e.g. com_foo 290 * @param string $type The type of the extension, e.g. component 291 * @param int $clientId [optional] Joomla client for the extension, see the #__extensions table 292 * @param string|null $folder Extension folder, only applies for 'plugin' type 293 * 294 * @return array 295 * 296 * @since 4.0.0 297 */ 298 public static function getExtensionDownloadKey( 299 string $element, 300 string $type, 301 int $clientId = 1, 302 ?string $folder = null 303 ): array { 304 // Get the database driver. If it fails we cannot report whether the extension supports download keys. 305 try { 306 $db = Factory::getDbo(); 307 } catch (Exception $e) { 308 return [ 309 'supported' => false, 310 'valid' => false, 311 ]; 312 } 313 314 // Try to retrieve the extension information as a CMSObject 315 $query = $db->getQuery(true) 316 ->select($db->quoteName('extension_id')) 317 ->from($db->quoteName('#__extensions')) 318 ->where($db->quoteName('type') . ' = :type') 319 ->where($db->quoteName('element') . ' = :element') 320 ->where($db->quoteName('folder') . ' = :folder') 321 ->where($db->quoteName('client_id') . ' = :client_id'); 322 $query->bind(':type', $type, ParameterType::STRING); 323 $query->bind(':element', $element, ParameterType::STRING); 324 $query->bind(':client_id', $clientId, ParameterType::INTEGER); 325 $query->bind(':folder', $folder, ParameterType::STRING); 326 327 try { 328 $extension = new CMSObject($db->setQuery($query)->loadAssoc()); 329 } catch (Exception $e) { 330 return [ 331 'supported' => false, 332 'valid' => false, 333 ]; 334 } 335 336 // Use the getDownloadKey() method to return the download key information 337 return self::getDownloadKey($extension); 338 } 339 340 /** 341 * Returns a list of update site IDs which support download keys. By default this returns all qualifying update 342 * sites, even if they are not enabled. 343 * 344 * 345 * @param bool $onlyEnabled [optional] Set true to only returned enabled update sites. 346 * 347 * @return int[] 348 * @since 4.0.0 349 */ 350 public static function getDownloadKeySupportedSites($onlyEnabled = false): array 351 { 352 /** 353 * NOTE: The closures are not inlined because in this case the Joomla Code Style standard produces two mutually 354 * exclusive errors, making the file impossible to commit. Using closures in variables makes the code less 355 * readable but works around that issue. 356 */ 357 358 $extensions = self::getUpdateSitesInformation($onlyEnabled); 359 360 $filterClosure = function (CMSObject $extension) { 361 $dlidInfo = self::getDownloadKey($extension); 362 363 return $dlidInfo['supported']; 364 }; 365 $extensions = array_filter($extensions, $filterClosure); 366 367 $mapClosure = function (CMSObject $extension) { 368 return $extension->get('update_site_id'); 369 }; 370 371 return array_map($mapClosure, $extensions); 372 } 373 374 /** 375 * Returns a list of update site IDs which are missing download keys. By default this returns all qualifying update 376 * sites, even if they are not enabled. 377 * 378 * @param bool $exists [optional] If true, returns update sites with a valid download key. When false, 379 * returns update sites with an invalid / missing download key. 380 * @param bool $onlyEnabled [optional] Set true to only returned enabled update sites. 381 * 382 * @return int[] 383 * @since 4.0.0 384 */ 385 public static function getDownloadKeyExistsSites(bool $exists = true, $onlyEnabled = false): array 386 { 387 /** 388 * NOTE: The closures are not inlined because in this case the Joomla Code Style standard produces two mutually 389 * exclusive errors, making the file impossible to commit. Using closures in variables makes the code less 390 * readable but works around that issue. 391 */ 392 393 $extensions = self::getUpdateSitesInformation($onlyEnabled); 394 395 // Filter the extensions by what supports Download Keys 396 $filterClosure = function (CMSObject $extension) use ($exists) { 397 $dlidInfo = self::getDownloadKey($extension); 398 399 if (!$dlidInfo['supported']) { 400 return false; 401 } 402 403 return $exists ? $dlidInfo['valid'] : !$dlidInfo['valid']; 404 }; 405 $extensions = array_filter($extensions, $filterClosure); 406 407 // Return only the update site IDs 408 $mapClosure = function (CMSObject $extension) { 409 return $extension->get('update_site_id'); 410 }; 411 412 return array_map($mapClosure, $extensions); 413 } 414 415 416 /** 417 * Get information about the update sites 418 * 419 * @param bool $onlyEnabled Only return enabled update sites 420 * 421 * @return CMSObject[] List of update site and linked extension information 422 * @since 4.0.0 423 */ 424 protected static function getUpdateSitesInformation(bool $onlyEnabled): array 425 { 426 try { 427 $db = Factory::getDbo(); 428 } catch (Exception $e) { 429 return []; 430 } 431 432 $query = $db->getQuery(true) 433 ->select( 434 $db->quoteName( 435 [ 436 's.update_site_id', 437 's.enabled', 438 's.extra_query', 439 'e.extension_id', 440 'e.type', 441 'e.element', 442 'e.folder', 443 'e.client_id', 444 'e.manifest_cache', 445 ], 446 [ 447 'update_site_id', 448 'enabled', 449 'extra_query', 450 'extension_id', 451 'type', 452 'element', 453 'folder', 454 'client_id', 455 'manifest_cache', 456 ] 457 ) 458 ) 459 ->from($db->quoteName('#__update_sites', 's')) 460 ->innerJoin( 461 $db->quoteName('#__update_sites_extensions', 'se'), 462 $db->quoteName('se.update_site_id') . ' = ' . $db->quoteName('s.update_site_id') 463 ) 464 ->innerJoin( 465 $db->quoteName('#__extensions', 'e'), 466 $db->quoteName('e.extension_id') . ' = ' . $db->quoteName('se.extension_id') 467 ) 468 ->where($db->quoteName('state') . ' = 0'); 469 470 if ($onlyEnabled) { 471 $enabled = 1; 472 $query->where($db->quoteName('s.enabled') . ' = :enabled') 473 ->bind(':enabled', $enabled, ParameterType::INTEGER); 474 } 475 476 // Try to get all of the update sites, including related extension information 477 try { 478 $items = []; 479 $db->setQuery($query); 480 481 foreach ($db->getIterator() as $item) { 482 $items[] = new CMSObject($item); 483 } 484 485 return $items; 486 } catch (Exception $e) { 487 return []; 488 } 489 } 490 }
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 |