linux + 宝塔 + thinkphp5.0 搭建后端api各种问题集合
安装宝塔
官方地址:https://www.bt.cn/bbs/thread-19376-1-1.html
我用的centos 7 所以有以下指令
yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
安装完毕,记下我们服务器的宝塔账号和密码
然后登陆宝塔,在软件商店中安装nginx + php,我用的云数据库,所以没有安装mysql
然后我们去安装thinkphp 5,官方地址:https://www.kancloud.cn/manual/thinkphp5/118006
Composer安装
curl -sS https://getcomposer.org/installer | php mv composer.phar /usr/local/bin/composer
用composer安装别忘了更改镜像源,国内镜像源比较快
composer config -g repo.packagist composer https://packagist.phpcomposer.com
然后到web根目录下去执行
composer create-project topthink/think=5.0.* tp5 --prefer-dist
compser过程中putenv、proc_open被禁用和版本报错
去宝塔的软件商店设置一下php禁用函数
找到putenv然后删除
![](https://img2020.cnblogs.com/blog/1905499/202103/1905499-20210325135030349-1432077918.png)
同理,解除proc_open禁用
版本报错
替换镜像源即可
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
php启动服务过程中passthru被禁用
在宝塔中解除禁用即可
Git安装
亲测,码云的这个已经不能用了
直接用github的,稍微慢一点
git clone https://github.com/top-think/think tp5 git clone https://github.com/top-think/framework thinkphp
然后进入thinkphp目录,切换核心库到master分支
cd thinkphp git checkout master git pull https://github.com/top-think/framework
上述步骤结束,tp5就安装完成了,然后我们去宝塔配置下nginx
到网站选项添加站点
点设置打开配置文件
在51行添加以下代码来支持tp的pathinfo
location / { try_files $uri $uri/ /index.php$is_args$args; if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=$1 last; break; } }
如果有证书的话,下载下来配置ssl
然后去网站目录更改运行目录为框架低下的public目录
至此宝塔这部分结束
tp5在linux下的权限问题
进入主目录,将runtime目录设置为777,注意-R一定是大写的R,不然无法执行
chmod -R 777 runtime/
然后将public目录设置为755,如果运行有问题,则将其设置为755
chmod -R 755 public/
没有意外情况出现的话,tp5可以正常运行
如果还运行不了,将整个工程设置为777,然后重复上述两步
数据库配置
tp5支持解析带端口号的数据库地址
根据实际情况配置,单一库或者主从库
<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- return [ // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => 'bj-cdb-nivnaury.sql.tencentcdb.com:60991', // 数据库名 'database' => 'lianmai', // 用户名 'username' => 'username', // 密码 'password' => 'password', // 端口 'hostport' => '60991', // 连接dsn 'dsn' => '', // 数据库连接参数 'params' => [], // 数据库编码默认采用utf8 'charset' => 'utf8', // 数据库表前缀 'prefix' => '', // 数据库调试模式 'debug' => true, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 'deploy' => 0, // 数据库读写是否分离 主从式有效 'rw_separate' => true, // 读写分离后 主服务器数量 'master_num' => 1, // 指定从服务器序号 'slave_no' => '', // 自动读取主库数据 'read_master' => false, // 是否严格检查字段是否存在 'fields_strict' => true, // 数据集返回类型 'resultset_type' => 'array', // 自动写入时间戳字段 'auto_timestamp' => false, // 时间字段取出后的默认时间格式 'datetime_format' => 'Y-m-d H:i:s', // 是否需要进行SQL性能分析 'sql_explain' => false, //'unix_socket' => '/var/run/mysqld/mysqld.sock' ];
数据迁移工具Migration
https://www.cnblogs.com/YC-L/p/12635731.html
跨域处理
在应用生命周期的开头注册下面的跨域类
use think\Response; class CORS { public function appInit(&$params) { header('Access-Control-Allow-Origin: *'); header("Access-Control-Allow-Headers: token,Origin, X-Requested-With, Content-Type, Accept"); header("Access-Control-Allow-Methods:GET, POST, OPTIONS, DELETE"); if (request()->isOptions()) { exit(); } } }
tp5.0应用生命周期
tags.php
<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- // 应用行为扩展定义文件 return [ // 应用初始化 'app_init' => [ 'app\\api\\behavior\\CORS' ], // 应用开始 'app_begin' => [], // 模块初始化 'module_init' => [], // 操作开始执行 'action_begin' => [], // 视图内容过滤 'view_filter' => [], // 日志写入 'log_write' => [], // 应用结束 'app_end' => [], ];
Jwt的使用
github地址:https://github.com/lcobucci/jwt
composer安装
composer require lcobucci/jwt
然后写令牌
<?php namespace app\admin\token; use Lcobucci\JWT\Builder; use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Parser; use Lcobucci\JWT\ValidationData; class Token { // 生成jwt public static function token($uid = '', $user_name = ''){ $signer = new Sha256(); $token = (new Builder())->setIssuer('https://sqadmin.dao-tech.com') ->setAudience('https://sqadmin.dao-tech.com') ->setId($uid . $user_name, true) //自定义标识 ->setIssuedAt(time()) ->setExpiration(time() + (86400 * 30)) //token有效期时长 ->set('uid', $uid) ->sign($signer, 'llwhappyeveryday') ->getToken(); return (String) $token; } // 验证jwt public static function check($token, $uid, $user_name) { $token = (new Parser())->parse((String) $token); $signer = new Sha256(); if (!$token->verify($signer, 'llwhappyeveryday')) { return false; //签名不正确 } $validationData = new ValidationData(); $validationData->setIssuer('https://sqadmin.dao-tech.com'); $validationData->setAudience('https://sqadmin.dao-tech.com'); $validationData->setId($uid . $user_name);//自定义标识 return $token->validate($validationData); } }
应用配置 config.php
常用的配置
- 应用模式
- 路由缓存
- pathinfo配置
- 分页
- session和cookie
- 自定义的全局变量
<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- return [ // +---------------------------------------------------------------------- // | 应用设置 // +---------------------------------------------------------------------- // 应用调试模式 'app_debug' => true, // 应用Trace 'app_trace' => false, // 应用模式状态 'app_status' => '', // 是否支持多模块 'app_multi_module' => true, // 入口自动绑定模块 'auto_bind_module' => false, // 注册的根命名空间 'root_namespace' => [], // 扩展函数文件 'extra_file_list' => [THINK_PATH . 'helper' . EXT], // 默认输出类型 'default_return_type' => 'html', // 默认AJAX 数据返回格式,可选json xml ... 'default_ajax_return' => 'json', // 默认JSONP格式返回的处理方法 'default_jsonp_handler' => 'jsonpReturn', // 默认JSONP处理方法 'var_jsonp_handler' => 'callback', // 默认时区 'default_timezone' => 'PRC', // 是否开启多语言 'lang_switch_on' => false, // 默认全局过滤方法 用逗号分隔多个 'default_filter' => '', // 默认语言 'default_lang' => 'zh-cn', // 应用类库后缀 'class_suffix' => false, // 控制器类后缀 'controller_suffix' => false, // +---------------------------------------------------------------------- // | 模块设置 // +---------------------------------------------------------------------- // 默认模块名 'default_module' => 'index', // 禁止访问模块 'deny_module_list' => ['common'], // 默认控制器名 'default_controller' => 'Index', // 默认操作名 'default_action' => 'index', // 默认验证器 'default_validate' => '', // 默认的空控制器名 'empty_controller' => 'Error', // 操作方法后缀 'action_suffix' => '', // 自动搜索控制器 'controller_auto_search' => false, // +---------------------------------------------------------------------- // | URL设置 // +---------------------------------------------------------------------- // PATHINFO变量名 用于兼容模式 'var_pathinfo' => 's', // 兼容PATH_INFO获取 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], // pathinfo分隔符 'pathinfo_depr' => '/', // URL伪静态后缀 'url_html_suffix' => 'html|json|xml', // URL普通方式参数 用于自动生成 'url_common_param' => false, // URL参数方式 0 按名称成对解析 1 按顺序解析 'url_param_type' => 0, // 是否开启路由 'url_route_on' => true, // 路由使用完整匹配 'route_complete_match' => false, // 路由配置文件(支持配置多个) 'route_config_file' => ['route'], // 是否开启路由解析缓存 'route_check_cache' => false, // 是否强制使用路由 'url_route_must' => true, // 域名部署 'url_domain_deploy' => false, // 域名根,如thinkphp.cn 'url_domain_root' => '', // 是否自动转换URL中的控制器和操作名 'url_convert' => true, // 默认的访问控制器层 'url_controller_layer' => 'controller', // 表单请求类型伪装变量 'var_method' => '_method', // 表单ajax伪装变量 'var_ajax' => '_ajax', // 表单pjax伪装变量 'var_pjax' => '_pjax', // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 'request_cache' => false, // 请求缓存有效期 'request_cache_expire' => null, // 全局请求缓存排除规则 'request_cache_except' => [], // +---------------------------------------------------------------------- // | 模板设置 // +---------------------------------------------------------------------- 'template' => [ // 模板引擎类型 支持 php think 支持扩展 'type' => 'Think', // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 'auto_rule' => 1, // 模板路径 'view_path' => '', // 模板后缀 'view_suffix' => 'html', // 模板文件名分隔符 'view_depr' => DS, // 模板引擎普通标签开始标记 'tpl_begin' => '{', // 模板引擎普通标签结束标记 'tpl_end' => '}', // 标签库标签开始标记 'taglib_begin' => '{', // 标签库标签结束标记 'taglib_end' => '}', ], // 视图输出字符串内容替换 'view_replace_str' => [], // 默认跳转页面对应的模板文件 'dispatch_success_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl', 'dispatch_error_tmpl' => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl', // +---------------------------------------------------------------------- // | 异常及错误设置 // +---------------------------------------------------------------------- // 异常页面的模板文件 'exception_tmpl' => THINK_PATH . 'tpl' . DS . 'think_exception.tpl', // 错误显示信息,非调试模式有效 'error_message' => '页面错误!请稍后再试~', // 显示错误信息 'show_error_msg' => false, // 异常处理handle类 留空使用 \think\exception\Handle 'exception_handle' => '', // +---------------------------------------------------------------------- // | 日志设置 // +---------------------------------------------------------------------- 'log' => [ // 日志记录方式,内置 file socket 支持扩展 'type' => 'File', // 日志保存目录 'path' => LOG_PATH, // 日志记录级别 'level' => [], ], // +---------------------------------------------------------------------- // | Trace设置 开启 app_trace 后 有效 // +---------------------------------------------------------------------- 'trace' => [ // 内置Html Console 支持扩展 'type' => 'Html', ], // +---------------------------------------------------------------------- // | 缓存设置 // +---------------------------------------------------------------------- 'cache' => [ // 驱动方式 'type' => 'File', // 缓存保存目录 'path' => CACHE_PATH, // 缓存前缀 'prefix' => '', // 缓存有效期 0表示永久缓存 'expire' => 0, ], // +---------------------------------------------------------------------- // | 会话设置 // +---------------------------------------------------------------------- 'session' => [ 'id' => '', // SESSION_ID的提交变量,解决flash上传跨域 'var_session_id' => '', // SESSION 前缀 'prefix' => 'think', // 驱动方式 支持redis memcache memcached 'type' => '', // 是否自动开启 SESSION 'auto_start' => true, ], // +---------------------------------------------------------------------- // | Cookie设置 // +---------------------------------------------------------------------- 'cookie' => [ // cookie 名称前缀 'prefix' => '', // cookie 保存时间 'expire' => 0, // cookie 保存路径 'path' => '/', // cookie 有效域名 'domain' => '', // cookie 启用安全传输 'secure' => false, // httponly设置 'httponly' => '', // 是否使用 setcookie 'setcookie' => true, ], //分页配置 'paginate' => [ 'type' => 'bootstrap', 'var_page' => 'page', 'list_rows' => 15, ], // 小程序信息設置 'wxapp' => [ 'appid' =>'', 'appsecret'=>'' ], 'aliyun_access'=>[ 'accessKeyID'=>'', 'accessKeySecret'=>'' ] ];
路由配置
定义路由
use think\Route; // 注册路由到index模块的News控制器的read操作 Route::rule('new/:id','index/News/read');
带提交方式
Route::rule('new/:id','News/update','POST');
直接使用提交方式的函数
Route::get('new/:id','News/read'); // 定义GET请求路由规则 Route::post('new/:id','News/update'); // 定义POST请求路由规则 Route::put('new/:id','News/update'); // 定义PUT请求路由规则 Route::delete('new/:id','News/delete'); // 定义DELETE请求路由规则 Route::any('new/:id','News/read'); // 所有请求都支持的路由规则
同一个请求,多种提交方式
Route::rule('new/:id','News/read','GET|POST');
使用数组批量添加路由
Route::rule([ 'new/:id' => 'News/read', 'blog/:id' => ['Blog/update',['ext'=>'shtml'],['id'=>'\d{4}']], ... ],'','GET',['ext'=>'html'],['id'=>'\d+']);
变量规则
全局变量
// 设置name变量规则(采用正则定义) Route::pattern('name','\w+'); // 支持批量添加 Route::pattern([ 'name' => '\w+', 'id' => '\d+', ]);
局部变量
// 定义GET请求路由规则 并设置name变量规则 Route::get('new/:name','News/read',[],['name'=>'\w+']);
完整url规则
// 定义GET请求路由规则 并设置完整URL变量规则 Route::get('new/:id','News/read',[],['__url__'=>'new\/\w+$']);
路由参数
method | 请求类型检测,支持多个请求类型 |
ext | URL后缀检测,支持匹配多个后缀 |
deny_ext | URL禁止后缀检测,支持匹配多个后缀 |
https | 检测是否https请求 |
domain | 域名检测 |
before_behavior | 前置行为(检测) |
after_behavior | 后置行为(执行) |
callback | 自定义检测方法 |
merge_extra_vars | 合并额外参数 |
bind_model | 绑定模型(V5.0.1+ ) |
cache | 请求缓存(V5.0.1+ ) |
param_depr | 路由参数分隔符(V5.0.2+ ) |
ajax | Ajax检测(V5.0.2+ ) |
pjax | Pjax检测(V5.0.2+ ) |
路由地址定义
方式1:路由到模块/控制器 | '[模块/控制器/操作]?额外参数1=值1&额外参数2=值2...' |
方式2:路由到重定向地址 | '外部地址'(默认301重定向) 或者 ['外部地址','重定向代码'] |
方式3:路由到控制器的方法 | '@[模块/控制器/]操作' |
方式4:路由到类的方法 | '\完整的命名空间类::静态方法' 或者 '\完整的命名空间类@动态方法' |
方式5:路由到闭包函数 | 闭包函数定义(支持参数传入) |
可以用路由到控制器方法,这种不用二次解析路由
'blog/:id'=>'@index/blog/read'
系统会直接执行
Loader::action('index/blog/read');
路由到类方法
'blog/:id'=>'\app\index\service\Blog@read'
重定向地址使用动态变量即可
'blog/:id'=>'http://blog.thinkphp.cn/read/:id'
路由别名
// user 别名路由到 index/User 控制器 Route::alias('user','index/User');
在route.php种定义
return [ '__alias__' => [ 'user' => 'index/User', ], ];
路由别名可以指向任意一个有效的路由地址,例如下面指向一个类
// user 路由别名指向 User控制器类 Route::alias('user','\app\index\controller\User');
路由别名设置路由条件
// user 别名路由到 index/user 控制器 Route::alias('user','index/user',['ext'=>'html']);
在route.php中配置
return [ '__alias__' => [ 'user' => ['index/user',['ext'=>'html']], ], ];
操作方法黑白名单
路由别名的操作方法支持白名单或者黑名单机制,例如:
// user 别名路由到 index/user 控制器 Route::alias('user','index/user',[ 'ext'=>'html', 'allow'=>'index,read,edit,delete', ]);
或者使用黑名单机制
// user 别名路由到 index/user 控制器 Route::alias('user','index/user',[ 'ext'=>'html', 'except'=>'save,delete', ]);
并且支持设置操作方法的请求类型,例如:
// user 别名路由到 index/user 控制器 Route::alias('user','index/user',[ 'ext'=>'html', 'allow'=>'index,save,delete', 'method'=>['index'=>'GET','save'=>'POST','delete'=>'DELETE'], ]);
路由分组
'blog/:id' => ['Blog/read', ['method' => 'get'], ['id' => '\d+']],
'blog/:name' => ['Blog/read', ['method' => 'post']],
可以合并到一个blog分组
'[blog]' => [ ':id' => ['Blog/read', ['method' => 'get'], ['id' => '\d+']], ':name' => ['Blog/read', ['method' => 'post']], ],
可以使用Group类的group方法
Route::group('blog',[ ':id' => ['Blog/read', ['method' => 'get'], ['id' => '\d+']], ':name' => ['Blog/read', ['method' => 'post']], ]);
路由分组支持嵌套
Route::group(['method'=>'get','ext'=>'html'],function(){ Route::group('blog',function(){ Route::any('blog/:id','blog/read',[],['id'=>'\d+']); Route::any('blog/:name','blog/read',[],['name'=>'\w+']); } });
全部miss路由
return [ 'new/:id' => 'News/read', 'blog/:id' => ['Blog/update',['method' => 'post|put'], ['id' => '\d+']], '__miss__' => 'public/miss', ];
也可以使用miss方法
Route::miss('public/miss');
分组miss路由
return [ '[blog]' => [ 'edit/:id' => ['Blog/edit',['method' => 'get'], ['id' => '\d+']], ':id' => ['Blog/read',['method' => 'get'], ['id' => '\d+']], '__miss__' => 'blog/miss', ], 'new/:id' => 'News/read', '__miss__' => 'public/miss', ];
在group方法中嵌套miss方法
Route::group('blog',function(){ Route::rule(':id','blog/read',[],['id'=>'\d+']); Route::rule(':name','blog/read',[],['name'=>'\w+']); Route::miss('blog/miss'); },['method'=>'get','ext'=>'html']);
路由闭包函数
Route::get('hello/:name',function($name){ return 'Hello,'.$name; });
睁开眼,书在面前 闭上眼,书在心里