LoginSignup
7
12

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-04-11

関連記事: 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で分かってくれよ」と言うだろうから、文字数が5文字以下なら頭に「00:」を付けるなどして 対応しよう。

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

日付と時刻

2017/04/11 19:34

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

2017/04/11 19:34:00

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

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

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

プレイヤー名

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

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

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

クリアタイム

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

Gazo

<<<<<<< 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を流そう。

-- 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

// 参考記事: 「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を流そう。

-- 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] 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();

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

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

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

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

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

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

クリアタイム
24:59'637

を、

CLEARTIME CLEARTIME_MS
24:59 637

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

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

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

インサート用のPHP

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

insert4.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 の第1引数 "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
// ヒント: このファイルのエンコーディングを 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

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

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

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

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

    //----------------------------------------
    // ID列以外が重複しているレコードは、1つを残して削除する
    //----------------------------------------
    $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
// ヒント: このファイルのエンコーディングを 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 の第1引数 "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列以外が重複しているレコードは、1つを残して削除する
    //----------------------------------------
    $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

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

こう書いておいて、

table.php

<div class="table_container">

テーブルを囲んでいたdivタグのstyle属性をclass属性に変更。
また、table.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で 書式指定は どうやるのだろうか。
  • ミリ秒も、3桁表示しないと 1 ミリ秒が '1 では 100ミリ秒になってしまう。

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

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

こんな風にした。

    // 連想配列を取得
    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 のケースもあった。

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

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

            // '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";
    }

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

7
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
12