おひっこしします。
色々と使いづらかったので、レンタルサーバでWordPress使うことにしました。
てっく★ゆきろぐ Rev2
| 固定リンク
先日の記事で、eregのひとはmb_eregに移行するといいよ、って記事を書きました。
ところがその後。
tweetAngelで、設定した文字列が一致しないということがありまして。
(実は、mb_eregを使用してます(参考))
気になって、こんなコードを書いてみました。
if ( mb_ereg( "メモ" , "メモ。あとで(以下略" ) === FALSE ) {
print "no match.\n" ;
} else {
print "match.\n" ;
}
no match.
もしかして・・・と思って、ちょっと調べたら・・・やっぱりありました!
mb_eregで日本語検索すると・・ : アシアルブログ
mb_ereg系関数を使う際の文字エンコーディング設定がちゃんとなってなかったようです。
どうやら同様の件は、結構はまるポイントのようです。
詳細は上記ブログにて解説がありますのでそちらに譲るといたしまして。
結論言うと、mb_ereg()系関数を使う場合、 mb_regex_encoding() で使用する文字エンコーディングをきちんと指定してあげる必要があります。
そんなわけであっさり解決。
| 固定リンク
| コメント (0)
| トラックバック (0)
twitterで書いたのをそのまま持ち込み。
メモ: Google カレンダーの API とツール - Google Code - http://code.google.com/intl/ja/apis/calendar/メモ GoogleカレンダーのAPIについて書いてあるサイトを教えてください。 特にPHPとの連携があるとうれしいです。個人のブログや掲示板のトピックなどでも結構です。 具体的に.. - 人力検索はてな - http://q.hatena.ne.jp/1182325546メモ(+見てる) Data API Developer's Guide: The Protocol - Google Calendar APIs and Tools - Google Code: http://bit.ly/44JTzz見てるぅ> AuthSub for Web Applications - Accounts APIs - Google Code - http://code.google.com/intl/ja/apis/accounts/docs/AuthSub.htmlメモ: Googleカレンダーの要素定義はここにある。>Common Elements: "Kinds" - Google Data Protocol - Google Code - http://bit.ly/yNAKW
| 固定リンク
まぁ、いままでereg多用しとったわけです。
ereg関数はPHP6.0でコアから消える予定【PHP】 - Programming Magic
そんなわけでereg厨の俺涙目状態、なわけです。
というか、実はeregにはさらにヤバい問題がありまして。
23. 関数とバイナリセーフ - PHP TIPS:ITpro
こちらの説明がわかりやすいので読んでいただければ、どういうことかは理解できると思います。
Cから入ってる人はひっかかりやすい部分だと思います。
とりあえず、実際にコードかいてみました。
<?php
header( "Content-type: text/html ; charset=utf-8" ) ;
?>
<HTML>
<TITLE>TEST</TITLE>
<BODY>
<P>テスト。
<P>\0 を途中に入れるとどうなる?
<P>\0 あり
<?php
$u = "1234567890" . "\x00" . "HOGEHOGE" ;
print "<P>PRINT raw = " . $u . "<br />\n" ;
print "htmlspecialchars = " . htmlspecialchars( $u ) . "<br />\n" ;
print "strlen = " . strlen( $u ) . "<br />\n" ;
print "is_numeric = " . var_export( is_numeric( $u ) , TRUE ). "<br />\n" ;
print "ctype_digit = " . var_export( ctype_digit( $u ) , TRUE ) . "<br />\n" ;
print "ereg(\"[^0-9]+\") = " . var_export( ereg( "[^0-9]+" , $u ) , TRUE ) . "<br />\n" ;
print "mb_ereg(\"[^0-9]+\")=" . var_export( mb_ereg( "[^0-9]+" , $u ) , TRUE ) . "<br />\n" ;
print "preg_match(\"/[^0-9]+/\")=" . var_export( preg_match( "/[^0-9]+/" , $u ) , TRUE ) . "<br />\n" ;
?>
<P>\0 なし
$u = "1234567890HOGEHOGE";
print "<P>PRINT raw = " . $u . "<br />\n" ;
print "htmlspecialchars = " . htmlspecialchars( $u ) . "<br />\n" ;
print "strlen = " . strlen( $u ) . "<br />\n" ;
print "is_numeric = " . var_export( is_numeric( $u ) , TRUE ). "<br />\n" ;
print "ctype_digit = " . var_export( ctype_digit( $u ) , TRUE ) . "<br />\n" ;
print "ereg(\"[^0-9]+\") = " . var_export( ereg( "[^0-9]+" , $u ) , TRUE ) . "<br />\n" ;
print "mb_ereg(\"[^0-9]+\")=" . var_export( mb_ereg( "[^0-9]+" , $u ) , TRUE ) . "<br />\n" ;
print "preg_match(\"/[^0-9]+/\")=" . var_export( preg_match( "/[^0-9]+/" , $u ) , TRUE ) . "<br />\n" ;
?>
<P>\0 なし、数字のみ
$u = "1234567890";
print "<P>PRINT raw = " . $u . "<br />\n" ;
print "htmlspecialchars = " . htmlspecialchars( $u ) . "<br />\n" ;
print "strlen = " . strlen( $u ) . "<br />\n" ;
print "is_numeric = " . var_export( is_numeric( $u ) , TRUE ). "<br />\n" ;
print "ctype_digit = " . var_export( ctype_digit( $u ) , TRUE ) . "<br />\n" ;
print "ereg(\"[^0-9]+\") = " . var_export( ereg( "[^0-9]+" , $u ) , TRUE ) . "<br />\n" ;
print "mb_ereg(\"[^0-9]+\")=" . var_export( mb_ereg( "[^0-9]+" , $u ) , TRUE ) . "<br />\n" ;
print "preg_match(\"/[^0-9]+/\")=" . var_export( preg_match( "/[^0-9]+/" , $u ) , TRUE ) . "<br />\n" ;
?>
</BODY>
</HTML>
テスト。\0 を途中に入れるとどうなる?
\0 あり
PRINT raw = 1234567890HOGEHOGE
htmlspecialchars = 1234567890HOGEHOGE
strlen = 19
is_numeric = false
ctype_digit = false
ereg("[^0-9]+") = false
mb_ereg("[^0-9]+")=1
preg_match("/[^0-9]+/")=1\0 なし
PRINT raw = 1234567890HOGEHOGE
htmlspecialchars = 1234567890HOGEHOGE
strlen = 18
is_numeric = false
ctype_digit = false
ereg("[^0-9]+") = 1
mb_ereg("[^0-9]+")=1
preg_match("/[^0-9]+/")=1\0 なし、数字のみ
PRINT raw = 1234567890
htmlspecialchars = 1234567890
strlen = 10
is_numeric = true
ctype_digit = true
ereg("[^0-9]+") = false
mb_ereg("[^0-9]+")=false
preg_match("/[^0-9]+/")=0
<?php
$u = $_GET['p'] ;
if ( ereg( "[^0-9]" , $u ) ) ) {
// error !
} else {
// ok ! go !
$query = "SELECT * FROM table01 WHERE id=$u" ;
mysql_query( $query , $connection ) ;
(以下略)
http://example.com/request.php?p=12345678%00%20union%20(以下略)
ちなみにこの系列で同様の影響を受けるのが以下の関数。これらはPHP6.0でereg()同様に廃止となります。
・ereg_replace()
・eregi()
・eregi_replace()
・split()
・spliti()
ちなみに正規表現を使わない場合、split()ではなくexplode()を使うといいです(そのぶん高速、かつバイナリセーフ)
この場面の・・・いや、今後の対策としては、
・mb_ereg() にする (いちばん簡単かつ確実)
・preg_match() をはじめとした PCRE関数に転向 書き換える( /〜/ を入れる必要があるので面倒)
・数字なら、is_numeric() とか ctype_digit() とかを使うようにする
あたりでしょうか。
参考:PHPネタ関連メモとか
| 固定リンク
あちらのほうで書いたとおり、昨日参加してきました、わんくま東京勉強会#38。
そこでのライトニングトークの2本目で話した内容についてです。
ちなみに当日使ったスライド(PDF)
まぁ、ソースがわりとひどかったりします(苦笑)。
設定読むのにglobal使ってたりとか、SQLを複数行に分けてかくときの処理が割とひどいとか・・・ねー。
実は当日会場で作ったスライドで、5分という限られた時間のなかでおさえておきたいところだけを言ったんで、細かいところがいろいろとおかしかったりもしますが、そこんとこはご容赦をー。
最近はPHPでもいいフレームワーク(CakePHPとかsymfonyとか)があるのでそちらに頼ればいいんですが、頼らなくても十分なケースは多々あったりするもので、そのときに注意したいことをいろいろと話してみました。
要約するとこう。
(1)入力から処理されるまでのロジック(コード)と、表示ロジック(HTML)は分けよう
コードは前半、表示は後半にはっきりわける。
(2)コード処理では以下の順番で書く
・共通で読み込む処理
・GET/POST/COOKIEからの取得、ならびに値のvalidation check。
あらかじめ、ここで使用する全部の引数に対して、まとめて行っておく。
そのときそのときでやると、ミスする可能性が大きいからです。
※validation checkしてから、実際に使用する変数に代入するとなおよし
(私はこの方法でやってます。チェックずみかどうかを意識したいので)
↑これ、言い忘れてましたw
・入出力データの処理
GET/POST/COOKIEのデータ、ファイル、データベース・・・
(3)表示部分は表示処理(とそれに必要かつ表示にしか使用されない処理)に徹する。
・HTMLタグに使われる文字のエスケープは必須(一部例外を除く)
・ちなみにエスケープ関数は自前で書いてます。
以前htmlspecialcharsを使ったら動作がキモかったので・・・。
(4)データ入出力で特にデータベースを使う場合は、別に関数、出来ればクラスを定義してそこで集中して処理させる
・・・はい、メイン部分でSQLを意識しちゃダメです(笑)。
個人的にはクラス作ってそこで処理させるのが非常に望ましいと思ってます。データの代入・取得とDBへの登録/DBからの取得を1つのインスタンスで出来ちゃうので。
ただ、PHPのクラスは「あとづけ」的かんじがして結構醜い(笑)部分がありますが、そこさえ我慢すれば十分使えると思います。
SQLの特別文字のエスケープはこのクラス/関数内で。SQLを生成する段階でエスケープさせます。
(5)変数名のつけかたに(極力)ルールを持たせる
・私自身の場合、実体データ、配列、表示用データ、クラスのインスタンス、クラス内変数、・・・・といろいろありますが、先頭1〜3文字でわかるようにしています。
話した内容+αは、ここまでー。
あと言いわすれていましたが、これは言っておきたいんで。
・入ってくるデータは信用してはいけない。
特にid等に関しては「○○は弾く」ではなく「○○しか認めない」方式にする。
・「magic_quotes_gpc」はオフにすべき。
正直、入力チェックを徹底している場合、「¥」を勝手に挿入される→取り除くための処理で、かえって邪魔で余計なバグを増やすだけなので(笑)。
今回の件で読んでおいてほしいページとか
・@IT:クロスサイトスクリプティング対策の基本
・今夜分かるSQLインジェクション対策 - @IT
・クッキーに隠されたSQLインジェクション、対策は? - @IT
または、このへんに関連した各サイト。たまに読み返すといいと思います。
参考になりそうなサイト。というかクラスの話が出たので、
・@IT:オブジェクト指向の世界(10)
このへんは、技術というよりは哲学の話ですねー。
| 固定リンク
はじめに断っておきますが、万年カレンダーを作る、ってはなしではありません。
お仕事で祝日判定のルーチンを書くことになりまして。
国民の祝日について
…こんなふうに書きました。
function isholiday( $f_date ) {
// 毎年 mmdd が変わらない日
// 元旦 建国 昭和 憲法 みど こど
$fday_common = array( "0101","0211","0429","0503","0504","0505",
// 文化 勤労 天皇
"1103","1123","1223");
// mmdd が変わる日+国民の休日
$fday_alter = array(
// 2009 成人 春分 振替 海 敬老 国休
"2009" => array( "0112","0320","0506","0720","0921","0922",
// 秋分 体育
"0923","1012") ,
// 2010 成人 春分 振替 海 敬老 秋分
"2010" => array( "0111","0321","0322","0719","0920","0923",
// 体育
"1011") ,
// 2011 成人 春分 海 敬老 秋分 体育
"2011" => array( "0110","0322","0718","0919","0923","1010")
) ;
$yy = substr( $f_date , 0 , 4 ) ;
$mm = substr( $f_date , 5 , 2 ) ;
$dd = substr( $f_date , 8 , 2 ) ;
$mmdd = $mm . $dd ;
if ( in_array( $mmdd , $fday_common ) ) return TRUE ;
if ( in_array( $mmdd , $fday_alter{ $yy } ) ) return TRUE ;
// 以下省略
まぁ、はっきり言って
とかいろいろツッコミどころが多いと思います(苦笑)
まぁ、私としては、
とかいうヌルい考えで組んだわけです(笑)
これだけじゃ、あんまりなんで、ちょっと遊んでみたいと思います。
twitterでこんなこと書いてみました。
そんなわけで、たとえば「1月の第2月曜日は何日になるかを求めるプログラムを書きなさい」とかいう課題は面白そうだとふと思った。
ぱっと思いついたのは、
1月の1日から数えて何回月曜日がくるかを数えて、2回目だったら祝日
という方法。
●年●月●日が何曜日かというのを求めるには、一番有名な方法としては、Zellerの公式、というのがありますが、今回は手抜きしてmktimeとdateでやっちゃいます。
$yy = 2009 ; // 年
$mm = 1 ; // 月
$wnum = 2 ; // 第何週?
$wday=date("w",mktime(0,0,0,$mm,1,$yy));
$target_day = ( $wday > 1? $wnum : $wnum-1 ) * 7 + 2 -$wday ;
こっちのほうがわかりやすいかな。
$target_day = $wnum * 7 + 2 - ( $wday + ( $wday > 1 ? 0 : 7 ) ) ;
$wday>1 なのは、日曜が0、月曜が1、火曜が2、となっているためです。
日曜始まりの暦を見ると、月曜日は2番目に位置しています。だから +2 。
第何週なので、そのぶん*7します。
そこから、$wday (1日の曜日) をひきます。曜日が土曜日に向かうほど、月曜日が近くなりますから。
ざっとですが、コードと解説、かいてみました。
| 固定リンク
PHPのXMLパーサをクラスで使おうとすると、難しいというか、簡単にはうまくいきません。
すでにxml_parseとか使って書いちゃったよ!って場合、泣かされてしまうところです。
けど、PEARのXML_Parserを使うと、移行がわりと簡単にできます。
まず、以前のようにXMLパーサ関数を使った処理の流れは大体こんなかんじ。
・要素の開始・終了時の処理、cdata(文字データ)の処理を行うハンドラ関数を作成する
・xml_parser_create() でXMLパーサを作成
・xml_set_element_handler() で、要素の開始・終了のハンドラを定義する
・xml_set_characer_data_handler() で、cdataハンドラを定義する
・xml_parse() で、XMLドキュメントの処理
・xml_parser_free() でXMLパーサの解放
手抜きしてるけど、ソースコードを例にするとこんなかんじ。
まず、xmlパース処理を呼び出すところをこんなかんじで作っております。
$xmlparser = xml_parser_create() ;
xml_set_element_handler( $xmlparser ,
"xmlparse_h_element_start" ,
"xmlparse_h_element_end" ) ;
xml_set_character_data_handler( $xmlparser ,
"xmlparse_h_data" ) ;
$res = xml_parse( $xmlparser , $xmldata ) ;
xml_parser_free( $xmlparser ) ;
function xmlparse_h_element_start ( $parser , $name , $attrs )
{
/* 中略。ここで element の開始(開きタグ)処理 */
}
function xmlparse_h_element_end( $parser , $name )
{
/* 中略。ここで element 終了(閉じタグ)処理 */
}
function xmlparse_h_data( $parser , $data )
{
/* 中略。ここで 文字データ処理 */
}
これを、移行する方法は、こんなかんじ。
・XML_Parserの派生クラスを作る
・コンストラクタ(__construct)で、最後に「parent::XML_Parser」を呼ぶとき(必ず呼ぶこと!)、2番目の引数を 'event' にするのを忘れない。
・xml_set_element_handler()で定義した要素開始のハンドラ関数の中身を、 startHandler メンバ関数に持ってくる
・xml_set_element_handler()で定義した要素終了のハンドラ関数の中身を、 endHandler メンバ関数に持ってくる
・xml_set_characer_data_handler() で定義したcdataハンドラ関数の中身を、cdataHandler メンバ関数に持ってくる
・必要に応じて、グローバル変数とかを使ってた部分をクラス変数に変更するなど、修正する
・他から呼ぶときは、普段のクラスの呼び出しと同じ。
・初期化:$xmlp = new MyXmlPaser( 'UTF-8' , 'UTF-8' ) ;
・入力データのセット:$xmlp->setInputString( $xmldata ) ;
・XML処理実行:$xmlp->parse() ;
クラス部分はこんなかんじ。
require_once 'XML/Parser.php' ;
class MyXmlPaser extends XML_Parser
{
function __construct( $ca_srcenc , $ca_dstenc ) {
parent::XML_Parser( $ca_srcenc , 'event' , $ca_dstenc ) ;
}
function startHandler ( $ca_parser , $ca_name , $ca_attrs )
{ /* element start 処理 */
}
function endHandler( $ca_parser , $ca_name )
{
/* element end 処理 */
}
function cdataHandler( $ca_parser , $ca_data )
{
if ( $ca_data == FALSE ) {
} else {
/* cdata 処理 */
}
}
}
$xmlp = new MyXmlPaser( 'UTF-8' , 'UTF-8' ) ;
$xmlp->setInputString( $xmldata ) ;
$xmlp->parse() ;
この移行によって、大幅に処理の追加や変更をする場所は(基本的に)ありません。
クラス化することによって、全部クラスに集約できるので、グローバル変数で扱うことがなくて、楽になりました。
| 固定リンク
| コメント (0)
| トラックバック (0)
クラス内でxml_paserを使って・・・と思ったら、どう足掻いても使えないことがわかったので(参考:PHP-users 23513)、pearからXML_Parserを突っ込もうとしたら・・・
なんということでしょう〜('A`)pear install XML_Parser
pear.php.net is using a unsupported protocal - This should never happen.
というわけで調べたら、
pear.php.net is using a unsupported protocal - This should never happen. - Do You PHP はてな
5.2.9と5.2.10がだめくさい。
というわけで、調べたら、
きたよ・・・きたよ・・・あたりのバージョンだよ・・・オワタ\(^o^)/% php -v
PHP 5.2.10 (cli) (built: Jul 1 2009 18:42:15)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
・・・というわけで。自前でPEAR入れる以外の解決策が(当面は)ありませんでしたので、やることにしました。
(※サポートに言えば多分やってくれるとは思うけど)
さくらでpearインストール覚書
を参考にちょちょいとやってみました。
ちょっと古いのか、一部読み替える必要があります。
1. go-pear.php はここから落とす。→http://pear.php.net/go-pear (参考:Manual :: マネージャの取得 )
2.〜9. まではこのままでOK。ちなみに私は.cshrcにこう書いた。
setenv PATH $HOME/php/bin:$PATH
としたときに、which pear
と出ればOKです。/home/〜/bin/pear
pear config-set bin_dir ~/php/bin
pear config-set php_dir ~/php
pear config-set doc_dir ~/php/PEAR/docs
pear config-set test_dir ~/php/PEAR/test
pear config-set data_dir ~/php/PEAR/data
pear update-channel
pear install XML_Parser
| 固定リンク
| コメント (1)
| トラックバック (1)
前回のおはなし。
twitterでOAuthを使う方法(その1:認証まで)
認証までの手順を説明しました。
・前準備:コンシューマの登録
・ユーザからのリクエスト→サービスプロバイダへリクエストトークンを要求
・サービスプロバイダの認証画面へリダイレクト→サービスプロバイダの承認
・サービスプロバイダへアクセストークンを要求
前回の説明で、署名に関して説明不足の点がありました。
リクエストに絡む情報すべて(※1)ですが、
・リクエストヘッダ
・POSTメソッドによる本体
・GETメソッドのquery_string
すべてを、「&」で結んだあとに、一括してurlencodeします。
・リクエストヘッダ「a: 60」「c: 30」「g: 40」こういうふうに与えられてる場合、
・POSTメソッド「b=11」「e=50」
・GETのquery_string「d=24&f=33&h=66」
a=60&b=11&c=30&d=24&e=50&f=33&g=40&h=66というふうになります。
面倒なんで、コードで書くとこんなかんじです。
// make signature --> See 9.2
private function MakeSignature( $ca_method , $ca_request_uri , $ca_header ,$ca_data ,
$ca_consumer_secret , $ca_token_secret ) {
$cl_dataarray = array() ;
// もとになるデータを生成
// Header
if ( $ca_header != NULL ) {
foreach ( $ca_header as $cl_key => $cl_val ) {
$cl_data = $cl_key . "=" . $cl_val ;
array_push( $cl_dataarray , $cl_data ) ;
}
}
// POST body
if ( $ca_data != NULL ) {
foreach ( $ca_data as $cl_key => $cl_val ) {
$cl_data = $cl_key . "=" . $cl_val ;
array_push( $cl_dataarray , $cl_data ) ;
}
}
// query_string for GET
if ( ereg( "\?" , $ca_request_uri ) ) {
$cl_uri_spl = explode( "?" , $ca_request_uri , 2 ) ; // split -> explode
$cl_request_uri = $cl_uri_spl[0] ;
if ( $cl_uri_spl[1] != "" ) {
$cl_req_qry = explode( "&" , $cl_uri_spl[1] ) ;
foreach( $cl_req_qry as $cl_data ) {
array_push( $cl_dataarray , $cl_data ) ;
}
}
} else {
$cl_request_uri = $ca_request_uri ;
}
$cl_count = 0 ;
$cl_dataall = "" ;
sort( $cl_dataarray ) ;
foreach ( $cl_dataarray as $cl_key => $cl_val ) {
if ( $cl_count > 0 ) {
$cl_dataall .= "&" ;
}
$cl_dataall .= $cl_val ;
$cl_count ++ ;
}
$cl_base = $ca_method . "&" . urlencode( $cl_request_uri ) ."&" . urlencode( $cl_dataall ) ;
$cl_base = ereg_replace( "\+" , "%20" , $cl_base ) ; // +ではなく%20で。
$cl_key = $ca_consumer_secret . "&" . $ca_token_secret ;
// HMAC-SHA1 でhash値生成
$cl_hash = hash_hmac( 'sha1' , $cl_base , $cl_key , TRUE ) ;
// 結果の処理
$cl_enc = base64_encode( $cl_hash ) ; // まずはbase64エンコードして
$cl_enc = ereg_replace( '\n' , '' , $cl_enc ) ;
$cl_enc2 = urlencode( $cl_enc ) ; // 続いてurlencodeする( 5.1 )
return $cl_enc2 ;
}
●APIへのアクセス (7)
OAuthを使う場合、APIへのアクセス方法は、
・リクエストヘッダにoAuth関連のパラメータを埋める
・GETのquery stringに埋める
・POSTの送信データに埋める
の3つの方法があります。
twitterの場合、残念ながら(リバースプロキシの関係?)、リクエストヘッダに埋める方法には対応しておりません(503エラーがかえってきます。ついでに、くじらさんが拝めます)。
従って、GET/POSTの(フォーム)データに埋めるしかありません。
与えるパラメータは以下の通りです。
・oauth_consumer_key ・・・ コンシューマのキー
・oauth_token ・・・ステップ4で(正式発行された) アクセストークン
あと、必要なもの
・OAuthのバージョン (oauth_version )
・タイムスタンプ ( oauth_timestamp )
・当該アクセスに対して、一意性を表す文字列( oauth_nonce )
・署名のプロトコル( oauth_signature_method )
・署名( oauth_signature )
そして、
・APIに与えるパラメータ
署名の作成ですが、例によって、署名以外のデータを対象にします。
署名に使うキーですが、 oauth_consumer_secret と oauth_token_secret (ステップ4で発行されたもの) を "&" でつないだものを使います。
リクエストを投げる先は、これまで通りのAPIのURIです。
○あと、気がついたこと。
認証の許可と解除を繰り返したせいかはわかりませんが。
気のせいか、updateのAPIがやたら不安定です。
よく『401 Not Authorized』を返してきます。署名が一致しないようで。
| 固定リンク
| コメント (0)
| トラックバック (0)
OAuthって結構難しいと思われてるようですが、難しいというよりは、『ややこしい』です(苦笑)
そんなわけで。
手順毎に順番に説明をしようと思います。
※2009/09/23 説明の図(手書きでごめんなさい)追加しました。
●語句の説明
・サービスプロバイダ(service provider)・・・サービスを提供しているところ。この場合、twitter。
・ユーザ(user)・・・サービスプロバイダに登録していて、そのサービスを利用している人。
・コンシューマ(consumer)・・・サービスを提供しているところに、ユーザにかわって、そのサービスに対してアクセスする第三者。サードパーティ、とでも言うべきでしょうか。要は、この記事を見て「何か作ってみたい」という、あなたです。
●ステップ0:まずは登録→Cosumer Token/Secretの取得
まずは、アプリケーションの登録作業です。ある程度かたちになってからのほうが望ましいですが、ぶっちゃけ適当でかまいません(笑)
OAuthの仕様書では、この取得に関するプロトコルは定めておりません。
サービスプロバイダとコンシューマの間で直接やりとりしてね、ってことです。
ここから登録できます→http://twitter.com/apps/new
1.「設定」
2.「Connections」
3.右側の「Developers can edit the registration settings for their applications here.」
4.一番下に「Register a new application »」とあるので、こいつをクリック!
と行けば、登録画面に行けます。
たまにくじらさんが出ますが、そのときはリロードしてください。
登録に必要な項目は以下の通りです。
・Application Icon ・・・アプリケーションのアイコンです。アイコンはわりと重要です。
・Application Name ・・・アプリケーション名称です。
・Description ・・・アプリケーションについての説明。あまり長く書けないので簡潔に。
・Application Website ・・・ アプリケーションのサイト。説明してるサイト、もしくはホームを書きます。
・Organization ・・・ 作ってる組織。自分の名前(ニックネーム)でいいでしょう。
・Website ・・・ 作ってる組織のウェブサイト。twitterやってるなら、プロフィールのweb欄と同じで大丈夫。
・Application Type ・・・アプリケーションの種類です。
・Cient・・・クライアントアプリケーション。
・Browser・・・ブラウザベースで使用する場合。webアプリの場合はこちらでOKです。
・Callback URL・・・認証に成功したときにtwitterが戻すURI
・Use Twitter for login・・・twitterのidを認証に使用する場合はチェック
※twitterのidを使って自分のサービスで認証しないときは、チェックする必要はありません。
登録すると、以下の情報がもらえます。
・Consumer key ・・・コンシューマを識別するキー
・Consumer secret ・・・コンシューマの秘密鍵
・Request token URL ・・・ Request token の処理に用いる URI
・Access token URL ・・・ Access token の処理に用いる URI
・Authorize URL ・・・ 認証に用いる URI (今回は使用しない )
登録は以上です。
Consumer key , Consumer secret は、今後の処理で必要なので、忘れずに控えておいて下さい(といっても、自分の作ったアプリ一覧画面で出るから大丈夫だけど )
これからが、実際の「ユーザによる認証」のプロセスとなります。
●ステップ1:ユーザから、サービスプロバイダへのアクセスを「許可したい」と、コンシューマにリクエストが来る
あなたが提供しているサービスに対して、twitterのOAuthを使ってアクセス許可を出したい、というリクエストがきます。
●ステップ2:サービスプロバイダへ利用許可を求める (6.1)
はい、ここからが本番です。
コンシューマ(要は、あなた)は、サービスプロバイダへ「request token」を投げます。
必要な、固有の情報は以下のとおりです。
・コンシューマキー ( oauth_consumer_key )
・ユーザが承認したときに(最終的にコンシューマの使用を許可させるために)差し戻すURI ( oauth_callback )
あと、必要なもの
・OAuthのバージョン (oauth_version )
・タイムスタンプ ( oauth_timestamp )
・当該アクセスに対して、一意性を表す文字列( oauth_nonce )
・署名のプロトコル( oauth_signature_method )
・署名( oauth_signature )
※署名に関してはややこしいので、あとで説明します。
以上の情報を添えて、サービスプロバイダへrequest tokenを投げます。
コンシューマキーと署名の情報が合致した場合、サービスプロバイダは以下の情報を返します。
・oauth_token ・・・ユーザのトークン(仮)
・oauth_token_secret ・・・ ユーザの秘密鍵
・oauth_callback_confirmed ・・・ OKだった場合これが「true」になる
なお、そもそも失敗した場合、HTTPプロトコルの「401」がかえってきますので、成功の可否はこちらで見るべきです。
無事に情報がかえってきた場合、コンシューマ(つまり、あなた)は、ユーザに対して、サービスプロバイダの認証用URIに行くように指示(リダイレクト)してください。
twitterなら、 http://twitter.com/authorize
引数には、さきほど返してきた「oauth_token」を入れます。
oauth_tokenに「hogehoge1234」とついていた場合、
http://twitter.com/authorize?oauth_token=hogehoge1234
というURI、となります。
これにより、サービスプロバイダ(この場合、twitter)の認証画面へ飛びます。
●ステップ3:サービスプロバイダによる許可 (6.2)
認証画面に行くと、「このアプリケーションへの使用許可を出しますか?」という画面になります。
ユーザはここで「Accept(許可する)」を選択します。
すると、サービスプロバイダはユーザに対して、ステップ2でサービスプロバイダに与えた「oauth_callback」へ、行くように指示します(リダイレクト)。
このとき、以下のパラメータを付与します。
・oauth_token・・・ステップ2で戻ってきた oauth_token
・oauth_verifier・・・ユーザがOKしたということを示す(verify) キー
●ステップ4:コールバック→アクセストークンの取得 (6.3)
callbackされたリソースは、oauth_token/oauth_verifierを使って、ステップ2のユーザが「本当にリクエストしてきた」ということを証明するため、もう一度、サービスプロバイダへアクセスします。
・oauth_consumer_key ・・・ コンシューマのキー
・oauth_token ・・・ステップ2で戻ってきた oauth_token(ユーザごとの、ね)
あと、必要なもの
・OAuthのバージョン (oauth_version )
・タイムスタンプ ( oauth_timestamp )
・当該アクセスに対して、一意性を表す文字列( oauth_nonce )
・署名のプロトコル( oauth_signature_method )
・署名( oauth_signature )
※署名に関してはややこしいので、あとで説明します。
※この時点で、oauth_token_secret (ユーザごとの秘密鍵) が存在することを忘れないでください。
このリクエストを投げると、ユーザからのリクエストが正式なものとして扱われ、以下の情報がかえってきます。
・oauth_token ・・・ 『正式の』アクセストークン
・oauth_token_secret ・・・『正式の』アクセストークン秘密鍵
コンシューマは、この2つの情報を保持して、当該ユーザの情報とリンクさせて、サービスプロバイダへのアクセスに使用します。
これで、すべての認証プロセスは終了です。
●最大の問題:署名
一番厄介な部分がここだと思います。
■signature base string ... 署名の対象となる文字列
とりあえず、単刀直入にこんなかんじになります。
・リクエストメソッド(GET/POST等)
・リクエストを投げるURI (?以降は含まない)
・リクエストに絡む情報すべて(※1)
この3つを「&」で結びます。
こんなかんじ。
POST&http%3A%2F%2Fexample.net%2Fapi.php&oauth_consumer_key=dpf43f3p2l4k3l03%26oauth_nonce=kllo9940pd9333jh%26oauth_signature_method=HMAC-SHA1%26oauth_timestamp=1191242096%26oauth_token=nnch734d00sl2jdk%26oauth_version=1.0
このsignature base stringに対して、指定したアルゴリズム(twitterなら、HMAC-SHA1 )で、処理したあと、base64エンコーディングします(改行コード等は取り除く)
これで、署名は完成です。
もし、何か間違いがありましたら、気軽にご指摘いただければな、と思います。
参考文献
・OAuth core 1.0 ・・・オフィシャル
・Yahoo!デベロッパーネットワーク - OAuth - フロー
・APIアクセス権を委譲するプロトコル、OAuthを知る − @IT
| 固定リンク
| コメント (0)
| トラックバック (3)
最近のコメント