Webdesign in Siegen

HTTP Klasse

Fragen zum Thema PHP können hier gestellt werden

Moderator: Basti

Re: HTTP Klasse

Beitragvon Ingo am 12.05.2008, 20:02

Hi.
Dein Hinweis auf die Rechenintensität hat mich auf die Idee gebracht, hier vllt. ganz auf reguläre
Ausdrücke zu verzichten:

Code: Alles auswählen
$text = 'name1=value1&name2=value2&name3=value3';

$res = explode('&',$text);  // print_r($res);
foreach($res as $v)
{
  list($name,$value) = explode('=',$v);
  $params[$name] = $value;
}

Was aber nicht heißen soll, dass sich die Beschäftigung mit RegExp nicht lohnt - ganz im Gegenteil. :wink:
Gruß, Ingo :)
Die beste Browserweiche ... sitzt zwischen den Ohren ;o]
Benutzeravatar
Ingo
Moderator
 
Beiträge: 578
Registriert: 01.04.2007
Wohnort: Neuss/NRW

Re: HTTP Klasse

Beitragvon Avedo am 12.05.2008, 21:25

Abend!
Ja ich muss mich unbedingt mir RegExp beschäftigen. Dazu gibt es ja sogar ein ganz ganz tolles Tutorial, dass ich allerdings wegen des Abistresses nie fertig lesen konnte. Das muss ich unbedingt in nächster Zeit mal nacholen. Aber auf diese Idee bin ich jetzt gar nicht gekommen. Danke Ingo! Ich hoffe ich bin bald mit dieser Klasse fertig. Es gibt noch so viel zu tun.
MfG, Andy
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 553
Registriert: 09.12.2007
Wohnort: Göttingen

Re: HTTP Klasse

Beitragvon Avedo am 13.05.2008, 17:26

Hallo!
Endlich ist es soweit. Die Klasse ist eigentlich fertig. Leider habe ich sie noch nicht testen können und werde das die nächsten Tage wohl auch nicht schaffen. vielleicht hat aber jemand von euch Lust und Zeit mal etwas mit der Klasse zu experimentieren. Über Rückmeldungen, was Programmierung, Code und Usability angeht, bin ich wie immer sehr froh.

Leider hat die Klasse immer noch einen Fehler, den ich leider auch nicht beheben kann. Und zwar extrahiert die Methode divideReply() ja die Daten aus der Antwort des Servers und packt diese in ein Array. Das funktioniert eigentlich ganz gut. Doch leider macht immer noch der Content Probleme. Der Content wird nicht einfach an seinen Platz im Array geschrieben, sondern es wird noch etwas angehängt. Ein oder mehrere Zeichen sowie zwei Absätze. Leider konnte ich die betreffende Stelle im RFC nicht finden, mit der ich dieses Problem lösen könnte. Hat jemand von euch eine Idee? Ich bin absolut am verzweifeln.

Wäre echt super dankbar für Rückmeldungen und Hilfe bei meinem Problem.
MfG, Andy

Code: Alles auswählen
<?php 
error_reporting(E_ALL);

/***
* HttpConnect class allows easy connecting to a foreign server.

* @package HttpConnect
* @version 0.4
* @author Andreas Wilhelm <Andreas2209@web.de>
* @copyright Andreas Wilhelm
**/ 
class HttpConnect
{
   // protected class variables
   protected $host;
   protected $port;
   
   protected $ssl;
   
   // tip by Denis Wronka, who said, that many servers need a referrer
   protected $referrer;
   
   protected $logStats;
   protected $log;

   /**
   * Constructor - Is called when the class is instanced
   *
   * @access: public
   * @param Str $host
   * @param Int $port
   * @param Bool $log   
   * @return NONE
   */
   public function __construct($host='localhost', $port=80, $ssl=false, $log=false, $referrer="PHP/Http-Referrer")
   {
      // set server-variables
      $this->host = $host;
      $this->port = $port;
      
      $this->ssl = $ssl;
      $this->referrer = $referrer;
      
      // set if the connection with the server should be logged
      $this->logStats = $log;
   }

   /**
   * login() - Connects to the server
   *
   * @access: private
   * @param Str $host
   * @param Int $port
   * @return Handle
   */
   private function login()
   {   
      if ($this->ssl == true)
      {   
         // use ssl-connection and save connection handle
         $handle = @fsockopen('ssl://'.$this->host, $this->port);
         
         // throw error in case of failure
         if (!$handle)
         {
            throw new Exception("SSL-connection failed.\n");
         }
      }

      else
      {
         // connection handle is saved to $handle
         $handle = @fsockopen($this->host, $this->port);
                  
         // throw error in case of failure
         if (!$handle)
         {
            throw new Exception("Connection failed.\n");
         }
      }
      
      
      // switch to non-blocking mode - just return data no response
      set_socket_blocking($handle, true);
      
      // set timeout of the server connection
      stream_set_timeout($handle, 0, 200000);
      
      return $handle;
   }

   /**
   * auth() - Creates a connection to a secured server
   *
   * @access: private
   * @param Str $user
   * @param Str $password
   * @return String
   */
   private function auth($user, $password)
   {      
      if (!empty($user))
      {
         $auth = 'Authorization: Basic '.base64_encode($user.':'.$password)."\r\n";
      }

      else
      {
         $auth = '';
      }
      
      return $auth;
   }
 
   /**
   * logout() - Closes the connection
   *
   * @access: private
   * @return NONE
   */     
   private function logout($handle)
   {
      fclose($handle);
   }

   /**
   * sendCmd() - Sends a command to the server
   *
   * @access: private
   * @param Str $cmd
   * @return NONE
   */
   private function sendCmd($handle, $cmd)
   {
      // send the request
      fputs($handle, $cmd);
      
      // log the request
      $this->log("-> $cmd");
   }
   
   /**
   * readSock() - Reads out the response from the server
   *
   * @access: private
   * @return String
   */
   private function readSock($handle)
   {   
      $response = "";

      while(!feof($handle))
      {
         $response .= fread($handle, 1025);
      }
      
      $this->log($response);
      
      return $response;
   }
         
   /**
   * divideReply() - Spilts up the reply into the different information
   *
   * @access: private
   * @param Str $reply
   * @return Array
   */
   private function divideReply($reply)
   {      
       if( !preg_match('/^HTTP\/(1\.[01]) ([1-5][0-9]{2})/', $reply, $match) )
       {
         return false;
       }
      
       $hb = strpos($reply, "\r\n")+2;
       $cb = strpos($reply, "\r\n\r\n")+4;
      
       $parsed = array(
         'HTTP_VERSION'  => $match[1],
         'STATUS_CODE'   => $match[2],
         'HEADER_FIELDS' => array(),
         'CONTENT'       => (string) substr($reply, $cb+2)
       );
      
       $headerFields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', substr($reply, $hb, $cb-$hb-4)));
       foreach( $headerFields as $headerField )
       {
         if( preg_match('/([^:]+):(.+)/m', $headerField, $match) )
         {
           $parsed['HEADER_FIELDS'][$this->getName($match[1])] = trim($match[2]);
         }
       }
      
       return $parsed;
   }
   
   /**
   * getName() - Returns the name of a received htpp-header-field
   *
   * @access: private
   * @param Str $string
   * @return String
   */
   private function getName( $string )
   {
       return preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', strtolower(trim($string)));
   } 
         
   /**
   * head() - Returns the HTTP-header like a GET or POST reply but without the file
   *
   * @access: public
   * @param Str $uri
   * @param Str $params
   * @param Str $cookies
   * @param Str $user
   * @param Str $password
   * @return Array
   */
   public function head($uri='/', $params=false, $cookies=false, $user="", $password="")
   {
      // login to the server
      $handle = $this->login();
      
      // create authorization-string
      $auth = $this->auth($user, $password);
      
      // prepare uri for request
      if (empty($uri) || ($uri{0}!='/'))
      {
         $uri = "/$uri";
      }
            
      // check if parameters should be used and prepare them for request
      if (($params!=false) && (!empty($params)))
      {
         $params = "?$params";
      }
      
      else
      {
         $params = '';
      }
      
      // check if cookies should be used and prepare them for request
      if (($cookies!=false) && (!empty($cookies)))
      {
            $cookies = "Cookie: $cookies\r\n";
      }
      
      else
      {
         $cookies = '';
      }
      
      // prepare host-data
      $host = $this->host;
      
      if ($this->port != 80)
      {
         $host .= ':'.$this->port;
      }
      
      // send request to the server
      $this->sendCmd($handle, "HEAD $uri"."$params HTTP/1.1\r\n");
      $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
      $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
      $this->sendCmd($handle, "Connection: close\r\n\r\n");
      
      // get server response
      $reply = $this->readSock($handle);
      
      // end connection to the server
      $this->logout($handle);
      
      // prepare headers
      $data = $this->divideReply($reply);
      
      return $data;
   }
         
   /**
   * get() - Returns the HTTP-header and the output of the file
   *
   * @access: public
   * @param Str $uri
   * @param Str $params
   * @param Str $cookies
   * @param Str $user
   * @param Str $password
   * @return Array
   */
   public function get($uri='/', $params=false, $cookies=false, $user="", $password="")
   {
      // login to the server
      $handle = $this->login();
      
      // create authorization-string
      $auth = $this->auth($user, $password);
      
      // prepare uri for request
      if (empty($uri) || ($uri{0}!='/'))
      {
         $uri = "/$uri";
      }
            
      // check if parameters should be used and prepare them for request
      if (($params!=false) && (!empty($params)))
      {
         $params = "?$params";
      }
      
      else
      {
         $params = '';
      }
      
      // check if cookies should be used and prepare them for request
      if (($cookies!=false) && (!empty($cookies)))
      {
            $cookies = "Cookie: $cookies\r\n";
      }
      
      else
      {
         $cookies = '';
      }
      
      // prepare host-data
      $host = $this->host;
      if ($this->port != 80)
      {
         $host .= ':'.$this->port;
      }
      
      // send request to the server
      $this->sendCmd($handle, "GET $uri"."$params HTTP/1.1\r\n");
      $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
      $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
      $this->sendCmd($handle, "Connection: close\r\n\r\n");
      
      // get server response
      $reply = $this->readSock($handle);
      
      // end connection to the server
      $this->logout($handle);
      
      // prepare headers and file
      $data = $this->divideReply($reply);
      
      return $data;
   }
         
   /**
   * post() - Returns the HTTP-header and the output of the file
   *
   * @access: public
   * @param Str $uri
   * @param Str $params
   * @param Str $cookies
   * @param Str $fileparams
   * @param Str $mimes
   * @param Str $user
   * @param Str $password
   * @return Array
   */
   public function post($uri='/', $params=false, $cookies=false, $fileparams=false, $mimes=false, $user='',$password='')
   {
      // login to the server
      $handle = $this->login();
      
      // create authorization-string
      $auth = $this->auth($user, $password);
      
      // prepare uri for request
      if (empty($uri) || ($uri{0}!='/'))
      {
         $uri = "/$uri";
      }
            
      // check if parameters should be used and prepare them for request
      if (($params!=false) && (!empty($params)))
      {
         $params = "?$params";
      }
      
      else
      {
         $params = '';
      }
      
      // check if cookies should be used and prepare them for request
      if (($cookies!=false) && (!empty($cookies)))
      {
            $cookies = "Cookie: $cookies\r\n";
      }
      
      else
      {
         $cookies = '';
      }
      
      // prepare host-data
      $host = $this->host;
      if ($this->port != 80)
      {
         $host .= ':'.$this->port;
      }
      
      if (($fileparams==false) || (empty($fileparams)))
      {
         if (($params!=false) && (!empty($params)))
         {
            //prepare the attribut Content-Length
            $length = strlen($params);
            
            // send request and parameters to the server
            $this->sendCmd($handle, "POST ".$uri." HTTP/1.1\r\n");
            $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
            $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
            $this->sendCmd($handle, "Connection: close\r\n");
            
            $this->sendCmd($handle, "Content-Type: application/x-www-form-urlencoded\r\n");
            $this->sendCmd($handle, "Content-Length: ".$length."\r\n\r\n".$params);
         }

         else
         {
            // send request without parameters
            $this->sendCmd($handle, "POST ".$uri." HTTP/1.1\r\n");
            $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
            $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
            $this->sendCmd($handle, "Connection: close\r\n");
         }
      }
      
      else
      {
         // save the name and the value of the parameters to an array
         $res = split('&',$params);
         foreach($res as $v)
         {
            list($name, $value) = split('=', $v);
            $param[$name] = $value;
         }
         
         // do the same with the file-parameters
         $rep = split('&',$fileparams);
         foreach($rep as $v)
         {
            list($name, $value) = split('=', $v);
            $fparam[][$name] = $value;
         }
         
         // save given mimetypes to an array
         if ( ($mimes!=false) && (!empty($mimes)) )
         {
            $mimeparam = split(',', $mimes);
         }
         
         // create array for mimetypes if no exist
         if (!isset($mimeparam))
         {
            $mimeparam = array();
         }
         
         // fill empty mimetype-spaces with standrad-mimetype
         while (count($mimeparam) < count($fparam))         
         {
            $mimeparam[]='application/octet-stream';
         }         
         
         // the boundary seperates the different blocks holding the parameters
         $boundary = md5(uniqid());
         $content = '';         
         
         // start counter
         $key = 0;

         // prepare the blocks with the file-parameters
         foreach($fparam as $name => $fname)
         {
            $fp = fopen($fname, 'r');
            $fcontent = fread($fp, filesize($fname));
            $content .= '--'.$boundary."\r\n";
            $content .= 'Content-Disposition: form-data; name="'.$name.'"; filename="'.$fname.'"'."\r\n";
            $content .= 'Content-Type: '.$mimeparam[$key]."\r\n\r\n";
            $content .= $filecontent."\r\n";
   
            $key++;
         }
         
         // prepare the blocks for the parameters
         foreach($param as $name => $value)
         {
            $content .= '--'.$boundary."\r\n";
            $content .= 'Content-Disposition: form-data; name="'.$name.'"'."\r\n\r\n";
            
            if (!empty($value))
            {
               $content .= $value."\r\n";
            }
         }
         
         $content .= '--'.$boundary."--\r\n";
         
         // get length of the content
         $length = strlen($content);
         
         // send standard data
         $this->sendCmd($handle, "POST ".$uri." HTTP/1.1\r\n");
         $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
         $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
         $this->sendCmd($handle, "Connection: close\r\n");                  
                  
         // send the the parameters and file-parameters
         $this->sendCmd($handle, "Content-Type: multipart/form-data; boundary=".$boundary."\r\n");
         $this->sendCmd($handle, "Content-Length: ".$length."\r\n\r\n");
         $this->sendCmd($handle, $content);
      }
      
      // get server response
      $reply = $this->readSock($handle);
      
      // end connection to the server
      $this->logout($handle);
      
      // prepare headers and file
      $data = $this->divideReply($reply);
      
      return $data;
   }
         
   /**
   * log() - Saves all request to the server and their responses into $log
   *
   * @access: private
   * @param Str $str
   * @return NONE
   */
   private function log($str)
   {
      if($this->logStats)
      {
         $this->log .= $str;
      }
   }
         
   /**
   * getLog() - Prints out all requests to the server and their responses
   *
   * @access: public
   * @return NONE
   */
   public function getLog()
   {
      return $this->log;
   }
}

try
{
   // change Content-Type
   header('Content-Type: text/plain');
   $http = new HttpConnect("www.avedo.net", 80, false, true);
   
   $data = $http->head();
   
   $data2 = $http->get("httptest/test.php", "num=45");
   
   echo $http->getLog();
   
   print_r ($data);
   
   print_r ($data2);
}

catch(Exception $e)
{
   echo $e->getMessage();
}
?>
Zuletzt geändert von Avedo am 14.05.2008, 00:56, insgesamt 2-mal geändert.
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 553
Registriert: 09.12.2007
Wohnort: Göttingen

Re: HTTP Klasse

Beitragvon Ingo am 13.05.2008, 20:14

Hi. - Zwischenmeldung zur Syntax:

Zeile 425, gegen Ende: ein " zuviel
Zeile 479, im foreach-Kopf: Ein doppelter Pfeil? Als Zugriff auf ein 2-dim. Array? Hab ich so noch nie gesehen :?

Gruß, Ingo :)
Die beste Browserweiche ... sitzt zwischen den Ohren ;o]
Benutzeravatar
Ingo
Moderator
 
Beiträge: 578
Registriert: 01.04.2007
Wohnort: Neuss/NRW

Re: HTTP Klasse

Beitragvon Avedo am 13.05.2008, 23:04

Ups war wohl gestern Abend zu spät. Sehr interessante Sache mit dem foreach() doch muss ich schon Sagen. Was habe ich mir dabei gedacht? ^^ Ich hefte es mal unter unergründlichen Schwachsinn ab und ändere das ganze mal in folgendes:
Code: Alles auswählen
         // start counter
         $key = 0;

         // prepaare the blocks with the file-parameters
         foreach($fparam as $name => $fname)
         {
            $fp = fopen($fname, 'r');
            $fcontent = fread($fp, filesize($fname));
            $content .= '--'.$boundary."\r\n";
            $content .= 'Content-Disposition: form-data; name="'.$name.'"; filename="'.$fname.'"'."\r\n";
            $content .= 'Content-Type: '.$mimeparam[$key]."\r\n\r\n";
            $content .= $filecontent."\r\n";

            $key++;
         }

Muss dann halt auch die Zeile oben noch ändern.
Aber erstmal vielen Dank für deine Rückmeldung. Bin dankbar für jeden weiteren Kommentar.
MfG, Andy

//EDIT: Bis auf den Fehler mit dem " ist alles denke ichmal behoben. Habe leider momentan keinen Editor, da ich nicht zuhause bin. Keine Arbeitsoberfläche! :-(

//EDIT: Sollten jetzt beide Fehler behoben sein.
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 553
Registriert: 09.12.2007
Wohnort: Göttingen

Re: HTTP Klasse

Beitragvon Avedo am 18.05.2008, 20:32

Hallo!
Es ist wieder etwas voran gegangen und die Klasse ist fast fertig. Es bleibt allerdings der Fehler mit dem verqueren Content zu lösen. Doch auch dort hat sich etwas getan. es liegt wohl am Transfere-Encoding. Dies ist in dieser Übertragung chunked. Wer nicht weiß, was das ist und nicht gerade im RFC suchen will, dem sei gesagt, dass das Transfere-Encoding chunked bei der Übertragung von Daten verwendet wird, deren Länge am Anfang der Server-Antwort noch nicht absehbar ist. Zum Glück ist die Decodierung relativ einfach. Zudem wurde ich sogar auf einen allgemeinen Algorithmus aufmerksam gemacht, der die Decodierung eigentlich schon erklärt. Deshalb dachte ich mir, dass ich dann doch einfach eine weitere Methode in meine Klasse einbinde, die eben diese Decodierung vornimmt. das ganze sieht bisher so aus:
Code: Alles auswählen
   /**
   * decodeChunked() - Decodes Content in chunked encoding
   *
   * @access: private
   * @param Arr $chunked
   * @return Array
   */
   private function decodeChunked( $chunked )
   {      
      $length = 0;
      $body = '';      
      
      read chunk-size | chunk-extension (if any) and CRLF /([a-fA-F0-9_]+)(|(.+))\x0D\x0A/
      while (chunk-size > 0)
      {
         $chunk = read chunk-data and CRLF; /(.+)\x0D\x0A/
         $body .= $chunk;
         $length = $length + $chunkSize;
         read chunk-size and CRLF /([a-fA-F0-9_]+)\x0D\x0A/
      }
      
      // das habe ich noch nicht verstanden
      // muss ich mich nochmal genauer einlesen
      read entity-header   
      while (entity-header not empty)
      {
         append entity-header to existing header fields
         read entity-header
      }
      
      // set right Content-Length
      $chunked['HEADER_FIELDS']['Content-Length'] = $length;
      
      // change Transfere-Encoding
      $chunked['HEADER_FIELDS']['Transfer-Encoding'] = 'token';
      
      return $chunked;      
   } 

Wie ihr seht habe ich mich an der PHP-Form dieses Algorithmus schon versucht, bin allerdings nicht ganz fertig geworden. Und zwar bin ich mir nicht sicher, ob die RegExp, die ich da verfasst habe, auch wirklich stimmen. Des weiteren weiß ich leider nicht wirklich von welchen entity-headern da die Rede ist, aber das bekomme ich bestimmt noch raus. Wäre nett, wenn mir da mal jemand helfen könnte.
MfG, Andy

//EDIT: Ich befürchte alles was ich hier geschrieben und gefragt habe ist Bullshit. Nicht alles ist Bullshit, aber ich brauche keine RegExp, da man die Chunked-Codierung wohl leichter Sequenziell dekodiert.
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 553
Registriert: 09.12.2007
Wohnort: Göttingen

Re: HTTP Klasse

Beitragvon Avedo am 21.05.2008, 17:20

Hallo!
Endlich ist es soweit! Die Klasse ist fertig und soweit, wie ich das testen konnte, zum Einsatz bereit. Auf ihr baue ich gerade meine Repository-Klasse auf, die für ein kleines CMS mit Package-Management genutzt werden soll. Man kann allerdings viel viel mehr noch damit machen. man kann zum Beispiel den Status eines ICQ-Users ganz einfach abfragen (vielleicht auch eine Idee für der-webdesigner.net). Wie soetwas geht seht ihr zum Beispiel in den Testaufrufen am Ende der Klasse. Dort wird unter anderem mein ICQ-Status überprüft und entweder online, offline oder N/A als Status angegeben. Diese Angaben kann man finden, wenn man sich mal den unten stehenden Testaufruf anschaut. Diese ist dort im zweiten Response-Array unter CONTENT zu finden.

Da ich diese Klasse nicht so schnell hinbekommen hätte, hätte ich keine Hilfe gehabt, möchte ich mich besonders nochmal bei Basti, ingo, gumbo und Denis Wronka von tutorials.de bedanken. Basti, Ingo und gumbo standen mir des öfteren mit Rat und Tat beiseite und durch Denis Wronka bin ich darauf aufmerksam geworden, dass man bei vielen Servern einen Referrer angeben muss, da der Server den Request sonst nicht bearbeitet.

Ich würde mich sehr freuen, wenn einige die Klasse noch etwas ausführlicher testen würden und mir ein paar Hinweise zur Optimierung bzw. eine allgemeine Rückmeldung geben könnten.

MfG, Andy

Code: Alles auswählen
<?php 
error_reporting(E_ALL);

/***
* HttpConnect class allows easy connecting to a foreign server.

* @package HttpConnect
* @version 0.7
* @author Andreas Wilhelm <Andreas2209@web.de>
* @copyright Andreas Wilhelm
**/ 
class HttpConnect
{
   // protected class variables
   protected $host;
   protected $port;
   
   protected $ssl;
   
   // tip by Denis Wronka, who said, that many servers need a referrer
   protected $referrer;
   
   protected $logStats;
   protected $log;

   /**
   * connect() - Sets the server-variables
   *
   * @access: public
   * @param Str $host
   * @param Int $port
   * @param Bool $log   
   * @return NONE
   */
   public function connect($host='localhost', $port=80, $ssl=false, $log=false, $referrer="PHP/Http-Referrer")
   {
      // set server-variables
      $this->host = $host;
      $this->port = $port;
      
      $this->ssl = $ssl;
      $this->referrer = $referrer;
      
      // set if the connection with the server should be logged
      $this->logStats = $log;
   }

   /**
   * login() - Connects to the server
   *
   * @access: private
   * @param Str $host
   * @param Int $port
   * @return Handle
   */
   private function login()
   {   
      if ($this->ssl == true)
      {   
         // use ssl-connection and save connection handle
         $handle = @fsockopen('ssl://'.$this->host, $this->port);
         
         // throw error in case of failure
         if (!$handle)
         {
            throw new Exception("SSL-connection failed.\n");
         }
      }

      else
      {
         // connection handle is saved to $handle
         $handle = @fsockopen($this->host, $this->port);
                  
         // throw error in case of failure
         if (!$handle)
         {
            throw new Exception("Connection failed.\n");
         }
      }
      
      
      // switch to non-blocking mode - just return data no response
      set_socket_blocking($handle, true);
      
      // set timeout of the server connection
      stream_set_timeout($handle, 0, 200000);
      
      return $handle;
   }

   /**
   * auth() - Creates a connection to a secured server
   *
   * @access: private
   * @param Str $user
   * @param Str $password
   * @return String
   */
   private function auth($user, $password)
   {      
      if (!empty($user))
      {
         $auth = 'Authorization: Basic '.base64_encode($user.':'.$password)."\r\n";
      }

      else
      {
         $auth = '';
      }
      
      return $auth;
   }
 
   /**
   * logout() - Closes the connection
   *
   * @access: private
   * @return NONE
   */     
   private function logout($handle)
   {
      fclose($handle);
   }

   /**
   * sendCmd() - Sends a command to the server
   *
   * @access: private
   * @param Str $cmd
   * @return NONE
   */
   private function sendCmd($handle, $cmd)
   {
      // send the request
      fputs($handle, $cmd);
      
      // log the request
      $this->log("-> $cmd");
   }
   
   /**
   * readSock() - Reads out the response from the server
   *
   * @access: private
   * @return String
   */
   private function readSock($handle)
   {   
      $response = "";

      while(!feof($handle))
      {
         $response .= fread($handle, 1025);
      }
      
      $this->log($response);
      
      return $response;
   }
         
   /**
   * divideReply() - Spilts up the reply into the different information
   *
   * @access: private
   * @param Str $reply
   * @return Array
   */
   private function divideReply( $reply )
   {      
      if( !preg_match('/^HTTP\/(1\.[01]) ([1-5][0-9]{2})/', $reply, $match) )
      {
         return false;
      }
      
      $hb = strpos($reply, "\r\n")+2;
      $cb = strpos($reply, "\r\n\r\n")+4;
      
      $parsed = array(
         'HTTP_VERSION'  => $match[1],
         'STATUS_CODE'   => $match[2],
         'HEADER_FIELDS' => array(),
         'CONTENT'       => (string) substr($reply, $cb)
      );
      
      $headerFields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', substr($reply, $hb, $cb-$hb-4)));
      foreach( $headerFields as $headerField )
      {
         if( preg_match('/([^:]+):(.+)/m', $headerField, $match) )
         {
            $parsed['HEADER_FIELDS'][$this->getName($match[1])] = trim($match[2]);
         }
      }
      
      if( isset($parsed['HEADER_FIELDS']['Transfer-Encoding']) && $parsed['HEADER_FIELDS']['Transfer-Encoding'] == 'chunked' )   
      {
         $return = $this->decodeChunked($parsed);
      }
      
      else
      {
         $return = $parsed;
      }
      
      return $return;
   }
   
   /**
   * getName() - Returns the name of a received htpp-header-field
   *
   * @access: private
   * @param Str $string
   * @return String
   */
   private function getName($string)
   {
       return preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', strtolower(trim($string)));
   } 
   
   /**
   * decodeChunked() - Decodes body in chunked encoding
   *
   * @access: private
   * @param Arr $chunked
   * @return Array
   */
   private function decodeChunked($chunked)
   {   
      $body = '';
      $length = NULL;
      $size = NULL;
      
      // save chunked body to a variable
      $chunk = $chunked['CONTENT'];

      while(true)
      {
         // get next occurrence of CRLF
         $pos = @strpos($chunk, "\r\n", 0);

         if(!($pos === false) && $size === NULL)
         {
            // get the size of following chunk from hex
            $size = hexdec(substr($chunk, 0, $pos));
            
            // get the following chunk
            $body .= substr($chunk, $pos+2, $size);
            
            // update the content not encoded
            $chunk = substr($chunk, $pos+2+$size);
            
            // update content-length
            $length += $size;
            
            // reset chunk-size
            $size = NULL;
         }
         
         else
         {
            // leave loop
            break;
         }
      }
      
      // set right Content
      $chunked['CONTENT'] = $body;
      
      // set right Content-Length
      $chunked['HEADER_FIELDS']['Content-Length'] = $length;
      
      // change Transfere-Encoding
      $chunked['HEADER_FIELDS']['Transfer-Encoding'] = 'token';
   
      return $chunked;
   } 
         
   /**
   * head() - Returns the HTTP-header like a GET or POST reply but without the file
   *
   * @access: public
   * @param Str $uri
   * @param Str $params
   * @param Str $cookies
   * @param Str $user
   * @param Str $password
   * @return Array
   */
   public function head($uri='/', $params=false, $cookies=false, $user="", $password="")
   {
      // login to the server
      $handle = $this->login();
      
      // create authorization-string
      $auth = $this->auth($user, $password);
      
      // prepare uri for request
      if (empty($uri) || ($uri{0}!='/'))
      {
         $uri = "/$uri";
      }
            
      // check if parameters should be used and prepare them for request
      if (($params!=false) && (!empty($params)))
      {
         $params = "?$params";
      }
      
      else
      {
         $params = '';
      }
      
      // check if cookies should be used and prepare them for request
      if (($cookies!=false) && (!empty($cookies)))
      {
            $cookies = "Cookie: $cookies\r\n";
      }
      
      else
      {
         $cookies = '';
      }
      
      // prepare host-data
      $host = $this->host;
      
      if ($this->port != 80)
      {
         $host .= ':'.$this->port;
      }
      
      // send request to the server
      $this->sendCmd($handle, "HEAD $uri"."$params HTTP/1.1\r\n");
      $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
      $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
      $this->sendCmd($handle, "Connection: close\r\n\r\n");
      
      // get server response
      $reply = $this->readSock($handle);
      
      // end connection to the server
      $this->logout($handle);
      
      // prepare headers
      $data = $this->divideReply($reply);
      
      return $data;
   }
         
   /**
   * get() - Returns the HTTP-header and the output of the file
   *
   * @access: public
   * @param Str $uri
   * @param Str $params
   * @param Str $cookies
   * @param Str $user
   * @param Str $password
   * @return Array
   */
   public function get($uri='/', $params=false, $cookies=false, $user="", $password="")
   {
      // login to the server
      $handle = $this->login();
      
      // create authorization-string
      $auth = $this->auth($user, $password);
      
      // prepare uri for request
      if (empty($uri) || ($uri{0}!='/'))
      {
         $uri = "/$uri";
      }
            
      // check if parameters should be used and prepare them for request
      if (($params!=false) && (!empty($params)))
      {
         $params = "?$params";
      }
      
      else
      {
         $params = '';
      }
      
      // check if cookies should be used and prepare them for request
      if (($cookies!=false) && (!empty($cookies)))
      {
            $cookies = "Cookie: $cookies\r\n";
      }
      
      else
      {
         $cookies = '';
      }
      
      // prepare host-data
      $host = $this->host;
      if ($this->port != 80)
      {
         $host .= ':'.$this->port;
      }
      
      // send request to the server
      $this->sendCmd($handle, "GET $uri"."$params HTTP/1.1\r\n");
      $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
      $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
      $this->sendCmd($handle, "Connection: close\r\n\r\n");
      
      // get server response
      $reply = $this->readSock($handle);
      
      // end connection to the server
      $this->logout($handle);
      
      // prepare headers and file
      $data = $this->divideReply($reply);
      
      return $data;
   }
         
   /**
   * post() - Returns the HTTP-header and the output of the file
   *
   * @access: public
   * @param Str $uri
   * @param Str $params
   * @param Str $cookies
   * @param Str $fileparams
   * @param Str $mimes
   * @param Str $user
   * @param Str $password
   * @return Array
   */
   public function post($uri='/', $params=false, $cookies=false, $fileparams=false, $mimes=false, $user='',$password='')
   {
      // login to the server
      $handle = $this->login();
      
      // create authorization-string
      $auth = $this->auth($user, $password);
      
      // prepare uri for request
      if (empty($uri) || ($uri{0}!='/'))
      {
         $uri = "/$uri";
      }
            
      // check if parameters should be used and prepare them for request
      if (($params!=false) && (!empty($params)))
      {
         $params = "?$params";
      }
      
      else
      {
         $params = '';
      }
      
      // check if cookies should be used and prepare them for request
      if (($cookies!=false) && (!empty($cookies)))
      {
            $cookies = "Cookie: $cookies\r\n";
      }
      
      else
      {
         $cookies = '';
      }
      
      // prepare host-data
      $host = $this->host;
      if ($this->port != 80)
      {
         $host .= ':'.$this->port;
      }
      
      if (($fileparams==false) || (empty($fileparams)))
      {
         if (($params!=false) && (!empty($params)))
         {
            //prepare the attribut Content-Length
            $length = strlen($params);
            
            // send request and parameters to the server
            $this->sendCmd($handle, "POST ".$uri." HTTP/1.1\r\n");
            $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
            $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
            $this->sendCmd($handle, "Connection: close\r\n");
            
            $this->sendCmd($handle, "Content-Type: application/x-www-form-urlencoded\r\n");
            $this->sendCmd($handle, "Content-Length: ".$length."\r\n\r\n".$params);
         }

         else
         {
            // send request without parameters
            $this->sendCmd($handle, "POST ".$uri." HTTP/1.1\r\n");
            $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
            $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
            $this->sendCmd($handle, "Connection: close\r\n");
         }
      }
      
      else
      {
         // save the name and the value of the parameters to an array
         $res = split('&',$params);
         foreach($res as $v)
         {
            list($name, $value) = split('=', $v);
            $param[$name] = $value;
         }
         
         // do the same with the file-parameters
         $rep = split('&',$fileparams);
         foreach($rep as $v)
         {
            list($name, $value) = split('=', $v);
            $fparam[][$name] = $value;
         }
         
         // save given mimetypes to an array
         if ( ($mimes!=false) && (!empty($mimes)) )
         {
            $mimeparam = split(',', $mimes);
         }
         
         // create array for mimetypes if no exist
         if (!isset($mimeparam))
         {
            $mimeparam = array();
         }
         
         // fill empty mimetype-spaces with standrad-mimetype
         while (count($mimeparam) < count($fparam))         
         {
            $mimeparam[]='application/octet-stream';
         }         
         
         // the boundary seperates the different blocks holding the parameters
         $boundary = md5(uniqid());
         $content = '';         
         
         // start counter
         $key = 0;

         // prepare the blocks with the file-parameters
         foreach($fparam as $name => $fname)
         {
            $fp = fopen($fname, 'r');
            $fcontent = fread($fp, filesize($fname));
            $content .= '--'.$boundary."\r\n";
            $content .= 'Content-Disposition: form-data; name="'.$name.'"; filename="'.$fname.'"'."\r\n";
            $content .= 'Content-Type: '.$mimeparam[$key]."\r\n\r\n";
            $content .= $filecontent."\r\n";
   
            $key++;
         }
         
         // prepare the blocks for the parameters
         foreach($param as $name => $value)
         {
            $content .= '--'.$boundary."\r\n";
            $content .= 'Content-Disposition: form-data; name="'.$name.'"'."\r\n\r\n";
            
            if (!empty($value))
            {
               $content .= $value."\r\n";
            }
         }
         
         $content .= '--'.$boundary."--\r\n";
         
         // get length of the content
         $length = strlen($content);
         
         // send standard data
         $this->sendCmd($handle, "POST ".$uri." HTTP/1.1\r\n");
         $this->sendCmd($handle, "Host: $host\r\n".$cookies.$auth);
         $this->sendCmd($handle, "User-Agent: ".$this->referrer."\r\n");
         $this->sendCmd($handle, "Connection: close\r\n");                  
                  
         // send the the parameters and file-parameters
         $this->sendCmd($handle, "Content-Type: multipart/form-data; boundary=".$boundary."\r\n");
         $this->sendCmd($handle, "Content-Length: ".$length."\r\n\r\n");
         $this->sendCmd($handle, $content);
      }
      
      // get server response
      $reply = $this->readSock($handle);
      
      // end connection to the server
      $this->logout($handle);
      
      // prepare headers and file
      $data = $this->divideReply($reply);
      
      return $data;
   }
         
   /**
   * log() - Saves all request to the server and their responses into $log
   *
   * @access: private
   * @param Str $str
   * @return NONE
   */
   private function log($str)
   {
      if($this->logStats)
      {
         $this->log .= $str;
      }
   }
         
   /**
   * getLog() - Prints out all requests to the server and their responses
   *
   * @access: public
   * @return NONE
   */
   public function getLog()
   {
      return $this->log;
   }
}

try
{
   // change Content-Type
   header('Content-Type: text/plain');
   $http = new HttpConnect();
   
   // send request to avedo.net
   $http->connect("www.avedo.net", 80, false, true);
   $data = $http->get("http/test.php", "num=45");
      
   // send request to status.icq.com
   $http->connect("status.icq.com", 80, false, true);
   $data2 = $http->head("online.gif", "icq=237076093");
   
  if (strstr($data2['HEADER_FIELDS']['Location'], 'online1'))
  {
    $data2['CONTENT'] = 'Der User is online!';
  }
 
  if (strstr($data2['HEADER_FIELDS']['Location'], 'online0'))
  {
    $data2['CONTENT'] = 'Der User is offline!';
  }
 
  if (strstr($data2['HEADER_FIELDS']['Location'], 'online2'))
  {
    $data2['CONTENT'] = 'Der User is N/A!';
  }
   
   // print out the Data
   echo $http->getLog();
   
   print_r ($data);
   
   print_r ($data2);
}

catch(Exception $e)
{
   echo $e->getMessage();
}
?>
Ich bin zu Mimis Religion konvertiert!
I'm so tired of slitting the throats of people calling me a violent psychopath.
Benutzeravatar
Avedo
Mitglied
 
Beiträge: 553
Registriert: 09.12.2007
Wohnort: Göttingen

Vorherige

Zurück zu PHP

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste