<?php
/***************************************************************************

Browser Emulating file functions v2.0
(c) Kai Blankenhorn
www.bitfolge.de/en
kaib@bitfolge.de


This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

****************************************************************************


Changelog:

v2.0	03-09-03
	added a wrapper class; this has the advantage that you no longer need
		to specify a lot of parameters, just call the methods to set 
		each option
	added option to use a special port number, may be given by setPort or
		as part of the URL (e.g. server.com:80)
	added getLastResponseHeaders()

v1.5
	added Basic HTTP user authorization
	minor optimizations

v1.0
	initial release



***************************************************************************/
/**
 * BrowserEmulator class. Provides methods for opening urls and emulating 
 * a web browser request.
 **/
     class BrowserEmulator {

     var $headerLines = Array ();
     var $postData = Array ();
     var $authUser = "";
     var $authPass = "";
     var $port;
     var $lastResponse = Array ();

     function BrowserEmulator () {
	  $this->resetHeaderLines ();
	  $this->resetPort ();
     }

	/**
	* Adds a single header field to the HTTP request header. The resulting header
	* line will have the format
	* $name: $value\n
	**/
     function addHeaderLine ($name, $value) {
	  $this->headerLines[$name] = $value;
     }

	/**
	* Deletes all custom header lines. This will not remove the User-Agent header field,
	* which is necessary for correct operation.
	**/
     function resetHeaderLines () {
	  $this->headerLines = Array ();

		/*******************************************************************************/
		/**************    YOU MAX SET THE USER AGENT STRING HERE    *******************/
	  /*                                                                             */
	  /* default is "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",            */
	  /* which means Internet Explorer 6.0 on WinXP                                  */

	  $this->headerLines["User-Agent"] =
	       "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";

		/*******************************************************************************/

     }

	/**
	* Add a post parameter. Post parameters are sent in the body of an HTTP POST request.
	**/
     function addPostData ($name, $value) {
	  $this->postData[$name] = $value;
     }

	/**
	* Deletes all custom post parameters.
	**/
     function resetPostData () {
	  $this->postData = Array ();
     }

	/**
	* Sets an auth user and password to use for the request.
	* Set both as empty strings to disable authentication.
	**/
     function setAuth ($user, $pass) {
	  $this->authUser = $user;
	  $this->authPass = $pass;
     }

	/**
	* Selects a custom port to use for the request.
	**/
     function setPort ($portNumber) {
	  $this->port = $portNumber;
     }

	/**
	* Resets the port used for request to the HTTP default (80).
	**/
     function resetPort () {
	  $this->port = 80;
     }

	/**
	* Make an fopen call to $url with the parameters set by previous member
	* method calls. Send all set headers, post data and user authentication data.
	* Returns a file handle on success, or false on failure.
	**/
     function fopen ($url) {
	  $debug = false;

	  $this->lastResponse = Array ();

	  preg_match ("~([a-z]*://)?([^:^/]*)(:([0-9]{1,5}))?(/.*)?~i", $url,
		      $matches);
	  if ($debug)
	       var_dump ($matches);
	  $protocol = $matches[1];
	  $server = $matches[2];
	  $port = $matches[4];
	  $path = $matches[5];
	  if ($port != "") {
	       $this->setPort ($port);
	  }
	  if ($path == "")
	       $path = "/";
	  $socket = false;
	  $socket = fsockopen ($server, $this->port);
	  if ($socket) {
	       $this->headerLines["Host"] = $server;

	       if ($this->authUser != "" AND $this->authPass != "") {
		    $headers["Authorization"] =
			 "Basic ".base64_encode ($this->authUser.":".$this->
						 authPass);
	       }

	       if (count ($this->postData) == 0) {
		    $request = "GET $path HTTP/1.0\r\n";
	       }
	       else {
		    $request = "POST $path HTTP/1.0\r\n";
	       }

	       if ($debug)
		    echo $request;
	       fputs ($socket, $request);

	       if (count ($this->postData) > 0) {
		    $PostStringArray = Array ();
		    foreach ($this->postData AS $key => $value) {
			 $PostStringArray[] = "$key=$value";
		    }
		    $PostString = join ("&", $PostStringArray);
		    $this->headerLines["Content-Length"] =
			 strlen ($PostString);
	       }

	       foreach ($this->headerLines AS $key => $value) {
		    if ($debug)
			 echo "$key: $value\n";
		    fputs ($socket, "$key: $value\r\n");
	       }
	       if ($debug)
		    echo "\n";
	       fputs ($socket, "\r\n");
	       if (count ($this->postData) > 0) {
		    if ($debug)
			 echo "$PostString";
		    fputs ($socket, $PostString."\r\n");
	       }
	  }
	  if ($debug)
	       echo "\n";
	  if ($socket) {
	       $line = fgets ($socket, 1000);
	       if ($debug)
		    echo $line;
	       $this->lastResponse[] = $line;
	       $status = substr ($line, 9, 3);
	       while (trim ($line = fgets ($socket, 1000)) != "") {
		    if ($debug)
			 echo "$line";
		    $this->lastResponse[] = $line;
		    if ($status == "401" AND strpos ($line, "WWW-Authenticate: Basic realm=\"")  === 0) {
			 fclose ($socket);
			 return FALSE;
		    }
	       }
	  }
	  return $socket;
     }

	/**
	* Make an file call to $url with the parameters set by previous member
	* method calls. Send all set headers, post data and user authentication data.
	* Returns the requested file as an array on success, or false on failure.
	**/
     function file ($url) {
	  $file = Array ();
	  $socket = $this->fopen ($url);
	  if ($socket) {
	       $file = Array ();
	       while (!feof ($socket)) {
		    $file[] = fgets ($socket, 10000);
	       }
	  }
	  else {
	       return FALSE;
	  }
	  return $file;
     }

     function getLastResponseHeaders () {
	  return $this->lastResponse;
     }
}



// example code
/*
$be = new BrowserEmulator(); 
//$be->addHeaderLine("Referer", "http://previous.server.com/");
//$be->addHeaderLine("Accept-Encoding", "x-compress; x-zip");
//$be->addPostData("Submit", "OK");
//$be->addPostData("item", "42");
//$be->setAuth("admin", "secretpass");
// also possible: 
// $be->setPort(10080); 

$file = $be->fopen("http://us.imdb.com/Title?0209144");
$response = $be->getLastResponseHeaders(); 

while ($line = fgets($file, 1024)) { 
    // do something with the file
    echo $line;
} 
fclose($file); 

*/

?>
