Exfile
File upload persistence and processing for Phoenix / Plug, with a focus on flexibility and extendability.
Inspired heavily by Refile. If you use Ruby, check Refile out. I like it. ๐
Requires Elixir ~> 1.2.0
. At this point, it is only tested against the most
recent version of Elixir.
Exfile is used in a production environment at this point, but it still may go through some breaking changes. Exfile aims to adheres to semver v2.0.
Storage Adapters
Exfile supports storage backend adapters. A local filesystem based
adapter is included (Exfile.Backend.FileSystem
) as an example.
- exfile-b2 โ storage adapter for the Backblaze B2 cloud storage service.
File Processors
Exfile also supports file processors / filters. If youโre working with
images, exfile-imagemagick
is recommended.
- exfile-imagemagick โ uses ImageMagick to resize, crop, and transform images.
- exfile-encryption โ encrypts files before uploading them and decrypts them after downloading them from the backend.
Usage Overview
Exfile applies transforms on the fly; it only stores the original file in the storage backend. It is expected to be behind a caching HTTP proxy and/or a caching CDN for performance. Because dimensions and processors are determined by the path, it is authenticated with a HMAC to make sure it is not tampered with.
The Phoenix integration comes with two helper functions, exfile_url
and
exfile_path
.
For example, the following code will return a path to the user
โs profile_picture
that is converted to JPEG (if not already in JPEG format) and limited to 1024 ร 1024.
exfile_url(@conn, @user.profile_picture, format: "jpg", processor: "limit", processor_args: [1024, 1024])
For more information about what processors are available for images, check out exfile-imagemagick.
Installation
Add exfile to your list of dependencies in
mix.exs
:def deps do [{:exfile, "~> 0.3.2"}] end ```
Ensure exfile is started before your application:
def application do [applications: [:exfile]] end ```
- Mount the Exfile routes in your router.
Phoenix
defmodule MyApp.Router do
use MyApp.Web, :router
foward "/attachments", Exfile.Router
...
To use the exfile_path
and exfile_url
helpers, include the
Exfile.Phoenix.Helpers
module where you need it (probably in the view
section of your web/web.ex
file).
Phoenix uses Plug.Parsers
with a 8 MB limit by default โ this affects Exfile
too. To increase it, find Plug.Parsers
in MyApp.Endpoint
and add the length
option:
defmodule MyApp.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
plug Plug.Parsers,
...
length: 25_000_000 # bytes; any value you deem necessary
end
Plug
defmodule MyApp.Router do
use Plug.Router
forward "/attachments", to: Exfile.Router
...
Ecto Integration
The following example will upload a file to the backend configured as โstoreโ.
If you want to upload files to an alternate backend, please take a look at
Exfile.Ecto.File
and Exfile.Ecto.FileTemplate
for instructions on making
a custom Ecto.Type
for your needs.
defmodule MyApp.User do
use Ecto.Schema
schema "users" do
field :profile_picture, Exfile.Ecto.File
end
end
defmodule MyApp.Repo.Migrations.AddProfilePictureToUsers do
use Ecto.Migration
def change do
alter table(:users) do
add :profile_picture, :string
end
end
end
Configuration
In config.exs
:
config :exfile, Exfile,
secret: "secret string to generate the token used to authenticate requests",
backends: %{
"store" => configuration for the default persistent store
"cache" => configuration for an ephemeral store holding temporarily uploaded content
}
See Exfile.Config
for defaults.