| Current Path : /home/eolienneia/www/templates/yootheme/vendor/yootheme/image/src/ |
| Current File : /home/eolienneia/www/templates/yootheme/vendor/yootheme/image/src/ImageProvider.php |
<?php
namespace YOOtheme;
class ImageProvider
{
const IMAGE = '/<(?:div|img)\s+[^>]*?(\w+-)?src=((["\'])[^\'"]+?\.(?:gif|png|jpe?g|webp)#[^\'"]+?\3)[^>]*>/i';
/**
* @var string
*/
public $cache;
/**
* @var string
*/
public $route;
/**
* @var string
*/
protected $secret;
/**
* @var array
*/
protected $params = [];
/**
* @var array
*/
protected $loaders = [];
/**
* Constructor.
*
* @param string $cache
* @param array $config
*/
public function __construct($cache, array $config = [])
{
$this->cache = Path::resolve($cache);
$this->route = isset($config['route']) ? $config['route'] : '@image';
$this->secret = isset($config['secret']) ? $config['secret'] : filemtime(__FILE__);
$this->params = isset($config['params']) ? $config['params'] : [];
}
/**
* Adds a loader callback.
*
* @param callable $loader
*
* @return static
*/
public function addLoader(callable $loader)
{
$this->loaders[] = $loader;
return $this;
}
/**
* Creates an image tag from src attribute's relative URL.
*
* @param string $src
* @param bool $resource
*
* @return Image|void
*/
public function create($src, $resource = true)
{
list($file, $params) = $this->parse($src);
if (Path::isAbsolute($file) || str_ends_with(strtolower($file), '.svg')) {
return;
}
$image = new Image($file, $resource);
$image->setAttribute('src', $src);
if ($image->getFile()) {
$image = $image->setAttribute('params', $params);
foreach ($this->loaders as $loader) {
$image = $loader($image, $this) ?: $image;
}
return $image;
}
}
/**
* Parse image url.
*
* @param string $url
*
* @return array
*/
public function parse($url)
{
$url = urldecode($url);
$file = parse_url($url, PHP_URL_PATH);
$data = parse_url($url, PHP_URL_FRAGMENT) ?: '';
// replace params
if ($this->params) {
$data = strtr($data, $this->params);
}
// parse params
parse_str($data, $params);
return [$file, $params];
}
/**
* Replace images in HTML.
*
* @param string $text
*
* @return string
*/
public function replace($text)
{
if (stripos($text, '<div') !== false || stripos($text, '<img') !== false) {
return preg_replace_callback(static::IMAGE, [$this, 'replaceCallback'], $text);
}
return $text;
}
/**
* Replace image callback.
*
* @param array $matches
*
* @return string
*/
public function replaceCallback($matches)
{
list($tag, $prefix, $source) = $matches;
$src = html_entity_decode(trim($source, "\"'"));
if ($image = $this->create($src, false)) {
$attrs = $this->getSrcsetAttrs($image, $prefix);
$srcAttr = "{$prefix}src";
$params = $image->getAttribute('params');
$image = $image->apply($params);
// set prefix for width/height
if (!$prefix && isset($attrs["{$prefix}srcset"])) {
$prefix = 'data-';
}
// set image width
if (!stripos($tag, 'width=')) {
$attrs["{$prefix}width"] = $image->width;
}
// set image height
if (!stripos($tag, 'height=')) {
$attrs["{$prefix}height"] = $image->height;
}
// format image attrs
$attributes = [];
foreach ($attrs as $key => $value) {
$attributes[] = sprintf(
$key != $srcAttr ? '%1$s="%2$s"' : '"%2$s"',
$key,
htmlspecialchars($value)
);
}
return str_replace($source, join(' ', $attributes), $tag);
}
return $tag;
}
/**
* Gets the image hash.
*
* @param string $data
*
* @return string
*/
public function getHash($data)
{
return hash_hmac('md5', $data, $this->secret);
}
/**
* Gets the image URL.
*
* @param string|Image $image
*
* @return string|null
*/
public function getUrl($image)
{
if (is_string($image)) {
if (!($image = $this->create($src = $image, false))) {
return Url::to($src);
}
$image = $image->apply($image->getAttribute('params'));
}
$cached = $image->getHash() ? $image->getFilename($this->cache) : null;
// url to source or cached image
if (
is_null($cached) ||
(file_exists($cached) &&
(($ctime = filectime($cached)) > filectime($image->getFile()) ||
$ctime > filemtime($image->getFile())))
) {
return Url::to($cached ?: $image->getFile());
}
return Url::route($this->route, [
'src' => ($src = base64_encode($image)),
'hash' => $this->getHash($src),
]);
}
/**
* Gets the image source set.
*
* @param Image $image
*
* @return array
*/
public function getSrcset($image)
{
$params = $image->getAttribute('params');
if (!isset($params['srcset'])) {
return [];
}
$imageDst = $image->apply($params);
$maxWidth = min(max($image->width, $imageDst->width), $imageDst->width * 2);
$maxHeight = min(max($image->height, $imageDst->height), $imageDst->height * 2);
foreach (explode(',', $params['srcset']) as $value) {
$resized = $image->apply($params)->resize($value);
// if oversized, use original image sizes
if (1 < ($scale = max($resized->width / $maxWidth, $resized->height / $maxHeight))) {
$sizes = [round($resized->width / $scale), round($resized->height / $scale)];
} else {
$sizes = [$resized->width, $resized->height];
}
// set image parameters
foreach (['crop', 'resize', 'thumbnail'] as $key) {
if (isset($params[$key]) && ($param = explode(',', $params[$key]))) {
$resized = $image->apply(array_merge($params, [$key => $sizes + $param]));
}
}
$images[$resized->width] = $resized;
}
$images[$imageDst->width] = $imageDst;
ksort($images);
return $images;
}
public function getSrcsetAttrs(Image $image, $prefix = '')
{
$images = $this->getSrcset($image);
$params = $image->getAttribute('params');
$image = $image->apply($params);
$attrs = ["{$prefix}src" => $this->getUrl($image)];
foreach ($images as $img) {
$srcset[] = "{$this->getUrl($img)} {$img->width}w";
}
if (isset($srcset)) {
// merge default sizes
$params = array_merge(
[
'sizes' => "(min-width: {$image->width}px) {$image->width}px",
],
$params
);
// set image srcset/sizes
$attrs["{$prefix}srcset"] = join(', ', $srcset);
$attrs["{$prefix}sizes"] = $params['sizes'];
}
return $attrs;
}
/**
* Gets the image info.
*
* @param string $file
*
* @return array
*/
public static function getInfo($file)
{
static $cache = [];
if (isset($cache[$file])) {
return $cache[$file];
}
if ($data = @getimagesize($file, $info)) {
return $cache[$file] = [$data[0], $data[1], substr($data['mime'], 6), $info];
}
}
}