ブログとWiki全盛のこの時代ですが、旧来のホームページを作成する場合にはFTPは欠かせません。
まあこれもブラウザ上から行うことが可能ですが、当然PHPにもFTP接続を行う関数が用意されています。
ftp.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//FTP
$ftp_server='example.com';
$ftp_user='user';
$ftp_pass='password';
//ダウンロード
$ftp_file='/download.txt';
$ftp_url='ftp://'.$ftp_user.':'.$ftp_pass.'@'.$ftp_server.$ftp_file;
$f = file_get_contents($ftp_url);
//アップロード
$ftp_file='/upload.txt';
$str='hogehoge';
//デフォルトでは上書きが禁止されているので許可する
$opts = array('ftp' => array('overwrite' => true));
$context = stream_context_create($opts);
$ftp_url='ftp://'.$ftp_user.':'.$ftp_pass.'@'.$ftp_server.$ftp_file;
$f=file_put_contents($ftp_url,$str,LOCK_EX,$context);
|
FTP関数は?
実は関数を使わなくても、簡単な方法でFTPアクセスを行うことができます。
上記の'ftp://'から始まるURLはURLラッパーと呼ばれ、FTPにアクセスする標準的な実装です。
別にPHP固有のものでも何でもなく、実際作成された$ftp_urlをブラウザに入力すると普通にファイル内容を取得することができます。
そのURLに対しfile_get_contentsすればダウンロードできますし、file_put_contentsすればアップロードすることができます。
ということになっているのですが、手元の適当なサーバに試してみたところ、file_put_contentsにLOCK_EXを掛けた場合何故かアップロードに失敗するという事態に。
バージョンは対応しているはずなのにぃ。
普通に
$fp=fopen($ftp_url,'w',false,$context);
flock($fp,LOCK_EX);
fwrite($fp,$str);
fclose($fp);
としてみたらflockがfalseになった。
残念ながらflockに非対応のサーバだったようです。
さてこのFTPラッパー、表現的にはわかりやすいしPHP5ではmkdirからunlinkまで何でもできるのですが、プログラム組む際には少々扱いにくいです。
例によってクラスに突っ込んでみましょう。
ftp.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
class ftpClass{
private $ftp=array();
private $fc='';
private $context='';
//コンストラクタ
function __construct($ftp_server,$ftp_user,$ftp_pass){
$this->ftp['ftp_server']=$ftp_server;
$this->ftp['ftp_user']=$ftp_user;
$this->ftp['ftp_pass']=$ftp_pass;
$opts = array('ftp' => array('overwrite' => true));
$this->context = stream_context_create($opts);
}
//ステータス
function status($ftp_file){
$this->ftp['ftp_file']=$ftp_file;
$this->_ftp_url();
$this->fc=stat($this->ftp['ftp_url']);
if(!$this->fc){$this->_error('取得失敗');}
return $this->fc;
}
//削除
function delete($ftp_file){
$this->ftp['ftp_file']=$ftp_file;
$this->_ftp_url();
$this->fc=unlink($this->ftp['ftp_url']);
if(!$this->fc){$this->_error('削除失敗');}
return true;
}
//アップロード
function put($ftp_file,$str){
$this->ftp['ftp_file']=$ftp_file;
$this->_ftp_url();
$fp=fopen($this->ftp['ftp_url'],'w',false,$this->context);
if(!$fp){$this->_error('ファイルオープン失敗');}
$ret=flock($fp,LOCK_EX);
//if(!$ret){$this->_error('ファイルロック失敗');}
$ret=fwrite($fp,$str);
if(!$ret){$this->_error('ファイル書き込み失敗');}
fclose($fp);
return true;
}
//ダウンロード
function get($ftp_file){
$this->ftp['ftp_file']=$ftp_file;
$this->_ftp_url();
$this->fc=file_get_contents($this->ftp['ftp_url']);
if(!$this->fc){$this->_error('取得失敗');}
$this->fc=mb_convert_encoding(
$this->fc
,'UTF-8'
,mb_detect_encoding(
$this->fc,'UTF-8,eucjp-win,sjis-win'
)
);
return $this->fc;
}
//URLを作成
function _ftp_url(){
if(
!$this->ftp['ftp_user']
|| !$this->ftp['ftp_pass']
|| !$this->ftp['ftp_server']
|| !$this->ftp['ftp_file']
){
$this->_error('引数不足');
}
if($this->ftp['ftp_file'][0]!=='/'){
$slash='/';
}else{
$slash='';
}
$this->ftp['ftp_url']=
'ftp://'
.$this->ftp['ftp_user']
.':'
.$this->ftp['ftp_pass']
.'@'
.$this->ftp['ftp_server']
.$slash
.$this->ftp['ftp_file'];
}
//えらー
function _error($str=''){
print("<html><pre>");var_dump($str,$this);die();
}
#↓クラスのおわり}
|
思ったより長くなってしまった。
$this->ftp['ftp_file']以外は先に作っておいた方が負荷が軽くなりそうだとか、file_get_contentsした後はクラス内に保持しておくべきとか、エラー処理が適当すぎるだろとか色々改善点もありますが、まあいいや。
使用する場合はこのように。
ftp.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
//接続用設定
$ftp_server='example.com';
$ftp_user='user';
$ftp_pass='password';
//FTP
require_once('./ftp.class.php');
$ftp=new ftpClass($ftp_server,$ftp_user,$ftp_pass);
//ダウンロード
$filename='sample1.txt';
$ret=$ftp->get($filename);
//アップロード
$filename='sample2.txt';
$str='テスト';
$ret=$ftp->put($filename,$str);
//ステータス
$ret=$ftp->status($filename);
//削除
$filename='sample2.txt';
$ret=$ftp->delete($filename);
|
今回はサーバがflock使えなかったのでエラー部分をコメントアウトしてあります。
これでFTP関数とか'ftp://'とかの面倒な処理を書かなくて済むようになりました。
いつものようにnewしてファイル名を突っ込むだけで簡単にFTPアクセスを行うことができます。
PR
トラックバック
トラックバックURL: