<?php
define('idDiGIR_utils','$Id: DiGIR_utils.php,v 1.14 2004/05/18 17:51:29 rdg Exp $');
if (defined('idDIGIR_VERSION_REQUEST'))
    return;
/**
* $Id: DiGIR_utils.php,v 1.14 2004/05/18 17:51:29 rdg Exp $
*
* Utility methods for use in DiGIR
*/

include_once("DiGIR_globals.php");
include_once(DIGIR_XPATH_LIBRARY);

/**
* For debugging.  Sends a message when _DEBUG is true
*/
function DebugMsg($x)
{
    if (_DEBUG)
    {
      echo "<d>DEBUG:<![CDATA[";
      print_r($x);
      echo "]]></d>\n";
    }
}

/**
* Simple array dumper.  For debugging stuff
*/
function dumpArray($a)
{
	if (!is_array($a))
		return;
	$s = "";
	$kys = array_keys($a);
	for ($i=0; $i<count($kys); $i++)
	{
			$s = $s."[".$kys[$i]."]".$a[$i];
	}
	return $s;
}

/**
* Loads a parameter from GET or POST or uses defaultval if none supplied
*
* @param string name Name of parameter to load
* @param variant defaultVal Default value to use if parameter does not exist in GET or POST data
*
* Return is the value of the requested parameter
*/
function getVar($name,$defaultval)
{
    global $HTTP_GET_VARS;
    global $HTTP_POST_VARS;
    if (is_array($HTTP_GET_VARS))
    {
        $kys = array_keys($HTTP_GET_VARS);
        $n = count($HTTP_GET_VARS);
        for ($i=0; $i < $n; $i++)
        {
            if (strcasecmp($kys[$i],$name)==0)
            {
                $tmp = $kys[$i];
                if (strlen($tmp) <= 0)
                    return NULL;
                    return $HTTP_GET_VARS[$kys[$i]];
            }
        }
    }
    if (is_array($HTTP_POST_VARS))
    {
        $kys = array_keys($HTTP_POST_VARS);
        $n = count($HTTP_POST_VARS);
        for ($i=0; $i < $n; $i++)
        {
            if (strcasecmp($kys[$i],$name)==0)
            {
                $tmp = $kys[$i];
                if (strlen($tmp) <= 0)
                    return NULL;
                    return $HTTP_POST_VARS[$kys[$i]];
            }
        }
    }
    return $defaultval;
}

/**
* Simple check to determine if the supplied string is a URL
*
* @param string tst String to test
*
* returns TRUE or FALSE
*/
function isURL($tst)
{
	//simple check to see if a string is a URL.
	//just looks at the first few characters to see if the scheme is http or ftp
	//add a single char so we don't get confused with a false answer
	//being the same as a zero
	$tst = " ".substr($tst,0,8);
	$tst = strtolower($tst);
	if (strpos($tst,"http://") == 1)
		return true;
	if (strpos($tst,"ftp://") == 1)
		return true;
	return false;
}


/**
* Computes day =res[0] and month =res[1] given Julian day
* @param number $jd Julian day
* @return array [0] = day, [1]=month
*/
function JDtoDM($jd)
{
        $days = array(31,28,31,30,31,30,31,31,30,31,30,31);
        $res = array(1,1);
        if ($jd <= $days[0])
        {
                $res[0] = $jd;
                return $res;
        }
        while ($jd > $days[$res[1]])
        {
                $jd = $jd - $days[$res[1]];
                $res[1] = $res[1] + 1;
        }
        $res[1] ++;
        $res[0] = $jd;
        return $res;
}

/**
* Used for compatibility with zASP code
*/
function formatString($s,$a)
{
        $p="";
        for ($i=0; $i<count($a);$i++)
        {
                $p = $p."\"".$a[$i]."\"";
                if ($i < count($a)-1)
                        $p = $p.",";
        }
        $f = "\$res = sprintf(\"".$s."\",".$p.");";
        eval($f);
        return $res;
}

/**
* Used internally for compatibility to zASP code
*/
function MakeSQLStub($sFmt,$sOp,$sTerm,$nRep)
{
        // the c++ version will handle upto
        $atmp = array();
        $i =0;
        for ($i=0; $i < $nRep; $i++)
        {
                array_push($atmp,$sOp);
                array_push($atmp,$sTerm);
        }
        $sRes = formatString($sFmt,$atmp);
        return $sRes;
}

/**
* Used by the PQN parser
*/
function opType($s)
{
        $s = strtolower($s);
        $res = 0;
        if ($s == "and")
                return op_AND;
        else if ($s=="or")
                return op_OR;
        else if ($s=="attr")
                return op_ATTR;
        else if ($s=="set")
                return op_RESULTSET;
        else if ($s=="aset")
                return op_ATTRIBUTESET;
        return op_NONE;
}

/**
* Used by the PQN parser
*/
function cpToText($cp)
{
        switch ($cp)
        {
        case cp_lt: return "<";
        case cp_lteq: return "<=";
        case cp_eq: return "=";
        case cp_gteq: return ">=";
        case cp_gt: return ">";
        case cp_like: return "LIKE";
        case cp_in: return "IN";
        case cp_contains: return "CONTAINS";
        case cp_freetext: return "FREETEXT";
        case cp_matches: return "MATCHES";
        }
}

/**
* Returns this script URL
*/
function serviceID()
{
    global $_SERVER;
    $sn = isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:'localhost';
    $sp = isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:'80';
    $ss = isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:'/DiGIR.php';
    $s = "http://".$sn.":".$sp.$ss;
    return $s;
}

/**
* Generates the DiGIR header structure
*
* @param requestType integer Code indicating type of request (0=status, 1=metadata, 2=search, 3=inventory)
* @param destID string Address of the system to which this response is directed
* @param resource string The name of the resource (database) targeted by the request
*
* Returns a string that represents the header structure.
*/
function DiGIRHeader($requestType,$destID,$resource="",$clientKey="")
{
    $types = array('status', 'metadata', 'search', 'inventory');
    // ISO8601 datetime
    $sendTime = implode('T', explode(' ', date(TIME_FORMAT_STRING, time())));
    $s = "<header";
    if (strlen($clientKey) > 0)
    {
        $s.= " clientKey='".$clientKey."'";
    }
    $s .= ">\n";
    $s .= "<version>".DiGIRVERSION."</version>\n";
    $s .= "<sendTime>".$sendTime."</sendTime>\n";
    $s .= "<source";	
    if ($resource != "")
    {
        $s.= " resource=\"".$resource."\"";
    }
    $s .= ">".serviceID()."</source>\n";
    $s .= "<destination>".$destID."</destination>\n";
    $s .= "<type>".$types[$requestType]."</type>\n";
    $s .= "</header>\n";
    return $s;
}

/**
* Escapes XML special chars in a string
*
* @param $s string String to be escaped (assumed to be in utf-8)
* @return string Escaped string
*/
function escapeXMLSpecialChars($s)
{
    // Since "htmlspecialchars" does not work with utf-8 in versions
    // prior than 4.3.0 (stable!), we need to use mb_ereg_replace as an alternative
    if (version_compare(phpversion(), "4.3.0", ">=") > 0)
    {
        $s = htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
    }
    else
    {
        if (function_exists('mb_regex_encoding'))
        {
            mb_regex_encoding('UTF-8');
            $s = mb_ereg_replace('&', '&amp;' , $s);
            $s = mb_ereg_replace('>', '&gt;'  , $s);
            $s = mb_ereg_replace('<', '&lt;'  , $s);
            $s = mb_ereg_replace('"', '&quot;', $s);
        }
        else
        { 
            // TODO: If $s contains any xml special char, we should raise an error here!
            $s = htmlspecialchars($s);
        }
    }

    return $s;
}

function maketag($element,$value)
{
	$s = "<".$element.">";
	$s .= escapeXMLSpecialChars($value);
	$s .= "</".$element.">\n";
	return $s;
}

/**
* Loads all the name spaces from the XPath object into an array.
*
* @param XPath $xp An XPath object with the document loaded.
* @return array The default namespace is [0], all others are keyed by the namespace handle
*/
function getNamespaces(&$xp,$res=NULL)
{
    if ($res == NULL)
        $res = array();
    //get list of nodes with attributes
    $qry = "//*[@*]";
    $nodes = $xp->evaluate($qry);
    foreach ($nodes as $k=>$v)
    {
        $attrs = $xp->getAttributes($v);
        //find attributes that start with "xmlns:"
        foreach ($attrs as $hndl => $aval)
        {
           if ($hndl == "xmlns")
            {
                $res[0] = $aval;
            }
            elseif (strpos($hndl,"xmlns:") === 0)
            {
                $tmp = split(":",$hndl);
                $res[$tmp[1]] = $aval;
            }
        }
    }
    return $res;
}

/**
* @return string The default parameter in a http GET or POST operation.
*      Returns null if there was no default parameter.
*
* A default parameter can be set of both GET and POST.  If both are set, then
* the POST value takes precedence.
*/
function getDefaultParameter()
{
    $res = null;
    $cGET = count($_GET);
    $cPOST = count($_POST);
    if ($cGET == 1)
    {
        $k = array_keys($_GET);
        if (isset($_GET[$k[0]]) && (strlen($_GET[$k[0]]) <= 0))
            $res = urldecode($k[0]);
    }
    if ($cPOST == 1)
    {
        $k = array_keys($_POST);
        if (isset($_POST[$k[0]]) && (strlen($_POST[$k[0]]) <= 0))
            $res = urldecode($k[0]);
    }
    return $res;
}

/**
* Loads an array of resources from the resources.xml file. The returned file
* names do not include the path, just the file name.
*
* @param object $xp An xparser object ready to be used (with the xml
*                list of resources already loaded)
* @return array List of available resoruces.  key=name, value=filename
*/
function getResourceList($xp=null)
{
    $ares = array();
    if (!is_object($xp))
    {
        $resFileName = realpath(DIGIR_CONFIG_DIR.'/'.DIGIR_RESOURCE_FILE);
        $xp = new XPath();
        $xp->setVerbose(0);
        $xp->setXmlOption(XML_OPTION_CASE_FOLDING,false);
        $xp->setXmlOption(XML_OPTION_SKIP_WHITE,true);
        if (!$xp->importFromFile($resFileName))
        {
            appendError(DC_NORESOURCESFILE,
                "Could not load the resources.xml file (".
                $resFileName."). Please check provider installation.",
                DIAG_ERROR);
            return $ares;
        }
    }
    $pths = $xp->match("//resources/resource");
    foreach ($pths as $pth)
    {
        $nm = $xp->getAttributes($pth,"name");
        $fn = $xp->getAttributes($pth,"configFile");
        if (!$fn)
        {
            $fn = $xp->getData($pth."/configFile[1]");
        }
        $ares[$nm] = $fn;
    }
    return $ares;		
}

/**
* Returns the name of a config file given a resource name. The
* returned file name does not include the path.
*
* @param string $resourceName The name of the resource to locate
* @param object $xparser An xparser object ready to be used (with the xml
*                list of resources already loaded)
* @return string The name of the resource file, or null of not located.  Note that
*                only the file name is returned, not the full path.
*/
function getResourceConfigFile($resourceName, $xparser=null)
{
    $res = null;
    if (!is_object($xparser))
    {
        $resFileName = realpath(DIGIR_CONFIG_DIR.'/'.DIGIR_RESOURCE_FILE);
        $xparser = new XPath();
	$xparser->setVerbose(0);
	$xparser->setXmlOption(XML_OPTION_CASE_FOLDING,false);
	$xparser->setXmlOption(XML_OPTION_SKIP_WHITE,true);
        if (!$xparser->importFromFile($resFileName))
        {
            appendError(DC_NORESOURCESFILE,
                "Could not load the resources.xml file (".
                $resFileName."). Please check provider installation.",
                DIAG_ERROR);
            return $res;
        }
    }
    $qry = "//resource[@name=\"".$resourceName."\"]";
    $fnode = $xparser->match($qry);
    if (count($fnode) > 0 )
    {
        $res = $xparser->getData($fnode[0]."/configFile[1]");
        if (!$res)
        {
            $res = $xparser->getAttributes($fnode[0],"configFile");
        }
    }
    return $res;
}

/**
* Returns a windows code page for the specified encoding parameter.
* This is used to set the code page for connection to COM objects, such as
* database connections using OLEDB
*/
function encodingToCodePage($encoding)
{
    if (strcasecmp($encoding,"UTF-8") === 0)
        return 65001;
    return NULL;
}

/**
* Loads the specified library if not already, trying to be platform independent.
*
* @param $libname string Name of the library to load
*/
function loadlibrary_x($libname)
{
    $res = true;
    if (!extension_loaded($libname))
    {
    	if (DIGIR_OS_WINDOWS)
	{
    	    $res = @dl('php_'.$libname.'.dll');
	}
    	elseif (DIGIR_PHP_OS == 'HP-UX')
	{
    	    $res = @dl($libname.'.sl');
	}
    	elseif (DIGIR_PHP_OS == 'AIX')
	{
    	    $res = @dl($libname.'.a');
	}
    	else
	{
    	    $res = @dl($libname.'.so');
	}
    }
    return $res;
}

/**
* Converts a SQL statement to the current database charset encoding (if different from UTF-8).
*
* @param $sql string SQL statement.
* @param $encoding string Database charset encoding.
* @return string SQL statement to be sent to database
*/
function encodeSQL($sql, $encoding)
{
    if (strcasecmp($encoding, 'UTF-8'))
    {
        if (function_exists('mb_convert_encoding'))
            $sql = mb_convert_encoding($sql, $encoding, 'UTF-8');
    }
    return $sql;
}

function typeNameToType($t)
{
    $t = strToUpper($t);
    if ($t == "TEXT")
        return type_TEXT;
    if ($t == "NUMERIC")
        return type_NUMERIC;
    if ($t == "BBOUNDING")
        return type_BBOUNDING;
    if ($t == "JULIAN")
        return type_JULIANDAY;
    if ($t == "DATETIME")
        return type_DATETIME;
    if ($t == "SQLSTUB")
        return type_SQLSTUB;
    return type_TEXT;
}

function typeToTypeName($t)
{
    switch ($t)
    {
        case type_TEXT: return "TEXT";
        case type_NUMERIC : return "NUMERIC";
        case type_BBOUNDING : return "BBOUNDING";
        case type_JULIANDAY : return "JULIAN";
        case type_DATETIME : return "DATETIME";
        case type_SQLSTUB : return "SQLSTUB";
        default : return "Invalid type code";
    }
}

function requestStringToRequest($req)
{
    if (strcasecmp($req,"getCapabilities") == 0)
        return request_getCapabilities;
    if (strcasecmp($req,"search") == 0)
        return request_Search;
    if (strcasecmp($req,"scan") == 0)
        return request_Scan;
    return request_getCapabilities;
}

?>