質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

2381閲覧

タイマーを複数クライアントで共有できるWebアプリをつくりたい

sa-ku-ra

総合スコア3

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2021/09/11 02:02

タイマーを複数クライアントで共有できるWebアプリケーションを
PHP,JavaScript,MySQL等で作りたいと考えています。

イメージとしては、ある1つのWebクライアントがタイマーのスタートボタンを押すと
そのサーバーにアクセスしている他のWebクライアントのタイマーもカウントダウンが始まる、
というものです。

例えば、サーバーでタイマーを動かし、Ajaxで残り時間を受け取ることができれば
実現は可能なのでしょうか。

システム構成についてイメージがつかめておらず、
アドバイス等ありましたらご教授いただけますと幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2021/09/11 02:10

>例えば まずその思ったとおりにやってみては
guest

回答2

0

ベストアンサー

ふんわり原始的な方法で書いてみました。

MySQLではなく、ファイル./time.txtを作成してそこに保存してます。
ajaxでは残り時間ではなく、タイムアウトする時刻のようなもの(0と負値は意味が違う)を返しています。
ご参考までに。

※100msに1回APIを呼び出すので、実行するならローカル環境だけにしてください

ファイル: ./timer.html

html

1<!DOCTYPE html> 2<html lang="ja"> 3 4<head> 5 <meta charset="utf8"> 6 <title>timer</title> 7</head> 8<div> 9 <button id="toggle_button">toggle</button><span id="time"></span> 10</div> 11<script> 12 document.addEventListener('DOMContentLoaded', (ev) => { 13 async function update(toggle) { 14 const timeout = ( 15 await fetch(`./timer_api.php?toggle=${toggle}`) 16 .then(res => res.json()) 17 ).utcms_from1970; 18 const current = Date.now().valueOf(); 19 document.querySelector('#time').textContent = timeout !== 0 20 ? (timeout < 0 21 ? ((-timeout) / 1000).toFixed(2) 22 : (timeout > current 23 ? ((timeout - current) / 1000).toFixed(2) 24 : 'timeout!')) 25 : '-'; 26 } 27 document.querySelector('#toggle_button') 28 .addEventListener('click', (ev) => { 29 update(1); 30 }); 31 const intervalId = setInterval(() => { 32 update(0); 33 }, 100); 34 document.addEventListener('unload', (ev) => { 35 clearInterval(intervalId); 36 }); 37 }); 38</script> 39 40</html>

ファイル: ./timer_api.php

php

1<?php 2header("Content-Type: application/json; charset=UTF-8"); 3$FILENAME = "./time.txt"; 4$TIMER_IN_MS = 10000; 5 6function unixtime_in_ms() 7{ 8 return round(microtime(true) * 1000); 9} 10 11$toggle = filter_input(INPUT_GET, "toggle"); 12 13if (file_exists($FILENAME)) { 14 $time = intval(file_get_contents($FILENAME)); 15} else { 16 $time = 0; 17} 18 19if ($toggle) { 20 if ($time > 0) { 21 $time = $time - unixtime_in_ms(); 22 if ($time > 0) { 23 $time = -$time; 24 } else { 25 $time = 0; 26 } 27 } else if ($time < 0) { 28 $time = unixtime_in_ms() - $time; 29 } else { 30 $time = unixtime_in_ms() + $TIMER_IN_MS; 31 } 32 file_put_contents($FILENAME, $time, LOCK_EX); 33} 34 35echo json_encode(["utcms_from1970" => $time]);

(追記1)
状態遷移図書いてみました。
イメージ説明
teratailではsvg使えないみたいなので、↑はPNGですが、元は↓のSVGです。

svg

1<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="151px" preserveAspectRatio="none" style="width:1173px;height:151px;background:#FFFFFF;" version="1.1" viewBox="0 0 1173 151" width="1173px" zoomAndPan="magnify"><defs><filter height="300%" id="flbkmc7f8q21n" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><ellipse cx="74" cy="16" fill="#000000" filter="url(#flbkmc7f8q21n)" rx="10" ry="10" style="stroke:none;stroke-width:1.0;"/><g id="初期状態"><rect fill="#FEFECE" filter="url(#flbkmc7f8q21n)" height="50.2656" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="134" x="7" y="87"/><line style="stroke:#A80036;stroke-width:1.5;" x1="7" x2="141" y1="113.2969" y2="113.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="56" x="46" y="104.9951">初期状態</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="114" x="12" y="129.4355">(0)タイマ動いてない</text></g><g id="タイマ動作中"><rect fill="#FEFECE" filter="url(#flbkmc7f8q21n)" height="50.2656" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="226" x="381" y="87"/><line style="stroke:#A80036;stroke-width:1.5;" x1="381" x2="607" y1="113.2969" y2="113.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="84" x="452" y="104.9951">タイマ動作中</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="206" x="386" y="129.4355">(正の整数)タイムアウトするUTC[ms]</text></g><g id="タイマ一時停止中"><rect fill="#FEFECE" filter="url(#flbkmc7f8q21n)" height="50.2656" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="322" x="837" y="87"/><line style="stroke:#A80036;stroke-width:1.5;" x1="837" x2="1159" y1="113.2969" y2="113.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="112" x="942" y="104.9951">タイマ一時停止中</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="302" x="842" y="129.4355">(負の整数)タイムアウトまでの残り時間を符号反転[ms]</text></g><!--MD5=[deaffe79b3ee21e90318abb8f74e4bd6] 2link *start to 初期状態--><path d="M74,26.013 C74,38.698 74,62.4093 74,81.5698 " fill="none" id="*start-to-初期状態" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="74,86.8404,78,77.8404,74,81.8404,70,77.8404,74,86.8404" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[d30e3980f9843bd17f71c4a10a4dad22] 3link 初期状態 to タイマ動作中--><path d="M141.32,124.398 C161.265,127.5283 183.199,130.4416 203.5,132 C260.143,136.3482 323.034,133.0252 375.773,127.9279 " fill="none" id="初期状態-to-タイマ動作中" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="380.844,127.4292,371.4953,124.3305,375.8681,127.9192,372.2793,132.292,380.844,127.4292" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="113" x="204.5" y="128.0669">update(toggle=1)</text><!--MD5=[f4aff1e9f12684eed04a722415600c46] 4link タイマ動作中 to 初期状態--><path d="M380.961,112 C306.382,112 210.899,112 146.381,112 " fill="none" id="タイマ動作中-to-初期状態" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="141.015,112,150.015,116,146.015,112,150.015,108,141.015,112" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="203" x="159.5" y="105.0669">update(toggle=1)[残り時間&lt;=0]</text><!--MD5=[528ec752e90b9c75408ab4ceb4f5b690] 5link タイマ動作中 to タイマ一時停止中--><path d="M607.107,112 C673.145,112 757.689,112 831.248,112 " fill="none" id="タイマ動作中-to-タイマ一時停止中" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="836.525,112,827.525,108,831.525,112,827.525,116,836.525,112" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="193" x="625.5" y="105.0669">update(toggle=1)[残り時間&gt;0]</text><!--MD5=[824f9ec85e989e5fe711c3d4bd431b3b] 6link タイマ一時停止中 to タイマ動作中--><path d="M836.858,129.3611 C782.151,133.2067 720.667,135.283 664.5,132 C647.648,131.015 629.906,129.4868 612.494,127.704 " fill="none" id="タイマ一時停止中-to-タイマ動作中" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="607.102,127.1429,615.6386,132.0547,612.075,127.6614,616.4683,124.0978,607.102,127.1429" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="113" x="665.5" y="128.0669">update(toggle=1)</text><!--MD5=[7650aa9408f90a6e04a087846f450031] 7@startuml 8[*] - -> 初期状態 9初期状態 : (0)タイマ動いてない 10初期状態-> タイマ動作中:update(toggle=1) 11タイマ動作中 : (正の整数)タイムアウトするUTC[ms] 12タイマ動作中->タイマ一時停止中:update(toggle=1)[残り時間>0] 13タイマ一時停止中 : (負の整数)タイムアウトまでの残り時間を符号反転[ms] 14タイマ一時停止中->タイマ動作中:update(toggle=1) 15タイマ動作中->初期状態:update(toggle=1)[残り時間<=0] 16@enduml 17 18PlantUML version 1.2021.11beta1(Unknown compile time) 19(GPL source distribution) 20Java Runtime: Java(TM) SE Runtime Environment 21JVM: Java HotSpot(TM) 64-Bit Server VM 22Default Encoding: UTF-8 23Language: en 24Country: US 25--></g></svg>

投稿2021/09/12 23:26

編集2021/09/13 21:07
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sa-ku-ra

2021/09/13 12:56

ご教示いただいたコードにより、複数のWebクライアントで同じタイマーを表示できるようになりました。ありがとうございました。 もしよろしければ、このタイマーをリセットする方法についてもお教えいただけませんでしょうか。何卒よろしくお願いいたします。
退会済みユーザー

退会済みユーザー

2021/09/13 20:37

リセットというのがよく分かりません。コードはあまり分かりやすく書いていませんし、解説もしていないので、これを修正する方法を説明するのはアレなのですが、基本的にはphpでAPIを追加して、それを呼び出すためのボタンをhtmlに追加して叩くのが一番簡単でしょうね。
sa-ku-ra

2021/09/14 01:17

説明不足で申し訳ありません。「リセット」は「初期状態に戻す」ことをイメージしておりました。
退会済みユーザー

退会済みユーザー

2021/09/14 01:19

では上の方法のとおりです。
sa-ku-ra

2021/09/16 15:44 編集

ご教示いただいたコード(timer_api.php)を自分なりに解読してみたのですが、以下のような認識で合っておりますでしょうか。 if ($toggle) {// time.txt($time, timeout)にはどんな値が入るか if ($time > 0) { $time = $time - unixtime_in_ms();//$time=残りの秒数【unixtimeから秒に変換】 if ($time > 0) { $time = -$time;//タイマー停止中のtime.txtの値は「残りの秒数($time)」 } else { $time = 0;//タイマー開始前(-, 初期値)のtime.txtの値は「0」 } } else if ($time < 0) { $time = unixtime_in_ms() - $time;//タイマー動作中のtime.txtの値は「(直前にボタンを押した時のunixtime)+(残りの秒数)」【unixtime表示】 } else { $time = unixtime_in_ms() + $TIMER_IN_MS;//タイマー終了時のtime.txtの値は「(直前にボタンを押した時のunixtime)+(タイマーの設定時間)」【unixtime表示】 } file_put_contents($FILENAME, $time, LOCK_EX); } また、以上のように考えると、初期状態に戻すためには、$time=0となるような新たなtoggleを作成すればよいということでしょうか。 間違いがありましたらご指摘いただきたく、何卒よろしくお願いいたします。
退会済みユーザー

退会済みユーザー

2021/09/16 16:34

すみませんが、質問は可能かどうかを尋ねられたので、可能である旨をお伝えするために書いたコードであり、解説もしておりません。申し訳ありませんが、前にも言ったとおりこのコードを元に何かをして頂きたいとは全く思っておりません。なので、どんなコードなのかを尋ねられるのはご容赦ください。 また質問するにしても、分からない部分のみをせいぜい1つくらいまで聞く形でないと、答えようがないというのが実情です。1行ずつ全て聞かないといけないのだとすると、まるで違う質問になってしまいます。 意地悪をしているわけではないのですが、私にも時間の都合があり、無制限にあなたに時間を使うことはできません。
sa-ku-ra

2021/09/18 05:04

ご指摘の通り、質問内容を逸脱しておりました。甘えてしまってすみませんでした。 ありがとうございました。
guest

0

要件がふわっとしていて(たとえばどの程度の精度を求めるのかなど)答えにくい質問な気がするのですが、あえて答えてみます。

例えば、サーバーでタイマーを動かし、Ajaxで残り時間を受け取ることができれば

実現は可能なのでしょうか。

おそらく可能だと思います。まずは非同期通信を用いて簡単なエコーサーバやリアルタイムチャットみたいな簡単なものから学習するといいと思います。その辺の知識が深まれば、タイマーを共有する方法のイメージも自ずとつかめてくると思いますよ。イメージがつかめないと言うことは、まだそれに手を付けるのが早いと言うことです。もう少し身近な目標地点を定めるといいと思います。

投稿2021/09/11 17:09

AbeTakashi

総合スコア4853

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問