Subversion Repositories personal-webbase

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * ViaThinkSoft
  5.  * PHP Simple Internet Class (HTTPC = HTTP Class)
  6.  * Version: 1.4.1 (2009-08-06)
  7.  * Source: http://www.viathinksoft.de/?page=projektanzeige&seite=download&id=152
  8.  */
  9.  
  10. /* USAGE EXAMPLE */
  11.  
  12. /* function inetconn_ok() {
  13.         return true;
  14. }
  15.  
  16. $http = new HTTPClass;
  17.  
  18. // Everything is optional in this part
  19. $http->connection_checker = 'inetconn_ok';
  20. $http->user_agent = 'Hello World Browser';
  21. $http->redirect_limit = 15;
  22. $http->time_out = 10;
  23. $http->error_level = HTTPC_ERRLVL_FATAL_ERRORS;
  24. $http->use_old_http_protocol_version = false;
  25. $http->use_post_method = false;
  26. $http->additional_fields['Referer'] = 'http://www.viathinksoft.de/';
  27.  
  28. $res = $http->execute_http_request('http://www.example.com/');
  29. if ($res->error != HTTPC_NO_ERROR) {
  30.         echo 'Error!';
  31. } else {
  32.         if (!is_null($res->final_redirected_url)) echo '<p>Last redirection was: '.$res->final_redirected_url.'</p>';
  33.         echo '<p><code>'.nl2br(htmlentities($res->content)).'</code></p>';
  34. } */
  35.  
  36. define('HTTPC_NO_ERROR', 0);
  37. define('HTTPC_ERROR_INTERNET_CONNECTION', 1);
  38. define('HTTPC_ERROR_PROTOCOL', 2);
  39. define('HTTPC_ERROR_SOCKET', 3);
  40. define('HTTPC_WARNING_HTTP_STATUS_CODE', 4);
  41. define('HTTPC_ERROR_TOO_MANY_REDIRECTS', 5);
  42. define('HTTPC_WARNING_UNKNOWN_STATUS', 6);
  43. define('HTTPC_WARNING_REDIRECT_IGNORED', 7);
  44. define('HTTPC_WARNING_CONNECTION_CHECKER_INVALID', 8);
  45.  
  46. class HTTPClassResult {
  47.  
  48.         public $content = null;
  49.         public $status_code = null;
  50.         public $error = HTTPC_NO_ERROR;
  51.         public $error_info = null;
  52.         public $final_redirected_url = null;
  53.         public $redirect_counter = 0;
  54.         public $header = null;
  55.  
  56. }
  57.  
  58. define('HTTPC_ERRLVL_NO_ERRORS', 0);
  59. define('HTTPC_ERRLVL_FATAL_ERRORS', 1);
  60. define('HTTPC_ERRLVL_WARNINGS', 2);
  61.  
  62. class HTTPClass {
  63.  
  64.         public $user_agent;
  65.         public $redirect_limit;
  66.         public $time_out;
  67.         public $error_level;
  68.         public $connection_checker;
  69.         public $use_old_http_protocol_version;
  70.         public $use_post_method;
  71.         public $additional_fields;
  72.  
  73.         // Konstruktor
  74.  
  75.         function HTTPClass()
  76.         {
  77.                 $this->user_agent = 'PHP/'.phpversion();
  78.                 $this->redirect_limit = 50;
  79.                 $this->time_out = 10;
  80.                 $this->error_level = HTTPC_ERRLVL_WARNINGS;
  81.                 $this->connection_checker = null;
  82.                 $this->use_old_http_protocol_version = false;
  83.                 $this->use_post_method = false;
  84.                 $this->additional_fields = array();
  85.         }
  86.  
  87.         // http://de.php.net/manual/de/function.fsockopen.php#73581
  88.         // http://de.php.net/manual/de/function.fsockopen.php#75175
  89.  
  90.         private function decode_header ( $str )
  91.         {
  92.                 $part = preg_split ( "/\r?\n/", $str, -1, PREG_SPLIT_NO_EMPTY );
  93.                 $out = array ();
  94.  
  95.                 for ( $h = 0; $h < sizeof ( $part ); $h++ )
  96.                 {
  97.                         if ( $h != 0 )
  98.                         {
  99.                                 $pos = strpos ( $part[$h], ':' );
  100.                                 $k = strtolower ( str_replace ( ' ', '', substr ( $part[$h], 0, $pos ) ) );
  101.                                 $v = trim ( substr ( $part[$h], ( $pos + 1 ) ) );
  102.                         }
  103.                         else
  104.                         {
  105.                                 $k = 'status';
  106.                                 $v = explode ( ' ', $part[$h] );
  107.                                 $v = $v[1];
  108.                         }
  109.  
  110.                         if ($k == '') break; // Zusatz von Personal WebBase
  111.  
  112.                         if ( $k == 'set-cookie' )
  113.                         {
  114.                                 $out['cookies'][] = $v;
  115.                         }
  116.                         else if ( $k == 'content-type' )
  117.                         {
  118.                                 if ( ( $cs = strpos ( $v, ';' ) ) !== false )
  119.                                 {
  120.                                         $out[$k] = substr ( $v, 0, $cs );
  121.                                 }
  122.                                 else
  123.                                 {
  124.                                         $out[$k] = $v;
  125.                                 }
  126.                         }
  127.                         else
  128.                         {
  129.                                 $out[$k] = $v;
  130.                         }
  131.                 }
  132.  
  133.                 return $out;
  134.         }
  135.  
  136.         private function decode_body ( $info, $str, $eol = "\r\n" )
  137.         {
  138.                 $tmp = $str;
  139.                 $add = strlen ( $eol );
  140.                 $str = '';
  141.                 if ( isset ( $info['transfer-encoding'] ) && $info['transfer-encoding'] == 'chunked' )
  142.                 {
  143.                         do
  144.                         {
  145.                                 $tmp = ltrim ( $tmp );
  146.                                 $pos = strpos ( $tmp, $eol );
  147.                                 $len = hexdec ( substr ( $tmp, 0, $pos ) );
  148.                                 if ( isset ( $info['content-encoding'] ) )
  149.                                 {
  150.                                         $str .= gzinflate ( substr ( $tmp, ( $pos + $add + 10 ), $len ) );
  151.                                 }
  152.                                 else
  153.                                 {
  154.                                         $str .= substr ( $tmp, ( $pos + $add ), $len );
  155.                                 }
  156.  
  157.                                 $tmp = substr ( $tmp, ( $len + $pos + $add ) );
  158.                                 $check = trim ( $tmp );
  159.                         }
  160.                         while ( ! empty ( $check ) );
  161.                 }
  162.                 else if ( isset ( $info['content-encoding'] ) )
  163.                 {
  164.                         $str = gzinflate ( substr ( $tmp, 10 ) );
  165.                 }
  166.                 else {
  167.                         $str = $tmp;
  168.                 }
  169.                 return $str;
  170.         }
  171.  
  172.         private function url_protokoll_vorhanden($url)
  173.         {
  174.                 $ary = explode('://', $url);
  175.                 return ((strpos($ary[0], '/') === false) && (isset($ary[1])));
  176.         }
  177.  
  178.         private function get_error_class($code)
  179.         {
  180.                 return floor($code / 100);
  181.         }
  182.  
  183.         public function execute_http_request($url, $data_to_send)
  184.         {
  185.                 $result = new HTTPClassResult();
  186.  
  187.                 if (!is_null($this->connection_checker)) {
  188.                         if (!function_exists($this->connection_checker)) {
  189.                                 if ($this->error_level >= HTTPC_ERRLVL_WARNINGS) {
  190.                                         trigger_error("The connection checker function does not exists!", E_USER_WARNING);
  191.                                 }
  192.                                 $result->error = HTTPC_WARNING_CONNECTION_CHECKER_INVALID;
  193.                                 $result->error_info = null;
  194.                         } else {
  195.                                 if (!call_user_func($this->connection_checker)) {
  196.                                         if ($this->error_level >= HTTPC_ERRLVL_FATAL_ERRORS) {
  197.                                                 trigger_error('No internet connection', E_USER_ERROR);
  198.                                         }
  199.                                         $result->error = HTTPC_ERROR_INTERNET_CONNECTION;
  200.                                         return $result;
  201.                                 }
  202.                         }
  203.                 }
  204.  
  205.                 for ($result->redirect_counter = 0; $result->redirect_counter <= $this->redirect_limit; $result->redirect_counter++) {
  206.                         if (!$this->url_protokoll_vorhanden($url)) $url = 'http://'.$url;
  207.  
  208.                         // URL splitten
  209.                         $ary = explode('://', $url);
  210.                         $cry = explode('/', $ary[1]);
  211.                         $bry = explode(':', $cry[0]);
  212.  
  213.                         // Protokoll festlegen
  214.                         $protocol = strtolower($ary[0]);
  215.  
  216.                         // Und nun prüfen, ob das Protokoll gültig ist
  217.                         if (($protocol != 'http') && ($protocol != 'https')) {
  218.                                 if ($this->error_level >= HTTPC_ERRLVL_FATAL_ERRORS) {
  219.                                         trigger_error("Unknown protocol '$protocol'", E_USER_ERROR);
  220.                                 }
  221.                                 $result->error = HTTPC_ERROR_PROTOCOL;
  222.                                 $result->error_info = $protocol;
  223.                                 return $result;
  224.                         }
  225.  
  226.                         // Host festlegen
  227.                         $host = $bry[0];
  228.  
  229.                         // Port festlegen und ggf. SSL-Präfix setzen
  230.                         if (isset($bry[1])) {
  231.                                 // Es ist ein Port angegeben
  232.                                 $port = $bry[1];
  233.                         } else {
  234.                                 // Wenn nicht, dann den Standardports für das Protokoll anwählen
  235.  
  236.                                 if ($protocol == 'http') {
  237.                                         $port = 80;
  238.                                 } else if ($protocol == 'https') {
  239.                                         $port = 443;
  240.                                 }
  241.                         }
  242.  
  243.                         // Wenn SSL verwendet wird, dann den Präfix setzen
  244.                         if ($protocol == 'https') {
  245.                                 $ssl_prefix = 'ssl://';
  246.                         } else {
  247.                                 $ssl_prefix = '';
  248.                         }
  249.  
  250.                         // Request-String festlegen
  251.                         $req = '';
  252.                         for ($i=1; isset($cry[$i]); $i++) {
  253.                                 $req .= '/'.$cry[$i];
  254.                         }
  255.                         if ($req == '') $req = '/';
  256.  
  257.                         // Anfrage starten
  258.                         $fp = @fsockopen($ssl_prefix.$host, $port, $errno, $errstr, $this->time_out);
  259.                         if (!$fp) {
  260.                                 if ($this->error_level >= HTTPC_ERRLVL_FATAL_ERRORS) {
  261.                                         trigger_error("Could not open socket: '$errstr' ($errno)", E_USER_ERROR);
  262.                                 }
  263.                                 $result->error = HTTPC_ERROR_SOCKET;
  264.                                 $result->error_info = "$errstr ($errno)";
  265.                                 return $result;
  266.                         }
  267.  
  268.                         if ($this->use_post_method) {
  269.                                 // Anmerkung: Es gab Fälle, bei denen PHP in eine Endlosschleife stieg, wenn man bei POST nicht einzelne puts() verwendet
  270.  
  271.                                 if ($this->use_old_http_protocol_version) {
  272.                                         @fputs ($fp, "POST $req HTTP/1.0\r\n");
  273.                                 } else {
  274.                                         @fputs ($fp, "POST $req HTTP/1.1\r\n");
  275.                                         @fputs ($fp, "Host: $host\r\n");
  276.                                         @fputs ($fp, "Connection: close\r\n");
  277.                                 }
  278.  
  279.                                 foreach ($this->additional_fields as $akey => $aval) {
  280.                                         @fputs ($fp, "$akey: $aval\r\n");
  281.                                 }
  282.  
  283.                                 if ($data_to_send != '') {
  284.                                         fputs($fp, "Content-length: ". strlen($data_to_send) ."\r\n");
  285.                                 }
  286.  
  287.                                 @fputs ($fp, "User-Agent: ".$this->user_agent."\r\n\r\n");
  288.                                 @fputs($fp, $data_to_send);
  289.                         } else {
  290.                                 if ($this->use_old_http_protocol_version) {
  291.                                         $request  = "GET $req HTTP/1.0\r\n";
  292.                                 } else {
  293.                                         $request  = "GET $req HTTP/1.1\r\n";
  294.                                         $request .= "Host: $host\r\n";
  295.                                         $request .= "Connection: close\r\n";
  296.                                 }
  297.  
  298.                                 foreach ($this->additional_fields as $akey => $aval) {
  299.                                         $request .= "$akey: $aval\r\n";
  300.                                 }
  301.  
  302.                                 if ($data_to_send != '') {
  303.                                         fputs($fp, "Content-length: ". strlen($data_to_send) ."\r\n");
  304.                                 }
  305.  
  306.                                 $request .= "User-Agent: ".$this->user_agent."\r\n\r\n";
  307.                                 $request .= $data_to_send;
  308.  
  309.                                 @fputs ($fp, $request);
  310.                         }
  311.  
  312.                         $tmp = '';
  313.                         while (!@feof($fp)) {
  314.                                 $tmp .= @fgets($fp,128);
  315.                         }
  316.                         @fclose($fp);
  317.  
  318.                         // Die Kopfzeilen auswerten
  319.  
  320.                         $result->header = $this->decode_header($tmp);
  321.  
  322.                         if (isset($result->header['status'])) {
  323.                                 $result->status_code = $result->header['status'];
  324.                         } else {
  325.                                 // Das sollte niemals passieren ...
  326.  
  327.                                 if ($this->error_level >= HTTPC_ERRLVL_WARNINGS) {
  328.                                         trigger_error("HTTP-Status-Code unknown!", E_USER_WARNING);
  329.                                 }
  330.                                 $result->error = HTTPC_WARNING_UNKNOWN_STATUS;
  331.                                 $result->error_info = null;
  332.  
  333.                                 $result->status_code = 0;
  334.                         }
  335.  
  336.                         // Fehler (Status-Klassen ab 4)?
  337.  
  338.                         if ($this->get_error_class($result->status_code) >= 4) {
  339.                                 if ($this->error_level >= HTTPC_ERRLVL_WARNINGS) {
  340.                                         trigger_error("HTTP-Status-Code: '".$result->status_code."'!", E_USER_WARNING);
  341.                                 }
  342.                                 $result->error = HTTPC_WARNING_HTTP_STATUS_CODE;
  343.                                 $result->error_info = $result->status_code;
  344.                                 // Here NO return, since we also want to see the HTML-content of the error page
  345.                         }
  346.  
  347.                         // Prüfen, ob eine Weiterleitung vorhanden ist.
  348.  
  349.                         $location_vorhanden = ((isset($result->header['location'])) && ($result->header['location'] != ''));
  350.  
  351.                         if ((($this->get_error_class($result->status_code) == 3) || ($result->status_code == 201)) &&
  352.                                  ($location_vorhanden)) {
  353.                                 // Anmerkung: Laut RFC2616 ist das Feld "Location" scheinbar nur bei HTTP-Code 201 oder 3xx gültig.
  354.                                 // Daher prüfe ich zusätzlich, ob der Statuscode 3xx oder 201 vorliegt.
  355.                                 $weiterleitung = $result->header['location'];
  356.                         } else {
  357.                                 $weiterleitung = null;
  358.  
  359.                                 if ($location_vorhanden) {
  360.                                         // Das sollte eigentlich nicht passieren ...
  361.  
  362.                                         if ($this->error_level >= HTTPC_ERRLVL_WARNINGS) {
  363.                                                 trigger_error("A redirect was found but ignored because the status code '".$result->status_code."' did not allow it", E_USER_WARNING);
  364.                                         }
  365.                                         $result->error = HTTPC_WARNING_REDIRECT_IGNORED;
  366.                                         $result->error_info = $result->header['location']." (".$result->status_code.")";
  367.                                 }
  368.                         }
  369.  
  370.                         if (!is_null($weiterleitung)) {
  371.                                 if (strpos($weiterleitung, '://') !== false) {
  372.                                         // 1. Fall: http://www.example.com/test.php
  373.  
  374.                                         $url = $weiterleitung;
  375.                                 } else if (substr($weiterleitung, 0, 2) == './') {
  376.                                         // 2. Fall: ./test.php
  377.  
  378.                                         if (substr($req, strlen($req)-1, 1) != '/') {
  379.                                                 // Entweder ein Verzeichnis ohne / am Ende oder eine Datei
  380.                                                 // Letztes Element muss abgeschnitten werden
  381.                                                 $x = '';
  382.                                                 $gry = explode('/', $req);
  383.                                                 for ($j=1; isset($gry[$j+1]); $j++) {
  384.                                                         $x .= '/'.$gry[$j];
  385.                                                 }
  386.                                                 $x .= '/';
  387.                                         } else {
  388.                                                 $x = $req;
  389.                                         }
  390.                                         $x .= substr($weiterleitung, 2, strlen($weiterleitung)-2);
  391.  
  392.                                         $url = $protocol.'://'.$host.$x;
  393.                                 } else if (substr($weiterleitung, 0, 1) == '/') {
  394.                                         // 3. Fall: /test.php
  395.  
  396.                                         $x = $weiterleitung;
  397.  
  398.                                         $url = $protocol.'://'.$host.$x;
  399.                                 } else {
  400.                                         // 4. Fall: test.php (= ./test.php)
  401.  
  402.                                         $x = $req;
  403.                                         if (substr($req, strlen($req)-1, 1) != '/') {
  404.                                                 // Entweder ein Verzeichnis ohne / am Ende oder eine Datei
  405.                                                 // Letztes Element muss abgeschnitten werden
  406.                                                 $x = '';
  407.                                                 $gry = explode('/', $req);
  408.                                                 for ($j=1; isset($gry[$j+1]); $j++) {
  409.                                                         $x .= '/'.$gry[$j];
  410.                                                 }
  411.                                                 $x .= '/';
  412.                                         } else {
  413.                                                 $x = $req;
  414.                                         }
  415.                                         $x .= $weiterleitung;
  416.  
  417.                                         $url = $protocol.'://'.$host.$x;
  418.                                 }
  419.  
  420.                                 $result->header = null;
  421.                                 $result->final_redirected_url = $url;
  422.                         } else {
  423.                                 // Keine Weiterleitungen vorhanden
  424.  
  425.                                 // Content filtern
  426.                                 $con = explode("\r\n\r\n", $tmp);
  427.                                 $tmp = '';
  428.                                 for ($i=1; isset($con[$i]); $i++) {
  429.                                         $tmp .= $con[$i];
  430.                                         if (isset($con[$i+1])) $tmp .= "\r\n\r\n";
  431.                                 }
  432.  
  433.                                 $result->content = $this->decode_body($result->header, $tmp);
  434.                                 return $result;
  435.                         }
  436.                 }
  437.  
  438.                 // Es wurde zu oft umgeleitet
  439.                 if ($this->error_level >= HTTPC_ERRLVL_FATAL_ERRORS) {
  440.                         trigger_error("Redirect limit of '".$this->redirect_limit."' at URL '".$url."' redirects exceeded", E_USER_ERROR);
  441.                 }
  442.                 $result->error = HTTPC_ERROR_TOO_MANY_REDIRECTS;
  443.                 $result->error_info = $this->redirect_limit;
  444.                 return $result;
  445.         }
  446. }
  447.  
  448. ?>