{"id":22125728,"url":"https://github.com/czim/laravel-paperclip","last_synced_at":"2025-04-09T06:09:57.821Z","repository":{"id":45660166,"uuid":"99704786","full_name":"czim/laravel-paperclip","owner":"czim","description":"Laravel file attachment solution for Eloquent","archived":false,"fork":false,"pushed_at":"2024-09-18T11:01:19.000Z","size":329,"stargazers_count":79,"open_issues_count":13,"forks_count":17,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-02T02:06:08.695Z","etag":null,"topics":["attachment","eloquent-models","file-uploads","laravel","resize-images"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/czim.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-08T14:56:37.000Z","updated_at":"2025-03-18T04:33:47.000Z","dependencies_parsed_at":"2023-11-16T13:45:00.893Z","dependency_job_id":"911cccae-d5a3-46ec-ac9c-c90124d9b5f8","html_url":"https://github.com/czim/laravel-paperclip","commit_stats":{"total_commits":226,"total_committers":17,"mean_commits":"13.294117647058824","dds":0.4336283185840708,"last_synced_commit":"5793ae9b11ca9d50298a9303ad6903a3d6b27edc"},"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czim%2Flaravel-paperclip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czim%2Flaravel-paperclip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czim%2Flaravel-paperclip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czim%2Flaravel-paperclip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/czim","download_url":"https://codeload.github.com/czim/laravel-paperclip/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247987285,"owners_count":21028895,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attachment","eloquent-models","file-uploads","laravel","resize-images"],"created_at":"2024-12-01T16:37:47.283Z","updated_at":"2025-04-09T06:09:57.806Z","avatar_url":"https://github.com/czim.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Software License][ico-license]](LICENSE.md)\n[![Build Status](https://travis-ci.com/czim/laravel-paperclip.svg?branch=master)](https://travis-ci.com/czim/laravel-paperclip)\n[![Coverage Status](https://coveralls.io/repos/github/czim/laravel-paperclip/badge.svg?branch=master)](https://coveralls.io/github/czim/laravel-paperclip?branch=master)\n\n# Laravel Paperclip: File Attachment Solution\n\nAllows you to attach files to Eloquent models.\n\nThis is a re-take on [CodeSleeve's Stapler](https://github.com/CodeSleeve/stapler).\nIt is mainly intended to be more reusable and easier to adapt to different Laravel versions.\nDespite the name, this should not be considered a match for Ruby's Paperclip gem.\n\nInstead of tackling file storage itself, it uses Laravel's internal storage drivers and configuration.\n\nThis uses [czim/file-handling](https://github.com/czim/file-handling) under the hood,\nand any of its (and your custom written) variant manipulations may be used with this package.\n\n\n## Version Compatibility\n\n| Laravel       | Package  | PHP Version   |\n|:--------------|:---------|:--------------|\n| 5.4 and below | 1.0, 2.1 | 7.4 and below |\n| 5.5           | 1.5, 2.5 | 7.4 and below |\n| 5.6, 5.7      | 2.6      | 7.4 and below |\n| 5.8, 6        | 2.7      | 7.4 and below |\n| 7, 8          | 3.2      | 7.4 and below |\n| 7, 8, 9       | 4.0      | 8.0 and up    |\n| 9 and up      | 5.0      | 8.1 and up    |\n\n\n## Change log\n\n[View the changelog](CHANGELOG.md).\n\n\n## Installation\n\nVia Composer:\n\n``` bash\n$ composer require czim/laravel-paperclip\n```\n\nAuto-discover may be used to register the service provider automatically.\nOtherwise, you can manually register the service provider in `config/app.php`:\n\n```php\n\u003c?php\n   'providers' =\u003e [\n        ...\n        Czim\\Paperclip\\Providers\\PaperclipServiceProvider::class,\n        ...\n   ],\n```\n\nPublish the configuration file:\n\n``` bash\nphp artisan vendor:publish --provider=\"Czim\\Paperclip\\Providers\\PaperclipServiceProvider\"\n```\n\n\n## Set up and Configuration\n\n### Model Preparation\n\nModify the database to add some columns for the model that will get an attachment.\nUse the attachment key name as a prefix.\n\nAn example migration:\n\n```php\n\u003c?php\n    Schema::create('your_models_table', function (Blueprint $table) {\n        $table-\u003estring('attachmentname_file_name')-\u003enullable();\n        $table-\u003einteger('attachmentname_file_size')-\u003enullable();\n        $table-\u003estring('attachmentname_content_type')-\u003enullable();\n        $table-\u003etimestamp('attachmentname_updated_at')-\u003enullable();\n    });\n```\n\nReplace `attachmentname` here with the name of the attachment.\nThese attributes should be familiar if you've used Stapler before.\n\nA `\u003ckey\u003e_variants` text or varchar column is optional:\n\n```php\n\u003c?php\n    $table-\u003estring('attachmentname_variants', 255)-\u003enullable();\n```\n\nA `text()` column is recommended in cases where a seriously *huge* amount of variants are created.\n\nIf it is added and configured to be used (more on that [in the config section](CONFIG.md)),\nJSON information about variants will be stored in it.\n\n\n### Attachment Configuration\n\nTo add an attachment to a model:\n\n- Make it implement `Czim\\Paperclip\\Contracts\\AttachableInterface`.\n- Make it use the `Czim\\Paperclip\\Model\\PaperclipTrait`.\n- Configure attachments in the constructor (very similar to Stapler)\n\n```php\n\u003c?php\nclass Comment extends Model implements \\Czim\\Paperclip\\Contracts\\AttachableInterface\n{\n    use \\Czim\\Paperclip\\Model\\PaperclipTrait;\n\n    public function __construct(array $attributes = [])\n    {\n        $this-\u003ehasAttachedFile('image', [\n            'variants' =\u003e [\n                'medium' =\u003e [\n                    'auto-orient' =\u003e [],\n                    'resize'      =\u003e ['dimensions' =\u003e '300x300'],\n                ],\n                'thumb' =\u003e '100x100',\n            ],\n            'attributes' =\u003e [\n                'variants' =\u003e true,\n            ],\n        ]);\n\n        parent::__construct($attributes);\n    }\n}\n```\n\nNote: If you perform the `hasAttachedFile()` call(s) *after* the `parent::__construct()` call,\neverything will work the same, except that you cannot assign an image directly when creating a model.\n`ModelClass::create(['attachment' =\u003e ...])` will not work in that case.\n\n\nSince version `2.5.7` it is also possible to use an easier to use fluent object syntax for defining variant steps:\n\n```php\n\u003c?php\n    use \\Czim\\Paperclip\\Config\\Variant;\n    use \\Czim\\Paperclip\\Config\\Steps\\AutoOrientStep;\n    use \\Czim\\Paperclip\\Config\\Steps\\ResizeStep;\n\n    // ...\n\n    $this-\u003ehasAttachedFile('image', [\n        'variants' =\u003e [\n            Variant::make('medium')-\u003esteps([\n                AutoOrientStep::make(),\n                ResizeStep::make()-\u003ewidth(300)-\u003eheight(150)-\u003ecrop(),\n            ]),\n            Variant::make('medium')-\u003esteps(ResizeStep::make()-\u003esquare(100)),\n        ],\n    ]);\n```\n\n\n### Variant Configuration\n\nFor the most part, the configuration of variants is nearly identical to Stapler,\nso it should be easy to make the transition either way.\n\nSince version `2.6`, Stapler configuration support is disabled by default, but legacy support for this\nmay be enabled by setting the `paperclip.config.mode` to `'stapler'`.\n\n[Get more information on configuration here](CONFIG.md).\n\n\n#### Custom Variants\n\nThe file handler comes with a few common variant strategies, including resizing images and taking screenshots from videos.\nIt is easy, however, to add your own custom strategies to manipulate files in any way required.\n\nVariant processing is handled by [the file-handler package](https://github.com/czim/file-handling).\nCheck out its source to get started writing custom variant strategies.\n\n\n### Storage configuration\n\nYou can configure a storage location for uploaded files by setting up a Laravel storage (in `config/filesystems.php`),\nand registering it in the `config/paperclip.php` config file.\n\nMake sure that `paperclip.storage.base-urls.\u003cyour storage disk\u003e` is set, so valid URLs to stored content are returned.\n\n### Hooks Before and After Processing\n\nIt is possible to 'hook' into the paperclip goings on when files are processed. This may be done by using the\n`before` and/or `after` configuration keys. Before hooks are called after the file is uploaded and stored locally,\nbut before variants are processed; after hooks are called when all variants have been processed.\n\nMore information and examples are in [the Config section](CONFIG.md).\n\n### Events\n\nThe following events are available:\n\n* `AttachmentSavedEvent`: dispatched when any attachment is saved with a file\n\n### Refreshing models\n\nWhen changing variant configurations for models, you may reprocess variants from previously created attachments with the `paperclip:refresh` Artisan command.\n\nExample:\n\n```bash\nphp artisan paperclip:refresh \"App\\Models\\BlogPost\" --attachments header,background\n```\n\n\n## Usage\n\nOnce a model is set up and configured for an attachment, you can simply set the attachment attribute on that model to create an attachment.\n\n```php\n\u003c?php\npublic function someControllerAction(Request $request) {\n\n    $model = ModelWithAttachment::first();\n\n    // You can set any UploadedFile instance from a request on\n    // the attribute you configured a Paperclipped model for.\n    $model-\u003eattachmentname = $request-\u003efile('uploaded');\n\n    // Saving the model will then process and store the attachment.\n    $model-\u003esave();\n\n    // ...\n}\n```\n\n\n### Setting attachments without uploads\n\nUsually, you will want to set an uploaded file as an attachment. If you want to store a file from within your application,\nwithout the context of a request or a file upload, you can use the following approach:\n\n```php\n\u003c?php\n// You can use the built in SplFileInfo class:\n$model-\u003eattachmentname = new \\SplFileInfo('local/path/to.file');\n\n\n// Or a file-handler class that allows you to override values:\n$file = new \\Czim\\FileHandling\\Storage\\File\\SplFileInfoStorableFile();\n$file-\u003esetData(new \\SplFileInfo('local/path/to.file'));\n// Optional, will be derived from the file normally\n$file-\u003esetMimeType('image/jpeg');\n// Optional, the file's current name will be used normally\n$file-\u003esetName('original-file-name.jpg');\n$model-\u003eattachmentname = $file;\n\n\n// Or even a class representing raw content\n$raw = new \\Czim\\FileHandling\\Storage\\File\\RawStorableFile();\n$raw-\u003esetData('... string with raw content of file ...');\n$raw-\u003esetMimeType('image/jpeg');\n$raw-\u003esetName('original-file-name.jpg');\n$model-\u003eattachmentname = $raw;\n```\n\n\n### Clearing attachments\n\nIn order to prevent accidental deletion, setting the attachment to `null` will *not* destroy a previously stored attachment.\nInstead you have to explicitly destroy it.\n\n```php\n\u003c?php\n// You can set a special string value, the deletion hash, like so:\n$model-\u003eattachmentname = \\Czim\\Paperclip\\Attachment\\Attachment::NULL_ATTACHMENT;\n// In version 2.5.5 and up, this value is configurable and available in the config:\n$model-\u003eattachmentname = config('paperclip.delete-hash');\n\n// You can also directly clear the attachment by flagging it for deletion:\n$model-\u003eattachmentname-\u003esetToBeDeleted();\n\n\n// After any of these approaches, saving the model will make the deletion take effect.\n$model-\u003esave();\n```\n\n\n## Differences with Stapler\n\n- Paperclip does not handle (s3) storage internally, as Stapler did.\nAll storage is performed through Laravel's storage solution.\nYou can still use S3 (or any other storage disk), but you will have to configure it in Laravel's storage configuration first.\nIt is possible to use different storage disks for different attachments.\n\n- Paperclip *might* show slightly different behavior when storing a `string` value on the attachment attribute.\nIt will attempt to interpret the string as a URI (or a dataURI), and otherwise treat the string as raw text file content.\n\nIf you wish to force storing the contents of a URL without letting Paperclip interpret it, you have some options.\nYou can use the `Czim\\FileHandling\\Storage\\File\\StorableFileFactory@makeFromUrl` method and its return value.\nOr, you can download the contents yourself and store them in a `Czim\\FileHandling\\Storage\\File\\RawStorableFile`\n(e.g.: `(new RawStorableFile)-\u003esetData(file_get_contents('your-URL-here'))`).\nYou can also download the file to local disk, and store it on the model through an `\\SplFileInfo` instance (see examples on the main readme page).\n\n- The `convert_options` configuration settings are no longer available.\nConversion options are now handled at the level of the variant strategies.\nYou can set them per attachment configuration, or modify the variant strategy to use a custom global configuration.\n\n- The refresh command (`php artisan paperclip:refresh`) is very similar to stapler's refresh command,\n- but it can optionally take a `--start #` and/or `--stop #` option, with ID numbers.\nThis makes it possible to refresh only a subset of models.\nUnder the hood, the refresh command is also much less likely to run out of memory (it uses a generator to process models in chunks).\n\n- The Paperclip trait uses its own Eloquent boot method, not the global Model's `boot()`.\n This makes Paperclip less likely to conflict with other traits and model implementations.\n\n\n## Amazon S3 cache-control\n\nIf you use Amazon S3 as storage disk for your attachments, note that you can set `Cache-Control` headers in the options for the `filesystems.disks.s3` configuration key.\nFor example, to set `max-age` headers on all uploaded files to S3, edit `config/filesystems.php` like so:\n\n```\n's3' =\u003e [\n    'driver' =\u003e env('S3_DRIVER', 's3'),\n    'key'    =\u003e env('S3_KEY', 'your-key'),\n    'secret' =\u003e env('S3_SECRET', 'your-secret'),\n    'region' =\u003e env('S3_REGION', 'your-region'),\n    'bucket' =\u003e env('S3_BUCKET', 'your-bucket'),\n    'visibility' =\u003e 'public',\n    'options' =\u003e [\n        'CacheControl' =\u003e 'max-age=315360000, no-transform, public',\n    ],\n],\n```\n\n## Upgrade Guide\n\n### Upgrading from 1.5.* to 2.5.*\n\n**Estimated Upgrade Time: 5 - 10 Minutes**\n\n### Updating Dependencies\n\nUpdate your `czim/laravel-paperclip` dependency to `^2.5` in your `composer.json` file.\n\n```\n\t\"require\": {\n\t\t...\n\t\t\"czim/laravel-paperclip\": \"^2.5\",\n\t\t...\n\t}\n```\n\nThen, in your terminal run:\n\n```\ncomposer update czim/laravel-paperclip --with-dependencies\n```\n\nIn addition, if you are using the `czim/file-handling` package directly, you should upgrade the package\nto its `^1,0` release, but be sure to checkout the [CHANGELOG](https://github.com/czim/file-handling/blob/master/CHANGELOG.md)\n\n```\n\t\"require\": {\n\t\t...\n\t\t\"czim/file-handling\": \"^1.0\",\n\t\t...\n\t}\n```\n\n### Update Configuration\n\nUpdate your `config/paperclip.php` file and replace:\n\n```\n        // The base path that the interpolator should use\n        'base-path' =\u003e ':class/:id_partition/:attribute',\n```\n\nWith:\n\n```\n        // The path to the original file to be interpolated. This will also\\\n        // be used for variant paths if the variant key is unset.\n        'original' =\u003e ':class/:id_partition/:attribute/:variant/:filename',\n\n        // If the structure for variant filenames should differ from the\n        // original, it may be defined here.\n        'variant'  =\u003e null,\n```\n\nThis should now include placeholders to make a full file path including the filename, as opposed to only a directory.\nNote that this makes the path interpolation logic more in line with the way Stapler handled it.\n\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n\n## Credits\n\n- [All Contributors][link-contributors]\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n\n[ico-version]: https://img.shields.io/packagist/v/czim/laravel-paperclip.svg?style=flat-square\n[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square\n[ico-downloads]: https://img.shields.io/packagist/dt/czim/laravel-paperclip.svg?style=flat-square\n\n[link-packagist]: https://packagist.org/packages/czim/laravel-paperclip\n[link-downloads]: https://packagist.org/packages/czim/laravel-paperclip\n[link-author]: https://github.com/czim\n[link-contributors]: ../../contributors\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczim%2Flaravel-paperclip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fczim%2Flaravel-paperclip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczim%2Flaravel-paperclip/lists"}