Hatena::ブログ(Diary)

xmallocのプログラミングノート

2010年08月01日

Twitter APIから取得したテキストをHTMLに変換するための公式ライブラリ

Twitter statuses/public_timeline APIとか、ツイートを取得する系のAPIのデータから@とか#とかhttp://をURLに変換する公式ライブラリがあるようなので簡単にレポ。

まずライブラリ自体は以下のURLからダウンロードできる。

mzsanford's twitter-text-rb at master - GitHub

mzsanford's twitter-text-java at master - GitHub

mzsanford's twitter-text-php at master - GitHub

Python Package Index : twitter-text-py 1.0.3

Tweet Entities | dev.twitter.comにツイートからエンティティ抜き出すにはtwitter-text使えって書いてるからこれらが公式ってことでほぼ問題無いと思う。mzsanford氏はツイッターの国際化チームの一員。ただしPythonは作者違うようなので公式扱いでは無いかもしれない。Perlは無いっぽい。



使い方

Ruby版が大元っぽかったのでそっちの使い方説明しようと思ったんだけど、rakeの動かし方がいまいちよく分からんかった(何かファイルが無いと怒られた)ので、PHP版で説明。(個人的にはPython版が一番要るんだけど作者違うのでアレ。)

  1. mzsanford's twitter-text-php at master - GitHubからリポジトリをcloneしてダウンロード
    $ git clone http://github.com/mzsanford/twitter-text-php.git
    
  2. リポジトリ中のsrc/Twitterをinclude_pathの通ったディレクトリにコピー。
    $ cd twitter-text-php/src
    $ cp -r Twitter WHERE
    
  3. Twitter_Autolinkクラスのautolinkメソッドで、APIから取得したテキストをHTMLに変換できる。
    <?php
    require_once "Twitter/Autolink.php";
    $a = new Twitter_Autolink();
    echo $a->autolink('RT @mashable @LinkedIn Beefs Up Its Twitter Integration [PICS] http://bit.ly/bkB7cA #linkedin #tweets #twitter'), "\n";
    ?>
    
    出力はこんな感じ。スクリーンネームハッシュタグURLが<a>タグでリンクになってる。
    RT @<a class="tweet-url username" href="http://twitter.com/mashable">mashable</a> @<a class="tweet-url username" href="http://twitter.com/LinkedIn">LinkedIn</a> Beefs Up Its Twitter Integration [PICS] <a href="http://bit.ly/bkB7cA">http://bit.ly/bkB7cA</a> <a href="http://twitter.com/search?q=%23linkedin" title="#linkedin" class="tweet-url hashtag">#linkedin</a> <a href="http://twitter.com/search?q=%23tweets" title="#tweets" class="tweet-url hashtag">#tweets</a> <a href="http://twitter.com/search?q=%23twitter" title="#twitter" class="tweet-url hashtag">#twitter</a>
    
    ちなみに$Twitter_Autolink->noFollowで<a>タグにnofollow属性付けれるってソースに書いてあるんだけどPHP版は実装されてないっぽい。有効にしたかったら要改造。

Githubにも使い方が書いてあるのでそっちも見てくれ・・・まあそれ紹介すれば済む話なんだけど。

他の言語のは誰か親切な人が説明してくれるはず。



後書き

不勉強ながらこのライブラリの存在自体知らなかったりしました。Tweet Entities | dev.twitter.comを読んでたらたまたま見つけた感じです。twitter-text-rbとかでググるとそれなりに使ってる人いるみたいですが、普及してるとは言い難い感じ。

とりあえず、一時期あった日本語ハッシュタグとかの公式変換ルールがいまいちよく分からん問題とかはこれ一発で解決ですよ、ということで。

2010年07月13日

DOMモジュールをテンプレートエンジン代わりに使う三つの利点+1

PHP5からPHP標準添付のDOMモジュールもlibxml2ベースのものになって、htmlも処理できるようになったのでだいぶ使いやすくなったと思う。DOMを使うと文書構造にアクセスして編集できるので、テンプレートエンジンの代わりとしてそれなりに利用されてても良いと思うんだけど少なくとも個人的観測範囲内だと全ったくもって流行ってなかったりして*1大変残念なので、PHPDOMモジュールテンプレートエンジン代わりに使う利点をまとめてみました。



1.インスコ不要

最初に書いたけど、PHP5のDOMモジュールインスコしなくても標準で使える。もう少し具体的に言うと--disable-dom configureオプションを付けてビルドしてなかったら使える、ってことなのでその辺のレン鯖でも普通は動くので便利です。

インスコ不要なものはデプロイするときに「あれ入れた?」「忘れたー」「あれは入れた?」「忘れたー」「あっちは」「うーん知らない」「氏ね」ループに陥らなくて精神的に大変よろしいと思います。



2.デザイナー/コーダーへの説明が楽

どのテンプレートエンジンにしろ、だいたいそれ用の構文があったりします。無いやつもあるけどだいたいあります。特にSmartyとか人気のやつはだいたいあります。

いずれにしてもテンプレートエンジンを使うとなったら、「ここはテンプレートエンジンの構文なんで変えないでくださいね」「そこも同じなんで以下同文」「あーそれも同じなんで以下同文」「だからそこ変えるんじゃねーよボケ」という不毛な説明を延々と繰り返すハメになることを覚悟する必要がある。世の中には大変素晴らしい企業さんもあるようで、そういう説明が要らないところもあるみたいですが、うち場合デザイナーがいない上、デザイナー/コーダー=お客さんってプロジェクトが大半なので、単に可否の問題でなく営業的な問題であまりこの辺を強く言えない事情もあったりします。なので物分かりのあまり良くないお客さんの場合は延々と不毛な説明するとかえってややこしいので、htmlもらってこっちでテンプレートに変換する退屈な作業を延々と繰り返してます。

でもDOMなら不毛な説明も退屈な作業も不要。id属性とかclass属性とか、テンプレートとして使用する要素がhtmlそのものなので向こうも分かるはず。さすがにこの程度も分からない奴とは一緒に仕事できないのです。



3.DOMなんで覚えるのも簡単

DOMなんでJavaScriptかじってたら多少は知ってるはず・・・て言うかウェブ関係のプログラミングやってれば知らないのはかなり問題。知らんと思ってる人もgetElementByIdとかcreateElementとかがDOMだと言われれば「へぇー、これって2年くらい前に流行ってたよね、2年くらい前に見たわ」と返事してくれることでしょう。

という感じでたぶんDOM自体は知ってると思うので、簡単なサンプルも載せときます。


まずテンプレートとしてexam1.htmlを作ります。モジュールの仕様の関係で、doctypeとmetaタグによるcharsetの指定を省略すると挙動が変わるので省略しないように。

<!doctype HTML>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <div id="message"></div>
  </body>
</html>

次にexam1.htmlを読み込んでid="message"のdivの中身を"あいうえお"に書き換えるスクリプトを作ります。

<?php
$doc = new DOMDocument();
$doc->loadHTMLFile("exam1.html");
$message = $doc->getElementById("message");
$message->appendChild($doc->createTextNode("あいうえお"));
echo $doc->saveHtml();
?>

このスクリプトを動かすと以下の出力が得られます。

<!DOCTYPE HTML>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head>
<body>
    <div id="message">あいうえお</div>
  </body>
</html>

ところどころ改行とスペースが詰められるは、まあそういう仕様なんで諦めてください。スペース入れたいときは&nbsp;使った方が良いですよ、ということです。

もっと詳しいことはPHP: DOM - Manualからどうぞ。



+1.ドキュメントに直接アクセスできる

うちだけの話かもしれないので+1にしたけど、例えばhtmlフォームのラベルとか、ユーザーなんだかデザイナーなんだかよく分からない人が適当にいじくりたいという要望がたまにあります。それでまあフォームの場合、そのラベルをエラーメッセージに埋め込みたいとか言う話になるので、コンフィギュレーションファイルを用意したり結局プログラムで二重持ちしたりしてることがありますが、色々なやましい問題がこの辺で噴出します。

そこでDOMの出番ですよ、と。テンプレートDOMにしとけば、htmlから適当な要素の値を抜いてくれば良いだけですので、この手の問題は全部解決です。


例えばこんな感じのexam2.htmlがあって、

<!doctype HTML>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p id="error" style="display:none"></p>
    <form method="post">
      <label for="username">ユーザー</label>
      <input type="text" id="username" name="username" />
      <input type="submit" />
    </form>
  </body>
</html>

usernameが未入力ならlabelを含んだエラーメッセージを表示する場合はこんなスクリプトで解決できます。

<?php
$doc = new DOMDocument();
$doc->loadHTMLFile("exam2.html");
if (isset($_POST['username']) && !$_POST['username']) {
    $username = $doc->getElementById('username');
    $labels = $doc->getElementsByTagName('label');
    for ($i = 0; $i < count($labels); $i++) {
        $label = $labels->item($i);
        if ($label->getAttribute('for') == $username->getAttribute('id')) {
            $mesg = "{$label->textContent}が未入力です。";
            $error = $doc->getElementById('error');
            $error->removeAttribute('style');
            $error->appendChild($doc->createTextNode($mesg));
            break;
        }
    }
}
echo $doc->saveHtml();
?>

エラーメッセージを含む出力はこんな感じ。ちゃんとメッセージにlabel for="username"の値が表示されます。

<!DOCTYPE HTML>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head>
<body>
    <p id="error">ユーザーが未入力です。</p>
    <form method="post">
      <label for="username">ユーザー</label>
      <input type="text" id="username" name="username"><input type="submit">
</form>
  </body>

</html>


ということで、騙されたと思って一度騙されてください。

*1DOMテンプレート代わりに使うといったことを書いてるブログは確認してますが、流行ってないってところに力点置いてます

2010年05月13日

PHPだけで使ってはいけない関数をチェックする

PHPのtoken_get_all関数を使えば、RATSでPHPの利用すべきでない関数をチェックと似たようなことをPHPだけできるのでさくっと書いてみました。脆弱性チェックを細かく追加していくには不足だと思いますが、http://jp2.php.net/manual/ja/migration53.deprecated.phpに書いてある問題のある関数の存在チェックぐらいならこれでもできますよ、という感じで。とりあえずPHPだけで動くので試すのは簡単だと思います。

まずソース。

<?php

$deprecated_functions = array(
    'call_user_method',
    'call_user_method_array',
    'define_syslog_variables',
    'dl',
    'ereg',
    'ereg_replace',
    'eregi',
    'eregi_replace',
    'set_magic_quotes_runtime',
    'session_register',
    'session_unregister',
    'session_is_registered',
    'set_socket_blocking',
    'split',
    'spliti',
    'sql_regcase',
    'mysql_db_query',
    'mysql_escape_string',
    'mktime',
);

for ($i = 1; $i < $argc; ++$i) {
    $ctx = file_get_contents($argv[$i]);
    if ($ctx === false) {
        exit(1);
    }
    $tokens = token_get_all($ctx);
    foreach ($tokens as $token) {
        if ($token[0] == T_STRING && in_array($token[1], $deprecated_functions)) {
            echo "{$token[1]} at {$argv[$i]} lines {$token[2]}\n";
        }
    }
}

これをdepcheck.phpに保存します。

保存したら以下のソースをsrc.phpとして用意して、

<?php
list($user, $pass, $uid, $gid, $extra) =
    split(":", $passwd_line, 5);
?>

コマンドラインから実行します。

$ php depfunc.php b.php
split at src.php lines 3

$deprecated_functionsにリストされた関数が存在すれば、出現位置を表示します。

2010年05月11日

PHPをクロスサイトスクリプティングできなくするパッチを作ってみた

PHPをクロスサイトスクリプティングできなくするパッチを作ってみました。とっととブツを見たい人はhttp://github.com/xmalloc/php-auto-escapeからどうぞ。



クロスサイトスクリプティングとは

パッチの話に入る前に、クロスサイトスクリプティング(以下XSS)について簡単に説明します。XSSとはあるウェブアプリケーションの入力可能な項目にユーザーが任意のJavaScriptを入力できるようになっている場合に発生する脆弱性のことで、XSS可能なウェブサイトではユーザーが任意のJavaScript*1を埋め込むことが可能になります。

例えば以下のようなPHPスクリプトがあった場合に、$contentに入力フォームなどからユーザーが任意の文字列を入力できる形になっていると、

<p>
<?php echo $content; ?>
</p>

$contentに任意のJavaScriptを埋め込むことができます。

<p>
<script type="text/javascript">alert('XSS');</script>
</p>

この例で埋め込んだコードは'XSS'をalertするだけですが、ウィルスを読み込ませるコードを埋め込むような悪意あるコードも埋め込むことができます。


XSS対策として一般的なのは、PHPからHTMLを出力する際にhtmlspecialchars関数などを使ってすべての変数出力をエスケープすることです。上のPHPコードは以下のように書き換えることでXSS脆弱性を取り除くことができなくなります。

<p>
<?php echo htmlspecialchars($content); ?>
</p>

HTMLが埋め込み可能になってる場合のほか、javascript:スキーマのURLを埋め込むことができたり、任意のCSSを埋め込むことができる場合*2にもXSS脆弱性が存在します。そのようなXSS脆弱性については、htmlspecialcharsでは対応できません。URLの妥当性チェックや、任意のCSSをユーザーから入力できないようにする必要があります。



PHPをクロスサイトスクリプティングできなくするパッチとは

このパッチはPHPに自動エスケープ機能を追加するものです。このパッチを適用したPHPでは、__auto_escape関数を呼び出して自動エスケープの有効/無効を切り替えることができるようになります。自動エスケープを有効にすると、echo、print、printf、vprintf、<?= ?>からの出力はすべて、htmlspecialchars(ENT_QUOTES)によりエスケープしてから出力されるようになります。

以下のPHPスクリプトをパッチを適用したPHPから動かすと、

<?php __auto_escape(1); ?>
<html>
<?php echo "<>&\"'\n"; ?>
</html>

スクリプトの出力は以下の様になります。

<html>

&lt;&gt;&amp;&quot;&#039;

</html>


__auto_escape(1)を呼び出すか、<?php ?>タグの中の出力(<?= ?gt;含む)がすべて自動でhtmlspecialcharsでエスケープされるようになります。__auto_escape(0)を呼び出すと自動エスケープは無効になります。

<?php __auto_escape(1); ?>
<html>
<?php echo "<エスケープされる>\n"; ?>
<?php __auto_escape(0); ?>
<?php echo "<エスケープされない>\n"; ?>
</html>

自動エスケープを有効にした上でエスケープ済みの文字列を出力したい場合は__safe関数が使用できます。__safeは自動エスケープの有効/無効に関わらず、文字列をエスケープせずに出力します。

<?php __auto_escape(1); ?>
<script type="text/javascript">
var x = <?php __safe(json_encode($x)); ?>;
</script>

自動エスケープの有効/無効は、__auto_escape関数以外にphp.iniや.htaccessでも制御できます。__auto_escape ini変数にOnを指定すると、PHP起動時に自動エスケープが有効になります。パッチしていないPHPとの互換性を確保するため、__auto_escape ini変数のデフォルトはOffです。パッチしたソースツリー上のphp.iniファイルに__auto_escapeが追加されてますので、詳しくはそちらをご覧ください。



インストール

PHPのアーカイブをhttp://www.php.net/downloads.phpからダウンロードし、パッチをhttp://github.com/xmalloc/php-auto-escapeからダウンロードしてから、アーカイブとパッチを同じディレクトリに置いて以下のコマンド(PHP-5.3.2の場合)を実行してください。configureのオプションは環境に合わせて適宜設定してください。(パッチにより追加されるconfigureオプションはありません。)

$ tar xvzf php-5.3.2.tar.bz2
$ cd php-5.3.2
$ patch -p0 < ../php-5.3.2-auto-escape.diff
$ ./configure
$ make
$ make install

今のところパッチを用意しているPHPのバージョンは、5.2.12、5.2.13、5.3.2です。



開発経緯とか

最近、既存プログラムを修正するプロジェクトに携わったのですが、すべてのPHPスクリプトにXSS脆弱性が存在する上コード量も結構あり、すべて手直しするのは時間がかかるし修正漏れも発生しそうだったので、PHP自体を改造することにしました。元々Djangoのautoespaceフィルタがみたいな機能がPHPにもあれば便利かなーと思っていたのですが、実際に実装してみるとハンパ無く便利です。普段は以下のようなhtmlspecialcharsのラッパー関数を用意しているのですが、抜けが無いかチェックするのも結構しんどかったりするので、そういう瑣末な作業から開放されるのは気分良いです。

<?php
function xecho($str) {
    echo htmlspecialchars($str);
}

PHP自体にパッチするので共用レンタルサーバとかだとちょっと使うのは難しそうですし、新規プロジェクトならテンプレートエンジンの自動エスケープ機能があればそれを使えば事足りるので、パッチの実用性について若干???な部分もありますが、XSS対策のオプションが増えること自体は悪いことでも無いと思うので公開することにしました。

パッチが既存のPHPの機能と衝突してる箇所は無いはずです。自動エスケープを有効にした場合もob_startによるバッファリングとは干渉しないことは確認しています。何か問題を見つけた方は、このエントリにコメントしていただけると助かります。

*1:VBScriptとかも埋め込めるはずですがw

*2:CSSからJavaScriptを実行できるため

2010年05月04日

そろそろOAuth対応しないとヤベーんじゃねーのと思ってるPHPerに贈るコピペ用コード

ツイッターAPIですが6月30日からBASIC認証がNGになるということで、なんか適当にbotとか作ったんだけどそろそろ対応しないといけないんじゃねーの?と思ってる方もいらっしゃるのではないかと思います。そんなお困りのあなたに今日はコピペ用コードをご用意しました。

以下、BASIC認証をOAuth認証に変更するための大まかな順序です。

  1. OAuthライブラリダウンロードする
  2. OAuthアプリケーション登録する
  3. コードを直す

では具体的な方法について説明しますが、今回説明するのはbot等のユーザー固定のツイッターアプリの認証方法をOAuthに変える方法です。OAuth認証を使って不特定多数のユーザーからウェブサービスを利用できるようにする方法ではありませんのでご注意ください。


OAuthライブラリダウンロードする

一からコーディングしてもいいのですが全部説明するのも面倒なので、その辺に転がってるライブラリを利用させて頂くことにします。探せばPHPのOAuthライブラリも色々あると思いますが、今回はツイッター本家のページからリンクされているTwitterOAuthを利用することにします。(以下の例ではこのライブラリを使用しjsonでツイッターAPIを呼び出していますが、PHP-5.2.10未満のjsonモジュールにはバグがあるため、PHP-5.2.10以降が必要です。この辺については後述します。)

http://github.com/abraham/twitteroauthにアクセスしてアーカイブをダウンロードしてもいいのですが(そうしたい人はどうぞ)、必要なのはOAuth.phpとtwitteroauth.phpの二つだけですので、http://github.com/abraham/twitteroauth/tree/master/twitteroauth/から個別にファイルをダウンロードした方が早いと思います。

とりあえずダウンロードしたら適当なフォルダに保存しておいてください。使い方は後で説明します。


OAuthアプリケーション登録する

ライブラリダウンロードしたらOAuthアプリケーション登録をします。順番的にはこちらを先にしても構いません。

アプリケーション登録はhttp://dev.twitter.com/apps/newから行います。ページにアクセスすると以下の登録フォームが表示されます。

f:id:xmalloc:20100504014631p:image

各項目には以下の内容を入力してください。

  • アプリケーション名: OAuthアプリケーションの名称。OAuth経由でつぶやいたとき、ツイッターのタイムラインにこのアプリ名が表示されます。
  • アプリケーションの説明: とりあえず適当に。
  • アプリケーションのウェブサイトURL: ウェブサイトを持ってる人は自分のサイトのURLをセットしとけば良いです。ツイッターのタイムラインのアプリ名をクリックするとこのURLが開きます。ウェブサイト持ってない人は、自分のtwitterアカウントページとか、上の例みたいにexample.comとかをセットしとけば良いと思います。
  • お知らせ機能: とりあえず空でいいです。
  • あなたの招待状: 今回はBASIC認証からOAuthへの移行のみを例にしていますので、送信にします。不特定多数から使用可能なウェブアプリを作成する場合はブラウザアプリケーションにする必要があります。
  • Default Access type: アプリからツイッターに投稿する場合はRead & Write、しない場合はRead-onlyを指定します。

各項目を入力したら「アプリケーションを登録する」ボタンを押してください。エラーが無ければアプリケーションのページに遷移します。


アプリケーションのページに遷移したら後で必要になる項目を控えておいてください。まずアプリケーションのページのOAuth 1.0a Settingsから、Consumer keyとConsumer secret(以下のモザイクをかけた部分)をメモっておきます。

f:id:xmalloc:20100504014632p:image

次に、アプリケーションのページのサイドバーのMy Access Tokenをクリックし、oauth_tokenとoauth_token_secret(以下のモザイクをかけた部分)をメモっておきます。

f:id:xmalloc:20100504014633p:image

oauth_token_secretとかは人が読める形で保存するなと書いてますが、(繰り返し言いますが非公開前提ですので)華麗にスルーします。


コードを直す

準備が終わりましたので、プログラムの方をいじくります。

例として、home_timelineを読み込む処理を想定します。PHPのcURLモジュールを使用してAPIを呼び出し、jsonモジュールPHPのオブジェクトに変換しています。

<?php
function home_timeline($username, $password) {
    $ch = curl_init('http://api.twitter.com/1/statuses/home_timeline.json');
    curl_setopt($ch, CURLOPT_USERPWD, "{$username}:{$password}");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $ctx = curl_exec($ch);
    if ($ctx === false) {
        curl_close($ch);
        return false;
    }
    $info = curl_getinfo($ch);
    curl_close($ch);
    if ($info['http_code'] != 200) {
        return false;
    }
    return json_decode($ctx);
}

これをBASIC認証をOAuth認証に変えます。ダウンロードしたtwitteroauth.phpとOAuth.phpを同じディレクトリ(もしくは適当なPATH)に配置し、以下のようにコードを書き換え認証をOAuthに変更します。

<?php
require_once 'twitteroauth.php';
$CONSUMER_KEY = 'CONSUMER_KEY';
$CONSUMER_SECRET = 'CONSUMER_SECRET';
function oauth_home_timeline($oauth_token, $oauth_token_secret) {
    global $CONSUMER_KEY, $CONSUMER_SECRET;
    $t = new TwitterOAuth($CONSUMER_KEY, $CONSUMER_SECRET, $oauth_token, $oauth_token_secret);
    $result = $t->get('statuses/home_timeline');
    if ($t->http_code != 200) {
        return false;
    }
    if (isset($result->error)) {
        return false;
    }
    return $result;
}

$CONSUMER_KEYと$CONSUMER_SECRETにはアプリケーション登録時にメモったConsumer keyとConsumer secretをセットしてください。関数の引数の$oauth_tokenと$oauth_token_secretにはMy Access Tokenのoauth_tokenとoauth_token_secretをセットします。この辺の作りについてはあくまでも例ですのでお好きなように。require_onceと、new TwitterOAuthからreturn $resultあたりをコピペして、元のコードに合わせて適当に改造してください。

TwitterOAuthを使用する場合、API呼び出し時のエントリポイントとなるURLhttp://api.twitter.com/1/statuses/home_timeline.json)は、TwitterOAuthが適当に変換してくれます。上の例ではその挙動を利用してTwitterOAuth::getの引数に'statuses/home_timeline'を渡していますが、完全なURLを指定してもちゃんと動きます。


次はpostする例です。呼び出すAPIがupdate.jsonになり、POSTメソッドでHTTPリクエストを発行していること以外は上の例と同じです。

<?php
function post($username, $password, $status) {
    $ch = curl_init('http://api.twitter.com/1/statuses/update.json');
    curl_setopt($ch, CURLOPT_USERPWD, "{$username}:{$password}");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, 'status=' . rawurlencode($status));
    $ctx = curl_exec($ch);
    if ($ctx === false) {
        curl_close($ch);
        return false;
    }
    $info = curl_getinfo($ch);
    curl_close($ch);
    if ($info['http_code'] != 200) {
        return false;
    }
    return json_decode($ctx);
}

これも認証をOAuthに変更します。API呼び出しに使用するメソッドがTwitterOAuth::getでは無くTwitterOAuth::postとなっている点以外については、基本的に上のhome_timelineの例と同じです。

<?php
require_once 'twitteroauth.php';
$CONSUMER_KEY = 'CONSUMER_KEY';
$CONSUMER_SECRET = 'CONSUMER_SECRET';
function oauth_post($oauth_token, $oauth_token_secret, $status) {
    global $CONSUMER_KEY, $CONSUMER_SECRET;
    $t = new TwitterOAuth($CONSUMER_KEY, $CONSUMER_SECRET, $oauth_token, $oauth_token_secret);
    $result = $t->post('statuses/update', array('status' => $status));
    if ($t->http_code != 200) {
        return false;
    }
    if (isset($result->error)) {
        return false;
    }
    return $result;
}

$status引数が投稿するツイートです。($statusにはUTF-8文字列を渡してください。)

実際に投稿するとhttp://twitter.com/xmalloc1/status/13345684719のようになります。通常「webから」等になっている使用クライアント名がアプリケーション登録した際のアプリケーション名となっており、リンク先も登録時のアプリケーションのウェブサイトURLとなっているのが分かります。


補遺 PHP-5.2.10未満の場合

上述した通りPHP-5.2.10未満のjsonモジュールにはバグがあり、PHPのint(マシン依存、通常32bit)を越える数値を扱うことができません。

PHP-5.2.10未満を使用しており、PHPのアップグレードも難しい場合は、XMLでのAPI呼び出しを検討してください。以下はhome_timelineの例をXMLでのAPI呼び出しに変更したものです。TwitterOAuth::formatプロパティを'xml'に変更し、simplexml_load_stringによりPHPオブジェクトに変換します。

<?php
require_once 'twitteroauth.php';
$CONSUMER_KEY = 'CONSUMER_KEY';
$CONSUMER_SECRET = 'CONSUMER_SECRET';
function home_timeline($oauth_token, $oauth_token_secret) {
    global $CONSUMER_KEY, $CONSUMER_SECRET;
    $t = new TwitterOAuth($CONSUMER_KEY, $CONSUMER_SECRET, $oauth_token, $oauth_token_secret);
    $t->format = 'xml';
    $xml = $t->get('statuses/home_timeline');
    if ($t->http_code != 200) {
        return false;
    }
    $result = simplexml_load_string($xml);
    if (isset($result->error)) {
        return false;
    }
    return $result;
}

PHP-5.2.10未満を使用しており、どうしてもjsonでAPIを呼び出したい場合はService_JSON PEARパッケージが使用できます。Service_JSONを使用する場合は、TwitterOAuth::decode_jsonプロパティにfalseをセットしてからAPIコールを行います。TwitterOAuth::get/postが文字列でレスポンスを返しますので、Service_JSONで変換してください。例は省略します。