GisVisualizationController.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <?php
  2. declare(strict_types=1);
  3. namespace PhpMyAdmin\Controllers\Table;
  4. use PhpMyAdmin\Core;
  5. use PhpMyAdmin\DatabaseInterface;
  6. use PhpMyAdmin\Gis\GisVisualization;
  7. use PhpMyAdmin\Message;
  8. use PhpMyAdmin\Response;
  9. use PhpMyAdmin\Template;
  10. use PhpMyAdmin\Url;
  11. use PhpMyAdmin\Util;
  12. use function array_merge;
  13. /**
  14. * Handles creation of the GIS visualizations.
  15. */
  16. final class GisVisualizationController extends AbstractController
  17. {
  18. /** @var GisVisualization */
  19. private $visualization;
  20. /** @var DatabaseInterface */
  21. private $dbi;
  22. /**
  23. * @param Response $response
  24. * @param string $db Database name.
  25. * @param string $table Table name.
  26. * @param DatabaseInterface $dbi
  27. */
  28. public function __construct($response, Template $template, $db, $table, $dbi)
  29. {
  30. parent::__construct($response, $template, $db, $table);
  31. $this->dbi = $dbi;
  32. }
  33. public function index(): void
  34. {
  35. global $cfg, $url_params, $PMA_Theme, $db, $err_url;
  36. Util::checkParameters(['db']);
  37. $err_url = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
  38. $err_url .= Url::getCommon(['db' => $db], '&');
  39. if (! $this->hasDatabase()) {
  40. return;
  41. }
  42. // SQL query for retrieving GIS data
  43. $sqlQuery = '';
  44. if (isset($_GET['sql_query'], $_GET['sql_signature'])) {
  45. if (Core::checkSqlQuerySignature($_GET['sql_query'], $_GET['sql_signature'])) {
  46. $sqlQuery = $_GET['sql_query'];
  47. }
  48. } elseif (isset($_POST['sql_query'])) {
  49. $sqlQuery = $_POST['sql_query'];
  50. }
  51. // Throw error if no sql query is set
  52. if ($sqlQuery == '') {
  53. $this->response->setRequestStatus(false);
  54. $this->response->addHTML(
  55. Message::error(__('No SQL query was set to fetch data.'))
  56. );
  57. return;
  58. }
  59. // Execute the query and return the result
  60. $result = $this->dbi->tryQuery($sqlQuery);
  61. // Get the meta data of results
  62. $meta = $this->dbi->getFieldsMeta($result);
  63. // Find the candidate fields for label column and spatial column
  64. $labelCandidates = [];
  65. $spatialCandidates = [];
  66. foreach ($meta as $column_meta) {
  67. if ($column_meta->type === 'geometry') {
  68. $spatialCandidates[] = $column_meta->name;
  69. } else {
  70. $labelCandidates[] = $column_meta->name;
  71. }
  72. }
  73. // Get settings if any posted
  74. $visualizationSettings = [];
  75. if (Core::isValid($_POST['visualizationSettings'], 'array')) {
  76. $visualizationSettings = $_POST['visualizationSettings'];
  77. }
  78. // Check mysql version
  79. $visualizationSettings['mysqlVersion'] = $this->dbi->getVersion();
  80. $visualizationSettings['isMariaDB'] = $this->dbi->isMariaDB();
  81. if (! isset($visualizationSettings['labelColumn'])
  82. && isset($labelCandidates[0])
  83. ) {
  84. $visualizationSettings['labelColumn'] = '';
  85. }
  86. // If spatial column is not set, use first geometric column as spatial column
  87. if (! isset($visualizationSettings['spatialColumn'])) {
  88. $visualizationSettings['spatialColumn'] = $spatialCandidates[0];
  89. }
  90. // Convert geometric columns from bytes to text.
  91. $pos = $_GET['pos'] ?? $_SESSION['tmpval']['pos'];
  92. if (isset($_GET['session_max_rows'])) {
  93. $rows = $_GET['session_max_rows'];
  94. } else {
  95. if ($_SESSION['tmpval']['max_rows'] !== 'all') {
  96. $rows = $_SESSION['tmpval']['max_rows'];
  97. } else {
  98. $rows = $GLOBALS['cfg']['MaxRows'];
  99. }
  100. }
  101. $this->visualization = GisVisualization::get(
  102. $sqlQuery,
  103. $visualizationSettings,
  104. $rows,
  105. $pos
  106. );
  107. if (isset($_GET['saveToFile'])) {
  108. $this->saveToFile($visualizationSettings['spatialColumn'], $_GET['fileFormat']);
  109. return;
  110. }
  111. $this->addScriptFiles([
  112. 'vendor/openlayers/OpenLayers.js',
  113. 'vendor/jquery/jquery.svg.js',
  114. 'table/gis_visualization.js',
  115. ]);
  116. // If all the rows contain SRID, use OpenStreetMaps on the initial loading.
  117. if (! isset($_POST['displayVisualization'])) {
  118. if ($this->visualization->hasSrid()) {
  119. $visualizationSettings['choice'] = 'useBaseLayer';
  120. } else {
  121. unset($visualizationSettings['choice']);
  122. }
  123. }
  124. $this->visualization->setUserSpecifiedSettings($visualizationSettings);
  125. if ($visualizationSettings != null) {
  126. foreach ($this->visualization->getSettings() as $setting => $val) {
  127. if (isset($visualizationSettings[$setting])) {
  128. continue;
  129. }
  130. $visualizationSettings[$setting] = $val;
  131. }
  132. }
  133. /**
  134. * Displays the page
  135. */
  136. $url_params['goto'] = Util::getScriptNameForOption(
  137. $cfg['DefaultTabDatabase'],
  138. 'database'
  139. );
  140. $url_params['back'] = Url::getFromRoute('/sql');
  141. $url_params['sql_query'] = $sqlQuery;
  142. $url_params['sql_signature'] = Core::signSqlQuery($sqlQuery);
  143. $downloadUrl = Url::getFromRoute('/table/gis-visualization', array_merge(
  144. $url_params,
  145. [
  146. 'saveToFile' => true,
  147. 'session_max_rows' => $rows,
  148. 'pos' => $pos,
  149. ]
  150. ));
  151. $html = $this->template->render('table/gis_visualization/gis_visualization', [
  152. 'url_params' => $url_params,
  153. 'download_url' => $downloadUrl,
  154. 'label_candidates' => $labelCandidates,
  155. 'spatial_candidates' => $spatialCandidates,
  156. 'visualization_settings' => $visualizationSettings,
  157. 'sql_query' => $sqlQuery,
  158. 'visualization' => $this->visualization->toImage('svg'),
  159. 'draw_ol' => $this->visualization->asOl(),
  160. 'theme_image_path' => $PMA_Theme->getImgPath(),
  161. ]);
  162. $this->response->addHTML($html);
  163. }
  164. /**
  165. * @param string $filename File name
  166. * @param string $format Save format
  167. */
  168. private function saveToFile(string $filename, string $format): void
  169. {
  170. $this->response->disable();
  171. $this->visualization->toFile($filename, $format);
  172. }
  173. }