<?php
/**
 * Project:
 * Contenido Content Management System
 *
 * Description:
 * Path resolving functions
 *
 * Requirements:
 * @con_php_req 5.0
 *
 *
 * @package    Contenido Backend includes
 * @version    1.1.9
 * @author     Timo A. Hummel
 * @copyright  four for business AG <www.4fb.de>
 * @license    http://www.contenido.org/license/LIZENZ.txt
 * @link       http://www.4fb.de
 * @link       http://www.contenido.org
 * @since      file available since contenido release <= 4.6
 *
 * {@internal
 *   created unknown
 *   modified 2006-12-14, init array $results in fct prResolvePathViaURLNames, prResolvePathViaCategoryNames, return type is now integer
 *   modified 2008-06-26, Frederic Schneider, add security fix
 * 	 modified 2008-08-11, Bilal Arslan, Change prResolvePathViaCategoryNames function for take current path language id!
 * 	 modified 2008-11-11, Andreas Lindner, Change prResolvePathViaCategoryNames, suppress change of current language if an url path
 * 	 						is found in current and at least one more language
 *   modified 2009-10-23, Murat Purc, removed deprecated function (PHP 5.3 ready) and formatting
 *
 *   $Id$:
 * }}
 *
 */

if(!defined('CON_FRAMEWORK')) {
    die('Illegal call');
}

/**
 * prResolvePathViaURLNames: Resolves a path using some fuzzy logic.
 *
 * Warning: If you use this function, try to pass a "good" path. This
 *          function doesn't guarantee that the matches are logically
 *          best-matches.
 *
 * This function operates on the category aliases. It compares the given path with the urlpaths generated by function
 * prCreateURLNameLocationString() based on category aliases.
 *
 * @param $path string Path to resolve
 * @return integer Closest matching category ID (idcat)
 */
function prResolvePathViaURLNames($path) {
    $handle = startTiming("prResolvePathViaURLNames", array ($path));

    global $cfg, $lang, $client;

    /* Initialize variables */
    $db = new DB_ConLite;
    $categories = array();
    $results = array();

    /* Pre-process path */
    $path = strtolower(str_replace(" ", "", $path));

    if ($cfg["pathresolve_heapcache"] == true) {
        $pathresolve_tablename = $cfg["sql"]["sqlprefix"]."_pathresolve_cache";

        $sql = "SHOW TABLES LIKE '".Contenido_Security::escapeDB($pathresolve_tablename, $db)."'";
        $db->query($sql);

        if (!$db->next_record()) {
            /**
             * @TODO: Externalize table creation
             *
             * Important: This is really a hack! Don't use pathresolve_heapcache if you are
             * not sure what it does.
             */
            $sql = 'CREATE TABLE `'.Contenido_Security::escapeDB($pathresolve_tablename, $db).'` (
                            `idpathresolvecache` INT( 10 ) NOT NULL PRIMARY KEY ,
                            `path` VARCHAR( 255 ) NOT NULL ,
                            `idcat` INT( 10 ) NOT NULL ,
                            `idlang` INT( 10 ) NOT NULL ,
                            `lastcached` INT(10) NOT NULL
                            ) TYPE = HEAP;';

            $db->query($sql);
        }

        $sql = "SELECT idpathresolvecache, idcat, lastcached FROM %s WHERE path LIKE '%s' AND idlang='%s' ORDER BY lastcached DESC LIMIT 1";
        $db->query(sprintf($sql, Contenido_Security::escapeDB($pathresolve_tablename, $db), Contenido_Security::escapeDB($path, $db), Contenido_Security::toInteger($lang)));

        if ($db->next_record()) {
            if (isset ($cfg["pathresolve_heapcache_time"])) {
                $iCacheTime = $cfg["pathresolve_heapcache_time"];
            } else {
                $iCacheTime = 60 * 60 * 24;
            }

            $tmp_idcat = $db->f("idcat");

            if ($db->f("lastcached") + $iCacheTime < time()) {
                $sql = "DELETE FROM %s WHERE idpathresolvecache = '%s'";
                $db->query(sprintf($sql, Contenido_Security::escapeDB($pathresolve_tablename, $db), Contenido_Security::toInteger($db->f("idpathresolvecache"))));
            } else {
                return $db->f("idcat");
            }
        }
    }

    /* Fetch all category names, build path strings */
//	change the where statement for get all languages
    $sql = "SELECT * FROM ".$cfg["tab"]["cat_tree"]." AS A, ".$cfg["tab"]["cat"]." AS B, ".$cfg["tab"]["cat_lang"]." AS C WHERE A.idcat=B.idcat AND B.idcat=C.idcat AND C.idlang='".Contenido_Security::toInteger($lang)."'
            AND C.visible = 1 AND B.idclient='".Contenido_Security::toInteger($client)."' ORDER BY A.idtree";
    $db->query($sql);

    $catpath = array ();
    while ($db->next_record()) {
        $cat_str = "";
        prCreateURLNameLocationString($db->f("idcat"), "/", $cat_str, false, "", 0, 0, true, true);

        /* Store path */
        $catpath[$db->f("idcat")] = $cat_str;
        $catnames[$db->f("idcat")] = $db->f("name");
        $catlevels[$db->f("idcat")] = $db->f("level");
    }

    /* Compare strings using the similar_text algorythm */
    $percent = 0;
    foreach ($catpath as $key => $value) {
        $value = strtolower(str_replace(" ", "", $value));

        similar_text($value, $path, $percent);

        $firstpath = strpos($value, "/");

        if ($firstpath !== 0) {
            $xpath = substr($value, $firstpath);
            $ypath = substr($path, 0, strlen($path) - 1);
            if ($xpath == $ypath) {
                $results[$key] = 100;
            } else {
                $results[$key] = $percent;
            }
        } else {
            $results[$key] = $percent;
        }

    }

    arsort($results, SORT_NUMERIC);
    reset($results);

    endAndLogTiming($handle);

    if ($cfg["pathresolve_heapcache"] == true) {
        $nid = $db->nextid($pathresolve_tablename);

        $sql = "INSERT INTO %s SET idpathresolvecache='%s', path='%s', idcat='%s', idlang='%s', lastcached=%s";
        $db->query(sprintf($sql, Contenido_Security::toInteger($pathresolve_tablename), Contenido_Security::toInteger($nid), Contenido_Security::escapeDB($path, $db), Contenido_Security::toInteger(key($results)), Contenido_Security::toInteger($lang), time()));
    }

    return (int) key($results);
}

/**
 * prResolvePathViaCategoryNames: Resolves a path using some fuzzy logic.
 *
 * Warning: If you use this function, try to pass a "good" path. This
 *          function doesn't guarantee that the matches are logically
 *          best-matches.
 *
 * This function operates on the actual category names.
 *
 * @param $path string Path to resolve
 * @return integer Closest matching category ID (idcat)
 */
function prResolvePathViaCategoryNames($path, &$iLangCheck) {
    $handle = startTiming("prResolvePathViaCategoryNames", array ($path));

    global $cfg, $lang, $client;

    /* Initialize variables */
    $db = new DB_ConLite;
    $categories = array ();
    $results = array();
    $iLangCheckOrg = $iLangCheck;

    /* Added since 2008-08 from Bilal Arslan */
//	To take only path body
    if (preg_match('/^\/(.*)\/$/', $path, $aResults)) {
        $aResult = explode("/", $aResults[1]);
    } elseif (preg_match('/^\/(.*)$/', $path, $aResults)) {
        $aResult = explode("/", $aResults[1]);
    } else {
        $aResults[1] = $path;
    }

    $aResults[1] = strtolower(preg_replace('/-/', ' ', $aResults[1]));

//	Init to Compare, save path in array
    $aPathsToCompare = explode("/", $aResults[1]);
    $iCountPath = count($aPathsToCompare);

//  init lang id
    $iLangCheck=0;

    /* Pre-process path */
    $path = strtolower(str_replace(" ", "", $path));

    /* Fetch all category names, build path strings */
//	change the where statement for get all languages
    $sql = "SELECT * FROM ".$cfg["tab"]["cat_tree"]." AS A, ".$cfg["tab"]["cat"]." AS B, ".$cfg["tab"]["cat_lang"]." AS C WHERE A.idcat=B.idcat AND B.idcat=C.idcat
            AND C.visible = 1 AND B.idclient='".Contenido_Security::toInteger($client)."' ORDER BY A.idtree";
    $db->query($sql);

    $catpath = array ();
    $arrLangMatches = array();

    while ($db->next_record()) {
        $cat_str = "";
        $aTemp = "";
        $iFor = 0;
        $bLang = false;

//		$level is changeless 0!!!
        conCreateLocationString($db->f("idcat"), "/", $cat_str, false, '', 0, $db->f("idlang"));
        /* Store path */
        $catpath[$db->f("idcat")] =  $cat_str;
        $catnames[$db->f("idcat")] = $db->f("name");
        $catlevels[$db->f("idcat")] = $db->f("level");

//		Init variables for take a language id
        $aTemp =  strtolower($cat_str);
        $aDBToCompare =  explode("/", $aTemp);
        $iCountDB = count($aDBToCompare);
        $iCountDBFor = $iCountDB - 1;
//		take min. count of two arrays
        ($iCountDB > $iCountPath) ? $iFor = $iCountPath : $iFor = $iCountDB;
        $iCountM = $iFor-1;

        for ($i=0; $i<$iFor; $i++) {
            if ($aPathsToCompare[$iCountM] == $aDBToCompare[$iCountDBFor]) {
                $bLang	= true;
            } else {
                $bLang = false;
            }
            $iCountM--;
            $iCountDBFor--;
//			compare, only if current element is lastone and we are in true path
            if($i == $iFor-1 && $bLang) {
                $iLangCheck = $db->f("idlang");
                $arrLangMatches[] = $iLangCheck;
            }
        }

    }

    #Suppress wrongly language change if url name can be found in current language
    if ($iLangCheckOrg == 0) {
        if (in_array($lang, $arrLangMatches)) {
            $iLangCheck = $lang;
        }
    }

    /* Compare strings using the similar_text algorythm */
    $percent = 0;
    foreach ($catpath as $key => $value) {
        $value = strtolower(str_replace(" ", "", $value));

        similar_text($value, $path, $percent);

        $results[$key] = $percent;
    }

    foreach ($catnames as $key => $value) {
        $value = strtolower(str_replace(" ", "", $value));
        similar_text($value, $path, $percent);

        /* Apply weight */
        $percent = $percent * $catlevels[$key];

        if ($results[$key] > $percent) {
            $results[$key] = $percent;
        }
    }

    arsort($results, SORT_NUMERIC);
    reset($results);

    endAndLogTiming($handle);
    return (int) key($results);
}

/**
 * Recursive function to create an URL name location string
 *
 * @param int $idcat ID of the starting category
 * @param string $seperator Seperation string
 * @param string $cat_str Category location string (by reference)
 * @param boolean $makeLink create location string with links
 * @param string $linkClass stylesheet class for the links
 * @param integer first navigation level location string should be printed out (first level = 0!!)
 *
 * @return string location string
 *
 * @author Jan Lengowski <jan.lengowski@4fb.de>
 * @author Marco Jahn <marco.jahn@4fb.de>
 *
 * @copyright four for business AG <www.4fb.de>
 */
function prCreateURLNameLocationString($idcat, $seperator, & $cat_str, $makeLink = false, $linkClass = "",
    $firstTreeElementToUse = 0, $uselang = 0, $final = true, $usecache = false) {
    global $cfg, $client, $cfgClient, $lang, $sess, $_URLlocationStringCache;

    if ($final == true) {
        $cat_str = "";
    }

    if ($idcat == 0) {
        $cat_str = "Lost and Found";
        return;
    }

    if ($uselang == 0) {
        $uselang = $lang;
    }

    if ($final == true && $usecache == true) {
        if (!is_array($_URLlocationStringCache)) {
            if (file_exists($cfgClient[$client]["path"]["frontend"]."cache/locationstring-url-cache-$uselang.txt")) {
                $_URLlocationStringCache = unserialize(file_get_contents($cfgClient[$client]["path"]["frontend"]."cache/locationstring-url-cache-$uselang.txt"));
            } else {
                $_URLlocationStringCache = array ();
            }
        }

        if (array_key_exists($idcat, $_URLlocationStringCache)) {
            if ($_URLlocationStringCache[$idcat]["expires"] > time()) {
                $cat_str = $_URLlocationStringCache[$idcat]["name"];
                return;
            }
        }
    }

    $db = new DB_ConLite;

    $sql = "SELECT
                    a.urlname AS urlname,
                    a.name	AS name,
                    a.idcat AS idcat,
                    b.parentid AS parentid,
                    c.level as level
                FROM
                    ".$cfg["tab"]["cat_lang"]." AS a,
                    ".$cfg["tab"]["cat"]." AS b,
                    ".$cfg["tab"]["cat_tree"]." AS c
                WHERE
                    a.idlang    = '".Contenido_Security::toInteger($uselang)."' AND
                    b.idclient  = '".Contenido_Security::toInteger($client)."' AND
                    b.idcat     = '".Contenido_Security::toInteger($idcat)."' AND
                    a.idcat     = b.idcat AND
                    c.idcat = b.idcat";

    $db->query($sql);
    $db->next_record();

    if ($db->f("level") >= $firstTreeElementToUse) {
        $name = $db->f("urlname");

        if (trim($name) == "") {
            $name = $db->f("name");
        }

        $parentid = $db->f("parentid");

        //create link
        if ($makeLink == true) {
            $linkUrl = $sess->url("front_content.php?idcat=$idcat");
            $name = '<a href="'.$linkUrl.'" class="'.$linkClass.'">'.$name.'</a>';
        }

        $tmp_cat_str = $name.$seperator.$cat_str;
        $cat_str = $tmp_cat_str;
    }

    if ($parentid != 0) {
        prCreateURLNameLocationString($parentid, $seperator, $cat_str, $makeLink, $linkClass, $firstTreeElementToUse, $uselang, false, $usecache);
    } else {
        $sep_length = strlen($seperator);
        $str_length = strlen($cat_str);
        $tmp_length = $str_length - $sep_length;
        $cat_str = substr($cat_str, 0, $tmp_length);
    }

    if ($final == true && $usecache == true) {
        $_URLlocationStringCache[$idcat]["name"] = $cat_str;
        $_URLlocationStringCache[$idcat]["expires"] = time() + 3600;

        if (is_writable($cfgClient[$client]["path"]["frontend"]."cache/") || (strtolower(substr(PHP_OS, 0, 3)) == "win")) {
            file_put_contents($cfgClient[$client]["path"]["frontend"]."cache/locationstring-url-cache-$uselang.txt", serialize($_URLlocationStringCache));
        }
    }
}
?>
