FormFlashFile.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <?php
  2. /**
  3. * @package Grav\Framework\Form
  4. *
  5. * @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Framework\Form;
  9. use Grav\Framework\Psr7\Stream;
  10. use Psr\Http\Message\StreamInterface;
  11. use Psr\Http\Message\UploadedFileInterface;
  12. class FormFlashFile implements UploadedFileInterface, \JsonSerializable
  13. {
  14. private $field;
  15. private $moved = false;
  16. private $upload;
  17. private $flash;
  18. public function __construct(string $field, array $upload, FormFlash $flash)
  19. {
  20. $this->field = $field;
  21. $this->upload = $upload;
  22. $this->flash = $flash;
  23. $tmpFile = $this->getTmpFile();
  24. if (!$tmpFile && $this->isOk()) {
  25. $this->upload['error'] = \UPLOAD_ERR_NO_FILE;
  26. }
  27. if (!isset($this->upload['size'])) {
  28. $this->upload['size'] = $tmpFile && $this->isOk() ? filesize($tmpFile) : 0;
  29. }
  30. }
  31. /**
  32. * @return StreamInterface
  33. */
  34. public function getStream()
  35. {
  36. $this->validateActive();
  37. $resource = \fopen($this->getTmpFile(), 'rb');
  38. return Stream::create($resource);
  39. }
  40. public function moveTo($targetPath)
  41. {
  42. $this->validateActive();
  43. if (!\is_string($targetPath) || empty($targetPath)) {
  44. throw new \InvalidArgumentException('Invalid path provided for move operation; must be a non-empty string');
  45. }
  46. $this->moved = \copy($this->getTmpFile(), $targetPath);
  47. if (false === $this->moved) {
  48. throw new \RuntimeException(\sprintf('Uploaded file could not be moved to %s', $targetPath));
  49. }
  50. $this->flash->removeFile($this->getClientFilename(), $this->field);
  51. }
  52. public function getSize()
  53. {
  54. return $this->upload['size'];
  55. }
  56. public function getError()
  57. {
  58. return $this->upload['error'] ?? \UPLOAD_ERR_OK;
  59. }
  60. public function getClientFilename()
  61. {
  62. return $this->upload['name'] ?? 'unknown';
  63. }
  64. public function getClientMediaType()
  65. {
  66. return $this->upload['type'] ?? 'application/octet-stream';
  67. }
  68. public function isMoved() : bool
  69. {
  70. return $this->moved;
  71. }
  72. public function getMetaData() : array
  73. {
  74. if (isset($this->upload['crop'])) {
  75. return ['crop' => $this->upload['crop']];
  76. }
  77. return [];
  78. }
  79. public function getDestination()
  80. {
  81. return $this->upload['path'] ?? '';
  82. }
  83. public function jsonSerialize()
  84. {
  85. return $this->upload;
  86. }
  87. public function getTmpFile() : ?string
  88. {
  89. $tmpName = $this->upload['tmp_name'] ?? null;
  90. if (!$tmpName) {
  91. return null;
  92. }
  93. $tmpFile = $this->flash->getTmpDir() . '/' . $tmpName;
  94. return file_exists($tmpFile) ? $tmpFile : null;
  95. }
  96. public function __debugInfo()
  97. {
  98. return [
  99. 'field:private' => $this->field,
  100. 'moved:private' => $this->moved,
  101. 'upload:private' => $this->upload,
  102. ];
  103. }
  104. /**
  105. * @throws \RuntimeException if is moved or not ok
  106. */
  107. private function validateActive(): void
  108. {
  109. if (!$this->isOk()) {
  110. throw new \RuntimeException('Cannot retrieve stream due to upload error');
  111. }
  112. if ($this->moved) {
  113. throw new \RuntimeException('Cannot retrieve stream after it has already been moved');
  114. }
  115. if (!$this->getTmpFile()) {
  116. throw new \RuntimeException('Cannot retrieve stream as the file is missing');
  117. }
  118. }
  119. /**
  120. * @return bool return true if there is no upload error
  121. */
  122. private function isOk(): bool
  123. {
  124. return \UPLOAD_ERR_OK === $this->getError();
  125. }
  126. }