BaseAsset.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. /**
  3. * @package Grav\Common\Assets
  4. *
  5. * @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Common\Assets;
  9. use Grav\Common\Assets\Traits\AssetUtilsTrait;
  10. use Grav\Common\Config\Config;
  11. use Grav\Common\Grav;
  12. use Grav\Common\Uri;
  13. use Grav\Common\Utils;
  14. use Grav\Framework\Object\PropertyObject;
  15. use SplFileInfo;
  16. /**
  17. * Class BaseAsset
  18. * @package Grav\Common\Assets
  19. */
  20. abstract class BaseAsset extends PropertyObject
  21. {
  22. use AssetUtilsTrait;
  23. protected const CSS_ASSET = true;
  24. protected const JS_ASSET = false;
  25. /** @var string|false */
  26. protected $asset;
  27. /** @var string */
  28. protected $asset_type;
  29. /** @var int */
  30. protected $order;
  31. /** @var string */
  32. protected $group;
  33. /** @var string */
  34. protected $position;
  35. /** @var int */
  36. protected $priority;
  37. /** @var array */
  38. protected $attributes = [];
  39. /** @var string */
  40. protected $timestamp;
  41. /** @var int|false */
  42. protected $modified;
  43. /** @var bool */
  44. protected $remote;
  45. /** @var string */
  46. protected $query = '';
  47. // Private Bits
  48. /** @var bool */
  49. private $css_rewrite = false;
  50. /** @var bool */
  51. private $css_minify = false;
  52. /**
  53. * @return string
  54. */
  55. abstract function render();
  56. /**
  57. * BaseAsset constructor.
  58. * @param array $elements
  59. * @param string|null $key
  60. */
  61. public function __construct(array $elements = [], $key = null)
  62. {
  63. $base_config = [
  64. 'group' => 'head',
  65. 'position' => 'pipeline',
  66. 'priority' => 10,
  67. 'modified' => null,
  68. 'asset' => null
  69. ];
  70. // Merge base defaults
  71. $elements = array_merge($base_config, $elements);
  72. parent::__construct($elements, $key);
  73. }
  74. /**
  75. * @param string|false $asset
  76. * @param array $options
  77. * @return $this|false
  78. */
  79. public function init($asset, $options)
  80. {
  81. $config = Grav::instance()['config'];
  82. $uri = Grav::instance()['uri'];
  83. // set attributes
  84. foreach ($options as $key => $value) {
  85. if ($this->hasProperty($key)) {
  86. $this->setProperty($key, $value);
  87. } else {
  88. $this->attributes[$key] = $value;
  89. }
  90. }
  91. // Force priority to be an int
  92. $this->priority = (int) $this->priority;
  93. // Do some special stuff for CSS/JS (not inline)
  94. if (!Utils::startsWith($this->getType(), 'inline')) {
  95. $this->base_url = rtrim($uri->rootUrl($config->get('system.absolute_urls')), '/') . '/';
  96. $this->remote = static::isRemoteLink($asset);
  97. // Move this to render?
  98. if (!$this->remote) {
  99. $asset_parts = parse_url($asset);
  100. if (isset($asset_parts['query'])) {
  101. $this->query = $asset_parts['query'];
  102. unset($asset_parts['query']);
  103. $asset = Uri::buildUrl($asset_parts);
  104. }
  105. $locator = Grav::instance()['locator'];
  106. if ($locator->isStream($asset)) {
  107. $path = $locator->findResource($asset, true);
  108. } else {
  109. $path = GRAV_WEBROOT . $asset;
  110. }
  111. // If local file is missing return
  112. if ($path === false) {
  113. return false;
  114. }
  115. $file = new SplFileInfo($path);
  116. $asset = $this->buildLocalLink($file->getPathname());
  117. $this->modified = $file->isFile() ? $file->getMTime() : false;
  118. }
  119. }
  120. $this->asset = $asset;
  121. return $this;
  122. }
  123. /**
  124. * @return string|false
  125. */
  126. public function getAsset()
  127. {
  128. return $this->asset;
  129. }
  130. /**
  131. * @return bool
  132. */
  133. public function getRemote()
  134. {
  135. return $this->remote;
  136. }
  137. /**
  138. * @param string $position
  139. * @return $this
  140. */
  141. public function setPosition($position)
  142. {
  143. $this->position = $position;
  144. return $this;
  145. }
  146. /**
  147. * Receive asset location and return the SRI integrity hash
  148. *
  149. * @param string $input
  150. * @return string
  151. */
  152. public static function integrityHash($input)
  153. {
  154. $grav = Grav::instance();
  155. $assetsConfig = $grav['config']->get('system.assets');
  156. if ( !empty($assetsConfig['enable_asset_sri']) && $assetsConfig['enable_asset_sri'] )
  157. {
  158. $dataToHash = file_get_contents( GRAV_WEBROOT . $input);
  159. $hash = hash('sha256', $dataToHash, true);
  160. $hash_base64 = base64_encode($hash);
  161. return ' integrity="sha256-' . $hash_base64 . '"';
  162. }
  163. return '';
  164. }
  165. /**
  166. *
  167. * Get the last modification time of asset
  168. *
  169. * @param string $asset the asset string reference
  170. *
  171. * @return string the last modifcation time or false on error
  172. */
  173. // protected function getLastModificationTime($asset)
  174. // {
  175. // $file = GRAV_WEBROOT . $asset;
  176. // if (Grav::instance()['locator']->isStream($asset)) {
  177. // $file = $this->buildLocalLink($asset, true);
  178. // }
  179. //
  180. // return file_exists($file) ? filemtime($file) : false;
  181. // }
  182. /**
  183. *
  184. * Build local links including grav asset shortcodes
  185. *
  186. * @param string $asset the asset string reference
  187. *
  188. * @return string|false the final link url to the asset
  189. */
  190. protected function buildLocalLink($asset)
  191. {
  192. if ($asset) {
  193. return $this->base_url . ltrim(Utils::replaceFirstOccurrence(GRAV_WEBROOT, '', $asset), '/');
  194. }
  195. return false;
  196. }
  197. /**
  198. * Implements JsonSerializable interface.
  199. *
  200. * @return array
  201. */
  202. public function jsonSerialize()
  203. {
  204. return ['type' => $this->getType(), 'elements' => $this->getElements()];
  205. }
  206. /**
  207. * Placeholder for AssetUtilsTrait method
  208. *
  209. * @param string $file
  210. * @param string $dir
  211. * @param bool $local
  212. * @return string
  213. */
  214. protected function cssRewrite($file, $dir, $local)
  215. {
  216. return;
  217. }
  218. }