/** * 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; }
/** * * * @param bool $Enabled * @param bool $OnlyUpdates * @return array|bool * @throws Exception */ public function getAddonUpdates($Enabled = false, $OnlyUpdates = true) { // Get the addons on this site. $MyAddons = $this->GetAddons($Enabled); // Build the query for them. $Slugs = array_keys($MyAddons); array_map('urlencode', $Slugs); $SlugsString = implode(',', $Slugs); $Url = $this->AddonSiteUrl . '/addon/getlist.json?ids=' . $SlugsString; $SiteAddons = ProxyRequest($Url); $UpdateAddons = array(); if ($SiteAddons) { $SiteAddons = val('Addons', json_decode($SiteAddons, true)); $UpdateAddons = $this->CompareAddons($MyAddons, $SiteAddons); } return $UpdateAddons; }
public function UpdateProxy() { $Fields = $_POST; foreach ($Fields as $Field => $Value) { if (get_magic_quotes_gpc()) { if (is_array($Value)) { $Count = count($Value); for ($i = 0; $i < $Count; ++$i) { $Value[$i] = stripslashes($Value[$i]); } } else { $Value = stripslashes($Value); } $Fields[$Field] = $Value; } } $UpdateCheckUrl = C('Garden.UpdateCheckUrl', 'http://vanillaforums.org/addons/update'); echo ProxyRequest($UpdateCheckUrl.'?'.http_build_query($Fields)); $Database = Gdn::Database(); $Database->CloseConnection(); }
protected function _GetForeignCredentials($ForeignIdentityUrl) { // Get the contents of the Authentication Url (timeout 5 seconds); @session_write_close(); $Response = ProxyRequest($ForeignIdentityUrl, 5); if ($Response) { $ReadMode = strtolower(C("Garden.Authenticators.proxy.RemoteFormat", "ini")); switch ($ReadMode) { case 'ini': $Result = @parse_ini_string($Response); break; case 'json': $Result = @json_decode($Response); break; default: throw new Exception("Unexpected value '$ReadMode' for 'Garden.Authenticators.proxy.RemoteFormat'"); } if ($Result) { $ReturnArray = array( 'Email' => ArrayValue('Email', $Result), 'Name' => ArrayValue('Name', $Result), 'UniqueID' => ArrayValue('UniqueID', $Result), 'TransientKey' => ArrayValue('TransientKey', $Result, NULL) ); if (isset($Result['Roles'])) $ReturnArray['Roles'] = $Result['Roles']; return $ReturnArray; } } return FALSE; }
/** * This is the asynchronous callback * * This method is triggerd on every page request via a callback AJAX request * so that it may execute asychronously and reduce lag for users. It tracks * views, handles registration for new installations, and sends stats every * day as needed. * * @return void; */ public function Tick() { // If we're local and not allowed, or just directly disabled, gtfo if (!self::CheckIsEnabled()) { return; } if (Gdn::Session()->CheckPermission('Garden.Settings.Manage')) { if (Gdn::Get('Garden.Analytics.Notify', FALSE) !== FALSE) { $CallMessage = '<span class="InformSprite Bandaid"></span> '; $CallMessage .= sprintf(T("There's a problem with Vanilla Analytics that needs your attention.<br/> Handle it <a href=\"%s\">here »</a>"), Url('dashboard/statistics')); Gdn::Controller()->InformMessage($CallMessage, array('CssClass' => 'HasSprite')); } } // If the config file is not writable, gtfo $ConfFile = PATH_LOCAL_CONF . DS . 'config.php'; if (!is_writable($ConfFile)) { return; } $InstallationID = Gdn::InstallationID(); // Check if we're registered with the central server already. If not, this request is // hijacked and used to perform that task instead of sending stats or recording a tick. if (is_null($InstallationID)) { $AttemptedRegistration = Gdn::Get('Garden.Analytics.Registering', FALSE); // If we last attempted to register less than 60 seconds ago, do nothing. Could still be working. if ($AttemptedRegistration !== FALSE && time() - $AttemptedRegistration < 60) { return; } return $this->Register(); } // Add a pageview entry. $TimeSlot = date('Ymd'); $Px = Gdn::Database()->DatabasePrefix; try { Gdn::Database()->Query("insert into {$Px}AnalyticsLocal (TimeSlot, Views) values (:TimeSlot, 1)\n on duplicate key update Views = Views+1", array(':TimeSlot' => $TimeSlot)); } catch (Exception $e) { // If we just tried to run the structure, and failed, don't blindly try again. // Just disable ourselves quietly. if (Gdn::Get('Garden.Analytics.AutoStructure', FALSE)) { SaveToConfig('Garden.Analytics.Enabled', FALSE); Gdn::Set('Garden.Analytics.AutoStructure', NULL); return; } // If we get here, insert failed. Try proxyconnect to the utility structure Gdn::Set('Garden.Analytics.AutoStructure', TRUE); ProxyRequest(Url('utility/update', TRUE), 0, FALSE); } // If we get here and this is true, we successfully ran the auto structure. Remove config flag. if (Gdn::Get('Garden.Analytics.AutoStructure', FALSE)) { Gdn::Set('Garden.Analytics.AutoStructure', NULL); } // Fire an event for plugins to track their own stats. // TODO: Make this analyze the path and throw a specific event (this event will change in future versions). $this->EventArguments['Path'] = Gdn::Request()->Post('Path'); $this->FireEvent('Tick'); // If we get here, the installation is registered and we can decide on whether or not to send stats now. $LastSentDate = self::LastSentDate(); if (empty($LastSentDate) || $LastSentDate < date('Ymd', strtotime('-1 day'))) { return $this->Stats(); } }
protected function _GetForeignCredentials($ForeignIdentityUrl) { // Get the contents of the Authentication Url (timeout 5 seconds); @session_write_close(); $Response = ProxyRequest($ForeignIdentityUrl, 5); if ($Response) { $ReadMode = strtolower(C("Garden.Authenticators.proxy.RemoteFormat", "ini")); switch ($ReadMode) { case 'ini': $Response = trim($Response); $IniResult = array(); $RawIni = explode("\n", $Response); foreach ($RawIni as $ResponeLine) { $ResponeLine = trim($ResponeLine); if (stristr($ResponeLine, '=') === FALSE) { continue; } $ResponseParts = explode("=", $ResponeLine); $ResponseKey = array_shift($ResponseParts); $ResponseValue = implode("=", $ResponseParts); $IniResult[$ResponseKey] = $ResponseValue; } if (sizeof($IniResult)) { $Result = $IniResult; } break; case 'json': $Result = @json_decode($Response); break; default: throw new Exception("Unexpected value '{$ReadMode}' for 'Garden.Authenticators.proxy.RemoteFormat'"); } if ($Result) { // Bad page? Get out. $UniqueID = GetValue('UniqueID', $Result, NULL); $Email = GetValue('Email', $Result, NULL); if (is_null($Email) || is_null($UniqueID)) { return FALSE; } $ReturnArray = array('Email' => $Email, 'UniqueID' => $UniqueID, 'Name' => GetValue('Name', $Result, NULL), 'TransientKey' => GetValue('TransientKey', $Result, NULL)); if (isset($Result['Roles'])) { $ReturnArray['Roles'] = $Result['Roles']; } return $ReturnArray; } } return FALSE; }
public function PreviewTheme($ThemeFolder = '') { $this->Permission('Garden.Themes.Manage'); $ThemeManager = new Gdn_ThemeManager(); $this->AvailableThemes = $ThemeManager->AvailableThemes(); $PreviewThemeName = ''; $PreviewThemeFolder = $ThemeFolder; foreach ($this->AvailableThemes as $ThemeName => $ThemeInfo) { if ($ThemeInfo['Folder'] == $ThemeFolder) { $PreviewThemeName = $ThemeName; } } // If we failed to get the requested theme, default back to the one currently enabled if ($PreviewThemeName == '') { $this->ThemeName = $ThemeManager->EnabledTheme(); foreach ($this->AvailableThemes as $ThemeName => $ThemeInfo) { if ($ThemeName == $PreviewThemeName) { $PreviewThemeFolder = $ThemeInfo['Folder']; } } } // Check for errors $Session = Gdn::Session(); $Test = ProxyRequest(Url('/dashboard/settings/testaddon/Theme/' . $ThemeName . '/' . $Session->TransientKey() . '?DeliveryType=JSON', TRUE)); if ($Test != 'Success') { $this->Form->AddError(sprintf(T('The theme could not be previewed because it generated a fatal error: <pre>%s</pre>'), strip_tags($Test))); $this->View = 'themes'; $this->Themes(); } else { $Session->SetPreference(array('PreviewThemeName' => $PreviewThemeName, 'PreviewThemeFolder' => $PreviewThemeFolder)); Redirect('/'); } }
protected function _GetForeignCredentials($ForeignIdentityUrl) { $Response = ProxyRequest($ForeignIdentityUrl, 5); if ($Response) { $Result = @parse_ini_string($Response); if ($Result) { $ReturnArray = array('Email' => ArrayValue('Email', $Result), 'Name' => ArrayValue('Name', $Result), 'UniqueID' => ArrayValue('UniqueID', $Result)); return $ReturnArray; } } return FALSE; }
protected function QueryRemote($Provider, $Task, $Arguments = NULL, $Secure = TRUE, $GetBody = FALSE) { if (!is_array($Arguments)) { $Arguments = array(); } $Arguments = array_merge($Arguments, array('ProxyConnectAutoconfigure' => 'configure', 'Task' => $Task)); if ($Secure) { $Arguments = array_merge($Arguments, array('Key' => GetValue('AssociationSecret', $Provider))); } $RealURL = GetValue('URL', $Provider) . "?" . http_build_query($Arguments); if ($GetBody) { return ProxyRequest($RealURL, FALSE, TRUE); } else { return ProxyHead($RealURL, NULL, FALSE, TRUE); } }
/** * Proxy an RSS feed for Dashboard use across our kingdom. * * @param Gdn_Controller $sender * @param $Url * @return mixed|string * @throws Exception */ public function homeController_proxyFeed_create($sender, $Url) { $Key = 'Feed|' . $Url; $Feed = Gdn::cache()->get($Key); if (!$Feed) { $Feed = ProxyRequest($Url, 5); Gdn::cache()->store($Key, $Feed, array(Gdn_Cache::FEATURE_EXPIRY => 5 * 60)); } return $Feed; }