用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页面查看,感谢您的查看。
非常感谢您的阅读,我们下一次在其他文章中见!