PHP get_headers() fails with Pinterest - php

I'm currently working on a tool to integrates link of different social networks:
Facebook: https://www.facebook.com/jonathan.parentlevesque
Google plus: https://plus.google.com/+JonathanParentL%C3%A9vesque
Instagram: https://instagram.com/mariloubiz/
Pinterest: https://www.pinterest.com/jonathan_parl/
RSS: https://regex101.com
Twitter: https://twitter.com/arcadefire
Vimeo: https://vimeo.com/ondemand/crashtest/135301838
Youtube: https://www.youtube.com/user/Darkjo666
I'm using very basic regex like this one:
/^https?:\/\/(?:[a-z]{2}|[w]{3})?\.pinterest.com\/[\S]{5,}$/i
on client and server side for minimal domain validation on each links.
Then, I'm using this function to validate that the page really exists (it's useless to integrate social network links that don't work after all):
public static function isUrlExists($url){
$exists = false;
if(!StringManager::stringStartWith($url, "http") and !StringManager::stringStartWith($url, "ftp")){
$url = "https://" . $url;
}
if (preg_match(RegularExpression::URL, $url)){
$headers = get_headers($url);
if ($headers !== false and !empty($headers)){
if (strpos($headers[0], '404') === false){
$exists = true;
}
}
}
return $exists;
}
Note: In this function I'm using Diego Perini's regex for validating the URL before sending the request:
const URL = "%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?#|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)(?:\.(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)*(?:\.[a-z\x{00a1}-\x{ffff}]{2,6}))(?::\d+)?(?:[^\s]*)?$%iu"; //#copyright Diego Perini
All the tested links so far didn't generate any error, but testing Pinterest produce me this quite scary series of error messages:
get_headers(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Array
(
[url] => https://www.pinterest.com/jonathan_parl/
[exists] =>
)
get_headers(): Failed to enable crypto
Array
(
[url] => https://www.pinterest.com/jonathan_parl/
[exists] =>
)
get_headers(https://www.pinterest.com/jonathan_parl/): failed to open stream: operation failed
Array
(
[url] => https://www.pinterest.com/jonathan_parl/
[exists] =>
)
Is anyone has an idea what I'm doing wrong here?
I mean, ain't Pinterest a popular social network with a valid certificate (I don't use it personally, I just created an account for testing)?
Thank you for your help,
Jonathan Parent-Lévesque from Montreal

I tried to create a self-signed certificate for my development environment (Xampp) as suggested by N.B. in his comment. That solution didn't worked for me.
His other solution was to use cUrl or guzzle instead get_headers(). Not only it worked, but, according to this developper's tests:
http://php.net/manual/fr/function.get-headers.php#104723
it is also way faster than get_headers().
For those interested, here's the code of my new function for those interested:
/**
* Send an HTTP request to a the $url and check the header posted back.
*
* #param $url String url to which we must send the request.
* #param $failCodeList Int array list of codes for which the page is considered invalid.
*
* #return Boolean
*/
public static function isUrlExists($url, array $failCodeList = array(404)){
$exists = false;
if(!StringManager::stringStartWith($url, "http") and !StringManager::stringStartWith($url, "ftp")){
$url = "https://" . $url;
}
if (preg_match(RegularExpression::URL, $url)){
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($handle, CURLOPT_HEADER, true);
curl_setopt($handle, CURLOPT_NOBODY, true);
curl_setopt($handle, CURLOPT_USERAGENT, true);
$headers = curl_exec($handle);
curl_close($handle);
if (empty($failCodeList) or !is_array($failCodeList)){
$failCodeList = array(404);
}
if (!empty($headers)){
$exists = true;
$headers = explode(PHP_EOL, $headers);
foreach($failCodeList as $code){
if (is_numeric($code) and strpos($headers[0], strval($code)) !== false){
$exists = false;
break;
}
}
}
}
return $exists;
}
Let me explains the curl options:
CURLOPT_RETURNTRANSFER: return a string instead of displaying the calling page on the screen.
CURLOPT_SSL_VERIFYPEER: cUrl won't checkout the certificate
CURLOPT_HEADER: include the header in the string
CURLOPT_NOBODY: don't include the body in the string
CURLOPT_USERAGENT: some site needs that to function properly (by example : https://plus.google.com)
Additional note: I explode the header string and user headers[0] to be sure to only validate only the return code and message (example: 200, 404, 405, etc.)
Additional note 2: Sometime validating only the code 404 is not enough (see the unit test), so there's an optional $failCodeList parameter to supply all the code list to reject.
And, of course, here's the unit test to legitimates my coding:
public function testIsUrlExists(){
//invalid
$this->assertFalse(ToolManager::isUrlExists("woot"));
$this->assertFalse(ToolManager::isUrlExists("https://www.facebook.com/jonathan.parentlevesque4545646456"));
$this->assertFalse(ToolManager::isUrlExists("https://plus.google.com/+JonathanParentL%C3%A9vesque890800"));
$this->assertFalse(ToolManager::isUrlExists("https://instagram.com/mariloubiz1232132/", array(404, 405)));
$this->assertFalse(ToolManager::isUrlExists("https://www.pinterest.com/jonathan_parl1231/"));
$this->assertFalse(ToolManager::isUrlExists("https://regex101.com/546465465456"));
$this->assertFalse(ToolManager::isUrlExists("https://twitter.com/arcadefire4566546"));
$this->assertFalse(ToolManager::isUrlExists("https://vimeo.com/**($%?%$", array(400, 405)));
$this->assertFalse(ToolManager::isUrlExists("https://www.youtube.com/user/Darkjo666456456456"));
//valid
$this->assertTrue(ToolManager::isUrlExists("www.google.ca"));
$this->assertTrue(ToolManager::isUrlExists("https://www.facebook.com/jonathan.parentlevesque"));
$this->assertTrue(ToolManager::isUrlExists("https://plus.google.com/+JonathanParentL%C3%A9vesque"));
$this->assertTrue(ToolManager::isUrlExists("https://instagram.com/mariloubiz/"));
$this->assertTrue(ToolManager::isUrlExists("https://www.facebook.com/jonathan.parentlevesque"));
$this->assertTrue(ToolManager::isUrlExists("https://www.pinterest.com/"));
$this->assertTrue(ToolManager::isUrlExists("https://regex101.com"));
$this->assertTrue(ToolManager::isUrlExists("https://twitter.com/arcadefire"));
$this->assertTrue(ToolManager::isUrlExists("https://vimeo.com/"));
$this->assertTrue(ToolManager::isUrlExists("https://www.youtube.com/user/Darkjo666"));
}
I hope this solution will help someone,
Jonathan Parent-Lévesque from Montreal

Related

HTTP Response Code 0 - Site is working

I am making a website that will check if a website is working and live. I pass in the URL of the site I would like to check and the following code will check if the site is live and return the HTTP response code as well as true or false.
function urlExists($url=NULL)
{
if($url == NULL) return false;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpcode == 0) {
return array (false, $httpcode);
}
else if($httpcode < 400){
return array (true, $httpcode);
} else {
return array (false, $httpcode);
}
}
With one of the sites I am testing though I am getting the HTTP response code of 0 even though I know that the site is live and working.
The site is very slow as its a large site on a not very powerful server so response times can vary between 7 - 25 seconds.
Any help would be greatly appreciated.
Thanks,
Sam
Based on these two links:-
https://curl.haxx.se/libcurl/c/CURLOPT_TIMEOUT.html
And
https://curl.haxx.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html
First one is:- set maximum time the request is allowed to take
Second one is:- timeout for the connect phase
As you said that the Site URL you are hitting is taking 7-25 second for responding. meanwhile your CURL request is terminated and closed because of these two time settings.
Increase these two time settings in your code and it will work for you.
thanks.
I will offer 2 alternatives for you to compare - along with your curl() function, you will have 3 options to see which one is better/faster for you.
Option A (all php versions), requires fopen() to be activated:
if (!$fp = fopen($url, 'r'))
{
trigger_error("Unable to open URL ($url)", E_USER_ERROR);
}
$headers = stream_get_meta_data($fp);
fclose($fp);
$http_header_info = $headers['wrapper_data'][0];
$httpCode = (int)substr($http_header_info, 9, 3);
Option B (php5+):
$headers = get_headers($url, 1);
$http_header_info = $headers[0];
$httpCode = substr($http_header_info, 9, 3);
Also, if anyone has benchmarks on these 3 approaches, i am curious to see which is more appropriate (only for retrieving http response headers of course)
Code 0 returns often when used invalid URL syntax or host not found error.
You can also call curl_error($ch) function (http://php.net/manual/en/function.curl-error.php) to determine error details.

simplexml_load_file not working with variable but works with string

I am trying to connect to a CRM (Pardot).
I have this to create the URL necessary to call the XML:
//this will log in and print your API Key (good for 1 hour) to the console
$rz_key = callPardotApi('https://pi.pardot.com/api/login/version/3',
array(
'email' => 'myemail#email.com',
'password' => 'password',
'user_key' => '032222222222222b75a192daba28d'
)
);
$number_url = 'https://pi.pardot.com/api/prospect/version/3/do/query';
$number_url .= '?user_key=032222222222222b75a192daba28d';
$number_url .= '&api_key=';
$number_url .= trim($rz_key);
$number_url .= '&list_id=97676';
$ike = simplexml_load_file($number_url);
print_r($ike);
Now this code returns :
SimpleXMLElement Object ( [#attributes] => Array ( [stat] => fail [version] => 1.0 ) [err] => Invalid API key or user key )
However, if I echo $number_url, and copy and paste that URL into my browser, it loads wonderfully. If I copy and paste the same echoed URL into simplexml_load_file it works wonderfully also. I MUST use a variable, because the API key is only good for one hour. Any ideas?
The rest of the code is here, which was provided by Pardot :
<?php
/**
* Call the Pardot API and get the raw XML response back
*
* #param string $url the full Pardot API URL to call, e.g. "https://pi.pardot.com/api/prospect/version/3/do/query"
* #param array $data the data to send to the API - make sure to include your api_key and user_key for authentication
* #param string $method GET", "POST", "DELETE"
* #return string the raw XML response from the Pardot API
* #throws Exception if we were unable to contact the Pardot API or something went wrong
*/
function callPardotApi($url, $data, $method = 'GET')
{
// build out the full url, with the query string attached.
$queryString = http_build_query($data, null, '&');
if (strpos($url, '?') !== false) {
$url = $url . '&' . $queryString;
} else {
$url = $url . '?' . $queryString;
}
$curl_handle = curl_init($url);
// wait 5 seconds to connect to the Pardot API, and 30
// total seconds for everything to complete
curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($curl_handle, CURLOPT_TIMEOUT, 30);
// https only, please!
curl_setopt($curl_handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
// ALWAYS verify SSL - this should NEVER be changed. 2 = strict verify
curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2);
// return the result from the server as the return value of curl_exec instead of echoing it
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
if (strcasecmp($method, 'POST') === 0) {
curl_setopt($curl_handle, CURLOPT_POST, true);
} elseif (strcasecmp($method, 'GET') !== 0) {
// perhaps a DELETE?
curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, strtoupper($method));
}
$pardotApiResponse = curl_exec($curl_handle);
if ($pardotApiResponse === false) {
// failure - a timeout or other problem. depending on how you want to handle failures,
// you may want to modify this code. Some folks might throw an exception here. Some might
// log the error. May you want to return a value that signifies an error. The choice is yours!
// let's see what went wrong -- first look at curl
$humanReadableError = curl_error($curl_handle);
// you can also get the HTTP response code
$httpResponseCode = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
// make sure to close your handle before you bug out!
curl_close($curl_handle);
throw new Exception("Unable to successfully complete Pardot API call to $url -- curl error: \"".
"$humanReadableError\", HTTP response code was: $httpResponseCode");
}
// make sure to close your handle before you bug out!
curl_close($curl_handle);
return $pardotApiResponse;
}
//this will log in and print your API Key (good for 1 hour) to the console
$rz_key = callPardotApi('https://pi.pardot.com/api/login/version/3',
array(
'email' => 'myemail#email.com',
'password' => 'myPassword',
'user_key' => '********************'
)
);
$number_url = 'https://pi.pardot.com/api/prospect/version/3/do/query';
$number_url .= '?user_key=****************';
$number_url .= '&api_key=';
$number_url .= $rz_key;
$number_url .= '&list_id=97676';
$number_url = preg_replace('/\s+/', '', $number_url);
$ike = simplexml_load_file($number_url);
print_r($ike);
?>

Curl Replacement on GAE for BaseFacebook class

I am wanting to implement federated logins to my GAE app in PHP.
I have looked at a couple of third parties like janrain or the OAuth plugin, but I just can't integrate them very easily and I don't want to pay or have limits. I just want something simple that will hook into the GAE authentication model.
At the moment I have google and yahoo as they are the only 2 that use an endpoint that doesn't require a username, and I can use the UserService::createLoginUrl()
I want to add Facebook, Twitter and Microsoft, plus others I guess, but these are my aim for now.
I started with facebook I am trying to use the facebook connector. Initially I started with the Javascript API and it worked well until you sit behind a firewall and facebook is blocked (then $.getScript() fails unmanageably), so I then started looking at the PHP library (at least then the blocking is a) visible to the user, b) not my responsibility for trapping and handling and c) fits nicely into the URL endpoint model I have)
The problem is that the BaseFacebook class uses cURL. GAE does not.
Does anyone know of a way to build the authentication into GAE so I can use login: required or if not, can anyone with better streams/curl knowlege than me replace the cURL stuff in the BaseFacebook class. Here is the function that's causing my grief:
/**
* Makes an HTTP request. This method can be overridden by subclasses if
* developers want to do fancier things or use something other than curl to
* make the request.
*
* #param string $url The URL to make the request to
* #param array $params The parameters to use for the POST body
* #param CurlHandler $ch Initialized curl handle
*
* #return string The response text
*/
protected function makeRequest($url, $params, $ch=null) {
if (!$ch) {
$ch = curl_init();
}
$opts = self::$CURL_OPTS;
if ($this->getFileUploadSupport()) {
$opts[CURLOPT_POSTFIELDS] = $params;
} else {
$opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
}
$opts[CURLOPT_URL] = $url;
// disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
// for 2 seconds if the server does not support this header.
if (isset($opts[CURLOPT_HTTPHEADER])) {
$existing_headers = $opts[CURLOPT_HTTPHEADER];
$existing_headers[] = 'Expect:';
$opts[CURLOPT_HTTPHEADER] = $existing_headers;
} else {
$opts[CURLOPT_HTTPHEADER] = array('Expect:');
}
curl_setopt_array($ch, $opts);
$result = curl_exec($ch);
$errno = curl_errno($ch);
// CURLE_SSL_CACERT || CURLE_SSL_CACERT_BADFILE
if ($errno == 60 || $errno == 77) {
self::errorLog('Invalid or no certificate authority found, '.
'using bundled information');
curl_setopt($ch, CURLOPT_CAINFO,
dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fb_ca_chain_bundle.crt');
$result = curl_exec($ch);
}
// With dual stacked DNS responses, it's possible for a server to
// have IPv6 enabled but not have IPv6 connectivity. If this is
// the case, curl will try IPv4 first and if that fails, then it will
// fall back to IPv6 and the error EHOSTUNREACH is returned by the
// operating system.
if ($result === false && empty($opts[CURLOPT_IPRESOLVE])) {
$matches = array();
$regex = '/Failed to connect to ([^:].*): Network is unreachable/';
if (preg_match($regex, curl_error($ch), $matches)) {
if (strlen(#inet_pton($matches[1])) === 16) {
self::errorLog('Invalid IPv6 configuration on server, '.
'Please disable or get native IPv6 on your server.');
self::$CURL_OPTS[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
$result = curl_exec($ch);
}
}
}
if ($result === false) {
$e = new FacebookApiException(array(
'error_code' => curl_errno($ch),
'error' => array(
'message' => curl_error($ch),
'type' => 'CurlException',
),
));
curl_close($ch);
throw $e;
}
curl_close($ch);
return $result;
}
login: required in Google App Engine is not extensible by your application. If you wish to offer login from multiple providers you will need to turn that off in your app.yaml and instead handle the authentication within your application - which it sounds like you're working on.
You might want to look at using the Google Identity Toolkit - it offers login for some of the providers you list (more than just Google) and has PHP examples:
https://developers.google.com/identity-toolkit/

How to use REST services hosted on Apache 2.2 via cURL to send SSL requests?

What is the procedure for sending secure data (login id, password) over https to an Apache 2.2 server with self-signed certificates?
<?php
$uid=$_POST['user'];
$password=$_POST['pass'];
$url = "https://example.com/login";
$cert_file = './certificate.com.pem';
$cert_password = 'xxxxxx';
$ch = curl_init();
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_POSTFIELDS => 'uid:'.$uid.'&password:'.$password,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_VERBOSE => true,
CURLOPT_URL => $url ,
CURLOPT_SSLCERT => $cert_file ,
CURLOPT_SSLCERTPASSWD => $cert_password ,
CURLOPT_POST => true
);
curl_setopt_array($ch , $options);
$output = curl_exec($ch);
if(!$output)
{
echo "Curl Error : " . curl_error($ch);
}
else
{
echo htmlentities($output);
}
?>
the ERROR we are getting is :
curl error:unable to use client certificate (no key found or wrong passphrase ?)
You'd need to think about it this way:
Your local server asks the remote server to validate the login info. — You would need to make an exception for the self-signed certificate and remember it. (It would be a really a bad habit to simply ignore certificate errors.)
Your local server then checks if the data the remote one sent back isn't an error message and is indeed valid JSON data.
Here's some info on how to make curl remember the self-signed certificate and trust it permanently: http://turboflash.wordpress.com/2009/06/23/curl-adding-installing-trusting-new-self-signed-certificate/ — It should work for the command-line utility just as well as the PHP module.
So, let's make a little function for it. — I'm not going to test its functionality, so I can't promise to have it perfectly error free. I'm also using some practices I wouldn't use in production code, don't account for an API key, use GET parameters and I also make the remote server responsible for any serious sort of error checking and sanitation.
<?php
function remote_login($username, $password) {
/*
Initialize the curl object
*/
$login = curl_init();
/*
Some sanitation. This is probably not enough though.
*/
$username = urlencode($username);
$password = urlencode($password);
/*
Set the url we're going to use.
REST services use clean urls, but here we simply use GET parapeters.
*/
$login_url = 'https://example.com/?username='+$username+'&password='+$password;
curl_setopt($login, CURLOPT_URL, $login_url);
/*
Tell curl we would like to use the data returned from the remote server
*/
curl_setopt($login, CURLOPT_RETURNTRANSFER, true);
/*
Set the returned data as a variable
*/
$login_data = curl_exec($login);
$login_json = json_decode($login_data);
/*
We're not going to do anything else if we encounter any sort of error.
*/
if (($login_data == false) || ($login_json == false)) {
return false;
}
/*
Return the login result as a JSON object
*/
return json_decode($login_data);
}
?>
Hope this helps.

Correct PHP way to check if external image exists?

I know that there are at least 10 the same questions with answers but none of them seems to work for me flawlessly. I'm trying to check if internal or external image exists (is image URL valid?).
fopen($url, 'r') fails unless I use #fopen():
Warning: fopen(http://example.com/img.jpg) [function.fopen]: failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in file.php on line 21
getimagesize($img) fails when image doesn't exist (PHP 5.3.8):
Warning: getimagesize() [function.getimagesize]: php_network_getaddresses: getaddrinfo failed
CURL fails because it isn't supported by some servers (although it's present mostly everywhere).
fileExists() fails because it doesn't work with external URLs and
can't possibly check if we're dealing with image.
Four methods that are the most common answers to such question are wrong. What would be the correct way to do that?
getimagesize($img) fails when image doesn't exist: am not sure you understand what you want .....
FROM PHP DOC
The getimagesize() function will determine the size of any given image file and return the dimensions along with the file type and a height/width text string to be used inside a normal HTML IMG tag and the correspondant HTTP content type.
On failure, FALSE is returned.
Example
$img = array("http://i.stack.imgur.com/52Ha1.png","http://example.com/img.jpg");
foreach ( $img as $v ) {
echo $v, getimagesize($v) ? " = OK \n" : " = Not valid \n";
}
Output
http://i.stack.imgur.com/52Ha1.png = OK
http://example.com/img.jpg = Not valid
getimagesize works just fine
PHP 5.3.19
PHP 5.4.9
Edit
#Paul .but your question is essentially saying "How do I handle this so I won't get an error when there's an error condition". And the answer to that is "you can't". Because all these functions will trigger an error when there is an error condition. So (if you don't want the error) you suppress it. None of this should matter in production because you shouldn't be displaying errors anyway ;-) – DaveRandom
This code is actually to check file... But, it does works for images!
$url = "http://www.myfico.com/Images/sample_overlay.gif";
$header_response = get_headers($url, 1);
if ( strpos( $header_response[0], "404" ) !== false )
{
// FILE DOES NOT EXIST
}
else
{
// FILE EXISTS!!
}
function checkExternalFile($url)
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$retCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $retCode;
}
$fileExists = checkExternalFile("http://example.com/your/url/here.jpg");
// $fileExists > 400 = not found
// $fileExists = 200 = found.
If you're using PHP >=5.0.0 you can pass an additional parameter into fopen to specify context options for HTTP, among them whether to ignore failure status codes.
$contextOptions = array( 'http' => array('ignore_errors' => true));
$context = stream_context_create($contextOptions);
$handle = fopen($url, 'r', false, $context);
Use fsockopen, connect to the server, send a HEAD request and see what status you get back.
The only time you need to be aware of problems is if the domain doesn't exist.
Example code:
$file = "http://example.com/img.jpg";
$path = parse_url($file);
$fp = #fsockopen($path['host'],$path['port']?:80);
if( !$fp) echo "Failed to connect... Either server is down or host doesn't exist.";
else {
fputs($fp,"HEAD ".$file." HTTP/1.0\r\n"
."Host: ".$path['host']."\r\n\r\n");
$firstline = fgets($fp);
list(,$status,$statustext) = explode(" ",$firstline,3);
if( $status == 200) echo "OK!";
else "Status ".$status." ".$statustext."...";
}
You can use the PEAR/HTTP_Request2 Package for this. You can find it here
Here comes an example. The Example expects that you have installed or downloaded the HTTP_Request2 package properly. It uses the old style socket adapter, not curl.
<?php
require_once 'HTTP/Request2.php';
require_once 'HTTP/Request2/Adapter/Socket.php';
$request = new HTTP_Request2 (
$your_url,
HTTP_Request2::METHOD_GET,
array('adapter' => new HTTP_Request2_Adapter_Socket())
);
switch($request->send()->getResponseCode()) {
case 404 :
echo 'not found';
break;
case 200 :
echo 'found';
break;
default :
echo 'needs further attention';
}
I found try catch the best solution for this. It is working fine with me.
try{
list($width, $height) = getimagesize($h_image->image_url);
}
catch (Exception $e)
{
}
I know you wrote "without curl" but still, somebody may find this helpfull:
function curl_head($url) {
$ch = curl_init($url);
//curl_setopt($ch, CURLOPT_USERAGENT, 'Your user agent');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1); # get headers
curl_setopt($ch, CURLOPT_NOBODY, 1); # omit body
//curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); # do SSL check
//curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); # verify domain within cert
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); # follow "Location" redirs
//curl_setopt($ch, CURLOPT_TIMEOUT_MS, 700); # dies after 700ms
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
print_r(curl_head('https://www.example.com/image.jpg'));
You will see someting like this HTTP/1.1 200 OK or HTTP/1.1 404 Not Found in returned header array. You can do also multiple parallel requests with curl multi.
There are multiple steps, there is no single solution:
Validate URL
Check whether the file is available (can be done directly with step 3)
Download the image into a tmp file.
Use getimagesize to check the size of the image.
For this kind of work you can catch the exceptions and handle them well to define your answer. In this case you could even suppress errors because it's intended that they trick might fail. So you handle the errors correctly.
Because it's not possible to do a 100% check on it without having the actual image downloaded. So step 1 and 2 are required, 3 and 4 optional for a more definitive answer.

Categories