Google Crisis Response(Google)
災害に関する情報源や、行方不明者情報の収集と検索を行う『パーソンファインダー』を初めとするツールの提供が行われています。

2011年9月17日 土曜日

WordPress の Transients API

Filed under: WordPress,ハック,プログラミング
タグ:, , ,
時間:18時29分
投稿者:よしとも
AddClips 経由でソーシャルブックマークに登録

ウェブアプリケーションでは、一定期間状態を保持したいことが多くあります。それを実現するためにさまざまな方法が提案され、利用されてきました。古くはブラウザに保持させる Cookie、サーバーに保存させるセッション。最近では HTML5 の Web Storage があります。

WordPress には、この一定期間保持するという目的にぴったりのAPI(Application Programming Interface)があります。Transients API と呼ばれるもので、指定した秒数が経過するまでデーターベース上に保持してくれるというものです。保存・取り出し・削除の3つの関数で構成されているシンプルなものです。WordPress 2.8.0 から使えるようになったもので、現在ではコアファイルのさまざまなところで使われています。

使い方については他のサイトを見ていただくとして、この記事ではhackネタを書いてみたいと思います。

まずは、ちょっと長いですが関数の定義部分から。引用元は WordPress 3.2.1 の wp-includes/function.php です。

  1. /**
  2.  * Delete a transient
  3.  *
  4.  * @since 2.8.0
  5.  * @package WordPress
  6.  * @subpackage Transient
  7.  *
  8.  * @uses do_action() Calls 'delete_transient_$transient' hook before transient is deleted.
  9.  * @uses do_action() Calls 'deleted_transient' hook on success.
  10.  *
  11.  * @param string $transient Transient name. Expected to not be SQL-escaped.
  12.  * @return bool true if successful, false otherwise
  13.  */
  14. function delete_transient( $transient ) {
  15.     global $_wp_using_ext_object_cache;
  16.  
  17.     do_action( 'delete_transient_' . $transient, $transient );
  18.  
  19.     if ( $_wp_using_ext_object_cache ) {
  20.         $result = wp_cache_delete( $transient, 'transient' );
  21.     } else {
  22.         $option_timeout = '_transient_timeout_' . $transient;
  23.         $option = '_transient_' . $transient;
  24.         $result = delete_option( $option );
  25.         if ( $result )
  26.             delete_option( $option_timeout );
  27.     }
  28.  
  29.     if ( $result )
  30.         do_action( 'deleted_transient', $transient );
  31.     return $result;
  32. }
  1. /**
  2.  * Get the value of a transient
  3.  *
  4.  * If the transient does not exist or does not have a value, then the return value
  5.  * will be false.
  6.  *
  7.  * @uses apply_filters() Calls 'pre_transient_$transient' hook before checking the transient.
  8.  *  Any value other than false will "short-circuit" the retrieval of the transient
  9.  *  and return the returned value.
  10.  * @uses apply_filters() Calls 'transient_$option' hook, after checking the transient, with
  11.  *  the transient value.
  12.  *
  13.  * @since 2.8.0
  14.  * @package WordPress
  15.  * @subpackage Transient
  16.  *
  17.  * @param string $transient Transient name. Expected to not be SQL-escaped
  18.  * @return mixed Value of transient
  19.  */
  20. function get_transient( $transient ) {
  21.     global $_wp_using_ext_object_cache;
  22.  
  23.     $pre = apply_filters( 'pre_transient_' . $transient, false );
  24.     if ( false !== $pre )
  25.         return $pre;
  26.  
  27.     if ( $_wp_using_ext_object_cache ) {
  28.         $value = wp_cache_get( $transient, 'transient' );
  29.     } else {
  30.         $transient_option = '_transient_' . $transient;
  31.         if ( ! defined( 'WP_INSTALLING' ) ) {
  32.             // If option is not in alloptions, it is not autoloaded and thus has a timeout
  33.             $alloptions = wp_load_alloptions();
  34.             if ( !isset( $alloptions[$transient_option] ) ) {
  35.                 $transient_timeout = '_transient_timeout_' . $transient;
  36.                 if ( get_option( $transient_timeout ) < time() ) {
  37.                     delete_option( $transient_option  );
  38.                     delete_option( $transient_timeout );
  39.                     return false;
  40.                 }
  41.             }
  42.         }
  43.  
  44.         $value = get_option( $transient_option );
  45.     }
  46.  
  47.     return apply_filters( 'transient_' . $transient, $value );
  48. }
  1. /**
  2.  * Set/update the value of a transient
  3.  *
  4.  * You do not need to serialize values. If the value needs to be serialized, then
  5.  * it will be serialized before it is set.
  6.  *
  7.  * @since 2.8.0
  8.  * @package WordPress
  9.  * @subpackage Transient
  10.  *
  11.  * @uses apply_filters() Calls 'pre_set_transient_$transient' hook to allow overwriting the
  12.  *  transient value to be stored.
  13.  * @uses do_action() Calls 'set_transient_$transient' and 'setted_transient' hooks on success.
  14.  *
  15.  * @param string $transient Transient name. Expected to not be SQL-escaped.
  16.  * @param mixed $value Transient value. Expected to not be SQL-escaped.
  17.  * @param int $expiration Time until expiration in seconds, default 0
  18.  * @return bool False if value was not set and true if value was set.
  19.  */
  20. function set_transient( $transient, $value, $expiration = 0 ) {
  21.     global $_wp_using_ext_object_cache;
  22.  
  23.     $value = apply_filters( 'pre_set_transient_' . $transient, $value );
  24.  
  25.     if ( $_wp_using_ext_object_cache ) {
  26.         $result = wp_cache_set( $transient, $value, 'transient', $expiration );
  27.     } else {
  28.         $transient_timeout = '_transient_timeout_' . $transient;
  29.         $transient = '_transient_' . $transient;
  30.         if ( false === get_option( $transient ) ) {
  31.             $autoload = 'yes';
  32.             if ( $expiration ) {
  33.                 $autoload = 'no';
  34.                 add_option( $transient_timeout, time() + $expiration, '', 'no' );
  35.             }
  36.             $result = add_option( $transient, $value, '', $autoload );
  37.         } else {
  38.             if ( $expiration )
  39.                 update_option( $transient_timeout, time() + $expiration );
  40.             $result = update_option( $transient, $value );
  41.         }
  42.     }
  43.     if ( $result ) {
  44.         do_action( 'set_transient_' . $transient );
  45.         do_action( 'setted_transient', $transient );
  46.     }
  47.     return $result;
  48. }

基本的には、2つの項目をセットにしてオプションとして保存しています。項目はデータ自体となる _transient_識別子文字列 と、保持期限となる _transient_timeout_識別子文字列

識別子文字列と値に対してのサニタイズやシリアライズ処理は関数が面倒を見てくれますが、識別子文字列が長い場合は注意が必要です。テーブルのカラムから来る制限で45文字を超えることが出来ないのですが、サニタイズによってこの長さを超えてしまう可能性があります。半角英数を使うのが無難でしょう。

取り出すときには有効期限ないかどうかを確認し(756行目)、期限を過ぎている場合には削除もしてくれます(757・758行目)。Codex を見る限りでは何もしなくても期限が過ぎれば削除してくれるようですが、相当する処理は見つけられませんでした。

オブジェクトキャッシュが有効になっている場合には、データーベースの変わりにそちらを使うので更なる高速化が期待できます。

拙作プラグインの AmazonLink でも試験的に導入してみました。自前で行っていた処理がほとんどいらなくなったおかげで、プログラムがかなり簡略化できています。今のところ問題も起きていないので、このまま次のリリースに入れる予定です。2.8.0以上という条件はありますが、これはお勧めです。

Comments (2)

2011年2月19日 土曜日

WordPress の HTTP API

Filed under: WordPress,プログラミング
タグ:, , , , ,
時間:12時49分
投稿者:よしとも
AddClips 経由でソーシャルブックマークに登録

WordPress には、Snoopy という HTTP 通信用のライブラリが以前から使われています。自前で用意するには結構大変なので、拙作の AmazonLink でも利用しています。

WordPress 2.7.0 では、これに変わるものとして HTTP API が導入されました。ライブラリの変更ではなく、WordPress の持つ機能の1つという扱いです。

導入された段階では実験的な扱いでしたが、次第に多くの部分で使われるようになり、WordPress 3.0 でついに Snoopy が非推奨扱いとなっています。HTTP API が十分熟したと判断したのでしょう。

これを機会に、AmazonLink でも導入してみることにしました。現時点では Snoopy と併用するか完全に切り替えてしまうかは検討中ですが、最終的には完全な切り替えを行うことになると思います。

Snoopy の場合は別のライブラリということで、ファイルのインクルードを行い、Class のオブジェクトを取得し、実際に使用するという3段階の作業が必要です。

  1. include_once(ABSPATH.'wp-includes/class-snoopy.php');
  2. $Snoopy = new Snoopy();
  3.  
  4. $url = 'http://www.example.com';
  5. $Snoopy->fetch($url);
  6. $content = $Snoopy->results;

これに対して、HTTP API の場合は自動的にオブジェクトを取得してくれるので、いきなり実行することができます。WordPress に組み込まれているおかげです。

  1. $url = 'http://www.example.com';
  2. $result = wp_remote_get($url);
  3. $content = $result['body'];

ほかにもいろいろな機能が含まれています。残念ながら本家 Codex でもドキュメントが充実しているとは言えない状況ですので、興味のある方は実際のコードを参照してみてください。ファイルは wp-includes/http.php です。Codex 以上の説明があり、かなり参考になると思います。

ちなみに、自動的にオブジェクトを取得してくれる仕組みですが、内部でそのための関数を呼び出しています。

  1. /**
  2.  * Retrieve the raw response from the HTTP request using the GET method.
  3.  *
  4.  * @see wp_remote_request() For more information on the response array format.
  5.  *
  6.  * @since 2.7.0
  7.  *
  8.  * @param string $url Site URL to retrieve.
  9.  * @param array $args Optional. Override the defaults.
  10.  * @return WP_Error|array The response or WP_Error on failure.
  11.  */
  12. function wp_remote_get($url, $args = array()) {
  13.     $objFetchSite = _wp_http_get_object();
  14.     return $objFetchSite->get($url, $args);
  15. }

その関数の定義はこちら。プライベート関数なので直接利用するのは厳禁です。

  1. /**
  2.  * Returns the initialized WP_Http Object
  3.  *
  4.  * @since 2.7.0
  5.  * @access private
  6.  *
  7.  * @return WP_Http HTTP Transport object.
  8.  */
  9. function &_wp_http_get_object() {
  10.     static $http;
  11.  
  12.     if ( is_null($http) )
  13.         $http = new WP_Http();
  14.  
  15.     return $http;
  16. }

注目するべきは、10行目の static $http; という部分。関数から出てもこの変数は維持され、再利用が可能になります。このような手法をメモ化と言うようです。10年以上プログラムを扱ってきましたが、単語自体知りませんでした。まだまだです。

PHP のメモ化については、次のサイトを参考にしました。

ベンチマーク結果を見るとかなりの高速化が期待できそうです。HTTP 通信を行うプラグインが複数動く場合には効果的かもしれません。最近はコアでも通信を行っているようですし。

Comments (0)

2009年5月31日 日曜日

PHPバージョンアンケート

Filed under: AmazonLink,プログラミング
タグ:,
時間:3時21分
投稿者:よしとも
AddClips 経由でソーシャルブックマークに登録

AmazonLink を Product Advertising API(旧 Amazon アソシエイト Web サービス)に対応させるに当たり、PHPのバージョンの傾向を知るためのアンケートを開始しました。アンケートはサイドバーにも掲載されます。

PHPは4.x がすでに公式に開発終了となっていますが、まだまだ生き残っています。5.x に移行するべきではありますが、サーバー側で対応していなければどうしようもありません。大手レンタルサーバーはすでにかなり対応していますが、4.x しか使えないところも残っているようです。

現時点でどれくらいのサーバーが移行できているのかを知ることが目的です。ご協力よろしくお願いします。

メインサーバーで使えるPHPのバージョンは?
Total Votes: 114 Started: 2009年5月30日 Saturday Back to Vote Screen
Comments (0)

2009年5月10日 日曜日

”Amazon アソシエイト Web サービス”が”Product Advertising API”に

Filed under: AmazonLink,アフィリエイト,プログラミング
タグ:, , , , , , ,
時間:17時46分
投稿者:よしとも
AddClips 経由でソーシャルブックマークに登録

Amazon.co.jp からいろいろな情報を取得することができる”Amazon アソシエイト Web サービス”というサービスがありますが、”Product Advertising API”という名称に変わるとのことです。そして、情報のリクエストには署名による認証が必要になるとのこと。

拙作 WordPress プラグインの AmazonLink でもこのサービスを使用しているので他人事ではありません。

基本方式はほとんど変わらないとのことですが、認証で使用する電子署名の作成には、開発者登録をしたときに作成した Secret Access Key というものが必要になるようです。リクエスト時のデータによって変わるため、電子署名データだけをプログラムに埋め込んでおくことができません。また、Secret Access と言うくらいなのでこれを公開するのも駄目でしょう。

詳しい情報がまだ得られていないのでなんとも言えませんが、ただ使うだけの人にも開発者登録をしてもらわないと駄目になるかもしれません。

今のところは、たつをさんによる記事が一番詳しそう。

電子署名データの作成には RFC 2104-compliant HMAC with the SHA256 hash algorithm という変換処理のようなものが必要で、これを行うための関数である hash は PHP5 でないと標準では使用できません。PHP4 はすでに終了宣言が出ているのですが、まだ PHP5 が使用できないサーバーもあるので悩みどころです。

Comments (0)

2008年5月24日 土曜日

Amazon Web Service の価格情報と発送時期

Filed under: AmazonLink,アフィリエイト,プログラミング
時間:17時25分
投稿者:よしとも
AddClips 経由でソーシャルブックマークに登録

 AmazonLink 2.0 を開発中ですが、価格情報と発送時期の表示で悩んでしまっています。

 基本的に、Amazon Web Service では商品情報を24時間までキャッシュとして所持することが可能です。めったに変更されない情報については1ヶ月まで可能ですが、現時点では24時間を基準として更新するという実装をしています。

 今のところはうまく動いているのでこのまま価格についても実装するつもりだったのですが、途中で価格情報と発送時期はキャッシュ禁止となっていることが判明しました。規約に、other than pricing or availability information とあります。

 キャッシュが出来ないとなると毎回取得することになるのですが、1秒に1回というリクエスト制限があるために表示に時間がかかってしまいます。WordPress プラグインの仕様上記事単位の処理となり、1ページに複数の記事がある場合では1回のリクエストで一括して取得するという方法が使えません。

 現在の選択肢は次の2つ。

  1. 表示時間がかかってもいいから毎回リクエスト
  2. 価格情報および発送時期の表示機能をつけない

 今のところ1のやり方で出来ないかと検討しています。テンプレートに価格情報か発送時期のコードがあるときにだけリクエスト処理をすれば、使う人が選択することが出来ます。プログラムが汚くなりそうなのが心配ですが・・・。

 一番いいのはキャッシュをさせてくれるようになることですね。期限を1時間とか30分とかにしたとしても、アクセスの多い大手ブログでは効果が出ると思うのです。
 規約によると、表示された価格と発送時期を1時間ごとに強制更新する必要があるのだそうです。逆に言えば、1時間は同じままでもいいということですよね。だったら、「価格と発送時期は1時間までキャッシュ可能」とすればいいはず。

 いい解決手段があればぜひご連絡ください。

Comments (0)

2008年3月16日 日曜日

Smarty で date() の書式設定を使う

Filed under: プログラミング
時間:22時39分
投稿者:よしとも
AddClips 経由でソーシャルブックマークに登録

 Smarty というテンプレートエンジンがあります。おそらく、PHP では定番中の定番だと思います。

 この Smarty は私のお気に入りでして、PHP でそれなりの規模のもの(といっても、プログラムとしては小さなものですが)を作るときには必ずといっていいほど使っています。現在製作中のものにも使っているのですが、日付を表示させる部分で不満がありました。1桁の時には10の位の部分が0になったり半角スペースになってしまうのです。

 書式を指定して日付を表示するには date_format という就職子を使うのですが、書式がいまいち充実していなくて思うような表示をさせることができません。データ保持に使っている MySQL のほうがよっぽど多機能だったので、思わずそちらで整形済みの日付を作成してしまいました。しかし、できれば Smarty 側で処理をさせたいと思い、大雑把ですがプラグイン機能を使って実装してしまいました。

実装

 実装したといっても、大したことはやってなかったりします。もともと date_format もプラグインとして実装されていて、内部では PHP の strftime() という組み込み関数を使用しています。冒頭で書いた不満は、この関数の機能に起因します。

 対して、同じ組み込み関数である date() では、1桁の時には1桁で表示するということが可能です。そこで、date_format のファイルを基にして date() を使うようにしてみたというわけです。それが次のコードです。ライセンスは Smarty に従って LGPL となります。

  1. <?php
  2. /**
  3.  * Smarty plugin
  4.  * @package Smarty
  5.  * @subpackage plugins
  6.  */
  7.  
  8. /**
  9.  * Include the {@link shared.make_timestamp.php} plugin
  10.  */
  11. require_once $smarty->_get_plugin_filepath('shared', 'make_timestamp');
  12. /**
  13.  * Smarty date_format modifier plugin
  14.  *
  15.  * Type:     modifier<br>
  16.  * Name:     date<br>
  17.  * Purpose:  format datestamps via date<br>
  18.  * Input:<br>
  19.  *         - string: input date string
  20.  *         - format: strftime format for output
  21.  *         - default_date: default date if $string is empty
  22.  * @author   Yoshitomo
  23.  * @param string
  24.  * @param string
  25.  * @param string
  26.  * @return string|void
  27.  * @uses smarty_make_timestamp()
  28.  */
  29. function smarty_modifier_date($string, $format = 'M d, Y', $default_date = '')
  30. {
  31.     if ($string != '') {
  32.         $timestamp = smarty_make_timestamp($string);
  33.     } elseif ($default_date != '') {
  34.         $timestamp = smarty_make_timestamp($default_date);
  35.     } else {
  36.         return;
  37.     }
  38.     return date($format, $timestamp);
  39. }
  40.  
  41. /* vim: set expandtab: */
  42.  
  43. ?>

 この内容を、modifier.date.php というファイル名で保存して、Smarty のプラグインディレクトリに置いてください。使い方は書式が date() に従うというだけで、あとは date_format と同じです。

[Smarty]
{$date_value|date:”Y年n月j日”}
[/Smarty]

残る不満

 無事便利になったわけですが、分と秒に関しては結局満足できる結果にはなりませんでした。この2つの項目は、なぜか1桁で表示するという書式設定ができません。
 書式の表をよく見てみると、小文字のときは0がついて、大文字の時には0がつかないと言うようになっていることがわかります。そして、分と秒に対する0のつく場合の文字としては i と s があり、その大文字である I と S はすでに別の項目で使われてしまっています。大文字と小文字の対応を崩したくないために実装していないのではないかと、思わず疑ってしまいました。

 I も S も、日本ではあまり需要がない項目であるのがなんとも残念です。時間を見て実装をと思っていますが、もしすでにあってご存知でしたらぜひ教えてください。

Comments (0)

HTML convert time: 0.348 sec. Powered by

Images is enhanced with WordPress Lightbox JS by Zeo