PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/phpmyadmin/libraries/import/shp.php

https://bitbucket.org/graaaf/garant
PHP | 426 lines | 360 code | 31 blank | 35 comment | 35 complexity | d4758b746773d12b24f5cf54c687636e MD5 | raw file
Possible License(s): GPL-2.0, Apache-2.0
  1. <?php
  2. /**
  3. * ESRI Shape file import plugin for phpMyAdmin
  4. *
  5. * @package PhpMyAdmin-Import
  6. * @subpackage ESRI_Shape
  7. */
  8. if (! defined('PHPMYADMIN')) {
  9. exit;
  10. }
  11. // Drizzle does not suppost GIS data types
  12. if (PMA_DRIZZLE) {
  13. return;
  14. }
  15. if (isset($plugin_list)) {
  16. $plugin_list['shp'] = array(
  17. 'text' => __('ESRI Shape File'),
  18. 'extension' => 'shp',
  19. 'options' => array(),
  20. 'options_text' => __('Options'),
  21. );
  22. } else {
  23. if ((int) ini_get('memory_limit') < 512) {
  24. @ini_set('memory_limit', '512M');
  25. }
  26. @set_time_limit(300);
  27. // Append the bfShapeFiles directory to the include path variable
  28. set_include_path(get_include_path() . PATH_SEPARATOR . getcwd() . '/libraries/bfShapeFiles/');
  29. include_once './libraries/bfShapeFiles/ShapeFile.lib.php';
  30. $GLOBALS['finished'] = false;
  31. $buffer = '';
  32. $eof = false;
  33. // Returns specified number of bytes from the buffer.
  34. // Buffer automatically fetches next chunk of data when the buffer falls short.
  35. // Sets $eof when $GLOBALS['finished'] is set and the buffer falls short.
  36. function readFromBuffer($length){
  37. global $buffer, $eof;
  38. if (strlen($buffer) < $length) {
  39. if ($GLOBALS['finished']) {
  40. $eof = true;
  41. } else {
  42. $buffer .= PMA_importGetNextChunk();
  43. }
  44. }
  45. $result = substr($buffer, 0, $length);
  46. $buffer = substr($buffer, $length);
  47. return $result;
  48. }
  49. /**
  50. * This class extends ShapeFile class to cater the following phpMyAdmin
  51. * specific requirements.
  52. * 1) To load data from .dbf file only when the dBase extension is available.
  53. * 2) To use PMA_importGetNextChunk() functionality to read data, rather than
  54. * reading directly from a file. Using readFromBuffer() in place of fread().
  55. * This makes it possible to use compressions.
  56. */
  57. class PMA_ShapeFile extends ShapeFile
  58. {
  59. function _isDbaseLoaded()
  60. {
  61. return extension_loaded('dbase');
  62. }
  63. function loadFromFile($FileName)
  64. {
  65. $this->_loadHeaders();
  66. $this->_loadRecords();
  67. if ($this->_isDbaseLoaded()) {
  68. $this->_closeDBFFile();
  69. }
  70. }
  71. function _loadHeaders()
  72. {
  73. readFromBuffer(24);
  74. $this->fileLength = loadData("N", readFromBuffer(4));
  75. readFromBuffer(4);
  76. $this->shapeType = loadData("V", readFromBuffer(4));
  77. $this->boundingBox = array();
  78. $this->boundingBox["xmin"] = loadData("d", readFromBuffer(8));
  79. $this->boundingBox["ymin"] = loadData("d", readFromBuffer(8));
  80. $this->boundingBox["xmax"] = loadData("d", readFromBuffer(8));
  81. $this->boundingBox["ymax"] = loadData("d", readFromBuffer(8));
  82. if ($this->_isDbaseLoaded() && $this->_openDBFFile()) {
  83. $this->DBFHeader = $this->_loadDBFHeader();
  84. }
  85. }
  86. function _loadRecords()
  87. {
  88. global $eof;
  89. readFromBuffer(32);
  90. while (true) {
  91. $record = new PMA_ShapeRecord(-1);
  92. $record->loadFromFile($this->SHPFile, $this->DBFFile);
  93. if ($record->lastError != "") {
  94. return false;
  95. }
  96. if ($eof) {
  97. break;
  98. }
  99. $this->records[] = $record;
  100. }
  101. }
  102. }
  103. /**
  104. * This class extends ShapeRecord class to cater the following phpMyAdmin
  105. * specific requirements.
  106. * 1) To load data from .dbf file only when the dBase extension is available.
  107. * 2) To use PMA_importGetNextChunk() functionality to read data, rather than
  108. * reading directly from a file. Using readFromBuffer() in place of fread().
  109. * This makes it possible to use compressions.
  110. */
  111. class PMA_ShapeRecord extends ShapeRecord
  112. {
  113. function loadFromFile(&$SHPFile, &$DBFFile)
  114. {
  115. $this->DBFFile = $DBFFile;
  116. $this->_loadHeaders();
  117. switch ($this->shapeType) {
  118. case 0:
  119. $this->_loadNullRecord();
  120. break;
  121. case 1:
  122. $this->_loadPointRecord();
  123. break;
  124. case 3:
  125. $this->_loadPolyLineRecord();
  126. break;
  127. case 5:
  128. $this->_loadPolygonRecord();
  129. break;
  130. case 8:
  131. $this->_loadMultiPointRecord();
  132. break;
  133. default:
  134. $this->setError(sprintf("The Shape Type '%s' is not supported.", $this->shapeType));
  135. break;
  136. }
  137. if (extension_loaded('dbase') && isset($this->DBFFile)) {
  138. $this->_loadDBFData();
  139. }
  140. }
  141. function _loadHeaders()
  142. {
  143. $this->recordNumber = loadData("N", readFromBuffer(4));
  144. //We read the length of the record
  145. $tmp = loadData("N", readFromBuffer(4));
  146. $this->shapeType = loadData("V", readFromBuffer(4));
  147. }
  148. function _loadPoint()
  149. {
  150. $data = array();
  151. $data["x"] = loadData("d", readFromBuffer(8));
  152. $data["y"] = loadData("d", readFromBuffer(8));
  153. return $data;
  154. }
  155. function _loadMultiPointRecord()
  156. {
  157. $this->SHPData = array();
  158. $this->SHPData["xmin"] = loadData("d", readFromBuffer(8));
  159. $this->SHPData["ymin"] = loadData("d", readFromBuffer(8));
  160. $this->SHPData["xmax"] = loadData("d", readFromBuffer(8));
  161. $this->SHPData["ymax"] = loadData("d", readFromBuffer(8));
  162. $this->SHPData["numpoints"] = loadData("V", readFromBuffer(4));
  163. for ($i = 0; $i <= $this->SHPData["numpoints"]; $i++) {
  164. $this->SHPData["points"][] = $this->_loadPoint();
  165. }
  166. }
  167. function _loadPolyLineRecord()
  168. {
  169. $this->SHPData = array();
  170. $this->SHPData["xmin"] = loadData("d", readFromBuffer(8));
  171. $this->SHPData["ymin"] = loadData("d", readFromBuffer(8));
  172. $this->SHPData["xmax"] = loadData("d", readFromBuffer(8));
  173. $this->SHPData["ymax"] = loadData("d", readFromBuffer(8));
  174. $this->SHPData["numparts"] = loadData("V", readFromBuffer(4));
  175. $this->SHPData["numpoints"] = loadData("V", readFromBuffer(4));
  176. for ($i = 0; $i < $this->SHPData["numparts"]; $i++) {
  177. $this->SHPData["parts"][$i] = loadData("V", readFromBuffer(4));
  178. }
  179. $readPoints = 0;
  180. reset($this->SHPData["parts"]);
  181. while (list($partIndex, $partData) = each($this->SHPData["parts"])) {
  182. if (! isset($this->SHPData["parts"][$partIndex]["points"])
  183. || !is_array($this->SHPData["parts"][$partIndex]["points"])
  184. ) {
  185. $this->SHPData["parts"][$partIndex] = array();
  186. $this->SHPData["parts"][$partIndex]["points"] = array();
  187. }
  188. while (! in_array($readPoints, $this->SHPData["parts"])
  189. && ($readPoints < ($this->SHPData["numpoints"]))
  190. ) {
  191. $this->SHPData["parts"][$partIndex]["points"][] = $this->_loadPoint();
  192. $readPoints++;
  193. }
  194. }
  195. }
  196. }
  197. $shp = new PMA_ShapeFile(1);
  198. // If the zip archive has more than one file,
  199. // get the correct content to the buffer from .shp file.
  200. if ($compression == 'application/zip' && PMA_getNoOfFilesInZip($import_file) > 1) {
  201. $zip_content = PMA_getZipContents($import_file, '/^.*\.shp$/i');
  202. $GLOBALS['import_text'] = $zip_content['data'];
  203. }
  204. $temp_dbf_file = false;
  205. // We need dbase extension to handle .dbf file
  206. if (extension_loaded('dbase')) {
  207. // If we can extract the zip archive to 'TempDir'
  208. // and use the files in it for import
  209. if ($compression == 'application/zip'
  210. && ! empty($cfg['TempDir'])
  211. && is_writable($cfg['TempDir'])
  212. ) {
  213. $dbf_file_name = PMA_findFileFromZipArchive('/^.*\.dbf$/i', $import_file);
  214. // If the corresponding .dbf file is in the zip archive
  215. if ($dbf_file_name) {
  216. // Extract the .dbf file and point to it.
  217. $extracted = PMA_zipExtract(
  218. $import_file,
  219. realpath($cfg['TempDir']),
  220. array($dbf_file_name)
  221. );
  222. if ($extracted) {
  223. $dbf_file_path = realpath($cfg['TempDir'])
  224. . (PMA_IS_WINDOWS ? '\\' : '/') . $dbf_file_name;
  225. $temp_dbf_file = true;
  226. // Replace the .dbf with .*, as required by the bsShapeFiles library.
  227. $file_name = substr($dbf_file_path, 0, strlen($dbf_file_path) - 4) . '.*';
  228. $shp->FileName = $file_name;
  229. }
  230. }
  231. }
  232. // If file is in UploadDir, use .dbf file in the same UploadDir
  233. // to load extra data.
  234. elseif (! empty($local_import_file)
  235. && ! empty($cfg['UploadDir'])
  236. && $compression == 'none'
  237. ) {
  238. // Replace the .shp with .*,
  239. // so the bsShapeFiles library correctly locates .dbf file.
  240. $file_name = substr($import_file, 0, strlen($import_file) - 4) . '.*';
  241. $shp->FileName = $file_name;
  242. }
  243. }
  244. // Load data
  245. $shp->loadFromFile('');
  246. if ($shp->lastError != "") {
  247. $error = true;
  248. $message = PMA_Message::error(__('There was an error importing the ESRI shape file: "%s".'));
  249. $message->addParam($shp->lastError);
  250. return;
  251. }
  252. // Delete the .dbf file extracted to 'TempDir'
  253. if ($temp_dbf_file) {
  254. unlink($dbf_file_path);
  255. }
  256. $esri_types = array(
  257. 0 => 'Null Shape',
  258. 1 => 'Point',
  259. 3 => 'PolyLine',
  260. 5 => 'Polygon',
  261. 8 => 'MultiPoint',
  262. 11 => 'PointZ',
  263. 13 => 'PolyLineZ',
  264. 15 => 'PolygonZ',
  265. 18 => 'MultiPointZ',
  266. 21 => 'PointM',
  267. 23 => 'PolyLineM',
  268. 25 => 'PolygonM',
  269. 28 => 'MultiPointM',
  270. 31 => 'MultiPatch',
  271. );
  272. include_once './libraries/gis/pma_gis_geometry.php';
  273. switch ($shp->shapeType) {
  274. // ESRI Null Shape
  275. case 0:
  276. $gis_obj = null;
  277. break;
  278. // ESRI Point
  279. case 1:
  280. include_once './libraries/gis/pma_gis_point.php';
  281. $gis_obj = PMA_GIS_Point::singleton();
  282. break;
  283. // ESRI PolyLine
  284. case 3:
  285. include_once './libraries/gis/pma_gis_multilinestring.php';
  286. $gis_obj = PMA_GIS_Multilinestring::singleton();
  287. break;
  288. // ESRI Polygon
  289. case 5:
  290. include_once './libraries/gis/pma_gis_multipolygon.php';
  291. $gis_obj = PMA_GIS_Multipolygon::singleton();
  292. break;
  293. // ESRI MultiPoint
  294. case 8:
  295. include_once './libraries/gis/pma_gis_multipoint.php';
  296. $gis_obj = PMA_GIS_Multipoint::singleton();
  297. break;
  298. default:
  299. $error = true;
  300. if (! isset($esri_types[$shp->shapeType])) {
  301. $message = PMA_Message::error(__('You tried to import an invalid file or the imported file contains invalid data'));
  302. } else {
  303. $message = PMA_Message::error(__('MySQL Spatial Extension does not support ESRI type "%s".'));
  304. $message->addParam($param);
  305. }
  306. return;
  307. }
  308. $num_rows = count($shp->records);
  309. // If .dbf file is loaded, the number of extra data columns
  310. $num_data_cols = isset($shp->DBFHeader) ? count($shp->DBFHeader) : 0;
  311. $rows = array();
  312. $col_names = array();
  313. if ($num_rows != 0) {
  314. foreach ($shp->records as $record) {
  315. $tempRow = array();
  316. if ($gis_obj == null) {
  317. $tempRow[] = null;
  318. } else {
  319. $tempRow[] = "GeomFromText('" . $gis_obj->getShape($record->SHPData) . "')";
  320. }
  321. if (isset($shp->DBFHeader)) {
  322. foreach ($shp->DBFHeader as $c) {
  323. $cell = trim($record->DBFData[$c[0]]);
  324. if (! strcmp($cell, '')) {
  325. $cell = 'NULL';
  326. }
  327. $tempRow[] = $cell;
  328. }
  329. }
  330. $rows[] = $tempRow;
  331. }
  332. }
  333. if (count($rows) == 0) {
  334. $error = true;
  335. $message = PMA_Message::error(__('The imported file does not contain any data'));
  336. return;
  337. }
  338. // Column names for spatial column and the rest of the columns,
  339. // if they are available
  340. $col_names[] = 'SPATIAL';
  341. for ($n = 0; $n < $num_data_cols; $n++) {
  342. $col_names[] = $shp->DBFHeader[$n][0];
  343. }
  344. // Set table name based on the number of tables
  345. if (strlen($db)) {
  346. $result = PMA_DBI_fetch_result('SHOW TABLES');
  347. $table_name = 'TABLE '.(count($result) + 1);
  348. } else {
  349. $table_name = 'TBL_NAME';
  350. }
  351. $tables = array(array($table_name, $col_names, $rows));
  352. // Use data from shape file to chose best-fit MySQL types for each column
  353. $analyses = array();
  354. $analyses[] = PMA_analyzeTable($tables[0]);
  355. $table_no = 0; $spatial_col = 0;
  356. $analyses[$table_no][TYPES][$spatial_col] = GEOMETRY;
  357. $analyses[$table_no][FORMATTEDSQL][$spatial_col] = true;
  358. // Set database name to the currently selected one, if applicable
  359. if (strlen($db)) {
  360. $db_name = $db;
  361. $options = array('create_db' => false);
  362. } else {
  363. $db_name = 'SHP_DB';
  364. $options = null;
  365. }
  366. // Created and execute necessary SQL statements from data
  367. $null_param = null;
  368. PMA_buildSQL($db_name, $tables, $analyses, $null_param, $options);
  369. unset($tables);
  370. unset($analyses);
  371. $finished = true;
  372. $error = false;
  373. // Commit any possible data in buffers
  374. PMA_importRunQuery();
  375. }
  376. ?>