Remove spaces at EOL.
Remove spaces at EOL.

File last commit:

f4cda9e28354
f4cda9e28354
Show More
search.php
598 lines | 15.4 KiB | text/x-php | PhpLexer
/ search.php
Add root-directory files.
r2 <?php
require_once('frontend.inc.php');
$strings = $queries = $rhits = $hcount = $magic = $value = $sub_magic = $sub_value = Array();
$sub_queries = $sub_rhits = $sub_uhits = Array();
$META_TYPES = $META_TEMP = $SEARCH_TYPES = $SEARCH_TEMP = Array();
$query = '';
$modifier = '';
$random = false;
$date = $date_f = false;
if(isset($_REQUEST['q']) && ctype_digit($_REQUEST['q'])) {
$MAX_METHOD_ID = max_strip_id();
if($MAX_METHOD_ID >= $_REQUEST['q'] && $_REQUEST['q'] > 0)
{
header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . SITE_HOST . SITE_PATH . "/strip/$_REQUEST[q]");
exit(0);
}
}
#check if it's a date
#try these three different formats
# mm dd yyyy first
$date = strptime($_REQUEST['q'], "%m.%d.%Y");
if(!$date) $date = strptime($_REQUEST['q'], "%m/%d/%Y");
if(!$date) $date = strptime($_REQUEST['q'], "%m-%d-%Y");
#then yyyy mm dd
if(!$date) $date = strptime($_REQUEST['q'], "%Y/%m/%d");
if(!$date) $date = strptime($_REQUEST['q'], "%Y.%m.%d");
if(!$date) $date = strptime($_REQUEST['q'], "%Y-%m-%d");
#if date, convert to unix timestamp
if($date)
{
$date_formatted = (1900+$date['tm_year']).'-'.(1+$date['tm_mon']).'-'.$date['tm_mday'];
$date_f = strtotime($date_formatted);
$date_f = strtotime("+1 day", $date_f);
}
#if unix timestamp, try to go there
if($date_f && $date)
{
$goto = get_by_date($date_f);
if(isset($goto) && $goto > 0)
{
header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . SITE_HOST . SITE_PATH . "/strip/$goto");
exit(0);
}
}
if(isset($_REQUEST['q']))
{
Remove spaces at EOL.
r36 if( isset($_GET['method-fp_x']) || isset($_GET['method-fp_y'])
Add root-directory files.
r2 || isset($_GET['method-fp.x']) || isset($_GET['method-fp.y']) ) {
array_push($magic, 'max');
array_push($value, $_GET['current'] - 1);
Remove spaces at EOL.
r36
Add root-directory files.
r2 array_push($magic, 'method');
Remove spaces at EOL.
r36 array_push($value, 'Find Previous');
Add root-directory files.
r2 }
Remove spaces at EOL.
r36 if( isset($_GET['method-fn_x']) || isset($_GET['method-fn_y'])
Add root-directory files.
r2 || isset($_GET['method-fn.x']) || isset($_GET['method-fn.y']) ) {
array_push($magic, 'min');
array_push($value, $_GET['current'] + 1);
Remove spaces at EOL.
r36
Add root-directory files.
r2 array_push($magic, 'method');
array_push($value, 'Find Next');
}
// Turn named parameters into query string items
$_REQUEST['q'] = trim($_REQUEST['q']);
foreach($_GET as $k => $v) {
if( $k == 'x' || $k == 'y' ) continue;
if( $k == 'q' || $k == 'current' ) continue;
if( substr($k, 0, 7) == 'method-' ) continue;
if(is_array($v)) {
foreach($v as $val)
$_REQUEST['q'] = trim("$_REQUEST[q] $k:\"$val\"");
} else {
$_REQUEST['q'] = trim("$_REQUEST[q] $k:\"$v\"");
}
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 if(get_magic_quotes_gpc())
$_REQUEST['q'] = stripslashes($_REQUEST['q']);
Remove spaces at EOL.
r36
Add root-directory files.
r2 $tokens = tpw_parse_line('\s+', $_REQUEST['q']);
# Protect against SQL injection in the event of Register Globals being on.
$SEARCH_MIN = $SEARCH_MAX = null;
Remove spaces at EOL.
r36
Add root-directory files.
r2 foreach($tokens as $token) {
$token = strtolower($token);
# Determine if we want to subtract
if($token[0] == '-') {
$token = substr($token, 1);
$loop_magic =& $sub_magic;
$loop_value =& $sub_value;
} else {
$loop_magic =& $magic;
$loop_value =& $value;
}
$subtokens = preg_match('/(?:\w+|[#*]):/', $token) ? preg_split('/:/', $token, 2) : Array( false, $token );
Remove spaces at EOL.
r36
Add root-directory files.
r2 # Magic values are easy, just throw them on the list
array_push($loop_magic, $subtokens[0]);
Remove spaces at EOL.
r36
Add root-directory files.
r2 # Values, however, need a bit more cleaning up first
if('""' == $subtokens[1])
array_push($loop_value, '""');
else
array_push($loop_value, preg_replace('/[[:punct:]]|(?<=\s)\s+/', '', $subtokens[1]));
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 #DEBUG
#print_r($magic);
#echo "<br>";
#print_r($value);
#echo "<br>";
#do subtraction logic first
if(count($sub_magic) > 0)
{
#iterate over all subtraction magic/value pairs
foreach($sub_magic as $i => $m)
{
$query = "SELECT DISTINCT strip.id FROM strip
LEFT JOIN transcript ON strip.id = transcript.strip
JOIN strip_t ON strip.type = strip_t.id
LEFT JOIN meta ON strip_t.id = meta.type
LEFT JOIN meta_t ON meta.meta = meta_t.id
WHERE (strip.published < NOW())
AND (transcript.speaker NOT LIKE \"#%\"
OR transcript.speaker IS NULL) ";
Remove spaces at EOL.
r36
Add root-directory files.
r2 $flag = false;
Remove spaces at EOL.
r36
Add root-directory files.
r2 if($m) #attempt to short-circuit on no magic
{
# well, we have magic
if($m == "type" || $m == "chapter")
{
if(ctype_digit(strval($sub_value[$i])))
{
$modifier .= " AND (strip_t.description NOT LIKE '%chapter ".mysqli_real_escape_string($link,$sub_value[$i])."%')";
continue;
}
else
{
$modifier .= " AND (strip_t.description NOT LIKE '%".mysqli_real_escape_string($link,$sub_value[$i])."%')";
continue;
}
}
else if($m == "meta")
{
$modifier .= " AND (meta_t.name NOT LIKE '".mysqli_real_escape_string($link,$sub_value[$i])."%')";
continue;
}
else if($m == "*")
{
#we want to exclude the speaker from this search
# but here, we don't actually need to do much
$m = mysqli_real_escape_string($link,$m);
}
else
{
#it's not a special operator, so assume they mean a character speaking
$tmp = mysqli_real_escape_string($link,$m);
$query .= "AND (transcript.speaker LIKE \"%$tmp%\" ) ";
$flag = true;
}
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 #now, handle the $value portion of the string
# first, handle for ""
switch($sub_value[$i]) {
case '""':
$query .= "AND (transcript.search = '' ) ";
break;
case '':
break;
case '*':
$query .= "AND (transcript.search != '' ) ";
break;
default:
$tmp = mysqli_real_escape_string($link,$sub_value[$i]);
$query .= "AND (transcript.search LIKE \"%$tmp%\"";
if($m != '*' && !$flag)
{
$query.= "OR transcript.speaker = \"$tmp\"
OR strip.title LIKE \"%$tmp%\" ";
}
$query.=") ";
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 array_push($sub_queries, $query);
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 foreach($sub_queries as $q)
{
#DEBUG: run the search
#echo $q;
$result = mysqli_query($link,$q);
Remove spaces at EOL.
r36
Add root-directory files.
r2 if(!$result)
{
continue;
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 while($row = mysqli_fetch_row($result))
{
#and put all the hits onto an array
array_push($sub_rhits, $row[0]);
}
}
}
foreach($magic as $i => $m)
{
$query = "SELECT DISTINCT strip.id FROM strip
LEFT JOIN transcript ON strip.id = transcript.strip
JOIN strip_t ON strip.type = strip_t.id
LEFT JOIN meta ON strip_t.id = meta.type
LEFT JOIN meta_t ON meta.meta = meta_t.id
WHERE (strip.published < NOW())
AND (transcript.speaker NOT LIKE \"#%\"
OR transcript.speaker IS NULL) ";
Remove spaces at EOL.
r36
Add root-directory files.
r2 $flag = false;
Remove spaces at EOL.
r36
Add root-directory files.
r2 if($m) #attempt to short-circuit on no magic
{
# well, we have magic
# so handle special operators first
# max and min don't really generate queries, so they short-circuit the loop
if($m == "min")
{
if(ctype_digit(strval($value[$i])))
$SEARCH_MIN = (int)$value[$i];
continue;
}
else if($m == "max")
{
if(ctype_digit(strval($value[$i])))
$SEARCH_MAX = (int)$value[$i];
continue;
}
else if($m == "#")
{
if(ctype_digit(strval($value[$i])))
{
header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . SITE_HOST . SITE_PATH . "/strip/$value[$i]");
exit(0);
}
elseif($value[$i] == "random")
{
$random = true;
}
continue;
}
else if($m == "type" || $m == "chapter")
{
if(ctype_digit(strval($value[$i])))
{
array_push($SEARCH_TYPES, mysqli_real_escape_string($link,"chapter ".$value[$i]));
continue;
}
else
{
array_push($SEARCH_TYPES, mysqli_real_escape_string($link,$value[$i]));
continue;
}
}
else if($m == "meta")
{
array_push($META_TYPES, mysqli_real_escape_string($link,$value[$i]));
continue;
}
else if($m == "book")
{
if(ctype_digit(strval($value[$i])))
{
$BOOK = " AND (strip.book =" . (int)$value[$i] . ") ";
continue;
}
}
else if($m == "page")
{
if(ctype_digit(strval($value[$i])))
{
$PAGE = " AND (strip.page =" . (int)$value[$i] . ") ";
continue;
}
}
else if($m == "method")
{
$METHOD = $value[$i];
continue;
}
else if($m == "*")
{
#we want to exclude the speaker from this search
# but here, we don't actually need to do much
$m = mysqli_real_escape_string($link,$m);
}
else
{
#it's not a special operator, so assume they mean a character speaking
$tmp = mysqli_real_escape_string($link,$m);
$query .= "AND (transcript.speaker LIKE \"%$tmp%\" ) ";
$flag = true;
}
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 #now, handle the $value portion of the string
# first, handle for ""
switch($value[$i]) {
case '""':
$query .= "AND (transcript.search = '' ) ";
break;
case '':
break;
case '*':
$query .= "AND (transcript.search != '' ) ";
break;
default:
$tmp = mysqli_real_escape_string($link,$value[$i]);
$query .= "AND (transcript.search LIKE \"%$tmp%\"";
if($m != '*' && !$flag)
{
$query.= "OR transcript.speaker = \"$tmp\"
OR strip.title LIKE \"%$tmp%\" ";
}
$query.=") ";
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 array_push($queries, $query);
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 if(count($queries) == 0)
{
array_push($queries, $query);
}
#additive search logic
#generate type and metatype strings now
#searching for a specific type is a little messy
if(count($SEARCH_TYPES) > 0)
{
foreach($SEARCH_TYPES as $SEARCH)
{
array_push($SEARCH_TEMP, "strip_t.description LIKE '%$SEARCH%'
OR strip_t.name LIKE '%$SEARCH%'");
}
#second, collapse them into one clause
$modifier .= " AND (" . implode(" OR ", $SEARCH_TEMP) . ") ";
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 #now the metatypes, just like the types
if(count($META_TYPES) > 0)
{
#OK, now apply the metatype restrictions...
foreach($META_TYPES as $META)
{
#first, generate the restriction strings
array_push($META_TEMP, "meta_t.name LIKE '" . $META . "%'");
}
#second, collapse them into one clause
$modifier .= " AND (" . implode(" OR ", $META_TEMP) . ") ";
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 #now do min and max
if(isset($SEARCH_MIN))
{
$modifier .= "AND ($SEARCH_MIN <= strip.id) ";
}
if(isset($SEARCH_MAX))
{
$modifier .= "AND (strip.id <= $SEARCH_MAX) ";
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 #and now book and page
if(isset($BOOK))
{
$modifier .= $BOOK;
}
if(isset($PAGE))
{
$modifier .= $PAGE;
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 foreach($queries as $q)
{
#apply modifiers
$q .= $modifier;
#DEBUG: run the search
#echo $q;
if(empty($q)) {
continue;
}
$result = mysqli_query($link,$q);
Remove spaces at EOL.
r36
Add root-directory files.
r2 if(!$result)
{
continue;
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 while($row = mysqli_fetch_row($result))
{
#and put all the hits onto an array
array_push($rhits, $row[0]);
}
}
#so, now all the raw hits are in the same spot
#now comes The Magic
Remove spaces at EOL.
r36
Add root-directory files.
r2 # if book and page are used, break out
if(isset($BOOK) && isset($PAGE) && count($rhits) != 0)
{
header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . SITE_HOST . SITE_PATH . "/strip/$rhits[0]");
exit(0);
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 #first, reverse sort and uniquify a copy
rsort($rhits);
$uhits = array_unique($rhits);
#do the same for the subtraction hits
$sub_uhits = array_unique($sub_rhits);
Remove spaces at EOL.
r36
Add root-directory files.
r2 #now... the subtraction!
$uhits = array_diff($uhits, $sub_uhits);
Remove spaces at EOL.
r36
Add root-directory files.
r2 #if we're redirecting, break out of the normal search logic here
if(isset($METHOD) && count($uhits) > 0)
{
#$METHOD has a value, so we're bustin' outta here!
if($METHOD == "Find Next")
{
$target = end($rhits);
}
else if($METHOD == "Find Previous")
{
$target = $rhits[0];
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 //die($METHOD);
Remove spaces at EOL.
r36
Add root-directory files.
r2 header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . SITE_HOST . SITE_PATH . "/index.php?strip_id=$target" . "&q=" . urlencode($_REQUEST['q']));
exit(0);
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 $revhits = array_reverse($rhits);
#now create a count for each unique hit
foreach($uhits as $key => $value)
{
$first = array_search($value, $rhits);
$last = array_search($value, $revhits);
Remove spaces at EOL.
r36
Add root-directory files.
r2 $numhits = count($rhits) - $first - $last;
Remove spaces at EOL.
r36
Add root-directory files.
r2 array_push($hcount, $numhits);
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 if(count($uhits) > 0) {
if($random)
{
$rand = mt_rand(1, count($uhits));
header('Location: ' . SITE_HOST . SITE_PATH . "/index.php?strip_id=$uhits[$rand]" . "&q=" . urlencode($_REQUEST['q']));
}
$qsearch = mysqli_query($link,'SELECT id, title FROM strip WHERE id IN(' . implode(', ', $uhits) . ') GROUP BY id ORDER BY id DESC');
while($result = mysqli_fetch_array($qsearch))
{
$entry = "<li><a href=\"strip/$result[0]\">".str_pad($result[0], 4, 0, STR_PAD_LEFT);
$entry.= " - ". htmlentities($result[1]) . "</a></li>";
array_push($strings, $entry);
}
Remove spaces at EOL.
r36
Add root-directory files.
r2 #now, a clever multisort...
array_multisort($hcount, SORT_DESC, SORT_NUMERIC,
$uhits, SORT_DESC, SORT_NUMERIC,
$strings, SORT_ASC, SORT_STRING);
}
}
pagehead('search', 'Search');
?>
<form class="search" action="search.php" method="get"><div>
<input type="text" name="q" <?php if( $_REQUEST['q'] ) { printf('value="%s"', utfentities($_REQUEST['q']) ); } ?> />
<input type="submit" value="Search" />
</div></form>
Remove spaces at EOL.
r36 <?php if(count($uhits) > 0) {
Add root-directory files.
r2 echo '<div class="content"><div><ol class="results">';
/*$qsearch = mysqli_query($link,'SELECT id, title FROM strip WHERE id IN(' . implode(', ', $uhits) . ')');
while($result = mysqli_fetch_array($qsearch))
printf('<li><a href="?strip_id=%d">%s - %s</a></li>',
$result[0], str_pad($result[0], 4, 0, STR_PAD_LEFT), $result[1]);*/
foreach($strings as $str)
{
echo $str;
}
echo '</ol></div>';
echo '<div><p class="results"><a href="search_help">Learn to direct search ninjas!</a></p></div></div>';
Remove spaces at EOL.
r36
Add root-directory files.
r2 ?>
<form class="search" action="search.php" method="get"><div>
<input type="text" name="q" <?php if( $_REQUEST['q'] ) { printf('value="%s"', utfentities($_REQUEST['q']) ); } ?> />
<input type="submit" value="Search" />
Remove spaces at EOL.
r36 </div></form>
Add root-directory files.
r2 <?php
} elseif(isset($_REQUEST['q']) && (strlen($_REQUEST['q']) > 0)) {
echo '<div class="content"><div><p class="results">So sorry. Search ninjas obey without fail, yet find nothing.</p></div>';
echo '<div><p class="results"><a href="search_help">Learn to direct search ninjas!</a></p></div></div>';
} else
{
echo '<div class="content"><div><p class="results"><a href="search_help">Learn to direct search ninjas!</a></p></div></div>';
}
#search_help();
Remove spaces at EOL.
r36
Add root-directory files.
r2 ?>
<?php pagefoot() ?>
</body>
</html>
<?php
function tpw_parse_line($delimiter, $line)
{
$i = 0;
$bits = Array();
$word = '';
$valid_quotes = '"';
# $line must not have trailing slash or quote
$line = preg_replace('/((?:\\\\\\\\)*)\\\\?$/', '\1', rtrim($line));
if(substr_count($line, '"') % 2 == 1)
$line .= '"';
$regex = "/^([$valid_quotes])((?:\\\\.|(?!\\1)[^\\\\])*)\\1([\\000-\\377]*)|" .
"^((?:\\\\.|[^\\\\$valid_quotes])*?)(\\Z(?!\\n)|$delimiter|(?!^)(?=[$valid_quotes]))([\\000-\\377]*)/x";
while (strlen($line) && $i++ < 100) {
$tokens = preg_match($regex, $line, $matches);
$tpw_quote = $matches[1];
$tpw_quoted = $matches[2];
$tpw_unquoted = $matches[4];
$tpw_delim = $matches[5];
if ($tpw_quote || strlen($tpw_unquoted) || strlen($tpw_delim)) { }
else { return; }
$line = (isset($matches[6]) ? $matches[6] : $matches[3]);
// Remove quotes and backslashes from tokens
/* $tpw_unquoted = preg_replace("/\\\\(.)/", '$1', $tpw_unquoted);
if (isset($tpw_quote)) {
preg_replace("/\\\\(.)/", '$1', $tpw_quoted);
} */
// Keep quotes and backslashes in tokens
$tpw_quoted = "$tpw_quote$tpw_quoted$tpw_quote";
$word .= ($tpw_quote ? $tpw_quoted : $tpw_unquoted);
if (strlen($tpw_delim)) {
array_push($bits, $word);
$word = '';
}
if (!strlen($line)) {
array_push($bits, $word);
}
}
return $bits;
}
function get_by_date($stamp)
{
global $link;
$qr = mysqli_query($link,"SELECT MAX(id) FROM strip WHERE published < NOW() AND published < FROM_UNIXTIME($stamp)") or die(mysqli_error($link));
return current(mysqli_fetch_row($qr));
}
?>