メモ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
*/
?>
♪ 当記事がお役に立ちましたらシェアして頂ければ嬉しいです。
zanmai @2016年03月31日
» ①②③④の順で設定できるはず。…