Make POST request with large file in body for PHP 5.5+ -


there api need work php application. 1 endpoint receives file upload body of post request. uploaded file can rather huge (up 25gb). endpoint returns simple json content either 200 ok or different other status codes.

example request may this:

post /api/upload http/1.1 host: <hostname> content-type: application/octet-stream content-length: 26843545600 connection: close  <raw file data 25 gb> 

basically, need write method perform such request without killing server.

i tried find reasonable implementation but, can see, both curl , non-curl (stream_context_create) methods require string request body, may exhaust server memory.

is there simple way achieve without writing a separate socket transport layer?

since no better options found, went default solution fsockopen.

here full source code of utility function perform http request low memory consumption. data parameter can accept string, array , splfileinfo object.

/**  * performs memory-safe http request.  *  * @param string $url       request url, e.g. "https://example.com:23986/api/upload".  * @param string $method    request method, e.g. "get", "post", "patch", etc.  * @param mixed $data       [optional] data pass request.  * @param array $headers    [optional] additional headers.  *  * @return string           response body.  *  * @throws exception  */ function request($url, $method, $data = null, array &$headers = []) {     static $schemes = [         'https' => ['ssl://', 443],         'http'  => ['', 80],     ];      $u = parse_url($url);     if (!isset($u['host']) || !isset($u['scheme']) || !isset($schemes[$u['scheme']])) {         throw new exception('url parameter must valid url.');     }      $scheme = $schemes[$u['scheme']];     if (isset($u['port'])) {         $scheme[1] = $u['port'];     }      $fp = @fsockopen($scheme[0] . $u['host'], $scheme[1], $errno, $errstr);     if ($fp === false) {         throw new exception($errstr, $errno);     }      $uri = isset($u['path']) ? $u['path'] : '/';     if (isset($u['query'])) {         $uri .= '?' . $u['query'];     }      if (is_array($data)) {         $data = http_build_query($data);         $headers['content-type'] = 'application/x-www-form-urlencoded';         $headers['content-length'] = strlen($data);     } elseif ($data instanceof splfileinfo) {         $headers['content-length'] = $data->getsize();     }      $headers['host'] = $this->host;     $headers['connection'] = 'close';      fwrite($fp, sprintf("%s /api%s http/1.1\r\n", $method, $uri));     foreach ($headers $header => $value) {         fwrite($fp, $header . ': ' . $value . "\r\n");     }     fwrite($fp, "\r\n");      if ($data instanceof splfileinfo) {         $fh = fopen($data->getpathname(), 'rb');         while ($chunk = fread($fh, 4096)) {             fwrite($fp, $chunk);         }         fclose($fh);     } else {         fwrite($fp, $data);     }      $response = '';     while (!feof($fp)) {         $response .= fread($fp, 1024);     }     fclose($fp);      if (false === $pos = strpos($response, "\r\n\r\n")) {         throw new exception('bad server response body.');     }      $headers = explode("\r\n", substr($response, 0, $pos));     if (!isset($headers[0]) || strpos($headers[0], 'http/1.1 ')) {         throw new exception('bad server response headers.');     }      return substr($response, $pos + 4); } 

example usage:

$file = new splfileobject('/path/to/file', 'rb'); $contents = request('https://example.com/api/upload', 'post', $file, $headers); if ($headers[0] == 'http/1.1 200 ok') {     print $contents; } 

Comments

Popular posts from this blog

java - Static nested class instance -

c# - Bluetooth LE CanUpdate Characteristic property -

JavaScript - Replace variable from string in all occurrences -