DiactorosFactory.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bridge\PsrHttpMessage\Factory;
  11. use Psr\Http\Message\UploadedFileInterface;
  12. use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
  13. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  14. use Symfony\Component\HttpFoundation\File\UploadedFile;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpFoundation\Response;
  17. use Symfony\Component\HttpFoundation\StreamedResponse;
  18. use Zend\Diactoros\Response as DiactorosResponse;
  19. use Zend\Diactoros\ServerRequest;
  20. use Zend\Diactoros\ServerRequestFactory as DiactorosRequestFactory;
  21. use Zend\Diactoros\Stream as DiactorosStream;
  22. use Zend\Diactoros\UploadedFile as DiactorosUploadedFile;
  23. /**
  24. * Builds Psr\HttpMessage instances using the Zend Diactoros implementation.
  25. *
  26. * @author Kévin Dunglas <dunglas@gmail.com>
  27. */
  28. class DiactorosFactory implements HttpMessageFactoryInterface
  29. {
  30. public function __construct()
  31. {
  32. if (!class_exists('Zend\Diactoros\ServerRequestFactory')) {
  33. throw new \RuntimeException('Zend Diactoros must be installed to use the DiactorosFactory.');
  34. }
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function createRequest(Request $symfonyRequest)
  40. {
  41. $server = DiactorosRequestFactory::normalizeServer($symfonyRequest->server->all());
  42. $headers = $symfonyRequest->headers->all();
  43. if (PHP_VERSION_ID < 50600) {
  44. $body = new DiactorosStream('php://temp', 'wb+');
  45. $body->write($symfonyRequest->getContent());
  46. } else {
  47. $body = new DiactorosStream($symfonyRequest->getContent(true));
  48. }
  49. $request = new ServerRequest(
  50. $server,
  51. DiactorosRequestFactory::normalizeFiles($this->getFiles($symfonyRequest->files->all())),
  52. $symfonyRequest->getSchemeAndHttpHost().$symfonyRequest->getRequestUri(),
  53. $symfonyRequest->getMethod(),
  54. $body,
  55. $headers
  56. );
  57. $request = $request
  58. ->withCookieParams($symfonyRequest->cookies->all())
  59. ->withQueryParams($symfonyRequest->query->all())
  60. ->withParsedBody($symfonyRequest->request->all())
  61. ->withRequestTarget($symfonyRequest->getRequestUri())
  62. ;
  63. foreach ($symfonyRequest->attributes->all() as $key => $value) {
  64. $request = $request->withAttribute($key, $value);
  65. }
  66. return $request;
  67. }
  68. /**
  69. * Converts Symfony uploaded files array to the PSR one.
  70. *
  71. * @param array $uploadedFiles
  72. *
  73. * @return array
  74. */
  75. private function getFiles(array $uploadedFiles)
  76. {
  77. $files = array();
  78. foreach ($uploadedFiles as $key => $value) {
  79. if (null === $value) {
  80. $files[$key] = new DiactorosUploadedFile(null, 0, UPLOAD_ERR_NO_FILE, null, null);
  81. continue;
  82. }
  83. if ($value instanceof UploadedFile) {
  84. $files[$key] = $this->createUploadedFile($value);
  85. } else {
  86. $files[$key] = $this->getFiles($value);
  87. }
  88. }
  89. return $files;
  90. }
  91. /**
  92. * Creates a PSR-7 UploadedFile instance from a Symfony one.
  93. *
  94. * @param UploadedFile $symfonyUploadedFile
  95. *
  96. * @return UploadedFileInterface
  97. */
  98. private function createUploadedFile(UploadedFile $symfonyUploadedFile)
  99. {
  100. return new DiactorosUploadedFile(
  101. $symfonyUploadedFile->getRealPath(),
  102. (int) $symfonyUploadedFile->getSize(),
  103. $symfonyUploadedFile->getError(),
  104. $symfonyUploadedFile->getClientOriginalName(),
  105. $symfonyUploadedFile->getClientMimeType()
  106. );
  107. }
  108. /**
  109. * {@inheritdoc}
  110. */
  111. public function createResponse(Response $symfonyResponse)
  112. {
  113. if ($symfonyResponse instanceof BinaryFileResponse) {
  114. $stream = new DiactorosStream($symfonyResponse->getFile()->getPathname(), 'r');
  115. } else {
  116. $stream = new DiactorosStream('php://temp', 'wb+');
  117. if ($symfonyResponse instanceof StreamedResponse) {
  118. ob_start(function ($buffer) use ($stream) {
  119. $stream->write($buffer);
  120. return '';
  121. });
  122. $symfonyResponse->sendContent();
  123. ob_end_clean();
  124. } else {
  125. $stream->write($symfonyResponse->getContent());
  126. }
  127. }
  128. $headers = $symfonyResponse->headers->all();
  129. if (!isset($headers['Set-Cookie']) && !isset($headers['set-sookie'])) {
  130. $cookies = $symfonyResponse->headers->getCookies();
  131. if (!empty($cookies)) {
  132. $headers['Set-Cookie'] = array();
  133. foreach ($cookies as $cookie) {
  134. $headers['Set-Cookie'][] = $cookie->__toString();
  135. }
  136. }
  137. }
  138. $response = new DiactorosResponse(
  139. $stream,
  140. $symfonyResponse->getStatusCode(),
  141. $headers
  142. );
  143. $protocolVersion = $symfonyResponse->getProtocolVersion();
  144. if ('1.1' !== $protocolVersion) {
  145. $response = $response->withProtocolVersion($protocolVersion);
  146. }
  147. return $response;
  148. }
  149. }