• 赤色のリンクは、まだ日本語Codexに存在しないページ・画像です。英語版と併せてご覧ください。(詳細

このWikiはいつでも誰でも編集できます

ファイルシステムAPI

提供: WordPress Codex 日本語版
移動先: 案内検索

概要

ファイルシステムAPIWordPress 2.6から、WordPress自身の自動アップデート機能のために開発されました。ファイルシステムAPIは、ファイルシステム上のローカルファイルを読み書きする機能を、異なるホスティング上でセキュアに行うために抽象化します。

WP_Filesystem_Base /enといくつかのそのサブクラスによって、異なるホストをサポートしつつ、ローカルのファイルシステムに接続するための異なる方法が実装されています。テーマやプラグインからファイルをローカルに書き込む際は、WP_Filesystemファミリーのクラスを使用するべきです。

目的

ホスティングシステムごとのウェブサーバーの設定方法によって、異なる制限があります。

特に、多くのホスティングシステム上のウェブサーバーは、WordPressファイルのオーナーとは異なるユーザーで動いています。この場合、ウェブサーバーからファイルを書き込まれる際に、実際のユーザーアカウントではなく、ウェブサーバーのユーザーアカウントがオーナーのファイルが作られます。このことは、複数のユーザーがひとつのウェブサーバーを共有し異なるサイトが動いている共有ホスティングの場合にセキュリティ上の問題を引き起こします。

WP_Filesystemはファイルを書き込むユーザーが異なるかどうかを判別し、FTPかそれに代わる手段に切り替える機能を有しています。利用可能なPHPライブラリーに依存しますが、WP_FilesystemはFTPを利用するための3つの異なる手段(エクステンション、ソケット、SSH経由)をサポートしており、自動的に最適な手段が選択されます。

この場合、プラグインまたはテーマでユーザーにFTPの認証情報を入力させるコードを実装する必要があります。入力フォームの見た目を統一し、実装を簡単にするための関数が用意されています。

ファイルシステムAPIクラスリファレンス

認証情報の取得

WP_Filesystem を使用する最初のステップは、ユーザーに認証情報を要求することです。フォームからの入力を保存する際か、ファイルを書き込むために必要と判断された際に、通常行われます。

認証情報の入力フォームは、次のコードを用いることで管理ページに表示させることができます。

$url = wp_nonce_url('themes.php?page=example','example-theme-options');
if (false === ($creds = request_filesystem_credentials($url, '', false, false, null) ) ) {
	return; // ここで処理を停止
}

request_filesystem_credentials() は5つの引数を取ります。

  • フォームを送信するURL(上記の例ではnonceがつけられたテーマページのURLが使われています)
  • オーバーライドメソッド(通常、空の文字列 "" のままにしておいてください)
  • エラーフラグ(エラーが検出されない限り、通常はfalse。下記参照)
  • コンテキストディレクトリ(false またはアクセスをテストしたい特定のディレクトリパス)
  • フォームフィールド(前のフォームから認証フォームの結果にそのまま渡したいフィールド名の配列、またはそれらがなければnull)

request_filesystem_credentials はまず認証なしにローカルのファイルシステムに直接書き込み可能かどうかをテストします。この場合、この関数は true を返し、何もしません。WP_Filesystem クラスを使って処理を継続することができます。

request_filesystem_credentials は次に wp-config.php ファイル内で定義されているホスト名やユーザー名、パスワードのようなハードコードされたアカウント情報を取得します。これらの値がファイルで定義されている場合は、ユーザーにフォームを表示することなく、これらの情報を返します。

ユーザーからの認証情報の入力が必要な場合は、この関数はFTP情報の入力フォームを出力し、false を返します。この場合、ユーザーに認証情報を入力させるために、その後のプロセスは停止してください。指定されたすべてのフォームフィールド名はフォームの結果に隠し入力フィールドとして含まれ、ユーザーがフォーム、この場合はFTPの認証情報、を再送信した際に戻されます。

注意:予約された名前(hostname, username, password, public_key, private_key)をあなたの独自の入力フィールドに使用しないでください。これらは認証フォームで使われています。これらを使ってしまった場合、request_filesystem_credentials 関数はそれらをFTP認証フォームの入力値として扱います。

認証フォームが送信されると、この関数は送信されたPOSTデータからこれらのフィールドを読み取り、次のステップでそれらを WP_Filesystem に渡すための配列として返します。

WP_Filesystem_Base を初期化

WP_Filesystem を使用する前に、正しい認証情報で初期化する必要があります。次のように行えます。

if ( ! WP_Filesystem($creds) ) {
	request_filesystem_credentials($url, '', true, false, null);
	return;
}

最初に、WP_Filesystem 関数に、取得した認証情報を渡します。次に、認証情報の検証を試みます。問題なければ、true を返します。そうでなければ、false を返します。

認証情報が間違っている場合、上記のコードは、エラーフラグを true にセットして、もう一度 request_filesystem_credentials() を呼び出しています。これによりフォームが再度表示され、さらに情報が間違っていることをユーザーに伝えるエラーメッセージが表示されます。ユーザーは情報をサイド入力し再試行することができます。

WP_Filesystem_Base Class の使用方法

クラスが初期化されると、グローバル変数 $wp_filesystem が定義され、使用可能になります。WP_Filesystem_Base クラスローカルファイルを読み書きするためのいくつかの方法を定義します。例えば、ファイルを書き込むには、次のようにします。

global $wp_filesystem;
$wp_filesystem->put_contents(
  '/tmp/example.txt',
  'ファイルのコンテンツのサンプル',
  FS_CHMOD_FILE // WordPress ファイルのためにあらかじめ定義されたモード
);

そのほかに get_contents() と get_contents_array() がファイルを読み込むために、wp_content_dir() と wp_plugins_dir(), wp_themes_dir() がこれらのディレクトリのファイルシステムパスを取得するために、mkdir() と rmdir() がディレクトリを削除するために、それぞれほかのファイルシステム関連の関数とともに利用可能になります。

ヒントとトリック

request_filesystem_credentials() はいつ呼び出せますか?
開発者がWPファイルシステムAPIを使用する際の最初のチャレンジは、どこでも初期化することができないということです。request_filesystem_credentials()関数はwp_loadedアクションフック以降でしか利用できません。また、管理画面でしか使えません。利用できる最も早いフックはadmin_initです。

WP Filesystem API の方法論
request_filesystem_credentials()を呼び出す際のもう一つの問題は、ファイルシステムに直接アクセスするかユーザーが認証情報を入力するかを決定できないということです。プラグインがアクティベートされる際にファイルを変更しようとした場合に、このことはUXの観点から問題になります。想像してください。ユーザーが管理画面からあなたのプラグインをインストールしようとして、FTP情報を入力し、インストールとアクティベーションを完了させようとします。しかしその直後に、FTP認証フォームが再度表示されると、ユーザーは混乱するでしょう。

より良い解決方法は、たとえば admin_notice などを使って、ユーザーにあなたのプラグインのインストールを完了させるためにファイルシステムに書き込む必要があることを通知することです。この通知に、request_filesystem_credentials() を呼び出すための関数を起動するためのボタンかリンクを追加すると良いでしょう。

しかし、このシナリオをさらに広げて、プラグインをアップデートするたびにファイルシステムへのアクセスが必要な場合を考えてみましょう。アップデートやバグフィクスをリリースするたびに、ユーザーがアップグレードをするたびに、あなたのアクションボタンをクリックさせることになります。request_filesystem_credentials() を呼び出す前に、直接書き込みできる権限があるかどうかを検証し、ユーザーへの通知なしにインストールできたほうが良いですよね。このような場合に、get_filesystem_method() が役立ちます。

$access_type = get_filesystem_method();
if($access_type === 'direct')
{
	/* request_filesystem_credentials() を安全に実行することができますので、URLを渡しても問題ありません */
	$creds = request_filesystem_credentials(site_url() . '/wp-admin/', '', false, false, array());

	/* API の初期化 */
	if ( ! WP_Filesystem($creds) ) {
		/* 問題が発生すれば処理を抜ける */
		return false;
	}	

	global $wp_filesystem;
	/* ファイルの操作を以下に実行する */
}	
else
{
	/* 直接書き込み権限がない場合は、ユーザーに通知を表示する */
	add_action('admin_notice', 'you_admin_notice_function'); 	
}

この方法は、ユーザーが直接書き込み権限を持っていない場合にファイルシステムに変更を加える際には通知が表示され、持っている場合には通知なしでプラグインが処理を継続できますので、両方の場合に良いアプローチです。

パスの操作
WordPress 開発者であれば、プラグインのパスにアクセスするために定数や変数を設定する方法についてご存知でしょう。通常、このように記述します。

define('MY_PLUGIN_DIR', plugin_dir_path( __FILE__ )); 

ファイルシステムAPI との関連で考慮しなければならないことは、そのパスは常に同じではないということです。直接書き込み権限がある場合は MY_PLUGIN_DIR 定数を使用しても問題ありませんが、FTP や SSH を使ってアクセスする際には問題があります。FTP や SSH は別の絶対パスをルートにアクセスするためです。ファイルシステムAPI は $wp_filesystem->wp_content_dir()$wp_filesystem->wp_plugins_dir() といったメソッドを使って、プラグインのパスを重複して定義しなくてもいいように、解決策を提供してくれます。

/* 絶対パスをファイルシステムAPIのパスに変換する */
 $plugin_path = str_replace(ABSPATH, $wp_filesystem->abspath(), MY_PLUGIN_DIR);

/* すべてのファイルシステムAPIメソッドの呼び出しに、$plugin_path を使うことができます */
if(!$wp_filesystem->is_dir($plugin_path . '/config/') 
{
	/* ディレクトリが存在しないので、作成しましょう */
	$wp_filesystem->mkdir($plugin_path . '/config/');
}

unzip_file($file, $to);

この関数はファイルシステムAPIの初期化を必要としますが、$wp_filesystem オブジェクトのメソッドではないため、この変数の引数はちょっと使いにくくなります。最初の $file パラメーターはファイルの直接の絶対パスが必要ですが、$to パラメーターはファイルシステム上の絶対パスへのポイントを必要とします。

define('MY_PLUGIN_DIR', plugin_dir_path( __FILE__ )); 

global $wp_filesystem; /* 事前にファイルシステムAPIの初期化済みとします */

$plugin_path = str_replace(ABSPATH, $wp_filesystem->abspath(), MY_PLUGIN_DIR); /* リモートシステムの絶対パスを取得します */

/* 良い方法 */
$file = MY_PLUGIN_DIR . '/plugin-file.zip'; 
$to = $plugin_path;

$result = unzip_file($file, $to); 

if($result !== true)
{
	/* 解凍に失敗したエラー処理 */
}

/* 悪い方法 */
$file = MY_PLUGIN_DIR . '/plugin-file.zip';
$to = MY_PLUGIN_DIR; /* $to は直接の絶対パスは指定できません。FTP や SSH メソッドに対応できません。 */

unzip_file($file, $to); 

$file = $plugin_path . '/plugin-file.zip'; /* $file が直接の絶対パスではない時、FTP や SSH メソッドを使っていないユーザーに対応できません。 */
$to = $plugin_path;

unzip_file($file, $to); 

外部リファレンス

最新英語版: WordPress Codex » Filesystem_API最新版との差分