ReplicationGui.php 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Functions for the replication GUI
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. namespace PhpMyAdmin;
  9. use PhpMyAdmin\Core;
  10. use PhpMyAdmin\Message;
  11. use PhpMyAdmin\Replication;
  12. use PhpMyAdmin\Response;
  13. use PhpMyAdmin\Url;
  14. use PhpMyAdmin\Util;
  15. /**
  16. * PhpMyAdmin\ReplicationGui class
  17. *
  18. * @package PhpMyAdmin
  19. */
  20. class ReplicationGui
  21. {
  22. /**
  23. * returns HTML for error message
  24. *
  25. * @return String HTML code
  26. */
  27. public static function getHtmlForErrorMessage()
  28. {
  29. $html = '';
  30. if (isset($_SESSION['replication']['sr_action_status'])
  31. && isset($_SESSION['replication']['sr_action_info'])
  32. ) {
  33. if ($_SESSION['replication']['sr_action_status'] == 'error') {
  34. $error_message = $_SESSION['replication']['sr_action_info'];
  35. $html .= Message::error($error_message)->getDisplay();
  36. $_SESSION['replication']['sr_action_status'] = 'unknown';
  37. } elseif ($_SESSION['replication']['sr_action_status'] == 'success') {
  38. $success_message = $_SESSION['replication']['sr_action_info'];
  39. $html .= Message::success($success_message)->getDisplay();
  40. $_SESSION['replication']['sr_action_status'] = 'unknown';
  41. }
  42. }
  43. return $html;
  44. }
  45. /**
  46. * returns HTML for master replication
  47. *
  48. * @return String HTML code
  49. */
  50. public static function getHtmlForMasterReplication()
  51. {
  52. $html = '';
  53. if (! isset($_POST['repl_clear_scr'])) {
  54. $html .= '<fieldset>';
  55. $html .= '<legend>' . __('Master replication') . '</legend>';
  56. $html .= __('This server is configured as master in a replication process.');
  57. $html .= '<ul>';
  58. $html .= ' <li><a href="#master_status_href" id="master_status_href">';
  59. $html .= __('Show master status') . '</a>';
  60. $html .= self::getHtmlForReplicationStatusTable('master', true, false);
  61. $html .= ' </li>';
  62. $html .= ' <li><a href="#master_slaves_href" id="master_slaves_href">';
  63. $html .= __('Show connected slaves') . '</a>';
  64. $html .= self::getHtmlForReplicationSlavesTable(true);
  65. $html .= ' </li>';
  66. $_url_params = $GLOBALS['url_params'];
  67. $_url_params['mr_adduser'] = true;
  68. $_url_params['repl_clear_scr'] = true;
  69. $html .= ' <li><a href="server_replication.php" data-post="';
  70. $html .= Url::getCommon($_url_params, '')
  71. . '" id="master_addslaveuser_href">';
  72. $html .= __('Add slave replication user') . '</a></li>';
  73. }
  74. // Display 'Add replication slave user' form
  75. if (isset($_POST['mr_adduser'])) {
  76. $html .= self::getHtmlForReplicationMasterAddSlaveUser();
  77. } elseif (! isset($_POST['repl_clear_scr'])) {
  78. $html .= "</ul>";
  79. $html .= "</fieldset>";
  80. }
  81. return $html;
  82. }
  83. /**
  84. * returns HTML for master replication configuration
  85. *
  86. * @return String HTML code
  87. */
  88. public static function getHtmlForMasterConfiguration()
  89. {
  90. $html = '<fieldset>';
  91. $html .= '<legend>' . __('Master configuration') . '</legend>';
  92. $html .= __(
  93. 'This server is not configured as a master server in a '
  94. . 'replication process. You can choose from either replicating '
  95. . 'all databases and ignoring some of them (useful if you want to '
  96. . 'replicate a majority of the databases) or you can choose to ignore '
  97. . 'all databases by default and allow only certain databases to be '
  98. . 'replicated. Please select the mode:'
  99. ) . '<br /><br />';
  100. $html .= '<select name="db_type" id="db_type">';
  101. $html .= '<option value="all">' . __('Replicate all databases; Ignore:');
  102. $html .= '</option>';
  103. $html .= '<option value="ign">' . __('Ignore all databases; Replicate:');
  104. $html .= '</option>';
  105. $html .= '</select>';
  106. $html .= '<br /><br />';
  107. $html .= __('Please select databases:') . '<br />';
  108. $html .= self::getHtmlForReplicationDbMultibox();
  109. $html .= '<br /><br />';
  110. $html .= __(
  111. 'Now, add the following lines at the end of [mysqld] section'
  112. . ' in your my.cnf and please restart the MySQL server afterwards.'
  113. ) . '<br />';
  114. $html .= '<pre id="rep"></pre>';
  115. $html .= __(
  116. 'Once you restarted MySQL server, please click on Go button. '
  117. . 'Afterwards, you should see a message informing you, that this server'
  118. . ' <b>is</b> configured as master.'
  119. );
  120. $html .= '</fieldset>';
  121. $html .= '<fieldset class="tblFooters">';
  122. $html .= ' <form method="post" action="server_replication.php" >';
  123. $html .= Url::getHiddenInputs('', '');
  124. $html .= ' <input type="submit" value="' . __('Go') . '" id="goButton" />';
  125. $html .= ' </form>';
  126. $html .= '</fieldset>';
  127. return $html;
  128. }
  129. /**
  130. * returns HTML for slave replication configuration
  131. *
  132. * @param bool $server_slave_status Whether it is Master or Slave
  133. * @param array $server_slave_replication Slave replication
  134. *
  135. * @return String HTML code
  136. */
  137. public static function getHtmlForSlaveConfiguration(
  138. $server_slave_status, array $server_slave_replication
  139. ) {
  140. $html = '<fieldset>';
  141. $html .= '<legend>' . __('Slave replication') . '</legend>';
  142. /**
  143. * check for multi-master replication functionality
  144. */
  145. $server_slave_multi_replication = $GLOBALS['dbi']->fetchResult(
  146. 'SHOW ALL SLAVES STATUS'
  147. );
  148. if ($server_slave_multi_replication) {
  149. $html .= __('Master connection:');
  150. $html .= '<form method="get" action="server_replication.php">';
  151. $html .= Url::getHiddenInputs($GLOBALS['url_params']);
  152. $html .= ' <select name="master_connection">';
  153. $html .= '<option value="">' . __('Default') . '</option>';
  154. foreach ($server_slave_multi_replication as $server) {
  155. $html .= '<option' . (isset($_POST['master_connection'])
  156. && $_POST['master_connection'] == $server['Connection_name'] ?
  157. ' selected="selected"' : '') . '>' . $server['Connection_name']
  158. . '</option>';
  159. }
  160. $html .= '</select>';
  161. $html .= ' <input type="submit" value="' . __('Go') . '" id="goButton" />';
  162. $html .= '</form>';
  163. $html .= '<br /><br />';
  164. }
  165. if ($server_slave_status) {
  166. $html .= '<div id="slave_configuration_gui">';
  167. $_url_params = $GLOBALS['url_params'];
  168. $_url_params['sr_take_action'] = true;
  169. $_url_params['sr_slave_server_control'] = true;
  170. if ($server_slave_replication[0]['Slave_IO_Running'] == 'No') {
  171. $_url_params['sr_slave_action'] = 'start';
  172. } else {
  173. $_url_params['sr_slave_action'] = 'stop';
  174. }
  175. $_url_params['sr_slave_control_parm'] = 'IO_THREAD';
  176. $slave_control_io_link = Url::getCommon($_url_params, '');
  177. if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') {
  178. $_url_params['sr_slave_action'] = 'start';
  179. } else {
  180. $_url_params['sr_slave_action'] = 'stop';
  181. }
  182. $_url_params['sr_slave_control_parm'] = 'SQL_THREAD';
  183. $slave_control_sql_link = Url::getCommon($_url_params, '');
  184. if ($server_slave_replication[0]['Slave_IO_Running'] == 'No'
  185. || $server_slave_replication[0]['Slave_SQL_Running'] == 'No'
  186. ) {
  187. $_url_params['sr_slave_action'] = 'start';
  188. } else {
  189. $_url_params['sr_slave_action'] = 'stop';
  190. }
  191. $_url_params['sr_slave_control_parm'] = null;
  192. $slave_control_full_link = Url::getCommon($_url_params, '');
  193. $_url_params['sr_slave_action'] = 'reset';
  194. $slave_control_reset_link = Url::getCommon($_url_params, '');
  195. $_url_params = $GLOBALS['url_params'];
  196. $_url_params['sr_take_action'] = true;
  197. $_url_params['sr_slave_skip_error'] = true;
  198. $slave_skip_error_link = Url::getCommon($_url_params, '');
  199. if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') {
  200. $html .= Message::error(
  201. __('Slave SQL Thread not running!')
  202. )->getDisplay();
  203. }
  204. if ($server_slave_replication[0]['Slave_IO_Running'] == 'No') {
  205. $html .= Message::error(
  206. __('Slave IO Thread not running!')
  207. )->getDisplay();
  208. }
  209. $_url_params = $GLOBALS['url_params'];
  210. $_url_params['sl_configure'] = true;
  211. $_url_params['repl_clear_scr'] = true;
  212. $reconfiguremaster_link = Url::getCommon($_url_params, '');
  213. $html .= __(
  214. 'Server is configured as slave in a replication process. Would you ' .
  215. 'like to:'
  216. );
  217. $html .= '<br />';
  218. $html .= '<ul>';
  219. $html .= ' <li><a href="#slave_status_href" id="slave_status_href">';
  220. $html .= __('See slave status table') . '</a>';
  221. $html .= self::getHtmlForReplicationStatusTable('slave', true, false);
  222. $html .= ' </li>';
  223. $html .= ' <li><a href="#slave_control_href" id="slave_control_href">';
  224. $html .= __('Control slave:') . '</a>';
  225. $html .= ' <div id="slave_control_gui" class="hide">';
  226. $html .= ' <ul>';
  227. $html .= ' <li><a href="server_replication.php" data-post="' . $slave_control_full_link . '">';
  228. $html .= (($server_slave_replication[0]['Slave_IO_Running'] == 'No' ||
  229. $server_slave_replication[0]['Slave_SQL_Running'] == 'No')
  230. ? __('Full start')
  231. : __('Full stop')) . ' </a></li>';
  232. $html .= ' <li><a class="ajax" id="reset_slave"'
  233. . ' href="server_replication.php" data-post="' . $slave_control_reset_link . '">';
  234. $html .= __('Reset slave') . '</a></li>';
  235. if ($server_slave_replication[0]['Slave_SQL_Running'] == 'No') {
  236. $html .= ' <li><a href="server_replication.php" data-post="' . $slave_control_sql_link . '">';
  237. $html .= __('Start SQL Thread only') . '</a></li>';
  238. } else {
  239. $html .= ' <li><a href="server_replication.php" data-post="' . $slave_control_sql_link . '">';
  240. $html .= __('Stop SQL Thread only') . '</a></li>';
  241. }
  242. if ($server_slave_replication[0]['Slave_IO_Running'] == 'No') {
  243. $html .= ' <li><a href="server_replication.php" data-post="' . $slave_control_io_link . '">';
  244. $html .= __('Start IO Thread only') . '</a></li>';
  245. } else {
  246. $html .= ' <li><a href="server_replication.php" data-post="' . $slave_control_io_link . '">';
  247. $html .= __('Stop IO Thread only') . '</a></li>';
  248. }
  249. $html .= ' </ul>';
  250. $html .= ' </div>';
  251. $html .= ' </li>';
  252. $html .= ' <li>';
  253. $html .= self::getHtmlForSlaveErrorManagement($slave_skip_error_link);
  254. $html .= ' </li>';
  255. $html .= ' <li><a href="server_replication.php" data-post="' . $reconfiguremaster_link . '">';
  256. $html .= __('Change or reconfigure master server') . '</a></li>';
  257. $html .= '</ul>';
  258. $html .= '</div>';
  259. } elseif (! isset($_POST['sl_configure'])) {
  260. $_url_params = $GLOBALS['url_params'];
  261. $_url_params['sl_configure'] = true;
  262. $_url_params['repl_clear_scr'] = true;
  263. $html .= sprintf(
  264. __(
  265. 'This server is not configured as slave in a replication process. '
  266. . 'Would you like to %sconfigure%s it?'
  267. ),
  268. '<a href="server_replication.php" data-post="' . Url::getCommon($_url_params, '') . '">',
  269. '</a>'
  270. );
  271. }
  272. $html .= '</fieldset>';
  273. return $html;
  274. }
  275. /**
  276. * returns HTML for Slave Error Management
  277. *
  278. * @param String $slave_skip_error_link error link
  279. *
  280. * @return String HTML code
  281. */
  282. public static function getHtmlForSlaveErrorManagement($slave_skip_error_link)
  283. {
  284. $html = '<a href="#slave_errormanagement_href" '
  285. . 'id="slave_errormanagement_href">';
  286. $html .= __('Error management:') . '</a>';
  287. $html .= ' <div id="slave_errormanagement_gui" class="hide">';
  288. $html .= Message::error(
  289. __('Skipping errors might lead into unsynchronized master and slave!')
  290. )->getDisplay();
  291. $html .= ' <ul>';
  292. $html .= ' <li><a href="server_replication.php" data-post="' . $slave_skip_error_link . '">';
  293. $html .= __('Skip current error') . '</a></li>';
  294. $html .= ' <li>';
  295. $html .= ' <form method="post" action="server_replication.php">';
  296. $html .= Url::getHiddenInputs('', '');
  297. $html .= sprintf(
  298. __('Skip next %s errors.'),
  299. '<input type="text" name="sr_skip_errors_count" value="1" '
  300. . 'class = "repl_gui_skip_err_cnt" />'
  301. );
  302. $html .= ' <input type="submit" name="sr_slave_skip_error" ';
  303. $html .= 'value="' . __('Go') . '" />';
  304. $html .= ' <input type="hidden" name="sr_take_action" value="1" />';
  305. $html .= ' </form></li>';
  306. $html .= ' </ul>';
  307. $html .= ' </div>';
  308. return $html;
  309. }
  310. /**
  311. * returns HTML for not configure for a server replication
  312. *
  313. * @return String HTML code
  314. */
  315. public static function getHtmlForNotServerReplication()
  316. {
  317. $_url_params = $GLOBALS['url_params'];
  318. $_url_params['mr_configure'] = true;
  319. $html = '<fieldset>';
  320. $html .= '<legend>' . __('Master replication') . '</legend>';
  321. $html .= sprintf(
  322. __(
  323. 'This server is not configured as master in a replication process. '
  324. . 'Would you like to %sconfigure%s it?'
  325. ),
  326. '<a href="server_replication.php" data-post="' . Url::getCommon($_url_params, '') . '">',
  327. '</a>'
  328. );
  329. $html .= '</fieldset>';
  330. return $html;
  331. }
  332. /**
  333. * returns HTML code for selecting databases
  334. *
  335. * @return String HTML code
  336. */
  337. public static function getHtmlForReplicationDbMultibox()
  338. {
  339. $multi_values = '';
  340. $multi_values .= '<select name="db_select[]" '
  341. . 'size="6" multiple="multiple" id="db_select" class="width96">';
  342. foreach ($GLOBALS['dblist']->databases as $current_db) {
  343. if ($GLOBALS['dbi']->isSystemSchema($current_db)) {
  344. continue;
  345. }
  346. $current_db = htmlspecialchars($current_db);
  347. $multi_values .= ' <option value="' . $current_db . '" ';
  348. $multi_values .= '>';
  349. $multi_values .= $current_db . '</option>';
  350. } // end while
  351. $multi_values .= '</select><br />';
  352. $multi_values .= '<a href="#" id="db_select_href">' . __('Select all') . '</a>';
  353. $multi_values .= '&nbsp;/&nbsp;';
  354. $multi_values .= '<a href="#" id="db_reset_href">' . __('Unselect all') . '</a>';
  355. return $multi_values;
  356. }
  357. /**
  358. * returns HTML for changing master
  359. *
  360. * @param String $submitname - submit button name
  361. *
  362. * @return String HTML code
  363. */
  364. public static function getHtmlForReplicationChangeMaster($submitname)
  365. {
  366. $html = '';
  367. list($username_length, $hostname_length)
  368. = self::getUsernameHostnameLength();
  369. $html .= '<form method="post" action="server_replication.php">';
  370. $html .= Url::getHiddenInputs('', '');
  371. $html .= ' <fieldset id="fieldset_add_user_login">';
  372. $html .= ' <legend>' . __('Slave configuration');
  373. $html .= ' - ' . __('Change or reconfigure master server') . '</legend>';
  374. $html .= __(
  375. 'Make sure you have a unique server-id in your configuration file (my.cnf). '
  376. . 'If not, please add the following line into [mysqld] section:'
  377. );
  378. $html .= '<br />';
  379. $html .= '<pre>server-id=' . time() . '</pre>';
  380. $html .= self::getHtmlForAddUserInputDiv(
  381. array('text'=>__('User name:'), 'for'=>"text_username"),
  382. array(
  383. 'type'=>'text',
  384. 'name'=>'username',
  385. 'id'=>'text_username',
  386. 'maxlength'=>$username_length,
  387. 'title'=>__('User name'),
  388. 'required'=>'required'
  389. )
  390. );
  391. $html .= self::getHtmlForAddUserInputDiv(
  392. array('text'=>__('Password:'), 'for'=>"text_pma_pw"),
  393. array(
  394. 'type'=>'password',
  395. 'name'=>'pma_pw',
  396. 'id'=>'text_pma_pw',
  397. 'title'=>__('Password'),
  398. 'required'=>'required'
  399. )
  400. );
  401. $html .= self::getHtmlForAddUserInputDiv(
  402. array('text'=>__('Host:'), 'for'=>"text_hostname"),
  403. array(
  404. 'type'=>'text',
  405. 'name'=>'hostname',
  406. 'id'=>'text_hostname',
  407. 'maxlength'=>$hostname_length,
  408. 'value'=>'',
  409. 'required'=>'required'
  410. )
  411. );
  412. $html .= self::getHtmlForAddUserInputDiv(
  413. array('text'=>__('Port:'), 'for'=>"text_port"),
  414. array(
  415. 'type'=>'number',
  416. 'name'=>'text_port',
  417. 'id'=>'text_port',
  418. 'maxlength'=>6,
  419. 'value'=>'3306',
  420. 'required'=>'required'
  421. )
  422. );
  423. $html .= ' </fieldset>';
  424. $html .= ' <fieldset id="fieldset_user_privtable_footer" class="tblFooters">';
  425. $html .= ' <input type="hidden" name="sr_take_action" value="true" />';
  426. $html .= ' <input type="hidden" name="' . $submitname . '" value="1" />';
  427. $html .= ' <input type="submit" id="confslave_submit" value="';
  428. $html .= __('Go') . '" />';
  429. $html .= ' </fieldset>';
  430. $html .= '</form>';
  431. return $html;
  432. }
  433. /**
  434. * returns HTML code for Add user input div
  435. *
  436. * @param array $label_array label tag elements
  437. * @param array $input_array input tag elements
  438. *
  439. * @return String HTML code
  440. */
  441. public static function getHtmlForAddUserInputDiv(array $label_array, array $input_array)
  442. {
  443. $html = ' <div class="item">';
  444. $html .= ' <label for="' . $label_array['for'] . '">';
  445. $html .= $label_array['text'] . '</label>';
  446. $html .= ' <input ';
  447. foreach ($input_array as $key=>$value) {
  448. $html .= ' ' . $key . '="' . $value . '" ';
  449. }
  450. $html .= ' />';
  451. $html .= ' </div>';
  452. return $html;
  453. }
  454. /**
  455. * This function returns html code for table with replication status.
  456. *
  457. * @param string $type either master or slave
  458. * @param boolean $hidden if true, then default style is set to hidden,
  459. * default value false
  460. * @param boolean $title if true, then title is displayed, default true
  461. *
  462. * @return String HTML code
  463. */
  464. public static function getHtmlForReplicationStatusTable($type, $hidden = false, $title = true)
  465. {
  466. global ${"{$type}_variables"};
  467. global ${"{$type}_variables_alerts"};
  468. global ${"{$type}_variables_oks"};
  469. global ${"server_{$type}_replication"};
  470. global ${"strReplicationStatus_{$type}"};
  471. $html = '';
  472. // TODO check the Masters server id?
  473. // seems to default to '1' when queried via SHOW VARIABLES ,
  474. // but resulted in error on the master when slave connects
  475. // [ERROR] Error reading packet from server: Misconfigured master
  476. // - server id was not set ( server_errno=1236)
  477. // [ERROR] Got fatal error 1236: 'Misconfigured master
  478. // - server id was not set' from master when reading data from binary log
  479. //
  480. //$server_id = $GLOBALS['dbi']->fetchValue(
  481. // "SHOW VARIABLES LIKE 'server_id'", 0, 1
  482. //);
  483. $html .= '<div id="replication_' . $type . '_section" style="';
  484. $html .= ($hidden ? 'display: none;' : '') . '"> ';
  485. if ($title) {
  486. if ($type == 'master') {
  487. $html .= '<h4><a name="replication_' . $type . '"></a>';
  488. $html .= __('Master status') . '</h4>';
  489. } else {
  490. $html .= '<h4><a name="replication_' . $type . '"></a>';
  491. $html .= __('Slave status') . '</h4>';
  492. }
  493. } else {
  494. $html .= '<br />';
  495. }
  496. $html .= ' <table id="server' . $type . 'replicationsummary" class="data"> ';
  497. $html .= ' <thead>';
  498. $html .= ' <tr>';
  499. $html .= ' <th>' . __('Variable') . '</th>';
  500. $html .= ' <th>' . __('Value') . '</th>';
  501. $html .= ' </tr>';
  502. $html .= ' </thead>';
  503. $html .= ' <tbody>';
  504. foreach (${"{$type}_variables"} as $variable) {
  505. $html .= ' <tr>';
  506. $html .= ' <td class="name">';
  507. $html .= htmlspecialchars($variable);
  508. $html .= ' </td>';
  509. $html .= ' <td class="value">';
  510. // TODO change to regexp or something, to allow for negative match
  511. if (isset(${"{$type}_variables_alerts"}[$variable])
  512. && ${"{$type}_variables_alerts"}[$variable] == ${"server_{$type}_replication"}[0][$variable]
  513. ) {
  514. $html .= '<span class="attention">';
  515. } elseif (isset(${"{$type}_variables_oks"}[$variable])
  516. && ${"{$type}_variables_oks"}[$variable] == ${"server_{$type}_replication"}[0][$variable]
  517. ) {
  518. $html .= '<span class="allfine">';
  519. } else {
  520. $html .= '<span>';
  521. }
  522. // allow wrapping long table lists into multiple lines
  523. static $variables_wrap = array(
  524. 'Replicate_Do_DB', 'Replicate_Ignore_DB',
  525. 'Replicate_Do_Table', 'Replicate_Ignore_Table',
  526. 'Replicate_Wild_Do_Table', 'Replicate_Wild_Ignore_Table');
  527. if (in_array($variable, $variables_wrap)) {
  528. $html .= htmlspecialchars(str_replace(
  529. ',',
  530. ', ',
  531. ${"server_{$type}_replication"}[0][$variable]
  532. ));
  533. } else {
  534. $html .= htmlspecialchars(${"server_{$type}_replication"}[0][$variable]);
  535. }
  536. $html .= '</span>';
  537. $html .= ' </td>';
  538. $html .= ' </tr>';
  539. }
  540. $html .= ' </tbody>';
  541. $html .= ' </table>';
  542. $html .= ' <br />';
  543. $html .= '</div>';
  544. return $html;
  545. }
  546. /**
  547. * returns html code for table with slave users connected to this master
  548. *
  549. * @param boolean $hidden - if true, then default style is set to hidden,
  550. * - default value false
  551. *
  552. * @return string
  553. */
  554. public static function getHtmlForReplicationSlavesTable($hidden = false)
  555. {
  556. $html = '';
  557. // Fetch data
  558. $data = $GLOBALS['dbi']->fetchResult('SHOW SLAVE HOSTS', null, null);
  559. $html .= ' <br />';
  560. $html .= ' <div id="replication_slaves_section" style="';
  561. $html .= ($hidden ? 'display: none;' : '') . '"> ';
  562. $html .= ' <table class="data">';
  563. $html .= ' <thead>';
  564. $html .= ' <tr>';
  565. $html .= ' <th>' . __('Server ID') . '</th>';
  566. $html .= ' <th>' . __('Host') . '</th>';
  567. $html .= ' </tr>';
  568. $html .= ' </thead>';
  569. $html .= ' <tbody>';
  570. foreach ($data as $slave) {
  571. $html .= ' <tr>';
  572. $html .= ' <td class="value">' . $slave['Server_id'] . '</td>';
  573. $html .= ' <td class="value">' . $slave['Host'] . '</td>';
  574. $html .= ' </tr>';
  575. }
  576. $html .= ' </tbody>';
  577. $html .= ' </table>';
  578. $html .= ' <br />';
  579. $html .= Message::notice(
  580. __(
  581. 'Only slaves started with the '
  582. . '--report-host=host_name option are visible in this list.'
  583. )
  584. )->getDisplay();
  585. $html .= ' <br />';
  586. $html .= ' </div>';
  587. return $html;
  588. }
  589. /**
  590. * get the correct username and hostname lengths for this MySQL server
  591. *
  592. * @return array username length, hostname length
  593. */
  594. public static function getUsernameHostnameLength()
  595. {
  596. $fields_info = $GLOBALS['dbi']->getColumns('mysql', 'user');
  597. $username_length = 16;
  598. $hostname_length = 41;
  599. foreach ($fields_info as $val) {
  600. if ($val['Field'] == 'User') {
  601. strtok($val['Type'], '()');
  602. $v = strtok('()');
  603. if (is_int($v)) {
  604. $username_length = $v;
  605. }
  606. } elseif ($val['Field'] == 'Host') {
  607. strtok($val['Type'], '()');
  608. $v = strtok('()');
  609. if (is_int($v)) {
  610. $hostname_length = $v;
  611. }
  612. }
  613. }
  614. return array($username_length, $hostname_length);
  615. }
  616. /**
  617. * returns html code to add a replication slave user to the master
  618. *
  619. * @return String HTML code
  620. */
  621. public static function getHtmlForReplicationMasterAddSlaveUser()
  622. {
  623. $html = '';
  624. list($username_length, $hostname_length)
  625. = self::getUsernameHostnameLength();
  626. if (isset($_POST['username']) && strlen($_POST['username']) === 0) {
  627. $GLOBALS['pred_username'] = 'any';
  628. }
  629. $html .= '<div id="master_addslaveuser_gui">';
  630. $html .= '<form autocomplete="off" method="post" ';
  631. $html .= 'action="server_privileges.php"';
  632. $html .= ' onsubmit="return checkAddUser(this);">';
  633. $html .= Url::getHiddenInputs('', '');
  634. $html .= '<fieldset id="fieldset_add_user_login">'
  635. . '<legend>' . __('Add slave replication user') . '</legend>'
  636. . self::getHtmlForAddUserLoginForm($username_length)
  637. . '<div class="item">'
  638. . '<label for="select_pred_hostname">'
  639. . ' ' . __('Host:')
  640. . '</label>'
  641. . '<span class="options">'
  642. . ' <select name="pred_hostname" id="select_pred_hostname" title="'
  643. . __('Host') . '"';
  644. $_current_user = $GLOBALS['dbi']->fetchValue('SELECT USER();');
  645. if (! empty($_current_user)) {
  646. $thishost = str_replace(
  647. "'",
  648. '',
  649. mb_substr(
  650. $_current_user,
  651. (mb_strrpos($_current_user, '@') + 1)
  652. )
  653. );
  654. if ($thishost != 'localhost' && $thishost != '127.0.0.1') {
  655. $html .= ' data-thishost="' . htmlspecialchars($thishost) . '" ';
  656. } else {
  657. unset($thishost);
  658. }
  659. }
  660. $html .= '>' . "\n";
  661. unset($_current_user);
  662. // when we start editing a user, $GLOBALS['pred_hostname'] is not defined
  663. if (! isset($GLOBALS['pred_hostname']) && isset($_POST['hostname'])) {
  664. switch (mb_strtolower($_POST['hostname'])) {
  665. case 'localhost':
  666. case '127.0.0.1':
  667. $GLOBALS['pred_hostname'] = 'localhost';
  668. break;
  669. case '%':
  670. $GLOBALS['pred_hostname'] = 'any';
  671. break;
  672. default:
  673. $GLOBALS['pred_hostname'] = 'userdefined';
  674. break;
  675. }
  676. }
  677. $html .= ' <option value="any"'
  678. . ((isset($GLOBALS['pred_hostname']) && $GLOBALS['pred_hostname'] == 'any')
  679. ? ' selected="selected"' : '') . '>' . __('Any host')
  680. . '</option>'
  681. . ' <option value="localhost"'
  682. . ((isset($GLOBALS['pred_hostname'])
  683. && $GLOBALS['pred_hostname'] == 'localhost')
  684. ? ' selected="selected"' : '') . '>' . __('Local')
  685. . '</option>';
  686. if (!empty($thishost)) {
  687. $html .= ' <option value="thishost"'
  688. . ((isset($GLOBALS['pred_hostname'])
  689. && $GLOBALS['pred_hostname'] == 'thishost')
  690. ? ' selected="selected"' : '') . '>' . __('This Host')
  691. . '</option>';
  692. }
  693. unset($thishost);
  694. $html .= self::getHtmlForTableInfoForm($hostname_length);
  695. $html .= '</form>';
  696. $html .= '</div>';
  697. return $html;
  698. }
  699. /**
  700. * returns html code to add a replication slave user to the master
  701. *
  702. * @param int $username_length Username length
  703. *
  704. * @return String HTML code
  705. */
  706. public static function getHtmlForAddUserLoginForm($username_length)
  707. {
  708. $html = '<input type="hidden" name="grant_count" value="25" />'
  709. . '<input type="hidden" name="createdb" id="createdb_0" value="0" />'
  710. . '<input id="checkbox_Repl_slave_priv" type="hidden"'
  711. . ' title="Needed for the replication slaves." '
  712. . 'value="Y" name="Repl_slave_priv"/>'
  713. . '<input id="checkbox_Repl_client_priv" type="hidden" '
  714. . 'title="Needed for the replication slaves."'
  715. . ' value="Y" name="Repl_client_priv"/> '
  716. . '<input type="hidden" name="sr_take_action" value="true" />'
  717. . '<div class="item">'
  718. . '<label for="select_pred_username">'
  719. . ' ' . __('User name:')
  720. . '</label>'
  721. . '<span class="options">'
  722. . ' <select name="pred_username" id="select_pred_username" '
  723. . 'title="' . __('User name') . '">'
  724. . ' <option value="any"'
  725. . ((isset($GLOBALS['pred_username'])
  726. && $GLOBALS['pred_username'] == 'any') ? ' selected="selected"' : '')
  727. . '>' . __('Any user') . '</option>'
  728. . ' <option value="userdefined"'
  729. . ((! isset($GLOBALS['pred_username'])
  730. || $GLOBALS['pred_username'] == 'userdefined')
  731. ? ' selected="selected"' : '')
  732. . '>' . __('Use text field:') . '</option>'
  733. . ' </select>'
  734. . '</span>'
  735. . '<input type="text" name="username" id="pma_username" maxlength="'
  736. . $username_length . '" title="' . __('User name') . '"'
  737. . (empty($_POST['username']) ? '' : ' value="'
  738. . (isset($GLOBALS['new_username'])
  739. ? $GLOBALS['new_username']
  740. : htmlspecialchars($_POST['username'])) . '"')
  741. . ' />'
  742. . '</div>';
  743. return $html;
  744. }
  745. /**
  746. * returns HTML for TableInfoForm
  747. *
  748. * @param int $hostname_length Selected hostname length
  749. *
  750. * @return String HTML code
  751. */
  752. public static function getHtmlForTableInfoForm($hostname_length)
  753. {
  754. $html = ' <option value="hosttable"'
  755. . ((isset($GLOBALS['pred_hostname'])
  756. && $GLOBALS['pred_hostname'] == 'hosttable')
  757. ? ' selected="selected"' : '') . '>' . __('Use Host Table')
  758. . '</option>'
  759. . ' <option value="userdefined"'
  760. . ((isset($GLOBALS['pred_hostname'])
  761. && $GLOBALS['pred_hostname'] == 'userdefined')
  762. ? ' selected="selected"' : '')
  763. . '>' . __('Use text field:') . '</option>'
  764. . ' </select>'
  765. . '</span>'
  766. . '<input type="text" name="hostname" id="pma_hostname" maxlength="'
  767. . $hostname_length . '" value="'
  768. . (isset($_POST['hostname']) ? htmlspecialchars($_POST['hostname']) : '')
  769. . '" title="' . __('Host')
  770. . '" />'
  771. . Util::showHint(
  772. __(
  773. 'When Host table is used, this field is ignored '
  774. . 'and values stored in Host table are used instead.'
  775. )
  776. )
  777. . '</div>'
  778. . '<div class="item">'
  779. . '<label for="select_pred_password">'
  780. . ' ' . __('Password:')
  781. . '</label>'
  782. . '<span class="options">'
  783. . ' <select name="pred_password" id="select_pred_password" title="'
  784. . __('Password') . '">'
  785. . ' <option value="none"';
  786. if (isset($_POST['username'])) {
  787. $html .= ' selected="selected"';
  788. }
  789. $html .= '>' . __('No Password') . '</option>'
  790. . ' <option value="userdefined"'
  791. . (isset($_POST['username']) ? '' : ' selected="selected"')
  792. . '>' . __('Use text field:') . '</option>'
  793. . ' </select>'
  794. . '</span>'
  795. . '<input type="password" id="text_pma_pw" name="pma_pw" title="'
  796. . __('Password') . '" />'
  797. . '</div>'
  798. . '<div class="item">'
  799. . '<label for="text_pma_pw2">'
  800. . ' ' . __('Re-type:')
  801. . '</label>'
  802. . '<span class="options">&nbsp;</span>'
  803. . '<input type="password" name="pma_pw2" id="text_pma_pw2" title="'
  804. . __('Re-type') . '" />'
  805. . '</div>'
  806. . '<div class="item">'
  807. . '<label for="button_generate_password">'
  808. . ' ' . __('Generate password:')
  809. . '</label>'
  810. . '<span class="options">'
  811. . ' <input type="button" class="button" '
  812. . 'id="button_generate_password" value="' . __('Generate')
  813. . '" onclick="suggestPassword(this.form)" />'
  814. . '</span>'
  815. . '<input type="text" name="generated_pw" id="generated_pw" />'
  816. . '</div>'
  817. . '</fieldset>';
  818. $html .= '<fieldset id="fieldset_user_privtable_footer" class="tblFooters">'
  819. . ' <input type="hidden" name="adduser_submit" value="1" />'
  820. . ' <input type="submit" id="adduser_submit" value="' . __('Go') . '" />'
  821. . '</fieldset>';
  822. return $html;
  823. }
  824. /**
  825. * handle control requests
  826. *
  827. * @return NULL
  828. */
  829. public static function handleControlRequest()
  830. {
  831. if (isset($_POST['sr_take_action'])) {
  832. $refresh = false;
  833. $result = false;
  834. $messageSuccess = null;
  835. $messageError = null;
  836. if (isset($_POST['slave_changemaster']) && ! $GLOBALS['cfg']['AllowArbitraryServer']) {
  837. $_SESSION['replication']['sr_action_status'] = 'error';
  838. $_SESSION['replication']['sr_action_info'] = __('Connection to server is disabled, please enable $cfg[\'AllowArbitraryServer\'] in phpMyAdmin configuration.');
  839. } elseif (isset($_POST['slave_changemaster'])) {
  840. $result = self::handleRequestForSlaveChangeMaster();
  841. } elseif (isset($_POST['sr_slave_server_control'])) {
  842. $result = self::handleRequestForSlaveServerControl();
  843. $refresh = true;
  844. switch ($_POST['sr_slave_action']) {
  845. case 'start':
  846. $messageSuccess = __('Replication started successfully.');
  847. $messageError = __('Error starting replication.');
  848. break;
  849. case 'stop':
  850. $messageSuccess = __('Replication stopped successfully.');
  851. $messageError = __('Error stopping replication.');
  852. break;
  853. case 'reset':
  854. $messageSuccess = __('Replication resetting successfully.');
  855. $messageError = __('Error resetting replication.');
  856. break;
  857. default:
  858. $messageSuccess = __('Success.');
  859. $messageError = __('Error.');
  860. break;
  861. }
  862. } elseif (isset($_POST['sr_slave_skip_error'])) {
  863. $result = self::handleRequestForSlaveSkipError();
  864. }
  865. if ($refresh) {
  866. $response = Response::getInstance();
  867. if ($response->isAjax()) {
  868. $response->setRequestStatus($result);
  869. $response->addJSON(
  870. 'message',
  871. $result
  872. ? Message::success($messageSuccess)
  873. : Message::error($messageError)
  874. );
  875. } else {
  876. Core::sendHeaderLocation(
  877. './server_replication.php'
  878. . Url::getCommonRaw($GLOBALS['url_params'])
  879. );
  880. }
  881. }
  882. unset($refresh);
  883. }
  884. }
  885. /**
  886. * handle control requests for Slave Change Master
  887. *
  888. * @return boolean
  889. */
  890. public static function handleRequestForSlaveChangeMaster()
  891. {
  892. $sr = array();
  893. $_SESSION['replication']['m_username'] = $sr['username']
  894. = $GLOBALS['dbi']->escapeString($_POST['username']);
  895. $_SESSION['replication']['m_password'] = $sr['pma_pw']
  896. = $GLOBALS['dbi']->escapeString($_POST['pma_pw']);
  897. $_SESSION['replication']['m_hostname'] = $sr['hostname']
  898. = $GLOBALS['dbi']->escapeString($_POST['hostname']);
  899. $_SESSION['replication']['m_port'] = $sr['port']
  900. = $GLOBALS['dbi']->escapeString($_POST['text_port']);
  901. $_SESSION['replication']['m_correct'] = '';
  902. $_SESSION['replication']['sr_action_status'] = 'error';
  903. $_SESSION['replication']['sr_action_info'] = __('Unknown error');
  904. // Attempt to connect to the new master server
  905. $link_to_master = Replication::connectToMaster(
  906. $sr['username'], $sr['pma_pw'], $sr['hostname'], $sr['port']
  907. );
  908. if (! $link_to_master) {
  909. $_SESSION['replication']['sr_action_status'] = 'error';
  910. $_SESSION['replication']['sr_action_info'] = sprintf(
  911. __('Unable to connect to master %s.'),
  912. htmlspecialchars($sr['hostname'])
  913. );
  914. } else {
  915. // Read the current master position
  916. $position = Replication::slaveBinLogMaster($link_to_master);
  917. if (empty($position)) {
  918. $_SESSION['replication']['sr_action_status'] = 'error';
  919. $_SESSION['replication']['sr_action_info']
  920. = __(
  921. 'Unable to read master log position. '
  922. . 'Possible privilege problem on master.'
  923. );
  924. } else {
  925. $_SESSION['replication']['m_correct'] = true;
  926. if (! Replication::slaveChangeMaster(
  927. $sr['username'],
  928. $sr['pma_pw'],
  929. $sr['hostname'],
  930. $sr['port'],
  931. $position,
  932. true,
  933. false
  934. )
  935. ) {
  936. $_SESSION['replication']['sr_action_status'] = 'error';
  937. $_SESSION['replication']['sr_action_info']
  938. = __('Unable to change master!');
  939. } else {
  940. $_SESSION['replication']['sr_action_status'] = 'success';
  941. $_SESSION['replication']['sr_action_info'] = sprintf(
  942. __('Master server changed successfully to %s.'),
  943. htmlspecialchars($sr['hostname'])
  944. );
  945. }
  946. }
  947. }
  948. return $_SESSION['replication']['sr_action_status'] === 'success';
  949. }
  950. /**
  951. * handle control requests for Slave Server Control
  952. *
  953. * @return boolean
  954. */
  955. public static function handleRequestForSlaveServerControl()
  956. {
  957. if (empty($_POST['sr_slave_control_parm'])) {
  958. $_POST['sr_slave_control_parm'] = null;
  959. }
  960. if ($_POST['sr_slave_action'] == 'reset') {
  961. $qStop = Replication::slaveControl("STOP");
  962. $qReset = $GLOBALS['dbi']->tryQuery("RESET SLAVE;");
  963. $qStart = Replication::slaveControl("START");
  964. $result = ($qStop !== false && $qStop !== -1 &&
  965. $qReset !== false && $qReset !== -1 &&
  966. $qStart !== false && $qStart !== -1);
  967. } else {
  968. $qControl = Replication::slaveControl(
  969. $_POST['sr_slave_action'],
  970. $_POST['sr_slave_control_parm']
  971. );
  972. $result = ($qControl !== false && $qControl !== -1);
  973. }
  974. return $result;
  975. }
  976. /**
  977. * handle control requests for Slave Skip Error
  978. *
  979. * @return boolean
  980. */
  981. public static function handleRequestForSlaveSkipError()
  982. {
  983. $count = 1;
  984. if (isset($_POST['sr_skip_errors_count'])) {
  985. $count = $_POST['sr_skip_errors_count'] * 1;
  986. }
  987. $qStop = Replication::slaveControl("STOP");
  988. $qSkip = $GLOBALS['dbi']->tryQuery(
  989. "SET GLOBAL SQL_SLAVE_SKIP_COUNTER = " . $count . ";"
  990. );
  991. $qStart = Replication::slaveControl("START");
  992. $result = ($qStop !== false && $qStop !== -1 &&
  993. $qSkip !== false && $qSkip !== -1 &&
  994. $qStart !== false && $qStart !== -1);
  995. return $result;
  996. }
  997. }