Location: PHPKode > projects > ETraxis > etraxis-2.1.1/src/engine/utility.php
<?php

/**
 * Utility functions
 *
 * This module contains several wide-purpose utility functions.
 *
 * @package Engine
 */

//--------------------------------------------------------------------------------------------------
//
//  eTraxis - Records tracking web-based system.
//  Copyright (C) 2004-2009 by Artem Rodygin
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along
//  with this program; if not, write to the Free Software Foundation, Inc.,
//  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//--------------------------------------------------------------------------------------------------
//  Author                  Date            Description of modifications
//--------------------------------------------------------------------------------------------------
//  Artem Rodygin           2004-11-17      new-001: Records tracking web-based system should be implemented.
//  Artem Rodygin           2005-07-02      bug-007: Descending sorting of records by ID sorts them wrong.
//  Artem Rodygin           2005-08-09      new-008: Predefined metrics.
//  Artem Rodygin           2005-08-22      bug-041: PHP Warning: odbc_exec(): SQL error: The name 'ru0' is not permitted in this context.
//  Artem Rodygin           2005-08-31      bug-079: String database columns are not enough to store UTF-8 values.
//  Artem Rodygin           2005-09-07      new-100: 'Date' field type should be implemented.
//  Artem Rodygin           2005-09-08      new-101: 'Duration' field type should be implemented.
//  Artem Rodygin           2005-09-12      new-105: Format of date values are being entered should depend on user locale settings.
//  Artem Rodygin           2005-09-12      bug-104: XML parser failure on some UTF-8 characters.
//  Artem Rodygin           2005-09-22      new-141: Source code review.
//  Artem Rodygin           2005-11-13      bug-177: Multibyte string functions should be used instead of 'eregi' and 'split'.
//  Artem Rodygin           2006-04-22      new-237: Found text should be marked with red when search is activated.
//  Artem Rodygin           2006-10-15      new-137: Custom queries.
//  Artem Rodygin           2006-11-07      new-366: Export to CSV.
//  Artem Rodygin           2006-12-09      bug-427: MySQL losts backslashes.
//  Artem Rodygin           2006-12-11      bug-438: PHP Warning: odbc_exec(): SQL error: Incorrect syntax near 'eTraxis'.
//  Artem Rodygin           2006-12-14      bug-442: Backslash character is doubled in text values.
//  Artem Rodygin           2006-12-17      bug-454: Backslash character is doubled in text values.
//  Artem Rodygin           2006-12-28      bug-473: List item integer part must not be greater than 2^31.
//  Artem Rodygin           2007-03-16      bug-504: [SF1674710] bad character in user's input leads to XML formatter error
//  Artem Rodygin           2007-03-26      bug-516: Comma is removed in values of text fields.
//  Artem Rodygin           2007-07-12      new-544: The 'ctype' library should not be used.
//  Artem Rodygin           2007-09-12      new-576: [SF1788286] Export to CSV
//  Artem Rodygin           2007-10-08      bug-593: Some valid email addresses are rejected.
//  Artem Rodygin           2007-11-05      new-571: View should show all records of current filters set.
//  Artem Rodygin           2008-03-02      new-294: PostgreSQL support.
//  Artem Rodygin           2008-06-21      new-723: Wrap calls of 'mail' function.
//  Artem Rodygin           2008-06-30      bug-727: Notifications are not sent via Lotus Domino SMTP server.
//  Artem Rodygin           2008-09-11      new-716: 'Today' value in date field range.
//  Artem Rodygin           2008-09-13      bug-744: Dots are lost at the beginning of each line in mail notifications.
//  Artem Rodygin           2008-09-17      new-743: Include attached files in the notification.
//  Artem Rodygin           2008-10-14      bug-753: XML failure on some search results.
//  Artem Rodygin           2008-10-27      bug-695: BBCode // Address between [url] and [/url] is cut when contains a space.
//  Artem Rodygin           2008-11-08      bug-760: Backslashes are lost in checking PCRE patterns for textual fields.
//  Artem Rodygin           2009-02-28      bug-794: [SF2643676] Security problem when logout.
//  Artem Rodygin           2009-03-02      bug-795: [SF2653127] Security problem when logon in konqueror
//  Artem Rodygin           2009-03-05      bug-789: Custom fields show empty values in a view (PostgreSQL).
//  Artem Rodygin           2009-03-11      bug-799: eTraxis doesn't work with XAMPP on Windows.
//  Artem Rodygin           2009-04-13      bug-812: Strange Subject Messages in mail
//  Artem Rodygin           2009-04-25      new-801: Range of valid date values must be related to current date.
//  Artem Rodygin           2009-06-21      new-828: [SF2809460] Support for SMTP email
//  Artem Rodygin           2009-08-29      new-826: Native unicode support for Microsoft SQL Server.
//  Artem Rodygin           2009-09-06      new-827: Microsoft SQL Server 2005/2008 support.
//  Artem Rodygin           2009-10-13      bug-847: Email notification is broken when it's being sent with attachment.
//--------------------------------------------------------------------------------------------------

/**#@+
 * Dependency.
 */
require_once('../engine/debug.php');
require_once('../engine/smtp.php');
/**#@-*/

//--------------------------------------------------------------------------------------------------
//  Definitions.
//--------------------------------------------------------------------------------------------------

/**
 * Maximum integer value.
 */
define('MAXINT', 0x7FFFFFFF);

/**#@+
 * Number of seconds.
 */
define('SECS_IN_DAY',  86400);   // 60 * 60 * 24
define('SECS_IN_WEEK', 604800);  // 60 * 60 * 24 * 7
/**#@-*/

/**
 * Allowed CSV-delimiters.
 */
define('CSV_DELIMITERS', '!#$%&\'()*+,-./:;<=>?@[\]^_`{|}~');

//--------------------------------------------------------------------------------------------------
//  Functions.
//--------------------------------------------------------------------------------------------------

/**
 * Unicode (UTF-8) analogue of standard {@link http://www.php.net/strlen strlen} PHP function.
 *
 * Returns the length of the given string.
 *
 * @param string $str The UTF-8 encoded string being measured for length.
 * @return int The length (amount of UTF-8 characters) of the string on success, and 0 if the string is empty.
 */
function ustrlen ($str)
{
    return mb_strlen($str, 'UTF-8');
}

/**
 * Unicode (UTF-8) analogue of standard {@link http://www.php.net/strpos strpos} PHP function.
 *
 * Find position of first occurrence of a case-sensitive UTF-8 encoded string.
 * Returns the numeric position (offset in amount of UTF-8 characters) of the first occurrence of <i>needle</i> in the <i>haystack</i> string.
 *
 * @param string $haystack The UTF-8 encoded string being searched in.
 * @param string $needle The UTF-8 encoded string being searched for.
 * @param int $offset The optional <i>offset</i> parameter allows you to specify which character in <i>haystack</i> to start searching.
 * The position returned is still relative to the beginning of <i>haystack</i>.
 * @return int Returns the position as an integer. If <i>needle</i> is not found, the function will return boolean FALSE.
 */
function ustrpos ($haystack, $needle, $offset = 0)
{
    return mb_strpos($haystack, $needle, $offset, 'UTF-8');
}

/**
 * Unicode (UTF-8) analogue of standard {@link http://www.php.net/stripos stripos} PHP function.
 *
 * Find position of first occurrence of a case-insensitive UTF-8 encoded string.
 * Returns the numeric position (offset in amount of UTF-8 characters) of the first occurrence of <i>needle</i> in the <i>haystack</i> string.
 *
 * @param string $haystack The UTF-8 encoded string being searched in.
 * @param string $needle The UTF-8 encoded string being searched for.
 * @param int $offset The optional <i>offset</i> parameter allows you to specify which character in <i>haystack</i> to start searching.
 * The position returned is still relative to the beginning of <i>haystack</i>.
 * @return int Returns the position as an integer. If <i>needle</i> is not found, the function will return boolean FALSE.
 */
function ustripos ($haystack, $needle, $offset = 0)
{
    $haystack = mb_strtolower($haystack, 'UTF-8');
    $needle   = mb_strtolower($needle,   'UTF-8');

    return mb_strpos($haystack, $needle, $offset, 'UTF-8');
}

/**
 * Unicode (UTF-8) analogue of standard {@link http://www.php.net/strrpos strrpos} PHP function.
 *
 * Find position of last occurrence of a case-sensitive UTF-8 encoded string.
 * Returns the numeric position (offset in amount of UTF-8 characters) of the last occurrence of <i>needle</i> in the <i>haystack</i> string.
 *
 * @param string $haystack The UTF-8 encoded string being searched in.
 * @param string $needle The UTF-8 encoded string being searched for.
 * @return int Returns the position as an integer. If <i>needle</i> is not found, the function will return boolean FALSE.
 */
function ustrrpos ($haystack, $needle)
{
    return mb_strrpos($haystack, $needle, 'UTF-8');
}

/**
 * Unicode (UTF-8) analogue of standard {@link http://www.php.net/strtolower strtolower} PHP function.
 *
 * Make a string lowercase.
 *
 * @param string $str The UTF-8 encoded string to be lowercased.
 * @return string Specified string with all alphabetic characters converted to lowercase.
 */
function ustrtolower ($str)
{
    return mb_strtolower($str, 'UTF-8');
}

/**
 * Unicode (UTF-8) analogue of standard {@link http://www.php.net/substr substr} PHP function.
 *
 * Returns the portion of string specified by the <i>start</i> and <i>length</i> parameters.
 *
 * @param string $str The UTF-8 encoded string.
 * @param int $start Start of portion to be returned. Position is counted in amount of UTF-8 characters from the beginning of <i>str</i>.
 * First character's position is 0. Second character position is 1, and so on.
 * @param int $length If <i>length</i> is given, the string returned will contain at most <i>length</i> characters beginning from <i>start</i> (depending on the length of string).
 * If <i>length</i> is omitted, the rest of string from <i>start</i> will be returned.
 * @return string The extracted UTF-8 encoded part of input string.
 */
function usubstr ($str, $start, $length = NULL)
{
    return mb_substr($str, $start, (is_null($length) ? mb_strlen($str, 'UTF-8') : $length), 'UTF-8');
}

/**
 * Unicode (UTF-8) analogue of standard {@link http://www.php.net/str-replace str_replace} PHP function.
 *
 * Replace all occurrences of the search string with the replacement string.
 *
 * @param string $search The UTF-8 encoded string being searched for.
 * @param string $replace The UTF-8 encoded string being replaced with.
 * @param string $subject The UTF-8 encoded string being searched in.
 * @return string The UTF-8 encoded string with the replaced values.
 */
function ustr_replace ($search, $replace, $subject)
{
    $from = 0;
    $len  = ustrlen($search);

    while (TRUE)
    {
        $from = ustripos($subject, $search, $from);

        if ($from === FALSE)
        {
            break;
        }

        $subject = usubstr($subject, 0, $from) . $replace . usubstr($subject, $from + $len);
        $from += ustrlen($replace);
    }

    return $subject;
}

/**
 * Trims UTF-8 encoded string and then cuts it to specified length.
 *
 * @param string $str The UTF-8 encoded string being cut.
 * @param int $maxlen New length of the string (amount of UTF-8 characters).
 * @return string Cut string.
 */
function ustrcut ($str, $maxlen)
{
    return mb_substr(trim($str), 0, $maxlen, 'UTF-8');
}

/**
 * The function accepts variable number of arguments and replaces each "%i" (where <i>i</i> is
 * a natural number) substring of input string with related argument.
 *
 * Passed arguments can be any type of; in case of string they should be UTF-8 encoded.
 *
 * @param string $str The UTF-8 encoded string being processed.
 * @param mixed Value, which each "%1" substring will be replaced with.
 * @param mixed Value, which each "%2" substring will be replaced with.
 * @param mixed ... (and so on)
 * @return string Processed string.
 *
 * <br/>Example:<br/>
 * <code>
 * ustrprocess("Name: %1\nSex: %3\nAge: %2", "Artem", 30, "male");
 * </code>
 * <br/>will output<br/>
 * <pre>
 * Name: Artem
 * Sex: male
 * Age: 30
 * </pre>
 */
function ustrprocess ($str)
{
    for ($i = func_num_args(); $i > 1; $i--)
    {
        $search  = '%' . ($i - 1);
        $replace = func_get_arg($i - 1);
        $str     = ustr_replace($search, $replace, $str);
    }

    return $str;
}

/**
 * Converts UTF-8 encoded string to integer (natural) value.
 *
 * If resulted integer value is less then specified <i>min</i> value, the <i>min</i> value will be returned.
 * If resulted integer value is greater then specified <i>max</i> value, the <i>max</i> value will be returned.
 *
 * @param string $str The UTF-8 encoded string being converted.
 * @param int $min Minimum allowed result value.
 * @param int $max Maximum allowed result value.
 * @return int Natural value of range from <i>min</i> to <i>max</i>.
 */
function ustr2int ($str, $min = 0, $max = MAXINT)
{
    $res = (ustrlen($str) == 0 ? $min : intval($str));

    if ($res < $min)
    {
        $res = $min;
    }
    elseif ($res > $max)
    {
        $res = $max;
    }

    return $res;
}

/**
 * Converts specified amount of minutes to its string representation in format "hh:mm".
 *
 * @param int $time Amount of minutes.
 * @return string String representation (e.g. for 127 it will be "2:07").
 */
function time2ustr ($time)
{
    return intval(floor($time / 60)) . ':' . str_pad($time % 60, 2, '0', STR_PAD_LEFT);
}

/**
 * Strips HTML-tags from UTF-8 encoded string.
 *
 * @param string $str The UTF-8 encoded string.
 * @return string HTML-safe UTF-8 encoded string.
 */
function ustr2html ($str)
{
    if (is_null($str)) return NULL;

    $str = mb_ereg_replace("([\x00-\x08]|[\x0B-\x0C]|[\x0E-\x1F])", NULL, $str);
    return @htmlspecialchars($str, ENT_COMPAT, 'UTF-8');
}

/**
 * Strips quotes from UTF-8 encoded string.
 *
 * @param string $str The UTF-8 encoded string.
 * @return string JavaScript-safe UTF-8 encoded string.
 */
function ustr2js ($str)
{
    return ustr_replace('"', '&quot;', $str);
}

/**
 * Strips apostrophes from UTF-8 encoded string.
 *
 * @param string $str The UTF-8 encoded string.
 * @return string SQL-safe UTF-8 encoded string.
 */
function ustr2sql ($str)
{
    if ((DATABASE_DRIVER == 1) ||
        (DATABASE_DRIVER == 4))
    {
        $str = ustr_replace('\\', '\\\\', $str);
    }

    $str = ustr_replace('\'', '\'\'', $str);

    return $str;
}

/**
 * Convert UTF-8 encoded string to CSV format.
 *
 * @param string $str The UTF-8 encoded string.
 * @param string $delimiter CSV delimiter.
 * @param string $enclosure CSV enclosure.
 * @return string CSV string (UTF-8 encoded).
 */
function ustr2csv ($str, $delimiter = ',', $enclosure = '"')
{
    $str = ustr_replace($enclosure, $enclosure . $enclosure, $str);

    if (ustrpos($str, $enclosure) !== FALSE ||
        ustrpos($str, $delimiter) !== FALSE ||
        ustrpos($str, "\n")       !== FALSE)
    {
        $str = $enclosure . $str . $enclosure;
    }

    return $str;
}

/**
 * Parse UTF-8 encoded CSV string into an array.
 *
 * @param string $str The UTF-8 encoded CSV string.
 * @param string $delimiter CSV delimiter.
 * @param string $enclosure CSV enclosure.
 * @return array Indexed array containing the fields read (UTF-8 encoded), or NULL on error.
 */
function ustr_getcsv ($str, $delimiter = ',', $enclosure = '"')
{
    $csv = mb_split($delimiter, $str);

    for ($i = 0; $i < count($csv); $i++)
    {
        if (usubstr($csv[$i], 0, ustrlen($enclosure)) == $enclosure)
        {
            while ($i < count($csv) &&
                   usubstr($csv[$i], ustrlen($csv[$i]) - ustrlen($enclosure)) != $enclosure)
            {
                $csv[$i] .= $delimiter . $csv[$i + 1];
                array_splice($csv, $i + 1, 1);
            }

            $csv[$i] = usubstr($csv[$i], ustrlen($enclosure), ustrlen($csv[$i]) - ustrlen($enclosure) * 2);
        }
    }

    return $csv;
}

/**
 * Converts boolean value to integer for use in SQL queries.
 *
 * @param bool $value Boolean value.
 * @return int '1' on TRUE, or '0' on FALSE.
 */
function bool2sql ($value)
{
    return ($value ? 1 : 0);
}

/**
 * Returns value of user HTML-form request, if it exists; otherwise returns specified default value.
 *
 * @param string $request Name of user HTML-form request.
 * @param mixed $value Default value.
 * @return mixed User HTML-form request, or default value if specified request cannot be found.
 */
function try_request ($request, $value = NULL)
{
    global $_REQUEST;
    return (isset($_REQUEST[$request]) ? $_REQUEST[$request] : $value);
}

/**
 * Exchanges values of two variables.
 *
 * @param mixed &$value1 First variable.
 * @param mixed &$value2 Second variable.
 */
function swap (&$value1, &$value2)
{
    $temp   = $value1;
    $value1 = $value2;
    $value2 = $temp;
}

/**
 * Finds whether the given UTF-8 encoded string contains valid integer value.
 *
 * @param string $str The UTF-8 encoded string being evaluated.
 * @return bool TRUE if <i>str</i> contains valid integer value, FALSE otherwise.
 */
function is_intvalue ($str)
{
    mb_regex_encoding('UTF-8');
    return mb_eregi('^(\+|\-)*([0-9])+$', $str);
}

/**
 * Finds whether the given UTF-8 encoded string contains valid login
 * (only latin characters, digits, and underline are allowed).
 *
 * @param string $str The UTF-8 encoded string being evaluated.
 * @return bool TRUE if <i>str</i> contains valid login, FALSE otherwise.
 */
function is_username ($str)
{
    mb_regex_encoding('UTF-8');
    return mb_eregi('^([_0-9a-z])+$', $str);
}

/**
 * Finds whether the given UTF-8 encoded string contains valid email address.
 *
 * @param string $str The UTF-8 encoded string being evaluated.
 * @return bool TRUE if <i>str</i> contains valid email address, FALSE otherwise.
 */
function is_email ($str)
{
    mb_regex_encoding('UTF-8');

    $atom   = '[-a-z0-9!#$%&\'*+/=?^_`{|}~]';      // allowed characters for part before "at" character
    $domain = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)';  // allowed characters for part after "at" character

    return mb_eregi("^{$atom}+(\\.{$atom}+)*@({$domain}{1,63}\\.)+{$domain}{2,63}$", $str);
}

/**
 * Sends email notification.
 *
 * @param string $sender Name of sender.
 * @param string $from Email address of sender.
 * @param string $to Email addresses of recipients (comma-separated).
 * @param string $subject Subject of the notification.
 * @param string $message Body of the notification.
 * @param int $attachment_id {@link http://www.etraxis.org/docs-schema.php#tbl_attachments_attachment_id ID} of attachment if it should be included in email, NULL otherwise.
 * @param string $attachment_name {@link http://www.etraxis.org/docs-schema.php#tbl_attachments_attachment_name Name} of attachment if it should be included in email, NULL otherwise.
 * @param string $attachment_type {@link http://www.etraxis.org/docs-schema.php#tbl_attachments_attachment_type MIME type} of attachment if it should be included in email, NULL otherwise.
 * @param int $attachment_size {@link http://www.etraxis.org/docs-schema.php#tbl_attachments_attachment_size Size} of attachment if it should be included in email, NULL otherwise.
 * @return bool TRUE if the mail was successfully accepted for delivery, FALSE otherwise.
 */
function sendmail ($sender, $from, $to, $subject, $message, $attachment_id = NULL, $attachment_name = NULL, $attachment_type = NULL, $attachment_size = NULL)
{
    debug_write_log(DEBUG_TRACE, '[sendmail]');

    if (strtolower(substr(PHP_OS, 0, 3)) == 'win')
    {
        $eol = "\r\n";

        // When PHP is talking to a SMTP server directly, if a full stop is found on the start of
        // a line, it is removed. To counter-act this, replace these occurrences with a double dot.
        $message = ustr_replace("\n.", "\n..", $message);
    }
    elseif (strtolower(substr(PHP_OS, 0, 3)) == 'mac')
    {
        $eol = "\r";
    }
    else
    {
        $eol = "\n";
    }

    $is_attachment = ($attachment_size <= EMAIL_ATTACHMENTS_MAXSIZE * 1024 && !is_null($attachment_id));

    $boundary = 'eTraxis-boundary:' . md5(uniqid(time()));

    $headers = implode($eol, array('Date: ' . date('r'),
                                   'From: ' . $sender . ' <' . (EMAIL_NOTIFICATIONS_ENABLED == SMTP_CLIENT_BUILDIN ? SMTP_MAILFROM : $from) . '>',
                                   'To: ' . $to,
                                   'Reply-To: ' . $from,
                                   'Return-Path: ' . $from,
                                   'Message-ID: <' . md5(uniqid(time())) . '@' . $_SERVER['SERVER_NAME'] . '>',
                                   'X-Priority: 3',
                                   'X-Mailer: eTraxis ' . VERSION,
                                   'MIME-Version: 1.0',
                                   ($is_attachment ? 'Content-Type: multipart/mixed; boundary="' . $boundary . '"'
                                                   : 'Content-Type: text/html; charset="utf-8"')
                                   ));

    if ($is_attachment)
    {
        $message = implode($eol, array('This is a multi-part message in MIME format.',
                                       NULL,
                                       '--' . $boundary,
                                       'Content-Type: text/html; charset="utf-8"',
                                       NULL,
                                       $message,
                                       NULL,
                                       '--' . $boundary,
                                       'Content-Type: ' . $attachment_type . '; name="' . $attachment_name . '"',
                                       'Content-Transfer-Encoding: base64',
                                       'Content-Disposition: attachment; filename="' . $attachment_name . '"',
                                       NULL,
                                       chunk_split(base64_encode(file_get_contents(ATTACHMENTS_PATH . $attachment_id))),
                                       NULL,
                                       '--' . $boundary . '--'));
    }

    debug_write_log(DEBUG_DUMP, '[sendmail] $to = ' . $to);
    debug_write_log(DEBUG_DUMP, '[sendmail] $subject = ' . $subject);
    debug_write_log(DEBUG_DUMP, "[sendmail] \$headers =\n{$headers}");
    debug_write_log(DEBUG_DUMP, "[sendmail] \$message =\n{$message}");

    switch (EMAIL_NOTIFICATIONS_ENABLED)
    {
        case SMTP_CLIENT_PHP:
            return @mail($to, $subject, $message, $headers);
        case SMTP_CLIENT_BUILDIN:
            return smtp_send_mail($to, $subject, $message, $headers);
        default:
            debug_write_log(DEBUG_WARNING, '[sendmail] Email notifications are disabled.');
    }

    return FALSE;
}

/**
 * Round specified timestamp down to midnight.
 *
 * @param int $timestamp Unix timestamp (see {@link http://en.wikipedia.org/wiki/Unix_time})
 * @return int Unix timestamp (see {@link http://en.wikipedia.org/wiki/Unix_time}) for midnight of the same date.
 */
function date_floor ($timestamp)
{
    $date = getdate($timestamp);
    return mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']);
}

/**
 * Returns timestamp, shifted from specified for particular number of days.
 * Negative offset shifts to past, positive - to future.
 *
 * @param int $timestamp Unix timestamp (see {@link http://en.wikipedia.org/wiki/Unix_time}) to be shifted from
 * @param int $offset Number of days to be shifted for
 * @return int Unix timestamp (see {@link http://en.wikipedia.org/wiki/Unix_time}) for resulting shifted date.
 */
function date_offset ($timestamp, $offset)
{
    $now      = date_floor($timestamp);
    $min_date = date_floor(0);
    $max_date = date_floor(MAXINT);

    // Determine maximum allowed shifts to both past and future to avoid byte overflow error
    // (any timestamp must be in range from 0x00000000 to 0x7FFFFFFF)
    $max_backward = round(($min_date - $now) / SECS_IN_DAY);
    $max_forward  = round(($max_date - $now) / SECS_IN_DAY);

    // If specified offset looks to far in the past, adjust it to the maximum allowed offset.
    if ($offset < $max_backward)
    {
        $offset = $max_backward;
    }

    // If specified offset looks to far in the future, adjust it to the maximum allowed offset.
    if ($offset > $max_forward)
    {
        $offset = $max_forward;
    }

    return strtotime("{$offset} days", $timestamp);
}

/**
 * Generates Basic HTTP Authentication realm, based on client browser.
 *
 * @return string Generated realm.
 */
function get_http_auth_realm ()
{
    $realm = 'eTraxis';

    if (stripos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== FALSE ||
        stripos($_SERVER['HTTP_USER_AGENT'], 'Opera')     !== FALSE ||
        stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')    !== FALSE)
    {
        $realm .= '-' . time();
    }

    return $realm;
}

?>
Return current item: ETraxis