[PHP]ftp_nlist()のディレクトリパスに円スラッシュ(バックスラッシュ)は使えない

Read More



これはLinux上にあるFTPサーバに対して、
ローカルのWindows環境にあるバッチファイルを叩いたときに起きたとある現象。


このバッチファイル内ではdirname()ftp_nlist()を組み合わせた独自関数が定義してあったのだけど、
自分がdirname()の挙動をきちんと把握してなかったのが失敗の原因。


dirname()は親ディレクトリのパスを返す関数。
まあdirname()のわけのわからん挙動はPHPマニュアルにちゃんと書いてあったので下に書き出す。

■dirname() の例
<?php
echo '1) '. dirname("/etc/passwd"). PHP_EOL;
echo '2) '. dirname("/etc/"). PHP_EOL;
echo '3) '. dirname("."). PHP_EOL;
echo '4) '. dirname("/"). PHP_EOL;
echo '5) '. dirname("/etc"). PHP_EOL;
?>
†PHP:dirname http://php.net/manual/ja/function.dirname.php

■結果
1) /etc
2) \
3) .
4) \
5) \


わけがわからんのが1と2の差。
1はディレクトリセパレートがスラッシュで返ってきてるのに対して、
2はバックスラッシュで返ってきている。


つまりdirename()は環境・状況によって、返す文字列のディレクトリセパレートがスラッシュだったりバックスラッシュだったりすることがある、ということがわかった。

ほええ



--
さて、ここからがタイトルに書いた内容。


ftp_nlist()に渡すディレクトリパスを加工するのにdirname()を使ってしまっていたことにより、
いつくかのパターンで意図せずバックスラッシュ付きのパスを渡してしまっていた。


するとどうなるか。


バックスラッシュが含まれるパスをftp_nlist()に渡すと、
必ず空のリストが返ってくる。

渡すパスにバックスラッシュが含まれるだけでこうなる。
つまりパスが'\'だろうと'\test'だろうと'\test\'だろうと必ず空のリストが返る。

だから本来そこにあるはずのファイルが何度やっても見つからなかった。

しかも残念なことにこの時エラーとかワーニングにはならない。



ということでなので、
dirname()と組み合わせてftp_nlist()を使うような場合は、パスにバックスラッシュが含まれないように十分気を付けておく必要がある。


あとftp_nlist()のこの動作の理由を考えてみたが、
きっと内部ではFTPコマンドを叩いてるだけなのだろう。

そうするとこの挙動はFTPサーバがLinuxだからなのだろうか。
FTPサーバがWindows上にあった場合はこうはならない気がする(未検証)。




--
さて総括。


Windows環境で動作させる可能性がある場合、パスの区切り文字には十分気を付けるべし。

うん、改めていうようなことでもないな。


とはいえ、dirname()使ったらスラッシュがバックスラッシュになって返ってくることがあるとは思いもしなかった。

それにPHPマニュアルには、
dirname() は、入力文字列を単純にそのまま処理します。

って書いてあったけど「単純にそのまま処理」っていうのは「サーバに依存する」ってことなんだな。


これは勘違いする。
わからんわ。



-- 2017/10/23 一部修正
プログラム部分がわかりづらかったので試しと結果を分けて記述するように変更