donia-shaker/media-library

Maintainers

Package info

github.com/donia-shaker/media-library

pkg:composer/donia-shaker/media-library

Transparency log

Statistics

Installs: 2 607

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v3.0.5 2026-08-11 15:29 UTC

This package is auto-updated.

Last update: 2026-08-11 15:29:59 UTC


README

This package provides a set of functions for handling media files, including images, audio, video, PDF files, and other documents.

Features

  • Public and Private Storage: Store media in publicly accessible storage or protected private storage.
  • Image Conversion: Convert and store images in multiple formats.
  • Automatic Thumbnail Generation: Automatically generate thumbnails when enabled.
  • Universal File Storage: Store images, documents, PDFs, videos, audio files, and other file types.
  • Soft Delete Support: Restore accidentally deleted media records when needed.
  • Public and Protected URL Generation: Generate direct URLs for public media and signed authenticated URLs for private media.
  • Image Upload Rules: Apply customizable dimensions, size, and format validation rules.
  • Authentication Support: Protect private media using configurable Laravel authentication guards.
  • Frontend Independent: Private media can be consumed from Vue, React, Angular, mobile applications, or any client capable of sending authenticated HTTP requests.

Installation

To install the DoniaShaker\MediaLibrary package, follow these steps.

1. Install the package

composer require donia-shaker/media-library

2. Publish migrations and config

php artisan vendor:publish --tag=media-library-migrations
php artisan vendor:publish --tag=media-library-config

3. Configure the default image format

Edit:

config/media.php

Example:

'default_image_format' => 'webp',

4. Configure environment variables

MEDIA_USE_STORAGE=true
MEDIA_CREATE_THUMBNAILS=true

Private media uses the sanctum authentication guard by default.

If your project uses another authentication guard, such as JWT with an api guard:

MEDIA_PRIVATE_AUTH_GUARD=api

5. Run migrations

php artisan migrate

Usage

Initialization

Import the controller:

use DoniaShaker\MediaLibrary\MediaController;

Create an instance:

$media_controller = new MediaController();

The $format parameter can be null. In this case, the package uses the configured default_image_format.

Save Image

Saves an image, optionally resizes it, controls image quality, and generates a thumbnail when enabled.

$media_controller->saveImage($model, $model_id, $file, $format, $maxWidth, $maxHeight, $quality);

$format, $maxWidth, $maxHeight, and $quality are optional.

Create Temporary Image

Creates a temporary image.

$media_controller->saveTempImage($model, $model_id, $file);

Convert Temporary Image

Converts a temporary image into a normal media file and associates it with a model.

$media_controller->convertTempImage($model, $model_id, $media->id);

Delete Temporary Image

Deletes a temporary image and its media record.

$media_controller->deleteTemp();

Save Audio File

Saves an audio file and associates it with a model.

$media_controller->audio($model, $model_id, $file);

Save Video File

Saves a video file and associates it with a model.

$media_controller->video($model, $model_id, $file);

Save Document File

Saves a document or other uploaded file and associates it with a model.

$media_controller->uploadFile($model, $model_id, $file);

Private Media

Media can be stored as either:

public

or:

private

The default visibility is:

public

Existing package usage therefore remains backward compatible.

Private files are stored outside the publicly accessible storage directory and are served through an authenticated signed route.

To save private media, pass:

'private'

as the visibility parameter.

Save Private Image

$media_controller->saveImage($model, $model_id, $file, $format, $maxWidth, $maxHeight, $quality, 'private');

Example:

$media_controller->saveImage('order', $order->id, $file, null, 1600, 1600, 75, 'private');

Save Private Document

$media_controller->uploadFile($model, $model_id, $file, 'private');

Example:

$media_controller->uploadFile('order_receipt_invoice', $order->id, $file, 'private');

Save Private Audio

$media_controller->audio($model, $model_id, $file, 'private');

Save Private Video

$media_controller->video($model, $model_id, $file, 'private');

Private Media Authentication Guards

Private media authentication is controlled by the configured authentication guards.

By default, the package uses the sanctum guard:

'privateAuthGuards' => env('MEDIA_PRIVATE_AUTH_GUARDS', 'sanctum'),

If the application already uses Sanctum, no additional configuration is required.

Single Guard

For a JWT-based application using the api guard:

MEDIA_PRIVATE_AUTH_GUARDS=api

For another custom guard:

MEDIA_PRIVATE_AUTH_GUARDS=delegate

Multiple Guards

The package also supports multiple authentication guards.

Configure them as a comma-separated list:

MEDIA_PRIVATE_AUTH_GUARDS=sanctum,api,delegate

The package checks the configured guards in order and uses the first guard that has an authenticated user.

Conceptually:

$guards = explode(
    ',',
    config('media.privateAuthGuards', 'sanctum')
);

foreach ($guards as $guard) {
    $user = Auth::guard(trim($guard))->user();

    if ($user) {
        return $user;
    }
}

This allows the same media library to work with applications that have multiple authentication systems, such as:

sanctum
api
admin
delegate

The frontend does not need to know which guard is being used.

The frontend only needs to send the authentication credentials required by the application, such as a Bearer token or the configured authentication mechanism.

The package handles guard resolution internally.

Private Media URL

Private media URLs are generated automatically from the url attribute.

$media->url;

Example response:

https://example.com/api/media/private/10?auth_id=1&signature=...

The package automatically generates:

  • Media ID
  • Authenticated user ID
  • Signed URL signature

The application should not manually create or modify auth_id or signature.

For example:

'image' => $media->url,

may return:

{
    "image": "https://example.com/api/media/private/10?auth_id=1&signature=..."
}

The signed URL is bound to the authenticated user for whom it was generated.

When the private media endpoint is requested, the package verifies:

  1. The signed URL is valid.
  2. The media record is private.
  3. The request contains a valid authenticated user.
  4. The authenticated user's ID matches the signed auth_id.
  5. The physical private file exists.

If any verification fails, the endpoint returns:

404 Not Found

Access Private Media From Frontend

Bearer Token Authentication

When using JWT, Sanctum API tokens, or another Bearer Token authentication system, private media must be requested with:

Authorization: Bearer YOUR_TOKEN

Do not directly use the private URL like this with JWT:

<img src="PRIVATE_MEDIA_URL">

A normal <img> request does not automatically attach a Bearer Token.

Instead, request the private URL through an authenticated HTTP request.

JavaScript Fetch

const response = await fetch(media.url, { headers: { Authorization: `Bearer ${token}` } });

Convert the response to a Blob:

const blob = await response.blob();

Create a browser URL:

const imageUrl = URL.createObjectURL(blob);

Display it:

<img src="BLOB_URL">

Complete example:

const response = await fetch(media.url, { headers: { Authorization: `Bearer ${token}` } });
const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);

Vue

const response = await fetch(media.url, { headers: { Authorization: `Bearer ${token}` } });
const blob = await response.blob();
imageUrl.value = URL.createObjectURL(blob);

Then:

<img :src="imageUrl">

React

const response = await fetch(media.url, { headers: { Authorization: `Bearer ${token}` } });
const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);

Then:

<img src={imageUrl} alt="" />

Axios

const response = await axios.get(media.url, { headers: { Authorization: `Bearer ${token}` }, responseType: 'blob' });

Then:

const imageUrl = URL.createObjectURL(response.data);

Authenticated API Client

If the application already has an HTTP client that automatically sends the authentication token, the token does not need to be manually added again.

Example:

const blob = await $api(media.url, { responseType: "blob" });

Then:

const imageUrl = URL.createObjectURL(blob);

The important requirement is that the request reaching the private media endpoint contains the application's authentication credentials.

For JWT or Bearer Token authentication, the request must contain:

Authorization: Bearer YOUR_TOKEN

Private Thumbnail

Private thumbnails are also returned as protected signed URLs.

Example:

$media->thumb_url;

A private thumbnail may return:

https://example.com/api/media/private/10?auth_id=1&thumb=1&signature=...

It should be requested using the same authenticated process as the original private media file.

Example:

const response = await fetch(media.thumb_url, { headers: { Authorization: `Bearer ${token}` } });
const blob = await response.blob();
const thumbnailUrl = URL.createObjectURL(blob);

Public vs Private Media

Public Media

Public media can be displayed directly.

<img :src="media.url">

Example URL:

https://example.com/storage/media/images/order/10-image.webp

No authenticated media request is required.

Private Media

Private media is accessed through a protected API endpoint.

media.url
    ↓
Authenticated HTTP Request
    ↓
Authorization: Bearer TOKEN
    ↓
Signed URL Validation
    ↓
User Authentication
    ↓
User Identity Validation
    ↓
Private File
    ↓
Blob
    ↓
<img>

In short:

Public  -> Use media.url directly
Private -> Request media.url with authentication

Media Object

Explanation of the media object properties:

  • id: The unique identifier of the media object.
  • model: The model associated with the media object.
  • format: The file format.
  • model_id: The ID of the associated model.
  • order: The order of the media object when a model has multiple media files.
  • file_name: The unique file name.
  • has_thumb: Indicates whether a thumbnail exists.
  • is_active: Indicates whether the media is active.
  • is_temp: Indicates whether the media is temporary.
  • visibility: Defines whether the media is public or private.
  • deleted_at: The media deletion timestamp.
  • created_at: The media creation timestamp.
  • updated_at: The media last update timestamp.
  • url: Public URL for public media or signed authenticated URL for private media.
  • thumb_url: Public thumbnail URL or protected signed thumbnail URL when available.

Example:

{
    "id": 10,
    "model": "order",
    "model_id": 500,
    "format": "webp",
    "visibility": "private",
    "url": "https://example.com/api/media/private/10?auth_id=1&signature=...",
    "thumb_url": "https://example.com/api/media/private/10?auth_id=1&thumb=1&signature=..."
}

Rules

Square Image

Use SquareImageRule to validate that an uploaded image is square.

use DoniaShaker\MediaLibrary\Rules\SquareImageRule;

Usage:

'file' => [..., new SquareImageRule],

Troubleshooting and Collaboration

If you encounter any issues or have suggestions, please feel free to open an issue on GitHub.