tbl_tracking.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Table tracking page
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. // Run common work
  9. require_once './libraries/common.inc.php';
  10. define('TABLE_MAY_BE_ABSENT', true);
  11. require './libraries/tbl_common.inc.php';
  12. $url_query .= '&amp;goto=tbl_tracking.php&amp;back=tbl_tracking.php';
  13. $url_params['goto'] = 'tbl_tracking.php';;
  14. $url_params['back'] = 'tbl_tracking.php';
  15. // Init vars for tracking report
  16. if (isset($_REQUEST['report']) || isset($_REQUEST['report_export'])) {
  17. $data = PMA_Tracker::getTrackedData(
  18. $_REQUEST['db'], $_REQUEST['table'], $_REQUEST['version']
  19. );
  20. $selection_schema = false;
  21. $selection_data = false;
  22. $selection_both = false;
  23. if (! isset($_REQUEST['logtype'])) {
  24. $_REQUEST['logtype'] = 'schema_and_data';
  25. }
  26. if ($_REQUEST['logtype'] == 'schema') {
  27. $selection_schema = true;
  28. } elseif ($_REQUEST['logtype'] == 'data') {
  29. $selection_data = true;
  30. } else {
  31. $selection_both = true;
  32. }
  33. if (! isset($_REQUEST['date_from'])) {
  34. $_REQUEST['date_from'] = $data['date_from'];
  35. }
  36. if (! isset($_REQUEST['date_to'])) {
  37. $_REQUEST['date_to'] = $data['date_to'];
  38. }
  39. if (! isset($_REQUEST['users'])) {
  40. $_REQUEST['users'] = '*';
  41. }
  42. $filter_ts_from = strtotime($_REQUEST['date_from']);
  43. $filter_ts_to = strtotime($_REQUEST['date_to']);
  44. $filter_users = array_map('trim', explode(',', $_REQUEST['users']));
  45. }
  46. // Prepare export
  47. if (isset($_REQUEST['report_export'])) {
  48. /**
  49. * Filters tracking entries
  50. *
  51. * @param array $data the entries to filter
  52. * @param string $filter_ts_from "from" date
  53. * @param string $filter_ts_to "to" date
  54. * @param string $filter_users users
  55. *
  56. * @return array filtered entries
  57. */
  58. function PMA_filter_tracking(
  59. $data, $filter_ts_from, $filter_ts_to, $filter_users
  60. ) {
  61. $tmp_entries = array();
  62. $id = 0;
  63. foreach ( $data as $entry ) {
  64. $timestamp = strtotime($entry['date']);
  65. if ($timestamp >= $filter_ts_from
  66. && $timestamp <= $filter_ts_to
  67. && (in_array('*', $filter_users) || in_array($entry['username'], $filter_users))
  68. ) {
  69. $tmp_entries[] = array( 'id' => $id,
  70. 'timestamp' => $timestamp,
  71. 'username' => $entry['username'],
  72. 'statement' => $entry['statement']
  73. );
  74. }
  75. $id++;
  76. }
  77. return($tmp_entries);
  78. }
  79. $entries = array();
  80. // Filtering data definition statements
  81. if ($_REQUEST['logtype'] == 'schema'
  82. || $_REQUEST['logtype'] == 'schema_and_data'
  83. ) {
  84. $entries = array_merge(
  85. $entries,
  86. PMA_filter_tracking(
  87. $data['ddlog'], $filter_ts_from, $filter_ts_to, $filter_users
  88. )
  89. );
  90. }
  91. // Filtering data manipulation statements
  92. if ($_REQUEST['logtype'] == 'data'
  93. || $_REQUEST['logtype'] == 'schema_and_data'
  94. ) {
  95. $entries = array_merge(
  96. $entries,
  97. PMA_filter_tracking(
  98. $data['dmlog'], $filter_ts_from, $filter_ts_to, $filter_users
  99. )
  100. );
  101. }
  102. // Sort it
  103. foreach ($entries as $key => $row) {
  104. $ids[$key] = $row['id'];
  105. $timestamps[$key] = $row['timestamp'];
  106. $usernames[$key] = $row['username'];
  107. $statements[$key] = $row['statement'];
  108. }
  109. array_multisort(
  110. $timestamps, SORT_ASC, $ids, SORT_ASC, $usernames,
  111. SORT_ASC, $statements, SORT_ASC, $entries
  112. );
  113. }
  114. // Export as file download
  115. if (isset($_REQUEST['report_export'])
  116. && $_REQUEST['export_type'] == 'sqldumpfile'
  117. ) {
  118. @ini_set('url_rewriter.tags', '');
  119. // Replace all multiple whitespaces by a single space
  120. $table = htmlspecialchars(preg_replace('/\s+/', ' ', $_REQUEST['table']));
  121. $dump = "# " . sprintf(
  122. __('Tracking report for table `%s`'), $table
  123. )
  124. . "\n" . "# " . date('Y-m-d H:i:s') . "\n";
  125. foreach ($entries as $entry) {
  126. $dump .= $entry['statement'];
  127. }
  128. $filename = 'log_' . $table . '.sql';
  129. PMA_downloadHeader($filename, 'text/x-sql', strlen($dump));
  130. echo $dump;
  131. exit();
  132. }
  133. /**
  134. * Gets tables informations
  135. */
  136. echo '<br />';
  137. /**
  138. * Actions
  139. */
  140. // Create tracking version
  141. if (isset($_REQUEST['submit_create_version'])) {
  142. $tracking_set = '';
  143. if ($_REQUEST['alter_table'] == true) {
  144. $tracking_set .= 'ALTER TABLE,';
  145. }
  146. if ($_REQUEST['rename_table'] == true) {
  147. $tracking_set .= 'RENAME TABLE,';
  148. }
  149. if ($_REQUEST['create_table'] == true) {
  150. $tracking_set .= 'CREATE TABLE,';
  151. }
  152. if ($_REQUEST['drop_table'] == true) {
  153. $tracking_set .= 'DROP TABLE,';
  154. }
  155. if ($_REQUEST['create_index'] == true) {
  156. $tracking_set .= 'CREATE INDEX,';
  157. }
  158. if ($_REQUEST['drop_index'] == true) {
  159. $tracking_set .= 'DROP INDEX,';
  160. }
  161. if ($_REQUEST['insert'] == true) {
  162. $tracking_set .= 'INSERT,';
  163. }
  164. if ($_REQUEST['update'] == true) {
  165. $tracking_set .= 'UPDATE,';
  166. }
  167. if ($_REQUEST['delete'] == true) {
  168. $tracking_set .= 'DELETE,';
  169. }
  170. if ($_REQUEST['truncate'] == true) {
  171. $tracking_set .= 'TRUNCATE,';
  172. }
  173. $tracking_set = rtrim($tracking_set, ',');
  174. $versionCreated = PMA_Tracker::createVersion(
  175. $GLOBALS['db'],
  176. $GLOBALS['table'],
  177. $_REQUEST['version'],
  178. $tracking_set,
  179. PMA_Table::isView($GLOBALS['db'], $GLOBALS['table'])
  180. );
  181. if ($versionCreated) {
  182. $msg = PMA_Message::success(
  183. sprintf(
  184. __('Version %1$s was created, tracking for %2$s is active.'),
  185. htmlspecialchars($_REQUEST['version']),
  186. htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table'])
  187. )
  188. );
  189. $msg->display();
  190. }
  191. }
  192. // Deactivate tracking
  193. if (isset($_REQUEST['submit_deactivate_now'])) {
  194. $deactivated = PMA_Tracker::deactivateTracking(
  195. $GLOBALS['db'], $GLOBALS['table'], $_REQUEST['version']
  196. );
  197. if ($deactivated) {
  198. $msg = PMA_Message::success(
  199. sprintf(
  200. __('Tracking for %1$s was deactivated at version %2$s.'),
  201. htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table']),
  202. htmlspecialchars($_REQUEST['version'])
  203. )
  204. );
  205. $msg->display();
  206. }
  207. }
  208. // Activate tracking
  209. if (isset($_REQUEST['submit_activate_now'])) {
  210. $activated = PMA_Tracker::activateTracking(
  211. $GLOBALS['db'], $GLOBALS['table'], $_REQUEST['version']
  212. );
  213. if ($activated) {
  214. $msg = PMA_Message::success(
  215. sprintf(
  216. __('Tracking for %1$s was activated at version %2$s.'),
  217. htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table']),
  218. htmlspecialchars($_REQUEST['version'])
  219. )
  220. );
  221. $msg->display();
  222. }
  223. }
  224. // Export as SQL execution
  225. if (isset($_REQUEST['report_export']) && $_REQUEST['export_type'] == 'execution') {
  226. foreach ($entries as $entry) {
  227. $sql_result = PMA_DBI_query("/*NOTRACK*/\n" . $entry['statement']);
  228. }
  229. $msg = PMA_Message::success(__('SQL statements executed.'));
  230. $msg->display();
  231. }
  232. // Export as SQL dump
  233. if (isset($_REQUEST['report_export']) && $_REQUEST['export_type'] == 'sqldump') {
  234. $new_query = "# "
  235. . __('You can execute the dump by creating and using a temporary database. Please ensure that you have the privileges to do so.')
  236. . "\n"
  237. . "# " . __('Comment out these two lines if you do not need them.') . "\n"
  238. . "\n"
  239. . "CREATE database IF NOT EXISTS pma_temp_db; \n"
  240. . "USE pma_temp_db; \n"
  241. . "\n";
  242. foreach ($entries as $entry) {
  243. $new_query .= $entry['statement'];
  244. }
  245. $msg = PMA_Message::success(
  246. __('SQL statements exported. Please copy the dump or execute it.')
  247. );
  248. $msg->display();
  249. $db_temp = $db;
  250. $table_temp = $table;
  251. $db = $table = '';
  252. include_once './libraries/sql_query_form.lib.php';
  253. PMA_sqlQueryForm($new_query, 'sql');
  254. $db = $db_temp;
  255. $table = $table_temp;
  256. }
  257. /*
  258. * Schema snapshot
  259. */
  260. if (isset($_REQUEST['snapshot'])) {
  261. echo '<h3>' . __('Structure snapshot')
  262. . ' [<a href="tbl_tracking.php?' . $url_query . '">' . __('Close')
  263. . '</a>]</h3>';
  264. $data = PMA_Tracker::getTrackedData(
  265. $_REQUEST['db'], $_REQUEST['table'], $_REQUEST['version']
  266. );
  267. // Get first DROP TABLE/VIEW and CREATE TABLE/VIEW statements
  268. $drop_create_statements = $data['ddlog'][0]['statement'];
  269. if (strstr($data['ddlog'][0]['statement'], 'DROP TABLE')
  270. || strstr($data['ddlog'][0]['statement'], 'DROP VIEW')) {
  271. $drop_create_statements .= $data['ddlog'][1]['statement'];
  272. }
  273. // Print SQL code
  274. echo PMA_Util::getMessage(
  275. sprintf(
  276. __('Version %s snapshot (SQL code)'),
  277. htmlspecialchars($_REQUEST['version'])
  278. ),
  279. $drop_create_statements
  280. );
  281. // Unserialize snapshot
  282. $temp = PMA_safeUnserialize($data['schema_snapshot']);
  283. if ($temp === null) {
  284. $temp = array('COLUMNS' => array(), 'INDEXES' => array());
  285. }
  286. $columns = $temp['COLUMNS'];
  287. $indexes = $temp['INDEXES'];
  288. echo '<h3>' . __('Structure') . '</h3>';
  289. echo '<table id="tablestructure" class="data">';
  290. echo '<thead>';
  291. echo '<tr>';
  292. echo '<th>' . __('Column') . '</th>';
  293. echo '<th>' . __('Type') . '</th>';
  294. echo '<th>' . __('Collation') . '</th>';
  295. echo '<th>' . __('Null') . '</th>';
  296. echo '<th>' . __('Default') . '</th>';
  297. echo '<th>' . __('Extra') . '</th>';
  298. echo '<th>' . __('Comment') . '</th>';
  299. echo '</tr>';
  300. echo '</thead>';
  301. echo '<tbody>';
  302. $style = 'odd';
  303. foreach ($columns as $field_index => $field) {
  304. echo '<tr class="noclick ' . $style . '">';
  305. if ($field['Key'] == 'PRI') {
  306. echo '<td><b><u>' . htmlspecialchars($field['Field']) . '</u></b></td>';
  307. } else {
  308. echo '<td><b>' . htmlspecialchars($field['Field']) . '</b></td>';
  309. }
  310. echo "\n";
  311. echo '<td>' . htmlspecialchars($field['Type']) . '</td>';
  312. echo '<td>' . htmlspecialchars($field['Collation']) . '</td>';
  313. echo '<td>' . (($field['Null'] == 'YES') ? __('Yes') : __('No')) . '</td>';
  314. echo '<td>';
  315. if (isset($field['Default'])) {
  316. $extracted_columnspec = PMA_Util::extractColumnSpec($field['Type']);
  317. if ($extracted_columnspec['type'] == 'bit') {
  318. // here, $field['Default'] contains something like b'010'
  319. echo PMA_Util::convertBitDefaultValue($field['Default']);
  320. } else {
  321. echo htmlspecialchars($field['Default']);
  322. }
  323. } else {
  324. if ($field['Null'] == 'YES') {
  325. echo '<i>NULL</i>';
  326. } else {
  327. echo '<i>' . _pgettext('None for default', 'None') . '</i>';
  328. }
  329. }
  330. echo '</td>';
  331. echo '<td>' . htmlspecialchars($field['Extra']) . '</td>';
  332. echo '<td>' . htmlspecialchars($field['Comment']) . '</td>';
  333. echo '</tr>';
  334. if ($style == 'even') {
  335. $style = 'odd';
  336. } else {
  337. $style = 'even';
  338. }
  339. }
  340. echo '</tbody>';
  341. echo '</table>';
  342. if (count($indexes) > 0) {
  343. echo '<h3>' . __('Indexes') . '</h3>';
  344. echo '<table id="tablestructure_indexes" class="data">';
  345. echo '<thead>';
  346. echo '<tr>';
  347. echo '<th>' . __('Keyname') . '</th>';
  348. echo '<th>' . __('Type') . '</th>';
  349. echo '<th>' . __('Unique') . '</th>';
  350. echo '<th>' . __('Packed') . '</th>';
  351. echo '<th>' . __('Column') . '</th>';
  352. echo '<th>' . __('Cardinality') . '</th>';
  353. echo '<th>' . __('Collation') . '</th>';
  354. echo '<th>' . __('Null') . '</th>';
  355. echo '<th>' . __('Comment') . '</th>';
  356. echo '</tr>';
  357. echo '<tbody>';
  358. $style = 'odd';
  359. foreach ($indexes as $indexes_index => $index) {
  360. if ($index['Non_unique'] == 0) {
  361. $str_unique = __('Yes');
  362. } else {
  363. $str_unique = __('No');
  364. }
  365. if ($index['Packed'] != '') {
  366. $str_packed = __('Yes');
  367. } else {
  368. $str_packed = __('No');
  369. }
  370. echo '<tr class="noclick ' . $style . '">';
  371. echo '<td><b>' . htmlspecialchars($index['Key_name']) . '</b></td>';
  372. echo '<td>' . htmlspecialchars($index['Index_type']) . '</td>';
  373. echo '<td>' . $str_unique . '</td>';
  374. echo '<td>' . $str_packed . '</td>';
  375. echo '<td>' . htmlspecialchars($index['Column_name']) . '</td>';
  376. echo '<td>' . htmlspecialchars($index['Cardinality']) . '</td>';
  377. echo '<td>' . htmlspecialchars($index['Collation']) . '</td>';
  378. echo '<td>' . htmlspecialchars($index['Null']) . '</td>';
  379. echo '<td>' . htmlspecialchars($index['Comment']) . '</td>';
  380. echo '</tr>';
  381. if ($style == 'even') {
  382. $style = 'odd';
  383. } else {
  384. $style = 'even';
  385. }
  386. }
  387. echo '</tbody>';
  388. echo '</table>';
  389. } // endif
  390. echo '<br /><hr /><br />';
  391. }
  392. // end of snapshot report
  393. /*
  394. * Tracking report
  395. */
  396. if (isset($_REQUEST['report'])
  397. && (isset($_REQUEST['delete_ddlog']) || isset($_REQUEST['delete_dmlog']))
  398. ) {
  399. if (isset($_REQUEST['delete_ddlog'])) {
  400. // Delete ddlog row data
  401. $delete_id = $_REQUEST['delete_ddlog'];
  402. // Only in case of valable id
  403. if ($delete_id == (int)$delete_id) {
  404. unset($data['ddlog'][$delete_id]);
  405. $successfullyDeleted = PMA_Tracker::changeTrackingData(
  406. $_REQUEST['db'], $_REQUEST['table'],
  407. $_REQUEST['version'], 'DDL', $data['ddlog']
  408. );
  409. if ($successfullyDeleted) {
  410. $msg = PMA_Message::success(
  411. __('Tracking data definition successfully deleted')
  412. );
  413. } else {
  414. $msg = PMA_Message::rawError(__('Query error'));
  415. }
  416. $msg->display();
  417. }
  418. }
  419. if (isset($_REQUEST['delete_dmlog'])) {
  420. // Delete dmlog row data
  421. $delete_id = $_REQUEST['delete_dmlog'];
  422. // Only in case of valable id
  423. if ($delete_id == (int)$delete_id) {
  424. unset($data['dmlog'][$delete_id]);
  425. $successfullyDeleted = PMA_Tracker::changeTrackingData(
  426. $_REQUEST['db'], $_REQUEST['table'],
  427. $_REQUEST['version'], 'DML', $data['dmlog']
  428. );
  429. if ($successfullyDeleted) {
  430. $msg = PMA_Message::success(
  431. __('Tracking data manipulation successfully deleted')
  432. );
  433. } else {
  434. $msg = PMA_Message::rawError(__('Query error'));
  435. }
  436. $msg->display();
  437. }
  438. }
  439. }
  440. if (isset($_REQUEST['report']) || isset($_REQUEST['report_export'])) {
  441. echo '<h3>' . __('Tracking report')
  442. . ' [<a href="tbl_tracking.php?' . $url_query . '">' . __('Close')
  443. . '</a>]</h3>';
  444. echo '<small>' . __('Tracking statements') . ' '
  445. . htmlspecialchars($data['tracking']) . '</small><br/>';
  446. echo '<br/>';
  447. echo '<form method="post" action="tbl_tracking.php'
  448. . PMA_generate_common_url(
  449. $url_params + array('report' => 'true', 'version' => $_REQUEST['version'])
  450. )
  451. . '">';
  452. $str1 = '<select name="logtype">'
  453. . '<option value="schema"'
  454. . ($selection_schema ? ' selected="selected"' : '') . '>'
  455. . __('Structure only') . '</option>'
  456. . '<option value="data"'
  457. . ($selection_data ? ' selected="selected"' : ''). '>'
  458. . __('Data only') . '</option>'
  459. . '<option value="schema_and_data"'
  460. . ($selection_both ? ' selected="selected"' : '') . '>'
  461. . __('Structure and data') . '</option>'
  462. . '</select>';
  463. $str2 = '<input type="text" name="date_from" value="'
  464. . htmlspecialchars($_REQUEST['date_from']) . '" size="19" />';
  465. $str3 = '<input type="text" name="date_to" value="'
  466. . htmlspecialchars($_REQUEST['date_to']) . '" size="19" />';
  467. $str4 = '<input type="text" name="users" value="'
  468. . htmlspecialchars($_REQUEST['users']) . '" />';
  469. $str5 = '<input type="hidden" name="list_report" value="1" />'
  470. . '<input type="submit" value="' . __('Go') . '" />';
  471. printf(
  472. __('Show %1$s with dates from %2$s to %3$s by user %4$s %5$s'),
  473. $str1, $str2, $str3, $str4, $str5
  474. );
  475. // Prepare delete link content here
  476. $drop_image_or_text = '';
  477. if ('icons' == $GLOBALS['cfg']['ActionsLinksMode']) {
  478. $drop_image_or_text .= PMA_Util::getImage(
  479. 'b_drop.png', __('Delete tracking data row from report')
  480. );
  481. }
  482. if (in_array(
  483. $GLOBALS['cfg']['ActionLinksMode'],
  484. array('text', 'both')
  485. )
  486. ) {
  487. $drop_image_or_text .= __('Delete');
  488. }
  489. /*
  490. * First, list tracked data definition statements
  491. */
  492. $i = 1;
  493. if (count($data['ddlog']) == 0 && count($data['dmlog']) == 0) {
  494. $msg = PMA_Message::notice(__('No data'));
  495. $msg->display();
  496. }
  497. if ($selection_schema || $selection_both && count($data['ddlog']) > 0) {
  498. echo '<table id="ddl_versions" class="data" width="100%">';
  499. echo '<thead>';
  500. echo '<tr>';
  501. echo '<th width="18">#</th>';
  502. echo '<th width="100">' . __('Date') . '</th>';
  503. echo '<th width="60">' . __('Username') . '</th>';
  504. echo '<th>' . __('Data definition statement') . '</th>';
  505. echo '<th>' . __('Delete') . '</th>';
  506. echo '</tr>';
  507. echo '</thead>';
  508. echo '<tbody>';
  509. $style = 'odd';
  510. foreach ($data['ddlog'] as $entry) {
  511. if (strlen($entry['statement']) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) {
  512. $statement = substr(
  513. $entry['statement'],
  514. 0,
  515. $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']
  516. ) . '[...]';
  517. } else {
  518. $statement = PMA_Util::formatSql(PMA_SQP_parse($entry['statement']));
  519. }
  520. $timestamp = strtotime($entry['date']);
  521. if ($timestamp >= $filter_ts_from
  522. && $timestamp <= $filter_ts_to
  523. && (in_array('*', $filter_users) || in_array($entry['username'], $filter_users))
  524. ) {
  525. echo '<tr class="noclick ' . $style . '">';
  526. echo '<td><small>' . $i . '</small></td>';
  527. echo '<td><small>' . htmlspecialchars($entry['date']) . '</small></td>';
  528. echo '<td><small>' . htmlspecialchars($entry['username']) . '</small></td>';
  529. echo '<td>' . $statement . '</td>';
  530. echo '<td class="nowrap"><a href="tbl_tracking.php'
  531. . PMA_generate_common_url(
  532. $url_params + array(
  533. 'report' => 'true',
  534. 'version' => $_REQUEST['version'],
  535. 'delete_ddlog' => ($i - 1),
  536. )
  537. )
  538. . '">' . $drop_image_or_text
  539. . '</a></td>';
  540. echo '</tr>';
  541. if ($style == 'even') {
  542. $style = 'odd';
  543. } else {
  544. $style = 'even';
  545. }
  546. $i++;
  547. }
  548. }
  549. echo '</tbody>';
  550. echo '</table>';
  551. } //endif
  552. // Memorize data definition amount
  553. $ddlog_count = $i;
  554. /*
  555. * Secondly, list tracked data manipulation statements
  556. */
  557. if (($selection_data || $selection_both) && count($data['dmlog']) > 0) {
  558. echo '<table id="dml_versions" class="data" width="100%">';
  559. echo '<thead>';
  560. echo '<tr>';
  561. echo '<th width="18">#</th>';
  562. echo '<th width="100">' . __('Date') . '</th>';
  563. echo '<th width="60">' . __('Username') . '</th>';
  564. echo '<th>' . __('Data manipulation statement') . '</th>';
  565. echo '<th>' . __('Delete') . '</th>';
  566. echo '</tr>';
  567. echo '</thead>';
  568. echo '<tbody>';
  569. $style = 'odd';
  570. foreach ($data['dmlog'] as $entry) {
  571. if (strlen($entry['statement']) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) {
  572. $statement = substr(
  573. $entry['statement'],
  574. 0,
  575. $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']
  576. ) . '[...]';
  577. } else {
  578. $statement = PMA_Util::formatSql(PMA_SQP_parse($entry['statement']));
  579. }
  580. $timestamp = strtotime($entry['date']);
  581. if ($timestamp >= $filter_ts_from
  582. && $timestamp <= $filter_ts_to
  583. && (in_array('*', $filter_users) || in_array($entry['username'], $filter_users))
  584. ) {
  585. echo '<tr class="noclick ' . $style . '">';
  586. echo '<td><small>' . $i . '</small></td>';
  587. echo '<td><small>' . htmlspecialchars($entry['date']) . '</small></td>';
  588. echo '<td><small>' . htmlspecialchars($entry['username']) . '</small></td>';
  589. echo '<td>' . $statement . '</td>';
  590. echo '<td class="nowrap"><a href="tbl_tracking.php?'
  591. . PMA_generate_common_url(
  592. $url_params + array(
  593. 'report' => 'true',
  594. 'version' => $_REQUEST['version'],
  595. 'delete_dmlog' => ($i - $ddlog_count),
  596. )
  597. )
  598. . '">'
  599. . $drop_image_or_text
  600. . '</a></td>';
  601. echo '</tr>';
  602. if ($style == 'even') {
  603. $style = 'odd';
  604. } else {
  605. $style = 'even';
  606. }
  607. $i++;
  608. }
  609. }
  610. echo '</tbody>';
  611. echo '</table>';
  612. }
  613. echo '</form>';
  614. echo '<form method="post" action="tbl_tracking.php'
  615. . PMA_generate_common_url(
  616. $url_params + array('report' => 'true', 'version' => $_REQUEST['version'])
  617. )
  618. . '">';
  619. printf(
  620. __('Show %1$s with dates from %2$s to %3$s by user %4$s %5$s'),
  621. $str1, $str2, $str3, $str4, $str5
  622. );
  623. $str_export1 = '<select name="export_type">'
  624. . '<option value="sqldumpfile">' . __('SQL dump (file download)') . '</option>'
  625. . '<option value="sqldump">' . __('SQL dump') . '</option>'
  626. . '<option value="execution" onclick="alert(\''
  627. . PMA_escapeJsString(__('This option will replace your table and contained data.'))
  628. .'\')">' . __('SQL execution') . '</option>' . '</select>';
  629. $str_export2 = '<input type="hidden" name="report_export" value="1" />'
  630. . '<input type="submit" value="' . __('Go') .'" />';
  631. echo '</form>';
  632. echo '<form class="disableAjax" method="post" action="tbl_tracking.php'
  633. . PMA_generate_common_url(
  634. $url_params + array('report' => 'true', 'version' => $_REQUEST['version'])
  635. )
  636. . '">';
  637. echo '<input type="hidden" name="logtype" value="'
  638. . htmlspecialchars($_REQUEST['logtype']) . '" />';
  639. echo '<input type="hidden" name="date_from" value="'
  640. . htmlspecialchars($_REQUEST['date_from']) . '" />';
  641. echo '<input type="hidden" name="date_to" value="'
  642. . htmlspecialchars($_REQUEST['date_to']) . '" />';
  643. echo '<input type="hidden" name="users" value="'
  644. . htmlspecialchars($_REQUEST['users']) . '" />';
  645. echo "<br/>" . sprintf(__('Export as %s'), $str_export1)
  646. . $str_export2 . "<br/>";
  647. echo '</form>';
  648. echo "<br/><br/><hr/><br/>\n";
  649. } // end of report
  650. /*
  651. * List selectable tables
  652. */
  653. $sql_query = " SELECT DISTINCT db_name, table_name FROM " .
  654. PMA_Util::backquote($GLOBALS['cfg']['Server']['pmadb']) . "." .
  655. PMA_Util::backquote($GLOBALS['cfg']['Server']['tracking']) .
  656. " WHERE db_name = '" . PMA_Util::sqlAddSlashes($GLOBALS['db']) . "' " .
  657. " ORDER BY db_name, table_name";
  658. $sql_result = PMA_queryAsControlUser($sql_query);
  659. if (PMA_DBI_num_rows($sql_result) > 0) {
  660. echo '<form method="post" action="tbl_tracking.php?' . $url_query . '">';
  661. echo '<select name="table">';
  662. while ($entries = PMA_DBI_fetch_array($sql_result)) {
  663. if (PMA_Tracker::isTracked($entries['db_name'], $entries['table_name'])) {
  664. $status = ' (' . __('active') . ')';
  665. } else {
  666. $status = ' (' . __('not active') . ')';
  667. }
  668. if ($entries['table_name'] == $_REQUEST['table']) {
  669. $s = ' selected="selected"';
  670. } else {
  671. $s = '';
  672. }
  673. echo '<option value="' . htmlspecialchars($entries['table_name']) . '"' . $s . '>' . htmlspecialchars($entries['db_name']) . ' . ' . htmlspecialchars($entries['table_name']) . $status . '</option>' . "\n";
  674. }
  675. echo '</select>';
  676. echo '<input type="hidden" name="show_versions_submit" value="1" />';
  677. echo '<input type="submit" value="' . __('Show versions') . '" />';
  678. echo '</form>';
  679. }
  680. echo '<br />';
  681. /*
  682. * List versions of current table
  683. */
  684. $sql_query = " SELECT * FROM " .
  685. PMA_Util::backquote($GLOBALS['cfg']['Server']['pmadb']) . "." .
  686. PMA_Util::backquote($GLOBALS['cfg']['Server']['tracking']) .
  687. " WHERE db_name = '" . PMA_Util::sqlAddSlashes($_REQUEST['db']) . "' ".
  688. " AND table_name = '" . PMA_Util::sqlAddSlashes($_REQUEST['table']) ."' ".
  689. " ORDER BY version DESC ";
  690. $sql_result = PMA_queryAsControlUser($sql_query);
  691. $last_version = 0;
  692. $maxversion = PMA_DBI_fetch_array($sql_result);
  693. $last_version = $maxversion['version'];
  694. if ($last_version > 0) {
  695. echo '<table id="versions" class="data">';
  696. echo '<thead>';
  697. echo '<tr>';
  698. echo '<th>' . __('Database') . '</th>';
  699. echo '<th>' . __('Table') . '</th>';
  700. echo '<th>' . __('Version') . '</th>';
  701. echo '<th>' . __('Created') . '</th>';
  702. echo '<th>' . __('Updated') . '</th>';
  703. echo '<th>' . __('Status') . '</th>';
  704. echo '<th>' . __('Show') . '</th>';
  705. echo '</tr>';
  706. echo '</thead>';
  707. echo '<tbody>';
  708. $style = 'odd';
  709. PMA_DBI_data_seek($sql_result, 0);
  710. while ($version = PMA_DBI_fetch_array($sql_result)) {
  711. if ($version['tracking_active'] == 1) {
  712. $version_status = __('active');
  713. } else {
  714. $version_status = __('not active');
  715. }
  716. if ($version['version'] == $last_version) {
  717. if ($version['tracking_active'] == 1) {
  718. $tracking_active = true;
  719. } else {
  720. $tracking_active = false;
  721. }
  722. }
  723. echo '<tr class="noclick ' . $style . '">';
  724. echo '<td>' . htmlspecialchars($version['db_name']) . '</td>';
  725. echo '<td>' . htmlspecialchars($version['table_name']) . '</td>';
  726. echo '<td>' . htmlspecialchars($version['version']) . '</td>';
  727. echo '<td>' . htmlspecialchars($version['date_created']) . '</td>';
  728. echo '<td>' . htmlspecialchars($version['date_updated']) . '</td>';
  729. echo '<td>' . $version_status . '</td>';
  730. echo '<td><a href="tbl_tracking.php';
  731. echo PMA_generate_common_url(
  732. $url_params + array('report' => 'true', 'version' => $version['version'])
  733. );
  734. echo '">' . __('Tracking report') . '</a>';
  735. echo '| <a href="tbl_tracking.php';
  736. echo PMA_generate_common_url(
  737. $url_params + array('snapshot' => 'true', 'version' => $version['version'])
  738. );
  739. echo '">' . __('Structure snapshot') . '</a>';
  740. echo '</td>';
  741. echo '</tr>';
  742. if ($style == 'even') {
  743. $style = 'odd';
  744. } else {
  745. $style = 'even';
  746. }
  747. }
  748. echo '</tbody>';
  749. echo '</table>';
  750. if ($tracking_active) {
  751. echo '<div id="div_deactivate_tracking">';
  752. echo '<form method="post" action="tbl_tracking.php?' . $url_query . '">';
  753. echo '<fieldset>';
  754. echo '<legend>';
  755. printf(
  756. __('Deactivate tracking for %s'),
  757. htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table'])
  758. );
  759. echo '</legend>';
  760. echo '<input type="hidden" name="version" value="' . $last_version . '" />';
  761. echo '<input type="hidden" name="submit_deactivate_now" value="1" />';
  762. echo '<input type="submit" value="' . __('Deactivate now') . '" />';
  763. echo '</fieldset>';
  764. echo '</form>';
  765. echo '</div>';
  766. } else {
  767. echo '<div id="div_activate_tracking">';
  768. echo '<form method="post" action="tbl_tracking.php?' . $url_query . '">';
  769. echo '<fieldset>';
  770. echo '<legend>';
  771. printf(
  772. __('Activate tracking for %s'),
  773. htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table'])
  774. );
  775. echo '</legend>';
  776. echo '<input type="hidden" name="version" value="' . $last_version . '" />';
  777. echo '<input type="hidden" name="submit_activate_now" value="1" />';
  778. echo '<input type="submit" value="' . __('Activate now') . '" />';
  779. echo '</fieldset>';
  780. echo '</form>';
  781. echo '</div>';
  782. }
  783. }
  784. echo '<div id="div_create_version">';
  785. echo '<form method="post" action="tbl_tracking.php?' . $url_query . '">';
  786. echo PMA_generate_common_hidden_inputs($GLOBALS['db'], $GLOBALS['table']);
  787. echo '<fieldset>';
  788. echo '<legend>';
  789. printf(
  790. __('Create version %1$s of %2$s'),
  791. ($last_version + 1),
  792. htmlspecialchars($GLOBALS['db'] . '.' . $GLOBALS['table'])
  793. );
  794. echo '</legend>';
  795. echo '<input type="hidden" name="version" value="' . ($last_version + 1) . '" />';
  796. echo '<p>' . __('Track these data definition statements:') . '</p>';
  797. echo '<input type="checkbox" name="alter_table" value="true" checked="checked" /> ALTER TABLE<br/>';
  798. echo '<input type="checkbox" name="rename_table" value="true" checked="checked" /> RENAME TABLE<br/>';
  799. echo '<input type="checkbox" name="create_table" value="true" checked="checked" /> CREATE TABLE<br/>';
  800. echo '<input type="checkbox" name="drop_table" value="true" checked="checked" /> DROP TABLE<br/>';
  801. echo '<br/>';
  802. echo '<input type="checkbox" name="create_index" value="true" checked="checked" /> CREATE INDEX<br/>';
  803. echo '<input type="checkbox" name="drop_index" value="true" checked="checked" /> DROP INDEX<br/>';
  804. echo '<p>' . __('Track these data manipulation statements:') . '</p>';
  805. echo '<input type="checkbox" name="insert" value="true" checked="checked" /> INSERT<br/>';
  806. echo '<input type="checkbox" name="update" value="true" checked="checked" /> UPDATE<br/>';
  807. echo '<input type="checkbox" name="delete" value="true" checked="checked" /> DELETE<br/>';
  808. echo '<input type="checkbox" name="truncate" value="true" checked="checked" /> TRUNCATE<br/>';
  809. echo '</fieldset>';
  810. echo '<fieldset class="tblFooters">';
  811. echo '<input type="hidden" name="submit_create_version" value="1" />';
  812. echo '<input type="submit" value="' . __('Create version') . '" />';
  813. echo '</fieldset>';
  814. echo '</form>';
  815. echo '</div>';
  816. echo '<br class="clearfloat"/>';