[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> confutils.php (source)

   1  <?php
   2  
   3  /**
   4   * Utilities for collecting data from config files
   5   *
   6   * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
   7   * @author     Harry Fuecks <hfuecks@gmail.com>
   8   */
   9  
  10  /*
  11   * line prefix used to negate single value config items
  12   * (scheme.conf & stopwords.conf), e.g.
  13   * !gopher
  14   */
  15  
  16  use dokuwiki\Extension\AuthPlugin;
  17  use dokuwiki\Extension\Event;
  18  
  19  const DOKU_CONF_NEGATION = '!';
  20  
  21  /**
  22   * Returns the (known) extension and mimetype of a given filename
  23   *
  24   * If $knownonly is true (the default), then only known extensions
  25   * are returned.
  26   *
  27   * @author Andreas Gohr <andi@splitbrain.org>
  28   *
  29   * @param string $file file name
  30   * @param bool   $knownonly
  31   * @return array with extension, mimetype and if it should be downloaded
  32   */
  33  function mimetype($file, $knownonly = true)
  34  {
  35      $mtypes = getMimeTypes();     // known mimetypes
  36      $ext    = strrpos($file, '.');
  37      if ($ext === false) {
  38          return [false, false, false];
  39      }
  40      $ext = strtolower(substr($file, $ext + 1));
  41      if (!isset($mtypes[$ext])) {
  42          if ($knownonly) {
  43              return [false, false, false];
  44          } else {
  45              return [$ext, 'application/octet-stream', true];
  46          }
  47      }
  48      if ($mtypes[$ext][0] == '!') {
  49          return [$ext, substr($mtypes[$ext], 1), true];
  50      } else {
  51          return [$ext, $mtypes[$ext], false];
  52      }
  53  }
  54  
  55  /**
  56   * returns a hash of mimetypes
  57   *
  58   * @author Andreas Gohr <andi@splitbrain.org>
  59   */
  60  function getMimeTypes()
  61  {
  62      static $mime = null;
  63      if (!$mime) {
  64          $mime = retrieveConfig('mime', 'confToHash');
  65          $mime = array_filter($mime);
  66      }
  67      return $mime;
  68  }
  69  
  70  /**
  71   * returns a hash of acronyms
  72   *
  73   * @author Harry Fuecks <hfuecks@gmail.com>
  74   */
  75  function getAcronyms()
  76  {
  77      static $acronyms = null;
  78      if (!$acronyms) {
  79          $acronyms = retrieveConfig('acronyms', 'confToHash');
  80          $acronyms = array_filter($acronyms, 'strlen');
  81      }
  82      return $acronyms;
  83  }
  84  
  85  /**
  86   * returns a hash of smileys
  87   *
  88   * @author Harry Fuecks <hfuecks@gmail.com>
  89   */
  90  function getSmileys()
  91  {
  92      static $smileys = null;
  93      if (!$smileys) {
  94          $smileys = retrieveConfig('smileys', 'confToHash');
  95          $smileys = array_filter($smileys, 'strlen');
  96      }
  97      return $smileys;
  98  }
  99  
 100  /**
 101   * returns a hash of entities
 102   *
 103   * @author Harry Fuecks <hfuecks@gmail.com>
 104   */
 105  function getEntities()
 106  {
 107      static $entities = null;
 108      if (!$entities) {
 109          $entities = retrieveConfig('entities', 'confToHash');
 110          $entities = array_filter($entities, 'strlen');
 111      }
 112      return $entities;
 113  }
 114  
 115  /**
 116   * returns a hash of interwikilinks
 117   *
 118   * @author Harry Fuecks <hfuecks@gmail.com>
 119   */
 120  function getInterwiki()
 121  {
 122      static $wikis = null;
 123      if (!$wikis) {
 124          $wikis = retrieveConfig('interwiki', 'confToHash', [true]);
 125          $wikis = array_filter($wikis, 'strlen');
 126  
 127          //add sepecial case 'this'
 128          $wikis['this'] = DOKU_URL . '{NAME}';
 129      }
 130      return $wikis;
 131  }
 132  
 133  /**
 134   * Returns the jquery script URLs for the versions defined in lib/scripts/jquery/versions
 135   *
 136   * @trigger CONFUTIL_CDN_SELECT
 137   * @return array
 138   */
 139  function getCdnUrls()
 140  {
 141      global $conf;
 142  
 143      // load version info
 144      $versions = [];
 145      $lines = file(DOKU_INC . 'lib/scripts/jquery/versions');
 146      foreach ($lines as $line) {
 147          $line = trim(preg_replace('/#.*$/', '', $line));
 148          if ($line === '') continue;
 149          [$key, $val] = sexplode('=', $line, 2, '');
 150          $key = trim($key);
 151          $val = trim($val);
 152          $versions[$key] = $val;
 153      }
 154  
 155      $src = [];
 156      $data = ['versions' => $versions, 'src' => &$src];
 157      $event = new Event('CONFUTIL_CDN_SELECT', $data);
 158      if ($event->advise_before()) {
 159          if (!$conf['jquerycdn']) {
 160              $jqmod = md5(implode('-', $versions));
 161              $src[] = DOKU_BASE . 'lib/exe/jquery.php' . '?tseed=' . $jqmod;
 162          } elseif ($conf['jquerycdn'] == 'jquery') {
 163              $src[] = sprintf('https://code.jquery.com/jquery-%s.min.js', $versions['JQ_VERSION']);
 164              $src[] = sprintf('https://code.jquery.com/ui/%s/jquery-ui.min.js', $versions['JQUI_VERSION']);
 165          } elseif ($conf['jquerycdn'] == 'cdnjs') {
 166              $src[] = sprintf(
 167                  'https://cdnjs.cloudflare.com/ajax/libs/jquery/%s/jquery.min.js',
 168                  $versions['JQ_VERSION']
 169              );
 170              $src[] = sprintf(
 171                  'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/%s/jquery-ui.min.js',
 172                  $versions['JQUI_VERSION']
 173              );
 174          }
 175      }
 176      $event->advise_after();
 177  
 178      return $src;
 179  }
 180  
 181  /**
 182   * returns array of wordblock patterns
 183   *
 184   */
 185  function getWordblocks()
 186  {
 187      static $wordblocks = null;
 188      if (!$wordblocks) {
 189          $wordblocks = retrieveConfig('wordblock', 'file', null, 'array_merge_with_removal');
 190      }
 191      return $wordblocks;
 192  }
 193  
 194  /**
 195   * Gets the list of configured schemes
 196   *
 197   * @return array the schemes
 198   */
 199  function getSchemes()
 200  {
 201      static $schemes = null;
 202      if (!$schemes) {
 203          $schemes = retrieveConfig('scheme', 'file', null, 'array_merge_with_removal');
 204          $schemes = array_map('trim', $schemes);
 205          $schemes = preg_replace('/^#.*/', '', $schemes);
 206          $schemes = array_filter($schemes);
 207      }
 208      return $schemes;
 209  }
 210  
 211  /**
 212   * Builds a hash from an array of lines
 213   *
 214   * If $lower is set to true all hash keys are converted to
 215   * lower case.
 216   *
 217   * @author Harry Fuecks <hfuecks@gmail.com>
 218   * @author Andreas Gohr <andi@splitbrain.org>
 219   * @author Gina Haeussge <gina@foosel.net>
 220   *
 221   * @param array $lines
 222   * @param bool $lower
 223   *
 224   * @return array
 225   */
 226  function linesToHash($lines, $lower = false)
 227  {
 228      $conf = [];
 229      // remove BOM
 230      if (isset($lines[0]) && str_starts_with($lines[0], pack('CCC', 0xef, 0xbb, 0xbf)))
 231          $lines[0] = substr($lines[0], 3);
 232      foreach ($lines as $line) {
 233          //ignore comments (except escaped ones)
 234          $line = preg_replace('/(?<![&\\\\])#.*$/', '', $line);
 235          $line = str_replace('\\#', '#', $line);
 236          $line = trim($line);
 237          if ($line === '') continue;
 238          $line = preg_split('/\s+/', $line, 2);
 239          $line = array_pad($line, 2, '');
 240          // Build the associative array
 241          if ($lower) {
 242              $conf[strtolower($line[0])] = $line[1];
 243          } else {
 244              $conf[$line[0]] = $line[1];
 245          }
 246      }
 247  
 248      return $conf;
 249  }
 250  
 251  /**
 252   * Builds a hash from a configfile
 253   *
 254   * If $lower is set to true all hash keys are converted to
 255   * lower case.
 256   *
 257   * @author Harry Fuecks <hfuecks@gmail.com>
 258   * @author Andreas Gohr <andi@splitbrain.org>
 259   * @author Gina Haeussge <gina@foosel.net>
 260   *
 261   * @param string $file
 262   * @param bool $lower
 263   *
 264   * @return array
 265   */
 266  function confToHash($file, $lower = false)
 267  {
 268      $conf = [];
 269      $lines = @file($file);
 270      if (!$lines) return $conf;
 271  
 272      return linesToHash($lines, $lower);
 273  }
 274  
 275  /**
 276   * Read a json config file into an array
 277   *
 278   * @param string $file
 279   * @return array
 280   * @throws JsonException
 281   */
 282  function jsonToArray($file)
 283  {
 284      $json = file_get_contents($file);
 285  
 286      $conf = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
 287  
 288      if ($conf === null) {
 289          return [];
 290      }
 291  
 292      return $conf;
 293  }
 294  
 295  /**
 296   * Retrieve the requested configuration information
 297   *
 298   * @author Chris Smith <chris@jalakai.co.uk>
 299   *
 300   * @param  string   $type     the configuration settings to be read, must correspond to a key/array in $config_cascade
 301   * @param  callback $fn       the function used to process the configuration file into an array
 302   * @param  array    $params   optional additional params to pass to the callback
 303   * @param  callback $combine  the function used to combine arrays of values read from different configuration files;
 304   *                            the function takes two parameters,
 305   *                               $combined - the already read & merged configuration values
 306   *                               $new - array of config values from the config cascade file being currently processed
 307   *                            and returns an array of the merged configuration values.
 308   * @return array    configuration values
 309   */
 310  function retrieveConfig($type, $fn, $params = null, $combine = 'array_merge')
 311  {
 312      global $config_cascade;
 313  
 314      if (!is_array($params)) $params = [];
 315  
 316      $combined = [];
 317      if (!is_array($config_cascade[$type])) trigger_error('Missing config cascade for "' . $type . '"', E_USER_WARNING);
 318      foreach (['default', 'local', 'protected'] as $config_group) {
 319          if (empty($config_cascade[$type][$config_group])) continue;
 320          foreach ($config_cascade[$type][$config_group] as $file) {
 321              if (file_exists($file)) {
 322                  $config = call_user_func_array($fn, array_merge([$file], $params));
 323                  $combined = $combine($combined, $config);
 324              }
 325          }
 326      }
 327  
 328      return $combined;
 329  }
 330  
 331  /**
 332   * Include the requested configuration information
 333   *
 334   * @author Chris Smith <chris@jalakai.co.uk>
 335   *
 336   * @param  string   $type     the configuration settings to be read, must correspond to a key/array in $config_cascade
 337   * @return array              list of files, default before local before protected
 338   */
 339  function getConfigFiles($type)
 340  {
 341      global $config_cascade;
 342      $files = [];
 343  
 344      if (!is_array($config_cascade[$type])) trigger_error('Missing config cascade for "' . $type . '"', E_USER_WARNING);
 345      foreach (['default', 'local', 'protected'] as $config_group) {
 346          if (empty($config_cascade[$type][$config_group])) continue;
 347          $files = array_merge($files, $config_cascade[$type][$config_group]);
 348      }
 349  
 350      return $files;
 351  }
 352  
 353  /**
 354   * check if the given action was disabled in config
 355   *
 356   * @author Andreas Gohr <andi@splitbrain.org>
 357   * @param string $action
 358   * @returns boolean true if enabled, false if disabled
 359   */
 360  function actionOK($action)
 361  {
 362      static $disabled = null;
 363      if (is_null($disabled) || defined('SIMPLE_TEST')) {
 364          global $conf;
 365          /** @var AuthPlugin $auth */
 366          global $auth;
 367  
 368          // prepare disabled actions array and handle legacy options
 369          $disabled = explode(',', $conf['disableactions']);
 370          $disabled = array_map('trim', $disabled);
 371          if (
 372              (isset($conf['openregister']) && !$conf['openregister']) || !$auth instanceof AuthPlugin
 373              || !$auth->canDo('addUser')
 374          ) {
 375              $disabled[] = 'register';
 376          }
 377          if (
 378              (isset($conf['resendpasswd']) && !$conf['resendpasswd']) || !$auth instanceof AuthPlugin
 379              || !$auth->canDo('modPass')
 380          ) {
 381              $disabled[] = 'resendpwd';
 382          }
 383          if ((isset($conf['subscribers']) && !$conf['subscribers']) || !$auth instanceof AuthPlugin) {
 384              $disabled[] = 'subscribe';
 385          }
 386          if (!$auth instanceof AuthPlugin || !$auth->canDo('Profile')) {
 387              $disabled[] = 'profile';
 388          }
 389          if (!$auth instanceof AuthPlugin || !$auth->canDo('delUser')) {
 390              $disabled[] = 'profile_delete';
 391          }
 392          if (!$auth instanceof AuthPlugin) {
 393              $disabled[] = 'login';
 394          }
 395          if (!$auth instanceof AuthPlugin || !$auth->canDo('logout')) {
 396              $disabled[] = 'logout';
 397          }
 398          $disabled = array_unique($disabled);
 399      }
 400  
 401      return !in_array($action, $disabled);
 402  }
 403  
 404  /**
 405   * check if headings should be used as link text for the specified link type
 406   *
 407   * @author Chris Smith <chris@jalakai.co.uk>
 408   *
 409   * @param   string  $linktype   'content'|'navigation', content applies to links in wiki text
 410   *                                                      navigation applies to all other links
 411   * @return  boolean             true if headings should be used for $linktype, false otherwise
 412   */
 413  function useHeading($linktype)
 414  {
 415      static $useHeading = null;
 416      if (defined('DOKU_UNITTEST')) $useHeading = null; // don't cache during unit tests
 417  
 418      if (is_null($useHeading)) {
 419          global $conf;
 420  
 421          if (!empty($conf['useheading'])) {
 422              switch ($conf['useheading']) {
 423                  case 'content':
 424                      $useHeading['content'] = true;
 425                      break;
 426  
 427                  case 'navigation':
 428                      $useHeading['navigation'] = true;
 429                      break;
 430                  default:
 431                      $useHeading['content'] = true;
 432                      $useHeading['navigation'] = true;
 433              }
 434          } else {
 435              $useHeading = [];
 436          }
 437      }
 438  
 439      return (!empty($useHeading[$linktype]));
 440  }
 441  
 442  /**
 443   * obscure config data so information isn't plain text
 444   *
 445   * @param string       $str     data to be encoded
 446   * @param string       $code    encoding method, values: plain, base64, uuencode.
 447   * @return string               the encoded value
 448   */
 449  function conf_encodeString($str, $code)
 450  {
 451      switch ($code) {
 452          case 'base64':
 453              return '<b>' . base64_encode($str);
 454          case 'uuencode':
 455              return '<u>' . convert_uuencode($str);
 456          case 'plain':
 457          default:
 458              return $str;
 459      }
 460  }
 461  /**
 462   * return obscured data as plain text
 463   *
 464   * @param  string      $str   encoded data
 465   * @return string             plain text
 466   */
 467  function conf_decodeString($str)
 468  {
 469      switch (substr($str, 0, 3)) {
 470          case '<b>':
 471              return base64_decode(substr($str, 3));
 472          case '<u>':
 473              return convert_uudecode(substr($str, 3));
 474          default:  // not encoded (or unknown)
 475              return $str;
 476      }
 477  }
 478  
 479  /**
 480   * array combination function to remove negated values (prefixed by !)
 481   *
 482   * @param  array $current
 483   * @param  array $new
 484   *
 485   * @return array the combined array, numeric keys reset
 486   */
 487  function array_merge_with_removal($current, $new)
 488  {
 489      foreach ($new as $val) {
 490          if (str_starts_with($val, DOKU_CONF_NEGATION)) {
 491              $idx = array_search(trim(substr($val, 1)), $current);
 492              if ($idx !== false) {
 493                  unset($current[$idx]);
 494              }
 495          } else {
 496              $current[] = trim($val);
 497          }
 498      }
 499  
 500      return array_slice($current, 0);
 501  }
 502  //Setup VIM: ex: et ts=4 :