目录
前言
大家好,又来挖坑了,前段时间做了一个网站,网站主要是一个休闲娱乐为主题的,但平时感觉不常用、而且比较简单且垃圾。
接下来我就给大家介绍一下我的网站的制作过程,还有一些坑给大家避一下。
一样一样,还是 Windows,别的用不了这个方法。
准备工作
Html or php
::::info[一大堆废话]
首先我们先把他们的全称写一下:
- HTML:HyperText Markup Language(超文本标记语言)
- PHP:Hypertext Preprocessor(超文本预处理器)
通过全称,我们可以看到:HTML 其实就是将你的代码放在网页上;php 你可以理解为就是把你的代码预处理成 html,然后再运行 html 在网页上。
如果你只是想做一个静态的,那就用 html,因为 html 在本地电脑上就可以运行。
但你想做一个网站比如可以登录的,那就用 php,但是 php 有一个缺点就是你需要下载一些可以运行 php 的东西。
::::
一句话概括上面的废话,建议用 php。
链接:https://www.php.net/downloads.php 我就是从这里下载的,里面翻译一下找到自己的版本下载就行。
解压,然后放到,D 盘?E 盘?哪个盘的哪个位置都行,当一个样板或直接在上面做网站。
如果按照上面的链接,你需要复制一个
php.ini-development,粘贴在原文件夹,重命名为php.ini。
这里有个坑:千万不要下载 phpStudy 或所谓的 php 编辑器,因为那基本上要么和你想要的不是一个东西,要么要花钱。
数据库
这里我比较推荐 MySQL,因为如果从上面的链接里下载的 php 是有自带的 mysqli 的,比较方便。
但你还需要下载一个 mysqli,下载链接:https://dev.mysql.com/downloads/installer 这个的操作步骤可以问 AI 大人,Ta 是会给你解答的。
这一部分是在样板里改。
但是,你需要开启这个 mysqli,在 php.ini 中改,例如下图 898 行处,把前面的分号删了:

别的啥也不用改。
开始写网站
做一个网站最重要的就是开始写!
先复制一个样板过来,重命名任意。
接下来用管理员权限运行你的 Windows PowerShell。
用 cd 命令切到你的项目主文件夹,例如:你的项目主文件夹为 D:/www/,那你就写:
cd D:/www
然后,让 php 能够运行到网页上(此处的 80 是端口号,可以改):
php -S 127.0.0.1:80
这样你访问 http://127.0.0.1:80 就能出来你的网站了。
写网站
初始化数据库
在网站主文件夹下写一个 database.php,可以参考我的。
::::success[database.php]{open}
这一段不用怀疑,是 AI 大人写的。
php
<?php
// 连接参数
$host = 'localhost';
$user = 'root';
$pass = ''; // 你的 MySQL 密码
$link = mysqli_connect($host, $user, $pass);
if ($link) {
// SQL 文件路径
$sql_file = $_SERVER['DOCUMENT_ROOT'].'cc';
if (!file_exists($sql_file)) {
die("❌ SQL 文件不存在: $sql_file\n");
}
// 读取 SQL 文件内容
$sql_content = file_get_contents($sql_file);
// 分割 SQL 语句(处理分号,但保留存储过程中的分号)
$queries = [];
$current_query = '';
$in_string = false;
$string_char = '';
for ($i = 0; $i < strlen($sql_content); $i++) {
$char = $sql_content[$i];
// 处理字符串
if ($char === "'" || $char === '"') {
if (!$in_string) {
$in_string = true;
$string_char = $char;
} elseif ($char === $string_char) {
// 检查是否是转义
if ($i > 0 && $sql_content[$i-1] !== '\\') {
$in_string = false;
}
}
}
$current_query .= $char;
// 不在字符串中且遇到分号,结束当前语句
if (!$in_string && $char === ';') {
$queries[] = trim($current_query);
$current_query = '';
}
}
// 添加最后一个查询(如果没有分号结尾)
if (!empty(trim($current_query))) {
$queries[] = trim($current_query);
}
// 执行每个查询
$success = 0;
$failed = 0;
foreach ($queries as $index => $query) {
if (empty(trim($query))) {
continue;
}
$query_num = $index + 1;
echo "[$query_num] 执行: " . substr($query, 0, 60) . "... ";
if ($link->query($query)) {
echo "✅ 成功\n";
$success++;
} else {
echo "❌ 失败: " . $link->error . "\n";
$failed++;
}
}
echo "\n📊 执行结果:\n";
echo "✅ 成功: $success 条\n";
echo "❌ 失败: $failed 条\n";
} else {
echo "❌ 连接失败: " . mysqli_connect_error() . "\n";
echo "\n可能原因:\n";
echo "1. MySQL 服务未运行 - 运行: net start MySQL80\n";
echo "2. 密码错误 - 你设置的密码是: '$pass'\n";
echo "3. 端口被占用 - 检查端口 3306\n";
}
?>
::::
但是先别运行。
接下来再新建一个 /db/app_db233.sql,里面先写:
sql
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+08:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `app_db233` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
USE `app_db233`;
接下来就是新建各种数据表,比如。
sql
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `user_id` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `user_id`
--
LOCK TABLES `user_id` WRITE;
/*!40000 ALTER TABLE `user_id` DISABLE KEYS */;
/*!40000 ALTER TABLE `user_id` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `user_info`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `user_info` (
`username` varchar(20) NOT NULL,
`password` char(32) NOT NULL,
`encrypt` int(11) NOT NULL DEFAULT '0',
`decrypt` int(11) NOT NULL DEFAULT '0',
`color` varchar(32) NOT NULL DEFAULT 'cyan',
`manage` char(1) DEFAULT NULL,
`banned` char(1) DEFAULT NULL,
`muted` char(1) DEFAULT NULL,
PRIMARY KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `user_info`
--
LOCK TABLES `user_info` WRITE;
/*!40000 ALTER TABLE `user_info` DISABLE KEYS */;
/*!40000 ALTER TABLE `user_info` ENABLE KEYS */;
UNLOCK TABLES;
最后可以运行 /database.php 了。
运行方法:浏览器访问 http://127.0.0.1:80/database.php 进行初始化数据库。
网站主体可以用 Route 实现
我建议写一个 Route,可以直接套用我这个,在主文件夹下建很多文件可以参考下图:
主文件夹
|- models
| |- Route.php
|- index.php
|- route.php
注:不包括已有文件。
这里的所有文件都可以抄我的:
::::success[/models/Route.php]{open}
这个显然不是 AI 大人写的。
php
<?php
class Route {
protected static $routes = array();
protected static $patterns = array();
protected static $groupStack = array(array());
public static function match($methods, $uri, $action) {
return self::addRoute(array_map('strtoupper', (array)$methods), $uri, $action);
}
public static function any($uri, $action) {
return self::addRoute(array('GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'), $uri, $action);
}
public static function get($uri, $action) {
return self::addRoute(['GET', 'HEAD'], $uri, $action);
}
public static function post($uri, $action) {
return self::addRoute('POST', $uri, $action);
}
public static function put($uri, $action) {
return self::addRoute('PUT', $uri, $action);
}
public static function patch($uri, $action) {
return self::addRoute('PATCH', $uri, $action);
}
public static function delete($uri, $action) {
return self::addRoute('DELETE', $uri, $action);
}
public static function group(array $attributes, Closure $callback) {
self::$groupStack[] = array_merge(self::getGroup(), $attributes);
call_user_func($callback);
array_pop(self::$groupStack);
}
public static function getGroup() {
return self::$groupStack[count(self::$groupStack) - 1];
}
public static function pattern($name, $pat) {
self::$patterns[$name] = $pat;
}
public static function dispatch() {
foreach (self::$routes as $route) {
if (self::checkRoute($route)) {
include $_SERVER['DOCUMENT_ROOT'].$route['action'];
return $route;
}
}
// 你个人的 404 页面
}
protected static function addRoute($methods, $uri, $action) {
if (is_string($methods)) {
$methods = [$methods];
}
$cur = array();
$cur['methods'] = $methods;
$cur['uri'] = rtrim($uri, '/');
$cur['action'] = $action;
$cur = array_merge(self::getGroup(), $cur);
self::$routes[] = $cur;
return $cur;
}
public static function httpHost() {
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
return $_SERVER['HTTP_X_FORWARDED_HOST'];
} elseif (isset($_SERVER['HTTP_HOST'])) {
return $_SERVER['HTTP_HOST'];
} else {
return $_SERVER['SERVER_NAME'].($_SERVER['SERVER_PORT'] == '80' ? '' : ':'.$_SERVER['SERVER_PORT']);
}
}
public static function requestPath() {
$uri = $_SERVER['REQUEST_URI'];
$p = strpos($uri, '?');
if ($p === false) {
return $uri;
} else {
return substr($uri, 0, $p);
}
}
protected static function checkRoute($route) {
if (!in_array($_SERVER['REQUEST_METHOD'], $route['methods'])) {
return false;
}
$rep_arr = array();
foreach (self::$patterns as $name => $pat) {
$rep_arr['{'.$name.'}'] = "(?P<$name>$pat)";
}
$rep_arr['/'] = '\/';
$rep_arr['.'] = '\.';
$matches = array();
if (isset($route['domain'])) {
$domain_pat = strtr($route['domain'], $rep_arr);
if (!preg_match('/^'.$domain_pat.'$/', self::httpHost(), $domain_matches)) {
return false;
}
$matches = array_merge($matches, $domain_matches);
}
$uri_pat = strtr($route['uri'], $rep_arr);
if (!preg_match('/^'.$uri_pat.'$/', rtrim(self::requestPath(), '/'), $uri_matches)) {
return false;
}
$matches = array_merge($matches, $uri_matches);
foreach ($matches as $key => $val) {
if (!is_numeric($key)) {
$_GET[$key] = $val;
}
}
return true;
}
}
注意要改一下第 50 行。
::::
::::success[route.php]{open}
php
<?php
Route::pattern('username', '[a-zA-Z0-9_]{1,20}');
Route::pattern('id', '[1-9][0-9]{0,9}');
// 如果还有还可以加,左边是字符串名,右边是格式
Route::group([
'domain' => ''// 网站域名,不加 'http://'
], function() {
Route::any('/', '/app/index.php');
Route::any('/user/{username}', '/app/user_info.php');
// 还可以加,左边是网站链接,右边是本地具体文件
}
);
::::
::::success[index.php]{open}
php
<?php
require $_SERVER['DOCUMENT_ROOT'].'/models/Route.php';
require $_SERVER['DOCUMENT_ROOT'].'/route.php';
Route::dispatch();
?>
::::
其他文件都要按照网站主体来走
建议大家按照我的这个来,后面的文件/文件夹:
主文件夹
|- app
| |- index.php // 真正的主页
| |- // 其他文件,但都要是 route.php 里出现的
|- views
| |- header.php
| |- footer.php
| |- // 其他特殊的,比如:main.php
|- libs
| |- html-lib.php
| |- query-lib.php
| |- rand-lib.php
| |- security-lib.php
| |- validate-lib.php
下面是分别解释
/app/ 的文件是网站最终显示的页面
基本是这个结构
php
<!DOCTYPE html>
<html>
<?php
$host = 'localhost';
$user = 'root';
$pass = '';// 密码
$DB = mysqli_connect($host, $user, $pass);
$DB->query('USE `app_db233`;');
include $_SERVER['DOCUMENT_ROOT'].'/libs/rand-lib.php';
include $_SERVER['DOCUMENT_ROOT'].'/libs/validate-lib.php';
include $_SERVER['DOCUMENT_ROOT'].'/libs/query-lib.php';
include $_SERVER['DOCUMENT_ROOT'].'/libs/html-lib.php';
include $_SERVER['DOCUMENT_ROOT'].'/libs/security-lib.php';
?>
<head>
<meta charset="utf-8" />
<title>标题</title>
<?php include $_SERVER['DOCUMENT_ROOT'].'/views/header.php'; ?>
</head>
<body>
正文
<?php include $_SERVER['DOCUMENT_ROOT'].'/views/footer.php'; ?>
</body>
</html>
有了上面的代码结构写 /views/ 的代码就不难了
基本大家都知道要写什么了。
/libs/ 基本要写的东西不多
/libs/html-lib.php一般写一些比如becomeMsgPage(msg, title), become403Page(), become404Page()等等......
::::info[参考代码,我做的网站的]{open}
php
<?php
function user() {
$host = 'localhost';
$user = 'root';
$pass = '';
$DB = mysqli_connect($host, $user, $pass);
$DB->query('USE `app_zyxot233`;');
if (Cookie::get("zyxOT_username") && Cookie::get("zyxOT_username_checksum")) {
if (Cookie::get("zyxOT_username_checksum") != Cookie::checksum("zyxOT_username", Cookie::get("zyxOT_username")) || !$DB->query("select `password` from user_info where `username` = '{$_COOKIE['zyxOT_username']}'")->num_rows || $DB->query("select banned from user_info where `username` = '{$_COOKIE['zyxOT_username']}'")->fetch_assoc()['banned']) {
return 0;
}
return $_COOKIE['zyxOT_username'];
}
return 0;
}
function isSuperuser() {
$host = 'localhost';
$user = 'root';
$pass = '';
$DB = mysqli_connect($host, $user, $pass);
$DB->query('USE `app_zyxot233`;');
if (user() && $DB->query("select manage from user_info where `username` = '{$_COOKIE['zyxOT_username']}'")->fetch_assoc()['manage'])
return 1;
return 0;
}
function nowTime() {
date_default_timezone_set('Asia/Shanghai');
return date('Y-m-d H:i:s');
}
function nowTimeYear() {
date_default_timezone_set('Asia/Shanghai');
return date('Y');
}
function becomeMsgPage($msg, $title = '消息') {
echo '<script>document.querySelector("title").innerHTML = "'.$title.' - 在线加密系统";</script>';
echo '<div class="uoj-content container flex-fill">'.$msg.'</div>';
include $_SERVER['DOCUMENT_ROOT'].'/view/footer.php';
echo '</div>
<!-- /container -->
</body>
</html>';
die();
}
function become404Page() {
becomeMsgPage('<div class="text-center"><div style="font-size:233px">404</div><p>唔......未找到该页面......你是从哪里点进来的......>_<......</p></div>', '404');
}
function become403Page() {
becomeMsgPage('<div class="text-center"><div style="font-size:233px">403</div><p>禁止入内! T_T</p></div>', '403');
}
function getClickZanBlock($type, $id, $cnt, $user, $val = null) {
if ($val == null) {
$val = queryZanVal($id, $type, $user);
}
if ($user == user())
return '<div class="uoj-click-zan-block" data-id="'.$id.'" data-type="'.$type.'" data-val="'.$val.'" data-cnt="'.$cnt.'"></div>';
return '<div class="uoj-click-zan-block" data-id="'.$id.'" data-type="'.$type.'" data-val="'.$val.'" data-cnt="'.$cnt.'" data-user="'.$user.'"></div>';
}
function getUserLink($username) {
$host = 'localhost';
$user = 'root';
$pass = '';
$DB = mysqli_connect($host, $user, $pass);
$DB->query('USE `app_zyxot233`;');
$text = $username;
if (strlen($username) && $username[0] == '@')
$username = substr($username, 1);
if ($username == '加密系统官方')
return '<span class="uoj-username" data-color="red">'.$text.'</span>';
if (!$DB->query("select `password` from `user_info` where `username` = '$username'")->num_rows)
return '/';
$color = ' data-color="'.$DB->query("select `color` from `user_info` where `username` = '$username'")->fetch_assoc()['color'].'"';
$banned = '';
if ($DB->query("select `banned` from `user_info` where `username` = '$username'")->fetch_assoc()['banned'] == '1')
$banned = ' data-banned="1"';
return '<span class="uoj-username"'.$color.$banned.'>'.$text.'</span>';
}
function getUserSpan($username) {
$host = 'localhost';
$user = 'root';
$pass = '';
$DB = mysqli_connect($host, $user, $pass);
$DB->query('USE `app_zyxot233`;');
$text = $username;
if (strlen($username) && $username[0] == '@')
$username = substr($username, 1);
if ($username == '加密系统官方')
return '<span class="uoj-username" data-color="red" data-link="0">'.$text.'</span>';
if (!$DB->query("select `password` from `user_info` where `username` = '$username'")->num_rows)
return '/';
$color = ' data-color="'.$DB->query("select `color` from `user_info` where `username` = '$username'")->fetch_assoc()['color'].'"';
$banned = '';
if ($DB->query("select `banned` from `user_info` where `username` = '$username'")->fetch_assoc()['banned'] == '1')
$banned = ' data-banned="1"';
return '<span class="uoj-username"'.$color.$banned.' data-link="0">'.$text.'</span>';
}
?>
::::
/libs/query-lib.php一般写请求一个键值在 DB 中的所有信息。
::::info[示例代码,我的网站的]{open}
php
<?php
function queryUser($username) {
$host = 'localhost';
$user = 'root';
$pass = '';
$DB = mysqli_connect($host, $user, $pass);
$DB->query('USE `app_zyxot233`;');
if (!validateUsername($username)) {
return null;
}
return $DB->query("select * from user_info where username='" . $DB->real_escape_string($username) . "'")->fetch_assoc();
}
function queryZanVal($id, $type, $username) {
$host = 'localhost';
$user = 'root';
$pass = '';
$DB = mysqli_connect($host, $user, $pass);
$DB->query('USE `app_zyxot233`;');
if (!$username) {
return 0;
}
$esc_type = $DB->real_escape_string($type);
$row = $DB->query("select val from click_zans where username='".$username."' and type='$esc_type' and target_id='$id'");
if (!$row->num_rows) {
return 0;
}
return $row->fetch_array(MYSQLI_ASSOC)['val'];
}
::::
/libs/rand-lib.php一般写在用于登录、注册时的随机数。
::::info[示例代码,我的网站的]{open}
php
<?php
function uojRand($l, $r) {
return mt_rand($l, $r);
}
function uojRandString($len, $charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
$n_chars = strlen($charset);
$str = '';
for ($i = 0; $i < $len; $i++) {
$str .= $charset[uojRand(0, $n_chars - 1)];
}
return $str;
}
::::
/libs/security-lib.php一般写有关安全的问题,比如用户的密码......
::::info[示例代码,我的网站的]{open}
php
<?php
function getPasswordToStore($password, $username) {
return md5($username . $password);
}
function checkPassword($username, $password) {
$host = 'localhost';
$user = 'root';
$pass = '';
$DB = mysqli_connect($host, $user, $pass);
$DB->query('USE `app_zyxot233`;');
return $DB->query("select `password` from `user_info` where `username` = '$username'")->fetch_assoc()['password'] == md5($username . $password);
}
function getPasswordClientSalt() {
return "salt0";
}
function crsf_token() {
if (!isset($_SESSION['_token'])) {
$_SESSION['_token'] = uojRandString(60);
}
return $_SESSION['_token'];
}
function crsf_check() {
if (isset($_POST['_token'])) {
$_token = $_POST['_token'];
} elseif (isset($_GET['_token'])) {
$_token = $_GET['_token'];
} else {
return false;
}
return $_token === $_SESSION['_token'];
}
function crsf_defend() {
if (!crsf_check()) {
becomeMsgPage('This page has expired.');
}
}
::::
/libs/validate-lib.php一般写有关检测格式对不对(如用户名、密码)、合不合法的内容......
::::warning[参考代码,我的网站的]{open}
由于此文件中会有一些涉及用户密码、checksum 所以不能给大家参考所有的了。
php
<?php
function validateUsername($username) {
return is_string($username) && preg_match('/^[a-zA-Z0-9_]{1,20}$/', $username);
}
function validatePassword($password) {
return is_string($password) && preg_match('/^[a-z0-9]{32}$/', $password);
}
function validateEmail($email) {
return is_string($email) && strlen($email) <= 50 && preg_match('/^(.+)@(.+)$/', $email);
}
function validateQQ($QQ) {
return is_string($QQ) && strlen($QQ) <= 15 && preg_match('/^[0-9]{5,15}$/', $QQ);
}
function validateMotto($motto) {
return is_string($motto) && ($len = mb_strlen($motto, 'UTF-8')) !== false && $len <= 50;
}
function validateUInt($x) { // [0, 1000000000)
if (!is_string($x)) {
return false;
}
if ($x === '0') {
return true;
}
return preg_match('/^[1-9][0-9]{0,8}$/', $x);
}
function validateInt($x) {
if (!is_string($x)) {
return false;
}
if ($x[0] == '-') {
$x = substr($x, 1);
}
return validateUInt($x);
}
function validateUploadedFile($name) {
return isset($_FILES[$name]) && is_uploaded_file($_FILES[$name]['tmp_name']);
}
function validateIP($ip) {
return filter_var($ip, FILTER_VALIDATE_IP) !== false;
}
::::
内网穿透
接下来就是内网穿透了,我用的是 zeronews,我不知道这个让不让说,我就提一下我用的是什么吧,别的我就不说了,这种问题网上也有很多教程,大家可以参考。
最后,网站就完成了
这种方法最后的网站是以自己电脑做服务器的,所以可能有的时候电脑不开访问不了。
但这个问题解决不了,除非不用自己电脑,去网上找一些可以托管网站的网站也行,如果不找的话问题其实也不是很大。
这样大家的网站就完成了,可以把域名分享在评论区哟~
在这里我也分(xuan)享(chuan)一下我的网站 https://fx6d4ukd61.fy.takin.cc,其实是和 zyx 一起做的,他是主页面算法设计者,我是网站设计者,因为是拿我自己电脑做服务器,所以可能会不稳定(有的时候访问不了)qwq
感谢大家的时间,下次再见(挖坑)!