core-bundle/src/Resources/contao/library/Contao/Search.php
public static function indexPage($arrData)
	{
		$objDatabase = Database::getInstance();

		$arrSet['tstamp'] = time();
		$arrSet['url'] = $arrData['url'];
		$arrSet['title'] = $arrData['title'];
		$arrSet['protected'] = $arrData['protected'];
		$arrSet['filesize'] = $arrData['filesize'];
		$arrSet['groups'] = $arrData['groups'];
		$arrSet['pid'] = $arrData['pid'];
		$arrSet['language'] = $arrData['language'];

		// Get the file size from the raw content
		if (!$arrSet['filesize'])
		{
			$arrSet['filesize'] = number_format((\strlen($arrData['content']) / 1024), 2, '.', '');
		}

		// Replace special characters
		$strContent = str_replace(array("\n", "\r", "\t", '&#160;', '&nbsp;', '&shy;'), array(' ', ' ', ' ', ' ', ' ', ''), $arrData['content']);

		// Strip script tags
		while (($intStart = strpos($strContent, '<script')) !== false)
		{
			if (($intEnd = strpos($strContent, '</script>', $intStart)) !== false)
			{
				$strContent = substr($strContent, 0, $intStart) . substr($strContent, $intEnd + 9);
			}
			else
			{
				break; // see #5119
			}
		}

		// Strip style tags
		while (($intStart = strpos($strContent, '<style')) !== false)
		{
			if (($intEnd = strpos($strContent, '</style>', $intStart)) !== false)
			{
				$strContent = substr($strContent, 0, $intStart) . substr($strContent, $intEnd + 8);
			}
			else
			{
				break; // see #5119
			}
		}

		// Strip non-indexable areas
		while (($intStart = strpos($strContent, '<!-- indexer::stop -->')) !== false)
		{
			if (($intEnd = strpos($strContent, '<!-- indexer::continue -->', $intStart)) !== false)
			{
				$intCurrent = $intStart;

				// Handle nested tags
				while (($intNested = strpos($strContent, '<!-- indexer::stop -->', $intCurrent + 22)) !== false && $intNested < $intEnd)
				{
					if (($intNewEnd = strpos($strContent, '<!-- indexer::continue -->', $intEnd + 26)) !== false)
					{
						$intEnd = $intNewEnd;
						$intCurrent = $intNested;
					}
					else
					{
						break; // see #5119
					}
				}

				$strContent = substr($strContent, 0, $intStart) . substr($strContent, $intEnd + 26);
			}
			else
			{
				break; // see #5119
			}
		}

		// HOOK: add custom logic
		if (isset($GLOBALS['TL_HOOKS']['indexPage']) && \is_array($GLOBALS['TL_HOOKS']['indexPage']))
		{
			foreach ($GLOBALS['TL_HOOKS']['indexPage'] as $callback)
			{
				System::importStatic($callback[0])->{$callback[1]}($strContent, $arrData, $arrSet);
			}
		}

		// Free the memory
		unset($arrData['content']);

		$arrMatches = array();
		preg_match('/<\/head>/', $strContent, $arrMatches, PREG_OFFSET_CAPTURE);
		$intOffset = \strlen($arrMatches[0][0]) + $arrMatches[0][1];

		// Split page in head and body section
		$strHead = substr($strContent, 0, $intOffset);
		$strBody = substr($strContent, $intOffset);

		unset($strContent);

		$tags = array();

		// Get the description
		if (preg_match('/<meta[^>]+name="description"[^>]+content="([^"]*)"[^>]*>/i', $strHead, $tags))
		{
			$arrData['description'] = trim(preg_replace('/ +/', ' ', StringUtil::decodeEntities($tags[1])));
		}

		// Get the keywords
		if (preg_match('/<meta[^>]+name="keywords"[^>]+content="([^"]*)"[^>]*>/i', $strHead, $tags))
		{
			$arrData['keywords'] = trim(preg_replace('/ +/', ' ', StringUtil::decodeEntities($tags[1])));
		}

		// Read the title and alt attributes
		if (preg_match_all('/<* (title|alt)="([^"]*)"[^>]*>/i', $strBody, $tags))
		{
			$arrData['keywords'] .= ' ' . implode(', ', array_unique($tags[2]));
		}

		// Add a whitespace character before line-breaks and between consecutive tags (see #5363)
		$strBody = str_ireplace(array('<br', '><'), array(' <br', '> <'), $strBody);
		$strBody = strip_tags($strBody);

		// Put everything together
		$arrSet['text'] = $arrData['title'] . ' ' . $arrData['description'] . ' ' . $strBody . ' ' . $arrData['keywords'];
		$arrSet['text'] = trim(preg_replace('/ +/', ' ', StringUtil::decodeEntities($arrSet['text'])));

		// Calculate the checksum
		$arrSet['checksum'] = md5($arrSet['text']);

		$objIndex = $objDatabase->prepare("SELECT id, url FROM tl_search WHERE checksum=? AND pid=?")
								->limit(1)
								->execute($arrSet['checksum'], $arrSet['pid']);

		// Update the URL if the new URL is shorter or the current URL is not canonical
		if ($objIndex->numRows && $objIndex->url != $arrSet['url'])
		{
			if (strpos($arrSet['url'], '?') === false && strpos($objIndex->url, '?') !== false)
			{
				// The new URL is more canonical (no query string)
				$objDatabase->prepare("DELETE FROM tl_search WHERE id=?")
							->execute($objIndex->id);

				$objDatabase->prepare("DELETE FROM tl_search_index WHERE pid=?")
							->execute($objIndex->id);
			}
			elseif (substr_count($arrSet['url'], '/') > substr_count($objIndex->url, '/') || (strpos($arrSet['url'], '?') !== false && strpos($objIndex->url, '?') === false) || \strlen($arrSet['url']) > \strlen($objIndex->url))
			{
				// The current URL is more canonical (shorter and/or less fragments)
				$arrSet['url'] = $objIndex->url;
			}
			else
			{
				// The same page has been indexed under a different URL already (see #8460)
				return false;
			}
		}

		$objIndex = $objDatabase->prepare("SELECT id FROM tl_search WHERE url=?")
								->limit(1)
								->execute($arrSet['url']);

		// Add the page to the tl_search table
		if ($objIndex->numRows)
		{
			$objDatabase->prepare("UPDATE tl_search %s WHERE id=?")
						->set($arrSet)
						->execute($objIndex->id);

			$intInsertId = $objIndex->id;
		}
		else
		{
			$objInsertStmt = $objDatabase->prepare("INSERT INTO tl_search %s")
										 ->set($arrSet)
										 ->execute();

			$intInsertId = $objInsertStmt->insertId;
		}

		// Remove quotes
		$strText = str_replace(array('´', '`'), "'", $arrSet['text']);

		unset($arrSet);

		// Split words
		$arrWords = self::splitIntoWords(Utf8::strtolower($strText), $arrData['language']);
		$arrIndex = array();

		// Index words
		foreach ($arrWords as $strWord)
		{
			if (isset($arrIndex[$strWord]))
			{
				$arrIndex[$strWord]++;
				continue;
			}

			$arrIndex[$strWord] = 1;
		}

		// Remove the existing index
		$objDatabase->prepare("DELETE FROM tl_search_index WHERE pid=?")
					->execute($intInsertId);

		$arrQuery = array();
		$arrValues = array();

		foreach ($arrIndex as $k=>$v)
		{
			$arrQuery[] = '(?, ?, ?, ?)';
			$arrValues[] = $intInsertId;
			$arrValues[] = $k;
			$arrValues[] = $v;
			$arrValues[] = $arrData['language'];
		}

		// Create the new index
		$objDatabase->prepare("INSERT INTO tl_search_index (pid, word, relevance, language) VALUES " . implode(', ', $arrQuery))
					->execute($arrValues);

		return true;
	}
public static function indexPage($arrData)
	{
		$objDatabase = Database::getInstance();

		$arrSet['tstamp'] = time();
		$arrSet['url'] = $arrData['url'];
		$arrSet['title'] = $arrData['title'];
		$arrSet['protected'] = $arrData['protected'];
		$arrSet['filesize'] = $arrData['filesize'];
		$arrSet['groups'] = $arrData['groups'];
		$arrSet['pid'] = $arrData['pid'];
		$arrSet['language'] = $arrData['language'];

		// Get the file size from the raw content
		if (!$arrSet['filesize'])
		{
			$arrSet['filesize'] = number_format((\strlen($arrData['content']) / 1024), 2, '.', '');
		}

		// Replace special characters
		$strContent = str_replace(array("\n", "\r", "\t", '&#160;', '&nbsp;', '&shy;'), array(' ', ' ', ' ', ' ', ' ', ''), $arrData['content']);

		// Strip script tags
		while (($intStart = strpos($strContent, '<script')) !== false)
		{
			if (($intEnd = strpos($strContent, '</script>', $intStart)) !== false)
			{
				$strContent = substr($strContent, 0, $intStart) . substr($strContent, $intEnd + 9);
			}
			else
			{
				break; // see #5119
			}
		}

		// Strip style tags
		while (($intStart = strpos($strContent, '<style')) !== false)
		{
			if (($intEnd = strpos($strContent, '</style>', $intStart)) !== false)
			{
				$strContent = substr($strContent, 0, $intStart) . substr($strContent, $intEnd + 8);
			}
			else
			{
				break; // see #5119
			}
		}

		// Strip non-indexable areas
		while (($intStart = strpos($strContent, '<!-- indexer::stop -->')) !== false)
		{
			if (($intEnd = strpos($strContent, '<!-- indexer::continue -->', $intStart)) !== false)
			{
				$intCurrent = $intStart;

				// Handle nested tags
				while (($intNested = strpos($strContent, '<!-- indexer::stop -->', $intCurrent + 22)) !== false && $intNested < $intEnd)
				{
					if (($intNewEnd = strpos($strContent, '<!-- indexer::continue -->', $intEnd + 26)) !== false)
					{
						$intEnd = $intNewEnd;
						$intCurrent = $intNested;
					}
					else
					{
						break; // see #5119
					}
				}

				$strContent = substr($strContent, 0, $intStart) . substr($strContent, $intEnd + 26);
			}
			else
			{
				break; // see #5119
			}
		}

		// HOOK: add custom logic
		if (isset($GLOBALS['TL_HOOKS']['indexPage']) && \is_array($GLOBALS['TL_HOOKS']['indexPage']))
		{
			foreach ($GLOBALS['TL_HOOKS']['indexPage'] as $callback)
			{
				System::importStatic($callback[0])->{$callback[1]}($strContent, $arrData, $arrSet);
			}
		}

		// Free the memory
		unset($arrData['content']);

		$arrMatches = array();
		preg_match('/<\/head>/', $strContent, $arrMatches, PREG_OFFSET_CAPTURE);
		$intOffset = \strlen($arrMatches[0][0]) + $arrMatches[0][1];

		// Split page in head and body section
		$strHead = substr($strContent, 0, $intOffset);
		$strBody = substr($strContent, $intOffset);

		unset($strContent);

		$tags = array();

		// Get the description
		if (preg_match('/<meta[^>]+name="description"[^>]+content="([^"]*)"[^>]*>/i', $strHead, $tags))
		{
			$arrData['description'] = trim(preg_replace('/ +/', ' ', StringUtil::decodeEntities($tags[1])));
		}

		// Get the keywords
		if (preg_match('/<meta[^>]+name="keywords"[^>]+content="([^"]*)"[^>]*>/i', $strHead, $tags))
		{
			$arrData['keywords'] = trim(preg_replace('/ +/', ' ', StringUtil::decodeEntities($tags[1])));
		}

		// Read the title and alt attributes
		if (preg_match_all('/<* (title|alt)="([^"]*)"[^>]*>/i', $strBody, $tags))
		{
			$arrData['keywords'] .= ' ' . implode(', ', array_unique($tags[2]));
		}

		// Add a whitespace character before line-breaks and between consecutive tags (see #5363)
		$strBody = str_ireplace(array('<br', '><'), array(' <br', '> <'), $strBody);
		$strBody = strip_tags($strBody);

		// Put everything together
		$arrSet['text'] = $arrData['title'] . ' ' . $arrData['description'] . ' ' . $strBody . ' ' . $arrData['keywords'];
		$arrSet['text'] = trim(preg_replace('/ +/', ' ', StringUtil::decodeEntities($arrSet['text'])));

		// Calculate the checksum
		$arrSet['checksum'] = md5($arrSet['text']);

		$objIndex = $objDatabase->prepare("SELECT id, url FROM tl_search WHERE checksum=? AND pid=?")
								->limit(1)
								->execute($arrSet['checksum'], $arrSet['pid']);

		// Update the URL if the new URL is shorter or the current URL is not canonical
		if ($objIndex->numRows && $objIndex->url != $arrSet['url'])
		{
			if (strpos($arrSet['url'], '?') === false && strpos($objIndex->url, '?') !== false)
			{
				// The new URL is more canonical (no query string)
				$objDatabase->prepare("DELETE FROM tl_search WHERE id=?")
							->execute($objIndex->id);

				$objDatabase->prepare("DELETE FROM tl_search_index WHERE pid=?")
							->execute($objIndex->id);
			}
			elseif (substr_count($arrSet['url'], '/') > substr_count($objIndex->url, '/') || (strpos($arrSet['url'], '?') !== false && strpos($objIndex->url, '?') === false) || \strlen($arrSet['url']) > \strlen($objIndex->url))
			{
				// The current URL is more canonical (shorter and/or less fragments)
				$arrSet['url'] = $objIndex->url;
			}
			else
			{
				// The same page has been indexed under a different URL already (see #8460)
				return false;
			}
		}

		$objIndex = $objDatabase->prepare("SELECT id FROM tl_search WHERE url=?")
								->limit(1)
								->execute($arrSet['url']);

		// Add the page to the tl_search table
		if ($objIndex->numRows)
		{
			$objDatabase->prepare("UPDATE tl_search %s WHERE id=?")
						->set($arrSet)
						->execute($objIndex->id);

			$intInsertId = $objIndex->id;
		}
		else
		{
			$objInsertStmt = $objDatabase->prepare("INSERT INTO tl_search %s")
										 ->set($arrSet)
										 ->execute();

			$intInsertId = $objInsertStmt->insertId;
		}

		// Remove quotes
		$strText = str_replace(array('´', '`'), "'", $arrSet['text']);

		unset($arrSet);

		// Split words
		$arrWords = self::splitIntoWords(Utf8::strtolower($strText), $arrData['language']);
		$arrIndex = array();

		// Index words
		foreach ($arrWords as $strWord)
		{
			if (isset($arrIndex[$strWord]))
			{
				$arrIndex[$strWord]++;
				continue;
			}

			$arrIndex[$strWord] = 1;
		}

		// Remove the existing index
		$objDatabase->prepare("DELETE FROM tl_search_index WHERE pid=?")
					->execute($intInsertId);

		$arrQuery = array();
		$arrValues = array();

		foreach ($arrIndex as $k=>$v)
		{
			$arrQuery[] = '(?, ?, ?, ?)';
			$arrValues[] = $intInsertId;
			$arrValues[] = $k;
			$arrValues[] = $v;
			$arrValues[] = $arrData['language'];
		}

		// Create the new index
		$objDatabase->prepare("INSERT INTO tl_search_index (pid, word, relevance, language) VALUES " . implode(', ', $arrQuery))
					->execute($arrValues);

		return true;
	}
public static function indexPage ( $ arrData ) { $ objDatabase = Database :: getInstance ( ) ; $ arrSet [ 'tstamp' ] = time ( ) ; $ arrSet [ 'url' ] = $ arrData [ 'url' ] ; $ arrSet [ 'title' ] = $ arrData [ 'title' ] ; $ arrSet [ 'protected' ] = $ arrData [ 'protected' ] ; $ arrSet [ 'filesize' ] = $ arrData [ 'filesize' ] ; $ arrSet [ 'groups' ] = $ arrData [ 'groups' ] ; $ arrSet [ 'pid' ] = $ arrData [ 'pid' ] ; $ arrSet [ 'language' ] = $ arrData [ 'language' ] ; // Get the file size from the raw content if ( ! $ arrSet [ 'filesize' ] ) { $ arrSet [ 'filesize' ] = number_format ( ( \ strlen ( $ arrData [ 'content' ] ) / 1024 ) , 2 , '.' , '' ) ; } // Replace special characters $ strContent = str_replace ( array ( "\n" , "\r" , "\t" , '&#160;' , '&nbsp;' , '&shy;' ) , array ( ' ' , ' ' , ' ' , ' ' , ' ' , '' ) , $ arrData [ 'content' ] ) ; // Strip script tags while ( ( $ intStart = strpos ( $ strContent , '<script' ) ) !== false ) { if ( ( $ intEnd = strpos ( $ strContent , '</script>' , $ intStart ) ) !== false ) { $ strContent = substr ( $ strContent , 0 , $ intStart ) . substr ( $ strContent , $ intEnd + 9 ) ; } else { break ; // see #5119 } } // Strip style tags while ( ( $ intStart = strpos ( $ strContent , '<style' ) ) !== false ) { if ( ( $ intEnd = strpos ( $ strContent , '</style>' , $ intStart ) ) !== false ) { $ strContent = substr ( $ strContent , 0 , $ intStart ) . substr ( $ strContent , $ intEnd + 8 ) ; } else { break ; // see #5119 } } // Strip non-indexable areas while ( ( $ intStart = strpos ( $ strContent , '<!-- indexer::stop -->' ) ) !== false ) { if ( ( $ intEnd = strpos ( $ strContent , '<!-- indexer::continue -->' , $ intStart ) ) !== false ) { $ intCurrent = $ intStart ; // Handle nested tags while ( ( $ intNested = strpos ( $ strContent , '<!-- indexer::stop -->' , $ intCurrent + 22 ) ) !== false && $ intNested < $ intEnd ) { if ( ( $ intNewEnd = strpos ( $ strContent , '<!-- indexer::continue -->' , $ intEnd + 26 ) ) !== false ) { $ intEnd = $ intNewEnd ; $ intCurrent = $ intNested ; } else { break ; // see #5119 } } $ strContent = substr ( $ strContent , 0 , $ intStart ) . substr ( $ strContent , $ intEnd + 26 ) ; } else { break ; // see #5119 } } // HOOK: add custom logic if ( isset ( $ GLOBALS [ 'TL_HOOKS' ] [ 'indexPage' ] ) && \ is_array ( $ GLOBALS [ 'TL_HOOKS' ] [ 'indexPage' ] ) ) { foreach ( $ GLOBALS [ 'TL_HOOKS' ] [ 'indexPage' ] as $ callback ) { System :: importStatic ( $ callback [ 0 ] ) -> { $ callback [ 1 ] } ( $ strContent , $ arrData , $ arrSet ) ; } } // Free the memory unset ( $ arrData [ 'content' ] ) ; $ arrMatches = array ( ) ; preg_match ( '/<\/head>/' , $ strContent , $ arrMatches , PREG_OFFSET_CAPTURE ) ; $ intOffset = \ strlen ( $ arrMatches [ 0 ] [ 0 ] ) + $ arrMatches [ 0 ] [ 1 ] ; // Split page in head and body section $ strHead = substr ( $ strContent , 0 , $ intOffset ) ; $ strBody = substr ( $ strContent , $ intOffset ) ; unset ( $ strContent ) ; $ tags = array ( ) ; // Get the description if ( preg_match ( '/<meta[^>]+name="description"[^>]+content="([^"]*)"[^>]*>/i' , $ strHead , $ tags ) ) { $ arrData [ 'description' ] = trim ( preg_replace ( '/ +/' , ' ' , StringUtil :: decodeEntities ( $ tags [ 1 ] ) ) ) ; } // Get the keywords if ( preg_match ( '/<meta[^>]+name="keywords"[^>]+content="([^"]*)"[^>]*>/i' , $ strHead , $ tags ) ) { $ arrData [ 'keywords' ] = trim ( preg_replace ( '/ +/' , ' ' , StringUtil :: decodeEntities ( $ tags [ 1 ] ) ) ) ; } // Read the title and alt attributes if ( preg_match_all ( '/<* (title|alt)="([^"]*)"[^>]*>/i' , $ strBody , $ tags ) ) { $ arrData [ 'keywords' ] .= ' ' . implode ( ', ' , array_unique ( $ tags [ 2 ] ) ) ; } // Add a whitespace character before line-breaks and between consecutive tags (see #5363) $ strBody = str_ireplace ( array ( '<br' , '><' ) , array ( ' <br' , '> <' ) , $ strBody ) ; $ strBody = strip_tags ( $ strBody ) ; // Put everything together $ arrSet [ 'text' ] = $ arrData [ 'title' ] . ' ' . $ arrData [ 'description' ] . ' ' . $ strBody . ' ' . $ arrData [ 'keywords' ] ; $ arrSet [ 'text' ] = trim ( preg_replace ( '/ +/' , ' ' , StringUtil :: decodeEntities ( $ arrSet [ 'text' ] ) ) ) ; // Calculate the checksum $ arrSet [ 'checksum' ] = md5 ( $ arrSet [ 'text' ] ) ; $ objIndex = $ objDatabase -> prepare ( "SELECT id, url FROM tl_search WHERE checksum=? AND pid=?" ) -> limit ( 1 ) -> execute ( $ arrSet [ 'checksum' ] , $ arrSet [ 'pid' ] ) ; // Update the URL if the new URL is shorter or the current URL is not canonical if ( $ objIndex -> numRows && $ objIndex -> url != $ arrSet [ 'url' ] ) { if ( strpos ( $ arrSet [ 'url' ] , '?' ) === false && strpos ( $ objIndex -> url , '?' ) !== false ) { // The new URL is more canonical (no query string) $ objDatabase -> prepare ( "DELETE FROM tl_search WHERE id=?" ) -> execute ( $ objIndex -> id ) ; $ objDatabase -> prepare ( "DELETE FROM tl_search_index WHERE pid=?" ) -> execute ( $ objIndex -> id ) ; } elseif ( substr_count ( $ arrSet [ 'url' ] , '/' ) > substr_count ( $ objIndex -> url , '/' ) || ( strpos ( $ arrSet [ 'url' ] , '?' ) !== false && strpos ( $ objIndex -> url , '?' ) === false ) || \ strlen ( $ arrSet [ 'url' ] ) > \ strlen ( $ objIndex -> url ) ) { // The current URL is more canonical (shorter and/or less fragments) $ arrSet [ 'url' ] = $ objIndex -> url ; } else { // The same page has been indexed under a different URL already (see #8460) return false ; } } $ objIndex = $ objDatabase -> prepare ( "SELECT id FROM tl_search WHERE url=?" ) -> limit ( 1 ) -> execute ( $ arrSet [ 'url' ] ) ; // Add the page to the tl_search table if ( $ objIndex -> numRows ) { $ objDatabase -> prepare ( "UPDATE tl_search %s WHERE id=?" ) -> set ( $ arrSet ) -> execute ( $ objIndex -> id ) ; $ intInsertId = $ objIndex -> id ; } else { $ objInsertStmt = $ objDatabase -> prepare ( "INSERT INTO tl_search %s" ) -> set ( $ arrSet ) -> execute ( ) ; $ intInsertId = $ objInsertStmt -> insertId ; } // Remove quotes $ strText = str_replace ( array ( '´', `') , '", a rrSet[ ' text'] ) ; unset ( $ arrSet ) ; // Split words $ arrWords = self :: splitIntoWords ( Utf8 :: strtolower ( $ strText ) , $ arrData [ 'language' ] ) ; $ arrIndex = array ( ) ; // Index words foreach ( $ arrWords as $ strWord ) { if ( isset ( $ arrIndex [ $ strWord ] ) ) { $ arrIndex [ $ strWord ] ++ ; continue ; } $ arrIndex [ $ strWord ] = 1 ; } // Remove the existing index $ objDatabase -> prepare ( "DELETE FROM tl_search_index WHERE pid=?" ) -> execute ( $ intInsertId ) ; $ arrQuery = array ( ) ; $ arrValues = array ( ) ; foreach ( $ arrIndex as $ k => $ v ) { $ arrQuery [ ] = '(?, ?, ?, ?)' ; $ arrValues [ ] = $ intInsertId ; $ arrValues [ ] = $ k ; $ arrValues [ ] = $ v ; $ arrValues [ ] = $ arrData [ 'language' ] ; } // Create the new index $ objDatabase -> prepare ( "INSERT INTO tl_search_index (pid, word, relevance, language) VALUES " . implode ( ', ' , $ arrQuery ) ) -> execute ( $ arrValues ) ; return true ; }
Index a page

@param array $arrData The data array

@return boolean True if a new record was created
Index a page