Page No.2

ところでと・・・。
管理画面の中であれば、使用方法はわかりました。
しかし、それならば通常のアクセスしたページにおいてはどうすればいいのだろうかと。
たとえば、アクセスログなんぞをとるときですね。
ネットでちょっと調べてみると、ちゃんと教えてくれている方がいてすぐに見つけることが出来ます。
これにて機能するということです。

<?php
	// WP_Filesystemのを使用するためにはファイルの読み込みが必要
	require_once(ABSPATH . 'wp-admin/includes/file.php');

	// WP_Filesystemの初期化
	if ( WP_Filesystem() ) {

		// $wp_filesystemオブジェクトの呼び出し
		global $wp_filesystem;

		...処理を書く
		...
	}
?>
PHP
CopyExpand

ためしに以下のようなコードを作って、さきのテーマのオプションを読み込んだり設定したりするクラスの中にいれて、クラス読み込みの時に実行されるようにしてみました。

<?php
	private function save_access_log() {
		if ( ! is_user_logged_in() ) {
			$cdt = date( 'Y/m/d H:i:s' );
			$ipadrs = $_SERVER['REMOTE_ADDR'];
			$hpadrs = $_SERVER['REQUEST_URI'];
			$hname = gethostbyaddr( $ipadrs );
			$refer = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
			$agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';

			if ( false !== strpos( $agent, 'bot') or false !== strpos( $agent, 'crawl' ) or false !== strpos( $agent, 'search' )  or false !== strpos( $hname, 'bot' )) {
				return;
			}

			// WP_filesystem
			require_once(ABSPATH . 'wp-admin/includes/file.php');

			//WP_Filesystemの初期化
			if ( WP_Filesystem() ) {

				//$wp_filesystemオブジェクトの呼び出し
				global $wp_filesystem;

				$data = $cdt . '~' . $ipadrs . '~' . $hname . '~' . $agent . '~' . $refer . '~' . $hpadrs . "\n";
				$filnam = get_stylesheet_directory() . '/log/accesslog.php';

				$wp_filesystem->put_contents( $filnam, $data );
			}

		}
	}
?>
PHP
CopyExpand

確かに、これでちゃんと機能します。
しかし、何度かやっていると意図に反していることに気が付きます。ファイルにデータが加えられて蓄積されているのではなく、常に一行だけのファイルになってしまうということ。
う~む、これはモードの問題か?と、思いつつ、こうなったら腰を据えてじっくりとファイルの中身を見てみようという気になります。
「WP_Filesystem() 」「wp-admin/includes/file.php 」 の中に書かれています。
「get_filesystem_method() 」「request_filesystem_credentials() 」も同じファイルです。
管理画面においてはcodex にあったものをそのまま使用したわけですが、その時は「request_filesystem_credentials() 」を使用していました。これに関しては、説明書きが
「Displays a form to the user to request for their FTP/SSH details in order to connect to the filesystem. 」 「ファイルシステムに接続するために、ユーザーに彼らのFTP/SSHに関しての詳細を要請するためにフォームを表示します。」 と、いう事だと思うので、普通にサイトにアクセスしてくる不特定の方々に対して使うことではないですね。
で、「WP_Filesystem() 」がなにをやっているかと探っていくと、

<?php
	function WP_Filesystem( $args = false, $context = false, $allow_relaxed_file_ownership = false ) {
		global $wp_filesystem;

		// class-wp-filesystem-baseはWP_Filesystemのクラスのベースとなるファイル
		// 他のclass-wp-filesystem-$method はこのクラスのextend用のファイル
		require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php');
	
		$method = get_filesystem_method( $args, $context, $allow_relaxed_file_ownership );
	
		if ( ! $method )
			return false;
	
		if ( ! class_exists( "WP_Filesystem_$method" ) ) {
	
			/**
			 * Filters the path for a specific filesystem method class file.
			 *
			 * @since 2.6.0
			 *
			 * @see get_filesystem_method()
			 *
			 * @param string $path   Path to the specific filesystem method class file.
			 * @param string $method The filesystem method to use.
			 */
			$abstraction_file = apply_filters( 'filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method );
	
			if ( ! file_exists($abstraction_file) )
				return;
	
			require_once($abstraction_file);
		}
		$method = "WP_Filesystem_$method";
	
		$wp_filesystem = new $method($args);
		...つづく
		...
?>
PHP
CopyExpand

と、もう少しつづきますが、このあたりまででよさそうです。
まぁ、割とさっぱりしてます。やはり9行目のget_filesystem_method()がみそですね。
get_filesystem_method()の戻り値の$method false であれば、すぐに処理を中止し、$method により得られるクラスが存在しない時はフィルターフックを用意しつつクラスの存在しうるファイル名を取得し、そのファイルが存在しなければこれまた処理を中止し、 あればファイルを読み込んで、$method により得られたクラスのインスタンスを作って変数$wp_filesystem に入れておくということです。
しかしてその「get_filesystem_method()」が何者かとみてみると、
注:下記英注釈の訳は全て私によるものです。

<?php
	function get_filesystem_method( $args = array(), $context = '', $allow_relaxed_file_ownership = false ) {

		// Please ensure that this is either 'direct', 'ssh2', 'ftpext' or 'ftpsockets'
		// これが 'direct', 'ssh2', 'ftpext' or 'ftpsockets' のどれかを確認してください
		$method = defined('FS_METHOD') ? FS_METHOD : false; 
	
		if ( ! $context ) {
			$context = WP_CONTENT_DIR;
		}
	
		// If the directory doesn't exist (wp-content/languages) then use the parent directory as we'll create it.
		// wp-content/languagesディレクトリが存在しない場合、我々が作成するであろう親ディレクトリを使用します。
		if ( WP_LANG_DIR == $context && ! is_dir( $context ) ) {
			$context = dirname( $context );
		}
	
		$context = trailingslashit( $context );
	
		if ( ! $method ) {
	
			$temp_file_name = $context . 'temp-write-test-' . time();
			$temp_handle = @fopen($temp_file_name, 'w');
			if ( $temp_handle ) {
	
				// Attempt to determine the file owner of the WordPress files, and that of newly created files
				// WordPressファイルの所有者と新しく作成されたファイルの所有者を確定するための試み
				$wp_file_owner = $temp_file_owner = false;
				if ( function_exists('fileowner') ) {
					$wp_file_owner = @fileowner( __FILE__ );
					$temp_file_owner = @fileowner( $temp_file_name );
				}
	
				if ( $wp_file_owner !== false && $wp_file_owner === $temp_file_owner ) {
					// WordPress is creating files as the same owner as the WordPress files,
					// this means it's safe to modify & create new files via PHP.
					// WordPressはWordPressファイルと同じ所有者のファイルを作成した。
					// これが意味するところは、PHPによりファイルの変更や新規作成が安全であるということ。
					$method = 'direct';
					$GLOBALS['_wp_filesystem_direct_method'] = 'file_owner';
				} elseif ( $allow_relaxed_file_ownership ) {
					// The $context directory is writable, and $allow_relaxed_file_ownership is set, this means we can modify files
					// safely in this directory. This mode doesn't create new files, only alter existing ones.
					// $contextディレクトリが書き込み可能であり、$allow_relaxed_file_ownershipがセットされているということは、
					// このディレクトリのファイルは安全に変更できるということである。このモードは存在するファイルの変更だけであり新規作成は出来ない。
					$method = 'direct';
					$GLOBALS['_wp_filesystem_direct_method'] = 'relaxed_ownership';
				}
	
				@fclose($temp_handle);
				@unlink($temp_file_name);
			}
	 	}
	
		if ( ! $method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') && function_exists('stream_get_contents') ) $method = 'ssh2';
		if ( ! $method && extension_loaded('ftp') ) $method = 'ftpext';
		if ( ! $method && ( extension_loaded('sockets') || function_exists('fsockopen') ) ) $method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread
	
		/**
		 * Filters the filesystem method to use.
		 *
		 * @since 2.6.0
		 *
		 * @param string $method  Filesystem method to return.
		 * @param array  $args    An array of connection details for the method.
		 * @param string $context Full path to the directory that is tested for being writable.
		 * @param bool   $allow_relaxed_file_ownership Whether to allow Group/World writable.
		 */
		return apply_filters( 'filesystem_method', $method, $args, $context, $allow_relaxed_file_ownership );
	}
?>
PHP
CopyExpand

定数FS_METHOD の値を確認してくださいと書いてあるので自サイトとローカルな環境で確認してみましたが、いずれもfalse でした。と、いうのは当然ですね。これはwp-config にて設定する値であり、してないのでなくて当然です。codex を見ても、「一般にアップデートで問題が発生する場合にのみ変更してください。」と、書いてあるぐらいなので、定義していないのが普通なのでは。
と、いうことで20行目のif ( ! $method ) は大体において合致するもので、ここから53行目までが重要なところということだと思います。
WordPress により新規にファイルを作成し、そのファイルの所有者と、WordPress 自体のファイルの所有者が同じであれば、PHPによるファイルの変更や新規作成が安全であるということなんだそうですが、なんだかいまひとつよくわからないのです。
共有サーバーにおいて別の所有者のディレクトリにファイルを作るときに、果たしてこのシステムを動かしているのだろうかと。ただ単に、間違えてしまうことを避けるためだけのことなんだろうか。
まぁ、よくわかっていないから、頼っていたほうがいいんだろうと思います。

codex 「wp-config.php の編集」のページのFS_METHODのところでも最優先のデフォルトは”direct”ということですが、実際に$method の値はどうなのかと、自サイトとローカルで値を得てみるとやはりというか当然と言うことなのか”direct”でしたね。
と、いうことなので適用されているWP_Filesystem のクラスは、WP_Filesystem_Direct であり、ファイルはclass-wp-filesystem-direct.php だということがわかりました。
いざ、class-wp-filesystem-direct.php の中の、put_contents() を見てみると、思った通りですね。

<?php
	$fp = @fopen( $file, 'wb' );
?>
PHP
CopyExpand

と、fopen のモードが'wb'になっています。'w'はファイルポインタを先頭にするので、最後に追加ということにはなりえないです。この関数を見る限りにおいてはこのモードを変更することはできないです。他のクラスのファイルの中を調べてみても、それようの関数は見当たりませんでした。

さてどうしたものかと考えていると、そういえばWP_Filesystem にフィルターフックがあったなぁ、と。
WP_Filesystem の説明書きにも、
「Plugins may add extra transports, And force WordPress to use them by returning the filename via the {@see 'filesystem_method_file'} filter.」
「プラグインは、特別なトランスポートを追加し、そしてフィルタを介してファイル名を返すことによって(フィルターフック 'filesystem_method_file'を見るべし)、ワードプレスにそれらを使用するようにさせることができます。」
と、いう感じでしょうか。

あらためてWP_Filesystem() を見ると、get_filesystem_method()の戻り値$method によって得られるクラスを、実際に$wp_filesystem として使用するということです。そしてその部分にフィルターフックが用意してある。これは、このフィルターフックを使えば、使用させるクラスを書いたファイルをディレクトリを含めて指定できるものと思われます。
再び、あらためてget_filesystem_method()を見れば、最後にある、$method を引数として得られるフィルターフック 'filesystem_method' において、自分が作成したクラスを使用させるために、そのファイルの名前の固有の部分を$method として指定してやればできそうだと思われます。

どちらで指定するかですか、実際にやってみるとget_filesystem_method()フィルターフック 'filesystem_method' を使って、$method の値を変更してもできます。ただしこの場合WordPress は指定されたファイル"class-wp-filesystem-$method.php" を、/wp-admin/includes/にて探しますから、$method には固有の文字列を指定し、その文字列にて識別できるファイルを/wp-admin/includes/に用意する必要があります。
また、WP_Filesystem() フィルターフック 'filesystem_method_file' を使用しても、$method の値は”direct”のままで、自作のテーマフォルダにコピーして独自の関数をくわえたテーマフォルダにあるclass-wp-filesystem-direct.php を指定してやることでできました。
もちろん両方を使えば、$method の値も変更し、/wp-admin/includes/ではないフォルダにおいた"class-wp-filesystem-$method.php" のファイルを指定することも可能でした。
しかし、$method の値は変更せず(get_filesystem_method()フィルターフック 'filesystem_method' は使用せずに)、WP_Filesystem() フィルターフック 'filesystem_method_file' だけを使用して、独自の名前を付けた、たとえばclass-wp-filesystem-sanbanze.php といったファイルを、/wp-admin/includes/ではないフォルダにおいた場合、そのファイルを指定することはできませんでした。エラーが出てしまいます。コードを見る限りそれもできそうではあったのですが、ダメでした。

$method の値は、どうしてもそうすることが必要ということでないのなら、システム的にもあまり変更しないほうが良いような気がします。ただ、普通にサイトにアクセスするぶんには、ファイル操作などするわけも無く、file.php すら読み込んでいない状態なので、別段、なんら問題無いようにも思えます。正直なところ、よくわかりません。
まぁ、なんとなくではありますが、WP_Filesystem() フィルターフック 'filesystem_method_file' を使用して、テーマフォルダにある独自の関数をくわえたclass-wp-filesystem-direct.php を指定してやる方法が良いように思いましたのでそれでやりました。
ただねぇ、これだと「Theme Check」からおしかりをうけてしまうのですが・・・ね。
とりあえず、/wp-admin/includes/にあるclass-wp-filesystem-direct.php を、我がテーマフォルダにコピーして、ファイルの最後に追加するためのadd_contents()関数をくわえました。

<?php
/**
 * WordPress Sanbanze Theme custom Filesystem.
 * @package WordPress
 * @subpackage Filesystem
 *
 * WordPress Filesystem Sanbanze Theme Class for direct PHP file and folder manipulation.
 * custom funciton is added only add_contents
 * @since 2.5.0
 * @package WordPress
 * @subpackage Filesystem
 * @uses WP_Filesystem_Base Extends class
 */
class WP_Filesystem_Direct extends WP_Filesystem_Base {
	/**
	 * constructor
	 * @access public
	 * @param mixed $arg ignored argument
	 */
	public function __construct($arg) {
		$this->method = 'direct';
		$this->errors = new WP_Error();
	}

	/**
	 * Add a string line at end to a file
	 * Sanbenze Theme custom function
	 * 元々あるput_contents関数のfopenのモード'wb'を'a+b'に変更しただけ
	 * @access public
	 * @param string $file     Remote path to the file where to write the data.
	 * @param string $contents The data to write.
	 * @param int    $mode     Optional. The file permissions as octal number, usually 0644.
	 *                         Default false.
	 * @return bool False upon failure, true otherwise.
	 */
	public function add_contents( $file, $contents, $mode = false ) {
		$fp = @fopen( $file, 'a+b' );
		if ( ! $fp )
			return false;

		mbstring_binary_safe_encoding();
		$data_length = strlen( $contents );
		$bytes_written = fwrite( $fp, $contents );
		reset_mbstring_encoding();
		fclose( $fp );

		if ( $data_length !== $bytes_written )
			return false;

		$this->chmod( $file, $mode );
		return true;
	}

	/**
	 * Reads entire file into a string
	 * @access public
	 * @param string $file Name of the file to read.
	 * @return string|bool The function returns the read data or false on failure.
	 */
	public function get_contents($file) {
		return @file_get_contents($file);
	}
	...まだまだ続きます
	...以下、省略
	...
?>
PHP
CopyExpand

そして、フィルターフックにて呼び出す関数。

<?php
	function change_path_filesystem( $path ) {
		$path = get_template_directory() . '/class-wp-filesystem-direct.php';
		return $path;
	}
?>
PHP
CopyExpand

最後に、前述したアクセスログを保存する関数を訂正したもの。
フィルターフックは20行目です。

<?php
	private function save_access_log() {

		// 管理画面では動かないようにする・・・重要です。
		if ( ! is_user_logged_in() ) {
			$cdt = date( 'Y/m/d H:i:s' );
			$ipadrs = $_SERVER['REMOTE_ADDR'];
			$hpadrs = $_SERVER['REQUEST_URI'];
			$hname = gethostbyaddr( $ipadrs );
			$refer = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
			$agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';

			if ( false !== strpos( $agent, 'bot') or false !== strpos( $agent, 'crawl' ) or false !== strpos( $agent, 'search' )  or false !== strpos( $hname, 'bot' )) {
				return;
			}

			// WP_filesystem
			require_once(ABSPATH . 'wp-admin/includes/file.php');

			$access_type = get_filesystem_method();
			if ( 'direct' === $access_type ) {
				add_filter( 'filesystem_method_file', 'change_path_filesystem' );

				//WP_Filesystemの初期化
				if ( WP_Filesystem() ) {

					//$wp_filesystemオブジェクトの呼び出し
					global $wp_filesystem;

					$data = $cdt . '~' . $ipadrs . '~' . $hname . '~' . $agent . '~' . $refer . '~' . $hpadrs . "\n";
					$filnam = get_stylesheet_directory() . '/log/accesslog.php';

					$wp_filesystem->add_contents( $filnam, $data );
				}

			}


		}
	}
?>
PHP
CopyExpand

以上、しかし、長いな~!
もし、こんなのを最後まで読んで下さった方がいたとしたら、感激です。感謝!

Sanbanse Funabashi

Top

スクロールさせるか画像をクリックすると元に戻ります。