api.updates.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. <?php
  2. /**
  3. * Performs deploy of database and config files updates
  4. */
  5. class UbillingUpdateManager {
  6. /**
  7. * System alter.ini config as key=>value
  8. *
  9. * @var array
  10. */
  11. protected $altCfg = array();
  12. /**
  13. * System billing.ini config as key=>value
  14. *
  15. * @var array
  16. */
  17. protected $billCfg = array();
  18. /**
  19. * System mysql.ini config as key=>value
  20. *
  21. * @var array
  22. */
  23. protected $mySqlCfg = array();
  24. /**
  25. * System message helper object placeholder
  26. *
  27. * @var object
  28. */
  29. protected $messages = '';
  30. /**
  31. * Available mysql dumps for apply as release=>filename
  32. *
  33. * @var array
  34. */
  35. protected $allDumps = array();
  36. /**
  37. * Contains available configs updates as release=>configdata
  38. *
  39. * @var array
  40. */
  41. protected $allConfigs = array();
  42. /**
  43. * Contais configs filenames as shortid=>filename
  44. *
  45. * @var array
  46. */
  47. protected $configFileNames = array();
  48. /**
  49. * system sudo path
  50. *
  51. * @var string
  52. */
  53. protected $sudoPath = '/usr/local/bin/sudo';
  54. /**
  55. * Automatic updater full path
  56. *
  57. * @var string
  58. */
  59. protected $atoupdaterPath = '/bin/ubautoupgrade.sh';
  60. const URL_RELEASE_STABLE = 'http://ubilling.net.ua/RELEASE';
  61. const URL_RELEASE_CURRENT = 'http://snaps.ubilling.net.ua/RELEASE';
  62. const DUMPS_PATH = 'content/updates/sql/';
  63. const CONFIGS_PATH = 'content/updates/configs/';
  64. const URL_ME = '?module=updatemanager';
  65. const URL_RELNOTES = 'wiki.ubilling.net.ua/doku.php?id=relnotes#section';
  66. const ROUTE_AUTOSYSUPGRADE = 'autosystemupgrade';
  67. const PROUTE_UPGRADEAGREE = 'runsystemupgrade';
  68. const PID_AUTOSYSUPGRADE = 'UPDMGRAUTOUPGRADE';
  69. /**
  70. * Creates new update manager instance
  71. *
  72. * @return void
  73. */
  74. public function __construct() {
  75. $this->loadSystemConfigs();
  76. $this->setOptions();
  77. $this->initMessages();
  78. $this->setConfigFilenames();
  79. $this->loadDumps();
  80. $this->loadConfigs();
  81. $this->ConnectDB();
  82. }
  83. /**
  84. * Loads all required system config files into protected props for further usage
  85. *
  86. * @global object $ubillingConfig
  87. *
  88. * @return void
  89. */
  90. protected function loadSystemConfigs() {
  91. global $ubillingConfig;
  92. $this->altCfg = $ubillingConfig->getAlter();
  93. $this->billCfg = $ubillingConfig->getBilling();
  94. $this->mySqlCfg = rcms_parse_ini_file(CONFIG_PATH . 'mysql.ini');
  95. }
  96. /**
  97. * Sets all required options
  98. *
  99. * @return void
  100. */
  101. protected function setOptions() {
  102. if (!empty($this->billCfg)) {
  103. $this->sudoPath = $this->billCfg['SUDO'];
  104. }
  105. }
  106. /**
  107. * Inits system messages helper object instance
  108. *
  109. * @return void
  110. */
  111. protected function initMessages() {
  112. $this->messages = new UbillingMessageHelper();
  113. }
  114. /**
  115. * Loads available mysql dumps filenames into protected prop
  116. *
  117. * @return void
  118. */
  119. protected function loadDumps() {
  120. $dumpsTmp = rcms_scandir(self::DUMPS_PATH, '*.sql');
  121. if (!empty($dumpsTmp)) {
  122. rsort($dumpsTmp);
  123. foreach ($dumpsTmp as $io => $each) {
  124. $release = str_replace('.sql', '', $each);
  125. $this->allDumps[$release] = $each;
  126. }
  127. }
  128. }
  129. /**
  130. * Loads available configs update into protected prop
  131. *
  132. * @return void
  133. */
  134. protected function loadConfigs() {
  135. $configsTmp = rcms_scandir(self::CONFIGS_PATH, '*.ini');
  136. if (!empty($configsTmp)) {
  137. rsort($configsTmp);
  138. foreach ($configsTmp as $io => $each) {
  139. $release = str_replace('.ini', '', $each);
  140. $fileContent = rcms_parse_ini_file(self::CONFIGS_PATH . $each, true);
  141. $this->allConfigs[$release] = $fileContent;
  142. }
  143. }
  144. }
  145. /**
  146. * Sets shortid=>filename with path configs associations array
  147. *
  148. * @return void
  149. */
  150. protected function setConfigFilenames() {
  151. $this->configFileNames = array(
  152. 'alter' => 'config/alter.ini',
  153. 'billing' => 'config/billing.ini',
  154. 'ymaps' => 'config/ymaps.ini',
  155. 'userstats' => 'userstats/config/userstats.ini',
  156. 'mysql' => 'config/mysql.ini'
  157. );
  158. }
  159. /**
  160. * Initialises connection with Ubilling database server and selects needed db
  161. *
  162. * @param MySQL Connection Id $connection
  163. *
  164. * @return MySQLDB
  165. */
  166. protected function ConnectDB() {
  167. $dbport = (empty($this->mySqlCfg['port']) ? '' : $this->mySqlCfg['port']);
  168. $this->DBConnection = new DbConnect($this->mySqlCfg['server'], $this->mySqlCfg['username'], $this->mySqlCfg['password'], $this->mySqlCfg['db'], true, false, $dbport);
  169. }
  170. /**
  171. * Returns list of files which was updated in some release
  172. *
  173. * @param string $release
  174. *
  175. * @return string
  176. */
  177. protected function getReleaseConfigFiles($release) {
  178. $result = '';
  179. if (isset($this->allConfigs[$release])) {
  180. if (!empty($this->allConfigs[$release])) {
  181. foreach ($this->allConfigs[$release] as $shortid => $data) {
  182. $filename = (isset($this->configFileNames[$shortid])) ? $this->configFileNames[$shortid] : $shortid;
  183. $result .= $filename . ' ';
  184. }
  185. }
  186. }
  187. return ($result);
  188. }
  189. /**
  190. * Checks is CLI batch updater available or not?
  191. *
  192. * @return bool
  193. */
  194. public function isUpdaterAvailable() {
  195. $result = false;
  196. if (file_exists($this->atoupdaterPath)) {
  197. $result = true;
  198. }
  199. return ($result);
  200. }
  201. /**
  202. * Apply Mysql Dump and returns results
  203. *
  204. * @param string $release
  205. *
  206. * @return string
  207. */
  208. protected function DoSqlDump($release) {
  209. $result = '';
  210. if (!empty($release)) {
  211. $fileName = self::DUMPS_PATH . $this->allDumps[$release];
  212. $file = explode(';', file_get_contents($fileName));
  213. $sql_dumps = array_diff($file, array('')); // Delete empty data Array
  214. $sql_array = array_map('trim', $sql_dumps);
  215. // Open DB connection and set character
  216. $this->DBConnection->open();
  217. $this->DBConnection->query("set character_set_client='" . $this->mySqlCfg['character'] . "'");
  218. $this->DBConnection->query("set character_set_results='" . $this->mySqlCfg['character'] . "'");
  219. $this->DBConnection->query("set collation_connection='" . $this->mySqlCfg['character'] . "_general_ci'");
  220. foreach ($sql_array as $query) {
  221. if (!empty($query)) {
  222. $this->DBConnection->query($query);
  223. if (!$this->DBConnection->error()) {
  224. $result .= $this->messages->getStyledMessage(wf_tag('b', false) . __('Done') . ': ' . wf_tag('b', true) . wf_tag('pre', false) . $query . wf_tag('pre', true), 'success') . wf_tag('br');
  225. } else {
  226. $result .= $this->messages->getStyledMessage(wf_tag('b', false) . __('Error') . ': ' . wf_tag('b', true) . $this->DBConnection->error() . wf_tag('pre', false) . $query . wf_tag('pre', true), 'error') . wf_tag('br');
  227. }
  228. }
  229. }
  230. $this->DBConnection->close();
  231. }
  232. return ($result);
  233. }
  234. /**
  235. * Renders list of sql dumps available for applying
  236. *
  237. * @return string
  238. */
  239. public function renderSqlDumpsList() {
  240. $result = '';
  241. if (!empty($this->allDumps)) {
  242. $cells = wf_TableCell(__('Ubilling release'));
  243. $cells .= wf_TableCell(__('Details'));
  244. $cells .= wf_TableCell(__('Actions'));
  245. $rows = wf_TableRow($cells, 'row1');
  246. foreach ($this->allDumps as $release => $filename) {
  247. $relnotesUrl = self::URL_RELNOTES . str_replace('.', '', $release);
  248. $relnotesLink = wf_Link('http://' . $relnotesUrl, __('Release notes') . ' ' . $release, false, '', 'target="_BLANK"');
  249. $alertText = __('Are you serious') . ' ' . __('Apply') . ' Ubilling ' . $release . '?';
  250. $actLink = wf_JSAlert(self::URL_ME . '&applysql=' . $release, wf_img('skins/icon_restoredb.png', __('Apply')), $alertText);
  251. $cells = wf_TableCell($release);
  252. $cells .= wf_TableCell($relnotesLink);
  253. $cells .= wf_TableCell($actLink);
  254. $rows .= wf_TableRow($cells, 'row5');
  255. }
  256. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  257. } else {
  258. $result = $this->messages->getStyledMessage(__('Nothing found'), 'info');
  259. }
  260. return ($result);
  261. }
  262. /**
  263. * Renders list of available config files updates
  264. *
  265. * @return string
  266. */
  267. public function renderConfigsList() {
  268. $result = '';
  269. if (!empty($this->allConfigs)) {
  270. $cells = wf_TableCell(__('Ubilling release'));
  271. $cells .= wf_TableCell(__('Details'));
  272. $cells .= wf_TableCell(__('Files'));
  273. $cells .= wf_TableCell(__('Actions'));
  274. $rows = wf_TableRow($cells, 'row1');
  275. foreach ($this->allConfigs as $release => $filename) {
  276. $relnotesUrl = self::URL_RELNOTES . str_replace('.', '', $release);
  277. $relnotesLink = wf_Link('http://' . $relnotesUrl, __('Release notes') . ' ' . $release, false, '', 'target="_BLANK"');
  278. $alertText = __('Are you serious') . ' ' . __('Apply') . ' Ubilling ' . $release . '?';
  279. $actLink = wf_JSAlert(self::URL_ME . '&showconfigs=' . $release, wf_img('skins/icon_addrow.png', __('Apply')), $alertText);
  280. $cells = wf_TableCell($release);
  281. $cells .= wf_TableCell($relnotesLink);
  282. $cells .= wf_TableCell($this->getReleaseConfigFiles($release));
  283. $cells .= wf_TableCell($actLink);
  284. $rows .= wf_TableRow($cells, 'row5');
  285. }
  286. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  287. } else {
  288. $result = $this->messages->getStyledMessage(__('Nothing found'), 'info');
  289. }
  290. return ($result);
  291. }
  292. /**
  293. * Applies mysql dump to current database
  294. *
  295. * @param string $release
  296. *
  297. * @return string
  298. */
  299. public function applyMysqlDump($release) {
  300. $result = '';
  301. $release = trim($release);
  302. $release = vf($release);
  303. if (isset($this->allDumps[$release])) {
  304. if (wf_CheckPost(array('applyconfirm', 'applysqldump'))) {
  305. $result .= $this->messages->getStyledMessage(__('MySQL dump applying result below'), 'info');
  306. $result .= wf_CleanDiv();
  307. log_register('UPDMGR APPLY SQL RELEASE `' . $release . '`');
  308. $result .= $this->DoSqlDump($release);
  309. $result .= wf_BackLink(self::URL_ME);
  310. } else {
  311. if ((!wf_CheckPost(array('applyconfirm'))) and (wf_CheckPost(array('applysqldump')))) {
  312. $result .= $this->messages->getStyledMessage(__('You are not mentally prepared for this'), 'error');
  313. $result .= wf_delimiter();
  314. $result .= wf_BackLink(self::URL_ME . '&applysql=' . $release);
  315. } else {
  316. $result .= $this->messages->getStyledMessage(__('Caution: these changes can not be undone.'), 'warning');
  317. $result .= wf_tag('br');
  318. $inputs = __('Apply changes for Ubilling release') . ' ' . $release . '?';
  319. $inputs .= wf_tag('br');
  320. $inputs .= wf_tag('br');
  321. $inputs .= wf_HiddenInput('applysqldump', 'true');
  322. $inputs .= wf_CheckInput('applyconfirm', __('I`m ready'), true, false);
  323. $inputs .= wf_tag('br');
  324. $inputs .= wf_Submit(__('Apply'));
  325. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  326. $result .= wf_CleanDiv();
  327. $result .= wf_delimiter();
  328. $result .= wf_BackLink(self::URL_ME);
  329. }
  330. }
  331. } else {
  332. $result = $this->messages->getStyledMessage(__('Wrong release'), 'error');
  333. log_register('UPDMGR FAIL SQL RELEASE `' . $release . '`');
  334. }
  335. return ($result);
  336. }
  337. /**
  338. * Changes access rights for some path to be writable
  339. *
  340. * @param string $path
  341. *
  342. * @return void
  343. */
  344. protected function fixAccessRights($path) {
  345. $command = $this->sudoPath . ' chmod -R 777 ' . $path;
  346. shell_exec($command);
  347. }
  348. /**
  349. * Renders interface and applies new options to some config files
  350. *
  351. * @param string $release
  352. *
  353. * @return string
  354. */
  355. public function applyConfigOptions($release) {
  356. $result = '';
  357. $release = trim($release);
  358. $release = vf($release);
  359. $newOptsCount = 0;
  360. if (isset($this->allConfigs[$release])) {
  361. $releaseData = $this->allConfigs[$release];
  362. if (!empty($releaseData)) {
  363. foreach ($releaseData as $configId => $configOptions) {
  364. @$configName = $this->configFileNames[$configId];
  365. $canUpdate = false;
  366. if (!empty($configName)) {
  367. if (file_exists($configName)) {
  368. $currentConfigOptions = rcms_parse_ini_file($configName);
  369. $result .= $this->messages->getStyledMessage(__('Existing config file') . ': ' . $configName, 'success');
  370. //some logging
  371. if (wf_CheckPost(array('applyconfigoptions', 'applyconfirm'))) {
  372. //Initial line break and update header
  373. $configUpdateHeader = "\n";
  374. $configUpdateHeader .= ';release ' . $release . ' update' . "\n";
  375. if (is_writable($configName)) {
  376. $canUpdate = true;
  377. } else {
  378. $canUpdate = false;
  379. $result .= $this->messages->getStyledMessage(__('Permission denied') . ': ' . $configName . '.', 'error');
  380. $result .= $this->messages->getStyledMessage(__('Trying to set write permissions for') . ' ' . $configName . ' ' . __('to fix this issue') . '.', 'warning');
  381. $this->fixAccessRights($configName);
  382. if (is_writable($configName)) {
  383. $canUpdate = true;
  384. $result .= $this->messages->getStyledMessage(__('Success! Config file') . ' ' . $configName . ' ' . __('now is writable') . '.', 'success');
  385. } else {
  386. $canUpdate = false;
  387. $result .= $this->messages->getStyledMessage(__('Seems like we failed with making this file writable') . '.', 'error');
  388. }
  389. }
  390. //now real put update header
  391. if ($canUpdate) {
  392. file_put_contents($configName, $configUpdateHeader, FILE_APPEND);
  393. log_register('UPDMGR APPLY CONFIG `' . $configId . '` RELEASE `' . $release . '`');
  394. }
  395. }
  396. if (!empty($configOptions)) {
  397. foreach ($configOptions as $optionName => $optionContent) {
  398. if (!isset($currentConfigOptions[$optionName])) {
  399. $newOptsCount++;
  400. $result .= $this->messages->getStyledMessage(__('New option') . ': ' . $optionName . ' ' . __('will be added with value') . ' ' . $optionContent, 'info');
  401. if (wf_CheckPost(array('applyconfigoptions', 'applyconfirm'))) {
  402. $saveOptions = $optionName . '=' . $optionContent . "\n";
  403. if (is_writable($configName)) {
  404. file_put_contents($configName, $saveOptions, FILE_APPEND);
  405. $result .= $this->messages->getStyledMessage(__('Option added') . ': ' . $optionName . '= ' . $optionContent, 'success');
  406. $newOptsCount--;
  407. } else {
  408. $result .= $this->messages->getStyledMessage(__('New option') . ' ' . $optionName . ' ' . __('not created') . '. ' . __('Permission denied') . '.', 'error');
  409. }
  410. }
  411. } else {
  412. $result .= $this->messages->getStyledMessage(__('Option already exists, will be ignored') . ': ' . $optionName, 'warning');
  413. }
  414. }
  415. }
  416. } else {
  417. $result .= $this->messages->getStyledMessage(__('Wrong config path') . ': ' . $configName, 'error');
  418. }
  419. } else {
  420. $result .= $this->messages->getStyledMessage(__('Unknown config') . ': ' . $configId, 'error');
  421. }
  422. }
  423. //confirmation checkbox notice
  424. if ((wf_CheckPost(array('applyconfigoptions'))) and (!wf_CheckPost(array('applyconfirm')))) {
  425. $result .= $this->messages->getStyledMessage(__('You are not mentally prepared for this'), 'error');
  426. }
  427. //apply form assembly
  428. if ($newOptsCount > 0) {
  429. $result .= wf_tag('br');
  430. $inputs = __('Apply changes for Ubilling release') . ' ' . $release . '?';
  431. $inputs .= wf_tag('br');
  432. $inputs .= wf_tag('br');
  433. $inputs .= wf_HiddenInput('applyconfigoptions', 'true');
  434. $inputs .= wf_CheckInput('applyconfirm', __('I`m ready'), true, false);
  435. $inputs .= wf_tag('br');
  436. $inputs .= wf_Submit(__('Apply'));
  437. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  438. $result .= wf_CleanDiv();
  439. } else {
  440. $result .= $this->messages->getStyledMessage(__('Everything is fine. All required options for release') . ' ' . $release . ' ' . __('is on their places.'), 'success');
  441. }
  442. }
  443. $result .= wf_CleanDiv();
  444. $result .= wf_delimiter();
  445. $result .= wf_BackLink(self::URL_ME);
  446. } else {
  447. $result .= $this->messages->getStyledMessage(__('Wrong release'), 'error');
  448. log_register('UPDMGR FAIL CONF RELEASE `' . $release . '`');
  449. }
  450. return ($result);
  451. }
  452. /**
  453. * Renders current release info data and update check controls
  454. *
  455. * @return string
  456. */
  457. public function renderVersionInfo() {
  458. $currentRelease = file_get_contents("RELEASE");
  459. $updatechecker = wf_tag('br') . wf_tag('div', false, '', 'style="margin-left: 3%;"');
  460. $updatechecker .= wf_AjaxLink('?module=updatemanager&checkupdates=true', wf_img('skins/question.png') . ' ' . __('Check updates'), 'lastrelease', false, 'ubButton');
  461. $updatechecker .= wf_tag('div', true);
  462. $updatechecker .= wf_CleanDiv();
  463. $releaseInfo = wf_tag('style') . '#ubajaxloaderanim { margin-left: 3%; margin-top: 10px; }' . wf_tag('style', true);
  464. $releaseInfo .= $updatechecker;
  465. $releaseInfo .= $this->messages->getStyledMessage(__('Current Ubilling version') . ': ' . $currentRelease, 'info');
  466. $releaseInfo .= wf_AjaxContainer('lastrelease', '', '');
  467. $releaseInfo .= wf_AjaxLoader();
  468. return ($releaseInfo);
  469. }
  470. /**
  471. * Performs automatic system upgrade
  472. *
  473. * @param string $branch
  474. *
  475. * @return void/string on error
  476. */
  477. public function performAutoUpgrade($branch) {
  478. $result = '';
  479. $updateProcess = new StarDust(self::PID_AUTOSYSUPGRADE);
  480. if ($updateProcess->notRunning()) {
  481. $updateProcess->start();
  482. log_register('UPDMGR AUTOUPGRADE `' . $branch . '` STARTED');
  483. if ($this->sudoPath and $this->atoupdaterPath) {
  484. if (file_exists($this->atoupdaterPath)) {
  485. $command = $this->sudoPath . ' ' . $this->atoupdaterPath . ' ' . $branch;
  486. $autoUpdaterResult = shell_exec($command);
  487. if (!ispos($autoUpdaterResult, 'SUCCESS')) {
  488. $result .= __('Something went wrong') . ': ' . $autoUpdaterResult;
  489. log_register('UPDMGR AUTOUPGRADE `' . $branch . '` FAILED');
  490. }
  491. } else {
  492. $result .= $this->atoupdaterPath . ' ' . __('not exists');
  493. }
  494. }
  495. log_register('UPDMGR AUTOUPGRADE `' . $branch . '` FINISHED');
  496. $updateProcess->stop();
  497. } else {
  498. $result .= __('System update') . ' ' . __('already running');
  499. log_register('UPDMGR AUTOUPGRADE `' . $branch . '` SKIPPED');
  500. }
  501. return ($result);
  502. }
  503. }
  504. /**
  505. * Ubilling updates deployment routines
  506. */
  507. class UbillingUpdateStuff {
  508. /**
  509. * Contains system billing.ini as key=>value
  510. *
  511. * @var array
  512. */
  513. protected $billingCfg = array();
  514. /**
  515. * Wget path
  516. *
  517. * @var string
  518. */
  519. protected $wgetPath = '/usr/local/bin/wget';
  520. /**
  521. * Tar archiver path
  522. *
  523. * @var string
  524. */
  525. protected $tarPath = '/usr/bin/tar';
  526. /**
  527. * system sudo path
  528. *
  529. * @var string
  530. */
  531. protected $sudoPath = '/usr/local/bin/sudo';
  532. /**
  533. * Gzip archiver path
  534. *
  535. * @var gzip
  536. */
  537. protected $gzipPath = '/usr/bin/gzip';
  538. public function __construct() {
  539. $this->loadConfig();
  540. $this->setOptions();
  541. }
  542. /**
  543. * Loads all required configs
  544. *
  545. * @global object $ubillingConfig
  546. *
  547. * @return void
  548. */
  549. protected function loadConfig() {
  550. global $ubillingConfig;
  551. $this->billingCfg = $ubillingConfig->getBilling();
  552. }
  553. /**
  554. * Sets custom paths to required software
  555. *
  556. * @return void
  557. */
  558. protected function setOptions() {
  559. if (isset($this->billingCfg['SUDO'])) {
  560. $this->sudoPath = $this->billingCfg['SUDO'];
  561. }
  562. if (isset($this->billingCfg['WGET_PATH'])) {
  563. $this->wgetPath = $this->billingCfg['WGET_PATH'];
  564. }
  565. if (isset($this->billingCfg['TAR_PATH'])) {
  566. $this->tarPath = $this->billingCfg['TAR_PATH'];
  567. }
  568. if (isset($this->billingCfg['GZIP_PATH'])) {
  569. $this->gzipPath = $this->billingCfg['GZIP_PATH'];
  570. }
  571. }
  572. /**
  573. * Changes access rights for some directory to be writable
  574. *
  575. * @param string $directory
  576. *
  577. * @return void
  578. */
  579. public function fixAccessRights($directory) {
  580. $command = $this->sudoPath . ' chmod -R 777 ' . $directory;
  581. shell_exec($command);
  582. }
  583. /**
  584. * Downloads file from remote host
  585. *
  586. * @param string $url
  587. * @param string $directory
  588. * @param string $filename
  589. *
  590. * @return void
  591. */
  592. public function downloadRemoteFile($url, $directory, $filename = '') {
  593. if ($filename) {
  594. $wgetOptions = '--output-document=' . $directory . $filename . ' ';
  595. } else {
  596. $wgetOptions = '--directory-prefix=' . $directory . basename($url) . ' ';
  597. }
  598. $wgetOptions .= '--no-check-certificate ';
  599. if (file_exists($directory)) {
  600. if (!is_writable($directory)) {
  601. throw new Exception('DOWNLOAD_DIRECTORY_NOT_WRITABLE');
  602. }
  603. $command = $this->wgetPath . ' ' . $wgetOptions . ' ' . $url;
  604. shell_exec($command);
  605. } else {
  606. throw new Exception('DOWNLOAD_DIRECTORY_NOT_EXISTS');
  607. }
  608. }
  609. /**
  610. * Extracts tar.gz archive to some path
  611. *
  612. * @param string $archivePath
  613. * @param string $extractPath
  614. *
  615. * @return void
  616. */
  617. public function extractTgz($archivePath, $extractPath) {
  618. if (file_exists($archivePath)) {
  619. if (is_readable($archivePath)) {
  620. if (file_exists($extractPath)) {
  621. if (!is_writable($extractPath)) {
  622. $this->fixAccessRights($extractPath);
  623. }
  624. //unpacking archive
  625. $command = $this->tarPath . ' zxvf ' . $archivePath . ' -C ' . $extractPath;
  626. shell_exec($command);
  627. } else {
  628. throw new Exception('EXTRACT_DIRECTORY_NOT_EXISTS');
  629. }
  630. }
  631. }
  632. }
  633. }