EPESI BIM • Business Information Manager • Cloud CRM/ERP http://epe.si/
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.

update.php 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. <?php
  2. /**
  3. * EPESI Core updater.
  4. *
  5. * @author Adam Bukowski <abukowski@telaxus.com> and Pawel Bukowski <pbukowski@telaxus.com>
  6. * @version 2.0
  7. * @copyright Copyright &copy; 2014, Telaxus LLC
  8. * @license MIT
  9. * @package epesi-base
  10. */
  11. defined("_VALID_ACCESS") || define("_VALID_ACCESS", true);
  12. class EpesiPackageDownloader
  13. {
  14. private $versions;
  15. private function __construct()
  16. {
  17. self::check_system_requirements();
  18. }
  19. public static function instance()
  20. {
  21. static $instance;
  22. if ($instance === null) {
  23. $instance = new self();
  24. }
  25. return $instance;
  26. }
  27. public function get_update_json()
  28. {
  29. $ret = self::download('http://ess.epe.si/update.json');
  30. $update_json = @json_decode($ret, true);
  31. if ($update_json === null) {
  32. throw new ErrorException('Cannot decode update.json file: ' . $ret);
  33. }
  34. return $update_json;
  35. }
  36. public function get_versions()
  37. {
  38. if (!$this->versions) {
  39. $update_json = $this->get_update_json();
  40. if (!isset($update_json['files'])) {
  41. throw new ErrorException('No files defined in update.json');
  42. }
  43. $this->versions = $update_json['files'];
  44. }
  45. return $this->versions;
  46. }
  47. public function get_latest_package_info()
  48. {
  49. $versions = $this->get_versions();
  50. $latest = end($versions);
  51. return $latest;
  52. }
  53. public function get_package_info($current_revision, $offset)
  54. {
  55. $versions = $this->get_versions();
  56. $found = false;
  57. $skip_update = ($offset != 0);
  58. foreach ($versions as $v) {
  59. if ($found == false && $v['revision'] == $current_revision) {
  60. $found = true;
  61. if ($offset == 0) {
  62. return $v;
  63. }
  64. $offset -= 1;
  65. continue;
  66. }
  67. if ($found) {
  68. if ($skip_update && isset($v['skip']) && $v['skip']) continue;
  69. if ($offset == 0) {
  70. return $v;
  71. }
  72. $offset -= 1;
  73. }
  74. }
  75. return false;
  76. }
  77. public function download_package($current_revision, $offset)
  78. {
  79. $package_info = $this->get_package_info($current_revision, $offset);
  80. if (!$package_info) {
  81. return false;
  82. }
  83. foreach (array('file', 'checksum', 'signature') as $key) {
  84. if (!isset($package_info[$key])) {
  85. throw new ErrorException("Missing '$key' in package info");
  86. }
  87. }
  88. $filename = EPESI == 'EPESI' ? 'epesi' : 'update';
  89. $package_file = "$filename-$package_info[version]-$package_info[revision].ei.zip";
  90. $file_exists = file_exists($package_file);
  91. if (!$file_exists) {
  92. self::download($package_info['file'], $package_file);
  93. }
  94. $package_checksum = sha1_file($package_file);
  95. if ($package_info['checksum'] != $package_checksum) {
  96. throw new ErrorException("Checksum mismatch. Downloaded=$package_checksum, should be=$package_info[checksum]");
  97. }
  98. $verify_status = openssl_verify(file_get_contents($package_file), base64_decode($package_info['signature']), self::get_public_key(), OPENSSL_ALGO_SHA256);
  99. if ($verify_status === 0) {
  100. throw new ErrorException("Signature incorrect");
  101. }
  102. if ($verify_status === -1) {
  103. $error_string = openssl_error_string();
  104. if (!$error_string) {
  105. $error_string = 'no error string reported';
  106. }
  107. throw new ErrorException("Signature verify error: " . $error_string);
  108. }
  109. return new EpesiUpdatePackage($package_file);
  110. }
  111. public function get_update_package_info($current_revision)
  112. {
  113. $package_info = $this->get_package_info($current_revision, 1);
  114. return $package_info;
  115. }
  116. public function get_update_package($current_revision)
  117. {
  118. return $this->download_package($current_revision, 1);
  119. }
  120. public function get_current_package($current_revision)
  121. {
  122. return $this->download_package($current_revision, 0);
  123. }
  124. public static function get_public_key()
  125. {
  126. $PUBLIC_KEY = <<<KEY
  127. -----BEGIN PUBLIC KEY-----
  128. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvWFAZMVAGr3fPNK0v9Vt
  129. IErRSpl4I3wIWTr1kybpY8/+j9IX/t9qLvOPY4OVrkzURmKvS+VbSU8MSYZz9QIL
  130. TJUmNYkkyqJieSpQCq/7x5J2it+i1TeGKk8m3sOpL17+NUa/1e8a4W6FmLl9hwLd
  131. 8TQnlVQJIva3JXA46S1E3BNPbaWdQrwABs5xGUterE890+rW63/pgD1pT1qEbmif
  132. oiTuG+dyhCo+REcjo8YWIpi+8BNJoo3Nn7Xxi71yA2Ps8DElIjjNRa/ca5A6SE61
  133. euoJaHtTSc7OsuDug2Rv0aQkvR7OmFyfIJAdAasZHWePWeuezlKJAAcvNFdjZ0Zw
  134. KwIDAQAB
  135. -----END PUBLIC KEY-----
  136. KEY;
  137. return $PUBLIC_KEY;
  138. }
  139. public static function download($fileurl, $file = null) {
  140. $ch = curl_init($fileurl);
  141. curl_setopt($ch, CURLOPT_VERBOSE, 0);
  142. curl_setopt($ch, CURLOPT_HEADER, 0);
  143. curl_setopt($ch, CURLOPT_TIMEOUT, 50);
  144. curl_setopt($ch, CURLOPT_TIMEOUT, 300);
  145. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  146. if ($file) {
  147. $f = fopen($file, 'w');
  148. if ($f === false) {
  149. throw new ErrorException("Cannot write into file: $file");
  150. }
  151. curl_setopt($ch, CURLOPT_FILE, $f);
  152. } else {
  153. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  154. }
  155. $output = curl_exec($ch);
  156. $error_message = curl_error($ch);
  157. curl_close($ch);
  158. if ($file) {
  159. fclose($f);
  160. }
  161. if ($error_message != '') throw new ErrorException($error_message);
  162. return $output;
  163. }
  164. public static function check_system_requirements()
  165. {
  166. if (!class_exists('ZipArchive')) {
  167. throw new ErrorException('Missing zip extension');
  168. }
  169. if (!function_exists('curl_init')) {
  170. throw new ErrorException('Missing cURL extension');
  171. }
  172. }
  173. }
  174. class EpesiUpdatePackage
  175. {
  176. private $file;
  177. private $zip;
  178. public function __construct($file)
  179. {
  180. $this->file = $file;
  181. $this->zip = new ZipArchive();
  182. $status = $this->zip->open($file);
  183. if ($status !== true) {
  184. throw new ErrorException(__('Zip %s open error: %s', array($this->file,$status)));
  185. }
  186. }
  187. public function __destruct()
  188. {
  189. $this->zip->close();
  190. }
  191. public function delete()
  192. {
  193. @unlink($this->file);
  194. }
  195. public function get_file()
  196. {
  197. return $this->file;
  198. }
  199. public function files_not_writable()
  200. {
  201. $problems = array();
  202. for ($i = 0; $i < $this->zip->numFiles; $i++) {
  203. $stat = $this->zip->statIndex($i);
  204. $f = './' . $stat['name'];
  205. if (file_exists($f)) {
  206. if (!is_writable($f)) {
  207. $problems[] = $f;
  208. }
  209. } else {
  210. $up_f = basename($f);
  211. if (file_exists($up_f) && !is_writable($up_f)) {
  212. $problems[] = $up_f;
  213. }
  214. }
  215. }
  216. return $problems;
  217. }
  218. public function files_modified()
  219. {
  220. $problems = array();
  221. for ($i = 0; $i < $this->zip->numFiles; $i++) {
  222. $stat = $this->zip->statIndex($i);
  223. $f = './' . $stat['name'];
  224. if (file_exists($f)) {
  225. $system_file_checksum = sprintf("%u", hexdec(hash_file('crc32b', $f)));
  226. $archive_file_checksum = sprintf("%u", $stat['crc']);
  227. if ($system_file_checksum != $archive_file_checksum) {
  228. $problems[] = $f;
  229. }
  230. }
  231. }
  232. return $problems;
  233. }
  234. public function extract()
  235. {
  236. $success = $this->zip->extractTo('./');
  237. return $success;
  238. }
  239. public function wipe() {
  240. for ($i = 0; $i < $this->zip->numFiles; $i++) {
  241. $stat = $this->zip->statIndex($i);
  242. $f = './' . $stat['name'];
  243. if (file_exists($f) && !is_dir($f)) {
  244. unlink($f);
  245. }
  246. }
  247. }
  248. public function create_backup_of_modified_files()
  249. {
  250. $files = $this->files_modified();
  251. if (empty($files)) {
  252. return '';
  253. }
  254. $release_package = substr($this->file, 0, -4);
  255. do {
  256. $random_string = substr(str_shuffle("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 12);
  257. $backup_file = "modified_since_{$release_package}_{$random_string}.bkp.zip";
  258. } while (file_exists($backup_file));
  259. $b = new Backup($backup_file);
  260. $b->create($files, "Modified files backup");
  261. return $backup_file;
  262. }
  263. }
  264. class EpesiUpdate
  265. {
  266. public function run()
  267. {
  268. try {
  269. $this->load_epesi();
  270. if ($this->check_user()) {
  271. if (!epesi_requires_update()) {
  272. if ($this->handle_update_package() == false) {
  273. $this->version_up_to_date();
  274. }
  275. }
  276. $this->update_process();
  277. } else {
  278. $this->require_admin_login();
  279. }
  280. } catch (Exception $ex) {
  281. $this->quit('Exception occured: ' . $ex->getMessage());
  282. }
  283. }
  284. protected function load_epesi()
  285. {
  286. $this->CLI = (php_sapi_name() == 'cli');
  287. if ($this->CLI) {
  288. global $argv;
  289. // allow to define DATA directory for CLI in argument
  290. if (isset($argv)) {
  291. define('EPESI_DIR','/');
  292. foreach (array_slice($argv, 1) as $x) {
  293. if ($x == '-f') {
  294. $this->cli_force_update = true;
  295. } elseif ($x == '-b') {
  296. $this->cli_create_backup = true;
  297. } else {
  298. define('DATA_DIR', $x);
  299. }
  300. }
  301. }
  302. }
  303. define('CID', false);
  304. require_once 'include.php';
  305. require_once 'include/backups.php';
  306. // Enable all disabled modules
  307. // check if method exists, because we recommend to use this update
  308. // script on older installations where method was not present
  309. if (method_exists('ModuleManager', 'enable_modules')) {
  310. ModuleManager::enable_modules(ModuleManager::MODULE_NOT_FOUND);
  311. }
  312. ModuleManager::load_modules();
  313. Base_LangCommon::load();
  314. $this->system_version = Variable::get('version');
  315. $this->current_version = EPESI_VERSION;
  316. $this->current_revision = EPESI_REVISION;
  317. }
  318. protected function quit($msg)
  319. {
  320. if ($this->CLI) {
  321. die(strip_tags($msg) . "\n");
  322. } else {
  323. $this->body($msg);
  324. die();
  325. }
  326. }
  327. protected function check_user()
  328. {
  329. if ($this->CLI) {
  330. Base_AclCommon::set_sa_user();
  331. if (!Base_AclCommon::i_am_sa()) {
  332. $this->quit('No proper admin user.');
  333. }
  334. }
  335. return Base_AclCommon::i_am_sa();
  336. }
  337. public function version_up_to_date()
  338. {
  339. $net_blocked = $this->net_update_blocked();
  340. $net_blocked_msg = __('Network update has been blocked.');
  341. $msg = __('Your %s does not require update', array(EPESI));
  342. if ($this->CLI) {
  343. if ($net_blocked) print ($net_blocked_msg . "\n");
  344. print ($msg . "\n");
  345. print (__('Update procedure forced') . "\n");
  346. } else {
  347. if ($net_blocked) $msg .= '<br><br>' . $net_blocked_msg;
  348. $msg .= $this->saved_backups_list();
  349. $this->quit($msg);
  350. }
  351. }
  352. public function saved_backups_list()
  353. {
  354. $files = array();
  355. foreach (glob('*.bkp.zip') as $f) $files[$f] = new Backup($f);
  356. if (isset($_GET['delete']) && isset($files[$_GET['delete']]) && file_exists($_GET['delete'])) {
  357. unlink($_GET['delete']);
  358. unset($files[$_GET['delete']]);
  359. $this->redirect(array());
  360. }
  361. uasort($files, function(Backup $a, Backup $b) { return $a->get_date() > $b->get_date();});
  362. $backups = '';
  363. foreach ($files as $file => $backup) {
  364. $download_url = urlencode($file);
  365. $download = "<a target=\"_blank\" href=\"$download_url\">[" . __('Download') . "]</a>";
  366. $delete_href = '?' . http_build_query(array('delete' => $file));
  367. $delete = "<a href=\"$delete_href\">[" . __('Delete') . "]</a>";
  368. $description = date("Y-m-d H:i:s", $backup->get_date()) . " - $file $download $delete";
  369. $backups .= "$description<br>";
  370. }
  371. $ret = '';
  372. if ($backups) {
  373. $ret = "<h3>" . __('Backups') . "</h3><p>$backups</p>";
  374. }
  375. return $ret;
  376. }
  377. protected function require_admin_login()
  378. {
  379. $msg = '<p><strong>' . __("You need to be logged in as super admin use this script.") . '</strong></p>';
  380. $msg .= $this->login_form();
  381. $this->quit($msg);
  382. }
  383. protected function login_form()
  384. {
  385. if (Base_AclCommon::i_am_user() && !Base_AclCommon::i_am_sa()) {
  386. Base_User_LoginCommon::logout();
  387. }
  388. $form = SimpleLogin::form();
  389. return "<p>$form</p>";
  390. }
  391. protected function cli_msg($msg)
  392. {
  393. if ($this->CLI) {
  394. print ($msg . "\n");
  395. }
  396. }
  397. protected function net_update_blocked()
  398. {
  399. return file_exists('.git') || file_exists('.noupdate');
  400. }
  401. protected function get_update_package()
  402. {
  403. if ($this->net_update_blocked()) {
  404. return false;
  405. }
  406. return EpesiPackageDownloader::instance()->get_update_package_info($this->current_revision);
  407. }
  408. protected function handle_update_package()
  409. {
  410. $update_package_info = $this->get_update_package();
  411. if ($update_package_info) {
  412. if (!$this->CLI && (TRIAL_MODE || DEMO_MODE)) {
  413. $this->quit(__('There is an update, but you don\'t have permissions to perform it. Please contact system administrator.'));
  414. }
  415. $latest_package_info = EpesiPackageDownloader::instance()->get_latest_package_info();
  416. $latest_version = $update_package_info['revision'] == $latest_package_info['revision'];
  417. $this->cli_msg("There is update package...");
  418. $action = false;
  419. if ($this->CLI) $action = 'get';
  420. if (isset($_GET['action'])) $action = $_GET['action'];
  421. if ($action) {
  422. $this->cli_msg("Downloading update package: $update_package_info[version]-$update_package_info[revision]...");
  423. $update_package = EpesiPackageDownloader::instance()->get_update_package($this->current_revision);
  424. $problems = $update_package->files_not_writable();
  425. if ($problems) {
  426. $this->quit('<p><strong>' . __('Files not writable (please fix permissions)') . ':</strong></p>'."\n" . implode("<br>\n", $problems));
  427. }
  428. $this->cli_msg("Downloading current release package...");
  429. $current_package = EpesiPackageDownloader::instance()->get_current_package($this->current_revision);
  430. if (!$current_package) {
  431. throw new ErrorException('Cannot download current package');
  432. }
  433. $this->cli_msg("Looking for changes or permissions problems...");
  434. $problems = $current_package->files_not_writable();
  435. if ($problems) {
  436. $this->quit('<p><strong>' . __('Files not writable (please fix permissions)') . ':</strong></p>'."\n" . implode("<br>\n", $problems));
  437. }
  438. if ($this->CLI) {
  439. $problems = $current_package->files_modified();
  440. if ($problems) {
  441. $this->cli_msg("Modified files:\n" . implode("\n", $problems));
  442. if ($this->cli_create_backup) {
  443. $this->cli_msg('Creating backup of modified files');
  444. $backup_file = $current_package->create_backup_of_modified_files();
  445. $this->cli_msg("Backup saved to: $backup_file");
  446. }
  447. if ($this->cli_force_update) {
  448. $this->cli_msg('Update forced!');
  449. } else {
  450. $this->quit('Use -f switch to force update, -b to create backup of modified files. Both -f -b to backup and update');
  451. }
  452. }
  453. } else {
  454. if ($action == 'update') {
  455. // do nothing
  456. } elseif ($action == 'backup') {
  457. $backup_file = $current_package->create_backup_of_modified_files();
  458. $backup_msg = '<p><strong>' . __('Backup has been made') . '</strong></p>' . "\n";
  459. $backup_msg .= '<br>' . '<p>' . __('Your backup is in the file: %s', array($backup_file)) . "</p>\n";
  460. $backup_msg .= '<br>' . '<p><a class="button" href="?action=update">' . __('Update!') . '</a></p>';
  461. $this->quit($backup_msg);
  462. } else {
  463. $problems = $current_package->files_modified();
  464. if ($problems) {
  465. $create_backup_msg = '<p><strong>' . __('Files with custom modifications') . ':</strong></p>' . "\n" . implode("<br>\n", $problems);
  466. $create_backup_msg .= '<br>' . '<p><a class="button" href="?action=backup">' . __('Backup modified files!') . '</a></p>';
  467. $this->quit($create_backup_msg);
  468. }
  469. }
  470. }
  471. $this->turn_on_maintenance_mode();
  472. $this->cli_msg("Wipe current files...");
  473. $current_package->wipe();
  474. $this->cli_msg("Extract new files...");
  475. if ($update_package->extract()) {
  476. $this->cli_msg("Delete package files...");
  477. $current_package->delete();
  478. if ($latest_version) {
  479. $update_package->delete();
  480. }
  481. $this->cli_msg("Patches redirect...");
  482. $this->redirect(array());
  483. } else {
  484. $current_package->extract();
  485. $this->quit(__('Extract error occured'));
  486. }
  487. } else {
  488. $header = __('Update package available to download!');
  489. $version_with_revision = "$this->current_version-$this->current_revision";
  490. $update_info = "$update_package_info[version]-$update_package_info[revision]";
  491. $current_ver = __('Your current %s version', array(EPESI)) . ': <strong>' . $version_with_revision . '</strong>';
  492. $text_p = __('Update Package') . ': <strong>' . $update_info . '</strong>';
  493. $warning_message = __('All core files will be replaced!') . '<br/><br/>'
  494. . __('If you have changed any of those files, then we will backup them first.');
  495. $info_message = __('Custom modules and your data will be preserved.');
  496. $msg = "<p><strong>$header</strong></p><p>$current_ver</p><p>$text_p</p>";
  497. $msg .= "<p style=\"color: red; font-weight: bold\">$warning_message</p>";
  498. $msg .= "<p style=\"font-weight: bold\">$info_message</p>";
  499. $msg .= '<p><a class="button" href="?action=get">' . __('Download!') . '</a></p>';
  500. $this->quit($msg);
  501. }
  502. }
  503. return false;
  504. }
  505. protected function update_process()
  506. {
  507. @set_time_limit(0);
  508. // console
  509. if ($this->CLI) {
  510. PatchUtil::disable_time_management();
  511. $this->perform_update_start();
  512. $this->perform_update_patches(false);
  513. $this->perform_update_end();
  514. $update_package = $this->get_update_package();
  515. if ($update_package) $this->redirect(array());
  516. $this->quit(__('Done'));
  517. }
  518. // browser
  519. $up = & $_GET['up'];
  520. if ($up == 'start') {
  521. $this->perform_update_start();
  522. $this->redirect(array('up' => 'patches'));
  523. } elseif ($up == 'patches') {
  524. $success = $this->perform_update_patches();
  525. if ($success) {
  526. $this->redirect(array('up' => 'end'));
  527. }
  528. } elseif ($up == 'end') {
  529. $this->perform_update_end();
  530. $update_package = $this->get_update_package();
  531. $redirect = $update_package ? array() : get_epesi_url();
  532. $this->redirect($redirect);
  533. } else {
  534. $this->update_body();
  535. }
  536. }
  537. protected function redirect($url_or_get)
  538. {
  539. if ($this->CLI) {
  540. global $argv;
  541. print("Redirect...\n");
  542. $args = array_slice($argv, 1);
  543. array_unshift($args, __FILE__);
  544. system((defined('PHP_BINARY')?PHP_BINARY:'php').' '.implode(' ', $args));
  545. exit();
  546. }
  547. if (is_string($url_or_get)) {
  548. $location = $url_or_get;
  549. } else {
  550. $location = $_SERVER['PHP_SELF'];
  551. if (count($url_or_get)) {
  552. $location .= '?' . http_build_query($url_or_get);
  553. }
  554. }
  555. header("Location: $location");
  556. die();
  557. }
  558. protected function update_msg()
  559. {
  560. $msg = __('Update %s from version %s to %s.', array(EPESI, $this->system_version, $this->current_version));
  561. return "<p>$msg</p>";
  562. }
  563. protected function update_process_info_msg()
  564. {
  565. $do_not_close = __('Please do not close this window until process will be fully finished.');
  566. $url_text = __('help file');
  567. $url = get_epesi_url() . '/docs/UPDATE.md';
  568. $url = htmlspecialchars($url);
  569. $link = "<a href=\"$url\" target=\"_blank\">$url_text</a>";
  570. $info = __('Your browser drives update process. For more information read %s', array($link));
  571. $msg = "<p><strong>$do_not_close</strong></p><p>$info</p>";
  572. return "$msg";
  573. }
  574. protected function update_body()
  575. {
  576. $msg = $this->update_msg();
  577. $msg .= $this->update_process_info_msg();
  578. $msg .= ' <a class="button" href="?up=start">' . __('Update!') . '</a>';
  579. $this->quit($msg);
  580. }
  581. protected function turn_on_maintenance_mode()
  582. {
  583. if (MaintenanceMode::is_on()) return;
  584. $msg = __('%s is currently updating. Please wait or contact your system administrator.', array(EPESI));
  585. if ($this->CLI) {
  586. MaintenanceMode::turn_on($msg);
  587. } else {
  588. MaintenanceMode::turn_on_with_cookie($msg);
  589. }
  590. }
  591. protected function perform_update_start()
  592. {
  593. $this->cli_msg("Update from " . $this->system_version . " to " . $this->current_version . "...");
  594. $this->turn_on_maintenance_mode();
  595. //restore innodb tables in case of db reimport
  596. $mysql = stripos(DATABASE_DRIVER, 'mysql') !== false;
  597. if ($mysql) {
  598. $tbls = DB::MetaTables('TABLE', true);
  599. foreach ($tbls as $t) {
  600. $tbl = DB::GetRow('SHOW CREATE TABLE ' . $t);
  601. if (!isset($tbl[1]) || preg_match('/ENGINE=myisam/i', $tbl[1])) {
  602. DB::Execute('ALTER TABLE ' . $t . ' ENGINE = INNODB');
  603. }
  604. }
  605. }
  606. }
  607. protected function perform_update_patches($browser = true)
  608. {
  609. $this->turn_on_maintenance_mode();
  610. $patches = PatchUtil::apply_new(true);
  611. if ($browser) {
  612. $success = PatchUtil::all_successful($patches);
  613. if (!$success) {
  614. $msg = self::format_patches_msg($patches);
  615. $this->body($msg);
  616. }
  617. return $success;
  618. }
  619. }
  620. protected function format_patches_msg($patches)
  621. {
  622. $msg = "<h1>" . __('Patches to apply') . ":</h1>";
  623. $msg .= "<p>" . __('Last refresh') . ' - ' . date('Y-m-d H:i:s') . "</p>";
  624. $msg .= '<table>';
  625. // table header
  626. $format = "<tr><th>%s</th><th>%s</th><th>%s</th></tr>\n";
  627. $msg .= sprintf($format, __('Module'), __('Patch'), __('Status'));
  628. $format = "<tr><td>%s</td><td>%s</td><td style=\"text-align: center; font-size: 0.8em; color: gray\">%s</td></tr>\n";
  629. /** @var Patch $patch */
  630. foreach ($patches as $patch) {
  631. // show only awaiting or processed one
  632. if ($patch->get_apply_status() == Patch::STATUS_SUCCESS) {
  633. continue;
  634. }
  635. $status = __('pending');
  636. if ($patch->get_apply_status() == Patch::STATUS_TIMEOUT) {
  637. $status = '<img src="images/loader.gif" alt="Processing..." width="128" height="5" border="0">';
  638. }
  639. if (($user_message = $patch->get_user_message()) != null) {
  640. $status .= "<div>$user_message</div>";
  641. }
  642. $msg .= sprintf($format, $patch->get_module(), $patch->get_short_description(), $status);
  643. }
  644. $msg .= '</table>';
  645. $msg .= '<script type="text/javascript">location.reload(true)</script>';
  646. return $msg;
  647. }
  648. protected function perform_update_end()
  649. {
  650. $this->turn_on_maintenance_mode();
  651. Base_ThemeCommon::themeup();
  652. Base_LangCommon::update_translations();
  653. ModuleManager::create_load_priority_array();
  654. Variable::set('version', EPESI_VERSION);
  655. MaintenanceMode::turn_off();
  656. $this->cli_msg("Updated to " . $this->current_version);
  657. }
  658. protected function body($html)
  659. {
  660. ?>
  661. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  662. <html>
  663. <head>
  664. <meta content="text/html; charset=utf-8" http-equiv="content-type">
  665. <title><?php print(EPESI); ?> update</title>
  666. <link href="setup.css" type="text/css" rel="stylesheet"/>
  667. <meta name="robots" content="NOINDEX, NOARCHIVE">
  668. </head>
  669. <body>
  670. <table id="banner" border="0" cellpadding="0" cellspacing="0">
  671. <tr>
  672. <td class="image">&nbsp;</td>
  673. <td class="back">&nbsp;</td>
  674. </tr>
  675. </table>
  676. <br>
  677. <center>
  678. <table id="main" border="0" cellpadding="0" cellspacing="0">
  679. <tr>
  680. <td>
  681. <center>
  682. <?php print $html; ?>
  683. </center>
  684. </td>
  685. </tr>
  686. </table>
  687. </center>
  688. <br>
  689. <center>
  690. <span class="footer">Copyright &copy; 2016 &bull; <a
  691. href="http://www.telaxus.com">Telaxus LLC</a></span>
  692. <br>
  693. <p><a href="http://www.epesi.org"><img
  694. src="images/epesi-powered.png" alt="image"
  695. border="0"></a></p>
  696. </center>
  697. </body>
  698. </html>
  699. <?php
  700. }
  701. protected $CLI;
  702. protected $cli_force_update = false;
  703. protected $cli_create_backup = false;
  704. protected $system_version;
  705. protected $current_version;
  706. protected $current_revision;
  707. }
  708. $x = new EpesiUpdate();
  709. $x->run();