expstudio/laraclip

使用 Eloquent 的附件上传包,适用于 Laravel 4,支持 PHP5.3.x 版本降级自 Expstudio/laraclip

1.0.0 2014-06-15 17:03 UTC

This package is not auto-updated.

Last update: 2024-09-28 15:59:54 UTC


README

#LaraClip

Laravel 4 的附件上传包,支持 PHP5.3.x。

起始版本 - v0.1.0

  • LaraClip 1.0 支持 Laravel 框架 4.1.* 以及 PHP5.3.x 的向后兼容。

LaraClip 由 Watee Wichiennit 从 Codesleeve/Stapler 降级而来。

要求

LaraClip 目前需要 php >= 5.3(LaraClip 取消了 traits 并回到正常类继承)。

安装

LaraClip 以 composer 包的形式发布,这是在您的应用程序中使用它的方式。

使用 Composer 安装此包。编辑您的项目 composer.json 文件,添加 expstudio/laraclip 作为依赖项。

  "require": {
    "laravel/framework": "4.*",
    "expstudio/laraclip": "dev-master"
  }

此操作完成后,下一步是添加服务提供者。打开 app/config/app.php,并在 providers 数组中添加一个新项。

    'Expstudio\LaraClip\LaraClipServiceProvider'

警告

不要使用新的 PHP5.4+ 数组语法 ([] 方括号)。请使用旧式数组 (array())。

快速入门

在您的应用程序根目录(可能是公共文件夹)中,创建一个名为 system 的文件夹,并授予您的应用程序对该文件夹的写权限。

在您的模型中

use Expstudio\LaraClip\LaraClip;

class User extends LaraClip {

  public function __construct(array $attributes = array()) {
      $this->hasAttachedFile('image', array(
            'styles' => array(
                          'large' => '450x450#',
                          'thumb' => '100x100#'
                        )
        ));

      parent::__construct($attributes);
  }
}

确保在您的模型中,在 parent::__construct() 之前调用 hasAttachedFile() 方法。

从命令行使用迁移生成器

php artisan laraclip:fasten users avatar
php artisan migrate

在您的新视图中

<?= Form::open(['url' => action('UsersController@store'), 'method' => 'POST', 'files' => true]) ?>
	<?= Form::file('avatar') ?>
    <?= Form::submit('save') ?>   
<?= Form::close() ?>

在您的控制器中

public function store()
{
	// Create a new user, assigning the uploaded file field ('named avatar in the form')
    // to the 'avatar' property of the user model.   
    $user = User::create(['avatar' => Input::file('avatar')]);	
}

在您的展示视图中

<img src="<?= $user->avatar->url() ?>" >
<img src="<?= $user->avatar->url('medium') ?>" >
<img src="<?= $user->avatar->url('thumb') ?>" >

要分离(重置)文件,只需在保存之前调用附件属性上的 clear() 方法(您还可以分配常量 LARACLIP_NULL)

$user->avatar->clear();
$user->save();

$user->avatar = LARACLIP_NULL;
$user->save();

这将确保数据库表记录中相应的附件字段被清除,并且当前文件从存储中删除。数据库表记录本身将不会被销毁,并且可以像平常一样使用(或者甚至可以分配新的文件上传)。

概览

LaraClip 通过将文件上传附加到数据库表记录来工作。这是通过在表的相应模型中定义附件,然后在保存模型之前将上传的文件(从您的表单中)作为属性(以附件的名称命名)分配给模型来完成的。本质上,这允许上传的文件像模型上的任何其他属性一样被处理;laraclip 将抽象出所有文件处理、存储等,这样您就可以专注于项目的其余部分,而无需担心文件在哪里或如何检索它们。

一个模型可以定义多个附件(头像、照片、foo 等),而每个附件可以定义多个大小(样式)。当上传图像或文件时,LaraClip 将处理所有文件处理(移动、调整大小等),并提供一个带有处理上传文件的方法的附件对象(作为模型属性)。为了实现这一点,需要在包含文件附件的任何模型对应的表中创建四个字段(通过 laraclip:fasten 或手动创建),字段名称以附件命名。例如,对于在名为 'User' 的模型中定义的名为 'avatar' 的附件,需要向 'users' 表添加以下字段

  • (字符串) avatar_file_name
  • (整数) avatar_file_size
  • (字符串) avatar_content_type
  • (时间戳) avatar_updated_at

在您的表迁移文件中,以下内容应该足够

$table->string("avatar_file_name")->nullable();
$table->integer("avatar_file_size")->nullable();
$table->string("avatar_content_type")->nullable();
$table->timestamp("avatar_updated_at")->nullable();

配置

配置可以在每个附件的基础上设置,也可以通过配置文件全局设置。LaraClip 在处理配置方面非常灵活;可以在每个附件的基础上覆盖全局配置选项,这样您就可以轻松地将您希望在所有附件上设置的配置级联,同时仍然有自由度来定制单个附件的配置。要开始,您可能首先想做的就是将默认配置选项发布到您的 app/config 目录。

 php artisan config:publish expstudio/laraclip

完成此操作后,您现在应该能够根据您的需要配置 LaraClip,而无需担心未来的更新会覆盖您的配置文件。

LaraClip-配置

以下配置设置适用于 LaraClip。

  • storage:上传文件的底层存储驱动程序。默认为文件系统(本地存储),但也可以设置为 's3' 以用于 AWS S3。
  • image_processing_library:正在使用的底层图像处理库。默认为 GD,但也可以设置为 Imagick 或 Gmagick。
  • default_url:当记录不存在文件上传时返回的默认文件。
  • default_style:从 LaraClip 文件位置辅助方法返回的默认样式。上传文件的未修改版本始终存储在 'original' 样式中,但是默认样式可以设置为指向样式数组中定义的任何样式。
  • styles:为文件附件定义的一组图像大小。LaraClip 将尝试将文件上传格式化为定义的样式。
  • keep_old_files:将其设置为 true 以防止在记录更新时从文件系统中删除较旧的文件上传。
  • preserve_old_files:将其设置为 true 以防止在附件对象被销毁时(附件在相应的模型被从数据库中删除/销毁时被销毁)从文件系统中删除附件的文件上传。

默认值

  • storage:'filesystem'
  • image_processing_library:'GD'
  • default_url:'/:attachment/:style/missing.png'
  • default_style:'original'
  • styles: []
  • keep_old_files:false
  • preserve_old_files:false

文件系统存储配置

文件系统(本地磁盘)是 LaraClip 的默认存储选项。使用它时,以下配置设置可用:

  • url:文件将存储的 url(相对于您的项目文档根目录)。它由 'interpolations' 组成,在运行时将被它们对应的值替换。它是独一无二的,因为它既是一个配置选项,也是一个插值。
  • path:类似于 url,路径选项是在磁盘上存储文件的位置。应该注意,路径选项不应与 url 选项冲突。LaraClip 提供了合理的默认值,为您处理这个问题。
  • override_file_permissions:覆盖 LaraClip 创建新文件时使用的默认文件权限。将此值留为 null 将导致 LaraClip 使用 chmod 将文件更改权限为 0666。将其设置为特定的八进制值,LaraClip 将相应地进行 chmod。将其设置为 false 以阻止 chmod 发生(适用于非 Unix 环境很有用)。

默认值

  • url:'/system/:class/:attachment/:id_partition/:style/:filename'
  • path:':laravel_root/public:url'
  • override_file_permissions:null

S3 存储配置

随着您的Web应用不断增长,您可能会发现自己需要比本地文件系统提供的更强大的文件存储功能(例如,您正在使用多个服务器实例,需要共享位置来存储/访问上传的文件资产)。LaraClip提供了一个简单的机制,让您可以轻松地使用亚马逊简单存储服务(Amazon S3)存储和检索文件对象。实际上,在与您的附件交互时,除了几个额外的配置设置外,S3存储和文件系统存储之间几乎没有区别。要开始使用S3存储,您首先需要将AWS SDK添加到您的composer.json文件中。

  "require": {
    "laravel/framework": "4.0.*",
    "expstudio/laraclip": "dev-master",
    "aws/aws-sdk-php": "2.4.*@dev"
  }

接下来,将config/laraclip.php中的存储设置从'filesystem'更改为's3'(请注意,如果您只想为特定的附件使用S3,则可以按附件进行此操作)。完成后,打开config/s3.php以查看S3存储设置列表。

  • 路径:这是文件将要存储的存储桶中的键。URL将由存储桶和路径构建而成。您将想要替换的部分。键应该是唯一的,就像文件名一样,尽管S3(严格来说)不支持目录,但您仍然可以使用/来分隔文件名的一部分。
  • 密钥:这是一个由字母数字文本字符串组成的唯一标识符,用于标识账户的所有者。两个账户不能有相同的AWS访问密钥。
  • 秘密:此密钥扮演密码的角色。它被称为秘密,因为它假设只有所有者知道。访问密钥与密码的组合形成了一个安全的信息集,用于确认用户的身份。建议您将您的秘密密钥保存在安全的地方。
  • 存储桶:您希望存储对象的存储桶。Amazon S3中的每个对象都存储在一个存储桶中。如果指定的存储桶不存在,LaraClip将尝试创建它。存储桶名称将不会被替换。
  • ACL:这是一个字符串/数组,应该是S3提供的预定义访问策略之一(私有、公开读取、公开读写、认证读取、存储桶所有者读取、存储桶所有者完全控制)。LaraClip的默认值为公开读取。可以通过关联数组(样式 => 权限)传递以指定基于样式的权限。
  • 方案:生成的S3资产的URL协议。可以是'http'或'https'。当ACL为'公开读取'(默认值)时默认为'http',当ACL为其他任何内容时默认为'https'。
  • 区域:您的存储桶的区域名称(例如,'us-east-1'、'us-west-1'、'us-west-2'、'eu-west-1')。确定存储对象的基础URL(例如,us-west-2区域的基础URL为s3-us-west-2.amazonaws.com)。此字段的默认值为空(US标准 *)。您可以在此处找到更完整的区域列表/解释。

默认值

  • 路径:':attachment/:id/:style/:filename'
  • 密钥: ''
  • 秘密: ''
  • 存储桶: ''
  • ACL:'公开读取'
  • 方案:'http'
  • 区域: ''

插值

使用LaraClip,通过配置/定义指向您上传的文件资产的路径、URL和默认_URL字符串来访问上传的文件。这是通过字符串插值完成的。目前,以下插值可用于使用

  • :attachment - 在hasAttachedFile函数中声明的文件附件名称,例如'avatar'。
  • :class - 包含文件附件的模型的类名,例如User。LaraClip可以处理类的命名空间。
  • :extension - 上传文件的文件扩展类型,例如'.jpg'。
  • :filename - 上传文件的名称,例如'some_file.jpg'。
  • :id - 对应数据库记录的ID,用于上传的文件。
  • :id_partition - 上传文件的对应数据库记录的分区ID,例如id = 1将被插入为000/000/001。这是LaraClip的默认和推荐设置。分区ID有助于克服在基于nix的系统上使用EXT3文件系统时出现的32k子文件夹问题。
  • :hash - 对应数据库记录ID的sha256哈希值。
  • :laravel_root - Laravel项目根目录的路径。
  • :style - 文件的调整大小样式(仅限图片),例如'缩略图'或'原始'。
  • :url - 指向您的上传文件的URL字符串。这种插入实际上是另一个插入。它可以由上述任何插入(除自身外)组成。

图像处理

LaraClip使用imagine图像库进行所有图像处理。开箱即用,当定义LaraClip样式时,将识别以下图像处理模式/指令

  • width:仅定义宽度的样式(横向)。高度将自动选择以保持宽高比。这对于调整适合在移动设备上显示的图像等非常有效。
  • xheight:仅定义高度的样式(纵向)。宽度将自动选择以保持宽高比。
  • widthxheight#:调整大小后裁剪。
  • widthxheight!:精确调整宽度和高度。宽度和高度明确给出,将忽略原始宽高比。
  • widthxheight:在调整大小时自动确定宽度和高度。这将尽可能接近给定的尺寸进行调整,同时仍保持原始宽高比。

要为附件创建样式,只需在附件的样式数组中定义它们(您可以使用任何喜欢的样式名称:foo、bar、baz等),并使用上述定义的指令的组合

'styles' => array(
    'thumbnail' => '50x50',
    'large' => '150x150',
    'landscape' => '150',
    'portrait' => 'portrait' => 'x150',
    'foo' => '75x75',
    'fooCropped' => '75x75#'
)

对于更定制的图像处理,您还可以将可调用类型作为给定样式定义的值。LaraClip将自动注入上传的文件对象实例以及Imagine\Image\ImagineInterface对象实例供您使用。完成处理后,只需从可调用中返回Imagine\Image\ImageInterface的实例。使用可调用来定义样式定义提供了在图像处理方面的大量灵活性。作为一个例子,让我们使用闭包创建一个带水印的图像(我们将使用Imagine进行一些图像处理)

'styles' => array(
   'watermarked' => function($file, $imagine) {
       $watermark = $imagine->open('/path/to/images/watermark.png');   // Create an instance of ImageInterface for the watermark image.
       $image     = $imagine->open($file->getRealPath());              // Create an instance of ImageInterface for the uploaded image.
       $size      = $image->getSize();                                 // Get the size of the uploaded image.
       $watermarkSize = $watermark->getSize();                         // Get the size of the watermark image.
       
       // Calculate the placement of the watermark (we're aiming for the bottom right corner here).
       $bottomRight = new Imagine\Image\Point($size->getWidth() - $watermarkSize->getWidth(), $size->getHeight() - $watermarkSize->getHeight());
       
       // Paste the watermark onto the image.
       $image->paste($watermark, $bottomRight);

       // Return the Imagine\Image\ImageInterface instance.
       return $image;
   }
)

示例

创建一个名为'picture'的附件,具有缩略图(100x100)和大型(300x300)样式,并使用自定义URL和默认URL配置。

public function __construct(array $attributes = array()) {
    $this->hasAttachedFile('picture', array(
        'styles' =>  array(
            'thumbnail' => '100x100',
            'large' => '300x300'
        ),
        'url' => '/system/:attachment/:id_partition/:style/:filename',
        'default_url' => '/:attachment/:style/missing.jpg'
    ));

    parent::__construct($attributes);
}

创建一个名为'picture'的附件,具有缩略图(100x100)和大型(300x300)样式,并使用自定义URL和默认URL配置,将keep_old_files标志设置为true(因此旧文件上传不会被从文件系统中删除)并开启图像裁剪。

public function __construct(array $attributes = array()) {
    $this->hasAttachedFile('picture',  array(
        'styles' =>  array(
            'thumbnail' => '100x100#',
            'large' => '300x300#'
        ),
        'url' => '/system/:attachment/:id_partition/:style/:filename',
        'default_url' => '/:attachment/:style/missing.jpg',
        'keep_old_files' => true
    ));

    parent::__construct($attributes);
}

要将此存储在s3上,您需要设置一些特定的s3配置选项(当使用s3存储时,URL插入将不再必要)

public function __construct(array $attributes = array()) {
    $this->hasAttachedFile('picture',  array(
        'styles' =>  array(
            'thumbnail' => '100x100#',
            'large' => '300x300#'
        ),
        'default_url' => '/:attachment/:style/missing.jpg',
        'storage' => 's3',
        'key' => 'yourPublicKey',
        'secret' => 'yourSecreteKey',
        'bucket' => 'your.s3.bucket',
        'keep_old_files' => true
    ));

    parent::__construct($attributes);
}

LaraClip还使管理多个文件上传变得容易。在laraclip中,附件(以及它们代表的上传文件对象)直接与数据库记录相关联。因此,处理多个文件上传只是定义模型之间的正确Eloquent关系的问题。

以下是如何实现此功能的示例。假设我们有一个系统,其中用户需要拥有多个个人照片(比如3张)。此外,假设用户需要在创建用户表单中上传所有三张照片。为此,我们需要两个表(用户和用户照片),并设置它们的关系,使得照片属于用户,并且一个用户有多个照片。通过这样做,上传的图片可以附加到ProfilePicture模型,而User模型的实例可以通过与ProfilePicture模型的hasMany关系访问上传的文件。下面是这个过程的示例:

在models/user.php

// A user has many profile pictures.
public function profilePictures(){
    return $this->hasMany('ProfilePicture');
}

在models/ProfilePicture.php

public function __construct(array $attributes = array()) {
    // Profile pictures have an attached file (we'll call it photo).
    $this->hasAttachedFile('photo',  array(
        'styles' =>  array(
            'thumbnail' => '100x100#'
        )
    ));

    parent::__construct($attributes);
}

// A profile picture belongs to a user.
public function user(){
    return $this->belongsTo('User');
}

在用户创建视图

<?= Form::open(['url' => '/users', 'method' => 'post', 'files' => true]) ?>
    <?= Form::text('first_name') ?>
    <?= Form::text('last_name') ?>
    <?= Form::file('photos[]') ?>
    <?= Form::file('photos[]') ?>
    <?= Form::file('photos[]') ?>
<?= Form::close() ?>

在controllers/UsersController.php

public function store()
{
    // Create the new user
    $user = new User(Input::get());
    $user->save();

    // Loop through each of the uploaded files:
    // 1. Create a new ProfilePicture instance. 
    // 2. Attach the file to the new instance (laraclip will process it once it's saved).
    // 3. Attach the ProfilePicture instance to the user and save it.
    foreach(Input::file('photos') as $photo)
    {
        $profilePicture = new ProfilePicture();             // (1)
        $profilePicture->photo = $photo;                    // (2)
        $user->profilePictures()->save($profilePicture);    // (3)
    }
}

显示上传的文件也很简单。当处理模型实例时,每个附件都可以作为模型上的属性访问。附件对象提供了访问底层上传文件对象属性、路径和URL的方法。例如,对于名为'photo'的附件,模型将提供path()、url()、createdAt()、contentType()、size()和originalFilename()等方法。以我们上面的示例继续,我们可以遍历用户的个人照片并显示每个上传的文件如下:

// Display a resized thumbnail style image belonging to a user record:
<img src="<?= asset($profilePicture->photo->url('thumbnail')) ?>">

// Display the original image style (unmodified image):
<img src="<?=  asset($profilePicture->photo->url('original')) ?>">

// This also displays the unmodified original image (unless the :default_style interpolation has been set to a different style):
<img src="<?=  asset($profilePicture->photo->url()) ?>">

我们还可以检索上传文件的路径、大小、原始文件名等信息。

$profilePicture->photo->path('thumbnail');
$profilePicture->photo->size();
$profilePicture->photo->originalFilename();

获取远程图片

从LaraClip v1.0.0-Beta4版本开始,可以通过将绝对URL分配给模型上定义的附件属性来获取远程图片。

$profilePicture->photo = "http://foo.com/bar.jpg"; 

当与第三方API(如facebook、twitter等)一起工作时,这非常有用。请注意,此功能要求PHP安装中包含CURL扩展。

高级用法

在处理附件时,可能会有需要执行超出常规工作流程的操作的情况。例如,假设您想要清除一个附件(在底层表记录中清空附件字段并从存储中删除上传的文件),而无需销毁记录本身。如上所述,您可以在保存记录之前始终将附件属性设置为LARACLIP_NULL,但是这只有在保存记录之后才有效。在您希望在不保存记录的情况下从存储中清除上传文件的情况下,您可以使用附件的destroy方法。

// Remove all of the attachment's uploaded files and empty the attacment attributes on the model:
$profilePicture->photo->destroy();

// For finer grained control, you can remove thumbnail files only (attachment attributes in the model will not be emptied).
$profilePicture->photo->destroy(['thumbnail']);

您还可以通过调用reprocess()命令重新处理附件上的上传图片(这对于向已上传记录的现有附件类型添加新样式非常有用)。

// Programmatically reprocess an attachment's uploaded images:
$profilePicture->photo->reprocess();

这也可以通过调用laraclip:refresh命令来实现。

重新处理ProfilePicture模型的全部附件:php artisan laraclip:refresh ProfilePicture

仅重新处理ProfilePicture模型上的照片附件:php artisan laraclip:refresh TestPhoto --attachments="photo"

重新处理ProfilePicture模型上的附件列表:php artisan laraclip:refresh TestPhoto --attachments="foo, bar, baz, etc"