_name = ''; $this->_servers = array(); $this->_query = ''; $this->_start = 0; $this->_cacheDirectory = '/tmp'; $this->_cacheTime = 3600; /* 1 hour */ } /** * Add server to server list * * @param $hostName string hostname * @param $timeOut int timeout in seconds */ function addServer($hostName, $timeOut = 15) { $this->_servers[] = array('hostName' => $hostName, 'timeOut' => $timeOut); } /** * Set query (for search) * * @param $query string */ function setQuery($query = '') { $this->_query = $query; } /** * Set start of results (for search) * @param $start int (0,10,20,30, etc) */ function setStart($start = 0) { $this->_start = $start; } /** * Set search name * @param $name string */ function setName($name = '') { $this->_name = $name; } /** * Set cache directory * @param $directory string */ function setCacheDirectory($directory = 'tmp') { if (!is_dir($directory)) { error_log($directory . ' is not a directory'); } $this->_cacheDirectory = $directory; } /** * Set cache time * @param $seconds int */ function setCacheTime($seconds = 0) { $this->_cacheTime = $seconds; } /** * Perform query * * @return bool true on success */ function doQuery() { $queryString = "in=" . urlencode($this->_query); if ($this->_start > 0) { $queryString .= '&s=' . intval($this->_start); } if ($this->getDataFromServers('search', $queryString)) { // success return true; } // failure return false; } /** * Get must popular keywords * * @param $period string Period (yesteray|month) * @return array array_of_popular_keywords */ function doGetPopularKeywords($period = 'month') { if ($period == 'yesterday') { $action = 'top.keywords.yesterday.xml'; } else { $action = 'top.keywords.last.month.xml'; } $data = $this->getDataFromServers($action, ''); if ($data) { return true; } else { // failure return false; } } /** * Get search statistics * * @return array array_of_statistics */ function doGetStatistics() { $data = $this->getDataFromServers('statistics.xml', ''); if ($data) { return true; } else { // failure return false; } } /** * Return parsed search results * * @return array array */ function getSearchResults() { return $this->_searchResults; } // var methods function getDataFromServers($action, $queryString = '') { if ($this->_cacheTime > 0) { $cacheFile = $this->_cacheDirectory . '/search_cache_' . $this->_name . '_' . $action . '_' . md5($queryString) . '_cache.tmp'; // Check Cache if (file_exists($cacheFile) && (time()-filemtime($cacheFile)) < $this->_cacheTime) { $data = @file_get_contents($cacheFile); $this->setSearchResults(xmltoarray($data)); return true; } } $serverCnt = 0; while(isset($this->_servers[$serverCnt])) { $data = $this->getDataFromServer($this->_servers[$serverCnt]['hostName'],$this->_servers[$serverCnt]['timeOut'], $action, $queryString); if ($data) { // success if ($this->_cacheTime > 0) { file_put_contents($cacheFile, $data); } // Parse data (XML) to array $this->setSearchResults(xmltoarray($data)); return true; } // Failure; try next server $serverCnt++; } // all servers failed error_log('All servers failed; action = ' . $action . '; queryString = ' . $queryString); return false; } function setSearchResults($searchResults) { $this->_searchResults = $searchResults; } function getDataFromServer($hostName, $timeOut, $action = 'search', $queryString = '') { $fp = fsockopen($hostName, 80); if (!$this->_name) { // No name set die('No search name set'); } $data = ''; $header = ''; if (!$fp) { // Failed to open socket error_log('Failed to open socket (' . $hostName . ')'); return null; } // Write GET query to socket fwrite($fp, "GET /" . urlencode($this->_name) . "/" . $action .($queryString ? "?".$queryString : "") . " HTTP/1.0\r\n"); fwrite($fp, "Host: " . $hostName ."\r\n"); fwrite($fp, "Connection: Close\r\n\r\n"); stream_set_blocking($fp, TRUE); stream_set_timeout($fp, $timeOut); $info = stream_get_meta_data($fp); $readingHeader = true; while ((!feof($fp)) && (!$info['timed_out'])) { if ($readingHeader) { $line = fgets($fp,1024*4); $info = stream_get_meta_data($fp); if((strlen($line) < 4) && str_replace(array("\r","\n"),array("",""),$line) == "") { // Analyze header if (!substr($header,0,4) == 'HTTP') { // Response didn't start with HTTP return null; } $p = strpos($header,' '); if ($p===false) { // not a space on the first line return null; } if (intval(substr($header, $p+1, $p+4)) != 200) { // Not 200 OK response return null; } // Done reading header $readingHeader = false; } else { $header .= $line; } } else { $data .= fread($fp, 4096); $info = stream_get_meta_data($fp); } } if ($info['timed_out']) { error_log('Connection to ' . $hostName . ' Timed Out!'); fclose($fp); return null; } fclose ($fp); return $data; } } // Helper functions function &last(&$array) { if (!count($array)) return null; end($array); return $array[key($array)]; } function parseXML(&$vals, &$dom, &$lev) { do { $curr = current($vals); $lev = $curr['level']; switch ($curr['type']) { case 'open': if (isset($dom[$curr['tag']])) { $tmp = $dom[$curr['tag']]; if (!array_key_exists('__multi', $tmp) || !$tmp['__multi']) { $dom[$curr['tag']] = array('__multi' => true, $tmp); } array_push($dom[$curr['tag']], array()); $new = &last($dom[$curr['tag']]); } else { $dom[$curr['tag']] = array(); $new = &$dom[$curr['tag']]; } next($vals); parseXML($vals, $new, $lev); break; case 'cdata': break; case 'complete': if (!isset($dom[$curr['tag']])) $dom[$curr['tag']] = (isset($curr['value']) ? $curr['value'] : null); else { if (is_array($dom[$curr['tag']])) { @array_push($dom[$curr['tag']] , $curr['value']); } else { @array_push($dom[$curr['tag']] = array($dom[$curr['tag']]) , $curr['value']); } } break; case 'close': return; } } while (next($vals)!==FALSE); } function xmltoarray($XML) { $xml_parser = xml_parser_create(); xml_parse_into_struct($xml_parser, $XML, $vals); xml_parser_free($xml_parser); reset($vals); $dom = array(); $lev = 0; parseXML($vals, $dom, $lev); return $dom; } ?>