2016年お盆にLINEっぽいリアルタイムチャットをダサい技術で再現する。

ブログを書かなきゃ、ということで

  • 映画見ながら作ったので2時間ぐらい?
  • 最速のSqliteを永続化層に使用。
  • サーバーサイドはPHP
  • リアルタイムはポーリング方式

JavaScriptのスキルここ10年ぐらい進歩していない。残念なコードができた。

貼り付けていきます。

<?php
$name = "名無し";
if(isset($_COOKIE["name"])){
    $name = $_COOKIE["name"];
}
if(isset($_REQUEST["name"])){
    $name = $_REQUEST["name"];
}
?>
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,user-scalable=0">
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <!--[if lt IE 9]>
    <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
    <title>bandchat</title>
    <link rel="stylesheet" href="css/app.css?<?php echo time()?>" type="text/css" media="screen" />
    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>    
    <script>
      var NAME = '名無し';
      function getName(){
          if($("#name").val() != ""){
             NAME = $("#name").val();
          }
          return NAME;
      }
    </script>
    <script type="text/javascript" src="js/app.js?<?php echo time()?>"></script>
    <script type="text/template" id="me">
      <div class="me arrow-right">
        <h5>{name}</h5>
        <div>{content}</div>
        <div style="text-align:right;">{date}</div>
      </div>
    </script>
    <script type="text/template" id="other">
      <div class="other arrow-left">
        <h5>{name}</h5>
        <div>{content}</div>
        <div style="text-align:right;">{date}</div>
      </div>
    </script>
  </head>
  <body>
    <div id="main">
      <h1>おれらのLINE</h1>
      <div id="chat">
      </div>
      <div id="inputarea">
      <input id="name" value="<?php echo $name?>"/><br/>
<textarea rows="3" id="input">
</textarea>
        <button id="say">送信</button>
      </div>
    </div>
  </body>
</html>
var App = {
  load : function(cursor){
      $.ajax({
                 async:false,
                 dataType: "json",
                 url: "load.php",
                 data: {cursor:cursor},
                 success:function(data){
                     if(data.length > 0){
                         App._plot(data);
                     }
                 }
             });
  },
  refresh : function(){
    App.load(App._cursor);
  },
  say : function(){
     var content = $("#input").val();
     if("" == content){
         return;
     }
     var name = getName();
     var data = {name:name,content:content};
     $.ajax({
                async:false,
                dataType: "json",
                url : "say.php",
                data : data,
                success : function(json){
                   $("#input").val("");
                }
            });
     App.refresh();
  },
  _bottom : function(){
     setTimeout(function() {
         window.scroll(0,$(document).height());
     },0);
  },
  _cursor : 0,
  _data : "",
  _plot : function(data){
      var name = getName();
      for(var i=0,l=data.length;i<l;i++){
          if(name == data[i].name) {
              App._plot_(data[i],"me");
          } else {
              App._plot_(data[i],"other");
          }
          App._cursor = data[i].id;
      }
      $("#chat").append(App._data);
      App._data = "";
      App._bottom();
  },
  _plot_ : function(chat,kind){
      if(kind == "me"){
        var template = $("#me").text();
      }else{
        var template = $("#other").text();
      }
      var plot = template.replace(/\{name\}/,chat.name).replace(/\{content\}/,chat.content).replace(/\{date\}/,chat.created_at);
      App._data += plot;
  }
};


$(function(){
  // initial load 
  App.load("load");
  // event
  $("#say").click(function(){ App.say(); });
  // polling
  setInterval(App.refresh,1000);
});
<?php

/**
 * get DB connection(PDO)
 */
function getDB(){
    $db = dirname(__FILE__) . "/chat2.db";
    $dsn = "sqlite:" . $db;
    $user = '';
    $pass = '';
    $dbh;
    try{
        $dbh = new PDO($dsn, $user, $pass);
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }catch (PDOException $e){
        echo('Error:'.$e->getMessage());
        die();
    }
    return $dbh;
}
<?php
require_once(dirname(__FILE__) . "/config.php");

error_reporting(E_ALL);
setlocale(LC_ALL, "ja_JP.utf8");

function loadSay(){
    $pdo = getDB();
    if($_REQUEST["cursor"] == "load"){
        $sql = "select * from chat where content > :cursor OR 1 = 1;";
    }else{
        $sql = "select * from chat where id > :cursor ";
    }
    $stmt = $pdo->prepare($sql);
    $stmt->execute(array(":cursor" => $_REQUEST["cursor"]));
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

$arr = loadSay();

header("Content-Type:application/json");
echo json_encode($arr);
<?php
require_once(dirname(__FILE__) . "/config.php");

error_reporting(E_ALL);
setlocale(LC_ALL, "ja_JP.utf8");

$name = $_REQUEST["name"];
$content = htmlspecialchars($_REQUEST["content"]);

function replaceYoutube($string){
  $regex = "/https\:\/\/www\.youtube\.com\/watch\?v\=(.*)/";
  // https://i.ytimg.com/vi/xTU0K5q7Zbo/mqdefault.jpg
  if(preg_match($regex,$string,$m)){
      return array("replaced" => true , "content" => "<a href='". $string . "' target='_blank'>" . $string ."\n<img src='https://i.ytimg.com/vi/". $m[1] . "/mqdefault.jpg'/></a>\n"); 
  }else{
      return array("replaced" => false , "content" => $string . "\n") ;
  }
}

function replaceLink($string){
    $regex = "/http.*/";
    if(preg_match($regex,$string,$m)){
        return array("replaced" => true, "content" => "<a href='" . $string . "' target='_blank'>" . $string . "</a>\n");
    }else{
        return array("replaced" => false, "content" => $string . "\n" );
    }
}

function insertSay($name,$content){
    $sql = "insert into chat(name,content) values(:name,:content);";
    $pdo = getDB();
    $stmt = $pdo->prepare($sql);
    $stmt->execute(array(":name" => $name, ":content" => nl2br($content)));
}

$content = str_replace("\r\n","\n",$content);
$content_ar = explode("\n",$content);
for($i=0,$l=count($content_ar);$i<$l;$i++){
    $ret = replaceYoutube($content_ar[$i]);
    if($ret["replaced"]){
        $content_ar[$i] = $ret["content"];
    }else{
        $ret = replaceLink($content_ar[$i]);
        $content_ar[$i] = $ret["content"];
    }
}
$content = implode($content_ar,"");
//var_dump($content);
insertSay($name,$content);

setcookie("name",$name,time()+60*60*24*365);

header("Content-Type:application/json");
echo json_encode(array("status" => "ok"));