How can I forward $_POST with PHP and cURL?
I receive a POST request at my PHP script and would like to forward this POST call to another script using POST too. How can I do this? I can use cURL if it’s required for this action.
4 Answers 4
curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);
This can either be passed as a urlencoded string like ‘para1=val1¶2=val2&. ‘ or as an array with the field name as key and field data as value.
Have you tried this before? With the version of CURL I use, this will send the fields in «multipart/form-data», not a regular post.
I have never tried it before, but the PHP documentation does do a good job of documenting the functionality.
This is the answer most of the times. However, if you have deep variables passed in the post content (e.g. «. &var1[var2]=val&. «) it won’t work ( var1 will be passed as an empty array). ZZCoder’s answer below (using http_build_query() ) is the (complete) right answer.
curl_setopt($handle, CURLOPT_POSTFIELDS, http_build_query($_POST));
Here’s a fully functional cURL request that re-routes $_POST where you want (based on ZZ coder’s reply)
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://urlOfFileWherePostIsSubmitted.com"); curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // ZZ coder's part curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST)); $response = curl_exec($ch); curl_close($ch);
$mixCurlOptValue) < curl_setopt($mixCH, $strCurlOpt, $mixCurlOptValue); >$mixResponse = curl_exec($mixCH); curl_close($mixCH); return $mixResponse; > // If need any HTTP authentication $username = 'http-auth-username'; $password = 'http-auth-password'; $requestType = 'POST'; // This can be PUT or POST // This can be $arrPostData = $_POST; $arrPostData = array( 'key1' => 'value-1-for-k1y-1', 'key2' => 'value-2-for-key-2', 'key3' => array( 'key31' => 'value-for-key-3-1', 'key32' => array( 'key321' => 'value-for-key321' ) ), 'key4' => array( 'key' => 'value' ) ); // You can set your POST data $postData = http_build_query($arrPostData); // Raw PHP array $postData = json_encode($arrPostData); // ONLY use this when requesting JSON data $arrResponse = executeCurl(array( CURLOPT_URL => 'http://whatever-your-request-url.com/xyz/yii', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPGET => true, CURLOPT_VERBOSE => true, CURLOPT_AUTOREFERER => true, CURLOPT_CUSTOMREQUEST => $requestType, CURLOPT_POSTFIELDS => $postData, CURLOPT_HTTPHEADER => array( "X-HTTP-Method-Override: " . $requestType, 'Content-Type: application/json', // ONLY use this when request json data ), // If HTTP authentication is required , use the below lines CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_USERPWD => $username. ':' . $password ));
PHP, How to Redirect/Forward HTTP Request with header and body?
If you have access to the Apache server config you can create a virtualhost with the following settings:
ProxyPreserveHost OffProxyPass / http://remotesite.domain.tld/ProxyPassReverse / http://remotesite.domain.tld/ProxyPassReverseCookieDomain remotesite.domain.tld proxysite.tld
You’ll need to enable mod_proxy and mod_proxy_http for this.Substitute remotesite.domain.tld to the site you forward to, and proxysite.tld to the forwarder.
If you don’t have access to the server config files, you can still do in php, by manually setting up curl and forward everything.
error_reporting(E_ALL);ini_set('display_errors', '1');/* Set it true for debugging. */$logHeaders = FALSE;/* Site to forward requests to. */$site = 'http://remotesite.domain.tld/';/* Domains to use when rewriting some headers. */$remoteDomain = 'remotesite.domain.tld';$proxyDomain = 'proxysite.tld';$request = $_SERVER['REQUEST_URI'];$ch = curl_init();/* If there was a POST request, then forward that as well.*/if ($_SERVER['REQUEST_METHOD'] == 'POST')< curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);>curl_setopt($ch, CURLOPT_URL, $site . $request);curl_setopt($ch, CURLOPT_HEADER, TRUE);$headers = getallheaders();/* Translate some headers to make the remote party think we actually browsing that site. */$extraHeaders = array();if (isset($headers['Referer'])) < $extraHeaders[] = 'Referer: '. str_replace($proxyDomain, $remoteDomain, $headers['Referer']);>if (isset($headers['Origin'])) < $extraHeaders[] = 'Origin: '. str_replace($proxyDomain, $remoteDomain, $headers['Origin']);>/* Forward cookie as it came. */curl_setopt($ch, CURLOPT_HTTPHEADER, $extraHeaders);if (isset($headers['Cookie']))< curl_setopt($ch, CURLOPT_COOKIE, $headers['Cookie']);>curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);if ($logHeaders)< $f = fopen("headers.txt", "a"); curl_setopt($ch, CURLOPT_VERBOSE, TRUE); curl_setopt($ch, CURLOPT_STDERR, $f);>curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);$response = curl_exec($ch);$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);$headers = substr($response, 0, $header_size);$body = substr($response, $header_size);$headerArray = explode(PHP_EOL, $headers);/* Process response headers. */foreach($headerArray as $header)< $colonPos = strpos($header, ':'); if ($colonPos !== FALSE) < $headerName = substr($header, 0, $colonPos); /* Ignore content headers, let the webserver decide how to deal with the content. */ if (trim($headerName) == 'Content-Encoding') continue; if (trim($headerName) == 'Content-Length') continue; if (trim($headerName) == 'Transfer-Encoding') continue; if (trim($headerName) == 'Location') continue; /* -- */ /* Change cookie domain for the proxy */ if (trim($headerName) == 'Set-Cookie') < $header = str_replace('domain='.$remoteDomain, 'domain='.$proxyDomain, $header); > /* -- */ > header($header, FALSE);>echo $body;if ($logHeaders)< fclose($f);>curl_close($ch);?>
And of course the script must be in the root directory of a (sub)domain.And you should have a .htaccess that rewrites everything to it:
RewriteEngine OnRewriteRule .* index.php
this is the solution i have found (there might be better)
public static function getResponse ($url,$headers,$body) < $params = '?' . http_build_query($headers); $redirect_url = $url . $params; $ch = curl_init($redirect_url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $body); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $response = curl_exec($ch); if (!isset($response)) return null; return $response; >
I have used the code by Rehmat and Calmarius and made a few changes so now it handles multiple fields with same name like
"text" name="example[]">"text" name="example[]">"text" name="example[]">
and to upload files too, including multiple files that use the same field name.
error_reporting(E_ALL);ini_set('display_errors', '1');class proxy < private $logHeaders = false; /* Site to forward requests to. */ private $site = 'http://redirectToSite'; /* Domains to use when rewriting some headers. */ private $remoteDomain = 'redirectToSite'; private $proxyDomain = 'yourproxydomain.com'; public function __construct() < $request = $_SERVER['REQUEST_URI']; $ch = curl_init(); /* If there was a POST request, then forward that as well.*/ if ($_SERVER['REQUEST_METHOD'] == 'POST') < $post = $this->sanitizePostFields($_POST); $files = $this->sanitizeFiles($_FILES); if ($files) < $post = array_merge($post, $files); > curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); /* // this is enough if not uploading files curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query($_POST) ); */ > curl_setopt($ch, CURLOPT_URL, $this->site . $request); curl_setopt($ch, CURLOPT_HEADER, TRUE); $headers = getallheaders(); /* Translate some headers to make the remote party think we actually browsing that site. */ $extraHeaders = array(); if (isset($headers['Referer'])) < $extraHeaders[] = 'Referer: '. str_replace( $this->proxyDomain, $this->remoteDomain, $headers['Referer'] ); > if (isset($headers['Origin'])) < $extraHeaders[] = 'Origin: '. str_replace( $this->proxyDomain, $this->remoteDomain, $headers['Origin'] ); > /* Forward cookie as it came. */ curl_setopt($ch, CURLOPT_HTTPHEADER, $extraHeaders); if (isset($headers['Cookie'])) < curl_setopt($ch, CURLOPT_COOKIE, $headers['Cookie']); > curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); if ($this->logHeaders) < $f = fopen("headers.txt", "a"); curl_setopt($ch, CURLOPT_VERBOSE, TRUE); curl_setopt($ch, CURLOPT_STDERR, $f); > //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $response = curl_exec($ch); $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $header_size); $body = substr($response, $header_size); $headerArray = explode(PHP_EOL, $headers); /* Process response headers. */ foreach($headerArray as $header) < $colonPos = strpos($header, ':'); if ($colonPos !== FALSE) < $headerName = substr($header, 0, $colonPos); /* Ignore content headers, let the webserver decide how to deal with the content. */ if (trim($headerName) == 'Content-Encoding') continue; if (trim($headerName) == 'Content-Length') continue; if (trim($headerName) == 'Transfer-Encoding') continue; //if (trim($headerName) == 'Location') continue; /* -- */ /* Change cookie domain for the proxy */ if (trim($headerName) == 'Set-Cookie') < $header = str_replace( 'domain='.$this->remoteDomain, 'domain='.$this->proxyDomain, $header ); > /* -- */ if (trim($headerName) == 'Location') < $header = str_replace( $this->remoteDomain, $this->proxyDomain, $header ); > > header($header, FALSE); > echo $body; if ($this->logHeaders) < fclose($f); > curl_close($ch); > private function sanitizePostFields($post, $fieldName = '') < if (empty($post)) < return false; > if (!is_array($post)) < return false; > $result = []; foreach ($post as $k => $v) < if (is_string($v)) < $result[($fieldName ? " [ ]" : $k)] = $v; > elseif (is_array($v)) < $result = array_merge( $result, $this->sanitizePostFields($v, $k) ); > > return $result; > private function sanitizeFiles($files) < if (empty($files)) < return false; > if (!is_array($files)) < return false; > $result = []; foreach ($files as $k => $v) < if (empty($v['name'])) < continue; > if (is_array($v['name'])) < // more than one file using the same name field[] $nFields = count($v['name']); for ($i = 0; $i < $nFields; $i++) < if (empty($v['tmp_name'][$i])) < continue; > $curl_file_upload = new CURLFile( $v['tmp_name'][$i], $v['type'][$i], $v['name'][$i] ); $result[" [ ]"] = $curl_file_upload; > > else < $curl_file_upload = new CURLFile( $v['tmp_name'], $v['type'], $v['name'] ); $result[$k] = $curl_file_upload; > > return $result; > >$proxy = new proxy();