Location: PHPKode > projects > Joomla SEF / SEO - extending OpenSEF > core/sef.mapper.php
<?php
/**
 * JoomlaSEF for Joomla!
 * @copyright (c) 2005 The OpenSEF Project (www.opensef.org)
 * @copyright (c) 2004-2005 Xaneon Development (www.xaneon.com)
 * @license GPL http://www.gnu.org/copyleft/gpl.html
 *
 * The Auto-Mapper is responsible for creating human-friendly addresses
 * for content items. In other words, this is where the 'magic' happens,
 * turning index.php?option=com_content&task=view&id=6&Itemid=2 into
 * /news/latest/example_news_item_1.html when the original URL is
 * accessed for the first time.
 *
 * This is also an obvious candidate for site-specific customization by
 * the site developer/administrator, should they wish to implement URLs
 * that significantly differ from what's achievable with OpenSEF's
 * configuration settings. Overriding the auto-mapper means creating an
 * OpenSEF extension and subclassing the sefAutoMapper class.
 *
 * NOTE: this code is one of the likeliest places to experience a high
 * proportion of bugs in special circumstances, as of beta 2.
 */

/** Ensure this file is being included by a parent file */
defined( '_VALID_MOS' ) or die( 'Direct access to this location is not allowed.' );

@define( '_SEF_AUTOMAPPER', 'sefAutoMapper' );

/**
 * Enter description here...
 *
 */
class sefAutoMapper extends sefObject {
  var $replace = null;

  /**
   * fucntion sefautomapper
   *
   * @param object $db the database connection object
   * @param object $config an instance of JosOpenSEFConfig
   * @param object $site an instance of JosOpenSEFSite
   * @return sefAutoMapper
   */
  function sefAutoMapper( &$db, &$config, &$site ) {
    $this->sefObject( $db, $config, $site );
    $this->replace = array(
      ' / ' => '/',
      ' ' => (!empty( $this->config->encode_space_char ) ?
        $this->config->encode_space_char : '_'),
    );
  }

  /**
   * This could be considered the only public interface of this class.
   * It takes an internal Joomla URL as a parameter, attempts to
   * auto-map it, stores the result in the URL database, and returns
   * the row object.
   *
   * Note that if the auto-mapping didn't succeed an URL alias record is still
   * created, but with the Published field set to false.
   *
   * @param string $url the internal Joomla URL to auto-map
   * @return JosOpenSEFAlias the newly created URL alias record
   */
  function map( $url ) {
    global $database,$urlpoll;

    $title = $this->getContentPath( $url );
    if ($title == '/') { return; }
    $alias =& new JosOpenSEFAlias( $this->db );
    if (@$this->site->id == null) $this->site->id = -1;
    $alias->site_id = $this->site->id;
    $alias->published = ($title ? '1' : '0');
    $alias->valid = '1';
    $alias->external = $title;
    if (eregi("mosmsg=", $url)) {
      return $url;
    }
    $url = str_replace( '0/', '&limitstart=0', $url ); // Just in case...
    if (isset($urlpoll)){
      $url = $urlpoll;
    }
    parse_str( $url, $info );
    $alias->link_prio = $this->getLinkPriority($info['id'],$info['index_php?option'] );
    $alias->internal = $url;
    $alias->hits = 0; // Auto-redirect will cause a hit...
    if (!empty( $this->config->use_automap)) {
      $alias->check();
      if (!$alias->store( false )) {
        // TODO: insert failed, should not happen. Are SQL tables missing?
        die( "DEBUG: row->store() failed!" );
      }
    }
    return $alias;
  }

  /**
   * Given a section, returns the encoded form of its name or
   * title (as determined by the configuration) suitable for use
   * in a URL alias.
   *
   * @param mixed $item the section's ID or a mosSection instance
   * @return string the encoded section name or title
   */
  function getSectionURL( $item ) {
    if (is_numeric( $item )) {
      $id = $item;
      $item =& new mosSection( $this->db );
      $item->load( $id );
    }
    $title_field = $this->config->section_title_field;
    $title = ($title_field == 'name' && @$item->name ?
      @$item->name : @$item->title);
    return $this->encode( $title );
  }

  /**
   * Given a category, returns the encoded form of its name or
   * title (as determined by the configuration) suitable for use
   * in a URL alias.
   *
   * @param mixed $item the section's ID or a mosCategory instance
   * @return string the encoded category name or title
   */
  function getCategoryURL( $item ) {
    if (is_numeric( $item )) {
      $id = $item;
      $item =& new mosCategory( $this->db );
      $item->load( $id );
    }
    $title_field = $this->config->category_title_field;
    $title = ($title_field == 'name' && @$item->name ?
      @$item->name : @$item->title);
    return $this->encode( $title );
  }

  /**
   * Attempts to convert an internal Joomla URL to a friendly URL
   * alias. This is the very meat of the matter.
   *
   * @param string $str an internal Joomla URL (index.php?option=com_...)
   * @return string|null a friendly URL or null if auto-mapping failed
   */
  function getContentPath( $str ) {
    global $database, $urlpoll;
    parse_str( $str, $info );

    $title_field = $this->config->content_title_field;
    $path_type = $this->config->content_path_type;
    $page_format = $this->config->content_page_format;
    if ($page_format == '') $page_format = '%s_%d';
    $page_suffix = $this->config->encode_page_suffix;

    if (isset($info['limit'])){
      $info['limit'] = str_replace( '0/', '', $info['limit'] ); // Just in case...
    }
    $path = array();

    if (isset($info['index_php?option'])) {
    if ( $info['index_php?option'] == 'com_weblinks') {;
        if ($this->config->use_alias_links) {
          $path[] = $this->config->alias_links;
        }
        $suffix = '/';
        if (isset($info['catid']) && !$info['id']) {
              $path[] = $this->getCategoryURL( $info['catid'] );
          }
      if (isset($info['catid']) && isset( $info['id'] ) ) {
        $path[] = $this->getCategoryURL( $info['catid'] );
        $path[] = $this->getWebLinkURL( $info['id'] );
        $suffix = $page_suffix;
        $info['task'] = '';
      }
      }
      if ( $info['index_php?option'] == 'com_newsfeeds') {;
        if ($this->config->use_alias_newsfeeds) {
          $path[] = $this->config->alias_newsfeeds;
        }
        $suffix = '/';
        if (isset($info['catid'])) {
              $path[] = $this->getCategoryURL( $info['catid'] );
          }
      if (isset( $info['feedid'] ) ) {
        $catid = $this->getNewsfeedsCatURL( $info['feedid'] );
        $path[] = $this->getCategoryURL( $catid );
        $path[] = $this->getNewsfeedsURL( $info['feedid'] );
        $suffix = $page_suffix;
        $info['task'] = '';
      }
      }
      if ( $info['index_php?option'] == 'com_wrapper') {;
        if ($this->config->use_alias_wrapper) {
          $path[] = $this->config->alias_wrapper;
        }
        $suffix = '/';
        if (isset( $info['Itemid'] ) ) {
          $database->setQuery("SELECT name FROM #__menu WHERE id=".$info['Itemid']);
        $path[] = $database->loadResult();
        $suffix = $page_suffix;
        $info['task'] = '';
        }
      }
      if ( $info['index_php?option'] == 'com_banners') {;
        if ($this->config->use_alias_banner) {
          $path[] = $this->config->alias_banner;
        }
        $suffix = '/';
        if (isset($info['bid'])) {
            $path[] = $this->getBannerURL( $info['bid'] );
              $info['task'] = '';
              $suffix = $page_suffix;
          }
      }

    }
    switch ($info['task']) {

      case 'view':
        $title = $this->uniqueItemid($info['id'], $info['Itemid']);
        if ($title == '') {
          break;
      }
      if (isset( $info['limit'] ) && isset( $info['limitstart'] )) {
              $page = $info['limitstart'];
              if (!is_numeric( $page ))
                return null;
              $page = (int)$page + 1;
              if ($page > 1) {
                $title = str_replace( array( '%s', '%d' ), array( $title, $page ), $page_format );
              } else {
              // TODO: should be able to set alias direction to outgoing only?
              }
          }
          $path[] = $title;
          $suffix = $page_suffix;
        break;


        // index.php?option=com_content&task=section&id=3&Itemid=40
    case 'section':
          if ($info['id'] > 0) {
            $path[] = $this->getSectionURL( $info['id'] );
          }
      $title="";
          if (isset( $info['limit'] ) && isset( $info['limitstart'] )) {
            $page = $info['limitstart'] / $info['limit'];
            $page = (int)$page + 1;
            if (!is_numeric( $page ))
                return null;
            if ($page > 1) {
                $title = $this->config->content_page_name;
                $title = str_replace( array( '%s', '%d' ), array( $title, $page ), $page_format );
                if ($info['id'] > 0) {
                  $path[] = '/'.$title;
                } else {
                  $path[] = $title;
                }
                $suffix = $page_suffix;
              } else {
                $path[] = $info['limit'];
                $path[] = $info['limitstart'];
                $suffix = '/';
              }
            } else {
          $suffix = '/';
        }
        break;
        case 'blogsection':
          if ($info['id'] == 0){
            if ($this->config->content_blogsection != ""){
                $path[] = $this->config->content_blogsection;
            } else {
              $database->setQuery("SELECT name FROM #__menu WHERE id=".$info['Itemid']);
            $path[] = $this->encode($database->loadResult());
        }
          } else {
            $path[] = $this->getSectionURL( $info['id'] );
          }
      $title="";
          if (isset( $info['limit'] ) && isset( $info['limitstart'] )) {
            $page = $info['limitstart'] / $info['limit'];
            $page = (int)$page + 1;
            if (!is_numeric( $page ))
                return null;
            if ($page > 1) {
                $title = $this->config->content_page_name;
                $title = str_replace( array( '%s', '%d' ), array( $title, $page ), $page_format );
                $path[] = $title;
                $suffix = $page_suffix;
              } else {
                $suffix = '/';
              }
            } else {
          $suffix = '/';
        }
        break;
        // index.php?option=com_content&task=category&sectionid=3&id=7&Ite...
    case 'category':
          $cat =& new mosCategory( $this->db );
            $cat->load( $info['id'] );
            if ($path_type == 'full' && $cat->section) {
              $path[] = $this->getSectionURL( $cat->section );
              $path[] = $this->getCategoryURL( $cat );
            }
            else if ($path_type == 'section' && $cat->section) {
              $path[] = $this->getSectionURL( $cat->section );
            }
            else if ($path_type == 'category' ) {
            $path[] = $this->getCategoryURL( $cat );
            }
            $title="";
            if (isset( $info['limit'] ) && isset( $info['limitstart'] )) {
              $page = $info['limitstart'] / $info['limit'];
            $page = (int)$page + 1;
            if (!is_numeric( $page ))
                return null;
            if ($page > 1) {
                $title = $this->config->content_page_name;
                $title = str_replace( array( '%s', '%d' ), array( $title, $page ), $page_format );
                $path[] ='/'.$title;
                $suffix = $page_suffix;
              } else {
                $suffix = '/';
              }
          } elseif (isset( $info['limit'] ) && !isset( $info['limitstart'] )) {
            $suffix = '/';
          } else {
          $suffix = '/';
      }

        break;
        case 'blogcategory':
          if ($info['id'] == 0){
            if ($this->config->content_blogcategory != ""){
                $path[] = $this->config->content_blogcategory;
            } else {
              $database->setQuery("SELECT name FROM #__menu WHERE id=".$info['Itemid']);
            $path[] = $this->encode($database->loadResult());
        }
          } else {
              $cat =& new mosCategory( $this->db );
              $cat->load( $info['id'] );
              if ($path_type == 'full' && $cat->section) {
                $path[] = $this->getSectionURL( $cat->section );
                $path[] = $this->getCategoryURL( $cat );
              }
              else if ($path_type == 'section' && $cat->section) {
                $path[] = $this->getSectionURL( $cat->section );
              }
              else if ($path_type == 'category' ) {
              $path[] = $this->getCategoryURL( $cat );
              }
          }
            $title="";
            if (isset( $info['limit'] ) && isset( $info['limitstart'] )) {
              $page = $info['limitstart'] / $info['limit'];
            $page = (int)$page + 1;
            if (!is_numeric( $page ))
                return null;
            if ($page > 1) {
                $title = $this->config->content_page_name;
                $title = str_replace( array( '%s', '%d' ), array( $title, $page ), $page_format );
                $path[] = '/'.$title;
                $suffix = $page_suffix;
              } else {
                $suffix = '/';
              }
          } elseif (isset( $info['limit'] ) && !isset( $info['limitstart'] )) {
            $suffix = '/';
          } else {
          $suffix = '/';
        }

        break;

        // index.php?option=com_content&task=archivesection&id=3...
        case 'archivesection':
          if ($info['id']) {
            if ($info['task'] == 'archivesection' && $this->config->content_archivesection != ""){
                $path[] = $this->config->content_archivesection.'/';
            }
            $path[] = $this->getSectionURL( $info['id'] );
            $title="";
        if (isset( $info['limit'] ) && isset( $info['limitstart'] )) {
          $page = $info['limitstart'] / $info['limit'];
              $page = (int)$page + 1;
              if (!is_numeric( $page ))
                  return null;
              if ($page > 1) {
                  $title = $this->config->content_page_name;
                  $title = str_replace( array( '%s', '%d' ), array( $title, $page ), $page_format );
                  $path[] ='/'.$title;
                  $suffix = $page_suffix;
                } else {
                  $suffix = '/';
                }
            } else {
            $suffix = '/';
          }
          }
        break;

        // index.php?option=com_content&task=archivecategory&year=2006&month=11&module=1...
        case 'archivecategory':
          if ($info['task'] == 'archivecategory' && $this->config->content_archivecategory != ""){
              $path[] = $this->config->content_archivecategory.'/';
          }
          if (isset( $info['year'] ) && isset( $info['month'] )) {
        if ($info['year'] > 0){
          $path[] = $info['year'];
          $path[] = $info['month'];
          $path[] = $info['module'];
        }
        $suffix = '/';
          }
        break;

      default:
        break;
    }

    if (count( $path ) > 0) {
      $urls = '';
      foreach ($path as $item) {
        if ($item != '')
          $urls .= '/' . $this->encode( $item );
      }
      if (!empty( $suffix ))
        $urls .= $suffix;
        $urls = str_replace( '//', '/', $urls ); // Just in case...
      return $urls;
    }
    return null;
  }

  /**
   * Given a Weblink item, returns the encoded form of its title or
   * title alias (as determined by the configuration) suitable for use
   * in a URL alias.
   *
   * @param mixed $item the weblink item's ID
   * @return string the encoded title or title alias
   */
  function getWebLinkURL( $item ) {
    if (is_numeric( $item )) {
      $id = $item;
      $item =& new getWeblink( $this->db );
      $item->load( $id );
    }
    $title = ($title_field == 'title' && $item->title ?
      $item->title : $item->title );
    return $this->encode( $title );
  }
  /**
   * Given a Newsfeed item, returns the encoded form of its title or
   * title alias (as determined by the configuration) suitable for use
   * in a URL alias.
   *
   * @param mixed $item the newsfeed item's ID
   * @return string the encoded title or title alias
   */
  function getNewsfeedsURL( $item ) {
    if (is_numeric( $item )) {
      $id = $item;
      $item =& new getNewsfeeds( $this->db );
      $item->load( $id );
    }
    $title = ($title_field == 'name' && $item->name ?
      $item->name : $item->name );
    return $this->encode( $title );
  }
  /**
   * Get the Newsfeed Category
   *
   * @param mixed $item the newsfeed item's ID
   * @return cat ID
   */
  function getNewsfeedsCatURL( $item ) {
    if (is_numeric( $item )) {
      $id = $item;
      $item =& new getNewsfeeds( $this->db );
      $item->load( $id );
    }
    $catid = $item->catid;
    return $catid;
  }

  /**
   * Given a Banner item, returns the encoded form of its title or
   * title alias (as determined by the configuration) suitable for use
   * in a URL alias.
   *
   * @param mixed $item the banner item's ID
   * @return string the encoded title or title alias
   */
  function getBannerURL( $item ) {
    if (is_numeric( $item )) {
      $id = $item;
      $item =& new getBanner( $this->db );
      $item->load( $id );
    }
    $title = $item->name;
    return $this->encode( $title );
  }

  /**
   * Given a content item, returns the encoded form of its title or
   * title alias (as determined by the configuration) suitable for use
   * in a URL alias.
   *
   * @param mixed $item the content item's ID
   * @param string $itemid
   * @return string the encoded title or title alias
   */
  function uniqueItemid($info,$itemid){
    global $database;

    $sefstring="";
    $title_field = $this->config->content_title_field;
    $cat_field = $this->config->category_title_field;
    $sec_field = $this->config->section_title_field;
    $path_type = $this->config->content_path_type;
    $date_format = $this->config->append_date_format;

    if ($this->config->append_itemid OR $this->config->append_date OR $this->config->append_contentid) {
    $query = "SELECT i.id AS item_id, i.$title_field AS item_alias, i.title AS item_title, DATE_FORMAT(i.created,'$date_format') AS item_date, c.$cat_field AS category_name, c.title AS category_title, s.$sec_field AS section_name, s.title AS section_title "
      ."FROM #__content AS i "
      ."LEFT JOIN #__categories AS c "
      ."ON i.catid=c.id "
      ."LEFT JOIN #__sections AS s "
      ."ON c.section=s.id "
      ."WHERE i.id=".$info;
  } else {
  $query = "SELECT i.id AS item_id, i.$title_field AS item_alias, i.title AS item_title, c.$cat_field AS category_name, c.title AS category_title, s.$sec_field AS section_name, s.title AS section_title "
      ."FROM #__content AS i "
      ."LEFT JOIN #__categories AS c "
      ."ON i.catid=c.id "
      ."LEFT JOIN #__sections AS s "
      ."ON c.section=s.id "
      ."WHERE i.id=".$info;
  }
  $database->setQuery($query);
  if ($database->loadResult() ) {
    $result = $database->loadObjectList();
    $row = $result[0];

    $art_title = ($title_field == 'title_alias' && @$row->item_alias ? @$row->item_alias : @$row->item_title );
      $item_title = $this->encode( $art_title );

      $sec_title = ($sec_field == 'name' && @$row->section_name ? @$row->section_name : @$row->section_title);
      $section_name = $this->encode( $sec_title );

      $cat_title = ($cat_field == 'name' && @$row->category_name ? @$row->category_name : @$row->category_title);
      $category_name = $this->encode( $cat_title );
  }
    if ($this->config->append_date && $section_name !="" && $category_name !="") {
    $item_title .= " ".$row->item_date;
  }
  if ($this->config->append_contentid && $section_name !="" && $category_name !="") {
    $item_id = $row->item_id;
    $item_title .= " ".$item_id;
  }
  if ($this->config->append_itemid && $section_name !="" && $category_name !="" ) {
    $item_title .= " ".$itemid;
  }
  if ($section_name!="" && $category_name!="") {
    if ($path_type == 'full' || $path_type == 'section') {
      $sefstring .= $section_name."/";
    }
        if ($path_type == 'full' || $path_type == 'category') {
        $sefstring .= $category_name."/";
      }
      $sefstring .= $item_title;
  } else {
    if ($this->config->category_title_field == "name" || $this->config->section_title_field == 'name') {
      $sefstring .= $item_title;
    } else {
      $database->setQuery("SELECT m.name AS menu_name "
      ."FROM #__menu AS m "
      ."LEFT JOIN #__content AS c "
      ."ON m.componentid=c.id "
      ."WHERE m.type='content_typed' "
      ."AND c.id=".$info);
      if ($database->loadResult()) {
        $result = $database->loadObjectList();
        $row = $result[0];
        $menu_name = $this->encode($row->menu_name);
        $sefstring .= $menu_name;
      } else {
        $sefstring .= $item_title;
      }
    }
  }
  return $sefstring;
  }

  function getLinkPriority ($id, $option) {
  global $database;

  /*
  1CIL = 1) Content Item Link
  2TCL = 2) Typed Content Link
  3CSL = 3) Content Section List
  4CCL = 4) Content Category List
  5CSBs = 5) Content Section Blog (specific)
  6CCBs = 6) Content Category Blog (specific)
  7CSBg = 7) Content Section Blog (global)
  8CCBg = 8 ) Content Category Blog (global)
  */

  $link_prio = "";

  // 1) Content Item Link
  if ($link_prio == "") {
    $database->setQuery( "SELECT id "
      ."FROM #__menu "
      ."WHERE type='content_item_link' AND published='1' AND link='index.php?option=$option&task=view&id=$id'" );
      if ($database->loadResult()) {
        $link_prio = '1';
      }
  }

  // 2) Typed Content Link
  if ($link_prio == "") {
    $database->setQuery( "SELECT id "
      ."FROM #__menu "
      ."WHERE type='content_typed' AND published='1' AND link='index.php?option=$option&task=view&id=$id'" );
      if ($database->loadResult()) {
        $link_prio = '2';
      }
  }

  // 3) Content Section List
  if ($link_prio == "") {
    $database->setQuery( "SELECT m.id "
      ."FROM #__content AS i "
      ."LEFT JOIN #__sections AS s ON i.sectionid=s.id "
      ."LEFT JOIN #__menu AS m ON m.componentid=s.id "
      ."WHERE m.type='content_section' AND m.published='1' AND i.id='$id'" );
      if ($database->loadResult()) {
        $link_prio = '3';
      }
  }

  // 4) Content Category List
  if ($link_prio == "") {
    $database->setQuery( "SELECT sectionid, catid "
      ."FROM #__content WHERE id='$id'" );
    $row = null;
    $database->loadObject( $row );

    $database->setQuery("SELECT id "
      ."FROM #__menu "
      ."WHERE type='content_category' AND published='1' AND link='index.php?option=$option&task=category&sectionid=$row->sectionid&id=$row->catid'");
      if ($database->loadResult()) {
        $link_prio = '4';
      }
  }

  // 5) Content Section Blog (specific)
  if ($link_prio == "") {
    $database->setQuery( "SELECT m.id "
      ."FROM #__content AS i "
      ."LEFT JOIN #__categories AS c ON i.catid=c.id "
      ."LEFT JOIN #__menu AS m ON m.componentid=c.id "
      ."WHERE m.type='content_blog_category' AND m.published='1' AND i.id='$id'" );
      if ($database->loadResult()) {
        $link_prio = '5';
      }
  }

  //  6) Content Category Blog (specific)
  if ($link_prio == "") {
    $database->setQuery( "SELECT m.id "
      ."FROM #__content AS i "
      ."LEFT JOIN #__sections AS s ON i.sectionid=s.id "
      ."LEFT JOIN #__menu AS m ON m.componentid=s.id "
      ."WHERE m.type='content_blog_section' AND m.published='1' AND i.id='$id'" );
      if ($database->loadResult()) {
        $link_prio = '6';
      }
  }

  // 7) Content Section Blog (global)
  if ($link_prio == "") {
    $database->setQuery( "SELECT id "
      ."FROM #__menu "
      ."WHERE type='content_blog_category' AND published='1' AND componentid='0'" );
      if ($database->loadResult()) {
        $link_prio = '7';
      }
  }

  // 8 ) Content Category Blog (global)
  if ($link_prio == "") {
    // Search in global blog section
    $database->setQuery( "SELECT id "
      ."FROM #__menu "
      ."WHERE type='content_blog_section' AND published='1' AND componentid='0'" );
      if ($database->loadResult()) {
        $link_prio = '8';
      }
  }
  if ($link_prio != "") {
    return $link_prio;
  } else {
    return '99';
  }
}

  /**
   * Converts e.g. "H�ll� �v�r���� ��kk��set!" => "Hello Everyone AakkOoset!"
   * Credits go to hide@address.com for the original version of
   * this incredibly useful little function!
   * For more information see http://php.net/manual/en/function.str-replace.php
   *
   * @param unknown_type $text
   * @return unknown
   */
  function unaccent( $text ) {
    // Get the HTML entities table into an array
    $trans = get_html_translation_table( HTML_ENTITIES );
    $search = array();
    $replace = array();
    // Go through the entity mappings one-by-one
    foreach ($trans as $literal => $entity) {
      // Make sure we don't process any other characters such as fractions,
      // quotes etc:
      if (ord( $literal ) >= 192) {
        // Get the accented form of the letter
        $search[] = $literal;
        // Get e.g. 'E' from string '&Eaccute'
        $replace[] = $entity[1];
      }
    }
    return str_replace( $search, $replace, $text );
  }

  /**
   * One-way conversion of a string (such as a document title) to a
   * URL. In the default auto-mapper this process is irreversible,
   * that is, the URL can't be turned back into the document title.
   * However, one can also conceive of a 'naive' implementation that
   * would replace this code with a simple call to PHP's urlencode,
   * such as is done (by necessity) with components supporting
   * the Joomla Advanced SEF API.
   *
   * @param unknown_type $string
   * @return unknown
   */
  function encode( $string ) {
    // Trim off any leading or trailing spaces
    $string = trim( $string );
    // Replace characters according to user-defined rules
    $string = str_replace(
      array_keys( $this->replace ),
      array_values( $this->replace ),
      $string );
     // Strip off any banned entities such !?# etc.
    if (!empty( $this->config->encode_strip_chars )) {
      $replace = explode(",", $this->config->encode_strip_chars );
      foreach ($replace as $value) {
      if ($value != "") {
        $string = str_replace( $value, "", $string );
      }
    }
    }
    if ($this->config->spec_chars_d != "" && $this->config->spec_chars != "") {
      $spec_chars_d = explode(",",$this->config->spec_chars_d);
      $spec_chars = explode(",",$this->config->spec_chars);

      if (is_array( $spec_chars_d) && is_array( $spec_chars) ) {
          foreach ($spec_chars_d as $i => $spec_char) {
          $string = str_replace(stripslashes($spec_char ), stripslashes($spec_chars[$i]), $string);
          }
      }
    }
    // Convert e.g. "H�ll� �v�r����" to "Hello Everyone"
   $string = sefAutoMapper::unaccent( $string );

   $replace = array("&",">","ï","¿","?","$","%","@","#","+","^",":",";","|","[","]","{","}",",","'","`" );
   foreach ($replace as $value) {
    if ($value != "") {
      $string = str_replace( $value, "", $string );
    }
  }
    $string = str_replace( '"', '', $string );
    // Make the text lowercase, unless the configuration says otherwise.
    if (!empty( $this->config->encode_lowercase ))
      $string = strtolower( $string );
    return $string;
  }
}
?>
Return current item: Joomla SEF / SEO - extending OpenSEF