Ultimate SEO URLs模块

安装

1) 上传文件

  • 将类文件“seo.class.php”放置在目录“includes/classes/”
  • 将文件“reset_seo_cache.php”复制到“admin/includes/”

2) 编辑预处理文件includes/appliation_top.php

查找:

// include the language translations
require(DIR_WS_LANGUAGES . $language . '.php');

在它的下面添加以下代码:

// Ultimate SEO URLs v2.1
include_once(DIR_WS_CLASSES . 'seo.class.php');
if ( !is_object($seo_urls) ){
  $seo_urls = new SEO_URL($languages_id);
}

3) 编辑includes/functions/html_output.php

查找 tep_href_link()函数:

////
// The HTML href link wrapper function
function tep_href_link($page = '', $parameters = '', $connection = 'NONSSL',
$add_session_id = true, $search_engine_safe = true) {
  global $request_type, $session_started, $SID;

  if (!tep_not_null($page)) {
    die('<br><br><font color="#ff0000"><b>Error!</b></font><br><br><b>Unable to determine the page link!<br><br>');
  }

  if ($connection == 'NONSSL') {
    $link = HTTP_SERVER . DIR_WS_HTTP_CATALOG;
  } elseif ($connection == 'SSL') {
    if (ENABLE_SSL == true) {
      $link = HTTPS_SERVER . DIR_WS_HTTPS_CATALOG;
    } else {
      $link = HTTP_SERVER . DIR_WS_HTTP_CATALOG;
    }
  } else {
    die('<br><br><font color="#ff0000"><b>Error!</b></font><br><br><b>Unable to determine connection method on a link!<br><br>Known methods: NONSSL SSL</b><br><br>'); 
  }

  if (tep_not_null($parameters)) {
    $link .= $pae . '?' . tep_output_string($parameters);
    $separator = '&';
  } else {
    $link .= $page;
    $separator = '?';
  }

   while ( (substr($link, -1) == '&') || (substr($link, -1) == '?') ) $link = substr($link, 0, -1);

  // Add the session ID when moving from different HTTP and HTTPS servers, or when SID is defined
  if ( ($add_session_id == true) && ($session_started == true) && (SESSION_FORCE_COOKIE_USE == 'False') ) {
    if (tep_not_null($SID)) {
      $_sid = $SID;
    } elseif ( ( ($request_type == 'NONSSL') && ($connection == 'SSL') && (ENABLE_SSL == true) ) || ( ($request_type == 'SSL') && ($connection == 'NONSSL') ) ) {
      if (HTTP_COOKIE_DOMAIN != HTTPS_COOKIE_DOMAIN) {
        $_sid = tep_session_name() . '=' . tep_session_id();
      }
    }
  }

  if ( (SEARCH_ENGINE_FRIENDLY_URLS == 'true') && ($search_engine_safe == true) ) {
    while (strstr($link, '&&')) $link = str_replace('&&', '&', $link);
    $link = str_replace('?', '/', $link);
    $link = str_replace('&', '/', $link);
    $link = str_replace('=', '/', $link);
    $separator = '?';
  }

  if (isset($_sid)) {
    $link .= $separator . $_sid;
  }

  return $link;
}

替换此函数为:

////
// Ultimate SEO URLs v2.1
// The HTML href link wrapper function
function tep_href_link($page = '', $parameters = '', $connection = 'NONSSL', $add_session_id = true, $search_engine_safe = true) {
  global $seo_urls;

  if ( !is_object($seo_urls) ){
    if ( !class_exists('SEO_URL') ){
      include_once(DIR_WS_CLASSES . 'seo.class.php');
    }

    global $languages_id;
    $seo_urls = new SEO_URL($languages_id);
  }

  return $seo_urls->href_link($page, $parameters, $connection, $add_session_id);
}

4) 编辑admin/categories.php

查找代码:

$action = (isset($HTTP_GET_VARS['action']) ? $HTTP_GET_VARS['action'] : '');

在其下添加:

// Ultimate SEO URLs v2.1
// If the action will affect the cache entries
if ( eregi("(insert|update|setflag)", $action) ) include_once('includes/reset_seo_cache.php');

5) 编辑admin/includes/functions/general.php

将以下代码添加到?>标签的上面:

// Function to reset SEO URLs database cache entries
// Ultimate SEO URLs v2.1
function tep_reset_cache_data_seo_urls($action){
  switch ($action){
    case 'reset':
      tep_db_query("DELETE FROM cache WHERE cache_name LIKE '%seo_urls%'");
      tep_db_query("UPDATE configuration SET configuration_value='false' WHERE configuration_key='SEO_URLS_CACHE_RESET'");
      break;
    default:
      break;
  }

  # The return value is used to set the value upon viewing
  # It's NOT returining a false to indicate failure!!
  return 'false';
}

6) 编辑.htaccess文件

.htaccess 文件必须放置在“catalog”目录下,如果.htaccess 文件不存在,请先创建该文件。

如果你的网站前台文件放置在“directory”目录下,那么你需要使用下面的代码作为.htacess 文件 的内容,同时将“RewriteBase /directory/”中的“diretory”替换成你的真实目录。

.htaccess 文件内容如下:

Options +FollowSymLinks
RewriteEngine On
RewriteBase /directory/
RewriteRule ^(.*)-p-(.*).html$ product_info.php?products_id=$2&%{QUERY_STRING} RewriteRule ^(.*)-c-(.*).html$ index.php?cPath=$2&%{QUERY_STRING}
RewriteRule ^(.*)-m-([0-9]+).html$ index.php?manufacturers_id=$2&%{QUERY_STRING} RewriteRule ^(.*)-pi-([0-9]+).html$ popup_image.php?pID=$2&%{QUERY_STRING} RewriteRule ^(.*)-t-([0-9]+).html$ articles.php?tPath=$2&%{QUERY_STRING} RewriteRule ^(.*)-a-([0-9]+).html$ article_info.php?articles_id=$2&%{QUERY_STRING} RewriteRule ^(.*)-pr-([0-9]+).html$ product_reviews.php?products_id=$2&%{QUERY_STRING}
RewriteRule ^(.*)-pri-([0-9]+).html$
product_reviews_info.php?products_id=$2&%{QUERY_STRING}
RewriteRule ^(.*)-i-([0-9]+).html$ information.php?info_id=$2&%{QUERY_STRING}
RewriteRule ^(.*)-links-(.*).html$ links.php?lPath=$2&%{QUERY_STRING}

如果你的网站前台文件放置在站点根目录(osCommerce MS2.2 以前的版本),那么请使用下面的 代码作为.htaccess 文件的内容:

Options +FollowSymLinks
RewriteEngine On
RewriteBase /

RewriteRule ^(.*)-p-(.*).html$ product_info.php?products_id=$2&%{QUERY_STRING} RewriteRule ^(.*)-c-(.*).html$ index.php?cPath=$2&%{QUERY_STRING}
RewriteRule ^(.*)-m-([0-9]+).html$ index.php?manufacturers_id=$2&%{QUERY_STRING} RewriteRule ^(.*)-pi-([0-9]+).html$ popup_image.php?pID=$2&%{QUERY_STRING} RewriteRule ^(.*)-t-([0-9]+).html$ articles.php?tPath=$2&%{QUERY_STRING} RewriteRule ^(.*)-a-([0-9]+).html$ article_info.php?articles_id=$2&%{QUERY_STRING} RewriteRule ^(.*)-pr-([0-9]+).html$ product_reviews.php?products_id=$2&%{QUERY_STRING}
RewriteRule ^(.*)-pri-([0-9]+).html$
product_reviews_info.php?products_id=$2&%{QUERY_STRING}
RewriteRule ^(.*)-i-([0-9]+).html$ information.php?info_id=$2&%{QUERY_STRING}
RewriteRule ^(.*)-links-(.*).html$ links.php?lPath=$2&%{QUERY_STRING}

参数

Ultimate SEO URLS 插件的参数在后台的 Configuration->SEO URLs 里,

参数 默认值 说明
Enable SEO URLs true 开启/关闭 SEO URLs 插件
Add cPath to product URLs false 是否将产品分类路径追加到产品 URL 上 例:some-product-p-1.html?cPath=xx
Add category parent to begining of URLs true 是否在产品 URL 前面添加上级分类的名称 例:parent-category-p-1.html
Choose URL Rewrite Type Rewrite URL 重写方式,只支持 Apache Rewrite 方式
Filter Short Words 3 过滤长度小于多少的词
Output W3C valid URLs (parameter string) true 输出 W3C 标准的 URL
Enable SEO cache to save queries true 是否开启 SEO 缓存
Enable product cache true 是否开启产品缓存
Enable categories cache true 是否开启产品分类缓存
Enable manufacturers cache true 是否开启制造商缓存
Enable articles cache true 是否开启文章缓存,仅限已安装 Article 文章模块
Enable information cache true 是否开启信息页面缓存,仅限已安装 information 信息模块
Enable topics cache true 是否开启话题缓存,仅限已安装 topics 话题模块
Enable automatic redirects true 是否启用自动跳转,当以旧的 URL 访问时会自动以 301 方式跳转到新 URL
Enter special character conversions 特殊字符对应表
格式: char=>conv, char2=>conv2, char3=>conv3
提示: 多个字符替换方案之间用逗号分隔
Remove all non-alphanumeric characters false 是否删除识别关键字前的所有非数字字符 例:some-product-p-1.html 将转变成 someproduct-p-1.html
Reset SEO URLs Cache false 重置 SEO URLs 缓存

提示:

重置 SEO URLs 缓存,需要选择“reset”然后点击“update”按钮

代码分析

动态页面的 URL 静态化,实际为网址重写(URL Rewrite),即指定 URL 规则让 Apache 按新 的 URL 规则进行解析重定向(具体代码请见安装第 6 步:“编辑.htaccess 文件”)。但要做到完全 静态化,则必须在程序中能够轻松地得到指定页面的静态 URL。

所以我们将分析的重点放在静态 URL 的如何得到上面,因为 osCommerce 的 URL 生成都是由 tep_href_link 函数实现,所以我们的 分析重点也就理所当然地放在了“tep_href_link”函数的分析上。

Utimate SEO URLs(以下简称SEO)修改了原有的“tep_href_link”函数,最主要是下面这段代码:

return $seo_urls->href_link($page, $parameters, $connection, $add_session_id);

其中$seo_urls 是 SEO 类的对象,可以看出新的 tep_href_link 函数,将实现的细节直接转移到了 SEO 类的方法 href_link 上了。

我们先不直接查看 href_link 方法,首先分析一下 SEO 类的初始化 方法即 SEO_URL 方法,因为接下来你可以看到在具体分析 href_link 方法时,将使用到这里讲的 内容。

SEO_URL 类 includes/classes/seo.class.php

// SEO类初始化以$languages_id为参数,即需指定 语言类型。因为不同的语言对应于不同的产品名称/分类名称,而 URL 里会使用到这些名称,所以 SEO 类即使是 在同一个产品的处理上,如果是不同语言的情况下,也可能会生成不同的 URL
function SEO_URL($languages_id){
  global $session_started, $SID;

  $this->installer = new SEO_URL_INSTALLER;
  $this->DB = new SEO_DataBase(DB_SERVER, DB_SERVER_USERNAME, DB_DATABASE, DB_SERVER_PASSWORD);

  // SEO类所在的文件除了SEO类以外,还有两个类,SEO_URL_INSTALLER类是其中之一,SEO_DataBase 类是另外的一个类。这两个类都是 SEO 类的辅助类

  // 其中SEO_URL_INSTALLER类负责SEO类的安装及清除(处理SEO的参数选项以及SEO缓存表等),Utimate SEO URLs插件之所以不像其它插件那样需要手工执行SQL语句,就是因为SEO_URL_INSTALLER类可以判断 SEO 类是否已经安装,并且会自动安装。感兴趣的读者可以仔细研究它的原理。

  // SEO_DataBase 类则是 SEO 类专属的数据库访问类,它封装了 Query 、FetchArray 、NumRows 、 InsertID 、Free 、Slashes 、DBPerform 等方法,其中 DBPerform 方法用于快速执行新增或更新操作。

  $this->languages_id = (int)$languages_id;
  $this->data = array();
  $this->turnOffBrokenUrls(); // 关闭 osCommerce 自带的 SEO 功能选项
  $seo_pages = array(
    FILENAME_DEFAULT,
    FILENAME_PRODUCT_INFO,
    FILENAME_POPUP_IMAGE,
    FILENAME_PRODUCT_REVIEWS,
    FILENAME_PRODUCT_REVIEWS_INFO
  );

  // $seo_pages变量是一个所有需要进行SEO静态化的文件列表,也就是就SEO类有对应的URL改写规则生 成该文件的静态 URL,如果文件不在此列表里,那么在 href_link 方法里会将使用不同的方法得到 URL

  if ( defined('FILENAME_ARTICLES') ) $seo_pages[] = FILENAME_ARTICLES;
  if ( defined('FILENAME_ARTICLE_INFO') ) $seo_pages[] = FILENAME_ARTICLE_INFO;
  if ( defined('FILENAME_INFORMATION') ) $seo_pages[] = FILENAME_INFORMATION;
  if ( defined('FILENAME_LINKS') ) $seo_pages[] = FILENAME_LINKS;

  $this->attributes = array(
    'PHP_VERSION' => PHP_VERSION,
    'SESSION_STARTED' => $session_started,
    'SID' => $SID,
    'SEO_ENABLED' => defined('SEO_ENABLED') ? SEO_ENABLED : 'false',
    'SEO_ADD_CPATH_TO_PRODUCT_URLS' => defined('SEO_ADD_CPATH_TO_PRODUCT_URLS') ? SEO_ADD_CPATH_TO_PRODUCT_URLS : 'false',
    'SEO_ADD_CAT_PARENT' => defined('SEO_ADD_CAT_PARENT') ? SEO_ADD_CAT_PARENT : 'true',
    'SEO_URLS_USE_W3C_VALID' => defined('SEO_URLS_USE_W3C_VALID') ? SEO_URLS_USE_W3C_VALID : 'true',
    'USE_SEO_CACHE_GLOBAL' => defined('USE_SEO_CACHE_GLOBAL') ? USE_SEO_CACHE_GLOBAL : 'false',
    'USE_SEO_CACHE_PRODUCTS' => defined('USE_SEO_CACHE_PRODUCTS') ? USE_SEO_CACHE_PRODUCTS : 'false',
    'USE_SEO_CACHE_CATEGORIES' => defined('USE_SEO_CACHE_CATEGORIES') ? USE_SEO_CACHE_CATEGORIES : 'false',
    'USE_SEO_CACHE_MANUFACTURERS' => defined('USE_SEO_CACHE_MANUFACTURERS') ? USE_SEO_CACHE_MANUFACTURERS : 'false',
    'USE_SEO_CACHE_ARTICLES' => defined('USE_SEO_CACHE_ARTICLES') ? USE_SEO_CACHE_ARTICLES : 'false',
    'USE_SEO_CACHE_TOPICS' => defined('USE_SEO_CACHE_TOPICS') ? USE_SEO_CACHE_TOPICS : 'false',
    'USE_SEO_CACHE_INFO_PAGES' => defined('USE_SEO_CACHE_INFO_PAGES') ? USE_SEO_CACHE_INFO_PAGES : 'false',
    'USE_SEO_CACHE_LINKS' => defined('USE_SEO_CACHE_LINKS') ? USE_SEO_CACHE_LINKS : 'false',
    'USE_SEO_REDIRECT' => defined('USE_SEO_REDIRECT') ? USE_SEO_REDIRECT : 'false',
    'SEO_REWRITE_TYPE' => defined('SEO_REWRITE_TYPE') ? SEO_REWRITE_TYPE : 'false',
    'SEO_URLS_FILTER_SHORT_WORDS' => defined('SEO_URLS_FILTER_SHORT_WORDS') ? SEO_URLS_FILTER_SHORT_WORDS : 'false',
    'SEO_CHAR_CONVERT_SET' => defined('SEO_CHAR_CONVERT_SET') ? $this->expand(SEO_CHAR_CONVERT_SET) : 'false',
    'SEO_REMOVE_ALL_SPEC_CHARS' => defined('SEO_REMOVE_ALL_SPEC_CHARS') ? SEO_REMOVE_ALL_SPEC_CHARS : 'false',
    'SEO_PAGES' => $seo_pages,
    'SEO_INSTALLER' => $this->installer->attributes
  );

  // $attributes成员几乎完全是Ultimate SEO URLs所有参数的复制

  $this->base_url = HTTP_SERVER . DIR_WS_HTTP_CATALOG;
  $this->base_url_ssl = HTTPS_SERVER . DIR_WS_HTTPS_CATALOG; // SEO 类可以根据用户的需要生成 NOSSL 以及 SSL 的链接

  $this->cache = array();
  $this->timestamp = 0;
  $this->reg_anchors = array(
    'products_id' => '-p-',
    'cPath' => '-c-',
    'manufacturers_id' => '-m-',
    'pID' => '-pi-',
    'tPath' => '-t-',
    'articles_id' => '-a-',
    'products_id_review' => '-pr-',
    'products_id_review_info' => '-pri-',
    'info_id' => '-i-',
    'lPath' => '-links-'
  );

  /*
  $reg_anchors 成员是 SEO 类的主角,即 URL 改写规则,可以看到这里的规则必须与在.htaccess 文件里
  应用的规则完全一致,细心的读者一定已经发现,Utimate SEO URLs 插件生成的 URL 都有一个规律,即“名 称”+“关键字”+“识别 ID”,也正因为如此,SEO 类的 URL 改写规则才能如此简单。
  */

  $this->performance = array(
    'NUMBER_URLS_GENERATED' => 0,
    'NUMBER_QUERIES' => 0,
    'NUMBER_STANDARD_URLS_GENERATED' => 0,
    'TOTAL_CACHED_PER_PAGE_RECORDS' => 0,
    // $performance用于统计SEO类的性能
    'CACHE_QUERY_SAVINGS' => 0,
    'TOTAL_TIME' => 0,
    'TIME_PER_URL' => 0,
    'QUERIES' => array()
  );

  if ($this->attributes['USE_SEO_CACHE_GLOBAL'] == 'true'){
    $this->cache_file = 'seo_urls_v2_';
    $this->cache_gc();

    if ( $this->attributes['USE_SEO_CACHE_PRODUCTS'] == 'true' ) $this->generate_products_cache();
    if ( $this->attributes['USE_SEO_CACHE_CATEGORIES'] == 'true' ) $this->generate_categories_cache();
    if ( $this->attributes['USE_SEO_CACHE_MANUFACTURERS'] == 'true' ) $this->generate_manufacturers_cache();
    if ( $this->attributes['USE_SEO_CACHE_ARTICLES'] == 'true' && defined('TABLE_ARTICLES_DESCRIPTION')) $this->generate_articles_cache();
    if ( $this->attributes['USE_SEO_CACHE_TOPICS'] == 'true' && defined('TABLE_TOPICS_DESCRIPTION')) $this->generate_topics_cache();
    if ( $this->attributes['USE_SEO_CACHE_INFO_PAGES'] == 'true' && defined('TABLE_INFORMATION')) $this->generate_information_cache();
    if ( $this->attributes['USE_SEO_CACHE_LINK_PAGES'] == 'true' && defined('TABLE_LINK_CATEGORIES')) $this->generate_links_cache();
  } # end if // 上面的代码用于生成 URL 缓存

  if ($this->attributes['USE_SEO_REDIRECT'] == 'true'){
    $this->check_redirect();
  } # end if
} # end constructor

好了,看完了初始化方法,下面让我们来看 href_link 方法吧:

function href_link($page = '', $parameters = '', $connection = 'NONSSL', $add_session_id = true){
  // Some sites have hardcoded &amp;
  $parameters = str_replace('&amp;', '&', $parameters);
  $this->start($this->timestamp);
  $this->performance['NUMBER_URLS_GENERATED']++;

  if ( !in_array($page, $this->attributes['SEO_PAGES']) || $this->attributes['SEO_ENABLED'] == 'false' ) { // 如果没有指定页面的 URL 规则就需要使用默认的 URL 方案
    return $this->stock_href_link($page, $parameters, $connection,
    $add_session_id);
  }

  $link = $connection == 'NONSSL' ? $this->base_url : $this->base_url_ssl;
  $separator = '?';

  if ($this->not_null($parameters)) {
    $link .= $this->parse_parameters($page, $parameters,
    $separator); // parse_parameters 方法分析传入的参数,根据 URL 规则得到优化后的 URL
  } else {
    $link .= $page;
  }

  $link = $this->add_sid($link, $add_session_id, $connection, $separator); //add_sid方法用于决定是否在URL里追加会话ID
  $this->stop($this->timestamp, $time);
  $this->performance['TOTAL_TIME'] += $time;

  switch($this->attributes['SEO_URLS_USE_W3C_VALID']){
    case ('true'): // 当设置了生成的 URL 必须兼容 W3C 时执行下面的程序
      if (!isset($_SESSION['customer_id']) &&
        defined('ENABLE_PAGE_CACHE') && ENABLE_PAGE_CACHE == 'true' && class_exists('page_cache')){
        return $link;
      } else {
        return htmlspecialchars(utf8_encode($link));
      }
      break;
    case ('false'):
      return $link;
      break;
  }
} # end function

根据上面的代码,具体得到 URL 的方法是 parse_parameters,所以我们需要继续分析 parse_parameters 方法:

function parse_parameters($page, $params, &$separator){
  $p = @explode('&', $params);
  krsort($p);

  $container = array();
  foreach ($p as $index => $valuepair){
    $p2 = @explode('=', $valuepair);
    switch($p2[0]){
      //这里判断GET参数,选择适当的URL替换规则
      case 'products_id': // 适用产品页 URL 替换规则
        switch(true){
          case ( $page == FILENAME_PRODUCT_INFO && !$this->is_attribute_string($p2[1]) ):
            // make_url方法实现了URL生成过程
             $url = $this->make_url($page, urlencode($this->get_product_name($p2[1])), $p2[0], $p2[1], '.html', $separator);
            break;
          case ( $page == FILENAME_PRODUCT_REVIEWS ):
            // 产品评论页
            $url = $this->make_url($page, urlencode($this->get_product_name($p2[1])), 'products_id_review', $p2[1], '.html', $separator);
            break;
          case ( $page == FILENAME_PRODUCT_REVIEWS_INFO):
            //评论详细页
            $url = $this->make_url($page, urlencode($this->get_product_name($p2[1])), 'products_id_review_info', $p2[1], '.html', $separator);
            break;
          default:
            $container[$p2[0]] = $p2[1];
            break;
        } # end switch
        break;
      case 'cPath': // 适用产品分类页 URL 替换规则
        switch(true){
          case ($page == FILENAME_DEFAULT):
            $url = $this->make_url($page, urlencode($this->get_category_name($p2[1])), $p2[0], $p2[1], '.html', $separator);
            break;
          case ( !$this->is_product_string($params)):
            if ($this->attributes['SEO_ADD_CPATH_TO_PRODUCT_URLS'] == 'true' ){
               $container[$p2[0]] = $p2[1];
            }
            break;
          default:
            $container[$p2[0]] = $p2[1];
            break;
        } # end switch
        break;
      case 'manufacturers_id': // 适用制造商页 URL 替换规则
        switch(true){
          case ($page == FILENAME_DEFAULT && !$this->is_cPath_string($params) && !$this->is_product_string($params) ):
            $url = $this->make_url($page, urlencode($this->get_manufacturer_name($p2[1])), $p2[0], $p2[1], '.html', $separator);
            break;
          case ($page == FILENAME_PRODUCT_INFO):
            break;
          default:
            $container[$p2[0]] = $p2[1];
            break;
        } # end switch
        break;
      case 'pID': // 适用产品图片页 URL 替换规则
        switch(true){
          case ($page == FILENAME_POPUP_IMAGE):
            $url = $this->make_url($page, urlencode($this->get_product_name($p2[1])), $p2[0], $p2[1], '.html', $separator);
            break;
          default:
            $container[$p2[0]] = $p2[1];
            break;
        } # end switch
        break;
      case 'tPath': // 适用文章页 URL 替换规则(需安装文章 Article 模块)
        switch(true){
        case ($page == FILENAME_ARTICLES):
          $url = $this->make_url($page, urlencode($this->get_topic_name($p2[1])), $p2[0], $p2[1], '.html', $separator);
          break;
        default:
          $container[$p2[0]] = $p2[1];
          break;
      } # end switch
      break;
      //ojp lPath
      case 'lPath': // 适用链接页 URL 替换规则(需安装链接 Link 模块)
        switch(true){
          case ($page == FILENAME_LINKS):
            $url = $this->make_url($page, urlencode($this->get_link_name($p2[1])), $p2[0], $p2[1], '.html', $separator);
            break;
          default:
            $container[$p2[0]] = $p2[1];
            break;
        } # end switch
        break;
      case 'articles_id': // 适用详细文章内容页 URL 替换规则(需安装文章 Article 模块)
        switch(true){
          case ($page == FILENAME_ARTICLE_INFO):
            $url = $this->make_url($page, urlencode($this->get_article_name($p2[1])), $p2[0], $p2[1], '.html', $separator);
            break;
          default:
            $container[$p2[0]] = $p2[1];
            break;
        } # end switch
        break;
      case 'info_id': // 适用介绍页 URL 替换规则(需安装信息Information 模块)
        switch(true){
          case ($page == FILENAME_INFORMATION):
            $url = $this->make_url($page, urlencode($this->get_information_name($p2[1])), $p2[0], $p2[1], '.html', $separator);
            break;
          default:
            $container[$p2[0]] = $p2[1];
            break;
        } # end switch
        break;
      default:
        if( isset($p2[1]) ) $container[$p2[0]] = $p2[1];
        break;
    } # end switch
  } # end foreach $p

  $url = isset($url) ? $url : $page;
  if ( sizeof($container) > 0 ){
    if ( $imploded_params = $this->implode_assoc($container) ){
      $url .= $separator . $this->output_string($imploded_params );
      $separator = '&';
    } 
  }

  return $url;
} # end function

以下是 make_url 方法的代码:

function make_url($page, $string, $anchor_type, $id, $extension = '.html', &$separator){
  // 参数
  // $page:页面(保留用法)
  // $string:URL前导文本
  // $anchor_type:识别符
  // $id:识别ID
  // $extension:扩展名
  // $separator:分隔符(保留用法)  
  // Right now there is but one rewrite method since cName was dropped
  // In the future there will be additional methods here in the switch
  switch ( $this->attributes['SEO_REWRITE_TYPE'] ){
    case 'Rewrite':
      return $string . $this->reg_anchors[$anchor_type] . $id .  $extension;
      break;
    default:
      break;
  } # end switch
} # end function

因为在指定参数时,需要根据 ID,得到名称(如指定产品 ID,最后生成的 URL 前导为产品 名称),所以 Ultimate SEO URLs 使用了缓存来保存相关信息,以减少查询数据库的次数提高效率。

Ultimate SEO URLs 将每个此类功能都封装成单独的函数,如 get_product_name 函数用于获得指定 ID 的产品名称,我们下面以 get_product_name 函数为例介绍缓存技术在 Ultimate SEO URLs 里的应用,其它类似功能请读者参考源码。

function get_product_name($pID){
  switch(true){
    case ($this->attributes['USE_SEO_CACHE_GLOBAL'] == 'true' && defined('PRODUCT_NAME_' . $pID)): // 当开启了全局变量选项时,需要通过全局变量获得缓存的数据
      $this->performance['CACHE_QUERY_SAVINGS']++;
      $return = constant('PRODUCT_NAME_' . $pID);
      $this->cache['PRODUCTS'][$pID] = $return;
      break;
    case ($this->attributes['USE_SEO_CACHE_GLOBAL'] == 'true' && isset($this->cache['PRODUCTS'][$pID])):
      // 如果没有开启全局变量选项,需要访问成员 cache 数 组的值获得缓存数据
      $this->performance['CACHE_QUERY_SAVINGS']++;
      $return = $this->cache['PRODUCTS'][$pID];
      break;
    default: // 如果没有缓存数据,则必须查询数据库
      $this->performance['NUMBER_QUERIES']++; $sql = "SELECT products_name as pName FROM ".TABLE_PRODUCTS_DESCRIPTION." WHERE products_id='".(int)$pID."' AND language_id='".(int)$this->languages_id."' LIMIT 1";
      $result = $this->DB->FetchArray( $this->DB->Query( $sql ));

      $pName = $this->strip( $result['pName'] );
      $this->cache['PRODUCTS'][$pID] = $pName; // 保存结果至成员cache 数组实现缓存
      $this->performance['QUERIES']['PRODUCTS'][] = $sql;
      $return = $pName;
      break;
    } # end switch

    return $return;
  } # end function

提示:

get_product_name 方法里,Ultimate SEO URLs 使用了 switch 语句替代 if...else 语句的代码习惯, 因为在 PHP 较代版本前,有分析称这样可以提高代码效率,但在新版 PHP 里,这种优点已经是 不存在的了。

不过诸位可以在适当的时候使用一下这种使用 switch(true)代替 if...else 的代码风格,因为这种代码 风格可能会使条理更清晰一些。

通过上面的介绍,我们已经了解了在指定了 URL 替换规则时的 URL 该如何生成,接下来介绍没 有指定 URL 替换规则时的处理。

function stock_href_link($page = '', $parameters = '', $connection = 'NONSSL', $add_session_id = true, $search_engine_safe = true) {
  global $request_type, $session_started, $SID;

  if (!$this->not_null($page)) {
    die('</td></tr></table></td></tr></table><br><br><font color="#ff0000"><b>Error!</b></font><br><br><b>Unable to determine the page link!<br><br>');
  }

  if ($page == '/') $page = '';
  if ($connection == 'NONSSL') { // 判断是 SSL 连接方式还是普通连接方式
    $link = HTTP_SERVER . DIR_WS_HTTP_CATALOG;
  } elseif ($connection == 'SSL') {
    if (ENABLE_SSL == true) {
      $link = HTTPS_SERVER . DIR_WS_HTTPS_CATALOG;
    } else {
      $link = HTTP_SERVER . DIR_WS_HTTP_CATALOG;
    }
  } else {
    die('</td></tr></table></td></tr></table><br><br><font color="#ff0000"><b>Error!</b></font><br><br><b>Unable to determine connection method on a link!<br><br>Known methods: NONSSL SSL</b><br><br>');
  }

  if ($this->not_null($parameters)) { // 是否设置了参数
    $link .= $page . '?' . $this->output_string($parameters); $separator = '&';
  } else {
    $link .= $page;
    $separator = '?';
  }

  while ( (substr($link, -1) == '&') || (substr($link, -1) == '?') ) $link = substr($link, 0, -1);

  if ( ($add_session_id == true) && ($session_started == true) && (SESSION_FORCE_COOKIE_USE == 'False') ) {
    if ($this->not_null($SID)) {
      $_sid = $SID;
    } elseif ( ( ($request_type == 'NONSSL') && ($connection == 'SSL') && (ENABLE_SSL == true) ) || ( ($request_type == 'SSL') && ($connection == 'NONSSL') ) ) {
      if (HTTP_COOKIE_DOMAIN != HTTPS_COOKIE_DOMAIN) {
        $_sid = $this->SessionName() . '=' . $this->SessionID();
      }
    }
  }

  if ( (SEARCH_ENGINE_FRIENDLY_URLS == 'true') && ($search_engine_safe == true) ) {
    // 如果设置了搜索引擎友好方法 Search Engine Friendly URL 选项,则需要替换掉不合要求的特殊字符
    while (strstr($link, '&&')) $link = str_replace('&&', '&', $link);
    $link = str_replace('?', '/', $link);
    $link = str_replace('&', '/', $link);
    $link = str_replace('=', '/', $link);
    $separator = '?';
  }

  switch(true){ // 追加会话 ID
    case (!isset($_SESSION['customer_id']) && defined('ENABLE_PAGE_CACHE') && ENABLE_PAGE_CACHE == 'true' && class_exists('page_cache')):
      $page_cache = true;
      $return = $link . $separator . '<osCsid>';
      break;
    case (isset($_sid)):
      $page_cache = false;
      $return = $link . $separator . tep_output_string($_sid);
      break;
    default:
      $page_cache = false;
      $return = $link;
      break;
  } # end switch

  $this->performance['NUMBER_STANDARD_URLS_GENERATED']++;
  $this->cache['STANDARD_URLS'][] = $link;
  $time = 0;
  $this->stop($this->timestamp, $time);
  $this->performance['TOTAL_TIME'] += $time;

  switch(true){
    case ($this->attributes['SEO_URLS_USE_W3C_VALID'] == 'true' && !$page_cache):
      return htmlspecialchars(utf8_encode($return)); // 输出 W3C 兼容格式的 URL
      break;
    default:
      return $return;
      break;
  }# end swtich
} # end default tep_href function

results matching ""

    No results matching ""