TwitterToMail Alpha

Twitterの最低限の機能をメールで済ませてしまおうという計画のもとに作ったスクリプト.要PEAR::Mail,PEAR::Net::POP3
APIを使わないのは回数制限を回避するため,自分のTLを使わないのは遅延を回避するため,のつもり.
まだ投稿部分ができていない.fooとかbarとか多いのは,行き当たりばったりに作っているので勘弁.
コピーレフトなのでむしろ誰か改良して私にください.

<?php
// ログイン情報
$login = array('session[username_or_email]' => "", // twitter id
	       'session[password]'          => ""); // twitter password

// SMTPサーバ情報
$smtp_server = "";
$smtp_id = "";
$smtp_pass = "";

// POPサーバ情報
$pop_server = "";
$pop_id = "";
$pop_pass = "";

// アドレス
$to_addr = "";
$from_addr = "";

// 定数
$_cachedir = './cache/';
$_cookiefile = $_cachedir . 'cookie.tmp';
$_remember_me = 'remember_me=0';

// 変数
$_following = array();
$_statuses = array();


// ログイン処理
$foo = "";
foreach($login as $key => $value) {
  $foo .= $key . '=' . $value . '&';
}
$foo .= $_remember_me;

$fp = fopen($_cookiefile, 'w');
flock($fp, LOCK_EX);

$cURL = curl_init();
curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true);
curl_setopt($cURL, CURLOPT_SSLVERSION, 3);
curl_setopt($cURL, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($cURL, CURLOPT_URL, 'https://twitter.com/sessions');
curl_setopt($cURL, CURLOPT_POST, true);
curl_setopt($cURL, CURLOPT_POSTFIELDS, $foo);
curl_setopt($cURL, CURLOPT_WRITEHEADER, $fp);
curl_exec($cURL);
curl_close($cURL);

unset($foo);
fclose($fp);


// followingの取得
$cURL = curl_init();
curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true);
curl_setopt($cURL, CURLOPT_COOKIEFILE, $_cookiefile);
curl_setopt($cURL, CURLOPT_URL, 'http://twitter.com/friends');
$foo = curl_exec($cURL);
curl_exec($cURL);
curl_close($cURL);

while(preg_match('/<tr id="person_\d+" class="vcard person (.+?)">(.*)$/s', $foo, $match)) {
  $_following[] = $match[1];
  $foo = $match[2];
}

unset($foo, $match);


// followingごとに最新の情報を取得する
function get_page($id, $page) {
  global $_cookiefile, $cURL;
  
  $cURL = curl_init();
  curl_setopt($cURL, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($cURL, CURLOPT_COOKIEFILE, $_cookiefile);
  curl_setopt($cURL, CURLOPT_URL, 'http://twitter.com/' . $id . '?page=' . $page);
  $foo = curl_exec($cURL);
  curl_exec($cURL);
  curl_close($cURL);
  
  $return = array();
  while(preg_match('/<span class="entry-content">\s*(.+?)\s*(<a href="http:\/\/twitter.com\/[^\/]+\/status\/\d+">...<\/a>|\s*)<\/span> <span class="meta entry-meta"><a href="http:\/\/twitter.com\/[^\/]+\/status\/(\d+)" class="entry-date" rel="bookmark"><span class="published" title="([^"]+)">(.*)$/s', $foo, $match)) {
    $match[1] = preg_replace('/@<a.*?>/', '@', $match[1]);
    $match[1] = preg_replace('/<a href="(.+?)".*?>.*?<\/a>/', '$1', $match[1]);
    $match[1] = preg_replace('/<\/a>/', '', $match[1]);
    $return[$match[3]] = array('id' => $id, 'time' => strtotime($match[4]), 'data' => $match[1]);
    $foo = $match[5];
    unset($match);
  }
  unset($foo);
  krsort($return);
  
  return $return;
}

foreach($_following as $value) {
  $foo = array();
  
  $bar = $_cachedir . $value . '.cache';
  // 初めての時は,最新の1個を取得する
  if(!file_exists($bar)) {
    $hoge = get_page($value, 1);
    if(count($hoge) > 0) {
      $fuga = reset($hoge);
      $fp = fopen($bar, 'w');
      flock($fp, LOCK_EX);
      fwrite($fp, $fuga['time']);
      fclose($fp);
      unset($fp, $fuga);
    }
    foreach($hoge as $key2 => $value2) {
      $foo[$key2] = $value2;
      break;
    }
    unset($key2, $value2, $hoge);
  }
  // 更新があった時は,取得する
  else {
    $fp = fopen($bar, 'r');
    flock($fp, LOCK_SH);
    $hoge = trim(fgets($fp));
    fclose($fp);
    
    $fuga = true;
    for($i = 1; $fuga; $i++) {
      $piyo = get_page($value, $i);
      foreach($piyo as $key2 => $value2) {
	if($hoge >= $value2['time']) {
	  $fuga = false;
	  break;
	}
	$foo[$key2] = $value2;
      }
      unset($key2, $value2, $piyo);
    }
    unset($fuga, $hoge);
    
    if(count($foo) > 0) {
      $hoge = reset($foo);
      $fp = fopen($bar, 'w');
      flock($fp, LOCK_EX);
      fwrite($fp, $hoge['time']);
      fclose($fp);
      unset($fp, $hoge);
    }
  }
  unset($bar);
  
  foreach($foo as $key2 => $value2) {
    $_statuses[$key2] = $value2;
  }
  unset($key2, $value2, $foo);
}
unset($key, $value);
ksort($_statuses);


// メール化して送信する
require_once('Mail.php');
foreach($_statuses as $key => $value) {
  $mail_object =& Mail::factory("SMTP", array('host' => $smtp_server, 'port' => 25, 'auth' => true, 'username' => $smtp_id, 'password' => $smtp_pass, 'localhost' => "localhost"));
  $mail_object->send($to_addr, array('From' => $from_addr, 'To' => $to_addr, 'Subject' => $key), $value['id'] . ": " . mb_convert_encoding($value['data'], 'JIS', 'utf-8'));
}
unset($key, $value);


// POP受信を行い,APIを利用してPOSTで書き込む
require_once('Net/POP3.php');
$foo = new Net_POP3();
$foo->connect($pop_server, 110);
$foo->login($pop_id, $pop_pass, LOGIN);

/* 未実装 
 件名がRe: statusidだったら,@.. とreply to.. をつけて投稿,それ以外は普通に投稿
*/

$foo->disconnect();

// 終了処理
unlink($_cookiefile);
exit();
?>