PHP: get_headers set temporary stream_context - php

I guess PHP's get_headers does not allow for a context, so I have to change the default stream context to only get the HEAD of a request. This causes some issues with other requests on the page. I can't seem to figure out how to reset the default stream context. I'm trying something like:
$default = stream_context_get_default(); //Get default stream context so we can reset it
stream_context_set_default( //Only fetch the HEAD
array(
'http' => array(
'method' => 'HEAD'
)
)
);
$headers = get_headers($url, 1); //Url can be whatever you want it to be
//var_dump($headers);
var_dump($default);
stream_context_set_default($default); //This doesn't work as it expects an array and not a resource pointer
Does anyone know a fix for this?
I know it has been suggested to use Curl, but I would rather not for this one. Thanks!

I ended up using the stream_get_meta_data() function to get the HTTP headers.
This is how I implemented it:
function get_headers_with_stream_context($url, $context, $assoc = 0) {
$fp = fopen($url, 'r', null, $context);
$metaData = stream_get_meta_data($fp);
fclose($fp);
$headerLines = $metaData['wrapper_data'];
if(!$assoc) return $headerLines;
$headers = array();
foreach($headerLines as $line) {
if(strpos($line, 'HTTP') === 0) {
$headers[0] = $line;
continue;
}
list($key, $value) = explode(': ', $line);
$headers[$key] = $value;
}
return $headers;
}
Called like this,
$context = stream_context_create(array('http' => array('method' => 'HEAD')));
$headers = get_headers_with_stream_context($url, $context, 1);
it gives you what you're after while leaving the standard stream_context unmodified.
Please note that this function will fail if passed anything other than an http url.
There seems to be a feature request for an additional argument for get_headers(), but the bug tracker is down as I'm writing this, so I can't check for other solutions there.

I had a similar issue but I just used the file_get_contents function with the custom stream context instead.
Here's how I implemented it:
$options = array(
'http' => array(
'method' => 'HEAD',
'follow_location' => 0
)
);
$context = stream_context_create($options);
#file_get_contents($url, NULL, $context);
var_dump($http_response_header);
Using this context only the headers will be fetched by file_get_contents and will populate the $http_response_header PHP variable.

Instead of the accepted answer, I did the following, which will work in PHP 5.3 and above, though I haven't fully tested it. (There's also a stream_context_get_params($context) but I think this is enough.)
$stream_context_defaults = stream_context_get_options(stream_context_get_default());
stream_context_set_default(
array(
'http' => array(
'method' => 'HEAD'
)
)
);
for ($i = 1; $i <= 10; $i++) {
$headers = get_headers('http://www.example.org');
}
stream_context_set_default($stream_context_defaults); // reset to defaults

As of PHP 7.1.0, get_headers() now accepts a third parameter for context.
$context = stream_context_create(
array(
'http' => array('method' => 'HEAD')
)
);
$headers = get_headers($url, true, $context);

Related

Azure search - $skip in PHP

Let's say I have this code in PHP:
public function getFromAzure($searchParam, $jobCategory, $top, $skip, $request){
$listingManager = $this->get('rd.model_manager.job_listing');
$url = $listingManager->getAzureSearchParam($request, 'azure_search_idx');
$apiKey = $listingManager->getAzureSearchParam($request, 'azure_key');
$searchParam = preg_replace('/\s+/', '+', $searchParam);
$postdata = json_encode(
array(
'search' => $searchParam,
'filter' => $category,
'orderby'=> 'publishedDate desc',
'facets' => array('locationName','employmentType', 'workSchedule','jobFunction','positionLevel','industry'),
'top' => $top,
'skip' => $skip,
'count' => true
)
);
$opts = array(
'http'=>array(
'method'=>"POST",
'header'=>"Content-type: application/json\r\n" .
"api-key: ". $apiKey . "\r\n" .
"Accept: application/json",
'content'=>$postdata
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents($url, false, $context);
$file = json_decode($file,true);
return $file;
}
Is there a way I can iterate the $skip inside this function(PHP)?
Currently I am iterating skip through Ajax call from javascript. 1 ajax call per (15 record) skip.
I need to iterate the skip because I need to load about 2,000 records(and counting)on page load, which per query is limited to 1,000. and assuming if I have 10,000 records or more. then I would have to run ajax every 1000 (for example) which could have performance issue.
btw fyi only- I need this on facets. where I have to iterate throught all records and get their value of my facet categories.
Thank you in advance! Cheers!

Webservice not able to parse JSON Request from a PHP file

I'm trying to access a webservice. I'm already using this webservice from an android app but now I need to access some functions from a php document. If I use chromes advanced rest client application for testing it works fine if I select the POST option and application/x-www-form-urlencode as content-type. But when I try to access the webservice from my PHP file I get the response from the server that it can't find the value "tag". This is the code:
$data = array( 'tag' => 'something');
$options = array('http' => array(
'method' => 'POST',
'content' => $data,
'header' => "Content-Type: application/x-www-form-urlencode")
);
$context = stream_context_create($options);
$url = 'myurl';
$result = file_get_contents($url,false,$context);
$response = json_decode($result);
What is wrong with this code?
Thanks for any help!
Try this:
$data = http_build_query( array( 'tag' => 'something') );
As defined here, "Content" value must be a string: http_build_query generate the URL-encoded query string you need.

How to log into a web service with php post request

So i need to gain access to a web service containing some json, but to do so I was told to make use of PHP POST method to first log into the web service. I was giving an array with 3 types/values.
{
"Username":"user",
"password":"1234",
"LoginClient":"user"
}
I have been searching all day for a solution, but have come up short :(.
Any advice or push into a right direction would be much appreciated.
Hope I have explained this clearly enough.
you could do as follows:
$url = 'http://yourDomain.net/api/auth/';
$data = array('Username' => 'user', 'password' => '1234', 'LoginClient' => 'user');
$opts = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
)
);
$context = stream_context_create($opts); //Creates and returns a stream context with any options supplied in options preset.
$response = file_get_contents($url, false, $context);
var_dump($response);
Or you could read about CURL as another option to make POST requests.

file_get_contents(): stream does not support seeking

I'm getting this error:
`file_get_contents(): stream does not support seeking
I have no clue to fix it. There is no Resource Id or whatsoever.
This is my code:
$postData = array('name' => $name, 'description' => $description, 'date_begin' => $start, 'date_end' => $end);
$stream = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n"
. "Authorization: Basic Y3Nub2VrOnNuMDNr\r\n",
'method' => 'POST',
'content' => http_build_query($postData)
)
);
return stream_context_create($stream);
And in the file where the stream returns to. Its the function getApiContext.
$responseJson = json_decode(file_get_contents('http://10.0.0.89/api/v1/projects', false, BaseController::getApiContext(), true));
And then I get this annoying error. I know about cUrl, but I must use streams.
why have you got true on your file_get_contents offset param? perhaps you meant to put this in the json_decode if so, try this:
$responseJson = json_decode(file_get_contents('http://10.0.0.89/api/v1/projects', false, BaseController::getApiContext()),true);
It seems you are passing the fourth parameter to file_get_contents, this is not supported for remote streams (as per the documentation: http://no1.php.net/manual/en/function.file-get-contents.php)
Change your call to file_get_contents to exclude it (or pass it to json_decode if that was your intent).
$responseJson = json_decode(file_get_contents('http://10.0.0.89/api/v1/projects', false, BaseController::getApiContext()));

PHP stream_context_create and HTTP headers - array or string, \r\n at the end, Content-Length optional?

I am troubleshooting some problems with POSTing to a remote site, specifically the remote host never returns any data (empty string).
Before I try to troubleshoot anything else, I want to make sure the calling code is actually correct. The code is:
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => "Content-Type: application/xml",
'timeout' => 60.0,
'ignore_errors' => true, # return body even if HTTP status != 200
'content' => $send_xml
)));
$response = trim(file_get_contents($this->bulk_service_url, false, $context));
All my questions belong to the "header" option and it's values, and how to correctly format it and write it. The PHP documentation, discussion below it and even stackoverflow research yield very inconsistent results.
1) do I have to include the Content-Length header, and if not, will PHP calculate it correctly? The documentation does not include it, but I've seen many people include it manually, is it then respected or overwritten by PHP?
2) do I have to pass the header option as a string, or an associative array? Manual says string, majority pass it as a string, but this comment says that if PHP was compiled with --with-curlwrappers option, you have to pass it as an array. This is very inconsistent behavior.
3) when passing as a string, do I have to include terminating \r\n characters? Especially when specifying just one header. Manual does not provide such an example, first comment on manual page does include it, second one does not, again, no clear rule on how to specify this. Does PHP automatically handle both cases?
The server is using PHP 5.3.
You should really store your headers within code as an array and finalize the preparation just prior to sending the request...
function prepareHeaders($headers) {
$flattened = array();
foreach ($headers as $key => $header) {
if (is_int($key)) {
$flattened[] = $header;
} else {
$flattened[] = $key.': '.$header;
}
}
return implode("\r\n", $flattened);
}
$headers = array(
'Content-Type' => 'application/xml',
'ContentLength' => $dl,
);
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => prepareHeaders($headers),
'timeout' => 60.0,
'ignore_errors' => true,
'content' => $send_xml
)));
$response = trim(file_get_contents($url, FALSE, $context));
Preparing context try to add:
ContentLength: {here_calculated_length} in 'header' key preceded with \r\n
"\r\n" at the end of 'header' key.
So it should look like:
$dl = strlen($send_xml);//YOUR_DATA_LENGTH
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => "Content-Type: application/xml\r\nContentLength: $dl\r\n",
'timeout' => 60.0,
'ignore_errors' => true, # return body even if HTTP status != 200
'content' => $send_xml
)));
Just a little improvement of the suggestion by #doublejosh, in case it helps someone:
(use of array notation and one-liner lambda function)
$headers = [
'Content-Type' => 'application/xml',
'Content-Length' => strlen($send_xml)
];
$context = stream_context_create(['http' => [
'method' => "POST",
'header' => array_map(function ($h, $v) {return "$h: $v";}, array_keys($headers), $headers),
'timeout' => 60.0,
'ignore_errors'=> true,
'content' => $send_xml
]
]);

Categories