<?php
/**
 * @created 2007-07-17
 * @file fetcher.php
 * @author Damian Świstowski <dswistowski@firma.gery.pl>
 * 
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
 * 
 * @brief plik z klasą do pobierania danych z serwera adcentral
 * 
 * 
 */
 
 /**
  * @brief pobieracz danych
  * 
  * Klasa pobierająca dane z serwera adcentral przy użyciu protokołu HTTP/1.1, umożliwia zalogowanie użytkownika, którego dane są podane w configu i wszystkie operacje tego użytkownika wykonywać jako on.
  */
 class fetcher
 {
 	protected $headers = array();
 	protected $body = '';
 	protected $sock = false;
 	protected $cookies = array();
 	
 	public function __construct(config $config)
 	{
 		$this->opcje = $config->fetcher;
 		$this->config = $config;
 		if($this->opcje['login'])
 			$this->zaloguj();
 	}
 	
 	/**
 	 * Zwraca nagłówki ostatniego zapytania
 	 */
 	public function ostatnieNaglowki()
 	{
 		return $this->headers;
 	}
 	
 	/**
 	 * Zwraca treść ostatniego zapytania
 	 */
 	public function ostatniaTresc()
 	{
 		return $this->body;
 	}
 	
 	/**
 	 * Logowanie użytkownika wg danych podanych w configu
 	 */
 	private function zaloguj()
 	{
 		$data = array('login'=>$this->opcje['login'], 'passwd'=>$this->opcje['haslo']);
		$this->wyslijPost('/logowanie/', $data);
		
 	}
 	/**
 	 * Przetwarza nagłówki ze stringów na tablicę asocjacyjną
 	 * @param $headers nagłówki otrzymane od serwera www
 	 */
 	protected function ustawNaglowki($headers)
 	{
 		$new_headers = array();
 		foreach(explode("\n",$headers) as $header)
 		{
 			$header = explode(': ', $header);
 			if(count($header)>1)
 			{
 				$new_headers[$header[0]] = $header[1];
 			}
 		}
 		$this->headers = $new_headers;
 		if(array_key_exists('Set-Cookie', $this->headers) )
 		{
 			$cookie = explode(';', $this->headers['Set-Cookie']);
 			$this->cookies[] = $cookie[0];
 		}
 	}
 	
 	/**
 	 * getter aktywnego połączenia
 	 */
 	private function getSock()
 	{
 		if(!($this->sock && is_resource($this->sock)))
 		{
	 		$this->sock = fsockopen($this->opcje['serwer'], 80, $errno, $errstr, 30);
			if (!$this->sock) throw new Exception("Bład przy połączeniu z serwerem adcentral $errstr ($errno)");
 		}
 		return $this->sock;
 	}
	
	/**
	 * helper zamieniający tablicę asocjacyjną na url
	 */
	private function urlencodearray($data)
	{
		if(is_array($data))
 		{
 			$new_data = array();
 			foreach($data as $klucz=>$wartosc)
 				$new_data[] = urlencode($klucz)."=".urlencode($wartosc);
 			$data = implode('&', $new_data);
 		}
 		return $data;
	}
	
	/**
	 * @brief wysłanie zapytania get
	 * 
	 * Wysyła zapytanie get do serwera podanego w configu
	 * @param $link adres pobieranego zasobu
	 * @param $data parametry przekazywane w zapytaniu
	 */
 	public function wyslijGet($link, $data = array())
 	{
 		$data = $this->urlencodearray($data);
 		if($data)
 			$data = '?'.$data; 
 		$sock = $this->getSock();
 		if(!fwrite($sock, "GET $link$data HTTP/1.1\r\n"))
 			throw new Exception("Błąd przy pobieraniu linku $link");
 		$this->sendHeaders();
 		$this->pobierzDane();
 	}
 
 	/**
 	 * @brief wysłanie zapytania post
 	 * 
 	 * Wysyła zapytanie post do serwera podanego w configu
 	 * @param $link adres do którego jest skierowane zapytanie
 	 * @param $data dane formularza
 	 */
 	public function wyslijPost($link, $data)
 	{
 		$data = $this->urlencodearray($data);
 		$serwer = $this->opcje['serwer'];
 		$sock = $this->getSock();
		fwrite($sock, "POST $link HTTP/1.1\r\n");
		$inne = array(
			'Content-type'=> 'application/x-www-form-urlencoded', 
			'Content-length'=>strlen($data));
		$this->sendHeaders($inne);
		
		fwrite($sock, "$data\r\n");
		fwrite($sock, "\r\n");
		$this->pobierzDane();
 	}
 	
 	/**
 	 * wewnętrzna funkcja odczytująca wynik żądania
 	 */
 	private function pobierzDane()
 	{
 		$sock = $this->getSock();
 		
 		$headers = "";
		while ($str = trim(fgets($sock, 4096)))
		  $headers .= "$str\n";
		$this->ustawNaglowki($headers);
		
		$body = "";
		$pobrane = " ";
		if(array_key_exists('Content-Length',$this->headers))
		{
				fwrite($sock,"\r\n");
				$dlugosc = ((int) $this->headers['Content-Length'])-1;
				while(($dlugosc>0) && strlen($pobrane))
				{
					$pobrane = fread($sock,$dlugosc);
					$body.=$pobrane;
					$dlugosc-=strlen($pobrane);
				}
		}
		else
		for(;;)
		{
			$dlugosc =  trim(fgets($sock));
			$dlugosc = intval($dlugosc,16);
			
			if(!$dlugosc) break;
			while($dlugosc && strlen($pobrane))
			{
				$pobrane = fread($sock, $dlugosc);
				$body.=$pobrane;
				$dlugosc-=strlen($pobrane);
			
			}
			fgets($sock);
		}
		fgets($sock);
		//wycięcie śmieci
		$body = ereg_replace('>[^>]*$','>',$body);
		$this->body = $body;
 	}
 	
 	/**
 	 * Wysyła nagłówki zapytania, łącznie z nagłówkami ciasteczek
 	 * @param $inne tablica z dodatkowymi nagłówkami
 	 */
 	private function sendHeaders($inne = array())
 	{
 		fwrite($this->sock, "Host: ".$this->opcje['serwer']."\r\n");
		fwrite($this->sock, "Accept: */*\r\n");
		fwrite($this->sock, "Keep-Alive: 300\r\n");
		fwrite($this->sock, "Connection: keep-alive\r\n");
		fwrite($this->sock, "User-Agent: Adcentral pobieracz v ".$this->config->wersja."\r\n");
		fwrite($this->sock, "X-Fetcher-Server: ".$_SERVER['SERVER_NAME']."\r\n");
		fwrite($this->sock, "X-Fetcher-Skrypt: ".$_SERVER['SCRIPT_NAME']."\r\n");
		foreach($inne as $nazwa=>$wartosc)
			fwrite($this->sock, "$nazwa: $wartosc\r\n");
		if($this->cookies)
			fwrite($this->sock, "Cookie: ".implode('; ',$this->cookies)."\r\n");
		fwrite($this->sock, "\r\n");
 	}
 	
 	public function __destruct()
 	{
 		if($this->sock && is_resource($this->sock))
 		{
			fwrite($this->sock, "\r\n");
			fclose($this->sock);
 		}
 	}
 }
?>
