安装方法3 z5 t& z0 j4 d8 r- |1 F/ V: ^. I1 m
服务器环境为: PHP 7.2+ 和 MySQL 5.6+, 并且需要安装 Composer。Composer加速,可配置腾讯云镜像# T3 k; [0 o9 Q: L- R
: m" C. C2 f& z, W; K' M/ I- Q$ [
背景故事Discuz! Q项目由于是从 0 到 1,介于我们的目标,如果从第一行代码开始编写,是极为庞大的工程。想想Discuz!X,代码量依赖 10 多年的时间的积累,才完善出各种工具类、自己的框架及插件机制等。 在此背景下,我们必须借助开源的力量,才得以快速构建出Discuz! Q。以下是整个Discuz! Q中所用到的技术栈,在此特别感谢他们 安装服务器要求Discuz! Q 对系统有一些要求,请确保你的服务器满足以下要求:
2 d# d; `0 i- c7 }2 [ o- PHP >= 7.2.0
# k% |8 e4 G2 {( _. e9 O - BCMath PHP 拓展
2 q' D6 g$ G. a) \0 f. q - Ctype PHP 拓展 t3 G2 u' e3 [8 c' |8 h- g) ?
- JSON PHP 拓展0 e( \( n2 ?9 ]/ s
- Mbstring PHP 拓展
6 X6 t9 N! J" B' D; U - OpenSSL PHP 拓展
4 B0 C6 {5 n3 N9 t2 k - PDO PHP 拓展1 c7 h" f% Q; v- {
- Tokenizer PHP 拓展
1 ~; O% ~# _+ e" R4 d7 }3 B7 D - XML PHP 拓展
' x- b% v. [% S( \0 I% R 安装 Discuz! Q
7 U: r. X0 Z" w/ I# d! x
! d b8 D( t7 ^* h: C/ |Discuz! Q 使用 Composer 来管理项目依赖。因此,在使用 Discuz! Q 之前,请确保你的机器已经安装了 Composer。
& B$ T( p) E7 F# { r& n4 Q5 e, _通过站点启动安装首先,部署好服务器环境: 然后打开 http://{您的域名}/install 进入安装界面,按照页面提示进行安装。
1 P4 n# A5 Q. Z配置公共路径安装完 Discuz! Q 之后,你应该配置你的 web 服务的文档目录指向 public 路径。该路径下的 index.php 文件作为所有接口控制器, index.html 作为所有前端 HTTP 请求控制器。 % p! W5 `7 l9 B4 |" M" L b1 E- n
配置文件Discuz! Q 的所有配置文件存放在 config 目录下。每个选项都有文档标注,便于通过文件查看并熟悉对你有用的选项。 目录权限在安装 Discuz! Q 后,你可能需要配置一些权限。 storage 目录在你的 web 服务下应该是可写的权限,否则 Discuz! Q 将无法运行。 应用密钥安装好 Discuz! Q 之后的下一步是设置你的应用密钥为随机字符串。如果你通过 Composer 或者 Discuz! Q 安装器安装的,这个密钥已经通过 php disco key:generate 命令为你设置好了。 通常,这个字符串应该是 32 个字符长度。这个密钥将会设置在 config.php 文件中。如果应用密钥还没有设置,你的用户会话和其他的加密数据将会不安全 其他配置Discuz! Q 几乎不需要除上面所说的其他什么配置了。打开你的站点开始你建站之旅然而,你可能会想要再次查看 config/config.php 文件和它的注释说明。它包含一些你希望根据你应用来更改的选项,诸如: timezone 和 locale 。 ) s" \% T+ U: l4 Z: H2 Z9 B
Web 服务器配置优雅链接ApacheDiscuz! Q 中包含了一个 public/.htaccess 文件,通常用于在资源路径中隐藏 index.php 的前端控制器。在用 Apache 为 Discuz! Q 提供服务之前,确保启用了 mod_rewrite 模块,这样 .htaccess 文件才能被服务器解析。 如果 Discuz! Q 附带的 .htaccess 文件不起作用,尝试下面的方法替代: - Options +FollowSymLinks -Indexes
- RewriteEngine On
- RewriteCond %{HTTP:Authorization} .
- RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
- RewriteCond %{REQUEST_FILENAME} !-d
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteRule ^ index.php [L]
复制代码
6 m$ ^" W1 C# y7 ~& I7 I复制代码
. R0 y; W3 B5 I( e* r( {# a7 `2 zNginx如果你使用 Nginx ,在你的站点配置中加入以下配置,建义开启 https 和 http2 ,所有的请求将会引导至 index.html 前端控制器和后端 index.php API控制器: - listen 443 ssl http2;
- server_name www.xxx.com;
- root /home/wwww;
- ssl_certificate /xxx/server.crt;
- ssl_certificate_key /xxx/server.key;
- ssl_session_cache shared:SSL:1m;
- ssl_session_timeout 5m;
- ssl_prefer_server_ciphers on;
- ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256::!MD5;
- ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
- add_header Strict-Transport-Security "max-age=31536000";
- add_header X-Frame-Options "SAMEORIGIN";
- add_header X-XSS-Protection "1; mode=block";
- add_header X-Content-Type-Options "nosniff";
- index index.html;
- location /install {
- try_files $uri $uri/ /index.php?$query_string;
- }
- location /api {
- try_files $uri $uri/ /index.php?$query_string;
- }
- location / {
- try_files $uri $uri/ /index.html;
- }
- location = /favicon.ico { access_log off; log_not_found off; }
- location = /robots.txt { access_log off; log_not_found off; }
- error_page 404 /index.php;
复制代码
8 m3 ?* @7 {' V! H: P$ t8 u: b6 `配置信息0 N8 d# D' T/ w g: T7 _: Q
2 ?$ q+ t% X! ^- <?php
- return [
- 'debug' => true,
- 'locale' => 'zh-CN',
- 'fallback_locale' => 'zh-CN',
- 'timezone' => 'Asia/Shanghai',
- 'key' => 'base64:JtNRiS14Mopb+HNi3ztxi6259im9DTDBJXOzLDbcquw=',
- 'cipher' => 'AES-256-CBC',
- 'site_url' => 'DummySiteUrl',
- 'database' =>
- [
- 'driver' => 'mysql',
- 'host' => 'DummyDbHost',
- 'port' => 'DummyDbPort',
- 'database' => 'DummyDbDatabase',
- 'username' => 'DummyDbUsername',
- 'password' => 'DummyDbPassword',
- 'charset' => 'utf8mb4',
- 'collation' => 'utf8mb4_unicode_ci',
- 'prefix' => 'DummyDbPrefix',
- 'prefix_indexes' => true,
- 'strict' => true,
- 'options' => extension_loaded('pdo_mysql') ? array_filter([
- PDO::MYSQL_ATTR_SSL_CA => '',
- ]) : [],
- ],
- 'redis' => [
- 'client' => 'phpredis',
- 'options' => [
- 'cluster' => 'redis',
- 'prefix' => Str::slug('discuz', '_').'_database_'
- ],
- 'default' => [
- 'url' => '',
- 'host' => '127.0.0.1',
- 'password' => '123',
- 'port' => 6379,
- 'database' => 0
- ],
- 'cache' => [
- 'url' => '',
- 'host' => '127.0.0.1',
- 'password' => '123',
- 'port' => 6379,
- 'database' => 1
- ],
- ],
- //缓存系统配置
- 'cache' => [
- 'default' => 'file', //如果配置的 redis 可用, 会自动切换为redis
- 'stores' => [
- 'file' => [
- 'driver' => 'file',
- 'path' => storage_path('cache/data'),
- ],
- 'redis' => [
- 'driver' => 'redis',
- 'connection' => 'cache',
- ],
- ],
- 'prefix' => 'discuz_cache',
- ],
- //文件系统配置
- 'filesystems' => [
- 'default' => 'local',
- 'cloud' => '',
- 'disks' => [
- 'local' => [
- 'driver' => 'local',
- 'root' => storage_path('app'),
- ],
- 'public' => [
- 'driver' => 'local',
- 'root' => storage_path('app/public'),
- 'url' => 'public',
- 'visibility' => 'public',
- ],
- 'avatar' => [
- 'driver' => 'local',
- 'root' => storage_path('app/public/avatars'),
- 'url' => 'avatar',
- 'visibility' => 'public',
- ],
- 'attachment' => [
- 'driver' => 'local',
- 'root' => storage_path('app/public/attachment'),
- 'url' => 'attachment'
- ],
- 'cos' => [
- 'driver' => 'cos',
- 'region' => 'ap-beijing', //设置一个默认的存储桶地域
- 'schema' => 'https', //协议头部,默认为http
- 'bucket' => 'test-1251011534',
- 'read_from_cdn' => false, //是否从cdn读取,如果为true , 设置cdn地址
- 'credentials'=> [
- 'secretId' => 'COS_SECRETID', //"云 API 密钥 SecretId";
- 'secretKey' => 'COS_SECRETKEY', //"云 API 密钥 SecretKey";
- 'token' => 'token' //"临时密钥 token";
- ]
- ]
- ]
- ],
- 'queue' => [
- 'default' => 'redis',
- 'connections' => [
- 'redis' => [
- 'driver' => 'redis',
- 'connection' => 'default',
- 'queue' => 'REDIS_QUEUE',
- 'retry_after' => 90,
- 'block_for' => null,
- ]
- ]
- ],
- 'excel' => [
- 'root' => storage_path('public/exports')
- ],
- //加载ServiceProvider
- 'providers' => [
- App\Formatter\FormatterServiceProvider::class,
- App\Providers\EventServiceProvider::class,
- App\Providers\SettingsServiceProvider::class,
- App\Providers\CategoryServiceProvider::class,
- App\Providers\UserServiceProvider::class,
- App\Providers\ThreadServiceProvider::class,
- App\Providers\PostServiceProvider::class,
- App\Providers\OrderServiceProvider::class,
- App\Providers\UserWalletLogsServiceProvider::class,
- App\Providers\UserWalletCashServiceProvider::class,
- App\Providers\UserWalletServiceProvider::class,
- ],
- 'sms' => [
- // HTTP 请求的超时时间(秒)
- 'timeout' => 5.0,
- // 默认发送配置
- 'default' => [
- // 网关调用策略,默认:顺序调用
- 'strategy' => Overtrue\EasySms\Strategies\OrderStrategy::class,
- // 默认可用的发送网关
- 'gateways' => [
- 'qcloud'
- ],
- ],
- // 可用的网关配置
- 'gateways' => [
- 'errorlog' => [
- 'file' => storage_path('log/easy-sms.log')
- ],
- 'qcloud' => [
- 'sdk_app_id' => 'xxx', // SDK APP ID
- 'app_key' => 'xxxx', // APP KEY
- 'sign_name' => 'xxx', // 短信签名,如果使用默认签名,该字段可缺省(对应官方文档中的sign)
- ],
- ],
- ]
- ];
复制代码 API 说明
6 w' m! O( w" O6 h& ^7 E) ]jsonapi.orgDiscuz! Q 使用的是 jsonapi.org 定义的格式,使用 tobscure/json-api 包的实现。
) P' H. n* Y9 B路由分别对应" x8 r+ D6 O6 H# d8 Q
- 以psr-2基础命名规则外,下面为实践中相关命名规则
" w6 b& F: t G K - 以user为例, 路由和路由名称为小写复数按功能以.分开, q4 \7 }& D$ p# }% Y
- 控制器按功能,列表为复数,其它单条担任可为单数驼峰命名
2 B7 T, H& N7 I# Q% H9 { - 序列化模型名为单数驼峰命名
I) n; u* t2 {& u" S' ?/ z7 q' d - 数据库模型以单数驼峰命名
- p/ b: m3 x4 X8 H7 a# W( b - 表名以复数命名
& a9 _4 f; k. Q7 _ 下面为具体增删改查路由例子: : j, W& y( i. [+ ]
- $route->get('/users', 'users.index', ListUsersController::class);
- $route->get('/users/{id}', 'users.resource', ResourceUserController::class);
- $route->post('/users', 'users.create', CreateUserController::class);
- $route->patch('/users/{id}', 'users.update', UpdateUserController::class);
- $route->delete('/users/{id}', 'users.delete', DeleteUserController::class);
复制代码 列表数据继承 Discuz\Api\Controller\AbstractListController 需要指定 $serializer 要用于序列化模型的 data 方法,并实现返回模型集合的方法。该 data 方法接收 Request 对象和 tobscure/json-api Document。 + T# {* J2 f* m1 L
- class ListUsersController extends AbstractListController
- {
- public $serializer = UserSerializer::class;
- public function data(ServerRequestInterface $request, Document $document)
- {
- return User::all();
- }
- }
复制代码 # M1 X; t8 X/ u6 K
单条数据同列表数据一样继承 Discuz\Api\Controller\AbstractResourceController 并实现相关属性和方法,接收参数一样 ( M2 A0 o5 H1 ^# L2 y9 B
- class ResourceUserController extends AbstractResourceController
- {
- public $serializer = UserSerializer::class;
- public function data(ServerRequestInterface $request, Document $document)
- {
- $body = $request->getQueryParams();
- $id = $body->get('id');
- return User::findOrFail($id);
- }
- }
复制代码 创建数据继承 Discuz\Api\Controller\AbstractCreateController。这与单条数据相同,但响应状态代码将自动设置为 201 Created。您可以通过以下方式访问传入的 JSON:API POST传过来的数据可通过 $request->getParsedBody() 来取到 json 数组,并通过 Laravel Arr 类来获取数组相关信息 - class CreateUserController extends AbstractCreateController
- {
- public $serializer = UserSerializer::class;
- public function data(ServerRequestInterface $request, Document $document)
- {
- $attributes = Arr::get($request->getParsedBody(), 'data.attributes');
- return User::create([
- 'name' => Arr::get($attributes, 'name')
- ]);
- }
- }
复制代码 更新数据继承 Discuz\Api\Controller\AbstractResourceController 同单条数据一样,现相关属性和方法,接收参数一样,返回相关数据,获取同创建数据一样 - class UpdateUserController extends AbstractCreateController
- {
- public $serializer = UserSerializer::class;
- public function data(ServerRequestInterface $request, Document $document)
- {
- $attributes = Arr::get($request->getParsedBody(), 'data.attributes', []);
- $body = $request->getQueryParams();
- $attributes = $body->get('id');
- $user = User::findOrFail($id);
- $user->name = $attributes['name'];
- $user->save();
- return $user;
- }
- }
复制代码 删除数据继承 Discuz\Api\Controller\AbstractDeleteController 实现delete 方法,该方法接收 Request,默认返回空 204 No Content 响应。 - class DeleteUserController extends AbstractDeleteController
- public function delete(ServerRequestInterface $request)
- {
- $id = Arr::get($request->getQueryParams(), 'id');
- User::findOrFail($id)->delete();
- }
- }
复制代码
[1 |) m6 B3 J+ e2 A" x j序列化模型说明继承 Discuz\Api\Serializer\AbstractSerializer 实现 getDefaultAttributes 方法,该方法接收数据库模型,写好 type 属性 - class UserSerializer extends AbstractSerializer
- {
- protected $type = 'user';
- public function getDefaultAttributes($model)
- {
- return [
- 'id' => $model->id,
- 'username' => $model->username,
- 'email' => $model->email
- ];
- }
- }
复制代码 $ m' b- i& d5 h
( |* N6 m# P3 i" `! h; H s
自定义返回类型实现接口 Psr\Http\Server\RequestHandlerInterface
8 C0 h; d7 p. k5 S$ l0 X( ?
- <?php
- namespace Discuz\Api\Controller;
- use Psr\Http\Server\RequestHandlerInterface;
- class AbstractSerializeController implements RequestHandlerInterface
- {
- public function handle(ServerRequestInterface $request): ResponseInterface
- {
- return new HtmlResponse();
- }
- }
复制代码 |