作者: Mr.Li

  • laravel validate验证参数说明

     

    validate的介绍

    Laravel提供了几种不同的方法来验证应用程序的传入数据。默认情况下,Laravel的基本控制器类使用ValidatesRequests特征,该特征提供了一种方便的方法,可以使用各种功能强大的验证规则来验证传入的HTTP请求。

    validate的使用

    以下为控制器方法

    简单的表单验证

    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);
    
        // The blog post is valid...
    }

    在这个例子里,如果 title字段没有通过 unique,那么不会检查 max 规则。规则会按照分配的顺序来验证。

    关于数组数据的注意事项

    如果你的 HTTP 请求包含一个 「嵌套」 参数(即数组),那你可以在验证规则中通过 「点」 语法来指定这些参数。

    $this->validate($request, [
        'title' => 'required|unique:posts|max:255',
        'author.name' => 'required',
        'author.description' => 'required',
    ]);

    validate验证参数说明

    accepted

    验证的字段必须为 yes、 on、 1、或 true。这在确认「服务条款」是否同意时相当有用。

    active_url

    相当于使用了 PHP 函数 dns_get_record,验证的字段必须具有有效的 A 或 AAAA 记录。

    after:date

    验证的字段必须是给定日期后的值。这个日期将会通过 PHP 函数 strtotime 来验证。

    'start_date' => 'required|date|after:tomorrow'

    你也可以指定其它的字段来比较日期:

    'finish_date' => 'required|date|after:start_date'

    after_or_equal:date

    验证的字段必须等于给定日期或之后的值。更多信息请参见 after 规则。

    alpha

    验证的字段必须完全是字母的字符。

    alpha_dash

    验证的字段可能具有字母、数字、破折号( – )以及下划线( _ )。

    alpha_num

    验证的字段必须完全是字母、数字。

    array

    验证的字段必须是一个 PHP 数组。

    before:date

    验证的字段必须是给定日期之前的值。这个日期将会通过 PHP 函数 strtotime 来验证。

    before_or_equal:date

    验证的字段必须等于给定日期或之前的值。这个日期将会使用 PHP 函数 strtotime 来验证。

    between:min,max

    验证的字段的大小必须在给定的 min 和 max 之间。字符串、数字、数组或是文件大小的计算方式都用 size 方法进行评估。

    当需要验证表单数据中数字的大小时,在验证规则中一定要加入 Numeric 或 Integer 其一,size、between、max、min这些验证才会起作用。

    boolean

    验证的字段必须能够被转换为布尔值。可接受的参数为 true、false、1、0、“1” 以及 “0”。

    confirmed

    验证的字段必须和 foo_confirmation 的字段值一致。例如,如果要验证的字段是 password,输入中必须存在匹配的 password_confirmation 字段。

    date

    验证的字段值必须是通过 PHP 函数 strtotime 校验的有效日期。

    date_equals:date

    验证的字段必须等于给定的日期。该日期会被传递到 PHP 函数 strtotime。

    date_format:format

    验证的字段必须与给定的格式相匹配。你应该只使用 date 或 date_format 其中一个用于验证,而不应该同时使用两者。

    different:field

    验证的字段值必须与字段 (field) 的值不同。

    digits:value

    验证的字段必须是数字,并且必须具有确切的值。

    digits_between:min,max

    验证的字段的长度必须在给定的 min 和 max 之间。

    dimensions

    验证的文件必须是图片并且图片比例必须符合规则:

    'avatar' => 'dimensions:min_width=100,min_height=200'

    可用的规则为: min_width、 max_width 、 min_height 、 max_height 、 width 、 height 、 ratio。

    比例应该使用宽度除以高度的方式来约束。这样可以通过 3/2 这样的语句或像 1.5 这样的浮点的约束:

    'avatar' => 'dimensions:ratio=3/2'

    由于此规则需要多个参数,因此你可以 Rule::dimensions 方法来构造可读性高的规则:

    use Illuminate\Validation\Rule;
    
    Validator::make($data, [
        'avatar' => [
            'required',
            Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
        ],
    ]);

    distinct

    验证数组时,指定的字段不能有任何重复值。

    ‘foo.*.id’ => ‘distinct’

    email

    验证的字段必须符合 e-mail 地址格式。

    exists:table,column

    验证的字段必须存在于给定的数据库表中。

    Exists 规则的基本使用方法

    'state' => 'exists:states'

    指定自定义字段名称

    'state' => 'exists:states,abbreviation'

    如果你需要指定 exists 方法用来查询的数据库。你可以通过使用「点」语法将数据库的名称添加到数据表前面来实现这个目的:

    'email' => 'exists:connection.staff,email'

    如果要自定义验证规则执行的查询,可以使用 Rule 类来定义规则。在这个例子中,我们使用数组指定验证规则,而不是使用 | 字符来分隔它们:

    use Illuminate\Validation\Rule;
    
    Validator::make($data, [
        'email' => [
            'required',
            Rule::exists('staff')->where(function ($query) {
                $query->where('account_id', 1);
            }),
        ],
    ]);

    file

    验证的字段必须是成功上传的文件。

    filled

    验证的字段在存在时不能为空。

    image

    验证的文件必须是一个图像( jpeg、png、bmp、gif、或 svg )。

    in:foo,bar,…

    验证的字段必须包含在给定的值列表中。因为这个规则通常需要你 implode 一个数组,Rule::in 方法可以用来构造规则:

    use Illuminate\Validation\Rule;
    
    Validator::make($data, [
        'zones' => [
            'required',
            Rule::in(['first-zone', 'second-zone']),
        ],
    ]);

    in_array:anotherfield

    验证的字段必须存在于另一个字段(anotherfield)的值中。

    integer

    验证的字段必须是整数。

    ip

    验证的字段必须是 IP 地址。

    ipv4

    验证的字段必须是 IPv4 地址。

    ipv6

    验证的字段必须是 IPv6 地址。

    json

    验证的字段必须是有效的 JSON 字符串。

    max:value

    验证中的字段必须小于或等于 value。字符串、数字、数组或是文件大小的计算方式都用 size 方法进行评估。

    mimetypes:text/plain,…

    验证的文件必须与给定 MIME 类型之一匹配:

    'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'

    要确定上传文件的 MIME 类型,会读取文件的内容来判断 MIME 类型,这可能与客户端提供的 MIME 类型不同。

    mimes:foo,bar,…

    验证的文件必须具有与列出的其中一个扩展名相对应的 MIME 类型。

    MIME 规则基本用法

    'photo' => 'mimes:jpeg,bmp,png'

    即使你可能只需要验证指定扩展名,但此规则实际上会验证文件的 MIME 类型,其通过读取文件的内容以猜测它的 MIME 类型。

    这个过程看起来只需要你指定扩展名,但实际上该规则是通过读取文件的内容并判断其 MIME 的类型来验证的。

    min:value

    验证中的字段必须具有最小值。字符串、数字、数组或是文件大小的计算方式都用 size 方法进行评估。

    nullable

    验证的字段可以为 null。这在验证基本数据类型时特别有用,例如可以包含空值的字符串和整数。

    not_in:foo,bar,…

    验证的字段不能包含在给定的值列表中。Rule::notIn 方法可以用来构建规则:

    use Illuminate\Validation\Rule;
    
    Validator::make($data, [
        'toppings' => [
            'required',
            Rule::notIn(['sprinkles', 'cherries']),
        ],
    ]);
    
    numeric

    验证的字段必须是数字。

    present

    验证的字段必须存在于输入数据中,但可以为空。

    regex:pattern

    验证的字段必须与给定的正则表达式匹配。

    注意: 当使用 regex 规则时,你必须使用数组,而不是使用 | 分隔符,特别是如果正则表达式包含 | 字符。

    required

    验证的字段必须存在于输入数据中,而不是空。如果满足以下条件之一,则字段被视为「空」:

    该值为 null.

    该值为空字符串。

    该值为空数组或空的 可数 对象。

    该值为没有路径的上传文件。

    required_if:anotherfield,value,…

    如果指定的其它字段( anotherfield )等于任何一个 value 时,被验证的字段必须存在且不为空。

    required_unless:anotherfield,value,…

    如果指定的其它字段( anotherfield )等于任何一个 value 时,被验证的字段不必存在。

    required_with:foo,bar,…

    只要在指定的其他字段中有任意一个字段存在时,被验证的字段就必须存在并且不能为空。

    required_with_all:foo,bar,…

    只有当所有的其他指定字段全部存在时,被验证的字段才必须存在并且不能为空。

    required_without:foo,bar,…

    只要在其他指定的字段中有任意一个字段不存在,被验证的字段就必须存在且不为空。

    required_without_all:foo,bar,…

    只有当所有的其他指定的字段都不存在时,被验证的字段才必须存在且不为空。

    same:field

    给定字段必须与验证的字段匹配。

    size:value

    验证的字段必须具有与给定值匹配的大小。对于字符串来说,value 对应于字符数。对于数字来说,value 对应于给定的整数值。对于数组来说, size 对应的是数组的 count 值。对文件来说,size 对应的是文件大小(单位 kb )。

    string

    验证的字段必须是字符串。如果要允许该字段的值为 null ,就将 nullable 规则附加到该字段中。

    timezone

    验证的字段必须是有效的时区标识符,会根据 PHP 函数 timezone_identifiers_list 来判断。

    url

    验证的字段必须是有效的 URL。

    结束

    以上很多为开发过程中经常使用的方法,希望文章总结可以给你带来帮助👍

    ————————————————
    版权声明:本文为CSDN博主「WXiangQian王先森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq175023117/article/details/107284330
  • laravel 发送邮件

    本文出处:https://learnku.com/articles/64183

    发送文本邮件

        $data = "测试发送";
        $from = "xxxx@qq.com";
        $name = "xxx";
        $title = "测试标题";
        $to = "xxxxx@qq.com";
        Mail::raw($data,function ($message) use($from, $name, $title, $to) {
       $message->from($from,$name);
       $message->to($to);
    });

    发送视图邮件#

       $from = "xxxxx@qq.com";
       $name = "xxx";
       $title = "测试";
       $to = "xxxxx@qq.com";
       $data = ["name" => "xxxxx"];
       Mail::send("welcome",$data,function ($message) use($from,$name,$title,$to) {
        $message->from($from,$name);
        $message->subject($title);
        $message->to($to);
     });

    发送视图邮件文本附件#

      $from = "xxxxx@qq.com";
      $name = "xxxx";
      $title = "测试";
      $to = "xxxxxx@qq.com";
      Mail::send("welcome",[],function ($message) use($from, $name, $title, $to) {
       $message->from($from, $name);
       $message->subject($title);
       $message->to($to);
       $attachment = public_path("robots.txt");
       $message->attach($attachment,['as' => 'root.txt']);
     });

    发送视图邮件图片附件#

      $from = "xxxxxxx@qq.com";
      $name = "xxxxx";
      $title = "测试";
      $to = "xxxxx@qq.com";
      $img = public_path("kato.jpeg");
      Mail::send("welcome",[],function ($message) use($from, $name, $title, $to,$img) {
       $message->from($from, $name);
       $message->subject($title);
       $message->attach($img);
       $message->to($to);
      });

  • laravel8 jwt多用户认证

    本文出处:https://learnku.com/articles/55800

    一、下载jwt

    https://github.com/tymondesigns/jwt-auth/wiki/Installation
    composer require tymon/jwt-auth

    发布配置文件

    php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

    二、生成jwt秘钥

    php artisan jwt:secret 

    三、配置guard

    'guards' => [
            'web' => [
                'driver' => 'session',
                'provider' => 'users',
            ],
    
            'api' => [
                'driver' => 'jwt',
                'provider' => 'users',
            ],
    
            'admin' => [
                'driver' => 'jwt',
                'provider' => 'admins'
            ]
        ],

    四、配置providers

    'providers' => [
            'users' => [
                'driver' => 'eloquent',
                'model' => App\Models\User::class,
            ],
    
             'admins' => [
                 'driver' => 'eloquent',
                 'model' => App\Models\Admin::class,
             ],
        ],

    五、生成jwt 中间件

    php artisan make:middleware JWTRoleAuth 

    六、配置jwt中间件

    use Closure;
    use Tymon\JWTAuth\Facades\JWTAuth;
    use Tymon\JWTAuth\Exceptions\JWTException;
    use Tymon\JWTAuth\Exceptions\TokenExpiredException;
    use Tymon\JWTAuth\Exceptions\TokenInvalidException;
    
    class JWTRoleAuth
    {
        public function handle($request, Closure $next)
        {
            try {
                if (! $user = JWTAuth::parseToken()->authenticate()) {  //获取到用户数据,并赋值给$user
                    return response()->json([
                        'code' => 1004,
                        'message' => '无此用户'
    
                    ], 404);
                }
                return $next($request);
    
            } catch (TokenExpiredException $e) {
    
                return response()->json([
                    'code' => 1003,
                    'message' => 'token 过期' ,
                ]);
    
            }  catch (TokenInvalidException $e) {
                return response()->json([
                    'code' => 1002,
                    'message' => 'token 无效',
                ]);
    
            } catch (JWTException $e) {
    
                return response()->json([
                    'code' => 1001,
                    'message' => '缺少token' ,
                ]);
            }
        }
    }

    七、编辑模型

    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    use Illuminate\Notifications\Notifiable;
    use Tymon\JWTAuth\Contracts\JWTSubject;
    
    
    class Admin extends Authenticatable implements JWTSubject
    {
        use HasFactory, Notifiable;
    
        protected $table="admins";
    
    
        protected $fillable = [
            'name', 'email', 'password',
        ];
    
        /**
         * 获取会储存到 jwt 声明中的标识
         */
        public function getJWTIdentifier()
        {
            return $this->getKey();
        }
    
        /**
         * 返回包含要添加到 jwt 声明中的自定义键值对数组
         * @return array
         */
        public function getJWTCustomClaims()
        {
            return ["role"=>"admin"];
        }
    }

    八 、编写代码测试

    如果你是api auth:api
    如果你是admin auth:admin

    use App\Http\Controllers\Controller;
    use App\Service\Api\RegisterService;
    use Illuminate\Http\Request;
    
    class LoginController extends Controller
    {
    
        /**
         * @var RegisterService
         */
    
        private $registerService;
    
        /**
         * LoginController constructor.
         * @param RegisterService $registerService
         */
        public function __construct(RegisterService  $registerService)
        {
            $this->registerService = $registerService;
            $this->middleware("auth:api",['except' => ['login', 'register',"logout"]]);
        }
    
        public function register(Request $request)
        {
            $name = $request->input("name");
    
            $email = $request->input("email");
    
            $password = $request->input("password");
    
            $data = $this->registerService->register($name,$email,$password);
    
            if ($data){
                return $this->success("0",$data,"注册成功");
            } else {
                return $this->error("425",$data,"注册失败");
            }
    
        }
    
        public function login(Request $request)
        {
            $credentials = request(['name', 'password']);
    
            if (! $token = auth("api")->attempt($credentials)) {
                $this->error("0",[],"登录失败");
            }
    
            return $this->success("1",$this->respondWithToken($token),"登录成功");
        }
    
        /**
         * Refresh a token.
         * 刷新token,如果开启黑名单,以前的token便会失效。
         * 值得注意的是用上面的getToken再获取一次Token并不算做刷新,两次获得的Token是并行的,即两个都可用。
         * @return \Illuminate\Http\JsonResponse
         */
        public function refresh()
        {
            return $this->success('0',$this->respondWithToken(auth('api')->refresh()),'刷新成功');
        }
    
        /**
         * Get the token array structure.
         *
         * @param  string $token
         *
         * @return \Illuminate\Http\JsonResponse
         */
        protected function respondWithToken($token)
        {
            return response()->json([
                'access_token' => $token,
                'token_type' => 'bearer',
                'expires_in' => auth('api')->factory()->getTTL() * 60
            ]);
        }
    
        /**
         * 用户退出登录
         * @return \Illuminate\Http\JsonResponse
         */
        public function logout()
        {
            auth('api')->logout();
    
            return response()->json(['message' => 'Successfully logged out']);
        }
    
        public function me()
        {
            $data = auth("api")->user();
            return $this->success("0",$data,"查询成功");
        }
    }

    九、测试#

    测试注册

    测试登录

    测试我的信息

    测试登出

    十、我的环境是

    php7.4.16 + nginx1.19.8 + mysql8.0.23 + laravel8.34.0

     

  • Laravel8中间件组的简单使用

    本文出处:https://learnku.com/articles/67696

    系统相关情况:ubuntu + php7.4 + Laravel8


    说明:最近在写JWT相关逻辑,参考这篇文章配置JWT,具体怎么配置,这里就不说了,这篇文章主要针对token的验证,通过中间件来实现。

    补充一下,我的项目是两个模块的,路由api那个我同事再用,我是后台所以新增一个admin路由文件,用户体系也不同,他是user表,我是user_admin表,所以第一步先配置我的模块的信息

    第一步,配置自己的guards

    在config/auth.php里面的guards数组新增admin键值:

    'guards' => [
            'web' => [
                'driver' => 'session',
                'provider' => 'users',
            ],
            'api' => [
                'driver' => 'jwt',
                'provider' => 'apiusers',
            ],
            'admin' => [ //admin模块
                'driver' => 'jwt',
                'provider' => 'admin',
            ],
        ],

    然后我下面找providers数组,新增admin模块:

    'providers' => [
            'users' => [
                'driver' => 'eloquent',
                'model' => App\Models\User::class,
            ],
    
            'apiusers' => [
                'driver' => 'eloquent',
                'model' => App\Models\User::class,
            ],
    
            'admin' => [ //admin模块
                'driver' => 'eloquent',
                'model' => App\Models\UserAdmin::class, //admin的用户模型
            ],
        ],

    第二步,生产中间件

    通过命令:

    php artisan make:middleware AuthAdminJwt 

    AuthAdminJwt类里面内容如下:

    <?php
    namespace App\Http\Middleware;
    
    use App\Models\UserAdmin;
    use Closure;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Config;
    use Tymon\JWTAuth\Facades\JWTAuth;
    use Tymon\JWTAuth\Exceptions\JWTException;
    use Tymon\JWTAuth\Exceptions\TokenExpiredException;
    use Tymon\JWTAuth\Exceptions\TokenInvalidException;
    
    class AuthAdminJwt
    {
        /**
         * @param Request $request
         * @param Closure $next
         * @return \Illuminate\Http\JsonResponse|mixed
         */
        public function handle(Request $request, Closure $next)
        {
            //配置JWTAuth::parseToken()->authenticate()读取user_admin表,默认读取user表
            Config::set('auth.providers.users.model', UserAdmin::class);
            try {
                if (!$user = JWTAuth::parseToken()->authenticate()) { //获取到用户数据,并赋值给$user
                    return response()->json([
                        'code' => 1,
                        'message' => '用户不存在'
                    ], 404);
                }
                return $next($request);
            } catch (TokenExpiredException $e) {
                return response()->json([
                    'code' => 1003,
                    'message' => 'token已过期',
                ]);
            } catch (TokenInvalidException $e) {
                return response()->json([
                    'code' => 1002,
                    'message' => 'token无效',
                ]);
            } catch (JWTException $e) {
                return response()->json([
                    'code' => 1001,
                    'message' => '缺少token参数',
                ]);
            }
        }
    }
    

    第三步:配置路由

    第一种:配置路由中间件属性

    (1):通过路由规则配:


    在Http\Kernel.php里面:

    protected $routeMiddleware = [
            'jwt.admin.auth' => \App\Http\Middleware\AuthAdminJwt::class,
        ];

    然后配置路由规则:

    Route::get("/user/detail", [UserController::class, "detail"])->middleware('jwt.admin.auth');

    运行这个路由,如果没有给token,就会报错。成功。

    (2)还有一种是通过控制器配置中间件:


    在Http\Kernel.php里面,这个和上面一样:

    protected $routeMiddleware = [
            'jwt.admin.auth' => \App\Http\Middleware\AuthAdminJwt::class,
        ];

    接着在控制器里面的构造方法里面:

    <?php
    /**
     * Created by PhpStorm.
     * User: xyf
     * Date: 2022/5/6
     * Time: 13:34
     */
    
    namespace App\Http\Admin\Account;
    
    use App\Http\Admin\Controller;
    use App\Http\Requests\AdminLoginRequest;
    use App\Models\UserAdmin;
    
    class LoginController extends Controller
    {
        public function __construct()
        {
            //除了login方法,其他需要验证token
            $this->middleware('jwt.admin.auth', ['except' => ['login']]);
        }
    
        /**
         * 登录
         *
         * @param AdminLoginRequest $request
         * @return \Illuminate\Http\JsonResponse
         */
        public function login(AdminLoginRequest $request)
        {
            $credentials = request(['mobile', 'password']);
            if (!$token = auth("admin")->attempt($credentials)) {
                return $this->fail("登录失败");
            }
    
            return $this->success([
                'access_token' => $token,
                'token_type' => 'Bearer',
                'expires_in' => auth('admin')->factory()->getTTL()
            ]);
        }
    
        /**
         * 退出登录
         *
         * @return \Illuminate\Http\JsonResponse
         */
        public function logout()
        {
            auth("admin")->logout();
            return $this->success();
        }
    
        public function test()
        {
            return $this->success();
        }
    }
    

    第二种:配置路由中间件组属性

    在Http\Kernel.php里面:

     protected $middlewareGroups = [
            'web' => [
               //.......
            ],
    
            'api' => [
              //......
            ],
            'admin'=>[
                \App\Http\Middleware\Auth\AuthAdminJwt::class,
            ]
        ];

    或则另一种写法:

     protected $middlewareGroups = [
            'web' => [
               //.......
            ],
    
            'api' => [
              //......
            ],
            'admin'=>[
                  /**
                  这种写法前提是在protected $routeMiddleware = [
                 'jwt.admin.auth' => \App\Http\Middleware\AuthAdminJwt::class,]配置了
                 **/
              "jwt.admin.auth"
        ];
            ]
        ];

    然后配置路由规则:

    Route::group(['middleware' => 'admin'],function(){
        Route::post("/account/test", [LoginController::class, "test"]);
        Route::post("/account/logout", [LoginController::class, "logout"]);
    });

    或则另一种写法:

    Route::middleware(['admin'])->group(function (){
      Route::post("/account/test", [LoginController::class, "test"]);
      Route::post("/account/logout", [LoginController::class, "logout"]);
    });

    这样你运行上面的路由就会验证token

     

     

  • Laravel 使用 Redis

    //redis key 名称
    $cache_frequency_key = 'cache_frequency_key';
    //判断是否存在
    if (Redis::exists($cache_frequency_key)) {
        abort(206, '正在排队中,请稍后查看。');
    }

    //设置key

    Redis::setex($cache_frequency_key, $cacheTime, 1);
    Redis::SADD($cache_frequency_key, $item['item_id'] . '#' . $item['number']);

    //删除key

    Redis::del($cache_frequency_key);

    //取key

    Redis::get($cache_key)
  • PHP小技巧之计算文本相似度

    有这样一个需求:需要对于用户发布的内容标题进行相似度对比,如果有之前的内容和当前发布的内容标题相似度到达某个阈值时则禁止发布或进行其他的一些操作。

     

    看到这个需求,可能就想到需要使用某种算法来实现,例如:TF-IDF、基于空间向量的余弦算法、最长公共子序列、最小编辑距离算法、Jaccard 系数等等。

    最小编辑距离算法在 PHP 中已经有了实现:levenshtein,计算两个字符串之间的编辑距离。

    levenshtein(
        string $string1,
        string $string2,
        int $insertion_cost = 1,
        int $replacement_cost = 1,
        int $deletion_cost = 1
    ): int

    编辑距离,是指两个字符串之间,通过替换、插入、删除等操作将字符串 string1 转换成 string2 所需要操作的最少字符数量。

    该算法的复杂度是 O(m*n),其中 n 和 m 分别是 string1string2 的长度。

    来点废话文学演示一下:

    echo levenshtein('听君一席话', '听君一席话'); // 0
    echo levenshtein('听君一席话', '如听一席话'); // 3
    echo levenshtein('我不要你觉得', '我要我觉得'); // 6
    echo levenshtein('今天的天气怎么样?', '你吃饭了吗?'); // 21

    当编辑距离越小时,相似度就越高。

    除了编辑距离,PHP 还直接提供了一个计算两个字符串相似度的函数:similar_text

    similar_text(string $string1, string $string2, float &$percent = null): int

    返回两个字符串中匹配字符的数量。

    通过将引用作为第三个参数传递,similar_text() 会通过将 similar_text() 的结果除以给定字符串的平均长度,乘以百分比来计算相似度 100。

    echo similar_text('听君一席话', '听君一席话', $percent); // 15
    echo $percent; // 100
    
    echo similar_text('听君一席话', '如听一席话', $percent); // 12
    echo $percent; // 80
    
    echo similar_text('我不要你觉得', '我要我觉得', $percent); // 12
    echo $percent; // 72.727272727273
    
    echo similar_text('今天的天气怎么样?', '你吃饭了吗?', $percent); // 6
    echo $percent; // 26.666666666667

    这个函数的相似程度计算依据 Programming Classics: Implementing the World's Best Algorithms by Oliver (ISBN 0-131-00413-1) 的描述进行。

    这个函数的实现使用了递归调用,所以可能会导致整个过程变慢或者变快,该算法的复杂度是 O(N**3),N 是最长字符串的长度。

    $percent 越大时,相似度越高。

    匹配字符的数量是通过找到最长的第一个公共子字符串来计算的,然后递归地对前缀和后缀执行此操作。将所有找到的公共子字符串的长度相加。

  • laravel 软删除与表单唯一验证

    laravel 软删除与表单唯一验证

    在laravel中表单唯一验证与软删除的使用

    常规使用

    写着方便,初学不好时理解起来有点困难
    不知道大家看了官网上的讲解是什么感觉,反正我是一头雾水,我写了一下我自己的理解;
    在这里插入图片描述
    我们先开看这张表

    样式:unique:table,column,except,idColumn,key1,value1,key2,value2,key3,value3···keyn,valuen
    例子:'email' => 'unique:users,email_address,'.$code.',serial'
    table:表名(users)
    column:数据库中存email的字段名email_address
    except:排除主键值$code
    idColumn:主键名,默认为id,当不是id时需要指明,如serial
    value1,key2,value2,key3,value3···keyn,valuen:会转where条件
    	注意value表示空要写成大写NULL,非空要也是大写NOT_NULL
    转成sql大概意思就是这样
    unique($table,$column,$except,$idColumn='id',key1,value1,key2,value2,key3,value3,...keyn,valuen){
    	$num = DB::table($table)
    	->where($idColumn,'<>',$except)
    	->where('key1','=','value1')
    	->where('key2','='.'value2')
    	->where('key3','=','value3')
    			.
    			.
    			.
    	->where('keyn','=','valuen')
    	->count($column);
    	if($num>1){
    		return false;
    	}else{
    		return true;
    	}
    }

    在这里插入图片描述
    注意:value要表示为空时,必须写成NULL,必须写成NULL,必须写成NULL,
    注意:value要表示不为空时,必须写成NOT_NULL,必须写成NOT_NULL,必须写成NOT_NULL,
    相信通过上面的例子应该是清楚unique的用法了,我通常喜欢用deleted_at是否为空来判断此数据是否被删除,这里有个坑,小心了,NULL必须是全部大写的NULL,否则null会被当成字符串来处理

    #错误
    'email_address'=>"unique:users,email_address,$selfId,id,deleted_at,null",
    #错误
    'email_address'=>"unique:users,email_address,$selfId,id,deleted_at,Null",
    #正确
    'email_address'=>"unique:users,email_address,$selfId,id,deleted_at,NULL",

    如果你用的是Request写法,这里需要结合你的路由来设置,比如你的路由是这样的
    以修改为例:
    用uuid查询出数据并修改name

    Route::put('sites/update/{uuid}', 'SitesController@update')->name('conf.sites.update');

    传递了uuid作为查询主键,那么你的验证规则就应该这样写

    验证规则
    'name'  => 'unique:users(你验证的表名称users),name(你要排除的字段名称name),'.$this->uuid(你路由中传递的变量uuid).',uuid(你的主键名称uuid)',
    'name'  => 'unique:users,name,'.$this->uuid.',uuid',
    //注意了,你路由中用abc接收变量,你这里就写成$this->abc
    //Route::put('sites/update/{uuid}', 'SitesController@update')->name('conf.sites.update');
    //'name'  => 'unique:users,name,'.$this->abc.',uuid',

    看到这里你是不是要问,我艹$this->abc是什么鬼,怎么就能拿到我们传递的值?要是不放心,可以在你的Request中逐步打印一下,或是写成下面的样式,详情去看获取路由参数的方法

    dd($this);
    dd($this->route());
    dd($this->route()->parameters);
    dd($this->route()->parameters['abc']);
    dd($this->route('abc'));
    //就这种
    'name'  => 'unique:users,name,'.$this->route('abc').',uuid',

    在这里插入图片描述

    闭包方式

    容易理解,写着复杂

    #引一下
    use Illuminate\Validation\Rule;
     'email' =>[
         'required',
         'Max:120',
         Rule::unique('stands')->where(function ($query) use($id) {
             $query->where('deleted_at', null)->where('id','<>',$id);
         })
     ],
     注意:闭包方式=》后必须用数组[]来存,不能用“|”的方式

    中文文档

    下面这是文档里复制出来的关于唯一性验证的讲解

    unique:table,column,except,idColumn
    在指定的数据表中,验证字段必须是唯一的。如果没有指定 column,将会使用字段本身的名称。
    
    指定一个特定的字段名称:
    
    'email' => 'unique:users,email_address'
    自定义数据库连接
    
    有时候你可能需要自定义一个连接,来通过 Validator 对数据库进行查找。如上面所示,设置 unique:users 作为验证规则,通过默认数据库连接来做数据库查找。如果要重写验证规则,可在指定的连接的表单名称后面加上「.」:
    
    'email' => 'unique:connection.users,email_address'
    强迫 Unique 规则忽略指定 ID:
    
    有时候,你希望在验证字段时对指定 ID 进行忽略。例如,在「更新个人资料」页面会包含用户名、邮箱等字段。这时你会想要验证更新的 e-mail 值是否为唯一的。如果用户仅更改了名称字段而不是 e-mail 字段,就不需要抛出验证错误,因为此用户已经是这个 e-mail 的拥有者了。假设用户提供的 e-mail 已经被其他用户使用,则需要抛出验证错误。若要用指定规则来忽略用户 ID,则应该把要发送的 ID 当作第三个参数:
    
    'email' => 'unique:users,email_address,'.$user->id
    如果你的数据表使用的主键名称不是 id,那么你可以在第四个参数中来指定它:
    
    'email' => 'unique:users,email_address,'.$user->id.',user_id'
    增加额外的 Where 语句:
    
    你也可以指定更多的条件到「where」查询语句:
    
    'email' => 'unique:users,email_address,NULL,id,account_id,1'
    上述规则中,只有 account_id 为 1 的数据列会被包含在 unique 规则的验证。
    
    •  
  • go出现missing go.sum entry for module providing package 错误

    在项目目录下打开终端,执行go mod tidy解决,这个命令会删除不需要的依赖包、下载新的依赖包、更新go.sum

  • Laravel实现软删除

    Laravel实现软删除

    Laravel 的 Eloquent ORM 提供了一个漂亮、简洁的 ActiveRecord 实现来和数据库交互。每个数据库表都有一个对应的「模型」用来与该表交互。你可以通过模型查询数据表中的数据,以及在数据表中插入新记录。

    官方文档对于软删除的解释如下:

    除了真实删除数据库记录,Eloquent 也可以「软删除」模型。软删除的模型并不是真的从数据库中删除了。 事实上,是在模型上设置了deleted_at属性并将其值写入数据库。如果deleted_at值非空,代表这个模型已被软删除。如果要开启模型软删除功能,你需要在模型上使用Illuminate\Database\Eloquent\SoftDeletes

     

    下面我们来编写一个用户表,实现软删除的例子:

    • 创建生成模型和迁移文件
    php artisan make:model User -m

    实体类:

    class User
    {
    
        // 调用定义的trait类 和继承效果一样 
        // 开启软删除
        use SoftDeletes;
        // 设置添加的数据
        // 拒绝不添加的数据 使用create才有效
        protected $guarded = [];
        
        // 软删除标识字段
        protected $dates = ['deleted_at'];
    }

    实体类必须加上 use SoftDeletes;

    • 迁移文件:
    class CreateUsersTable extends Migration
    {
    
        /**
         * 用户表
         */
        public function up()
        {
            Schema::create('users', function (Blueprint $table) {
                $table->bigIncrements('id');
                // 角色
                $table->unsignedInteger('role_id')->default(0)->comment('角色ID');
                $table->string('username', 50)->comment("账号");
                $table->string('truename', 20)->default('未知')->comment("账号");
                $table->string('password', 255)->comment('密码');
                $table->string('email', 50)->nullable()->comment('邮箱');
                $table->string('phone', 15)->default('')->comment('手机号码');
                $table->enum('sex', ['先生','女士'])->default('先生')->comment('性别');
                $table->char('last_ip', 15)->default('')->comment('登录IP');
                $table->timestamps();
                // 实现软删除,需要添加delete_at字段,$table->softDeletes();
                $table->softDeletes();
            });
        }
    
        public function down()
        {
            Schema::dropIfExists('users');
        }
    }

    执行php artisan migrate创建表

    表结构如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R4vrLGRp-1594996196435)(1.png)]

    • 查询方法:

    如果不使用withTrashed(),已经进行了软删除的数据就查不出来,因为Laravel默认查询结果会自动剔除已被软删除的结果。

       public function index(){
           // 分页  withTrashed 显示所有的,包括已经进行了软删除的
           $data = User::orderBy('id', 'desc')->withTrashed()->paginate($this->pageSize);
           return view('admin.user.index', compact('data'));
       }

    当然,使用onlyTrashed() 方法可以获取已软删除的模型

        public function index(){
            $data = User::orderBy('id', 'desc')->onlyTrashed()->paginate($this->pageSize);
            return view('admin.user.index', compact('data'));
        }
    • 软删除方法:

    直接调用delete()方法或者destroy()方法即可

        public function del(int $id){
            User::destroy($id);
            // 删除
    		// User::find($id)->delete();
            return ['status' => '0', 'msg' => '删除成功'];
        }

    调用删除方法删除数据之后,因为我们开启了软删除,所以在调用删除方法之前,deleted_at字段是为空的,调用之后会给deleted_at赋值上当前的时间戳,标识该记录已经被 “删除”。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o8EqmV8s-1594996196445)(2.jpg)]

    • 永久删除

    直接删除数据

        public function del(int $id){
            User::forceDeleted($id);
            return ['status' => '0', 'msg' => '删除成功'];
        }
    • 恢复删除

    既然是软删除,那就可以进行数据的恢复,简单地说就是把deleted_at字段置空就行。Laravel也为我们提供了restore()方法

        public function restore(int $id){
            User::onlyTrashed()->where('id', $id)->restore();
            return redirect(route('admin.user.index'))->with(['success' => '还原成功']);
        }
  • mysql 遇到错误问题 MySQL5.7.26\bin\mysqld.exe: Error while setting value ‘NO_ENGINE_SUBSTITUTION

    这种问题的出现是因为升级后的mysql的配置文件my.ini中的sql_mode的值,逗号后面都会自动加上空格导致无法启动,要手动删掉空格就可以了。

    my.ini原来的部分代码如下:

    sql_mode=NO_ENGINE_SUBSTITUTION,  STRICT_TRANS_TABLES
     
    my.ini修改后的代码:

    sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES