パブリックタグ登録申請サンプルサイト ソース解説

場所情報コード入力・確認ページ1

概要

このファイルでは、パラメータにより発行申請入力画面・修正申請入力画面・発行申請確認画面・修正申請確認画面・発行申請完了画面・修正申請完了画面・発行申請再入力画面(APIアクセスに失敗した場合)・修正申請再背院生画面(APIアクセスに失敗した場合)を提供する。 主要なパラメータは次のとおりである。

pubtag
パブリックタグか否か
最初にほかのファイルの画面から遷移した場合のみ指定され、inpub.phpの出力する画面同士では、dataに含めて引き渡す
ucode
修正申請の対象となる場所情報コード 配列でucode[対象コード]=修正
最初にほかのファイルの画面から遷移した場合のみ指定され、inpub.phpの出力する画面同士では、dataに含めて引き渡す
data
入力データ data['name']などと配列で指定する
confirm
確認画面を表示する
regist
申請APIにアクセスする
post_key
XSRF対策のためのデータ
どの画面が出力されるかは、下図のように判定される。

なお、このファイル内では$dataという大域変数がセットされる。 この変数は入力フォームの初期値として使用され、その値は、 まず、1.パラメータdataが指定された場合は、その値 2.パラメータdataが指定されずucodeが指定さた場合は場所情報コードAPIで取得した情報 3.それ以外の場合は、空の配列 となる。 次に、パラメータpubtagおよびucodeが指定された場合には、$data['pubtag']および$data['ucode']に格納する。

入力画面および再入力画面で使用されるいくつかの機能について、本解説サイトの場所情報コード入力・確認ページ2および場所情報コード入力・確認ページ3に解説する。

解説

XSRF対策のpost_keyは、下記のように用意する。
if(isset($_REQUEST['post_key'])){
    if(!isset($_SESSION['post_key']) || $_SESSION['post_key'] != $_REQUEST['post_key']){
        die();
    }
}elseif(!isset($_SESSION['post_key'])){
    $_SESSION['post_key'] = rand_str(16);
}

パラメータにpost_keyが指定されていれば、セッションに保存されたpost_keyと比較し、一致しなければ異常終了する。post_keyが指定されていなければ、ランダムな文字列を生成してセッションに保存する。

パラメータにregistが指定されているとき、パラメータpost_keyが指定されているか確認し、指定されていればAPIにアクセスする。

if(isset($_REQUEST['regist'])){
    if(!isset($_REQUEST['post_key']))die();
    $_SESSION['post_key'] = rand_str(16);

    $data = $_REQUEST['data'];

    //申請実行
    $apply_data = $data;
    $apply_data['token'] = $_SESSION['token'];
    if(isset($apply_data['latitude']))
        $apply_data['latitude'] = dec_to_60($apply_data['latitude'],2);
    if(isset($apply_data['longitude']))
        $apply_data['longitude'] = dec_to_60($apply_data['longitude'],3);
    $context = stream_context_create(
            array(
                    'http' => array(
                            'method'=> (empty($apply_data['ucode'])?'POST':'PUT'),
                            'header' => "Content-Type: application/x-www-form-urlencoded",
                            'ignore_errors' => true,
                            'content' =>  http_build_query( $apply_data )
                    )
                )
            );
    $apply_result = json_decode(file_get_contents(UCODE_APPLY_API, false, $context),true);
    $error_params = $apply_result['error_params'];
    preg_match('/HTTP\/1\.[0|1|x] ([0-9]{3})/', $http_response_header[0], $matches);
    $status_code = $matches[1];
    if($status_code == 200 || $status_code == 201 || !$apply_result) $mode = 'result';
}

APIにアクセスして得られたデータは、$apply_resultに格納される。 また、エラーのあるパラメータのリストが、$error_paramsに格納される。 $status_codeにはAPIアクセスした際のHTTPステータスが格納され、200又は201の場合は申請成功なので、$modeに申請成功画面を表す'result'をセットする。 申請成功画面は、以下のコードで出力している。

<?php if($mode == 'result'):?>
    <?php if(isset($apply_result) && $status_code == 200):?>
修正申請完了しました。<br>
<br>
<a href="token.php" class="button">戻る</a>

    <?php elseif(isset($apply_result) && $status_code == 201):?>
発行申請完了しました。<br>
<br>
<dl>
    <dt>ucode</dt>
    <dd>
        <?php h($apply_result['ucode'])?>
    </dd>
</dl>
<br>
<a href="token.php" class="button">戻る</a>

    <?php elseif(isset($apply_result) && !$apply_result):?>
申請に失敗しました。<br>
<br>
<a href="token.php" class="button">戻る</a>
    <?php endif; ?>

$status_codeが200のときは修正申請成功であり、201のときは発行申請成功である。 $apply_resultが定義されたにもかかわらずその内容が空である場合は、ユーザーの入力内容の誤りなどではなくURLの誤り、APIの動作不良などによりAPIアクセスそのものに失敗しているので、失敗した旨のみを表示する。

パラメータにconfirmが指定されているとき、次のコードによって入力確認画面の表示が確定する。

elseif(isset($_REQUEST['confirm'])){
    $mode = 'confirm';
    $data = $_REQUEST['data'];
}
また、次のように画面が出力される。フォーム内にpost_keyを含めることに注意する。
<form method="POST">
    <input type="hidden" name="post_key" value="<?php h($_SESSION['post_key']) ?>"">
    <dl>
    <?php
    $has_error = false;
    $names = array('name'=>'名称','administrator'=>'施設管理者','longitude'=>'緯度・経度','observation_date'=>'位置測定日','level_code'=>'屋外・階数など','format_version_code'=>'利用の分類(大まかな分類)','point_type_code'=>'種別(細かい分類)','media'=>'媒体','oprrlb'=>'運用の信頼度','serial'=>'整理番号','base_date'=>'位置情報の基準日','altitude'=>'標高','city_code'=>'市町村コード','address'=>'住所(大字以下の町名番地)','feature'=>'属性(キーワード)','ucode_url'=>'詳細URL','tag_id'=>'タグ固有ID','expr'=>'場所情報の表現の種類','nonblinfo'=>'緯度経度以外の場所指定情報','remark'=>'備考','disclosure1'=>'位置に関する情報の公開','disclosure2'=>'付随する情報の公開','status'=>'運用の状態');
    $list_items = array('horizontal_accuracy'=>'horizontal_accuracy','accuracy_reliability'=>'accuracy_reliability','format_version_code'=>'format_version','point_type_code'=>'shubetsu','media'=>'media','oprrlb'=>'oprrlb','status'=>'status','altitude_reliability'=>'altitude_reliability','expr'=>'expr');
    $empty = "<span class=\"empty\">(未入力)</span>";
    foreach($data as $k=>$v){
        printf('<input type="hidden" name="data[%s]" value="%s">',$k,htmlspecialchars($v,true));
        if(isset($names[$k])){
            if($k == 'longitude'){
                $dd = sprintf("緯度:%s<br>経度:%s<br>",$data['latitude']?htmlspecialchars($data['latitude']):$empty,$data['longitude']?htmlspecialchars($data['longitude']):$empty);
                $list = get_list('horizontal_accuracy');
                $dd .= sprintf("測定精度:%s<br>",$data['horizontal_accuracy']?$list[$data['horizontal_accuracy']]:$empty);
                $list = get_list('accuracy_reliability');
                $dd .= sprintf("測定精度の信頼度:%s<br>",$data['accuracy_reliability']?$list[$data['accuracy_reliability']]:$empty);
            }elseif($k=='altitude'){
                $dd = sprintf("標高:%sm<br>",$data['altitude']?htmlspecialchars($data['altitude']):$empty);
                $list = get_list('altitude_accuracy');
                $dd .= sprintf("測定精度:%s<br>",$data['altitude_accuracy']?$list[$data['altitude_accuracy']]:$empty);
                $list = get_list('altitude_reliability');
                $dd .= sprintf("測定精度の信頼度:%s<br>",$data['altitude_reliability']?$list[$data['altitude_reliability']]:$empty);
            }elseif(isset($list_items[$k])){
                $list = get_list($list_items[$k]);
                if($v)
                    $dd = htmlspecialchars($list[$v]);
                else
                    $dd = $empty;
            }elseif($k=='level_code'){
                if(isset($kaiso_list[$v]) && $v != 0){
                    $dd = htmlspecialchars($kaiso_list[$v]);
                }elseif($v == ''){
                    $dd = $empty;
                }else{
                    if($data['level_code']==0){
                        $kaisuu = 'グランドフロア';
                    }elseif($data['level_code']>0){
                        $kaisuu = htmlspecialchars($data['level_code']).'階';
                    }else{
                        $kaisuu = '地下'.htmlspecialchars(-$data['level_code']).'階';
                    }
                    $dd = '屋内 '.$kaisuu.' '.($data['middle_floor']==0?'整数階':'中間階');
                }
            }else{
                if($v)
                    $dd = htmlspecialchars($v);
                else
                    $dd = $empty;
            }
            $error = chk_item($k,$v,$data);
            if($error){
                echo "\n<dt class=\"error\">$names[$k]<dt>\n";
                $has_error = true;
            }else{
                echo "\n<dt>$names[$k]<dt>\n";
            }
            echo "<dd>$dd<div class=\"error\">$error</div></dd>";
        }
    }
    ?>
    </dl>
<input type="submit" class="button" value="戻る">
    <?php if(!$has_error):?>
<input type="submit" class="button" name="regist" value="申請実行">
    <?php endif;?>
</form>
    <?php if(isset($data['latitude']) && isset($data['longitude'])):?>
<iframe src="gsimap/#18/<?php echo $data['latitude']?>"/<?php echo $data['longitude']?>" id="map2"></iframe>
    <?php endif;?>

ここで、chk_item($k,$v,$data)は入力値の検証を行う関数であり、 $ kは検証対象のパラメータの名称、 $v は値、 $data は入力パラメータの全体となる。 また、get_list($itemname)は、媒体や運用状態など、リストから選択させる値の、値リストを取得する関数である。 $itemname は、基本的にはCSVファイルの名前を指定するが、水平精度と標高精度は同じ seido.csv から読み込むので、特別に horizontal_accuracy および altitude_reliability を指定する。 値リストから選択させるものは $list_items に列挙されており、パラメータ名が配列のインデックス、ファイル名が値となる。 foreach($data as $k=>$v)としているので、修正申請時には変更するパラメータのみを表示することができ、また発行申請時にもパブリックタグか否かで処理を分ける必要がない。

基本的に各パラメータに対して以下のようなHTMLを出力するが、
<dt>パラメータの名称</dt>
<dd>入力された値</dd>
リスト選択するものはコードを名称に変換して表示する。また、水平位置、標高、階層に関しては特別な表示を行う。

chk_item()の戻り値はエラーメッセージであり、エラーがなければ空文字列を返す。 エラーがある場合は<dt>および<dd>にクラスerrorを設定すると、CSSにより赤く着色される。 また、<dd>内にえらーメッセージを表示する。 一つもエラーがなければ、申請実行ボタンを表示する。

ソースコード

<?php
include 'lib.php';
deny_path_info();
if(empty($_SESSION['token'])){
    header("Location: token.php");
    exit();
}
if(isset($_REQUEST['post_key'])){
    if(!isset($_SESSION['post_key']) || $_SESSION['post_key'] != $_REQUEST['post_key']){
        die();
    }
}elseif(!isset($_SESSION['post_key'])){
    $_SESSION['post_key'] = rand_str(16);
}
$data = array();
$error_params = array();
$mode = 'input';

if(isset($_REQUEST['regist'])){
    if(!isset($_REQUEST['post_key']))die();
    $_SESSION['post_key'] = rand_str(16);

    $data = $_REQUEST['data'];

    //申請実行
    $apply_data = $data;
    $apply_data['token'] = $_SESSION['token'];
    if(isset($apply_data['latitude']))
        $apply_data['latitude'] = dec_to_60($apply_data['latitude'],2);
    if(isset($apply_data['longitude']))
        $apply_data['longitude'] = dec_to_60($apply_data['longitude'],3);
    $context = stream_context_create(
            array(
                    'http' => array(
                            'method'=> (empty($apply_data['ucode'])?'POST':'PUT'),
                            'header' => "Content-Type: application/x-www-form-urlencoded",
                            'ignore_errors' => true,
                            'content' =>  http_build_query( $apply_data )
                    )
                )
            );
    $apply_result = json_decode(file_get_contents(UCODE_APPLY_API, false, $context),true);
    $error_params = $apply_result['error_params'];
    preg_match('/HTTP\/1\.[0|1|x] ([0-9]{3})/', $http_response_header[0], $matches);
    $status_code = $matches[1];
    if($status_code == 200 || $status_code == 201 || !$apply_result) $mode = 'result';
}elseif(isset($_REQUEST['confirm'])){
    $mode = 'confirm';
    $data = $_REQUEST['data'];
}elseif(isset($_REQUEST['data'])){
    $data = $_REQUEST['data'];
}elseif(isset($_REQUEST['ucode'])){
    $search_result = json_decode(file_get_contents(UCODE_SEARCH_API.'ucode='.urlencode(key($_REQUEST['ucode']))),true);
    preg_match('/HTTP\/1\.[0|1|x] ([0-9]{3})/', $http_response_header[0], $matches);
    $status_code = $matches[1];
    if($search_result && $search_result['status'] == 200){
        $data = $search_result['items'][0];
        if(isset($data['intermediate_level_code']))$data['middle_floor'] = $data['intermediate_level_code'];
        if(isset($data['media_code']))$data['media'] = $data['media_code'];
        if(isset($data['altitude_accuracy_code']))$data['altitude_accuracy'] = $data['altitude_accuracy_code'];
        if(isset($data['coordinate'])){
            $data['latitude'] = $data['coordinate']['latitude'];
            $data['longitude'] = $data['coordinate']['longitude'];
        }
    }
}
if(isset($_REQUEST['pubtag'])) $data['pubtag'] = $_REQUEST['pubtag'];

$kaiso_list = get_list('kaiso',true,array('0'=>'屋内'));
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style=Type" content="text/css" />
<meta name="viewport" content="width=device-width" >
<title><?php h(SITE_NAME);?></title>
<link rel="stylesheet" href="base.css" />
<style>
dt{
    background-color: #e0e0e0;
}
<?php if(!isset($data['ucode']) && !isset($apply_result)): ?>
dl#optional{
    display: none;
}
<?php endif; ?>
<?php if(!isset($data['ucode'])): ?>
input.modify{
    display: none;
}
<?php endif; ?>
#map,#geocode{
    display: none;
    width: 100%;
    height: 100vh;
    border: none;
}
#contents{

}
dt.error{
    background-color: #fbb;
}
dt.error+dd{
    background-color: #fee;
    border: 1px solid red;
}
body{
    height: 100%;
}
div.error{
    color: red;
}
span.empty{
    background-color: #eff;
}
#map2{
    width: 80%;
    margin-left: 10%;
}
</style>
<script>
var map = null;
var geocode = null;
var edit_map = <?php echo $mode == 'input'?'true':'false'?>;
<?php if($mode == 'input'):?>
function init(){
    map = document.getElementById('map');
    geocode = document.getElementById('geocode');
    toggle_okunai();
    display_latlng();
    document.getElementsByName('kaiso')[0].onchange = function(){
        toggle_okunai();
        if(this.value=='0'){
            document.getElementsByName('data[level_code]')[0].value =
                document.getElementsByName('kaisuu')[0].value;
        }else{
            document.getElementsByName('data[level_code]')[0].value = this.value;
            document.getElementsByName('data[middle_floor]')[0].value = 0;
        }
    }
    document.getElementsByName('kaisuu')[0].onchange = function(){
        document.getElementsByName('data[level_code]')[0].value = this.value;
    }
    document.getElementsByName('latitude')[0].onchange = function(){
        var latitude;
        if(document.getElementById('deg60').checked){
            latitude = dec_from_60(this.value,2);
            if(!latitude)latitude = '';
        }else{
            latitude = this.value;
        }
        document.getElementsByName('data[latitude]')[0].value=latitude;
    }
    document.getElementsByName('longitude')[0].onchange = function(){
        var longitude;
        if(document.getElementById('deg60').checked){
            longitude = dec_from_60(this.value,3);
            if(!longitude)longitude = '';
        }else{
            longitude = this.value;
        }
        document.getElementsByName('data[longitude]')[0].value=longitude;
    }
    <?php if(isset($data['ucode'])): ?>
    var modify = document.getElementsByClassName('modify');
    for(var i=0; i<modify
    //水平精度・標高精度のセット
    accuracy_change('horizontal');
    accuracy_change('altitude');
}
    <?php if(isset($data['ucode'])): ?>
function toggle_modify(){
    toggle_modify2(this);
}
function toggle_modify2(element){
    var tagnames = ['input','select','textarea'];
    for(var j=0; j<tagnames
function toggle_okunai(){
    if(document.getElementsByName('kaiso')[0].value=='0'){
        document.getElementById('okunai').style.display = 'block';
    }else{
        document.getElementById('okunai').style.display = 'none';
    }
}
function set_latlng(lat,lng,zoom){
    document.getElementsByName('data[latitude]')[0].value = lat;
    document.getElementsByName('data[longitude]')[0].value = lng;
    if(zoom){
        if(zoom>=18){
            document.getElementsByName('data[horizontal_accuracy]')[0].value = 20;
            accuracy_change('horizontal');
        }else{
            document.getElementsByName('data[horizontal_accuracy]')[0].value = 30;
            accuracy_change('horizontal');
        }
    }
    display_latlng();
    get_altitude();
}
function open_map(){
    document.getElementById('contents').style.display = 'none';
    map.style.display = 'block';
    var latlng = get_latlng();
    if(!(latlng.lat > 0 && latlng.lng > 0)){
        latlng = {lat:36.104638,lng:140.084619};
    }
    map.src="gsimap/#15/"+latlng.lat+'/'+latlng.lng;
}
function close_map(){
    map.style.display = 'none';
    document.getElementById('contents').style.display = 'block';
}
function get_latlng(){
    return {lat:document.getElementsByName('data[latitude]')[0].value,lng:document.getElementsByName('data[longitude]')[0].value};
}
function device_latlng(){
    var btn = document.getElementById('device_latlng_btn');
    btn.setAttribute('disabled','disabled');
    btn.value = '現在地取得中…';
    if( navigator.geolocation ){
        navigator.geolocation.getCurrentPosition( device_latlng_got , device_latlng_error , {'enableHighAccuracy':true,'timeout':'5000'} ) ;
    }else{
        alert( "お使いの機器またはブラウザは位置情報の取得に対応していません。" ) ;
    }
}
function device_latlng_got(position){
    var btn = document.getElementById('device_latlng_btn');
    btn.removeAttribute('disabled');
    btn.value = '現在地を入力';
    if(position.coords.latitude>0 && position.coords.longitude>0){
        set_latlng(position.coords.latitude,position.coords.longitude);
        alert('位置情報の取得に成功しました。');
    }else{
        alert('位置情報の取得に失敗しました。\n緯度:'+position.coords.latitude+' 経度:'+position.coords.longitude);
    }
}
function device_latlng_error(error){
    var btn = document.getElementById('device_latlng_btn');
    btn.removeAttribute('disabled');
    btn.value = '現在地を入力';
    if(error.code == 1)
        alert('ブラウザの設定を確認し、現在地の使用を許可してください。');
    else
        alert('位置情報の取得に失敗しました。\nエラーコード:'+error.code);
}
function toggle_required_optional(){
    var required = document.getElementById('required');
    var optional = document.getElementById('optional');
    var btn = document.getElementById('btn_toggle_required_optional');
    if(required.style.display == 'none'){
        required.style.display = 'block';
        optional.style.display = 'none';
        btn.value = '任意項目入力';
    }else{
        required.style.display = 'none';
        optional.style.display = 'block';
        btn.value = '必須項目入力';
    }
}
function get_city_code(){
    var latlng = get_latlng();
    if(!(latlng.lat>0&&latlng.lat<900&&latlng.lng<1800&&latlng.lat<900&&latlng.lng<18060||hun<060||byou<0(val_aa/10+1)) return;
            var opt = document.createElement('option');
            opt.innerText = str;
            opt.value = i;
            if(val_ra == i)opt.selected = true;
            sel_ra.appendChild(opt);
        });
        document.getElementsByName('data['+direction+'_accuracy]')[0].value = parseInt(val_ra)+parseInt(val_aa);
    }
}
function accuracy_change(direction){
    var accuracy = document.getElementsByName('data['+direction+'_accuracy]')[0];
    var absolute_accyracy = document.getElementById(direction+'_absolute_accyracy');
    var value = accuracy.value
    if(accuracy.value == 99) absolute_accyracy.value = 99;
    else if(accuracy.value > 0) absolute_accyracy.value = Math.floor(accuracy.value/10)*10;
    else accuracy.value = 0;
    absolute_accyracy_change(direction);
    document.getElementById(direction+'_relative_accuracy').value = value - absolute_accyracy.value;
    accuracy.value = value;
}
function relative_accuracy_change(direction){
    document.getElementsByName('data['+direction+'_accuracy]')[0].value =
        parseInt(document.getElementById(direction+'_absolute_accyracy').value) + parseInt(document.getElementById(direction+'_relative_accuracy').value);
}
<?php elseif($mode == 'confirm'):?>
function init(){
    map = document.getElementById('map2');
    map.style.height = Math.min(map.clientWidth,window.innerHeight*0.8)+'px';
    window.onresize=function(){
        map.style.height = Math.min(map.clientWidth,window.innerHeight*0.8)+'px';
    }
}
<?php else: ?>
function init(){

}
<?php endif;?>
</script>
</head>
<body onload="init()">
<?php if($mode == 'input'): ?>
<iframe id="map"></iframe>
<iframe id="geocode"></iframe>
<?php endif; ?>
<div id="contents">
<h2><?php h(SITE_NAME);?></h2>
<?php if($mode == 'result'):?>
    <?php if(isset($apply_result) && $status_code == 200):?>
修正申請完了しました。<br>
<br>
<a href="token.php" class="button">戻る</a>

    <?php elseif(isset($apply_result) && $status_code == 201):?>
発行申請完了しました。<br>
<br>
<dl>
    <dt>ucode</dt>
    <dd>
        <?php h($apply_result['ucode'])?>
    </dd>
</dl>
<br>
<a href="token.php" class="button">戻る</a>

    <?php elseif(isset($apply_result) && !$apply_result):?>
申請に失敗しました。<br>
<br>
<a href="token.php" class="button">戻る</a>
    <?php endif; ?>
<?php elseif($mode == 'confirm'):?>
<form method="POST">
    <input type="hidden" name="post_key" value="<?php h($_SESSION['post_key']) ?>"">
    <dl>
    <?php
    $has_error = false;
    $names = array('name'=>'名称','administrator'=>'施設管理者','longitude'=>'緯度・経度','observation_date'=>'位置測定日','level_code'=>'屋外・階数など','format_version_code'=>'利用の分類(大まかな分類)','point_type_code'=>'種別(細かい分類)','media'=>'媒体','oprrlb'=>'運用の信頼度','serial'=>'整理番号','base_date'=>'位置情報の基準日','altitude'=>'標高','city_code'=>'市町村コード','address'=>'住所(大字以下の町名番地)','feature'=>'属性(キーワード)','ucode_url'=>'詳細URL','tag_id'=>'タグ固有ID','expr'=>'場所情報の表現の種類','nonblinfo'=>'緯度経度以外の場所指定情報','remark'=>'備考','disclosure1'=>'位置に関する情報の公開','disclosure2'=>'付随する情報の公開','status'=>'運用の状態');
    $list_items = array('horizontal_accuracy'=>'horizontal_accuracy','accuracy_reliability'=>'accuracy_reliability','format_version_code'=>'format_version','point_type_code'=>'shubetsu','media'=>'media','oprrlb'=>'oprrlb','status'=>'status','altitude_reliability'=>'altitude_reliability','expr'=>'expr');
    $empty = "<span class=\"empty\">(未入力)</span>";
    foreach($data as $k=>$v){
        printf('<input type="hidden" name="data[%s]" value="%s">',$k,htmlspecialchars($v,true));
        if(isset($names[$k])){
            if($k == 'longitude'){
                $dd = sprintf("緯度:%s<br>経度:%s<br>",$data['latitude']?htmlspecialchars($data['latitude']):$empty,$data['longitude']?htmlspecialchars($data['longitude']):$empty);
                $list = get_list('horizontal_accuracy');
                $dd .= sprintf("測定精度:%s<br>",$data['horizontal_accuracy']?$list[$data['horizontal_accuracy']]:$empty);
                $list = get_list('accuracy_reliability');
                $dd .= sprintf("測定精度の信頼度:%s<br>",$data['accuracy_reliability']?$list[$data['accuracy_reliability']]:$empty);
            }elseif($k=='altitude'){
                $dd = sprintf("標高:%sm<br>",$data['altitude']?htmlspecialchars($data['altitude']):$empty);
                $list = get_list('altitude_accuracy');
                $dd .= sprintf("測定精度:%s<br>",$data['altitude_accuracy']?$list[$data['altitude_accuracy']]:$empty);
                $list = get_list('altitude_reliability');
                $dd .= sprintf("測定精度の信頼度:%s<br>",$data['altitude_reliability']?$list[$data['altitude_reliability']]:$empty);
            }elseif(isset($list_items[$k])){
                $list = get_list($list_items[$k]);
                if($v)
                    $dd = htmlspecialchars($list[$v]);
                else
                    $dd = $empty;
            }elseif($k=='level_code'){
                if(isset($kaiso_list[$v]) && $v != 0){
                    $dd = htmlspecialchars($kaiso_list[$v]);
                }elseif($v == ''){
                    $dd = $empty;
                }else{
                    if($data['level_code']==0){
                        $kaisuu = 'グランドフロア';
                    }elseif($data['level_code']>0){
                        $kaisuu = htmlspecialchars($data['level_code']).'階';
                    }else{
                        $kaisuu = '地下'.htmlspecialchars(-$data['level_code']).'階';
                    }
                    $dd = '屋内 '.$kaisuu.' '.($data['middle_floor']==0?'整数階':'中間階');
                }
            }else{
                if($v)
                    $dd = htmlspecialchars($v);
                else
                    $dd = $empty;
            }
            $error = chk_item($k,$v,$data);
            if($error){
                echo "\n<dt class=\"error\">$names[$k]<dt>\n";
                $has_error = true;
            }else{
                echo "\n<dt>$names[$k]<dt>\n";
            }
            echo "<dd>$dd<div class=\"error\">$error</div></dd>";
        }
    }
    ?>
    </dl>
<input type="submit" class="button" value="戻る">
    <?php if(!$has_error):?>
<input type="submit" class="button" name="regist" value="申請実行">
    <?php endif;?>
</form>
    <?php if(isset($data['latitude']) && isset($data['longitude'])):?>
<iframe src="gsimap/#18/<?php echo $data['latitude']?>"/<?php echo $data['longitude']?>" id="map2"></iframe>
    <?php endif;?>
<?php else: //入力フォーム表示?>
    <?php if(isset($search_result) && (!$search_result || $search_result['status'] != 200)):?>
    指定された場所情報コードの情報を取得できませんでした。<br>
    <div><?php if(isset($search_result['message']))h($search_result['message']); ?></div>
    <?php endif; ?>
    <?php
        if(!empty($apply_result)){
            if($status_code == 400){
                echo "入力に不備があります。入力内容を確認してください。<br>";
            }
            echo nl2br($apply_result['message']);
        }
    ?>
    <form method="POST">
    <input type="hidden" name="data[pubtag]" value="<?php h($data['pubtag'])?>"">
    <?php if(isset($data['ucode'])): ?>
    <input type="hidden" name="data[ucode]" value="<?php h($data['ucode'])?>"">
    <?php endif;?>
    <dl id="required">
        <dt class=" pubtag <?php echo in_array('name',$error_params)?'error':''?>""><input type="checkbox" class="modify" >名称</dt>
        <dd><input type="text" name="data[name]" value="<?php h(_d($data,'name'))?>""></dd>

        <dt class=" pubtag <?php echo in_array('latitude',$error_params)|| in_array('longitude',$error_params)?'error':''?>""><input type="checkbox" class="modify" >水平位置(緯度・経度)</dt>
        <dd>緯度:<input type="text" name="latitude"><input type="hidden" name="data[latitude]" value="<?php h(_d($data,'latitude'))?>""><br>
            経度:<input type="text" name="longitude"><input type="hidden" name="data[longitude]" value="<?php h(_d($data,'longitude'))?>""><br>
            <input type="checkbox" name="deg60" value="1" id="deg60" onclick="display_latlng()" ><label for="deg60">60進(緯度:ddmmss.ss 経度:dddmmss.ss)で入力</label><br>
            <input type="button" onclick="open_map();return false;"  value="地図から入力">&nbsp;<input type="button" onclick="device_latlng();return false;" id="device_latlng_btn" value="現在地を入力">&nbsp;<input type="button" onclick="open_geocode();return false;" value="住所から入力"><br>
            <input type="hidden" name="data[horizontal_accuracy]" value="<?php h(_d($data,'horizontal_accuracy'))?>"">
            測定精度:絶対精度:<select id="horizontal_absolute_accyracy" onchange="absolute_accyracy_change('horizontal');"><option value='0</option><option value='10高精度</option><option value='20中精度</option><option value='30低精度</option><option value='99精度不明</option></select>
                    相対精度:<select id="horizontal_relative_accuracy" onchange="relative_accuracy_change('horizontal');"></select><br>
            測定精度の信頼度:<?php echo make_select('data[accuracy_reliability]',get_list('accuracy_reliability'),_d($data,'accuracy_reliability'))?>
        </dd>

        <?php if($data['pubtag']=="no"):?>
        <dt class=" pubtag <?php echo in_array('observation_date',$error_params)?'error':''?>""><input type="checkbox" class="modify" >位置測定日</dt>
        <dd><input type="text" name="data[observation_date]" value="<?php h(_d($data,'observation_date'))?>""></dd>
        <?php endif;?>

        <dt class=" pubtag <?php echo in_array('level_code',$error_params)?'error':''?>""><input type="checkbox" class="modify" >屋外・階数など</dt>
        <dd><input type="hidden" name="data[level_code]" value="<?php h(_d($data,'level_code'))?>"">
            <?php echo make_select('kaiso',$kaiso_list,!isset($data['level_code'])||$data['level_code']==''?'':($data['level_code']<989?'0':$data['level_code'])) ?><br>
            <div id="okunai">
            階数:
            <?php echo make_select('kaisuu',get_kaisuu_list(),isset($data['level_code'])&&$data['level_code']<989?$data['level_code']:1);   ?>
            <?php echo make_select('data[middle_floor]',array('0'=>'整数階','0.5'=>'中間階'),_d($data,'middle_floor')) ?>
            </div>
        </dd>

        <?php if($data['pubtag']=="no"):?>
        <dt class=" <?php echo in_array('city_code',$error_params)?'error':''?>""><input type="checkbox" class="modify" >市町村コード</dt>
        <dd><input type="text" name="data[city_code]" value="<?php h(_d($data,'city_code'))?>"">
            <input type="button" onclick="get_city_code();return false;" value="緯度・経度から取得">
        </dd>

        <dt class=" <?php echo in_array('format_version_code',$error_params)?'error':''?>""><input type="checkbox" class="modify" >利用の分類(大まかな分類)</dt>
        <dd><?php echo make_select('data[format_version_code]',get_list('format_version'),_d($data,'format_version_code'))?></dd>

        <dt class=" <?php echo in_array('point_type_code',$error_params)?'error':''?>""><input type="checkbox" class="modify" >種別(細かい分類)</dt>
        <dd><?php echo make_select('data[point_type_code]',get_list('shubetsu'),_d($data,'point_type_code'))?></dd>
        <?php endif; ?>

        <dt class=" pubtag <?php echo in_array('media',$error_params)?'error':''?>""><input type="checkbox" class="modify" >媒体</dt>
        <dd><?php echo make_select('data[media]',get_list('media'),_d($data,'media'))?></dd>

        <dt class=" <?php echo in_array('tag_id',$error_params)?'error':''?>""><input type="checkbox" class="modify" >タグ固有ID</dt>
        <dd><input type="text" name="data[tag_id]" value="<?php h(_d($data,'tag_id'))?>""></dd>

        <dt class=" pubtag <?php echo in_array('oprrlb',$error_params)?'error':''?>""><input type="checkbox" class="modify" >可用性の指標</dt>
        <dd><?php echo make_select('data[oprrlb]',get_list('oprrlb'),_d($data,'oprrlb'))?></dd>

        <dt class=" pubtag <?php echo in_array('administrator',$error_params)?'error':''?>""><input type="checkbox" class="modify" >施設管理者</dt>
        <dd><input type="text" name="data[administrator]" value="<?php h(_d($data,'administrator'))?>""></dd>

        <?php if($data['pubtag']=="yes"):?>
        <dt class=" pubtag <?php echo in_array('status',$error_params)?'error':''?>""><input type="checkbox" class="modify" >運用状態</dt>
        <dd><?php echo make_select('data[status]',get_list('status'),_d($data,'status'))?></dd>
        <?php endif; ?>
    </dl>

    <dl id="optional">

        <?php if($data['pubtag']=="no"):?>
        <dt class=" <?php echo in_array('serial',$error_params)?'error':''?>""><input type="checkbox" class="modify" >整理番号</dt>
        <dd><input type="text" name="data[serial]" value="<?php h(_d($data,'serial'))?>""></dd>

        <dt class=" <?php echo in_array('base_date',$error_params)?'error':''?>""><input type="checkbox" class="modify" >位置情報の基準日</dt>
        <dd><input type="text" name="data[base_date]" value="<?php h(_d($data,'base_date'))?>""></dd>

        <?php endif; ?>
        <dt class=" <?php echo in_array('altitude',$error_params)?'error':''?>""><input type="checkbox" class="modify" >標高</dt>
        <dd>標高:<input type="text" name="data[altitude]" value="<?php h(_d($data,'altitude'))?>"">m<br>
        <input type="hidden" name="data[altitude_accuracy]" value="<?php h(_d($data,'altitude_accuracy'))?>"">
        測定精度:絶対精度:<select id="altitude_absolute_accyracy" onchange="absolute_accyracy_change('altitude');"><option value='0</option><option value='10高精度</option><option value='30低精度</option><option value='99精度不明</option></select>
                    相対精度:<select id="altitude_relative_accuracy" onchange="relative_accuracy_change('altitude');"></select><br>
        測定精度の信頼度:<?php echo make_select('data[altitude_reliability]',get_list('altitude_reliability'),_d($data,'altitude_reliability'))?>
        </dd>

        <?php if($data['pubtag']=="no"):?>
        <dt class=" <?php echo in_array('address',$error_params)?'error':''?>""><input type="checkbox" class="modify" >住所(大字以下の町名番地)</dt>
        <dd><input type="text" name="data[address]" value="<?php h(_d($data,'address'))?>""></dd>
        <?php endif;?>

        <dt class=" <?php echo in_array('feature',$error_params)?'error':''?>""><input type="checkbox" class="modify" >属性(キーワード)</dt>
        <dd><input type="text" name="data[feature]" value="<?php h(_d($data,'feature'))?>""></dd>

        <dt class=" <?php echo in_array('ucode_url',$error_params)?'error':''?>""><input type="checkbox" class="modify" >詳細URL</dt>
        <dd><input type="text" name="data[ucode_url]" value="<?php h(_d($data,'ucode_url'))?>""></dd>

        <?php if($data['pubtag']=="yes"):?>
        <dt class=" <?php echo in_array('expr',$error_params)?'error':''?>""><input type="checkbox" class="modify" >場所情報の種類</dt>
        <dd><?php echo make_select('data[expr]',get_list('expr'),_d($data,'expr'))?></dd>

        <dt class=" <?php echo in_array('nonblinfo',$error_params)?'error':''?>""><input type="checkbox" class="modify" >緯度経度以外の場所指定情報</dt>
        <dd><input type="text" name="data[nonblinfo]" value="<?php h(_d($data,'nonblinfo'))?>""></dd>
        <?php endif;?>

        <?php if($data['pubtag']=="no"):?>
        <dt class=" <?php echo in_array('remark',$error_params)?'error':''?>""><input type="checkbox" class="modify" >備考</dt>
        <dd><textarea name="data[remark]" ><?php h(_d($data,'remark'))?></textarea></dd>

        <dt class=" <?php echo in_array('disclosure1',$error_params)?'error':''?>""><input type="checkbox" class="modify" >位置に関する情報の公開</dt>
        <dd><input type="radio" name="disclosure1" id="disclosure1_yes" value="yes"  ><label for="disclosure1_yes">yes</label>
            <input type="radio" name="disclosure1" id="disclosure1_no" value="no" ><label for="disclosure1_no">no</label></dd>

        <dt class=" <?php echo in_array('disclosure2',$error_params)?'error':''?>""><input type="checkbox" class="modify" >付随する情報の公開</dt>
        <dd><input type="radio" name="disclosure2" id="disclosure2_yes" value="yes" ><label for="disclosure2_yes">yes</label>
            <input type="radio" name="disclosure2" id="disclosure2_no" value="no" ><label for="disclosure2_no">no</label></dd>
        <?php endif;?>
    </dl>
    <div>
    <?php if(!isset($data['ucode']) && !isset($apply_result)):?>
    <input type="button" class="button"  onclick="toggle_required_optional();return false;" id="btn_toggle_required_optional" value="任意項目入力">
    <?php endif;?>
    <input type="submit" class="button" name="confirm" value="確認">
    </div>
    </form>
<?php endif;?>
</div>

</body>
</html>
<?php
function make_select($name,$options,$value = null,$attrs = array()){
    $option_str = '';
    foreach($options as $k => $v){
        $option_str .= sprintf('<option value="%s" %s>%s</option>',
                htmlspecialchars($k),($value != null && $value != '' &&$value==$k?'selected':''),htmlspecialchars($v));
    }
    $name_ = htmlspecialchars($name,ENT_QUOTES);
    $attrs_str = '';
    foreach($attrs as $a=>$v)$attrs_str .= " $a=$v";
    $str = "<select name=\"$name\" $attrs_str>$option_str</select>";
    return $str;
}
function upfile_to_utf8($fname){
    $tmp = file_get_contents($fname);
    $tmp = mb_convert_encoding($tmp,'UTF-8', "auto");
    $file = tmpfile();
    fwrite($file,$tmp);
    fseek($file,0);
    return $file;
}
function get_list($name,$add_empty=true,$add_items = array()){
    $retdata = array();
    if($add_empty)
        $retdata[''] = '';
    foreach($add_items as $k => $v)
        $retdata[$k] = $v;
    switch($name){
        case 'horizontal_accuracy':
        case 'altitude_accuracy':
            $filename = 'seido';
                break;
        default:
            $filename = $name;
                break;
    }
    $csvfile = upfile_to_utf8(CODE_CSV_PATH.$filename.'.csv');
    fgetcsv($csvfile);
    while($row = fgetcsv($csvfile)){
        if(strpos($row[1],'予約') !== false)continue;
        switch ($name){
            case 'horizontal_accuracy':
                if($row[2] == '水平' || $row[2] == '両方')
                    $retdata[$row[0]] = "$row[1]";
                break;
            case 'altitude_accuracy':
                if($row[2] == '垂直' || $row[2] == '両方')
                    $retdata[$row[0]] = "$row[1]";
                break;
            default:
                $retdata[$row[0]] = "$row[1]";
                break;
        }
    }
    return $retdata;
}
function get_kaisuu_list(){
    $list = array();
    for($i=200;$i>0;$i--){
        $list[$i] = $i.'階';
    }
    $list[0] = 'グランドフロア';
    for($i=-1;$i>=-50;$i--){
        $list[$i] = '地下'.(-$i).'階';
    }
    return $list;
}
function dec_to_60($deg){
    $ji = floor($deg);
    $hun = floor(($deg-$ji)*60);
    $byou = (($deg-$ji)*60-$hun)*60;
    return sprintf("%d%02d%05.2f",$ji,$hun,$byou);
}
function chk_item($k,$v,$data){
    $required_item = array('name','administrator','longitude','latitude','horizontal_accuracy','level_code','middle_floor','media','accuracy_reliability','oprrlb','format_version_code','point_type_code','observation_date');
    $error = '';
    if(in_array($k,$required_item) && $v == '')
        return "必須項目です";
    if($k=='name'){
        if(mb_strwidth($data['name'])>200){
            $error .= "名称が長すぎます。\n";
        }
    }
    if($k=='administrator'){
        if(mb_strwidth($data['administrator'])>200){
            $error .= "施設管理者が長すぎます。\n";
        }
    }
    if($k == 'longitude'){
        if(!is_numeric($data['longitude'])||$data['longitude']>180||$data['longitude']<0)
            $error .= "経度が不正です\n";
        if(!is_numeric($data['latitude'])||$data['latitude']>90||$data['latitude']<0)
            $error .= "緯度が不正です\n";
        if(!$data['horizontal_accuracy'])
            $error .= "測定精度が未入力です\n";
        if(!$data['accuracy_reliability'])
            $error .= "測定精度の信頼度が未入力です\n";
    }
    if($k=='observation_date' && !empty($v)){
        if(date('Ymd',strtotime($data['observation_date'])) != $data['observation_date']){
            $error .= "位置情報の基準日が不正な値です\n";

        }
    }
    if($k=='level_code' && !empty($v)){
        if(!is_numeric($data['level_code']) or $data['level_code'] < -50 or $data['level_code'] > 200 and $data['level_code'] < 989 or $data['level_code'] > 999) {
            $error .= "階数が不正な値です\n";
        }
    }
    if($k=='serial'){
        if(mb_strwidth($data['serial'])>24){
            $error .= "整理番号が長すぎます。\n";

        }
    }
    if($k=='base_date' && !empty($v)){
        if(date('Ymd',strtotime($data['base_date'])) != $data['base_date']){
            $error .= "位置情報の基準日が不正な値です\n";

        }
    }
    if($k=='altitude'){
        if($v>9000 || ($v && !is_numeric($v)) || strlen($v)>16){
            $error .= "標高が不正な値です\n";
        }

    }
    if($k=='city_code'){
    }
    if($k=='address'){
        if(mb_strwidth($data['address'])>200){
            $error .= "住所が長すぎます。\n";
        }
    }
    if($k=='feature'){
        if(mb_strwidth($v)>400){
            $error .= "属性が長すぎます。\n";
        }
    }
    if($k=='ucode_url' && !empty($v)){
        if(!preg_match('/^[!-~]+$/',$v)){
            $error .= "詳細URLが不正です。\n";
        }elseif(mb_strwidth($v)>300){
            $error .= "詳細URLが長すぎます。\n";
        }
    }
    if($k=='tag_id' && !empty($v)){
        if(!preg_match('/^[0-9A-Za-z]*$/',$v)){
            $error .= "tag_idが不正です。\n";
        }elseif(mb_strwidth($v)>40){
            $error .= "tag_idが長すぎます。\n";
        }

    }
    if($k=='remarks'){
        if(mb_strwidth($v)>400){
            $error .= "備考が長すぎます。\n";
        }
    }
    if($k=='expr' && !empty($v)){
        if(!is_numeric($v) || $v<0 || $v>99){
            $error .= "場所情報の表現の種類が不正です。\n";

        }
    }
    if($k=='nonblinfo'){
        if(mb_strwidth($v)>400){
            $error .= "緯度経度以外の場所指定情報が長すぎます。\n";

        }
    }
    return $error;
}
?>