ImportShp.class.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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, $message;
  76. $GLOBALS['finished'] = false;
  77. $shp = new PMA_ShapeFile(1);
  78. // If the zip archive has more than one file,
  79. // get the correct content to the buffer from .shp file.
  80. if ($compression == 'application/zip'
  81. && PMA_getNoOfFilesInZip($import_file) > 1
  82. ) {
  83. $zip_content = PMA_getZipContents($import_file, '/^.*\.shp$/i');
  84. $GLOBALS['import_text'] = $zip_content['data'];
  85. }
  86. $temp_dbf_file = false;
  87. // We need dbase extension to handle .dbf file
  88. if (extension_loaded('dbase')) {
  89. // If we can extract the zip archive to 'TempDir'
  90. // and use the files in it for import
  91. if ($compression == 'application/zip'
  92. && ! empty($GLOBALS['cfg']['TempDir'])
  93. && is_writable($GLOBALS['cfg']['TempDir'])
  94. ) {
  95. $dbf_file_name = PMA_findFileFromZipArchive(
  96. '/^.*\.dbf$/i', $import_file
  97. );
  98. // If the corresponding .dbf file is in the zip archive
  99. if ($dbf_file_name) {
  100. // Extract the .dbf file and point to it.
  101. $extracted = PMA_zipExtract(
  102. $import_file,
  103. realpath($GLOBALS['cfg']['TempDir']),
  104. array($dbf_file_name)
  105. );
  106. if ($extracted) {
  107. $dbf_file_path = realpath($GLOBALS['cfg']['TempDir'])
  108. . (PMA_IS_WINDOWS ? '\\' : '/') . $dbf_file_name;
  109. $temp_dbf_file = true;
  110. // Replace the .dbf with .*, as required
  111. // by the bsShapeFiles library.
  112. $file_name = substr(
  113. $dbf_file_path, 0, strlen($dbf_file_path) - 4
  114. ) . '.*';
  115. $shp->FileName = $file_name;
  116. }
  117. }
  118. } elseif (! empty($local_import_file)
  119. && ! empty($GLOBALS['cfg']['UploadDir'])
  120. && $compression == 'none'
  121. ) {
  122. // If file is in UploadDir, use .dbf file in the same UploadDir
  123. // to load extra data.
  124. // Replace the .shp with .*,
  125. // so the bsShapeFiles library correctly locates .dbf file.
  126. $file_name = substr($import_file, 0, strlen($import_file) - 4)
  127. . '.*';
  128. $shp->FileName = $file_name;
  129. }
  130. }
  131. // Load data
  132. $shp->loadFromFile('');
  133. if ($shp->lastError != "") {
  134. $error = true;
  135. $message = PMA_Message::error(
  136. __('There was an error importing the ESRI shape file: "%s".')
  137. );
  138. $message->addParam($shp->lastError);
  139. return;
  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. $esri_types = array(
  149. 0 => 'Null Shape',
  150. 1 => 'Point',
  151. 3 => 'PolyLine',
  152. 5 => 'Polygon',
  153. 8 => 'MultiPoint',
  154. 11 => 'PointZ',
  155. 13 => 'PolyLineZ',
  156. 15 => 'PolygonZ',
  157. 18 => 'MultiPointZ',
  158. 21 => 'PointM',
  159. 23 => 'PolyLineM',
  160. 25 => 'PolygonM',
  161. 28 => 'MultiPointM',
  162. 31 => 'MultiPatch',
  163. );
  164. switch ($shp->shapeType) {
  165. // ESRI Null Shape
  166. case 0:
  167. break;
  168. // ESRI Point
  169. case 1:
  170. $gis_type = 'point';
  171. break;
  172. // ESRI PolyLine
  173. case 3:
  174. $gis_type = 'multilinestring';
  175. break;
  176. // ESRI Polygon
  177. case 5:
  178. $gis_type = 'multipolygon';
  179. break;
  180. // ESRI MultiPoint
  181. case 8:
  182. $gis_type = 'multipoint';
  183. break;
  184. default:
  185. $error = true;
  186. if (! isset($esri_types[$shp->shapeType])) {
  187. $message = PMA_Message::error(
  188. __(
  189. 'You tried to import an invalid file or the imported file'
  190. . ' contains invalid data!'
  191. )
  192. );
  193. } else {
  194. $message = PMA_Message::error(
  195. __('MySQL Spatial Extension does not support ESRI type "%s".')
  196. );
  197. $message->addParam($esri_types[$shp->shapeType]);
  198. }
  199. return;
  200. }
  201. if (isset($gis_type)) {
  202. include_once './libraries/gis/GIS_Factory.class.php';
  203. $gis_obj = PMA_GIS_Factory::factory($gis_type);
  204. } else {
  205. $gis_obj = null;
  206. }
  207. $num_rows = count($shp->records);
  208. // If .dbf file is loaded, the number of extra data columns
  209. $num_data_cols = isset($shp->DBFHeader) ? count($shp->DBFHeader) : 0;
  210. $rows = array();
  211. $col_names = array();
  212. if ($num_rows != 0) {
  213. foreach ($shp->records as $record) {
  214. $tempRow = array();
  215. if ($gis_obj == null) {
  216. $tempRow[] = null;
  217. } else {
  218. $tempRow[] = "GeomFromText('"
  219. . $gis_obj->getShape($record->SHPData) . "')";
  220. }
  221. if (isset($shp->DBFHeader)) {
  222. foreach ($shp->DBFHeader as $c) {
  223. $cell = trim($record->DBFData[$c[0]]);
  224. if (! strcmp($cell, '')) {
  225. $cell = 'NULL';
  226. }
  227. $tempRow[] = $cell;
  228. }
  229. }
  230. $rows[] = $tempRow;
  231. }
  232. }
  233. if (count($rows) == 0) {
  234. $error = true;
  235. $message = PMA_Message::error(
  236. __('The imported file does not contain any data!')
  237. );
  238. return;
  239. }
  240. // Column names for spatial column and the rest of the columns,
  241. // if they are available
  242. $col_names[] = 'SPATIAL';
  243. for ($n = 0; $n < $num_data_cols; $n++) {
  244. $col_names[] = $shp->DBFHeader[$n][0];
  245. }
  246. // Set table name based on the number of tables
  247. if (strlen($db)) {
  248. $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES');
  249. $table_name = 'TABLE ' . (count($result) + 1);
  250. } else {
  251. $table_name = 'TBL_NAME';
  252. }
  253. $tables = array(array($table_name, $col_names, $rows));
  254. // Use data from shape file to chose best-fit MySQL types for each column
  255. $analyses = array();
  256. $analyses[] = PMA_analyzeTable($tables[0]);
  257. $table_no = 0; $spatial_col = 0;
  258. $analyses[$table_no][TYPES][$spatial_col] = GEOMETRY;
  259. $analyses[$table_no][FORMATTEDSQL][$spatial_col] = true;
  260. // Set database name to the currently selected one, if applicable
  261. if (strlen($db)) {
  262. $db_name = $db;
  263. $options = array('create_db' => false);
  264. } else {
  265. $db_name = 'SHP_DB';
  266. $options = null;
  267. }
  268. // Created and execute necessary SQL statements from data
  269. $null_param = null;
  270. PMA_buildSQL($db_name, $tables, $analyses, $null_param, $options);
  271. unset($tables);
  272. unset($analyses);
  273. $finished = true;
  274. $error = false;
  275. // Commit any possible data in buffers
  276. PMA_importRunQuery();
  277. }
  278. /**
  279. * Returns specified number of bytes from the buffer.
  280. * Buffer automatically fetches next chunk of data when the buffer
  281. * falls short.
  282. * Sets $eof when $GLOBALS['finished'] is set and the buffer falls short.
  283. *
  284. * @param int $length number of bytes
  285. *
  286. * @return string
  287. */
  288. public static function readFromBuffer($length)
  289. {
  290. global $buffer, $eof;
  291. if (strlen($buffer) < $length) {
  292. if ($GLOBALS['finished']) {
  293. $eof = true;
  294. } else {
  295. $buffer .= PMA_importGetNextChunk();
  296. }
  297. }
  298. $result = substr($buffer, 0, $length);
  299. $buffer = substr($buffer, $length);
  300. return $result;
  301. }
  302. }