confutils.php 13 KB

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