PHP
JavaScript
Twitter
Conoha
ConoHaDay 15

PHP+JSでNGワードを投稿したらこのはちゃんにおこられるTwitterWebクライアントをつくる

NGワードを投稿したらこのはちゃんに強制変換されるTwitterWebクライアントをつくる(スタンプ対応)

この記事は、ConoHa Advent Calendar2017の15日目の記事です。

はじめまして、14日目担当の@kazさんからバトン頂きました、15日目担当@hozuです。

そもそも目的と理由

1.プログラミングと無縁の環境に就職したから気晴らしに組みたかった。
2.Twitterクライアントだったら作れそうだったから(ライブラリ使用すれば)
3.このは・あんずスタンプが使えるクライアントを作りたかった。(清楚でかわいい)
(コミケの頒布物を作る現実逃避ではないです)
9.NGワードを記載ができる

1.使う物

1.PHP+JS(jQuery不使用:3月まで小学生に教えていたJSだけでなんとかする)
2.ConoHaのLAMP(VPSのアプリケーション[LAMP],メモリ512MB)
3.ConoHaが出しているTwitterスタンプ

2.工程

とりあえず、ConoHaのLAMPを導入。というか契約

image.png

image.png

おそらく、LAMPのみを使っている人は少ないんじゃないかなと思い、
LAMPにしました。いつもは、ConoHaの別のVPSを使っていて、
PHPやら諸々好みに設定変えているのですが、LAMPってあまり使ったことが無かったので。

あっけなく導入完了。(1分かからず)
image.png

ひとまずOSは
image.png

CentOS Linux release 7.3.1611 (Core)でした。

3.組んだプログラムをアップロード

本来はPHPとCSSとJS分離した構造でしたが、まとめました。

今回は、abraham氏による twitteroauth[ https://twitteroauth.com/ ]ライブラリを使用します。

開発環境はgithubを導入していないWindowsでやってしまったため、abraham氏の所からダウンロードして、展開して・・・・
で、LAMPにFTPで突っ込む。

今回作った物の仕様は、

・「おっさん」って文字を入力すると、フォームにおいて強制的に「清楚でかわいい」に変換されます。
・TimeLine取得後、「おっさん」って文字ががあると、「禁則ワード」として変換してひょうじされます。
・Twitterスタンプがあるので、そのスタンプを選んでツイートに付加することができます。

で、出来た物がこちら

まず、禁則ワードがTimeLineに合った場合
image.png

次に、「おっさん」と入力した場合。
image.png

スタンプを押した場合。
image.png

このようになります。

で、肝心のプログラムは、gitにアップしようと思ったけど、諸事情でやれず。

非常識だけど、index.phpをここにそのまま記述します。
いつか、気が向いたらアップし直します。

また、かなり言葉足らずですが、
rootのままユーザーを作らずにやっている時点でかなり危ないですが、その場しのぎです。

index.php
<html>
<head>
  <meta charset="UTF-8">

    <style type="text/css">
<!--





body{
  margin:0;
  padding:0;
  border:none;
  list-style:none;
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}


#timeline{

  margin:10;
  padding:10;
  border:none;
  list-style:none;
}


.style {
  margin:70px auto;
  background:#394674;
  width:347px;
  text-align:center;
  padding:40px;

}



input {
    position: relative;
    top:10px;
  background:#262454;
  color:#FFFFFF;
  display:block;
  width:269px;
  padding:15px;
  margin-bottom:10px;

}




button {
  text-align: center;
  margin-top:15px;
  margin-bottom:15px;
  padding:20px;
  width:270px;
  font-size:20px;

}

button:active {
  top:5px;
}



#kakudai{
  position:relative;
  left:50px;
}

.conoha_s{

  width: 40px;
  height: 40px;
}

img.conoha_s {
  -webkit-transition:0.2s ease-in-out;
  -moz-transition:0.2s ease-in-out;
  -ms-transition:0.2s ease-in-out;
  -o-transition:0.2s ease-in-out;
  transition:0.2s ease-in-out;
}

img.conoha_s:hover {
  -webkit-transform:scale(4,4);
  -moz-transform:scale(4,4);
  -ms-transform:scale(4,4);
  -o-transform:scale(4,4);
  transform:scale(4,4);
}

#replay{
  font-size: 4px;
  color: #0000ff;
}

.post_window{

  width: 700px;
  height: 70px;
  background-color: #ffffff;
}

#post_post_window{  
    margin: 10px;
    position: fixed;    
    bottom: 0; 
    text-align: center;
    background-color: #eaeaea;
}  

#input_button{
  position: relative;
  left:300px;
  }

textarea{
  font-size: 1.2em;
  margin: 10px;
}

#replay_tweet{
  color: #0000ff;
}




//-->
</style>




  <script type="text/javascript">
    var conoha_tweet=["664328654315393024","664328635302604800","664328617787154432","664328600628293632","664328561772228608","664328543044632576","664328526468747264","664328508391297024","664328482072080388","664328457690570752","664327659346726912","664327638446575616","666512187192537088","664327581118828544","664327556607426560","664327534570409984","664327505164177408","664327481931882496","664327455784570881","664327419273195521","664324349667573760","664324316511645696","664324291882647553","664324260291186688","664324229614080000","664324197263409152","664324168918302720","664324140308889600","664324086458220544","664324050294935552","664319114740039680","664319087602827264","664319049199816704","664319016861741056","664318986784366592","664318960423170048","664318931927044096","664318905398132736","664318879842201600","664318855917867008","664318826767519744","664318777220198400"];
var conoha_double=0;
var open_close=0;

function start () {
    stamp_close ();
}
function username_check () {

    var username = "";
    var username_after ="";
    username=document.getElementById("input_username_original").value;
    username.replace(/[^\x01-\x7E]|[A-Za-z0-9!"#$%&'\(\)\?_=|+\~\[\]\^\-\\\`/*,<>;:{}.\@]/g,
        function(s){
        if (4<=(escape(s).length)){
            username_after=username_after+ String.fromCharCode(s.charCodeAt(0)+0);
        }else{
            username_after=username_after+ String.fromCharCode(s.charCodeAt(0)+65248);
        }


        }       );
    document.getElementById("username").value=username_after;



}

function tweet_check(){



    var text = "";
    var text_after ="";
    var text_count=280;
    text=document.getElementById("input_msg_original").value;

    text.replace(/[^\x01-\x7E]|[A-Za-z0-9!"#$%&'\(\)\?_=|+\~\[\]\^\-\\\`/*,<>;:{}.\@]/g,    
        function(s){
        if (4<=(escape(s).length)){

            text_after=text_after+ String.fromCharCode(s.charCodeAt(0)+0);
            text_count=text_count-2;
        }else{

            text_after=text_after+ String.fromCharCode(s.charCodeAt(0)+65248);
            text_count=text_count-1;
        }



        }       );

    text_after=text;
    document.getElementById("input_msg").value=text_after;



    var input_count=text_after.length;
    if(text_count>=280){
        document.getElementById("input_count").textContent="";
    }else{
    document.getElementById("input_count").textContent="文字"+(100-Math.floor((text_count/280)*100))+"%";
    }


    if ((( text_after.indexOf('おっさん') != -1)|| ( text_after.indexOf('ossan') != -1))||(( text_after.indexOf('おっさn') != -1)|| ( text_after.indexOf('おっさn') != -1))) {
//strにhogeを含む場合の処理

var ng1 = "おっさん" ;
var regExp = new RegExp( ng1, "g" ) ;
var a = text_after.replace( regExp , "清楚でかわいい" ) ;


var ng2 = "ossan" ;
var regExp = new RegExp( ng2, "g" ) ;
var a = a.replace( regExp , "清楚でかわいい" ) ;

document.getElementById('input_msg_original').value=a;


}else{

}

    if(input_count==0){
        document.getElementById("input_button").disabled = true;
        document.getElementById("input_alert").textContent="";
        document.getElementById("input_alert").style.color="#000000";
        document.getElementById("input_count").style.color="#000000";
    }else if(input_count<=280){
        document.getElementById("input_button").disabled = false;
        document.getElementById("input_count").style.color="#000000";
        document.getElementById("input_alert").textContent="";
        document.getElementById("input_alert").style.color="#000000";

    }else{
        document.getElementById("input_button").disabled = true;
        document.getElementById("input_alert").textContent="文字制限を超えています!送信できません。";
        document.getElementById("input_alert").style.color="#ff0000";
        document.getElementById("input_count").style.color="#ff0000";

    }
}


function conoha_okoru(){

    text=document.getElementById("input_msg_original").value;
    text=text.replace("おっさん","清楚");
    document.getElementById("input_msg_original").Value=text;
    document.getElementById("conoha").src="img/re_fanfic_10.jpg";


}

function conoha_s(num){

    var text=document.getElementById("input_msg_original").value;

    if(!(text.indexOf('#みくもスタンプ') != -1)){


        document.getElementById("input_msg_original").value=text+"#みくもスタンプ\nhttps://www.conoha.jp/conoben/?p=10747\nhttps://twitter.com/M/status/"+conoha_tweet[num]+"/photo/1";

    }else{
        alert("スタンプは一つしか押せないよ");
    }
}



function replay (user_num) {
    var user=document.getElementById('user'+user_num).value;
    text=document.getElementById("input_msg_original").value;
    document.getElementById("input_msg_original").value="@"+user+" "+text;
}

function stamp_open () {
    if(open_close==0){
        document.getElementById('kakudai').style.display="block";
        document.getElementById('br1').innerHTML="<br><br><br>";
        document.getElementById('br2').innerHTML="<br><br><br>";
        document.getElementById('open_menu').innerHTML="▼このはスタンプ集 閉じる▼";
        open_close++;
    }else{
        open_close=0;
        stamp_close();
    }



}
function stamp_close () {
    document.getElementById('kakudai').style.display="none";
    document.getElementById('br1').innerHTML="";
    document.getElementById('br2').innerHTML="";
    document.getElementById('open_menu').innerHTML="▼このはスタンプ集 開く▼";

}




    </script>
  <meta http-equiv="Pragma" content="no-cache">
  <meta http-equiv="Cache-Control" content="no-cache">
  <meta http-equiv="Expires" content="0">
  <title>このはったー</title>
</head>
<body onload="start()">


<?php
require 'twitteroauth-master/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;



//ここにキーを入力


//
$consumerKey = "";
$consumerSecret = "";
$accessToken = "";
$accessTokenSecret = "";



$connection = new TwitterOAuth($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret);

print "<div id=\"timeline\">";

if(@$_POST["input_msg_original"]){
  $result = $connection->post("statuses/update", array("status" => $_POST["input_msg_original"]));


}


$statuses = $connection->get("statuses/home_timeline", ["count" => 50]); //タイムラインを50ツイート取得
if(isset($statuses->errors)) {
  //エラー
  $statuses->errors[0]->message;
} else {
  //ツイートの取得に成功
  for ($i=0; $i < 49; $i++) {


    $get_tweet=$statuses[$i]->text;


    $get_tweet = str_replace("おっさん", "[禁則ワード]", $get_tweet);

    print  "<img src=".$statuses[$i]->user->profile_image_url.">";

    print $statuses[$i]->user->name."(@". $statuses[$i]->user->screen_name.")";
    print "<br>";
    print $get_tweet;
  print "<br>".$statuses[$i]->created_at;
  print "<br><input type=hidden id=\"user".$i."\" value=\"".$statuses[$i]->user->screen_name."\">";
  print "<span id=\"replay_tweet\" onClick=\"replay(".$i.")\">このユーザー宛にリプライする</span>";


    print "<br>--------------------------------------------------------------------<br>";





    }
  }

print "</div>";


?>

<div id="post_post_window">

        ツイート
        <form enctype="multipart/form-data" action="index.php" method="POST">


        <textarea type="text" class="post_window" id="input_msg_original"  name="input_msg_original"  onkeyup="tweet_check()"  ></textarea><span id="input_count">文字0%</span>
        <br><span id="input_alert"></span>
        <span id="open_menu"  onClick="stamp_open()">▼このはスタンプ集 開く▼</span>
<span id="br1"></span>
<div id="kakudai">
        <img class="conoha_s" src="./img/st01.jpg" onclick="conoha_s(1)">
        <img class="conoha_s" src="./img/st02.jpg" onclick="conoha_s(2)">
        <img class="conoha_s" src="./img/st03.jpg" onclick="conoha_s(3)">
        <img class="conoha_s" src="./img/st04.jpg" onclick="conoha_s(4)">
        <img class="conoha_s" src="./img/st05.jpg" onclick="conoha_s(5)">
        <img class="conoha_s" src="./img/st06.jpg" onclick="conoha_s(6)">
        <img class="conoha_s" src="./img/st07.jpg" onclick="conoha_s(7)">
        <img class="conoha_s" src="./img/st08.jpg" onclick="conoha_s(8)">
        <img class="conoha_s" src="./img/st09.jpg" onclick="conoha_s(9)">
        <img class="conoha_s" src="./img/st10.jpg" onclick="conoha_s(10)">

        <img class="conoha_s" src="./img/st11.jpg" onclick="conoha_s(11)">
        <img class="conoha_s" src="./img/st12.jpg" onclick="conoha_s(12)">
        <img class="conoha_s" src="./img/st13.jpg" onclick="conoha_s(13)">
        <img class="conoha_s" src="./img/st14.jpg" onclick="conoha_s(14)">
        <br>
        <img class="conoha_s" src="./img/st15.jpg" onclick="conoha_s(15)">

        <img class="conoha_s" src="./img/st16.jpg" onclick="conoha_s(16)">
        <img class="conoha_s" src="./img/st17.jpg" onclick="conoha_s(17)">
        <img class="conoha_s" src="./img/st18.jpg" onclick="conoha_s(18)">
        <img class="conoha_s" src="./img/st19.jpg" onclick="conoha_s(19)">
        <img class="conoha_s" src="./img/st20.jpg" onclick="conoha_s(20)">

        <img class="conoha_s" src="./img/st21.jpg" onclick="conoha_s(21)">
        <img class="conoha_s" src="./img/st22.jpg" onclick="conoha_s(22)">
        <img class="conoha_s" src="./img/st23.jpg" onclick="conoha_s(23)">
        <img class="conoha_s" src="./img/st24.jpg" onclick="conoha_s(24)">
        <img class="conoha_s" src="./img/st25.jpg" onclick="conoha_s(25)">
        <img class="conoha_s" src="./img/st26.jpg" onclick="conoha_s(26)">
        <img class="conoha_s" src="./img/st27.jpg" onclick="conoha_s(27)">
        <img class="conoha_s" src="./img/st28.jpg" onclick="conoha_s(28)">
        <br>
        <img class="conoha_s" src="./img/st29.jpg" onclick="conoha_s(29)">
        <img class="conoha_s" src="./img/st30.jpg" onclick="conoha_s(30)">

        <img class="conoha_s" src="./img/st31.jpg" onclick="conoha_s(31)">
        <img class="conoha_s" src="./img/st32.jpg" onclick="conoha_s(32)">
        <img class="conoha_s" src="./img/st33.jpg" onclick="conoha_s(33)">
        <img class="conoha_s" src="./img/st34.jpg" onclick="conoha_s(34)">
        <img class="conoha_s" src="./img/st35.jpg" onclick="conoha_s(35)">
        <img class="conoha_s" src="./img/st36.jpg" onclick="conoha_s(36)">
        <img class="conoha_s" src="./img/st37.jpg" onclick="conoha_s(37)">
        <img class="conoha_s" src="./img/st38.jpg" onclick="conoha_s(38)">
        <img class="conoha_s" src="./img/st39.jpg" onclick="conoha_s(39)">
        <img class="conoha_s" src="./img/st40.jpg" onclick="conoha_s(40)">

        <img class="conoha_s" src="./img/st41.jpg" onclick="conoha_s(41)">
        <img class="conoha_s" src="./img/st42.jpg" onclick="conoha_s(42)">
        <br>
        スタンプ画像については 再使用の禁止 (C)GMO Internet, Inc.   
        <br>
        <span id="br2"></span>

        <span id="conoha_close" onClick="stamp_close()">▲閉じる▲</span>
      </div>



        <input type="hidden" id="input_msg" >
<input type="submit" id="input_button" value="送信/更新">

  <address></address>
</div>
</div>

こんな感じです。

スタンプの画像参照のところですが、今回は一つ一つダウンロードしていたので
./img/st16.jpg
このようになっています。

Twitterのクライアントを設定する場合の
https://apps.twitter.com/app
で、
もし、クライアントとか有る場合は、今回は
https://getaccesstoken.herokuapp.com
を使い、アクセストークンとか取得し、PHPの各値にいれました。

4.補足:別のConoHaのVPSでもやってみた

環境 [ConoHa VPS OS:Debian,メモリ:1GB]

どうやら、LAMP版と違ってポート開放が出来ていないようで、外部参照できなかったです。
(Twitterへアクセスが出来ず)
持ち時間的にも厳しくなってきたので、教え子(@Yanorei32 )に投げたら、開放とかやってくれた・・・けど、詳細を載せる余裕がありませんでした。。。。

余談

SSDってこともあって、凄くレスポンス速くて正直自分の使っているPCが使い物にならないぐらい驚いてます。