function cron_example()
{
    if (!inCLI()) {
        // send headers (for running through web with "Run Manually" link above)
        if (!headers_sent()) {
            header("Content-type: text/plain");
            header("Content-Disposition: inline; filename='output.txt'");
            // Force IE to display as text and not download file
            ob_disable();
            // Turn off browser buffering
        }
        // This lines are only needed if your cron script is going to be called directly and you need to enforce security, if cron is added as a CMS "Background Task" then you can specify access rights in: pluginAction_addHandlerAndLink
        // $CMS_USER = getCurrentUserFromCMS();                                                                       // security check for web access - don't show cron filepaths unless logged in
        // if (!@$CMS_USER['isAdmin']) { die(t("You must be logged in as Admin to run this script from the web!")); } // security check for web access - don't show cron filepaths unless logged in
        ignore_user_abort(true);
        // continue running even if user clicks stop on their browser
        session_write_close();
        // v2.51 - End the current session and store session data so locked session data doesn't prevent concurrent access to CMS by user while backup in progress
    }
    set_time_limit(0);
    // ignore PHP's max_execution_time directive
    //
    print "My sample Cron \n";
    print "--------------------------------------------------------------------------------\n";
    // Add your own code here...
    print "The current time is: " . date('Y-m-d H:i:s') . "\n\n";
    print "Done!\n";
    // return summary message
    $summary = "Successful";
    if (@$_REQUEST['_pluginAction'] == __FUNCTION__) {
        exit;
    }
    // exit if being run manually from web
    return $summary;
    // otherwise, return summary if being run by cron
}
function _init_startSession()
{
    // Remove 0-byte session files on shutdown - added in v2.52
    // PHP _always_ creates session files, even when the sessions are empty.  This means 10 hits from a search engine spider creates
    // ... ten 0-byte session files that won't be removed until after session.gc_maxlifetime is reached.  This can create tens of thousands
    // ... of unneeded files.  This function removes zero-byte session files on shutdown by calling session destroy. For session in active
    // ... use, unsetting all $_SESSION values will cause the session file to be removed, but the same file will be recreated on next page-view.
    // PHP Docs Reference: "A file for each session (regardless of if any data is associated with that session) will be created. This is due to
    // ... the fact that a session is opened (a file is created) but no data is even written to that file. Note that this behavior is a
    // ... side-effect of the limitations of working with the file system... from: http://php.net/manual/en/session.installation.php
    function _remove_empty_session_file()
    {
        if (isset($_SESSION) && empty($_SESSION) && session_id()) {
            @session_destroy();
        }
    }
    // removes session file
    register_shutdown_function('_remove_empty_session_file');
    // remove session file on shutdown
    // note: run this here so even if we're not creating a session, session's created by other PHP code won't leave 0 byte files either.
    // check if we need to start a session
    $startSession = false;
    if (inCLI()) {
        $startSession = false;
    } elseif (inDemoMode()) {
        $startSession = true;
    } elseif (defined('IS_CMS_ADMIN')) {
        $startSession = true;
    } elseif (defined('START_SESSION')) {
        $startSession = true;
    }
    // if starting a session is explicitly requested
    if (!$startSession) {
        return;
    }
    startSessionIfRequired();
}
function cron_dispatcher()
{
    // runs due or overdue jobs
    // get last cron.php run time
    $cronLastRunTime = $GLOBALS['SETTINGS']['bgtasks_lastRun'];
    $thisCronRunTime = time();
    // call log function if cron jobs exit or die
    register_shutdown_function('cron_logErrorsOnDieOrExit');
    // run cron tasks
    $dispatchedTaskCounter = 0;
    foreach (getCronList() as $cron) {
        //print "DEBUG: Checking... " .$cron['function']. " => " .$cron['expression']. "\n";
        // get last job run time and oldest time to check
        $jobLastLogRecord = mysql_get('_cron_log', null, ' function = "' . mysql_escape($cron['function']) . '" ORDER BY num DESC');
        $jobLastRunTime = strtotime($jobLastLogRecord['createdDate']);
        $oldestTimeToCheck = max($cronLastRunTime, $jobLastRunTime);
        // get most recent valid run time (from now to the last time cron.php ran)
        $lastScheduleRunTime = cronExpression_getLastScheduledTime($cron['expression'], $oldestTimeToCheck, $cronExprParseErrors);
        $skipTask = false;
        if (!$lastScheduleRunTime && !$cronExprParseErrors) {
            $skipTask = true;
        }
        // skip if no scheduled runtime found since last cronrun (and no errors which might have caused that)
        if ($lastScheduleRunTime && $lastScheduleRunTime <= $cronLastRunTime) {
            $skipTask = true;
        }
        // skip if scheduled to run, but not quite yet (if scheduled time is blank then there was an error)
        if ($thisCronRunTime - 60 < $jobLastRunTime) {
            $skipTask = true;
        }
        // don't run jobs more than once a minute
        if ($skipTask) {
            if (!inCLI()) {
                print "Skipping {$cron['activity']}, function: {$cron['function']} (not scheduled to run again yet)\n";
            }
            continue;
        }
        // Add log entry for job
        $hasLock = mysql_get_lock($cron['function']);
        // get a lock for this specific function
        if ($cronExprParseErrors) {
            $summary = $cronExprParseErrors;
        } elseif (!$hasLock) {
            $summary = t('Aborting, task still running from last time.');
        } else {
            $summary = t('Running...');
        }
        $jobLogNum = mysql_insert('_cron_log', array('createdDate=' => 'NOW()', 'function' => $cron['function'], 'activity' => $cron['activity'], 'summary' => $summary, 'completed' => 0));
        // skip if errors parsing cronExpression or getting lock
        if ($cronExprParseErrors || !$hasLock) {
            continue;
        }
        // execute function
        $dispatchedTaskCounter++;
        if (!inCLI()) {
            print "Running {$cron['activity']}, function: {$cron['function']}\n";
        }
        ob_start();
        $startTime = microtime(true);
        $GLOBALS['CRON_JOB_START'] = $startTime;
        // store job num in a global so we can update it after die/exit with cron_logErrorsOnDieOrExit
        $GLOBALS['CRON_JOB_LOG_NUM'] = $jobLogNum;
        // store job num in a global so we can update it after die/exit with cron_logErrorsOnDieOrExit
        $summary = call_user_func($cron['function'], array('note' => 'this $info array is for future use'));
        $GLOBALS['CRON_JOB_LOG_NUM'] = '';
        $endTime = microtime(true);
        $output = ob_get_clean();
        // update job log entry
        mysql_update('_cron_log', $jobLogNum, null, array('completed' => 1, 'summary' => $summary, 'output' => $output, 'runtime' => sprintf("%0.2f", $endTime - $startTime)));
        mysql_release_lock($cron['function']);
    }
    // update lastrun time
    $GLOBALS['SETTINGS']['bgtasks_lastRun'] = time();
    saveSettings();
}
function saveSettings($forceDevFile = false)
{
    // added arg in 2.53
    if (inCLI() && !isInstalled()) {
        return;
    }
    // prevent cron.php from saving auto-generated settings until software has been installed (not all setting defaults can be set from CLI as $_SERVER values aren't available).
    $settingsPath = $forceDevFile ? SETTINGS_DEV_FILEPATH : SETTINGS_FILEPATH;
    saveStruct($settingsPath, $GLOBALS['SETTINGS'], true);
}
function connectToMySQL($returnErrors = false)
{
    global $SETTINGS, $DBH;
    ### Get connection details
    $hostname = getFirstDefinedValue(@$SETTINGS["mysql:{$_SERVER['HTTP_HOST']}"]['hostname'], $SETTINGS['mysql']['hostname']);
    $username = getFirstDefinedValue(@$SETTINGS["mysql:{$_SERVER['HTTP_HOST']}"]['username'], $SETTINGS['mysql']['username']);
    $password = getFirstDefinedValue(@$SETTINGS["mysql:{$_SERVER['HTTP_HOST']}"]['password'], $SETTINGS['mysql']['password']);
    $database = getFirstDefinedValue(@$SETTINGS["mysql:{$_SERVER['HTTP_HOST']}"]['database'], $SETTINGS['mysql']['database']);
    $textOnlyErrors = coalesce(inCLI(), @$SETTINGS["mysql:{$_SERVER['HTTP_HOST']}"]['textOnlyErrors'], $SETTINGS['mysql']['textOnlyErrors']);
    ##  SLOW REMOTE CONNECTION
    ##  If you are connecting to a remote database that is intolerably slow, try
    ##  updating the mysql configuration file (often "/etc/my.cfg") by adding the
    ##  following option to the [mysqld] section:
    ##
    ##     skip-name-resolve
    ##
    ##  Here is the MySQL documentation for this option:
    ##
    ##    --skip-name-resolve
    ##    Do not resolve host names when checking client connections. Use only IP addresses.
    ##    If you use this option, all Host column values in the grant tables must be IP addresses or localhost.
    ### Connect to database
    $DBH = @mysql_connect($hostname, $username, $password);
    if (!$DBH) {
        $connectionError = mysql_error();
        if ($returnErrors) {
            return "Error connecting to MySQL:<br/>\n{$connectionError}";
        } elseif ($textOnlyErrors) {
            die("Error connecting to MySQL: {$connectionError}");
        } else {
            $libDir = pathinfo(__FILE__, PATHINFO_DIRNAME);
            // viewers may be in different dirs
            include "{$libDir}/menus/dbConnectionError.php";
        }
        exit;
    }
    // select db
    $isDbSelected = mysql_select_db($database);
    if (!$isDbSelected) {
        mysql_query("CREATE DATABASE `{$database}`") or die("MySQL Error: " . mysql_error() . "\n");
        mysql_select_db($database) or die("MySQL Error: " . mysql_error() . "\n");
    }
    ### check for required mysql version
    $currentVersion = preg_replace("/[^0-9\\.]/", '', mysql_get_server_info());
    if (version_compare(REQUIRED_MYSQL_VERSION, $currentVersion, '>')) {
        $error = "This program requires MySQL v" . REQUIRED_MYSQL_VERSION . " or newer. This server has v{$currentVersion} installed.<br/>\n";
        $error .= "Please ask your server administrator to install MySQL v" . REQUIRED_MYSQL_VERSION . " or newer.<br/>\n";
        if ($returnErrors) {
            return $error;
        }
        die($error);
    }
    ### Set Character Set
    # note: set through PHP 'set_charset' function so mysql_real_escape string() knows what charset to use. setting the charset
    # ... through mysql queries with 'set names' didn't cause mysql_client_encoding() to return a different value
    mysql_set_charset("utf8") or die("Error loading character set utf8: " . mysql_error() . '');
    # set MySQL strict mode - http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
    mysqlStrictMode(true);
    # set MySQL timezone offset
    setMySqlTimezone();
    //
    return '';
}