Contents

PHP 代码技巧

blade模版

json_encode数组后的字符串可以在模版中直接用作数组

  • helps.php 代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
if (!function_exists('getPreviousMonth')) {
    function getPreviousMonth(): string
    {
        $currentDate = \Illuminate\Support\Carbon::now();
        $firstDayOfPreviousMonth = $currentDate->copy()->subMonth()->startOfMonth();
        $lastDayOfPreviousMonth = $currentDate->copy()->subMonth()->endOfMonth();

        return json_encode([$firstDayOfPreviousMonth->toDateString(), $lastDayOfPreviousMonth->toDateString()]);
    }
}
  • blade模版中可直接获取数组
1
{!! getPreviousMonth() !!}

新前端模版替换样式等资源的链接规则:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
href="((?!.*(?:https|http|html))[^{>"#]*)"
href="{{asset('theme/$1')}}"

src="((?!.*(?:https|http|html))[^{>"#]*)"
src="{{asset('theme/$1')}}"

52.073679870128096, 4.31522233905295

background
url\('?((?!.*(?:https|http|html))[^{>'"#]*)'?\)
url({{asset('UpConstruction-1.0.0/$1')}})

Carbon

时区

  • php内置函数获取所有时区
1
timezone_identifiers_list();
  • parse转换时区
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
use Carbon\Carbon;
// 定义上海时区
date_default_timezone_set('Asia/Shanghai');
// 将字符串直接转为Carbon
Carbon::parse('2023-08-21 05:37:05')->format('Y-m-d H:i:s');
// 输出UTC时间
Carbon::parse('2023-08-21 05:37:05')->timezone('UTC')->format('Y-m-d H:i:s');
// 将字符串根据时区转为Carbon,等效于把一个Carbon转换,比如now()
Carbon::parse('2023-08-21 05:37:05 Europe/Amsterdam')->format('Y-m-d H:i:s');
// 输出UTC时间
Carbon::parse('2023-08-21 05:37:05 Europe/Amsterdam')->timezone('UTC')->format('Y-m-d H:i:s');
// 下方的时间字符串格式也可以获取UTC时间
Carbon::parse('2023-08-25T17:06:00Z')->format("Y-m-d H:i:s");
// 对比
Carbon::parse('2023-08-25T17:06:00Z')->tz('UTC')->format("Y-m-d H:i:s");
Carbon::parse('2023-08-25 17:06:00')->tz('UTC')->format("Y-m-d H:i:s");
https://static.duan1v.top/images/20230821153457.png https://static.duan1v.top/images/20230910003909.png
  • php保存时间到mysql
1
2
3
4
// 先根据系统的时区,或者前端传过来的时间+时区,转成UTC时区,再保存到mysql
Carbon::parse('2023-08-21 05:37:05')->timezone('UTC')->format('Y-m-d H:i:s');
// 等同于
Carbon::parse('2023-08-21 05:37:05')->utc()->format('Y-m-d H:i:s');
  • php从mysql读取时间
1
2
// 根据UTC时间转换字段,转成系统的时区,或者指定的其他时区
Carbon::parse('2023-08-21 05:37:05 UTC')->timezone('Asia/Shanghai')->format('Y-m-d H:i:s');
  • 关于mysql选用的字段,推荐datetime
Mysql的datetime和timestamp的区别
  • 范围:datetime 数据类型的范围是从 ‘1000-01-01 00:00:00’ 到 ‘9999-12-31 23:59:59’,而 timestamp 数据类型的范围是从 ‘1970-01-01 00:00:01’ UTC 到 ‘2038-01-19 03:14:07’ UTC。因此,datetime 支持更广泛的日期范围,而 timestamp 受限于 1970 年至 2038 年之间的范围。
  • 存储空间:datetime 数据类型占用固定的 8 字节存储空间,而 timestamp 数据类型占用 4 字节存储空间。
  • 自动更新功能:当插入或更新记录时,datetime 列不会自动更新,它将保留插入或更新时的值。而 timestamp 列具有自动更新功能,当插入或更新记录时,会自动更新为当前时间戳。
  • 时区处理:datetime 列不会自动转换时区,它存储的是直接输入的日期和时间值。而 timestamp 列会自动将日期和时间值从当前会话时区转换为 UTC 进行存储,并在检索时再将其转换回会话时区。
  • 获取格式化时区
1
$timezone = 'GMT' . now()->format("P");
  • 获取 2023-08-21T05:37:05+00:00 格式的时间
1
Carbon::parse('2023-08-21 05:37:05 UTC')->toW3cString();

时间差

  • 主要是注意第二个参数
1
2
3
4
5
use Carbon\Carbon;
//为正负数
Carbon::parse('2023-08-21')->diffInDays('2023-08-11', false); 
//为正负数的绝对值
Carbon::parse('2023-08-21')->diffInDays('2023-08-11', true);

注意

  • 由于时令的存在,会导致进入时令的那天的时间不是24小时,即两天的时间戳(strtotime()函数获取)之差/3600不是24

自定义的Debugbar

自定义logger

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('customer_logger', function ($app) {
            $logger = new Logger('custom');
            $handler=new RotatingFileHandler(storage_path('logs/custom.log'),5, Logger::INFO);
            $formatter = new LineFormatter(
                '[%datetime%] %channel%.%level_name%: %message% %context% %extra%' . PHP_EOL,
                'Y-m-d H:i:s.u'
            );
            $handler->setFormatter($formatter);
            $logger->pushHandler($handler);
            return $logger;
        });
    }
}

新建Middleware

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php

namespace App\Http\Middleware;

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;

/**
 * Class QueryDebugMiddleware
 * @package App\Http\Middleware
 *
 */
class QueryDebugMiddleware
{
    public function handle($request, \Closure $next)
    {
        $logger = app('customer_logger');
        DB::listen(function ($query) use ($logger) {
            $caller = $this->getCallerInfo();
            $file = $caller['file'];
            $line = $caller['line'];

            // 在这里进行自定义的记录逻辑,例如使用日志记录
            $logger->info('SQL Query', [
                'fullSql' => vsprintf(str_replace('?', "'%s'", $query->sql), $query->bindings),
                'time'    => $query->time,
                'file'    => $file,
                'line'    => $line,
            ]);
        });

        return $next($request);
    }

    protected function getCallerInfo()
    {
        $queryFiles = [
            'Illuminate/Database/',
        ];
        $traces = collect(debug_backtrace())->pluck('line', 'file');
        $start = false;
        $end = true;
        foreach ($traces as $file => $line) {
            if (!$start) {
                $start = collect($queryFiles)->contains(function ($value) use ($file) {
                    return strpos($file, $value) !== false;
                });
            } else {
                $end = collect($queryFiles)->contains(function ($value) use ($file) {
                    return strpos($file, $value) !== false;
                });
            }
            if (!$end && $file && $line) {
                return [
                    'file' => $file,
                    'line' => $line,
                ];
            }
        }
        return [
            'file' => 'Unknown',
            'line' => 'Unknown',
        ];
    }
}

在线上需要观察的方法中添加

1
2
3
4
    public function __construct()
    {
        $this->middleware(QueryDebugMiddleware::class)->only('functionName');
    }

文件

文件上传限制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
代码里设置这个
ini_set('memory_limit',-1);
ini_set("max_execution_time", "500");
set_time_limit(500);

php配置里
file_uploads = On

; Temporary directory for HTTP uploaded files (will use system default if not
; specified).
; https://php.net/upload-tmp-dir
;upload_tmp_dir =

; Maximum allowed size for uploaded files.
; https://php.net/upload-max-filesize
upload_max_filesize = 50M

; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20

post_max_size = 50M

nginx里设置这个
proxy_connect_timeout  500s;
proxy_send_timeout  500s;
proxy_read_timeout  500s;
fastcgi_connect_timeout 500s;
fastcgi_send_timeout 500s;
fastcgi_read_timeout 500s;


# client_max_body_size 用来修改允许客户端上传文件的大小。默认为1m,如果设置为0,表示上传文件大小不受限制。
# 可以在以下模块设置: http, server, location
client_max_body_size 10m;

迁移文件

对于laravel较旧的版本(5之前吧),无法直接指定迁移文件,但老的迁移文件又有问题,无法维护,可以新建文件夹,指定新建的文件夹进行迁移

1
php artisan migrate --path=database/migrations/new
coffee