<?php
/*
* $Id$
*
* browser utils
*
* Copyright (C) 2004 Borislav Manolov
*
* 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.
* http://www.gnu.org/copyleft/gpl.html
*
* Author: Borislav Manolov
* E-mail: b.manolov at web.de
* Home page: http://purl.oclc.org/NET/manolov/
*/
class Browser {
var $host = ''; // host name we are connecting to
var $agent = 'Mozilla/5.0 (PHPBrowser)'; // user agent string
var $cookies = array(); // cookies
var $print_cookies = false;
var $accept = '*/*'; // http accept types
var $results = ''; // content returned from server
var $headers = array(); // headers returned from server
var $error = ''; // error messages
var $read_timeout = 0; // timeout on read operations, in seconds, 0 to disallow
var $timed_out = false;// whether a read operation timed out
var $conn_timeout = 30; // timeout for socket connection
var $redirect_uri = false;// set if page fetched is a redirect
var $fetch_method = 'GET'; // fetch method
var $submit_method = 'POST'; // submit method
var $http_version = 'HTTP/1.1';// http version
var $content_type = array( // content types
'text' => 'application/x-www-form-urlencoded',
'binary' => 'multipart/form-data'
);
var $mime_boundary = ''; // MIME boundary for binary submission
/*
* constructor
* $params - assoc array (name => value)
* return nothing
*/
function Browser($params) {
settype($params, 'array');
foreach ( $params as $field => $value ) {
if ( isset($this->$field) ) {
$this->$field = $value;
}
}
$this->mime_boundary = 'PHPBrowser' . md5( uniqid( microtime() ) );
}
/*
* fetch the contents of a page
* $uri - location of the page
* return true by success
*/
function fetch($uri) {
return $this->make_request($uri, $this->fetch_method);
}
/*
* submit an http form
* $uri - the location of the page to submit
* $vars - assoc array with form fields and their values
* $file - assoc array (field name => file name)
* set only by upload
* return true by success
*/
function submit( $uri, $vars, $file = array() ) {
$postdata = '';
if ( empty($file) ) {
foreach ( $vars as $key => $val ) {
$postdata .= urlencode($key) .'='. urlencode($val) .'&';
}
} else {
foreach ( $vars as $key => $val ) {
$postdata .= '--'. $this->mime_boundary ."\r\n";
$postdata .= 'Content-Disposition: form-data; name="'. $key ."\"\r\n\r\n";
$postdata .= $val . "\r\n";
}
list($field_name, $file_name) = each($file);
if ( !is_readable($file_name) ) {
$this->error = 'File "' . $file_name . '" is not readable.';
return false;
}
$fp = fopen($file_name, 'r');
$file_content = fread( $fp, filesize($file_name) );
fclose($fp);
$base_name = basename($file_name);
$postdata .= '--'. $this->mime_boundary ."\r\n";
$postdata .= '"Content-Disposition: form-data; name="'.
$field_name . '"; filename="' . $base_name . "\"\r\n\r\n";
$postdata .= $file_content . "\r\n";
$postdata .= '--'. $this->mime_boundary ."--\r\n";
}
$content_type = empty($file)
? $this->content_type['text']
: $this->content_type['binary'] ;
return $this->make_request($uri, $this->submit_method,
$content_type, $postdata);
}
/*
* get the data from the server
* $uri - the location the page
* $request_method - GET / POST
* $content_type - content type (for POST submission)
* $postdata - data (for POST submission)
* return true if the request succeeded, false otherwise
*/
function make_request($uri, $request_method, $content_type = '', $postdata = '') {
$uri_parts = parse_url($uri);
if ( $uri_parts['scheme'] != 'http') { // not a valid protocol
$this->error = 'Invalid protocol: "'. $uri_parts['scheme'] .'"';
return false;
}
$this->host = $uri_parts['host'];
$fp = fsockopen($this->host, 80, $errno, $errstr, $this->conn_timeout);
if ( !$fp ) {
$this->error = $errno .' / Reason: '. $errstr;
return false;
}
$path = $uri_parts['path'] .
($uri_parts['query'] ? '?'. $uri_parts['query'] : '');
$cookie_headers = '';
if ($this->redirect_uri) {
$this->setcookies();
}
if ( empty($path) )
$path = '/';
$headers = $request_method .' '. $path .' '. $this->http_version ."\r\n";
$headers .= 'User-Agent: '. $this->agent ."\r\n";
$headers .= 'Host: ' . $this->host ."\r\n";
$headers .= 'Accept: ' . $this->accept ."\r\n";
if ( !empty($this->cookies) ) {
settype($this->cookies, 'array');
reset($this->cookies);
if ( count($this->cookies) > 0 ) {
$cookie_headers .= 'Cookie: ';
foreach ( $this->cookies as $key => $val ) {
$cookie_headers .= $key .'='. urlencode($val) .'; ';
}
$headers .= substr($cookie_headers, 0, -2) . "\r\n";
}
}
if ( !empty($content_type) ) {
$headers .= "Content-type: $content_type";
if ($content_type == $this->content_type['binary'])
$headers .= '; boundary=' . $this->mime_boundary;
$headers .= "\r\n";
}
if ( !empty($postdata) ) {
$headers .= "Content-length: ". strlen($postdata) ."\r\n";
}
$headers .= "\r\n";
// set the read timeout if needed
if ($this->read_timeout > 0)
socket_set_timeout($fp, $this->read_timeout);
$this->timed_out = false;
fwrite( $fp, $headers . $postdata, strlen($headers . $postdata) );
$this->redirect_uri = false;
unset($this->headers);
while ( $curr_header = fgets($fp, 4096) ) {
if ($curr_header == "\r\n")
break;
// if a header begins with Location: or URI:, set the redirect
if ( preg_match('/^(Location:|URI:)[ ]+(.*)/', $curr_header, $matches) ) {
$this->redirect_uri = rtrim($matches[2]);
}
$this->headers[] = $curr_header;
}
$results = '';
while ( $data = fread($fp, 500000) ) {
$results .= $data;
}
$this->results = $results;
fclose($fp);
if ($this->redirect_uri) {
$this->make_request($this->redirect_uri, $request_method,
$content_type, $postdata);
}
return true;
}
/*
* set cookies for a redirection
*/
function setcookies() {
for ($x=0; $x < count($this->headers); $x++) {
if (preg_match('/^Set-Cookie:[\s]+([^=]+)=([^;]+)/i', $this->headers[$x], $match)) {
$this->cookies[$match[1]] = $match[2];
if ( $this->print_cookies ) {
echo "\n" . $match[1] . ' = ' . $match[2];
}
}
}
}
} // end class Browser
?>