2018-12-23に更新

ピュアPHP+prototype.jsで無理やりリアルタイムチャットを作った

読了目安:14分

(Crieit アドベントカレンダー 23日目の記事ですね~)


こんにちは!まともな記事を書くのは初めての高校生 ウラル(@barley_ural)です。

2年半くらい前から、「スプランプ」というサイトで「スプラトゥーン」シリーズの二次創作Webサービスとかを色々作っています。

誰も知らないと思うので 作ったものを軽く紹介させて頂くと、

サーモンラン研究所
Splatoon2の新モード「サーモンラン」の次回のシフト(変則開催で、毎回様々に条件が変わるのです!)を画像付きでお知らせするTwitter botです。

サーモンランカレンダー
サーモンランのシフトの開催情報を、icsファイル(iCal形式のカレンダーデータ)でサーバーから配信し続けるサービスです。ほとんどの端末で使えます。カレンダーが勝手に更新されていくの面白いですよ。

イカ語翻訳
文章を架空言語「イカ語」に可逆変換できるネタアプリです。DBは一切使っていないのですが、#イカ語翻訳などにツイートされているテキストは全て原文に戻すことができ、不思議に思ってもらえたようです。この変な暗号化は、日本語ドメインでおなじみ「Punycode」の仕組みを改造して作りました。

みんなで大仏建立ボタン
これはSplatoonと関係ないです。2018年は「災」と言われるように、不幸が多かったので、みんなで架空の役職をこなすことで、大仏が完成していくというクソアプリです。本題のサービスの開発の合間に、MySQLの限界を試してみたかった(???)のと、Ajaxで遊んでみたかったので作りました。

本題

タイトルの通り、ピュアPHP+prototype.jsで無理やりリアルタイムチャットを作りました。

「オクトチャット」

キャプチャ.png

Splatoon2の追加コンテンツ「オクト・エキスパンション」には「チャットログ」という、物語を掴む重要な手がかりとなる要素があるのですが、「もしこのチャットが現実にあったら…」と思って開発を始めました。
追加コンテンツ配信前の6月くらいから作り始めていますね。

【オクト】これは「チャットログ」。8号とアタリメの脱出劇を地上から見守っているテンタクルズのふたりが暇つぶしに作ったチャットルーム、その履歴を見ることができる。他愛のない会話の中から、ヒメとイイダ、そしてアタリメ司令の人となりを知ることができそうだ。 pic.twitter.com/GurNFOhT9M

— Splatoon(スプラトゥーン) (@SplatoonJP) 2018年5月4日

開発

オクトチャットでは、Prototype以外にフレームワークを使いませんでした。
と、いうより、使い方が分からず…。
ええ、そうです。
ここにいるのはPHPしか使ったことがない無職の個人開発者。
綺麗なコードも流行りの技術も知ったもんか!
作りたいものを作るためなら手順なんて知ったもんか!!
という流れで、JavaScriptもPHPのフレームワークも使ったことがない人がチャット作りを始めたわけです。

仕組み

PHPでリアルタイムチャットを実現するなら、流れる画面を実現するため、要素の中に別のPHPファイルを表示して、一定時間で更新すれば行けそうですね。
尋常じゃないペースでDBを叩くことになりますが、、、そこは見ぬふりで。

PHPを一定時間で更新して要素に反映させるのはどうすればいいか。
iframeの中に定期的にリフレッシュするページを埋め込めば行けそうだけど、ちょっと気持ち悪いですし。

で、調べたら出てきたのが「Prototype JavaScript Framework」でした。
2006年公開。最後のバージョンが2015年。
ヤバそうですね。使いましょう。


…で、これが結構使いやすかったのです。
Prototype.jsで使えるAjaxの機能は大きく2つ。

・定期更新

//事前にファイルを読み込みます
<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.3.0/prototype.js"></script>

<script>
new Ajax.PeriodicalUpdater(
    'show', // 返り値を挿入する id を指定する
    'log.php', // 非同期通信を行いたいURL
    {
    method: 'get',
    frequency: 3 // 何秒毎に通信を行うかを指定する
    }
);
</script>

・イベント更新

new Ajax.Updater( 'show', 'log.php', {method: 'get'});

使い方は、上述が書かれた状態で、id = "show" をHTMLにタグに書いてあげると、そのタグの内側に 読み込ませたページの中身がぶち込まれます。

あとは内側に表示するPHPファイルとその入れ物となるページを用意するだけです。


次に、投稿処理を考えました。
同期通信であればformとinputで送信するところですが、このAjaxモドキではどう実現したものか。
***
実は、普通にformとinputを使いました。ただそのままだと送信時に画面が遷移してしまうので、ここでiframeを使いました。

<form accept-charset="UTF-8" method="post" action="post.php" target="ipost">
<input name="write" type="text" id="form">
</form>

<iframe name="ipost" height="0" width="0" style="display:none"></iframe>

これは、formのターゲット先にiframeを指定することで、画面の遷移先がiframeに表示されるという仕組みです。
ただし、iframeはdisplay:none;にしてるから表示されませんし、そもそもレスポンスも返していません。

これで上手くいくかと思いきや、実はこのままでは送信したあとも入力中の内容は消えません。それでは困るので、jsでキーボードの「Enter」が押されるか、送信ボタンが押されたらフォームの中身が空っぽになるようにします。

document.onkeydown = function (e){
    var key_code = e.keyCode;
    if(key_code == 13){
        setTimeout(function() {
            document.getElementById('form').value = '';
        },30);
    }
}

setTimeoutで少し待機しているのは、送信中に空っぽにならないようにするためです。
実際はここにさらに
・フォーカスの解除
・更新処理(押した瞬間に投稿が出てくると嬉しいので)
・スクロール処理
があったりします。


で、わちゃわちゃしたら完成しました。Cookieをフル活用したログインの仕組みだとか、本当はもっともっとたくさん技術的に面白い部分があって、きっと大人はやらないだろうな~みたいなぶっとんだ内容をいっぱい書きたいんですが、眠りたいのと時間が足りない(これ書いてるの朝4時…)のとで、また後日書かせてください…。

そういえば、CSSは全部自分で書きました。ゲームの中の世界観自体が1980年代~2000年代のイメージだったので、そういう部分も考えてゲーム本編に寄せつつデザインしました。


全然関係ない話をしますけど、二次創作サイトって需要の割に供給が少ないので、やりがいがあるしとても楽しいですよ。
出尽くした感の溢れる世の中の需要を発掘するのも楽しいですが、疲れてきたら別の趣味と絡めて遊んでみるの、けっこう良いかもしれません。

これから

ほとんど同じ仕様で、最新の技術を使って作り直した姉妹版サービスをいつか作ろうと思っています。
技術書典で「初心者でも大丈夫!! lonicとFirebaseでゼロからはじめるアプリ開発」って本を買ったので、頑張れば行けるんじゃないかな…?

これから2

オクトチャットはまだまだやりたいことが山のように残っています。
自動返信するbotだとか、そのbotのAPIを作ってみんなが使えるようにしたりとか、パクられたくないから言えない秘密の機能とか。
そういう拡張性(仕様変更への柔軟さ)を考えて設計したし、これからも楽しく作ることを目標に頑張りたいです。
今回はちょっと開発期間が長くなりすぎて途中で鬱っぽくなりました。

追記:公開したからなんか元気になりました!!!あらゆるモチベがモチモチして弾けそうな気分です!!ひゃっほい!!!
Splatoon2を遊んだことある方はもちろん、知らない方でも十分楽しめるようにしっかりと作りました!
気軽に遊びに来てもらえたら嬉しいですー!
オクトチャット


明日はgeneさんです!


ウラル

作るの大好き|楽しいサービスでざいなー|ナモすけ@dnm_b サーモンラン研究所@salmon_lab 推し@look_cookie7|KDN11th(高2) とぅーにー|任天堂+PHP+創作+バイオリン+最近ピアノ

Crieitはβバージョンで開発中です。進捗は公式Twitterアカウントをフォローして確認してください。 興味がある方は是非記事の投稿もお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

関連記事

コメント