= $_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'])) { if( isset($_GET['method-fp_x']) || isset($_GET['method-fp_y']) || isset($_GET['method-fp.x']) || isset($_GET['method-fp.y']) ) { array_push($magic, 'max'); array_push($value, $_GET['current'] - 1); array_push($magic, 'method'); array_push($value, 'Find Previous'); } if( isset($_GET['method-fn_x']) || isset($_GET['method-fn_y']) || isset($_GET['method-fn.x']) || isset($_GET['method-fn.y']) ) { array_push($magic, 'min'); array_push($value, $_GET['current'] + 1); 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\""); } } if(get_magic_quotes_gpc()) $_REQUEST['q'] = stripslashes($_REQUEST['q']); $tokens = tpw_parse_line('\s+', $_REQUEST['q']); # Protect against SQL injection in the event of Register Globals being on. $SEARCH_MIN = $SEARCH_MAX = null; 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 ); # Magic values are easy, just throw them on the list array_push($loop_magic, $subtokens[0]); # 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])); } #DEBUG #print_r($magic); #echo "
"; #print_r($value); #echo "
"; #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) "; $flag = false; 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; } } #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.=") "; } array_push($sub_queries, $query); } foreach($sub_queries as $q) { #DEBUG: run the search #echo $q; $result = mysqli_query($link,$q); if(!$result) { continue; } 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) "; $flag = false; 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; } } #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.=") "; } array_push($queries, $query); } 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) . ") "; } #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) . ") "; } #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) "; } #and now book and page if(isset($BOOK)) { $modifier .= $BOOK; } if(isset($PAGE)) { $modifier .= $PAGE; } foreach($queries as $q) { #apply modifiers $q .= $modifier; #DEBUG: run the search #echo $q; if(empty($q)) { continue; } $result = mysqli_query($link,$q); if(!$result) { continue; } 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 # 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); } #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); #now... the subtraction! $uhits = array_diff($uhits, $sub_uhits); #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]; } //die($METHOD); header('HTTP/1.0 301 Moved Permanently'); header('Location: ' . SITE_HOST . SITE_PATH . "/index.php?strip_id=$target" . "&q=" . urlencode($_REQUEST['q'])); exit(0); } $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); $numhits = count($rhits) - $first - $last; array_push($hcount, $numhits); } 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 = "
  • ".str_pad($result[0], 4, 0, STR_PAD_LEFT); $entry.= " - ". htmlentities($result[1]) . "
  • "; array_push($strings, $entry); } #now, a clever multisort... array_multisort($hcount, SORT_DESC, SORT_NUMERIC, $uhits, SORT_DESC, SORT_NUMERIC, $strings, SORT_ASC, SORT_STRING); } } pagehead('search', 'Search'); ?> 0) { echo '
      '; /*$qsearch = mysqli_query($link,'SELECT id, title FROM strip WHERE id IN(' . implode(', ', $uhits) . ')'); while($result = mysqli_fetch_array($qsearch)) printf('
    1. %s - %s
    2. ', $result[0], str_pad($result[0], 4, 0, STR_PAD_LEFT), $result[1]);*/ foreach($strings as $str) { echo $str; } echo '
    '; echo '

    Learn to direct search ninjas!

    '; ?> 0)) { echo '

    So sorry. Search ninjas obey without fail, yet find nothing.

    '; echo '

    Learn to direct search ninjas!

    '; } else { echo '

    Learn to direct search ninjas!

    '; } #search_help(); ?>