Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Function Reference : URL Functions : get_headers

get_headers

Fetches all the headers sent by the server in response to a HTTP request (PHP 5)
array get_headers ( string url [, int format] )

get_headers() returns an array with the headers sent by the server in response to a HTTP request.

Parameters

url

The target URL.

format

If the optional format parameter is set to 1, get_headers() parses the response and sets the array's keys.

Return Values

Returns an indexed or associative array with the headers, or FALSE on failure.

ChangeLog

Version Description
5.1.3 This function now uses the default stream context, which can be set/changed with the stream_context_get_default() function.

Examples

Example 2565. get_headers() example

<?php
$url
= 'http://www.example.com';

print_r(get_headers($url));

print_r(get_headers($url, 1));
?>

The above example will output something similar to:

Array
(
   [0] => HTTP/1.1 200 OK
   [1] => Date: Sat, 29 May 2004 12:28:13 GMT
   [2] => Server: Apache/1.3.27 (Unix)  (Red-Hat/Linux)
   [3] => Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
   [4] => ETag: "3f80f-1b6-3e1cb03b"
   [5] => Accept-Ranges: bytes
   [6] => Content-Length: 438
   [7] => Connection: close
   [8] => Content-Type: text/html
)

Array
(
   [0] => HTTP/1.1 200 OK
   [Date] => Sat, 29 May 2004 12:28:14 GMT
   [Server] => Apache/1.3.27 (Unix)  (Red-Hat/Linux)
   [Last-Modified] => Wed, 08 Jan 2003 23:11:55 GMT
   [ETag] => "3f80f-1b6-3e1cb03b"
   [Accept-Ranges] => bytes
   [Content-Length] => 438
   [Connection] => close
   [Content-Type] => text/html
)


Code Examples / Notes » get_headers

denilson

This is a modified version of code from "stuart at sixletterwords dot com", at 14-Sep-2005 04:52. This version tries to emulate get_headers() function at PHP4. I think it works fairly well, and is simple. It is not the best emulation available, but it works.
Features:
- supports (and requires) full URLs.
- supports changing of default port in URL.
- stops downloading from socket as soon as end-of-headers is detected.
Limitations:
- only gets the root URL (see line with "GET / HTTP/1.1").
- don't support HTTPS (nor the default HTTPS port).
<?php
if(!function_exists('get_headers'))
{
function get_headers($url,$format=0)
{
$url=parse_url($url);
$end = "\r\n\r\n";
$fp = fsockopen($url['host'], (empty($url['port'])?80:$url['port']), $errno, $errstr, 30);
if ($fp)
{
$out  = "GET / HTTP/1.1\r\n";
$out .= "Host: ".$url['host']."\r\n";
$out .= "Connection: Close\r\n\r\n";
$var  = '';
fwrite($fp, $out);
while (!feof($fp))
{
$var.=fgets($fp, 1280);
if(strpos($var,$end))
break;
}
fclose($fp);
$var=preg_replace("/\r\n\r\n.*\$/",'',$var);
$var=explode("\r\n",$var);
if($format)
{
foreach($var as $i)
{
if(preg_match('/^([a-zA-Z -]+): +(.*)$/',$i,$parts))
$v[$parts[1]]=$parts[2];
}
return $v;
}
else
return $var;
}
}
}
?>


sey

The replacement updated get_headers function by aeontech at gmail dot com improperly formats dates when $format = 1.
Replace:
<?
else {
$headers[strtolower($h2[0])] = trim($h2[1]);
}
?>
With:
<?
else {
$foo = implode( ':', $h2 );
$foo = preg_replace( '/[a-zA-Z- ]*: /', '', $foo );
$headers[strtolower($h2[0])] = trim( $foo );
}


rsyring+phppost

Once again another update.  The improvements are:
HTTPS support (make sure you have SSL support enabled -- PHP5 is as simple as uncommenting extension=php_openssl.dll in php.ini)
Fixed bug with exploding the header on ':'.  This caused the location header to be broken and just return 'http'.
Set stream timeout in addition to socket timeout.
<?php
function my_get_headers($url ) {
      $url_info=parse_url($url);
      if (isset($url_info['scheme']) && $url_info['scheme'] == 'https') {
          $port = 443;
          @$fp=fsockopen('ssl://'.$url_info['host'], $port, $errno, $errstr, 10);
      } else {
          $port = isset($url_info['port']) ? $url_info['port'] : 80;
          @$fp=fsockopen($url_info['host'], $port, $errno, $errstr, 10);
      }
      if($fp) {
          stream_set_timeout($fp, 10);
          $head = "HEAD ".@$url_info['path']."?".@$url_info['query'];
          $head .= " HTTP/1.0\r\nHost: ".@$url_info['host']."\r\n\r\n";
          fputs($fp, $head);
          while(!feof($fp)) {
              if($header=trim(fgets($fp, 1024))) {
                       $sc_pos = strpos( $header, ':' );
                       if( $sc_pos === false ) {
                          $headers['status'] = $header;
                       } else {
                           $label = substr( $header, 0, $sc_pos );
                           $value = substr( $header, $sc_pos+1 );
                           $headers[strtolower($label)] = trim($value);
                       }
              }
          }
          return $headers;
      }
      else {
          return false;
      }
  }
?>


tylerxxdurden

my version
cleans the input URL a little bit
(you should be able to put in almost every shit, and it should still work)
Should work for:
http://test.de
http://test.de/
www.test.de
http://test.de/
http://test.de/test.html
http://test.de/test.html?testme
...
not nice, but seems to work for me
<?
function get_headers2($url,$format=0) {
      $url_info=parse_url($url);
      $port = isset($url_info['port']) ? $url_info['port'] : 80;
      $fp=fsockopen($url_info['host'], $port, $errno, $errstr, 30);
      if($fp) {
          if(!$url_info['path']){
$url_info['path'] = "/";
}
if($url_info['path'] && !$url_info['host']){
$url_info['host'] = $url_info['path'];
$url_info['path'] = "/";
}
if( $url_info['host'][(strlen($url_info['host'])-1)] == "/" ){
$url_info['host'][(strlen($url_info['host'])-1)] = "";
}
if(!$url_array[scheme]){
$url_array[scheme] = "http"; //we always use http links
}
$head = "HEAD ".@$url_info['path'];
if( $url_info['query'] ){
$head .= "?".@$url_info['query'];
}
print_r($url_info);
          $head .= " HTTP/1.0\r\nHost: ".@$url_info['host']."\r\n\r\n";
          echo $head;
fputs($fp, $head);
          while(!feof($fp)) {
              if($header=trim(fgets($fp, 1024))) {
                  if($format == 1) {
                      $h2 = explode(':',$header);
                      // the first element is the http header type, such as HTTP/1.1 200 OK,
                      // it doesn't have a separate name, so we have to check for it.
                      if($h2[0] == $header) {
                          $headers['status'] = $header;
                      }
                      else {
                          $headers[strtolower($h2[0])] = trim($h2[1]);
                      }
                  }
                  else {
                      $headers[] = $header;
                  }
              }
          }
          return $headers;
      }
      else {
          return false;
      }
  }
?>


aeontech

In response to dotpointer's modification of Jamaz' solution...
Here is a small modification of your function, this adds the emulation of the optional $format parameter.
<?php
if(!function_exists('get_headers')) {

/**
* @return array
* @param string $url
* @param int $format
* @desc Fetches all the headers
* @author cpurruc fh-landshut de
* @modified by dotpointer
* @modified by aeontech
*/
function get_headers($url,$format=0)
{
$url_info=parse_url($url);
$port = isset($url_info['port']) ? $url_info['port'] : 80;
$fp=fsockopen($url_info['host'], $port, $errno, $errstr, 30);

if($fp)
{
$head = "HEAD ".@$url_info['path']."?".@$url_info['query']." HTTP/1.0\r\nHost: ".@$url_info['host']."\r\n\r\n";      
fputs($fp, $head);      
while(!feof($fp))
{
if($header=trim(fgets($fp, 1024)))
{
if($format == 1)
{
$key = array_shift(explode(':',$header));
// the first element is the http header type, such as HTTP 200 OK,
// it doesn't have a separate name, so we have to check for it.
if($key == $header)
{
$headers[] = $header;
}
else
{
$headers[$key]=substr($header,strlen($key)+2);
}
unset($key);
}
else
{
$headers[] = $header;
}
}
}
return $headers;
}
else
{
return false;
}
}
}
?>


10-may-2006 12:10

If you want to get headers that current PHP process is going to send back to browser, see headers_list()

13-nov-2006 08:29

I've noticed it.
Some Server will simply return the false reply header if you sent 'HEAD' request instead of 'GET'. The 'GET' request header always receiving the most actual HTTP header instead of 'HEAD' request header. But If you don't mind for a fast but risky method then 'HEAD' request is better for you.
btw ... this is get header with additional information such as User, Pass & Refferer. ...
<?php
function get_headers_x($url,$format=0, $user='', $pass='', $referer='') {
if (!empty($user)) {
$authentification = base64_encode($user.':'.$pass);
$authline = "Authorization: Basic $authentification\r\n";
}
if (!empty($referer)) {
$refererline = "Referer: $referer\r\n";
}
$url_info=parse_url($url);
$port = isset($url_info['port']) ? $url_info['port'] : 80;
$fp=fsockopen($url_info['host'], $port, $errno, $errstr, 30);
if($fp) {
$head = "GET ".@$url_info['path']."?".@$url_info['query']." HTTP/1.0\r\n";
if (!empty($url_info['port'])) {
$head .= "Host: ".@$url_info['host'].":".$url_info['port']."\r\n";
} else {
$head .= "Host: ".@$url_info['host']."\r\n";
}
$head .= "Connection: Close\r\n";
$head .= "Accept: */*\r\n";
$head .= $refererline;
$head .= $authline;
$head .= "\r\n";
fputs($fp, $head);      
while(!feof($fp) or ($eoheader==true)) {
if($header=fgets($fp, 1024)) {
if ($header == "\r\n") {
$eoheader = true;
break;
} else {
$header = trim($header);
}
if($format == 1) {
$key = array_shift(explode(':',$header));
if($key == $header) {
$headers[] = $header;
} else {
$headers[$key]=substr($header,strlen($key)+2);
}
unset($key);
} else {
$headers[] = $header;
}
}
}
return $headers;
} else {
return false;
}
}
?>
Regards.
Donovan


stuart

hey, i came across this afew weeks ago and used the function in an app for recording info about domains that my company owns, and found that the status this returns was wrong most of the time (400 bad request or void for sites that were clearly online). then looking into it i noticed the problem was that it wasn't able to get the correct info about sites with redirections. but thats not the full problem because everything on my server was returning the wrong status too. i searched around on php.net for other info and found that fsockopen's example worked better and only needed some tweeking.
heres the function i put together from it and a small change.
<?
if(!function_exists('get_headers')) {
  function get_headers($url,$format=0,$httpn=0){
$fp = fsockopen($url, 80, $errno, $errstr, 30);
if ($fp) {
  $out = "GET / HTTP/1.1\r\n";
  $out .= "Host: $url\r\n";
  $out .= "Connection: Close\r\n\r\n";
  fwrite($fp, $out);
  while (!feof($fp)) {
      $var.=fgets($fp, 1280);
  }
$var=explode("<",$var);
$var=$var[0];
$var=explode("\n",$var);
fclose($fp);
return $var;
}
}
}
?>
this returns an array of the header (only problem being that if the site doesn't have correct html it'll pull in some content too).
hope this'll help someone else.


15-jul-2005 09:37

For anyone reading the previous comments, here is code that takes into account all the previous suggestions and includes a bugfix, too.
This code basically provides the "get_headers" function even on systems that are not running PHP 5.0.  It uses strtolower() on the keys, as suggested.  It uses the $h2 array instead of the $key, as suggested.  It removes a line about unsetting the $key -- no reason to unset something which is no longer used.  And I've changed the status header to be named "status" (instead of "0") in the array.  Note that if more than one header is returned without a label, they'll be stuck in "status" -- but I think status is the only header that comes back without a label, so it works for me.  So, first the code, then a sample of the usage:
<?php
if(!function_exists('get_headers')) {
  /**
  * @return array
* @param string $url
* @param int $format
* @desc Fetches all the headers
* @author cpurruc fh-landshut de
* @modified by dotpointer
* @modified by aeontech
*/
function get_headers($url,$format=0) {
$url_info=parse_url($url);
$port = isset($url_info['port']) ? $url_info['port'] : 80;
$fp=fsockopen($url_info['host'], $port, $errno, $errstr, 30);
if($fp) {
$head = "HEAD ".@$url_info['path']."?".@$url_info['query'];
$head .= " HTTP/1.0\r\nHost: ".@$url_info['host']."\r\n\r\n";
fputs($fp, $head);
while(!feof($fp)) {
if($header=trim(fgets($fp, 1024))) {
if($format == 1) {
$h2 = explode(':',$header);
// the first element is the http header type, such as HTTP/1.1 200 OK,
// it doesn't have a separate name, so we have to check for it.
if($h2[0] == $header) {
$headers['status'] = $header;
}
else {
$headers[strtolower($h2[0])] = trim($h2[1]);
}
}
else {
$headers[] = $header;
}
}
}
return $headers;
}
else {
return false;
}
}
}
?>
OK?  Here's the usage:
<?php
$response = get_headers('http://www.example.com/', 1);
if (!$response) {
echo 'Unable to initiate connection.';
}
else {
print_r($response);
}
?>


eis

denilson at vialink:
if you want just the headers, use HEAD request, not GET.


angelo

Be forewarned, none of the get_headers() functions below will replicate the behavior of PHP 5's get_headers() for URLs that use the 'Location:' redirect header or return File Not Found headers.
According to RFC1945, A user agent should never automatically redirect a request more than 5 times, since such redirections usually indicate an infinite loop.  For true compatibility, the functions below should be able to handle up to 5 Location redirects within one function call.  Only the native get_headers() function exhibits this behavior.  None of the functions below handle the 'Location' redirection.
The native PHP >= 5 get_headers() function will not return headers in some instances where the functions below would.  For example, if the server returns a 404 status, get_headers() will throw a PHP warning.  Unfortunately, the 404 error can only be known by looking at the headers.  From first glance, all of the functions below will return 404 headers, which may be a desired effect but does not replicate the behavior of the native get_headers() function.


david

After discovering that some webservers reply with "Content-Type" and others with "Content-type" I modified the function below to use strtolower($key) to make for easy checking against these case differences.

drfickle2

aeontech, this the below change adds support for SSL connections. Thanks for the code!
       if (isset($url_info['scheme']) && $url_info['scheme'] == 'https') {
           $port = 443;
           $fp=fsockopen('ssl://'.$url_info['host'], $port, $errno, $errstr, 30);
       } else {
          $port = isset($url_info['port']) ? $url_info['port'] : 80;
           $fp=fsockopen($url_info['host'], $port, $errno, $errstr, 30);
       }


chortos-2

aeontech, I'd edit your function a little... How about replacing this:
<?
                      $key = array_shift(explode(':',$header));
                      // the first element is the http header type, such as HTTP 200 OK,
                      // it doesn't have a separate name, so we have to check for it.
                      if($key == $header)
                      {
                          $headers[] = $header;
                      }
                      else
                      {
                          $headers[$key]=substr($header,strlen($key)+2);
                      }
?>
with this:
<?
                      $h2 = explode(':',$header);
                      // the first element is the http header type, such as HTTP/1.1 200 OK,
                      // it doesn't have a separate name, so we have to check for it.
                      if($h2[0] == $header)
                      {
                          $headers[] = $header;
                      }
                      else
                      {
                          $headers[ $h2[0] ] = trim($h2[1]);
                      }
?>
I think it looks a bit nicer :)


Change Language


Follow Navioo On Twitter
base64_decode
base64_encode
get_headers
get_meta_tags
http_build_query
parse_url
rawurldecode
rawurlencode
urldecode
urlencode
eXTReMe Tracker