<?php
/**
 * Common tools
 *
 * This file contains a variety of tools that might be usefull to all
 * applications, no matter wether the use the rest of the framework or not.
 *
 * @package     yana
 * @subpackage  utilities
 * @licence http://creativecommons.org/licenses/by-nc-sa/2.5/
 */

/**
 * list contents of a directory
 *
 * The argument $filter may contain multiple file extension,
 * use a pipe '|' sign to seperate them.
 * Example: "*.xml|*.html" will find all xml- and html-files
 *
 * @param  string  $dir
 * @param  string  $filter
 * @param  return  array
 */
function dirlist($dir, $filter = "")
{
    assert('is_string($dir);');
    assert('is_string($filter);');
    settype($dir, "string");
    settype($filter, "string");

    if (strpos($filter,'|') !== false) {
        $filter = preg_replace("/[^\.\-\_\w\d\|]/", "", $filter);
        $tok = strtok($filter, "|");
        $filter = "";
        while ($tok !== false)
        {
            $filter .= toRegExp($tok);
            $tok = strtok("|");
            if ($tok !== false) {
                $filter .= "|";
            }
        }
    } else {
        $filter = preg_replace("/[^\.\-\_\w\d]/", "", $filter);
        $filter = toRegExp($filter);
    }

    $dirlist = array();
    if (file_exists($dir)) {
        assert('is_dir($dir);');
        $dir = dir($dir);
        while($entry=$dir->read())
        {
            if (!preg_match('/^\.{1,2}.*$/i',$entry) && !in_array($entry, $dirlist) && preg_match('/'.$filter.'$/i',$entry)) {
                 array_push($dirlist, $entry);
            }
        }
        $dir->close();
        sort($dirlist);
    }
    assert('is_array($dirlist);');
    return $dirlist;

}

/**
 * escape a string to be used as a regular expression
 *
 * For internal use as an alternative to preg_quote() only.
 *
 * @param string $input
 * @param return string
 * @ignore
 */
function toRegExp($input)
{
    assert('is_string($input);');
    settype($input, "string");
    /* Note:
     * The '$' character is not quoted by intention.
     */
    return addcslashes($input, '+()[]{}.?*\/');
}

/**
 * recursively merge two arrays to one
 *
 * This function is pretty much the same as the php function "array_merge_recursive"
 * except for the way how duplicate keys are treated. Dupplicate keys get replaced
 * in this implementation rather than being appended.
 *
 * @param array $A
 * @param array $B
 * @return array
 */
function mergeArrays($A, $B)
{
    assert('is_array($A);');
    assert('is_array($B);');
    settype($A, "array");

    /* for better performance check trivial cases first */
    if (count($B)==0) {
        return $A;
    } else if (count($A)==0) {
        return $B;
    /* only in case non of this applies, do the real thing */
    } else {
        for ($i=1; $i < func_num_args(); $i++)
        {
            foreach (func_get_arg($i) as $k=>$e)
            {
                if (is_array($e)) {
                    if (isset($A[$k])) {
                        $A[$k] = mergeArrays($A[$k], $e);
                    } else {
                        $A[$k] = $e;
                    }
                } else {
                    $A[$k] = $e;
                }
            }
        }
        assert('is_array($A);');
        return $A;
    }
}

/**
 * Lowercase or uppercase all keys of an associative array
 *
 * This is a recursive implementation of the PHP function array_change_key_case().
 * It takes the same arguments: an array $input to work on and an optional
 * argument $case. The argument $case can be one of two constants: CASE_LOWER and
 * CASE_UPPER, where CASE_LOWER is the default.
 *
 * @param  array     $A
 * @param  int|bool  $case  CASE_UPPER or CASE_LOWER
 * @return array
 */
function changeCaseArray($input, $case = CASE_LOWER)
{
    assert('is_array($input);');
    assert('is_bool($case) || ($case===CASE_UPPER||$case===CASE_LOWER);');
    if (is_bool($case)) {
        if ($case===true) {
            $case = CASE_UPPER;
        } else {
            $case = CASE_LOWER;
        }
    }
    if ($case===CASE_UPPER||$case===CASE_LOWER) {
        if(is_array($input)) {
            $input = array_change_key_case($input, $case);
            foreach ($input as $k=>$e)
            {
                if (is_array($e)) {
                    $input[$k] = changeCaseArray($e,$case);
                }
            }
        } else {
            trigger_error("Wrong argument type for argument 1 in function changeCaseArray(). Array expected, found '".gettype($input)."' instead.", E_USER_ERROR);
            return $input;
        }
    } else {
        trigger_error("Wrong argument type for argument 2 in function changeCaseArray(). Boolean expected, found '".gettype($case)."' instead.", E_USER_ERROR);
        return $input;
    }
    assert('is_array($input);');
    return $input;
}

$instance_id = base64_decode('PHAgY2xhc3M9IktPTU1FTlRBUiIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlciI+V2ViVG9vbHMgcG93ZXJlZCBieSA8QSBIUkVGPSJodHRwOi8vd3d3LkFsbC1Db21tdW5pdHkuZGUiIHRhcmdldD0iX2JsYW5rIiB0aXRsZT0iRGllIENvbW11bml0eSBkZXIgV2VibWFzdGVyIj48c3BhbiBzdHlsZT0iY29sb3I6IzY0OTVFRCI+d3d3Ljwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6I0ZGQTUwMCI+IEFsbCAtIENvbW11bml0eSA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiM2NDk1RUQiPi5kZTwvc3Bhbj48L0E+');

/**
 * Untaint user input taken from a web form
 *
 * This function scrubbs your user input data shiny and clean.
 *
 * It ensures: the data has a given type, maximum length, and syntax.
 * E.g. if the data comes out of an input-field use this function with
 * the argument $escape set to YANA_ESCAPE_LINEBREAK, to enforce the
 * input does not have any unexpected line breaks.
 *
 * Valid values for parameter $type:
 *
 * <ul>
 * <li>  int, integer  </li>
 * <li>  float, double  </li>
 * <li>  boolean, bool  </li>
 * <li>  string  </li>
 * <li>  object  </li>
 * <li>  time   = the input is an unix time code  </li>
 * <li>  mail   = the input is a mail adress  </li>
 * <li>  ip     = the input is an IP adress  </li>
 * <li>  select = the input is taken from a select field (treated as "string")  </li>
 * <li>  text   = the input is taken from a textarea field (treated as "string")  </li>
 * </ul>
 *
 * Valid values for parameter $escape:
 *
 * <ul>
 * <li>  YANA_ESCAPE_NONE      = leave special chars alone (default)  </li>
 * <li>  YANA_ESCAPE_SLASHED   = apply addslashes()  </li>
 * <li>  YANA_ESCAPE_TOKEN     = replace template delimiters with html-entities  </li>
 * <li>  YANA_ESCAPE_CODED     = convert all characters to html-entities  </li>
 * <li>  YANA_ESCAPE_LINEBREAK = revert all white-space to spaces<br />(for security reasons you should ALWAYS use this setting if you<br />expect data from any other field than textarea)  </li>
 * <li>  YANA_ESCAPE_USERTEXT  = treat full-text message from an textarea element,<br />prevents flooding by removing doubled elements  </li>
 * </ul>
 *
 * @uses  $saveInput = untaintInput($_GET['message'], 'string', 1024, YANA_ESCAPE_USERTEXT)
 *
 * @param mixed $value the input data
 * @param string $type desired type, note that this should always be a scalar type
 * @param int $length maximum length (as number of characters!), note that a float of 10.3 and length 3 will convert to 10., NOT 10.3!
 * @param int $escape choose how special characters should be treated
 * @return mixed
 */
function untaintInput($value, $type = "", $length = 0, $escape = 0)
{
    assert('is_string($type);');
    assert('is_int($length);');
    assert('is_int($escape);');
    settype($type,   "string");
    settype($length, "integer");
    settype($escape, "integer");
    $type = strtolower($type);

    if (is_string($value)) {
        $value = preg_replace('/[\x00-\x08\x0b]*|[\x0e-\x1f]*/', '', $value);
    }

    switch ($type)
    {
        case "time":
            $test   = true;
            $type   = "integer";
            $length = 11;
        break;

        case "ip":
            if (!preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $value)) {
                return "0.0.0.0";
            }
            $test   = true;
            $type   = "string";
            $length = 15;
        break;

        case "url": case "uri":
            settype($value, "string");
            /* URI reg-exp as proposed by W3C */
            if (preg_match('/^(?:([^:\/\?#]+):\/\/)?([^\/\?#]*)([^\?#]*)(?:\?([^#]*))?(?:#(.*))?/', $value, $m)) {
                /* validate syntax of provided uri
                 * Note: this implements rather strict checking since it does not allow
                 * url encoded strings
                 */
                $valid = true;
                /* check scheme */
                if (isset($m[1])) {
                    $valid = $valid && preg_match('/^\w*$/',$m[1]);
                }
                /* check authority */
                if (isset($m[2])) {
                    $valid = $valid && preg_match('/^[\w\d-_\/\.]+$/',$m[2]);
                } else {
                    /* empty authority is considered not valid */
                    return "";
                }
                /* check path */
                if (isset($m[3])) {
                    $valid = $valid && preg_match('/^[\w\d-_\/\. ]*$/',$m[3]);
                }
                /* check query */
                if (isset($m[4])) {
                    $valid = $valid && preg_match('/^[\w\d-_&;=]*$/',$m[4]);
                }
                /* check fragment */
                if (isset($m[5])) {
                    $valid = $valid && preg_match('/^[\w\d-_]*$/',$m[5]);
                }
            } else {
                $valid = false;
            }
            if ($valid === true) {
                $test   = true;
                $type   = "string";
            } else {
                return "";
            }
        break;

        case "mail":
            settype($value, "string");
            if (preg_match("/^[äöüß\w\d-_\.]{1,}\@[äöüß\w\d-_\.]{2,}\.[\w\d-_\.]{2,}$/i", $value)) {
                if ($escape > 0) {
                    return addslashes($value);
                } else {
                    return $value;
                }
            } else {
                return "";
            }
        break;

        case "select":
            $test  = true;
            $type  = "string";
        break;

        case "array":
            $test  = true;
            $type  = "string";
            settype($value, 'array');
            $value = makeConfig($value);
        break;

        case "text":
            $test = true;
            $type = "string";
        break;

        case "string": case "object":
            $test = true;
        break;

        /* this maps aliases to values, returned by gettype according to php manual*/
        case "int": case "integer":
            $test = true;
            $type = "integer";
        break;

        case "float": case "double":
            $test = true;
            $type = "double";
        break;

        case "boolean": case "bool":
            $test = true;
            $type = "boolean";
        break;

        default:
            $test = false;
        break;

    }

    if ($test === true) {
        settype($value, $type);
    }
    if ($length > 0) {
        $value = substr($value, 0, $length);
    }
    /* type may have been changed! */
    if ($test === true) {
        settype($value, $type);
    }
    switch ($escape)
    {
        case YANA_ESCAPE_SLASHED:
            if (is_string($value)) {
                $value = addslashes($value);
            }
        break;
        case YANA_ESCAPE_CODED:
            settype($value, "string");
            $value = String_type::htmlEntities($value);
        break;
        case YANA_ESCAPE_TOKEN:
            if (is_string($value)) {
                $value = str_replace(YANA_UNI_DELIMITER, '&#'.ord(YANA_UNI_DELIMITER).';', $value);
                $value = str_replace('$', '&#'.ord('$').';', $value);
            }
        break;
        case YANA_ESCAPE_LINEBREAK:
            if (is_string($value)) {
                $value = trim(preg_replace("/\s/", " ",$value));
            }
        break;
        case YANA_ESCAPE_USERTEXT:
            if (is_string($value)) {
                /* Note: it is important to ensure that an already checked string
                 * that undergoes the same procedure again remains unchanged,
                 * to avoid double conversion.
                 */
                $value = nl2br($value);
                /* white space */
                $value = preg_replace('/[\x00-\x1f]/','',$value);
                /* length */
                if (is_int($length) && $length > 0) {
                    $value = preg_replace("/^(.{". $length     ."}\S*).*/", "\\1", $value);
                    $value = preg_replace("/^(.{". ($length+100) ."}).*/", "\\1", $value);
                }
                /* white space before start- and after end- tag */
                $value = preg_replace("/(\[\/\S+\])(\S)/U", "\\1 \\2", $value);
                $value = preg_replace("/(\S)(\[!(?:wbr|br|\/[^\s\]]+)\])/U", "\\1 \\2", $value);
                /* white space around emoticons */
                $value = preg_replace("/(\S)(\:\S+\:)(\S)/U", "\\1 \\2 \\3", $value);
                /* line break */
                $value = preg_replace("/(\S{80})(\S)/", "\\1[wbr]\\2", $value);
                /* clean up */
                $value = preg_replace("/\[wbr\]\[wbr\]/", "[wbr]", $value);
                $value = preg_replace("/\<br\s*\/?>/", "[br]", $value);
                $value = preg_replace("/\s/"," ",$value);
                /* trim spaces */
                $value = trim($value);
                $value = stripcslashes($value);
                /* Escape Token-delimiters, to prevent possible code injection.
                 * Note: YANA_UNI_DELIMITER has also to be a part of YANA_LEFT_DELIMITER and
                 * YANA_RIGHT_DELIMITER, so these will also be escaped.
                 */
                $value = str_replace(YANA_UNI_DELIMITER, '&#'.ord(YANA_UNI_DELIMITER).';', $value);
                /* It is necessary to leave the ampersand '&' character untouched.
                 * Otherwise it would run into a double conversion if this function is to be
                 * called multiple times.
                 */
                $value = Layout::htmlSpecialCharsWithoutAmp($value);
                /* Escape '$' character, to prevent possible code injection. */
                $value = str_replace('$', '&#'.ord('$').';', $value);
            }
        break;
        default:
            /* intentionally left blank */
        break;
    } /* end switch $escape */

    assert('$type === "" || gettype($value) === $type;');
    return $value;

}

$lcn_note = base64_decode("PHAgY2xhc3M9IktPTU1FTlRBUiIgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj5yZWdpc3RlcmVkIFZJUC12ZXJzaW9uOiA8c3BhbiBjbGFzcz0iQkVTQ0hSSUZUVU5HIj4mcXVvdDslT1dORVIlJnF1b3Q7PC9zcGFuPjwvcD4=");

?>