public static function importCsv($filepath, $separator = ';', $enclosure = '"', $skipline = 0, $lang = 'fr', $fields = '') { self::$_lang = $lang; self::$_strings['Yes']['fr'] = 'oui'; self::$_strings['Yes']['de'] = 'ja'; self::$_strings['No']['fr'] = 'non'; self::$_strings['No']['de'] = 'nein'; $knowledge['fr'] = array('non renseigné', 'littérature, prospecté', 'littérature prospecté', 'sondé', 'fouillé'); $knowledge['en'] = array('unknown', 'literature', 'literature', 'surveyed', 'excavated'); $knowledge['de'] = array('unbestimmt', 'literatur, lesefund', 'literatur', 'sondiert', 'ausgegraben'); $occupation['fr'] = array('non renseigné', 'unique', 'continue', 'multiple'); $occupation['en'] = array('unknown', 'uniq', 'continuous', 'multiple'); $occupation['de'] = array('unbestimmt', 'einzelphase', 'durchgehend', 'mehrphasig'); $epsgCodes['wgs84'] = 4326; self::$_cache['period_start'] = array(); self::$_cache['period_end'] = array(); self::$_cache['realestate'] = array(); self::$_cache['furniture'] = array(); self::$_cache['landscape'] = array(); self::$_cache['production'] = array(); self::$_cache['siteperiod'] = array(); self::$_cache['specialperiod'] = array(); $stop = false; $uid = NULL; // Get user ID if ($_SESSION['login'] == 'admin') { $uid = 0; } else { $uid = \mod\user\Main::getUserId($_SESSION['login']); } if (!is_int($uid)) { die("User ID cannot be found"); } if (!is_file($filepath) || !is_readable($filepath)) { // Check if filename is in current directory (for tests) $moduleDir = dirname(__FILE__); if (is_file("{$moduleDir}/{$filepath}") && is_readable("{$moduleDir}/{$filepath}")) { $filepath = "{$moduleDir}/{$filepath}"; } else { throw new \Exception("File does not exist or is not readable: \"{$filepath}\""); } } if ($separator == '\\t') { $separator = "\t"; } $os = ''; if (($handle = fopen($filepath, "r")) !== FALSE) { while (($content = fgetcsv($handle, 1000, $separator, $enclosure)) !== FALSE) { $lines[] = $content; $os .= implode($content, ''); } } //\core\Core::$db->exec('BEGIN'); // Retrieve special periods foreach (\core\Core::$db->fetchAll('SELECT "node_path", "pe_name_' . $lang . '" FROM "ark_period" WHERE "pe_name_' . $lang . '" IN (?, ?, ?, ?, ?, ?, ?)', array('BRF3/HAC1', 'HAC2/HAD1', 'HAD3/LTA1', 'LTC2/LTD1', 'Grandes invasions', 'Grandes invasions', 'Völkerwanderungszeit')) as $row) { self::$_cache['specialperiod'][$lang][$row['pe_name_' . $lang]][] = $row['node_path']; } foreach ($lines as $datas) { self::$_lineNumber++; self::$_current = array(); self::$_csvDatas = implode(';', $datas); if (self::$_lineNumber != 0 && self::$_lineNumber <= $skipline) { continue; } $datas = array_map(array('self', '_cleanString'), $datas); // Skip blank lines if (!isset($datas[1])) { continue; } # 1 : Database self::_processDatabaseName($datas[1], $fields, $uid); # 0 : Site ID if (!self::_processSiteId($datas[0])) { self::_addError('No site unique ID provided'); continue; } # 10 z $datas[10] = trim($datas[10]); if (!empty($datas[10]) && !preg_match('/^[0-9]+$/', $datas[10])) { self::_addError('Altitude invalid: String provided, Int expected: ' . $datas[10]); continue; } // Site not already processed if (!isset(self::$_stored[self::$_current['code']])) { // If this site code already registered as error we do not process it if (isset(self::$_siteErrors[self::$_current['code']])) { self::_addError("Site with same id already registered as error, skipping."); continue; } # 2 : Site name # 3 : City name # 4 : City code foreach (array(2, 3, 4, 5) as $k) { if (!self::_checkDifference($k, $datas[$k])) { switch ($k) { case 2: $dataType = "Site name"; break; case 3: $dataType = "City name"; break; case 4: $dataType = "City code"; break; } self::_addError("{$dataType} ({$datas[$k]}) is different from the one previously defined with same site id. ({$dataType})"); } } # 5 : Projection SRID # 6 : x0 # 7 : y0 # 8 : x1 # 9 : y1 # 10 : z # 11 : centroid $stop = false; $datas[6] = str_replace(',', '.', $datas[6]); $datas[7] = str_replace(',', '.', $datas[7]); $datas[8] = str_replace(',', '.', $datas[8]); $datas[9] = str_replace(',', '.', $datas[9]); $coords = array(); self::$_current['centroid'] = false; // Site defined as centroid if (strtolower($datas[11]) == self::$_strings['Yes'][self::$_lang]) { self::$_current['centroid'] = true; } if (empty($datas[6]) || empty($datas[7])) { // City info not set: error if (empty($datas[3])) { self::_addError("Site has no coordinates and no city name provided."); } else { if (empty($datas[4])) { self::_addError("Site has no coordinates and no city code provided."); } else { // Get city coords try { $cityInfos = \mod\arkeogis\Tools::getCityInfos($datas[3], $datas[4]); $coords = array('x' => $cityInfos['x'], 'y' => $cityInfos['y'], 0); self::$_current['city_id'] = $cityInfos['id']; } catch (\Exception $e) { self::_addError("Unable to find coordinates from city."); } } } } else { if (empty($datas[8]) && empty($datas[9])) { $coords = array('x' => $datas[6], 'y' => $datas[7]); } else { // Get centroid coords try { $coords = \mod\arkeogis\Tools::getSquareCentroid($datas[6], $datas[7], $datas[8], $datas[9]); } catch (\Exception $e) { self::_addError("Unable to find centroid coordinates."); } } } // Compute coords if (isset($coords['x']) && isset($coords['y'])) { if (empty($datas[5])) { self::_addError("EPSG not provided"); } $epsg = (int) $datas[5]; if ($epsg < 2) { $os = strtolower($datas[5]); if (!isset($epsgCodes[$os])) { self::_addError("Unable to get EPSG from code {$datas['5']}"); } else { $epsg = $epsgCodes[$os]; } } if (!empty($epsg) && $epsg != 4326) { // Check if geom exists if (!\core\Core::$db->fetchOne('SELECT count(srtext) FROM "spatial_ref_sys" WHERE "srid" = ?', array($epsg))) { self::_addError("EPSG code provided not found ({$datas['5']}) it must be numeric, see http://www.epsg-registry.org/"); } else { try { $coords = \mod\arkeogis\Tools::transformPoint($coords, $epsg, 4326); if (empty($coords)) { self::_addError("Unable to transform coordinates in WGS84."); } } catch (\Exception $e) { self::_addError("Unable to transform coordinates in WGS84. Error: " . $e->getMessage()); $coords = null; } } } // Geom # 5 EPSG self::$_current['geom'] = is_array($coords) && !empty($coords['x']) && !empty($coords['y']) ? "ST_GeomFromText('POINT({$coords['x']} {$coords['y']} " . (!is_null($datas[10]) && $datas[10] != '' ? $datas[10] : -999) . ")', 4326)" : NULL; } else { self::$_current['geom'] = 'NULL'; } } // End of first time site processing # 12 : Knowledge if (in_array(strtolower($datas[12]), $knowledge[self::$_lang])) { $os = array_keys($knowledge[self::$_lang], strtolower($datas[12])); self::$_current['knowledge'] = $knowledge['en'][$os[0]]; } else { if (!empty($datas[12])) { self::_addError("Knowledge type ({$datas['12']}) is not referenced."); } else { self::$_current['knowledge'] = NULL; } } # 13 : Occupation if (in_array(strtolower($datas[13]), $occupation[self::$_lang])) { $os = array_keys($occupation[self::$_lang], strtolower($datas[13])); self::$_current['occupation'] = $occupation['en'][$os[0]]; self::$_current['period_isrange'] = 1; } else { if (!empty($datas[13])) { self::_addError("Occupation type ({$datas['13']}) is not referenced."); } else { if (!isset(self::$_stored[self::$_current['code']])) { self::_addError("Occupation type not defined"); } } } # 14 : Period start # 15 : Period end // We have starting and ending period if (!empty($datas[14]) && !empty($datas[15])) { self::$_current['period'] = self::_processPeriod($datas[14], $datas[15]); // We do not have starting and ending period } else { // It's the first time we process this site: error if (!isset(self::$_stored[self::$_current['code']])) { // No starting period if (empty($datas[14])) { self::_addError("Starting period not defined"); } // No ending period if (empty($datas[15])) { self::_addError("Ending period not defined"); } // We have already processed this site } else { self::$_current['period'] = self::$_stored[self::$_current['code']]['period']; self::$_current['period_isrange'] = 0; } // Done with new site, next it's common to new/already processed site } # 16 : Realestate level 1 # 17 : Realestate level 2 # 18 : Realestate level 3 # 19 : Realestate level 4 # if (empty($datas[16]) && (!empty($datas[17]) || !empty($datas[18]) || !empty($datas[19]))) { self::_addError("Realestate level 1 not set but some other realestate fields are defined"); } else { if (!empty($datas[16])) { self::_processLtree($datas[16], $datas[17], $datas[18], $datas[19], 'realestate'); } } /* # 20 : Depth if (!empty($datas[20])) { if (!preg_match("/^[0-9]*\.?[0-9]+$/", $datas[20]) || $datas[20] < 10) { self::_addError("Depth invalid ($datas[20])"); } else { self::$_current['depth'] = $datas[20]; } } */ # 20 : Realestate exceptional self::_processExceptional('realestate', $datas[20]); # 21 : Furniture level 1 # 22 : Furniture level 2 # 23 : Furniture level 3 # 24 : Furniture level 4 if (empty($datas[21]) && (!empty($datas[22]) || !empty($datas[23]) || !empty($datas[24]))) { self::_addError("Furniture level 1 not set but some other furniture fields are defined"); } else { if (!empty($datas[21])) { self::_processLtree($datas[21], $datas[22], $datas[23], $datas[24], 'furniture'); } } # 25 : Furniture exceptional self::_processExceptional('furniture', $datas[25]); # 26 : Production level 1 # 27 : Production level 2 # 28 : Production level 3 # 29 : Production level 4 if (empty($datas[26]) && (!empty($datas[27]) || !empty($datas[28]) || !empty($datas[29]))) { self::_addError("Production level 1 not set but some other production fields are defined"); } else { if (!empty($datas[26])) { self::_processLtree($datas[26], $datas[27], $datas[28], $datas[29], 'production'); } } # 30 : Production exceptional self::_processExceptional('production', $datas[30]); # 31 : Landscape 1 # 32 : Landscape 2 # 33 : Landscape 3 # 34 : Landscape 4 if (empty($datas[31]) && (!empty($datas[32]) || !empty($datas[33]) || !empty($datas[34]))) { self::_addError("Landscape level 1 not set but some other landscape fields are defined"); } else { if (!empty($datas[31])) { self::_processLtree($datas[31], $datas[32], $datas[33], $datas[34], 'landscape'); } } # 35 : Landcape exceptional self::_processExceptional('landscape', $datas[35]); # 36 : Biblio self::$_current['biblio'] = !empty($datas[36]) ? $datas[36] : NULL; # 37 : Comments self::$_current['comments'] = !empty($datas[37]) ? $datas[37] : NULL; // OK we check if we have at leat one carac if (!isset(self::$_current['realestate']) && !isset(self::$_current['furniture']) && !isset(self::$_current['production']) && !isset(self::$_current['landscape'])) { self::_addError('No characteristic defined for this site'); } // If no error if (!isset(self::$_siteErrors[self::$_current['code']])) { // If it's first time we process this site if (!isset(self::$_stored[self::$_current['code']]) || empty(self::$_stored[self::$_current['code']])) { // Store site informations try { self::$_current['siteId'] = \mod\arkeogis\ArkeoGIS::addSite(self::$_current['code'], self::$_current['name'], self::$_database['id'], isset(self::$_current['city_id']) ? self::$_current['city_id'] : NULL, self::$_current['geom'], self::$_current['centroid'], self::$_current['occupation'], trim($datas[3], '" '), trim($datas[4], '" '), $uid); self::$_nbSites += 1; self::$_stored[self::$_current['code']] = self::$_current; } catch (\Exception $e) { self::_addProcessingError($e->getMessage()); continue; } } // Store site period informations $md5Period = self::$_current['code'] . self::$_current['period']['start'] . '-' . self::$_current['period']['end']; if (!isset(self::$_current['siteId'])) { if (isset(self::$_stored[self::$_current['code']])) { $siteId = self::$_stored[self::$_current['code']]['siteId']; } else { throw new \Exception('Unable to get site id for this period'); } } else { $siteId = self::$_current['siteId']; } if (!empty($siteId)) { $existing = \mod\arkeogis\ArkeoGIS::getSitePeriod($siteId, self::$_current['period']['start'], self::$_current['period']['end']); } if (!empty($existing)) { self::$_cache['siteperiod'][$md5Period] = $existing; } else { try { self::$_cache['siteperiod'][$md5Period] = \mod\arkeogis\ArkeoGIS::addSitePeriod($siteId, self::$_current['period']['start'], self::$_current['period']['end'], isset(self::$_current['period_isrange']) ? self::$_current['period_isrange'] : NULL, NULL, self::$_current['knowledge'], self::$_current['comments'], self::$_current['biblio']); } catch (\Exception $e) { self::_addProcessingError($e->getMessage()); continue; } } foreach (array('realestate', 'furniture', 'production', 'landscape') as $carac) { if (isset(self::$_current[$carac]) && !is_null(self::$_current[$carac])) { try { \mod\arkeogis\ArkeoGIS::addSitePeriodCharacteristic(self::$_cache['siteperiod'][$md5Period], $carac, self::$_current[$carac], isset(self::$_current[$carac . '_ex']) && self::$_current[$carac . '_ex'] ? 1 : 0); } catch (\Exception $e) { self::_addProcessingError($e->getMessage()); } } } $existing = null; $siteId = null; self::$_linesDone += 1; } // End of site treatment, next one. } //\core\Core::$db->exec('COMMIT'); $nbLines = self::$_lineNumber - $skipline; $numErrors = self::countErrors(); self::_postProcess($filepath, self::$_linesDone, $uid); return array("total" => $nbLines, "processed" => self::$_nbSites, "numErrors" => $numErrors, "errors" => self::$_siteErrors, "processingErrors" => self::$_processingErrors); }