We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 20246
    • 33 Posts
    Доброе утро всем. Такая проблема. Стоит кодировка utf-8. В результатах поиска поиска выдается часть контента, но непонятно откуда (для меня непонятно smiley ) вылазят символы не относящиеся к utf-8. Допустим firefox их показывает как вопросики, а ie как квадратики.

    Помогите избавиться от них. Заранее сенкс.

    Страница http://test.morozoff.info/search/ ввести допустим слово медиа.

    Сниппет:

    <?php
    // ######################################################
    // FlexSearchForm - modified by Stephan Dale 01/05/2006 #
    // ######################################################
    // -----------------------
    // Snippet: FlexSearchForm
    // -----------------------
    // Version: 0.6j
    // Date: 2005.02.01
    // [email protected]
    //
    // This snippet was designed to create a search form
    // that is highly flexible in how it is presented. It
    // can be used as both a small, subtle, persistent
    // search field element, as well as present the search
    // results. All elements are branded with classes
    // for easy CSS styling.
    // 
    // 2006.02.06 added extract functionality by Marc Hinse, [email protected]
    // some extract functionality credits go to Joomla Open Source CMS
    
    // 2006.05.01 Modified by Stephan Dale for http://mindSpill.net. Email: modx(a)mindspill.net
    // Set config, markup changes and altered form action to be relative to site root (i.e. begin with a forward slash).
    // Added access control, i.e. hide private documents if the user doesn't have permission to view them. This functionality uses code lifted from the MODx getDocumentObject method in document.parser.class.inc.php.
    // Added better support for weblinks.
    // &useWeblink - [ true | false ] If true and the doc is of type 'reference', link to the doc's weblink (it's 'content' field) rather than to the doc itself. Defaults to false.
    // &weblinkClass - [ string ] CSS class for a weblink's anchor. Defaults to "weblink".
    
    // 2007.02.07 Modified by Stephan Dale for http://mindSpill.net. Email: modx(a)mindspill.net
    // Minor mods to fix two problems where php complained about the PrepareSearchContent function either declared 
    // twice or missing. This was done by testing whether the function exists before declaring it and moving the 
    // declarations to the top of the file.
    
    // CONFIGURE
    
    // $useWeblink [ true | false ]
    // If true and the doc has type 'reference', link to doc's weblink rather than the doc itself.
    // Defaults to false.
    $useWeblink = (!isset($useWeblink)) ? false : ($useWeblink==true);
    
    // $weblinkClass [ string ]
    // CSS class for a weblink's anchor. Defaults to "weblink".
    $weblinkClass = (!isset($weblinkClass)) ? 'weblink' : "$weblinkClass";
    
      // MAIN SNIPPET SETUP OPTIONS
      // --------------------------
    
       // $searchStyle [ 'relevance' | 'partial' ]
       // This option allows you to decide to use a faster,
       // relevance sorted search ('relevance') which WILL NOT
       // inlclude partial matches. Or use a slower, but
       // more inclusive search ('partial') that will include
       // partial matches. Results will NOT be sorted based on
       // relevance.
       //
       // This option contributed by Rich from Snappy Graffix Media to 
       // allow partial matching and LIKE matching of the search term.
       // [email protected]
       $searchStyle = 'partial';
       
       // $useAllWords [ true | false ]
       // If you want only documents which contain ALL words in the 
       // search string, set to true. Otherwise, the search will return
       // all pages with ONE or more of the search words (which can be 
       // a LOT more pages).
       $useAllWords = true;
    
       // $showSearchWithResults [1 | 0]
       // If you would like to turn off the search
       // form when showing results you can set
       // this to false. Can also be set in template
       // by using the snippet variable: FSF_showForm
       // like this (1=true, 0=false):
       // [[FlexSearchForm?FSF_showForm=0]]
       $showSearchWithResults = 1;
    
       // $resultsPage [int]
       // The default behavior is to show the results on
       // the current page, but you may define the results
       // page any way you like. The priority is:
       //
       // 1- snippet variable - set in page template like this:
       //    [[FlexSearchForm?FSF_landing=int]]
       //    where int is the page id number of the page you want
       //    your results on
       // 2- querystring variable FSF_form
       // 3- variable set here
       // 4- use current page
       //
       // This is VERY handy when you want to put the search form in
       // a discrete and/or small place on your page- like a side
       // column, but don't want all your results to show up there!
       // Set to results page or leave 0 as default
       $resultsPage = 0;
    
       // $showResults [1 | 0] (as passed in snippet variable ONLY)
       // You can define whether this snippet will show the results
       // of the search with it. Do this by assigning the snippet
       // variable FSF_showResults as:
       // [[FlexSearchForm?FSF_showResults=0]]
       //
       // This is useful in situations where you want to show the
       // search results in a different place than the search form.
       // In that type of situation, you would include two of these
       // snippets on the same page, one showing results, and one
       // showing the form.
       //
       // Default is true.
    
       // $grabMax [ int ]   
       // Set to the max number of records you would like on
       // each page. Set to 0 if unlimited.
       $grabMax = 10;
    
       // $pageLinkSeparator [ string ]
       // What you want, if anything, between your page link numbers
       $pageLinkSeparator = " | ";
    
       // $stripHTML [ true | false ]
       // Allow HTML characters in the search? Probably not.
       $stripHTML = true;
    		
       // $stripSnip [ true | false ]
       // Strip out snippet calls etc from the search string?
       $stripSnip = true;
       
       // $stripSnippets [ true | false ]
       // Strip out snippet names so users will not be able to "search"
       // to see what snippets are used in your content. This is a 
       // security benefit, as users will not be able to search for what pages
       // use specific snippets.
       $stripSnippets = true;
       
       // $xhtmlStrict [ true | false ]
       // If you want this form to validate as XHTML Strict compliance, then
       // this needs to be true, but IE has a fieldset bug that I don't know
       // a workaround for. So you can set this to false to avoid it.
       $xhtmlStrict = false;
    
       // $minChars [ int ]
       // Minimum number of characters to require for a word to be valid for
       // searching. MySQL will typically NOT search for words with less than
       // 4 characters (relevance mode). If you have $useAllWords = true and
       // a three or fewer word appears in the search string, the results will
       // always be 0. Setting this drops those words from the search in THAT
       // CIRCUMSTANCE ONLY (relevance mode, useAllWords=true).
       $minChars = 4;
    
    
      // LANGUAGE AND LABELS
      // --------------------------
    
       // $resultsIntroFailure
       // If nothing is found for the search. You should give the user
       // some indication that the search was a failure.
       $resultsIntroFailure = 'К сожалению, по вашему запросу ничего не найдено. Пожалуйста, постарайтесь использовать более общие термины. Также попробуйте написать фразу строчными буквами или наоборот.';
    
       // $searchButtonText [string]
       // Label the search button what
       // you wish
       $searchButtonText = 'Искать';
       
       // $boxText [ string ]
       // What, if anything, you want to have in the search box when the
       // form first loads. When clicked, it will disappear. This uses 
       // JavaScript. If you don't want this feature or the JavaScript,
       // just set to empty string: ''
       $boxText = 'Поиск по сайту';
    
       // $introMessage [ string ]
       // This is the text that will show up if the person arrives
       // at the search page without having done a search first.
       // You can leave this as an empty string if you like.
       $introMessage = 'Введите фразу для поиска.';
       
       // $resultsFoundTextSingle, $resultsFoundTextMultiple [ string patttern ]
       // The string that will tell the user how many results were found.
       // two variables will be provided at runtime:
       // %d    The number of results found (integer)
       // %s    The search string itself.
       $resultsFoundTextSingle = '%d результат найден по запросу "%s".';
       $resultsFoundTextMultiple = '%d результатов найдено по запросу "%s".';
       
       // $paginationTextSinglePage and $paginationTextMultiplePages [ string ]
       // The text that comes before the links to other pages. In this
       // example, "Result pages: " was the $paginationTextMultiplePages:
       // Result pages: 1 | 2 | 3 | 4
       // Page numbers will only appear if there is more than one page.
       $paginationTextSinglePage = '';
       $paginationTextMultiplePages = 'Стр.: ';
       //$paginationTextSinglePage = '';
       //$paginationTextMultiplePages = 'Ergebnisseiten: ';
       
       // $extract [true|false]
       // show the search terms highlighted in a little extract (like Google)
       $extract=true;
    
    // Styles
    // These styles are included in this snippet:
    //
    // .FSF_form{}
    // .FSF_input {}
    // .FSF_submit {}
    //
    // .FSF_SearchResults {}
    // .FSF_resultsIntroFailure{}
    // .FSF_result {}
    // .FSF_resultLink {}
    // .FSF_resultDescription {}
    // .FSF_pagination
    // .FSF_intro
    // .FSF_extract
    // .FSF_highlight1, FSF_highlight2... the different styles (e.g. colors) for highlighting the search terms.
    
    // -------------
    // End configure
    // -------------
    
    if (!function_exists('PrepareSearchContent')) {
    	function PrepareSearchContent( $text, $length=200, $search ) {
    		// strips tags won't remove the actual jscript
    		$text = preg_replace( "'<script[^>]*>.*?</script>'si", "", $text );
    		$text = preg_replace( '/{.+?}/', '', $text);
    		//$text = preg_replace( '/<a\s+.*?href="([^"]+)"[^>]*>([^<]+)<\/a>/is','\2', $text );
    		// replace line breaking tags with whitespace
    		$text = preg_replace( "'<(br[^/>]*?/|hr[^/>]*?/|/(div|h[1-6]|li|p|td))>'si", ' ', $text );
    
    		return SmartSubstr( strip_tags( $text ), $length, $search );
    	}
    }
    
    /**
    * returns substring of characters around a searchword
    * @param string The source string
    * @param int Number of chars to return
    * @param string The searchword to select around
    * @return string
    */
    if (!function_exists('SmartSubstr')) {
    	function SmartSubstr($text, $length=200, $search) {
    	  $wordpos = strpos(strtolower($text), strtolower($search));
    	  $halfside = intval($wordpos - $length/2 - strlen($search));
    	  if ($wordpos && $halfside > 0) {
    		return '...' . substr($text, $halfside, $length) . '...';
    	  } else {
    		return substr( $text, 0, $length);
    	  }
    	}
    }
    
    // establish whether to show the form or not
    $showSearchWithResults = (isset($FSF_showForm))? $FSF_showForm : $showSearchWithResults;
    
    // establish whether to show the results or not
    $showResults = (isset($FSF_showResults))? $FSF_showResults : true;
    
    // establish results page
    if (isset($FSF_landing)){ // set in snippet
      $searchAction = "[~".$FSF_landing."~]";
    } elseif ($resultsPage > 0){ // locally set
      $searchAction = "[~".$resultsPage."~]";
    }  else { //otherwise
      $searchAction = "[~".$modx->documentIdentifier."~]";
    }
    
    // Set newline variable
    $newline = "\n";
    
    // Initialize search string
    $searchString = '';
    
    // CLEAN SEARCH STRING
    if ( isset($_POST['search']) || isset($_GET['FSF_search']) ){
      // Prefer post to get
      $searchString = (isset($_POST['search']))? $_POST['search'] : urldecode($_GET['FSF_search']) ;
      // block sensitive search patterns
      $searchString =
      (
      $searchString != "{{" &&
      $searchString != "[[" &&
      $searchString != "[!" &&
      $searchString != "[(" &&
      $searchString != "[~" &&
      $searchString != "[*" 
      )
      ?
      $searchString : "" ;
    
      // Remove dangerous tags and such
    
      // Strip HTML too
      if ($stripHTML){
        $searchString = strip_tags($searchString);
      }
    
      // Regular expressions of things to remove from search string
      $modRegExArray[] = '~\[\[(.*?)\]\]~';   // [[snippets]]
      $modRegExArray[] = '~\[!(.*?)!\]~';     // [!noCacheSnippets!]
      $modRegExArray[] = '!\[\~(.*?)\~\]!is'; // [~links~]
      $modRegExArray[] = '~\[\((.*?)\)\]~';   // [(settings)]
      $modRegExArray[] = '~{{(.*?)}}~';       // {{chunks}}
      $modRegExArray[] = '~\[\*(.*?)\*\]~';   // [*attributes*]
      
      // Remove modx sensitive tags
      if ($stripSnip){
        foreach ($modRegExArray as $mReg){
          $searchString = preg_replace($mReg,'',$searchString);
        }
      }
    
      // Remove snippet names
      if ($stripSnippets && $searchString != ''){
        // get all the snippet names
        $tbl = $modx->dbConfig['dbase'] . "." . $modx->dbConfig['table_prefix'] . "site_snippets";
        $snippetSql = "SELECT $tbl.name FROM $tbl;";
        $snippetRs = $modx->dbQuery($snippetSql);
        $snippetCount = $modx->recordCount($snippetRs);
        $snippetNameArray = array();
        for ($s = 0; $s < $snippetCount; $s++){
          $thisSnippetRow = $modx->fetchRow($snippetRs);
          $snippetNameArray[] = strtolower($thisSnippetRow['name']);
        }
        // Split search into strings
        $searchWords = explode(' ',$searchString);
        $cleansedWords = '';
        foreach($searchWords as $word){
          if ($word != '' && 
              !in_array(strtolower($word),$snippetNameArray) &&
                ((!$useAllWords) ||
                ($searchStyle == 'partial') ||
                (strlen($word) >= $minChars && $useAllWords && $searchStyle == 'relevance'))
             ){
            $cleansedWords .= $word.' ';
          }
        }
        // Remove last space
        $cleansedWords = substr($cleansedWords,0,(strlen($cleansedWords)-1));
        
        $searchString = $cleansedWords;
      }
    
    } // End cleansing search string
    
    // check querystring
    $validSearch = ($searchString != '')? true : false ;
    
    //check for offset
    $offset = (isset($_GET['FSF_offset']))? $_GET['FSF_offset'] : 0;
    
    // initialize output
    $SearchForm = '';
    
    // establish form
    if (($validSearch && ($showSearchWithResults)) || $showSearchWithResults){
      $SearchForm .= '<form class="FSF_form" action="'.$searchAction.'" method="post"><div class="search-block"><div class="searchblock">';
      $SearchForm .= ($xhtmlStrict)? '<fieldset><legend>Search</legend>' : '' ;
      // decide what goes in search box
      $searchBoxVal = ($searchString == '' && $boxText != '')? $boxText : $searchString ;
      $SearchForm .= '<label for="sinp" class="inp"><input id="sinp" type="text" name="search" /></label>';
      $SearchForm .= '<input class="btn" type="image" name="sub" src="/assets/images/btnGo.gif" value="'.$searchButtonText.'" title="'.$searchButtonText.'" />';
      $SearchForm .= ($xhtmlStrict)? '</fieldset>' : '';
      $SearchForm .= '</div></div></form>'.$newline;
    }
    
    if ($showResults) {
      if($validSearch) {
        $search = explode(" ", $searchString);
        $tblsc = $modx->getFullTableName("site_content");
        $tbldg = $modx->getFullTableName("document_groups");
    
        // Get document groups for current user and write sql for document access control.
        if($docgrp = $modx->getUserDocGroups()) $docgrp = implode(",",$docgrp);
        $access = ($modx->isFrontend() ? "sc.privateweb=0":"1='".$_SESSION['mgrRole']."' OR sc.privatemgr=0").
    		  (!$docgrp ? "":" OR dg.document_group IN ($docgrp)");
    
        if ($searchStyle == 'partial'){
          $sql = "SELECT sc.id, sc.pagetitle, sc.description, sc.content, sc.type "; // Added type so can later determine whether a resource is a weblink (aka reference) or not.
          $sql .= "FROM $tblsc sc
    		LEFT JOIN $tbldg dg ON dg.document = sc.id
    		WHERE ";
          if (count($search)>1 && $useAllWords){
            foreach ($search as $searchTerm){
              $sql .= "(sc.pagetitle LIKE '%$searchString%' OR sc.description LIKE '%$searchString%' OR sc.content LIKE '%$searchTerm%') AND ";
            }
          } else {
            $sql .= "(sc.pagetitle LIKE '%$searchString%' OR sc.description LIKE '%$searchString%' OR sc.content LIKE '%$searchString%') AND ";
          }
          $sql .= "sc.published = 1 AND sc.searchable=1 AND sc.deleted=0";
        } else {
          $sql = "SELECT sc.id, sc.pagetitle, sc.description, sc.content, sc.type "; // Added type so can later determine whether a resource is a weblink (aka reference) or not.
          $sql .= "FROM $tblsc sc
    		LEFT JOIN $tbldg dg ON dg.document = sc.id
    		WHERE ";
          if (count($search)>1 && $useAllWords){
            foreach ($search as $searchTerm){
              $sql .= "MATCH (sc.pagetitle, sc.description, sc.content) AGAINST ('$searchTerm') AND ";
            }
          } else {
            $sql .= "MATCH (sc.pagetitle, sc.description, sc.content) AGAINST ('$searchString') AND ";
          }
          $sql .= "sc.published = 1 AND sc.searchable=1 AND sc.deleted=0";
        }
    
        $sql .= " AND ($access)"; // Add access control to sql.
    
        $rs = $modx->dbQuery($sql);
        $limit = $modx->recordCount($rs);
    
        if($limit>0) {
          $SearchForm .= '<div class="FSF_searchResults">'.$newline;
    
          // pagination
          if ($grabMax > 0){
            $numResultPages = ceil($limit/$grabMax);
            $resultPageLinks = '<span class="FSF_pages">';
            $resultPageLinks .= ($limit>$grabMax)? $paginationTextMultiplePages : $paginationTextSinglePage ;
            $resultPageLinkNumber = 1;
            for ($nrp=0;$nrp<$limit && $limit > $grabMax;$nrp+=$grabMax){
              if($offset == ($resultPageLinkNumber-1)*$grabMax){
                $resultPageLinks .= $resultPageLinkNumber;
              } else {
                $resultPageLinks .= '<a href="[~' . $modx->documentObject['id'] . '~]&FSF_offset=' . $nrp . '&FSF_search=' . urlencode($searchString) . '">' . $resultPageLinkNumber . '</a>';
              }
              $resultPageLinks .= ($nrp+$grabMax < $limit)? $pageLinkSeparator : '' ;
              $resultPageLinkNumber++;
            }
            $resultPageLinks .= "</span>".$newline;
            $SearchForm .= '<p class="FSF_pagination">';
            $resultsFoundText = ($limit > 1)? $resultsFoundTextMultiple : $resultsFoundTextSingle ;
            if ($extract) {
            $hits=1;
            $searchwords='';
            foreach ($search as $words) {
            $searchwords.='<span class="FSF_highlight'.$hits.'">'.$words.'</span> ';
            $hits++;
            }
            $SearchForm .= sprintf($resultsFoundText,$limit,$searchwords);
            } else {
            $SearchForm .= sprintf($resultsFoundText,$limit,$searchString);
            }
            $SearchForm .= '<br />'.$resultPageLinks."</p>".$newline;
          } // end if grabMax
    
          // search results
          $useLimit = ($grabMax > 0)? $offset+$grabMax : $limit;
          for ($y = $offset; ($y < $useLimit) && ($y<$limit); $y++) {
            $moveToRow = mysql_data_seek($rs,$y);
            $SearchFormsrc=$modx->fetchRow($rs);
            if ($extract) {
            $text=$SearchFormsrc['content'];
            if (count($search)>1){
            $count=1;
            $summary='';
               foreach ($search as $searchTerm){
               $summary .= PrepareSearchContent( $text, $length=200, $searchTerm );
               $summary = preg_replace( '/' . preg_quote( $searchTerm, '/' ) . '/i', '<span class="FSF_highlight'.$count.'">\0</span>', $summary );
               $count++;
               }
               $text=$summary;
            } else {
              $search=$searchString;
              $text=PrepareSearchContent( $text, $length=200, $search );
              $text = preg_replace( '/' . preg_quote( $searchString, '/' ) . '/i', '<span class="FSF_highlight1">\0</span>', $text );
              }
            }
            $SearchForm.='<div class="FSF_result">'.$newline;
    		
    	// Handle weblinks.
    	$theLink = '[~'.$SearchFormsrc['id'].'~]';
    	$linkClass = "";
    	if (($SearchFormsrc['type']=='reference') && $useWeblink) {
    		$theLink = $SearchFormsrc['content']; // Get the weblink content, which should be the URL that the link points to
    		$linkClass = $weblinkClass; // Set the css class.
    	}
    
            $SearchForm.='<h3><a class="FSF_resultLink '.$linkClass.'" href="'.$theLink.'" title="' . $SearchFormsrc['pagetitle'] . '">' . $SearchFormsrc['pagetitle'] . "</a></h3>".$newline;
            $SearchForm.='<div class="FSF_extract"> '. $text . ' </div>'.$newline;
            $SearchForm.='</div><!--end FlexSearchResult-->'.$newline;
          }
          $SearchForm.='<p class="FSF_pagination">'.$resultPageLinks.'</p>';
          $SearchForm.='</div><!--end FlexSearchResults-->'.$newline;
        } else {
          $SearchForm.='<p class="FSF_resultsIntroFailure">'.$resultsIntroFailure.'</p>';
        } // end if records found
    
      } else if (!$validSearch && isset($_POST['sub'])) {
    
        // message to show if search was performed but for something invalid
        $SearchForm .= '<p class="FSF_resultsIntroFailure">'.$resultsIntroFailure.'</p>';
        
      } else { // end if validSearch
    
        $SearchForm .= '<p class="FSF_intro">'.$introMessage.'</p>';
    
      } // end if not validSearch
    } // end if showResults
    
    return $SearchForm;
    ?>
      • 33694
      • 742 Posts
      Известная проблема.
      В сниппете нужно использовать мультибайнтые фукции (функции для работы с мультибайтныи строками; начинаются на mb_) вместо обычных. Тогда всё обрезаться будет правильно. Т.е. нужно переписывать всё.

      И судя по версии указанной в начале кода, сниппет у вас уж очень древний. Не так давно (по меркам вселенной) он уже обновлялся. У меня например:
      // Version: 2r4
      // Date: 2007.01.03
      // Release: 2007.01.03
        • 31213
        • 153 Posts
        Проблема состоит в том, что PHP < 6 версии не имеет встроенной поддержки Unicode, из-за особенностей этой кодировки. Поэтому некоторые из встроенных функций по работе со строками, в данном случае, substr работают не правильно. Надо использовать (как правильно сказал) [e]Bu$ter функции обработки мультибайтных строк, однако проблема их использования может также заключаться в остсутствии данного модуля у хостера (можно правда подключить с помощью dl(), если разрешено). Также можно для внутренних операций перекодировать UTF-8 в другие кодировки, а потом выводить опять UTF-8.

        Лично я использую немного подправленный FlexSearch:
        // -----------------------
        // Snippet: FlexSearchForm
        // -----------------------
        // Version: 0.6j
        // Date: 2005.02.01
        // [email protected]
        //
        // This snippet was designed to create a search form
        // that is highly flexible in how it is presented. It
        // can be used as both a small, subtle, persistent
        // search field element, as well as present the search
        // results. All elements are branded with classes
        // for easy CSS styling.
        
        // CONFIGURE
        
          // MAIN SNIPPET SETUP OPTIONS
          // --------------------------
        
           // $searchStyle [ 'relevance' | 'partial' ]
           // This option allows you to decide to use a faster,
           // relevance sorted search ('relevance') which WILL NOT
           // inlclude partial matches. Or use a slower, but
           // more inclusive search ('partial') that will include
           // partial matches. Results will NOT be sorted based on
           // relevance.
           //
           // This option contributed by Rich from Snappy Graffix Media to 
           // allow partial matching and LIKE matching of the search term.
           // [email protected]
           $searchStyle = 'partial';
           
           // $useAllWords [ true | false ]
           // If you want only documents which contain ALL words in the 
           // search string, set to true. Otherwise, the search will return
           // all pages with ONE or more of the search words (which can be 
           // a LOT more pages).
           $useAllWords = true;
        
           // $showSearchWithResults [1 | 0]
           // If you would like to turn off the search
           // form when showing results you can set
           // this to false. Can also be set in template
           // by using the snippet variable: FSF_showForm
           // like this (1=true, 0=false):
           // [[FlexSearchForm?FSF_showForm=0]]
           $showSearchWithResults = 1;
        
           // $resultsPage [int]
           // The default behavior is to show the results on
           // the current page, but you may define the results
           // page any way you like. The priority is:
           //
           // 1- snippet variable - set in page template like this:
           //    [[FlexSearchForm?FSF_landing=int]]
           //    where int is the page id number of the page you want
           //    your results on
           // 2- querystring variable FSF_form
           // 3- variable set here
           // 4- use current page
           //
           // This is VERY handy when you want to put the search form in
           // a discrete and/or small place on your page- like a side
           // column, but don't want all your results to show up there!
           // Set to results page or leave 0 as default
           $resultsPage = 0;
        
           // $showResults [1 | 0] (as passed in snippet variable ONLY)
           // You can define whether this snippet will show the results
           // of the search with it. Do this by assigning the snippet
           // variable FSF_showResults as:
           // [[FlexSearchForm?FSF_showResults=0]]
           //
           // This is useful in situations where you want to show the
           // search results in a different place than the search form.
           // In that type of situation, you would include two of these
           // snippets on the same page, one showing results, and one
           // showing the form.
           //
           // Default is true.
        
           // $grabMax [ int ]   
           // Set to the max number of records you would like on
           // each page. Set to 0 if unlimited.
           $grabMax = 10;
        
           // $pageLinkSeparator [ string ]
           // What you want, if anything, between your page link numbers
           $pageLinkSeparator = "";
        
           // $stripHTML [ true | false ]
           // Allow HTML characters in the search? Probably not.
           $stripHTML = true;
        		
           // $stripSnip [ true | false ]
           // Strip out snippet calls etc from the search string?
           $stripSnip = true;
           
           // $stripSnippets [ true | false ]
           // Strip out snippet names so users will not be able to "search"
           // to see what snippets are used in your content. This is a 
           // security benefit, as users will not be able to search for what pages
           // use specific snippets.
           $stripSnippets = true;
           
           // $xhtmlStrict [ true | false ]
           // If you want this form to validate as XHTML Strict compliance, then
           // this needs to be true, but IE has a fieldset bug that I don't know
           // a workaround for. So you can set this to false to avoid it.
           $xhtmlStrict = false;
        
           // $minChars [ int ]
           // Minimum number of characters to require for a word to be valid for
           // searching. MySQL will typically NOT search for words with less than
           // 4 characters (relevance mode). If you have $useAllWords = true and
           // a three or fewer word appears in the search string, the results will
           // always be 0. Setting this drops those words from the search in THAT
           // CIRCUMSTANCE ONLY (relevance mode, useAllWords=true).
           $minChars = 4;
        
        
          // LANGUAGE AND LABELS
          // --------------------------
        
           // $resultsIntroFailure
           // If nothing is found for the search. You should give the user
           // some indication that the search was a failure.
           $resultsIntroFailure = 'Увы. Поиск не дал результатов.';
        
           // $searchButtonText [string]
           // Label the search button what
           // you wish
           $searchButtonText = 'Искать';
           
           // $boxText [ string ]
           // What, if anything, you want to have in the search box when the
           // form first loads. When clicked, it will disappear. This uses 
           // JavaScript. If you don't want this feature or the JavaScript,
           // just set to empty string: ''
           $boxText = 'поиск...';
        
           // $introMessage [ string ]
           // This is the text that will show up if the person arrives
           // at the search page without having done a search first.
           // You can leave this as an empty string if you like.
           $introMessage = 'Пожалуйста, введите строку для поиска';   
           
           $minSymbols = 'Количество символов строки поиска не должно быть меньше четырех';
           
           // $resultsFoundTextSingle, $resultsFoundTextMultiple [ string patttern ]
           // The string that will tell the user how many results were found.
           // two variables will be provided at runtime:
           // %d    The number of results found (integer)
           // %s    The search string itself.
           $resultsFoundTextSingle = 'Найдено одно соответствие: ';
           $resultsFoundTextMultiple = 'Найдено соответствий: %d';
           
           // $paginationTextSinglePage and $paginationTextMultiplePages [ string ]
           // The text that comes before the links to other pages. In this
           // example, "Result pages: " was the $paginationTextMultiplePages:
           // Result pages: 1 | 2 | 3 | 4
           // Page numbers will only appear if there is more than one page.
           $paginationTextSinglePage = '';
           $paginationTextMultiplePages = 'Страницы: ';
        
        // Styles
        // These styles are included in this snippet:
        //
        // .FSF_form{}
        // .FSF_input {}
        // .FSF_submit {}
        //
        // .FSF_SearchResults {}
        // .FSF_resultsIntroFailure{}
        // .FSF_result {}
        // .FSF_resultLink {}
        // .FSF_resultDescription {}
        // .FSF_pagination
        // .FSF_intro
        
        // -------------
        // End configure
        // -------------
        
        // establish whether to show the form or not
        $showSearchWithResults = (isset($FSF_showForm))? $FSF_showForm : $showSearchWithResults;
        
        // establish whether to show the results or not
        $showResults = (isset($FSF_showResults))? $FSF_showResults : true;
        
        // establish results page
        if (isset($FSF_landing)){ // set in snippet
          $searchAction = "[~".$FSF_landing."~]";
        } elseif ($resultsPage > 0){ // locally set
          $searchAction = "[~".$resultsPage."~]";
        }  else { //otherwise
          $searchAction = "[~".$modx->documentIdentifier."~]";
        }
        
        // Set newline variable
        $newline = "\n";
        
        // Initialize search string
        $searchString = '';
        
        $temp = $_POST['search'];
        if (strlen($temp)>3) 
        {
        	$minimumSymbols = true;
        }
        else 
        {
        	$minimumSymbols = false;
        }
        
        // CLEAN SEARCH STRING
        if ($minimumSymbols){
          // Prefer post to get
          $searchString = (isset($_POST['search']))? $_POST['search'] : urldecode($_GET['FSF_search']) ;
          // block sensitive search patterns
          $searchString =
          (
          $searchString != "{{" &&
          $searchString != "[[" &&
          $searchString != "[!" &&
          $searchString != "[(" &&
          $searchString != "[~" &&
          $searchString != "[*" 
          )
          ?
          $searchString : "" ;
        
          // Remove dangerous tags and such
        
          // Strip HTML too
          if ($stripHTML){
            $searchString = strip_tags($searchString);
          }
        
          // Regular expressions of things to remove from search string
          $modRegExArray[] = '~\[\[(.*?)\]\]~';   // [[snippets]]
          $modRegExArray[] = '~\[!(.*?)!\]~';     // [!noCacheSnippets!]
          $modRegExArray[] = '!\[\~(.*?)\~\]!is'; // [~links~]
          $modRegExArray[] = '~\[\((.*?)\)\]~';   // [(settings)]
          $modRegExArray[] = '~{{(.*?)}}~';       // {{chunks}}
          $modRegExArray[] = '~\[\*(.*?)\*\]~';   // [*attributes*]
          
          // Remove modx sensitive tags
          if ($stripSnip){
            foreach ($modRegExArray as $mReg){
              $searchString = preg_replace($mReg,'',$searchString);
            }
          }
        
          // Remove snippet names
          if ($stripSnippets && $searchString != ''){
            // get all the snippet names
            $tbl = $modx->dbConfig['dbase'] . "." . $modx->dbConfig['table_prefix'] . "site_snippets";
            $snippetSql = "SELECT $tbl.name FROM $tbl;";
            $snippetRs = $modx->dbQuery($snippetSql);
            $snippetCount = $modx->recordCount($snippetRs);
            $snippetNameArray = array();
            for ($s = 0; $s < $snippetCount; $s++){
              $thisSnippetRow = $modx->fetchRow($snippetRs);
              $snippetNameArray[] = strtolower($thisSnippetRow['name']);
            }
            // Split search into strings
            $searchWords = explode(' ',$searchString);
            $cleansedWords = '';
            foreach($searchWords as $word){
              if ($word != '' && 
                  !in_array(strtolower($word),$snippetNameArray) &&
                    ((!$useAllWords) ||
                    ($searchStyle == 'partial') ||
                    (strlen($word) >= $minChars && $useAllWords && $searchStyle == 'relevance'))
                 ){
                $cleansedWords .= $word.' ';
              }
            }
            // Remove last space
            $cleansedWords = substr($cleansedWords,0,(strlen($cleansedWords)-1));
            
            $searchString = $cleansedWords;
          }
        
        } // End cleansing search string
        
        // check querystring
        $validSearch = ($searchString != '')? true : false ;
        
        //check for offset
        $offset = (isset($_GET['FSF_offset']))? $_GET['FSF_offset'] : 0;
        
        // initialize output
        $SearchForm = '';
        
        // establish form
        if (($validSearch && ($showSearchWithResults)) || $showSearchWithResults){
          $SearchForm .= '<form class="FSF_form" action="'.$searchAction.'" method="post">';
          $SearchForm .= ($xhtmlStrict)? '<fieldset><legend>Search</legend>' : '' ;
          // decide what goes in search box
          $searchBoxVal = ($searchString == '' && $boxText != '')? $boxText : $searchString ;
          $SearchForm .= '<input class="FSF_input" type="text" name="search" value="'.$searchBoxVal.'"  ';
          $SearchForm .= ($boxText)? 'onfocus="this.value=(this.value==\''.$boxText.'\')? \'\' : this.value ;" />' : '/>';
          $SearchForm .= '<input class="FSF_submit" type="submit" name="sub" value="'.$searchButtonText.'" />';
          $SearchForm .= ($xhtmlStrict)? '</fieldset>' : '';
          $SearchForm .= '</form>'.$newline;
        }
        
        if ($showResults) {
          if($validSearch) {
            $search = explode(" ", $searchString);
            $tbl = $modx->dbConfig['dbase'] . "." . $modx->dbConfig['table_prefix'] . "site_content";
        
            if ($searchStyle == 'partial'){
              $sql = "SELECT id, pagetitle, description ";
              $sql .= "FROM $tbl ";
              $sql .= "WHERE ";
              if (count($search)>1 && $useAllWords){
                foreach ($search as $searchTerm){
                  $sql .= "(pagetitle LIKE '%$searchString%' OR description LIKE '%$searchString%' OR content LIKE '%$searchTerm%') AND ";
                }
              } else {
                $sql .= "(pagetitle LIKE '%$searchString%' OR description LIKE '%$searchString%' OR content LIKE '%$searchString%') AND ";
              }
              $sql .= "$tbl.published = 1 AND $tbl.searchable=1 AND $tbl.deleted=0;";
            } else {
              $sql = "SELECT id, pagetitle, description ";
              $sql .= "FROM $tbl WHERE ";
              if (count($search)>1 && $useAllWords){
                foreach ($search as $searchTerm){
                  $sql .= "MATCH (pagetitle, description, content) AGAINST ('$searchTerm') AND ";
                }
              } else {
                $sql .= "MATCH (pagetitle, description, content) AGAINST ('$searchString') AND ";
              }
              $sql .= "$tbl.published = 1 AND $tbl.searchable=1 AND $tbl.deleted=0;";
            }
        
            $rs = $modx->dbQuery($sql);
            $limit = $modx->recordCount($rs);
        
            if($limit>0) {
              $SearchForm .= '<div class="FSF_searchResults">'.$newline;
        
              // pagination
              if ($grabMax > 0){
                $numResultPages = ceil($limit/$grabMax);
                $resultPageLinks = '<span class="FSF_pages">';
                $resultPageLinks .= ($limit>$grabMax)? $paginationTextMultiplePages : $paginationTextSinglePage ;
                $resultPageLinkNumber = 1;
                for ($nrp=0;$nrp<$limit && $limit > $grabMax;$nrp+=$grabMax){
                  if($offset == ($resultPageLinkNumber-1)*$grabMax){
                    $resultPageLinks .= '<span id="active">' . $resultPageLinkNumber . '</span>';
                  } else {
                    $resultPageLinks .= '<span class="passive"><a href="[~' . $modx->documentObject['id'] . '~]&FSF_offset=' . $nrp . '&FSF_search=' . urlencode($searchString) . '">' . $resultPageLinkNumber . '</a></span>';
                  }
                  $resultPageLinks .= ($nrp+$grabMax < $limit)? $pageLinkSeparator : '' ;
                  $resultPageLinkNumber++;
                }
                $resultPageLinks .= "</span>".$newline;
                $SearchForm .= '<span class="FSF_pagination">';
                $resultsFoundText = ($limit > 1)? $resultsFoundTextMultiple : $resultsFoundTextSingle ;
                $SearchForm .= sprintf($resultsFoundText,$limit,$searchString);
                $SearchForm .= "</span>".$newline;
              } // end if grabMax
        
              // search results
              $useLimit = ($grabMax > 0)? $offset+$grabMax : $limit;
              for ($y = $offset; ($y < $useLimit) && ($y<$limit); $y++) {
                $moveToRow = mysql_data_seek($rs,$y);
                $SearchFormsrc=$modx->fetchRow($rs);
                $SearchForm.='<div class="FSF_result">'.$newline;
                $SearchForm.='<a class="FSF_resultLink" href="[~'.$SearchFormsrc['id'].'~]" title="' . $SearchFormsrc['pagetitle'] . '">' . $SearchFormsrc['pagetitle'] . "</a>".$newline;
                $SearchForm.=$SearchFormsrc['description']!='' ? '<span class="FSF_resultDescription">' . $SearchFormsrc['description'] . "</span>".$newline : "" ;
                $SearchForm.='</div><!--end FlexSearchResult-->'.$newline;
              }
              $SearchForm.='<p class="FSF_pagination">'.$resultPageLinks.'</p>';
              $SearchForm.='</div><!--end FlexSearchResults-->'.$newline;
            } else {
              $SearchForm.='<p class="FSF_resultsIntroFailure">'.$resultsIntroFailure.'</p>';
            } // end if records found
        
          } else if (!$minimumSymbols) {
            	
        	$SearchForm .= '<p class="FSF_intro">'.$minSymbols.'</p>';
        	      
          } else if (!$validSearch && isset($_POST['sub'])) {
        
            // message to show if search was performed but for something invalid
            $SearchForm .= '<p class="FSF_resultsIntroFailure">'.$resultsIntroFailure.'</p>';
          
          } else { // end if validSearch
        
            $SearchForm .= '<p class="FSF_intro">'.$introMessage.'</p>';
        
          } // end if not validSearch
        } // end if showResults
        
        return $SearchForm;
        
          • 33694
          • 742 Posts
          Лично я использую немного подправленный FlexSearch: ...
          А что именно в нём подправлено, не расскажете? А то может многим полезно будет, но желание в слепую сравнивать исходники думаю мало у кого возникнет.

          И я так понимаю, за базу у вас взят всё тот же {// Version: 0.6j // Date: 2005.02.01}. Почему он?
            • 31213
            • 153 Posts
            Подправлена самая малость:
            1. Нельзя искать меньше, четырех символов
            2. Отсутствует вывод куска документа, есть только ссылка на документ.

            Использую то, что работает, а оно обеспечивает тот минимум функциональности, который мне необходим )) Я использую только два сниппета сторонних разработчиков - это WebLogin и FlexSearch, все остальное пишу сам.
              • 20246
              • 33 Posts
              Ну вот я уже поставил hyperflexsearch.

              Проблему с поиском русским решил с помощью mb_. Единственное что hyperstabilo осталось заставить не обращать внимание на регистр. Тогда великолепно будет работать.
                • 27168
                • 23 Posts
                сообщение удалено.

                причина: неверная кодировка сообщения.

                подробности в пункте 1
                  • 25463
                  • 61 Posts
                  Добрый день !
                  Скажите пожалуйста, а каким образом этот скрипт поиска поведет себя, если количество документов в системе будет насчитывать несколько тысяч? а также если документы будут иметь контент большого размера ? Все-таки приходится выполнять с помощью SQL-выражений выполнять поиск подстрок в строках.
                  Сервер MySQL это сможет переварить ?
                    • 19164
                    • 1,215 Posts
                    Вы лучше подумайте, как все остальное поведет себя при таком количестве документов, а не поиск. Эта тема обсуждалась в других ветках - эта версия движка не расчитана на такое количество документов в дереве.
                      DirectResize 0.9 beta. PHPThumb, sets of configurations, configuration, binded to specific path. No backward compatibility. | DirectResize 0.9. PHPThumb, наборы параметров, параметры, привязанные к определенным путям. Без обратной совместимости.

                      Unfortunately, DirectResize project is closed. If you want to continue development, PM me for access to project page on Google Code. К сожалению, проект DirectResize закрыт. Если вы желаете продолжить разработки, обращайтесь через ПМ для получения доступа к репозиторию на Google Code.

                      [PLUGIN] DirectResize - as Maxigallery but for single images :: Download :: [url=http://modxcms.com/forums/index.php/topic,21490]
                      • 25463
                      • 61 Posts
                      Как мне видится, проблема может возникнуть с отображением разделов в дереве, расположенном слева в админке.
                      Я в свое время баловался с созданием собственной CMS, у нее была также древовидная структура, напоминающая структуру MODx.
                      Сайт на ней - www.taganrog.orthodoxy.ru - там сейчас несколько тысяч документов, проблем со скоростью нет.