'localhost', 'port' => 8983, 'path' => '', 'http_user' => NULL, 'http_pass' => NULL, 'default_field'=>'id', ); parent::__construct($options['host'], $options['port'], $options['path']); if ($options['http_user'] && $options['http_pass']) { $this->http_auth = 'Basic ' . base64_encode($options['http_user'] . ':' . $options['http_pass']); } // Since /ping otherwise complains about missing default field. $this->_pingUrl .= '?q=' . $options['default_field'] . ':1'; // As of July 2011, the newest release is r60, with Service.php having // revision 59. Revision 40 is just anything between 22 (old) and that. $this->newClient = trim(parent::SVN_REVISION, '$ :A..Za..z') > 40; if ($this->newClient) { $this->_httpTransport = new SearchApiSolrHttpTransport($this->http_auth); } } /** * Central method for making a get operation against this Solr Server. * * @see Apache_Solr_Service::_sendRawGet() */ protected function _sendRawGet($url, $timeout = FALSE) { // Little "hack" to allow filter-only queries // Since "*:*" doesn't work with the dismax query handler, we mustn't set // "q", to let "q.alt" kick in. However, Apache_Solr_Service::search() will // always add "q", even if it is empty. Therefore, we delete empty "q" // parameters here. $url = preg_replace('/([?&])q=(&|$)/', '$1', $url); if ($this->newClient) { return parent::_sendRawGet($url, $timeout); } list($data, $headers) = $this->_makeHttpRequest($url, 'GET', array(), '', $timeout); $response = new Apache_Solr_Response($data, $headers, $this->_createDocuments, $this->_collapseSingleValueArrays); $code = (int) $response->getHttpStatus(); if ($code != 200) { $message = $response->getHttpStatusMessage(); if ($code >= 400 && $code != 403 && $code != 404) { // Add details, like Solr's exception message. $message .= $response->getRawResponse(); } throw new Exception('"' . $code . '" Status: ' . $message); } return $response; } /** * Central method for making a post operation against this Solr Server. * * @see Apache_Solr_Service::_sendRawPost() */ protected function _sendRawPost($url, $rawPost, $timeout = FALSE, $contentType = 'text/xml; charset=UTF-8') { if ($this->newClient) { return parent::_sendRawPost($url, $rawPost, $timeout, $contentType); } $request_headers = array('Content-Type' => $contentType); list($data, $headers) = $this->_makeHttpRequest($url, 'POST', $request_headers, $rawPost, $timeout); $response = new Apache_Solr_Response($data, $headers, $this->_createDocuments, $this->_collapseSingleValueArrays); $code = (int) $response->getHttpStatus(); if ($code != 200) { $message = $response->getHttpStatusMessage(); if ($code >= 400 && $code != 403 && $code != 404) { // Add details, like Solr's exception message. $message .= $response->getRawResponse(); } throw new Exception('"' . $code . '" Status: ' . $message); } return $response; } /** * Call the /admin/ping servlet, to test the connection to the server. * * @param $timeout * maximum time to wait for ping in seconds, -1 for unlimited (default 2). * @return * (float) seconds taken to ping the server, FALSE if timeout occurs. */ public function ping($timeout = 2) { if ($this->newClient) { return parent::ping($timeout); } $start = microtime(TRUE); if ($timeout <= 0.0) { $timeout = -1; } // Attempt a HEAD request to the solr ping url. list($data, $headers) = $this->_makeHttpRequest($this->_pingUrl, 'HEAD', array(), NULL, $timeout); $response = new Apache_Solr_Response($data, $headers); if ($response->getHttpStatus() == 200) { // Add 0.1 ms to the ping time so we never return 0.0. return microtime(TRUE) - $start + 0.0001; } else { return FALSE; } } /** * Helper method for making an HTTP request, without using stupid stuff like * file_get_contents(). */ protected function _makeHttpRequest($url, $method = 'GET', $headers = array(), $content = '', $timeout = FALSE) { $options = array( 'headers' => $headers, 'method' => $method, 'data' => $content, ); if ($this->http_auth) { $options['headers']['Authorization'] = $this->http_auth; } if ($timeout) { $options['timeout'] = $timeout; } $result = drupal_http_request($url, $options); if (!isset($result->code) || $result->code < 0) { $result->code = 0; $result->status_message = 'Request failed'; $result->protocol = 'HTTP/1.0'; } // Additional information may be in the error property. if (isset($result->error)) { $result->status_message .= ': ' . check_plain($result->error); } if (!isset($result->data)) { $result->data = ''; } // The headers have to be reformatted for the response class. $headers[] = "{$result->protocol} {$result->code} {$result->status_message}"; if (isset($result->headers)) { foreach ($result->headers as $name => $value) { $headers[] = "$name: $value"; } } return array($result->data, $headers); } /** * Convenience function for escaping a field name. * * Since field names can only contain one special character, ":", there is no * need to use the complete escape() method. * * @param string $value * The field name to escape. * * @return string * An escaped string suitable for passing to Solr. */ static public function escapeFieldName($value) { $value = str_replace(':', '\:', $value); return $value; } /** * Convenience function for creating phrase syntax from a value. * * @param string $value * The string to convert into a Solr phrase value. * * @return string * A quoted string suitable for passing to Solr. */ static public function phrase($value) { $value = str_replace("\\", "\\\\", $value); $value = str_replace('"', '\"', $value); return '"' . $value . '"'; } /** * Get metadata about the Lucene index. * * @param int $num_terms * Number of 'top terms' to return. * * @return Apache_Solr_Response * A response object containing schema information. */ public function getLuke($num_terms = 0) { if (!isset($this->luke[$num_terms])) { $url = $this->_constructUrl(self::LUKE_SERVLET, array('numTerms' => "$num_terms", 'wt' => self::SOLR_WRITER)); $this->luke[$num_terms] = $this->_sendRawGet($url); } return $this->luke[$num_terms]; } /** * Get metadata about fields in the Lucene index. * * @return array * An array of objects, keyed by field name, describing fields on the index. * * @see SearchApiSolrConnection::getLuke() * @see http://wiki.apache.org/solr/LukeRequestHandler */ public function getFields() { return (array) $this->getLuke()->fields; } }