一步一步用laravel开发回风博客系统-10-文件上传

原作者网站:http://laravelcoding.com/blog?tag=L5+Beauty
可以参考中文站点:http://laravelacademy.org/resources/blog

我是基于5.2的,而且有些东西我觉得有必要有的没必要,所以思路是跟着以上两个参考着搞,具体还是有区别的,我最终代码放在了Github:https://github.com/wedojava/hfblog.dev

由于正在补英语,所以有些我能看懂的就没从原作者那里翻译。

是否实现上传?为什么要犹豫:

  1. 为了更好的实现内容的解耦,方便转移,文字信息应当与附件信息解耦,文件下载和图片信息应当是在线保存到云服务器比较科学。
  2. 一些本地存储类的插件存在区别,比如非常棒的那款图片上传插件: http://image.intervention.io/ , 把它用上当然很方便了,那么如果用它又何必要自己去实现Upload功能呢?

考虑再三,觉得还是应该做下文件上传,原因:

  1. 如果该代码用于不能连接互联网或不能连接到网络存储类网站时,确实应该具备存储一些资源于本地的能力。
  2. 即使要用 intervention image 插件,那也是在编辑和发布内容页面,和 upload 功能页面不冲突。

下面,我们开干。

Configuring the File System

Let’s start with the configuration. Specifically, where will any files be stored? Create a upload directory within the project’s public directory. This way any files uploaded will be publicly accessible to the web.

Creating Upload Public Directory: mkdir public/uploads

Now edit config/blog.php, to match what’s below.

Updated blog configuration

'uploads' => [
'storage' => 'local',
'webpath' => '/uploads/',
],

With the above changes now config('blog.uploads.storage') will define the file system and the config('blog.uploads.webpath') will be the root of our storage on the web.

这里我用的是七牛存储,先做完七牛提供的 七牛 laravel 组件安装

  • composer require zgldh/qiniu-laravel-storage
  • config/app.php 里面的 providers 数组, 加上一行 zgldh\QiniuStorage\QiniuFilesystemServiceProvider
  • edit the config/filesystems.php, changing the section as specified below.

Changes to config/filesystems.php

'disks' => [
'local' => [
'driver' => 'local',
'root' => public_path('uploads'),
],
... ,
'qiniu' => [
'driver' => 'qiniu',
'domains' => [
'default' => 'xxxxx.com1.z0.glb.clouddn.com', //你的七牛域名
'https' => 'dn-yourdomain.qbox.me', //你的HTTPS域名
'custom' => 'static.abc.com', //你的自定义域名
],
'access_key'=> '', //AccessKey
'secret_key'=> '', //SecretKey
'bucket' => '', //Bucket名字
'notify_url'=> '', //持久化处理回调地址
],
],

这里,我没有设置 https,至于其他参数,access_keysecret_key 在七牛里,bucket 是你在七牛要用的那个box的名称,notify_url 我也是留空没写。local 字段主要修改了 root 的值为:public_path('uploads')

Modifying a Helpers file

Add two functions:

/**
* Return sizes readable by humans
*/
function human_filesize($bytes, $decimals = 2)
{
$size = ['B', 'kB', 'MB', 'GB', 'TB', 'PB'];
$factor = floor((strlen($bytes) - 1) / 3);

return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) .
@$size[$factor];
}

/**
* Is the mime type an image
*/
function is_image($mimeType)
{
return starts_with($mimeType, 'image/');
}

The human_filesize() function returns a file size which is easier to read than just a count of bytes. The is_image() function returns true if the mime type is an image.

Creating an Upload Manager Service

Now that the basic configuration is finished, let’s create a service class to manage our uploaded files.

Detecting Mime Types

Depending on the files being uploaded, we may want to have different actions occur. So it’d be nice to easily detect the Mime Type of files.
PHP has the function mime_content_type() , but it’s deprecated. The PHP Fileinfo function can detect the mime type,but in Windows a DLL must be copied to make fileinfo functions work.Let’s use a different solution.

Searching Packagist for “mime” shows a package by dflydev which looks good.

Add the package to composer with the instructions below.

Adding dflydev mime package to composer

composer require "dflydev/apache-mime-types"

We’ll use this package in the UploadsManager class to detect a file’s mime type.

Creating the UploadsManager class

Create the file UploadsManager in the app/Services directory with the following content.

Initial version of UploadsManager

<?php
namespace App\Services;

use Carbon\Carbon;
use Dflydev\ApacheMimeTypes\PhpRepository;
use Illuminate\Support\Facades\Storage;

class UploadsManager
{
protected $disk;
protected $mimeDetect;

public function __construct(PhpRepository $mimeDetect)
{
$this->disk = Storage::disk(config('blog.uploads.storage'));
$this->mimeDetect = $mimeDetect;
}

/**
* Return files and directories within a folder
* @param string $folder
* @return array of [
* 'folder' => 'path to current folder',
* 'folderName' => 'name of just current folder',
* 'breadcrumbs' => breadcrumb array of [ $path => $foldername ]
* 'folders' => array of [ $path => $foldername] of each subfolder
* 'files' => array of file details on each file in folder
* ]
*/
public function folderInfo($folder)
{
$folder = $this->cleanFolder($folder);

$breadcrumbs = $this->breadcrumbs($folder);
$slice = array_slice($breadcrumbs, -1); // 从数组末端开始,取出一段
$folderName = current($slice); // 返回数组中的当前单元
$breadcrumbs = array_slice($breadcrumbs, 0, -1); // 从偏移量 0 开始一直到 array 的末端

$subfolders = [];

// directories 方法返回给定目录下所有目录数组
// allDirectories 方法获取嵌套的所有子目录数组
foreach (array_unique($this->disk->directories($folder)) as $subfolder) {
$subfolders["/$subfolder"] = basename($subfolder); // basename — 返回路径中的文件名部分
}

$files = [];
// files 方法返回给定目录下的所有文件数组
// allFiles 方法获取给定目录下包含子目录的所有文件列表
foreach ($this->disk->files($folder) as $path) {
// fileDetails() Return an array of file details for a file
$files[] = $this->fileDetails($path);
}

return compact(
'folder',
'folderName',
'breadcrumbs',
'subfolders',
'files'
);
}

/**
* Sanitize the folder name
*/
public function cleanFolder($folder)
{
return '/' . trim(str_replace('..', '', $folder), '/'); // 过滤掉斜线,替换点点为空白
}

/**
* Return breadcrumbs to current folder
*/
public function breadcrumbs($folder)
{
$folder = trim($folder, '/');
$crumbs = ['/' => 'root'];

if (empty($folder)) {
return $crumbs;
}

$folders = explode('/', $folder);
$build = '';

foreach ($folders as $folder) {
$build .= '/' . $folder;
$crumbs[$build] = $folder;
}

return $crumbs;
}

/**
* Return an array of file details for a file
*/
public function fileDetails($path)
{
$path = '/' . ltrim($path, '/'); // ltrim — 删除字符串开头的空白字符(或其他字符)

return [
'name' => basename($path),
'fullPath' => $path,
'webPath' => $this->fileWebPath($path),
'mimeType' => $this->fileMimeType($path),
'size' => $this->fileSize($path),
'modified' => $this->fileModified($path),
];
}

/**
* Return the full web path to a file
*/
public function fileWebPath($path)
{
$path = rtrim(config('blog.uploads.webpath'), '/') . '/' . ltrim($path, '/');

return url($path);
}

/**
* Return the mime type
*/
public function fileMimeType($path)
{
return $this->mimeDetect->findType(
pathinfo($path, PATHINFO_EXTENSION)
);
}

/**
* Return the file size
*/
public function fileSize($path)
{
return $this->disk->size($path); //size 方法以字节方式返回文件大小
}

/**
* Return the last modified time
*/
public function fileModified($path)
{
return Carbon::createFromTimestamp(
$this->disk->lastModified($path) //lastModified方法以UNIX时间戳格式返回文件最后一次修改时间
);
}
}

  • __construct()
    • Inject dependencies.Use the disk defined in the blog configuration and the class from the dflydev/apache-mime-types package required earlier.
  • folderInfo
    • Here’s the main method that returns everything needed about the contents of a folder.

Implementing UploadController index

Now that the UploadsManager service class has been created to do the bulk of our work, implementing the index method is almost trivial.

Creating the index method

Update the UploadController.php file located in the app/Http/Controllers/Admin directory to match what’s below.

Updating UploadController for index