Cách làm: - Login host truy cập theo đường dẫn sau : /library/XenForo/Link.php -Tìm đến function buildBasicLinkWithIntegerParam , Cụ thể là dòng thứ 644 (open note pad ++) Thay bằng : CODE: Select All public static function buildBasicLinkWithIntegerParam($prefix, $action, $extension, $data, $intField, $titleField = ''){if ((is_array($data) || $data instanceof ArrayAccess) && isset($data[$intField])){self::prepareExtensionAndAction($extension, $action);$title = (($titleField && !empty($data[$titleField])) ? Hoặc có thể bạn copy toàn bộ nội dung bên dưới thay cho file Link.php CODE: Select All <?php/*** Helper methods to generate links to content. Links generated* by this are not necessarily HTML escaped. The calling code* should escape them for the output context they apply to.** @package XenForo_Core*/class XenForo_Link{/*** Stores a cache of handlers for prefixes. Many types of links will* be generated multiple times on a page, so this cache reduces the* amount of object creation/validation necessary.** @var array*/protected static $_handlerCache = array();/*** URL prefix to use when generating a canonical link.** @var string|null*/protected static $_canonicalLinkPrefix = null;/*** If true, uses friendly URLs that don't include index.php or a query string (unless required).** @var boolean*/protected static $_useFriendlyUrls = false;/*** If true, Romanize titles before outputting them in URLs.** @var boolean*/protected static $_romanizeTitles = false;/*** @var string*/protected static $_indexRoute = 'forums/';protected $_linkString = '';protected $_canPrependFull = true;/*** Constructor. Use the static methods in general. However, you can create* an object of this type from a link builder to generate an arbitrary URL.** @param string $linkString* @param boolean $canPrependFull True if the default full link prefix can be prepended to make a full URL*/public function __construct($linkString, $canPrependFull = true){$this->_linkString = $linkString;$this->_canPrependFull = $canPrependFull;}/*** @return string Link*/public function __toString(){return $this->_linkString;}/*** @return boolean*/public function canPrependFull(){return $this->_canPrependFull;}/*** Builds a link to a public resource. The type should contain a prefix* optionally split by a "/" with the specific action (eg "templates/edit").** @param string $type Prefix and action* @param mixed $data Data that the prefix/action should be applied to, if applicable* @param array $extraParams Additional params** @return string The link*/public static function buildPublicLink($type, $data = null, array $extraParams = array(), $skipPrepend = false){$type = self::_checkForFullLink($type, $fullLink, $fullLinkPrefix);$link = self::_buildLink('public', $type, $data, $extraParams, $prefix);$queryString = self::buildQueryString($extraParams);if ($link instanceof XenForo_Link){$isRaw = true;$canPrependFull = $link->canPrependFull();}else{$isRaw = false;$canPrependFull = true;if (strpos($link, '#') !== false){list($link, $hash) = explode('#', $link);}if ($link == self::$_indexRoute){$link = '';}else if (XenForo_Application::isRegistered('routeFiltersOut')){$routeFilters = XenForo_Application::get('routeFiltersOut');if (isset($routeFilters[$prefix])){foreach ($routeFilters[$prefix] AS $filter){list($from, $to) = self::translateRouteFilterToRegex($filter['find_route'], $filter['replace_route']);$newLink = preg_replace($from, $to, $link);if ($newLink != $link){$link = $newLink;break;}}}}}if (self::$_useFriendlyUrls || $isRaw){$outputLink = ($queryString !== '' ? "$link?$queryString" : $link);}else{if ($queryString !== '' && $link !== ''){$append = "?$link&$queryString";}else{// 1 or neither of these has content$append = $link . $queryString;if ($append !== ''){$append = "?$append";}}if ($skipPrepend){$outputLink = $append;}else{$outputLink = 'index.php' . $append;}}if ($fullLink && $canPrependFull){$outputLink = $fullLinkPrefix . $outputLink;}// deal with a hash in the $type {xen:link prefix#hash..}if (($hashPos = strpos($type, '#')) !== false){$hash = substr($type, $hashPos + 1);}if ($outputLink === ''){$outputLink = '.';}return $outputLink . (empty($hash) ? '' : '#' . $hash);}/*** Builds a link to an admin resource. The type should contain a prefix* optionally split by a "/" with the specific action (eg "templates/edit").** @param string $type Prefix and action* @param mixed $data Data that the prefix/action should be applied to, if applicable* @param array $extraParams Additional params** @return string The link*/public static function buildAdminLink($type, $data = null, array $extraParams = array()){$type = self::_checkForFullLink($type, $fullLink, $fullLinkPrefix);$link = self::_buildLink('admin', $type, $data, $extraParams);$queryString = self::buildQueryString($extraParams);if (strpos($link, '#') !== false){list($link, $hash) = explode('#', $link);}if ($queryString !== '' && $link !== ''){$append = $link . '&' . $queryString;}else{// 1 or neither of these has content$append = $link . $queryString;}// deal with a hash in the $type {xen:link prefix#hash..}if (($hashPos = strpos($type, '#')) !== false){$append .= substr($type, $hashPos + 1);}$outputLink = 'admin.php' . ($append !== '' ? '?' : '') . $append;if ($fullLink){$outputLink = $fullLinkPrefix . $outputLink;}return $outputLink . (empty($hash) ? '' : '#' . $hash);}/*** Builds a link along the lines of <prefix>/<sub-component>/<data.id>/<action>.** @param array $subComponents List of sub-components that are valid as keys, with specific child keys (title, intId, stringId)* @param string $outputPrefix* @param string $action* @param string $extension* @param mixed $data** @return string|false String if sub-component matched with appropriate data, false otherwise*/public static function buildSubComponentLink(array $subComponents, $outputPrefix, $action, $extension, $data){$parts = explode('/', $action, 2);$subComponentName = strtolower($parts[0]);foreach ($subComponents AS $Mã => $subComponent){if ($Mã == $subComponentName){$action = (isset($parts[1]) ? $parts[1] : '');if (isset($subComponent['intId'])){$titleField = (isset($subComponent['title']) ? $subComponent['title'] : '');return self::buildBasicLinkWithIntegerParam("$outputPrefix/$parts[0]", $action, $extension, $data, $subComponent['intId'], $titleField);}else if (isset($subComponent['stringId'])){return self::buildBasicLinkWithStringParam("$outputPrefix/$parts[0]", $action, $extension, $data, $subComponent['stringId']);}else{return false;}}}return false;}/*** Check to see if a full link is requested.** @param string $type Link type* @param boolean $fullLink Modified by ref. Returns whether a full link is requested.* @param string $fullLinkPrefix If a full link is requested, the prefix to use** @return string Link type, with full link param stripped off if necessary*/protected static function _checkForFullLink($type, &$fullLink, &$fullLinkPrefix){if (!$type){$fullLink = false;$fullLinkPrefix = '';return $type;}if ($type[0] == 'c' && substr($type, 0, 10) == 'canonical:'){$type = substr($type, 10);$fullLink = true;$fullLinkPrefix = self::getCanonicalLinkPrefix() . '/';}else if ($type[0] == 'f' && substr($type, 0, 5) == 'full:'){$type = substr($type, 5);$fullLink = true;$paths = XenForo_Application::get('requestPaths');$fullLinkPrefix = $paths['fullBasePath'];}else{$fullLink = false;$fullLinkPrefix = '';}return $type;}/*** Internal link builder.** @param string $group Type of link being built (admin or public)* @param string $type Type of data the link is for (prefix and action)* @param mixed $data* @param array $extraParams* @param string|null $prefix The prefix found** @return string*/protected static function _buildLink($group, $type, $data, array &$extraParams, &$prefix = null){if (isset($extraParams['_params']) && is_array($extraParams['_params'])){$params = $extraParams['_params'];unset($extraParams['_params']);$extraParams = array_merge($params, $extraParams);}$extension = '';if (($dotPos = strrpos($type, '.')) !== false){$extension = substr($type, $dotPos + 1);$type = substr($type, 0, $dotPos);}if (($hashPos = strpos($type, '#')) !== false){$type = substr($type, 0, $hashPos);}if (($slashPos = strpos($type, '/')) !== false){list($prefix, $action) = explode('/', $type, 2);if ($action == 'index'){$action = '';}}else{$prefix = $type;$action = '';}unset($type);$handler = self::_getPrefixHandler($group, $prefix, (boolean)$data);if ($handler === false){$link = false;}else{$link = $handler->buildLink($prefix, $prefix, $action, $extension, $data, $extraParams);}if ($link === false || $link === null){return self::buildBasicLink($prefix, $action, $extension);}else{return $link;}}/*** Gets the object that should handle building the link for this prefix.* May also return false if only the standard behavior is desired.** @param string $group Type of link (public or admin)* @param string $originalPrefix Prefix to build the link for (should be the "original prefix" in the DB)* @param boolean $haveData Whether we have a data element** @return object|false Object with "buildLink" method or false*/protected static function _getPrefixHandler($group, $originalPrefix, $haveData){if (!isset(self::$_handlerCache[$group])){self::$_handlerCache[$group] = self::_loadHandlerInfoForGroup($group);}if (!isset(self::$_handlerCache[$group][$originalPrefix])){return false;}$info =& self::$_handlerCache[$group][$originalPrefix];if ($haveData){if (!isset($info['handlerWithData'])){$info['handlerWithData'] = self::_loadPrefixHandlerClass($info, true);}return $info['handlerWithData'];}else{if (!isset($info['handlerNoData'])){$info['handlerNoData'] = self::_loadPrefixHandlerClass($info, false);}return $info['handlerNoData'];}}/*** Load the prefix link build handler class based on current settings.** @param array $info Info about how to build this link (includes build_link, route_class keys)* @param boolean $haveData True if we have a data param for this link** @return object|false Object with "buildLink" method or false*/protected static function _loadPrefixHandlerClass(array $info, $haveData){if ($info['build_link'] == 'none' || ($info['build_link'] == 'data_only' && !$haveData)){// never build or only build when we have data (and we don't now)return false;}if ($info['build_link'] == 'all'){// always build - check for a previous callif (isset($info['handlerWithData'])){return $info['handlerWithData'];}else if (isset($info['handlerNoData'])){return $info['handlerNoData'];}}// ...otherwise load the class we need$class = XenForo_Application::resolveDynamicClass($info['route_class'], 'route_prefix');if (!$class){return false;}$handler = new $class();if (!method_exists($handler, 'buildLink')){return false;}return $handler;}/*** Loads all the link build handler data for an entire group of prefixes.** @param string $group Type of prefix (public or admin)** @return array Keys are "original prefixes" and values are info about output prefix/class/build settings*/protected static function _loadHandlerInfoForGroup($group){return XenForo_Model::create('XenForo_Model_RoutePrefix')->getPrefixesForRouteCache($group);}/*** Gets the name of the specified prefix handler class.** @param string $group* @param string $prefix** @return string|false*/public static function getPrefixHandlerClassName($group, $prefix){if (!isset(self::$_handlerCache[$group])){self::$_handlerCache[$group] = self::_loadHandlerInfoForGroup($group);}if (!isset(self::$_handlerCache[$group][$prefix])){return false;}return self::$_handlerCache[$group][$prefix]['route_class'];}/*** Examines action and extra parameters from a link build call and formulates* a page number link parameter if applicable.** @param string $action* @param array $params** @return string $action*/public static function getPageNumberAsAction($action, array &$params){if (isset($params['page'])){if (strval($params['page']) !== XenForo_Application::$integerSentinel && $params['page'] <= 1){unset($params['page']);}else if (!$action){if ($params['page'] != XenForo_Application::$integerSentinel){$params['page'] = intval($params['page']);}$action = "page-$params[page]";unset($params['page']);}}return $action;}/*** Helper to manually set handler info for a group. Keys should be "original prefixes"* and values should be arrays with keys matching the xf_route_prefix table.** @param string $group Type of prefix to handle (public or admin)* @param array $info Info to set*/public static function setHandlerInfoForGroup($group, array $info){self::$_handlerCache[$group] = $info;}/*** Gets the handler info for the group of prefixes.** @param string $group** @return array*/public static function getHandlerInfoForGroup($group){if (!isset(self::$_handlerCache[$group])){self::$_handlerCache[$group] = self::_loadHandlerInfoForGroup($group);}return self::$_handlerCache[$group];}/*** Resets the handlers for all groups or for a particular group. Mainly used for testing.** @param string|false $group If false, resets all handlers; otherwise, resets the specified handler group*/public static function resetHandlerInfo($group = false){if ($group === false){self::$_handlerCache = array();}else{unset(self::$_handlerCache[strval($group)]);}}/*** Builds a basic link: a prefix and action only.** @param string $prefix* @param string $action* @param string $extension** @return string*/public static function buildBasicLink($prefix, $action, $extension = ''){if ($extension){self::prepareExtensionAndAction($extension, $action);}if ($prefix === 'index' && $action === ''){return '';}else{return "$prefix/$action$extension";}}/*** Prepares the link extension and action, if necessary. If an extension is specified,* the provided value will be prefixed with a ".". If there is an extension and there's* no action, an explicit "index" action will be specified.** @param string $extension Initially, the extension to the link specified; prefixed with "." if necessary* @param string $action The link action; modified if necessary*/public static function prepareExtensionAndAction(&$extension, &$action, $prepareAction = true){if ($extension){$extension = '.' . $extension;if ($action === ''){$action = 'index';}}}/*** Builds a basic link for a request that may have an integer param.* Output will be in the format [prefix]/[title].[int]/[action]/ or similar,* based on whether the correct values in data are set.** @param string $prefix Link prefix* @param string $action Link action* @param string $extension Link extension (for content type)* @param mixed $data Specific data to link to. If available, an array or an object that implements ArrayAccess* @param string $intField The name of the field that holds the integer identifier* @param string $titleField If there is a title field, the name of the field that holds the title** @return false|string False if no data is provided, the link otherwise*/public static function buildBasicLinkWithIntegerParam($prefix, $action, $extension, $data, $intField, $titleField = ''){if ((is_array($data) || $data instanceof ArrayAccess) && isset($data[$intField])){self::prepareExtensionAndAction($extension, $action);$title = (($titleField && !empty($data[$titleField])) ? $data[$titleField] : '');if($action=="" && $extension==""){return "$prefix/" . self::buildIntegerAndTitleUrlComponent($data[$intField], $title) . ".html";}else{return "$prefix/" . self::buildIntegerAndTitleUrlComponent($data[$intField], $title) . "/$action$extension";}}else{return false;}}/*** Builds a basic link for a request that may have a string param.* Output will be in the format [prefix]/[param]/[action].** Note that it is expected that the string param is already clean enough* to be inserted into the link.** @param string $prefix Link prefix* @param string $action Link action* @param string $extension Link extension (for content type)* @param mixed $data Specific data to link to. If available, an array or an object that implements ArrayAccess, or a simple string to be used directly* @param string $strField The name of the field that holds the string identifier** @return false|string False if no data is provided, the link otherwise*/public static function buildBasicLinkWithStringParam($prefix, $action, $extension, $data, $strField){if ($data){self::prepareExtensionAndAction($extension, $action);if ((is_array($data) || $data instanceof ArrayAccess)&& isset($data[$strField])&& $data[$strField] !== ''){return "$prefix/" . $data[$strField] . "/$action$extension";}else if (is_string($data)){return "$prefix/$data/$action$extension";}}return false;}/*** Builds the URL component for an integer and title. Outputs <int> or <int>-<title>.** @param integer $integer* @param string $title* @param boolean|null $romanize If true, non-latin strings are romanized. If null, use default setup** @return string*/public static function buildIntegerAndTitleUrlComponent($integer, $title = '', $romanize = null){if ($title && XenForo_Application::get('options')->includeTitleInUrls){if ($romanize === null){$romanize = self::$_romanizeTitles;}$title = self::getTitleForUrl($title, $romanize);if ($title !== ''){# /item-title.id/ (where delimiter is '.')return urlencode(self::getTitleForUrl($title, $romanize)) . XenForo_Application::URL_ID_DELIMITER . intval($integer);}}return intval($integer);}/*** Cache for getting prepped/Romanized titles for URLs** @var array*/protected static $_titleCache = array();/*** Gets version of a title that is valid in a URL. Invalid elements are stripped* or replaced with '-'. It may not be possible to reverse a URL'd title to the* original title.** @param string $title* @param boolean $romanize If true, non-latin strings are romanized** @return string*/public static function getTitleForUrl($title, $romanize = false){$title = strval($title);if (isset(self::$_titleCache[$title])){return self::$_titleCache[$title];}$original = $title;if ($romanize){$title = utf8_romanize(utf8_deaccent($title));}$title = strtr($title,'`!"$%^&*()-+={}[]<>;:@#~,./?|' . "\r\n\t\\",' ' . ' ');$title = strtr($title, array('"' => '', "'" => ''));if ($romanize){$title = preg_replace('/[^a-zA-Z0-9_ -]/', '', $title);}$title = preg_replace('/[ ]+/', '-', trim($title));$title = strtr($title, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');self::$_titleCache[$original] = $title;return $title;}/*** Builds a query string from an array of items. Keys of the array will become* names of items in the query string. Nested arrays are supported.** @param array $elements Elements to build the query string from* @param string $prefix For nested arrays, specifies the base context we're in.*Leave default unless wanting all elements inside an array.** @return string*/public static function buildQueryString(array $elements, $prefix = ''){$output = array();foreach ($elements AS $name => $value){if (is_array($value)){if (!$value){continue;}$encodedName = ($prefix ? $prefix . '[' . urlencode($name) . ']' : urlencode($name));$childOutput = self::buildQueryString($value, $encodedName);if ($childOutput !== ''){$output[] = $childOutput;}}else{if ($value === null || $value === false || $value === ''){continue;}$value = strval($value);if ($prefix){// part of an array$output[] = $prefix . '[' . urlencode($name) . ']=' . urlencode($value);}else{$output[] = urlencode($name) . '=' . urlencode($value);}}}return implode('&', $output);}/*** Set the prefix for links that are generated as canonical links.** @param string $linkPrefix*/public static function setCanonicalLinkPrefix($linkPrefix){self::$_canonicalLinkPrefix = self::convertUriToAbsoluteUri($linkPrefix, true);}/*** Gets the canonical link prefix to use for generating canonical links.** @return string*/public static function getCanonicalLinkPrefix(){if (self::$_canonicalLinkPrefix === null){self::$_canonicalLinkPrefix = self::convertUriToAbsoluteUri(XenForo_Application::get('options')->boardUrl, true);}return self::$_canonicalLinkPrefix;}/*** Sets whether friendly URLs should be used for generating links.** @param boolean $value*/public static function useFriendlyUrls($value){self::$_useFriendlyUrls = $value;}/*** Sets whether friendly titles should be romanized in links.** @param boolean $value*/public static function romanizeTitles($value){self::$_romanizeTitles = $value;}/*** Sets the index route** @param $value*/public static function setIndexRoute($value){self::$_indexRoute = $value;}/*** @return string*/public static function getIndexRoute(){return self::$_indexRoute;}/*** Converts what may be a relative link into an absolute URI.** @param string $uri URI to convert* @param boolean $includeHost If true, includes host, port, and protocol* @param array|null $paths Paths to override (uses application level if not provided)** @return string*/public static function convertUriToAbsoluteUri($uri, $includeHost = false, array $paths = null){if (!$paths){$paths = XenForo_Application::get('requestPaths');}if ($uri == '.'){$uri = ''; // current directory}if (substr($uri, 0, 2) == '//'){return $paths['protocol'] . ':' . $uri;}else if (substr($uri, 0, 1) == '/'){if ($includeHost){return $paths['protocol'] . '://' . $paths['host'] . $uri;}else{return $uri;}}else if (preg_match('#^[a-z0-9-]+://#i', $uri)){return $uri;}else if ($includeHost){return $paths['fullBasePath'] . $uri;}else{return $paths['basePath'] . $uri;}}public static function translateRouteFilterToRegex($from, $to){$to = strtr($to, array('\\' => '\\\\', '$' => '\\$'));$findReplacements = array();$replacementChr = chr(26);preg_match_all('/\{([a-z0-9_]+)(:([^}]+))?\}/i', $from, $matches, PREG_SET_ORDER);foreach ($matches AS $i => $match){$placeholder = $replacementChr . $i . $replacementChr;if (!empty($match[3])){switch ($match[3]){case 'digit': $replace = '(\d+)'; break;case 'string': $replace = '([^/.]+)'; break;default: $replace = '([^/]*)';}}else{$replace = '([^/]*)';}$findReplacements[$placeholder] = $replace;$from = str_replace($match[0], $placeholder, $from);$to = str_replace($match[0], '$' . ($i + 1), $to);}$from = preg_quote($from, '#');foreach ($findReplacements AS $findPlaceholder => $findReplacement){$from = str_replace($findPlaceholder, $findReplacement, $from);}return array('#^' . $from . '#', $to);}} Chúc các bạn thành công. Chú ý nếu url vẫn còn lỗi thì: Bạn nên dùng phần mềm Zend Studio 12.5.1 Full thay cho notepad ++ nhé.