ImportShp.class.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * ESRI Shape file import plugin for phpMyAdmin
  5. *
  6. * @package PhpMyAdmin-Import
  7. * @subpackage ESRI_Shape
  8. */
  9. if (! defined('PHPMYADMIN')) {
  10. exit;
  11. }
  12. // Drizzle does not support GIS data types
  13. if (PMA_DRIZZLE) {
  14. $GLOBALS['skip_import'] = true;
  15. return;
  16. }
  17. /* Get the import interface*/
  18. require_once 'libraries/plugins/ImportPlugin.class.php';
  19. /* Get the ShapeFile class */
  20. require_once 'libraries/bfShapeFiles/ShapeFile.lib.php';
  21. require_once 'libraries/plugins/import/ShapeFile.class.php';
  22. require_once 'libraries/plugins/import/ShapeRecord.class.php';
  23. /**
  24. * Handles the import for ESRI Shape files
  25. *
  26. * @package PhpMyAdmin-Import
  27. * @subpackage ESRI_Shape
  28. */
  29. class ImportShp extends ImportPlugin
  30. {
  31. /**
  32. * Constructor
  33. */
  34. public function __construct()
  35. {
  36. $this->setProperties();
  37. }
  38. /**
  39. * Sets the import plugin properties.
  40. * Called in the constructor.
  41. *
  42. * @return void
  43. */
  44. protected function setProperties()
  45. {
  46. $props = 'libraries/properties/';
  47. include_once "$props/plugins/ImportPluginProperties.class.php";
  48. $importPluginProperties = new ImportPluginProperties();
  49. $importPluginProperties->setText(__('ESRI Shape File'));
  50. $importPluginProperties->setExtension('shp');
  51. $importPluginProperties->setOptions(array());
  52. $importPluginProperties->setOptionsText(__('Options'));
  53. $this->properties = $importPluginProperties;
  54. }
  55. /**
  56. * This method is called when any PluginManager to which the observer
  57. * is attached calls PluginManager::notify()
  58. *
  59. * @param SplSubject $subject The PluginManager notifying the observer
  60. * of an update.
  61. *
  62. * @return void
  63. */
  64. public function update (SplSubject $subject)
  65. {
  66. }
  67. /**
  68. * Handles the whole import logic
  69. *
  70. * @return void
  71. */
  72. public function doImport()
  73. {
  74. global $db, $error, $finished, $compression,
  75. $import_file, $local_import_file;
  76. if ((int) ini_get('memory_limit') < 512) {
  77. @ini_set('memory_limit', '512M');
  78. }
  79. @set_time_limit(300);
  80. $GLOBALS['finished'] = false;
  81. $buffer = '';
  82. $eof = false;
  83. $shp = new PMA_ShapeFile(1);
  84. // If the zip archive has more than one file,
  85. // get the correct content to the buffer from .shp file.
  86. if ($compression == 'application/zip'
  87. && PMA_getNoOfFilesInZip($import_file) > 1
  88. ) {
  89. $zip_content = PMA_getZipContents($import_file, '/^.*\.shp$/i');
  90. $GLOBALS['import_text'] = $zip_content['data'];
  91. }
  92. $temp_dbf_file = false;
  93. // We need dbase extension to handle .dbf file
  94. if (extension_loaded('dbase')) {
  95. // If we can extract the zip archive to 'TempDir'
  96. // and use the files in it for import
  97. if ($compression == 'application/zip'
  98. && ! empty($GLOBALS['cfg']['TempDir'])
  99. && is_writable($GLOBALS['cfg']['TempDir'])
  100. ) {
  101. $dbf_file_name = PMA_findFileFromZipArchive(
  102. '/^.*\.dbf$/i', $import_file
  103. );
  104. // If the corresponding .dbf file is in the zip archive
  105. if ($dbf_file_name) {
  106. // Extract the .dbf file and point to it.
  107. $extracted = PMA_zipExtract(
  108. $import_file,
  109. $dbf_file_name
  110. );
  111. if ($extracted !== false) {
  112. $dbf_file_path = realpath($GLOBALS['cfg']['TempDir'])
  113. . (PMA_IS_WINDOWS ? '\\' : '/') . PMA_sanitizeFilename($dbf_file_name, true);
  114. $handle = fopen($dbf_file_path, 'wb');
  115. if ($handle !== false) {
  116. fwrite($handle, $extracted);
  117. fclose($handle);
  118. $temp_dbf_file = true;
  119. // Replace the .dbf with .*, as required
  120. // by the bsShapeFiles library.
  121. $file_name = substr(
  122. $dbf_file_path, 0, strlen($dbf_file_path) - 4
  123. ) . '.*';
  124. $shp->FileName = $file_name;
  125. }
  126. }
  127. }
  128. } elseif (! empty($local_import_file)
  129. && ! empty($GLOBALS['cfg']['UploadDir'])
  130. && $compression == 'none'
  131. ) {
  132. // If file is in UploadDir, use .dbf file in the same UploadDir
  133. // to load extra data.
  134. // Replace the .shp with .*,
  135. // so the bsShapeFiles library correctly locates .dbf file.
  136. $file_name = substr($import_file, 0, strlen($import_file) - 4)
  137. . '.*';
  138. $shp->FileName = $file_name;
  139. }
  140. }
  141. // Delete the .dbf file extracted to 'TempDir'
  142. if ($temp_dbf_file
  143. && isset($dbf_file_path)
  144. && file_exists($dbf_file_path)
  145. ) {
  146. unlink($dbf_file_path);
  147. }
  148. // Load data
  149. $shp->loadFromFile('');
  150. if ($shp->lastError != "") {
  151. $error = true;
  152. $message = PMA_Message::error(
  153. __('There was an error importing the ESRI shape file: "%s".')
  154. );
  155. $message->addParam($shp->lastError);
  156. return;
  157. }
  158. $esri_types = array(
  159. 0 => 'Null Shape',
  160. 1 => 'Point',
  161. 3 => 'PolyLine',
  162. 5 => 'Polygon',
  163. 8 => 'MultiPoint',
  164. 11 => 'PointZ',
  165. 13 => 'PolyLineZ',
  166. 15 => 'PolygonZ',
  167. 18 => 'MultiPointZ',
  168. 21 => 'PointM',
  169. 23 => 'PolyLineM',
  170. 25 => 'PolygonM',
  171. 28 => 'MultiPointM',
  172. 31 => 'MultiPatch',
  173. );
  174. switch ($shp->shapeType) {
  175. // ESRI Null Shape
  176. case 0:
  177. break;
  178. // ESRI Point
  179. case 1:
  180. $gis_type = 'point';
  181. break;
  182. // ESRI PolyLine
  183. case 3:
  184. $gis_type = 'multilinestring';
  185. break;
  186. // ESRI Polygon
  187. case 5:
  188. $gis_type = 'multipolygon';
  189. break;
  190. // ESRI MultiPoint
  191. case 8:
  192. $gis_type = 'multipoint';
  193. break;
  194. default:
  195. $error = true;
  196. if (! isset($esri_types[$shp->shapeType])) {
  197. $message = PMA_Message::error(
  198. __(
  199. 'You tried to import an invalid file or the imported file'
  200. . ' contains invalid data'
  201. )
  202. );
  203. } else {
  204. $message = PMA_Message::error(
  205. __('MySQL Spatial Extension does not support ESRI type "%s".')
  206. );
  207. $message->addParam($param);
  208. }
  209. return;
  210. }
  211. if (isset($gis_type)) {
  212. include_once './libraries/gis/pma_gis_factory.php';
  213. $gis_obj = PMA_GIS_Factory::factory($gis_type);
  214. } else {
  215. $gis_obj = null;
  216. }
  217. $num_rows = count($shp->records);
  218. // If .dbf file is loaded, the number of extra data columns
  219. $num_data_cols = isset($shp->DBFHeader) ? count($shp->DBFHeader) : 0;
  220. $rows = array();
  221. $col_names = array();
  222. if ($num_rows != 0) {
  223. foreach ($shp->records as $record) {
  224. $tempRow = array();
  225. if ($gis_obj == null) {
  226. $tempRow[] = null;
  227. } else {
  228. $tempRow[] = "GeomFromText('"
  229. . $gis_obj->getShape($record->SHPData) . "')";
  230. }
  231. if (isset($shp->DBFHeader)) {
  232. foreach ($shp->DBFHeader as $c) {
  233. $cell = trim($record->DBFData[$c[0]]);
  234. if (! strcmp($cell, '')) {
  235. $cell = 'NULL';
  236. }
  237. $tempRow[] = $cell;
  238. }
  239. }
  240. $rows[] = $tempRow;
  241. }
  242. }
  243. if (count($rows) == 0) {
  244. $error = true;
  245. $message = PMA_Message::error(
  246. __('The imported file does not contain any data')
  247. );
  248. return;
  249. }
  250. // Column names for spatial column and the rest of the columns,
  251. // if they are available
  252. $col_names[] = 'SPATIAL';
  253. for ($n = 0; $n < $num_data_cols; $n++) {
  254. $col_names[] = $shp->DBFHeader[$n][0];
  255. }
  256. // Set table name based on the number of tables
  257. if (strlen($db)) {
  258. $result = PMA_DBI_fetch_result('SHOW TABLES');
  259. $table_name = 'TABLE '.(count($result) + 1);
  260. } else {
  261. $table_name = 'TBL_NAME';
  262. }
  263. $tables = array(array($table_name, $col_names, $rows));
  264. // Use data from shape file to chose best-fit MySQL types for each column
  265. $analyses = array();
  266. $analyses[] = PMA_analyzeTable($tables[0]);
  267. $table_no = 0; $spatial_col = 0;
  268. $analyses[$table_no][TYPES][$spatial_col] = GEOMETRY;
  269. $analyses[$table_no][FORMATTEDSQL][$spatial_col] = true;
  270. // Set database name to the currently selected one, if applicable
  271. if (strlen($db)) {
  272. $db_name = $db;
  273. $options = array('create_db' => false);
  274. } else {
  275. $db_name = 'SHP_DB';
  276. $options = null;
  277. }
  278. // Created and execute necessary SQL statements from data
  279. $null_param = null;
  280. PMA_buildSQL($db_name, $tables, $analyses, $null_param, $options);
  281. unset($tables);
  282. unset($analyses);
  283. $finished = true;
  284. $error = false;
  285. // Commit any possible data in buffers
  286. PMA_importRunQuery();
  287. }
  288. /**
  289. * Returns specified number of bytes from the buffer.
  290. * Buffer automatically fetches next chunk of data when the buffer
  291. * falls short.
  292. * Sets $eof when $GLOBALS['finished'] is set and the buffer falls short.
  293. *
  294. * @param int $length number of bytes
  295. *
  296. * @return string
  297. */
  298. public static function readFromBuffer($length)
  299. {
  300. global $buffer, $eof;
  301. if (strlen($buffer) < $length) {
  302. if ($GLOBALS['finished']) {
  303. $eof = true;
  304. } else {
  305. $buffer .= PMA_importGetNextChunk();
  306. }
  307. }
  308. $result = substr($buffer, 0, $length);
  309. $buffer = substr($buffer, $length);
  310. return $result;
  311. }
  312. }