定制 escolalms/images 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

escolalms/images

Composer 安装命令:

composer require escolalms/images

包简介

Escola Headless LMS Images manipulation

README 文档

README

swagger codecov phpunit downloads downloads downloads Maintainability Test Coverage

What does it do

The package creates resized images from source by given parameters. This is a headless approach so the backend doesn't know the requested sizes before frontend requests any.

The input images are stored by Laravel in any of available disk (local storage/s3/any bucket). Once a resized version is requested a cached version in created and returend. Below are examples to show the overall idea.

The initial resize is done by Intervention/image with GD driver. That can be configured.

After inital resized all the images are optimized with image-optimizer.

For best results binaries must be installed. EscolaLMS prepared Docker Images are available for development (tag work) and production (tag prod).

Installation

  • composer require escolalms/images
  • php artisan migrate

Database

  • image_caches - table for saving the original and resized image path
id path hash_path created_at updated_at
1 avatars/1/avatar.jpg imgcache/68840270724ee4ff0b481f4fbd2299e13dfe2447.jpg 2022-05-05 11:29:04 2022-05-05 11:29:04
3 avatars/4/avatar4.jpg imgcache/d0f1ab43ae7f2924682b2ce734a24fa7066a8ea7.jpg 2022-05-05 11:30:49 2022-05-05 11:30:49
2 avatars/2/avatar2.jpg imgcache/94c6c83db6562161d38620a74e4e07fb3d9e39ed.jpg 2022-05-05 11:30:39 2022-05-05 11:30:39

Examples

Default. One image as 302 redirect result .

Basic resize is made by URL API call which redirects to new created file

Example GET call

  • http://localhost/api/images/img?path=test.jpg&w=100 call should return resized image to width 100px
  • checks if file exsitis
  • if not, creates one with availabe libraries
  • returns 302 redirect
  • example http://localhost/storage/imgcache/891ee133a8bb111497d494d4c91fe292d9d16bb3.jpg (assuming you're using local disk storage, in case of s3 location origin would differ)

Resizing many images at once. JSON array as a result.

Example POST call like

POST /api/images/img HTTP/1.1
Host: localhost:1000
Content-Type: application/json
Content-Length: 212

{
  "paths": [{
    "path": "tutor_avatar.jpg",
    "params": {
      "w": 100
    }
  }, {
    "path": "tutor_avatar.jpg",
    "params": {
      "w": 200
    }
  }, {
    "path": "tutor_avatar.jpg",
    "params": {
      "w": 300
    }
  }]
} 

generates following result

[
  {
    "url": "http://localhost/storage/imgcache/3421584c40d270d0fa7ef0c31445a1565db07cb4.jpg",
    "path": "imgcache/3421584c40d270d0fa7ef0c31445a1565db07cb4.jpg",
    "hash": "3421584c40d270d0fa7ef0c31445a1565db07cb4"
  },
  {
    "url": "http://localhost/storage/imgcache/7efc528c2cc7b57d79a42f80d2c1891b517cabfe.jpg",
    "path": "imgcache/7efc528c2cc7b57d79a42f80d2c1891b517cabfe.jpg",
    "hash": "7efc528c2cc7b57d79a42f80d2c1891b517cabfe"
  },
  {
    "url": "http://localhost/storage/imgcache/5db4f572d8c8b1cb6ad97a3bffc9fd6c18b56cc3.jpg",
    "path": "imgcache/5db4f572d8c8b1cb6ad97a3bffc9fd6c18b56cc3.jpg",
    "hash": "5db4f572d8c8b1cb6ad97a3bffc9fd6c18b56cc3"
  }
] 

Hashing algorithm

There is simple algorithm to guess the result image URL. This allows frontend application to know the processed URL without calling API. As follows

$path = 'test.jpg';
$params = ['w'=>100];

$hash = sha1($path.json_encode($params));

then result URL would be

$output_file = $url_prefix.$hash.$extension;

Endpoint

There is API endpoints documentation swagger

Tests

Run ./vendor/bin/phpunit to run tests.

Test details codecov phpunit

Events

This package extends filesystem.

$this->app->extend('filesystem', function ($service, $app) {
    return new CustomFilesystemManager($app);
});
  1. FileDeleted - The event is dispatched when you use delete method on the Storage facade.
  2. FileStored - The event is dispatched when you use put, putFile or putFileAs method.

Listeners

This package listens for FileDeleted and FileStored events and removes the resized images from the given path.

How to use this on frontend

Below is our totally headless approach on generating images

The following example tries to achives 2 purposes

  • generate image on fly, frontend decide what sizes are needed
  • images are not served by API

The idea is that since we know tha hashing algoritm for cached images we can guess that the URL will be like. If that URL is throwing 404 then we're calling the API endpoint to generate one. Fortunately this endpoint creates an requested image, caches it and returns redirect which is good for image src.

A major disadvantage of this approach is that first user once will get 404 in networking and experince few seconds delay before image is rendered after not founded.

<script type="text/javascript" src="sha1.js"></script>
<script>
  // Initial variables 
  const imgPath = "tutor_avatar.jpg";
  const imgPrefix = "http://localhost/storage/imgcache";
  const apiUrl = "http://localhost/api/images/img";
  const rndWith = Math.round(Math.random() * 1000);
  const params = { w: rndWith.toString() }; // random width params
  // super important that all param values are strings 
  // hash from { w: 100 } is different then { w: "100" }
			
  // stright forward helper to convert obejct to URL query params 
  const paramsToUrl = (params) =>
    Object.entries(params)
      .map((e) => e.join("="))
      .join("&");

  /** 
   * @param string path, example "tutor_avatar.jpg"
   * @param array params, example { w: "100" } or { w: "100", h: "10" }
   * @return Image 
   */ 
  const getImage = (path, params) => {
    const hash = SHA1(path + JSON.stringify(params));
    const url = `${imgPrefix}/${hash}.${path.split(".").pop()}`;
    const imgApiUrl = `${apiUrl}/?path=${imgPath}&${paramsToUrl(params)}`;
    const image = new Image();
    image.src = url;
    image.onerror = () => {
      if (image.src != imgApiUrl) {
        // the cached version does not exists yet, lets call API to create one and redirect.
        image.src = imgApiUrl;
      }
    };

    return image;
  };

  document.body.appendChild(getImage(imgPath, params));
</script> 

Working example is availabe in doc folder.

escolalms/images 适用场景与选型建议

escolalms/images 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 14.02k 次下载、GitHub Stars 达 1, 最近一次更新时间为 2021 年 07 月 30 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 escolalms/images 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 escolalms/images 我们能提供哪些服务?
定制开发 / 二次开发

基于 escolalms/images 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 14.02k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 0
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 2
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2021-07-30