PHPを使って効率的で安全なftpサーバーを実装する(2)、PHPでftpサーバーを実装する
前回の記事からの続きです。
1. ユーザークラス CUser を実装します。
ユーザーはテキスト形式で保存され、ユーザー配列はjsonエンコードされます。
リーリー
フォルダーとファイルの許可手順:
リーリー
実装コードは次のとおりです:
![](http://www.bkjia.com/uploads/allimg/151230/164F62010-0.gif)
クラスユーザー{
const I = 1;
//継承
const FD = 2;
//フォルダー削除
const FN = 4;
//フォルダーの名前を変更
const FC = 8;
//フォルダー作成
const FL = 16;
//フォルダーリスト
const D = 32;
//ファイル削除
const N = 64;
//ファイル名変更
const A = 128;
//ファイル追加
const W = 256;
//ファイル書き込み(アップロード)
const R = 512;
//ファイル読み取り(ダウンロード)
プライベート $hash_salt = ''
;
プライベート $user_file;
プライベート $group_file;
プライベート $users =
array();
プライベート $groups =
array();
プライベート $file_hash = ''
;
パブリック 関数 __construct(){
$this->user_file = BASE_PATH.'/conf/users'
;
$this->group_file = BASE_PATH.'/conf/groups'
;
$this->
reload();
}
/**
* 戻り权制限表达式
* @param int $access
* @戻り文字列
*/
パブリック 静的 関数 AC(
$access){
$str = ''
;
$char =
array('R','W','A','N','D','L','C','N','D','I'
);
for(
$i = 0;
$i $i++
){
if(
$access &
pow(2,9-
$i))
$str.=
$char[
$i];
else $str.= 「-」
;
}
リターン $str;
}
/**
* 追加用户データ
*/
パブリック 関数 reload(){
$user_file_hash =
md5_file(
$this->
user_file);
$group_file_hash =
md5_file(
$this->
group_file);
if(
$this->file_hash !=
md5(
$user_file_hash.
$group_file_hash)){
if((
$user =
file_get_contents(
$this->user_file)) !==
false){
$this->users = json_decode(
$user,
true);
if(
$this->
ユーザー){
//folder排序
foreach (
$this->ユーザー
as $user=>
$profile){
if(
isset(
$profile['フォルダ'
])){
$this->users[
$user]['folder'] =
$this->sortFolder(
$profile['folder'
]);
}
}
}
}if((
$group =
file_get_contents(
$this->group_file)) !==
false){
$this->groups = json_decode(
$group,
true);
if(
$this->
グループ){
//folder排序
foreach (
$this->グループ
as $group=>
$profile){
if(
isset(
$profile['フォルダ'
])){
$this->groups[
$group]['フォルダー'] =
$this->sortFolder(
$profile['フォルダー'
]);
}
}
}
}
$this->file_hash =
md5(
$user_file_hash.
$group_file_hash);
}
}
/**
*对フォルダ行排序
* @return 配列
*/
プライベート 関数 sortFolder(
$folder){
uasort(
$フォルダー,
関数(
$a,
$b){
return strnatcmp(
$a['path'],
$b['path'
]);
});
$result =
array();
foreach (
$フォルダー as $v){
$結果[] =
$v;
}
リターン $結果;
}
/**
*保存用户データ
*/
パブリック 関数 save(){
file_put_contents(
$this->user_file, json_encode(
$this->users),
LOCK_EX);
file_put_contents(
$this->グループファイル, json_encode(
$this->グループ),
LOCK_EX);
}
/**
* 添加用户
* @param 文字列 $user
* @param 文字列 $pass
* @param 文字列 $home
* @param string $expired
* @param boolean $active
* @param 文字列 $group
* @param string $description
* @param string $email
* @return ブール値
*/
public function addUser(
$user,
$pass,
$home,
$expired,
$active=
true,
$group='',
$description= '',
$email = ''
){
$user =
strto lower(
$user);
if(
isset(
$this->users[
$user]) ||
空(
$user)){
戻る false;
}
$this->users[
$user] =
array(
'パス' =>
md5(
$user.
$this->hash_salt.
$pass),
'ホーム' =>
$ホーム、
'期限切れ' =>
$期限切れ、
'アクティブ' =>
$アクティブ、
'グループ' =>
$グループ、
'説明' =>
$説明、
'電子メール' =>
$メール、
);
戻る 本当;
}
/**
* 設置用户費
* @param 文字列 $user
* @param 配列 $profile
* @return ブール値
*/
public function setUserProfile(
$user,
$profile){
$user =
strto lower(
$user);
if(
is_array(
$profile) &&
isset(
$this->users[
$user])){
if(
isset(
$profile['pass'
])){
$profile['pass'] =
md5(
$user.
$this->hash_salt.
$profile['pass'
]);
}if(
isset(
$profile['active'
])){
if(!
is_bool(
$profile['active'
])){
$profile['active'] =
$profile['active'] == 'true' ?
真:
偽;
}
}
$this->users[
$user] =
array_merge(
$this->users[
$user],
$profile);
戻る 本当;
}
戻る false;
}
/**
*获取用户资料
* @param 文字列 $user
* @return multitype:|boolean
*/
パブリック 関数 getUserProfile(
$user){
$user =
strto lower(
$user);
if(
isset(
$this->ユーザー[
$user])){
return $this->users[
$user];
}
戻る false;
}
/**
*删除用户
* @param 文字列 $user
* @return ブール値
*/
パブリック 関数 delUser(
$user){
$user =
strto lower(
$user);
if(
isset(
$this->ユーザー[
$user])){
設定解除(
$this->ユーザー[
$user]);
戻る 本当;
}
戻る false;
}
/**
* 获取用户列表
* @return 配列
*/
パブリック 関数 getUserList(){
$list =
array();
if(
$this->
ユーザー){
foreach (
$this->ユーザー
as $user=>
$profile){
$list[] =
$user;
}
}
並べ替え(
$リスト);
戻る $リスト;
}
/**
* 添加組
* @param 文字列 $group
* @param 文字列 $home
* @return ブール値
*/
パブリック 関数 addGroup(
$group,
$home){
$group =
strto lower(
$group);
if(
isset(
$this->グループ[
$group])){
戻る false;
}
$this->グループ[
$グループ] =
配列(
'ホーム' =>
$ホーム
);
戻る 本当;
}
/**
* 設置費
* @param 文字列 $group
* @param 配列 $profile
* @return ブール値
*/
public function setGroupProfile(
$group,
$profile){
$group =
strto lower(
$group);
if(
is_array(
$profile) &&
isset(
$this->groups[
$group])){
$this->グループ[
$グループ] =
array_merge(
$this->グループ[
$グループ],
$プロファイル);
戻る 本当;
}
戻る false;
}
/**
*获取组资料
* @param 文字列 $group
* @return multitype:|boolean
*/
パブリック 関数 getGroupProfile(
$group){
$group =
strto lower(
$group);
if(
isset(
$this->グループ[
$group])){
戻る $this->グループ[
$グループ];
}
戻る false;
}/**
* グループの削除
* @param 文字列 $group
* @return ブール値
*/
パブリック 関数 delGroup(
$group){
$group =
strto lower(
$group);
if(
isset(
$this->グループ[
$group])){
設定解除(
$this->グループ[
$group]);
foreach (
$this->ユーザー
as $user =>
$profile){
if(
$profile['グループ'] ==
$グループ)
$this->ユーザー[
$user]['グループ'] = ''
;
}
戻る 本当;
}
戻る false;
}
/**
* グループリストを取得する
* @return 配列
*/
パブリック 関数 getGroupList(){
$list =
array();
if(
$this->
グループ){
foreach (
$this->グループ
as $group=>
$profile){
$リスト[] =
$グループ;
}
}
並べ替え(
$リスト);
戻る $リスト;
}
/**
* グループユーザーリストの取得
* @param 文字列 $group
* @return 配列
*/
パブリック 関数 getUserListOfGroup(
$group){
$list =
array();
if(
isset(
$this->グループ[
$グループ]) &&
$this->
ユーザー){
foreach (
$this->ユーザー
as $user=>
$profile){
if(
isset(
$profile['グループ']) &&
$profile['グループ'] ==
$グループ){
$list[] =
$user;
}
}
}
並べ替え(
$リスト);
戻る $リスト;
}
/**
* ユーザ認証
* @param 文字列 $user
* @param 文字列 $pass
* @パラメータ文字列$ip
* @return ブール値
*/
public function checkUser(
$user,
$pass,
$ip = ''
){
$this->
reload();
$user =
strto lower(
$user);
if(
isset(
$this->ユーザー[
$user])){
if(
$this->users[
$user]['active'] &&
time() strtotime(
$this->users[
$user) ][「期限切れ」
])
&&
$this->users[
$user]['pass'] ==
md5(
$user.
$this->hash_salt.
$pass)){
if(
空(
$ip)){
戻る 本当;
}他{
//IP認証
return $this->checkIP(
$user,
$ip);
}
}他{
戻る false;
}
}
戻る false;
}/**
* 基本認証
* @パラメータ文字列$base64
*/
パブリック 関数 checkUserBasicAuth(
$base64){
$base64 =
trim(
str_replace('Basic ', '',
$base64));
$str =
base64_decode(
$base64);
if(
$str !==
false){
list(
$user,
$pass) =
explode(':',
$str,2
);
$this->
reload();
$user =
strto lower(
$user);
if(
isset(
$this->ユーザー[
$user])){
$group =
$this->users[
$user]['グループ'
];
if(
$group == 'admin' &&
$this->users[
$user]['active'] &&
time() <=
strtotime(
$this ->ユーザー[
$user]['期限切れ'
])
&&
$this->users[
$user]['pass'] ==
md5(
$user.
$this->hash_salt.
$pass)){
戻る 本当;
}他{
戻る false;
}
}
}
戻る false;
}
/**
* 用户登录ip验证
* @param 文字列 $user
* @パラメータ文字列$ip
*
* ユーザの IP 制限は、承認グループの IP 制限に従います。* マッチングルール:
* 1. グループ許可リストの照合を実行します。
* 2. 合格したかのように、グループ拒否リストのマッチングを実行します。
* 3. ユーザー権限の照合を実行します。
* 4. 合格した場合、ユーザー拒否マッチングを実行します。
*
*/
パブリック 関数 checkIP(
$user,
$ip){
$pass =
false;
//最初にグループ認証を実行します
$group =
$this->users[
$user]['グループ'
];
//グループでマッチングが可能です
if(
isset(
$this->グループ[
$group]['ip']['allow'
])){
foreach (
$this->groups[
$group]['ip']['allow']
as $addr){
$pattern = '/'.
str_replace('*','d+',
str_replace('.', '.',
$addr)).'/'
;
if(
preg_match(
$pattern,
$ip) && !
empty(
$addr)){
$pass =
true;
休憩;
}
}
}
//許可されている場合は、マッチングを拒否します
if(
$pass){
if(
isset(
$this->グループ[
$group]['ip']['deny'
])){
foreach (
$this->groups[
$group]['ip']['deny']
as $addr){
$pattern = '/'.
str_replace('*','d+',
str_replace('.', '.',
$addr)).'/'
;
if(
preg_match(
$pattern,
$ip) && !
empty(
$addr)){
$pass =
false;
休憩;
}
}
}
}
if(
isset(
$this->users[
$user]['ip']['allow'
])){
foreach (
$this->users[
$user]['ip']['allow']
as $addr){
$pattern = '/'.
str_replace('*','d+',
str_replace('.', '.',
$addr)).'/'
;
if(
preg_match(
$pattern,
$ip) && !
empty(
$addr)){
$pass =
true;
休憩;
}
}
}
if(
$pass){
if(
isset(
$this->users[
$user]['ip']['deny'
])){
foreach (
$this->users[
$user]['ip']['deny']
as $addr){
$pattern = '/'.
str_replace('*','d+',
str_replace('.', '.',
$addr)).'/'
;
if(
preg_match(
$pattern,
$ip) && !
empty(
$addr)){
$pass =
false;
休憩;
}
}
}
}
echo date('Y-m-d H:i:s')." [debug]tIP ACCESS:".' '.(
$pass?'true':'false')."n"
;
リターン $pass;
}
/**
* ユーザーのホームディレクトリを取得します
* @param 文字列 $user
* @戻り文字列
*/
パブリック 関数 getHomeDir(
$user){
$user =
strto lower(
$user);
$group =
$this->users[
$user]['グループ'
];
$dir = ''
;
if(
$グループ){
if(
isset(
$this->グループ[
$group]['home']))
$dir =
$this->グループ[
$group][ 「家」
];
}$dir = !
empty(
$this->users[
$user]['home'])?
$this->users[
$user]['home' ]:
$ディレクトリ;
return $dir;
}
//文件权限界判断
public function isReadable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][0] == 'R'
;
}他{
return $result['access'][0] == 'R' &&
$result['access'][9] == 'I'
;
}
}
public function isWritable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][1] == 'W'
;
}他{
return $result['access'][1] == 'W' &&
$result['access'][9] == 'I'
;
}
}
public function isAppendable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][2] == 'A'
;
}他{
return $result['access'][2] == 'A' &&
$result['access'][9] == 'I'
;
}
}
public function isRenamable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][3] == 'N'
;
}他{
return $result['access'][3] == 'N' &&
$result['access'][9] == 'I'
;
}
}
public function isDeletable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][4] == 'D'
;
}他{
return $result['access'][4] == 'D' &&
$result['access'][9] == 'I'
;
}
}
//目录权限界判断
public function isFolderListable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][5] == 'L'
;
}他{
return $result['access'][5] == 'L' &&
$result['access'][9] == 'I'
;
}
}
public function isFolderCreatable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][6] == 'C'
;
}他{
return $result['access'][6] == 'C' &&
$result['access'][9] == 'I'
;
}
}public function isFolderRenamable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][7] == 'N'
;
}他{
return $result['access'][7] == 'N' &&
$result['access'][9] == 'I'
;
}
}
public function isFolderDeletable(
$user,
$path){
$result =
$this->getPathAccess(
$user,
$path);
if(
$result['isExactMatch'
]){
return $result['access'][8] == 'D'
;
}他{
return $result['access'][8] == 'D' &&
$result['access'][9] == 'I'
;
}
}
/**
*获取目录权制限
* @param 文字列 $user
* @param 文字列 $path
* @return 配列
* 最长路径適合を実行します
*
* 戻り:
* 配列(
* 'access'=>目前权制限
* ,'isExactMatch'=>否か精确適合
*
* );
*
*如果精确適合、则忽略継承。
* 否则应判断是否继承父目录的权限,
* 权制限位表:
* +---+---+---+---+---+---+---+---+---+---+
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
* +---+---+---+---+---+---+---+---+---+---+
* | R | W |あ | N | D | L | C | N | D |私 |
* +---+---+---+---+---+---+---+---+---+---+
* | ファイル | フォルダ |
* +-------------------+-------------------+
*/
パブリック 関数 getPathAccess(
$user,
$path){
$this->
reload();
$user =
strto lower(
$user);
$group =
$this->users[
$user]['グループ'
];
//削除文書名
$path =
str_replace(
substr(
strrchr(
$path, '/'),1),'',
$path);
$access = self::AC(0
);
$isExactMatch =
false;
if(
$グループ){
if(
isset(
$this->グループ[
$グループ]['フォルダー'
])){
foreach (
$this->groups[
$group]['folder']
as $f){
//中文处理
$t_path =
iconv('UTF-8','GB18030',
$f['パス'
]);
if(
strpos(
$path,
$t_path) === 0
){
$access =
$f['access'
];
$isExactMatch = (
$path ==
$t_path?
true:
false);
}
}
}
}
if(
isset(
$this->users[
$user]['folder'
])){
foreach (
$this->users[
$user]['folder']
as $f){
//中文处理
$t_path =
iconv('UTF-8','GB18030',
$f['パス'
]);
if(
strpos(
$path,
$t_path) === 0
){
$access =
$f['access'
];
$isExactMatch = (
$path ==
$t_path?
true:
false);
}
}
}
echo date('Y-m-d H:i:s')." [debug]tACCESS:
$access ".' '.(
$isExactMatch?'1':'0')."
$pathn"
;
return array('access'=>
$access,'isExactMatch'=>
$isExactMatch);
}/**
* 追加在中用
* @param ShareMemory $shm
* @param swoole_server $serv
* @param 不明な $user
* @param 不明 $fd
* @param 不明な $ip
* @return Ambigous >
*/
public function addOnline(ShareMemory
$shm ,
$serv,
$user,
$fd,
$ip){
$shm_data =
$shm->
read();
if(
$shm_data !==
false){
$shm_data['online'][
$user.'-'.
$fd] =
array('ip'=>
$ip,'time'=>
time ());
$shm_data['last_login'][] =
array('user' =>
$user,'ip'=>
$ip,'time'=>
time( ));
//古いデータを削除
if(
count(
$shm_data['last_login'])>30)
array_shift(
$shm_data['last_login'
]);
$list =
array();
foreach (
$shm_data['online']
as $k =>
$v){
$arr =
爆発('-',
$k);
if(
$serv->connection_info(
$arr[1]) !==
false){
$list[
$k] =
$v;
}
}
$shm_data['オンライン'] =
$list;
$shm->write(
$shm_data);
}
戻る $shm_data;
}
/**
* 追加登陆失败记录
* @param ShareMemory $shm
* @param 不明な $user
* @param 不明な $ip
* @return 曖昧な
*/
public function addAttempt(ShareMemory
$shm ,
$user,
$ip){
$shm_data =
$shm->
read();
if(
$shm_data !==
false){
if(
isset(
$shm_data['login_attempt'][
$ip.'||'.
$user]['count'
])){
$shm_data['login_attempt'][
$ip.'||'.
$user]['count'] += 1
;
}他{
$shm_data['login_attempt'][
$ip.'||'.
$user]['count'] = 1
;
}
$shm_data['login_attempt'][
$ip.'||'.
$user]['time'] =
time();
//古いデータを削除
if(
count(
$shm_data['login_attempt'])>30)
array_shift(
$shm_data['login_attempt'
]);
$shm->write(
$shm_data);
}
戻る $shm_data;
}
/**
* 密暗号错误上限
* @param 不明 $shm
* @param 不明な $user
* @param 不明な $ip
* @return ブール値
*/
public function isAttemptLimit(ShareMemory
$shm,
$user,
$ip){
$shm_data =
$shm->
read();
if(
$shm_data !==
false){
if(
isset(
$shm_data['login_attempt'][
$ip.'||'.
$user]['count'
])){
if(
$shm_data['login_attempt'][
$ip.'||'.
$user]['count'] > 10 &&
time() -
$shm_data['login_attempt'][
$ip.'||'.
$user]['time'] < 600
){
戻る 本当;
}
}
}
戻る false;
}/**
* ランダムキーを生成
* @param int $len
* @return 曖昧な
*/
パブリック 静的 関数 genPassword(
$len){
$str =
null;
$strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz@!#$%*+-"
;
$max =
strlen(
$strPol)-1
;
for(
$i=0;
$i<
$len;
$i++
){
$str.=
$strPol[
rand(0,
$max)];
//rand($min,$max) は最小値と最大値の間の数値を生成します ランダムな整数
}
リターン $str;
}
}
コードを表示
2. 共有メモリ操作クラス
これは比較的簡単で、php の shmop 拡張機能を使用するだけです。
![](http://www.bkjia.com/uploads/allimg/151230/164F62010-0.gif)
クラス ShareMemory{
プライベート $mode = 0644
;
プライベート $shm_key;
プライベート $shm_size;
/**
*构造関数数
*/
パブリック 関数 __construct(){
$key = 'F'
;
$サイズ = 1024*1024
;
$this->shm_key = ftok(
__FILE__,
$key);
$this->shm_size =
$size + 1
;
}
/**
*读取内存数组
* @return 配列|ブール値
*/
パブリック 関数 read(){
if((
$shm_id = shmop_open(
$this->shm_key,'c',
$this->モード,
$this->shm_size)) !==
false ){
$str = shmop_read(
$shm_id,1,
$this->shm_size-1
);
shmop_close($shm_id);
if((
$i =
strpos(
$str," ")) !==
false)
$str =
substr(
$str,0,
$i );
if(
$str){
return json_decode(
$str,
true);
}他{
return array();
}
}
戻る false;
}
/**
* 写量组到内存
* @param 配列 $arr
* @return int|boolean
*/
パブリック 関数 write(
$arr){
if(!
is_array(
$arr))
return false;
$str = json_encode(
$arr)." "
;
if(
strlen(
$str) >
$this->shm_size)
return false;
if((
$shm_id = shmop_open(
$this->shm_key,'c',
$this->モード,
$this->shm_size)) !==
false ){
$count = shmop_write(
$shm_id,
$str,1
);
shmop_close($shm_id);
戻る $count;
}
戻る false;
}
/**
* 删除内保存块、次回使用時に再新开辟内保存块
* @return ブール値
*/
パブリック 関数 delete(){
if((
$shm_id = shmop_open(
$this->shm_key,'c',
$this->モード,
$this->shm_size)) !==
false ){
$result = shmop_delete(
$shm_id);
shmop_close($shm_id);
リターン $結果;
}
戻る false;
}
}
コードを表示
3.内置型Webサービス
これは主に ftp の http サーバー タイプに組み込まれており、機能が完璧ではなく、ftp の管理も実行できます。これは、apache などの他の http サーバーで実行される方法とは異なる可能性があることに注意してください。内に保管しております。
![](http://www.bkjia.com/uploads/allimg/151230/164F62010-0.gif)
クラス CWebServer{
保護 $buffer_header =
array();
保護 $buffer_maxlen = 65535;
//最大POSTサイズ
const DATE_FORMAT_HTTP = 'D, d-M-Y H:i:s T'
;
const HTTP_EOF = "rnrn"
;
const HTTP_HEAD_MAXLEN = 8192;
// http ヘッダーの最大長は 2k を超えてはなりません
const HTTP_POST_MAXLEN = 1048576;
//1m
const ST_FINISH = 1;
//完了、処理フローに入ります
const ST_WAIT = 2
//データを待っています;
const ST_ERROR = 3;
//エラー、このパッケージを破棄します
プライベート $requsts =
array();
プライベート $config =
array();
public function log(
$msg,
$level = 'デバッグ'
){
echo date('Y-m-d H:i:s').' ['.
$level."]t" .
$msg."n"
;
}
public function __construct(
$config =
array()){
$this->config =
array(
'wwwroot' => __DIR__.'/wwwroot/',
'インデックス' => 'インデックス.php',
'path_deny' =>
配列('/protected/'),
);
}
public function onReceive(
$serv,
$fd,
$data){
$ret =
$this->checkData(
$fd,
$data);
スイッチ (
$ret){
ケース self::ST_ERROR:
$serv->close(
$fd);
$this->cleanBuffer(
$fd);
$this->
log('受信エラー。'
);
休憩;
ケース self::ST_WAIT:
$this->
log('受信はお待ちください。'
);
戻る;
デフォルト:
休憩;
}
//完全なリクエストを開始します
$request =
$this->リクエスト[
$fd];
$info =
$serv->connection_info(
$fd);
$request =
$this->parseRequest(
$request);
$request['remote_ip'] =
$info['remote_ip'
];
$response =
$this->onRequest(
$request);
$output =
$this->parseResponse(
$request,
$response);
$serv->send(
$fd,
$output);
if(
isset(
$request['head']['Connection']) &&
strto lower(
$request['head']['Connection']) == 'close'
){
$serv->close(
$fd);
}
設定解除(
$this->リクエスト[
$fd]);
$_REQUEST =
$_SESSION =
$_COOKIE =
$_FILES =
$_POST =
$_SERVER =
$_GET =
array() ;
}/**
*处理请求
* @param 配列 $request
* @return array $response
*
* $リクエスト=配列(
* '時間'=>
* 'head'=>配列(
* 'メソッド'=>
* 'パス'=>
* 'プロトコル'=>
* 'uri'=>
* //その他の http ヘッダー
* '..'=>値
*)
* '本体'=>
* 'get'=>(該当する場合)
* 'post'=>(該当する場合)
* 'cookie'=>(該当する場合)
*
*
*)
*/
パブリック 関数 onRequest(
$request){
if(
$request['head']['path'][
strlen(
$request['head']['path']) - 1] == '/'
){
$request['head']['path'] .=
$this->config['index'
];
}
$response =
$this->プロセス(
$request);
リターン $レスポンス;
}
/**
* 消去データ
* @param 不明 $fd
*/
パブリック 関数 cleanBuffer(
$fd){
設定解除(
$this->リクエスト[
$fd]);
設定解除(
$this->buffer_header[
$fd]);
}
/**
* 检查データ
* @param 不明 $fd
* @param 不明な $data
* @戻り文字列
*/
パブリック 関数 checkData(
$fd,
$data){
if(
isset(
$this->buffer_header[
$fd])){
$data =
$this->buffer_header[
$fd].
$data;
}
$request =
$this->checkHeader(
$fd,
$data);
//请求头错误
if(
$request ===
false){
$this->buffer_header[
$fd] =
$data;
if(
strlen(
$data) > self::
HTTP_HEAD_MAXLEN){
return self::
ST_ERROR;
}他{
return self::
ST_WAIT;
}
}
//投稿请求检查
if(
$request['head']['method'] == 'POST'
){
return $this->checkPost(
$request);
}他{
return self::
ST_FINISH;
}
}
/**
*检查请求头
* @param 不明 $fd
* @param 不明な $data
* @return ブール値|配列
*/
public function checkHeader(
$fd,
$data){
//新しい依頼
if(!
isset(
$this->requsts[
$fd])){
//http头结束符
$ret =
strpos(
$data,self::
HTTP_EOF);
if(
$ret ===
false){
戻る false;
}他{
$this->buffer_header[
$fd] = ''
;
$request =
array();
list(
$header,
$request['body']) =
explode(self::HTTP_EOF,
$data,2
);
$request['head'] =
$this->parseHeader(
$header);
$this->リクエスト[
$fd] =
$リクエスト;
if(
$request['head'] ==
false){
戻る false;
}
}
}他{
//ポストデータマージ
$request =
$this->リクエスト[
$fd];
$request['body'] .=
$data;
}
返却 $リクエスト;
}
/**
* リクエストヘッダーを解析する
* @param string $header
* @return 配列
* 配列(
* 'メソッド'=>,
* 'uri'=>
* 'プロトコル'=>
* '名前'=>値,...
*
*
*
* }
*/
public function parseHeader(
$header){
$request =
array();
$headlines =
explode("rn",
$header);
list(
$request['メソッド'],
$request['uri'],
$request['プロトコル']) =
explode(' ',
$headlines[0] ,3
);
foreach (
$見出し as $k=>
$line){
$line =
トリム(
$line);
if(
$k && !
空(
$line) &&
strpos(
$line,':') !==
false){
list(
$name,
$value) =
explode(':',
$line,2
);
$request[
trim(
$name)] =
trim(
$value);
}
}
返却 $リクエスト;
}
/**
※投稿データが揃っているか確認してください
* @param 不明な $request
* @戻り文字列
*/
パブリック 関数 checkPost(
$request){
if(
isset(
$request['head']['Content-Length'
])){
if(
intval(
$request['head']['Content-Length']) > self::
HTTP_POST_MAXLEN){
return self::
ST_ERROR;
}
if(
intval(
$request['head']['Content-Length']) >
strlen(
$request['body'
])){
return self::
ST_WAIT;
}他{
return self::
ST_FINISH;
}
}
return self::
ST_ERROR;
}
/**
* リクエストを解析する
* @param 不明な $request
* @return 曖昧な
*/
パブリック 関数 parseRequest(
$request){
$request['time'] =
time();
$url_info =
parse_url(
$request['head']['uri'
]);
$request['head']['path'] =
$url_info['path'
];
if(
isset(
$url_info['フラグメント']))
$request['ヘッド']['フラグメント'] =
$url_info['フラグメント'
];
if(
isset(
$url_info['クエリ'
])){
parse_str(
$url_info['query'],
$request['get'
]);
}
//投稿本文を解析する
if(
$request['head']['method'] == 'POST'
){
//現在フォーム送信のみを処理しています
if (
isset(
$request['head']['Content-Type']) &&
substr(
$request['head']['Content-Type'], 0, 33 ) == 'application/x-www-form-urlencoded'
||
isset(
$request['head']['X-Request-With']) &&
$request['head']['X-Request-With'] == 'XMLHttpRequest'
){
parse_str(
$request['body'],
$request['post'
]);
}
}//クッキーを解析する
if(!
空(
$request['head']['Cookie'
])){
$params =
array();
$blocks =
explode(";",
$request['head']['Cookie'
]);
foreach (
$ブロック as $b){
$_r =
爆発("=,
$b, 2
);
if(
カウント(
$_r)==2
){
リスト (
$key,
$value) =
$_r;
$params[
trim(
$key)] =
trim(
$value, "rn t""
);
}他{
$params[
$_r[0]] = ''
;
}
}
$request['cookie'] =
$params;
}
返却 $リクエスト;
}
public function parseResponse(
$request,
$response){
if(!
isset(
$response['head']['Date'
])){
$response['head']['Date'] =
gmdate("D, d M Y H:i:s T"
);
}
if(!
isset(
$response['head']['Content-Type'
])){
$response['head']['Content-Type'] = 'text/html;charset=utf-8'
;
}
if(!
isset(
$response['head']['Content-Length'
])){
$response['head']['Content-Length'] =
strlen(
$response['body'
]);
}
if(!
isset(
$response['head']['Connection'
])){
if(
isset(
$request['head']['Connection']) &&
strto lower(
$request['head']['Connection']) == 'キープアライブ'
){
$response['head']['Connection'] = 'キープアライブ'
;
}他{
$response['head']['Connection'] = 'close'
;
}
}
$response['head']['Server'] = CFtpServer::
$software.'/'.CFtpServer::
VERSION;
$out = ''
;
if(
isset(
$response['head']['Status'
])){
$out .= 'HTTP/1.1 '.
$response['head']['Status']."rn"
;
unset(
$response['head']['Status'
]);
}他{
$out .= "HTTP/1.1 200 OKrn"
;
}
//ヘッダー
foreach(
$response['head']
as $k=>
$v){
$out .=
$k.': '.
$v."rn"
;
}
//クッキー
if(
$_COOKIE){
$arr =
array();
foreach (
$_COOKIE as $k =>
$v){
$arr[] =
$k.'='.
$v;
}
$out .= 'Set-Cookie: '.
implode(';',
$arr)."rn"
;
}
//終了
$out .= "rn"
;
$out .=
$response['body'
];
返品 $out