function split_keywords($search, $index = false, $partial_index = false, $is_date = false, $is_html = false) { # Takes $search and returns an array of individual keywords. global $config_trimchars; if ($index && $is_date) { # Date handling... index a little differently to support various levels of date matching (Year, Year+Month, Year+Month+Day). $s = explode("-", $search); if (count($s) >= 3) { return array($s[0], $s[0] . "-" . $s[1], $search); } else { return $search; } } # Remove any real / unescaped lf/cr $search = str_replace("\r", " ", $search); $search = str_replace("\n", " ", $search); $search = str_replace("\\r", " ", $search); $search = str_replace("\\n", " ", $search); $ns = trim_spaces($search); if (substr($ns, 0, 1) == "," || $index == false && strpos($ns, ":") !== false) { if (strpos($ns, "startdate") == false && strpos($ns, "enddate") == false) { $ns = cleanse_string($ns, true, !$index, $is_html); } $return = explode(",", $ns); # If we are indexing, append any values that contain spaces. # Important! Solves the searching for keywords with spaces issue. # Consider: for any keyword that has spaces, append to the array each individual word too # so for example: South Asia,USA becomes South Asia,USA,South,Asia # so a plain search for 'south asia' will match those with the keyword 'south asia' because the resource # will also be linked to the words 'south' and 'asia'. if ($index) { $return2 = $return; for ($n = 0; $n < count($return); $n++) { $keyword = trim($return[$n]); if (strpos($keyword, " ") !== false) { # append each word $words = explode(" ", $keyword); for ($m = 0; $m < count($words); $m++) { $return2[] = trim($words[$m]); } } } $return2 = trim_array($return2, $config_trimchars); if ($partial_index) { return add_partial_index($return2); } return $return2; } else { return trim_array($return, $config_trimchars); } } else { # split using spaces and similar chars (according to configured whitespace characters) $ns = explode(" ", cleanse_string($ns, false, !$index, $is_html)); $ns = trim_array($ns, $config_trimchars); if ($index && $partial_index) { return add_partial_index($ns); } return $ns; } }
function render_search_field($field, $value = "", $autoupdate, $class = "stdwidth", $forsearchbar = false, $limit_keywords = array()) { # Renders the HTML for the provided $field for inclusion in a search form, for example the # advanced search page. Standard field titles are translated using $lang. Custom field titles are i18n translated. # # $field an associative array of field data, i.e. a row from the resource_type_field table. # $name the input name to use in the form (post name) # $value the default value to set for this field, if any global $auto_order_checkbox, $lang, $category_tree_open, $minyear; $name = "field_" . $field["ref"]; if (!$forsearchbar) { ?> <div class="Question" <?php if (strlen($field["tooltip_text"]) >= 1) { echo "title=\"" . htmlspecialchars(lang_or_i18n_get_translated($field["tooltip_text"], "fieldtooltip-")) . "\""; } ?> > <label><?php echo lang_or_i18n_get_translated($field["title"], "fieldtitle-"); ?> </label> <?php } else { ?> <div class="SearchItem"> <?php echo lang_or_i18n_get_translated($field["title"], "fieldtitle-"); ?> </br> <?php } switch ($field["type"]) { case 0: # -------- Text boxes # -------- Text boxes case 1: case 5: ?> <input class="<?php echo $class; ?> " type=text name="field_<?php echo $field["ref"]; ?> " value="<?php echo htmlspecialchars($value); ?> " <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> onKeyPress="if (!(updating)) {setTimeout('UpdateResultCount()',2000);updating=true;}"><?php break; case 2: case 3: # -------- Show a check list or dropdown for dropdowns and check lists? # By default show a checkbox list for both (for multiple selections this enabled OR functionality) # Translate all options $options = trim_array(explode(",", $field["options"])); $adjusted_dropdownoptions = hook("adjustdropdownoptions"); if ($adjusted_dropdownoptions) { $options = $adjusted_dropdownoptions; } $option_trans = array(); $option_trans_simple = array(); for ($m = 0; $m < count($options); $m++) { $trans = i18n_get_translated($options[$m]); $option_trans[$options[$m]] = $trans; $option_trans_simple[] = $trans; } if ($auto_order_checkbox) { asort($option_trans); } $options = array_keys($option_trans); # Set the options array to the keys, so it is now effectively sorted by translated string if ($field["display_as_dropdown"]) { # Show as a dropdown box $set = trim_array(explode(";", cleanse_string($value, true))); ?> <select class="<?php echo $class; ?> " name="field_<?php echo $field["ref"]; ?> " <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> ><option value=""></option><?php foreach ($option_trans as $option => $trans) { if (trim($trans) != "") { ?> <option value="<?php echo htmlspecialchars(trim($trans)); ?> " <?php if (in_array(cleanse_string($trans, true), $set)) { ?> selected<?php } ?> ><?php echo htmlspecialchars(trim($trans)); ?> </option> <?php } } ?> </select><?php } else { # Show as a checkbox list (default) $set = trim_array(explode(";", cleanse_string($value, true))); $wrap = 0; $l = average_length($option_trans_simple); $cols = 10; if ($l > 5) { $cols = 6; } if ($l > 10) { $cols = 4; } if ($l > 15) { $cols = 3; } if ($l > 25) { $cols = 2; } # Filter the options array for blank values and ignored keywords. $newoptions = array(); foreach ($options as $option) { if ($option != "" && (count($limit_keywords) == 0 || in_array($option, $limit_keywords))) { $newoptions[] = $option; } } $options = $newoptions; $height = ceil(count($options) / $cols); global $checkbox_ordered_vertically; if ($checkbox_ordered_vertically) { if (!hook('rendersearchchkboxes')) { # ---------------- Vertical Ordering (only if configured) ----------- ?> <table cellpadding=2 cellspacing=0><tr><?php for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $cols; $x++) { # Work out which option to fetch. $o = $x * $height + $y; if ($o < count($options)) { $option = $options[$o]; $trans = $option_trans[$option]; $name = $field["ref"] . "_" . md5($option); if ($option != "") { ?> <td valign=middle><input type=checkbox id="<?php echo $name; ?> " name="<?php echo $name; ?> " value="yes" <?php if (in_array(cleanse_string($trans, true), $set)) { ?> checked<?php } ?> <?php if ($autoupdate) { ?> onClick="UpdateResultCount();"<?php } ?> ></td><td valign=middle><?php echo htmlspecialchars($trans); ?> </td> <?php } else { ?> <td></td><td></td><?php } } } ?> </tr><tr><?php } ?> </tr></table><?php } } else { # ---------------- Horizontal Ordering (Standard) --------------------- ?> <table cellpadding=2 cellspacing=0><tr><?php foreach ($option_trans as $option => $trans) { $wrap++; if ($wrap > $cols) { $wrap = 1; ?> </tr><tr><?php } $name = $field["ref"] . "_" . md5($option); if ($option != "") { ?> <td valign=middle><input type=checkbox id="<?php echo $name; ?> " name="<?php echo $name; ?> " value="yes" <?php if (in_array(cleanse_string(i18n_get_translated($option), true), $set)) { ?> checked<?php } ?> <?php if ($autoupdate) { ?> onClick="UpdateResultCount();"<?php } ?> ></td><td valign=middle><?php echo htmlspecialchars($trans); ?> </td> <?php } } ?> </tr></table><?php } } break; case 4: case 6: # ----- Date types $found_year = ''; $found_month = ''; $found_day = ''; $s = explode("-", $value); if (count($s) >= 3) { $found_year = $s[0]; $found_month = $s[1]; $found_day = $s[2]; } ?> <select name="<?php echo $name; ?> _year" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anyyear"]; ?> </option> <?php $y = date("Y"); for ($d = $minyear; $d <= $y; $d++) { ?> <option <?php if ($d == $found_year) { ?> selected<?php } ?> ><?php echo $d; ?> </option><?php } ?> </select> <select name="<?php echo $name; ?> _month" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anymonth"]; ?> </option> <?php for ($d = 1; $d <= 12; $d++) { $m = str_pad($d, 2, "0", STR_PAD_LEFT); ?> <option <?php if ($d == $found_month) { ?> selected<?php } ?> value="<?php echo $m; ?> "><?php echo $lang["months"][$d - 1]; ?> </option><?php } ?> </select> <select name="<?php echo $name; ?> _day" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anyday"]; ?> </option> <?php for ($d = 1; $d <= 31; $d++) { $m = str_pad($d, 2, "0", STR_PAD_LEFT); ?> <option <?php if ($d == $found_day) { ?> selected<?php } ?> value="<?php echo $m; ?> "><?php echo $m; ?> </option><?php } ?> </select> <?php break; case 7: # ----- Category Tree $options = $field["options"]; $set = trim_array(explode(";", cleanse_string($value, true))); if ($forsearchbar) { # On the search bar? # Produce a smaller version of the category tree in a single dropdown - max two levels ?> <select class="<?php echo $class; ?> " name="field_<?php echo $field["ref"]; ?> "><option value=""></option><?php $class = explode("\n", $options); for ($t = 0; $t < count($class); $t++) { $s = explode(",", $class[$t]); if (count($s) == 3 && $s[1] == 0) { # Found a first level ?> <option <?php if (in_array(cleanse_string($s[2], true), $set)) { ?> selected<?php } ?> ><?php echo $s[2]; ?> </option> <?php # Parse tree again looking for level twos at this point for ($u = 0; $u < count($class); $u++) { $v = explode(",", $class[$u]); if (count($v) == 3 && $v[1] == $s[0]) { # Found a first level ?> <option value="<?php echo $s[2] . "," . $v[2]; ?> " <?php if (in_array(cleanse_string($s[2], true), $set) && in_array(cleanse_string($v[2], true), $set)) { ?> selected<?php } ?> > - <?php echo $v[2]; ?> </option> <?php } } } } ?> </select> <?php } else { # For advanced search and elsewhere, include the category tree. include "../pages/edit_fields/7.php"; } break; case 9: #-- Dynamic keywords list $value = str_replace(";", ",", $value); # Different syntax used for keyword separation when searching. include "../pages/edit_fields/9.php"; break; } ?> <div class="clearerleft"> </div> </div> <?php }
function get_smart_themes($field, $node = 0, $themebar = false) { # Returns a list of smart themes (which are really field options). # The results are filtered so that only field options that are in use are returned. # Fetch field info $fielddata = sql_query("select * from resource_type_field where ref='{$field}'"); if (count($fielddata) > 0) { $fielddata = $fielddata[0]; } else { return false; } # Return a list of keywords that are in use for this field global $smart_themes_omit_archived; $inuse = sql_array("SELECT k.keyword value FROM keyword k JOIN resource_keyword rk ON k.ref = rk.keyword " . ($smart_themes_omit_archived ? "JOIN resource r ON rk.resource = r.ref" : "") . " WHERE resource_type_field = '{$field}' AND resource > 0 " . ($smart_themes_omit_archived ? "AND archive= 0 " : "") . " GROUP BY MD5(k.keyword)"); if ($fielddata["type"] == 7) { # Category tree style view $tree = explode("\n", $fielddata["options"]); $return = array(); global $themes_category_split_pages; if ($themes_category_split_pages && !$themebar) { # Return one level only, unless grabbing for themebar $levels = 1; } else { # Return an infinite number of levels $levels = -1; } $return = populate_smart_theme_tree_node($tree, $node, $return, 0, $levels); # For each option, if it is in use, add it to the return list. $out = array(); for ($n = 0; $n < count($return); $n++) { # Prepare a 'tidied' local language version of the name to use for the comparison # Only return items that are in use. $tidy = escape_check(cleanse_string(trim(mb_strtolower(str_replace("-", " ", htmlspecialchars_decode(i18n_get_collection_name($return[$n]))))), false)); if (in_array($tidy, $inuse)) { $c = count($out); $out[$c]["indent"] = $return[$n]["indent"]; $out[$c]["name"] = trim(htmlspecialchars_decode(i18n_get_collection_name($return[$n]))); $out[$c]["node"] = $return[$n]["node"]; $out[$c]["children"] = $return[$n]["children"]; } } return $out; } else { # Standard checkbox list or drop-down box # Fetch raw options list $options = explode(",", $fielddata["options"]); # Tidy list so it matches the storage format used for keywords. # The translated version is fetched as each option will be indexed in the local language version of each option. $options_base = array(); for ($n = 0; $n < count($options); $n++) { $options_base[$n] = escape_check(trim(mb_convert_case(i18n_get_translated($options[$n]), MB_CASE_LOWER, "UTF-8"))); } # For each option, if it is in use, add it to the return list. $return = array(); for ($n = 0; $n < count($options); $n++) { #echo "<li>Looking for " . $options_base[$n] . " in " . join (",",$inuse); if (in_array(str_replace("-", " ", $options_base[$n]), $inuse)) { $c = count($return); $return[$c]["name"] = trim(i18n_get_translated($options[$n])); $return[$c]["indent"] = 0; $return[$c]["node"] = 0; $return[$c]["children"] = 0; } } return $return; } }
" class="SearchWidth" onChange="FilterBasicSearchOptions('<?php echo $fields[$n]["name"]; ?> ',<?php echo $fields[$n]["resource_type"]; ?> );"> <option selected="selected" value=""> </option> <?php for ($m = 0; $m < count($options); $m++) { $c = i18n_get_translated($options[$m]); if ($c != "") { if (!hook('modifysearchfieldvalues')) { ?> <option <?php if (cleanse_string($c, false) == $value) { ?> selected<?php } ?> ><?php echo $c; ?> </option><?php } } } ?> </select> <?php # Add to the clear function so clicking 'clear' clears this box.
function render_search_field($field, $value = "", $autoupdate, $class = "stdwidth", $forsearchbar = false, $limit_keywords = array()) { # Renders the HTML for the provided $field for inclusion in a search form, for example the # advanced search page. Standard field titles are translated using $lang. Custom field titles are i18n translated. # # $field an associative array of field data, i.e. a row from the resource_type_field table. # $name the input name to use in the form (post name) # $value the default value to set for this field, if any global $auto_order_checkbox, $auto_order_checkbox_case_insensitive, $lang, $category_tree_open, $minyear, $daterange_search, $is_search, $values, $n; $name = "field_" . $field["ref"]; #Check if field has a display condition set $displaycondition = true; if ($field["display_condition"] != "") { $s = explode(";", $field["display_condition"]); $condref = 0; foreach ($s as $condition) { $displayconditioncheck = false; $s = explode("=", $condition); global $fields; for ($cf = 0; $cf < count($fields); $cf++) { if ($s[0] == $fields[$cf]["name"] && ($fields[$cf]["resource_type"] == 0 || $fields[$cf]["resource_type"] == $field["resource_type"])) { $scriptconditions[$condref]["field"] = $fields[$cf]["ref"]; # add new jQuery code to check value $scriptconditions[$condref]['type'] = $fields[$cf]['type']; $scriptconditions[$condref]['options'] = $fields[$cf]['options']; $checkvalues = $s[1]; $validvalues = explode("|", strtoupper($checkvalues)); $scriptconditions[$condref]["valid"] = "\""; $scriptconditions[$condref]["valid"] .= implode("\",\"", $validvalues); $scriptconditions[$condref]["valid"] .= "\""; if (isset($values[$fields[$cf]["name"]])) { $v = trim_array(explode(" ", strtoupper($values[$fields[$cf]["name"]]))); foreach ($validvalues as $validvalue) { if (in_array($validvalue, $v)) { $displayconditioncheck = true; } # this is a valid value } } if (!$displayconditioncheck) { $displaycondition = false; } #add jQuery code to update on changes if ($fields[$cf]["type"] == 2 && $fields[$cf]["display_as_dropdown"] == 0) { # construct the value from the ticked boxes $val = ","; # Note: it seems wrong to start with a comma, but this ensures it is treated as a comma separated list by split_keywords(), so if just one item is selected it still does individual word adding, so 'South Asia' is split to 'South Asia','South','Asia'. $options = trim_array(explode(",", $fields[$cf]["options"])); ?> <script type="text/javascript"> jQuery(document).ready(function() {<?php for ($m = 0; $m < count($options); $m++) { $checkname = $fields[$cf]["ref"] . "_" . md5($options[$m]); echo "\n jQuery('input[name=\"" . $checkname . "\"]').change(function (){\n checkDisplayCondition" . $field["ref"] . "();\n });"; } ?> }); </script><?php } else { if ($fields[$cf]['type'] == 12 && $fields[$cf]['display_as_dropdown'] == 0) { ?> <script type="text/javascript"> jQuery(document).ready(function() { // Check for radio buttons (default behaviour) jQuery('input[name=field_<?php echo $fields[$cf]["ref"]; ?> ]:radio').change(function() { checkDisplayCondition<?php echo $field["ref"]; ?> (); }); <?php $options = trim_array(explode(',', $fields[$cf]['options'])); foreach ($options as $option) { $name = 'field_' . $fields[$cf]['ref'] . '_' . sha1($option); ?> // Check for checkboxes (advanced search behaviour) jQuery('input[name=<?php echo $name; ?> ]:checkbox').change(function() { checkDisplayCondition<?php echo $field['ref']; ?> (); }); <?php } ?> }); </script> <?php } else { ?> <script type="text/javascript"> jQuery(document).ready(function() { jQuery('#field_<?php echo $fields[$cf]["ref"]; ?> ').change(function (){ checkDisplayCondition<?php echo $field["ref"]; ?> (); }); }); </script> <?php } } } } # see if next field needs to be checked $condref++; } # check next condition ?> <script type="text/javascript"> function checkDisplayCondition<?php echo $field["ref"]; ?> () { var questionField = jQuery('#question_<?php echo $n; ?> '); var fieldStatus = questionField.css('display'); var newFieldStatus = 'none'; var newFieldProvisional = true; var newFieldProvisionalTest; <?php foreach ($scriptconditions as $scriptcondition) { ?> newFieldProvisionalTest = false; if (jQuery('#field_<?php echo $scriptcondition["field"]; ?> ').length != 0) { fieldValues<?php echo $scriptcondition["field"]; ?> = jQuery('#field_<?php echo $scriptcondition["field"]; ?> ').val().toUpperCase().split(','); } else { <?php # Handle Radio Buttons type: if ($scriptcondition['type'] == 12) { $scriptcondition["options"] = explode(',', $scriptcondition["options"]); foreach ($scriptcondition["options"] as $key => $radio_button_value) { $scriptcondition["options"][$key] = sha1($radio_button_value); } $scriptcondition["options"] = implode(',', $scriptcondition["options"]); ?> var options_string = '<?php echo $scriptcondition["options"]; ?> '; var field<?php echo $scriptcondition["field"]; ?> _options = options_string.split(','); var checked = null; var fieldOkValues<?php echo $scriptcondition["field"]; ?> = [<?php echo $scriptcondition["valid"]; ?> ]; for(var i=0; i < field<?php echo $scriptcondition["field"]; ?> _options.length; i++) { if(jQuery('#field_<?php echo $scriptcondition["field"]; ?> _' + field<?php echo $scriptcondition["field"]; ?> _options[i]).is(':checked')) { checked = jQuery('#field_<?php echo $scriptcondition["field"]; ?> _' + field<?php echo $scriptcondition["field"]; ?> _options[i] + ':checked').val().toUpperCase(); if(jQuery.inArray(checked, fieldOkValues<?php echo $scriptcondition["field"]; ?> ) > -1) { newFieldProvisionalTest = true; } } } <?php } # end of handling radio buttons type ?> fieldValues<?php echo $scriptcondition["field"]; ?> = new Array(); checkedVals<?php echo $scriptcondition["field"]; ?> = jQuery('input[name^=<?php echo $scriptcondition["field"]; ?> _]'); jQuery.each(checkedVals<?php echo $scriptcondition["field"]; ?> , function() { if (jQuery(this).is(':checked')) { checkText<?php echo $scriptcondition["field"]; ?> = jQuery(this).parent().next().text().toUpperCase(); fieldValues<?php echo $scriptcondition["field"]; ?> .push(jQuery.trim(checkText<?php echo $scriptcondition["field"]; ?> )); } }); } fieldOkValues<?php echo $scriptcondition["field"]; ?> = [<?php echo $scriptcondition["valid"]; ?> ]; jQuery.each(fieldValues<?php echo $scriptcondition["field"]; ?> ,function(f,v) { if ((jQuery.inArray(v,fieldOkValues<?php echo $scriptcondition["field"]; ?> ))>-1 || (fieldValues<?php echo $scriptcondition["field"]; ?> == fieldOkValues<?php echo $scriptcondition["field"]; ?> )) { newFieldProvisionalTest = true; } }); if (newFieldProvisionalTest == false) { newFieldProvisional = false; } <?php } ?> if (newFieldProvisional == true) { newFieldStatus = 'block' } if (newFieldStatus != fieldStatus) { questionField.slideToggle(); if (questionField.css('display') == 'block') { questionField.css('border-top',''); } else { questionField.css('border-top','none'); } } } </script> <?php } $is_search = true; if (!$forsearchbar) { ?> <div class="Question" id="question_<?php echo $n; ?> " <?php if (!$displaycondition) { ?> style="display:none;border-top:none;"<?php } if (strlen($field["tooltip_text"]) >= 1) { echo "title=\"" . htmlspecialchars(lang_or_i18n_get_translated($field["tooltip_text"], "fieldtooltip-")) . "\""; } ?> > <label><?php echo htmlspecialchars(lang_or_i18n_get_translated($field["title"], "fieldtitle-")); ?> </label> <?php } else { ?> <div class="SearchItem"> <?php echo htmlspecialchars(lang_or_i18n_get_translated($field["title"], "fieldtitle-")); ?> </br> <?php } //hook("rendersearchhtml", "", array($field, $class, $value, $autoupdate)); switch ($field["type"]) { case 0: # -------- Text boxes # -------- Text boxes case 1: case 5: case 8: ?> <input class="<?php echo $class; ?> " type=text name="field_<?php echo $field["ref"]; ?> " id="field_<?php echo $field["ref"]; ?> " value="<?php echo htmlspecialchars($value); ?> " <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> onKeyPress="if (!(updating)) {setTimeout('UpdateResultCount()',2000);updating=true;}"><?php break; case 2: case 3: if (!hook("customchkboxes", "", array($field, $value, $autoupdate, $class, $forsearchbar, $limit_keywords))) { # -------- Show a check list or dropdown for dropdowns and check lists? # By default show a checkbox list for both (for multiple selections this enabled OR functionality) # Translate all options $options = trim_array(explode(",", $field["options"])); $adjusted_dropdownoptions = hook("adjustdropdownoptions"); if ($adjusted_dropdownoptions) { $options = $adjusted_dropdownoptions; } $option_trans = array(); $option_trans_simple = array(); for ($m = 0; $m < count($options); $m++) { $trans = i18n_get_translated($options[$m]); $option_trans[$options[$m]] = $trans; $option_trans_simple[] = $trans; } if ($auto_order_checkbox && !hook("ajust_auto_order_checkbox", "", array($field))) { if ($auto_order_checkbox_case_insensitive) { natcasesort($option_trans); } else { asort($option_trans); } } $options = array_keys($option_trans); # Set the options array to the keys, so it is now effectively sorted by translated string if ($field["display_as_dropdown"]) { # Show as a dropdown box $set = trim_array(explode(";", cleanse_string($value, true))); ?> <select class="<?php echo $class; ?> " name="field_<?php echo $field["ref"]; ?> " id="field_<?php echo $field["ref"]; ?> " <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> ><option value=""></option><?php foreach ($option_trans as $option => $trans) { if (trim($trans) != "") { ?> <option value="<?php echo htmlspecialchars(trim($trans)); ?> " <?php if (in_array(cleanse_string($trans, true), $set)) { ?> selected<?php } ?> ><?php echo htmlspecialchars(trim($trans)); ?> </option> <?php } } ?> </select><?php } else { # Show as a checkbox list (default) $set = trim_array(explode(";", cleanse_string($value, true))); $wrap = 0; $l = average_length($option_trans_simple); $cols = 10; if ($l > 5) { $cols = 6; } if ($l > 10) { $cols = 4; } if ($l > 15) { $cols = 3; } if ($l > 25) { $cols = 2; } # Filter the options array for blank values and ignored keywords. $newoptions = array(); foreach ($options as $option) { if ($option != "" && (count($limit_keywords) == 0 || in_array($option, $limit_keywords))) { $newoptions[] = $option; } } $options = $newoptions; $height = ceil(count($options) / $cols); global $checkbox_ordered_vertically, $checkbox_vertical_columns; if ($checkbox_ordered_vertically) { if (!hook('rendersearchchkboxes')) { # ---------------- Vertical Ordering (only if configured) ----------- ?> <table cellpadding=2 cellspacing=0><tr><?php for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $cols; $x++) { # Work out which option to fetch. $o = $x * $height + $y; if ($o < count($options)) { $option = $options[$o]; $trans = $option_trans[$option]; $name = $field["ref"] . "_" . md5($option); if ($option != "") { ?> <td valign=middle><input type=checkbox id="<?php echo htmlspecialchars($name); ?> " name="<?php echo $name; ?> " value="yes" <?php if (in_array(cleanse_string($trans, true), $set)) { ?> checked<?php } ?> <?php if ($autoupdate) { ?> onClick="UpdateResultCount();"<?php } ?> ></td><td valign=middle><?php echo htmlspecialchars($trans); ?> </td> <?php } else { ?> <td></td><td></td><?php } } } ?> </tr><tr><?php } ?> </tr></table><?php } } else { # ---------------- Horizontal Ordering (Standard) --------------------- ?> <table cellpadding=2 cellspacing=0><tr><?php foreach ($option_trans as $option => $trans) { $wrap++; if ($wrap > $cols) { $wrap = 1; ?> </tr><tr><?php } $name = $field["ref"] . "_" . md5($option); if ($option != "") { ?> <td valign=middle><input type=checkbox id="<?php echo htmlspecialchars($name); ?> " name="<?php echo htmlspecialchars($name); ?> " value="yes" <?php if (in_array(cleanse_string(i18n_get_translated($option), true), $set)) { ?> checked<?php } ?> <?php if ($autoupdate) { ?> onClick="UpdateResultCount();"<?php } ?> ></td><td valign=middle><?php echo htmlspecialchars($trans); ?> </td> <?php } } ?> </tr></table><?php } } } break; case 4: case 6: case 10: # ----- Date types $found_year = ''; $found_month = ''; $found_day = ''; $found_start_year = ''; $found_start_month = ''; $found_start_day = ''; $found_end_year = ''; $found_end_month = ''; $found_end_day = ''; if ($daterange_search) { $startvalue = substr($value, strpos($value, "start") + 5, 10); $ss = explode(" ", $startvalue); if (count($ss) >= 3) { $found_start_year = $ss[0]; $found_start_month = $ss[1]; $found_start_day = $ss[2]; } $endvalue = substr($value, strpos($value, "end") + 3, 10); $se = explode(" ", $endvalue); if (count($se) >= 3) { $found_end_year = $se[0]; $found_end_month = $se[1]; $found_end_day = $se[2]; } ?> <!-- date range search start --> <div><label class="InnerLabel"><?php echo $lang["fromdate"]; ?> </label> <select name="<?php echo htmlspecialchars($name); ?> _startyear" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anyyear"]; ?> </option> <?php $y = date("Y"); for ($d = $y; $d >= $minyear; $d--) { ?> <option <?php if ($d == $found_start_year) { ?> selected<?php } ?> ><?php echo $d; ?> </option><?php } ?> </select> <select name="<?php echo $name; ?> _startmonth" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anymonth"]; ?> </option> <?php for ($d = 1; $d <= 12; $d++) { $m = str_pad($d, 2, "0", STR_PAD_LEFT); ?> <option <?php if ($d == $found_start_month) { ?> selected<?php } ?> value="<?php echo $m; ?> "><?php echo $lang["months"][$d - 1]; ?> </option><?php } ?> </select> <select name="<?php echo $name; ?> _startday" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anyday"]; ?> </option> <?php for ($d = 1; $d <= 31; $d++) { $m = str_pad($d, 2, "0", STR_PAD_LEFT); ?> <option <?php if ($d == $found_start_day) { ?> selected<?php } ?> value="<?php echo $m; ?> "><?php echo $m; ?> </option><?php } ?> </select> </div><br><div><label></label><label class="InnerLabel"><?php echo $lang["todate"]; ?> </label><select name="<?php echo $name; ?> _endyear" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anyyear"]; ?> </option> <?php $y = date("Y"); for ($d = $y; $d >= $minyear; $d--) { ?> <option <?php if ($d == $found_end_year) { ?> selected<?php } ?> ><?php echo $d; ?> </option><?php } ?> </select> <select name="<?php echo $name; ?> _endmonth" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anymonth"]; ?> </option> <?php $md = date("n"); for ($d = 1; $d <= 12; $d++) { $m = str_pad($d, 2, "0", STR_PAD_LEFT); ?> <option <?php if ($d == $found_end_month) { ?> selected<?php } ?> value="<?php echo $m; ?> "><?php echo $lang["months"][$d - 1]; ?> </option><?php } ?> </select> <select name="<?php echo $name; ?> _endday" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anyday"]; ?> </option> <?php $td = date("d"); for ($d = 1; $d <= 31; $d++) { $m = str_pad($d, 2, "0", STR_PAD_LEFT); ?> <option <?php if ($d == $found_end_day) { ?> selected<?php } ?> value="<?php echo $m; ?> "><?php echo $m; ?> </option><?php } ?> </select> <!-- date range search end date--> </div> <?php } else { $s = explode("|", $value); if (count($s) >= 3) { $found_year = $s[0]; $found_month = $s[1]; $found_day = $s[2]; } ?> <select name="<?php echo $name; ?> _year" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anyyear"]; ?> </option> <?php $y = date("Y"); for ($d = $minyear; $d <= $y; $d++) { ?> <option <?php if ($d == $found_year) { ?> selected<?php } ?> ><?php echo $d; ?> </option><?php } ?> </select> <select name="<?php echo $name; ?> _month" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anymonth"]; ?> </option> <?php for ($d = 1; $d <= 12; $d++) { $m = str_pad($d, 2, "0", STR_PAD_LEFT); ?> <option <?php if ($d == $found_month) { ?> selected<?php } ?> value="<?php echo $m; ?> "><?php echo $lang["months"][$d - 1]; ?> </option><?php } ?> </select> <select name="<?php echo $name; ?> _day" class="SearchWidth" style="width:100px;" <?php if ($autoupdate) { ?> onChange="UpdateResultCount();"<?php } ?> > <option value=""><?php echo $lang["anyday"]; ?> </option> <?php for ($d = 1; $d <= 31; $d++) { $m = str_pad($d, 2, "0", STR_PAD_LEFT); ?> <option <?php if ($d == $found_day) { ?> selected<?php } ?> value="<?php echo $m; ?> "><?php echo $m; ?> </option><?php } ?> </select> <?php } break; case 7: # ----- Category Tree $options = $field["options"]; $set = trim_array(explode(";", cleanse_string($value, true))); if ($forsearchbar) { # On the search bar? # Produce a smaller version of the category tree in a single dropdown - max two levels ?> <select class="<?php echo $class; ?> " name="field_<?php echo $field["ref"]; ?> "><option value=""></option><?php $class = explode("\n", $options); for ($t = 0; $t < count($class); $t++) { $s = explode(",", $class[$t]); if (count($s) == 3 && $s[1] == 0) { # Found a first level ?> <option <?php if (in_array(cleanse_string($s[2], true), $set)) { ?> selected<?php } ?> ><?php echo htmlspecialchars($s[2]); ?> </option> <?php # Parse tree again looking for level twos at this point for ($u = 0; $u < count($class); $u++) { $v = explode(",", $class[$u]); if (count($v) == 3 && $v[1] == $s[0]) { # Found a first level ?> <option value="<?php echo htmlspecialchars($s[2]) . "," . htmlspecialchars($v[2]); ?> " <?php if (in_array(cleanse_string($s[2], true), $set) && in_array(cleanse_string($v[2], true), $set)) { ?> selected<?php } ?> > - <?php echo htmlspecialchars($v[2]); ?> </option> <?php } } } } ?> </select> <?php } else { # For advanced search and elsewhere, include the category tree. include "../pages/edit_fields/7.php"; } break; case 9: #-- Dynamic keywords list $value = str_replace(";", ",", $value); # Different syntax used for keyword separation when searching. include "../pages/edit_fields/9.php"; break; // Radio buttons: // Radio buttons: case 12: // auto save is not needed when searching $edit_autosave = FALSE; $display_as_radiobuttons = FALSE; $display_as_checkbox = TRUE; if ($field['display_as_dropdown']) { $display_as_dropdown = TRUE; $display_as_checkbox = FALSE; } include '../pages/edit_fields/12.php'; break; } ?> <div class="clearerleft"> </div> </div> <?php }
function do_search($search, $restypes = "", $order_by = "relevance", $archive = 0, $fetchrows = -1, $sort = "desc", $access_override = false, $starsearch = 0, $ignore_filters = false, $return_disk_usage = false, $recent_search_daylimit = "", $go = false) { debug("search={$search} {$go} {$fetchrows} restypes={$restypes} archive={$archive} daylimit={$recent_search_daylimit}"); # globals needed for hooks global $sql, $order, $select, $sql_join, $sql_filter, $orig_order, $checkbox_and, $collections_omit_archived, $search_sql_double_pass_mode, $usergroup; $alternativeresults = hook("alternativeresults", "", array($go)); if ($alternativeresults) { return $alternativeresults; } $modifyfetchrows = hook("modifyfetchrows", "", array($fetchrows)); if ($modifyfetchrows) { $fetchrows = $modifyfetchrows; } # Takes a search string $search, as provided by the user, and returns a results set # of matching resources. # If there are no matches, instead returns an array of suggested searches. # $restypes is optionally used to specify which resource types to search. # $access_override is used by smart collections, so that all all applicable resources can be judged regardless of the final access-based results # resolve $order_by to something meaningful in sql $orig_order = $order_by; global $date_field; $order = array("relevance" => "score {$sort}, user_rating {$sort}, hit_count {$sort}, field{$date_field} {$sort},r.ref {$sort}", "popularity" => "user_rating {$sort},hit_count {$sort},field{$date_field} {$sort},r.ref {$sort}", "rating" => "r.rating {$sort}, user_rating {$sort}, score {$sort},r.ref {$sort}", "date" => "field{$date_field} {$sort},r.ref {$sort}", "colour" => "has_image {$sort},image_blue {$sort},image_green {$sort},image_red {$sort},field{$date_field} {$sort},r.ref {$sort}", "country" => "country {$sort},r.ref {$sort}", "title" => "title {$sort},r.ref {$sort}", "file_path" => "file_path {$sort},r.ref {$sort}", "resourceid" => "r.ref {$sort}", "resourcetype" => "resource_type {$sort},r.ref {$sort}", "titleandcountry" => "title {$sort},country {$sort}", "random" => "RAND()"); if (!in_array($order_by, $order) && substr($order_by, 0, 5) == "field") { if (!is_numeric(str_replace("field", "", $order_by))) { exit("Order field incorrect."); } $order[$order_by] = "{$order_by} {$sort}"; } hook("modifyorderarray"); # Recognise a quoted search, which is a search for an exact string $quoted_string = false; if (substr($search, 0, 1) == "\"" && substr($search, -1, 1) == "\"") { $quoted_string = true; $search = substr($search, 1, -1); } $order_by = $order[$order_by]; $keywords = split_keywords($search); $search = trim($search); $modified_keywords = hook('dosearchmodifykeywords', '', array($keywords)); if ($modified_keywords) { $keywords = $modified_keywords; } # -- Build up filter SQL that will be used for all queries $sql_filter = ""; # append resource type filtering if ($restypes != "" && substr($restypes, 0, 6) != "Global") { if ($sql_filter != "") { $sql_filter .= " and "; } $restypes_x = explode(",", $restypes); $sql_filter .= "resource_type in ('" . join("','", $restypes_x) . "')"; } if ($starsearch != "" && $starsearch != 0) { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "user_rating >= '{$starsearch}'"; } if ($recent_search_daylimit != "") { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "creation_date > (curdate() - interval " . $recent_search_daylimit . " DAY)"; } # The ability to restrict access by the user that created the resource. global $resource_created_by_filter; if (isset($resource_created_by_filter) && count($resource_created_by_filter) > 0) { $created_filter = ""; foreach ($resource_created_by_filter as $filter_user) { if ($filter_user == -1) { global $userref; $filter_user = $userref; } # '-1' can be used as an alias to the current user. I.e. they can only see their own resources in search results. if ($created_filter != "") { $created_filter .= " or "; } $created_filter .= "created_by = '" . $filter_user . "'"; } if ($created_filter != "") { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "(" . $created_filter . ")"; } } # Geo zone exclusion # A list of upper/lower long/lat bounds, defining areas that will be excluded from geo search results. # Areas are defined as southwest lat, southwest long, northeast lat, northeast long global $geo_search_restrict; if (count($geo_search_restrict) > 0 && substr($search, 0, 4) == "!geo") { foreach ($geo_search_restrict as $zone) { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "(geo_lat is null or geo_long is null or not(geo_lat >= '" . $zone[0] . "' and geo_lat<= '" . $zone[2] . "'"; $sql_filter .= "and geo_long >= '" . $zone[1] . "' and geo_long<= '" . $zone[3] . "'))"; } } # If returning disk used by the resources in the search results ($return_disk_usage=true) then wrap the returned SQL in an outer query that sums disk usage. $sql_prefix = ""; $sql_suffix = ""; if ($return_disk_usage) { $sql_prefix = "select sum(disk_usage) total_disk_usage,count(*) total_resources from ("; $sql_suffix = ") resourcelist"; } # append resource type restrictions based on 'T' permission # look for all 'T' permissions and append to the SQL filter. global $userpermissions; $rtfilter = array(); for ($n = 0; $n < count($userpermissions); $n++) { if (substr($userpermissions[$n], 0, 1) == "T") { $rt = substr($userpermissions[$n], 1); if (is_numeric($rt) && !$access_override) { $rtfilter[] = $rt; } } } if (count($rtfilter) > 0) { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "resource_type not in (" . join(",", $rtfilter) . ")"; } # append "use" access rights, do not show restricted resources unless admin if (!checkperm("v") && !$access_override) { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.access<>'2'"; } # append archive searching (don't do this for collections or !listall, archived resources can still appear in these searches) if (substr($search, 0, 8) != "!listall" && substr($search, 0, 11) != "!collection" || $collections_omit_archived && !checkperm("e2")) { global $pending_review_visible_to_all; if ($archive == 0 && $pending_review_visible_to_all) { # If resources pending review are visible to all, when listing only active resources include # pending review (-1) resources too. if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "(archive='0' or archive=-1)"; } else { # Append normal filtering. if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "archive='{$archive}'"; global $userref, $pending_submission_searchable_to_all; if (!$pending_submission_searchable_to_all && $archive == "-2" && !(checkperm("e-2") && checkperm("t"))) { $sql_filter .= " and created_by='" . $userref . "'"; } } } # append ref filter - never return the batch upload template (negative refs) if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.ref>0"; # ------ Advanced 'custom' permissions, need to join to access table. $sql_join = ""; global $k; if (!checkperm("v") && !$access_override) { global $usergroup; global $userref; # one extra join (rca2) is required for user specific permissions (enabling more intelligent watermarks in search view) # the original join is used to gather group access into the search query as well. $sql_join = " left outer join resource_custom_access rca2 on r.ref=rca2.resource and rca2.user='******' and (rca2.user_expires is null or rca2.user_expires>now()) and rca2.access<>2 "; $sql_join .= " left outer join resource_custom_access rca on r.ref=rca.resource and rca.usergroup='{$usergroup}' and rca.access<>2 "; if ($sql_filter != "") { $sql_filter .= " and "; } # If rca.resource is null, then no matching custom access record was found # If r.access is also 3 (custom) then the user is not allowed access to this resource. # Note that it's normal for null to be returned if this is a resource with non custom permissions (r.access<>3). $sql_filter .= " not(rca.resource is null and r.access=3)"; } # Join thumbs_display_fields to resource table $select = "r.ref, r.resource_type, r.has_image, r.is_transcoding, r.hit_count, r.creation_date, r.rating, r.user_rating, r.user_rating_count, r.user_rating_total, r.file_extension, r.preview_extension, r.image_red, r.image_green, r.image_blue, r.thumb_width, r.thumb_height, r.archive, r.access, r.colour_key, r.created_by, r.file_modified, r.file_checksum, r.request_count, r.new_hit_count, r.expiry_notification_sent, r.preview_tweaks, r.file_path "; $modified_select = hook("modifyselect"); if ($modified_select) { $select .= $modified_select; } $modified_select2 = hook("modifyselect2"); if ($modified_select2) { $select .= $modified_select2; } # Return disk usage for each resource if returning sum of disk usage. if ($return_disk_usage) { $select .= ",r.disk_usage"; } # select group and user access rights if available, otherwise select null values so columns can still be used regardless # this makes group and user specific access available in the basic search query, which can then be passed through access functions # in order to eliminate many single queries. if (!checkperm("v") && !$access_override) { $select .= ",rca.access group_access,rca2.access user_access "; } else { $select .= ",null group_access, null user_access "; } # add 'joins' to select (adding them $joins = get_resource_table_joins(); foreach ($joins as $datajoin) { $select .= ",r.field" . $datajoin . " "; } # Prepare SQL to add join table for all provided keywods $suggested = $keywords; # a suggested search $fullmatch = true; $c = 0; $t = ""; $t2 = ""; $score = ""; $keysearch = true; # Do not process if a numeric search is provided (resource ID) global $config_search_for_number, $category_tree_search_use_and; if ($config_search_for_number && is_numeric($search)) { $keysearch = false; } # Fetch a list of fields that are not available to the user - these must be omitted from the search. $hidden_indexed_fields = get_hidden_indexed_fields(); if ($keysearch) { for ($n = 0; $n < count($keywords); $n++) { $keyword = $keywords[$n]; if (substr($keyword, 0, 1) != "!") { global $date_field; $field = 0; #echo "<li>$keyword<br/>"; if (strpos($keyword, ":") !== false && !$ignore_filters) { $kw = explode(":", $keyword, 2); global $datefieldinfo_cache; if (isset($datefieldinfo_cache[$kw[0]])) { $datefieldinfo = $datefieldinfo_cache[$kw[0]]; } else { $datefieldinfo = sql_query("select ref from resource_type_field where name='" . escape_check($kw[0]) . "' and type IN (4,6,10)", 0); $datefieldinfo_cache[$kw[0]] = $datefieldinfo; } if (count($datefieldinfo)) { $c++; $datefieldinfo = $datefieldinfo[0]; $datefield = $datefieldinfo["ref"]; if ($sql_filter != "") { $sql_filter .= " and "; } $val = str_replace("n", "_", $kw[1]); $val = str_replace("|", "-", $val); $sql_filter .= "rd" . $c . ".value like '" . $val . "%' "; $sql_join .= " join resource_data rd" . $c . " on rd" . $c . ".resource=r.ref and rd" . $c . ".resource_type_field='" . $datefield . "'"; } elseif ($kw[0] == "day") { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.field{$date_field} like '____-__-" . $kw[1] . "%' "; } elseif ($kw[0] == "month") { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.field{$date_field} like '____-" . $kw[1] . "%' "; } elseif ($kw[0] == "year") { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.field{$date_field} like '" . $kw[1] . "%' "; } elseif ($kw[0] == "startdate") { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.field{$date_field} >= '" . $kw[1] . "' "; } elseif ($kw[0] == "enddate") { if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.field{$date_field} <= '" . $kw[1] . " 23:59:59' "; } elseif (substr($kw[0], 0, 5) == "range") { $c++; $rangefield = substr($kw[0], 6); $daterange = false; if (strpos($kw[1], "start") !== FALSE) { $rangestart = str_replace(" ", "-", $kw[1]); if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "rd" . $c . ".value >= '" . substr($rangestart, strpos($rangestart, "start") + 5, 10) . "'"; } if (strpos($kw[1], "end") !== FALSE) { $rangeend = str_replace(" ", "-", $kw[1]); if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "rd" . $c . ".value <= '" . substr($rangeend, strpos($rangeend, "end") + 3, 10) . " 23:59:59'"; } $sql_join .= " join resource_data rd" . $c . " on rd" . $c . ".resource=r.ref and rd" . $c . ".resource_type_field='" . $rangefield . "'"; } else { $ckeywords = explode(";", $kw[1]); # Fetch field info global $fieldinfo_cache; if (isset($fieldinfo_cache[$kw[0]])) { $fieldinfo = $fieldinfo_cache[$kw[0]]; } else { $fieldinfo = sql_query("select ref,type from resource_type_field where name='" . escape_check($kw[0]) . "'", 0); $fieldinfo_cache[$kw[0]] = $fieldinfo; } if (count($fieldinfo) == 0) { debug("Field short name not found."); return false; } elseif (in_array($fieldinfo[0]["ref"], $hidden_indexed_fields)) { # Attempt to directly search field that the user does not have access to. return false; } $fieldinfo = $fieldinfo[0]; $field = $fieldinfo["ref"]; # Special handling for dates if ($fieldinfo["type"] == 4 || $fieldinfo["type"] == 6 || $fieldinfo["type"] == 10) { $ckeywords = array(str_replace(" ", "-", $kw[1])); } #special SQL generation for category trees to use AND instead of OR if ($fieldinfo["type"] == 7 && $category_tree_search_use_and || $fieldinfo["type"] == 2 && $checkbox_and) { for ($m = 0; $m < count($ckeywords); $m++) { $keyref = resolve_keyword($ckeywords[$m]); if (!($keyref === false)) { $c++; # Add related keywords $related = get_related_keywords($keyref); $relatedsql = ""; for ($r = 0; $r < count($related); $r++) { $relatedsql .= " or k" . $c . ".keyword='" . $related[$r] . "'"; } # Form join //$sql_join.=" join (SELECT distinct k".$c.".resource,k".$c.".hit_count from resource_keyword k".$c." where k".$c.".keyword='$keyref' $relatedsql) t".$c." "; $sql_join .= " join resource_keyword k" . $c . " on k" . $c . ".resource=r.ref and k" . $c . ".resource_type_field='" . $field . "' and (k" . $c . ".keyword='{$keyref}' {$relatedsql})"; if ($score != "") { $score .= "+"; } $score .= "k" . $c . ".hit_count"; # Log this daily_stat("Keyword usage", $keyref); } } } else { $c++; $sql_join .= " join resource_keyword k" . $c . " on k" . $c . ".resource=r.ref and k" . $c . ".resource_type_field='" . $field . "'"; if ($score != "") { $score .= "+"; } $score .= "k" . $c . ".hit_count"; # work through all options in an OR approach for multiple selects on the same field # where k.resource=type_field=$field and (k*.keyword=3 or k*.keyword=4) etc $keyjoin = ""; for ($m = 0; $m < count($ckeywords); $m++) { $keyref = resolve_keyword($ckeywords[$m]); if ($keyref === false) { $keyref = -1; } if ($m != 0) { $keyjoin .= " OR "; } $keyjoin .= "k" . $c . ".keyword='{$keyref}'"; # Also add related. $related = get_related_keywords($keyref); for ($o = 0; $o < count($related); $o++) { $keyjoin .= " OR k" . $c . ".keyword='" . $related[$o] . "'"; } # Log this daily_stat("Keyword usage", $keyref); } if ($keyjoin != "") { $sql_join .= " and (" . $keyjoin . ")"; } } } } else { # Normal keyword (not tied to a field) - searches all fields that the user has access to # If ignoring field specifications then remove them. if (strpos($keyword, ":") !== false && $ignore_filters) { $s = explode(":", $keyword); $keyword = $s[1]; } # Omit resources containing this keyword? $omit = false; if (substr($keyword, 0, 1) == "-") { $omit = true; $keyword = substr($keyword, 1); } global $noadd, $wildcard_always_applied; if (in_array($keyword, $noadd)) { $skipped_last = true; } else { # Handle wildcards if (strpos($keyword, "*") !== false || $wildcard_always_applied) { if ($wildcard_always_applied && strpos($keyword, "*") === false) { # Suffix asterisk if none supplied and using $wildcard_always_applied mode. $keyword = $keyword . "*"; } # Keyword contains a wildcard. Expand. $c++; global $use_temp_tables; if (!$use_temp_tables) { global $wildcard_expand_limit; $wildcards = sql_array("select ref value from keyword where keyword like '" . escape_check(str_replace("*", "%", $keyword)) . "' order by hit_count desc limit " . $wildcard_expand_limit); # Form join if (!$omit) { # Include in query $sql_join .= " join resource_keyword k" . $c . " on k" . $c . ".resource=r.ref and k" . $c . ".keyword in ('" . join("','", $wildcards) . "')"; # Allow keyword exclusion via plugin hook $sql_exclude_fields = hook("excludefieldsfromkeywordsearch"); if (!empty($sql_exclude_fields)) { $sql_join .= " and k" . $c . ".resource_type_field not in (" . $sql_exclude_fields . ")"; } # Omit fields to which the user does not have access. if (count($hidden_indexed_fields) > 0) { $sql_join .= " and k" . $c . ".resource_type_field not in ('" . join("','", $hidden_indexed_fields) . "')"; } } else { # Exclude matching resources from query (omit feature) if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.ref not in (select resource from resource_keyword where keyword in ('" . join("','", $wildcards) . "'))"; # Filter out resources that do contain the keyword. } #echo $sql_join; } else { //begin code for temporary table wildcard expansion // use a global counter to avoide temporary table naming collisions global $temptable_counter; if (!isset($temptable_counter)) { $temptable_counter = 0; } $temptable_counter++; $thetemptable = 'wcql' . $c . '_' . $temptable_counter; $sql_exclude_fields = hook("excludefieldsfromkeywordsearch"); $temptable_exclude = ''; if (!empty($sql_exclude_fields)) { $temptable_exclude .= "and rk.resource_type_field not in (" . $sql_exclude_fields . ")"; } # Omit fields to which the user does not have access. if (count($hidden_indexed_fields) > 0) { $temptable_exclude .= " and rk.resource_type_field not in ('" . join("','", $hidden_indexed_fields) . "')"; } sql_query("create temporary table {$thetemptable} (resource bigint unsigned)"); sql_query("insert into {$thetemptable} select distinct r.ref from resource r\n left join resource_keyword rk on r.ref = rk.resource {$temptable_exclude}\n left join keyword k on rk.keyword = k.ref\n where k.keyword like '" . escape_check(str_replace("*", "%", $keyword)) . "'"); if (!$omit) { # Include in query $sql_join .= " join {$thetemptable} on {$thetemptable}.resource = r.ref "; } else { # Exclude matching resources from query (omit feature) if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.ref not in (select resource from {$thetemptable})"; # Filter out resources that do contain the keyword. } } } else { # Not a wildcard. Normal matching. $keyref = resolve_keyword($keyword); # Resolve keyword. Ignore any wildcards when resolving. We need wildcards to be present later but not here. if ($keyref === false && !$omit) { $fullmatch = false; $soundex = resolve_soundex($keyword); if ($soundex === false) { # No keyword match, and no keywords sound like this word. Suggest dropping this word. $suggested[$n] = ""; } else { # No keyword match, but there's a word that sounds like this word. Suggest this word instead. $suggested[$n] = "<i>" . $soundex . "</i>"; } } else { # Key match, add to query. $c++; # Add related keywords $related = get_related_keywords($keyref); $relatedsql = ""; for ($m = 0; $m < count($related); $m++) { if ($m == 0) { $relatedsql .= " or k" . $c . ".keyword IN ("; } $relatedsql .= "'" . $related[$m] . "'"; if ($m == count($related) - 1) { $relatedsql .= ")"; } else { $relatedsql .= ","; } } # Form join global $use_temp_tables, $use_temp_tables_for_keyword_joins; if (substr($search, 0, 8) == "!related") { $use_temp_tables_for_keyword_joins = false; } // temp tables can't be used twice (unions) $sql_exclude_fields = hook("excludefieldsfromkeywordsearch"); if (!$use_temp_tables_for_keyword_joins || !$use_temp_tables) { // Not using temporary tables # Quoted string support $positionsql = ""; if ($quoted_string) { if ($c > 1) { $last_key_offset = 1; if (isset($skipped_last) && $skipped_last) { $last_key_offset = 2; } # Support skipped keywords - if the last keyword was skipped (listed in $noadd), increase the allowed position from the previous keyword. Useful for quoted searches that contain $noadd words, e.g. "black and white" where "and" is a skipped keyword. $positionsql = "and k" . $c . ".position=k" . ($c - 1) . ".position+" . $last_key_offset; } } if (!$omit) { # Include in query $sql_join .= " join resource_keyword k" . $c . " on k" . $c . ".resource=r.ref and (k" . $c . ".keyword='{$keyref}' {$relatedsql}) {$positionsql}"; if ($score != "") { $score .= "+"; } $score .= "k" . $c . ".hit_count"; if (!empty($sql_exclude_fields)) { $sql_join .= " and k" . $c . ".resource_type_field not in (" . $sql_exclude_fields . ")"; } if (count($hidden_indexed_fields) > 0) { $sql_join .= " and k" . $c . ".resource_type_field not in ('" . join("','", $hidden_indexed_fields) . "')"; } } else { # Exclude matching resources from query (omit feature) if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.ref not in (select resource from resource_keyword where keyword='{$keyref}')"; # Filter out resources that do contain the keyword. } } else { //use temp tables if (!isset($temptable_counter)) { $temptable_counter = 0; } $temptable_counter++; $jtemptable = 'jtt' . $c . '_' . $temptable_counter; sql_query("drop table IF EXISTS {$jtemptable} ", false); $exclude_sql = ''; # Quoted string support $positionsql = ""; if ($quoted_string) { if ($c > 1) { $last_key_offset = 1; if (isset($skipped_last) && $skipped_last) { $last_key_offset = 2; } # Support skipped keywords - if the last keyword was skipped (listed in $noadd), increase the allowed position from the previous keyword. Useful for quoted searches that contain $noadd words, e.g. "black and white" where "and" is a skipped keyword. $positionsql = "and {$jtemptable}.position=" . 'jtt' . ($c - 1) . '_' . ($temptable_counter - 1) . ".position+" . $last_key_offset; } } if (!empty($sql_exclude_fields)) { $exclude_sql .= "and k" . $c . ".resource_type_field not in (" . $sql_exclude_fields . ")"; } if (count($hidden_indexed_fields) > 0) { $exclude_sql .= " and k" . $c . ".resource_type_field not in ('" . join("','", $hidden_indexed_fields) . "')"; } $test = sql_query("create temporary table {$jtemptable} SELECT distinct k" . $c . ".resource,k" . $c . ".hit_count" . ($quoted_string ? ",k" . $c . ".position" : "") . " from resource_keyword k" . $c . " where (k" . $c . ".keyword='{$keyref}' {$relatedsql}) {$exclude_sql}"); if (!$omit) { # Include in query $sql_join .= " join {$jtemptable} on {$jtemptable}.resource = r.ref {$positionsql}"; if ($score != "") { $score .= "+"; } $score .= $jtemptable . ".hit_count"; } else { # Exclude matching resources from query (omit feature) if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.ref not in (select resource from {$jtemptable})"; # Filter out resources that do contain the keyword. } } # Log this daily_stat("Keyword usage", $keyref); } } $skipped_last = false; } } } } } # Could not match on provided keywords? Attempt to return some suggestions. if ($fullmatch == false) { if ($suggested == $keywords) { # Nothing different to suggest. debug("No alternative keywords to suggest."); return ""; } else { # Suggest alternative spellings/sound-a-likes $suggest = ""; if (strpos($search, ",") === false) { $suggestjoin = " "; } else { $suggestjoin = ", "; } for ($n = 0; $n < count($suggested); $n++) { if ($suggested[$n] != "") { if ($suggest != "") { $suggest .= $suggestjoin; } $suggest .= $suggested[$n]; } } debug("Suggesting {$suggest}"); return $suggest; } } # Some useful debug. #echo("keywordjoin=" . $sql_join); #echo("<br>Filter=" . $sql_filter); #echo("<br>Search=" . $search); hook("additionalsqlfilter"); hook("parametricsqlfilter", '', array($search)); # ------ Search filtering: If search_filter is specified on the user group, then we must always apply this filter. global $usersearchfilter; $sf = explode(";", $usersearchfilter); if (strlen($usersearchfilter) > 0) { for ($n = 0; $n < count($sf); $n++) { $s = explode("=", $sf[$n]); if (count($s) != 2) { exit("Search filter is not correctly configured for this user group."); } # Support for "NOT" matching. Return results only where the specified value or values are NOT set. $filterfield = $s[0]; $filter_not = false; if (substr($filterfield, -1) == "!") { $filter_not = true; $filterfield = substr($filterfield, 0, -1); # Strip off the exclamation mark. } # Find field(s) - multiple fields can be returned to support several fields with the same name. $f = sql_array("select ref value from resource_type_field where name='" . escape_check($filterfield) . "'"); if (count($f) == 0) { exit("Field(s) with short name '" . $filterfield . "' not found in user group search filter."); } # Find keyword(s) $ks = explode("|", strtolower(escape_check($s[1]))); for ($x = 0; $x < count($ks); $x++) { $ks[$x] = cleanse_string($ks[$x], true); } # Cleanse the string as keywords are stored without special characters $modifiedsearchfilter = hook("modifysearchfilter"); if ($modifiedsearchfilter) { $ks = $modifiedsearchfilter; } $kw = sql_array("select ref value from keyword where keyword in ('" . join("','", $ks) . "')"); #if (count($k)==0) {exit ("At least one of keyword(s) '" . join("', '",$ks) . "' not found in user group search filter.");} if (!$filter_not) { # Standard operation ('=' syntax) $sql_join .= " join resource_keyword filter" . $n . " on r.ref=filter" . $n . ".resource and filter" . $n . ".resource_type_field in ('" . join("','", $f) . "') and filter" . $n . ".keyword in ('" . join("','", $kw) . "') "; } else { # Inverted NOT operation ('!=' syntax) if ($sql_filter != "") { $sql_filter .= " and "; } $sql_filter .= "r.ref not in (select resource from resource_keyword where resource_type_field in ('" . join("','", $f) . "') and keyword in ('" . join("','", $kw) . "'))"; # Filter out resources that do contain the keyword(s) } } } $userownfilter = hook("userownfilter"); if ($userownfilter) { $sql_join .= $userownfilter; } # Handle numeric searches when $config_search_for_number=false, i.e. perform a normal search but include matches for resource ID first global $config_search_for_number; if (!$config_search_for_number && is_numeric($search)) { # Always show exact resource matches first. $order_by = "(r.ref='" . $search . "') desc," . $order_by; } # -------------------------------------------------------------------------------- # Special Searches (start with an exclamation mark) # -------------------------------------------------------------------------------- # Can only search for resources that belong to themes if (checkperm("J")) { $sql_join .= " join collection_resource jcr on jcr.resource=r.ref join collection jc on jcr.collection=jc.ref and length(jc.theme)>0 "; } # ------ Special searches ------ # View Last if (substr($search, 0, 5) == "!last") { # Replace r2.ref with r.ref for the alternative query used here. $order_by = str_replace("r.ref", "r2.ref", $order_by); if ($orig_order == "relevance") { $order_by = "r2.ref desc"; } # Extract the number of records to produce $last = explode(",", $search); $last = str_replace("!last", "", $last[0]); if (!is_numeric($last)) { $last = 1000; $search = "!last1000"; } # 'Last' must be a number. SQL injection filter. # Fix the order by for this query (special case due to inner query) $order_by = str_replace("r.rating", "rating", $order_by); return sql_query($sql_prefix . "select distinct *,r2.hit_count score from (select {$select} from resource r {$sql_join} where {$sql_filter} order by ref desc limit {$last} ) r2 order by {$order_by}" . $sql_suffix, false, $fetchrows); } # View Resources With No Downloads if (substr($search, 0, 12) == "!nodownloads") { if ($orig_order == "relevance") { $order_by = "ref desc"; } return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where {$sql_filter} and ref not in (select distinct object_ref from daily_stat where activity_type='Resource download') order by {$order_by}" . $sql_suffix, false, $fetchrows); } # Duplicate Resources (based on file_checksum) if (substr($search, 0, 11) == "!duplicates") { // old code disabled due to performance issues //return sql_query("select distinct r.hit_count score, $select from resource r $sql_join where $sql_filter and file_checksum in (select file_checksum from (select file_checksum,count(*) dupecount from resource group by file_checksum) r2 where r2.dupecount>1) order by file_checksum",false,$fetchrows); // new code relies on MySQL temporary tables being enabled, as well as checksums // if either is not turned on, just give up. global $use_temp_tables; global $file_checksums; if ($use_temp_tables && $file_checksums) { global $temptable_counter; if (!isset($temptable_counter)) { $temptable_counter = 0; } $temptable_counter++; $thetemptable = 'dupehashx' . '_' . $temptable_counter; $dupequery = "select distinct r.hit_count score, {$select} from resource r {$sql_join} join {$thetemptable} on r.file_checksum = {$thetemptable}.hash where {$sql_filter} order by file_checksum"; sql_query("create temporary table {$thetemptable} (`hash` varchar(255) NOT NULL,`hashcount` int(10) default NULL, KEY `Index 1` (`hash`))", false); sql_query("insert into {$thetemptable} select file_checksum, count(file_checksum) from resource where archive = 0 and ref > 0 and file_checksum <> '' and file_checksum is not null group by file_checksum having count(file_checksum) > 1", false); $duperesult = sql_query($sql_prefix . $dupequery . $sql_suffix, false, $fetchrows); return $duperesult; } else { return false; } } # View Collection if (substr($search, 0, 11) == "!collection") { if ($orig_order == "relevance") { $order_by = "c.sortorder asc,c.date_added desc,r.ref"; } $colcustperm = $sql_join; $colcustfilter = $sql_filter; // to avoid allowing this sql_filter to be modified by the $access_override search in the smart collection update below!!! if (getval("k", "") != "") { $sql_filter = "r.ref>0"; } # Special case if a key has been provided. # Extract the collection number $collection = explode(" ", $search); $collection = str_replace("!collection", "", $collection[0]); $collection = explode(",", $collection); // just get the number $collection = escape_check($collection[0]); # smart collections update global $allow_smart_collections, $smart_collections_async; if ($allow_smart_collections) { global $smartsearch_ref_cache; if (isset($smartsearch_ref_cache[$collection])) { $smartsearch_ref = $smartsearch_ref_cache[$collection]; // this value is pretty much constant } else { $smartsearch_ref = sql_value("select savedsearch value from collection where ref='{$collection}'", ""); $smartsearch_ref_cache[$collection] = $smartsearch_ref; } global $php_path; if ($smartsearch_ref != "") { if ($smart_collections_async && isset($php_path) && file_exists($php_path . "/php")) { exec($php_path . "/php " . dirname(__FILE__) . "/../pages/ajax/update_smart_collection.php " . escapeshellarg($collection) . " " . "> /dev/null 2>&1 &"); } else { include dirname(__FILE__) . "/../pages/ajax/update_smart_collection.php"; } } } $result = sql_query($sql_prefix . "select distinct c.date_added,c.comment,c.purchase_size,c.purchase_complete,r.hit_count score,length(c.comment) commentset, {$select} from resource r join collection_resource c on r.ref=c.resource {$colcustperm} where c.collection='" . $collection . "' and {$colcustfilter} group by r.ref order by {$order_by}" . $sql_suffix, false, $fetchrows); hook("beforereturnresults", "", array($result, $archive)); return $result; } # View Related if (substr($search, 0, 8) == "!related") { # Extract the resource number $resource = explode(" ", $search); $resource = str_replace("!related", "", $resource[0]); $order_by = str_replace("r.", "", $order_by); # UNION below doesn't like table aliases in the order by. return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r join resource_related t on (t.related=r.ref and t.resource='" . $resource . "') {$sql_join} where 1=1 and {$sql_filter} group by r.ref \n\t\tUNION\n\t\tselect distinct r.hit_count score, {$select} from resource r join resource_related t on (t.resource=r.ref and t.related='" . $resource . "') {$sql_join} where 1=1 and {$sql_filter} group by r.ref \n\t\torder by {$order_by}" . $sql_suffix, false, $fetchrows); } # Geographic search if (substr($search, 0, 4) == "!geo") { $geo = explode("t", str_replace(array("m", "p"), array("-", "."), substr($search, 4))); # Specially encoded string to avoid keyword splitting $bl = explode("b", $geo[0]); $tr = explode("b", $geo[1]); $sql = "select r.hit_count score, {$select} from resource r {$sql_join} where \n\n\t\t\t\t\tgeo_lat > '" . escape_check($bl[0]) . "'\n and geo_lat < '" . escape_check($tr[0]) . "'\t\t\n and geo_long > '" . escape_check($bl[1]) . "'\t\t\n and geo_long < '" . escape_check($tr[1]) . "'\t\t\n \n\t\t and {$sql_filter} group by r.ref order by {$order_by}"; return sql_query($sql_prefix . $sql . $sql_suffix, false, $fetchrows); } # Colour search if (substr($search, 0, 7) == "!colour") { $colour = explode(" ", $search); $colour = str_replace("!colour", "", $colour[0]); $sql = "select r.hit_count score, {$select} from resource r {$sql_join}\n\t\t\t\twhere \n\t\t\t\t\tcolour_key like '" . escape_check($colour) . "%'\n \tor colour_key like '_" . escape_check($colour) . "%'\n \n\t\t and {$sql_filter} group by r.ref order by {$order_by}"; return sql_query($sql_prefix . $sql . $sql_suffix, false, $fetchrows); } # Similar to a colour if (substr($search, 0, 4) == "!rgb") { $rgb = explode(":", $search); $rgb = explode(",", $rgb[1]); return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where has_image=1 and {$sql_filter} group by r.ref order by (abs(image_red-" . $rgb[0] . ")+abs(image_green-" . $rgb[1] . ")+abs(image_blue-" . $rgb[2] . ")) asc limit 500" . $sql_suffix, false, $fetchrows); } # Has no preview image if (substr($search, 0, 10) == "!nopreview") { return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where has_image=0 and {$sql_filter} group by r.ref" . $sql_suffix, false, $fetchrows); } # Similar to a colour by key if (substr($search, 0, 10) == "!colourkey") { # Extract the colour key $colourkey = explode(" ", $search); $colourkey = str_replace("!colourkey", "", $colourkey[0]); return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where has_image=1 and left(colour_key,4)='" . $colourkey . "' and {$sql_filter} group by r.ref" . $sql_suffix, false, $fetchrows); } global $config_search_for_number; if ($config_search_for_number && is_numeric($search) || substr($search, 0, 9) == "!resource") { $theref = escape_check($search); $theref = preg_replace("/[^0-9]/", "", $theref); return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where r.ref='{$theref}' and {$sql_filter} group by r.ref" . $sql_suffix); } # Searching for pending archive if (substr($search, 0, 15) == "!archivepending") { return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where archive=1 and ref>0 group by r.ref order by {$order_by}" . $sql_suffix, false, $fetchrows); } if (substr($search, 0, 12) == "!userpending") { if ($orig_order == "rating") { $order_by = "request_count desc," . $order_by; } return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where archive=-1 and ref>0 group by r.ref order by {$order_by}" . $sql_suffix, false, $fetchrows); } # View Contributions if (substr($search, 0, 14) == "!contributions") { global $userref; # Extract the user ref $cuser = explode(" ", $search); $cuser = str_replace("!contributions", "", $cuser[0]); if ($userref == $cuser) { $sql_filter = "archive='{$archive}'"; $sql_join = ""; } # Disable permissions when viewing your own contributions - only restriction is the archive status $select = str_replace(",rca.access group_access,rca2.access user_access ", ",null group_access, null user_access ", $select); return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where created_by='" . $cuser . "' and r.ref > 0 and {$sql_filter} group by r.ref order by {$order_by}" . $sql_suffix, false, $fetchrows); } # Search for resources with images if ($search == "!images") { return sql_query($sql_prefix . "select distinct r.hit_count score, {$select} from resource r {$sql_join} where has_image=1 group by r.ref order by {$order_by}" . $sql_suffix, false, $fetchrows); } # Search for resources not used in Collections if (substr($search, 0, 7) == "!unused") { return sql_query($sql_prefix . "SELECT distinct {$select} FROM resource r {$sql_join} where r.ref>0 and r.ref not in (select c.resource from collection_resource c) and {$sql_filter}" . $sql_suffix, false, $fetchrows); } # Search for resources with an empty field, ex: !empty18 or !emptycaption if (substr($search, 0, 6) == "!empty") { $nodatafield = explode(" ", $search); $nodatafield = rtrim(str_replace("!empty", "", $nodatafield[0]), ','); if (!is_numeric($nodatafield)) { $nodatafield = sql_value("select ref value from resource_type_field where name='" . escape_check($nodatafield) . "'", ""); } if ($nodatafield == "" || !is_numeric($nodatafield)) { exit('invalid !empty search'); } $rtype = sql_value("select resource_type value from resource_type_field where ref='{$nodatafield}'", 0); if ($rtype != 0) { if ($rtype == 999) { $restypesql = "(r.archive=1 or r.archive=2) and "; $sql_filter = str_replace("archive='0'", "(archive=1 or archive=2)", $sql_filter); } else { $restypesql = "r.resource_type ='{$rtype}' and "; } } else { $restypesql = ""; } return sql_query("{$sql_prefix} select distinct r.hit_count score,{$select} from resource r left outer join resource_data rd on r.ref=rd.resource and rd.resource_type_field='{$nodatafield}' {$sql_join} where {$restypesql} (rd.value ='' or rd.value is null or rd.value=',') and {$sql_filter} group by r.ref order by {$order_by} {$sql_suffix}"); } # Search for a list of resources # !listall = archive state is not applied as a filter to the list of resources. if (substr($search, 0, 5) == "!list") { $resources = explode(" ", $search); if (substr($search, 0, 8) == "!listall") { $resources = str_replace("!listall", "", $resources[0]); } else { $resources = str_replace("!list", "", $resources[0]); } $resources = explode(",", $resources); // separate out any additional keywords $resources = escape_check($resources[0]); if (strlen(trim($resources)) == 0) { $resources = "where r.ref IS NULL"; } else { $resources = "where (r.ref='" . str_replace(":", "' OR r.ref='", $resources) . "')"; } return sql_query($sql_prefix . "SELECT distinct r.hit_count score, {$select} FROM resource r {$sql_join} {$resources} and {$sql_filter} order by {$order_by}" . $sql_suffix, false, $fetchrows); } # Within this hook implementation, set the value of the global $sql variable: # Since there will only be one special search executed at a time, only one of the # hook implementations will set the value. So, you know that the value set # will always be the correct one (unless two plugins use the same !<type> value). $sql = ""; hook("addspecialsearch", "", array($search)); if ($sql != "") { debug("Addspecialsearch hook returned useful results."); return sql_query($sql_prefix . $sql . $sql_suffix, false, $fetchrows); } # ------------------------------------------------------------------------------------- # Standard Searches # ------------------------------------------------------------------------------------- # We've reached this far without returning. # This must be a standard (non-special) search. # Construct and perform the standard search query. #$sql=""; if ($sql_filter != "") { if ($sql != "") { $sql .= " and "; } $sql .= $sql_filter; } # Append custom permissions $t .= $sql_join; if ($score == "") { $score = "r.hit_count"; } # In case score hasn't been set (i.e. empty search) global $max_results; if ($t2 != "" && $sql != "") { $sql = " and " . $sql; } # Compile final SQL # Performance enhancement - set return limit to number of rows required if ($search_sql_double_pass_mode && $fetchrows != -1) { $max_results = $fetchrows; } $results_sql = $sql_prefix . "select distinct {$score} score, {$select} from resource r" . $t . " where {$t2} {$sql} group by r.ref order by {$order_by} limit {$max_results}" . $sql_suffix; # Debug debug("altert " . $results_sql); # Execute query $result = sql_query($results_sql, false, $fetchrows); # Performance improvement - perform a second count-only query and pad the result array as necessary if ($search_sql_double_pass_mode && count($result) >= $max_results) { $count_sql = "select count(distinct r.ref) value from resource r" . $t . " where {$t2} {$sql}"; $count = sql_value($count_sql, 0); $result = array_pad($result, $count, 0); } debug("Search found " . count($result) . " results"); if (count($result) > 0) { hook("beforereturnresults", "", array($result, $archive)); return $result; } # (temp) - no suggestion for field-specific searching for now - TO DO: modify function below to support this if (strpos($search, ":") !== false) { return ""; } # All keywords resolved OK, but there were no matches # Remove keywords, least used first, until we get results. $lsql = ""; $omitmatch = false; for ($n = 0; $n < count($keywords); $n++) { if (substr($keywords[$n], 0, 1) == "-") { $omitmatch = true; $omit = $keywords[$n]; } if ($lsql != "") { $lsql .= " or "; } $lsql .= "keyword='" . escape_check($keywords[$n]) . "'"; } if ($omitmatch) { return trim_spaces(str_replace(" " . $omit . " ", " ", " " . join(" ", $keywords) . " ")); } if ($lsql != "") { $least = sql_value("select keyword value from keyword where {$lsql} order by hit_count asc limit 1", ""); return trim_spaces(str_replace(" " . $least . " ", " ", " " . join(" ", $keywords) . " ")); } else { return array(); } }
# For each field, fetch all values and limit those that do not exist for ($n = 0; $n < count($s); $n++) { $e = explode(":", $s[$n]); if (count($e) == 2 && $n != $nofilter) { # $values=sql_array("select distinct k.keyword value from resource r join resource_keyword rk on rk.resource=r.ref and r.archive=0 and r.ref>0 and rk.resource_type_field='" . $field[$n]["ref"] . "' join keyword k on rk.keyword=k.ref " . $sql); $values = sql_array("select distinct k.keyword value from resource_keyword rk join keyword k on rk.keyword=k.ref " . $sql . " where rk.resource>0 and rk.resource_type_field='" . $field[$n]["ref"] . "'"); # Fetch the full list of available options $options = trim_array(explode(",", $field[$n]["options"])); sort($options); #print_r($options); # Remove existing options for this field #echo "<h2>" . $field[$n]["title"] . "</h2><ul>"; $select = "<option value=''>" . $lang["select"] . "</option>"; for ($m = 0; $m < count($options); $m++) { $value = i18n_get_translated($options[$m]); if (in_array(cleanse_string($value, true), $values)) { #echo "<li>" . i18n_get_translated($options[$m]); $select .= "<option"; if ($e[1] == $value) { $select .= " selected"; } $select .= ">" . $value . "</option>"; } } ?> jQuery('#field_<?php echo $field[$n]["name"]; ?> ').html("<?php echo $select; ?>
$adjusted_dropdownoptions=hook("adjustdropdownoptions"); if ($adjusted_dropdownoptions){$options=$adjusted_dropdownoptions;} $optionfields[]=$fields[$n]["name"]; # Append to the option fields array, used by the AJAX dropdown filtering ?> <select id="field_<?php echo htmlspecialchars($fields[$n]["name"]) ?>" name="field_drop_<?php echo htmlspecialchars($fields[$n]["name"]) ?>" class="SearchWidth" onChange="FilterBasicSearchOptions('<?php echo htmlspecialchars($fields[$n]["name"]) ?>',<?php echo htmlspecialchars($fields[$n]["resource_type"]) ?>);"> <option selected="selected" value=""> </option> <?php for ($m=0;$m<count($options);$m++) { $c=i18n_get_translated($options[$m]); if ($c!="") { if (!hook('modifysearchfieldvalues')) { ?><option <?php if (cleanse_string($c,false)==$value) { ?>selected<?php } ?>><?php echo htmlspecialchars($c) ?></option><?php } } } ?> </select> <?php # Add to the clear function so clicking 'clear' clears this box. $clear_function.="document.getElementById('field_" . $fields[$n]["name"] . "').selectedIndex=0;"; break; case 4: case 6: // Date types $d_year='';$d_month='';$d_day='';