用PHP制作了一个文件服务器

你好,我是技术猫。
(这是我第一次发帖)

我用Apache和PHP(以及Tailwind CSS)创建了一个文件服务器。
在本文中,我将介绍如何读取JSON文件以实现登录功能,
以及如何实现文件上传功能等。
还会附带一些关于使用PHP执行命令的小贴士。

如果你阅读代码中被注释的部分,就可以理解它的意思!
这篇文章介绍的代码可能存在安全隐患,请不要将其公开给外部等。

提供了以下内容的中文重述:

– 提供了源文件
– 给出了资源
– 给出了资料
– 给予了相关数据
– 给予了相关信息

 

我們通過GitHub的發布功能將所有編寫的程式碼以MIT許可證進行了分發。

只要有Apache和PHP,就可以使用。(测试环境为macOS)

登录功能

登录功能最初是在PHP内部编写的密码哈希,但后来需要出现的”用户添加功能”需要将其保存在Json文件中…

我立刻犯了錯!

因为我是一个编程初学者,所以在使用PHP读取JSON文件时,我采用了一种奇怪的写法。


{"users":[
    {
        "username":"admin",
        "password":"$2y$10$3dmC2Lq8r/9B8F83NrLqMulwkwuk.QgJsvQXXumwX83k6mQzmjQP2"
    }
]}


<?php
    require_once __DIR__ . '/functions.php';
    require_unlogined_session();
    function get_password($username) {
        $json = file_get_contents('http://192.168.1.100/tCloud/users.json');
        $datas = json_decode($json, true);
        $name = $datas['users']
        return $name[$username]['password']; 
        # users.jsonの中でも、"users"の中にはusernameはなく、"users"の1番目の中にusernameがある。
    }
    $username = filter_input(INPUT_POST, 'username');
    $password = filter_input(INPUT_POST, 'password');
    if ($username == "rsa"){

        header("Location: rsa.php");
        exit;

    }
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {

        if (password_verify($password,get_password($username))){ # なので、ここでエラー。
            session_regenerate_id(true);
            $_SESSION['username'] = $username;
            header('Location: /tCloud/');
            exit;
        } else {
            http_response_code(403);
        }
    }
    header('Content-Type: text/html; charset=UTF-8');
# この先省略

在使用 Microsoft Copilot(Bing) 提供的修正建议后进行了修正后的版本如下:


<?php
    require_once __DIR__ . '/functions.php';
    require_unlogined_session();
    function get_password($username) {
        $json = file_get_contents('http://192.168.1.100/tCloud/users.json');
        $datas = json_decode($json, true);
        foreach ($datas['users'] as $name) {
            if ($name['username'] == $username) {
                return $name['password']; #ちゃんと全部読み取ってみて
            }
        }
        return null; # なかったらNull
    }
    $username = filter_input(INPUT_POST, 'username');
    $password = filter_input(INPUT_POST, 'password');
    if ($username == "rsa"){
        header("Location: rsa.php");
        exit;
    }
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        if (password_verify($password,get_password($username))){
            session_regenerate_id(true);
            $_SESSION['username'] = $username;
            header('Location: /tCloud/');
            exit;
        } else {
            http_response_code(403);
        }
    }
    header('Content-Type: text/html; charset=UTF-8');

# この先省略

感觉就是这样。
因为需要指定是第几个,所以我在这时才意识到要使用foreach。

存储上传功能

上传进行了逐一检查并完成了。
感觉就像每个用户都有自己的存储空间和共享驱动器。


<?php

require_once __DIR__ . '/../functions.php';
require_logined_session();

header('Content-Type: text/html; charset=UTF-8');

?>

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Share File</title>
        <link rel="stylesheet" href="/dist/output.css" />
    </head>

    <body class="text-black bg-white">
        <div class="flex flex-col h-screen">
        <div class="">
            <font color="blue">
                <a href="#" onclick="history.back()"> < back </a>
            </font>
        </div>
            <div>
                <div class="flex justify-center mt-20">
                    <div class="w-9/12 border rounded-3xl bg-gray-200 dark:bg-gray-200">
                        <div class="my-16 text-center">

                            <img src="/link.png" style="display: block; margin: auto;">
                            <br><br>

                            <h2 class="text-xl">Upload</h2>

                            <font color="orange">

                            <?php
                                $temporary_file = $_FILES['user_file_name']['tmp_name']; # 一時ファイル名
                                $true_file = $_FILES['user_file_name']['name']; # 本来のファイル名

                                # is_uploaded_fileメソッドで、一時的にアップロードされたファイルが本当にアップロード処理されたかの確認
                                if (is_uploaded_file($temporary_file)) {
                                    if (move_uploaded_file($temporary_file , $true_file )) {
                                        echo "Upload completed.
                                        The file is located at the following URL:<br>
                                        <a href='http://192.168.1.100:8080/tCloud/files/" . $true_file . "'>http://192.168.1.100:8080/files/" . $true_file . "</a>";
                                    } else {
                                        echo "Upload failed.";
                                    }
                                } else {
                                    echo "Upload failed.";
                                }
                            ?>

                            </font>

                            <br><br>
                            <form enctype="multipart/form-data"  action="upload.php" method="POST">
                              <input type="hidden" name="name" value="value" />
                              <input name="user_file_name" type="file" />
                              <input type="submit" value="Upload" />
                            </form> 
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </body>
</html>

附赠内容:管理控制台

为了额外提供一项功能,我们创建了一个名为”Admin Console”的工具。
这个工具可以让管理员来管理用户的添加。


<?php

require_once __DIR__ . '/../functions.php';
require_logined_session();

$username = $_SESSION['username'];

if ($username == "admin"){

} else{
    header("Location: /403.php");
    exit();
}

header('Content-Type: text/html; charset=UTF-8');

?>

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Add User - tCloud</title>
        <link rel="stylesheet" href="/dist/output.css" />
    </head>
    <body class="text-black bg-white">
        <div class="flex flex-col h-screen">
        <div class="">
            <br>
        </div>
            <div>
                <div class="flex justify-center mt-20">
                    <div class="text-center">

                        <img src="/icon-128x128.png" style="display: block; margin: auto;">
                        <h1 class="text-5xl">tCloud</h1>
                        Admin Console
                        <br><br>
                        <form action="adduser.php" method="POST" class="mt-12 disabled:bg-slate-50 disabled:text-slate-500  disabled:shadow-none  invalid:text-pink-600  focus:invalid:ring-pink-500">
                            <div class="mb-3">
                                <input
                                    type="text"
                                    placeholder="ID"
                                    name="username"
                                    required
                                    class="w-80 focus:ring-2 focus:ring-blue-500 focus:outline-none appearance-none text-sm text-slate-900 placeholder-slate-400 rounded-md py-2 ring-1 ring-slate-200 shadow-sm"
                                />
                            </div>
                            <div class="mb-5">
                                <input
                                    type="text"
                                    placeholder=" PW"
                                    name="password"
                                    minlength="6"
                                    class="w-80 focus:ring-2 focus:ring-blue-500 focus:outline-none appearance-none text-sm text-slate-900 placeholder-slate-400 rounded-md py-2 ring-1 ring-slate-200 shadow-sm"
                                />
                            </div>
                            <input type="hidden" name="token" value="<?=h(generate_token())?>">
                            <button type="submit">
                                Create User
                            </button>
                        </form>

                    </div>
                </div>
            </div>
        </div>
    </body>
</html>

处理方面有两个。

有两个文件分别是/tCloud/admin/adduser.php和/tCloud/drive/adduser.php。

我在做的事情是执行命令和创建文件。

管理员文件夹中的adduser.php是。


<?php

    require_once __DIR__ . '/../functions.php';
    require_logined_session();

    $username = $_SESSION['username'];

    if ($username == "admin"){

    } else{
        header("Location: /403.php");
        exit();
    }

    $user = [
        'username' => $_POST['username'],
        'password' => password_hash($_POST['password'], PASSWORD_BCRYPT)
    ];

    $json = file_get_contents('http://192.168.1.100/tCloud/users.json'); # jsonを取得
    $data = json_decode($json, true); # jsonデータを配列へ
    $data['users'][] = $user; # jsonファイルの中の'users'の中を指定
    $json = json_encode($data); # 配列をjsonデータへ
    file_put_contents('../users.json', $json); # 'users'に追記

    header("Location: ../drive/adduser.php?username=" . $_POST['username']);
    # driveのadduser.phpに移動

?>

当你转到drive的adduser.php页面时,将加载以下文件。


<?php

    require_once __DIR__ . '/../functions.php';
    require_logined_session();

    $username = $_SESSION['username'];

    if ($username == "admin"){

    } else{
        header("Location: /403.php");
        exit();
    }

    exec("mkdir " . $_GET['username']); # ディレクトリ(フォルダ)作成
    exec("chmod 777 " . $_GET['username']); # 読み込み・書き込み権限つける
    exec("touch " . $_GET['username'] . "/index.php"); # index.php作成
    exec("chmod 777 " . $_GET['username'] . "/index.php"); # 読み込み・書き込み権限つける
    $file = fopen($_GET['username'] . "/index.php", "w");# ファイルを開く
    fwrite($file, '
    
    <?php

    require_once __DIR__ . "/../../functions.php";
    require_logined_session();
    
    $username = $_SESSION["username"];
    
    if ($username == "' . $_GET['username'] . '"){
    
    } else{
        header("Location: /403.php");
        exit();
    }
    
    header("Content-Type: text/html; charset=UTF-8");
    
    ?>
    
    <!DOCTYPE html>
    <html lang="ja">
        <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <title>Your Drive</title>
            <link rel="stylesheet" href="/dist/output.css" />
        </head>
    
        <body class="text-black bg-white">
            <div class="flex flex-col h-screen">
            <div class="">
                <font color="blue">
                    <a href="#" onclick="history.back()"> < back </a>
                </font>
            </div>
                <div>
                    <div class="flex justify-center mt-20">
                        <div class="w-9/12 border rounded-3xl bg-gray-200 dark:bg-gray-200">
                            <div class="my-16 text-center">
    
                              
                                <img src="/drive.png" style="display: block; margin: auto;">
                                <br><br>
    
                                <h2 class="text-xl">Upload</h2>
    
                                <form enctype="multipart/form-data"  action="upload.php" method="POST">
                                  <input type="hidden" name="name" value="value" />
                                  <input name="user_file_name" type="file" />
                                  <input type="submit" value="Upload" />
                                </form> 
    
                                <br><br>
    
                                <h2 class="text-xl">Files</h2>
    
                                <?PHP
                                  $dirpath = "./";
                                  $dirlist = dir($dirpath);
                                  while( $filename = $dirlist->read() ){
                                    if( (is_dir($filename) == false) && ($filename!=".." || $filename!= "." ) ){
                                      if ($filename !== "index.php" && $filename !== "upload.php"){
                                        print("<a href=\"/download.php?author=chii&path=" .  $filename . "\"><button>".$filename."</button></a><br>\n");
                                      }
                                    }
                                  }
                                  $dirlist->close();
                                ?>
                                
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </body>
    </html>
    
    
    
    '); # ファイルに書き込み
    fclose($file); # ファイルを閉じる

    exec("touch " . $_GET['username'] . "/upload.php"); # upload.phpを作成
    exec("chmod 777 " . $_GET['username'] . "/upload.php"); # 読み込み・書き込み権限をつける
    $file = fopen($_GET['username'] . "/upload.php", "w"); # upload.phpを開く
    fwrite($file, '
    
    <?php

require_once __DIR__ . "/../../functions.php";
require_logined_session();

header("Content-Type: text/html; charset=UTF-8");

$username = $_SESSION["username"];

if ($username == "' . $_GET['username'] . '"){

} else{
    header("Location: /403.php");
    exit();
}

?>

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Your Drive</title>
        <link rel="stylesheet" href="/dist/output.css" />
    </head>

    <body class="text-black bg-white">
        <div class="flex flex-col h-screen">
        <div class="">
            <font color="blue">
                <a href="#" onclick="history.back()"> < back </a>
            </font>
        </div>
            <div>
                <div class="flex justify-center mt-20">
                    <div class="w-9/12 border rounded-3xl bg-gray-200 dark:bg-gray-200">
                        <div class="my-16 text-center">

                          
                            <img src="/drive.png" style="display: block; margin: auto;">
                            <br><br>

                            <h2 class="text-xl">Upload</h2>

                            <font color="orange">

                            <?php
                                $temporary_file = $_FILES["user_file_name"]["tmp_name"]; 
                                $true_file = $_FILES["user_file_name"]["name"]; 

                                if (is_uploaded_file($temporary_file)) {
                                    if (move_uploaded_file($temporary_file , $true_file )) {
                                        echo $true_file . " is Uploaded";
                                    } else {
                                        echo "Upload failed";
                                    }
                                } else {
                                    echo "Upload failed";
                                }
                                var_dump($true_file);
                            ?>

                            </font>

                            <br><br>
                            <form enctype="multipart/form-data"  action="upload.php" method="POST">
                              <input type="hidden" name="name" value="value" />
                              <input name="user_file_name" type="file" />
                              <input type="submit" value="Upload" />
                            </form> 

                            <br><br>

                            <h2 class="text-xl">Files</h2>

                            <?PHP
                              $dirpath = "./";	
                              $dirlist = dir($dirpath);
                              while( $filename = $dirlist->read() ){
                                if( (is_dir($filename) == false) && ($filename!=".." || $filename!= "." ) ){
                                  if ($filename !== "index.php" && $filename !== "upload.php"){
                                    print("<a href=\"/download.php?author=chii&path=" .  $filename . "\"><button>".$filename."</button></a><br>\n");
                                  }
                                }
                              }
                              $dirlist->close();
                            ?>
                            
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </body>
</html>


    
    '); # ファイルに書き込み
    fclose($file); # ファイルを閉じる

    header("Location: ../admin/index.php"); # 最初の画面に戻る

?>

做这个有点难…

在中文中可以翻译为:最后

你觉得如何呢?由于是我最初发布的帖子,所以写作方式等还很困难,但如果对JSON的读取方法有所帮助的话,那真是太好了。

 

请务必去GitHub的release页面查看,感谢您的查看。
非常感谢您的阅读,我们下一次在其他文章中见!

广告
将在 10 秒后关闭
bannerAds