グーグル・スプレッドシートをデータベースの入力フォームにしようぜ

関連記事: http://qiita.com/muzudho1/items/51f2ec976377625ff0f1

グーグル・スプレッドシート、PHP、MySQL の連携は前の記事で　でけたのだった。

# 今回やりたいこと

|日付と時刻|プレイヤー名|クリアタイム|
|---|---|---|
|2017/04/11 19:34|むすでょ|24:59'637|

なるほど、こんな仕様書は　飛んでくるだろう。
グーグル・スプレッドシートなら、これはできる……が　微妙に　つまづく。

## 難点

24:59'637 を PHP で「24:59」と「637」に分けると、24分59秒 637 ミリ秒ではなく、24時59分00秒 637 ミリ秒だ。分かる。
時:分 ではなく 分:秒 だろ、「それぐらい分かってくれよ」を PHP に組み込む必要があるだろう。しかし世の中には 分秒表記が無いのだろうか？

「「”」や「’」を使ったタイム表記の例を教えてくだ…」YAHOO!JAPAN 知恵袋
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q136411458

なるほど、角度表記を使えば 24'59''637 で　すっきり　している。でもお客さんは「24:59'637で分かってくれよ」と言うだろうから、文字数が５文字以下なら頭に「00:」を付けるなどして　対応しよう。

さくっと済ませて　何が問題なのかというと、１年後に「分:秒 ではなく 時:分 だろ、お前は　そんなことも分からんのか！」とメールが飛んでくる可能性があるんだが、現時点でも　１年前からメールが飛んでくる可能性はある。タイムマシン・キャッチボールでもするか。

## 日付と時刻

```
2017/04/11 19:34
```

これは　そのまま打ち込めばいい。
内部的には

```
2017/04/11 19:34:00
```

のような形式で持っているが、見た目は　入力したまま保たれるようだ。

ツールバーの「123」と描かれたボタンから
 [表示形式の詳細設計] - [表示形式の詳細設計] - [その他の日付や時刻の形式...]
と進むと、秒は要らない、とか　がっちり　指定できるんだが、

仕様書通りにぴっちり作ると　実践では顧客から１年後ぐらいに「余計なことをしてくれた」と言われる可能性がある。
“サブマリン余計なことをしてくれた”　を食らうぐらいなら
グーグル・スプレッドシートの「自動」な挙動に任せた平凡なつくりにしておこう。

## プレイヤー名

４文字しか入らない、といった制限を設けたいことがあるだろう。

マクロ（グーグル・アプリ・スクリプト）を書けば　入力を弾くことはできそうなんだが、
要件定義では　そんなことは　やって欲しくはなく、データベースを入れるときに　問答無用で　切り落せばよさそうだ。

PHP側で切り落とす　方法を　あとで記述する。

## クリアタイム

ツールバーの「123」と描かれたボタンから
 [表示形式の詳細設計] - [表示形式の詳細設計] - [その他の日付や時刻の形式...]
と進み、
最初から入っている　年、月、日は　クリックして削除を選び、
新たに　分、秒、ミリ秒　を追加すること。
このとき、ミリ秒は　精度を 1/10、1/100、1/1000 で指定できる。1/1000 を選ぶ。

![Gazo](https://github.com/muzudho/HowToMakeGame/blob/master/img/2017-04/20170411a6.png?raw=true)

<<<<<<< HEAD
=======
# テスト用のデータベースを用意しよう

MySQL で 1000ミリ秒単位のデータを持つ方法が分からなかった。
精度が　3ミリ秒……、と書かれている記事もあり、1ミリ秒じゃなきゃ　やだい。
別途、ミリ秒を持つ列を作った方がいいのか？

TIME_ATTACK テーブル

|DATE|PLAYER|CLEARTIME|CLEARTIME_MS|
|---|---|---|---|
|2017/04/11 19:34|むすでょ|24:59|637|

TIME_ATTACK テーブル 列定義

|列名|型|サイズ|
|---|---|---|
|DATE|DATE||
|PLAYER|VARCHAR|4|
|CLEARTIME|TIME||
|CLEARTIME_MS|SMALLINT||

PhpMyAdmin でフォーム入力していけばいい気もするんだが、SQLを流そう。

```sql
-- phpMyAdmin SQL Dump
-- version 4.0.10.15
-- http://www.phpmyadmin.net
--
-- ホスト: localhost
-- 生成日時: 2017 年 4 月 11 日 19:13
-- サーバのバージョン: 5.1.73
-- PHP のバージョン: 5.6.29

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- データベース: `★データベース名`
--

-- --------------------------------------------------------

--
-- テーブルの構造 `RENSYU_TIME_ATTACK`
--

CREATE TABLE IF NOT EXISTS `RENSYU_TIME_ATTACK` (
  `DATE` date NOT NULL,
  `PLAYER` varchar(4) NOT NULL,
  `CLEARTIME` time NOT NULL,
  `CLEARTIME_MS` smallint(6) NOT NULL COMMENT 'ミリ秒 0～999'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Qiita記事用';

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
```

データベースを選択してから、SQL メニューを選んで クエリーを貼り付けて[実行]ボタンを押す。

>>>>>>> EDIT_REQUEST
# POST送信

このプログラムは　前にも書いた。
グーグルスプレッドシートから [スコア送信] - [スコア送信実行] を選ぶと、スプレッドシートの内容をサーバー側に送るものだ。

参考記事: 「Tool] Google SpreadSheetでマクロを使って作業を効率化」http://www.yoheim.net/blog.php?q=20130412

```js
// 参考記事: 「Tool] Google SpreadSheetでマクロを使って作業を効率化」http://www.yoheim.net/blog.php?q=20130412

// 起動時処理
function onOpen() {
  // メニューバーにカスタムメニューを追加
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [
    {name : "スコア送信実行"  , functionName : "submitRanking"},
  ];
  spreadsheet.addMenu("スコア送信", entries);
}

// メニューから実行する
function submitRanking(){

  //----------
  // 定数
  //----------

  // ヘッダー、データの開始列（先頭が1）
  var HEADER_COLUMN_START_INDEX = 1;
  // ヘッダー行
  var HEADER_ROW_INDEX = 1;
  // データの開始行
  var DATA_ROW_START_INDEX = 2;


  
  // Bookやシートを取得する
  var sheet = SpreadsheetApp.getActiveSheet();
  var ss    = SpreadsheetApp.getActiveSpreadsheet();
  
  // ヘッダ情報を取得する
  var headers = [],
      headerColumnPos = HEADER_COLUMN_START_INDEX;
  while (true) {
    // sheet.getRangeでRangeオブジェクトを取得できます。
    var val = sheet.getRange(HEADER_ROW_INDEX, headerColumnPos++).getValue();
    if (!val) {break;}
    headers.push(val);
  }
  // ログ出力はこんな感じ。
  // ScriptエディタのメニューバーのView -> Logsで確認できます。 
  Logger.log(headers);
  
    
  // 1行ずつ読み込みます。
  var rowIndex = DATA_ROW_START_INDEX;
  var rowData = [];
  while (true) {
    
    // if no data, exit loop.
    var checkVal = sheet.getRange(rowIndex, 1).getValue();
    if (!checkVal) {
      break;
    }
    
    // cerate data row by row
    var columnPos = HEADER_COLUMN_START_INDEX;
    var valueObject = {};
    for (var i = 0, len = headers.length; i < len; i++) {
      var key   = headers[i];
      var value = sheet.getRange(rowIndex, columnPos++).getValue();
      valueObject[key] = value;
    }
    rowData.push(valueObject);
    
    // next row.
    rowIndex++;
  }
  
  // Logger.log(rowData);
    
  
  // JSObject to JSON
  var json = JSON.stringify(rowData);
  Logger.log(json);
  
  // POST送信のテスト
  var formData = {
    'datas': json
  };
  var options = {
   'method' : 'post',
   'payload' : formData
  };
  UrlFetchApp.fetch("http://★サイトアドレス/insert4.php", options);

  // メッセージボックスにJSONを表示して終了します
  Browser.msgBox(json);
}
```

# テスト用のデータベースを用意しよう

MySQL で 1000ミリ秒単位のデータを持つ方法が分からなかった。
精度が　3ミリ秒……、と書かれている記事もあり、1ミリ秒じゃなきゃ　やだい。
別途、ミリ秒を持つ列を作った方がいいのか？

RENSYU_TIME_ATTACK テーブル

|PLAY_DATE|PLAYER|CLEARTIME|CLEARTIME_MS|
|---|---|---|---|
|2017/04/11 19:34|むすでょ|24:59|637|

- 重複レコードを削除したかったので、あとでID列を増やした
- 列名に DATE は避けて PLAY_DATEとか適当に付けた

RENSYU_TIME_ATTACK テーブル 列定義

|列名|型|サイズ|
|---|---|---|
|PLAY_DATE|DATE||
|PLAYER|VARCHAR|4|
|CLEARTIME|TIME||
|CLEARTIME_MS|SMALLINT||

PhpMyAdmin でフォーム入力していけばいい気もするんだが、SQLを流そう。

```php
-- phpMyAdmin SQL Dump
-- version 4.0.10.15
-- http://www.phpmyadmin.net
--
-- ホスト: localhost
-- 生成日時: 2017 年 4 月 11 日 19:13
-- サーバのバージョン: 5.1.73
-- PHP のバージョン: 5.6.29

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- データベース: `★データベース名`
--

-- --------------------------------------------------------

--
-- テーブルの構造 `RENSYU_TIME_ATTACK`
--

CREATE TABLE IF NOT EXISTS `RENSYU_TIME_ATTACK` (
  `PLAY_DATE` date NOT NULL,
  `PLAYER` varchar(4) NOT NULL,
  `CLEARTIME` time NOT NULL,
  `CLEARTIME_MS` smallint(6) NOT NULL COMMENT 'ミリ秒 0～999'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Qiita記事用';

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
```

データベースを選択してから、SQL メニューを選んで クエリーを貼り付けて[実行]ボタンを押す。
これで　テーブルの準備はおっけ！

# サーバー側の PHP

## データを送信できたか確かめるためのページ

table1a1.php

```php
<?php
// 参考: 「[PHP] mysqli使い方まとめ（MySQL接続～SELECT実行まで）」 http://qiita.com/yasumodev/items/bd2ba476f31804d527d3

// mysqliクラスのオブジェクトを作成
$mysqli = new mysqli('localhost', '★DBユーザー名', '★パスワード', '★DB名');
if ($mysqli->connect_error) {
    echo $mysqli->connect_error;
    exit();
} else {
    $mysqli->set_charset('utf8');
}

// ここにDB処理いろいろ書く（後述）

// 完成済みのSELECT文を実行する
$query = 'SELECT PLAY_DATE, PLAYER, CLEARTIME, CLEARTIME_MS FROM RENSYU_TIME_ATTACK';
if ($result = $mysqli->query($query)) {
    // 連想配列を取得
    while ($row = $result->fetch_assoc()) {
        echo $row['PLAY_DATE'] . ', ' . $row['PLAYER'] . ', ' . $row['CLEARTIME'] . ', ' . $row['CLEARTIME_MS'] . '<br />' . "\n";
    }
    // 結果セットを閉じる
    $result->close();
}

// DB接続を閉じる
$mysqli->close();
```

開発中に確認するだけ用なんで、ぺぺっと作る。

## 長い文字列の末尾を、文字数で切り捨てるには？

```php
// 注意: 半角1文字は1、全角1文字は2 とカウントされる
$PLAYER         = mb_strimwidth( $datas[0]['プレイヤー名'], 0, 8, '', 'UTF-8' );
```

こんなので　いいのだろうか？
もっといいのがあった。

```php
// 4文字で切り落とし
$PLAYER         = mb_substr( $record['プレイヤー名'], 0, 4 );
```

## 文字をスプリットするには？

|クリアタイム|
|---|
|24:59'637|

を、

|CLEARTIME|CLEARTIME_MS|
|---|---|
|24:59|637|

に分けるにはどうすればいいのか？　PHPにはスプリット関数があるんだろうか？

```php
$clear_time     = $datas[0]['クリアタイム'];
$tokens = explode("'", $clear_time);
$CLEARTIME      = $tokens[0];
$CLEARTIME_MS   = $tokens[1];
```

こんなので　いいのだろうか？

## インサート用のPHP

下のコードは　だいぶ　サボっていて、１行目しか送信しない。 $datas[0] と書いてあるところを改造してほしい。あとで改造後のを載せる。

insert4.php

```php
<?php
// ヒント: このファイルのエンコーディングを UTF-8 BOM有り にすること。
// 参考  : http://qiita.com/yasumodev/items/bd2ba476f31804d527d3

if(isset($_POST['datas'])){
    $datas =json_decode( $_POST['datas'], true);

    // mysqliクラスのオブジェクトを作成
    $mysqli = new mysqli('localhost', '★DBユーザー名', '★パスワード', '★DB名');
    if ($mysqli->connect_error) {
        echo $mysqli->connect_error;
        exit();
    } else {
        $mysqli->set_charset("utf8");
    }

    // ここにDB処理いろいろ書く

    // ひな型をもとにステートメントハンドルを取得する
    $sql = "INSERT INTO RENSYU_TIME_ATTACK (PLAY_DATE, PLAYER, CLEARTIME, CLEARTIME_MS) VALUES (?, ?, ?, ?)";
    if ($stmt = $mysqli->prepare($sql)) {
        // 条件値をSQLにバインドする
        // bind_param の第１引数 "is" は後続のデータ型を表します。
        // i=integer、s=string、d=double、b=blob など。DATE型は s で良いみたいです。
        // また下記のように値を引数内に直書きすることはできません。
        // 誤）$stmt->bind_param("is", 123, "hanako");
        $PLAY_DATE      = $datas[0]['日付と時刻'];

        // 4文字で切り落とし
        $PLAYER         = mb_substr( $record['プレイヤー名'], 0, 4 );

        // 12:34'567 と入っていれば 12分34秒567ミリ秒 とする。12時34分ではない。
        $clear_time     = $datas[0]['クリアタイム'];
        $tokens = explode("'", $clear_time);
        $CLEARTIME      = $tokens[0];
        if(5==mb_strlen($CLEARTIME)){
            // 00:00 形式と予想して、頭に 00: を付けることで 00:00:00 にする
            $CLEARTIME = '00:' . $CLEARTIME;
        }
        $CLEARTIME_MS   = $tokens[1];

        // 注意: 第一引数で型の指定も忘れないこと
        $stmt->bind_param("sssi", $PLAY_DATE, $PLAYER, $CLEARTIME, $CLEARTIME_MS);

        // 実行
        $stmt->execute();

        $stmt->close();
    }

    // DB接続を閉じる
    $mysqli->close();
}
else
{
    echo 'error: post data not found.' . "\n";
}
```

?, ?, ?, ? の数を合わせたり、 "sssi" とか書いたりすることを忘れていることに　気づきにくかった。

# じゃあ、これを　タイムが短い順に表示するには？

table7.php

```php
<?php
// ヒント: このファイルのエンコーディングを UTF-8 BOM有り にすること。
// 参考: 「[PHP] mysqli使い方まとめ（MySQL接続～SELECT実行まで）」http://qiita.com/yasumodev/items/bd2ba476f31804d527d3
// 参考: 「mysqlユーザーのためのmysqliラッパー」http://qiita.com/taro_3000/items/f9db8f816cf3837b59b9
// 参考: 「PHPで自分のファイル名を取得する方法」http://negimemo.net/1705
// 参考: 「＜テーブル＞　　*　 テーブル・セルにスクロールバーをつける　*」http://kowaza.boo.jp/03table/table-07-0scroll.html

// mysqliクラスのオブジェクトを作成
$mysqli = new mysqli('localhost', '★DBユーザー名', '★パスワード', '★DB名');
if ($mysqli->connect_error) {
    echo $mysqli->connect_error;
    exit();
} else {
    $mysqli->set_charset("utf8");
}

// ここにDB処理いろいろ書く

//----------
// テーブル表示
//----------
$query = 'SELECT PLAY_DATE, PLAYER, CLEARTIME, CLEARTIME_MS FROM RENSYU_TIME_ATTACK ORDER BY CLEARTIME, CLEARTIME_MS DESC';
if ($result = $mysqli->query($query)) {
?>
<div style="height:90px; width:300px; overflow-y:scroll;">
<table>
<?php
    // 連想配列を取得
    while ($row = $result->fetch_assoc()) {
        echo '<tr><td>' . $row['PLAY_DATE'] . '</td><td>' . $row['PLAYER'] . '</td><td>' . $row['CLEARTIME'] . '</td><td>' . $row['CLEARTIME_MS'] . '</td></tr>' . "\n";
    }
    // 結果セットを閉じる
    $result->close();
?>
</table>
</div>
<?php
}
else
{
    echo 'error: query failuer.';
}

// DB接続を閉じる
$mysqli->close();
```

これでいける。

# とはいえ、スプレッド・シートに記入されている全行を　送信したいだろう

毎回、重複する　全行　を送信するのが　シンプルな実装だし、仕事とあらば　そんなプログラムでも組む。
その代わり MySQL は重複するレコードを　マージか、弾くか　してくれないだろうか？

「MySQLで重複する行を削除する」Qiita
http://qiita.com/aosho235/items/d748dcb6386d8ce75604

なんか　麺３玉スーパー特盛ラーメンを食べたあとに　胃袋から２玉吐き出せば　ラーメン１玉分食べたに等しい、と言った感じのツジツマの合わせ方だ。

ID 列があると　クエリー１回　で済むのか。じゃあ ID 列を付けよう。

```sql
ALTER TABLE  `RENSYU_TIME_ATTACK` ADD  `ID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST ;
```

insert4.php の DBを切断する前のあたりに追記。あとで全部載せる。

```php
    //----------------------------------------
    // ID列以外が重複しているレコードは、１つを残して削除する
    //----------------------------------------
    $query = "DELETE FROM RENSYU_TIME_ATTACK WHERE id NOT IN (SELECT min_id from (SELECT MIN(id) min_id FROM RENSYU_TIME_ATTACK GROUP BY PLAY_DATE, PLAYER, CLEARTIME, CLEARTIME_MS) tmp)";
    if ($result = $mysqli->query($query)) {
        // 成功時
        // 結果セットを閉じる
        $result->close();
    }
```

これでどうか？

# ヘッダーを除く、全行送信する

insert4.php

```php
<?php
// ヒント: このファイルのエンコーディングを UTF-8 BOM有り にすること。
// 参考: 「[PHP] mysqli使い方まとめ（MySQL接続～SELECT実行まで）」http://qiita.com/yasumodev/items/bd2ba476f31804d527d3
// 参考: 「MySQLで重複する行を削除する」http://qiita.com/aosho235/items/d748dcb6386d8ce75604

if(isset($_POST['datas'])){
    $datas =json_decode( $_POST['datas'], true);

    // mysqliクラスのオブジェクトを作成
    $mysqli = new mysqli('localhost', '★DBユーザー名', '★パスワード', '★DB名');
    if ($mysqli->connect_error) {
        echo $mysqli->connect_error;
        exit();
    } else {
        $mysqli->set_charset("utf8");
    }

    // ここにDB処理いろいろ書く

    foreach ($datas as &$record) {
        // ひな型をもとにステートメントハンドルを取得する
        $sql = "INSERT INTO RENSYU_TIME_ATTACK (PLAY_DATE, PLAYER, CLEARTIME, CLEARTIME_MS) VALUES (?, ?, ?, ?)";
        if ($stmt = $mysqli->prepare($sql)) {

            // 条件値をSQLにバインドする
            // bind_param の第１引数 "is" は後続のデータ型を表します。
            // i=integer、s=string、d=double、b=blob など。DATE型は s で良いみたいです。
            // また下記のように値を引数内に直書きすることはできません。
            // 誤）$stmt->bind_param("is", 123, "hanako");
            $PLAY_DATE      = $record['日付と時刻'];

            // 注意: 半角1文字は1、全角1文字は2 とカウントされる
            $PLAYER         = mb_strimwidth( $record['プレイヤー名'], 0, 8, '', 'UTF-8' );
            // 4文字で切り落とし
            $PLAYER         = mb_substr( $record['プレイヤー名'], 0, 4 );

            // 12:34'567 と入っていれば 12分34秒567ミリ秒 とする。12時34分ではない。
            $clear_time     = $record['クリアタイム'];
            $tokens = explode("'", $clear_time);
            $CLEARTIME      = $tokens[0];
            if(5==mb_strlen($CLEARTIME)){
                // 00:00 形式と予想して、頭に 00: を付けることで 00:00:00 にする
                $CLEARTIME = '00:' . $CLEARTIME;
            }
            $CLEARTIME_MS   = $tokens[1];

            // 注意: 第一引数で型の指定も忘れないこと
            $stmt->bind_param("sssi", $PLAY_DATE, $PLAYER, $CLEARTIME, $CLEARTIME_MS);

            // 実行
            $stmt->execute();

            $stmt->close();
        }
    }

    //----------------------------------------
    // ID列以外が重複しているレコードは、１つを残して削除する
    //----------------------------------------
    $query = "DELETE FROM RENSYU_TIME_ATTACK WHERE id NOT IN (SELECT min_id from (SELECT MIN(id) min_id FROM RENSYU_TIME_ATTACK GROUP BY PLAY_DATE, PLAYER, CLEARTIME, CLEARTIME_MS) tmp)";
    if ($result = $mysqli->query($query)) {
        // 成功時
        // 結果セットを閉じる
        $result->close();
    }

    // DB接続を閉じる
    $mysqli->close();
}
else
{
    echo 'error: post data not found.' . "\n";
}
```

3行、4行　程度では　全レコード送信しても　気にならない。
よし。

# 文字数で切り出し

「[PHP] 文字数単位で文字を切り出す」PHPちょこっとリファレンス
https://php.programmer-reference.com/php-mb_substr/

mb_strimwidth だと 全角1文字は2文字分のカウントをされるんだが、mb_substr を使うと 全角1文字も1文字カウントなのか？

# スタイルの外出し

table.css

```css
div.table_container
{
    display   : inline-block;
    height    : 285px;
    overflow-y: scroll;
}
```

こう書いておいて、

table.php

```php
<div class="table_container">
```

テーブルを囲んでいたdivタグのstyle属性をclass属性に変更。
また、table.php の末尾のデータベースを切断した後あたりに次のように書く。

```php
// DB接続を閉じる
$mysqli->close();

//----------------------------------------
// <body>部で後からスタイルシート読込指定
//----------------------------------------
?>
<script type="text/javascript">
    addOnload(function(){
        var linkElement = document.createElement( "link" );
        linkElement.setAttribute( "rel"  ,"stylesheet" );
        linkElement.setAttribute( "type" ,"text/css"   );
        linkElement.setAttribute( "href" ,"./table.css" );
        document.getElementsByTagName( "head" )[0].appendChild( linkElement );
    });

    // onloadイベントを追加する
    function addOnload(func)
    {
        try {
            window.addEventListener("load", func, false);
        } catch (e) {
            // IE用
            window.attachEvent("onload", func);
        }
    }
</script>
```

参考記事: 「EXORK.JP」http://exork.sakura.ne.jp/140806/?p=300
参考記事: 「ビジネスマンの徹底パソコン奮闘サイト」http://pcrice.blog129.fc2.com/blog-entry-11.html

# タイムの表示

現状、列の中身をそのまま表示しているので、タイムの表示が

|日付と時刻|クリアタイム|
|---|---|
|2017-04-11|01:26:00 747|

となってしまっている。本当は次のように表示したい。

|日付と時刻|クリアタイム|
|---|---|
|2017/04/11 23:42:30|1:26'747|

- PHPで　書式指定は　どうやるのだろうか。
- ミリ秒も、３桁表示しないと 1 ミリ秒が '1 では 100ミリ秒になってしまう。

「date」php
http://php.net/manual/ja/function.date.php

「DateTime クラスのまとめメモ」Qiita
http://qiita.com/re-24/items/c3ed814f2e1ee0f8e811

こんな風にした。

```php
    // 連想配列を取得
    while ($row = $result->fetch_assoc()) {

        $PLAY_DATE_1 = new DateTime( $row['PLAY_DATE'] );
        $CLEARTIME_1 = new DateTime( $row['CLEARTIME'] );

        // 「時:分:秒」を取得し、先頭が「00:」なら、それを省く
        $ji_fun_byo = $CLEARTIME_1->format('H:i:s');
        if(0===strpos($ji_fun_byo, '00:')){
            $ji_fun_byo = mb_substr( $ji_fun_byo, 3 );
        }

        echo '<tr><td>' . $PLAY_DATE_1->format('Y/m/d H:i') . '</td><td>' . $row['PLAYER'] . '</td><td>' . $ji_fun_byo . "'" . str_pad($row['CLEARTIME_MS'], 3, 0, STR_PAD_LEFT) . '</td></tr>' . "\n";
    }
```

参考: 「【PHP】文字列の一致や、文字列を含むかどうかを判定」http://thesaibase.com/php/strstr
参考: 「PHPで0埋めをする2つの方法- sprintf関数とstr_pad関数」http://wp.tech-style.info/archives/582

# 不具合の対応

00:00 だけでなく、 0:00 のケースもあった。

```php
            if(mb_strlen($CLEARTIME) < 6){
                // 00:00 または 0:00 形式と予想して、頭に 00: を付けることで 00:00:00 にする
```

じゃあ、データを入力する方も　こうか？

```php
            // '1 と入っていれば 1ミリ秒 ではなく 100ミリ秒
            $CLEARTIME_MS   = str_pad($tokens[1], 3, 0, STR_PAD_RIGHT);
```

あと前の記事なんだが、

```
$query = 'SELECT DISTINCT WEIGHT FROM TAMESI1 ORDER BY WEIGHT';
if ($result = $mysqli->query($query)) {
    if(0 < $result->num_rows){
        echo '<a href="./' . basename($_SERVER['PHP_SELF']) . '">全て</a> '. "\n";
    }
```

絞り込み条件を付けない場合のリンクも出しておきたい。