| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  | <?php | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Helper class for building multipart/form-data request body | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * PHP version 5 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-07-10 16:23:21 +02:00
										 |  |  |  * LICENSE | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-07-10 16:23:21 +02:00
										 |  |  |  * This source file is subject to BSD 3-Clause License that is bundled | 
					
						
							|  |  |  |  * with this package in the file LICENSE and available at the URL | 
					
						
							|  |  |  |  * https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-07-10 16:23:21 +02:00
										 |  |  |  * @category  HTTP | 
					
						
							|  |  |  |  * @package   HTTP_Request2 | 
					
						
							|  |  |  |  * @author    Alexey Borzov <avb@php.net> | 
					
						
							|  |  |  |  * @copyright 2008-2014 Alexey Borzov <avb@php.net> | 
					
						
							|  |  |  |  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License | 
					
						
							|  |  |  |  * @link      http://pear.php.net/package/HTTP_Request2 | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-10 16:23:21 +02:00
										 |  |  | /** Exception class for HTTP_Request2 package */ | 
					
						
							|  |  |  | require_once 'HTTP/Request2/Exception.php'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Class for building multipart/form-data request body | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The class helps to reduce memory consumption by streaming large file uploads | 
					
						
							|  |  |  |  * from disk, it also allows monitoring of upload progress (see request #7630)
 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |  * @category HTTP | 
					
						
							|  |  |  |  * @package  HTTP_Request2 | 
					
						
							|  |  |  |  * @author   Alexey Borzov <avb@php.net> | 
					
						
							| 
									
										
										
										
											2014-07-10 16:23:21 +02:00
										 |  |  |  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License | 
					
						
							|  |  |  |  * @version  Release: 2.2.1 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |  * @link     http://pear.php.net/package/HTTP_Request2 | 
					
						
							|  |  |  |  * @link     http://tools.ietf.org/html/rfc1867 | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | class HTTP_Request2_MultipartBody | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * MIME boundary | 
					
						
							|  |  |  |      * @var  string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     private $_boundary; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Form parameters added via {@link HTTP_Request2::addPostParameter()} | 
					
						
							|  |  |  |      * @var  array | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     private $_params = array(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * File uploads added via {@link HTTP_Request2::addUpload()} | 
					
						
							|  |  |  |      * @var  array | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     private $_uploads = array(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Header for parts with parameters | 
					
						
							|  |  |  |      * @var  string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Header for parts with uploads | 
					
						
							|  |  |  |      * @var  string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Current position in parameter and upload arrays | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * First number is index of "current" part, second number is position within | 
					
						
							|  |  |  |      * "current" part | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @var  array | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     private $_pos = array(0, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Constructor. Sets the arrays with POST data. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param array $params      values of form fields set via | 
					
						
							|  |  |  |      *                           {@link HTTP_Request2::addPostParameter()} | 
					
						
							|  |  |  |      * @param array $uploads     file uploads set via | 
					
						
							|  |  |  |      *                           {@link HTTP_Request2::addUpload()} | 
					
						
							|  |  |  |      * @param bool  $useBrackets whether to append brackets to array variable names | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     public function __construct(array $params, array $uploads, $useBrackets = true) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->_params = self::_flattenArray('', $params, $useBrackets); | 
					
						
							|  |  |  |         foreach ($uploads as $fieldName => $f) { | 
					
						
							|  |  |  |             if (!is_array($f['fp'])) { | 
					
						
							|  |  |  |                 $this->_uploads[] = $f + array('name' => $fieldName); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 for ($i = 0; $i < count($f['fp']); $i++) { | 
					
						
							|  |  |  |                     $upload = array( | 
					
						
							|  |  |  |                         'name' => ($useBrackets? $fieldName . '[' . $i . ']': $fieldName) | 
					
						
							|  |  |  |                     ); | 
					
						
							|  |  |  |                     foreach (array('fp', 'filename', 'size', 'type') as $key) { | 
					
						
							|  |  |  |                         $upload[$key] = $f[$key][$i]; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     $this->_uploads[] = $upload; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Returns the length of the body to use in Content-Length header | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return   integer | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     public function getLength() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $boundaryLength     = strlen($this->getBoundary()); | 
					
						
							|  |  |  |         $headerParamLength  = strlen($this->_headerParam) - 4 + $boundaryLength; | 
					
						
							|  |  |  |         $headerUploadLength = strlen($this->_headerUpload) - 8 + $boundaryLength; | 
					
						
							|  |  |  |         $length             = $boundaryLength + 6; | 
					
						
							|  |  |  |         foreach ($this->_params as $p) { | 
					
						
							|  |  |  |             $length += $headerParamLength + strlen($p[0]) + strlen($p[1]) + 2; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         foreach ($this->_uploads as $u) { | 
					
						
							|  |  |  |             $length += $headerUploadLength + strlen($u['name']) + strlen($u['type']) + | 
					
						
							|  |  |  |                        strlen($u['filename']) + $u['size'] + 2; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Returns the boundary to use in Content-Type header | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return   string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     public function getBoundary() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (empty($this->_boundary)) { | 
					
						
							|  |  |  |             $this->_boundary = '--' . md5('PEAR-HTTP_Request2-' . microtime()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $this->_boundary; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Returns next chunk of request body | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param integer $length Number of bytes to read | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return   string  Up to $length bytes of data, empty string if at end | 
					
						
							| 
									
										
										
										
											2014-07-10 16:23:21 +02:00
										 |  |  |      * @throws   HTTP_Request2_LogicException | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     public function read($length) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $ret         = ''; | 
					
						
							|  |  |  |         $boundary    = $this->getBoundary(); | 
					
						
							|  |  |  |         $paramCount  = count($this->_params); | 
					
						
							|  |  |  |         $uploadCount = count($this->_uploads); | 
					
						
							|  |  |  |         while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) { | 
					
						
							|  |  |  |             $oldLength = $length; | 
					
						
							|  |  |  |             if ($this->_pos[0] < $paramCount) { | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |                 $param = sprintf( | 
					
						
							|  |  |  |                     $this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0] | 
					
						
							|  |  |  |                 ) . $this->_params[$this->_pos[0]][1] . "\r\n"; | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |                 $ret    .= substr($param, $this->_pos[1], $length); | 
					
						
							|  |  |  |                 $length -= min(strlen($param) - $this->_pos[1], $length); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             } elseif ($this->_pos[0] < $paramCount + $uploadCount) { | 
					
						
							|  |  |  |                 $pos    = $this->_pos[0] - $paramCount; | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |                 $header = sprintf( | 
					
						
							|  |  |  |                     $this->_headerUpload, $boundary, $this->_uploads[$pos]['name'], | 
					
						
							|  |  |  |                     $this->_uploads[$pos]['filename'], $this->_uploads[$pos]['type'] | 
					
						
							|  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |                 if ($this->_pos[1] < strlen($header)) { | 
					
						
							|  |  |  |                     $ret    .= substr($header, $this->_pos[1], $length); | 
					
						
							|  |  |  |                     $length -= min(strlen($header) - $this->_pos[1], $length); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 $filePos  = max(0, $this->_pos[1] - strlen($header)); | 
					
						
							| 
									
										
										
										
											2014-07-10 16:23:21 +02:00
										 |  |  |                 if ($filePos < $this->_uploads[$pos]['size']) { | 
					
						
							|  |  |  |                     while ($length > 0 && !feof($this->_uploads[$pos]['fp'])) { | 
					
						
							|  |  |  |                         if (false === ($chunk = fread($this->_uploads[$pos]['fp'], $length))) { | 
					
						
							|  |  |  |                             throw new HTTP_Request2_LogicException( | 
					
						
							|  |  |  |                                 'Failed reading file upload', HTTP_Request2_Exception::READ_ERROR | 
					
						
							|  |  |  |                             ); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         $ret    .= $chunk; | 
					
						
							|  |  |  |                         $length -= strlen($chunk); | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 if ($length > 0) { | 
					
						
							|  |  |  |                     $start   = $this->_pos[1] + ($oldLength - $length) - | 
					
						
							|  |  |  |                                strlen($header) - $this->_uploads[$pos]['size']; | 
					
						
							|  |  |  |                     $ret    .= substr("\r\n", $start, $length); | 
					
						
							|  |  |  |                     $length -= min(2 - $start, $length); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 $closing  = '--' . $boundary . "--\r\n"; | 
					
						
							|  |  |  |                 $ret     .= substr($closing, $this->_pos[1], $length); | 
					
						
							|  |  |  |                 $length  -= min(strlen($closing) - $this->_pos[1], $length); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if ($length > 0) { | 
					
						
							|  |  |  |                 $this->_pos     = array($this->_pos[0] + 1, 0); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 $this->_pos[1] += $oldLength; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return $ret; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Sets the current position to the start of the body | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * This allows reusing the same body in another request | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     public function rewind() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->_pos = array(0, 0); | 
					
						
							|  |  |  |         foreach ($this->_uploads as $u) { | 
					
						
							|  |  |  |             rewind($u['fp']); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Returns the body as string | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Note that it reads all file uploads into memory so it is a good idea not | 
					
						
							|  |  |  |      * to use this method with large file uploads and rely on read() instead. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return   string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     public function __toString() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->rewind(); | 
					
						
							|  |  |  |         return $this->read($this->getLength()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-05 14:29:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Helper function to change the (probably multidimensional) associative array | 
					
						
							|  |  |  |      * into the simple one. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param string $name        name for item | 
					
						
							|  |  |  |      * @param mixed  $values      item's values | 
					
						
							|  |  |  |      * @param bool   $useBrackets whether to append [] to array variables' names | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return   array   array with the following items: array('item name', 'item value'); | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-28 15:29:20 -04:00
										 |  |  |     private static function _flattenArray($name, $values, $useBrackets) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!is_array($values)) { | 
					
						
							|  |  |  |             return array(array($name, $values)); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             $ret = array(); | 
					
						
							|  |  |  |             foreach ($values as $k => $v) { | 
					
						
							|  |  |  |                 if (empty($name)) { | 
					
						
							|  |  |  |                     $newName = $k; | 
					
						
							|  |  |  |                 } elseif ($useBrackets) { | 
					
						
							|  |  |  |                     $newName = $name . '[' . $k . ']'; | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     $newName = $name; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 $ret = array_merge($ret, self::_flattenArray($newName, $v, $useBrackets)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return $ret; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ?>
 |