Update.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. <?php
  2. /**
  3. * This file is part of the ForkBB <https://github.com/forkbb>.
  4. *
  5. * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
  6. * @license The MIT License (MIT)
  7. */
  8. declare(strict_types=1);
  9. namespace ForkBB\Models\Pages\Admin;
  10. use ForkBB\Core\Config as CoreConfig;
  11. use ForkBB\Core\Container;
  12. use ForkBB\Core\Validator;
  13. use ForkBB\Models\Page;
  14. use ForkBB\Models\Pages\Admin;
  15. use PDO;
  16. use PDOException;
  17. use RuntimeException;
  18. use ForkBB\Core\Exceptions\ForkException;
  19. use function \ForkBB\__;
  20. class Update extends Admin
  21. {
  22. const PHP_MIN = '7.3.0';
  23. const REV_MIN_FOR_UPDATE = 42;
  24. const LATEST_REV_WITH_DB_CHANGES = 43;
  25. const LOCK_NAME = 'lock_update';
  26. const LOCk_TTL = 1800;
  27. const JSON_OPTIONS = \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR;
  28. const CONFIG_FILE = 'main.php';
  29. protected $configFile;
  30. /**
  31. * Флаг проверки пароля
  32. * @var bool
  33. */
  34. protected $okPass;
  35. public function __construct(Container $container)
  36. {
  37. parent::__construct($container);
  38. $container->Lang->load('validator');
  39. $container->Lang->load('admin_update');
  40. $this->aIndex = 'update';
  41. $this->httpStatus = 503;
  42. $this->onlinePos = null;
  43. $this->nameTpl = 'admin/form';
  44. $this->titleForm = 'Update ForkBB';
  45. $this->classForm = ['updateforkbb'];
  46. $this->configFile = $container->DIR_CONFIG . '/' . self::CONFIG_FILE;
  47. $this->header('Retry-After', '3600');
  48. }
  49. /**
  50. * Подготовка страницы к отображению
  51. */
  52. public function prepare(): void
  53. {
  54. $this->aNavigation = $this->aNavigation();
  55. $this->crumbs = $this->crumbs(...$this->aCrumbs);
  56. }
  57. /**
  58. * Возвращает массив ссылок с описанием для построения навигации админки
  59. */
  60. protected function aNavigation(): array
  61. {
  62. return [
  63. 'update' => [
  64. $this->c->Router->link('AdminUpdate'),
  65. __('Update ForkBB'),
  66. ],
  67. ];
  68. }
  69. /**
  70. * Возвращает страницу обслуживания с доп.сообщением
  71. */
  72. protected function returnMaintenance(bool $isStage = true): Page
  73. {
  74. $maintenance = $this->c->Maintenance;
  75. $maintenance->fIswev = ['w', 'Update script is running'];
  76. if ($isStage) {
  77. $maintenance->fIswev = ['e', 'Script runs error'];
  78. }
  79. return $maintenance;
  80. }
  81. /**
  82. * Проверяет наличие блокировки скрипта обновления
  83. */
  84. protected function hasLock(string $uid = null): bool
  85. {
  86. $lock = $this->c->Cache->get(self::LOCK_NAME);
  87. if (null === $uid) {
  88. return ! empty($lock);
  89. } else {
  90. return empty($lock) || ! \hash_equals($uid, (string) $lock);
  91. }
  92. }
  93. protected function setLock(string $uid = null): ?string
  94. {
  95. if (true === $this->hasLock($uid)) {
  96. return null;
  97. }
  98. if (null === $uid) {
  99. $uid = $this->c->Secury->randomHash(33);
  100. }
  101. $this->c->Cache->set(self::LOCK_NAME, $uid, self::LOCk_TTL);
  102. if (true === $this->hasLock($uid)) {
  103. return null;
  104. }
  105. return $uid;
  106. }
  107. /**
  108. * Подготавливает данные для страницы обновления форума
  109. */
  110. public function view(array $args, string $method): Page
  111. {
  112. if (true === $this->hasLock()) {
  113. return $this->returnMaintenance(false);
  114. }
  115. if (
  116. 'POST' === $method
  117. && empty($this->fIswev)
  118. ) {
  119. $v = $this->c->Validator->reset()
  120. ->addValidators([
  121. 'check_pass' => [$this, 'vCheckPass'],
  122. ])->addRules([
  123. 'token' => 'token:AdminUpdate',
  124. 'dbpass' => 'exist|string|check_pass',
  125. 'o_maintenance_message' => 'required|string:trim|max:65000 bytes|html',
  126. ])->addAliases([
  127. 'dbpass' => 'Database password',
  128. 'o_maintenance_message' => 'Maintenance message',
  129. ])->addMessages([
  130. ]);
  131. if (
  132. $v->validation($_POST)
  133. && $this->okPass
  134. ) {
  135. $e = null;
  136. // версия PHP
  137. if (
  138. null === $e
  139. && \version_compare(\PHP_VERSION, self::PHP_MIN, '<')
  140. ) {
  141. $e = __(['You are running error', 'PHP', \PHP_VERSION, $this->c->FORK_REVISION, self::PHP_MIN]);
  142. }
  143. // база не от ForkBB или старая ревизия
  144. if (
  145. null === $e
  146. && $this->c->config->i_fork_revision < self::REV_MIN_FOR_UPDATE
  147. ) {
  148. $e = 'Version mismatch error';
  149. }
  150. // загрузка и проверка конфига
  151. if (null === $e) {
  152. try {
  153. $coreConfig = new CoreConfig($this->configFile);
  154. } catch (ForkException $excp) {
  155. $e = $excp->getMessage();
  156. }
  157. }
  158. // проверка доступности базы данных на изменения
  159. if (
  160. null === $e
  161. && $this->c->config->i_fork_revision < self::LATEST_REV_WITH_DB_CHANGES
  162. ) {
  163. $testTable = '::test_tb_for_update';
  164. if (
  165. null === $e
  166. && true === $this->c->DB->tableExists($testTable)
  167. ) {
  168. $e = ['The %s table already exists. Delete it.', $testTable];
  169. }
  170. $schema = [
  171. 'FIELDS' => [
  172. 'id' => ['SERIAL', false],
  173. ],
  174. 'PRIMARY KEY' => ['id'],
  175. ];
  176. if (
  177. null === $e
  178. && false === $this->c->DB->createTable($testTable, $schema)
  179. ) {
  180. $e = ['Unable to create %s table', $testTable];
  181. }
  182. if (
  183. null === $e
  184. && false === $this->c->DB->addField($testTable, 'test_field', 'VARCHAR(80)', false, '')
  185. ) {
  186. $e = ['Unable to add test_field field to %s table', $testTable];
  187. }
  188. $sql = "INSERT INTO {$testTable} (test_field) VALUES ('TEST_VALUE')";
  189. if (
  190. null === $e
  191. && false === $this->c->DB->exec($sql)
  192. ) {
  193. $e = ['Unable to insert line to %s table', $testTable];
  194. }
  195. if (
  196. null === $e
  197. && false === $this->c->DB->dropField($testTable, 'test_field')
  198. ) {
  199. $e = ['Unable to drop test_field field from %s table', $testTable];
  200. }
  201. if (
  202. null === $e
  203. && false === $this->c->DB->dropTable($testTable)
  204. ) {
  205. $e = ['Unable to drop %s table', $testTable];
  206. }
  207. }
  208. if (null !== $e) {
  209. return $this->c->Message->message($e, true, 503);
  210. }
  211. $uid = $this->setLock();
  212. if (null === $uid) {
  213. $this->fIswev = ['e', 'Unable to write update lock'];
  214. } else {
  215. $this->c->config->o_maintenance_message = $v->o_maintenance_message;
  216. $this->c->config->save();
  217. return $this->c->Redirect->page('AdminUpdateStage', ['uid' => $uid, 'stage' => 1]);
  218. }
  219. } else {
  220. $this->fIswev = $v->getErrors();
  221. }
  222. } else {
  223. $v = null;
  224. }
  225. $this->form = $this->form($v);
  226. return $this;
  227. }
  228. /**
  229. * Проверяет пароль базы
  230. */
  231. public function vCheckPass(Validator $v, string $dbpass): string
  232. {
  233. $this->okPass = true;
  234. if (\substr($this->c->DB_DSN, 0, 6) === 'sqlite') {
  235. if (! \hash_equals($this->c->DB_DSN, "sqlite:{$dbpass}")) {
  236. $this->okPass = false;
  237. $v->addError(['Invalid file error', self::CONFIG_FILE]);
  238. }
  239. } else {
  240. if (! \hash_equals($this->c->DB_PASSWORD, $dbpass)) {
  241. $this->okPass = false;
  242. $v->addError(['Invalid password error', self::CONFIG_FILE]);
  243. }
  244. }
  245. return $dbpass;
  246. }
  247. /**
  248. * Формирует массив для формы
  249. */
  250. protected function form(?Validator $v): array
  251. {
  252. return [
  253. 'action' => $this->c->Router->link('AdminUpdate'),
  254. 'hidden' => [
  255. 'token' => $this->c->Csrf->create('AdminUpdate'),
  256. ],
  257. 'sets' => [
  258. 'update-info' => [
  259. 'info' => [
  260. [
  261. 'value' => __('Update message'),
  262. ],
  263. ],
  264. ],
  265. 'update' => [
  266. 'legend' => 'Update ForkBB',
  267. 'fields' => [
  268. 'dbpass' => [
  269. 'type' => 'password',
  270. 'value' => '',
  271. 'caption' => 'Database password',
  272. 'help' => 'Database password note',
  273. ],
  274. 'o_maintenance_message' => [
  275. 'type' => 'textarea',
  276. 'value' => $v->o_maintenance_message ?? $this->c->config->o_maintenance_message,
  277. 'caption' => 'Maintenance message',
  278. 'help' => 'Maintenance message info',
  279. 'required' => true,
  280. ],
  281. ],
  282. ],
  283. 'member-info' => [
  284. 'info' => [
  285. [
  286. 'value' => __('Members message'),
  287. ],
  288. ],
  289. ],
  290. ],
  291. 'btns' => [
  292. 'start' => [
  293. 'type' => 'submit',
  294. 'value' => __('Start update'),
  295. ],
  296. ],
  297. ];
  298. }
  299. /**
  300. * Обновляет форум
  301. */
  302. public function stage(array $args, string $method): Page
  303. {
  304. try {
  305. $uid = $this->setLock($args['uid']);
  306. if (null === $uid) {
  307. return $this->returnMaintenance();
  308. }
  309. $stage = \max($args['stage'], $this->c->config->i_fork_revision);
  310. do {
  311. if (\method_exists($this, 'stageNumber' . $stage)) {
  312. $start = $this->{'stageNumber' . $stage}($args);
  313. if (null === $start) {
  314. ++$stage;
  315. }
  316. return $this->c->Redirect->page(
  317. 'AdminUpdateStage',
  318. ['uid' => $uid, 'stage' => $stage, 'start' => $start]
  319. )->message(['Stage %1$s (%2$s)', $stage, (int) $start]);
  320. }
  321. ++$stage;
  322. } while ($stage < $this->c->FORK_REVISION);
  323. $this->c->config->i_fork_revision = $this->c->FORK_REVISION;
  324. $this->c->config->save();
  325. if (true !== $this->c->Cache->clear()) {
  326. throw new RuntimeException('Unable to clear cache');
  327. }
  328. return $this->c->Redirect->page('Index')->message('Successfully updated');
  329. } catch (ForkException $excp) {
  330. return $this->c->Message->message($excp->getMessage(), true, 503);
  331. }
  332. }
  333. # /**
  334. # * Выполняет определенный шаг обновления
  335. # *
  336. # * Возвращает null, если шаг выпонен
  337. # * Возвращает положительный int, если требуется продолжить выполнение шага
  338. # */
  339. # protected function stageNumber1(array $args): ?int
  340. # {
  341. # $coreConfig = new CoreConfig($this->configFile);
  342. #
  343. # $coreConfig->add(
  344. # 'multiple=>AdminUsersRecalculate',
  345. # '\\ForkBB\\Models\\Pages\\Admin\\Users\\Recalculate::class',
  346. # 'AdminUsersNew'
  347. # );
  348. #
  349. # $coreConfig->save();
  350. #
  351. # return null;
  352. # }
  353. /**
  354. * rev.42 to rev.43
  355. */
  356. protected function stageNumber42(array $args): ?int
  357. {
  358. $query = 'DELETE FROM ::users WHERE id=1';
  359. $this->c->DB->exec($query);
  360. $query = 'UPDATE ::forums SET last_poster_id=0 WHERE last_poster_id=1';
  361. $this->c->DB->exec($query);
  362. $query = 'UPDATE ::online SET user_id=0 WHERE user_id=1';
  363. $this->c->DB->exec($query);
  364. $query = 'UPDATE ::pm_posts SET poster_id=0 WHERE poster_id=1';
  365. $this->c->DB->exec($query);
  366. $query = 'UPDATE ::pm_topics SET poster_id=0 WHERE poster_id=1';
  367. $this->c->DB->exec($query);
  368. $query = 'UPDATE ::pm_topics SET target_id=0 WHERE target_id=1';
  369. $this->c->DB->exec($query);
  370. $query = 'UPDATE ::posts SET poster_id=0 WHERE poster_id=1';
  371. $this->c->DB->exec($query);
  372. $query = 'UPDATE ::posts SET editor_id=0 WHERE editor_id=1';
  373. $this->c->DB->exec($query);
  374. $query = 'UPDATE ::reports SET reported_by=0 WHERE reported_by=1';
  375. $this->c->DB->exec($query);
  376. $query = 'UPDATE ::reports SET zapped_by=0 WHERE zapped_by=1';
  377. $this->c->DB->exec($query);
  378. $query = 'UPDATE ::topics SET poster_id=0 WHERE poster_id=1';
  379. $this->c->DB->exec($query);
  380. $query = 'UPDATE ::topics SET last_poster_id=0 WHERE last_poster_id=1';
  381. $this->c->DB->exec($query);
  382. $query = 'UPDATE ::warnings SET poster_id=0 WHERE poster_id=1';
  383. $this->c->DB->exec($query);
  384. $coreConfig = new CoreConfig($this->configFile);
  385. $coreConfig->add(
  386. 'shared=>Groups/save',
  387. '\\ForkBB\\Models\\Group\\Save::class',
  388. 'Group/save'
  389. );
  390. $coreConfig->add(
  391. 'shared=>Groups/perm',
  392. '\\ForkBB\\Models\\Group\\Perm::class',
  393. 'Group/save'
  394. );
  395. $coreConfig->add(
  396. 'shared=>Groups/delete',
  397. '\\ForkBB\\Models\\Group\\Delete::class',
  398. 'Group/save'
  399. );
  400. $result = $coreConfig->delete('shared=>Group/delete');
  401. $result = $coreConfig->delete('shared=>Group/perm');
  402. $result = $coreConfig->delete('shared=>Group/save');
  403. $coreConfig->save();
  404. $this->c->config->a_guest_set = [
  405. 'show_smilies' => 1,
  406. 'show_sig' => 1,
  407. 'show_avatars' => 1,
  408. 'show_img' => 1,
  409. 'show_img_sig' => 1,
  410. ];
  411. $this->c->config->save();
  412. return null;
  413. }
  414. /**
  415. * rev.43 to rev.44
  416. */
  417. protected function stageNumber43(array $args): ?int
  418. {
  419. $config = $this->c->config;
  420. $config->i_timeout_visit = $config->o_timeout_visit ?? 3600;
  421. $config->i_timeout_online = $config->o_timeout_online ?? 900;
  422. $config->i_redirect_delay = $config->o_redirect_delay ?? 1;
  423. $config->b_show_user_info = '1' == $config->o_show_user_info ? 1 : 0;
  424. $config->b_show_post_count = '1' == $config->o_show_post_count ? 1 : 0;
  425. $config->b_smilies_sig = '1' == $config->o_smilies_sig ? 1 : 0;
  426. $config->b_smilies = '1' == $config->o_smilies ? 1 : 0;
  427. $config->b_make_links = '1' == $config->o_make_links ? 1 : 0;
  428. $config->b_quickpost = '1' == $config->o_quickpost ? 1 : 0;
  429. $config->b_users_online = '1' == $config->o_users_online ? 1 : 0;
  430. $config->b_censoring = '1' == $config->o_censoring ? 1 : 0;
  431. $config->b_show_dot = '1' == $config->o_show_dot ? 1 : 0;
  432. $config->b_topic_views = '1' == $config->o_topic_views ? 1 : 0;
  433. $config->b_regs_report = '1' == $config->o_regs_report ? 1 : 0;
  434. $config->b_avatars = '1' == $config->o_avatars ? 1 : 0;
  435. $config->b_forum_subscriptions = '1' == $config->o_forum_subscriptions ? 1 : 0;
  436. $config->b_topic_subscriptions = '1' == $config->o_topic_subscriptions ? 1 : 0;
  437. $config->b_smtp_ssl = '1' == $config->o_smtp_ssl ? 1 : 0;
  438. $config->b_regs_allow = '1' == $config->o_regs_allow ? 1 : 0;
  439. $config->b_announcement = '1' == $config->o_announcement ? 1 : 0;
  440. $config->b_rules = '1' == $config->o_rules ? 1 : 0;
  441. $config->b_maintenance = '1' == $config->o_maintenance ? 1 : 0;
  442. $config->b_default_dst = '1' == $config->o_default_dst ? 1 : 0;
  443. $config->b_message_bbcode = '1' == $config->p_message_bbcode ? 1 : 0;
  444. $config->b_message_all_caps = '1' == $config->p_message_all_caps ? 1 : 0;
  445. $config->b_subject_all_caps = '1' == $config->p_subject_all_caps ? 1 : 0;
  446. $config->b_sig_all_caps = '1' == $config->p_sig_all_caps ? 1 : 0;
  447. $config->b_sig_bbcode = '1' == $config->p_sig_bbcode ? 1 : 0;
  448. $config->b_force_guest_email = '1' == $config->p_force_guest_email ? 1 : 0;
  449. unset($config->p_force_guest_email);
  450. unset($config->p_sig_bbcode);
  451. unset($config->p_sig_all_caps);
  452. unset($config->p_subject_all_caps);
  453. unset($config->p_message_all_caps);
  454. unset($config->p_message_bbcode);
  455. unset($config->o_default_dst);
  456. unset($config->o_maintenance);
  457. unset($config->o_rules);
  458. unset($config->o_announcement);
  459. unset($config->o_regs_allow);
  460. unset($config->o_smtp_ssl);
  461. unset($config->o_topic_subscriptions);
  462. unset($config->o_forum_subscriptions);
  463. unset($config->o_avatars);
  464. unset($config->o_regs_report);
  465. unset($config->o_topic_views);
  466. unset($config->o_show_dot);
  467. unset($config->o_timeout_visit);
  468. unset($config->o_timeout_online);
  469. unset($config->o_redirect_delay);
  470. unset($config->o_show_user_info);
  471. unset($config->o_show_post_count);
  472. unset($config->o_smilies_sig);
  473. unset($config->o_smilies);
  474. unset($config->o_make_links);
  475. unset($config->o_quickpost);
  476. unset($config->o_users_online);
  477. unset($config->o_censoring);
  478. unset($config->o_quickjump);
  479. unset($config->o_search_all_forums);
  480. $config->save();
  481. return null;
  482. }
  483. /**
  484. * rev.44 to rev.45
  485. */
  486. protected function stageNumber44(array $args): ?int
  487. {
  488. if (! $this->c->DB->query('SELECT id FROM ::bbcode WHERE bb_tag=?s', ['from'])->fetchColumn()) {
  489. $bbcodes = include $this->c->DIR_CONFIG . '/defaultBBCode.php';
  490. foreach ($bbcodes as $bbcode) {
  491. if ('from' !== $bbcode['tag']) {
  492. continue;
  493. }
  494. $vars = [
  495. ':tag' => $bbcode['tag'],
  496. ':structure' => \json_encode($bbcode, self::JSON_OPTIONS),
  497. ];
  498. $query = 'INSERT INTO ::bbcode (bb_tag, bb_edit, bb_delete, bb_structure)
  499. VALUES(?s:tag, 1, 0, ?s:structure)';
  500. $this->c->DB->exec($query, $vars);
  501. }
  502. }
  503. return null;
  504. }
  505. /**
  506. * rev.45 to rev.46
  507. */
  508. protected function stageNumber45(array $args): ?int
  509. {
  510. $coreConfig = new CoreConfig($this->configFile);
  511. $coreConfig->add(
  512. 'shared=>Cache=>reset_mark',
  513. '\'%DB_DSN% %DB_PREFIX%\'',
  514. 'cache_dir'
  515. );
  516. $coreConfig->save();
  517. // чтобы кэш не был сброшен до завершения обновления
  518. $hash = \sha1($this->c->DB_DSN . ' ' . $this->c->DB_PREFIX);
  519. $this->c->Cache->set('reset_mark_hash', $hash);
  520. return null;
  521. }
  522. /**
  523. * rev.46 to rev.47
  524. */
  525. protected function stageNumber46(array $args): ?int
  526. {
  527. $coreConfig = new CoreConfig($this->configFile);
  528. $coreConfig->add(
  529. 'shared=>Mail=>ssl',
  530. '\'%config.b_smtp_ssl%\''
  531. );
  532. $coreConfig->save();
  533. return null;
  534. }
  535. /**
  536. * rev.47 to rev.48
  537. */
  538. protected function stageNumber47(array $args): ?int
  539. {
  540. $config = $this->c->config;
  541. $config->s_РЕГИСТР = 'Ok';
  542. $config->save();
  543. $coreConfig = new CoreConfig($this->configFile);
  544. $coreConfig->add(
  545. 'shared=>Config/insensitive',
  546. '\\ForkBB\\Models\\Config\\Insensitive::class',
  547. 'Config/save'
  548. );
  549. $coreConfig->save();
  550. return null;
  551. }
  552. /**
  553. * rev.48 to rev.49
  554. */
  555. protected function stageNumber48(array $args): ?int
  556. {
  557. $coreConfig = new CoreConfig($this->configFile);
  558. $coreConfig->add(
  559. 'DATE_FORMATS',
  560. ['\'Y-m-d\'', '\'d M Y\'', '\'Y-m-d\'', '\'Y-d-m\'', '\'d-m-Y\'', '\'m-d-Y\'', '\'M j Y\'', '\'jS M Y\''],
  561. 'HTTP_HEADERS'
  562. );
  563. $coreConfig->add(
  564. 'TIME_FORMATS',
  565. ['\'H:i:s\'', '\'H:i\'', '\'H:i:s\'', '\'H:i\'', '\'g:i:s a\'', '\'g:i a\''],
  566. 'DATE_FORMATS'
  567. );
  568. $coreConfig->add(
  569. 'shared=>%DIR_VIEWS%',
  570. '\'%DIR_APP%/templates\'',
  571. 'DB'
  572. );
  573. $coreConfig->add(
  574. 'shared=>%DIR_LOG%',
  575. '\'%DIR_APP%/log\'',
  576. 'DB'
  577. );
  578. $coreConfig->add(
  579. 'shared=>%DIR_LANG%',
  580. '\'%DIR_APP%/lang\'',
  581. 'DB'
  582. );
  583. $coreConfig->add(
  584. 'shared=>%DIR_CONFIG%',
  585. '\'%DIR_APP%/config\'',
  586. 'DB'
  587. );
  588. $coreConfig->add(
  589. 'shared=>%DIR_CACHE%',
  590. '\'%DIR_APP%/cache\'',
  591. 'DB'
  592. );
  593. $coreConfig->add(
  594. 'shared=>%DIR_APP%',
  595. '\'%DIR_ROOT%/app\'',
  596. 'DB'
  597. );
  598. $coreConfig->add(
  599. 'shared=>%DIR_PUBLIC%',
  600. '\'%DIR_ROOT%/public\'',
  601. 'DB'
  602. );
  603. $coreConfig->add(
  604. 'shared=>%DIR_ROOT%',
  605. '\\realpath(__DIR__ . \'/../..\')',
  606. 'DB'
  607. );
  608. $coreConfig->add(
  609. 'shared=>HTMLCleaner=>config',
  610. '\'%DIR_CONFIG%/jevix.default.php\''
  611. );
  612. $coreConfig->save();
  613. return null;
  614. }
  615. }