SqlQueryForm.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * functions for displaying the sql query form
  5. *
  6. * @usedby server_sql.php
  7. * @usedby db_sql.php
  8. * @usedby tbl_sql.php
  9. * @usedby tbl_structure.php
  10. * @usedby tbl_tracking.php
  11. * @package PhpMyAdmin
  12. */
  13. declare(strict_types=1);
  14. namespace PhpMyAdmin;
  15. use PhpMyAdmin\Bookmark;
  16. use PhpMyAdmin\Encoding;
  17. use PhpMyAdmin\Url;
  18. use PhpMyAdmin\Util;
  19. /**
  20. * PhpMyAdmin\SqlQueryForm class
  21. *
  22. * @package PhpMyAdmin
  23. */
  24. class SqlQueryForm
  25. {
  26. /**
  27. * return HTML for the sql query boxes
  28. *
  29. * @param boolean|string $query query to display in the textarea
  30. * or true to display last executed
  31. * @param boolean|string $display_tab sql|full|false
  32. * what part to display
  33. * false if not inside querywindow
  34. * @param string $delimiter delimiter
  35. *
  36. * @return string
  37. *
  38. * @usedby server_sql.php
  39. * @usedby db_sql.php
  40. * @usedby tbl_sql.php
  41. * @usedby tbl_structure.php
  42. * @usedby tbl_tracking.php
  43. */
  44. public function getHtml(
  45. $query = true,
  46. $display_tab = false,
  47. $delimiter = ';'
  48. ) {
  49. $html = '';
  50. if (! $display_tab) {
  51. $display_tab = 'full';
  52. }
  53. // query to show
  54. if (true === $query) {
  55. $query = $GLOBALS['sql_query'];
  56. }
  57. // set enctype to multipart for file uploads
  58. if ($GLOBALS['is_upload']) {
  59. $enctype = ' enctype="multipart/form-data"';
  60. } else {
  61. $enctype = '';
  62. }
  63. $table = '';
  64. $db = '';
  65. if (strlen($GLOBALS['db']) === 0) {
  66. // prepare for server related
  67. $goto = empty($GLOBALS['goto']) ?
  68. 'server_sql.php' : $GLOBALS['goto'];
  69. } elseif (strlen($GLOBALS['table']) === 0) {
  70. // prepare for db related
  71. $db = $GLOBALS['db'];
  72. $goto = empty($GLOBALS['goto']) ?
  73. 'db_sql.php' : $GLOBALS['goto'];
  74. } else {
  75. $table = $GLOBALS['table'];
  76. $db = $GLOBALS['db'];
  77. $goto = empty($GLOBALS['goto']) ?
  78. 'tbl_sql.php' : $GLOBALS['goto'];
  79. }
  80. // start output
  81. $html .= '<form method="post" action="import.php" ' . $enctype;
  82. $html .= ' class="ajax lock-page"';
  83. $html .= ' id="sqlqueryform" name="sqlform">' . "\n";
  84. $html .= '<input type="hidden" name="is_js_confirmed" value="0">'
  85. . "\n" . Url::getHiddenInputs($db, $table) . "\n"
  86. . '<input type="hidden" name="pos" value="0">' . "\n"
  87. . '<input type="hidden" name="goto" value="'
  88. . htmlspecialchars($goto) . '">' . "\n"
  89. . '<input type="hidden" name="message_to_show" value="'
  90. . __('Your SQL query has been executed successfully.') . '">'
  91. . "\n" . '<input type="hidden" name="prev_sql_query" value="'
  92. . htmlspecialchars($query) . '">' . "\n";
  93. // display querybox
  94. if ($display_tab === 'full' || $display_tab === 'sql') {
  95. $html .= $this->getHtmlForInsert(
  96. $query,
  97. $delimiter
  98. );
  99. }
  100. // Bookmark Support
  101. if ($display_tab === 'full') {
  102. $cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']);
  103. if ($cfgBookmark) {
  104. $html .= $this->getHtmlForBookmark();
  105. }
  106. }
  107. // Japanese encoding setting
  108. if (Encoding::canConvertKanji()) {
  109. $html .= Encoding::kanjiEncodingForm();
  110. }
  111. $html .= '</form>' . "\n";
  112. // print an empty div, which will be later filled with
  113. // the sql query results by ajax
  114. $html .= '<div id="sqlqueryresultsouter"></div>';
  115. return $html;
  116. }
  117. /**
  118. * Get initial values for Sql Query Form Insert
  119. *
  120. * @param string $query query to display in the textarea
  121. *
  122. * @return array ($legend, $query, $columns_list)
  123. */
  124. public function init($query)
  125. {
  126. $columns_list = [];
  127. if (strlen($GLOBALS['db']) === 0) {
  128. // prepare for server related
  129. $legend = sprintf(
  130. __('Run SQL query/queries on server “%s”'),
  131. htmlspecialchars(
  132. ! empty($GLOBALS['cfg']['Servers'][$GLOBALS['server']]['verbose'])
  133. ? $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['verbose']
  134. : $GLOBALS['cfg']['Servers'][$GLOBALS['server']]['host']
  135. )
  136. );
  137. } elseif (strlen($GLOBALS['table']) === 0) {
  138. // prepare for db related
  139. $db = $GLOBALS['db'];
  140. // if you want navigation:
  141. $tmp_db_link = '<a href="' . Util::getScriptNameForOption(
  142. $GLOBALS['cfg']['DefaultTabDatabase'],
  143. 'database'
  144. )
  145. . Url::getCommon(['db' => $db]) . '"';
  146. $tmp_db_link .= '>'
  147. . htmlspecialchars($db) . '</a>';
  148. $legend = sprintf(__('Run SQL query/queries on database %s'), $tmp_db_link);
  149. if (empty($query)) {
  150. $query = Util::expandUserString(
  151. $GLOBALS['cfg']['DefaultQueryDatabase'],
  152. 'backquote'
  153. );
  154. }
  155. } else {
  156. $db = $GLOBALS['db'];
  157. $table = $GLOBALS['table'];
  158. // Get the list and number of fields
  159. // we do a try_query here, because we could be in the query window,
  160. // trying to synchronize and the table has not yet been created
  161. $columns_list = $GLOBALS['dbi']->getColumns(
  162. $db,
  163. $GLOBALS['table'],
  164. null,
  165. true
  166. );
  167. $tmp_tbl_link = '<a href="' . Util::getScriptNameForOption(
  168. $GLOBALS['cfg']['DefaultTabTable'],
  169. 'table'
  170. ) . Url::getCommon(['db' => $db, 'table' => $table]) . '" >';
  171. $tmp_tbl_link .= htmlspecialchars($db)
  172. . '.' . htmlspecialchars($table) . '</a>';
  173. $legend = sprintf(__('Run SQL query/queries on table %s'), $tmp_tbl_link);
  174. if (empty($query)) {
  175. $query = Util::expandUserString(
  176. $GLOBALS['cfg']['DefaultQueryTable'],
  177. 'backquote'
  178. );
  179. }
  180. }
  181. $legend .= ': ' . Util::showMySQLDocu('SELECT');
  182. return [
  183. $legend,
  184. $query,
  185. $columns_list,
  186. ];
  187. }
  188. /**
  189. * return HTML for Sql Query Form Insert
  190. *
  191. * @param string $query query to display in the textarea
  192. * @param string $delimiter default delimiter to use
  193. *
  194. * @return string
  195. */
  196. public function getHtmlForInsert(
  197. $query = '',
  198. $delimiter = ';'
  199. ) {
  200. // enable auto select text in textarea
  201. if ($GLOBALS['cfg']['TextareaAutoSelect']) {
  202. $auto_sel = ' onclick="Functions.selectContent(this, sqlBoxLocked, true);"';
  203. } else {
  204. $auto_sel = '';
  205. }
  206. $locking = '';
  207. $height = $GLOBALS['cfg']['TextareaRows'] * 2;
  208. list($legend, $query, $columns_list) = $this->init($query);
  209. if (! empty($columns_list)) {
  210. $sqlquerycontainer_id = 'sqlquerycontainer';
  211. } else {
  212. $sqlquerycontainer_id = 'sqlquerycontainerfull';
  213. }
  214. $html = '<a id="querybox"></a>'
  215. . '<div id="queryboxcontainer">'
  216. . '<fieldset id="queryboxf">';
  217. $html .= '<legend>' . $legend . '</legend>';
  218. $html .= '<div id="queryfieldscontainer">';
  219. $html .= '<div id="' . $sqlquerycontainer_id . '">'
  220. . '<textarea tabindex="100" name="sql_query" id="sqlquery"'
  221. . ' cols="' . $GLOBALS['cfg']['TextareaCols'] . '"'
  222. . ' rows="' . $height . '"'
  223. . $auto_sel . $locking . '>'
  224. . htmlspecialchars($query)
  225. . '</textarea>';
  226. $html .= '<div id="querymessage"></div>';
  227. // Add buttons to generate query easily for
  228. // select all, single select, insert, update and delete
  229. if (! empty($columns_list)) {
  230. $html .= '<input type="button" value="SELECT *" id="selectall"'
  231. . ' class="btn btn-secondary button sqlbutton">';
  232. $html .= '<input type="button" value="SELECT" id="select"'
  233. . ' class="btn btn-secondary button sqlbutton">';
  234. $html .= '<input type="button" value="INSERT" id="insert"'
  235. . ' class="btn btn-secondary button sqlbutton">';
  236. $html .= '<input type="button" value="UPDATE" id="update"'
  237. . ' class="btn btn-secondary button sqlbutton">';
  238. $html .= '<input type="button" value="DELETE" id="delete"'
  239. . ' class="btn btn-secondary button sqlbutton">';
  240. }
  241. $html .= '<input type="button" value="' . __('Clear') . '" id="clear"'
  242. . ' class="btn btn-secondary button sqlbutton">';
  243. if ($GLOBALS['cfg']['CodemirrorEnable']) {
  244. $html .= '<input type="button" value="' . __('Format') . '" id="format"'
  245. . ' class="btn btn-secondary button sqlbutton">';
  246. }
  247. $html .= '<input type="button" value="' . __('Get auto-saved query')
  248. . '" id="saved" class="btn btn-secondary button sqlbutton">';
  249. // parameter binding
  250. $html .= '<div>';
  251. $html .= '<input type="checkbox" name="parameterized" id="parameterized">';
  252. $html .= '<label for="parameterized">' . __('Bind parameters') . '</label>';
  253. $html .= Util::showDocu('faq', 'faq6-40');
  254. $html .= '<div id="parametersDiv"></div>';
  255. $html .= '</div>';
  256. $html .= '</div>' . "\n";
  257. if (! empty($columns_list)) {
  258. $html .= '<div id="tablefieldscontainer">'
  259. . '<label>' . __('Columns') . '</label>'
  260. . '<select id="tablefields" name="dummy" '
  261. . 'size="' . ($GLOBALS['cfg']['TextareaRows'] - 2) . '" '
  262. . 'multiple="multiple" ondblclick="Functions.insertValueQuery()">';
  263. foreach ($columns_list as $field) {
  264. $html .= '<option value="'
  265. . Util::backquote(htmlspecialchars($field['Field']))
  266. . '"';
  267. if (isset($field['Field'])
  268. && strlen($field['Field']) > 0
  269. && isset($field['Comment'])
  270. ) {
  271. $html .= ' title="' . htmlspecialchars($field['Comment']) . '"';
  272. }
  273. $html .= '>' . htmlspecialchars($field['Field']) . '</option>' . "\n";
  274. }
  275. $html .= '</select>'
  276. . '<div id="tablefieldinsertbuttoncontainer">';
  277. if (Util::showIcons('ActionLinksMode')) {
  278. $html .= '<input type="button" class="btn btn-secondary button" name="insert"'
  279. . ' value="&lt;&lt;" onclick="Functions.insertValueQuery()"'
  280. . ' title="' . __('Insert') . '">';
  281. } else {
  282. $html .= '<input type="button" class="btn btn-secondary button" name="insert"'
  283. . ' value="' . __('Insert') . '"'
  284. . ' onclick="Functions.insertValueQuery()">';
  285. }
  286. $html .= '</div>' . "\n"
  287. . '</div>' . "\n";
  288. }
  289. $html .= '<div class="clearfloat"></div>' . "\n";
  290. $html .= '</div>' . "\n";
  291. $cfgBookmark = Bookmark::getParams($GLOBALS['cfg']['Server']['user']);
  292. if ($cfgBookmark) {
  293. $html .= '<div id="bookmarkoptions">';
  294. $html .= '<div class="formelement">';
  295. $html .= '<label for="bkm_label">'
  296. . __('Bookmark this SQL query:') . '</label>';
  297. $html .= '<input type="text" name="bkm_label" id="bkm_label"'
  298. . ' tabindex="110" value="">';
  299. $html .= '</div>';
  300. $html .= '<div class="formelement">';
  301. $html .= '<input type="checkbox" name="bkm_all_users" tabindex="111"'
  302. . ' id="id_bkm_all_users" value="true">';
  303. $html .= '<label for="id_bkm_all_users">'
  304. . __('Let every user access this bookmark') . '</label>';
  305. $html .= '</div>';
  306. $html .= '<div class="formelement">';
  307. $html .= '<input type="checkbox" name="bkm_replace" tabindex="112"'
  308. . ' id="id_bkm_replace" value="true">';
  309. $html .= '<label for="id_bkm_replace">'
  310. . __('Replace existing bookmark of same name') . '</label>';
  311. $html .= '</div>';
  312. $html .= '</div>';
  313. }
  314. $html .= '<div class="clearfloat"></div>' . "\n";
  315. $html .= '</fieldset>' . "\n"
  316. . '</div>' . "\n";
  317. $html .= '<fieldset id="queryboxfooter" class="tblFooters">' . "\n";
  318. $html .= '<div class="formelement">' . "\n";
  319. $html .= '</div>' . "\n";
  320. $html .= '<div class="formelement">';
  321. $html .= '<label for="id_sql_delimiter">[ ' . __('Delimiter')
  322. . '</label>' . "\n";
  323. $html .= '<input type="text" name="sql_delimiter" tabindex="131" size="3" '
  324. . 'value="' . $delimiter . '" '
  325. . 'id="id_sql_delimiter"> ]';
  326. $html .= '</div>';
  327. $html .= '<div class="formelement">';
  328. $html .= '<input type="checkbox" name="show_query" value="1" '
  329. . 'id="checkbox_show_query" tabindex="132">'
  330. . '<label for="checkbox_show_query">' . __('Show this query here again')
  331. . '</label>';
  332. $html .= '</div>';
  333. $html .= '<div class="formelement">';
  334. $html .= '<input type="checkbox" name="retain_query_box" value="1" '
  335. . 'id="retain_query_box" tabindex="133" '
  336. . ($GLOBALS['cfg']['RetainQueryBox'] === false
  337. ? '' : ' checked="checked"')
  338. . '>'
  339. . '<label for="retain_query_box">' . __('Retain query box')
  340. . '</label>';
  341. $html .= '</div>';
  342. $html .= '<div class="formelement">';
  343. $html .= '<input type="checkbox" name="rollback_query" value="1" '
  344. . 'id="rollback_query" tabindex="134">'
  345. . '<label for="rollback_query">' . __('Rollback when finished')
  346. . '</label>';
  347. $html .= '</div>';
  348. // Disable/Enable foreign key checks
  349. $html .= '<div class="formelement">';
  350. $html .= Util::getFKCheckbox();
  351. $html .= '</div>';
  352. $html .= '<input class="btn btn-primary" type="submit" id="button_submit_query" name="SQL"';
  353. $html .= ' tabindex="200" value="' . __('Go') . '">' . "\n";
  354. $html .= '<div class="clearfloat"></div>' . "\n";
  355. $html .= '</fieldset>' . "\n";
  356. return $html;
  357. }
  358. /**
  359. * return HTML for sql Query Form Bookmark
  360. *
  361. * @return string|null
  362. */
  363. public function getHtmlForBookmark()
  364. {
  365. $bookmark_list = Bookmark::getList(
  366. $GLOBALS['dbi'],
  367. $GLOBALS['cfg']['Server']['user'],
  368. $GLOBALS['db']
  369. );
  370. if (empty($bookmark_list) || count($bookmark_list) < 1) {
  371. return null;
  372. }
  373. $html = '<fieldset id="fieldsetBookmarkOptions">';
  374. $html .= '<legend>';
  375. $html .= __('Bookmarked SQL query') . '</legend>' . "\n";
  376. $html .= '<div class="formelement">';
  377. $html .= '<select name="id_bookmark" id="id_bookmark">' . "\n";
  378. $html .= '<option value="">&nbsp;</option>' . "\n";
  379. foreach ($bookmark_list as $bookmark) {
  380. $html .= '<option value="' . htmlspecialchars((string) $bookmark->getId()) . '"'
  381. . ' data-varcount="' . $bookmark->getVariableCount()
  382. . '">'
  383. . htmlspecialchars($bookmark->getLabel())
  384. . (empty($bookmark->getUser()) ? (' (' . __('shared') . ')') : '')
  385. . '</option>' . "\n";
  386. }
  387. // &nbsp; is required for correct display with styles/line height
  388. $html .= '</select>&nbsp;' . "\n";
  389. $html .= '</div>' . "\n";
  390. $html .= '<div class="formelement">' . "\n";
  391. $html .= '<input type="radio" name="action_bookmark" value="0"'
  392. . ' id="radio_bookmark_exe" checked="checked">'
  393. . '<label for="radio_bookmark_exe">' . __('Submit')
  394. . '</label>' . "\n";
  395. $html .= '<input type="radio" name="action_bookmark" value="1"'
  396. . ' id="radio_bookmark_view">'
  397. . '<label for="radio_bookmark_view">' . __('View only')
  398. . '</label>' . "\n";
  399. $html .= '<input type="radio" name="action_bookmark" value="2"'
  400. . ' id="radio_bookmark_del">'
  401. . '<label for="radio_bookmark_del">' . __('Delete')
  402. . '</label>' . "\n";
  403. $html .= '</div>' . "\n";
  404. $html .= '<div class="clearfloat"></div>' . "\n";
  405. $html .= '<div class="formelement hide">' . "\n";
  406. $html .= __('Variables');
  407. $html .= Util::showDocu('faq', 'faqbookmark');
  408. $html .= '<div id="bookmark_variables"></div>';
  409. $html .= '</div>' . "\n";
  410. $html .= '</fieldset>' . "\n";
  411. $html .= '<fieldset id="fieldsetBookmarkOptionsFooter" class="tblFooters">';
  412. $html .= '<input class="btn btn-primary" type="submit" name="SQL" id="button_submit_bookmark" value="'
  413. . __('Go') . '">';
  414. $html .= '<div class="clearfloat"></div>' . "\n";
  415. $html .= '</fieldset>' . "\n";
  416. return $html;
  417. }
  418. }