home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 108 / MacAddict108.iso / Software / Internet & Communication / WordPress 1.5.1.dmg / wordpress / wp-includes / class-snoopy.php < prev    next >
Encoding:
PHP Script  |  2005-01-06  |  26.8 KB  |  901 lines

  1. <?php
  2.  
  3. /*************************************************
  4.  
  5. Snoopy - the PHP net client
  6. Author: Monte Ohrt <monte@ispi.net>
  7. Copyright (c): 1999-2000 ispi, all rights reserved
  8. Version: 1.0
  9.  
  10.  * This library is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU Lesser General Public
  12.  * License as published by the Free Software Foundation; either
  13.  * version 2.1 of the License, or (at your option) any later version.
  14.  *
  15.  * This library is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18.  * Lesser General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU Lesser General Public
  21.  * License along with this library; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  23.  
  24. You may contact the author of Snoopy by e-mail at:
  25. monte@ispi.net
  26.  
  27. Or, write to:
  28. Monte Ohrt
  29. CTO, ispi
  30. 237 S. 70th suite 220
  31. Lincoln, NE 68510
  32.  
  33. The latest version of Snoopy can be obtained from:
  34. http://snoopy.sourceforge.net
  35.  
  36. *************************************************/
  37.  
  38. if ( !in_array('Snoopy', get_declared_classes() ) ) :
  39. class Snoopy
  40. {
  41.     /**** Public variables ****/
  42.     
  43.     /* user definable vars */
  44.  
  45.     var $host            =    "www.php.net";        // host name we are connecting to
  46.     var $port            =    80;                    // port we are connecting to
  47.     var $proxy_host        =    "";                    // proxy host to use
  48.     var $proxy_port        =    "";                    // proxy port to use
  49.     var $agent            =    "Snoopy v1.0";        // agent we masquerade as
  50.     var    $referer        =    "";                    // referer info to pass
  51.     var $cookies        =    array();            // array of cookies to pass
  52.                                                 // $cookies["username"]="joe";
  53.     var    $rawheaders        =    array();            // array of raw headers to send
  54.                                                 // $rawheaders["Content-type"]="text/html";
  55.  
  56.     var $maxredirs        =    5;                    // http redirection depth maximum. 0 = disallow
  57.     var $lastredirectaddr    =    "";                // contains address of last redirected address
  58.     var    $offsiteok        =    true;                // allows redirection off-site
  59.     var $maxframes        =    0;                    // frame content depth maximum. 0 = disallow
  60.     var $expandlinks    =    true;                // expand links to fully qualified URLs.
  61.                                                 // this only applies to fetchlinks()
  62.                                                 // or submitlinks()
  63.     var $passcookies    =    true;                // pass set cookies back through redirects
  64.                                                 // NOTE: this currently does not respect
  65.                                                 // dates, domains or paths.
  66.     
  67.     var    $user            =    "";                    // user for http authentication
  68.     var    $pass            =    "";                    // password for http authentication
  69.     
  70.     // http accept types
  71.     var $accept            =    "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
  72.     
  73.     var $results        =    "";                    // where the content is put
  74.         
  75.     var $error            =    "";                    // error messages sent here
  76.     var    $response_code    =    "";                    // response code returned from server
  77.     var    $headers        =    array();            // headers returned from server sent here
  78.     var    $maxlength        =    500000;                // max return data length (body)
  79.     var $read_timeout    =    0;                    // timeout on read operations, in seconds
  80.                                                 // supported only since PHP 4 Beta 4
  81.                                                 // set to 0 to disallow timeouts
  82.     var $timed_out        =    false;                // if a read operation timed out
  83.     var    $status            =    0;                    // http request status
  84.     
  85.     var    $curl_path        =    "/usr/bin/curl";
  86.                                                 // Snoopy will use cURL for fetching
  87.                                                 // SSL content if a full system path to
  88.                                                 // the cURL binary is supplied here.
  89.                                                 // set to false if you do not have
  90.                                                 // cURL installed. See http://curl.haxx.se
  91.                                                 // for details on installing cURL.
  92.                                                 // Snoopy does *not* use the cURL
  93.                                                 // library functions built into php,
  94.                                                 // as these functions are not stable
  95.                                                 // as of this Snoopy release.
  96.     
  97.     // send Accept-encoding: gzip?
  98.     var $use_gzip        = true;    
  99.     
  100.     /**** Private variables ****/    
  101.     
  102.     var    $_maxlinelen    =    4096;                // max line length (headers)
  103.     
  104.     var $_httpmethod    =    "GET";                // default http request method
  105.     var $_httpversion    =    "HTTP/1.0";            // default http request version
  106.     var $_submit_method    =    "POST";                // default submit method
  107.     var $_submit_type    =    "application/x-www-form-urlencoded";    // default submit type
  108.     var $_mime_boundary    =   "";                    // MIME boundary for multipart/form-data submit type
  109.     var $_redirectaddr    =    false;                // will be set if page fetched is a redirect
  110.     var $_redirectdepth    =    0;                    // increments on an http redirect
  111.     var $_frameurls        =     array();            // frame src urls
  112.     var $_framedepth    =    0;                    // increments on frame depth
  113.     
  114.     var $_isproxy        =    false;                // set if using a proxy server
  115.     var $_fp_timeout    =    30;                    // timeout for socket connection
  116.  
  117. /*======================================================================*\
  118.     Function:    fetch
  119.     Purpose:    fetch the contents of a web page
  120.                 (and possibly other protocols in the
  121.                 future like ftp, nntp, gopher, etc.)
  122.     Input:        $URI    the location of the page to fetch
  123.     Output:        $this->results    the output text from the fetch
  124. \*======================================================================*/
  125.  
  126.     function fetch($URI)
  127.     {
  128.     
  129.         //preg_match("|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|",$URI,$URI_PARTS);
  130.         $URI_PARTS = parse_url($URI);
  131.         if (!empty($URI_PARTS["user"]))
  132.             $this->user = $URI_PARTS["user"];
  133.         if (!empty($URI_PARTS["pass"]))
  134.             $this->pass = $URI_PARTS["pass"];
  135.                 
  136.         switch($URI_PARTS["scheme"])
  137.         {
  138.             case "http":
  139.                 $this->host = $URI_PARTS["host"];
  140.                 if(!empty($URI_PARTS["port"]))
  141.                     $this->port = $URI_PARTS["port"];
  142.                 if($this->_connect($fp))
  143.                 {
  144.                     if($this->_isproxy)
  145.                     {
  146.                         // using proxy, send entire URI
  147.                         $this->_httprequest($URI,$fp,$URI,$this->_httpmethod);
  148.                     }
  149.                     else
  150.                     {
  151.                         $path = $URI_PARTS["path"].(isset($URI_PARTS["query"]) ? "?".$URI_PARTS["query"] : "");
  152.                         // no proxy, send only the path
  153.                         $this->_httprequest($path, $fp, $URI, $this->_httpmethod);
  154.                     }
  155.                     
  156.                     $this->_disconnect($fp);
  157.  
  158.                     if($this->_redirectaddr)
  159.                     {
  160.                         /* url was redirected, check if we've hit the max depth */
  161.                         if($this->maxredirs > $this->_redirectdepth)
  162.                         {
  163.                             // only follow redirect if it's on this site, or offsiteok is true
  164.                             if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
  165.                             {
  166.                                 /* follow the redirect */
  167.                                 $this->_redirectdepth++;
  168.                                 $this->lastredirectaddr=$this->_redirectaddr;
  169.                                 $this->fetch($this->_redirectaddr);
  170.                             }
  171.                         }
  172.                     }
  173.  
  174.                     if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0)
  175.                     {
  176.                         $frameurls = $this->_frameurls;
  177.                         $this->_frameurls = array();
  178.                         
  179.                         while(list(,$frameurl) = each($frameurls))
  180.                         {
  181.                             if($this->_framedepth < $this->maxframes)
  182.                             {
  183.                                 $this->fetch($frameurl);
  184.                                 $this->_framedepth++;
  185.                             }
  186.                             else
  187.                                 break;
  188.                         }
  189.                     }                    
  190.                 }
  191.                 else
  192.                 {
  193.                     return false;
  194.                 }
  195.                 return true;                    
  196.                 break;
  197.             case "https":
  198.                 if(!$this->curl_path || (!is_executable($this->curl_path))) {
  199.                     $this->error = "Bad curl ($this->curl_path), can't fetch HTTPS \n";
  200.                     return false;
  201.                 }
  202.                 $this->host = $URI_PARTS["host"];
  203.                 if(!empty($URI_PARTS["port"]))
  204.                     $this->port = $URI_PARTS["port"];
  205.                 if($this->_isproxy)
  206.                 {
  207.                     // using proxy, send entire URI
  208.                     $this->_httpsrequest($URI,$URI,$this->_httpmethod);
  209.                 }
  210.                 else
  211.                 {
  212.                     $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : "");
  213.                     // no proxy, send only the path
  214.                     $this->_httpsrequest($path, $URI, $this->_httpmethod);
  215.                 }
  216.  
  217.                 if($this->_redirectaddr)
  218.                 {
  219.                     /* url was redirected, check if we've hit the max depth */
  220.                     if($this->maxredirs > $this->_redirectdepth)
  221.                     {
  222.                         // only follow redirect if it's on this site, or offsiteok is true
  223.                         if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
  224.                         {
  225.                             /* follow the redirect */
  226.                             $this->_redirectdepth++;
  227.                             $this->lastredirectaddr=$this->_redirectaddr;
  228.                             $this->fetch($this->_redirectaddr);
  229.                         }
  230.                     }
  231.                 }
  232.  
  233.                 if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0)
  234.                 {
  235.                     $frameurls = $this->_frameurls;
  236.                     $this->_frameurls = array();
  237.  
  238.                     while(list(,$frameurl) = each($frameurls))
  239.                     {
  240.                         if($this->_framedepth < $this->maxframes)
  241.                         {
  242.                             $this->fetch($frameurl);
  243.                             $this->_framedepth++;
  244.                         }
  245.                         else
  246.                             break;
  247.                     }
  248.                 }                    
  249.                 return true;                    
  250.                 break;
  251.             default:
  252.                 // not a valid protocol
  253.                 $this->error    =    'Invalid protocol "'.$URI_PARTS["scheme"].'"\n';
  254.                 return false;
  255.                 break;
  256.         }        
  257.         return true;
  258.     }
  259.  
  260.  
  261.  
  262. /*======================================================================*\
  263.     Private functions
  264. \*======================================================================*/
  265.     
  266.     
  267. /*======================================================================*\
  268.     Function:    _striplinks
  269.     Purpose:    strip the hyperlinks from an html document
  270.     Input:        $document    document to strip.
  271.     Output:        $match        an array of the links
  272. \*======================================================================*/
  273.  
  274.     function _striplinks($document)
  275.     {    
  276.         preg_match_all("'<\s*a\s+.*href\s*=\s*            # find <a href=
  277.                         ([\"\'])?                    # find single or double quote
  278.                         (?(1) (.*?)\\1 | ([^\s\>]+))        # if quote found, match up to next matching
  279.                                                     # quote, otherwise match up to next space
  280.                         'isx",$document,$links);
  281.                         
  282.  
  283.         // catenate the non-empty matches from the conditional subpattern
  284.  
  285.         while(list($key,$val) = each($links[2]))
  286.         {
  287.             if(!empty($val))
  288.                 $match[] = $val;
  289.         }                
  290.         
  291.         while(list($key,$val) = each($links[3]))
  292.         {
  293.             if(!empty($val))
  294.                 $match[] = $val;
  295.         }        
  296.         
  297.         // return the links
  298.         return $match;
  299.     }
  300.  
  301. /*======================================================================*\
  302.     Function:    _stripform
  303.     Purpose:    strip the form elements from an html document
  304.     Input:        $document    document to strip.
  305.     Output:        $match        an array of the links
  306. \*======================================================================*/
  307.  
  308.     function _stripform($document)
  309.     {    
  310.         preg_match_all("'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",$document,$elements);
  311.         
  312.         // catenate the matches
  313.         $match = implode("\r\n",$elements[0]);
  314.                 
  315.         // return the links
  316.         return $match;
  317.     }
  318.  
  319.     
  320.     
  321. /*======================================================================*\
  322.     Function:    _striptext
  323.     Purpose:    strip the text from an html document
  324.     Input:        $document    document to strip.
  325.     Output:        $text        the resulting text
  326. \*======================================================================*/
  327.  
  328.     function _striptext($document)
  329.     {
  330.         
  331.         // I didn't use preg eval (//e) since that is only available in PHP 4.0.
  332.         // so, list your entities one by one here. I included some of the
  333.         // more common ones.
  334.                                 
  335.         $search = array("'<script[^>]*?>.*?</script>'si",    // strip out javascript
  336.                         "'<[\/\!]*?[^<>]*?>'si",            // strip out html tags
  337.                         "'([\r\n])[\s]+'",                    // strip out white space
  338.                         "'&(quote|#34);'i",                    // replace html entities
  339.                         "'&(amp|#38);'i",
  340.                         "'&(lt|#60);'i",
  341.                         "'&(gt|#62);'i",
  342.                         "'&(nbsp|#160);'i",
  343.                         "'&(iexcl|#161);'i",
  344.                         "'&(cent|#162);'i",
  345.                         "'&(pound|#163);'i",
  346.                         "'&(copy|#169);'i"
  347.                         );                
  348.         $replace = array(    "",
  349.                             "",
  350.                             "\\1",
  351.                             "\"",
  352.                             "&",
  353.                             "<",
  354.                             ">",
  355.                             " ",
  356.                             chr(161),
  357.                             chr(162),
  358.                             chr(163),
  359.                             chr(169));
  360.                     
  361.         $text = preg_replace($search,$replace,$document);
  362.                                 
  363.         return $text;
  364.     }
  365.  
  366. /*======================================================================*\
  367.     Function:    _expandlinks
  368.     Purpose:    expand each link into a fully qualified URL
  369.     Input:        $links            the links to qualify
  370.                 $URI            the full URI to get the base from
  371.     Output:        $expandedLinks    the expanded links
  372. \*======================================================================*/
  373.  
  374.     function _expandlinks($links,$URI)
  375.     {
  376.         
  377.         preg_match("/^[^\?]+/",$URI,$match);
  378.  
  379.         $match = preg_replace("|/[^\/\.]+\.[^\/\.]+$|","",$match[0]);
  380.                 
  381.         $search = array(     "|^http://".preg_quote($this->host)."|i",
  382.                             "|^(?!http://)(\/)?(?!mailto:)|i",
  383.                             "|/\./|",
  384.                             "|/[^\/]+/\.\./|"
  385.                         );
  386.                         
  387.         $replace = array(    "",
  388.                             $match."/",
  389.                             "/",
  390.                             "/"
  391.                         );            
  392.                 
  393.         $expandedLinks = preg_replace($search,$replace,$links);
  394.  
  395.         return $expandedLinks;
  396.     }
  397.  
  398. /*======================================================================*\
  399.     Function:    _httprequest
  400.     Purpose:    go get the http data from the server
  401.     Input:        $url        the url to fetch
  402.                 $fp            the current open file pointer
  403.                 $URI        the full URI
  404.                 $body        body contents to send if any (POST)
  405.     Output:        
  406. \*======================================================================*/
  407.     
  408.     function _httprequest($url,$fp,$URI,$http_method,$content_type="",$body="")
  409.     {
  410.         if($this->passcookies && $this->_redirectaddr)
  411.             $this->setcookies();
  412.             
  413.         $URI_PARTS = parse_url($URI);
  414.         if(empty($url))
  415.             $url = "/";
  416.         $headers = $http_method." ".$url." ".$this->_httpversion."\r\n";        
  417.         if(!empty($this->agent))
  418.             $headers .= "User-Agent: ".$this->agent."\r\n";
  419.         if(!empty($this->host) && !isset($this->rawheaders['Host']))
  420.             $headers .= "Host: ".$this->host."\r\n";
  421.         if(!empty($this->accept))
  422.             $headers .= "Accept: ".$this->accept."\r\n";
  423.         
  424.         if($this->use_gzip) {
  425.             // make sure PHP was built with --with-zlib
  426.             // and we can handle gzipp'ed data
  427.             if ( function_exists(gzinflate) ) {
  428.                $headers .= "Accept-encoding: gzip\r\n";
  429.             }
  430.             else {
  431.                trigger_error(
  432.                    "use_gzip is on, but PHP was built without zlib support.".
  433.                 "  Requesting file(s) without gzip encoding.", 
  434.                 E_USER_NOTICE);
  435.             }
  436.         }
  437.         
  438.         if(!empty($this->referer))
  439.             $headers .= "Referer: ".$this->referer."\r\n";
  440.         if(!empty($this->cookies))
  441.         {            
  442.             if(!is_array($this->cookies))
  443.                 $this->cookies = (array)$this->cookies;
  444.     
  445.             reset($this->cookies);
  446.             if ( count($this->cookies) > 0 ) {
  447.                 $cookie_headers .= 'Cookie: ';
  448.                 foreach ( $this->cookies as $cookieKey => $cookieVal ) {
  449.                 $cookie_headers .= $cookieKey."=".urlencode($cookieVal)."; ";
  450.                 }
  451.                 $headers .= substr($cookie_headers,0,-2) . "\r\n";
  452.             } 
  453.         }
  454.         if(!empty($this->rawheaders))
  455.         {
  456.             if(!is_array($this->rawheaders))
  457.                 $this->rawheaders = (array)$this->rawheaders;
  458.             while(list($headerKey,$headerVal) = each($this->rawheaders))
  459.                 $headers .= $headerKey.": ".$headerVal."\r\n";
  460.         }
  461.         if(!empty($content_type)) {
  462.             $headers .= "Content-type: $content_type";
  463.             if ($content_type == "multipart/form-data")
  464.                 $headers .= "; boundary=".$this->_mime_boundary;
  465.             $headers .= "\r\n";
  466.         }
  467.         if(!empty($body))    
  468.             $headers .= "Content-length: ".strlen($body)."\r\n";
  469.         if(!empty($this->user) || !empty($this->pass))    
  470.             $headers .= "Authorization: BASIC ".base64_encode($this->user.":".$this->pass)."\r\n";
  471.  
  472.         $headers .= "\r\n";
  473.         
  474.         // set the read timeout if needed
  475.         if ($this->read_timeout > 0)
  476.             socket_set_timeout($fp, $this->read_timeout);
  477.         $this->timed_out = false;
  478.         
  479.         fwrite($fp,$headers.$body,strlen($headers.$body));
  480.         
  481.         $this->_redirectaddr = false;
  482.         unset($this->headers);
  483.         
  484.         // content was returned gzip encoded?
  485.         $is_gzipped = false;
  486.                         
  487.         while($currentHeader = fgets($fp,$this->_maxlinelen))
  488.         {
  489.             if ($this->read_timeout > 0 && $this->_check_timeout($fp))
  490.             {
  491.                 $this->status=-100;
  492.                 return false;
  493.             }
  494.                 
  495.         //    if($currentHeader == "\r\n")
  496.             if(preg_match("/^\r?\n$/", $currentHeader) )
  497.                   break;
  498.                         
  499.             // if a header begins with Location: or URI:, set the redirect
  500.             if(preg_match("/^(Location:|URI:)/i",$currentHeader))
  501.             {
  502.                 // get URL portion of the redirect
  503.                 preg_match("/^(Location:|URI:)\s+(.*)/",chop($currentHeader),$matches);
  504.                 // look for :// in the Location header to see if hostname is included
  505.                 if(!preg_match("|\:\/\/|",$matches[2]))
  506.                 {
  507.                     // no host in the path, so prepend
  508.                     $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port;
  509.                     // eliminate double slash
  510.                     if(!preg_match("|^/|",$matches[2]))
  511.                             $this->_redirectaddr .= "/".$matches[2];
  512.                     else
  513.                             $this->_redirectaddr .= $matches[2];
  514.                 }
  515.                 else
  516.                     $this->_redirectaddr = $matches[2];
  517.             }
  518.         
  519.             if(preg_match("|^HTTP/|",$currentHeader))
  520.             {
  521.                 if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$currentHeader, $status))
  522.                 {
  523.                     $this->status= $status[1];
  524.                 }                
  525.                 $this->response_code = $currentHeader;
  526.             }
  527.             
  528.             if (preg_match("/Content-Encoding: gzip/", $currentHeader) ) {
  529.                 $is_gzipped = true;
  530.             }
  531.             
  532.             $this->headers[] = $currentHeader;
  533.         }
  534.  
  535.         # $results = fread($fp, $this->maxlength);
  536.         $results = "";
  537.         while ( $data = fread($fp, $this->maxlength) ) {
  538.             $results .= $data;
  539.             if (
  540.                 strlen($results) > $this->maxlength ) {
  541.                 break;
  542.             }
  543.         }
  544.         
  545.         // gunzip
  546.         if ( $is_gzipped ) {
  547.             // per http://www.php.net/manual/en/function.gzencode.php
  548.             $results = substr($results, 10);
  549.             $results = gzinflate($results);
  550.         }
  551.         
  552.         if ($this->read_timeout > 0 && $this->_check_timeout($fp))
  553.         {
  554.             $this->status=-100;
  555.             return false;
  556.         }
  557.         
  558.         // check if there is a a redirect meta tag
  559.         
  560.         if(preg_match("'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]+URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match))
  561.         {
  562.             $this->_redirectaddr = $this->_expandlinks($match[1],$URI);    
  563.         }
  564.  
  565.         // have we hit our frame depth and is there frame src to fetch?
  566.         if(($this->_framedepth < $this->maxframes) && preg_match_all("'<frame\s+.*src[\s]*=[\'\"]?([^\'\"\>]+)'i",$results,$match))
  567.         {
  568.             $this->results[] = $results;
  569.             for($x=0; $x<count($match[1]); $x++)
  570.                 $this->_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host);
  571.         }
  572.         // have we already fetched framed content?
  573.         elseif(is_array($this->results))
  574.             $this->results[] = $results;
  575.         // no framed content
  576.         else
  577.             $this->results = $results;
  578.         
  579.         return true;
  580.     }
  581.  
  582. /*======================================================================*\
  583.     Function:    _httpsrequest
  584.     Purpose:    go get the https data from the server using curl
  585.     Input:        $url        the url to fetch
  586.                 $URI        the full URI
  587.                 $body        body contents to send if any (POST)
  588.     Output:        
  589. \*======================================================================*/
  590.     
  591.     function _httpsrequest($url,$URI,$http_method,$content_type="",$body="")
  592.     {
  593.         if($this->passcookies && $this->_redirectaddr)
  594.             $this->setcookies();
  595.  
  596.         $headers = array();        
  597.                     
  598.         $URI_PARTS = parse_url($URI);
  599.         if(empty($url))
  600.             $url = "/";
  601.         // GET ... header not needed for curl
  602.         //$headers[] = $http_method." ".$url." ".$this->_httpversion;        
  603.         if(!empty($this->agent))
  604.             $headers[] = "User-Agent: ".$this->agent;
  605.         if(!empty($this->host))
  606.             $headers[] = "Host: ".$this->host;
  607.         if(!empty($this->accept))
  608.             $headers[] = "Accept: ".$this->accept;
  609.         if(!empty($this->referer))
  610.             $headers[] = "Referer: ".$this->referer;
  611.         if(!empty($this->cookies))
  612.         {            
  613.             if(!is_array($this->cookies))
  614.                 $this->cookies = (array)$this->cookies;
  615.     
  616.             reset($this->cookies);
  617.             if ( count($this->cookies) > 0 ) {
  618.                 $cookie_str = 'Cookie: ';
  619.                 foreach ( $this->cookies as $cookieKey => $cookieVal ) {
  620.                 $cookie_str .= $cookieKey."=".urlencode($cookieVal)."; ";
  621.                 }
  622.                 $headers[] = substr($cookie_str,0,-2);
  623.             }
  624.         }
  625.         if(!empty($this->rawheaders))
  626.         {
  627.             if(!is_array($this->rawheaders))
  628.                 $this->rawheaders = (array)$this->rawheaders;
  629.             while(list($headerKey,$headerVal) = each($this->rawheaders))
  630.                 $headers[] = $headerKey.": ".$headerVal;
  631.         }
  632.         if(!empty($content_type)) {
  633.             if ($content_type == "multipart/form-data")
  634.                 $headers[] = "Content-type: $content_type; boundary=".$this->_mime_boundary;
  635.             else
  636.                 $headers[] = "Content-type: $content_type";
  637.         }
  638.         if(!empty($body))    
  639.             $headers[] = "Content-length: ".strlen($body);
  640.         if(!empty($this->user) || !empty($this->pass))    
  641.             $headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass);
  642.             
  643.         for($curr_header = 0; $curr_header < count($headers); $curr_header++)
  644.             $cmdline_params .= " -H \"".$headers[$curr_header]."\"";
  645.         
  646.         if(!empty($body))
  647.             $cmdline_params .= " -d \"$body\"";
  648.         
  649.         if($this->read_timeout > 0)
  650.             $cmdline_params .= " -m ".$this->read_timeout;
  651.         
  652.         $headerfile = uniqid(time());
  653.         
  654.         # accept self-signed certs
  655.         $cmdline_params .= " -k";
  656.         exec($this->curl_path." -D \"/tmp/$headerfile\"".$cmdline_params." ".$URI,$results,$return);
  657.         
  658.         if($return)
  659.         {
  660.             $this->error = "Error: cURL could not retrieve the document, error $return.";
  661.             return false;
  662.         }
  663.             
  664.             
  665.         $results = implode("\r\n",$results);
  666.         
  667.         $result_headers = file("/tmp/$headerfile");
  668.                         
  669.         $this->_redirectaddr = false;
  670.         unset($this->headers);
  671.                         
  672.         for($currentHeader = 0; $currentHeader < count($result_headers); $currentHeader++)
  673.         {
  674.             
  675.             // if a header begins with Location: or URI:, set the redirect
  676.             if(preg_match("/^(Location: |URI: )/i",$result_headers[$currentHeader]))
  677.             {
  678.                 // get URL portion of the redirect
  679.                 preg_match("/^(Location: |URI:)(.*)/",chop($result_headers[$currentHeader]),$matches);
  680.                 // look for :// in the Location header to see if hostname is included
  681.                 if(!preg_match("|\:\/\/|",$matches[2]))
  682.                 {
  683.                     // no host in the path, so prepend
  684.                     $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port;
  685.                     // eliminate double slash
  686.                     if(!preg_match("|^/|",$matches[2]))
  687.                             $this->_redirectaddr .= "/".$matches[2];
  688.                     else
  689.                             $this->_redirectaddr .= $matches[2];
  690.                 }
  691.                 else
  692.                     $this->_redirectaddr = $matches[2];
  693.             }
  694.         
  695.             if(preg_match("|^HTTP/|",$result_headers[$currentHeader]))
  696.             {
  697.                 $this->response_code = $result_headers[$currentHeader];
  698.                 if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$this->response_code, $match))
  699.                 {
  700.                 $this->status= $match[1];
  701.                         }
  702.             }
  703.             $this->headers[] = $result_headers[$currentHeader];
  704.         }
  705.  
  706.         // check if there is a a redirect meta tag
  707.         
  708.         if(preg_match("'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]+URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match))
  709.         {
  710.             $this->_redirectaddr = $this->_expandlinks($match[1],$URI);    
  711.         }
  712.  
  713.         // have we hit our frame depth and is there frame src to fetch?
  714.         if(($this->_framedepth < $this->maxframes) && preg_match_all("'<frame\s+.*src[\s]*=[\'\"]?([^\'\"\>]+)'i",$results,$match))
  715.         {
  716.             $this->results[] = $results;
  717.             for($x=0; $x<count($match[1]); $x++)
  718.                 $this->_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host);
  719.         }
  720.         // have we already fetched framed content?
  721.         elseif(is_array($this->results))
  722.             $this->results[] = $results;
  723.         // no framed content
  724.         else
  725.             $this->results = $results;
  726.  
  727.         unlink("/tmp/$headerfile");
  728.         
  729.         return true;
  730.     }
  731.  
  732. /*======================================================================*\
  733.     Function:    setcookies()
  734.     Purpose:    set cookies for a redirection
  735. \*======================================================================*/
  736.     
  737.     function setcookies()
  738.     {
  739.         for($x=0; $x<count($this->headers); $x++)
  740.         {
  741.         if(preg_match("/^set-cookie:[\s]+([^=]+)=([^;]+)/i", $this->headers[$x],$match))
  742.             $this->cookies[$match[1]] = $match[2];
  743.         }
  744.     }
  745.  
  746.     
  747. /*======================================================================*\
  748.     Function:    _check_timeout
  749.     Purpose:    checks whether timeout has occurred
  750.     Input:        $fp    file pointer
  751. \*======================================================================*/
  752.  
  753.     function _check_timeout($fp)
  754.     {
  755.         if ($this->read_timeout > 0) {
  756.             $fp_status = socket_get_status($fp);
  757.             if ($fp_status["timed_out"]) {
  758.                 $this->timed_out = true;
  759.                 return true;
  760.             }
  761.         }
  762.         return false;
  763.     }
  764.  
  765. /*======================================================================*\
  766.     Function:    _connect
  767.     Purpose:    make a socket connection
  768.     Input:        $fp    file pointer
  769. \*======================================================================*/
  770.     
  771.     function _connect(&$fp)
  772.     {
  773.         if(!empty($this->proxy_host) && !empty($this->proxy_port))
  774.             {
  775.                 $this->_isproxy = true;
  776.                 $host = $this->proxy_host;
  777.                 $port = $this->proxy_port;
  778.             }
  779.         else
  780.         {
  781.             $host = $this->host;
  782.             $port = $this->port;
  783.         }
  784.     
  785.         $this->status = 0;
  786.         
  787.         if($fp = fsockopen(
  788.                     $host,
  789.                     $port,
  790.                     $errno,
  791.                     $errstr,
  792.                     $this->_fp_timeout
  793.                     ))
  794.         {
  795.             // socket connection succeeded
  796.  
  797.             return true;
  798.         }
  799.         else
  800.         {
  801.             // socket connection failed
  802.             $this->status = $errno;
  803.             switch($errno)
  804.             {
  805.                 case -3:
  806.                     $this->error="socket creation failed (-3)";
  807.                 case -4:
  808.                     $this->error="dns lookup failure (-4)";
  809.                 case -5:
  810.                     $this->error="connection refused or timed out (-5)";
  811.                 default:
  812.                     $this->error="connection failed (".$errno.")";
  813.             }
  814.             return false;
  815.         }
  816.     }
  817. /*======================================================================*\
  818.     Function:    _disconnect
  819.     Purpose:    disconnect a socket connection
  820.     Input:        $fp    file pointer
  821. \*======================================================================*/
  822.     
  823.     function _disconnect($fp)
  824.     {
  825.         return(fclose($fp));
  826.     }
  827.  
  828.     
  829. /*======================================================================*\
  830.     Function:    _prepare_post_body
  831.     Purpose:    Prepare post body according to encoding type
  832.     Input:        $formvars  - form variables
  833.                 $formfiles - form upload files
  834.     Output:        post body
  835. \*======================================================================*/
  836.     
  837.     function _prepare_post_body($formvars, $formfiles)
  838.     {
  839.         settype($formvars, "array");
  840.         settype($formfiles, "array");
  841.  
  842.         if (count($formvars) == 0 && count($formfiles) == 0)
  843.             return;
  844.         
  845.         switch ($this->_submit_type) {
  846.             case "application/x-www-form-urlencoded":
  847.                 reset($formvars);
  848.                 while(list($key,$val) = each($formvars)) {
  849.                     if (is_array($val) || is_object($val)) {
  850.                         while (list($cur_key, $cur_val) = each($val)) {
  851.                             $postdata .= urlencode($key)."[]=".urlencode($cur_val)."&";
  852.                         }
  853.                     } else
  854.                         $postdata .= urlencode($key)."=".urlencode($val)."&";
  855.                 }
  856.                 break;
  857.  
  858.             case "multipart/form-data":
  859.                 $this->_mime_boundary = "Snoopy".md5(uniqid(microtime()));
  860.                 
  861.                 reset($formvars);
  862.                 while(list($key,$val) = each($formvars)) {
  863.                     if (is_array($val) || is_object($val)) {
  864.                         while (list($cur_key, $cur_val) = each($val)) {
  865.                             $postdata .= "--".$this->_mime_boundary."\r\n";
  866.                             $postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n";
  867.                             $postdata .= "$cur_val\r\n";
  868.                         }
  869.                     } else {
  870.                         $postdata .= "--".$this->_mime_boundary."\r\n";
  871.                         $postdata .= "Content-Disposition: form-data; name=\"$key\"\r\n\r\n";
  872.                         $postdata .= "$val\r\n";
  873.                     }
  874.                 }
  875.                 
  876.                 reset($formfiles);
  877.                 while (list($field_name, $file_names) = each($formfiles)) {
  878.                     settype($file_names, "array");
  879.                     while (list(, $file_name) = each($file_names)) {
  880.                         if (!is_readable($file_name)) continue;
  881.  
  882.                         $fp = fopen($file_name, "r");
  883.                         $file_content = fread($fp, filesize($file_name));
  884.                         fclose($fp);
  885.                         $base_name = basename($file_name);
  886.  
  887.                         $postdata .= "--".$this->_mime_boundary."\r\n";
  888.                         $postdata .= "Content-Disposition: form-data; name=\"$field_name\"; filename=\"$base_name\"\r\n\r\n";
  889.                         $postdata .= "$file_content\r\n";
  890.                     }
  891.                 }
  892.                 $postdata .= "--".$this->_mime_boundary."--\r\n";
  893.                 break;
  894.         }
  895.  
  896.         return $postdata;
  897.     }
  898. }
  899. endif;
  900.  
  901. ?>