分类 PHP 下的文章

ThinkPHP6.0的前身是ThinkPHP5.2,因为6.0版本改动比较大,所以直接将原定的5.2改成6.0
目前ThinkPHP6还没正式发布,还是Rc阶段,更新也比较频繁。
根据官方消息,计划在今年的5月1日之前发布第二个RC版本,届时还将迎来新版的手册,并且大部分扩展也会基本升级完成。

安装

从ThinkPHP5.1起,需要通过composer安装,不再提供安装包。
目前ThinkPHP6还没正式发布,还是Rc阶段,所以需要加上-dev选项。
以下命令大概意思是,在tp目录创建topthink/think项目,版本是6.0开发版

composer create-project topthink/think tp 6.0.*-dev

相比之前版本,6.0版本将框架放到了vendor目录,挺好的。

目录介绍

│  build.php                自动生成定义文件(参考)
│  composer.json composer   定义文件
│  composer.lock
│  LICENSE.txt              授权说明文件
│  README.md                README 文件
│  think                    命令行入口文件
├─app                       应用目录
│  │  .htaccess
│  │  common.php            公共函数文件
│  │  event.php             事件监听配置文件
│  │  middleware.php        中间件配置文件
│  └─controller             控制器目录
│          Index.php        控制器文件
├─config                    配置文件目录
│      app.php              应用配置
│      cache.php            缓存配置
│      console.php          控制台配置
│      cookie.php           Cookie配置
│      database.php         数据库配置
│      log.php              日志配置
│      route.php            应用路由设置
│      session.php          Session配置
│      template.php         模板引擎配置
│      trace.php            Trace配置
├─extend                    扩展类库目录
├─public                    WEB目录(对外访问目录)
│  │  index.php             入口文件
│  └─router.php             快速测试文件
├─route                     路由配置目录
├─runtime                   应用的运行时目录
└─vendor                    第三方类库目录(Composer)
    └─topthink
        ├─framework         ThinkPHP框架系统
        ├─think-installer   ThinkPHP安装器
        ├─think-template    模板引擎扩展
        └─think-view        视图扩展

配置

配置方便总体来说,改变不是很大。主要改变就是不支持动态配置了,并且获取配置的方法名变动了一下。
官方介绍得知,说是不能动态配置,但又可以通过以下方法写入配置,有些许矛盾。

Config::set([
    'name'  => 'jwj',
    'email' => 'jwjbjg@gmail.com',
    'blog'  => 'blog.ll00.cn'
], 'route');

没深入研究,但看代码得知,应该是将参数里的数组覆盖配置文件里配置的。总之肯定是没之前那么随心所欲了。
然后还有一点,不能跨模块读取配置了。

应用/控制器/方法/视图模板

应用

6.0版本已经没有模块了,取之而代的是应用,并且框架默认也关闭了多应用模式。
因为默认就是单应用,所以app目录下,直接就是控制器/视图/模型的目录了。
如果需要开启多应用,需要在入口文件里增加multi()方法,并且创建应用目录,将控制器/视图/模型等目录移动到应用目录下。
其实就是跟之前的模块差不多,只是换了个名称,但也预示着这块将会有大的改动。

入口文件代码:

<?php
namespace think;

// 引入Composer的autoload.php
require __DIR__ . '/../vendor/autoload.php';

// 执行HTTP应用并响应
$http = (new App())->http;

// 开启多应用模式
$http->multi(true);

// 执行应用程序
$response = $http->run();

// 发送数据到客户端
$response->send();

// HTTP应用
$http->end($response);

控制器

控制器对于我来说,是没有什么变化和影响的,唯一的影响就是继承的控制器类变了。
6.0版本的think\Controller不再封装视图方法,就是原来的fetchassign等视图方法不再包含在think\Controller里。
如果需要继续使用这些视图方法,需要改为继承think\ViewController类,或者使用助手函数或自己封装。

方法

方法对于我来说,也是没有什么变化和影响的,唯一的影响就是视图和模板的变动了。

视图和模板

视图和模板这个变动比较大,现在直接从框架核心移出去了,变成了扩展。
但5.1版本的时候就开始慢慢分离了,所以也不会很意外。
然后从用法方面来说是跟之前差不多,就是控制器那块的变化。

最近ThinkPHP框架出现了一个比较严重的漏洞,在没有开启强制路由的情况下可能的getshell漏洞,受影响的版本包括5.0.23和5.1.31之前的所有版本。
官方也很快提供了解决方案,大大的点个赞。但是只是讲了个重点,没讲太详细,对于一些新手和初学者可能不大方便操作。下面提供一些修复的方法,应该算是比较详细了。

ThinkPHP5.0

使用行为

手册:https://www.kancloud.cn/manual/thinkphp5/118130
/application/tags.php文件绑定模块初始化行为

<?php
\think\Hook::add('module_init',function(){
    if (!preg_match('/^[A-Za-z](\w|\.)*$/', \think\Request::instance()->controller())) {
        throw new \think\exception\HttpException(404, 'controller not exists:' . \think\Request::instance()->controller());
    }
});

直接修改框架

打开/thinkphp/library/think/App.php,搜索获取控制器名,然后在获取控制器的代码后面加上三行代码。
下面是示例(在一些比较低的版本,控制器名的变量是$controllerName):

// 获取控制器名
$controller = strip_tags($result[1] ?: $config['default_controller']);
$controller = $convert ? strtolower($controller) : $controller;

// 获取控制器的代码后面加上下面三行代码
if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) {
    throw new HttpException(404, 'controller not exists:' . $controller);
}

ThinkPHP5.1

使用行为

手册:https://www.kancloud.cn/manual/thinkphp5_1/354129
/application/tags.php文件绑定模块初始化行为

<?php
\think\facade\Hook::add('module_init', function () {
    if (!preg_match('/^[A-Za-z](\w|\.)*$/', \think\facade\Request::controller())) {
        throw new \think\exception\HttpException(404, 'controller not exists:' . \think\facade\Request::controller());
    }
});

使用中间件

手册:https://www.kancloud.cn/manual/thinkphp5_1/564279
/config/middleware.php文件注册中间件

<?php
\think\facade\Route::middleware(function (\think\Request $request, \Closure $next) {
    if (!preg_match('/^[A-Za-z](\w|\.)*$/', $request->controller())) {
        throw new \think\exception\HttpException(404, 'controller not exists:' . $request->controller());
    }
    return $next($request);
});

直接修改框架

打开/thinkphp/library/think/route/dispatch/Url.php,搜索解析控制器,然后在解析控制器的代码后面加上三行代码。
下面是示例:

if ($this->param['auto_search']) {
    $controller = $this->autoFindController($module, $path);
} else {
    // 解析控制器
    $controller = !empty($path) ? array_shift($path) : null;
}

// 解析控制器的代码后面加上下面三行代码
if ($controller && !preg_match('/^[A-Za-z][\w|\.]*$/', $controller)) {
    throw new HttpException(404, 'controller not exists:' . $controller);
}

在平常写项目的时候,不可避免的会用到时间计算。
如果只是简单的计算的话,只需要将时间字符串转换为时间戳然后对比即可。
但是如果需要计算具体的年月日时分秒的话,可以用日期对象来计算。

普通简单计算

// 时间1
$date1 = strtotime('2018-10-01'); // 1538352000
// 时间2
$date2 = strtotime('2018-11-01'); // 1541030400
// 时间2 比 时间1多多少秒
$diff = $date2 - $date1; // 2678400

使用时间对接来计算

http://php.net/manual/zh/datetime.diff.php

// 出生日期
$birthday = new \DateTime('1996-10-11');
// 当前时间
$now = new \DateTime();
// 计算出生日期和当前时间的时间查
$interval = $birthday->diff($now);
var_dump($interval);

打印出来是以下信息

object(DateInterval)[18]
  public 'y' => int 21 // 年
  public 'm' => int 6 // 月
  public 'd' => int 0 // 日
  public 'h' => int 17 // 时
  public 'i' => int 16 // 分
  public 's' => int 2 // 秒
  public 'weekday' => int 0
  public 'weekday_behavior' => int 0
  public 'first_last_day_of' => int 0
  public 'invert' => int 0
  public 'days' => int 7852 // 天数
  public 'special_type' => int 0
  public 'special_amount' => int 0
  public 'have_weekday_relative' => int 0
  public 'have_special_relative' => int 0

看上面的打印信息,就能看到很具体的时间了,而不用另外去计算
也就是说,生日至今,年龄是:21岁6个月17小时16分2秒7852

做的项目多了,总会遇到一些需要涉及需要用到地图坐标的。
既然有坐标,那肯定又得涉及位置距离。
例如我们平时使用美团,想搜索附近的美食店,这功能很方便是不是?
希望下面的经验能给你帮助,让你少走些弯路,同时自己做个笔记,方便自己。
毕竟老了,有些东西很快就自己也忘记了,也需要笔记来回忆~

数据库表结构

CREATE TABLE `markers` (
  `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID' ,
  `name` VARCHAR( 60 ) NOT NULL COMMENT '标记名称' ,
  `address` VARCHAR( 80 ) NOT NULL COMMENT '标记地址' ,
  `lat` FLOAT( 10, 6 ) NOT NULL COMMENT '纬度' ,
  `lng` FLOAT( 10, 6 ) NOT NULL COMMENT '经度'
) ENGINE = InnoDB COMMENT = '标记表' ;

数据库表数据

INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('北京市天安门','北京市东城区东长安街','39.915599','116.402687');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('广州华立科技职业学院','广东省广州市增城广州华立科技园华立路7号','23.248335','113.871302');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('韶关市风采楼','广东省韶关市浈江区风采路34号','24.813028','113.606039');

SQL语句

以下是基于半正矢公式 a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)的SQL查询语句。

  • 6371是地球的半径,单位:公里。如果想以英里搜索,将6371换成3959即可。
  • 39.915599是搜索点中心纬度(例如想搜索北京天安门附近的标记点,则这里就是北京天安门的纬度)
  • 116.402687是搜索点中心经度(例如想搜索北京天安门附近的标记点,则这里就是北京天安门的经度)
  • distance字段是标记点与搜索点中心的距离,单位:公里(如果地球半径是英里,则这里也是英里)
  • 25是范围,表示搜索出搜索中心点25公里以内的标记点
SELECT `id` , `name`
    , 6371 * acos(cos(radians(39.915599)) * cos(radians(`lat`)) * cos(radians(`lng`) - radians(116.402687)) + sin(radians(39.915599)) * sin(radians(`lat`))) AS `distance`
FROM `markers`
HAVING `distance` < 25
ORDER BY `distance`
LIMIT 0, 20;

查询结果

从以下结果能看出,还是有些误差的,两个点坐标一样,距离应该是0的。但误差较小,问题不大吧,嘿嘿。

idnamedistance
1北京市天安门0.00009493529796600342

来自:https://developers.google.com/maps/articles/phpsqlsearch_v3#findnearsql