PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/File/BinaryFile.php

https://bitbucket.org/wirbelwild/kiwa-core
PHP | 215 lines | 109 code | 36 blank | 70 comment | 11 complexity | be423364f465762844e7f8a4cc5d2978 MD5 | raw file
  1. <?php
  2. /**
  3. * Kiwa. A feather light web framework for small but professional static websites.
  4. *
  5. * @author Tobias Köngeter
  6. * @copyright Copyright © 2020 Bit&Black
  7. * @link https://www.bitandblack.com
  8. * @link https://www.kiwa.io
  9. * @license MIT
  10. */
  11. namespace Kiwa\File;
  12. use DateTime;
  13. use Exception;
  14. use Kiwa\DI;
  15. use Kiwa\Path;
  16. use Symfony\Component\Mime\MimeTypes;
  17. /**
  18. * The BinaryFile class holds information about a binary file.
  19. *
  20. * @package Kiwa\File
  21. */
  22. final class BinaryFile extends AbstractFile
  23. {
  24. /**
  25. * @var string
  26. */
  27. private $filePath;
  28. /**
  29. * @var int
  30. */
  31. private $status;
  32. /**
  33. * @var string|null
  34. */
  35. private $mimeType;
  36. /**
  37. * @var \DateTime|null
  38. */
  39. private $lastModified;
  40. /**
  41. * Creates a new binary file object.
  42. *
  43. * @param string $file Full path to the file.
  44. */
  45. public function __construct(string $file)
  46. {
  47. $this->status = 200;
  48. $extension = pathinfo($file, PATHINFO_EXTENSION);
  49. if ('' === $extension) {
  50. $this->status = 403;
  51. return;
  52. }
  53. if (null === $fileNameReal = $this->getFileNameIfExists($file)) {
  54. DI::getLog()->debug('File doesn\'t exist.');
  55. $this->status = 404;
  56. return;
  57. }
  58. $this->filePath = $fileNameReal;
  59. $mimeTypes = MimeTypes::getDefault()->getMimeTypes($extension);
  60. $this->mimeType = $mimeTypes[0] ?? 'application/octet-stream';
  61. if (false !== $lastModified = DateTime::createFromFormat('U', (string) filemtime($file))) {
  62. $this->lastModified = $lastModified;
  63. }
  64. }
  65. /**
  66. * Returns a files name if it exists.
  67. * This method is case insensitive.
  68. *
  69. * @param string $fileName
  70. * @return null|string
  71. */
  72. private function getFileNameIfExists(string $fileName): ?string
  73. {
  74. if (file_exists($fileName)) {
  75. return $fileName;
  76. }
  77. $directoryName = dirname($fileName);
  78. $files = glob($directoryName.DIRECTORY_SEPARATOR.'*', GLOB_NOSORT);
  79. $fileNameLowerCase = mb_strtolower($fileName);
  80. if (!is_array($files)) {
  81. return null;
  82. }
  83. foreach ($files as $file) {
  84. if (mb_strtolower($file) === $fileNameLowerCase) {
  85. return $file;
  86. }
  87. }
  88. return null;
  89. }
  90. /**
  91. * Reads a file.
  92. *
  93. * @return string|null
  94. */
  95. public function readFile(): ?string
  96. {
  97. if (null === $file = $this->getFileNameIfExists($this->getFilePath())) {
  98. return null;
  99. }
  100. $output = (string) file_get_contents($file);
  101. /**
  102. * Declare kiwa variable to use in template files.
  103. *
  104. * @deprecated
  105. * @todo Remove in v1.0.
  106. */
  107. $kiwa = self::$controller;
  108. if (false !== strpos($file, '.php')) {
  109. try {
  110. ob_start();
  111. include $file;
  112. $output = (string) ob_get_clean();
  113. } catch (Exception $exception) {
  114. $output = (string) $exception;
  115. $output.= PHP_EOL.PHP_EOL;
  116. $output.= ob_get_clean();
  117. }
  118. }
  119. return $output;
  120. }
  121. /**
  122. * Gets the full path to the file.
  123. *
  124. * @return string
  125. */
  126. public function getFilePath(): string
  127. {
  128. return $this->filePath;
  129. }
  130. /**
  131. * Gets the http status code of the file.
  132. *
  133. * @return int
  134. */
  135. public function getStatus(): int
  136. {
  137. return $this->status;
  138. }
  139. /**
  140. * Gets the mime type of the file.
  141. *
  142. * @return string|null
  143. */
  144. public function getMimeType(): ?string
  145. {
  146. return $this->mimeType;
  147. }
  148. /**
  149. * @return bool
  150. */
  151. public function isVersionedFile(): bool
  152. {
  153. $manifestJson = Path::getBuildFolder().DIRECTORY_SEPARATOR.'manifest.json';
  154. if (!file_exists($manifestJson)) {
  155. return false;
  156. }
  157. $manifest = (string) file_get_contents($manifestJson);
  158. $manifest = json_decode($manifest, true);
  159. if (null === $manifest) {
  160. $manifest = [];
  161. }
  162. $file = pathinfo($this->getFilePath(), PATHINFO_BASENAME);
  163. foreach ($manifest as $shortName => $versionedName) {
  164. $shortName = pathinfo($shortName, PATHINFO_BASENAME);
  165. $versionedName = pathinfo($versionedName, PATHINFO_BASENAME);
  166. if ($versionedName === $file) {
  167. return $shortName !== $versionedName;
  168. }
  169. }
  170. return false;
  171. }
  172. /**
  173. * @return \DateTime|null
  174. */
  175. public function getLastModified(): ?DateTime
  176. {
  177. return $this->lastModified;
  178. }
  179. }