XMLHTTPRequest in PHP 5
In PHP 5, while there is domDocument, there is no XMLHTTPRequest. I knew there is HTTP_Request, but since I don't want to have unnecessary dependency, I've decided to create my own one. Fortunately there is fsockopen. So in a several hours of quick learning and googling, I've created this wonderful wrapper class.
<?php /** * A wrapper class for handling HTTP request. * Only HTTP is supported. So don't try anything like HTTPS or FTP. * @author Ming Hong Ng <minghong@gmail.com> * @version 0.1, 2005/02/01 * @since 0.1 */ class XmlHttpRequest { /** * Constructor. * @version 0.1, 2005/02/01 * @since 0.1 */ function __construct() { $this->responseText = NULL; $this->responseXml = NULL; $this->status = NULL; $this->statusText = NULL; $this->error = NULL; $this->errorText = NULL; $this->components = array(); $this->requestHeaders = array( "User-Agent" => $_SERVER["SERVER_SOFTWARE"], "Accept" => $_SERVER["HTTP_ACCEPT"], "Accept-Language" => $_SERVER["HTTP_ACCEPT_LANGUAGE"], "Accept-Charset" => $_SERVER["HTTP_ACCEPT_CHARSET"], "Connection" => "Close" ); $this->responseHeaders = array(); } /** * Destructor. * @version 0.1, 2005/02/01 * @since 0.1 */ function __destruct() { if ( !is_null( $this->responseXml ) ) { unset( $this->responseXml ); } } /** * Assign method and URL to the pending request. * Upcoming transaction is always handled synchronously. * Please urlencode the URL before parsing into this method. * Please set method to "POST" if you want to post data. * @version 0.1, 2005/02/01 * @param method The request method * @param url The URL * @since 0.1 * @todo Supports method other than "GET" and "POST" */ public function open( $method, $url ) { $this->method = strtoupper( $method ); $this->components = parse_url( $url ); // Fill in the missing components, if any if ( is_null( $this->components["scheme"] ) ) { $this->components["scheme"] = "http"; } if ( is_null( $this->components["port"] ) ) { $this->components["port"] = ( $this->components["scheme"] == "http" ) ? 80 : 443; } if ( is_null( $this->components["path"] ) ) { $this->components["path"] = "/"; } } /** * Transmits the request with postable string/DOM content. * Content is ignored unless the method is "POST". * Please urlencode the key/value pairs unless you are sending XML data. * Set headerOnly to TRUE if you just need to get the headers (save time). * @version 0.1, 2005/02/01 * @param content An optional string/DOM content * @since 0.1 */ public function send( $content = NULL ) { // Prepare the request headers $path = $this->components["path"]; if ( !is_null( $this->components["query"] ) ) { $path .= "?" . $this->components["query"]; } if ( !is_null( $this->components["fragment"] ) ) { $path .= "#" . $this->components["fragment"]; } $request = sprintf( "%s %s " . $_SERVER["SERVER_PROTOCOL"] . "\r\nHost: %s\r\n", $this->method, $path, $this->components["host"] ); foreach( $this->requestHeaders as $key => $value ) { if ( $key != "Content-Type" && $key != "Content-Length" ) { $request .= "$key: $value\r\n"; } } if ( !is_null( $content ) ) { if ( $this->method == "POST" ) { $body = $content; $type = "application/x-www-form-urlencoded"; if ( get_class( $body ) == "DOMDocument" ) { $body = $body->saveXML(); $type = "application/xml"; } $lines = array( "Content-Type: $type", "Content-Length: " . strlen( $body ), "", $body ); $request .= implode( "\r\n", $lines ); } } $request .= "\r\n\r\n"; // Open socket connection to host $handle = @fsockopen( $this->components["host"], $this->components["port"], $this->error, $this->errorText ); // Cannot open socket connection to host if ( !$handle ) { // Abort return; } // Send the request fwrite( $handle, $request ); // Receive the response headers $line = ""; while ( $line != "\r\n" ) { $line = fgets( $handle, 1024 ); // Extract status code/text preg_match( "/^HTTP\/\d.\d (\d+) (.+)\r\n/", $line, $matches ); if ( count( $matches ) > 0 ) { $this->status = $matches[1]; $this->statusText = $matches[2]; } unset( $matches ); // Extract response name/value pairs preg_match( "/^([\w|\-]+): (.+)\r\n/", $line, $matches ); if ( count( $matches ) > 0 ) { $this->responseHeaders[ $matches[1] ] = $matches[2]; } unset( $matches ); } // Receive the response body, if needed if ( $this->method != "HEAD" ) { while ( !feof( $handle ) ) { $this->responseText .= fgets( $handle, 1024 ); } $this->responseXml = new domDocument(); if ( @!$this->responseXml->loadXML( $this->responseText ) ) { @$this->responseXml->loadHTML( $this->responseText ); } } } /** * Get the text of the specific response header. * @version 0.1, 2005/02/01 * @param header The name of the response header * @return The response header value * @since 0.1 */ public function getResponseHeader( $header ) { return $this->responseHeaders[$header]; } /** * Get the response headers as a string for HTTP request. * @version 0.1, 2005/02/01 * @return The response headers * @since 0.1 */ public function getAllResponseHeaders() { $headers = ""; foreach( $this->responseHeaders as $key => $value ) { $headers .= "$key: $value\r\n"; } return $headers; } /** * Set a HTTP request header for HTTP request. * @version 0.1, 2005/02/01 * @param header The name of the request header * @param The request header value * @since 0.1 */ public function setRequestHeader( $header, $value ) { $this->requestHeaders[$header] = $value; } public $responseText; // Response text public $responseXml; // Response XML public $status; // Status code public $statusText; // Status text public $error; // Error code public $errorText; // Error text private $method; // Request method private $components; // URL components private $requestHeaders; // Request headers private $responseHeaders; // Response headers } // An example of using this class header( "Content-Type: text/plain" ); $request = new XmlHttpRequest(); $request->open( "get", "http://www.example.com" ); $request->send(); echo "---------- Status ----------\r\n"; echo "$request->status $request->statusText\r\n"; echo "\r\n---------- Headers ----------\r\n"; echo $request->getAllResponseHeaders(); echo "\r\n---------- Body ----------\r\n"; echo $request->responseText; ?>
This should give you something like this:
---------- Status ---------- 200 OK ---------- Headers ---------- Date: Tue, 01 Feb 2005 16:21: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 ---------- Body ---------- <HTML> <HEAD> <TITLE>Example Web Page</TITLE> </HEAD> <body> <p>You have reached this web page by typing "example.com", "example.net", or "example.org" into your web browser.</p> <p>These domain names are reserved for use in documentation and are not available for registration. See <a href="http://www.rfc-editor.org/rfc/rfc2606.txt">RFC 2606</a>, Section 3.</p> </BODY> </HTML>
Feel free to use it! You just need to give me credit by keeping the javadoc-like comment.
0 Comments:
Note that troll and spam comments will be deleted without any notification.
Post a Comment
<< Home