vanilla /
garden
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * @author Todd Burry <[email protected]> |
||
| 4 | * @copyright 2009-2014 Vanilla Forums Inc. |
||
| 5 | * @license MIT |
||
| 6 | */ |
||
| 7 | |||
| 8 | namespace Garden; |
||
| 9 | |||
| 10 | /** |
||
| 11 | * Contains functionality that allows addons to enhance or change an application's functionality. |
||
| 12 | * |
||
| 13 | * An addon can do the following. |
||
| 14 | * |
||
| 15 | * 1. Any classes that the addon defines in its root, /controllers, /library, /models, and /modules |
||
| 16 | * directories are made available. |
||
| 17 | * 2. The addon can contain a bootstrap.php which will be included at the app startup. |
||
| 18 | * 3. If the addon declares any classes ending in *Plugin then those plugins will automatically |
||
| 19 | * bind their event handlers. (also *Hooks) |
||
| 20 | */ |
||
| 21 | class Addons { |
||
| 22 | /// Constants /// |
||
| 23 | const K_BOOTSTRAP = 'bootstrap'; // bootstrap path key |
||
| 24 | const K_CLASSES = 'classes'; |
||
| 25 | const K_DIR = 'dir'; |
||
| 26 | const K_INFO = 'info'; // addon info key |
||
| 27 | |||
| 28 | /// Properties /// |
||
| 29 | |||
| 30 | /** |
||
| 31 | * @var array An array that maps addon keys to full addon information. |
||
| 32 | */ |
||
| 33 | protected static $all; |
||
| 34 | |||
| 35 | /** |
||
| 36 | * @var string The base directory where all of the addons are found. |
||
| 37 | */ |
||
| 38 | protected static $baseDir; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * @var array An array that maps class names to their fully namespaced class names. |
||
| 42 | */ |
||
| 43 | // protected static $basenameMap; |
||
| 44 | |||
| 45 | /** |
||
| 46 | * @var array|null An array that maps class names to file paths. |
||
| 47 | */ |
||
| 48 | protected static $classMap; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * @var array An array that maps addon keys to full addon information for enabled addons. |
||
| 52 | */ |
||
| 53 | protected static $enabled; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * @var array An array of enabled addon keys. |
||
| 57 | */ |
||
| 58 | protected static $enabledKeys; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * @var bool Signals that the addon framework is in a shared environment and shouldn't use the enabled cache. |
||
| 62 | */ |
||
| 63 | public static $sharedEnvironment; |
||
| 64 | |||
| 65 | /// Methods /// |
||
| 66 | |||
| 67 | /** |
||
| 68 | * Get all of the available addons or a single addon from the available list. |
||
| 69 | * |
||
| 70 | * @param string $addon_key If you supply an addon key then only that addon will be returned. |
||
| 71 | * @param string $key Supply one of the Addons::K_* constants to get a specific key from the addon. |
||
| 72 | * @return array Returns the addon with the given key or all available addons if no key is passed. |
||
| 73 | */ |
||
| 74 | public static function all($addon_key = null, $key = null) { |
||
| 75 | if (self::$all === null) { |
||
| 76 | self::$all = static::cacheGet('addons-all', array(get_class(), 'scanAddons')); |
||
| 77 | } |
||
| 78 | |||
| 79 | // The array should be built now return the addon. |
||
| 80 | View Code Duplication | if ($addon_key === null) { |
|
| 81 | return self::$all; |
||
| 82 | } else { |
||
| 83 | $addon = val(strtolower($addon_key), self::$all); |
||
| 84 | if ($addon && $key) { |
||
| 85 | return val($key, $addon); |
||
| 86 | } elseif ($addon) { |
||
| 87 | return $addon; |
||
| 88 | } else { |
||
| 89 | return null; |
||
| 90 | } |
||
| 91 | } |
||
| 92 | } |
||
| 93 | |||
| 94 | /** |
||
| 95 | * An autoloader that will autoload a class based on which addons are enabled. |
||
| 96 | * |
||
| 97 | * @param string $classname The name of the class to load. |
||
| 98 | */ |
||
| 99 | 6 | public static function autoload($classname) { |
|
| 100 | 6 | list($fullClass, $path) = static::classMap($classname); |
|
| 101 | 6 | if ($path) { |
|
| 102 | 4 | require $path; |
|
| 103 | 4 | } |
|
| 104 | 6 | } |
|
| 105 | |||
| 106 | /** |
||
| 107 | * Gets/sets the base directory for addons. |
||
| 108 | * |
||
| 109 | * @param string $value Pass a value to set the new base directory. |
||
| 110 | * @return string Returns the base directory for addons. |
||
| 111 | */ |
||
| 112 | 34 | public static function baseDir($value = null) { |
|
| 113 | 34 | if ($value !== null) { |
|
| 114 | 34 | self::$baseDir = rtrim($value, '/'); |
|
| 115 | 34 | } elseif (self::$baseDir === null) { |
|
| 116 | self::$baseDir = PATH_ROOT.'/addons'; |
||
| 117 | } |
||
| 118 | 34 | } |
|
| 119 | |||
| 120 | |||
| 121 | /** |
||
| 122 | * Start up the addon framework. |
||
| 123 | * |
||
| 124 | * @param array $enabled_addons An array of enabled addons. |
||
| 125 | */ |
||
| 126 | 34 | public static function bootstrap($enabled_addons = null) { |
|
| 127 | // Load the addons from the config if they aren't passed in. |
||
| 128 | 34 | if (!is_array($enabled_addons)) { |
|
| 129 | $enabled_addons = config('addons', array()); |
||
| 130 | } |
||
| 131 | // Reformat the enabled array into the form: array('addon_key' => 'addon_key') |
||
| 132 | 34 | $enabled_keys = array_keys(array_change_key_case(array_filter($enabled_addons))); |
|
| 133 | 34 | $enabled_keys = array_combine($enabled_keys, $enabled_keys); |
|
| 134 | 34 | self::$enabledKeys = $enabled_keys; |
|
| 135 | 34 | self::$classMap = null; // invalidate so it will rebuild |
|
| 136 | |||
| 137 | // Enable the addon autoloader. |
||
| 138 | 34 | spl_autoload_register(array(get_class(), 'autoload'), true, true); |
|
| 139 | |||
| 140 | // Bind all of the addon plugin events now. |
||
| 141 | 34 | foreach (self::enabled() as $addon) { |
|
| 142 | 34 | if (!isset($addon[self::K_CLASSES])) { |
|
| 143 | continue; |
||
| 144 | } |
||
| 145 | |||
| 146 | 34 | foreach ($addon[self::K_CLASSES] as $class_name => $class_path) { |
|
| 147 | 34 | if (str_ends($class_name, 'plugin')) { |
|
| 148 | Event::bindClass($class_name); |
||
| 149 | 34 | } elseif (str_ends($class_name, 'hooks')) { |
|
| 150 | // Vanilla 2 used hooks files for themes and applications. |
||
| 151 | $basename = ucfirst(rtrim_substr($class_name, 'hooks')); |
||
| 152 | deprecated($basename.'Hooks', $basename.'Plugin'); |
||
| 153 | Event::bindClass($class_name); |
||
| 154 | } |
||
| 155 | 34 | } |
|
| 156 | 34 | } |
|
| 157 | |||
| 158 | Event::bind('bootstrap', function () { |
||
| 159 | // Start each of the enabled addons. |
||
| 160 | 34 | foreach (self::enabled() as $key => $value) { |
|
| 161 | 34 | static::startAddon($key); |
|
| 162 | 34 | } |
|
| 163 | 34 | }); |
|
| 164 | 34 | } |
|
| 165 | |||
| 166 | /** |
||
| 167 | * Get the cached file or hydrate the cache with a callback. |
||
| 168 | * |
||
| 169 | * @param string $key The cache key to get. |
||
| 170 | * @param callable $cache_cb The function to run when hydrating the cache. |
||
| 171 | * @return array Returns the cached array. |
||
| 172 | */ |
||
| 173 | 1 | protected static function cacheGet($key, callable $cache_cb) { |
|
| 174 | // Salt the cache with the root path so that it will invalidate if the app is moved. |
||
| 175 | 1 | $salt = substr(md5(static::baseDir()), 0, 10); |
|
| 176 | |||
| 177 | 1 | $cache_path = PATH_ROOT."/cache/$key-$salt.json.php"; |
|
| 178 | 1 | if (file_exists($cache_path)) { |
|
| 179 | $result = array_load($cache_path); |
||
| 180 | return $result; |
||
| 181 | } else { |
||
| 182 | 1 | $result = $cache_cb(); |
|
| 183 | 1 | array_save($result, $cache_path); |
|
| 184 | } |
||
| 185 | 1 | return $result; |
|
| 186 | } |
||
| 187 | |||
| 188 | /** |
||
| 189 | * A an array that maps class names to physical paths. |
||
| 190 | * |
||
| 191 | * @param string $classname An optional class name to get the path of. |
||
| 192 | * @return array Returns an array in the form `[fullClassname, classPath]`. |
||
| 193 | * If no {@link $classname} is passed then the entire class map is returned. |
||
| 194 | * @throws \Exception Throws an exception if the class map is corrupt. |
||
| 195 | */ |
||
| 196 | 36 | public static function classMap($classname = null) { |
|
| 197 | 36 | if (self::$classMap === null) { |
|
| 198 | // Loop through the enabled addons and grab their classes. |
||
| 199 | 34 | $class_map = array(); |
|
| 200 | 34 | foreach (static::enabled() as $addon) { |
|
| 201 | 34 | if (isset($addon[self::K_CLASSES])) { |
|
| 202 | 34 | $class_map = array_replace($class_map, $addon[self::K_CLASSES]); |
|
| 203 | 34 | } |
|
| 204 | 34 | } |
|
| 205 | 34 | self::$classMap = $class_map; |
|
| 206 | 34 | } |
|
| 207 | |||
| 208 | // Now that the class map has been built return the result. |
||
| 209 | 36 | if ($classname !== null) { |
|
| 210 | 36 | if (strpos($classname, '\\') === false) { |
|
| 211 | 34 | $basename = strtolower($classname); |
|
| 212 | 34 | } else { |
|
| 213 | 3 | $basename = strtolower(trim(strrchr($classname, '\\'), '\\')); |
|
| 214 | } |
||
| 215 | |||
| 216 | 36 | $row = val($basename, self::$classMap); |
|
| 217 | |||
| 218 | 36 | if ($row === null) { |
|
| 219 | 3 | return ['', '']; |
|
| 220 | 34 | } elseif (is_string($row)) { |
|
| 221 | return [$classname, $row]; |
||
| 222 | 34 | } elseif (is_array($row)) { |
|
| 223 | 34 | return $row; |
|
| 224 | } else { |
||
| 225 | return ['', '']; |
||
| 226 | } |
||
| 227 | } else { |
||
| 228 | return self::$classMap; |
||
| 229 | } |
||
| 230 | } |
||
| 231 | |||
| 232 | /** |
||
| 233 | * Get all of the enabled addons or a single addon from the enabled list. |
||
| 234 | * |
||
| 235 | * @param string $addon_key If you supply an addon key then only that addon will be returned. |
||
| 236 | * @param string $key Supply one of the Addons::K_* constants to get a specific key from the addon. |
||
| 237 | * @return array Returns the addon with the given key or all enabled addons if no key is passed. |
||
| 238 | * @throws \Exception Throws an exception if {@link Addons::bootstrap()} hasn't been called yet. |
||
| 239 | */ |
||
| 240 | 34 | public static function enabled($addon_key = null, $key = null) { |
|
| 241 | // Lazy build the enabled array. |
||
| 242 | 34 | if (self::$enabled === null) { |
|
| 243 | // Make sure the enabled addons have been added first. |
||
| 244 | 1 | if (self::$enabledKeys === null) { |
|
| 245 | throw new \Exception("Addons::boostrap() must be called before Addons::enabled() can be called.", 500); |
||
| 246 | } |
||
| 247 | |||
| 248 | 1 | if (self::$all !== null || self::$sharedEnvironment) { |
|
| 249 | // Build the enabled array by filtering the all array. |
||
| 250 | self::$enabled = array(); |
||
| 251 | foreach (self::all() as $key => $row) { |
||
| 252 | if (isset($key, self::$enabledKeys)) { |
||
| 253 | self::$enabled[$key] = $row; |
||
| 254 | } |
||
| 255 | } |
||
| 256 | } else { |
||
| 257 | // Build the enabled array by walking the addons. |
||
| 258 | 1 | self::$enabled = static::cacheGet('addons-enabled', function () { |
|
| 259 | 1 | return static::scanAddons(null, self::$enabledKeys); |
|
| 260 | 1 | }); |
|
| 261 | } |
||
| 262 | 1 | } |
|
| 263 | |||
| 264 | // The array should be built now return the addon. |
||
| 265 | 34 | View Code Duplication | if ($addon_key === null) { |
| 266 | 34 | return self::$enabled; |
|
| 267 | } else { |
||
| 268 | 34 | $addon = val(strtolower($addon_key), self::$enabled); |
|
| 269 | 34 | if ($addon && $key) { |
|
| 270 | return val($key, $addon); |
||
| 271 | 34 | } elseif ($addon) { |
|
| 272 | 34 | return $addon; |
|
| 273 | } else { |
||
| 274 | return null; |
||
| 275 | } |
||
| 276 | } |
||
| 277 | } |
||
| 278 | |||
| 279 | /** |
||
| 280 | * Return the info array for an addon. |
||
| 281 | * |
||
| 282 | * @param string $addon_key The addon key. |
||
| 283 | * @return array|null Returns the addon's info array or null if the addon wasn't found. |
||
| 284 | */ |
||
| 285 | public static function info($addon_key) { |
||
| 286 | $addon_key = strtolower($addon_key); |
||
| 287 | |||
| 288 | // Check the enabled array first so that we don't load all addons if we don't have to. |
||
| 289 | if (isset(self::$enabledKeys[$addon_key])) { |
||
| 290 | return static::enabled($addon_key, self::K_INFO); |
||
| 291 | } else { |
||
| 292 | return static::all($addon_key, self::K_INFO); |
||
| 293 | } |
||
| 294 | } |
||
| 295 | |||
| 296 | /** |
||
| 297 | * Scan an addon directory for information. |
||
| 298 | * |
||
| 299 | * @param string $dir The addon directory to scan. |
||
| 300 | * @param array &$addons The addons array. |
||
| 301 | * @param array $enabled An array of enabled addons or null to scan all addons. |
||
| 302 | * @return array Returns an array in the form [addonKey, addonInfo]. |
||
| 303 | */ |
||
| 304 | 1 | protected static function scanAddonRecursive($dir, &$addons, $enabled = null) { |
|
| 305 | 1 | $dir = rtrim($dir, '/'); |
|
| 306 | 1 | $addonKey = strtolower(basename($dir)); |
|
| 307 | |||
| 308 | // Scan the addon if it is enabled. |
||
| 309 | 1 | if ($enabled === null || in_array($addonKey, $enabled)) { |
|
| 310 | 1 | list($addonKey, $addon) = static::scanAddon($dir); |
|
| 311 | 1 | } else { |
|
| 312 | $addon = null; |
||
| 313 | } |
||
| 314 | |||
| 315 | // Add the addon to the collection array if one was supplied. |
||
| 316 | 1 | if ($addon !== null) { |
|
| 317 | 1 | $addons[$addonKey] = $addon; |
|
| 318 | 1 | } |
|
| 319 | |||
| 320 | // Recurse. |
||
| 321 | 1 | $addon_subdirs = array('/addons'); |
|
| 322 | 1 | foreach ($addon_subdirs as $addon_subdir) { |
|
| 323 | 1 | if (is_dir($dir.$addon_subdir)) { |
|
| 324 | static::scanAddons($dir.$addon_subdir, $enabled, $addons); |
||
| 325 | } |
||
| 326 | 1 | } |
|
| 327 | |||
| 328 | 1 | return array($addonKey, $addon); |
|
| 329 | } |
||
| 330 | |||
| 331 | /** |
||
| 332 | * Scan an individual addon directory and return the information about that addon. |
||
| 333 | * |
||
| 334 | * @param string $dir The path to the addon. |
||
| 335 | * @return array An array in the form of `[$addon_key, $addon_row]` or `[$addon_key, null]` if the directory doesn't |
||
| 336 | * represent an addon. |
||
| 337 | */ |
||
| 338 | 1 | protected static function scanAddon($dir) { |
|
| 339 | 1 | $dir = rtrim($dir, '/'); |
|
| 340 | 1 | $addon_key = strtolower(basename($dir)); |
|
| 341 | |||
| 342 | // Look for the addon info array. |
||
| 343 | 1 | $info_path = $dir.'/addon.json'; |
|
| 344 | 1 | $info = false; |
|
| 345 | 1 | if (file_exists($info_path)) { |
|
| 346 | 1 | $info = json_decode(file_get_contents($info_path), true); |
|
| 347 | 1 | } |
|
| 348 | 1 | if (!$info) { |
|
| 349 | $info = array(); |
||
| 350 | } |
||
| 351 | 1 | array_touch('name', $info, $addon_key); |
|
| 352 | 1 | array_touch('version', $info, '0.0'); |
|
| 353 | |||
| 354 | // Look for the bootstrap. |
||
| 355 | 1 | $bootstrap = $dir.'/bootstrap.php'; |
|
| 356 | 1 | if (!file_exists($dir.'/bootstrap.php')) { |
|
| 357 | 1 | $bootstrap = null; |
|
| 358 | 1 | } |
|
| 359 | |||
| 360 | // Scan the appropriate subdirectories for classes. |
||
| 361 | 1 | $subdirs = array('', '/library', '/controllers', '/models', '/modules', '/settings'); |
|
| 362 | 1 | $classes = array(); |
|
| 363 | 1 | foreach ($subdirs as $subdir) { |
|
| 364 | // Get all of the php files in the subdirectory. |
||
| 365 | 1 | $paths = glob($dir.$subdir.'/*.php'); |
|
| 366 | 1 | foreach ($paths as $path) { |
|
| 367 | 1 | $decls = static::scanFile($path); |
|
| 368 | 1 | foreach ($decls as $namespace_row) { |
|
| 369 | 1 | if (isset($namespace_row['namespace']) && $namespace_row) { |
|
| 370 | $namespace = rtrim($namespace_row['namespace'], '\\').'\\'; |
||
| 371 | $namespace_classes = $namespace_row['classes']; |
||
| 372 | } else { |
||
| 373 | 1 | $namespace = ''; |
|
| 374 | 1 | $namespace_classes = $namespace_row; |
|
| 375 | } |
||
| 376 | |||
| 377 | 1 | foreach ($namespace_classes as $class_row) { |
|
| 378 | 1 | $classes[strtolower($class_row['name'])] = [$namespace.$class_row['name'], $path]; |
|
| 379 | 1 | } |
|
| 380 | 1 | } |
|
| 381 | 1 | } |
|
| 382 | 1 | } |
|
| 383 | |||
| 384 | $addon = array( |
||
| 385 | 1 | self::K_BOOTSTRAP => $bootstrap, |
|
| 386 | 1 | self::K_CLASSES => $classes, |
|
| 387 | 1 | self::K_DIR => $dir, |
|
| 388 | 1 | self::K_INFO => $info |
|
| 389 | 1 | ); |
|
| 390 | |||
| 391 | 1 | return array($addon_key, $addon); |
|
| 392 | } |
||
| 393 | |||
| 394 | /** |
||
| 395 | * Scan a directory for addons. |
||
| 396 | * |
||
| 397 | * @param string $dir The directory to scan. |
||
| 398 | * @param array $enabled An array of enabled addons in the form `[addonKey => enabled, ...]`. |
||
| 399 | * @param array &$addons The addons will fill this array. |
||
| 400 | * @return array Returns all of the addons. |
||
| 401 | */ |
||
| 402 | 1 | protected static function scanAddons($dir = null, $enabled = null, &$addons = null) { |
|
| 403 | 1 | if (!$dir) { |
|
| 404 | 1 | $dir = static::$baseDir; |
|
| 405 | 1 | } |
|
| 406 | 1 | if ($addons === null) { |
|
| 407 | 1 | $addons = array(); |
|
| 408 | 1 | } |
|
| 409 | |||
| 410 | /* @var \DirectoryIterator */ |
||
| 411 | 1 | foreach (new \DirectoryIterator($dir) as $subdir) { |
|
| 412 | 1 | if ($subdir->isDir() && !$subdir->isDot()) { |
|
| 413 | // echo $subdir->getPathname().$subdir->isDir().$subdir->isDot().'<br />'; |
||
| 414 | 1 | static::scanAddonRecursive($subdir->getPathname(), $addons, $enabled); |
|
| 415 | 1 | } |
|
| 416 | 1 | } |
|
| 417 | 1 | return $addons; |
|
| 418 | } |
||
| 419 | |||
| 420 | /** |
||
| 421 | * Looks what classes and namespaces are defined in a file and returns the first found. |
||
| 422 | * |
||
| 423 | * @param string $file Path to file. |
||
| 424 | * @return array Returns an empty array if no classes are found or an array with namespaces and |
||
| 425 | * classes found in the file. |
||
| 426 | * @see http://stackoverflow.com/a/11114724/1984219 |
||
| 427 | */ |
||
| 428 | 1 | protected static function scanFile($file) { |
|
| 429 | 1 | $classes = $nsPos = $final = array(); |
|
| 430 | 1 | $foundNamespace = false; |
|
| 431 | 1 | $ii = 0; |
|
| 432 | |||
| 433 | 1 | if (!file_exists($file)) { |
|
| 434 | return array(); |
||
| 435 | } |
||
| 436 | |||
| 437 | 1 | $er = error_reporting(); |
|
| 438 | 1 | error_reporting(E_ALL ^ E_NOTICE); |
|
| 439 | |||
| 440 | 1 | $php_code = file_get_contents($file); |
|
| 441 | 1 | $tokens = token_get_all($php_code); |
|
| 442 | 1 | $count = count($tokens); |
|
| 443 | |||
| 444 | 1 | for ($i = 0; $i < $count; $i++) { |
|
| 445 | 1 | if (!$foundNamespace && $tokens[$i][0] == T_NAMESPACE) { |
|
| 446 | $nsPos[$ii]['start'] = $i; |
||
| 447 | $foundNamespace = true; |
||
| 448 | 1 | } elseif ($foundNamespace && ($tokens[$i] == ';' || $tokens[$i] == '{')) { |
|
| 449 | $nsPos[$ii]['end'] = $i; |
||
| 450 | $ii++; |
||
| 451 | $foundNamespace = false; |
||
| 452 | 1 | } elseif ($i - 2 >= 0 && $tokens[$i - 2][0] == T_CLASS && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING) { |
|
| 453 | 1 | if ($i - 4 >= 0 && $tokens[$i - 4][0] == T_ABSTRACT) { |
|
| 454 | $classes[$ii][] = array('name' => $tokens[$i][1], 'type' => 'ABSTRACT CLASS'); |
||
| 455 | } else { |
||
| 456 | 1 | $classes[$ii][] = array('name' => $tokens[$i][1], 'type' => 'CLASS'); |
|
| 457 | } |
||
| 458 | 1 | } elseif ($i - 2 >= 0 && $tokens[$i - 2][0] == T_INTERFACE && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING) { |
|
| 459 | $classes[$ii][] = array('name' => $tokens[$i][1], 'type' => 'INTERFACE'); |
||
| 460 | } |
||
| 461 | 1 | } |
|
| 462 | 1 | error_reporting($er); |
|
| 463 | 1 | if (empty($classes)) { |
|
| 464 | return []; |
||
| 465 | } |
||
| 466 | |||
| 467 | 1 | if (!empty($nsPos)) { |
|
| 468 | foreach ($nsPos as $k => $p) { |
||
| 469 | $ns = ''; |
||
| 470 | for ($i = $p['start'] + 1; $i < $p['end']; $i++) { |
||
| 471 | $ns .= $tokens[$i][1]; |
||
| 472 | } |
||
| 473 | |||
| 474 | $ns = trim($ns); |
||
| 475 | $final[$k] = array('namespace' => $ns, 'classes' => $classes[$k + 1]); |
||
| 476 | } |
||
| 477 | $classes = $final; |
||
| 478 | } |
||
| 479 | 1 | return $classes; |
|
| 480 | } |
||
| 481 | |||
| 482 | /** |
||
| 483 | * Start an addon. |
||
| 484 | * |
||
| 485 | * This function does the following: |
||
| 486 | * |
||
| 487 | * 1. Make the addon available in the autoloader. |
||
| 488 | * 2. Run the addon's bootstrap.php if it exists. |
||
| 489 | * |
||
| 490 | * @param string $addon_key The key of the addon to enable. |
||
| 491 | * @return bool Returns true if the addon was enabled. False otherwise. |
||
| 492 | */ |
||
| 493 | 34 | public static function startAddon($addon_key) { |
|
| 494 | 34 | $addon = static::enabled($addon_key); |
|
| 495 | 34 | if (!$addon) { |
|
|
0 ignored issues
–
show
|
|||
| 496 | return false; |
||
| 497 | } |
||
| 498 | |||
| 499 | // Run the class' bootstrap. |
||
| 500 | 34 | if ($bootstrap_path = val(self::K_BOOTSTRAP, $addon)) { |
|
| 501 | include_once $bootstrap_path; |
||
| 502 | } |
||
| 503 | 34 | return true; |
|
| 504 | } |
||
| 505 | } |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.