You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

135 lines
3.7 KiB

  1. <?php
  2. namespace dokuwiki\plugin\config\core;
  3. use dokuwiki\plugin\config\core\Setting\Setting;
  4. use dokuwiki\Logger;
  5. /**
  6. * Writes the settings to the correct local file
  7. */
  8. class Writer
  9. {
  10. /** @var string header info */
  11. protected $header = 'Dokuwiki\'s Main Configuration File - Local Settings';
  12. /** @var string the file where the config will be saved to */
  13. protected $savefile;
  14. /**
  15. * Writer constructor.
  16. */
  17. public function __construct()
  18. {
  19. global $config_cascade;
  20. $this->savefile = end($config_cascade['main']['local']);
  21. }
  22. /**
  23. * Save the given settings
  24. *
  25. * @param Setting[] $settings
  26. * @throws \Exception
  27. */
  28. public function save($settings)
  29. {
  30. global $conf;
  31. if ($this->isLocked()) throw new \Exception('no save');
  32. // backup current file (remove any existing backup)
  33. if (file_exists($this->savefile)) {
  34. if (file_exists($this->savefile . '.bak.php')) @unlink($this->savefile . '.bak.php');
  35. if (!io_rename($this->savefile, $this->savefile . '.bak.php')) throw new \Exception('no backup');
  36. }
  37. if (!$fh = @fopen($this->savefile, 'wb')) {
  38. io_rename($this->savefile . '.bak.php', $this->savefile); // problem opening, restore the backup
  39. throw new \Exception('no save');
  40. }
  41. $out = '';
  42. foreach ($settings as $setting) {
  43. if ($setting->shouldBeSaved()) {
  44. $out .= $setting->out('conf', 'php');
  45. }
  46. }
  47. if ($out === '') {
  48. throw new \Exception('empty config');
  49. }
  50. $out = $this->getHeader() . $out;
  51. fwrite($fh, $out);
  52. fclose($fh);
  53. if ($conf['fperm']) chmod($this->savefile, $conf['fperm']);
  54. $this->opcacheUpdate($this->savefile);
  55. }
  56. /**
  57. * Update last modified time stamp of the config file
  58. *
  59. * Will invalidate all DokuWiki caches
  60. *
  61. * @throws \Exception when the config isn't writable
  62. */
  63. public function touch()
  64. {
  65. if ($this->isLocked()) throw new \Exception('no save');
  66. @touch($this->savefile);
  67. $this->opcacheUpdate($this->savefile);
  68. }
  69. /**
  70. * Invalidate the opcache of the given file (if possible)
  71. *
  72. * @todo this should probably be moved to core
  73. * @param string $file
  74. */
  75. protected function opcacheUpdate($file)
  76. {
  77. if (!function_exists('opcache_invalidate')) return;
  78. set_error_handler(function ($errNo, $errMsg) {
  79. Logger::debug('Unable to invalidate opcache: ' . $errMsg);
  80. });
  81. opcache_invalidate($file);
  82. restore_error_handler();
  83. }
  84. /**
  85. * Configuration is considered locked if there is no local settings filename
  86. * or the directory its in is not writable or the file exists and is not writable
  87. *
  88. * @return bool true: locked, false: writable
  89. */
  90. public function isLocked()
  91. {
  92. if (!$this->savefile) return true;
  93. if (!is_writable(dirname($this->savefile))) return true;
  94. if (file_exists($this->savefile) && !is_writable($this->savefile)) return true;
  95. return false;
  96. }
  97. /**
  98. * Returns the PHP intro header for the config file
  99. *
  100. * @return string
  101. */
  102. protected function getHeader()
  103. {
  104. return implode(
  105. "\n",
  106. [
  107. '<?php',
  108. '/*',
  109. ' * ' . $this->header,
  110. ' * Auto-generated by config plugin',
  111. ' * Run for user: ' . ($_SERVER['REMOTE_USER'] ?? 'Unknown'),
  112. ' * Date: ' . date('r'),
  113. ' */',
  114. '',
  115. ''
  116. ]
  117. );
  118. }
  119. }