<?php
class httpParser {
	public $url = "";
	public $status = "";
	public $host = "";
	public $subdomain = "";
	public $path = "";
	public $query = "";
	public $info = array();
	public $headers = array();
	public $raw_headers = array();
	public $status_codes = array();
	public $all_headers = array();
	
	public $last_referer = "";
	public $max_redirects = 5;
	public $allow_redirects = true;
	
	public $num_redirect = 0;
	public $final_status = "";
	public $final_message = "";
	
	
	public function __construct($url) {
		$this->url = $url;
		$this->parse_url_request();
	}

	public function parseUrl($url) {
		$r  = "^(?:(?P<scheme>\w+)://)?";
		$r .= "(?:(?P<login>\w+):(?P<pass>\w+)@)?";
		
		$ip = "(?:[0-9]{1,3}+\.){3}+[0-9]{1,3}";//ip check
		$s = "(?P<subdomain>[-\w\.]+)\.)?";//subdomain
		$d = "(?P<domain>[-\w]+\.)";//domain
		$e = "(?P<extension>\w+)";//extension
		
		$r .= "(?P<host>(?(?=".$ip.")(?P<ip>".$ip.")|(?:".$s.$d.$e."))";
		
		$r .= "(?::(?P<port>\d+))?";
		$r .= "(?P<path>[\w/]*/(?P<file>\w+(?:\.\w+)?)?)?";
		$r .= "(?:\?(?P<arg>[\w=&]+))?";
		$r .= "(?:#(?P<anchor>\w+))?";
		$r = "!$r!";   // Delimiters
		preg_match($r, $url, $out);
		return $out;
	}
	
	
	public function parse_url_request() {
	 	if(strpos($this->url, "http") === false) {
			$this->url = "http://" . $this->url;
		}
		$url_obj = parse_url($this->url);
		$this->host = $url_obj['host'];
		$this->path = (isset($url_obj['path']) && $url_obj['path'] != "") ? $url_obj['path'] : "/";
		$this->query = (isset($url_obj['query']) && $url_obj['query'] != "") ? $url_obj['query'] : "";
		
		$extra = $this->parseUrl($this->url);
		if(isset($extra['subdomain']) && $extra['subdomain'] != "") {
			$this->subdomain = $extra['subdomain'];
		}
	}
	
    public function get_headers() {
    	$header = $this->raw_headers;
        $retVal = array();
        $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header));
        foreach( $fields as $field ) {
            if( preg_match('/([^:]+): (.+)/m', $field, $match) ) {
                $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', strtolower(trim($match[1])));
                if( isset($retVal[$match[1]]) ) {
                    $retVal[$match[1]] = array($retVal[$match[1]], $match[2]);
                } else {
                    $retVal[$match[1]] = trim($match[2]);
                }
            }
        }
        return $retVal;
    }

	public function request_headers() {
		//echo '<br/>', $this->num_redirect, ') URL: ', $this->url;
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_URL, $this->url);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
		curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
		curl_setopt($ch, CURLOPT_HEADER, true); // header will be at output
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
		//curl_setopt($ch, CURLOPT_NOBODY, true);
		
		$this->raw_headers = curl_exec ($ch);
		//echo '<br/>' , var_dump($this->raw_headers);
		
		if(!curl_errno($ch)) {
			$this->info = curl_getinfo($ch);
		}
		
		curl_close ($ch);
		
		if($this->raw_headers) {
			// Get the firt line from the response 
			// an try to parse the Status Code
			$status_codes = array();
			$first_line = trim(strtok($this->raw_headers, "\r\n"));
			
			if($first_line != "") {
				if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $first_line, $status_codes)) {
					$this->status_codes = array();
				}
				else {
					$this->status_codes = $status_codes;
					$http_version = $this->status_codes[1]; // not used
	    	        $this->status = intval($this->status_codes[2]);
	    	        $status_string = $this->status_codes[3]; // not used
				}
			}
			
			if($this->status != "") {
				$this->headers = $this->get_headers();
				$this->headers ['status'] = $this->status;
				$this->headers ['status_message'] = $status_string;
				$this->headers ['host'] = $this->host;
				$this->headers ['subdomain'] = $this->subdomain;
				$this->headers ['path'] = $this->path;
				$this->headers ['query'] = $this->query;
				$this->all_headers [$this->num_redirect] = $this->headers;
				return $this->switch_status_code();
			}
			else {
				$this->headers = $this->get_headers();
				$this->headers ['status'] = $this->status;
				$this->headers ['status_message'] = "";
				$this->headers ['host'] = $this->host;
				$this->headers ['subdomain'] = $this->subdomain;
				$this->headers ['path'] = $this->path;
				$this->headers ['query'] = $this->query;
				$this->all_headers [$this->num_redirect] = $this->headers;
				$this->final_status = "VALID";
				$this->final_message = $this->status_codes[3];
			}
		}
		else {
			if(strpos(strtolower($this->host), "www.") === false && $this->subdomain == "") {
				$this->host = "www." . $this->host;
				$this->url = $this->host . $this->path . $this->query;
				$this->parse_url_request();
				$this->request_headers();
			}
			else {
				$this->final_status = "INVALID";
				$this->final_message = "URL does not exist";
			}
		}
	}
	
	public function switch_status_code() {
		if($this->status == 200 || $this->status == 203 || $this->status == 204 || $this->status == 205) {
			$this->final_status = "VALID";
			$this->final_message = $this->status_codes[3];
		}
		
		if($this->status == 201 || $this->status == 202) {
			$this->final_status = "INVALID";
			$this->final_message = $this->status_codes[3];
		}
		
		if($this->status == 300 
			|| $this->status == 301 
			|| $this->status == 302 
			|| $this->status == 303 
			|| $this->status == 304 
			|| $this->status == 307) {
			
			if($this->allow_redirects) {
				if($this->num_redirect < $this->max_redirects) {
					$location = $this->headers['Location'];
					if($location != "/") {
						if(strpos($location, "http") === false) {
							// Is a local redirect
							$new_url = $this->headers['host'] . "/" . $location;
							$new_url = str_replace("//", "/", $new_url);
							$this->url = $new_url;
							$this->parse_url_request();
							$this->headers = array();
							$this->status_codes = array();
							$this->num_redirect += 1;
							$this->request_headers();
						}
						else {
							$new_url = $location;
							$this->url = $new_url;
							$this->parse_url_request();
							$this->headers = array();
							$this->status_codes = array();
							$this->num_redirect += 1;
							$this->request_headers();
						}
					}
					else {
						$this->final_status = "VALID";
						$this->final_message = $this->status_codes[3];
					}
				}
				else {
					$this->final_status = "VALID";
					$this->final_message = $this->status_codes[3];
				}
			}
			
			
		}
		
		$invalid_400_statuses = array(400, 404);
		
		if($this->status == 400 || $this->status == 404) {
			if($this->path != "" && $this->path != "/") {
				$new_url = $this->headers['host'];
				$new_url = str_replace("//", "/", $new_url);
				$this->url = $new_url;
				$this->parse_url_request();
				$this->headers = array();
				$this->status_codes = array();
				$this->num_redirect += 1;
				$this->request_headers();
			}
			else {
				$this->final_status = "INVALID";
				$this->final_message = $this->status_codes[3];
			}
		}
		
		if(intval($this->status / 100) == 4 && !in_array($this->status, $invalid_400_statuses)) {
			$this->final_status = "INVALID";
			$this->final_message = $this->status_codes[3];
		}
		
		
		$invalid_500_statuses = array(500, 501, 503, 504, 505, 507, 509);
		
		if(intval($this->status / 100) == 5) {
			if(!in_array($this->status, $invalid_500_statuses)) {
				$this->final_status = "INVALID";
				$this->final_message = $this->status_codes[3];
			}
			else {
				$this->final_status = "TEMPORARY";
				$this->final_message = $this->status_codes[3];
			}
		}
		
		return true;
	}
	
}
?>