update-functions.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <?php
  2. trait UpdateFunctions
  3. {
  4. public function testScriptFilePermissions($script, $retest = false)
  5. {
  6. if (file_exists($script)) {
  7. if (is_executable($script)) {
  8. return true;
  9. } elseif (!$retest) {
  10. $this->setLoggerChannel('Update')->notice('Attempting to set correct permissions', ['file' => $script]);
  11. $permissions = shell_exec('chmod 777 ' . $script);
  12. return $this->testScriptFilePermissions($script, true);
  13. } else {
  14. $this->setLoggerChannel('Update')->warning('Update script doesn\'t have the correct permissions', ['file' => $script]);
  15. return false;
  16. }
  17. } else {
  18. $this->setLoggerChannel('Update')->warning('Update script doesn\'t exist', ['file' => $script]);
  19. return false;
  20. }
  21. }
  22. public function updateOrganizr()
  23. {
  24. if ($this->docker) {
  25. return $this->dockerUpdate();
  26. } elseif ($this->getOS() == 'win') {
  27. return $this->windowsUpdate();
  28. } else {
  29. return $this->linuxUpdate();
  30. }
  31. }
  32. public function createUpdateStatusFile()
  33. {
  34. $file = $this->config['dbLocation'] . 'updateInProgress.txt';
  35. touch($file);
  36. return true;
  37. }
  38. public function removeUpdateStatusFile()
  39. {
  40. $file = $this->config['dbLocation'] . 'updateInProgress.txt';
  41. if (file_exists($file)) {
  42. @unlink($file);
  43. }
  44. return true;
  45. }
  46. public function hasUpdateStatusFile()
  47. {
  48. return file_exists($this->config['dbLocation'] . 'updateInProgress.txt');
  49. }
  50. public function checkForGitLockFile()
  51. {
  52. return file_exists($this->root . DIRECTORY_SEPARATOR . '.git' . DIRECTORY_SEPARATOR . 'index.lock');
  53. }
  54. public function removeGitLockFile()
  55. {
  56. if ($this->checkForGitLockFile()) {
  57. $removed = false;
  58. if (@unlink($this->root . DIRECTORY_SEPARATOR . '.git' . DIRECTORY_SEPARATOR . 'index.lock')) {
  59. $removed = true;
  60. }
  61. return $removed;
  62. }
  63. return true;
  64. }
  65. public function dockerUpdate()
  66. {
  67. if (!$this->docker) {
  68. $this->setResponse(409, 'Your install type is not Docker');
  69. return false;
  70. }
  71. if ($this->hasUpdateStatusFile()) {
  72. $this->setResponse(500, 'Already Update in progress');
  73. return false;
  74. } else {
  75. $this->createUpdateStatusFile();
  76. }
  77. if (!$this->removeGitLockFile()) {
  78. $this->setResponse(500, 'Git Lock file was found and could not be removed. Please remove manually');
  79. return false;
  80. }
  81. $dockerUpdate = null;
  82. ini_set('max_execution_time', 0);
  83. set_time_limit(0);
  84. chdir('/etc/cont-init.d/');
  85. if (file_exists('./30-install')) {
  86. $this->setAPIResponse('error', 'Update failed - OrgTools is deprecated - please use organizr/organizr', 500);
  87. return false;
  88. } elseif (file_exists('./40-install')) {
  89. $dockerUpdate = shell_exec('./40-install');
  90. }
  91. $this->removeUpdateStatusFile();
  92. if ($dockerUpdate) {
  93. $this->setAPIResponse('success', $dockerUpdate, 200);
  94. return true;
  95. } else {
  96. $this->setAPIResponse('error', 'Update failed', 500);
  97. return false;
  98. }
  99. }
  100. public function windowsUpdate()
  101. {
  102. if ($this->docker || $this->getOS() !== 'win') {
  103. $this->setResponse(409, 'Your install type is not Windows');
  104. return false;
  105. }
  106. if ($this->hasUpdateStatusFile()) {
  107. $this->setResponse(500, 'Already Update in progress');
  108. return false;
  109. } else {
  110. $this->createUpdateStatusFile();
  111. }
  112. $branch = ($this->config['branch'] == 'v2-master') ? '-m' : '-d';
  113. ini_set('max_execution_time', 0);
  114. set_time_limit(0);
  115. $logFile = $this->root . DIRECTORY_SEPARATOR . 'scripts' . DIRECTORY_SEPARATOR . 'log.txt';
  116. $windowsScript = $this->root . DIRECTORY_SEPARATOR . 'scripts' . DIRECTORY_SEPARATOR . 'windows-update.bat ' . $branch . ' > ' . $logFile . ' 2>&1';
  117. $windowsUpdate = shell_exec($windowsScript);
  118. $this->removeUpdateStatusFile();
  119. if ($windowsUpdate) {
  120. $this->setAPIResponse('success', $windowsUpdate, 200);
  121. return true;
  122. } else {
  123. $this->setAPIResponse('success', 'Update Complete - check log.txt for output', 200);
  124. return false;
  125. }
  126. }
  127. public function linuxUpdate()
  128. {
  129. if ($this->docker || $this->getOS() == 'win') {
  130. $this->setResponse(409, 'Your install type is not Linux');
  131. return false;
  132. }
  133. if ($this->hasUpdateStatusFile()) {
  134. $this->setResponse(500, 'Already Update in progress');
  135. return false;
  136. } else {
  137. $this->createUpdateStatusFile();
  138. }
  139. $branch = $this->config['branch'];
  140. ini_set('max_execution_time', 0);
  141. set_time_limit(0);
  142. $logFile = $this->root . DIRECTORY_SEPARATOR . 'scripts' . DIRECTORY_SEPARATOR . 'log.txt';
  143. $script = $this->root . DIRECTORY_SEPARATOR . 'scripts' . DIRECTORY_SEPARATOR . 'linux-update.sh';
  144. $scriptExec = $script . ' ' . $branch . ' > ' . $logFile . ' 2>&1';
  145. $checkScript = $this->testScriptFilePermissions($script);
  146. if (!$checkScript) {
  147. $this->setResponse(500, 'Update script permissions error');
  148. $this->removeUpdateStatusFile();
  149. return false;
  150. }
  151. $update = shell_exec($scriptExec);
  152. $this->removeUpdateStatusFile();
  153. if ($update) {
  154. $this->setAPIResponse('success', $update, 200);
  155. return true;
  156. } else {
  157. $this->setAPIResponse('success', 'Update Complete - check log.txt for output', 200);
  158. return false;
  159. }
  160. }
  161. public function upgradeInstall($branch = 'v2-master', $stage = '1')
  162. {
  163. // may kill this function in place for php script to run elsewhere
  164. if ($this->docker) {
  165. $this->setAPIResponse('error', 'Cannot perform update action on docker install - use script', 500);
  166. return false;
  167. }
  168. if ($this->getOS() == 'win') {
  169. $this->setAPIResponse('error', 'Cannot perform update action on windows install - use script', 500);
  170. return false;
  171. }
  172. $notWritable = array_search(false, $this->pathsWritable($this->paths));
  173. if ($notWritable == false) {
  174. ini_set('max_execution_time', 0);
  175. set_time_limit(0);
  176. $url = 'https://github.com/causefx/Organizr/archive/' . $branch . '.zip';
  177. $file = "upgrade.zip";
  178. $source = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'upgrade' . DIRECTORY_SEPARATOR . 'Organizr-' . str_replace('v2', '2', $branch) . DIRECTORY_SEPARATOR;
  179. $cleanup = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . "upgrade" . DIRECTORY_SEPARATOR;
  180. $destination = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR;
  181. switch ($stage) {
  182. case '1':
  183. $this->setLoggerChannel('Update')->info('Started Upgrade Process');
  184. if ($this->downloadFile($url, $file)) {
  185. $this->setLoggerChannel('Update')->info('Downloaded Update File for Branch: ' . $branch);
  186. $this->setAPIResponse('success', 'Downloaded file successfully', 200);
  187. return true;
  188. } else {
  189. $this->setLoggerChannel('Update')->warning('Downloaded Update File Failed for Branch: ' . $branch);
  190. $this->setAPIResponse('error', 'Download failed', 500);
  191. return false;
  192. }
  193. case '2':
  194. if ($this->unzipFile($file)) {
  195. $this->setLoggerChannel('Update')->info('Unzipped Update File for Branch: ' . $branch);
  196. $this->setAPIResponse('success', 'Unzipped file successfully', 200);
  197. return true;
  198. } else {
  199. $this->setLoggerChannel('Update')->warning('Unzip Failed for Branch: ' . $branch);
  200. $this->setAPIResponse('error', 'Unzip failed', 500);
  201. return false;
  202. }
  203. case '3':
  204. if ($this->rcopy($source, $destination)) {
  205. $this->setLoggerChannel('Update')->info('Files overwritten using Updated Files from Branch: ' . $branch);
  206. $updateComplete = $this->config['dbLocation'] . 'completed.txt';
  207. if (!file_exists($updateComplete)) {
  208. touch($updateComplete);
  209. }
  210. $this->setAPIResponse('success', 'Files replaced successfully', 200);
  211. return true;
  212. } else {
  213. $this->setLoggerChannel('Update')->warning('Overwrite Failed for Branch: ' . $branch);
  214. $this->setAPIResponse('error', 'File replacement failed', 500);
  215. return false;
  216. }
  217. case '4':
  218. if ($this->rrmdir($cleanup)) {
  219. $this->setLoggerChannel('Update')->info('Deleted Update Files from Branch: ' . $branch);
  220. $this->setLoggerChannel('Update')->info('Update Completed');
  221. $this->setAPIResponse('success', 'Removed update files successfully', 200);
  222. return true;
  223. } else {
  224. $this->setLoggerChannel('Update')->warning('Removal of Update Files Failed for Branch: ' . $branch);
  225. $this->setAPIResponse('error', 'File removal failed', 500);
  226. return false;
  227. }
  228. default:
  229. $this->setAPIResponse('error', 'Action not setup', 500);
  230. return false;
  231. }
  232. } else {
  233. $this->setAPIResponse('error', 'File permissions not set correctly', 500);
  234. return false;
  235. }
  236. }
  237. }