使用vsftp基於mysql搭建ftp服務器及使用web界面管理(附php源碼)

一、FTP服務器

   FTP,File Transfer Protocol 文件傳輸協議,FTP協議是一種古老的協議,它出現的比HTTP協議還要早,FTP主要應用於網絡空間數據交換操作。ftp在工作時會有兩個連接:一是命令連接,這個連接始終存在,只有使用bye命令退出會話時,連接纔會斷開;二是數據連接,數據傳輸完成,連接即斷開。ftp有兩種工作模式,主動模式和被動模式,主動模式工作在tcp/20端口,而被動模式則工作在tcp協議下的隨機端口。通常FTP在身份認證時工作在21號端口。

   在紅帽系統下,vsftp是一款相對安全的FTP軟件,在生產環境下可以使用它快速的實現FTP服務器的搭建。vsftp的用戶認證支持兩類用戶,一是系統用戶,二是虛擬用戶。系統用戶故名思義,就是使用系統上的普通用戶作爲FTP用戶,這種方式操作相對簡單。而虛擬用戶則是使用一個系統用戶映射成所有虛擬用戶,訪問時的文件目錄是爲此係統用戶家目錄。虛擬用戶的用戶帳號信息的存儲分兩種方式,一是將用戶信息保存於一個hash編碼的文件,奇數行爲用戶名,偶數行爲密碼;二是,存儲於關係型數據庫。我們知道,系統上幾乎所有的和帳號認證有關的操作都是通過系統的pam模塊負責管理,vsftp也不例外,我們使用mysql管理vsftp的帳號密碼信息,則可以使用pam的mysql模塊。pam默認不支持mysql數據庫,因此在使用前需要安裝此模塊。


二、FTP服務器實現

1、安裝軟件

# yum -y install vsftpd mysql-server mysql-devel pam_mysql

wKiom1M2PtuxG0yFAAINl1y4T9g787.jpg


wKioL1M2Pr7huOYpAAPWIqZqB0g984.jpg


2、創建數據庫

mysql> create database vsftpd;
mysql> grant all on vsftpd.* to 'vsftpuser'@'localhost' identified by 'vsftppass';
mysql> grant all on vsftpd.* to 'vsftpuser'@'127.0.0.1' identified by 'vsftppass';
mysql> grant all on vsftpd.* to 'vsftpuser'@'172.16.36.1' identified by 'vsftppass';
mysql> flush privileges;
mysql> use vsftpd;
mysql> create table users (
    -> id int AUTO_INCREMENT NOT NULL,
    -> name char(20) binary NOT NULL,
    -> password char(48) binary NOT NULL,
    -> primary key(id)
    -> );

wKiom1M2QRqQRIWVAAGjQ5jGDb8745.jpg


2、創建vsftp虛擬用戶

insert into users(name,password) values('wu',md5('wu'));
insert into users(name,password) values('json',md5('json'));

wKioL1M2c23QGzNHAAHLRJn3msU047.jpg


3、建立pam認證所需文件

#vi /etc/pam.d/vsftpd.mysql

添加如下兩行:

auth required /lib64/security/pam_mysql.so user=vsftpuser passwd=vsftppass host=172.16.36.1 db=vsftpd table=users usercolumn=name passwdcolumn=password crypt=3
account required /lib64/security/pam_mysql.so user=vsftpuser passwd=vsftppass host=172.16.36.1 db=vsftpd table=users usercolumn=name passwdcolumn=password crypt=3

user: 數據庫用戶名

passwd: 數據庫用戶密碼

host: 爲數據庫主機IP地址,如果是編譯安裝的數據庫,只能填寫遠程IP地址,並給把這個IP地址授權給用戶

db: 數據庫名

table: 表名

usercolumn: 用戶字段名

passwdcolumn: 用戶密碼字段名

crypt: 密碼保存方式,0爲明文,1爲encrypt函數加密,2爲password函數加密,3爲MD5加密


注意:由於mysql的安裝方式不同,pam_mysql.so基於unix sock連接mysql服務器時可能會出問題,此時,建議授權一個可遠程連接的mysql並訪問vsftpd數據庫的用戶。


4、建立虛擬用戶映射的系統用戶及對應的目錄

# useradd -s /sbin/nologin -d /var/ftproot vuser
# chmod go+rx /var/ftproot


5、請確保/etc/vsftpd/vsftpd.conf中已經啓用了以下選項

anonymous_enable=NO   #禁止匿名用戶登錄
local_enable=YES      #允許本地用戶登錄
write_enable=YES      #本地用戶有寫權限
anon_upload_enable=NO #匿名用戶沒有上傳權限
anon_mkdir_write_enable=NO #匿名用戶沒有創建權限
chroot_local_user=YES #禁錮用戶家目錄

而後添加以下選項

guest_enable=YES
guest_username=vuser

並確保pam_service_name選項的值如下所示

pam_service_name=vsftpd.mysql


6、重新啓動服務,測試一下。

service vsftpd restart

打開CMD程序遠程測試一下:

wKioL1M2d5Lx7S7HAAIuIbAIAh0966.jpg


兩個帳號都能成功登錄!


二、通過web管理VSFTP

   使用mysql管理vsftp用戶的一個好處是,當服務器數據遷移時,只要把相關的數據庫打包備份導入新的數據庫就行了,管理相當方便。如果本機上有web服務器的話,我們還可以使用PHP開發一個web界面專門用來管理vsftp。

例如:我們新建一個虛擬主機:

<VirtualHost *:80>
    DocumentRoot "/var/www/html/vsftpadmin"
    ServerName ftpadmin.wubinary.com
    ServerAlias ftpadmin.wubinary.com
    ErrorLog "logs/ftpadmin.wubinary.com.error_log"
    CustomLog "logs/ftpadmin.wubinary.com.access_log" common
    ProxyRequests Off
    ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/html/vsftpadmin/$1
    <Directory "/var/www/html/vsftpadmin">
      Options None
      AllowOverride AuthConfig
      AuthType Basic
      AuthName "Vsftp Admin"
      AuthUserFile /etc/httpd/extra/.htpasswd
      Require valid-user
    </Directory>
</VirtualHost>

對這個域名作身份認證,或者使用其它的方式對用戶進行限制,用PHP寫一個管理頁面放在相關的目錄下,我們就可以在web界面下管理我們的FTP服務器帳號了。

wKioL1M2ilfAVTAOAAHhbRmXfQg613.jpg


wKiom1M2io-wsfBAAAFA9QYAVe8057.jpg


整個FTP服務器的搭建工作到此就完成了。vsftp web管理界面的PHP源碼如下:


vsftpadmin.php


<?php
header("Content-Type:text/html;charset=utf-8");
error_reporting(E_ALL & ~ E_NOTICE);
//提示窗
function alertExit($msg,$flush=0){
    // echo "<script language='javascript'>alert($msg);</script>";
    echo "<script type='text/javascript' language='javascript'>alert('$msg');</script>";
    if ($flush == 1) {
        echo "<script type='text/javascript' language='javascript'>window.location.href='vsftpadmin.php'</script>";
    }elseif ($flush == 2) {
        echo "<script type='text/javascript' language='javascript'>history.back();self.location.reload();</script>";
    }
}
//輸出頭部
function htmlheader($title){
echo <<<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type"  content="text/html; charset=utf-8">
<title>{$title}</title>
<meta name="description" content="vsftp管理工具">
<meta name="keywords" content="linux,ftp,vsftp,mysql,pam_mysql,php">
<style type="text/css">
*{margin:0; padding:0; font-size:12px;}
ul,li{ list-style:none;}
a {text-decoration:none;color:#37a}
a:hover { background:#37a;color:white;padding:2px;}
img { border:0;}
.clear{ clear:both;}
.right{ float:right;}
.left{ float:left;}
#content{width:560px;margin:0 auto;text-align:center;margin-top:40px;}
.admin{border:1px solid #ccc; padding:30px;text-align:left;}
.admin h4{margin:10px 0;}
.admin p{margin:10px 0;}
.admin p .btn{padding:2px 4px;}
</style>
</head>
<body>
<div id="content">
    <div class="admin">
        <h4>{$title}</h4>
        <p class="admin_btn">管理菜單:<a href="?ac=ftp">ftp狀態</a>&nbsp;&nbsp;<a href="vsftpadmin.php">用戶列表</a>&nbsp;&nbsp;<a href="?ac=add">添加用戶</a></p>
EOF;
}
//輸出尾部
function htmlfooter(){
echo <<<EOF
    </div>
</div>
</body>
</html>
EOF;
}
//查詢
function query($sql){
                
    $result = mysql_query($sql)  or die ("SQL語句查詢錯誤: " . mysql_error());
    if (mysql_num_rows($result) == 0) {
            die('SQL: '.$sql.'<br>未查詢到相關數據');
    }
    $arrReturn = array();
    $index = 0;
    while($arr = mysql_fetch_assoc($result)){
        $arrReturn[$index] = $arr;
        $index++;
    }
    return $arrReturn;
}
//添加
function adduser($name,$password){
                
    if (strlen($name)<3) {
        alertExit('用戶名至少三位!',1);
    }
    if (strlen($password)<6) {
        alertExit('密碼必須大於八位!',1);
    }
    $sql = "select * from users where name='$name'";
    $result = mysql_query($sql)  or die ("SQL語句查詢錯誤: " . mysql_error());
    if (mysql_num_rows($result) > 0) {
            alertExit('用戶已存在',1);
    }else{
        $sql = "insert into users(name,password) values('$name',md5('$password'))";
        $result = mysql_query($sql)  or die ("添加角戶出錯: " . mysql_error());
        // echo mysql_affected_rows();
        if(mysql_affected_rows()==1){
            alertExit("添加用戶成功!",2);
        }
    }  
}
//刪除
function deluser($id){
    $sql = 'select * from users where id='.$id;
    $result = mysql_query($sql)  or die ("SQL語句查詢錯誤: " . mysql_error());
    if (mysql_num_rows($result) == 0) {
            alertExit('用戶不存在',1);
    }else{
        $sql = 'delete from users where id='.$id;
        $result = mysql_query($sql)  or die ("刪除角戶出錯: " . mysql_error());
        if(mysql_affected_rows()==1){
            alertExit("刪除用戶成功!",1);
        }
    }
}
//修改
function moduser($id,$name,$password){
    $sql = "select * from users where id=$id";
    $result = mysql_query($sql)  or die ("SQL語句查詢錯誤: " . mysql_error());
    if (mysql_num_rows($result) == 0) {
            alertExit('用戶不存在',1);
    }else{
        $sql = "select * from users where name='$name' and id!=$id";
        $result = mysql_query($sql)  or die ("SQL語句查詢錯誤: " . mysql_error());
        if (mysql_num_rows($result) > 0) {
                alertExit('用戶已存在',1);
        }else{     
            $sql = "update users set name='$name', password='$password' where id=$id";
            $result = mysql_query($sql)  or die ("修改角戶出錯: " . mysql_error());
            if(mysql_affected_rows()==1){
                alertExit("修改用戶成功!",1);
            }
            alertExit("未作任何操作!",1);
        }
    }
}
//ftp狀態管理
function ftpadmin($service='status'){
                
    $arrFtp = array();
    $result = mysql_query("SELECT id FROM users");
    $num_rows = mysql_num_rows($result);
    $arrFtp['usercount'] = $num_rows;
                
    if($service=='status'){
                    
        $arrFtp['status'] = `service vsftpd status`;
                    
    }elseif($service=='restart'){
                    
        $arrFtp['status'] = `service vsftpd restart`;
                    
    }elseif ($service=='stop') {
                    
        $arrFtp['status'] = `service vsftpd stop`;
                    
    }
                
    if(empty($arrFtp['status'])){
        $arrFtp['status'] = 'Unknow';
    }
    return $arrFtp;
                
}
$conn = @mysql_connect('127.0.0.1','root','')  or die ('數據庫連接錯誤: ' . mysql_error());
mysql_select_db('vsftp', $conn) or die ('選擇數據庫錯誤: ' . mysql_error());
$strAction = htmlspecialchars($_GET['ac']);
$arrAction = array('del', 'mod', 'add', 'ftp');
if (! in_array($strAction, $arrAction)) {
        htmlheader('Vsftp 管理');
        $arrUserList = query('select * from users');
        foreach ($arrUserList as $key => $value) {
        ?>
        <form action='./vsftpadmin.php?ac=mod' method='post'>
        <p><label>name:</label> <input type="text" name="name" value="<?php echo $value['name'];?>">
            <label>password:</label> <input type="password" name="password" value="<?php echo $value["password"];?>">
            <input type='hidden' name='id' value="<?php echo $value["id"];?>">
             <input type="submit" value="修改" class="btn">&nbsp;<input type="button" onclick="window.location.href='?id=<?php echo $value["id"];?>&ac=del'" value="刪除" class="btn"></p>
        </form>
        <?php }
        htmlfooter();
}else{
                
    if ($strAction=='add') {
                    
        if ($_SERVER['REQUEST_METHOD']=='POST') {
                        
            $name = htmlspecialchars($_POST['name']);
            $password = htmlspecialchars($_POST['password']);
                        
            adduser($name,$password);
                        
        }else{
            htmlheader('添加用戶');
            ?>
        <form action='./vsftpadmin.php?ac=add' method='post'>
        <p><label>name:</label> <input type="text" name="name" value="">
            <label>password:</label> <input type="password" name="password" value="">
            <input type="submit" value="提交" class="btn">&nbsp;<input type="reset" value="重置" class="btn"></p>
        </form>
<?php       
            htmlfooter();
        }
    }elseif ($strAction=='del') {
                    
        $intId = intval($_GET['id']);
                    
        if($intId!=''){
            deluser($intId);
        }else{
            alertExit('參數錯誤!',1);
        }
                    
    }elseif ($strAction=='mod') {
                    
        $intId = intval($_POST['id']);
                    
        $name = htmlspecialchars($_POST['name']);
        $password = htmlspecialchars($_POST['password']);
                                
        if($name!='' && $password!=''){
            moduser($intId,$name,$password);
        }else{
            alertExit('參數錯誤!',1);
        }
    }elseif($strAction=='ftp'){
            htmlheader('FTP狀態');
            $arrFtp = array();
            $status = htmlspecialchars($_GET['status']);
            if($status=='restart')$arrFtp = ftpadmin('restart');
            elseif($status=='stop')$arrFtp = ftpadmin('stop');
            else $arrFtp = ftpadmin();
            ?>
        <p><label>用戶總數:</label> <?php echo $arrFtp['usercount'];?> <br>
            <label>vsftp狀態:</label> <?php echo $arrFtp['status'];?>
            <input type="button" onclick="window.location.href='?ac=ftp&status=restart'" value="重啓" class="btn">&nbsp;<input type="button" onclick="window.location.href='?ac&status=stop'" value="停止" class="btn"></p>
<?php       
            htmlfooter();
                    
    }else{
        die('無效的地址!');
    }
}








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章