Laravel技巧库

上传头像

此课程是收费课程,请先购买或加入会员后再访问。

controller

这一集我们要是实现的功能是,在用户注册模块,添加一个上传头像的功能。

通过php artisan route:list看一下注册功能路由提交的地址,是在RegisterController@register之中。但是打开RegisterController后,发现根本没有resigter方法。不用说了,这个register方法一定又是放在了trait之中了。

我们这里为了调试方便,自己在RegisterController中,新建一个register方法,这样laravel自带的注册功能就不会生效了。

use Illuminate\Http\Request;

public function register(Request $request)
{
    return $request->all();
}

view

上传头像的表单,我也已经准备好了,大家直接复制过来就好了。

<form method="post" class="am-form" action="{{ route('register') }}" enctype="multipart/form-data">

    <!-- ... -->
    <div class="am-form-group am-form-file">
        <label class="am-form-label" for="avatar">头像: </label>
        <br>

        <button type="button" class="am-btn am-btn-success am-btn-sm">
            <i class="am-icon-cloud-upload" id="loading"></i> 上传新的缩略图
        </button>

        <input type="file" id="photo_upload" name="file">
        <input type="hidden" name="avatar" value="{{old('avatar')}}">

        <hr data-am-widget="divider" class="am-divider am-divider-dashed am-no-layout">
        <div>
            <img src="{{ old('avatar', 'https://images.itfun.tv/school/images/common/user_noimg.png') }}" id="photo_show" style="max-height: 200px;">
        </div>
    </div>
    <!-- ... -->

</form>

Tips:
需要注意的是,上传一定要在form标签中加上enctype="multipart/form-data"。只有这样,php才能就收到上传的数据。
上传的input这里的namefile,那么在php那边也应该要使用file这个名字来接受了。

上传试试

public function register(Request $request)
{
    //return $request->file;
    $path = $request->file->store('public/images');
    return $path;
}

那这里就,可以看到一个路径地址了,这就是我们刚才上传的文件了,只不过他还在一个临时目录之中。
其实在laravel实现上传功能,非常的简单,只需要这一行代码就可以了。这里store的意思就是将临时目录中的文件,保存到我们指定的路径,也就是这里定义的public/images

打开文件夹,找到storage/app/public/images路径中,这里就可以找到我们刚才上传的文件了。文件名是laravel自动生成的一个唯一的名字,所以你不需要担心上传文件名字重复的问题。

但是有点问题,storage这个路径通过浏览器是访问不到的。因为laravel的根目录public目录中。所以,你还要使用这么一条命令,来建立一个storagepublic的链接。

php artisan storage:link

这样上传功能其实已经实现了,并且通过浏览器地址栏也可以访问到了。

http://localhost:8000/storage/images/?.jpeg

完整上传方法

实际上这样做并不完善,文件上传的一些基本的验证功能都没有做。那么我们就来继续增加一些代码吧。

//...

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class RegisterController extends Controller
{
    //...

    public function register(Request $request)
    {
        if (!$request->hasFile('file')) {
            return response()->json(['message' => '没有上传文件'], 422);
        }

        if (!$request->file->isValid()) {
            return response()->json(['message' => '文件上传过程中出错了'], 422);
        }

        //上传格式验证
        $allow = ['image/jpeg', 'image/png', 'image/gif'];
        $type = $request->file->getMimeType();
        //return $type;

        if (!in_array($type, $allow)) {
            return response()->json(['message' => '文件类型错误,只能上传图片'], 422);
        }

        //文件大小验证
        $max_size = 1024 * 1024 * 2;
        $size = $request->file->getClientSize();
        //return $size;

        if ($size > $max_size) {
            return response()->json(['message' => '文件大小不能超过2M'], 422);
        }

        $path = $request->file->store('public/images');
        $url = Storage::url($path);
        return $url;
    }
}

php.ini

如果一直提示没有上传文件,或者直接报错,那可能是你上传的文件 > 2M。
你需要修改下php.ini中,我这里是以mac oshomebrew安装的php 7.1为例,vim /usr/local/etc/php/7.1/php.ini。不同的环境,php.ini的路径也不一样。

post_max_size = 20
upload_max_filesize = 20M

修改完php.ini后,一定要重启服务。如果不是用命令行,而是apache来运行的,那就必须重启apache才会生效。

结束

在laravel中上传文件,就是这么一个流程。但是这种做法的体验并不是特别好。
点击按钮后,页面不能马上就显示出用户的头像来,必须表单提交后上传的代码才会生效。

下一集我们会学习使用ajax来完善上传功能。