GET & DELETE using file_get_contents() very slow - php

I use the file_get_contents() from server M to get the response from server X. The result was success but it take too long.
$url = "http://10.20.30.40";
$opts = array('http' =>
array(
'method' => 'GET',
'header' => 'Connection: close\r\n'
)
);
$context = stream_context_create($opts);
$result = file_get_contents($url, false, $context);
$result = json_decode($result);
$response = parse_http_response_header($http_response_header);
print_r($result);
print_r($response);
/////// below is just function to parse the response ///////
function parse_http_response_header(array $headers)
{
$responses = array();
$buffer = NULL;
foreach ($headers as $header)
{
if ('HTTP/' === substr($header, 0, 5))
{
// add buffer on top of all responses
if ($buffer) array_unshift($responses, $buffer);
$buffer = array();
list($version, $code, $phrase) = explode(' ', $header, 3) + array('', FALSE, '');
$buffer['status'] = array(
'line' => $header,
'version' => $version,
'code' => (int) $code,
'phrase' => $phrase
);
$fields = &$buffer['fields'];
$fields = array();
continue;
}
list($name, $value) = explode(': ', $header, 2) + array('', '');
// header-names are case insensitive
$name = strtoupper($name);
// values of multiple fields with the same name are normalized into
// a comma separated list (HTTP/1.0+1.1)
if (isset($fields[$name]))
{
$value = $fields[$name].','.$value;
}
$fields[$name] = $value;
}
unset($fields); // remove reference
array_unshift($responses, $buffer);
return $responses;
}
Is there any suggestion or function option to get the response (the content and the response code) faster?
(NOTE: I am not allowed to install cURL, so please gimme other option)

Related

Optimize Php function that is too slow

i made this function to test if the content has 301 redirections..
Please can you help me opimize it better because it's too slow
function contains_http_301_link($content, $current_site){
$pattern = '~<a(.*?)href="([^"]+)"(.*?)>~';
$links = array();
// Check if there is a url in the content
if(preg_match_all($pattern, $content, $urls)) {
foreach($urls[0] as $url){
// get external links
if ( !strpos( $url, $current_site )) { // Is an external link
$vowels = array('"' ,"<a", " ", "href", "=", ">");
$links[] = str_replace($vowels, "", $url);
}
}
}
foreach ($links as $link) {
$_headers = #get_headers($link,1);
if($_headers && strpos( $_headers[0], '301')) {
return true;
}
}
return false;
}
I would change the last for-loop to:
<?php
stream_context_set_default(
array(
'http' => array(
'method' => 'HEAD'
)
))
);
foreach ($links as $link) {
$_headers = get_headers($link,1);
if($_headers && strpos( $_headers[0], '301')) {
return true;
}
}
?>
or as
$context = stream_context_create(array(
'http' => array(
'method' => 'HEAD'
)
);
foreach ($links as $link) {
$_headers = get_headers($link,1, $context);
if($_headers && strpos( $_headers[0], '301')) {
return true;
}
}
By the way: if the first of 10 links found will return 301, your function returns TRUE. The same if it is the last. So your function just checks if at least one has a redirect 301 (and not 302 or 303)

Limiting and Ordering Values in Array

Using some code from NHTSA's API, my own and ideas from this site, wrapping it into a function, it is working just fine but would not run on my live server.
On the live server, it was giving an error which I finally solved to the code using an array shortcut not supported by my live server's PHP version:
Parse error: syntax error, unexpected '[', expecting ')' in /home/pchome/public_html/verify/functions/sitefunctions.php on line 9
which is this line:
$postdata = http_build_query(["data" => $VINS, "format" => "JSON"]);
Changed to this it works and also changed similar code in several other places in the same manner:
$postdata = http_build_query(array("data" => $VINS, "format" => "JSON"));
Occasionally (but not always) I may want to pass multiple VINs to it as a semicolon-separated list. This format is not changeable so what is needed to give this functionality? (Sample VINs: 3GNDA13D76S000000;5XYKT3A12CG000000
// Uses NHTSA API to decode VIN(s)
function decodeVINS($VINS) {
if ($VINS) :
$return = "";
$postdata = http_build_query(array("data" => $VINS, "format" => "JSON"));
$stream_options = array(
'http' => array(
'header' => "Content-Type: application/x-www-form-urlencoded\r\n".
"Content-Length: ".strlen($postdata)."\r\n",
'method' => "POST",
'content' => $postdata
)
);
$context = stream_context_create($stream_options);
$apiURL = "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/";
$fp = #fopen($apiURL, 'rb', FALSE, $context);
$results = array_column(json_decode(#stream_get_contents($fp),TRUE), '0');
$results = $results[0];
$output = "<blockquote>\n";
$output .= "<div><strong>VIN: {$results['VIN']}</strong></div>\n";
$output .= "<div><strong>ErrorCode: {$results['ErrorCode']}</strong></div>\n";
if ($results['AdditionalErrorText']) :
$output .= "<div><strong>AdditionalErrorText: {$results['AdditionalErrorText']}</strong></div>\n";
endif;
foreach ($results as $key => $val) :
if ($val && $key != "VIN" && $key != "ErrorCode" && $key != "AdditionalErrorText") :
$output .= "<div>$key: $val</div>";
endif;
endforeach;
$output .= "</blockquote>\n\n";
else :
$output = "Enter VINs above separated by line breaks";
endif;
return $output;
}
. . . and it is outputting something like this:
VIN: JB7FJ43S5KJ000911
ErrorCode: 0 - VIN decoded clean. Check Digit (9th position) is correct
BodyClass: Sport Utility Vehicle (SUV)/Multi Purpose Vehicle (MPV)
DisplacementCC: 3000
DisplacementCI: 183.0712322841
DisplacementL: 3
DriveType: 4WD/4-Wheel Drive/4x4
EngineConfiguration: V-Shaped
EngineCylinders: 6
FuelTypePrimary: Gasoline
GVWR: Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg)
Make: DODGE
Manufacturer: MITSUBISHI MOTORS CORPORATION (MMC)
ManufacturerId: 1052
Model: Raider
ModelYear: 1989
PlantCity: Nagoya
PlantCompanyName: Nagoya #3
PlantCountry: Japan
VehicleType: TRUCK
Working with JSON instead of CSV, in my opinion, is going to be much easier/direct/stable.
I have added a parameter ($fields) to the custom function call which will dictate how to isolate and sort your data.
I have also modified the first parameter ($VINs), to be passed as an array instead of a semicolon delimited string. This I hope simplifies your processing -- if it doesn't you are welcome to fallback to your original string format and remove my implode(";",$VINs) call.
Code: (Demo)
function searchByVINs ($VINs,$fields) {
// test multi-VIN batching via textarea at bottom of https://vpic.nhtsa.dot.gov/api/
$stream_options_content = http_build_query(["data" => implode(";", $VINS), "format" => "JSON"]);
$stream_options = [
'http' => [
'header' => "Content-Type: application/x-www-form-urlencoded\r\n".
"Content-Length: ".strlen($postdata)."\r\n",
'method' => "POST",
'content' => $postdata
]
];
$context = stream_context_create($stream_options);
$apiURL = "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/";
if (!$fp = #fopen($apiURL, "rb", FALSE, $context)) {
return ["success" => false, "response" => "Unable to open stream"];
}
if (!$response = stream_get_contents($fp),true)) {
return ["success" => false, "response" => "Unable to receive streamed data"];
}
if(($data = #json_decode($response,true)) === null && json_last_error()!==JSON_ERROR_NONE){
return ["success" => false, "response" => "Unable to parse streamed data"];
}
if (!isset($data["Message"]) || $data["Message"] != "Results returned successfully") {
return ["success" => false, "response" => "Received unsuccessful dataset"];
}
$return = [];
$keys = array_flip($fields);
foreach ($data["Results"] as $dataset) {
$isolated = array_intersect_key($dataset,$keys); // only retain the elements with keys that match $fields values
$sorted = array_replace($keys,$isolated); // order the dataset by order of elements in $fields
$return[] = $sorted;
}
return ["success" => true, "response" => $return];
}
$VINs = ["3GNDA13D76S000000", "5XYKT3A12CG000000"];
$fields = ["VIN", "ModelYear", "Make", "FuelTypePrimary", "DriveType", "BodyClass"];
$response = searchByVINs($VINs,$fields);
if (!$response["success"]) {
echo "Oops, the api call failed. {$response["response"]}";
} else {
foreach ($response["response"] as $item){
echo "<div>";
foreach ($item as $key => $value) {
echo "<div>$key: $value</div>";
}
echo "</div>";
}
}
Output (from mocked demo)
<div>
<div>VIN: 3GNDA13D76S000000</div>
<div>ModelYear: 2006</div>
<div>Make: CHEVROLET</div>
<div>FuelTypePrimary: Gasoline</div>
<div>DriveType: </div>
<div>BodyClass: Wagon</div>
</div>
<div>
<div>VIN: 5XYKT3A12CG000000</div>
<div>ModelYear: 2012</div>
<div>Make: KIA</div>
<div>FuelTypePrimary: Gasoline</div>
<div>DriveType: 4x2</div>
<div>BodyClass: Wagon</div>
</div>
All working now so here is the final version! As needed, shows only rows with values and can handle multiple VINs in one submission. The function is called from a simple form that has a textarea for entering the VINs, along with a Submit button.
// Uses NHTSA API to decode VIN(s)
function decodeVINS($VINS) {
// sample VINs 3GNDA13D76S000000;5XYKT3A12CG000000
if ($VINS) :
$postdata = http_build_query(array("data" => $VINS, "format" => "JSON"));
$stream_options = array(
'http' => array(
'header' => "Content-Type: application/x-www-form-urlencoded\r\n".
"Content-Length: ".strlen($postdata)."\r\n",
'method' => "POST",
'content' => $postdata
)
);
$context = stream_context_create($stream_options);
$apiURL = "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/";
$fp = #fopen($apiURL, 'rb', FALSE, $context);
$returnValue = json_decode(#stream_get_contents($fp),TRUE);
if(!isset($returnValue['Results'])):
echo "Invalid return data or no return data. Exiting";
return FALSE;
endif;
$results = $returnValue['Results'];
if(!is_array($results)):
$results = array($results);
endif;
$output = '';
foreach($results as $result):
$output .= "<blockquote>\n";
$output .= "<div><strong>VIN: {$result['VIN']}</strong></div>\n";
$output .= "<div><strong>ErrorCode: {$result['ErrorCode']}</strong></div>\n";
if ($result['AdditionalErrorText']) :
$output .= "<div><strong>AdditionalErrorText: {$result['AdditionalErrorText']}</strong></div>\n";
endif;
foreach ($result as $key => $val) :
if ($val && $key != "VIN" && $key != "ErrorCode" && $key != "AdditionalErrorText") :
$output .= "<div>$key: $val</div>";
endif;
endforeach;
$output .= "</blockquote>\n\n";
endforeach;
else :
$output = "Enter VINs above separated by line breaks";
endif;
return $output;
}

Twitter usertimeline code not working

I have created this test script to get data from the twitter usertimeline which I'm sure was previously working however now it returns nothing. Is there something I am missing here? (To test simply amend the constants at the top)
define('CONSUMER_KEY', '');
define('CONSUMER_SECRET', '');
define('OAUTH_TOKEN','');
define('OAUTH_SECRET','');
define('USER_ID','');
function generateSignature($oauth,$fullurl,$http_method){
// Take params from url
$main_url = explode('?',$fullurl);
$urls = explode('&',$main_url[1]);
foreach ($urls as $param){
$bits = explode('=',$param);
if (strlen($bits[0])){
$oauth[$bits[0]] = rawurlencode($bits[1]);
}
}
ksort($oauth);
$string = http_build_query($oauth);
$new_string = strtoupper($http_method).'&'.urlencode($main_url[0]).'&'.urlencode(urldecode($string));
$sign_str = CONSUMER_SECRET.'&'.OAUTH_SECRET;
return urlencode(base64_encode(hash_hmac('sha1',$new_string,$sign_str,true)));
}
function random($len,$use_chars = false,$numU = false){
$num = range(0,9);
$letu = range('A','Z');
$letl = range('a','z');
$chars = array("!","*","£","$","^","(",")","_","+");
if ($use_chars){
$arr = array_merge($num,$letu,$letl,$chars);
} else {
$arr = array_merge($num,$letu,$letl);
}
// Shuffling - new addition 11/9 to make order actually random!
shuffle($arr);
// Create a number only random string
if ($numU){ $arr = $num; }
$rand = array_rand($arr,$len);
foreach ($rand as $num){
$out[] = $arr[$num];
}
return implode('',$out);
}
$method = 'GET';
// Twitter still uses Oauth1 (which is a pain)
$oauth = array(
'oauth_consumer_key'=>CONSUMER_KEY,
'oauth_nonce'=>random(32),
'oauth_signature_method'=>'HMAC-SHA1',
'oauth_timestamp'=>time(),
'oauth_token'=>OAUTH_TOKEN,
'oauth_version'=>'1.0',
);
$url = "https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=".USER_ID;
$oauth['oauth_signature'] = generateSignature($oauth,$url,$method,'');
ksort($oauth);
foreach ($oauth as $k=>$v){
$auths[] = $k.'="'.$v.'"';
}
$stream = array('http' =>
array(
'method' => $method,
// ignore_errors should be true
'ignore_errors'=>true, // http://php.net/manual/en/context.http.php - otherwise browser returns error not error content
'follow_location'=>false,
'max_redirects'=>0,
'header'=> array(
'Authorization: OAuth '.implode(', ',$auths),
'Connection: close'
)
)
);
echo $url;
$response = file_get_contents($url, false, stream_context_create($stream));
print'<pre>';print_r($stream);print'</pre>';
print'<pre>[';print_r($reponse);print']</pre>';
I found this:
// Create a number only random string
if ($numU){ $arr = $num; }
$rand = array_rand($arr,$len);
foreach ($rand as $num){
$out[] = $arr[$num];
}
I am not completly sure, but i think there shouldn't be a } after if ($numU){ $arr = $num;
I think it should be a open bracket. {
I found one more thing:
print'<pre>[';print_r($reponse);print']</pre>';
Here at the bottom of the code, you wrote "$reponse" instead of "$response"
I hope it helped! If it did, give it a upvote and choose as best answer!

file_get_contents get Cookies

I'm trying to develop a full PHP web browser that can handle cookies. I've created the following class:
<?php
class Browser
{
private $cookies = '';
private $response_cookies = '';
private $content = '';
/**
* Cookie manager
* #Description : To set or get cookies as Array or String
*/
public function set_cookies_json($cookies)
{
$cookies_json = json_decode($cookies, true);
$cookies_array = array();
foreach ($cookies_json as $key => $value)
{
$cookies_array[] = $key .'='.$value;
}
$this->cookies = 'Cookie: ' . $cookies_array.join('; ') . "\r\n";
}
public function set_cookies_string($cookies)
{
$this->cookies = 'Cookie: ' . $cookies . "\r\n";
}
private function get_cookies()
{
global $http_response_header;
$cookies_array = array();
foreach($http_response_header as $s)
{
if (preg_match('|^Set-Cookie:\s*([^=]+)=([^;]+);(.+)$|', $s, $parts))
{
$cookies_array[] = $parts[1] . '=' . $parts[2];
}
}
$this->cookies = 'Cookie: ' . $cookies_array.join('; ') . "\r\n";
}
/**
* GET and POST request
* Send a GET or a POST request to a remote URL
*/
public function get($url)
{
$opts = array(
'http' => array(
'method' => 'GET',
'header' => "Accept-language: en\r\n" .
$this->cookies
)
);
$context = stream_context_create($opts);
$this->content = file_get_contents($url, false, $context);
$this->get_cookies();
return $this->content;
}
public function post($url, $post_data)
{
$post_content = array();
foreach ($post_data as $key => $value)
{
$post_content[] = $key .'='.$value;
}
$opts = array(
'http' => array(
'method' => 'GET',
'header' => "Content-type: application/x-www-form-urlencoded\r\n" .
$this->cookies,
'content' => $post_content.join('&'),
)
);
$context = stream_context_create($opts);
$this->content = file_get_contents($url, false, $context);
$this->get_cookies();
return $this->content;
}
}
Basically, it can send a GET request and 'should' retrieve the cookies.
I've made a very simple test script:
<?php
require('browser.class.php');
$browser = new Browser();
$browser->get('http://google.com');
print_r($browser->response_cookies);
But it fails on line 32 as $http_response_header looks to be null. Isn't it supposed to contain the header of my response ? I've read that page but it looks to work well for this guy : get cookie with file_get_contents in PHP
I know I could use cUrl to handle this but I'd really like to use a rough PHP code.
Did I make something wrong ?
Thanks for your precious help.
Edit:
Solution is:
<?php
class Browser
{
public $request_cookies = '';
public $response_cookies = '';
public $content = '';
/**
* Cookie manager
* #Description : To set or get cookies as Array or String
*/
public function set_cookies_json($cookies)
{
$cookies_json = json_decode($cookies, true);
$cookies_array = array();
foreach ($cookies_json as $key => $value)
{
$cookies_array[] = $key .'='.$value;
}
$this->request_cookies = 'Cookie: ' . join('; ', $cookies_array) . "\r\n";
}
public function set_cookies_string($cookies)
{
$this->request_cookies = 'Cookie: ' . $cookies . "\r\n";
}
private function get_cookies($http_response_header)
{
$cookies_array = array();
foreach($http_response_header as $s)
{
if (preg_match('|^Set-Cookie:\s*([^=]+)=([^;]+);(.+)$|', $s, $parts))
{
$cookies_array[] = $parts[1] . '=' . $parts[2];
}
}
$this->response_cookies = 'Cookie: ' . join('; ', $cookies_array) . "\r\n";
}
/**
* GET and POST request
* Send a GET or a POST request to a remote URL
*/
public function get($url)
{
$opts = array(
'http' => array(
'method' => 'GET',
'header' => "Accept-language: en\r\n" .
$this->request_cookies
)
);
$context = stream_context_create($opts);
$this->content = file_get_contents($url, false, $context);
$this->get_cookies($http_response_header);
return $this->content;
}
public function post($url, $post_data)
{
$post_content = array();
foreach ($post_data as $key => $value)
{
$post_content[] = $key .'='.$value;
}
$opts = array(
'http' => array(
'method' => 'GET',
'header' => "Content-type: application/x-www-form-urlencoded\r\n" .
$this->request_cookies,
'content' => join('&', $post_content),
)
);
$context = stream_context_create($opts);
$this->content = file_get_contents($url, false, $context);
$this->get_cookies($http_response_header);
return $this->content;
}
}
According to php.net:
$http_response_header will be created in the local scope.
Because of this $http_response_header is available only in the scope of get().
You can pass it like $this->get_cookies($http_response_header); or create a property to store it.

why POST method is not working?

I have do post some information in cross domain . And i am achieving this thing by below code
<?php
function do_post_request($sendingurl, $data, $optional_headers = null) {
$params = array(
'http' => array(
'method' => 'POST',
'url' => $data
)
);
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
$ctx = stream_context_create($params);
$fp = #fopen($sendingurl, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with $sendingurl, $php_errormsg");
}
$response = #stream_get_contents($fp);
if ($response === false) {
throw new Exception("Problem reading data from $sendingurl, $php_errormsg");
}
return $response;
}
$response = do_post_request('http://mag16.playtrickz.com/testing.php','http%3A%2F%2Fwww.facebook.com');
echo $response;
But it is not working .
On successful POST Request : It will display its value
otherwise it will show : nodata found.
Why it is not working and how to make them work .
Here is how I would write your function:
function do_post_request($url, $data = NULL, $optional_headers = NULL) {
// Build a body string from an array
$content = (is_array($data)) ? http_build_query($data) : '';
// Parse the array of headers and strip values we will be setting
$headers = array();
if (is_array($optional_headers)) {
foreach ($optional_headers as $name => $value) {
if (!in_array(strtolower($name), array('content-type', 'content-length', 'connection'))) {
$headers[$name] = $value;
}
}
}
// Add our pre-set headers
$headers['Content-Type'] = 'application/x-www-form-urlencoded';
$headers['Content-Length'] = strlen($content);
$headers['Connection'] = 'close';
// Build headers into a string
$header = array();
foreach ($headers as $name => $value) {
if (is_array($value)) {
foreach ($value as $multi) {
$header[] = "$name: $multi";
}
} else {
$header[] = "$name: $value";
}
}
$header = implode("\r\n", $header);
// Create the stream context
$params = array(
'http' => array(
'method' => 'POST',
'header' => $header,
'content' => $content
)
);
$ctx = stream_context_create($params);
// Make the request
$fp = #fopen($url, 'rb', FALSE, $ctx);
if (!$fp) {
throw new Exception("Problem with $url, $php_errormsg");
}
$response = #stream_get_contents($fp);
if ($response === FALSE) {
throw new Exception("Problem reading data from $url, $php_errormsg");
}
return $response;
}
This has been re-built so that the data to send to the server and the headers are passed in as associative arrays. So you would build an array that looks like you would want $_POST to look in the remote script, and pass that in. You can also pass an array of additional headers to send, but the function will automatically add a Content-Type, Content-Length and Connection header.
So your request would be called like this:
$data = array(
'url' => 'http://www.facebook.com/'
);
$response = do_post_request('http://mag16.playtrickz.com/testing.php', $data);
echo $response;

Categories