Labs

<< 最初 < 前ページ 次ページ > 最後 >>
icon 2010/02/06 Twitter & mixi API はじめ
PHPライブラリは誰かの「twitter2mixivoice.php」もあったけど、

(1) PEAR依存
(2) 自前だと修正・拡張ができる

なんで、ライブラリも自前で。

■問題点
(1) mixiボイスのAPIがない
→よって、無理矢理ログインしてHTMLパース以外方法なし

(2) クロスドメイン制限
→swfで直接通信が理想なんだけど、mixiもtwitterもクロスドメイン制限があるので断念
 サーバかまして処理する事に

■主なポイント
(1) AMF通信
→高速かつFlexとオブジェクトの親和性が高いAMFを採用
 JSON、XML変換できるけど、今は必要なし
 てか、XMLって遅いし面倒だし通信においてメリットあるのか?といつも疑問に思う。

(2) データのマージ
 twitterはJSON、mixiはテキスト取得して日付ソートしながらデータマージ
 (超暫定で最低限のタイトルと日付だけ)

とりあえずデータ取得&マージまで作ったので、あとはマルチ投稿の仕様考える。
ある程度まとったら機能毎にクラス化へ。

途中までのソース
うーん、デザイン的にコードは別途コンポーネント作った方がいいなw
swf側ソースは、色々ネタが多いので別途記事にする予定(?)

■VoiceService.php
require_once 'Service.php';

class VoiceService extends Service {

    /**
     * データ取得
     **/
    public function getVoices() {
        $voices['mixi'] = $this->mixi_voices();
        $voices['twitter'] = $this->twitter_user_timeline();
        $results = $this->_marge_voices($voices);
        return $results;
    }

    /**
     * Twitterタイムライン取得
     **/
    private function twitter_user_timeline()
    {
        $this->_twitter_auth();
        $url = "http://twitter.com/statuses/user_timeline/{$this->twitter_user_name}.json";
        $url.= "?since=".urlencode(date('D, d M Y G:i:s GMT', strtotime('-10 day')));
        $results = $this->_twitter_request($url);
        return $results;
    }

    /**
     * Twitter投稿
     **/
    private function post_twitter()
    {
        if ($_POST['message']) {
            $this->_twitter_auth();
            $message = rawurlencode($_POST['message']);
            $url = "http://twitter.com/statuses/update.json";
            $posts = "status={$message}";
            $results = $this->_twitter_request($url, $posts);
            return $results;
        }
    }

    /**
     * mixiボイス取得
     **/
    private function mixi_voices()
    {
        $this->_mixi_login();
        $url = 'http://mixi.jp/list_echo.pl';
        $headers[] = "Cookie: {$this->cookie}";

        $html = $this->_mixi_request($url, $headers, 'POST');
        $results = $this->_parse_mixi_voice($html);
        return json_encode($results);
    }

    /**
     * mixiボイス投稿
     **/
    private function post_mixi_voice()
    {
        $this->_mixi_login();
        $url = 'http://mixi.jp/list_echo.pl';
        $headers[] = "Cookie: {$this->cookie}";
        $html = $this->_mixi_request($url, $headers, 'GET');
        $post_key = $this->_get_mixi_voice_post_key($html);

        $url = 'http://mixi.jp/add_echo.pl';
        $body = 'てすとー'.date('Y/m/d H:i');
        $posts = array(
            'body' => $body,
            'post_key' => $post_key,
            'redirect' => 'recent_echo',
            'default_value' => $body,
        );
        $html = $this->_mixi_request($url, $headers, 'POST', $posts);
        $results = mb_convert_encoding($html, 'UTF-8', 'EUC-JP');
        echo($results);
    }

    /**
     * データ形式の統一
     **/
    private function _marge_voices($values)
    {
        if (is_array($values)) {
            foreach ($values as $type => $value) {
                $voices = json_decode($value);
		foreach ($voices as $key => $voice) {
                    $time = strtotime($voice->created_at);
                    $sort_times['time'] = $time;
                    $result['type'] = $type; 
                    $result['time'] = $time;
                    $result['created_at'] = date('Y-m-d H:i:s', $time);
                    $result['text'] = $voice->text;
                    $results[] = $result;
               }
            }
        }
	if (is_array($result)) {
            array_multisort($sort_times, SORT_DESC, $results);
	    json_encode($results);
	    return $results;							}
    }

    /**
     * twitter認証設定
     **/
    private function _twitter_auth()
    {
        $this->twitter_user_name = TWITTER_USER_NAME;
        $this->twitter_email = TWITTER_EMAIL;
        $this->twitter_password = TWITTER_PASS;
    }

    /**
     * mixi認証設定
     **/
    private function _mixi_auth()
    {
        $this->mixi_id = MIXI_ID;
        $this->mixi_email = MIXI_EMAIL;
        $this->mixi_password = MIXI_PASS;
    }

    /**
     * mixiログイン処理
     **/
    private function _mixi_login()
    {
        $this->_mixi_auth();

        $posts = array(
                'email' => $this->mixi_email,
                'password' => $this->mixi_password,
                'next_url' => 'http://mixi.jp/home.pl'
            );
        $headers[] = 'Content-Type: application/x-www-form-urlencoded';
        $url = 'http://mixi.jp/login.pl';
        $this->_mixi_request($url, $headers, 'POST', $posts);
    }

    /**
     * mixiボイスpost_key取得
     **/
    private function _get_mixi_voice_post_key($html)
    {
        if ($html) {
            $html = mb_convert_encoding($html, 'UTF-8', 'EUC-JP');
        }
        $rows = explode("\n", $html);
        if (is_array($rows)) {
            foreach ($rows as $key => $row) {
                $pattern = '|]+>(.*)]+>|U';
                preg_match("{$pattern}", $row, $values);

                preg_match('/post_key=(.+)&/', $row, $params);
                if ($params) {
                    $post_key = $params[1];
                    if ($post_key) {
                        return $post_key;
                    }
                }
            }
        }
    }

    /**
     * mixiボイスパース
     **/
    private function _parse_mixi_voice($html)
    {
        if ($html) {
            $html = mb_convert_encoding($html, 'UTF-8', 'EUC-JP');
        }
        $rows = explode("\n", $html);
        if (is_array($rows)) {
            foreach ($rows as $key => $row) {
                $pattern = '|]+>(.*)]+>|U';
                preg_match("{$pattern}", $row, $values);

                $pattern_posttime = '';
                if (preg_match("{$pattern_posttime}", $values[0])) {
                    $voice['created_at'] = $values[1];
                    $voice['type'] = 'mixi';
                }

                $pattern_body = '';
                if (preg_match("{$pattern_body}", $values[0])) {
                    $voice['text'] = $values[1];
                    $voices[] = $voice;
                    $voice = null;
                    $values = null;
                }
            }
        }
        return $voices;
    }

    /**
     * mixi共通リクエスト
     **/
    private function _mixi_request($url, $headers, $method, $posts=null) {
        if (is_array($posts)) {
            $content = http_build_query($posts, '', '&');
            $content_length = strlen($content);
            $headers[] = "Content-Length: {$content_length}";

            $params['http']['content'] = $content;
        }

        $params['http']['method'] = $method;
        $params['http']['header'] = implode("\r\n", $headers);

        $context = stream_context_create($params);
        $contents = file_get_contents($url, false, $context);

        //cookie設定
        $this->_set_cokkie_for_response_header($http_response_header);
        return $contents;
    }

    private function _set_cokkie_for_response_header($http_response_header) {
        if (is_array($http_response_header)) {
            foreach ($http_response_header as $r) {
                if (strpos($r, 'Set-Cookie') === false) {
                    continue;
                }
                $params = explode(' ', $r);
                $this->cookies[] = str_replace(';', '', $params[1]);
            }
	    if (is_array($this->cookies)) {
               $this->cookie = implode('; ', $this->cookies);
            }
        }
    }

    /**
     * twitter共通リクエスト
     **/
    private function _twitter_request($url, $posts=null)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        if ($posts) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $posts);
        }
        curl_setopt($ch, CURLOPT_USERPWD, "{$this->twitter_email}:{$this->twitter_password}");
        $results = curl_exec($ch);
        curl_close($ch);
        return $results;
    }

    // WSSE Authentication
    function _mixi_wsse_authentication_header() {
        $nonce       = pack('H*', sha1(md5(time().rand().posix_getpid())));
        $created     = date('Y-m-d\TH:i:s\Z');
        $digest      = base64_encode(pack('H*', sha1($nonce . $created . $this->mixi_password)));
        $wsse_format   = 'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"';
        $wsse = sprintf($wsse_format, $this->mixi_email, $digest, base64_encode($nonce), $created);
        $header = "X-WSSE: {$wsse}";

        return $header;
    }		
}
icon 2010/02/05 SVNで危うく・・・
自宅←→会社の作業での個人プロジェクト共有のお話

ファイル転送ソフトとかいい加減馬鹿らしいので、SVNをyoo-s.comに構築している。
と記事にするまでもないネタだったのだが・・・

http経由でソースをオール公開していたのだが、
個人設定情報も去年から丸見えだった!事に今日気づくw

mixiとtwitterはおろか、Googleアカウントまで乗っ取られるとこだった((*_*))

取り合えずBasic認証をかける。
やっぱライブラリ系以外のソース公開は無理だな。

■Apache設定
 #vi /etc/apache2/mods-available/dav_svn.conf

<Location /svn>
  DAV svn
  SVNParentPath /var/svn
  AuthType Basic
  AuthName "Subversion Repository"
  AuthUserFile /etc/apache2/dav_svn.passwd
  AuthzSVNAccessFile /etc/apache2/dav_svn.authz
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>
</Location>

■Basic認証設定
- ユーザファイル
 #vi /etc/apache2dav_svn.authz

* = r
ユーザ名 = rw


- htpassword
 #htpasswd -c dav_svn.passwd ユーザ名


<< 最初 < 前ページ 次ページ > 最後 >>

このサイトについて

HTML5 & CSS3化しつつあるので、現在IEには対応してません。
できれば、Google Chromeやら Apple SafariのWebKit系をお勧めします。

DBからプログラムまで一応全て自作なので、バグってたらすいません。
実験でFlash版(Flex版)を先に作りましたが、ちょっと停止してます。

プロフィール

新宿近辺でSE & プログラマーしてます。
Webアプリの開発・設計とか、最近はiPhoneとか奮闘してます。
デザインはさっぱりです。

音楽は、昔からCubase打ち込み人間で、そっちの方が経歴は長いですが、最近はやる暇がないです。。。

今は、Gon's Privates ってバンドのキーボードやってます。
単発的に、なんちゃってジャズ系のライブもやってます。

名古屋生まれなのでドラゴンズ好きです。

Info && SNS

Gmail

 yohei.yoshikawa@gmail.com

Twitter

 http://twitter.com/yoo_yoo_yoo

あんまつぶやきませんが、一応技術系メインで使ってます。情報交換はこちらへ

FaceBook

 http://www.facebook.com/#!/profile.php?id=1439130626

海外の知り合いがいないので閑散としてます。

mixi

 http://mixi.jp/show_profile.pl?id=230072

音楽仲間とかはこっちメインでやってます。興味があればこちらへ