manage.php 15 KB

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