Perlで、Net::FTPモジュールを使って

サーバーにファイルをアップロード(PUT)しようとしているのですが
うまくいきません。

次のようなソースです。
何が悪いのか診断してもらえないでしょうか?

※補足
・FFFTPでは、PASVモード有効、ポート番号21でGETもPUTも成功しているので、
 FTPの設定の問題ではないと思います。
・$ftp->pwd()すると、cwdで移動したパスをちゃんと取ってくるので、
 ログインや cwdは成功しているようです。
・特に、$ftp->putでパソコン上のファイルのパスを指定する方法がよくわかりません。

use Net::FTP;

$FtpHostName = "hogehoge.com";
$FtpDataPath = "/home/hogehoge/www/sub";
$FtpUserName = "myname";
$FtpPassword = "letmein";

$datafile = "C:\\temp\\test.txt";

$ftp = Net::FTP->new( $FtpHostName );
$ftp -> login( $FtpUserName, $FtpPassword );
$ftp -> pasv();
$ftp -> port( 21 );
$ftp -> ascii();

$ftp -> cwd( $FtpDataPath );

$ftp -> put( $datafile ) or
die "PUT FAILED";
$ftp -> quit();

よろしくお願いします。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2010/07/13 02:15:37
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:rouge_2008 No.1

回答回数595ベストアンサー獲得回数351

ポイント200pt

「$ftp -> port( 21 );」の行を削除して試してみてください。

このメソッドは、サーバーの21番ポートに接続する事を指定するものではなく、クライアントPCのIPアドレスと待ち受けるポートを送信するもののようです。

http://x68000.q-e-d.net/~68user/net/ftp-4.html

・「ポート番号の伝達」より

・PORT … ポート番号を送信 (Active モード)

データコネクションの確立の際、FTP サーバ側から FTP クライアント側に接続するよう伝える。 FTP クライアントが IP アドレス 10.0.0.1 で動いており、ポート 5000 番を listen しているなら、

PORT 10,0,0,1,19,136

200 PORT command successful.

と送信する (5000=19×256+136)。 その後 FTP クライアントが LIST やRETR コマンドを送信すると、 FTP サーバ側が 10.0.0.1 のポート 5000 に接続し、データの送受信が始まる。

※次のように「$ftp->message」でコマンド実行で返されたメッセージを確認してみてください。

$ftp->pasv();
print $ftp->message . "<br>\r\n";

次のような形式でIPアドレスとポート番号が返されると思います。

Entering Passive Mode (***,***,***,***,242,90).

※上記の場合、242×256+90=62042番ポート

※Activeモードで接続する場合、「$ftp->port()」と何も指定しないで実行してみてください。(「$ftp->port(***,***,***,***,xxx,xx)」と自分のPCのIPとポート番号を指定しても接続できると思いますが、未確認です。)

※Passiveモードで接続するのでしたら、portを実行する必要はありません。



ActiveモードとPassiveモードの違いは、次のページも確認しておくとより理解できると思います。

http://x68000.q-e-d.net/~68user/net/ftp-3.html

※(1)から読んでもいいと思います

「Active モード」というもので、データコネクションの確立の際、「FTP サーバ側が能動的に FTP クライアント側に接続する」という動作になります。

一方、「Passive モード」というものがあります。このモードでは、「FTP サーバ側が受け手となり、FTP クライアントからの接続を待つ」という動作になります。つまり、FTP クライアントは、 bind・listen・accept などのサーバ的な動作をする必要がなくなるのです。


あるいは、オプションで次のように指定しても、すべての転送がPassiveモードになるようです。

$ftp = Net::FTP->new($FtpHostName, Passive => 1);

http://perldoc.jp/docs/modules/libnet-1.12/Net/FTP.pod

Passive - 0以外の値を設定すると、全てのデータ転送はパッシブモードを使って行われます。いくつかのダム(dumb)サーバーといくつかのファイアウォールの設定を除けば、通常、必要とされません。これは環境変数FTP_PASSIVEによって設定することもできます。

id:uta_at_home

とても詳しい解説をありがとうございます!


「$ftp -> port( 21 );」を削除しただけではうまくいかなかったので、

教えてもらった内容をじっくり理解して、いろいろ試してみようと思います。


結果は後ほど追記させてもらいます。

ありがとうございました!


■追記

報告が遅くなってすいません。

いろいろやってみたのですが、やはりアップロード(PUT)はうまくいきませんでした。


そこで試しに サーバー上のファイル "test.txt" をダウンロードしようと

下記方法で GETをしてみたところ、

$ftp -> get( "test.txt", "C:\\temp\\test.txt" )


なんと、"test.txt"が パソコンの "C:\temp\"フォルダにコピーされるのではなく、

サーバーのカレントディレクトリに "C:\temp\test.txt"というファイル名の

ファイルが1個コピーされました。


どうやら、Net::FTPは、サーバーとローカルPC間の FTP通信を行ってくれる

モジュールではないようです。

Net::FTPモジュールを使うのはやめて、別の方法でファイルをアップロードすることに

します。

お世話をかけて申し訳ありませんでした。


Net::FTPモジュールの問題は解決できませんでしたが、rouge_2008さんの回答で

今までなんとなく使っていたFTPについての理解が深まりました。

丁寧な回答をありがとうございました!

2010/07/13 02:15:00
  • id:rouge_2008
    セキュリティ対策ソフトは何を使用しているでしょうか?
    ファイアーウォール機能でPerl.exeを拒否していないか確認してみてください。(一応、Windowsのファイアーウォール機能の設定も・・・)
  • id:rouge_2008
    もしかして、レンタルサーバー等に設置したスクリプトにアクセスして実行していたのですか?
    ローカル環境に設置したスクリプトを実行して、外部のFTPサーバーに接続したいのだと思っていました・・・
    他の人にファイルをアップロードしてもらうのが目的でしたら、フォームを利用してアップロードするようにするといいかもしれません。

    たくさんのポイントといるかをありがとうございました。m(__)m
  • id:uta_at_home
    すいません。その通りです。
    レンタルサーバーに設置したCGIを使って
    ローカルPCのファイルをサーバーにアップロードしようとしていました。

    質問が説明不足で申し訳ありませんでした。

    回答とてもありがたかったです。
    お恥ずかしい話、
    今までは PASVモードもおまじないのようにON/OFFしていただけで
    意味もわかっておらず、
    今回初めて理解できました。
    FTPの仕組みがいろいろわかったので、今後の役に立つと思います。

    こちらこそありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません