2017年2月20日月曜日

Twitterの自動返信BOTをPHPで実装

// TwitterOAuthライブラリを使用
require 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

// ログファイル
define("LOG_FILE","koimoimo.log");
// 最新ツイートIDを保存するファイル
define("LATEST_FILE","latest.txt");

//TwitterのOAuth用パラメータ
define("C_KEY","--Consumer Key--");
define("C_SEC","--Consumer Secret--");
define("A_TOK","--Access Token--");
define("A_SEC","--Access Token Secret--");

// 自分自身のTwitter ID(@なしで指定)
define("MYNAME","--My Twitter ID--");
// 非公式RT用返信ヘッダ
define("MENTION_HEAD","ホアーッ RT @");
// マッチング文字列を配列に格納
$key_arr = [
"ブチッ",
"ブチッ",
"ぶちっ",
"シャコン",
"ブチっ",
"ぶちぶち",
"ブチブチ",
"ブチブチ"
];

// OAuthでTwitterに接続
$connection = new TwitterOAuth(C_KEY,C_SEC,A_TOK,A_SEC);
// 前回の最新ツイートIDを取得
$latest = load_file(dirname(__FILE__)."/".LATEST_FILE);
// ホームタイムラインからツイートを取得
$tl = $connection->get("statuses/home_timeline", ["count" => 200]);
// 今回の最新ツイートIDを保存しておく
save_file(dirname(__FILE__)."/".LATEST_FILE,$tl[0]->id_str);
// ツイートをスキャンし、マッチング文字列にヒットしたら非公式RTする
foreach($tl as $t){
    // 送信者が自分自身以外のツイートと、前回の最新より新しいツイートに絞る
    if($t->user->screen_name != MYNAME && $t->id_str > $latest){
        // ツイートをマッチング文字列配列でスキャンし、ヒット数を返す。
        $sc = get_key_score($t->text,$key_arr);
        // ヒット数が1以上で、かつツイート中に自身のIDが含まれるものに絞る
        if($sc > 0 && mb_strstr($t->text,"@".MYNAME) != NULL){
            // 多重メンション防止
            if(mb_strstr($t->text,MENTION_HEAD) == NULL){
                // 返信を投稿する
                send_mention($connection,$t->user->screen_name,$t->text);
            }
        }
    }
}

// ファイルを開き、内容を文字列変数に格納する
function load_file($filename)
{
    $fp = fopen($filename,"r");
    $buf = fgets($fp);
    fclose($fp);
    return $buf;
}

// 文字列変数の内容をファイルに書き込む
function save_file($filename,$buf)
{
    $fp = fopen($filename,"w");
    fwrite($fp,$buf);
    fclose($fp);
}

// 文字列変数の内容をファイルに追記する
function append_log_file($filename,$buf)
{
    $fp = fopen($filename,"a");
    fwrite($fp,$buf."\n");
    fclose($fp);
}

// 文字列からマッチング文字列配列のヒット数を返す
function get_key_score($txt,$key)
{
    $s = 0;
    foreach($key as $k){
        if(mb_strstr($txt,$k) != NULL) $s++;
    }
    return $s;
}

// 非公式RT形式でツイートし、内容をログに残す
function send_mention($con,$usr,$txt)
{
    $m = MENTION_HEAD.$usr.": ".$txt;
    if(mb_strlen($m) > 140) $m = mb_strimwidth($m,0,140,"...");
    $r = $con->post("statuses/update", ["status" => $m]);
    append_log_file(dirname(__FILE__)."/".LOG_FILE,date("Ymd_His").":".$m);
    return $r;
}

2017年2月7日火曜日

内向きDNSサーバ構築

何年も前からやろうやろう思っていて、
でもめんどくさそうで二の足を踏んでいた内向きDNSなのですが。
ここにきてえいやっとやってしまいました。

DNSサーバのIPアドレス:192.168.1.250
ドメイン名:mydomain.com
として、設定を進めます。
なお動的グローバルIP環境なので、内向きのみの名前解決とし、
外への名前解決はルータに丸投げするようにします。

手順は以下の通り。

BIND9とdnstoolsのインストール
debian-sv# apt-get -y install bind9 dnstools

named.confを編集する。
debian-sv# vi /etc/bind/named.conf
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
#include "/etc/bind/named.conf.default-zones"; # コメントアウト
include "/etc/bind/named.conf.internal-zones"; # 追加:内向き用定義ファイル

named.conf.optionを編集する。
debian-sv# vi /etc/bind/named.conf.options
options {
    directory "/var/cache/bind";
    # 問い合わせを許可する範囲
    allow-query { localhost; 192.168.1/24; };
    # ゾーン転送を許可する範囲
    allow-transfer { localhost; 192.168.1/24; };
    # 内向き以外の問い合わせは他のDNSに丸投げする
    forwarders { 192.168.1.1; };
    dnssec-validation auto;
    # conform to RFC1035
    auth-nxdomain no;
    # ipv6は使用しないのでnoneにする
    listen-on-v6 { none; };
};

内向き用ゾーン定義(named.conf.internal-zones)
debian-sv# vi /etc/bind/named.conf.internal-zones
view "internal" {
    match-clients {
        localhost;
        192.168.1/24;
    };
    zone "mydomain.com" {
        type master;
        file "/etc/bind/mydomain.com.lan";
        allow-update { none; };
    };
    zone "1.168.192.in-addr.arpa" {
        type master;
        file "/etc/bind/1.168.192.db";
        allow-update { none; };
    };
    include "/etc/bind/named.conf.default-zones";
};

内向きの正引き用設定ファイル
debian-sv# vi /etc/bind/mydomain.com.lan
$TTL 86400
@ IN SOA    ns.mydomain.com. root.mydomain.com. (
    2017020101  ;Serial
    28800       ;Refresh
    14400       ;Retry
    3600000     ;Expire
    86400       ;Minimum TTL
)
    IN  NS      ns.mydomain.com.
    IN  MX 10   mydomain.com.

    IN  A       192.168.1.250
ns  IN  A       192.168.1.250
*   IN  CNAME   192.168.1.250

内向きの逆引き用設定ファイル
debian-sv# vi /etc/bind/1.168.192.db
$TTL 86400
@ IN SOA    ns.mydomain.com.  root.mydomain.com.(
    2017020101  ;Serial
    28800       ;Refresh
    14400       ;Retry
    3600000     ;Expire
    86400       ;Minimum
)
    IN NS       ns.mydomain.com.
    IN MX 10    mydomain.com.
250 IN PTR      mydomain.com.

以上で設定完了。
BIND9を再起動させる。
debian-sv# systemctl restart bind9

動作確認してみる。
debian-sv# dig mydomain.com

; <<>> DiG 9.9.5-9+deb8u9-Debian <<>> mydomain.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15622
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;mydomain.com.                 IN      A

;; ANSWER SECTION:
mydomain.com.          86400   IN      A       192.168.1.250

;; AUTHORITY SECTION:
mydomain.com.          86400   IN      NS      ns.mydomain.com.

;; ADDITIONAL SECTION:
ns.mydomain.com.       86400   IN      A       192.168.1.250

;; Query time: 41 msec
;; SERVER: 192.168.1.250#53(192.168.1.250)
;; WHEN: Tue Feb 07 21:10:59 JST 2017
;; MSG SIZE  rcvd: 91

上手く引けてるっぽい。作業完了!

参考サイト:
mk-mode BLOG「Debian 8 (Jessie) - DNS サーバ構築!」
ペイパー・プログラマーズ・ダイアリー「BIND9で内向きDNS構築 on Ubuntu」
VineLinuxで自宅サーバー「内向きDNSサーバー構築」