2009年7月28日火曜日

OAuth調査メモ

OAuthの仕様を理解するための調査のメモなど。


Twitterでの RTの書き方いろいろ

Twitterで他人のつぶやき(Tweet)を再POST(ReTweet)する「RT」。人によって書き方がいろいろ。


基本形


一番多数派のかたち(何かのツールによるもの?)
 RT @xxx: XXXXXX

@リプライの後ににコロンを付けない
 RT @xxx XXXXXX

RTにコロンを付ける
 RT: @xxx XXXXXX

両方コロンを付ける
 RT: @xxx: XXXXXX

コロンの後にスペースを入れない
 RT @xxx:XXXXXX

コロンの前にもスペースを入れる(以前@geekpageさんがやってた)
 RT : @xxx: XXXXXX

小文字で書く
 rt @xxx XXXXXX

@リプライを入れない
 RT XXXXXX


応用編

RTにコメントを付ける
 YYYYYY RT @xxx XXXXXX

コメントを後ろに付ける(海外のユーザーに多い気がする)
 RT @xxx XXXXXX << YYYYYY

RTをさらにRTする際に、RTした人にも@リプライする
 RT @yyy RT @xxx XXXXXX

RTをさらにRTする際に、RTした人は後ろに書く
 RT @xxx XXXXXX (via @yyy)


コメントはRTの後とか@リプライの後とかに入れる人もいる。


参考:RT - Twitter Search

PHPで Twitterの Search APIを使って検索する例

例えばこんな感じ。

<?php
$url = 'http://search.twitter.com/search.json';
$params = http_build_query(array('q' => 'なう', 'lang' => 'ja', 'rpp' => 3));
$results = json_decode(file_get_contents("$url?$params"));

echo '<pre>';
var_dump($results);
var_dump($http_response_header);
echo '</pre>';


PythonやRubyと比べると、PHPは標準関数でいろいろなことができるなーと実感する。


参考:Twitter API Wiki / Twitter Search API Method: search

PHPの URLエンコード (urlencode, rawurlencode, http_build_query)

(2013/5/19 変更:rawurlencode()はRFC3986なのにRFC1738と書いてたので訂正。)


まずはurlencode()rawurlencode()を比較。

  • urlencode()
    • 半角チルダ(~)を%7Eに変換する
    • 半角スペースをプラス(+)に変換する
  • rawurlencode()
    • 半角チルダ(~)の変換についてはPHPのバージョンによって違う
      • PHP 5.2.xまでは、%7Eに変換する
      • PHP 5.3.0からは、%7Eに変換しない(チルダのまま)
    • 半角スペースを%20に変換する

rawurlencode()はRFC1738 RFC3986に沿った変換とされているので、基本的にはurlencode()よりrawurlencode()の方が無難。
ただし、RFC1738 3986ではチルダを%7Eに変換しない。


ちなみに、RFC1738はその後、RFC3986によって更新されているが、RFC3986はパッと見た感じではURLエンコードについては(JavaScriptのencodeURIComponent()で使われるRFC2396の方ではなく、)RFC1738を踏襲しているようだ。(2013/5/19 追記:一部変更されてる。)

Amazonの新しいAPIでも、RFC3986によるURLエンコードを使っている。(参考:Amazon Product Advertising API への対応(PHP版) - もやし日記



次に、http_build_query()の話。
http_build_query()は便利だが、URLエンコードの内容はurlencode()と同じなのが残念。
RFC1738/3986に沿った形にするには、もう1つ変換を咬ませなければならない。
//例
function encodeAlongRFC1738($str) {
return strtr($str, array('%7E' => '~', '+' => '%20'));
}

echo encodeAlongRFC1738(http_build_query($arr));
上記の変換は、PHP5.2までのrawurlencode()にも使える。



あとは実験結果。上記のencodeAlongRFC1738()も交えて。
元の文字
 "~_ _+"

urlencode()の場合
変換結果
 "%7E_+_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると(正しくデコードできない)
 "~_+_+"

rawurlencode()の場合(PHP 5.2)
変換結果
 "%7E_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"

rawurlencode()の場合(PHP 5.3)
変換結果
 "~_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"


urlencode() + encodeAlongRFC1738()の場合
変換結果
 "~_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"


元の配列
 array("test[0]" => "~_ _+")

http_build_query()の場合
変換結果
 "test%5B0%5D=%7E_+_%2B"
urldecode()すると
 "test[0]=~_ _+"
rawurldecode()すると(正しくデコードできない)
 "test[0]=~_+_+"

http_build_query() + encodeAlongRFC1738()の場合
変換結果

 "test%5B0%5D=~_%20_%2B"
urldecode()すると
 "test[0]=~_ _+"
rawurldecode()すると
 "test[0]=~_ _+"

urldecode()はurlencode()に対してもrawurlencode()に対しても使える。



参考:URIに使ってよい文字の話 - RFC2396 と RFC3986 - Text::Easyhacking

PHPでは 0 == 'A' がtrueになる

手元のPHP5.3.0で発現。もしかしたら5.2では起こらないかも。

下記は「0 == 'A'」を評価する際にPHP内部で行われていることの推測

  1. 式を評価する時に両辺のデータの型が違う場合、暗黙の型変換が行われる。
  2. その際に、どちらかが数値だと、もう一方も数値に変換して比較しようとする。
  3. さらに、PHPでは先頭が数字の文字列を数値に変換(キャスト)すると、先頭部分の数値になる(例:"123ABC" → 123)
  4. さらにさらに、先頭が数字でない文字列を数値型に変換する場合、ゼロになる

これにより、「0 == 'A'」は右辺が数値に変換され、先頭に数字が無いのでゼロになり、「0 == 0」になり、trueになる。


同じように「'A' == 0」も「1 == '1A'」もtrueになる。

「'0' == 'A'」や「0 === 'A'」はfalseになる。

PHPを5.3にバージョンアップしたら動かなくなった場合の対処法

Windows上のPHPを5.2から5.3にバージョンアップしたら動かなくなった時にやったこと。
(自分の環境での解決策のメモ)


トラブル1:Apacheを起動する時に下記のようなエラーが出て起動できない

ローカル コンピュータ の Apache2 サービスを開始できません。
エラー 1067: プロセスを途中で強制終了しました。
原因は存在しないextensionをロードする設定になっていることだった。
自分の場合、php_pdo.dllとphp_zip.dllをコメントアウトしたらApacheを起動できるようになった。
(以前、PHP 5.3 RC2に無いエクステンションを書いたことを思い出してやったら動いた。)


トラブル2:PHPのページを呼んでも帰ってこない OR 真っ白のページが表示される
Apacheのアクセスログにもエラーログにも何も記録されていない。PHPのエラーログにも何も書かれない。
ということはPHPのエラーログにエラーを書き出す前にこけてる?そしてApacheはPHPからの処理の戻りを待ち続けてる?

原因は、タイムゾーンの設定をしていないことだった。
date.timezone = Asia/Tokyo
上記設定をしてあげたら無事動くようになった。

これは仕様か?

2009年7月21日火曜日

新たな天才の出現に立ち会えた気がする(動画)

とにかくこの動画を見てみてください。



崖の上のポニョとCoccoのMy Dear Pigを足したような。絵もまた素晴らしい。

2009年7月12日日曜日

Pythonのメソッドのパラメータの不思議

Windows上のPython2.5のPytyon Shellで確認した。

こんなclassがあったとする。

class Test(object):
 def foo(self):
  return [self.bar(), self.bar({'buz': 10})]
 def bar(self, p={'buz': 1}):
  p['buz'] += 1
  return p

下記のように、dict型の引数pに初期値が設定されているメソッドbar()を引数無しで呼ぶと、前回呼んだ時のメソッド内の変数pの値が使われるようだ。
>>> Test().foo()
[{'buz': 2}, {'buz': 11}]
>>> Test().foo()
[{'buz': 3}, {'buz': 11}]

ちょっとびっくり。引数の型がdictの場合だけでなく、配列でも同じことが起きた。


また、classじゃなくても同じ現象になった。
def test(foo={'bar': 1}):
 foo['bar'] += 1
 return foo

>>> test()
{'bar': 2}
>>> test()
{'bar': 3}
>>> test({'bar': 10})
{'bar': 11}
>>> test()
{'bar': 4}
引数を付けた時だけ別になっている。

CakePHPでユニットテスト

CakePHPでユニットテストする場合、標準ではPHPUnitではなくSimpleTestを使う。


1. ダウンロード
SimpleTestはDownloading SimpleTestからtar.gzをダウンロードできる。
(なぜかSoureceForgeの方からはtar.gzがダウンロードできなかった。どうでもいいが上記のページには"... from SourceForget.net ..."と書いてある。ソースのことなど忘れたい...とか?)


2. セットアップ
基本的にCakePHP1.2の本家のリファレンスに沿って進めればセットアップできる。


3. setUp, tearDown
SimpleTestではxUnitと同様にsetUp() tearDown()が使えて、さらにそれに加えていろいろなタイミングで呼ばれるfunctionがあるらしい。
参考:CakePHPでSimpleTest その2 TestSuiteの動きをモデルのテストケースのスケルトンで確認 | ねねとまつの小部屋

<?php
//app/tests/cases/models/member.test.phpの例
App::import('Model', 'Member');

class MemberTestCase extends CakeTestCase {

 function setUp() {
  $this->Member =& ClassRegistry::init('Member');
 }

 function testHoge() {
  $result = $this->Member->hoge('foo');
  $expected = array('baz' => 'bar');
  $this->assertIdentical($result, $expected);
 }
}


4. assert
assertEqual()は"=="で比較するので危険らしい。常にassertIdentical()を使った方が良さそうだ。


5. Caverrage
"Analyze Code Coverage"を見るにはxdebugが必要らしい。


6. Controllerのテスト
$this->testAction()が使える
<?php
class MembersControllerTest extends CakeTestCase {
 function startCase() {
  echo '<h1>テストケースを開始します</h1>';
 }
 function endCase() {
  echo '<h1>テストケースを終了します</h1>';
 }
 function startTest($method) {
  echo '<h3>メソッド「' . $method . '」を開始します</h3>';
 }
 function endTest($method) {
  echo '<hr />';
 }
 //普通に呼び出す
 function testIndex() {
  $result = $this->testAction('/');

}
 //レンダリングしたHTMLを取得する
 function testIndexGetRenderedHtml() {
  $result = $this->testAction('/', array('return' => 'render'));
  //表示して確認
  debug(htmlentities($result));
 }
 //コントローラ内でセットしたデータを取得する
 function testIndexGetViewVars() {
  $result = $this->testAction('/', array('return' => 'vars'));
  $this->assertIdentical($result['fuga'], 'honyarara');
  //表示して確認
  debug($result);
 }
}

参考:コントローラのテスト :: テスト(Testing) :: CakePHPによる作業の定石 :: マニュアル :: 1.2 Collection :: The Cookbook

Linuxで svnにパスワードを保存させない設定

Linuxでsvnを使うと、デフォルトではSubversionサーバへの接続設定がパスワードも含めて全て平文で記録される。
rootに丸見えで気持ち悪い場合もある。

これをやめさせるには、ファイル ~/.subversion/config を編集し、パスワードを保存しないようにする。

store-passwords = no
パスワードだけでなく、なるべく保存される情報を無くしたいなら、auth-credsをnoにする。
store-auth-creds = no

上記設定をしても既に保存された情報は消えないので、 ~/.subversion/auth/svn.simple/ にあるハッシュっぽい名前のファイルを消しておく。


参考:Subversion - Linux Wiki

Google Chromeに Extension(拡張)をインストールするメモ

(2010/01/17追記)
面倒な事をしなくても、現在は下記のように簡単にExtensionが使えるようになるみたいですね。

  1. Google Chrome Extensionsのサイトを表示すると、もし使用中のChromeがExtension非対応の場合はBeta版のインストールを勧められる(英語)
  2. そこからChromeのBeta版をインストールして、Chromeを再起動する

(追記終わり)


Google ChromeでExtension(拡張)を使えるようにするメモ。

  1. Chromeをdev版に切り替える。
    Chrome dev版のダウンロードページ
    からdev版をダウンロードしてインストール。
  2. Extensionを有効にする。
    Chromeのショートカットのプロパティを開き、「リンク先」の最後に「 --enable-extensions」を付ける
    参考:Google Chrome 拡張(Chrome Extension) はてなブックマークのエントリー数を表示する Chrome拡張を作った - 忘れないようにメモ

以上。

ショートカットからChromeを立ち上げ、試しにAdSweepのページでAdSweepをインストールしてみればExtensionが有効になっているか分かる。
はてなブックマークのエントリー数を表示するChrome拡張なぜかインストールできなかった。(2009/08/12変更)インストールできるようになった。コメント欄参照。)

インストールしたExtensionは、chrome://extensions/ を見れば確認できる。


ExtensionはGoogle Chrome Addons, Themes, and Pluginsあたりから入手できるが、まだまだ欲しいものはない状況。
せめてRefControlが欲しいなあ。


参考:Early Access Release Channels ‎(Chromium Developer Documentation)‎

2009年7月5日日曜日

CMANのネットワーク監視が強化されるらしい

CMANのサイトリニューアルのご案内によると、無料でサイトを監視してくれるサービスをリニューアルするらしい。
微妙なバージョンアップだが、無料で続けるそうだ。頑張って欲しい。

2009年7月4日土曜日

RSSフィードを Twitterに POSTしてくれるサービスいろいろ

RSS/ATOMフィードを取得して、それをTwitterにPOSTしてくれるサービスの比較。


twitterfeed

  • この手のサービスでは一番有名。最近リニューアルした
  • OpenIDでログインすればユーザー登録不要
  • OAuthでTwitterとやり取りするのでTwitterのパスワードを預けなくてもよい(OAuthでなくてパスワードを預けてもできるみたい)
  • フィードはRSS2.0かATOMがお勧めらしい
  • フィードのエントリーの日付(pubDate)かGUIDかのどちらで新規投稿を特定するかを選べる
  • エントリーのタイトルをPOSTするか、本文か、その両方かを選べる
  • POSTの先頭と最後にそれぞれ任意の文字列を付けられる。最大20字と書いてあるが、日本語だと6文字程度しか入れられないようだ
  • URL短縮は多くのサービスから選べる。デフォルトはBit.lyで、Bit.lyのAPI KEYを入力すればBit.lyの方でクリック数等を追跡できる
  • 「30分ごと」「1時間ごと」と設定しても、2~3時間ごとにしか処理してくれない。(利用ユーザーが多くて処理が重いから?それともTwitter側による制限?)


RSS2twitter
  • OAuthでTwitterとやり取りするのでTwitterのパスワードを預けなくてもよい
  • 機能はtwitterfeedに近い。フィルタはこっちの方が少し上。いくつかtwitterfeedにはあるがこちらには無い機能がある
  • Prefixに日本語を入れたら文字化けした
  • URL短縮は独自のもの(http://url4.eu/xxx)。なのでクリック追跡もRSS2twitter内で見られる
  • フィードを登録するとすぐにPOSTしてくれるのが良い
  • 参考:RSS2twitterはOAuthで認証してTwitterにフィードを流す - F.Ko-Jiの「一秒後は未来」


HootSuite
  • Twitterをラップしてさらに機能を付加するWebのUI。フィードからPOSTする機能も付いている
  • フィードは5つまでしか登録できない
  • POSTするのはエントリーのタイトルのみ。本文はPOSTできない
  • 1時間ごとに設定してもその通りには処理してくれないのはTwitterfeedと同じ。Twitterfeedより早くPOSTしてくれることもあれば、その逆の場合もある
  • URL短縮はow.ly。これはHootSuiteの関連サービスのようだ。リダイレクトではなく、フレーム内に短縮先ページを表示するのが嫌だ


Pingvine
  • 最短5分間隔
  • シンプルで最低限の機能。ユーザー登録も無し
  • 1つのサービスにつき1つのフィードしか登録できない
  • 登録したがPOSTされない。と思ったら何日か経って忘れた頃にPOSTされ始めた。


Twitterボットを簡単につくれちゃう! Bot Maker(ボットメイカー)
  • 国産
  • シンプルで最低限の機能
  • (試してない)

PHP5.3だと CakePHPで Deprecatedエラーが出まくる問題の対処方法

PHP5.3ではE_ALLにE_DEPREATEDが含まれるので、こんなエラーが出まくる。

PHP Deprecated: Assigning the return value of new by reference is deprecated in ...

そこで、cake/libs/configure.phpの290行目あたりに下記の処理を入れればDeprecatedエラーが出なくなる。
if (isset($config['debug'])) {
 if ($_this->debug) {
  error_reporting(E_ALL);
  //この下のIF文を追加する
  if (error_reporting() > 6143) {
   error_reporting(E_ALL & ~E_DEPRECATED);
  }

ついでに、php.iniでのerror_reportingは「E_ALL | E_STRICT」にしてるけど、CakePHPではE_STRICTが出て嫌だという場合には、httpd.confまたは.htaccessにてCakeのディレクトリのみ下記のようにerror_reportingを設定すればOK。(この値はPHP5.3の場合)
php_value error_reporting 22527


この問題については#6026 (php 5.3 needs error_reporting(E_ALL & ~E_DEPRECATED);) - CakePHPでCakephp1.3に回されて、php 5.3 compatibility? - CakePHP | Google グループでは黙殺されている?


(2009/07/13 追記)
SimpleTestを使う場合、app/webroot/test.phpの28行目あたりにも下記を追加するとテスト時にDeprecatedが出なくなる。
error_reporting(E_ALL);
//この下のIF文を追加する
if (error_reporting() > 6143) {
error_reporting(E_ALL & ~E_DEPRECATED);
}
set_time_limit(0);
(追記終わり)


参考:
 PHP: 定義済み定数 - Manual (エラー定数のバージョンごとの値)

Firefox3.5で最後のタブを閉じてもWindowを閉じないようにする方法

Firefox3.0から3.5にUpdateしたら、全てのタブを閉じたときにFirefoxのWindow自体も閉じるようになってしまった。
(タブバーは常に表示するようにしている。)

これでは使いにくいので調べた。

Closing the only tab closes the windowにあるとおり、about:configで browser.tabs.closeWindowWithLastTab をfalseにすると、3.0までと同じように空のタブを残してくれるようになった。

どうも3.5がBeta版の時から論議が交わされてきた設定らしく、同じように不満を持つ人も少なくないようだ。

ブログ アーカイブ

tags