URL Tiếng Việt không dấu cho XenForo

Thảo luận trong 'SEO for XenForo' bắt đầu bởi VXF, 6/5/12.

1votes
5/5, 1 vote

  1. tpoclub

    tpoclub Member

    Bài viết:
    84
    Likes :
    36
    Chân thành cảm ơn bạn nhiều nhé, tại trước mình tải file link.php của anh em chia sẻ, (vừa tiếng Việt không dấu và có đuôi .html luôn bạn ạ)
    Mình chỉ mới thay code trên của bạn cho link.php Xen 1.4.4 thôi (chưa .html) may mà không lỗi link nội tuyến nào cả.
    Bạn share luôn đoạn .html cho Xen 1.4.4 chuẩn cho mình với được không?
    Thân!
     
  2. khoadh

    khoadh New Member

    Bài viết:
    46
    Likes :
    0

    Pac ơi mình chép đè lên cái file link.php cũ của mình thi diễn đàn không chay nữa, chỉ cách mình sửa v.
     
  3. khoadh

    khoadh New Member

    Bài viết:
    46
    Likes :
    0
    chép đè lên nó không chay nữa, vào thì nó báo dòng loi nhu the nay ne.


    D:\abc\htdocs\forum\library\XenForo\Application.php on line 785
     
  4. nhomainuti

    nhomainuti New Member

    Bài viết:
    1
    Likes :
    0
    khó khăn vậy ta???????????
     
  5. h2audio

    h2audio New Member

    Bài viết:
    4
    Likes :
    0
    em chèn thử nhưng ko được :v xong lại dùng cái add-on bên sinh viên IT, link ngon nghẻ lắm bác nào vào xem thử nhé raovatthainguyen.net
     
  6. Hardion

    Hardion New Member

    Bài viết:
    16
    Likes :
    0
    quá chuẩn!
     
  7. qnkingdom

    qnkingdom Member

    Bài viết:
    227
    Likes :
    11
    thâu lạy, down file link.php đè lên cái web vào không được luôn :( ai fix dùm cái
     
  8. dung3d

    dung3d Moderator Staff Member

    Bài viết:
    141
    Likes :
    41
    Mã:
    <?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;
    
        protected static $_includeTitlesInUrls = true;
    
        protected static $_routeFiltersOut = array();
    
        /**
        * @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 (isset(self::$_routeFiltersOut[$prefix]))
                {
                    foreach (self::$_routeFiltersOut[$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 $key => $subComponent)
            {
                if ($key == $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 call
                if (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 && self::$_includeTitlesInUrls)
            {
                if ($romanize === null)
                {
                    $romanize = self::$_romanizeTitles;
                }
                $title = self::getTitleForUrl($title, $romanize);
                if ($title !== '')
                {
                    # /item-title.id/ (where delimiter is '.')
                    return urlencode($title) . 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));
            }
           
            $aPattern = array (
    "a" => "á|à|ạ|ả|ã|ă|ắ|ằ|ặ|ẳ|ẵ|â|ấ|ầ|ậ|ẩ|ẫ|Á|À|Ạ|Ả|Ã|Ă|Ắ|Ằ|Ặ|Ẳ|Ẵ|Â|Ấ|Ầ|Ậ|Ẩ|Ẫ",
    "o" => "ó|ò|ọ|ỏ|õ|ô|ố|ồ|ộ|ổ|ỗ|ơ|ớ|ờ|ợ|ở|ỡ|Ó|Ò|Ọ|Ỏ|Õ|Ô|Ố|Ồ|Ộ|Ổ|Ỗ|Ơ|Ớ|Ờ|Ợ|Ở|Ỡ",
    "e" => "é|è|ẹ|ẻ|ẽ|ê|ế|ề|ệ|ể|ễ|É|È|Ẹ|Ẻ|Ẽ|Ê|Ế|Ề|Ệ|Ể|Ễ",
    "u" => "ú|ù|ụ|ủ|ũ|ư|ứ|ừ|ự|ử|ữ|Ú|Ù|Ụ|Ủ|Ũ|Ư|Ứ|Ừ|Ự|Ử|Ữ",
    "i" => "í|ì|ị|ỉ|ĩ|Í|Ì|Ị|Ỉ|Ĩ",
    "y" => "ý|ỳ|ỵ|ỷ|ỹ|Ý|Ỳ|Ỵ|Ỷ|Ỹ",
    "d" => "đ|Đ",
    );
    while(list($key,$value) = each($aPattern))
    {
    $title = @ereg_replace($value, $key, $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(
                    rtrim(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 whether titles will be included in URLs
        *
        * @param boolean $value
        */
        public static function includeTitlesInUrls($value)
        {
            self::$_includeTitlesInUrls = $value;
        }
    
        /**
        * Sets whether titles will be included in URLs
        *
        * @param array $value
        */
        public static function setRouteFiltersOut(array $value)
        {
            self::$_routeFiltersOut = $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);
        }
    }
    Toàn bộ file link.php đây. Bạn copy lại nhé.
     
  9. VanHuanHeo

    VanHuanHeo New Member

    Bài viết:
    10
    Likes :
    0
    Nếu như bây giờ em muốn những bài viết có ID > 500 thì mới dùng url dạng này.
    Còn nếu như ID <500 thì dùng url cũ thì em chỉnh sửa như thế nào ạ? Mấy bác giúp em với. Vì site của em đã có hơn 500 chủ đề nên giờ chỉnh sữa link sẽ dẫn đến trùng nội dung.
    Thank!
     
  10. dung3d

    dung3d Moderator Staff Member

    Bài viết:
    141
    Likes :
    41
    Trùng làm sao được vì mỗi một chủ đề ngoài tên ra còn có 1 số (ko giống nhau đằng sau) thì trùng làm sao dc.
     
    VanHuanHeo thích bài này.
  11. VanHuanHeo

    VanHuanHeo New Member

    Bài viết:
    10
    Likes :
    0
    Trùng nội dung với nhau ấy bác ơi, 2 link khác nhau mà nội dung trùng nhau thì không tốt cho SEO ấy bác.
    Ví dụ như bên dưới là trước và sau khi khắc phục lỗi url tiếng việt đó bác:
    Mã:
    http://vxf.vn/threads/url-ting-vit-khng-du-cho-xenforo.8/
    Mã:
    http://vxf.vn/threads/url-tieng-viet-khong-dau-cho-xenforo.8/
    2 link hoàn toàn khác nhau mà đều có 1 nội dung.
     
  12. dung3d

    dung3d Moderator Staff Member

    Bài viết:
    141
    Likes :
    41
    Bạn copy toàn bộ đoạn code file link.php này sau đó thay vào website của bạn nhé. Mình đang dùng cho web của mình. Mỗi link đều có 1 số id khác nhau.
    VD: tieng-viet.1
    tieng-viet.2

    Còn yêu cầu của bạn thì chịu chết. Chờ cao nhân.

    Mã:
    <?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;
    
    protected static $_includeTitlesInUrls = true;
    
    protected static $_routeFiltersOut = array();
    
    /**
    * @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 (isset(self::$_routeFiltersOut[$prefix]))
    {
    foreach (self::$_routeFiltersOut[$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 $key => $subComponent)
    {
    if ($key == $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 call
    if (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 && self::$_includeTitlesInUrls)
    {
    if ($romanize === null)
    {
    $romanize = self::$_romanizeTitles;
    }
    $title = self::getTitleForUrl($title, $romanize);
    if ($title !== '')
    {
    # /item-title.id/ (where delimiter is '.')
    return urlencode($title) . 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));
    }
    
    $aPattern = array (
    "a" => "á|à|ạ|ả|ã|ă|ắ|ằ|ặ|ẳ|ẵ|â|ấ|ầ|ậ|ẩ|ẫ|Á|À|Ạ|Ả|Ã|Ă|Ắ|Ằ|Ặ|Ẳ|Ẵ|Â|Ấ|Ầ|Ậ|Ẩ|Ẫ",
    "o" => "ó|ò|ọ|ỏ|õ|ô|ố|ồ|ộ|ổ|ỗ|ơ|ớ|ờ|ợ|ở|ỡ|Ó|Ò|Ọ|Ỏ|Õ|Ô|Ố|Ồ|Ộ|Ổ|Ỗ|Ơ|Ớ|Ờ|Ợ|Ở|Ỡ",
    "e" => "é|è|ẹ|ẻ|ẽ|ê|ế|ề|ệ|ể|ễ|É|È|Ẹ|Ẻ|Ẽ|Ê|Ế|Ề|Ệ|Ể|Ễ",
    "u" => "ú|ù|ụ|ủ|ũ|ư|ứ|ừ|ự|ử|ữ|Ú|Ù|Ụ|Ủ|Ũ|Ư|Ứ|Ừ|Ự|Ử|Ữ",
    "i" => "í|ì|ị|ỉ|ĩ|Í|Ì|Ị|Ỉ|Ĩ",
    "y" => "ý|ỳ|ỵ|ỷ|ỹ|Ý|Ỳ|Ỵ|Ỷ|Ỹ",
    "d" => "đ|Đ",
    );
    while(list($key,$value) = each($aPattern))
    {
    $title = @ereg_replace($value, $key, $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(
    rtrim(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 whether titles will be included in URLs
    *
    * @param boolean $value
    */
    public static function includeTitlesInUrls($value)
    {
    self::$_includeTitlesInUrls = $value;
    }
    
    /**
    * Sets whether titles will be included in URLs
    *
    * @param array $value
    */
    public static function setRouteFiltersOut(array $value)
    {
    self::$_routeFiltersOut = $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);
    }
    }
    
     
  13. phungquangquang

    phungquangquang Member

    Bài viết:
    221
    Likes :
    48
    Lấy file cũ đè lên
     
  14. phungquangquang

    phungquangquang Member

    Bài viết:
    221
    Likes :
    48
     
  15. thanhbinhvhks

    thanhbinhvhks New Member

    Bài viết:
    7
    Likes :
    0
    Của mình khi thay đổi code nó lại ko chuyển sang link tiếng việt mà nó biến thành số
    ai cứu em với ạ
    memmai.com/forum/index.php?forums/2/
     
  16. Kid

    Kid VIP Member

    Bài viết:
    863
    Likes :
    947
    Bạn xem file link.php ở trên, tuy nhiên ko thay toàn bộ mà chỉ thay mỗi đoạn
    $aPattern

    Nếu ko đc thì đưa file link.php (chưa sửa gì) của bạn lên đây để mình làm giúp.
     
  17. thanhbinhvhks

    thanhbinhvhks New Member

    Bài viết:
    7
    Likes :
    0
    Của em đây ạ!
    Nhờ bác xem giúp, em chân thành cảm ơn
    Ak tiện bác cho em hỏi giúp là em có thiết lập mail gửi xác nhận đăng ký thành viên nhưng khi gửi vào gmail toàn bộ chui hết vào spam. em có tham khảo trên các diễn đàn mà không được, bên em dùng mail server riêng thuê tên miền của mắt bão.
     

    Các file đính kèm:

    • Link.rar
      Kích thước:
      6.3 KB
      Đọc:
      2
  18. thanhbinhvhks

    thanhbinhvhks New Member

    Bài viết:
    7
    Likes :
    0
    Em install addon bác gửi thì bị báo lỗi như này.
    Bác thanhthanh ak
     

    Các file đính kèm:

  19. Kid

    Kid VIP Member

    Bài viết:
    863
    Likes :
    947
    Best Answer
    @thanhbinhvhks mình làm cho bạn xong rồi nhé, đã test trên localhost url_ko_dau
     

    Các file đính kèm:

    • Link.zip
      Kích thước:
      7 KB
      Đọc:
      5
    thanhbinhvhks thích bài này.
  20. thanhbinhvhks

    thanhbinhvhks New Member

    Bài viết:
    7
    Likes :
    0
    Troy!
    Em rất rất rất chân thành cảm ơn bác.
    Bác ơi trăm ngàn cái tiện thể bác xem giúp em cái phần mail đăng ký với!
    Em có thiết lập mail admin gửi xác nhận đăng ký thành viên nhưng khi gửi vào gmail toàn bộ chui hết vào spam.
    Bên em dùng mail [email protected], port 25 mọi thứ đã thiết lập nhưng vẫn bị cho là spam bác ạ
     
comments powered by Disqus

Chia sẻ trang này

Đang tải...