A Day In The Boy's Life -85ページ目

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

以前、「OAuthを使ってPHPからTwitterへ投稿する 」とかで、TwitterのOAuthを経由して投稿するPHPプログラムを書きましたが、TumblrもOAuthに対応したということなので、OAuth経由でTumblr上の情報を取得したり、投稿するPHPのスクリプトを書いてみました。


一応、最終系はbotとしても動かせるようになるのですが、Twitterと違いアクセストークンを手動で取得する必要がある(xAuthに対応しているようなので、申請するればそんなことも無いと思いますが)ので、Webサイト上にプログラムの配置と実行ができる環境が必要になります。


なお、OAuth経由でのAPI操作は前回同様にPEARのHTTP_OAuth を使っています。

使い方の詳細は、前エントリに書いてますので、そちらもあわせて参照してください。



Tumblrのアプリケーションを登録する


Twitterの時と同様にアプリケーションの登録が必要です。

Tumblrへログインした状態で、アプリケーション登録サイト へアクセスします。


登録する情報もほとんどTwitterの時と同様です。

アプリケーション名(Application name)や、そのウェブサイト(Application website)、概要(Application description)などを入力します。

OAuth認証する際のコールバックURL(Default callback URL)は、後で解説するアクセストークン取得用のプログラム(get-accesstoken.php)のURLを指定します。

この時点でわからなければ、必須ではないのでブランクのまま一旦登録しても問題ありません。


登録が完了したら、アプリケーションの一覧画面へ遷移します。


- Tumblr Applications
A Day In The Boy's Life-Tumblr-Apps


アプリケーション名のすぐ下に表示されているコンシューマーキーと、「Show secret key」のリンクをクリックすると表示される、コンシューマーシークレットキーの2つをメモっておきます


これでTumblrアプリケーションの登録は完了です。



アクセストークンを取得する


Twitterの場合は、アクセストークンをアプリケーションの管理画面上から取得できるため、そのままbotプログラムに埋め込んで利用することができますが、Tumblrではそれがありません。

なのでbotとして動かしたい場合は、xAuthを使う場合を除いて、予めアクセストークンを取得して利用可能な状態にしておく必要があります。


って事で、まずはアクセストークンを取得するためだけのプログラムを作り、Webサイト上のアクセスできる位置(ドキュメントルート以下)に配置します。


<?php

include 'HTTP/OAuth/Consumer.php';

$consumer_key    = 'Your Consumer Key';
$consumer_secret = 'Your Consumer Secret key';

$http_request = new HTTP_Request2();
$http_request->setConfig('ssl_verify_peer', false);

$consumer = new HTTP_OAuth_Consumer($consumer_key, $consumer_secret);
$consumer_request = new HTTP_OAuth_Consumer_Request;
$consumer_request->accept($http_request);
$consumer->accept($consumer_request);

session_start();

// 最初にアクセスした場合
if (empty($_GET['oauth_verifier'])) {

// リクエストトークンの発行を依頼
    $consumer->getRequestToken('http://www.tumblr.com/oauth/request_token');

// リクエストトークンを取得
    $_SESSION['request_token'] = $consumer->getToken();
    $_SESSION['request_token_secret'] = $consumer->getTokenSecret();

    $auth_url = $consumer->getAuthorizeUrl('http://www.tumblr.com/oauth/authorize');

// Tumblrのアプリケーションの認証を行うページへ遷移
    header("Location: $auth_url");
} else {
// 認証完了後には、oauth_verifierパラメータを付けてデフォルトのコールバックURLへ返ってくる

// リクエストトークンをセット
    $consumer->setToken($_SESSION['request_token']);
    $consumer->setTokenSecret($_SESSION['request_token_secret']);

    $consumer->getAccessToken('http://www.tumblr.com/oauth/access_token', $_GET['oauth_verifier']);

// アクセストークンを取得
    $_SESSION['access_token'] = $consumer->getToken();
    $_SESSION['access_token_secret'] = $consumer->getTokenSecret();

// アクセストークンをブラウザ上に表示
    echo "AccessToken:" . $_SESSION['access_token'] . "";
    echo "AccessTokenSecret:" . $_SESSION['access_token_secret'] . "
"; }


先頭にある、$consumer_keyと$consumer_secret変数内には、先ほどアプリケーション登録した際のキーをそれぞれ入力しておきます。


このプログラムを例えば


http://www.example.com/get-accesstoken.php


へ配置したなら、アプリケーション管理画面に戻り、アプリケーションの編集(アプリケーション名をクリックすると変種可能)から「Default Callback URL」の情報を上記のURLに更新しておきましょう。

準備ができたら、そのURLへブラウザからアクセスしてみます。

すると、アプリケーションの認証画面が表示されるはずです。


- アプリケーション認証画面
A Day In The Boy&#39;s Life-Tumblr-OAuth


画面上の「Allow」ボタンを押して、アプリケーションからのアクセスを許可します。

すると、先ほどのget-accesstoken.phpのプログラムに戻り、ブラウザ上にアクセストークンとアクセストークンシークレットキーが表示されますので、それをまたメモっておきます


アクセストークンを取得するアプリの簡単な流れとしては、コンシューマーキーを使ってTumblrへアクセスし、その後リクエストトークンの発行を依頼します。

リクエストトークンが無事に発行されたら、アプリケーションのOAuth認証画面に遷移させ、そこでアプリケーションを許可すると、コールバックURLへ戻ってきます。

コールバックURLへ戻ってくる際に、oauth_verifierパラメータが付いて戻ってくるので、その情報をと共にアクセストークンの発行依頼を行い、発行されたらブラウザ上に表示するという処理を行ってます。


botとして動かす場合は、一度アクセストークンを取得してしまうと、これらの処理は必要なくなります。

WebサービスとしてTumblrのOAuthを利用する場合でも、一度取得したアクセストークンをDBなどに保存しておけば、次回以降はユーザーに認証させることなしにサービスを利用してもらうことが可能になります。


一度しか使わないプログラムなので、上記の中ではエラーハンドリング等は行ってません。

また、アクセストークンを無事に取得できた後は、このプログラムはWebサイト上から削除しておきましょう



Tumblrから情報を取得するPHPスクリプト


って事で、やっと本題。

今回は、Tumblrのダッシュボードから情報を拾うスクリプトにしています。

適宜、APIのURLやオプションを指定することで、その他の操作も可能です。

詳細は、APIドキュメント も参照してください。


<?php

include 'HTTP/OAuth/Consumer.php';

$consumer_key    = 'Your Consumer Key';
$consumer_secret = 'Your Consumer Secret Key';

$access_token        = 'Your Access Token';
$access_token_secret = 'Your Access Token Secret';

$http_request = new HTTP_Request2();
$http_reques->setConfig('ssl_verify_peer', false);

try {

    $consumer = new HTTP_OAuth_Consumer($consumer_key, $consumer_secret);
    $consumer_request = new HTTP_OAuth_Consumer_Request;
    $consumer_request->accept($http_request);
    $consumer->accept($consumer_request);

// リクエストトークンの発行を依頼
    $consumer->getRequestToken('http://www.tumblr.com/oauth/request_token');

// リクエストトークンを取得
    $request_token = $consumer->getToken();
    $request_token_secret = $consumer->getTokenSecret();

// リクエストトークンをセット
    $consumer->setToken($request_token);
    $consumer->setTokenSecret($request_token_secret);

// 発行済みのアクセストークンをセット
    $consumer->setToken($access_token);
    $consumer->setTokenSecret($access_token_secret);

// ダッシュボードから取得する際のオプション
// 20件目から取得し、30件のデータを一回で取得する
    $params = array('start' => 20,
                    'num'   => 30);

// OAuthを利用してTumblrのAPIからダッシュボードの情報を取得
    $api_url = 'http://www.tumblr.com/api/dashboard';
    $response = $consumer->sendRequest($api_url, $params);

} catch (HTTP_OAuth_Consumer_Exception_InvalidResponse $e) {
// リクエストトークンの取得が失敗した場合
    echo $e->getMessage();
    exit;

} catch (HTTP_OAuth_Exception $e) {
// Tumblrからの読み込みが失敗した場合
    echo $e->getMessage();
    exit;
}

// 投稿した結果を取得
$xml = new SimpleXMLElement($response->getBody());

for ($i = 0; $i < count($xml->posts->post); $i++) {

    $attr = $xml->posts->post[$i]->attributes();

// Tumblrへ投稿された種類ごとに主要な情報を取得
    switch ($attr['type']) {
        case 'regular'      : $text = "[Text] " . $xml->posts->post[$i]->{'regular-body'}; break;
        case 'link'         : $text = "[Link] " . $xml->posts->post[$i]->{'link-text'}; break;
        case 'quote'        : $text = "[Quote] " . $xml->posts->post[$i]->{'quote-text'}; break;
        case 'photo'        : $text = "[Photo] " . $xml->posts->post[$i]->{'photo-caption'}; break;
        case 'conversation' : $text = "[Conversation] " . $xml->posts->post[$i]->{'conversation-text'}; break;
        case 'video'        : $text = "[Video] " . $xml->posts->post[$i]->{'video-caption'}; break;
        case 'audio'        : $text = "[Audio] " . $xml->posts->post[$i]->{'audio-caption'}; break;
        case 'answer'       : $text = "[Answer] " . $xml->posts->post[$i]->{'question'} . "/" . $xml->posts->post[$i]->answer; break;
        default: $text = "unknown";
    }
    echo $text . "\n\n";
}


基本的な処理の流れは「OAuthを通してPHPからタイムラインの情報を取得する 」と同様です。

APIのURLを下記のように変更すれば自分がTumblrへ投稿した情報も取得することができます。


$api_url = 'http://itboy.tumblr.com/api/read';


また、APIから情報を読み込む際のオプション($params)を変更することで、読み込み開始位置や取得件数を変更することもできます。


その他の違いとしては、Tumblrの場合は投稿された情報の種類(type)ごとに、格納されるXMLの要素名が異なります。

APIドキュメントを参照すると8種類のtypeがあるようなので、それぞれの主要な情報を抜き出して表示するようにしています。

その他にも、例えばQUOTEされてた場合はその引用元であったり、ブログ(regular)として投稿されていた場合は、タイトルがあったりもします。

APIドキュメントを参照しながら、適宜必要な情報を抜き出してみてください。



Tumblrへ情報を投稿するPHPスクリプト


今度は、Tumblrへ情報を投稿する場合です。

基本的な流れは同じで、後半に投稿用のAPIを呼び出し、情報をPOSTしています。

ここでは、引用(QUOTE)してTumblrへ投稿する処理を書いています。


<?php

include 'HTTP/OAuth/Consumer.php';

$consumer_key    = 'Your Consumer Key';
$consumer_secret = 'Your Consumer Secret Key';

$access_token        = 'Your Access Token';
$access_token_secret = 'Your Access Token Secret';

$http_request = new HTTP_Request2();
$http_request->setConfig('ssl_verify_peer', false);

try {

    $consumer = new HTTP_OAuth_Consumer($consumer_key, $consumer_secret);
    $consumer_request = new HTTP_OAuth_Consumer_Request;
    $consumer_request->accept($http_request);
    $consumer->accept($consumer_request);

// リクエストトークンの発行を依頼
    $consumer->getRequestToken('http://www.tumblr.com/oauth/request_token');

// リクエストトークンを取得
    $request_token = $consumer->getToken();
    $request_token_secret = $consumer->getTokenSecret();

// リクエストトークンをセット
    $consumer->setToken($request_token);
    $consumer->setTokenSecret($request_token_secret);

// 発行済みのアクセストークンをセット
    $consumer->setToken($access_token);
    $consumer->setTokenSecret($access_token_secret);

// Tumblrへ投稿時のオプション
// Quoteとして投稿する
    $params = array('type'   => 'quote',
                    'quote'  => mb_convert_encoding('ほげほげ', 'UTF-8'),
                    'source' => 'http://ameblo.jp/itboy/');

// OAuthを経由してTumblrの投稿APIへデータを投げる
    $api_url = 'http://www.tumblr.com/api/write';
    $response = $consumer->sendRequest($api_url, $params);

} catch (HTTP_OAuth_Consumer_Exception_InvalidResponse $e) {
// リクエストトークンの取得が失敗した場合
    echo $e->getMessage();
    exit;

} catch (HTTP_OAuth_Exception $e) {
// Tumblrからの読み込みが失敗した場合
    echo $e->getMessage();
    exit;
}


投稿する際のオプション($params)のtypeの中で、Tumblrへ投稿する修理をセットしています。

そして、引用した情報(quote)とその情報源(source)をあわせてセットして、書き込み用のAPIへ投稿しています。


- 実行結果
A Day In The Boy&#39;s Life-Tumblr-write


QUOTE以外の場合に、必要なオプションはAPIドキュメントを参照 してみてください。





ImageMagick は、コマンドライン上から様々な画像処理が行え、JavaやC++やPerl、PHPとこれまた多くのプログラムからもAPIを通して利用することができるソフトウェアです。

Unix/Linuxだけでなく、MacOSやWindows版も用意されています。

 

WindowsやMacOSであれば、多機能な画像処理ソフトがあったりもしますが、画像フォーマットを変更したり、リサイズをしたりと単純な作業を大量に行いたいという場合は、ImageMagickのようなコマンドラインから操作した方が便利かもしれません。

 

 

今回は、Linux環境(CentOS5.5)上でコマンドラインからの操作を中心に書いています。

 

そして、Webサービス上でよく使われるCAPTCHA(数字や文字の画像を表示して入力させるあれ)を作ってみます。

かなりオプションが多い ので、マニュアルもあわせて参照してみてください。

 

ImageMagickがインストールされていない場合は、yumコマンドから

 

 

# yum install -y ImageMagick.i386

 

 

とすることでインストールできるかもしれません。

 

 

 

ImageMagickからCAPTCHAを作ってみる

 

 

 

簡単な数字を並べ多少加工した画像を、コマンドラインから生成して出力してみます。

 

 

$ convert -size 200x50 xc:white -font /usr/share/fonts/ja/TrueType/kochi-gothic-subst.ttf -fill gray -pointsize 32 -gravity center -draw 'text 0,0 "1 4 6 0 7"' -swirl 50 -rotate 10 -fill blue -draw 'line 5,35 95,5' -fill red -draw 'line 20,55 180,45' image.gif

 

 

- 作った画像

 

A Day In The Boy&#39;s Life-CAPTCHA

オプションがいっぱい付いているので、以下その解説。

ちなみに、ImageMagickでは指定したオプションを順番に処理していくため、順番を入れ替えた場合には異なる画像ができあがります

 

□ 新規に画像を作成するオプション

 


まず、新規に画像を作る場合は、下記のようなオプションを指定します。

 

# convert -size 100x100 xc:white image.gif

 

 

上記で、横100px縦100pxのサイズで、背景が白のimage.gifファイルを作成しています。

 

 

 

□ 文字のフォントを指定するオプション

 

 

 

次のfontオプション ではその後のdrawオプションで書く文字のフォントを指定しています。

 

これは、環境内にインストールされているフォントを適当に指定しましょう。

もし、使っているLinux環境にフォントがインストールされていない場合は、フリーで配られているフォントをダウンロードして、サーバー上の/usr/share/fonts/以下の適当なディレクトリにコピーするか、yumで配られているフォントパッケージをインストールすれば使えるようになると思います。

 

# yum install fonts-japanese

 

 

- FreeSerifフォントで描いた場合

 

A Day In The Boy&#39;s Life-CAPTCHA-2

 

□ 文字の色と大きさを指定するオプション

 

 

次の、fillオプションpointsizeオプション はそれぞれ描く文字や線の色と文字の大きさを指定します。

 

上記の場合は、グレーの文字で文字サイズが32ポイントで書くように指定してます。

色はカラー名を指定 することもできますし、頭に#を付けた16進数で指定することも可能です。

(CSS内で色を指定する場合と同様ですね)

 

 

□ 文字のセンター寄せを指定するオプション

 

 

 

gravityオプション にcenterを指定することで文字を画像の真ん中に寄せることができます。

 

ただし、CAPTCHAを作るという意味では、文字の表示位置が固定になるのは、CAPTCHA解析をしやすくなることにもなるので、弱点にもなってしまいます。

文字の出力位置を不定にしたい場合は、次のdrawオプション内で、文字を書く位置を毎回ずらして出力した方が良いかもしれません。

 

 

□ 文字や線を書くオプション

 

 


次に(そして後半に線を書くために指定している)drawオプション では、キャンパス内に文字や線、円やその他の画像を描くことを指定することができます。

最初のdrawオプションでは、引数内にtextを指定することでCAPTCHA用の数字を描いています。

数字だけでは弱いという場合は、この中に英字も含めて出力すればより強固なものになるでしょう。

また、最初の数字にてどこから文字を描くか(X軸とY軸の座標)を指定できます。

これも、毎回キャンバスに収まる範囲で出力位置を変えることでより強固なCAPTCHAを作ることができるでしょう。

 

最後に指定している線(drawオプションの引数にlineを指定)は、CAPTCHAに描いた数字を人間にはわかるがコンピュータにはわかりづらくするために、入れているものです。

 

最初の線は青色で、(5, 35)の位置から(95, 5)の座標まで線を引っ張ってます。

同様に、赤色の線を(20, 55)の位置から(180, 55)の位置まで引っ張っています。

色や引っ張る線の数、そして線の引き方を変えればCAPTCHAを解析されにくくなるかもしれません。

あまりやりすぎると視認性が悪くなって、人も読めなくなりますけどね・・・。

 

- 線の変わりに円を出力してみた例

 

A Day In The Boy&#39;s Life-CAPTCHA-3

 

上記を出力した際のオプションは下記。

 

 

$ convert -size 200x50 xc:white -font /usr/share/fonts/ja/TrueType/kochi-gothic-subst.ttf -fill gray -pointsize 32 -gravity center -draw 'text 0,0 "1 4 6 0 7"' -swirl 50 -rotate 10 -fill none -stroke blue  -draw 'circle 95,50 75,30' -fill none -stroke red -draw 'circle 25,20 10,10' image.gif

 

 

fillオプションにnoneを指定することで円の中を透明にし、淵だけの円を描くことができます。

 

そして、淵の色はstrokeオプション で指定します。

 

 

□ 画像を渦状に加工するオプション

 

 

 

数字をよく見ると少しうねうねしていますが、人が見てわかる範囲のレベルで数字を加工して解析できにくくしています。

 

これは、swirlオプション によるもので、これを指定すると画像を渦状に加工することができます。

渦状に加工するレベルはその引数で指定できますので、視認性が保たれるレベルで出力する文字を加工してみればよいでしょう。

 

 

□ 画像を回転させるオプション

 

 

 

平坦に文字を書いてしまうと、コンピュータからも読みやすいものになってしまいますので、rotateオプション で画像を回転させて、見破られにくいものにしています。

 

これも、キャンバス内に収まる範囲で回転率を毎回違うものに指定すればより強固なCAPTCHAができるかもしれません。

 

 

まとめ

 

 

 

コマンドラインだけでできると書きつつも、オプションに指定する数値やCAPCHAの中身の文字は毎回変えないと意味がありませんので、やはりプログラム内からImageMagickを呼び出して画像を生成するというやり方の方が賢いかもしれません。

 

 

また、複数の画像を重ね合わせたり、文字を1文字ずつ異なる色で描いたりしてみたり、その他のオプションを使って画像をより複雑なものに加工することもできるので、自分なりのCAPTCHAを作ってみるのも楽しいでしょう。

 

何よりコマンドラインからも手軽に画像を生成することができますので、CAPTCHA以外にもImageMagickを応用する方法は多々あると思います。

 

 

 

 

 

wkhtmltopdf を使えば、Webページをコマンド一発でとてもシンプルにPDFや画像に変換することができます。

厳密に言えば、WebページのPDF変換と画像変換はコマンドが分かれており、wkhtmltopdfコマンドを使えばPDFへ、wkhtmltoimageを使えば画像へ変換することができます。

 

Linux版だけでなく、WindowsやMacOS版も用意されています。

 

ただし、2010年9月時点で最新版が0.10.0Beta5ということなので、ちょっとソフトウェア自体の安定度はどうかわかりませんが。

 

 

wkhtmltopdfのインストール

 

 

 

インストールといっても、ファイルを解凍すればバイナリファイルが出来上がるだけなのでとても簡単なんですが、最新の0.10.0ではLZMA形式で圧縮されたファイルになっており、解凍時に注意が必要です。

 

私のテストした環境でもLZMA形式のファイルを取り扱えなかったので、別途xzコマンドをインストールして対応しました。

 

# yum install xz.i386

 

 

xzコマンドを使えばLZMA形式で圧縮されたファイルを解凍できるので、先ほどダウンロードしたファイルを展開します。

 

 

$ xz -d wkhtmltopdf-0.10.0_beta5-static-i386.tar.lzma

$ tar -xvf wkhtmltopdf-0.10.0_beta5-static-i386.tar

 

 

すると、 wkhtmltopdf-i386という名前のバイナリファイルができるので、後はパスが通った適当なディレクトリにコピーしておきます。

 

 

# cp wkhtmltopdf-i386 /usr/local/bin/wkhtmltopdf

 

 

これで、wkhtmltopdfコマンドがどこからでも利用可能となりました。(wkhtmltoimageも同様です)

 

 

 

wkhtmltopdfの使い方

 

 

 

使い方もいたってシンプルなんですが、例えばGoogleのページのPDFファイルに変換したい場合は

 

 

$ wkhtmltopdf http://www.google.co.jp/ google.pdf
Loading pages (1/6)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done

 

 

とします。

 

 

- google.pdf
A Day In The Boy&#39;s Life-GooglePDF変換

 

 

若干メニューの部分がおかしいのですが、GoogleサイトがPDFファイルへ変換されています。

 

ちなみに、wkhtmltopdfコマンドはWebサイトだけでなくローカルのファイルも変換することが可能です。

しかも、HTMLファイルだけでなくテキストなどでも変換可能になっています。

 

 

wkhtmltoimageの使い方

 

 

 

こちらも同様にシンプルに使えます。

 

 

$ wkhtmltoimage http://www.google.co.jp/ google.jpg
Loading page (1/2)
Rendering (2/2)
Done

 

 

デフォルトだと、JPG形式で保存されます。

 

 

- google.jpg

 

A Day In The Boy&#39;s Life-GoogleImage

 

※ 画像サイズはブログ貼り付け用に変更しています。

 

 

その他の画像フォーマットに変換したい場合は

 

 

$ wkhtmltoimage -f png http://www.google.co.jp/ google.png
Loading page (1/2)
Rendering (2/2)
Done

 

 

というように、最初に「-f」オプションを指定します。

 

その他にも、画像の幅や高さ、画像のクオリティなどを指定することも可能です。

詳細は、

 

$ wkhtmltoimage --help

 

 

で、確認してみてください。

 

 

Web魚拓のようにWebサイトの情報を定期的に撮っておきたいような場合には、使えるかもしれませんね。