public function buildExcerpts(array $docs, $index, $words, array $opts = array())
{
foreach ($docs as $doc) {
if (!is_string($doc)) {
throw new \InvalidArgumentException('Document must be a string.');
}
}
if (!is_string($index)) {
throw new \InvalidArgumentException('Index name must be a string.');
}
if (!is_string($words)) {
throw new \InvalidArgumentException('Keywords must be a string.');
}
$this->mbPush();
if (!($fp = $this->connect())) {
$this->mbPop();
return false;
}
// default options
$defaults = array('before_match' => '<b>', 'after_match' => '</b>', 'chunk_separator' => ' ... ', 'limit' => 256, 'limit_passages' => 0, 'limit_words' => 0, 'around' => 5, 'exact_phrase' => false, 'single_passage' => false, 'use_boundaries' => false, 'weight_order' => false, 'query_mode' => false, 'force_all_words' => false, 'start_passage_id' => 1, 'load_files' => false, 'html_strip_mode' => 'index', 'allow_empty' => false, 'passage_boundary' => 'none', 'emit_zones' => false, 'load_files_scattered' => false);
foreach ($defaults as $opt => $default) {
if (!isset($opts[$opt])) {
$opts[$opt] = $default;
}
}
// build request
// v.1.2 req
$flags = 1;
foreach (array(2 => 'exact_phrase', 4 => 'single_passage', 8 => 'use_boundaries', 16 => 'weight_order', 32 => 'query_mode', 64 => 'force_all_words', 128 => 'load_files', 256 => 'allow_empty', 512 => 'emit_zones', 1024 => 'load_files_scattered') as $flag => $opt) {
if ((bool) $opts[$opt]) {
$flags |= $flag;
}
}
// mode=0, flags=$flags
$req = pack('NN', 0, $flags);
$req .= pack('N', strlen($index)) . $index;
$req .= pack('N', strlen($words)) . $words;
// options
$req .= pack('N', strlen($opts['before_match'])) . $opts['before_match'];
$req .= pack('N', strlen($opts['after_match'])) . $opts['after_match'];
$req .= pack('N', strlen($opts['chunk_separator'])) . $opts['chunk_separator'];
$req .= pack('NN', (int) $opts['limit'], (int) $opts['around']);
// v.1.2
$req .= pack('NNN', (int) $opts['limit_passages'], (int) $opts['limit_words'], (int) $opts['start_passage_id']);
$req .= pack('N', strlen($opts['html_strip_mode'])) . $opts['html_strip_mode'];
$req .= pack('N', strlen($opts['passage_boundary'])) . $opts['passage_boundary'];
// documents
$req .= pack('N', count($docs));
foreach ($docs as $doc) {
$req .= pack('N', strlen($doc)) . $doc;
}
// send query, get response
$len = strlen($req);
// add header
$req = pack('nnN', self::SEARCHD_COMMAND_EXCERPT, self::VER_COMMAND_EXCERPT, $len) . $req;
if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, self::VER_COMMAND_EXCERPT))) {
$this->mbPop();
return false;
}
// parse response
$pos = 0;
$res = array();
$rlen = strlen($response);
$ndoc = count($docs);
for ($i = 0; $i < $ndoc; $i++) {
list(, $len) = unpack('N*', substr($response, $pos, 4));
$pos += 4;
if ($pos + $len > $rlen) {
$this->error = 'incomplete reply';
$this->mbPop();
return false;
}
$res[] = $len ? substr($response, $pos, $len) : '';
$pos += $len;
}
$this->mbPop();
return $res;
}