1<?php 2/*********************************************************** 3 * Copyright (C) 2008-2012 Hewlett-Packard Development Company, L.P. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License version 2.1 as published by the Free Software Foundation. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with this library; if not, write to the Free Software Foundation, Inc.0 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 ***********************************************************/ 18use Fossology\Lib\Plugin\Plugin; 19 20/** 21 * \file 22 * \brief Core functions for user interface plugins 23 **/ 24 25/** 26 * \brief Global plugins array 27 **/ 28global $Plugins; 29$Plugins = array(); 30 31/** 32 * @brief Sort compare function. 33 * 34 * Sorts by dependency relationship. If a and b are at the same 35 * dependency level, then sort by the plugin level. 36 * 37 * @param Plugin a 38 * @param Plugin b 39 * 40 * @return -1, 0, 1 for plugin a being <, =, or > than b 41 */ 42function plugin_cmp($a, $b) 43{ 44 /* Sort by plugin version only when the name is the same */ 45 if (0 == strcmp($a->Name, $b->Name)) { 46 /* Sort by plugin version (descending order) */ 47 $rc = strcmp($a->Version, $b->Version); 48 if ($rc != 0) { 49 return (- $rc); 50 } 51 } 52 53 /* Sort by dependencies. */ 54 /* check if $a is a dependency for $b */ 55 // print "BEGIN Comparing $a->Name with $b->Name\n"; 56 foreach ($a->Dependency as $val) { 57 // print "Comparing $a->Name :: $val with $b->Name\n"; 58 if ($val == $b->Name) { 59 return (1); 60 } 61 } 62 /* check if $b is a dependency for $a */ 63 foreach ($b->Dependency as $val) { 64 // print "Comparing $b->Name :: $val with $a->Name\n"; 65 if ($val == $a->Name) { 66 return (- 1); 67 } 68 } 69 // print "STILL Comparing $a->Name with $b->Name\n"; 70 71 /* If same dependencies, then sort by plugin level (highest comes first) */ 72 if ($a->PluginLevel > $b->PluginLevel) { 73 return (- 1); 74 } elseif ($a->PluginLevel < $b->PluginLevel) { 75 return (1); 76 } 77 78 /* Nothing else to sort by -- sort by number of dependencies */ 79 $rc = count($a->Dependency) - count($b->Dependency); 80 return ($rc); 81} // plugin_cmp() 82 83/** 84 * \brief Disable all plugins that have a level greater than the users permission level. 85 * 86 * \param int $Level The user's DBaccess level 87 * \return void 88 */ 89function plugin_disable($Level) 90{ 91 /** @var Plugin[] $Plugins */ 92 global $Plugins; 93 94 /* Disable all plugins with >= $Level access */ 95 //echo "<pre>COMP: starting to disable plugins\n</pre>"; 96 $LoginFlag = empty($_SESSION['User']); 97 foreach ($Plugins as $pluginName => &$P) { 98 if ($P->State == PLUGIN_STATE_INVALID) { 99 // echo "<pre>COMP: Plugin $P->Name is in INVALID state\n</pre>"; 100 continue; 101 } 102 if ($P->DBaccess > $Level) { 103 // echo "<pre>COMP: Going to disable $P->Name\n</pre>"; 104 // echo "<pre>COMP: disabling plugins with $P->DBaccess >= 105 // $Level\n</pre>"; 106 $P->unInstall(); 107 unset($Plugins[$pluginName]); 108 } 109 unset($P); 110 } 111} // plugin_disable 112 113/** 114 * \brief Sort the global $Plugins by dependencies. This way plugins 115 * get loaded in the correct order. 116 **/ 117function plugin_sort() 118{ 119 global $Plugins; 120 121 /* Ideally, I would like to use usort. However, there are 122 dependency issues. Specifically: usort only works where there are 123 direct comparisons. It does not work with indirect dependencies. 124 For example: 125 A depends on B (A->B). 126 B depends on C (B->C). 127 If I just use usort, then C may be sorted AFTER A since there is 128 no explicit link from A->C. The array (B,A,C) is a possible usort 129 return, and it is wrong. 130 Before I can sort, we must fill out the dependency arrays. 131 */ 132 133 /* for each plugin, store the dependencies in a matrix */ 134 $DepArray = array(); 135 foreach ($Plugins as &$P) { 136 if (empty($P->Dependency[0])) { 137 continue; // ignore no dependencies 138 } 139 $DepArray[$P->Name] = array(); 140 $D = &$DepArray[$P->Name]; 141 for ($j = 0; $j < count($P->Dependency); $j ++) { 142 $D[$P->Dependency[$j]] = $P->PluginLevel; 143 } 144 unset($P); 145 } 146 147 /* Now iterate through the array. 148 This converts implied dependencies into direct dependencies. */ 149 foreach ($DepArray as $A => $a) { 150 $Aa = &$DepArray[$A]; 151 /* 152 * Find every element that depends on this element and merge the 153 * dependency lists 154 */ 155 foreach ($DepArray as $B => $b) { 156 $Bb = $DepArray[$B]; 157 if (! empty($Bb[$A])) { 158 /* merge in the entire list */ 159 $DepArray[$B] = array_merge($Aa, $Bb); 160 } 161 } 162 } 163 164 /* Finally: Put the direct dependencies back into the structures */ 165 foreach ($Plugins as &$P) { 166 if (empty($P->Dependency[0])) { 167 continue; // ignore no dependencies 168 } 169 $P->Dependency = array_keys($DepArray[$P->Name]); 170 unset($P); 171 } 172 173 /* Now it is safe to sort */ 174 uasort($Plugins, 'plugin_cmp'); 175} // plugin_sort() 176 177/** 178 * \brief Given the official name of a plugin, find the index to it in the 179 * global $Plugins array. 180 * 181 * \note Only plugins in PLUGIN_STATE_READY are scanned. 182 * \param $Name Plugin name 183 * \return -1 if the plugin $Name is not found. 184 **/ 185function plugin_find_id($pluginName) 186{ 187 /** \todo has to be removed */ 188 /** @var Plugin[] $Plugins */ 189 global $Plugins; 190 191 if (array_key_exists($pluginName, $Plugins)) { 192 $plugin = $Plugins[$pluginName]; 193 return $plugin->State === PLUGIN_STATE_READY ? $pluginName : - 1; 194 } 195 196 return -1; 197} 198 199/** 200 * @brief Given the official name of a plugin, return the $Plugins object. 201 * 202 * Only plugins in PLUGIN_STATE_READY are scanned. 203 * 204 * @param string $pluginName Name of the required plugin 205 * @return Plugin|NULL The plugin or NULL if the plugin name isn't found. 206 */ 207function plugin_find($pluginName) 208{ 209 global $Plugins; 210 return array_key_exists($pluginName, $Plugins) ? $Plugins[$pluginName] : null; 211} 212 213/** 214 * \brief Initialize every plugin in the global $Plugins array. 215 * 216 * plugin_sort() is called followed by the plugin 217 * PostInitialize() if PLUGIN_STATE_VALID, 218 * and RegisterMenus() if PLUGIN_STATE_READY. 219 **/ 220function plugin_preinstall() 221{ 222 /** @var Plugin[] $Plugins */ 223 global $Plugins; 224 225 plugin_sort(); 226 227 foreach (array_keys($Plugins) as $pluginName) { 228 if (array_key_exists($pluginName, $Plugins)) { 229 $Plugins[$pluginName]->preInstall(); 230 } 231 } 232} 233 234/** 235 * \brief Call the Install method for every plugin 236 */ 237function plugin_postinstall() 238{ 239 /** @var Plugin[] $Plugins */ 240 global $Plugins; 241 242 foreach ($Plugins as &$plugin) { 243 $plugin->postInstall(); 244 } 245} 246 247/** 248 * \brief Load every module ui found in mods-enabled 249 **/ 250function plugin_load() 251{ 252 global $SYSCONFDIR; 253 254 $ModsEnabledDir = "$SYSCONFDIR/mods-enabled"; 255 256 /* Open $ModsEnabledDir and include all the php files found in the ui/ subdirectory */ 257 258 if (is_dir($ModsEnabledDir)) { 259 foreach (glob("$ModsEnabledDir/*") as $ModDirPath) { 260 foreach (array( 261 "/ui", 262 "" 263 ) as $subdir) { 264 $targetPath = $ModDirPath . $subdir; 265 266 if (is_dir($targetPath)) { 267 foreach (glob("$targetPath/*.php") as $phpFile) { 268 if (! strstr($phpFile, 'ndex.php')) { 269 include_once ("$phpFile"); 270 } 271 } 272 break; 273 } 274 } 275 } 276 } 277} 278 279/** 280 * \brief Unload every plugin by calling its Destroy(). 281 **/ 282function plugin_unload() 283{ 284 /** @var Plugin[] $Plugins */ 285 global $Plugins; 286 287 foreach ($Plugins as $key => $plugin) { 288 if ($key == - 1) { 289 break; 290 } 291 if (empty($plugin)) { 292 continue; 293 } 294 295 $plugin->unInstall(); 296 } 297} // plugin_unload() 298 299/** 300 * Register a new plugin to the global Plugins array. 301 * @param Plugin $plugin Plugin to be added 302 * @throws \Exception If plugin has no name or is already registered 303 */ 304function register_plugin(Plugin $plugin) 305{ 306 /** @var Plugin[] $Plugins */ 307 global $Plugins; 308 309 $name = $plugin->getName(); 310 311 if (empty($name)) { 312 throw new \Exception("cannot create module without name"); 313 } 314 315 if (array_key_exists($name, $Plugins)) { 316 throw new \Exception("duplicate definition of plugin with name $name"); 317 } 318 319 $Plugins[$name] = $plugin; 320} 321 322/** 323 * Used to convert plugin to string representation by __toString() 324 * @param array $vars Associative array of variable name => value 325 * @param string $classname Name of the class of the object being represented 326 * @return string String representation of the object 327 */ 328function getStringRepresentation($vars, $classname) 329{ 330 $output = $classname . " {\n"; 331 foreach ($vars as $name => $value) { 332 if (! is_object($value)) { 333 $representation = print_r($value, true); 334 $lines = explode("\n", $representation); 335 $lines = array_map(function ($line){ 336 return " " . $line; 337 }, $lines); 338 $representation = trim(implode("\n", $lines)); 339 340 $output .= " $name: " . $representation . "\n"; 341 } 342 } 343 $output .= "}\n"; 344 return $output; 345} 346