/**
  * Uses curl or fsock to make a request to a remote server. Returns the
  * response.
  *
  * @param string $Url The full url to the page being requested (including http://)
  * @param integer $Timeout How long to allow for this request. Default Garden.SocketTimeout or 1, 0 to never timeout
  * @param boolean $FollowRedirects Whether or not to follow 301 and 302 redirects. Defaults false.
  * @return string Response (no headers)
  */
 function ProxyRequest($Url, $Timeout = FALSE, $FollowRedirects = FALSE)
 {
     $OriginalTimeout = $Timeout;
     if ($Timeout === FALSE) {
         $Timeout = C('Garden.SocketTimeout', 1.0);
     }
     $UrlParts = parse_url($Url);
     $Scheme = GetValue('scheme', $UrlParts, 'http');
     $Host = GetValue('host', $UrlParts, '');
     $Port = GetValue('port', $UrlParts, $Scheme == 'https' ? '443' : '80');
     $Path = GetValue('path', $UrlParts, '');
     $Query = GetValue('query', $UrlParts, '');
     // Get the cookie.
     $Cookie = '';
     $EncodeCookies = C('Garden.Cookie.Urlencode', TRUE);
     foreach ($_COOKIE as $Key => $Value) {
         if (strncasecmp($Key, 'XDEBUG', 6) == 0) {
             continue;
         }
         if (strlen($Cookie) > 0) {
             $Cookie .= '; ';
         }
         $EValue = $EncodeCookies ? urlencode($Value) : $Value;
         $Cookie .= "{$Key}={$EValue}";
     }
     $Response = '';
     if (function_exists('curl_init')) {
         //$Url = $Scheme.'://'.$Host.$Path;
         $Handler = curl_init();
         curl_setopt($Handler, CURLOPT_URL, $Url);
         curl_setopt($Handler, CURLOPT_PORT, $Port);
         curl_setopt($Handler, CURLOPT_SSL_VERIFYPEER, FALSE);
         curl_setopt($Handler, CURLOPT_HEADER, 1);
         curl_setopt($Handler, CURLOPT_USERAGENT, ArrayValue('HTTP_USER_AGENT', $_SERVER, 'Vanilla/2.0'));
         curl_setopt($Handler, CURLOPT_RETURNTRANSFER, 1);
         if ($Cookie != '') {
             curl_setopt($Handler, CURLOPT_COOKIE, $Cookie);
         }
         if ($Timeout > 0) {
             curl_setopt($Handler, CURLOPT_TIMEOUT, $Timeout);
         }
         // TIM @ 2010-06-28: Commented this out because it was forcing all requests with parameters to be POST. Same for the $Url above
         //
         //if ($Query != '') {
         //   curl_setopt($Handler, CURLOPT_POST, 1);
         //   curl_setopt($Handler, CURLOPT_POSTFIELDS, $Query);
         //}
         $Response = curl_exec($Handler);
         $Success = TRUE;
         if ($Response == FALSE) {
             $Success = FALSE;
             $Response = '';
             throw new Exception(curl_error($Handler));
         }
         curl_close($Handler);
     } else {
         if (function_exists('fsockopen')) {
             $Referer = Gdn_Url::WebRoot(TRUE);
             // Make the request
             $Pointer = @fsockopen($Host, $Port, $ErrorNumber, $Error, $Timeout);
             if (!$Pointer) {
                 throw new Exception(sprintf(T('Encountered an error while making a request to the remote server (%1$s): [%2$s] %3$s'), $Url, $ErrorNumber, $Error));
             }
             stream_set_timeout($Pointer, $Timeout);
             if (strlen($Cookie) > 0) {
                 $Cookie = "Cookie: {$Cookie}\r\n";
             }
             $HostHeader = $Host . ($Port != 80 ? ":{$Port}" : '');
             $Header = "GET {$Path}?{$Query} HTTP/1.1\r\n" . "Host: {$HostHeader}\r\n" . "User-Agent: " . ArrayValue('HTTP_USER_AGENT', $_SERVER, 'Vanilla/2.0') . "\r\n" . "Accept: */*\r\n" . "Accept-Charset: utf-8;\r\n" . "Referer: {$Referer}\r\n" . "Connection: close\r\n";
             if ($Cookie != '') {
                 $Header .= $Cookie;
             }
             $Header .= "\r\n";
             // Send the headers and get the response
             fputs($Pointer, $Header);
             while ($Line = fread($Pointer, 4096)) {
                 $Response .= $Line;
             }
             @fclose($Pointer);
             $Bytes = strlen($Response);
             $Response = trim($Response);
             $Success = TRUE;
             $StreamInfo = stream_get_meta_data($Pointer);
             if (GetValue('timed_out', $StreamInfo, FALSE) === TRUE) {
                 $Success = FALSE;
                 $Response = "Operation timed out after {$Timeout} seconds with {$Bytes} bytes received.";
             }
         } else {
             throw new Exception(T('Encountered an error while making a request to the remote server: Your PHP configuration does not allow curl or fsock requests.'));
         }
     }
     if (!$Success) {
         return $Response;
     }
     $ResponseHeaderData = trim(substr($Response, 0, strpos($Response, "\r\n\r\n")));
     $Response = trim(substr($Response, strpos($Response, "\r\n\r\n") + 4));
     $ResponseHeaderLines = explode("\n", trim($ResponseHeaderData));
     $Status = array_shift($ResponseHeaderLines);
     $ResponseHeaders = array();
     $ResponseHeaders['HTTP'] = trim($Status);
     /* get the numeric status code. 
      * - trim off excess edge whitespace, 
      * - split on spaces, 
      * - get the 2nd element (as a single element array), 
      * - pop the first (only) element off it... 
      * - return that.
      */
     $ResponseHeaders['StatusCode'] = array_pop(array_slice(explode(' ', trim($Status)), 1, 1));
     foreach ($ResponseHeaderLines as $Line) {
         $Line = explode(':', trim($Line));
         $Key = trim(array_shift($Line));
         $Value = trim(implode(':', $Line));
         $ResponseHeaders[$Key] = $Value;
     }
     if ($FollowRedirects) {
         $Code = GetValue('StatusCode', $ResponseHeaders, 200);
         if (in_array($Code, array(301, 302))) {
             if (array_key_exists('Location', $ResponseHeaders)) {
                 $Location = AbsoluteSource(GetValue('Location', $ResponseHeaders), $Url);
                 return ProxyRequest($Location, $OriginalTimeout, $FollowRedirects);
             }
         }
     }
     return $Response;
 }
 protected static function StaticDomDocumentReplace(&$String)
 {
     if (substr(ltrim($String), 0, 5) != '<?xml') {
         $String = '<?xml version="1.0" encoding="UTF-8"?' . ">\n" . $String;
     }
     $DOMDocument = DOMDocument::LoadXML($String, LIBXML_NOERROR);
     if ($DOMDocument === False) {
         return $String;
     }
     $ImageDimensions = self::ImageDimensions();
     $BeforeCount = count($ImageDimensions);
     $Domain = Gdn::Request()->Domain();
     $DomNodeList = $DOMDocument->GetElementsByTagName('img');
     for ($i = $DomNodeList->length - 1; $i >= 0; $i--) {
         $Node = $DomNodeList->Item($i);
         $Width = $Node->GetAttribute('width');
         $Height = $Node->GetAttribute('height');
         if ($Width == '' && $Height == '') {
             $Src = $Node->GetAttribute('src');
             if (!$Src) {
                 continue;
             }
             $Src = AbsoluteSource($Src, $Domain);
             $CrcKey = crc32($Src);
             if (!array_key_exists($CrcKey, $ImageDimensions)) {
                 $ImageSize = getimagesize($Src);
                 $ImageDimensions[$CrcKey] = array($ImageSize[0], $ImageSize[1], '_src' => $Src);
             } else {
                 $ImageSize = $ImageDimensions[$CrcKey];
             }
             if ($ImageSize[0] && $ImageSize[1]) {
                 $Node->SetAttribute('width', $ImageSize[0]);
                 $Node->SetAttribute('height', $ImageSize[1]);
             }
         }
     }
     // Save cache.
     if (count($ImageDimensions) != $BeforeCount) {
         self::ImageDimensions($ImageDimensions);
     }
     $String = $DOMDocument->saveXML();
     // LIBXML_NOXMLDECL | LIBXML_NOENT
     //$DOMDocument->formatOutput = True;
     //$String = $DOMDocument->saveXML(Null, LIBXML_NOXMLDECL | LIBXML_NOENT);
     //d($String);
 }