Пример #1
0
 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);
 }