This class abstracts the work of doing external requests.
Since: 2.0.18
Author: Tim Gunter (tim@vanillaforums.com)
 protected function request($method, $server, $path, $query = NULL, array $headers = array())
 {
     $Request = new ProxyRequest();
     $Request->Request(array('Method' => $method, 'URL' => trim($server, '/') . trim($path, '/')), $query, NULL, $headers);
     $MollomResponse = (object) array('code' => $Request->ResponseStatus, 'headers' => $Request->ResponseHeaders, 'body' => $Request->ResponseBody);
     return $MollomResponse;
 }
 /**
  *
  *
  * @param $Method
  * @param $RequestParameters
  * @param bool $Callback
  * @param bool $ParseResponse
  * @return array|bool|mixed|type
  * @throws Exception
  */
 public function analytics($Method, $RequestParameters, $Callback = false, $ParseResponse = true)
 {
     $FullMethod = explode('/', $Method);
     if (sizeof($FullMethod) < 2) {
         array_unshift($FullMethod, "analytics");
     }
     list($ApiController, $ApiMethod) = $FullMethod;
     $ApiController = strtolower($ApiController);
     $ApiMethod = stringEndsWith(strtolower($ApiMethod), '.json', true, true) . '.json';
     $FinalURL = 'http://' . combinePaths(array($this->AnalyticsServer, $ApiController, $ApiMethod));
     $RequestHeaders = array();
     // Allow hooking of analytics events
     $this->EventArguments['AnalyticsMethod'] =& $Method;
     $this->EventArguments['AnalyticsArgs'] =& $RequestParameters;
     $this->EventArguments['AnalyticsUrl'] =& $FinalURL;
     $this->EventArguments['AnalyticsHeaders'] =& $RequestHeaders;
     $this->fireEvent('SendAnalytics');
     // Sign request
     $this->sign($RequestParameters, true);
     $RequestMethod = val('RequestMethod', $RequestParameters, 'GET');
     unset($RequestParameters['RequestMethod']);
     try {
         $ProxyRequest = new ProxyRequest(false, array('Method' => $RequestMethod, 'Timeout' => 10, 'Cookies' => false));
         $Response = $ProxyRequest->request(array('Url' => $FinalURL, 'Log' => false), $RequestParameters, null, $RequestHeaders);
     } catch (Exception $e) {
         $Response = false;
     }
     if ($Response !== false) {
         $JsonResponse = json_decode($Response, true);
         if ($JsonResponse !== false) {
             if ($ParseResponse) {
                 $AnalyticsJsonResponse = (array) val('Analytics', $JsonResponse, false);
                 // If we received a reply, parse it
                 if ($AnalyticsJsonResponse !== false) {
                     $this->parseAnalyticsResponse($AnalyticsJsonResponse, $Response, $Callback);
                     return $AnalyticsJsonResponse;
                 }
             } else {
                 return $JsonResponse;
             }
         }
         return $Response;
     }
     return false;
 }
Exemple #3
0
 public function Analytics($Method, $RequestParameters, $Callback = FALSE, $ParseResponse = TRUE)
 {
     $FullMethod = explode('/', $Method);
     if (sizeof($FullMethod) < 2) {
         array_unshift($FullMethod, "analytics");
     }
     list($ApiController, $ApiMethod) = $FullMethod;
     $ApiController = strtolower($ApiController);
     $ApiMethod = StringEndsWith(strtolower($ApiMethod), '.json', TRUE, TRUE) . '.json';
     $FinalURL = 'http://' . CombinePaths(array($this->AnalyticsServer, $ApiController, $ApiMethod));
     // Allow hooking of analytics events
     $this->EventArguments['AnalyticsMethod'] =& $Method;
     $this->EventArguments['AnalyticsArgs'] =& $RequestParameters;
     $this->EventArguments['AnalyticsUrl'] =& $FinalURL;
     $this->FireEvent('SendAnalytics');
     // Sign request
     $this->Sign($RequestParameters, TRUE);
     $RequestMethod = GetValue('RequestMethod', $RequestParameters, 'GET');
     unset($RequestParameters['RequestMethod']);
     try {
         $ProxyRequest = new ProxyRequest(FALSE, array('Method' => $RequestMethod, 'Timeout' => 10, 'Cookies' => FALSE));
         $Response = $ProxyRequest->Request(array('Url' => $FinalURL), $RequestParameters);
     } catch (Exception $e) {
         $Response = FALSE;
     }
     if ($Response !== FALSE) {
         $JsonResponse = json_decode($Response, TRUE);
         if ($JsonResponse !== FALSE) {
             if ($ParseResponse) {
                 $AnalyticsJsonResponse = (array) GetValue('Analytics', $JsonResponse, FALSE);
                 // If we received a reply, parse it
                 if ($AnalyticsJsonResponse !== FALSE) {
                     $this->ParseAnalyticsResponse($AnalyticsJsonResponse, $Response, $Callback);
                     return $AnalyticsJsonResponse;
                 }
             } else {
                 return $JsonResponse;
             }
         }
         return $Response;
     }
     return FALSE;
 }
Exemple #4
0
 /**
  * Examine a page at {@link $Url} for title, description & images.
  *
  * Be sure to check the resultant array for any Exceptions that occurred while retrieving the page.
  *
  * @param string $url The url to examine.
  * @param integer $timeout How long to allow for this request.
  * Default Garden.SocketTimeout or 1, 0 to never timeout. Default is 0.
  * @param bool $sendCookies Whether or not to send browser cookies with the request.
  * @return array Returns an array containing Url, Title, Description, Images (array) and Exception
  * (if there were problems retrieving the page).
  */
 function fetchPageInfo($url, $timeout = 3, $sendCookies = false)
 {
     $PageInfo = array('Url' => $url, 'Title' => '', 'Description' => '', 'Images' => array(), 'Exception' => false);
     try {
         // Make sure the URL is valid.
         $urlParts = parse_url($url);
         if ($urlParts === false || !in_array(val('scheme', $urlParts), array('http', 'https'))) {
             throw new Exception('Invalid URL.', 400);
         }
         if (!defined('HDOM_TYPE_ELEMENT')) {
             require_once PATH_LIBRARY . '/vendors/simplehtmldom/simple_html_dom.php';
         }
         $Request = new ProxyRequest();
         $PageHtml = $Request->Request(array('URL' => $url, 'Timeout' => $timeout, 'Cookies' => $sendCookies));
         if (!$Request->status()) {
             throw new Exception('Couldn\'t connect to host.', 400);
         }
         $Dom = str_get_html($PageHtml);
         if (!$Dom) {
             throw new Exception('Failed to load page for parsing.');
         }
         // FIRST PASS: Look for open graph title, desc, images
         $PageInfo['Title'] = domGetContent($Dom, 'meta[property=og:title]');
         Trace('Getting og:description');
         $PageInfo['Description'] = domGetContent($Dom, 'meta[property=og:description]');
         foreach ($Dom->find('meta[property=og:image]') as $Image) {
             if (isset($Image->content)) {
                 $PageInfo['Images'][] = $Image->content;
             }
         }
         // SECOND PASS: Look in the page for title, desc, images
         if ($PageInfo['Title'] == '') {
             $PageInfo['Title'] = $Dom->find('title', 0)->plaintext;
         }
         if ($PageInfo['Description'] == '') {
             Trace('Getting meta description');
             $PageInfo['Description'] = domGetContent($Dom, 'meta[name=description]');
         }
         // THIRD PASS: Look in the page contents
         if ($PageInfo['Description'] == '') {
             foreach ($Dom->find('p') as $element) {
                 Trace('Looking at p for description.');
                 if (strlen($element->plaintext) > 150) {
                     $PageInfo['Description'] = $element->plaintext;
                     break;
                 }
             }
             if (strlen($PageInfo['Description']) > 400) {
                 $PageInfo['Description'] = SliceParagraph($PageInfo['Description'], 400);
             }
         }
         // Final: Still nothing? remove limitations
         if ($PageInfo['Description'] == '') {
             foreach ($Dom->find('p') as $element) {
                 Trace('Looking at p for description (no restrictions)');
                 if (trim($element->plaintext) != '') {
                     $PageInfo['Description'] = $element->plaintext;
                     break;
                 }
             }
         }
         // Page Images
         if (count($PageInfo['Images']) == 0) {
             $Images = domGetImages($Dom, $url);
             $PageInfo['Images'] = array_values($Images);
         }
         $PageInfo['Title'] = htmlEntityDecode($PageInfo['Title']);
         $PageInfo['Description'] = htmlEntityDecode($PageInfo['Description']);
     } catch (Exception $ex) {
         $PageInfo['Exception'] = $ex->getMessage();
     }
     return $PageInfo;
 }
 /**
  * Examines the page at $Url for title, description & images. Be sure to check the resultant array for any Exceptions that occurred while retrieving the page.
  * @param string $Url The url to examine.
  * @param integer $Timeout How long to allow for this request. Default Garden.SocketTimeout or 1, 0 to never timeout. Default is 0.
  * @return array an array containing Url, Title, Description, Images (array) and Exception (if there were problems retrieving the page).
  */
 function FetchPageInfo($Url, $Timeout = 3)
 {
     $PageInfo = array('Url' => $Url, 'Title' => '', 'Description' => '', 'Images' => array(), 'Exception' => FALSE);
     try {
         if (!defined('HDOM_TYPE_ELEMENT')) {
             require_once PATH_LIBRARY . '/vendors/simplehtmldom/simple_html_dom.php';
         }
         $Request = new ProxyRequest();
         $PageHtml = $Request->Request(array('URL' => $Url, 'Timeout' => $Timeout));
         $Dom = str_get_html($PageHtml);
         if (!$Dom) {
             throw new Exception('Failed to load page for parsing.');
         }
         /* Sample Facebook Open Graph code:
         
         <meta property="og:title" content="60 degrees in&nbsp;February" />
         <meta property="og:url" content="http://karinemily.wordpress.com/2012/02/02/60-degrees-in-february/" />
         <meta property="og:description" content="and Philadelphia explodes with babies, puppies, and hipsters." />
         <meta property="og:site_name" content="K a r i &#039; s" />
         <meta property="og:image" content="http://karinemily.files.wordpress.com/2012/02/dsc_0132.jpg?w=300&amp;h=300" />
         <meta property="og:image" content="http://karinemily.files.wordpress.com/2012/02/dsc_0214.jpg?w=300&amp;h=300" />
         <meta property="og:image" content="http://karinemily.files.wordpress.com/2012/02/dsc_0213.jpg?w=300&amp;h=300" />
         <meta property="og:image" content="http://karinemily.files.wordpress.com/2012/02/dsc_0221-version-2.jpg?w=300&amp;h=300" />
         
                   */
         // FIRST PASS: Look for open graph title, desc, images
         $PageInfo['Title'] = DomGetContent($Dom, 'meta[property=og:title]');
         Trace('Getting og:description');
         $PageInfo['Description'] = DomGetContent($Dom, 'meta[property=og:description]');
         foreach ($Dom->find('meta[property=og:image]') as $Image) {
             if (isset($Image->content)) {
                 $PageInfo['Images'][] = $Image->content;
             }
         }
         // SECOND PASS: Look in the page for title, desc, images
         if ($PageInfo['Title'] == '') {
             $PageInfo['Title'] = $Dom->find('title', 0)->plaintext;
         }
         if ($PageInfo['Description'] == '') {
             Trace('Getting meta description');
             $PageInfo['Description'] = DomGetContent($Dom, 'meta[name=description]');
         }
         // THIRD PASS: Look in the page contents
         if ($PageInfo['Description'] == '') {
             foreach ($Dom->find('p') as $element) {
                 Trace('Looking at p for description.');
                 if (strlen($element->plaintext) > 150) {
                     $PageInfo['Description'] = $element->plaintext;
                     break;
                 }
             }
             if (strlen($PageInfo['Description']) > 400) {
                 $PageInfo['Description'] = SliceParagraph($PageInfo['Description'], 400);
             }
         }
         // Final: Still nothing? remove limitations
         if ($PageInfo['Description'] == '') {
             foreach ($Dom->find('p') as $element) {
                 Trace('Looking at p for description (no restrictions)');
                 if (trim($element->plaintext) != '') {
                     $PageInfo['Description'] = $element->plaintext;
                     break;
                 }
             }
         }
         // Page Images
         if (count($PageInfo['Images']) == 0) {
             $Images = DomGetImages($Dom, $Url);
             $PageInfo['Images'] = array_values($Images);
         }
         $PageInfo['Title'] = HtmlEntityDecode($PageInfo['Title']);
         $PageInfo['Description'] = HtmlEntityDecode($PageInfo['Description']);
     } catch (Exception $ex) {
         $PageInfo['Exception'] = $ex->getMessage();
     }
     return $PageInfo;
 }
 protected function PollFeed($FeedURL, $LastImportDate)
 {
     $Pr = new ProxyRequest();
     $FeedRSS = $Pr->Request(array('URL' => $FeedURL));
     if (!$FeedRSS) {
         return FALSE;
     }
     $RSSData = simplexml_load_string($FeedRSS);
     if (!$RSSData) {
         return FALSE;
     }
     $Channel = GetValue('channel', $RSSData, FALSE);
     if (!$Channel) {
         return FALSE;
     }
     if (!array_key_exists('item', $Channel)) {
         return FALSE;
     }
     $Feed = $this->GetFeed($FeedURL, FALSE);
     $DiscussionModel = new DiscussionModel();
     $DiscussionModel->SpamCheck = FALSE;
     $LastPublishDate = GetValue('LastPublishDate', $Feed, date('c'));
     $LastPublishTime = strtotime($LastPublishDate);
     $FeedLastPublishTime = 0;
     foreach (GetValue('item', $Channel) as $Item) {
         $FeedItemGUID = trim((string) GetValue('guid', $Item));
         if (empty($FeedItemGUID)) {
             Trace('guid is not set in each item of the RSS.  Will attempt to use link as unique identifier.');
             $FeedItemGUID = GetValue('link', $Item);
         }
         $FeedItemID = substr(md5($FeedItemGUID), 0, 30);
         $ItemPubDate = (string) GetValue('pubDate', $Item, NULL);
         if (is_null($ItemPubDate)) {
             $ItemPubTime = time();
         } else {
             $ItemPubTime = strtotime($ItemPubDate);
         }
         if ($ItemPubTime > $FeedLastPublishTime) {
             $FeedLastPublishTime = $ItemPubTime;
         }
         if ($ItemPubTime < $LastPublishTime && !$Feed['Historical']) {
             continue;
         }
         $ExistingDiscussion = $DiscussionModel->GetWhere(array('ForeignID' => $FeedItemID));
         if ($ExistingDiscussion && $ExistingDiscussion->NumRows()) {
             continue;
         }
         $this->EventArguments['Publish'] = TRUE;
         $this->EventArguments['FeedURL'] = $FeedURL;
         $this->EventArguments['Feed'] =& $Feed;
         $this->EventArguments['Item'] =& $Item;
         $this->FireEvent('FeedItem');
         if (!$this->EventArguments['Publish']) {
             continue;
         }
         $StoryTitle = array_shift($Trash = explode("\n", (string) GetValue('title', $Item)));
         $StoryBody = (string) GetValue('description', $Item);
         $StoryPublished = date("Y-m-d H:i:s", $ItemPubTime);
         $ParsedStoryBody = $StoryBody;
         $ParsedStoryBody = '<div class="AutoFeedDiscussion">' . $ParsedStoryBody . '</div> <br /><div class="AutoFeedSource">Source: ' . $FeedItemGUID . '</div>';
         $DiscussionData = array('Name' => $StoryTitle, 'Format' => 'Html', 'CategoryID' => $Feed['Category'], 'ForeignID' => substr($FeedItemID, 0, 30), 'Body' => $ParsedStoryBody);
         // Post as Minion (if one exists) or the system user
         if (Gdn::PluginManager()->CheckPlugin('Minion')) {
             $Minion = Gdn::PluginManager()->GetPluginInstance('MinionPlugin');
             $InsertUserID = $Minion->GetMinionUserID();
         } else {
             $InsertUserID = Gdn::UserModel()->GetSystemUserID();
         }
         $DiscussionData[$DiscussionModel->DateInserted] = $StoryPublished;
         $DiscussionData[$DiscussionModel->InsertUserID] = $InsertUserID;
         $DiscussionData[$DiscussionModel->DateUpdated] = $StoryPublished;
         $DiscussionData[$DiscussionModel->UpdateUserID] = $InsertUserID;
         $this->EventArguments['FeedDiscussion'] =& $DiscussionData;
         $this->FireEvent('Publish');
         if (!$this->EventArguments['Publish']) {
             continue;
         }
         $InsertID = $DiscussionModel->Save($DiscussionData);
         $this->EventArguments['DiscussionID'] = $InsertID;
         $this->EventArguments['Vaidation'] = $DiscussionModel->Validation;
         $this->FireEvent('Published');
         // Reset discussion validation
         $DiscussionModel->Validation->Results(TRUE);
     }
     $FeedKey = self::EncodeFeedKey($FeedURL);
     $this->UpdateFeed($FeedKey, array('LastImport' => date('Y-m-d H:i:s'), 'LastPublishDate' => date('c', $FeedLastPublishTime)));
 }
Exemple #7
0
 /**
  * Generic API uses ProxyRequest class to fetch data from remote endpoints.
  *
  * @param $uri Endpoint on provider's server.
  * @param string $method HTTP method required by provider.
  * @param array $params Query string.
  * @param array $options Configuration options for the request (e.g. Content-Type).
  *
  * @return mixed|type.
  *
  * @throws Exception.
  * @throws Gdn_UserException.
  */
 protected function api($uri, $method = 'GET', $params = [], $options = [])
 {
     $proxy = new ProxyRequest();
     // Create default values of options to be passed to ProxyRequest.
     $defaultOptions['ConnectTimeout'] = 10;
     $defaultOptions['Timeout'] = 10;
     $headers = [];
     // Optionally over-write the content type
     if ($contentType = val('Content-Type', $options, $this->defaultContentType)) {
         $headers['Content-Type'] = $contentType;
     }
     // Obtionally add proprietary required Authorization headers
     if ($headerAuthorization = val('Authorization-Header-Message', $options, null)) {
         $headers['Authorization'] = $headerAuthorization;
     }
     // Merge the default options with the passed options over-writing default options with passed options.
     $proxyOptions = array_merge($defaultOptions, $options);
     $proxyOptions['URL'] = $uri;
     $proxyOptions['Method'] = $method;
     $this->log('Proxy Request Sent in API', ['headers' => $headers, 'proxyOptions' => $proxyOptions, 'params' => $params]);
     $response = $proxy->request($proxyOptions, $params, null, $headers);
     // Extract response only if it arrives as JSON
     if (stripos($proxy->ContentType, 'application/json') !== false) {
         $this->log('API JSON Response', ['response' => $response]);
         $response = json_decode($proxy->ResponseBody, true);
     }
     // Return any errors
     if (!$proxy->responseClass('2xx')) {
         if (isset($response['error'])) {
             $message = 'Request server says: ' . $response['error_description'] . ' (code: ' . $response['error'] . ')';
         } else {
             $message = 'HTTP Error communicating Code: ' . $proxy->ResponseStatus;
         }
         $this->log('API Response Error Thrown', ['response' => json_decode($response)]);
         throw new Gdn_UserException($message, $proxy->ResponseStatus);
     }
     return $response;
 }
 public function Controller_Test($Sender)
 {
     $Sender->AddSideMenu('dashboard/authentication');
     $Sender->Form = new Gdn_Form();
     // Load Provider
     $Authenticator = Gdn::Authenticator()->GetAuthenticator('proxy');
     $Provider = $Authenticator->GetProvider();
     if (!$Provider) {
         $Sender->SetData("Provider", FALSE);
         $Sender->Form->AddError("Authentication Provider information has not been configured");
     } else {
         $Sender->SetData("Provider", $Provider);
     }
     // No response by default
     $Sender->SetData('ConnectResponse', NULL);
     $Sender->SetData('Connected', FALSE);
     $Sender->SetData('ConnectedAs', FALSE);
     $Sender->SetData('Attempt', FALSE);
     if ($Sender->Form->IsPostBack()) {
         if (!$Sender->Form->ErrorCount()) {
             $Sender->SetData('Attempt', TRUE);
             // Do remote ping
             $Connect = new ProxyRequest();
             $AuthenticateURL = GetValue('AuthenticateUrl', $Provider);
             $Response = $Connect->Request(array('URL' => $AuthenticateURL, 'Cookies' => TRUE));
             $Response = trim($Response);
             if ($Response) {
                 // Store serialized struct
                 $Sender->SetData('RawResponse', $Response);
                 $Sender->SetData('ConnectResponse', $Response);
                 $ReadMode = strtolower(C("Garden.Authenticators.proxy.RemoteFormat", "ini"));
                 $Sender->SetData('ReadMode', $ReadMode);
                 switch ($ReadMode) {
                     case 'ini':
                         $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) {
                     // Store parsed struct
                     $Sender->SetData('ConnectResponse', $Result);
                     $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));
                     $Sender->SetData('Connected', $ReturnArray);
                     $Sender->SetData('ConnectedAs', GetValue('Name', $ReturnArray));
                 } else {
                     $Sender->SetData('NoParse', TRUE);
                 }
             }
         }
     }
     $Sender->Render('test', '', 'plugins/ProxyConnect');
 }
 /**
  * Examine a page at {@link $Url} for title, description & images.
  *
  * Be sure to check the resultant array for any Exceptions that occurred while retrieving the page.
  *
  * @param string $url The url to examine.
  * @param integer $timeout How long to allow for this request.
  * Default Garden.SocketTimeout or 1, 0 to never timeout. Default is 0.
  * @param bool $sendCookies Whether or not to send browser cookies with the request.
  * @return array Returns an array containing Url, Title, Description, Images (array) and Exception
  * (if there were problems retrieving the page).
  */
 function fetchPageInfo($url, $timeout = 3, $sendCookies = false)
 {
     $PageInfo = array('Url' => $url, 'Title' => '', 'Description' => '', 'Images' => array(), 'Exception' => false);
     try {
         // Make sure the URL is valid.
         $urlParts = parse_url($url);
         if ($urlParts === false || !in_array(val('scheme', $urlParts), array('http', 'https'))) {
             throw new Exception('Invalid URL.', 400);
         }
         $Request = new ProxyRequest();
         $PageHtml = $Request->Request(array('URL' => $url, 'Timeout' => $timeout, 'Cookies' => $sendCookies, 'Redirects' => true));
         if (!$Request->status()) {
             throw new Exception('Couldn\'t connect to host.', 400);
         }
         $Dom = pQuery::parseStr($PageHtml);
         if (!$Dom) {
             throw new Exception('Failed to load page for parsing.');
         }
         // FIRST PASS: Look for open graph title, desc, images
         $PageInfo['Title'] = domGetContent($Dom, 'meta[property="og:title"]');
         Trace('Getting og:description');
         $PageInfo['Description'] = domGetContent($Dom, 'meta[property="og:description"]');
         foreach ($Dom->query('meta[property="og:image"]') as $Image) {
             if ($Image->attr('content')) {
                 $PageInfo['Images'][] = $Image->attr('content');
             }
         }
         // SECOND PASS: Look in the page for title, desc, images
         if ($PageInfo['Title'] == '') {
             $PageInfo['Title'] = $Dom->query('title')->text();
         }
         if ($PageInfo['Description'] == '') {
             Trace('Getting meta description');
             $PageInfo['Description'] = domGetContent($Dom, 'meta[name="description"]');
         }
         // THIRD PASS: Look in the page contents
         if ($PageInfo['Description'] == '') {
             foreach ($Dom->query('p') as $element) {
                 Trace('Looking at p for description.');
                 if (strlen($element->plaintext) > 150) {
                     $PageInfo['Description'] = $element->text();
                     break;
                 }
             }
             if (strlen($PageInfo['Description']) > 400) {
                 $PageInfo['Description'] = SliceParagraph($PageInfo['Description'], 400);
             }
         }
         // Final: Still nothing? remove limitations
         if ($PageInfo['Description'] == '') {
             foreach ($Dom->query('p') as $element) {
                 Trace('Looking at p for description (no restrictions)');
                 if (trim($element->text()) != '') {
                     $PageInfo['Description'] = $element->text();
                     break;
                 }
             }
         }
         // Page Images
         if (count($PageInfo['Images']) == 0) {
             $Images = domGetImages($Dom, $url);
             $PageInfo['Images'] = array_values($Images);
         }
         $PageInfo['Title'] = htmlEntityDecode($PageInfo['Title']);
         $PageInfo['Description'] = htmlEntityDecode($PageInfo['Description']);
     } catch (Exception $ex) {
         $PageInfo['Exception'] = $ex->getMessage();
     }
     return $PageInfo;
 }
 public function __construct($Loud = FALSE)
 {
     self::$ConnectionHandles = array();
     $this->Loud = $Loud;
 }