PHP 8 原生 / MySQL 8 / MVC / 零框架
四尺寸 1920 / 800 / 400 + 原图+EXIF
EXIF 强制校验、JSON 入库、详情页八项
Shot 是一个纯原生 PHP 构建的摄影作品展示与社区平台。没有 Composer 框架,没有前端构建链,把上传、处理、审核、展示到互动的整条链路自己走完——界面退到幕后,把注意力全还给照片本身。
详细说明见: Shot 系统详细说明
也可以点击此链接查看 功能展示页
本系统是纯原生 PHP + MySQL,无框架、无 Node 构建,安装核心只有四步:装依赖 → 配 .env → 建库导数据 → 配 Web 服务器。
| 项目 | 要求 |
|---|---|
| PHP | 8.0+,推荐 8.2 / 8.3(已兼容 8.5) |
| PHP 扩展 | pdo_mysql、gd、exif、fileinfo、mbstring、openssl(SMTP 用);json/session/filter 为内置 |
| 数据库 | MySQL 5.7+ / 8.0,字符集 utf8mb4 |
| Composer | 用于安装 erusev/parsedown、league/html-to-markdown |
| Web 服务器 | Nginx(推荐)或 Apache,PHP-FPM |
| 可选 | exiftool 不需要;图片处理全部用 GD |
php.ini 建议值(手机/相机原图单张常有 5~10MB,且上传支持一次多张):
upload_max_filesize = 25M
post_max_size = 300M ; 一次多张的总和上限
memory_limit = 512M ; 处理大图建议 512M~1G
max_execution_time = 300
注意:
post_max_size必须大于“一次上传的图片总大小”,否则 PHP 会丢弃整个请求,表现为前端报 422 / “请选择图片”。
cd /path/to/shot
composer install --no-dev
会生成 vendor/,两个入口文件会自动加载 vendor/autoload.php(缺失时 Markdown 渲染会降级为纯文本转义)。
APP_NAME=Shot - 摄影作品展示平台
APP_URL=https://你的域名 # 结尾不要带斜杠;本地开发填 http://localhost:3009
APP_ENV=production # 开发环境可 development
APP_DEBUG=false # 生产环境务必 false
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=shot
DB_USER=shot
DB_PASS=你的数据库密码
UPLOAD_MAX_SIZE=20971520 # 单张应用层上限(字节),默认 20MB
THUMB_WIDTH=400
COVER_WIDTH=800
IMAGE_QUALITY=85
DEFAULT_QUOTA=1073741824 # 新用户默认存储配额(1GB)
PER_PAGE=20
.env 中的 DB_PORT 支持非 3306 端口;APP_URL 决定所有 url()/asset() 生成地址。
创建数据库之后,导入database.sql即可。
默认管理员
| 字段 | 值 |
|---|---|
| 邮箱 | me@rongyan.cc |
| 用户名 | rongyan |
| 密码 | Shot@2026 |
安装完成后第一件事:登录后台修改该密码。 后台「用户管理」可改密码,或直接更新 users.password_hash。
上传文件写入 public/uploads/(按 YYYY/MM/DD/ 分目录,含原图 + _thumb / _cover / _large 三种尺寸):
mkdir -p public/uploads/avatars
chown -R www:www public/uploads # 按实际运行用户调整
chmod -R 755 public/uploads
存储路径由 config/storage.php 的 path(public/uploads 绝对路径)决定。
站点根目录必须指向 public/,而不是项目根目录。示例:
server {
listen 80;
server_name your-domain.com;
root /www/wwwroot/shot/public;
index index.php;
client_max_body_size 300M;
# 前台:所有请求交给 index.php
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# 后台:独立入口
location /admin-system/ {
try_files $uri $uri/ /admin-system/index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock; # 按实际 PHP 版本修改
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
# 静态资源缓存(可选)
location ~* \.(jpg|jpeg|png|webp|avif|gif|svg|css|js)$ {
expires 7d;
access_log off;
}
# 安全:禁止访问隐藏文件
location ~ /\. { deny all; }
}
项目根目录的
nginx.conf只是参考模板(路径写死为/var/www/shot/public、PHP 8.2 socket),实际部署请按服务器路径调整。宝塔面板用户:站点根目录设为
public;“伪静态”里加入上面location /与location /admin-system/两段;PHP 设置里把upload_max_filesize/post_max_size/memory_limit调到第 0 节的建议值;敏感目录app/ controllers/ models/ views/ config/ migrations/不在public/下,天然不可访问。
虚拟主机 DocumentRoot 指向 public/,开启 mod_rewrite,并在 public/ 下放置:
Options -Indexes
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^admin-system/(.*)$ admin-system/index.php [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L,QSA]
</IfModule>
router.php 用于让 PHP 内置服务器模拟 Nginx 的 try_files(静态文件直出、/admin-system/ 走后台入口、其余走前台入口)。
cd /path/to/shot
php -d upload_max_filesize=25M -d post_max_size=300M -d memory_limit=1024M \
-S 0.0.0.0:3009 -t public router.php
http://localhost:3009http://本机IP:3009(监听 0.0.0.0)http://localhost:3009/admin-system// 返回 200,首屏大图正常显示(不是黑底)/about 与 /links 正常(后者为友情链接 + 申请表单)/admin-system/,立即修改密码.env 中 APP_DEBUG=false/tmp/shot_hero_photos.json