RequestBodyMultipart.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <?php
  2. /**
  3. * Copyright 2017 Facebook, Inc.
  4. *
  5. * You are hereby granted a non-exclusive, worldwide, royalty-free license to
  6. * use, copy, modify, and distribute this software in source code or binary
  7. * form for use in connection with the web services and APIs provided by
  8. * Facebook.
  9. *
  10. * As with any software that integrates with the Facebook platform, your use
  11. * of this software is subject to the Facebook Developer Principles and
  12. * Policies [http://developers.facebook.com/policy/]. This copyright notice
  13. * shall be included in all copies or substantial portions of the software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21. * DEALINGS IN THE SOFTWARE.
  22. *
  23. */
  24. namespace Facebook\Http;
  25. use Facebook\FileUpload\FacebookFile;
  26. /**
  27. * Class RequestBodyMultipartt
  28. *
  29. * Some things copied from Guzzle
  30. *
  31. * @package Facebook
  32. *
  33. * @see https://github.com/guzzle/guzzle/blob/master/src/Post/MultipartBody.php
  34. */
  35. class RequestBodyMultipart implements RequestBodyInterface
  36. {
  37. /**
  38. * @var string The boundary.
  39. */
  40. private $boundary;
  41. /**
  42. * @var array The parameters to send with this request.
  43. */
  44. private $params;
  45. /**
  46. * @var array The files to send with this request.
  47. */
  48. private $files = [];
  49. /**
  50. * @param array $params The parameters to send with this request.
  51. * @param array $files The files to send with this request.
  52. * @param string $boundary Provide a specific boundary.
  53. */
  54. public function __construct(array $params = [], array $files = [], $boundary = null)
  55. {
  56. $this->params = $params;
  57. $this->files = $files;
  58. $this->boundary = $boundary ?: uniqid();
  59. }
  60. /**
  61. * @inheritdoc
  62. */
  63. public function getBody()
  64. {
  65. $body = '';
  66. // Compile normal params
  67. $params = $this->getNestedParams($this->params);
  68. foreach ($params as $k => $v) {
  69. $body .= $this->getParamString($k, $v);
  70. }
  71. // Compile files
  72. foreach ($this->files as $k => $v) {
  73. $body .= $this->getFileString($k, $v);
  74. }
  75. // Peace out
  76. $body .= "--{$this->boundary}--\r\n";
  77. return $body;
  78. }
  79. /**
  80. * Get the boundary
  81. *
  82. * @return string
  83. */
  84. public function getBoundary()
  85. {
  86. return $this->boundary;
  87. }
  88. /**
  89. * Get the string needed to transfer a file.
  90. *
  91. * @param string $name
  92. * @param FacebookFile $file
  93. *
  94. * @return string
  95. */
  96. private function getFileString($name, FacebookFile $file)
  97. {
  98. return sprintf(
  99. "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"%s\r\n\r\n%s\r\n",
  100. $this->boundary,
  101. $name,
  102. $file->getFileName(),
  103. $this->getFileHeaders($file),
  104. $file->getContents()
  105. );
  106. }
  107. /**
  108. * Get the string needed to transfer a POST field.
  109. *
  110. * @param string $name
  111. * @param string $value
  112. *
  113. * @return string
  114. */
  115. private function getParamString($name, $value)
  116. {
  117. return sprintf(
  118. "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
  119. $this->boundary,
  120. $name,
  121. $value
  122. );
  123. }
  124. /**
  125. * Returns the params as an array of nested params.
  126. *
  127. * @param array $params
  128. *
  129. * @return array
  130. */
  131. private function getNestedParams(array $params)
  132. {
  133. $query = http_build_query($params, null, '&');
  134. $params = explode('&', $query);
  135. $result = [];
  136. foreach ($params as $param) {
  137. list($key, $value) = explode('=', $param, 2);
  138. $result[urldecode($key)] = urldecode($value);
  139. }
  140. return $result;
  141. }
  142. /**
  143. * Get the headers needed before transferring the content of a POST file.
  144. *
  145. * @param FacebookFile $file
  146. *
  147. * @return string
  148. */
  149. protected function getFileHeaders(FacebookFile $file)
  150. {
  151. return "\r\nContent-Type: {$file->getMimetype()}";
  152. }
  153. }