manage.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <?php
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaManageCmd UNA Manage command line script
  7. * @{
  8. */
  9. $GLOBALS['bx_profiler_disable'] = true;
  10. define('BX_DOL_CRON_EXECUTE', '1');
  11. /**
  12. * UNA command line interface
  13. */
  14. class BxDolManageCmd
  15. {
  16. protected $_sCmd;
  17. protected $_sCmdOptions;
  18. protected $_sPathToUna;
  19. protected $_aSiteConfig;
  20. protected $_isQuiet = false;
  21. protected $_isSkipFilesOperation = false;
  22. protected $_aReturnCodes = array(
  23. 'success' => array ('code' => 0, 'msg' => 'Success.'),
  24. 'una not found' => array ('code' => 1, 'msg' => 'UNA wasn\'t found in the specified path: '),
  25. 'unknown cmd' => array ('code' => 2, 'msg' => 'Unknown command.'),
  26. 'db connect failed' => array ('code' => 3, 'msg' => 'Database connection failed: '),
  27. 'system update failed' => array ('code' => 4, 'msg' => 'System update failed: '),
  28. 'module operation failed' => array ('code' => 5, 'msg' => 'Module operation failed: '),
  29. 'error' => array ('code' => 9, 'msg' => 'Error occured.'),
  30. );
  31. public function __construct()
  32. {
  33. $this->_aSiteConfig = array (
  34. 'db_host' => '',
  35. 'db_port' => '',
  36. 'db_sock' => '',
  37. 'db_name' => '',
  38. 'db_user' => '',
  39. 'db_password' => '',
  40. );
  41. }
  42. public function main()
  43. {
  44. // set neccessary options
  45. $a = getopt('hqic:u:p:o:', $this->getOptions());
  46. if (isset($a['h']))
  47. $this->finish($this->_aReturnCodes['success']['code'], $this->getHelp());
  48. if (isset($a['q']))
  49. $this->_isQuiet = true;
  50. if (isset($a['i']))
  51. $this->_isSkipFilesOperation = true;
  52. if (isset($a['u']))
  53. $this->_sPathToUna = $a['u'];
  54. if (isset($a['c']))
  55. $this->_sCmd = $a['c'];
  56. if (isset($a['o']))
  57. $this->_sCmdOptions = $a['o'];
  58. $this->_aSiteConfig = array_merge($this->_aSiteConfig, $a);
  59. // initialize environment
  60. $this->init();
  61. // run command
  62. $sMethod = $this->_sCmd ? 'cmd' . bx_gen_method_name($this->_sCmd) : 'cmdDefault';
  63. if (!method_exists($this, $sMethod))
  64. $this->finish($this->_aReturnCodes['unknown cmd']['code'], $this->_aReturnCodes['unknown cmd']['msg']);
  65. $this->$sMethod();
  66. $this->finish($this->_aReturnCodes['success']['code'], $this->_aReturnCodes['success']['msg']);
  67. }
  68. protected function getOptions()
  69. {
  70. $a = array ();
  71. foreach ($this->_aSiteConfig as $sKey => $sValue)
  72. if ('site_config' != $sKey)
  73. $a[] = "$sKey::";
  74. return $a;
  75. }
  76. protected function getHelp()
  77. {
  78. $s = "Usage: php manage.php [params]\n";
  79. $s .= str_pad("\t -h", 35) . "Print this help\n";
  80. $s .= str_pad("\t -q", 35) . "Quiet\n";
  81. $s .= str_pad("\t -u", 35) . "Path to UNA\n";
  82. $s .= str_pad("\t -c", 35) . "Command to run:\n";
  83. $s .= str_pad("\t -i", 35) . "Skip files oprations, such copying and deleting when performing update commands\n";
  84. $s .= str_pad("\t", 39) . "- update - options:\n";
  85. $s .= str_pad("\t", 43) . "'ignore_version_check' to ignore version comparison in DB and files\n";
  86. $s .= str_pad("\t", 39) . "- check_update - no options\n";
  87. $s .= str_pad("\t", 39) . "- update_modules - options:\n";
  88. $s .= str_pad("\t", 43) . "comma separated list of modules paths (ex: 'boonex/ads,boonex/wiki')\n";
  89. $s .= str_pad("\t", 39) . "- check_modules_updates - no options\n";
  90. $s .= str_pad("\t", 39) . "- install_modules - options:\n";
  91. $s .= str_pad("\t", 43) . "comma separated list of modules paths (ex: 'boonex/ads,boonex/wiki')\n";
  92. $s .= str_pad("\t", 39) . "- uninstall_modules - options:\n";
  93. $s .= str_pad("\t", 43) . "comma separated list of modules paths (ex: 'boonex/ads,boonex/wiki')\n";
  94. $s .= str_pad("\t", 39) . "- disable_modules - options:\n";
  95. $s .= str_pad("\t", 43) . "comma separated list of modules paths (ex: 'boonex/ads,boonex/wiki')\n";
  96. $s .= str_pad("\t", 39) . "- enable_modules - options:\n";
  97. $s .= str_pad("\t", 43) . "comma separated list of modules paths (ex: 'boonex/ads,boonex/wiki')\n";
  98. $s .= str_pad("\t -o", 35) . "Command options\n";
  99. foreach ($this->_aSiteConfig as $sKey => $sVal)
  100. if ('site_config' != $sKey)
  101. $s .= str_pad("\t --{$sKey}=<value>", 35) . "Database connection params\n";
  102. $s .= "\nIf DB params aren't specified then UNA DB params from header.inc.php are used.\n\n";
  103. $s .= "Examples:\n";
  104. $s .= "\tCheck if update is available:\n";
  105. $s .= "\tphp ./manage.php -u ../../unafolder -c check_update\n\n";
  106. $s .= "\tCheck if update is available using custom DB connection params:\n";
  107. $s .= "\tphp ./manage.php -u ../../unafolder --db_name=unadb --db_user=root --db_host=mysql --db_password=root -c check_update\n\n";
  108. $s .= "\tUpdate system files by ignoring version check and skip files copying, it's necessary when the source code is maintained using VCS:\n";
  109. $s .= "\tphp ./manage.php -u ../../unafolder --db_name=unadb --db_user=root --db_host=mysql --db_password=root -c update -i -o ignore_version_check\n\n";
  110. $s .= "\tCheck if updates for modules are available:\n";
  111. $s .= "\tphp ./manage.php -u ../../unafolder --db_name=unadb --db_user=root --db_host=mysql --db_password=root -c check_modules_updates\n\n";
  112. $s .= "\tUpdate Nexus and Albums modules by ignoring files copying operation, update must be already exists in module's 'updates' folder, to update paid modules authorize the request first in Studio > Apps > Purchases:\n";
  113. $s .= "\tphp ./manage.php -u ../../unafolder --db_name=unadb --db_user=root --db_host=mysql --db_password=root -c update_modules -i -o bx_nexus,bx_albums\n\n";
  114. $s .= "\tInstall Ads and Albums modules:\n";
  115. $s .= "\tphp ./manage.php -u ../../unafolder --db_name=unadb --db_user=root --db_host=mysql --db_password=root -c install_modules -o boonex/ads,boonex/albums\n\n";
  116. $s .= "Return codes:\n";
  117. foreach ($this->_aReturnCodes as $r) {
  118. $s .= str_pad("\t {$r['code']}", 5) . $r['msg'] . (mb_substr(trim($r['msg']), -1) == ':' ? 'message' : '') . "\n";
  119. }
  120. return $s;
  121. }
  122. protected function finish($iCode, $sMsg)
  123. {
  124. if (!$this->_isQuiet)
  125. fwrite($iCode ? STDERR : STDOUT, $sMsg . "\n");
  126. exit($iCode);
  127. }
  128. protected function init()
  129. {
  130. $this->_sPathToUna = trim($this->_sPathToUna);
  131. if ('.' == $this->_sPathToUna)
  132. $this->_sPathToUna = '';
  133. if (!$this->_sPathToUna || '/' !== $this->_sPathToUna[0]) {
  134. $aPathInfo = pathinfo(__FILE__);
  135. $this->_sPathToUna = $aPathInfo['dirname'] . '/' . $this->_sPathToUna;
  136. }
  137. $this->_sPathToUna = rtrim($this->_sPathToUna, '/');
  138. // include header.inc.php
  139. $sHeaderPath = $this->_sPathToUna . '/inc/header.inc.php';
  140. if (!file_exists($sHeaderPath))
  141. $this->finish($this->_aReturnCodes['una not found']['code'], $this->_aReturnCodes['una not found']['msg'] . $sHeaderPath);
  142. require_once($sHeaderPath);
  143. // db connection
  144. if (!empty($this->_aSiteConfig['db_name'])) {
  145. BxDolDb::getInstance()->cacheParamsClear();
  146. BxDolDb::getInstance()->disconnect();
  147. unset($GLOBALS['bxDolClasses']['BxDolDb']);
  148. $sErr = null;
  149. try {
  150. $oDb = BxDolDb::getInstanceWithConf(array(
  151. 'host' => $this->_aSiteConfig['db_host'],
  152. 'port' => $this->_aSiteConfig['db_port'],
  153. 'sock' => $this->_aSiteConfig['db_sock'],
  154. 'name' => $this->_aSiteConfig['db_name'],
  155. 'user' => $this->_aSiteConfig['db_user'],
  156. 'pwd' => $this->_aSiteConfig['db_password'],
  157. ), $sErr);
  158. } catch (Exception $e) {
  159. $this->finish($this->_aReturnCodes['db connect failed']['code'], $this->_aReturnCodes['db connect failed']['msg'] . $e->getMessage());
  160. }
  161. }
  162. }
  163. function cmdCheckUpdate()
  164. {
  165. $oUpgrader = bx_instance('BxDolUpgrader');
  166. $aUpdateInfo = $oUpgrader->getVersionUpdateInfo();
  167. if (!isset($aUpdateInfo['patch']))
  168. $this->finish($this->_aReturnCodes['success']['code'], 'No system update available');
  169. $s = str_pad(bx_get_ver(), 12) . str_pad($aUpdateInfo['patch']['ver'], 12) . $aUpdateInfo['latest_version'];
  170. $this->finish($this->_aReturnCodes['success']['code'], $s);
  171. }
  172. function cmdUpdate()
  173. {
  174. $aOptions = $this->_parseOptions($this->_sCmdOptions);
  175. $oCronDb = BxDolCronQuery::getInstance();
  176. $aCronJobs = $oCronDb->getTransientJobs();
  177. if (!isset($aCronJobs['sys_perform_upgrade'])) {
  178. $oUpgrader = bx_instance('BxDolUpgrader');
  179. $aUpdateInfo = $oUpgrader->getVersionUpdateInfo();
  180. $bUpgrade = $oUpgrader->isUpgradeAvailable($aUpdateInfo);
  181. if (!$bUpgrade)
  182. $this->finish($this->_aReturnCodes['system update failed']['code'], $this->_aReturnCodes['system update failed']['msg'] . 'you have up to date version');
  183. if(!$oUpgrader->prepare(false, in_array('ignore_version_check', $aOptions)))
  184. $this->finish($this->_aReturnCodes['system update failed']['code'], $this->_aReturnCodes['system update failed']['msg'] . $oUpgrader->getError());
  185. }
  186. $aCronJobs = $oCronDb->getTransientJobs();
  187. if (empty($aCronJobs['sys_perform_upgrade']))
  188. $this->finish($this->_aReturnCodes['system update failed']['code'], $this->_aReturnCodes['system update failed']['msg'] . 'no cron job with patch path was found');
  189. $sPatchDir = BX_DIRECTORY_PATH_ROOT . $aCronJobs['sys_perform_upgrade']['file'];
  190. $sPatchDir = str_replace('BxDolUpgradeCron.php', '', $sPatchDir);
  191. define ('BX_UPGRADE_DIR_UPGRADES', $sPatchDir . 'files/');
  192. require_once($sPatchDir . 'classes/BxDolUpgradeController.php');
  193. require_once($sPatchDir . 'classes/BxDolUpgradeUtil.php');
  194. require_once($sPatchDir . 'classes/BxDolUpgradeDb.php');
  195. $oController = new BxDolUpgradeController();
  196. if ($oController->setMaintenanceMode(true)) {
  197. $sFolder = $oController->getAvailableUpgrade();
  198. if ($sFolder && $oController->runUpgrade($sFolder, in_array('ignore_version_check', $aOptions), $this->_isSkipFilesOperation)) {
  199. setParam('sys_revision', getParam('sys_revision') + 1);
  200. @bx_rrmdir($sUpgradeDir);
  201. }
  202. $oController->setMaintenanceMode(false);
  203. }
  204. $oCronDb->deleteTransientJobs();
  205. if ($sErrorMsg = $oController->getErrorMsg()) {
  206. $this->finish($this->_aReturnCodes['system update failed']['code'], $this->_aReturnCodes['system update failed']['msg'] . $sErrorMsg);
  207. }
  208. }
  209. function cmdCheckModulesUpdates()
  210. {
  211. $aDownloaded = BxDolStudioInstallerUtils::getInstance()->getUpdates();
  212. $a = BxDolStudioInstallerUtils::getInstance()->checkUpdates();
  213. if (!$a)
  214. $this->finish($this->_aReturnCodes['success']['code'], 'No modules updates available');
  215. $s = '';
  216. foreach ($a as $r) {
  217. $s .= str_pad($r['name'], 20) . str_pad($r['file_version'], 12) . str_pad($r['file_version_to'], 12);
  218. $sDir = '';
  219. foreach ($aDownloaded as $j) {
  220. if ($j['module_name'] == $r['name'])
  221. $sDir .= $j['dir'];
  222. }
  223. if (!$sDir)
  224. $sDir = "Downloaded update wasn't found";
  225. $s .= "$sDir\n";
  226. }
  227. $this->finish($this->_aReturnCodes['success']['code'], trim($s));
  228. }
  229. function cmdUpdateModules()
  230. {
  231. // TODO: option to disable files operations
  232. $aModules = $this->_parseOptions($this->_sCmdOptions);
  233. if (!$aModules)
  234. $this->finish($this->_aReturnCodes['module operation failed']['code'], 'No modules were provided');
  235. $bErr = false;
  236. $s = "";
  237. $a = BxDolStudioInstallerUtils::getInstance()->getUpdates();
  238. if (!$a)
  239. $this->finish($this->_aReturnCodes['success']['code'], 'No modules updates available');
  240. foreach ($a as $r) {
  241. if (!in_array($r['module_name'], $aModules) && !in_array($r['module_dir'], $aModules))
  242. continue;
  243. $aParams = ['module_name' => $r['module_name']];
  244. if ($this->_isSkipFilesOperation)
  245. $aParams['disabled_actions'] = ['update_files'];
  246. $aRes = BxDolStudioInstallerUtils::getInstance()->perform($r['dir'], 'update', $aParams);
  247. $s .= str_pad($r['module_name'], 20);
  248. if (!isset($aRes['code']) || $aRes['code'] !== BX_DOL_STUDIO_IU_RC_SUCCESS) {
  249. $bErr = true;
  250. $s .= "ERROR " . html_entity_decode($aRes['message']) . "\n";
  251. } else {
  252. $s .= "OK\n";
  253. }
  254. }
  255. if (!$s)
  256. $this->finish($this->_aReturnCodes['module operation failed']['code'], 'No downloaded updates or no updates were found for specified modules');
  257. $iCode = $bErr ? $this->_aReturnCodes['module operation failed']['code'] : $this->_aReturnCodes['success']['code'];
  258. $this->finish($iCode, trim($s));
  259. /*
  260. BxDolStudioInstallerUtils::getInstance()->performModulesUpgrade(array(
  261. 'directly' => true,
  262. 'transient' => false,
  263. 'autoupdate' => true
  264. ));
  265. */
  266. }
  267. function cmdInstallModules()
  268. {
  269. $this->_cmdModules('install', ['auto_enable' => true, 'html_response' => false]);
  270. }
  271. function cmdUninstallModules()
  272. {
  273. $this->_cmdModules('uninstall', ['html_response' => false]);
  274. }
  275. function cmdEnableModules()
  276. {
  277. $this->_cmdModules('enable', ['html_response' => false]);
  278. }
  279. function cmdDisableModules()
  280. {
  281. $this->_cmdModules('disable', ['html_response' => false]);
  282. }
  283. function _parseOptions($s)
  284. {
  285. if (!$s)
  286. return [];
  287. $a = explode(',', trim($s));
  288. foreach ($a as $k => $v)
  289. $a[$k] = trim($v);
  290. return $a;
  291. }
  292. function _cmdModules($sOperation, $aOptions = [])
  293. {
  294. $aModules = $this->_parseOptions($this->_sCmdOptions);
  295. foreach ($aModules as $sModule) {
  296. $sModule = trim($sModule, '/') . '/';
  297. $a = BxDolStudioInstallerUtils::getInstance()->perform($sModule, $sOperation, array('auto_enable' => true, 'html_response' => false));
  298. if (!isset($a['code']) || $a['code'] !== BX_DOL_STUDIO_IU_RC_SUCCESS)
  299. $this->finish($this->_aReturnCodes['module operation failed']['code'], $this->_aReturnCodes['module operation failed']['msg'] . (!empty($a['message']) ? $a['message'] : 'Error occured.') . ' (' . $sOperation . ': ' . $sModule . ')');
  300. }
  301. }
  302. }
  303. $o = new BxDolManageCmd();
  304. $o->main();
  305. /** @} */