ホーム » ブログ » メモ20180926
このエントリーをはてなブックマークに追加
@2018/09/26

スポンサーリンク
メモ20180926

<?php
/** tide.php
 * 潮位・月齢を計算
 *
 * @動作環境	PHP 5/7
 * @参考URL		https://www.pahoo.org/e-soul/webtech/php02/php02-51-01.shtm
*/
// ================================================================初期化処理 
define('INTERNAL_ENCODING', 'UTF-8');
mb_internal_encoding(INTERNAL_ENCODING);
mb_regex_encoding(INTERNAL_ENCODING);

//jqPlotのあるフォルダ
define('JQPLOT_JS', './js/plugins/jquery/jqplot/');
define('JQPLOT_CSS', './css/plugins/jquery/jqplot/');
//月の満ち欠け画像ファイルの場所
define('MOONAGE', './moon/');
//プログラム・タイトル
define('TITLE', '潮位・月齢を計算');
//リファラ・チェック(直リン防止用;空文字ならチェックしない)
//define('REFER_ON', 'www.benri.jp');//TODO 要修正
define('REFER_ON', '');
//リリース・フラグ(公開時にはTRUEにすること)
define('RELEASE_FLAG', FALSE);//TODO 要修正
//潮位表:計算期間(日)の初期値
define('INTERVAL_DEF', 7);
//潮位グラフ:計算期間(日)の初期値
define('INTERVAL_GRAPH_DEF', 5);
//潮位グラフのプロット間隔(日)
define('INTERVAL_GRAPH', 0.02);
//潮位グラフの名前
define('GRAPH_TIDE', 'jqPlot_tide');
//観測地点の初期値
define('LOCATION_DEF', 'TK'); //東京
define('LONGITUDE_DEF', 139.767);
define('LATITUDE_DEF',  35.65);
//日本標準時(世界時との差異時間)
define('JST', +9);
//月齢計算時刻
define('MOONAGE_HOUR', 21);
//暦・潮位計算クラス:include_pathが通ったディレクトリに配置
require_once('benriCalendar.php');

//====================================================================================サブルーチン
/**
 * エラー処理ハンドラ
*/
function myErrorHandler ($errno, $errmsg, $filename, $linenum, $vars) {
	echo "Sory, system error occured !";
	exit(1);
}
error_reporting(E_ALL);
if (RELEASE_FLAG)	$old_error_handler = set_error_handler('myErrorHandler');

//リファラ・チェック
if (REFER_ON != '') {
	if (isset($_SERVER['HTTP_REFERER'])) {
		$url = parse_url($_SERVER['HTTP_REFERER']);
		$res = ($url['host'] == REFER_ON) ? TRUE : FALSE;
	} else {
		$res = FALSE;
	}
} else {
	$res = TRUE;
}
if (! $res) {
	echo "benri.jpのみ利用可能なサービス !";
	exit(1);
}

//====================================================================================メイン・プログラム

//--------------------------------------------------オブジェクト生成
$pc  = new benriCalendar(); //暦計算クラス
$bt  = new benriTide(); //潮位計算クラス
if ($bt->iserror()) {
	echo $bt->geterror();
	exit(1);
}
//--------------------------------------------------関数・変数・定数宣言
$msg = $errmsg = $html = '';

$displayFormat = array(
	'createTideTable'  => array('title'=>'潮位表', 'checked'=>'checked'),
	'createTideGraph'  => array('title'=>'潮位グラフ', 'checked'=>'')
);

//--------------------------------------------------requestパラメータ
$year      = getParam('year',		FALSE, date('Y'));
$month     = getParam('month',		FALSE, date('n'));
$day       = getParam('day',		FALSE, date('d'));
$interval  = getParam('interval',	FALSE, INTERVAL_DEF);
$station   = getParam('station',	FALSE, LOCATION_DEF); //地点記号
$longitude = getParam('longitude',	FALSE, LONGITUDE_DEF); //経度
$latitude  = getParam('latitude',	FALSE, LATITUDE_DEF); //緯度
$height    = getParam('height',		FALSE, 0.0); //観測地の標高
$response_type = getParam('rt', 	FALSE, 'html'); //返すコンテンツの種類
$calcFn 		= getParam('disp',	FALSE, 'createTideTable'); //潮位表orグラフ
$response_mode 	= getParam('rm',	FALSE, 'page'); //page:ページ単位のHTMLコード lite:部品htmlのみ

//--------------------------------------------------requestパラメータ計算・加工
//---観測点が存在の場合、経緯度取得
$items = array();
if ($bt->getLocation($station, $items) == TRUE) {
	if ($bt->iserror()) {
		$errmsg = $bt->geterror();
	} else {
		$longitude = $items['longitude'];
		$latitude  = $items['latitude'];
		$query = $items['prefecture'] . $items['address'];
	}
}

//--------------------------------------------------計算後のパラメータ
$params = array(
	'year'			=> $year,
	'month'			=> $month,
	'day'			=> $day,
	'interval'		=> $interval,
	'station'		=> $station,
	'longitude'		=> $longitude,
	'latitude'		=> $latitude,
	'height'		=> $height
);

//--------------------------------------------------結果を返す

//--------------------------htmlをレスポンスの場合
if($response_type == 'html') {
	$js_code = '';

	//--(潮位表・潮位グラフ)表示形式をセット
	setDisplayFormat($calcFn);
	
	//--潮位・月齢を計算
	$calcFn($bt, $pc, $params, $js_code, $html, $errmsg);

	//--HtmlHeaderコードを取得
	$HtmlHeader = createHtmlHeader();
	
	//--HtmlBodyコードを取得
	$HtmlBody = createHtmlBody($html, $errmsg);
	
	//--HtmlFooterコードを取得
	$HtmlFooter = createHtmlFooter();
	
	//--page:ページ単位のHTMLコード
	if ($response_mode == 'page') {
		echo $HtmlHeader;
		echo $HtmlBody;
		echo $HtmlFooter;
	//--lite:tide情報HTMLコードのみ
	} else {
		echo $html;
	}

//--------------------------jsonをレスポンスの場合	
} else if($response_type == 'json') {

//--------------------------xmlをレスポンスの場合	
} else if($response_type == 'xml') {

//--------------------------上記以外のをレスポンスの場合、エラー処理へ	
} else {
	echo "レスポンスタイプ指定エラー";
	exit(1);
}

$bt  = NULL;
$pc  = NULL;
//====================================================================================メイン・プログラム END







//====================================================================================メソッド
/**
 * 指定したボタンが押されてきたかどうか
 * @param	string $btn  ボタン名
 * @return	bool TRUE=押された/FALSE=押されていない
*/
function clickButton($btn) {
	if (isset($_GET[$btn]) && $_GET[$btn] != '')	return TRUE;
	if (isset($_POST[$btn]) && $_POST[$btn] != '')	return TRUE;
	return FALSE;
}

/**
 * 指定したパラメータを取り出す
 * @param	string $key  パラメータ名(省略不可)
 * @param	bool   $auto TRUE=自動コード変換あり/FALSE=なし(省略時:TRUE)
 * @param	mixed  $def  初期値(省略時:空文字)
 * @return	string パラメータ/NULL=パラメータ無し
*/
function getParam($key, $auto=TRUE, $def='') {
	if (isset($_GET[$key]))		$param = $_GET[$key];
	else if (isset($_POST[$key]))	$param = $_POST[$key];
	else							$param = $def;
	if ($auto)	$param = mb_convert_encoding($param, INTERNAL_ENCODING, 'auto');
	return $param;
}

/**
 * checkedされている処理を検索する
 * @return	string 選択された関数名/FALSE=checkedされている処理がない
*/
function getDisplayFormat() {
	global $displayFormat;

	foreach ($displayFormat as $key=>$val) {
		if ($val['checked'] == 'checked')	return $key;
	}
	return FALSE;
}

/**
 * 処理をchekedする
 * @param	string $func 処理関数名
 * @return	bool TRUE/FALSE
*/
function setDisplayFormat($func) {
	global $displayFormat;

	$old = getDisplayFormat();
	if ($func != FALSE) {
		$displayFormat[$old]['checked'] = '';
	}
	$displayFormat[$func]['checked'] = 'checked';

	return TRUE;
}

/**
 * 潮位表:潮位・月齢を計算する
 * @param	benriTide $bt  潮位計算クラス
 * @param	benriCalendar $pc  暦計算クラス
 * @param	array  $inputs 計算用パラメータ
 * @param	array  $items  計算結果格納用配列
 * @param	array  $locs   地点情報格納用配列
 * @param	string $errmsg エラーメッセージ格納用;エラーなければ空文字
 * @return	bool TRUE:計算成功/FALSE:失敗
*/
function calcTideTable($bt, $pc, $params, &$items, &$locs, &$errmsg) {
	//地点を設定
	$bt->setLocation($params['station']);
	if ($bt->iserror())	return FALSE;

	//地点を取得
	$bt->getLocation($params['station'], $locs);
	if ($bt->iserror())	return FALSE;

	//月齢・潮位を計算
	$res = TRUE;
	$jd = $pc->Gregorian2JD($params['year'], $params['month'], $params['day'], 0, 0, 0);
	for ($i = 0; $i < $params['interval']; $i++) {
		$arr = array();
		list($year, $month, $day, $hour, $min, $sec) = $pc->JD2Gregorian($jd);
		$yb = $pc->getWeekString($year, $month, $day);
		$items[$i]['dt'] = sprintf("%04d-%02d-%02d(%s)", $year, $month, $day, $yb);
		$items[$i]['moonage'] = $pc->moon_age($year, $month, $day, MOONAGE_HOUR, 0, 0);
		$moonmeridian = $pc->moon_time(2, $params['longitude'], $params['latitude'], $params['height'], $year, $month, $day);
		$moonmeridian = ($moonmeridian == FALSE) ? '---' : $pc->day2hhmm($moonmeridian);
		$items[$i]['tide'] = (preg_match('/([0-9]+):([0-9]+)/', $moonmeridian, $arr) > 0) ? $pc->tide($year, $month, $day, $arr[1], $arr[2], 0) : '';
		unset($arr);

		$arr = array();
		$bt->tide_day($params['station'], $year, $month, $day, $arr);
		//満潮
		for ($j = 0; $j < 4; $j++) {
			if (isset($arr['high'][$j])) {
				$items[$i]['high'][$j]['hhmm']  = $arr['high'][$j]['hhmm'];
				$items[$i]['high'][$j]['lev']   = sprintf("%d", $arr['high'][$j]['lev']);
				$items[$i]['high'][$j]['align'] = 'text-align:right;';
			} else {
				$items[$i]['high'][$j]['hhmm']  = '*';
				$items[$i]['high'][$j]['lev']   = '*';
				$items[$i]['high'][$j]['align'] = 'text-align:center;';
			}
		}
		//干潮
		for ($j = 0; $j < 4; $j++) {
			if (isset($arr['low'][$j])) {
				$items[$i]['low'][$j]['hhmm']  = $arr['low'][$j]['hhmm'];
				$items[$i]['low'][$j]['lev']   = sprintf("%d", $arr['low'][$j]['lev']);
				$items[$i]['low'][$j]['align'] = 'text-align:right;';
			} else {
				$items[$i]['low'][$j]['hhmm']  = '*';
				$items[$i]['low'][$j]['lev']   = '*';
				$items[$i]['low'][$j]['align'] = 'text-align:center;';
			}
		}
		$jd++;
	}

	return $res;
}

/**
 * 潮位表:表示用HTMLを作成
 * @param	benriTide     $bt      潮位計算クラス
 * @param	benriCalendar $pc      暦計算クラス
 * @param	array         $params  計算用パラメータ
 * @param	string        $js      スクリプト格納用
 * @param	string        $html    HTML格納用
 * @param	string        $errmsg  エラーメッセージ格納用
 * @return	bool TRUE:成功/FALSE:失敗
 * @return	表示用HTML
*/
function createTideTable($bt, $pc, $params, &$js, &$html, &$errmsg) {
	$js = $html = '';
	$items = array();
	$locs  = array();
	if (calcTideTable($bt, $pc, $params, $items, $locs, $errmsg) == FALSE)	return FALSE;

	$hour = MOONAGE_HOUR;
	$html =<<< EOD
<table class="Tide--table">
<caption>{$locs['title']}({$locs['prefecture']}{$locs['address']})</caption>
<tr><th rowspan="2">年月日</th><th rowspan="2">月齢<br /><span style="font-size:small; font-weight:normal;">{$hour}時</span></th><th rowspan="2">潮</th><th colspan="8">満潮</th><th colspan="8">干潮</th></tr>

EOD;
	$html .= "<tr>";
	for ($j = 0; $j < 8; $j++) {
		$html .= "<th class=\"index\">時刻</th><th class=\"index\">潮位<br />(cm)</th>";
	}
	$html .= "</tr>
";
	foreach ($items as $item) {
		$html .= sprintf("<tr><td>%s</td><td>%.1f</td><td>%s</td>", $item['dt'], $item['moonage'], $item['tide']);
		for ($j = 0; $j < 4; $j++) {
			$html .= sprintf("<td>%s</td><td style=\"%s\">%s</td>", $item['high'][$j]['hhmm'], $item['high'][$j]['align'], $item['high'][$j]['lev']);
		}
		for ($j = 0; $j < 4; $j++) {
			$html .= sprintf("<td>%s</td><td style=\"%s\">%s</td>", $item['low'][$j]['hhmm'], $item['low'][$j]['align'], $item['low'][$j]['lev']);
		}
		$html .= "</tr>
";
	}
	$html .= "</table>
";

	return TRUE;
}

/**
 * 潮位グラフ:潮位・月齢を計算する
 * @param	benriTide $bt  潮位計算クラス
 * @param	benriCalendar $pc  暦計算クラス
 * @param	array  $params 計算用パラメータ
 * @param	array  $items  潮位計算結果格納用配列
 * @param	array  $moons  月齢計算結果格納用配列
 * @param	array  $locs   地点情報格納用配列
 * @param	string $errmsg エラーメッセージ格納用;エラーなければ空文字
 * @return	bool TRUE:計算成功/FALSE:失敗
*/
function calcTideGraph($bt, $pc, $params, &$items, &$moons, &$locs, &$errmsg) {
	//地点を設定
	$bt->setLocation($params['station']);
	if ($bt->iserror())	return FALSE;

	//地点を取得
	$bt->getLocation($params['station'], $locs);
	if ($bt->iserror())	return FALSE;

	$res = TRUE;

	//潮位を計算
	$jd = $pc->Gregorian2JD($params['year'], $params['month'], $params['day'], -JST, 0, 0);
	$n = $params['interval'] / INTERVAL_GRAPH;
	for ($i = 0; $i < $n; $i++) {
		list($year, $month, $day, $hour, $min, $sec) = $pc->JD2Gregorian($jd + JST / 24);
		$items[$i]['dt'] = sprintf("%04d/%02d/%02d %02d:%02d", $year, $month, $day, $hour, $min);
		list($year, $month, $day, $hour, $min, $sec) = $pc->JD2Gregorian($jd);
		$bt->sun_moon($year, $month, $day);
		$items[$i]['tlevel'] = $bt->tide_level($year, $month, $day, $hour, $min);
		$jd += INTERVAL_GRAPH;
	}

	//月齢を計算
	$height = 0;		//標高0メートルを仮定
	$n = $params['interval'];
	$jd = $pc->Gregorian2JD($params['year'], $params['month'], $params['day'], 0, 0, 0);
	$i = $d = 0;
	while ($i < $n) {
		//月の南中時刻
		list($year, $month, $day, $hour, $min, $sec) = $pc->JD2Gregorian($jd);
		$moonmeridian = $pc->moon_time(2, $params['longitude'], $params['latitude'], $height, $year, $month, $day);
		if ($moonmeridian != FALSE) {
			$x = (double)$i + $moonmeridian;
			$moons[$i]['t']   = $d + $moonmeridian;
			$moons[$i]['age'] = $pc->moon_age($year, $month, $day, $moonmeridian * 24, 0, 0);
			$i++;
		}
		$jd++;
		$d++;
	}

	return $res;
}

/**
 * 潮位グラフ:表示用スクリプトおよびHTMLを作成
 * @param	benriTide     $bt      潮位計算クラス
 * @param	benriCalendar $pc      暦計算クラス
 * @param	array         $params  計算用パラメータ
 * @param	string        $js      スクリプト格納用
 * @param	string        $html    HTML格納用
 * @param	string        $errmsg  エラーメッセージ格納用
 * @return	bool TRUE:成功/FALSE:失敗
*/
function createTideGraph($bt, $pc, $params, &$js, &$html, &$errmsg) {
	$js = $html = '';
	$items = array();
	$moons = array();
	$locs  = array();
	if (calcTideGraph($bt, $pc, $params, $items, $moons, $locs, $errmsg) == FALSE)	return FALSE;

	$title = "{$locs['title']}({$locs['prefecture']}{$locs['address']})";
	$name   = GRAPH_TIDE;
	$width  = GOOGLE_MAPS_WIDTH;
	$height = GOOGLE_MAPS_HEIGHT;

	//潮位プロット・データ作成
	$data = '';
	foreach ($items as $item) {
		$data .= sprintf("['%s', %f], ", $item['dt'], $item['tlevel']);
	}

	//月齢データ作成
	$moon = '';
	$path = MOONAGE;
	foreach ($moons as $val) {
		$x = round(30 + (GOOGLE_MAPS_WIDTH - 70) / $params['interval'] * $val['t']);
		$fname = sprintf("{$path}moon_%02d.png", round($val['age']));
		$moon .=<<< EOD
<img style="position:absolute; top:35px; left:{$x}px; width:40px; height:40px; z-index:999;" src="{$fname}" />

EOD;
	}

	$js =<<< EOD
$(function() {
	jQuery.jqplot('{$name}',
	[
		[ {$data} ]
	],
	{
		//タイトル
		title: {
			text: '{$title}',
			show: true,
			fontSize: '16px',
			textAlign: 'center',
			textColor: 'black'
		},
		//背景
		grid: {
            background: '#EEFFFF'
        },
        //グラフ
		seriesDefaults: {
			showLine: true,
			rendererOptions: { smooth: false },
			markerOptions: { size: 0 },
			color: 'blue',
		},
		//軸ラベル
		axes: {
			xaxis: {
				renderer: $.jqplot.DateAxisRenderer,
				tickOptions: { formatString: '%m/%d' },
				tickInterval: '1 days'
			},
			yaxis: {
				label: '潮位(cm)'
			}
		}
	}
	);
});

EOD;
	$html =<<< EOD
<div id="{$name}" style="width:{$width}px; height:{$height}px;">
{$moon}
</div>

EOD;

	return TRUE;
}


/**---------------------------------------------------------------------
 * 共通HTMLヘッダー
 * @string $html tide情報Htmlコード
 * @string $errmsg エラーメッセージ
 **--------------------------------------------------------------------**/
function createHtmlBody($html, $errmsg) {

	if ($errmsg != '') {
		$errmsg = "<p style=\"color:red;\">{$errmsg}</p>
";
	}
	
	$body =<<< EOT
<body>
{$errmsg}
<!-- tide情報Htmlコード Start -->
{$html}
<!-- //tide情報Htmlコード END -->
EOT;

	return $body;
	
}

/**---------------------------------------------------------------------
 * 共通HTMLヘッダ
 * @global string $HtmlHeader
 **--------------------------------------------------------------------**/
 
function createHtmlHeader() {
	$encode = INTERNAL_ENCODING;
	$title  = TITLE;
	$jqplot_js = JQPLOT_JS;
	$jqplot_css = JQPLOT_CSS;

$HtmlHeader =<<< EOD
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="{$encode}">
<title>{$title}</title>
<meta name="author" content="benri.jp" />
<meta name="copyright" content="benri.jp" />
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js"></script>
<link type="text/css" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/ui-lightness/jquery-ui.css" rel="stylesheet" />
<script src="{$jqplot_js}jquery.jqplot.min.js"></script>
<script src="{$jqplot_js}jqplot.dateAxisRenderer.js"></script>
<link rel="stylesheet" type="text/css" href="{$jqplot_css}jquery.jqplot.min.css" />
<style type="text/css">
.date-sunday	.ui-state-default {
	background-image: none;
	background-color: #FF0000;
	color: #FFFFFF;
}
.date-saturday	.ui-state-default {
	background-image: none;
	background-color: #0000FF;
	color: #FFFFFF;
}
.date-holiday0	.ui-state-default {
	background-image: none;
	background-color: #FF6666;
	color: #FFFFFF;
}
.date-holiday1	.ui-state-default {
	background-image: none;
	background-color: #FFCCCC;
	color: #000088;
}
table.Tide--table {
	margin-top: 20px;
	border-collapse: collapse;
}
th {
	border: 1px gray solid;
	padding: 4px;
	background-color: gainsboro;
	white-space: nowrap;
}
th.index {
	border: 1px gray solid;
	padding: 4px;
	background-color: gainsboro;
	font-size: small;
	font-weight: normal;
	white-space: nowrap;
}
td {
	border: 1px gray solid;
	padding: 4px;
	font-size: small;
	text-align: center;
	white-space: nowrap;
}
</style>

</head>

EOD;

	return $HtmlHeader;
}
 
/**---------------------------------------------------------------------
 * 共通HTMLフッタ
 * @global string $HtmlFooter
 **--------------------------------------------------------------------**/
function createHtmlFooter() {
$HtmlFooter =<<< EOD
</body>
</html>
EOD;
	return $HtmlFooter;

}

/*
** バージョンアップ履歴 ===================================================
 *
 * @version  3.0  2018/09/25  benri.jpに適用
 * @version  2.0  2018/09/15  潮位グラフ機能を追加
 * @version  1.0  2018/08/03
*/
?>

♪ 当記事がお役に立ちましたらシェアして頂ければ嬉しいです。
0人
このエントリーをはてなブックマークに追加


★ 当記事を閲覧の方は下記の【関連記事】も閲覧していました。

お名前:

 

EMAIL:

 

URL:

 

認証コード:

zanmai.net-safecode

 


※会員の方は認証コードを要らないから、新規登録をオススメ!

check