zoukankan      html  css  js  c++  java
  • Laravel 进阶笔记 3

    上传图片/文件:

    <div class="form-group mb-4">
          <label for="" class="avatar-label">用户头像</label>
          <input type="file" name="avatar" class="form-control-file">
          @if($user->avatar)
               <br>
               <img class="thumbnail img-responsive" src="{{ $user->avatar }}" width="200" />
          @endif
    </div>

    view里面一个input, type是file, 记得把form的enctype="multipart/form-data"

    在后台, 有两种方法, 都通过Request来获取上传的文件.

    $ file = $request -> file('avatar');

    $ file = $request -> avatar;

    然后起一个类, appHandlersImageHandler.php

    namespace AppHandlers;
    
    class ImageUploadHandler
    {
        // 只允许以下后缀名的图片文件上传
        protected $allowed_ext = ["png", "jpg", "gif", 'jpeg'];
    
        public function save($file, $folder, $file_prefix)
        {
            // 构建存储的文件夹规则,值如:uploads/images/avatars/201709/21/
            // 文件夹切割能让查找效率更高。
            $folder_name = "uploads/images/$folder/" . date("Ym/d", time());
    
            // 文件具体存储的物理路径,public_path() 获取的是 public 文件夹的物理路径。
            // 值如:/home/vagrant/Code/larabbs/public/uploads/images/avatars/201709/21/
            $upload_path = public_path() . '/' . $folder_name;
    
            // 获取文件的后缀名,因图片从剪贴板里黏贴时后缀名为空,所以此处确保后缀一直存在
            $extension = strtolower($file->getClientOriginalExtension()) ?: 'png';
    
            // 拼接文件名,加前缀是为了增加辨析度,前缀可以是相关数据模型的 ID
            // 值如:1_1493521050_7BVc9v9ujP.png
            $filename = $file_prefix . '_' . time() . '_' . str_random(10) . '.' . $extension;
    
            // 如果上传的不是图片将终止操作
            if ( ! in_array($extension, $this->allowed_ext)) {
                return false;
            }
    
            // 将图片移动到我们的目标存储路径中
            $file->move($upload_path, $filename);
    
            return [
                'path' => config('app.url') . "/$folder_name/$filename"
            ];
        }
    }

    返回的是保存地址跟文件名.

    在UserController里面调用这个handler

        public function update(UserRequest $request,ImageUploadHandler $uploader, User $user)
        {
            $data = $request->all();
    
            //如果上传了头像
            if ($request->avatar) {
                //尝试保存头像并返回保存目录
                $result = $uploader->save($request->avatar, 'avatars', $user->id);
                //成功之后, 写入数组
                if ($result) {
                    $data['avatar'] = $result['path'];
                }
            }
    
            //写库
            $user->update($data);
    
            //dd($request->avatar);
            //$user->update($request->all());
            return redirect()->route('users.show', $user->id)->with('success', '个人资料更新成功!');
        }

    引出一个问题, php的函数形参, 不讲求顺序的么?

    可以乱来的?

    这可能就是这种语言的好处, 函数都是可以变的, 不用编译, 不像c, java这种, 一定要定义好方法的形参, 返回值, 因为一旦编译完, 不可能动态的修改函数的形参, 甚至数据类型都不可以, 但是好处是执行效率更高, 而php的灵活性更好, 甚至function的调用生成都可以是动态的.

    裁剪图片

    如果用户的图片太大, 为了节省宝贵的CDN流量费用, 用第三方的包进行图片裁剪吧, Intervention/image

    $ composer require intervention/image

    获取配置信息

    创建image的配置文件:

    $ php artisan vendor:publish --provider="InterventionImageImageServiceProviderLaravel5"

    在ImageUploadHandler里面写好裁剪的逻辑

    ...
            if ($max_width && $extension != 'gif') {
    
                // 此类中封装的函数,用于裁剪图片
                $this->reduceSize($upload_path . '/' . $filename, $max_width);
            }
    ...
    
      public function reduceSize($file_path, $max_width)
        {
            // 先实例化,传参是文件的磁盘物理路径
            $image = Image::make($file_path);
    
            // 进行大小调整的操作
            $image->resize($max_width, null, function ($constraint) {
    
                // 设定宽度是 $max_width,高度等比例双方缩放
                $constraint->aspectRatio();
    
                // 防止裁图时图片尺寸变大
                $constraint->upsize();
            });
    
            // 对图片修改后进行保存
            $image->save();
        }

    安全性

    游客是不可以edit任何人信息的, 现在不是, 所以要加中间件进行控制.

    在UsersController里面, 添加auth中间件, 除了show操作之外都要进行auth.

      public function __construct()
        {
            $this->middleware('auth', ['except' => ['show']]);
        }

    之所以加在controller里面, 因为controller每次被访问都会被实例化一次, 用Log::debug('')可验证.

    认证是一种逻辑, 另一种逻辑是, 用户自己编辑自己的资料, 而不能编辑别人的. 这样就需要UserPolicy, 生成policy可以用make:policy

    $ php artisan make:policy UserPolicy

    增加update方法,

        public function update(User $currentUser, User $user)
        {
            return $currentUser->id === $user->id;
        }

    然后再AuthServiceProvider里面注册一下这个update, 不然usercontroller的auth哪知道你定的什么规则.

     protected $policies = [
            'AppModel' => 'AppPoliciesModelPolicy',
            AppModelsUser::class  => AppPoliciesUserPolicy::class,
        ];

    然后在UserController里面, 把这个update认证policy用authorize方法限定一下:

      public function edit(User $user)
        {
            $this->authorize('update', $user);
            return view('users.edit', compact('user'));
        }
    
        public function update(UserRequest $request, ImageUploadHandler $uploader, User $user)
        {
            $this->authorize('update', $user);
            $data = $request->all();
    
            if ($request->avatar) {
                $result = $uploader->save($request->avatar, 'avatars', $user->id, 416);
                if ($result) {
                    $data['avatar'] = $result['path'];
                }
            }
    
            $user->update($data);
            return redirect()->route('users.show', $user->id)->with('success', '个人资料更新成功!');
        }

    这事儿是这么个意思吧, 本来是controller需要验证这个user, 如果单独写验证方法, 显得太傻, 无法复用, 于是写个规则, 就是这个叫'update'的policy, 然后将这个policy注册到auth的provider里面, 连同别的规则, 一起都放这里面, 然后你要使用的时候无论你是更新的时候还是update的时候, 都统一用authorize+policy名字的方法, 调用认证规则进行认证, 以后你要在其他controller, 操控其他资源, 也同样可以直接调用authorize这个policy即可, 这样就解耦了, 厉害!

    这个就是"提供者provider"的pattern.

  • 相关阅读:
    linux下面发布80端口的服务
    visio 安装
    SSH进行登录远程主机,实验室网站,项目
    论文遇到的问题
    ubuntu设置目录容量大小
    ubuntu 磁盘分区
    SpringBoot打成的jar包发布,shell关闭之后一直在服务器运行
    docker的安装,使用
    多线程下载文件,ftp文件服务器
    抖音红人,
  • 原文地址:https://www.cnblogs.com/Montauk/p/10194435.html
Copyright © 2011-2022 走看看