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.

Config.php 7.7KB

8 vuotta sitten
8 vuotta sitten
8 vuotta sitten
8 vuotta sitten
11 vuotta sitten
11 vuotta sitten
10 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Adam Williamson <awilliam@redhat.com>
  6. * @author Aldo "xoen" Giambelluca <xoen@xoen.org>
  7. * @author Bart Visscher <bartv@thisnet.nl>
  8. * @author Brice Maron <brice@bmaron.net>
  9. * @author Frank Karlitschek <frank@karlitschek.de>
  10. * @author Jakob Sack <mail@jakobsack.de>
  11. * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
  12. * @author Joas Schilling <coding@schilljs.com>
  13. * @author Lukas Reschke <lukas@statuscode.ch>
  14. * @author Michael Gapczynski <GapczynskiM@gmail.com>
  15. * @author Morris Jobke <hey@morrisjobke.de>
  16. * @author Philipp Schaffrath <github@philipp.schaffrath.email>
  17. * @author Robin Appelman <robin@icewind.nl>
  18. * @author Robin McCorkell <robin@mccorkell.me.uk>
  19. *
  20. * @license AGPL-3.0
  21. *
  22. * This code is free software: you can redistribute it and/or modify
  23. * it under the terms of the GNU Affero General Public License, version 3,
  24. * as published by the Free Software Foundation.
  25. *
  26. * This program is distributed in the hope that it will be useful,
  27. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. * GNU Affero General Public License for more details.
  30. *
  31. * You should have received a copy of the GNU Affero General Public License, version 3,
  32. * along with this program. If not, see <http://www.gnu.org/licenses/>
  33. *
  34. */
  35. namespace OC;
  36. /**
  37. * This class is responsible for reading and writing config.php, the very basic
  38. * configuration file of Nextcloud.
  39. */
  40. class Config {
  41. const ENV_PREFIX = 'NC_';
  42. /** @var array Associative array ($key => $value) */
  43. protected $cache = array();
  44. /** @var string */
  45. protected $configDir;
  46. /** @var string */
  47. protected $configFilePath;
  48. /** @var string */
  49. protected $configFileName;
  50. /**
  51. * @param string $configDir Path to the config dir, needs to end with '/'
  52. * @param string $fileName (Optional) Name of the config file. Defaults to config.php
  53. */
  54. public function __construct($configDir, $fileName = 'config.php') {
  55. $this->configDir = $configDir;
  56. $this->configFilePath = $this->configDir.$fileName;
  57. $this->configFileName = $fileName;
  58. $this->readData();
  59. }
  60. /**
  61. * Lists all available config keys
  62. *
  63. * Please note that it does not return the values.
  64. *
  65. * @return array an array of key names
  66. */
  67. public function getKeys() {
  68. return array_keys($this->cache);
  69. }
  70. /**
  71. * Returns a config value
  72. *
  73. * gets its value from an `NC_` prefixed environment variable
  74. * if it doesn't exist from config.php
  75. * if this doesn't exist either, it will return the given `$default`
  76. *
  77. * @param string $key key
  78. * @param mixed $default = null default value
  79. * @return mixed the value or $default
  80. */
  81. public function getValue($key, $default = null) {
  82. $envValue = getenv(self::ENV_PREFIX . $key);
  83. if ($envValue !== false) {
  84. return $envValue;
  85. }
  86. if (isset($this->cache[$key])) {
  87. return $this->cache[$key];
  88. }
  89. return $default;
  90. }
  91. /**
  92. * Sets and deletes values and writes the config.php
  93. *
  94. * @param array $configs Associative array with `key => value` pairs
  95. * If value is null, the config key will be deleted
  96. */
  97. public function setValues(array $configs) {
  98. $needsUpdate = false;
  99. foreach ($configs as $key => $value) {
  100. if ($value !== null) {
  101. $needsUpdate |= $this->set($key, $value);
  102. } else {
  103. $needsUpdate |= $this->delete($key);
  104. }
  105. }
  106. if ($needsUpdate) {
  107. // Write changes
  108. $this->writeData();
  109. }
  110. }
  111. /**
  112. * Sets the value and writes it to config.php if required
  113. *
  114. * @param string $key key
  115. * @param mixed $value value
  116. */
  117. public function setValue($key, $value) {
  118. if ($this->set($key, $value)) {
  119. // Write changes
  120. $this->writeData();
  121. }
  122. }
  123. /**
  124. * This function sets the value
  125. *
  126. * @param string $key key
  127. * @param mixed $value value
  128. * @return bool True if the file needs to be updated, false otherwise
  129. */
  130. protected function set($key, $value) {
  131. if (!isset($this->cache[$key]) || $this->cache[$key] !== $value) {
  132. // Add change
  133. $this->cache[$key] = $value;
  134. return true;
  135. }
  136. return false;
  137. }
  138. /**
  139. * Removes a key from the config and removes it from config.php if required
  140. * @param string $key
  141. */
  142. public function deleteKey($key) {
  143. if ($this->delete($key)) {
  144. // Write changes
  145. $this->writeData();
  146. }
  147. }
  148. /**
  149. * This function removes a key from the config
  150. *
  151. * @param string $key
  152. * @return bool True if the file needs to be updated, false otherwise
  153. */
  154. protected function delete($key) {
  155. if (isset($this->cache[$key])) {
  156. // Delete key from cache
  157. unset($this->cache[$key]);
  158. return true;
  159. }
  160. return false;
  161. }
  162. /**
  163. * Loads the config file
  164. *
  165. * Reads the config file and saves it to the cache
  166. *
  167. * @throws \Exception If no lock could be acquired or the config file has not been found
  168. */
  169. private function readData() {
  170. // Default config should always get loaded
  171. $configFiles = array($this->configFilePath);
  172. // Add all files in the config dir ending with the same file name
  173. $extra = glob($this->configDir.'*.'.$this->configFileName);
  174. if (is_array($extra)) {
  175. natsort($extra);
  176. $configFiles = array_merge($configFiles, $extra);
  177. }
  178. // Include file and merge config
  179. foreach ($configFiles as $file) {
  180. $fileExistsAndIsReadable = file_exists($file) && is_readable($file);
  181. $filePointer = $fileExistsAndIsReadable ? fopen($file, 'r') : false;
  182. if($file === $this->configFilePath &&
  183. $filePointer === false) {
  184. // Opening the main config might not be possible, e.g. if the wrong
  185. // permissions are set (likely on a new installation)
  186. continue;
  187. }
  188. // Try to acquire a file lock
  189. if(!flock($filePointer, LOCK_SH)) {
  190. throw new \Exception(sprintf('Could not acquire a shared lock on the config file %s', $file));
  191. }
  192. unset($CONFIG);
  193. include $file;
  194. if(isset($CONFIG) && is_array($CONFIG)) {
  195. $this->cache = array_merge($this->cache, $CONFIG);
  196. }
  197. // Close the file pointer and release the lock
  198. flock($filePointer, LOCK_UN);
  199. fclose($filePointer);
  200. }
  201. }
  202. /**
  203. * Writes the config file
  204. *
  205. * Saves the config to the config file.
  206. *
  207. * @throws HintException If the config file cannot be written to
  208. * @throws \Exception If no file lock can be acquired
  209. */
  210. private function writeData() {
  211. // Create a php file ...
  212. $content = "<?php\n";
  213. $content .= '$CONFIG = ';
  214. $content .= var_export($this->cache, true);
  215. $content .= ";\n";
  216. touch ($this->configFilePath);
  217. $filePointer = fopen($this->configFilePath, 'r+');
  218. // Prevent others not to read the config
  219. chmod($this->configFilePath, 0640);
  220. // File does not exist, this can happen when doing a fresh install
  221. if(!is_resource ($filePointer)) {
  222. // TODO fix this via DI once it is very clear that this doesn't cause side effects due to initialization order
  223. // currently this breaks app routes but also could have other side effects especially during setup and exception handling
  224. $url = \OC::$server->getURLGenerator()->linkToDocs('admin-dir_permissions');
  225. throw new HintException(
  226. "Can't write into config directory!",
  227. 'This can usually be fixed by giving the webserver write access to the config directory. See ' . $url);
  228. }
  229. // Try to acquire a file lock
  230. if(!flock($filePointer, LOCK_EX)) {
  231. throw new \Exception(sprintf('Could not acquire an exclusive lock on the config file %s', $this->configFilePath));
  232. }
  233. // Write the config and release the lock
  234. ftruncate ($filePointer, 0);
  235. fwrite($filePointer, $content);
  236. fflush($filePointer);
  237. flock($filePointer, LOCK_UN);
  238. fclose($filePointer);
  239. // Try invalidating the opcache just for the file we wrote...
  240. if (!\OC_Util::deleteFromOpcodeCache($this->configFilePath)) {
  241. // But if that doesn't work, clear the whole cache.
  242. \OC_Util::clearOpcodeCache();
  243. }
  244. }
  245. }