how does http Accept header work? - php

Here is my code;
<?php $url = #$_POST["ekleme"];
if (filter_var($url,FILTER_VALIDATE_URL) === FALSE) {
die("Geçersiz link!");
}
$cparams = array('http'=>array('method'=>"GET",'Accept'=>'image/jpg,image/gif,image/png'));
$context = stream_context_create($cparams);
$fp = #fopen($url, 'rb', false, $context);
if (!$fp) die("Problem with url");
$meta = stream_get_meta_data($fp);
var_dump($meta);
I am giving it an url for an pdf file. I expect it to give some kind of http error. But this is what I got;
array(10) {
["wrapper_data"]=>
array(9) {
[0]=>
string(15) "HTTP/1.1 200 OK"
[1]=>
string(35) "Date: Wed, 02 Jan 2013 14:16:02 GMT"
[2]=>
string(14) "Server: Apache"
[3]=>
string(44) "Last-Modified: Wed, 19 Dec 2012 13:53:09 GMT"
[4]=>
string(34) "ETag: "1c80e53-f5a7-4d134ef3b7b40""
[5]=>
string(20) "Accept-Ranges: bytes"
[6]=>
string(21) "Content-Length: 62887"
[7]=>
string(29) "Content-Type: application/pdf"
[8]=>
string(17) "Connection: close"
}
It continues to show other unrelated things. Did I get how Accept header works wrong, or am I doing something wrong? Is there a way to ask a server only send data if content type is something spesific?

The Accept header lets a client tell the server what types of data it can handle.
The server may ignore it completely (this is normal if a resource only exists in one format) or it may use it to pick the format best suited to the client (it might respond with a 406 Not Acceptable error if it doesn't have the data in a suitable format).
You are experiencing the former behaviour. The URL points to a PDF file. The server isn't set up to decide between PDF and other formats, so it doesn't pay attention to the Accept header and it returns the PDF.
Is there a way to ask a server only send data if content type is something spesific?
The accept header is as close as you can get.
If you want to avoid downloading large files that you might not be able to process, make a HEAD request and check the Content-Type of the response before you make a GET request.

When receiving a file, you are responsible for checking the content type. The accept header is just for telling the server which content type you prefer, not which one you demand.
Here is an example on how to check the returned content type.
$meta = stream_get_meta_data($fp);
$allowed = array("image/jpg", "image/gif", "image/png");
foreach($meta['wrapper_data'] as $header) {
if(preg_match('/content-type: (.*)/i', $header, $matches)) {
if(!in_array(strtolower($matches[1], $allowed)) {
die("Invalid content type");
}
}
}

Related

Check if URL exists - Not Working with php get_headers

I need to determine if a URL exits. I ran across this post.
How can I check if a URL exists via PHP?
$file = 'http://godaddy';
$file_headers = #get_headers($file);
if($file_headers[0] == 'HTTP/1.1 404 Not Found')
{
$exists = false;
}
else
{
$exists = true;
}
And implemented this code and when I tested it as a user who forgot to put in the .com it comes back with true. Which isn't correct because if you go to http://godaddy there is no website.
I tried validating the $file before hand but
filter_var($url, FILTER_VALIDATE_URL);
views http://godaddy as a valid url.
Any idea how to handle this sort of input?
var_dump($file_headers)= array(8) {
[0]=> string(15) "HTTP/1.1 200 OK"
[1]=> string(13) "Server: nginx"
[2]=> string(35) "Date: Mon, 29 Jun 2015 14:23:07 GMT"
[3]=> string(23) "Content-Type: text/html"
[4]=> string(17) "Connection: close"
[5]=> string(21) "Vary: Accept-Encoding"
[6]=> string(38) "Expires: Mon, 29 Jun 2015 14:23:06 GMT"
[7]=> string(23) "Cache-Control: no-cache"
}
Try without the # character. in this way you can see the direct error. I think the error masking cannot permit the correct reading of the response of the get_header

file_exists() return false for files with whitespaces in the name

I have this code:
$url = 'http://www.bgelectronics.eu/image/cache/data/cantell kabeli /14222-228x228.jpg';
$headers = get_headers($url, true);
var_dump($headers);
this returns error for missing file because of the whitespace in the file name:
array(6) { [0]=> string(34) "HTTP/1.1 500 Internal Server Error" ["Date"]=>
string(29) "Tue, 24 Mar 2015 16:11:18 GMT" ["Server"]=> string(6) "Apache"
["Content-Length"]=> string(3) "677" ["Connection"]=> string(5) "close"
["Content-Type"]=> string(29) "text/html; charset=iso-8859-1" } file size:677
Any suggestions please?
The problem is that file_exists() is for the file system, not http. You need to use server directory path. If it is on the same server as your code, it should rather look like:
if(file_exists('image/cache/data/cantell kabeli /202441-500x500.jpg')){
....
if on remote server, try:
if(file_get_contents('http://www.bgelectronics.eu/image/cache/data/cantell kabeli /202441-500x500.jpg')){
...
You can find many other ways here: How can one check to see if a remote file exists using PHP?
Try with this :
copy('http://www.bgelectronics.eu/image/cache/data/cantell kabeli /202441-500x500.jpg', '/image.jpeg');
if not, use file_get_contents
//Get the file
$content = file_get_contents("http://www.bgelectronics.eu/image/cache/data/cantell kabeli /202441-500x500.jpg");
//Store in the filesystem.
$fp = fopen("/location/to/save/image.jpg", "w");
fwrite($fp, $content);
fclose($fp);

Cannot retrieve reddit user identity

I need only to authenticate Reddit users in to my website (in php). I'm using simple file_get_contents with stream_context_create for headers. I have already implemented Facebook user authentication.
For Reddit, I can successfully get an access_token. But when I GET request /api/v1/me with that access_token, I'm always getting HTTP/1.1 403 Forbidden.
Please Help.
This is the php code I'm using after I receive access_token
$opts = array('http' =>
array(
'method' => 'GET',
'header' => 'Authorization: bearer '.$result->access_token)
);
$context = stream_context_create($opts);
$result = file_get_contents('https://oauth.reddit.com/api/v1/me', false, $context);
Is there anything I'm missing..
Here is the var_dump
array(7) {
[0]=> string(22) "HTTP/1.1 403 Forbidden"
[1]=> string(24) "Server: cloudflare-nginx"
[2]=> string(35) "Date: Sun, 23 Nov 2014 06:XX:XX GMT"
[3]=> string(38) "Content-Type: text/html; charset=UTF-8"
[4]=> string(17) "Connection: close"
[5]=> string(139) "Set-Cookie: __cfduid=XXXXXXXX; expires=Mon, 23-Nov-15 06:XX:XX GMT; path=/; domain=.reddit.com; HttpOnly"
[6]=> string(28) "CF-RAY: XXXXXXXXX-XXX"
}
Per the reddit API rules, you need to send a unique User-Agent with your request.
Change your client's User-Agent string to something unique and descriptive, preferably referencing your reddit username.
Example: User-Agent: flairbot/1.0 by spladug
Many default User-Agents (like "Python/urllib" or "Java") are drastically limited to encourage unique and descriptive user-agent strings.

Check if swf url avaliable or not using php get_headers Content-Type

I'm trying to drop invalid URLs from my flash games site.
Here is my code:
function valid($URL1) {
$headers = get_headers($URL1);
$headers = substr($headers[8],38,5);//leaves only flash word
if ($headers=='flash')
return true; else return false;
}
$URL1='http://www.ht83.com/medias/media-16/ht83com-cde-house-decoration.swf';
if(valid($URL1))
echo 'SWF are word>' ;
that code return true even Content-Type are not swf .
by the way I already tried
$headers=$headers['Content-Type'];
but give me no result .
When I tried
var_dump($headers);
return this for valid SWF URL
http://www.ht83.com/medias/media-16/ht83com-spongebob-squarepants-gone-fishing.swf
array(9) { [0]=> string(15) "HTTP/1.1 200 OK" [1]=> string(35) "Date:
Sat, 01 Feb 2014 01:36:35 GMT" [2]=> string(144) "Server:
Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.8m DAV/2
mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
mod_fcgid/2.3.5" [3]=> string(20) "Accept-Ranges: bytes" [4]=>
string(22) "Content-Length: 342771" [5]=> string(39) "Cache-Control:
max-age=62208000, public" [6]=> string(38) "Expires: Mon, 03 Mar 2014
01:36:35 GMT" [7]=> string(17) "Connection: close" [8]=> string(43)
"Content-Type: application/x-shockwave-flash" }
AND this for the Invalid SWF URL
http://www.ht83.com/medias/media-16/ht83com-cde-house-decoration.swf
array(12) { [0]=> string(15) "HTTP/1.1 200 OK" [1]=> string(35) "Date:
Sat, 01 Feb 2014 01:40:06 GMT" [2]=> string(144) "Server:
Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.8m DAV/2
mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
mod_fcgid/2.3.5" [3]=> string(24) "X-Powered-By: PHP/5.2.16" [4]=>
string(38) "Expires: Thu, 19 Nov 1981 08:52:00 GMT" [5]=> string(77)
"Cache-Control: no-store, no-cache, must-revalidate, post-check=0,
pre-check=0" [6]=> string(16) "Pragma: no-cache" [7]=> string(62)
"Set-Cookie: PHPSESSID=359cf391842876b3cc79066dcc3a08f4; path=/" [8]=>
string(21) "Vary: Accept-Encoding" [9]=> string(52) "Cache-Control:
max-age=600, private, must-revalidate" [10]=> string(17) "Connection:
close" [11]=> string(23) "Content-Type: text/html" }
So their is any easier way to get correct Content-Type of URL .
Looks like I used get_headers() in numeric only . this code from Sean Johnson works
function valid($URL) {
$headers = get_headers($URL, 1);//
return stripos($headers['Content-Type'],"application/x-shockwave-flash")!==false;
}
According to the very first example of the get_headers documentation you need to use the second argument if you want to be able to access the header by it's key value.
Try this:
function valid($URL) {
$headers = get_headers($URL,1);
return stripos($headers['Content-Type'],"flash")!==false;
}
Your code is assuming that the Content-Type header will always be the 9th header returned by the server, which is not the case.
You will need to loop through the headers and examine only the correct one (that is, the one that starts with Content-Type:).

LinkedIn API returns 'Unauthorized' response (PHP OAuth)

I've been struggling with this one for a few days now. I've got a test app set up to connect to LinkedIn via OAuth. I want to be able to update a user's status, but at the moment I'm unable to interact with LinkedIn's API at all.
I am able to successfully get a requestToken, then an accessToken, but when I issue a request to the API, I see an 'unauthorized' error that looks something like this:
object(OAuthException)#2 (8) {
["message:protected"]=> string(73) "Invalid auth/bad request (got a 401, expected HTTP/1.1 20X or a redirect)"
["string:private"]=> string(0) ""
["code:protected"]=> int(401)
["file:protected"]=> string(47) "/home/pmfeorg/public_html/dev/test/linkedin.php"
["line:protected"]=> int(48)
["trace:private"]=> array(1) {
[0]=> array(6) {
["file"]=> string(47) "/home/pmfeorg/public_html/dev/test/linkedin.php"
["line"]=> int(48)
["function"]=> string(5) "fetch"
["class"]=> string(5) "OAuth"
["type"]=> string(2) "->"
["args"]=> array(2) {
[0]=> string(35) "http://api.linkedin.com/v1/people/~"
[1]=> string(3) "GET"
}
}
}
["lastResponse"]=> string(358) " 401 1276375790558 0000 [unauthorized]. OAU:Bhgk3fB4cs9t4oatSdv538tD2X68-1OTCBg-KKL3pFBnGgOEhJZhFOf1n9KtHMMy|48032b2d-bc8c-4744-bb84-4eab53578c11|*01|*01:1276375790:xmc3lWhXJvLSUZh4dxMtrf55VVQ= "
["debugInfo"]=> array(5) {
["sbs"]=> string(329) "GET&http%3A%2F%2Fapi.linkedin.com%2Fv1%2Fpeople%2F~&oauth_consumer_key%3DBhgk3fB4cs9t4oatSdv538tD2X68-1OTCBg-KKL3pFBnGgOEhJZhFOf1n9KtHMMy%26oauth_nonce%3D7068001084c13f2ee6a2117.22312548%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1276375790%26oauth_token%3D48032b2d-bc8c-4744-bb84-4eab53578c11%26oauth_version%3D1.0"
["headers_sent"]=> string(401) "GET /v1/people/~?GET&oauth_consumer_key=Bhgk3fB4cs9t4oatSdv538tD2X68-1OTCBg-KKL3pFBnGgOEhJZhFOf1n9KtHMMy&oauth_signature_method=HMAC-SHA1&oauth_nonce=7068001084c13f2ee6a2117.22312548&oauth_timestamp=1276375790&oauth_version=1.0&oauth_token=48032b2d-bc8c-4744-bb84-4eab53578c11&oauth_signature=xmc3lWhXJvLSUZh4dxMtrf55VVQ%3D HTTP/1.1 User-Agent: PECL-OAuth/1.0-dev Host: api.linkedin.com Accept: */*"
["headers_recv"]=> string(148) "HTTP/1.1 401 Unauthorized Server: Apache-Coyote/1.1 Date: Sat, 12 Jun 2010 20:49:50 GMT Content-Type: text/xml;charset=UTF-8 Content-Length: 358"
["body_recv"]=> string(358) " 401 1276375790558 0000 [unauthorized]. OAU:Bhgk3fB4cs9t4oatSdv538tD2X68-1OTCBg-KKL3pFBnGgOEhJZhFOf1n9KtHMMy|48032b2d-bc8c-4744-bb84-4eab53578c11|*01|*01:1276375790:xmc3lWhXJvLSUZh4dxMtrf55VVQ= "
["info"]=> string(216) "About to connect() to api.linkedin.com port 80 (#0) Trying 64.74.98.83... connected Connected to api.linkedin.com (64.74.98.83) port 80 (#0) Connection #0 to host api.linkedin.com left intact Closing connection #0 "
}
}
My code looks like this (based on the FireEagle example from php.net):
$req_url = 'https://api.linkedin.com/uas/oauth/requestToken';
$authurl = 'https://www.linkedin.com/uas/oauth/authenticate';
$acc_url = 'https://api.linkedin.com/uas/oauth/accessToken';
$api_url = 'http://api.linkedin.com/v1/people/~';
$callback = 'http://www.pmfe.org/dev/test/linkedin.php';
$conskey = 'Bhgk3fB4cs9t4oatSdv538tD2X68-1OTCBg-KKL3pFBnGgOEhJZhFOf1n9KtHMMy';
$conssec = '####################SECRET KEY#####################';
session_start();
try {
$oauth = new OAuth($conskey,$conssec,OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI);
$oauth->enableDebug();
if(!isset($_GET['oauth_token'])) {
$request_token_info = $oauth->getRequestToken($req_url);
$_SESSION['secret'] = $request_token_info['oauth_token_secret'];
header('Location: '.$authurl.'?oauth_token='.$request_token_info['oauth_token']);
exit;
} else {
$oauth->setToken($_GET['oauth_token'],$_SESSION['secret']);
$access_token_info = $oauth->getAccessToken($acc_url);
$_SESSION['token'] = $access_token_info['oauth_token'];
$_SESSION['secret'] = $access_token_info['oauth_token_secret'];
}
$oauth->setToken($_SESSION['token'],$_SESSION['secret']);
$oauth->fetch($api_url, OAUTH_HTTP_METHOD_GET);
$response = $oauth->getLastResponse();
} catch(OAuthException $E) {
var_dump($E);
}
I've successfully set up a connection to Twitter and one to Facebook using OAuth, but LinkedIn keeps eluding me. If anyone could offer some advice or point me in the right direction, I will be extremely appreciative!
Well, I found the source of the problem, but there's a new problem now:
My original question was wrong - I wasn't getting an accessToken at all. The problem was that I wasn't passing the verifier code (obtained during the requestToken step) during the getAccessToken call.
So rather than this...
$access_token_info = $oauth->getAccessToken($acc_url);
...I needed to do this...
$_SESSION['verifier'] = $_GET['oauth_verifier'];
$access_token_info = $oauth->getAccessToken($acc_url, $_SESSION['verifier'], $_SESSION['verifier']);
I hope this info helps someone else out. This is the first time I've worked with OAuth, but it seems like LinkedIn has a very strict implementation.
Anyway, now I need to figure out why LI is returning a 401 when I try to update my status... I've authorized the app, and can pull data down, but am unable to set any data. Maybe there are additional permissions hidden in LI's settings somewhere?
Unless LinkedIn has a totally wonky view of HTTP status codes, 401 means it was expecting a WWW-Authenticate header (ie: username/password in base64 format) and didn't get it, so it's denying access.
Perhaps you have to do an OAuth::setAuthType().

Categories