1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8require_once 'lib/wiki/pluginslib.php'; 9 10class WikiPluginPluginManager extends PluginsLib 11{ 12 var $expanded_params = ['info']; 13 function getDefaultArguments() 14 { 15 return [ 16 'info' => 'description|parameters|paraminfo', 17 'plugin' => '', 18 'module' => '', 19 'singletitle' => 'none', 20 'titletag' => 'h3', 21 'start' => '', 22 'limit' => '', 23 'paramtype' => '', 24 'showparamtype' => 'n', 25 'showtopinfo' => 'y' 26 ]; 27 } 28 function getName() 29 { 30 return 'PluginManager'; 31 } 32 function getVersion() 33 { 34 return preg_replace("/[Revision: $]/", '', "\$Revision: 1.11 $"); 35 } 36 function getDescription() 37 { 38 return wikiplugin_pluginmanager_help(); 39 } 40 function run($data, $params) 41 { 42 global $helpurl; 43 $wikilib = TikiLib::lib('wiki'); 44 $tikilib = TikiLib::lib('tiki'); 45 if (! is_dir(PLUGINS_DIR)) { 46 return $this->error('No plugin directory defined'); 47 } 48 if (empty($helpurl)) { 49 $helpurl = 'http://doc.tiki.org/'; 50 } 51 52 $params = $this->getParams($params); 53 extract($params, EXTR_SKIP); 54 55 if (! empty($module) && ! empty($plugin)) { 56 return $this->error(tra('Either the module or plugin parameter must be set, but not both.')); 57 } elseif (! empty($module)) { 58 $aPrincipalField = ['field' => 'plugin', 'name' => 'Module']; 59 $helppath = $helpurl . $aPrincipalField['name'] . ' '; 60 $filepath = 'mod-func-'; 61 62 $modlib = TikiLib::lib('mod'); 63 $aPlugins = $modlib->list_module_files(); 64 $mod = true; 65 $type = ' module'; 66 $plugin = $module; 67 } else { 68 $aPrincipalField = ['field' => 'plugin', 'name' => 'Plugin']; 69 $helppath = $helpurl . $aPrincipalField['name']; 70 $filepath = 'wikiplugin_'; 71 $aPlugins = $wikilib->list_plugins(); 72 $mod = false; 73 $type = ' plugin'; 74 } 75 $all = $aPlugins; 76 //if the user set $module, that setting has now been moved to $plugin so that one code set is used 77 //$aPlugins and $all now has the complete list of plugin or module file names - the code below modifies $aPlugins 78 //if necessary based on user settings 79 if (! empty($plugin)) { 80 if (strpos($plugin, '|') !== false) { 81 $aPlugins = []; 82 $userlist = explode('|', $plugin); 83 foreach ($userlist as $useritem) { 84 $file = $filepath . $useritem . '.php'; 85 $confirm = in_array($file, $all); 86 if ($confirm === false) { 87 return '^' . tr('Plugin Manager error: %0%1 not found', $useritem, $type) . '^'; 88 } else { 89 $aPlugins[] = $file; 90 } 91 } 92 } elseif (strpos($plugin, '-') !== false) { 93 $userrange = explode('-', $plugin); 94 $begin = array_search($filepath . $userrange[0] . '.php', $aPlugins); 95 $end = array_search($filepath . $userrange[1] . '.php', $aPlugins); 96 $beginerror = ''; 97 $enderror = ''; 98 $type2 = $type; 99 if ($begin === false || $end === false) { 100 if ($begin === false) { 101 $beginerror = $userrange[0]; 102 } 103 if ($end === false) { 104 $enderror = $userrange[1]; 105 if (! empty($beginerror)) { 106 $and = ' and '; 107 } else { 108 $and = ''; 109 $type = ''; 110 } 111 } 112 return '^' . tr('Plugin Manager error: %0%1%2%3%4 not found', $beginerror, $type, $and, $enderror, $type2) . '^'; 113 } elseif ($end > $begin) { 114 $aPlugins = array_slice($aPlugins, $begin, $end - $begin + 1); 115 } else { 116 $aPlugins = array_slice($aPlugins, $end, $begin - $end + 1); 117 } 118 } elseif (! empty($limit)) { 119 $begin = array_search($filepath . $plugin . '.php', $aPlugins); 120 if ($begin === false) { 121 return '^' . tr('Plugin Manager error: %0%1 not found', $begin, $type) . '^'; 122 } else { 123 $aPlugins = array_slice($aPlugins, $begin, $limit); 124 } 125 } elseif ($plugin != 'all') { 126 $file = $filepath . $plugin . '.php'; 127 $confirm = in_array($file, $aPlugins); 128 if ($confirm === false) { 129 return '^' . tr('Plugin Manager error: %0%1 not found', $plugin, $type) . '^'; 130 } else { 131 $aPlugins = []; 132 $aPlugins[] = $file; 133 } 134 } 135 } else { 136 if (! empty($start) || ! empty($limit)) { 137 if (! empty($start) && ! empty($limit)) { 138 $aPlugins = array_slice($aPlugins, $start - 1, $limit); 139 } elseif (! empty($start)) { 140 $aPlugins = array_slice($aPlugins, $start - 1); 141 } else { 142 $aPlugins = array_slice($aPlugins, 0, $limit); 143 } 144 } 145 } 146 //Set all data variables needed for separate code used to generate the display table 147 $aData = []; 148 if ($singletitle == 'table' || count($aPlugins) > 1) { 149 foreach ($aPlugins as $sPluginFile) { 150 global $sPlugin, $numparams; 151 if ($mod) { 152 $infoPlugin = get_module_params($sPluginFile); 153 $namepath = $sPlugin; 154 } else { 155 $infoPlugin = get_plugin_info($sPluginFile); 156 $namepath = ucfirst($sPlugin); 157 } 158 if (in_array('description', $info)) { 159 if (isset($infoPlugin['description'])) { 160 if ($numparams > 1) { 161 $aData[$sPlugin]['description']['onekey'] = $infoPlugin['description']; 162 } else { 163 $aData[$sPlugin]['description'] = $infoPlugin['description']; 164 } 165 } else { 166 $aData[$sPlugin]['description'] = ' --- '; 167 } 168 } 169 if (in_array('parameters', $info)) { 170 if ($numparams > 0) { 171 if ($aPrincipalField['field'] == 'plugin' && ! in_array('options', $info) && $numparams > 1) { 172 $aData[$sPlugin][$aPrincipalField['field']]['rowspan'] = $numparams; 173 if (in_array('description', $info)) { 174 $aData[$sPlugin]['description']['rowspan'] = $numparams; 175 } 176 } 177 foreach ($infoPlugin['params'] as $paramname => $param) { 178 if (isset($infoPlugin['params'][$paramname]['description'])) { 179 $paramblock = '~np~' . $infoPlugin['params'][$paramname]['description'] . '~/np~'; 180 } 181 if (isset($param['options']) && is_array($param['options'])) { 182 $paramblock .= '<br /><em>' . tra('Options:') . '</em> '; 183 $i = 0; 184 foreach ($param['options'] as $oplist => $opitem) { 185 if (isset($opitem['value'])) { 186 $paramblock .= $opitem['value']; 187 } else { 188 $paramblock .= $opitem['text']; 189 } 190 $paramblock .= ' | '; 191 $i++; 192 } 193 $paramblock = substr($paramblock, 0, -3); 194 } 195 if (isset($infoPlugin['params'][$paramname]['required']) && $infoPlugin['params'][$paramname]['required'] == true) { 196 $aData[$sPlugin]['parameters']['<b><code>' . $paramname . '</code></b>'] = $paramblock; 197 } else { 198 $aData[$sPlugin]['parameters']['<code>' . $paramname . '</code>'] = $paramblock; 199 } 200 } 201 } else { 202 $aData[$sPlugin]['parameters']['<em>no parameters</em>'] = '<em>' . tra('n/a') . '</em>'; 203 } 204 } 205 $aData[$sPlugin]['plugin']['plugin'] = '[' . $helppath . $namepath . '|' . ucfirst($sPlugin) . ']'; 206 } // Plugins Loop 207 return PluginsLibUtil::createTable($aData, $info, $aPrincipalField); 208 } else { 209 //Replicates a documentation table for parameters for a single plugin or module 210 //Not using plugin lib table to avoid making custom modifications 211 global $sPlugin, $numparams; 212 if ($mod) { 213 $infoPlugin = get_module_params($aPlugins[0]); 214 $namepath = $sPlugin; 215 } else { 216 $infoPlugin = get_plugin_info($aPlugins[0]); 217 $namepath = ucfirst($sPlugin); 218 } 219 if ($singletitle == 'top') { 220 $title = '<' . $titletag . '>[' . $helppath . $namepath 221 . '|' . ucfirst($sPlugin) . ']</' . $titletag . '>'; 222 $title .= $infoPlugin['description'] . '<br />'; 223 } else { 224 $title = ''; 225 } 226 $headbegin = "\n\t\t" . '<th class="heading">'; 227 $cellbegin = "\n\t\t" . '<td>'; 228 $header = "\n\t" . '<tr class="heading">' . $headbegin . 'Parameters</td>'; 229 $rows = ''; 230 if (isset($numparams) && $numparams > 0) { 231 $header .= $headbegin . tra('Accepted Values') . '</th>'; 232 $header .= $headbegin . tra('Description') . '</th>'; 233 $rowCounter = 1; 234 //sort required params first 235 $reqarray = array_column($infoPlugin['params'], 'required'); 236 $keysarray = array_keys($infoPlugin['params']); 237 $reqarray = array_combine($keysarray, $reqarray); 238 if (count($reqarray) == count($infoPlugin['params'])) { 239 array_multisort($reqarray, SORT_DESC, $infoPlugin['params']); 240 } 241 //add body instructions to the parameter array 242 if (! empty($infoPlugin['body'])) { 243 $body = ['(body of plugin)' => ['description' => $infoPlugin['body']]]; 244 $infoPlugin['params'] = array_merge($body, $infoPlugin['params']); 245 } 246 foreach ($infoPlugin['params'] as $paramname => $paraminfo) { 247 unset($sep, $septext); 248 //check is paramtype filter is set 249 if (empty($params['paramtype']) 250 || ((empty($paraminfo['doctype']) && ! empty($params['paramtype']) && $params['paramtype'] === 'none') 251 || (! empty($paraminfo['doctype']) && $params['paramtype'] == $paraminfo['doctype'])) 252 ) { 253 $filteredparams[] = $paraminfo; 254 $rows .= "\n\t" . '<tr>' . $cellbegin; 255 //Parameters column 256 if (isset($paraminfo['required']) && $paraminfo['required'] == true) { 257 $rows .= '<strong><code>' . $paramname . '</code></strong>'; 258 } elseif ($paramname == '(body of plugin)') { 259 $rows .= tra('(body of plugin)'); 260 } else { 261 $rows .= '<code>' . $paramname . '</code>' ; 262 } 263 if (isset($params['showparamtype']) && $params['showparamtype'] === 'y' 264 && ! empty($paraminfo['doctype'])) { 265 $rows .= '<br /><small>(' . $paraminfo['doctype'] . ')</small>'; 266 } 267 $rows .= '</td>'; 268 //Accepted Values column 269 $rows .= $cellbegin; 270 if (isset($paraminfo['separator'])) { 271 $sep = $paraminfo['separator']; 272 $septext = tr('%0separator:%1 ', '<em>', '</em>') . '<code>' . $paraminfo['separator'] . 273 '</code>'; 274 } else { 275 $sep = '| '; 276 } 277 if (isset($paraminfo['accepted'])) { 278 $rows .= $paraminfo['accepted']; 279 if (isset($septext)) { 280 $rows .= '<br />' . $septext; 281 } 282 $rows .= '</td>'; 283 } elseif (isset($paraminfo['options'])) { 284 $optcounter = 1; 285 $numoptions = count($paraminfo['options']); 286 foreach ($paraminfo['options'] as $oplist => $opitem) { 287 $rows .= strlen($opitem['value']) == 0 ? tra('(blank)') : $opitem['value']; 288 if ($optcounter < $numoptions) { 289 if ($numoptions > 10) { 290 $rows .= $sep; 291 } else { 292 $rows .= '<br />'; 293 } 294 } 295 $optcounter++; 296 } 297 if (isset($septext)) { 298 $rows .= '<br />' . $septext; 299 } 300 $rows .= '</td>'; 301 } elseif (isset($paraminfo['filter'])) { 302 if ($paraminfo['filter'] == 'striptags') { 303 $rows .= tra('any string except for HTML and PHP tags'); 304 } else { 305 $rows .= $paraminfo['filter']; 306 } 307 if (isset($septext)) { 308 $rows .= '<br />' . $septext; 309 } 310 $rows .= '</td>'; 311 } else { 312 if (isset($septext)) { 313 $rows .= '<br />' . $septext; 314 } 315 $rows .= '</td>'; 316 } 317 //Description column 318 $rows .= $cellbegin . $paraminfo['description'] . '</td>'; 319 //Default column 320 if ($rowCounter == 1) { 321 $header .= $headbegin . tra('Default') . '</th>'; 322 } 323 if (! isset($paraminfo['default'])) { 324 $paraminfo['default'] = ''; 325 } 326 $rows .= $cellbegin . $paraminfo['default'] . '</td>'; 327 //Since column 328 if ($rowCounter == 1) { 329 $header .= $headbegin . tra('Since') . '</th>'; 330 } 331 $since = ! empty($paraminfo['since']) ? $paraminfo['since'] : ''; 332 $rows .= $cellbegin . $since . '</td>'; 333 $rows .= "\n\t" . '</tr>'; 334 $rowCounter++; 335 } 336 } 337 if (! empty($infoPlugin['additional']) && (empty($params['paramtype']) || $params['paramtype'] === 'none')) { 338 $rows .= '<tr><td colspan="5">' . $infoPlugin['additional'] . '</td></tr>'; 339 } 340 } else { 341 if (! empty($infoPlugin['body'])) { 342 $rows .= "\n\t" . '<tr>' . $cellbegin . '<em>' . tra('(body of plugin)') . ' - </em>' 343 . $infoPlugin['body'] . '</td>'; 344 } 345 $rows .= "\n\t" . '<tr>' . $cellbegin . '<em>' . tra('no parameters') . '</em></td>'; 346 } 347 $header .= "\n\t" . '</tr>'; 348 $pluginprefs = ! empty($infoPlugin['prefs']) && $params['showtopinfo'] !== 'n' ? '<em>' 349 . tra('Preferences required:') . '</em> ' . implode(', ', $infoPlugin['prefs']) . '<br/>' : ''; 350 $title .= isset($infoPlugin['introduced']) && $params['showtopinfo'] !== 'n' ? '<em>' . 351 tr('Introduced in %0', 'Tiki ' . $infoPlugin['introduced']) . '.</em>' : ''; 352 $required = ! empty($filteredparams) ? array_column($filteredparams, 'required') : false; 353 $bold = in_array(true, $required) > 0 ? '<em> ' . tr( 354 'Required parameters are in%0 %1bold%2', 355 '</em>', 356 '<strong><code>', 357 '</code></strong>.' 358 ) : ''; 359 $sOutput = $title . $bold . '<br>' . $pluginprefs . '<div class="table-responsive">' . 360 '<table class="table table-striped table-hover">' . $header . $rows . '</table></div>' . "\n"; 361 return $sOutput; 362 } 363 } 364 function processDescription($sDescription) 365 { 366 $sDescription = str_replace(',', ', ', $sDescription); 367 $sDescription = str_replace('|', '| ', $sDescription); 368 $sDescription = strip_tags(wordwrap($sDescription, 35)); 369 return $sDescription; 370 } 371} 372 373function wikiplugin_pluginmanager_info() 374{ 375 return [ 376 'name' => tra('Plugin Manager'), 377 'documentation' => 'PluginPluginManager', 378 'description' => tra('List wiki plugin or module information for the site'), 379 'prefs' => [ 'wikiplugin_pluginmanager' ], 380 'introduced' => 1, 381 'iconname' => 'plugin', 382 'params' => [ 383 'info' => [ 384 'required' => false, 385 'name' => tra('Information'), 386 'description' => tr('Determines what information is shown. Values separated with %0|%1. 387 Ignored when %0singletitle%1 is set to %0top%1 or %0none%1.', '<code>', '</code>'), 388 'filter' => 'text', 389 'accepted' => tra('One or more of: description | parameters | paraminfo'), 390 'default' => 'description | parameters | paraminfo ', 391 'since' => '1', 392 'options' => [ 393 ['text' => '', 'value' => ''], 394 ['text' => tra('Description'), 'value' => 'description'], 395 ['text' => tra('Description and Parameters'), 'value' => 'description|parameters'], 396 ['text' => tra('Description & Parameter Info'), 'value' => 'description|paraminfo'], 397 ['text' => tra('Parameters & Parameter Info'), 'value' => 'parameters|paraminfo'], 398 ['text' => tra('All'), 'value' => 'description|parameters|paraminfo'] 399 ] 400 ], 401 'plugin' => [ 402 'required' => false, 403 'name' => tra('Plugin'), 404 'description' => tr('Name of a plugin (e.g., backlinks), or list separated by %0|%1, or range separated 405 by %0-%1. Single plugin can be used with %0limit%1 parameter.', '<code>', '</code>'), 406 'filter' => 'text', 407 'default' => '', 408 'since' => '5.0', 409 ], 410 'module' => [ 411 'required' => false, 412 'name' => tra('Module'), 413 'description' => tr('Name of a module (e.g., calendar_new), or list separated by %0|%1, or range separated 414 by %0-%1. Single module can be used with %0limit%1 parameter.', '<code>', '</code>'), 415 'filter' => 'text', 416 'default' => '', 417 'since' => '6.1', 418 ], 419 'singletitle' => [ 420 'required' => false, 421 'name' => tra('Single Title'), 422 'description' => tr('Set placement of plugin name and description when displaying information for only one plugin'), 423 'filter' => 'alpha', 424 'default' => 'none', 425 'since' => '5.0', 426 'options' => [ 427 ['text' => tra(''), 'value' => ''], 428 ['text' => tra('Top'), 'value' => 'top'], 429 ['text' => tra('Table'), 'value' => 'table'], 430 ], 431 ], 432 'titletag' => [ 433 'required' => false, 434 'name' => tra('Title Heading'), 435 'description' => tr('Sets the heading size for the title, e.g., %0h2%1.', '<code>', '</code>'), 436 'filter' => 'alnum', 437 'default' => 'h3', 438 'since' => '5.0', 439 'advanced' => true, 440 ], 441 'start' => [ 442 'required' => false, 443 'name' => tra('Start'), 444 'description' => tra('Start with this plugin record number (must be an integer 1 or greater).'), 445 'filter' => 'digits', 446 'default' => '', 447 'since' => '5.0', 448 ], 449 'limit' => [ 450 'required' => false, 451 'name' => tra('Limit'), 452 'description' => tra('Number of plugins to show. Can be used either with start or plugin as the starting 453 point. Must be an integer 1 or greater.'), 454 'filter' => 'digits', 455 'default' => '', 456 'since' => '5.0', 457 ], 458 'paramtype' => [ 459 'required' => false, 460 'name' => tra('Parameter Type'), 461 'description' => tr('Only list parameters with this %0doctype%1 setting. Set to %0none%1 to show only 462 parameters without a type setting and the body instructions.', '<code>', '</code>'), 463 'since' => '15.0', 464 'filter' => 'alpha', 465 'default' => '', 466 'advanced' => true, 467 ], 468 'showparamtype' => [ 469 'required' => false, 470 'name' => tra('Show Parameter Type'), 471 'description' => tr('Show the parameter %0doctype%1 value.', '<code>', '</code>'), 472 'since' => '15.0', 473 'filter' => 'alpha', 474 'default' => '', 475 'advanced' => true, 476 'options' => [ 477 ['text' => '', 'value' => ''], 478 ['text' => tra('Yes'), 'value' => 'y'], 479 ['text' => tra('No'), 'value' => 'n'] 480 ] 481 ], 482 'showtopinfo' => [ 483 'required' => false, 484 'name' => tra('Show Top Info'), 485 'description' => tr('Show information above the table regarding preferences required and the first 486 version when the plugin became available. Shown by default.'), 487 'since' => '15.0', 488 'filter' => 'alpha', 489 'default' => '', 490 'advanced' => true, 491 'options' => [ 492 ['text' => '', 'value' => ''], 493 ['text' => tra('Yes'), 'value' => 'y'], 494 ['text' => tra('No'), 'value' => 'n'] 495 ] 496 ], 497 ], 498 ]; 499} 500 501function get_plugin_info($sPluginFile) 502{ 503 preg_match("/wikiplugin_(.*)\.php/i", $sPluginFile, $match); 504 global $sPlugin, $numparams; 505 $sPlugin = $match[1]; 506 include_once(PLUGINS_DIR . '/' . $sPluginFile); 507 global $tikilib; 508 $parserlib = TikiLib::lib('parser'); 509 510 $infoPlugin = $parserlib->plugin_info($sPlugin); 511 $numparams = isset($infoPlugin['params']) ? count($infoPlugin['params']) : 0; 512 return $infoPlugin; 513} 514 515function get_module_params($sPluginFile) 516{ 517 preg_match("/mod-func-(.*)\.php/i", $sPluginFile, $match); 518 global $sPlugin, $numparams; 519 $sPlugin = $match[1]; 520 include_once('modules/' . $sPluginFile); 521 $info_func = "module_{$sPlugin}_info"; 522 $infoPlugin = $info_func(); 523 $numparams = isset($infoPlugin['params']) ? count($infoPlugin['params']) : 0; 524 return $infoPlugin; 525} 526 527function wikiplugin_pluginmanager($data, $params) 528{ 529 $plugin = new WikiPluginPluginManager(); 530 return $plugin->run($data, $params); 531} 532