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

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

「ファイルシステムAPI」の版間の差分

提供: WordPress Codex 日本語版
移動先: 案内検索
(External References)
(外部リファレンス)
178行目: 178行目:
 
== 外部リファレンス ==
 
== 外部リファレンス ==
 
* [http://ottopress.com/2011/tutorial-using-the-wp_filesystem/ Tutorial: Using the WP_Filesystem] by Otto
 
* [http://ottopress.com/2011/tutorial-using-the-wp_filesystem/ Tutorial: Using the WP_Filesystem] by Otto
 +
* [http://www.sitepoint.com/introduction-to-the-wordpress-filesystem-api/ http://www.sitepoint.com/introduction-to-the-wordpress-filesystem-api/]
  
 
[[Category:上級トピック]]
 
[[Category:上級トピック]]

2015年6月18日 (木) 22:17時点における版

概要

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

WP_Filesystem_Base といくつかのそのサブクラスによって、異なるホストをサポートしつつ、ローカルのファイルシステムに接続するための異なる方法が実装されています。テーマやプラグインからファイルをローカルに書き込む際は、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() を呼び出すための関数を起動するためのボタンかリンクを追加すると良いでしょう。

しかし、このシナリオをさらに広げて、プラグインをアップデートするたびにファイルシステムへのアクセスが必要な場合を考えてみましょう。アップデートやバグフィクスをリリースするたびに、ユーザーがアップグレードをするたびに、あなたのアクションボタンをクリックさせることになります。What would be nice is to determine if we have direct write access before calling request_filesystem_credentials() and silently do the installation. That's where the get_filesystem_method() function comes into play.

$access_type = get_filesystem_method();
if($access_type === 'direct')
{
	/* you can safely run request_filesystem_credentials() without any issues and don't need to worry about passing in a URL */
	$creds = request_filesystem_credentials(site_url() . '/wp-admin/', '', false, false, array());

	/* initialize the API */
	if ( ! WP_Filesystem($creds) ) {
		/* any problems and we exit */
		return false;
	}	

	global $wp_filesystem;
	/* do our file manipulations below */
}	
else
{
	/* don't have direct write access. Prompt user with our notice */
	add_action('admin_notice', 'you_admin_notice_function'); 	
}

This approach works well for all involved. Users who don't have direct write permissions get prompted to make changes to the file system, while the plugin goes unnoticed (in a good way) on sites who can directly write to the file system.

Working with Paths
WordPress developers worth their salt should be familiar with setting up constants or variables to access their plugin's path. It usually looks like this:

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

What you need to take into consideration when working with the Filesystem API is the path to the files won't always be the same. When using the direct method you can safely use the MY_PLUGIN_DIR constant, but if you tried to do the same when the FTP or SSH method is used then you can run into problems. This is because FTP and SSH are usually rooted to a directory somewhere along the absolute path. Now, the Filesystem API gives us ways of overcoming this problem with methods like $wp_filesystem->wp_content_dir() and $wp_filesystem->wp_plugins_dir(), but it isn't practical to define the path to your plugin twice.

/* replace the 'direct' absolute path with the Filesystem API path */
 $plugin_path = str_replace(ABSPATH, $wp_filesystem->abspath(), MY_PLUGIN_DIR);

/* Now we can use $plugin_path in all our Filesystem API method calls */
if(!$wp_filesystem->is_dir($plugin_path . '/config/') 
{
	/* directory didn't exist, so let's create it */
	$wp_filesystem->mkdir($plugin_path . '/config/');
}

unzip_file($file, $to);

While this function requires the Filesystem API to be initialized, it isn't a method of the $wp_filesystem object, which might be why its arguments are at odds with each other. The first parameter, $file, needs to be the absolute 'direct' path to the file, while the $to parameter needs to point to the absolute path of the Filesystem.

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

global $wp_filesystem; /* already initialised the Filesystem API previously */

$plugin_path = str_replace(ABSPATH, $wp_filesystem->abspath(), MY_PLUGIN_DIR); /* get remote system absolute path */

/* Acceptable way to use the function */
$file = MY_PLUGIN_DIR . '/plugin-file.zip'; 
$to = $plugin_path;

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

if($result !== true)
{
	/* unzip failed. Handle Error */
}

/* Not acceptable */
$file = MY_PLUGIN_DIR . '/plugin-file.zip';
$to = MY_PLUGIN_DIR; /* $to cannot be the 'direct' absolute path to the folder otherwise FTP and SSH methods are left in the cold */

unzip_file($file, $to); 

$file = $plugin_path . '/plugin-file.zip'; /* If $file isn't the 'direct' absolute path then users not using FTP and SSH methods are left in the cold */
$to = $plugin_path;

unzip_file($file, $to); 

外部リファレンス

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