Writer.php 3.7 KB

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