PHP5 Code For Twitter Bot "mesoramen" Using MySQL
main script
<?php
require_once 'twuka/twuka.php';
require_once 'twuka/twukasql.php';
require_once 'twuka/twukahtml.php';
$mesoko = new TwitterPostMesoko();
$mesoko->mesoexec();
/**
* めそトーク投稿クラス
*
* @package TwitterPostMesoko
* @author Don
* @since PHP 5.2.9
* @version 0.3 2009/03/21
*/
class TwitterPostMesoko {
const TW_USERNAME = '****'; // TwitterユーザID
const TW_PASSWORD = '****'; // Twitterパスワード
const DB_SRV = '****'; // MySQLサーバー名
const DB_ID = '****'; // MySQLユーザーID
const DB_PASSWD = '****'; // MySQLパスワード
const DB_DBN = '****'; // MySQLデータベース名
const HTML_TITLE = 'mesoramen post'; // 投稿URLタイトル
const TALK_INTERVAL = 21600; // (60 * 60 * 24 / 4) = 21600 トーク間隔
// アクセスは2分間隔を想定で1日4回程度, 深夜は無し
private $twitterpost;
private $mysql;
private $html;
private $follow_date;
private $status_id;
private $user_screen_name; // これ別に使わないけど…
/**
* コンストラクタ
*/
public function __construct() {
// twitter投稿用インスタンスを作成
$this->twitterpost = new TwUka();
$this->twitterpost->set_param(
self::TW_USERNAME, self::TW_PASSWORD
);
// MySQL通信用インスタンスを作成
$this->mysql = new TwUkaSQL();
$this->mysql->set_param(
self::DB_SRV, self::DB_ID, self::DB_PASSWD, self::DB_DBN
);
// HTML表示用インスタンスを作成
$this->html = new TwUkaHTML();
$this->html->set_param(self::HTML_TITLE);
}
/**
* めそトークを投稿します。
*/
public function mesoexec() {
// セーブデータ取得
$this->get_param_db();
// 現在時間取得
date_default_timezone_set('Asia/Tokyo');
$today = getdate();
if ($today['mday'] != $this->follow_date) {
// 日付が変わったことを記録して自動フォロー
$this->set_date_db($today['mday']);
$this->twitterpost->auto_follow();
$mes = '自動フォローが完了しました';
$this->html->showhtml($mes);
exit;
}
// reply解析
$this->twitterpost->get_last_reply();
// 投稿条件準備
$max = (self::TALK_INTERVAL / 120) - 1;
$can_post = (!rand(0, $max)) && ($today['hours'] >= 6);
if ($this->twitterpost->get_status_id() > $this->status_id) {
// 新しいreplyがあれば結果を更新して反応する
$this->set_param_db();
$mes = $this->get_reply_db();
$this->twitterpost->posttwitter_with_param(
$mes,
$this->twitterpost->get_user_screen_name(),
$this->twitterpost->get_status_id()
);
$this->html->showhtml('投稿内容: '. $mes);
} elseif ($can_post) {
// トークを取得して投稿する
$mes = $this->get_talk_db();
$this->twitterpost->posttwitter($mes);
$this->html->showhtml('投稿内容: '. $mes);
} else {
// 投稿しない
$mes = '抽選漏れで投稿されませんでした';
$this->html->showhtml($mes);
}
}
/**
* データベースに問い合わせてパラメータを取得します。
*/
private function get_param_db() {
$sql = "
SELECT `follow_date`, `status_id`, `user_screen_name`
FROM `savedata`
WHERE `name` LIKE 'mesoramen'
LIMIT 1";
$rs = $this->mysql->send_sql($sql);
if (!$rs) {
$mes = 'can not connect db';
$this->html->showhtml($mes);
exit;
}
$item = mysql_fetch_array($rs); // supplied argument is not a valid MySQL result resource とか言われたので要調査
$this->follow_date = $item['follow_date'];
$this->status_id = $item['status_id'];
$this->user_screen_name = $item['user_screen_name'];
}
/**
* データベースに問い合わせて日付を更新します。
*
* @param integer $mday 日付
*/
private function set_date_db($mday) {
$sql = "
UPDATE `". self::DB_DBN. "`.`savedata`
SET `follow_date` = ". $mday. "
WHERE `savedata`.`name` LIKE 'mesoramen'
LIMIT 1";
$rs = $this->mysql->send_sql($sql);
if (!$rs) {
$mes = 'can not connect db';
$this->html->showhtml($mes);
exit;
}
}
/**
* データベースに問い合わせてパラメータを更新します。
*/
private function set_param_db() {
$sql = "
UPDATE `". self::DB_DBN. "`.`savedata`
SET `status_id` = ". $this->twitterpost->get_status_id(). "
, `user_screen_name` = '". $this->twitterpost->get_user_screen_name(). "'
WHERE `savedata`.`name` LIKE 'mesoramen'
LIMIT 1";
$rs = $this->mysql->send_sql($sql);
if (!$rs) {
$mes = 'can not connect db';
$this->html->showhtml($mes);
exit;
}
}
/**
* データベースに問い合わせてリプライトークを生成します。
*
* @return string
*/
private function get_reply_db() {
$sql = 'SELECT meso_reply FROM `meso_reply` ORDER BY RAND( ) LIMIT 1';
$rs = $this->mysql->send_sql($sql);
if (!$rs) {
$mes = 'can not connect db';
$this->html->showhtml($mes);
exit;
}
$item = mysql_fetch_array($rs);
$mes = $item['meso_reply'];
$mes = '@'. $this->twitterpost->get_user_screen_name(). ' '. $mes;
return $mes;
}
/**
* データベースに問い合わせてトークを生成します。
*
* @return string トーク
*/
private function get_talk_db() {
$sql = 'SELECT tsubuyaki FROM `mesoramen` ORDER BY RAND( ) LIMIT 1';
$rs = $this->mysql->send_sql($sql);
if (!$rs) {
$mes = 'can not connect db';
$this->html->showhtml($mes);
exit;
}
$item = mysql_fetch_array($rs);
$mes = $item['tsubuyaki'];
return $mes;
}
}
?>
twuka.php
<?php
/**
* Twitter Bot 用の機能色々
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @package TwUka
* @author Don
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @since PHP 5.2.9
* @version 0.3 2009/03/21
*/
class TwUka {
const TWITTER_POST_URL = 'http://twitter.com/statuses/update.xml';
const TWITTER_REPLY_URL = 'http://twitter.com/statuses/replies.xml';
const TWITTER_FOLLOWERS_URL = 'http://twitter.com/statuses/followers.xml';
const TWITTER_FOLLOWING_URL = 'http://twitter.com/statuses/friends.xml';
const TWITTER_FOLLOW_URL = 'http://twitter.com/friendships/create/';
const TWITTER_REMOVE_URL = 'http://twitter.com/friendships/destroy/';
private $username;
private $password;
private $status_id;
private $user_screen_name;
/**
* コンストラクタ
*/
public function __construct() {
$this->username = '';
$this->password = '';
}
/**
* メンバ変数に値をセットします。
*
* @param string $username TwitterユーザID
* @param string $password Twitterパスワード
*/
public function set_param($username, $password) {
$this->username = $username;
$this->password = $password;
}
/**
* 最終replyIDを取得します。
*
* @return integer 最終replyID
*/
public function get_status_id() {
return $this->status_id;
}
/**
* 最終reply元の名前を取得します。
*
* @return string 最終reply送信先
*/
public function get_user_screen_name() {
return $this->user_screen_name;
}
/**
* 最終受信reply情報を取得します。
*/
public function get_last_reply() {
$url = self::TWITTER_REPLY_URL;
$xmlstr = file_get_contents($url, false, stream_context_create(array(
'http' => array(
'method' => 'GET',
'header' => 'Authorization: Basic '. base64_encode(
$this->username. ':'. $this->password
)
)
)));
$xml = new SimpleXMLElement($xmlstr);
$this->status_id = $xml->status[0]->id;
$this->user_screen_name = $xml->status[0]->user->screen_name;
}
/**
* Twitterにメッセージを投稿します
*
* @param string $mes 投稿メッセージ
*/
public function posttwitter($mes) {
$url = self::TWITTER_POST_URL;
$params = '?status='. rawurlencode($mes);
$result = file_get_contents($url. $params , false, stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => 'Authorization: Basic '. base64_encode(
$this->username. ':'. $this->password
)
)
)));
}
/**
* Twitterにメッセージをパラメータ付きで投稿します。
*
* @param string $mes 投稿メッセージ
* @param string $in_reply_to reply 送信先ユーザID
* @param integer $in_reply_to_status_id reply 送信先ステータスID
*/
public function posttwitter_with_param($mes, $in_reply_to, $in_reply_to_status_id) {
$url = self::TWITTER_POST_URL;
$params = '?status='. rawurlencode($mes).
'&in_reply_to='. rawurlencode($in_reply_to).
'&in_reply_to_status_id='. rawurlencode($in_reply_to_status_id);
$result = file_get_contents($url. $params , false, stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => 'Authorization: Basic '. base64_encode(
$this->username. ':'. $this->password
)
)
)));
}
/**
* follow,removeメソッドを使ってfollowingをfollowersと一致させます。
* 100人以上の場合もうひと工夫必要です。
*/
public function auto_follow() {
// followersの取得
$url = self::TWITTER_FOLLOWERS_URL;
$xmlstr = file_get_contents($url, false, stream_context_create(array(
'http' => array(
'method' => 'GET',
'header' => 'Authorization: Basic '. base64_encode(
$this->username. ':'. $this->password
)
)
)));
$xml = new SimpleXMLElement($xmlstr);
foreach ($xml->user as $user) {
$followers[] = $user->screen_name;
}
// followingの取得
$url = self::TWITTER_FOLLOWING_URL;
$xmlstr = file_get_contents($url, false, stream_context_create(array(
'http' => array(
'method' => 'GET',
'header' => 'Authorization: Basic '. base64_encode(
$this->username. ':'. $this->password
)
)
)));
$xml = new SimpleXMLElement($xmlstr);
foreach ($xml->user as $user) {
$followings[] = $user->screen_name;
}
// followersとfollowingの差分
$not_following = array_diff($followers, $followings);
$not_followed = array_diff($followings, $followers);
// follow
if (count($not_following) > 0) {
foreach ($not_following as $user) {
$url = self::TWITTER_FOLLOW_URL. $user. ".xml";
// protected な相手だと HTTP/1.1 403 Forbidden を食らう
$xmlstr = @file_get_contents($url, false, stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => 'Authorization: Basic '. base64_encode(
$this->username. ':'. $this->password
)
)
)));
}
}
// remove
if (count($not_followed) > 0) {
foreach ($not_followed as $user) {
$url = self::TWITTER_REMOVE_URL. $user. ".xml";
$xmlstr = file_get_contents($url, false, stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => 'Authorization: Basic '. base64_encode(
$this->username. ':'. $this->password
)
)
)));
}
}
}
}
?>
twukasql.php
<?php
/**
* MySQLサーバにSQL文を投げるクラス
*/
class TwUkaSQL {
private $srv;
private $id;
private $passwd;
private $dbn;
/**
* メンバ変数に値をセットします。
*
* @param stirng $srv MySQLサーバー名
* @param string $id MySQLユーザーID
* @param string $passwd MySQLパスワード
* @param string $dbn MySQLデータベース名
*/
public function set_param($srv, $id, $passwd, $dbn) {
$this->srv = $srv;
$this->id = $id;
$this->passwd = $passwd;
$this->dbn = $dbn;
}
/**
* データベースに問い合わせてデータを返します。
*
* @param unknown_type $sql SQL文
* @return unknown mysql_queryの返り値resource, 失敗時はFALSE
*/
public function send_sql($sql) {
//DBへ接続開始
$dbHandle = mysql_connect($this->srv, $this->id, $this->passwd);
//サーバの接続に失敗した場合はFALSEを返す
if (!$dbHandle) {
return FALSE;
}
//文字コードをutf-8にする
$sql_charset = 'SET NAMES utf8';
$utf = mysql_query($sql_charset);
//DBの接続に失敗した場合はFALSEを返す
if (!mysql_select_db($this->dbn)) {
mysql_close($dbHandle);
return FALSE;
}
$rs = mysql_query($sql);
mysql_close($dbHandle);
return $rs;
}
}
?>
twukahtml.php
<?php
/**
* HTMLを出力するクラス
*/
class TwUkaHTML {
private $title;
/**
* メンバ変数に値をセットします。
*
* @param string $title 投稿ページのタイトル
*/
public function set_param($title) {
$this->title = $title;
}
/**
* ブラウザにメッセージを表示します。
*
* @param string $mes 表示メッセージ
*/
public function showhtml($mes) {
echo '<?xml version="1.0" encoding="UTF-8"?>'. "\n";
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'. "\n";
echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja" dir="ltr">'. "\n";
echo '<head>'. "\n";
echo '<meta http-equiv="content-type" content="text/html;charset=UTF-8" />'. "\n";
echo '<title>'. $this->title. '</title>'. "\n";
echo '</head>'. "\n";
echo '<body>'. "\n";
echo '<h1>'. $mes. '</h1>'. "\n";
echo '</body>'. "\n";
echo '</html>'. "\n";
}
}
?>
Perl5 Code For Twitter Bot "beefriends" Posting From SSP
main script
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode;
use CGI qw/:cgi/;
use Net::Twitter;
package main;
my $tw_username = '****';
my $tw_password = '****';
my $ssp_postkey = '****';
my $html_title = 'beefriends post';
my $bee = TwUkaTrans->new;
$bee->set_param($tw_username, $tw_password, $ssp_postkey, $html_title);
$bee->trans;
{
package TwUkaTrans;
sub new {
my $pkg = shift;
bless {
'tw_username' => undef,
'tw_password' => undef,
'ssp_postkey' => undef,
'html_title' => undef,
},$pkg;
}
sub set_param {
my $self = shift;
($self->{tw_username}, $self->{tw_password}, $self->{ssp_postkey}, $self->{html_title}) = @_;
}
sub trans {
my $self = shift;
my $cgi = new CGI;
$cgi->charset('utf-8');
my $mes = $cgi->param($self->{ssp_postkey});
if ($mes) {
$mes = $cgi->escapeHTML($mes);
my $twit = Net::Twitter->new(
username=>$self->{tw_username}
, password=>$self->{tw_password}
);
my $result = $twit->update($mes);
} else {
$mes = Encode::encode_utf8('投稿内容が不正です');
}
my $html = TwUkaHTML->new;
$html->set_param(Encode::encode_utf8($self->{html_title}));
print $html->showhtml($mes);
}
}
{
package TwUkaHTML;
sub new {
my $pkg = shift;
bless {
title => undef,
},$pkg;
}
sub set_param {
my $self = shift;
my $title = shift;
$self->{title} = $title;
}
sub showhtml {
my $self = shift;
my $mes = shift;
my $ret = '';
$ret .= 'Content-type: text/html;'. "\n";
$ret .= '<?xml version="1.0" encoding="UTF-8"?>'. "\n";
$ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'. "\n";
$ret .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">'. "\n";
$ret .= '<head>'. "\n";
$ret .= '<meta http-equiv="content-type" content="text/html;charset=UTF-8" />'. "\n";
$ret .= '<title>'. $self->{title}. '</title>'. "\n";
$ret .= '</head>'. "\n";
$ret .= '<body>'. "\n";
$ret .= '<h1>'. $mes. '</h1>'. "\n";
$ret .= '</body>'. "\n";
$ret .= '</html>'. "\n";
return $ret;
}
}