after the VIKO database
 * has been updated. If run before - an error message is shown.
 *
 * The files will be loaded into table File_Contents.
 */
// turn on all errors
// this has to be at the very beginning to catch all the errors beginning from here.
error_reporting(E_ALL);
// Modify the include path to fit the requirements of VIKO
// after we have adjusted the include path, we can start including required libraries.
initialize_php_include_path();
/**
 * HTML class is needed for generating HTML
 */
require_once "HTML.php";
/**
 * Main class for VIKO
 */
require_once 'VIKO.php';
/**
 * MimeType class is needed for determining MIME types
 */
require_once 'MimeType.php';
// load VIKO configuration file
Configuration::get( getcwd() . "/viko.conf");
// use ordinary database connection instead of DB object
// DB introduces too much overhead, and we need the fastest solution possible.
mysql_connect(
    Configuration::getDatabaseHost(),
    Configuration::getDatabaseUsername(),
    Configuration::getDatabasePassword()
);
mysql_select_db( Configuration::getDatabaseName() );
// first of all make sure that the database is updated before running this script.
// The old Files_Folder table should be dropped after the database update - so
// by checking the existance of that table we can find out, if the database is updated.
$files_folders_table = mysql_query("SHOW TABLES LIKE 'Files_Folders'");
if ( mysql_num_rows($files_folders_table) > 0 ) {
    // the table exists - therefore the database is not updated
    VIKO_page(
        "Error!",
        HTML::errorPage(
            "Before running this script, you have to update VIKO database. " .
            "Use the database update script in file sql/changes_2.0.sql."
        )
    );
}
// we ask a confirmation before running this script.
if ( !isset( $_POST['submit'] ) ) {
    // show a form with submit button.
    VIKO_page(
        "Import files to database",
        HTML::h2( "Import files to database" ) .
        '
";
    foreach ( $files_not_found as $file ) {
        $not_found_error .= "$file\n";
    }
    $not_found_error .= "";
}
$nr_of_files_to_process = get_nr_of_files_to_process();
if ( $nr_of_files_to_process > 0 ) {
    VIKO_page(
        "Part of the files imported to database",
        HTML::h2("Part of the files imported to database") .
        HTML::p("Because the server has time limit for PHP scripts, " .
            "it's not possible to import all files in one run. ".
            "You have to keep clicking 'Continue' until all files are imported.") .
        HTML::p("There are $nr_of_files_to_process more files to process.") .
        '' .
        $not_found_error
    );
}
else {
    $files_left_over = look_for_remaining_files();
    // if there were more files in files/ dir than in database, then show error and list of those files
    $left_over_error = "";
    if ( count($files_left_over) > 0 ) {
        $left_over_error = HTML::error(
            "The script found " . count($files_left_over) . " files from files/, " .
            "that were not mentioned in database. " .
            "Note, that this is a sign of error - your database and files folder are out of sync."
        );
        $left_over_error .= "";
        foreach ( $files_left_over as $file ) {
            $left_over_error .= "$file\n";
        }
        $left_over_error .= "";
    }
    if ( $not_found_error == "" && $left_over_error == "" ) {
        // no errors were recorded - exit with success message
        VIKO_page(
            "Success! File hierarchy converted",
            HTML::h2("Success! File hierarchy converted") .
            HTML::notice("Structure of files/ directory converted to VIKO 2.0.") .
            HTML::p("You should now remove the file 'convert-viko-files.php' from VIKO installation.")
        );
    }
    else {
        // the file
        VIKO_page(
            "Conversion finished with errors",
            HTML::h2("Conversion finished with errors") .
            HTML::p(
                "When converting structure of files/ directory to VIKO 2.0, " .
                "the following errors accoured:"
            ) .
            $not_found_error .
            $left_over_error
        );
    }
}
/**
 * Loads files from 'files/file_id/filename.ext' to database
 *
 * Also empties database field file_uri.
 *
 * If the database contained references to some files, that were not found
 * in filesystem, the function returns a list (array) of those missing files.
 * If everything went successfully an empty array is returned.
 *
 * @return array list of errors
 */
function load_files_to_database()
{
    // get listing of all files from database
    $r = mysql_query(
        "SELECT
            material_id,
            material_uri
        FROM
            Materials
        WHERE
            material_type = 'FILE'
            AND
            material_uri != ''
        "
    );
    $errors = array();
    // we may not exceed the maximum execution time
    // the default is 30 seconds, but we may not be sure.
    // probably it isn't smaller than 30 seconds, so we can extract 5 seconds for extra safety
    $time_limit = ini_get("max_execution_time") - 5;
    $start_time = time();
    while ( $file = mysql_fetch_array($r) ) {
        // get the name of old ID directory by removing everything after the slash "/" (including slash itself)
        $old_file_dir = 'files/' . preg_replace( '#/.*$#', '', $file["material_uri"] );
        if ( file_exists( $old_file_dir ) ) {
            // because the old filename might contain some strange characters which may not
            // correlate with the filename characters in database, open the directory and
            // read the filename from there into variable $filename
            $filename = get_first_file_from_dir( $old_file_dir );
            // load the file into database
            load_file_into_database( $file["material_id"], "$old_file_dir/$filename" );
            // remove the file from 'files'
            unlink( "$old_file_dir/$filename" );
            // remove the old file directory from 'files'
            rmdir( $old_file_dir );
        }
        else {
            $errors[] = "Directory '$old_file_dir' is missing!";
        }
        // determine the MIME type of file
        $mime_type = MimeType::determineFromFilename( $file["material_uri"] );
        // empty field file_uri in database and set the mime type
        mysql_query(
            "UPDATE
                Materials
            SET
                material_uri='',
                mime_type='$mime_type'
            WHERE
                material_id=$file[material_id]
            "
        );
        // check whether we have reached or exceeded time limit
        if (  $time_limit > 0   &&   time() >= $start_time + $time_limit  ) {
            return $errors;
        }
    }
    return $errors;
}
/**
 * Retrieves the name of the first file in directory
 *
 * @param string $dir directory
 * @return string filename
 */
function get_first_file_from_dir( $dir )
{
    $dir_handle = opendir( $dir );
    while ( false !== ($filename = readdir($dir_handle)) ) {
        if ( ! ($filename == '.' || $filename == '..') ) {
            break;
        }
    }
    closedir( $dir_handle );
    return $filename;
}
/**
 * Inserts file contents into table File_Contents
 *
 * @param int $file_id
 * @param string $filename
 */
function load_file_into_database( $file_id, $filename )
{
    // echo "loading $filename...";
    $file = file_get_contents( $filename );
    $file = mysql_real_escape_string( $file );
    mysql_query( "INSERT INTO Material_Contents (material_id, material_content) VALUES ( $file_id, '$file' )" );
    // echo " [done]\n";
}
/**
 * Checks, if there are any more files left in old 'files' directory
 *
 * If there are, returns array containing names of the files moved.
 *
 * @return array remaining files
 */
function look_for_remaining_files()
{
    $remaining_files = array();
    $dir_handle = opendir( 'files' );
    while ( false !== ($file = readdir($dir_handle)) ) {
        if ( $file == '.' || $file == '..' ) {
            // do nothing - these are system dirs
        }
        else {
            // count the files
            $remaining_files[] = "files/$file";
        }
    }
    closedir( $dir_handle );
    return $remaining_files;
}
/**
 * Returns the number of files in database that need loading to database
 *
 * @return int nr of files
 */
function get_nr_of_files_to_process()
{
    $r = mysql_query("SELECT COUNT(*) FROM Materials WHERE material_type = 'FILE' AND material_uri != '' ");
    $row = mysql_fetch_array( $r );
    return $row[0];
}
/**
 * Create VIKO error page
 *
 * @param string $title    the title of the page
 * @param string $content  the whole contents of the page
 */
function VIKO_page( $title, $content )
{
    $viko =& new VIKO();
    $viko->setTitle( $title );
    $viko->setContent( $content );
    // output page
    header("Content-type: text/html; charset=utf-8");
    echo $viko->toHTML();
    exit();
}
/**
 * Modifies PHP include path to contain paths to VIKO and PEAR code libraries
 *
 * VIKO code resides in two subdirectories of VIKO installation:
 *
 *