diff --git a/httprl.module b/httprl.module index a38c381..2f8f4b8 100644 --- a/httprl.module +++ b/httprl.module @@ -83,6 +83,11 @@ define('HTTPRL_REQUEST_TIMEOUT', -10060); define('HTTPRL_CONNECTION_REFUSED', -10061); /** + * HTTP encapsulation boundary string. + */ +define('HTTPRL_MULTIPART_BOUNDARY', '---------------------------' . str_replace('.','', microtime(TRUE))); + +/** * Implement hook_menu(). */ function httprl_menu() { @@ -464,8 +469,64 @@ function httprl_set_connection_flag(&$options, $uri) { */ function httprl_handle_data(&$options) { // Encode data if not already done. - if (!is_null($options['data']) && !is_string($options['data'])) { - $options['data'] = http_build_query($options['data'], '', '&'); + if (!empty($options['data']) && !is_string($options['data'])) { + // No files passed in, url-encode the data. + if (empty($options['data']['files']) || !is_array($options['data']['files'])) { + $options['data'] = http_build_query($options['data'], '', '&'); + + // Set the Content-Type to application/x-www-form-urlencoded if the data + // is not empty, the Content-Type is not set, and the method is POST or + // PUT. + if (!empty($options['data']) && !isset($options['headers']['Content-Type']) && ($options['method'] == 'POST' || $options['method'] == 'PUT')) { + $options['headers']['Content-Type'] = 'application/x-www-form-urlencoded'; + } + } + else { + $data_stream = ''; + // Add files to the request. + foreach ($options['data']['files'] as $field_name => $info) { + $multi_field = '[]'; + // Convert $info into an array if it's a string. + // This makes for one code path (the foreach loop). + if (is_string($info)) { + $multi_field = ''; + $temp = $info; + unset($info); + $info[] = $temp; + } + foreach ($info as $fullpath) { + // Strip '@' from the start of the path (cURL requirement). + if (substr($fullpath, 0, 1) == "@") { + $fullpath = substr($fullpath, 1); + } + $filename = basename($fullpath); + // TODO: mime detection. + $mimetype = 'application/octet-stream'; + + // Build the datastream for this file. + $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n"; + $data_stream .= 'Content-Disposition: form-data; name="files[' . $field_name . ']' . $multi_field . '"; filename="' . $filename . "\"\r\n"; + $data_stream .= 'Content-Transfer-Encoding: binary' . "\r\n"; + $data_stream .= 'Content-Type: ' . $mimetype . "\r\n\r\n"; + $data_stream .= file_get_contents($fullpath) . "\r\n"; + } + } + // Remove files from the data array as they have already been added. + $data_array = $options['data']; + unset($data_array['files']); + // Add fields to the request too: $_POST['foo'] = 'bar'. + httprl_multipart_encoder($data_stream, $data_array); + + // Signal end of request (note the trailing "--"). + $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "--\r\n"; + $options['data'] = $data_stream; + + // Set the Content-Type to multipart/form-data if the data is not empty, + // the Content-Type is not set, and the method is POST or PUT. + if (!empty($options['data']) && !isset($options['headers']['Content-Type']) && ($options['method'] == 'POST' || $options['method'] == 'PUT')) { + $options['headers']['Content-Type'] = 'multipart/form-data; boundary=' . HTTPRL_MULTIPART_BOUNDARY; + } + } } // Only add Content-Length if we actually have any content or if it is a POST @@ -476,11 +537,33 @@ function httprl_handle_data(&$options) { if ($content_length > 0 || $options['method'] == 'POST' || $options['method'] == 'PUT') { $options['headers']['Content-Length'] = $content_length; } +} - // Set the Content-Type to application/x-www-form-urlencoded if the data is - // not empty, the Content-Type is not set, and the method is POST. - if ($content_length > 0 && !isset($options['headers']['Content-Type']) && $options['method'] == 'POST') { - $options['headers']['Content-Type'] = 'application/x-www-form-urlencoded'; +/** + * Multipart encode a data array. + * + * PHP has http_build_query() which will url-encode data. There is no built in function to multipart encode data thus we have this function below. + * @param $uri + * Array from parse_url(). + * @param &$options + * Array containing options. + */ +function httprl_multipart_encoder(&$data_stream, $data_array, $prepend = array()) { + foreach ($data_array as $key => $value) { + $key_array = $prepend; + $key_array[] = $key; + if (is_array($value)) { + httprl_multipart_encoder($data_stream, $value, $key_array); + } + elseif (is_scalar($value)) { + $key_string = array_shift($key_array); + if (!empty($key_array)) { + $key_string .= '[' . implode('][', $key_array) . ']'; + } + $data_stream .= '--' . HTTPRL_MULTIPART_BOUNDARY . "\r\n"; + $data_stream .= 'Content-Disposition: form-data; name="' . $key_string . "\"\r\n\r\n"; + $data_stream .= $value . "\r\n"; + } } }