public function load_addresses($sidos) { // DB를 준비한다. $db = Postcodify_Utility::get_db(); $db->beginTransaction(); $ps_addr_insert = $db->prepare('INSERT INTO postcodify_addresses (postcode5, postcode6, ' . 'road_id, num_major, num_minor, is_basement, dongri_ko, dongri_en, jibeon_major, jibeon_minor, is_mountain, ' . 'building_id, building_name, building_nums, other_addresses) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'); $ps_kwd_insert = $db->prepare('INSERT INTO postcodify_keywords (address_id, keyword_crc32) VALUES (?, ?)'); $ps_num_insert = $db->prepare('INSERT INTO postcodify_numbers (address_id, num_major, num_minor) VALUES (?, ?, ?)'); $ps_building_insert = $db->prepare('INSERT INTO postcodify_buildings (address_id, keyword) VALUES (?, ?)'); // 이 쓰레드에서 처리할 시·도 목록을 구한다. $sidos = explode('|', $sidos); // Zip 파일을 연다. $zip = new Postcodify_Parser_NewAddress(); $zip->open_archive($this->_data_dir . '/' . substr($this->_data_date, 0, 6) . 'RDNMADR.zip'); // Update 클래스의 인스턴스를 생성한다. (누락된 우편번호 입력에 사용된다.) $update_class = new Postcodify_Indexer_Update(); // 카운터를 초기화한다. $count = 0; // 시·도를 하나씩 처리한다. foreach ($sidos as $sido) { // 시·도 데이터 파일을 연다. $open_status = $zip->open_named_file('건물정보_' . $sido); if (!$open_status) { throw new Exception('Failed to open 건물정보_' . $sido); } // 이전 주소를 초기화한다. $last_entry = null; $last_nums = array(); // 데이터를 한 줄씩 읽어 처리한다. while (true) { // 읽어온 줄을 분석한다. $entry = $zip->read_line(); // 이전 주소가 없다면 방금 읽어온 줄을 이전 주소로 설정한다. if ($last_entry === null) { $last_entry = $entry; if (($entry->has_detail || $entry->is_common_residence) && preg_match('/.+동$/u', $entry->building_detail)) { $last_nums = array(preg_replace('/동$/u', '', $entry->building_detail)); } elseif ($entry->building_detail) { $last_entry->building_names[] = $last_entry->building_detail; $last_nums = array(); } else { $last_nums = array(); } } elseif ($entry === false || $last_entry->road_id !== $entry->road_id || $last_entry->road_section !== $entry->road_section || $last_entry->num_major !== $entry->num_major || $last_entry->num_minor !== $entry->num_minor || $last_entry->is_basement !== $entry->is_basement) { // 상세건물명과 기타 주소를 정리한다. $building_nums = Postcodify_Utility::consolidate_building_nums($last_nums); if ($building_nums === '') { $building_nums = null; } $other_addresses = array(); if ($last_entry->admin_dongri && $last_entry->admin_dongri !== $last_entry->dongri) { $other_addresses[] = $last_entry->admin_dongri; } $last_entry->building_names = array_unique($last_entry->building_names); $last_entry->building_names = Postcodify_Utility::consolidate_building_names($last_entry->building_names, $last_entry->common_residence_name); natcasesort($last_entry->building_names); foreach ($last_entry->building_names as $building_name) { $other_addresses[] = str_replace(';', ':', $building_name); } $other_addresses = implode('; ', $other_addresses); if ($other_addresses === '') { $other_addresses = null; } // 공동주택인데 공동주택명이 없는 경우 다른 건물명을 이용한다. if ($last_entry->is_common_residence && $last_entry->common_residence_name === null) { if (strpos($other_addresses, '; ') === false) { $last_entry->common_residence_name = $other_addresses; $other_addresses = null; } } // 도로 정보를 구한다. if (isset(Postcodify_Utility::$road_cache[$last_entry->road_id . $last_entry->road_section])) { $road_info = explode('|', Postcodify_Utility::$road_cache[$last_entry->road_id . $last_entry->road_section]); $road_info = (object) array('road_name_ko' => $road_info[0], 'sido_ko' => $road_info[1], 'sigungu_ko' => $road_info[2], 'ilbangu_ko' => $road_info[3], 'eupmyeon_ko' => $road_info[4]); } else { $road_info = null; } // 우편번호가 누락된 경우, 범위 데이터를 사용하여 찾는다. if (!$this->_no_old_postcodes && ($last_entry->postcode6 === null || $last_entry->postcode6 === '000000')) { $last_entry->postcode6 = $update_class->find_postcode6($db, $road_info, $last_entry->dongri, $last_entry->admin_dongri, $last_entry->jibeon_major, $last_entry->jibeon_minor); } if ($last_entry->postcode5 === null || $last_entry->postcode5 === '00000') { $last_entry->postcode5 = $update_class->find_postcode5($db, $road_info, $last_entry->num_major, $last_entry->num_minor, $last_entry->dongri, $last_entry->admin_dongri, $last_entry->jibeon_major, $last_entry->jibeon_minor, $last_entry->postcode6); } // 주소 테이블에 입력한다. $ps_addr_insert->execute(array($last_entry->postcode5, $last_entry->postcode6, $last_entry->road_id . $last_entry->road_section, $last_entry->num_major, $last_entry->num_minor, $last_entry->is_basement, $last_entry->dongri, Postcodify_Utility::$english_cache[$last_entry->dongri], $last_entry->jibeon_major, $last_entry->jibeon_minor, $last_entry->is_mountain, $last_entry->building_id, $last_entry->common_residence_name, $building_nums, $other_addresses)); $proxy_id = $db->lastInsertId(); // 도로명 키워드를 입력한다. $road_name_array = Postcodify_Utility::get_variations_of_road_name($road_info->road_name_ko); foreach ($road_name_array as $keyword) { if (!$keyword) { continue; } $ps_kwd_insert->execute(array($proxy_id, Postcodify_Utility::crc32_x64($keyword))); } // 동·리 키워드를 입력한다. $dongri_array1 = Postcodify_Utility::get_variations_of_dongri($last_entry->dongri); $dongri_array2 = Postcodify_Utility::get_variations_of_dongri($last_entry->admin_dongri); $dongri_array = array_unique(array_merge($dongri_array1, $dongri_array2)); foreach ($dongri_array as $keyword) { if (!$keyword) { continue; } $ps_kwd_insert->execute(array($proxy_id, Postcodify_Utility::crc32_x64($keyword))); } // 건물번호 및 지번 키워드를 입력한다. $ps_num_insert->execute(array($proxy_id, $last_entry->num_major, $last_entry->num_minor)); $ps_num_insert->execute(array($proxy_id, $last_entry->jibeon_major, $last_entry->jibeon_minor)); // 건물명 키워드를 입력한다. if ($last_entry->common_residence_name || count($last_entry->building_names)) { if ($last_entry->common_residence_name !== null) { $last_entry->building_names[] = $last_entry->common_residence_name; } $building_names_str = Postcodify_Utility::compress_building_names($last_entry->building_names); if ($building_names_str !== '') { $ps_building_insert->execute(array($proxy_id, $building_names_str)); } } // 불필요한 변수들을 unset한다. unset($road_info, $road_name_array, $dongri_array1, $dongri_array2, $dongri_array); unset($keyword, $building_names, $building_names_str, $proxy_id); unset($last_entry, $last_nums); // 방금 읽어온 줄을 새로운 이전 주소로 설정한다. if ($entry !== false) { $last_entry = $entry; if (($entry->has_detail || $entry->is_common_residence) && preg_match('/.+동$/u', $entry->building_detail)) { $last_nums = array(preg_replace('/동$/u', '', $entry->building_detail)); } elseif ($entry->building_detail) { $last_entry->building_names[] = $last_entry->building_detail; $last_nums = array(); } else { $last_nums = array(); } } } else { if (count($entry->building_names)) { $last_entry->building_names = array_merge($last_entry->building_names, $entry->building_names); } if (($entry->has_detail || $entry->is_common_residence) && preg_match('/.+동$/u', $entry->building_detail)) { $last_nums[] = preg_replace('/동$/u', '', $entry->building_detail); } elseif ($entry->building_detail) { $last_entry->building_names[] = $entry->building_detail; } } // 카운터를 표시한다. if (++$count % 512 === 0) { $shmop = shmop_open($this->_shmop_key, 'w', 0, 0); $prev = current(unpack('L', shmop_read($shmop, 0, 4))); shmop_write($shmop, pack('L', $prev + 512), 0); shmop_close($shmop); } // 더이상 데이터가 없는 경우 루프를 탈출한다. if ($entry === false) { break; } // 메모리 누수를 방지하기 위해 모든 배열을 unset한다. unset($entry); } // 시·도 데이터 파일을 닫는다. $zip->close_file(); } // 뒷정리. $zip->close(); unset($zip); $db->commit(); unset($db); }