|
<?php
|
|
// Project: Web Reference Database (refbase) <http://www.refbase.net>
|
|
// Copyright: Matthias Steffens <mailto:refbase@extracts.de> and the file's
|
|
// original author(s).
|
|
//
|
|
// This code is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY. Please see the GNU General Public
|
|
// License for more details.
|
|
//
|
|
// File: ./includes/include.inc.php
|
|
// Repository: $HeadURL: file:///svn/p/refbase/code/branches/bleeding-edge/includes/include.inc.php $
|
|
// Author(s): Matthias Steffens <mailto:refbase@extracts.de>
|
|
//
|
|
// Created: 16-Apr-02, 10:54
|
|
// Modified: $Date: 2018-02-16 21:28:11 +0000 (Fri, 16 Feb 2018) $
|
|
// $Author: karnesky $
|
|
// $Revision: 1420 $
|
|
|
|
// This file contains important
|
|
// functions that are shared
|
|
// between all scripts.
|
|
|
|
|
|
// Incorporate some include files:
|
|
include 'initialize/db.inc.php'; // 'db.inc.php' is included to hide username and password
|
|
include 'initialize/ini.inc.php'; // include common variables
|
|
|
|
// include transliteration tables:
|
|
include 'includes/transtab_unicode_ascii.inc.php'; // include unicode -> ascii transliteration table
|
|
include 'includes/transtab_latin1_ascii.inc.php'; // include latin1 -> ascii transliteration table
|
|
include 'includes/transtab_unicode_latin1.inc.php'; // include unicode -> latin1 transliteration table
|
|
include 'includes/transtab_unicode_refbase.inc.php'; // include unicode -> refbase transliteration table
|
|
|
|
if ($contentTypeCharset == "UTF-8") // variable '$contentTypeCharset' is defined in 'ini.inc.php'
|
|
include_once 'includes/transtab_unicode_charset.inc.php'; // include unicode character case conversion tables
|
|
else // we assume "ISO-8859-1" by default
|
|
include_once 'includes/transtab_latin1_charset.inc.php'; // include latin1 character case conversion tables
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Untaint user data:
|
|
function clean($input, $maxlength)
|
|
{
|
|
$input = substr($input, 0, $maxlength);
|
|
$input = EscapeShellCmd($input);
|
|
return ($input);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Start a session:
|
|
function start_session($updateUserFormatsStylesTypesPermissions)
|
|
{
|
|
global $databaseBaseURL; // these variables are defined in 'ini.inc.php'
|
|
global $defaultMainFields;
|
|
global $filesBaseDir;
|
|
global $filesBaseURL;
|
|
|
|
global $loginEmail;
|
|
global $loginUserID;
|
|
global $loginFirstName;
|
|
global $loginLastName;
|
|
global $abbrevInstitution;
|
|
global $lastLogin;
|
|
global $referer; // '$referer' is made globally available from within this function
|
|
|
|
global $connection;
|
|
|
|
// Initialize the session:
|
|
if (!isset($_SESSION["sessionID"]))
|
|
{
|
|
// Ensure that cookies are enabled:
|
|
if (ini_get('session.use_cookies') == 0) // if 'session.use_cookies' is OFF for the current directory
|
|
ini_set('session.use_cookies', 1); // enable storage of sessions within cookies
|
|
|
|
session_start();
|
|
|
|
$sessionID = session_id(); // get the current session ID
|
|
|
|
if (!empty($sessionID))
|
|
saveSessionVariable("sessionID", $sessionID);
|
|
}
|
|
|
|
// Set the system's locale information:
|
|
list($systemLocaleCollate, $systemLocaleCType) = setSystemLocale();
|
|
|
|
// Set the default timezone used by all date/time functions
|
|
// Note: The 'date_default_timezone_set/date_default_timezone_get' functions are available since PHP 5.1.0
|
|
if (function_exists("date_default_timezone_set") && function_exists("date_default_timezone_get"))
|
|
@date_default_timezone_set(@date_default_timezone_get());
|
|
|
|
// NOTE: Upon first connection to the MySQL server, function 'connectToMySQLDatabase()' will query the
|
|
// MySQL server for the MySQL version and save it to a session variable
|
|
|
|
// Extract session variables (only necessary if register globals is OFF!):
|
|
if (isset($_SESSION['loginEmail']))
|
|
{
|
|
$loginEmail = $_SESSION['loginEmail'];
|
|
$loginUserID = $_SESSION['loginUserID'];
|
|
$loginFirstName = $_SESSION['loginFirstName'];
|
|
$loginLastName = $_SESSION['loginLastName'];
|
|
$abbrevInstitution = $_SESSION['abbrevInstitution'];
|
|
$lastLogin = $_SESSION['lastLogin'];
|
|
}
|
|
elseif ($updateUserFormatsStylesTypesPermissions)
|
|
{
|
|
// If the user isn't logged in we set the available export formats, citation styles, document types and permissions to
|
|
// the defaults which are specified in the 'formats', 'styles', 'types' and 'user_permissions' tables for 'user_id = 0'.
|
|
// (a 'user_id' of zero is used within these tables to indicate the default settings if the user isn't logged in)
|
|
// NOTE: As an exception, for anyone who isn't logged in, we don't load the default number of records from option
|
|
// 'records_per_page' in table 'user_options', but instead use the value given in variable '$defaultNumberOfRecords'
|
|
// in 'ini.inc.php'. Similarly, if the user isn't logged in, the list of "main fields" is taken from variable
|
|
// '$defaultMainFields' in 'ini.inc.php' and not from option 'main_fields' in table 'user_options. Same holds true
|
|
// for variable '$autoCompleteUserInput' vs. option 'show_auto_completions'.
|
|
|
|
// Get all export formats that were selected by the admin to be visible if a user isn't logged in
|
|
// and (if some formats were found) save them as semicolon-delimited string to the session variable 'user_export_formats':
|
|
getVisibleUserFormatsStylesTypes(0, "format", "export");
|
|
|
|
// Get all citation formats that were selected by the admin to be visible if a user isn't logged in
|
|
// and (if some formats were found) save them as semicolon-delimited string to the session variable 'user_cite_formats':
|
|
getVisibleUserFormatsStylesTypes(0, "format", "cite");
|
|
|
|
// Get all citation styles that were selected by the admin to be visible if a user isn't logged in
|
|
// and (if some styles were found) save them as semicolon-delimited string to the session variable 'user_styles':
|
|
getVisibleUserFormatsStylesTypes(0, "style", "");
|
|
|
|
// Get all document types that were selected by the admin to be visible if a user isn't logged in
|
|
// and (if some types were found) save them as semicolon-delimited string to the session variable 'user_types':
|
|
getVisibleUserFormatsStylesTypes(0, "type", "");
|
|
|
|
// Get the user permissions for the current user
|
|
// and save all allowed user actions as semicolon-delimited string to the session variable 'user_permissions':
|
|
getPermissions(0, "user", true);
|
|
|
|
// Get the default view for the current user
|
|
// and save it to the session variable 'userDefaultView':
|
|
getDefaultView(0);
|
|
|
|
// Get the default number of records per page preferred by the current user
|
|
// and save it to the session variable 'userRecordsPerPage':
|
|
getDefaultNumberOfRecords(0);
|
|
|
|
// Get the user's preference for displaying auto-completions
|
|
// and save it to the session variable 'userAutoCompletions':
|
|
getPrefAutoCompletions(0);
|
|
|
|
// Get the list of "main fields" for the current user
|
|
// and save the list of fields as comma-delimited string to the session variable 'userMainFields':
|
|
getMainFields(0);
|
|
}
|
|
else // if ($updateUserFormatsStylesTypesPermissions == false)
|
|
{
|
|
// The scripts 'error.php', 'install.php' & 'update.php' use 'start_session(false);' so that they execute without errors
|
|
// when there isn't any database yet. However, function 'buildQuickSearchElements()' (which builds the "Quick Search" form
|
|
// in the page header) requires the session variable 'userMainFields' to be present. So we take the list of "main fields"
|
|
// directly from the global variable '$defaultMainFields' and save it as session variable (we cannot use function
|
|
// 'getMainFields()' here since this would require database access):
|
|
if (!isset($_SESSION['userMainFields']))
|
|
saveSessionVariable("userMainFields", $defaultMainFields);
|
|
}
|
|
|
|
// Set the referrer:
|
|
if (isset($_REQUEST['referer']) AND !empty($_REQUEST['referer']) AND strpos($_REQUEST['referer'], '://')===false)
|
|
$referer = $_REQUEST['referer']; // get the referring URL from the superglobal '$_REQUEST' variable (if any)
|
|
|
|
elseif (isset($_SESSION['referer']) AND !empty($_SESSION['referer']))
|
|
{
|
|
$referer = $_SESSION['referer']; // get the referring URL from the superglobal '$_SESSION' variable (if any)
|
|
deleteSessionVariable("referer");
|
|
}
|
|
|
|
elseif (isset($_SERVER['HTTP_REFERER']) AND !empty($_SERVER['HTTP_REFERER']))
|
|
$referer = $_SERVER['HTTP_REFERER']; // get the referring URL from the superglobal '$_SERVER' variable (if any)
|
|
|
|
else // as an example, the referrer won't be set if a user clicked on a URL of type 'show.php?record=12345' within an email announcement
|
|
$referer = "index.php"; // if all other attempts fail, we'll re-direct to the main page
|
|
|
|
// Verify important variables from 'ini.inc.php':
|
|
// - Ensure that the given paths/URLs end with a slash:
|
|
$databaseBaseURL = checkPath($databaseBaseURL, "URL");
|
|
$filesBaseDir = checkPath($filesBaseDir);
|
|
$filesBaseURL = checkPath($filesBaseURL, "URL");
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Create a new session variable:
|
|
function saveSessionVariable($sessionVariableName, $sessionVariableContents)
|
|
{
|
|
// since PHP 4.1.0 or greater, adding variables directly to the '$_SESSION' variable
|
|
// will register a session variable regardless whether register globals is ON or OFF!
|
|
$_SESSION[$sessionVariableName] = $sessionVariableContents;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Remove a session variable:
|
|
function deleteSessionVariable($sessionVariableName)
|
|
{
|
|
if (ini_get('register_globals') == 1) // register globals is ON for the current directory
|
|
session_unregister($sessionVariableName); // clear the specified session variable
|
|
else // register globals is OFF for the current directory
|
|
unset($_SESSION[$sessionVariableName]); // clear the specified session variable
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Connect to the MySQL database:
|
|
// TODO: I18n
|
|
function connectToMySQLDatabase()
|
|
{
|
|
global $hostName; // these variables are specified in 'db.inc.php'
|
|
global $username;
|
|
global $password;
|
|
global $databaseName;
|
|
|
|
global $contentTypeCharset; // defined in 'ini.inc.php'
|
|
|
|
global $connection;
|
|
|
|
// If a connection parameter is not available, then use our own connection to avoid any locking problems
|
|
if (!isset($connection))
|
|
{
|
|
// (1) OPEN the database connection:
|
|
// (variables are set by include file 'db.inc.php'!)
|
|
if (!($connection = @ mysqli_connect($hostName, $username, $password, $databaseName)))
|
|
if (mysqli_errno($connection) != 0) // this works around a stupid(?) behaviour of the Roxen webserver that returns 'errno: 0' on success! ?:-(
|
|
showErrorMsg("The following error occurred while trying to connect to the host:");
|
|
|
|
// Get the MySQL version and save it to a session variable:
|
|
if (!isset($_SESSION['mysqlVersion']))
|
|
saveSessionVariable("mysqlVersion", getMySQLversion());
|
|
|
|
// (2) Set the connection character set (if connected to MySQL 4.1.x or greater):
|
|
// more info at <http://dev.mysql.com/doc/refman/5.1/en/charset-connection.html>
|
|
if (isset($_SESSION['mysqlVersion']) AND ($_SESSION['mysqlVersion'] >= 4.1))
|
|
{
|
|
// NOTE: "SET NAMES ..." requires MySQL 4.1 or greater
|
|
if ($contentTypeCharset == "UTF-8")
|
|
queryMySQLDatabase("SET NAMES utf8"); // set the character set for this connection to 'utf8'
|
|
else
|
|
queryMySQLDatabase("SET NAMES latin1"); // by default, we establish a 'latin1' connection
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Query the MySQL database:
|
|
// NOTE: This function requires an established MySQL $connection
|
|
// TODO: I18n
|
|
function queryMySQLDatabase($query)
|
|
{
|
|
global $connection;
|
|
global $client;
|
|
|
|
// (3) RUN the query on the database through the connection:
|
|
if (!($result = @ mysqli_query($connection, $query)))
|
|
if (mysqli_errno($connection) != 0) // this works around a stupid(?) behaviour of the Roxen webserver that returns 'errno: 0' on success! ?:-(
|
|
{
|
|
if (isset($client) AND preg_match("/^cli/i", $client)) // if the query originated from a command line client such as the "refbase" CLI client ("cli-refbase-1.0")
|
|
showErrorMsg("Your query: " . encodeHTML($query) . "\n\ncaused the following error:");
|
|
else
|
|
showErrorMsg("Your query: '" . $query . "' caused the following error:");
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Disconnect from the MySQL database:
|
|
// TODO: I18n
|
|
function disconnectFromMySQLDatabase()
|
|
{
|
|
global $connection;
|
|
|
|
if (isset($connection))
|
|
// (5) CLOSE the database connection:
|
|
if (!(mysqli_close($connection)))
|
|
if (mysqli_errno($connection) != 0) // this works around a stupid(?) behaviour of the Roxen webserver that returns 'errno: 0' on success! ?:-(
|
|
showErrorMsg("The following error occurred while trying to disconnect from the database:");
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get MySQL version:
|
|
// NOTE: This function requires an established MySQL $connection
|
|
function getMySQLversion()
|
|
{
|
|
// CONSTRUCT SQL QUERY:
|
|
$query = "SELECT VERSION()";
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$row = mysqli_fetch_row($result); // fetch the current row into the array $row (it'll be always *one* row, but anyhow)
|
|
$mysqlVersionString = $row[0]; // extract the contents of the first (and only) row (returned version string will be something like "4.0.20-standard" etc.)
|
|
$mysqlVersion = preg_replace("/^(\d+\.\d+).+/", "\\1", $mysqlVersionString); // extract main version number (e.g. "4.0") from version string
|
|
|
|
return $mysqlVersion;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get MySQL field info:
|
|
// (i.e. fetch field (column) information from a given result resource; returns the
|
|
// field property given in '$propertyName', else an array of all field properties;
|
|
// see <http://php.net/manual/en/mysqli-result.fetch-field-direct.php>)
|
|
function getMySQLFieldInfo($result, $fieldOffset, $propertyName = "")
|
|
{
|
|
$fieldInfoArray = array();
|
|
|
|
// Get field (column) metadata:
|
|
$fieldInfo = mysqli_fetch_field_direct($result, (int)$fieldOffset); // returns an object containing the field information
|
|
|
|
// Copy object properties to an array:
|
|
$fieldInfoArray["name"] = $fieldInfo->name; // column name
|
|
$fieldInfoArray["table"] = $fieldInfo->table; // name of the table the column belongs to
|
|
$fieldInfoArray["type"] = $fieldInfo->type; // the type of the column
|
|
$fieldInfoArray["def"] = $fieldInfo->def; // default value of the column
|
|
$fieldInfoArray["max_length"] = $fieldInfo->max_length; // maximum length of the column
|
|
$fieldInfoArray["max_length"] = $fieldInfo->max_length; // maximum length of the column
|
|
$fieldInfoArray["primary_key"] = $fieldInfo->primary_key; // 1 if the column is a primary key
|
|
$fieldInfoArray["unique_key"] = $fieldInfo->unique_key; // 1 if the column is a unique key
|
|
$fieldInfoArray["multiple_key"] = $fieldInfo->multiple_key; // 1 if the column is a non-unique key
|
|
$fieldInfoArray["numeric"] = $fieldInfo->numeric; // 1 if the column is numeric
|
|
$fieldInfoArray["blob"] = $fieldInfo->blob; // 1 if the column is a BLOB
|
|
$fieldInfoArray["unsigned"] = $fieldInfo->unsigned; // 1 if the column is unsigned
|
|
$fieldInfoArray["zerofill"] = $fieldInfo->zerofill; // 1 if the column is zero-filled
|
|
|
|
|
|
if (!empty($propertyName) AND isset($fieldInfoArray[$propertyName]))
|
|
return $fieldInfoArray[$propertyName];
|
|
else
|
|
return $fieldInfoArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Find out how many rows are available and (if there were rows found) seek to the current offset:
|
|
// Note that this function will also (re-)assign values to the variables '$rowOffset', '$showRows',
|
|
// '$rowsFound', '$previousOffset', '$nextOffset' and '$showMaxRow'.
|
|
function seekInMySQLResultsToOffset($result, $rowOffset, $showRows, $displayType, $citeType)
|
|
{
|
|
// Find out how many rows are available:
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
{
|
|
// ... setup variables in order to facilitate "previous" & "next" browsing:
|
|
// a) Set '$rowOffset' to zero if not previously defined, or if a wrong number (<=0) was given
|
|
if (empty($rowOffset) || ($rowOffset <= 0) || ((($displayType != "Export") AND !($displayType == "Cite" AND (!preg_match("/^html$/i", $citeType)))) && ($showRows >= $rowsFound))) // the third condition is only necessary if '$rowOffset' gets embedded within the 'displayOptions' form (see function 'buildDisplayOptionsElements()' in 'include.inc.php')
|
|
$rowOffset = 0;
|
|
|
|
// Adjust the '$showRows' value if not previously defined, or if a wrong number (<=0 or float) was given
|
|
if (empty($showRows) || ($showRows <= 0) || !preg_match("/^[0-9]+$/", $showRows))
|
|
$showRows = $_SESSION['userRecordsPerPage']; // get the default number of records per page preferred by the current user
|
|
|
|
// Adjust '$rowOffset' if it's value exceeds the number of rows found:
|
|
if ($rowOffset > ($rowsFound - 1))
|
|
{
|
|
if ($rowsFound > $showRows)
|
|
$rowOffset = ($rowsFound - $showRows); // start display at first record of last page to be displayed
|
|
else
|
|
$rowOffset = 0; // start display at the very first record
|
|
}
|
|
|
|
|
|
if (($displayType != "Export") AND !($displayType == "Cite" AND (!preg_match("/^html$/i", $citeType)))) // we have to exclude '$displayType=Export' here since, for export, '$rowOffset' must always point to the first row number in the result set that should be returned
|
|
{
|
|
// NOTE: The current value of '$rowOffset' is embedded as hidden tag within the 'displayOptions' form. By this, the current row offset can be re-applied
|
|
// after the user pressed the 'Show'/'Hide' button within the 'displayOptions' form. But then, to avoid that browse links don't behave as expected,
|
|
// we need to adjust the actual value of '$rowOffset' to an exact multiple of '$showRows':
|
|
$offsetRatio = ($rowOffset / $showRows);
|
|
if (!is_integer($offsetRatio)) // check whether the value of the '$offsetRatio' variable is not an integer
|
|
{ // if '$offsetRatio' is a float:
|
|
$offsetCorrectionFactor = floor($offsetRatio); // get it's next lower integer
|
|
if ($offsetCorrectionFactor != 0)
|
|
$rowOffset = ($offsetCorrectionFactor * $showRows); // correct the current row offset to the closest multiple of '$showRows' *below* the current row offset
|
|
else
|
|
$rowOffset = 0;
|
|
}
|
|
}
|
|
|
|
// b) The "Previous" page begins at the current offset LESS the number of rows per page
|
|
$previousOffset = $rowOffset - $showRows;
|
|
|
|
// c) The "Next" page begins at the current offset PLUS the number of rows per page
|
|
$nextOffset = $rowOffset + $showRows;
|
|
|
|
// d) Seek to the current offset
|
|
mysqli_data_seek($result, $rowOffset); // move internal result pointer to the row number given in '$rowOffset'
|
|
}
|
|
else // set variables to zero in order to prevent 'Undefined variable...' messages when nothing was found ('$rowsFound = 0'):
|
|
{
|
|
$rowOffset = 0;
|
|
$previousOffset = 0;
|
|
$nextOffset = 0;
|
|
}
|
|
|
|
// Calculate the maximum result number on each page ('$showMaxRow' is required as parameter to the 'displayDetails()' function)
|
|
if (($rowOffset + $showRows) < $rowsFound)
|
|
$showMaxRow = ($rowOffset + $showRows); // maximum result number on each page
|
|
else
|
|
$showMaxRow = $rowsFound; // for the last results page, correct the maximum result number if necessary
|
|
|
|
return array($result, $rowOffset, $showRows, $rowsFound, $previousOffset, $nextOffset, $showMaxRow);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Show error (prepares error output and redirects it to 'error.php' which displays the error message):
|
|
// TODO: I18n
|
|
function showErrorMsg($headerMsg)
|
|
{
|
|
global $client;
|
|
global $connection;
|
|
|
|
$errorNo = mysqli_errno($connection);
|
|
$errorMsg = mysqli_error($connection);
|
|
|
|
if (preg_match("/^cli/i", $client)) // if the query originated from a command line client such as the "refbase" CLI client ("cli-refbase-1.0")
|
|
// note that we also HTML encode the '$errorMsg' for CLI clients since a malicious user could use the client parameter to perform a cross-site scripting (XSS) attack
|
|
echo $headerMsg . "\n\nError " . $errorNo . ": " . encodeHTML($errorMsg) . "\n\n";
|
|
else
|
|
// in case of regular HTML output, '$errorMsg' gets HTML encoded in 'error.php'
|
|
header("Location: error.php?errorNo=" . $errorNo . "&errorMsg=" . rawurlencode($errorMsg) . "&headerMsg=" . rawurlencode($headerMsg));
|
|
|
|
exit;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Generate and return a message, and optionally save the message to a session variable:
|
|
// Following optional variables can be passed with the '$message' and will be used for non-CLI clients:
|
|
// - '$class' defines the name of the CSS class of the span element that encloses the message
|
|
// - '$flavour' is the (valid!) name of an HTML phrase element (such as "strong" or "em") that's wrapped around the message
|
|
// - '$sessionVariable' is the name of the session variable (such as "HeaderString") to which the message shall be saved
|
|
// - '$prefix' is a string that's added at the beginning of the generated message string
|
|
// - '$suffix' is a string that's appended at the end of the generated message string
|
|
function returnMsg($message, $class = "", $flavour = "", $sessionVariable = "", $prefix = "", $suffix = "")
|
|
{
|
|
global $client;
|
|
// Because we now sanitize the header message, we no longer output it as
|
|
// HTML
|
|
/*
|
|
if (preg_match("/^cli/i", $client)) // if the query originated from a command line client such as the "refbase" CLI client ("cli-refbase-1.0")
|
|
{
|
|
*/
|
|
$fullMsg = $message . "\n\n"; // for CLI clients, we just echo the message text
|
|
echo $fullMsg;
|
|
/* }
|
|
else // return an HTML-formatted message:
|
|
{
|
|
$fullMsg = $prefix;
|
|
|
|
if (!empty($flavour))
|
|
$fullMsg .= '<' . $flavour . '>';
|
|
|
|
if (!empty($class))
|
|
$fullMsg .= '<span class="' . $class . '">' . $message . '</span>';
|
|
else
|
|
$fullMsg .= $message;
|
|
|
|
if (!empty($flavour))
|
|
$fullMsg .= '</' . $flavour . '>';
|
|
|
|
$fullMsg .= $suffix;
|
|
|
|
if (!empty($sessionVariable))
|
|
saveSessionVariable($sessionVariable, $fullMsg); // write message to session variable
|
|
}
|
|
*/
|
|
return $fullMsg;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Show whether the user is logged in or not:
|
|
// TODO: I18n
|
|
function showLogin()
|
|
{
|
|
global $loginEmail;
|
|
global $loginWelcomeMsg;
|
|
global $loginFirstName;
|
|
global $loginLastName;
|
|
global $abbrevInstitution;
|
|
global $loginUserID;
|
|
global $loginStatus;
|
|
global $loginLinks;
|
|
global $adminLoginEmail; // ('$adminLoginEmail' is specified in 'ini.inc.php')
|
|
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
|
|
// $referer = $_SERVER["REQUEST_URI"]; // 'REQUEST_URI' does only seem to work for GET requests (but not for POST requests!) ?:-/
|
|
// so, as a workaround, we build an appropriate query string from scratch (which will also work for POST requests):
|
|
|
|
// --- BEGIN WORKAROUND ---
|
|
global $formType;
|
|
global $displayType;
|
|
global $queryURL;
|
|
global $showQuery;
|
|
global $showLinks;
|
|
global $showRows;
|
|
global $rowOffset;
|
|
|
|
global $citeStyle;
|
|
global $citeOrder;
|
|
global $orderBy;
|
|
|
|
global $recordAction;
|
|
global $serialNo;
|
|
global $headerMsg;
|
|
|
|
global $errorNo;
|
|
global $errorMsg;
|
|
|
|
// Get the path to the currently executing script, relative to the document root:
|
|
$scriptURL = scriptURL();
|
|
|
|
// Extract checkbox variable values from the request:
|
|
if (isset($_REQUEST['marked']))
|
|
$recordSerialsArray = $_REQUEST['marked']; // extract the values of all checked checkboxes (i.e., the serials of all selected records)
|
|
else
|
|
$recordSerialsArray = "";
|
|
$recordSerialsString = ""; // initialize variable
|
|
// join array elements:
|
|
if (!empty($recordSerialsArray)) // the user did check some checkboxes
|
|
$recordSerialsString = implode("&marked[]=", $recordSerialsArray); // prefix each record serial (except the first one) with "&marked[]="
|
|
$recordSerialsString = "&marked[]=" . $recordSerialsString; // prefix also the very first record serial with "&marked[]="
|
|
|
|
// based on the refering script we adjust the parameters that get included in the link:
|
|
if (preg_match("#/(index|install|update|simple_search|advanced_search|sql_search|library_search|duplicate_manager|duplicate_search|opensearch|query_history|extract|users|user_details|user_receipt)\.php#i", $scriptURL))
|
|
$referer = $scriptURL; // we don't need to provide any parameters if the user clicked login/logout on the main page, the install/update page or any of the search pages (we just need
|
|
// to re-locate back to these pages after successful login/logout). Logout on 'install.php', 'users.php', 'user_details.php' or 'user_receipt.php' will redirect to 'index.php'.
|
|
|
|
elseif (preg_match("#/user_options\.php#i", $scriptURL))
|
|
$referer = $scriptURL . "?" . "userID=" . $loginUserID;
|
|
|
|
elseif (preg_match("#/(record|receipt)\.php#i", $scriptURL))
|
|
$referer = $scriptURL . "?" . "recordAction=" . $recordAction . "&serialNo=" . $serialNo . "&headerMsg=" . rawurlencode($headerMsg);
|
|
|
|
elseif (preg_match("#/error\.php#i", $scriptURL))
|
|
$referer = $scriptURL . "?" . "errorNo=" . $errorNo . "&errorMsg=" . rawurlencode($errorMsg) . "&headerMsg=" . rawurlencode($headerMsg);
|
|
|
|
else
|
|
$referer = $scriptURL . "?" . "formType=" . "sqlSearch" . "&submit=" . $displayType . "&headerMsg=" . rawurlencode($headerMsg) . "&sqlQuery=" . $queryURL . "&showQuery=" . $showQuery . "&showLinks=" . $showLinks . "&showRows=" . $showRows . "&rowOffset=" . $rowOffset . $recordSerialsString . "&citeStyle=" . rawurlencode($citeStyle) . "&citeOrder=" . $citeOrder . "&orderBy=" . rawurlencode($orderBy);
|
|
// --- END WORKAROUND -----
|
|
|
|
|
|
// Is the user logged in?
|
|
if (isset($_SESSION['loginEmail']))
|
|
{
|
|
$loginStatus = $loc["Welcome"];
|
|
|
|
$loginWelcomeMsg = "<em>" . encodeHTML($loginFirstName) . " " . encodeHTML($loginLastName) . "</em>!";
|
|
|
|
if ($loginEmail == $adminLoginEmail)
|
|
$loginStatus .= " <span class=\"warning\">" . $loc["Admin"] . "</span>";
|
|
|
|
$loginLinks = "";
|
|
if ($loginEmail == $adminLoginEmail) // if the admin is logged in, add the 'Add User' & 'Manage Users' links:
|
|
{
|
|
$loginLinks .= "<a href=\"user_details.php\" title=\"add a user to the database\">Add User</a> | ";
|
|
$loginLinks .= "<a href=\"users.php\" title=\"manage user data\">Manage Users</a> | ";
|
|
}
|
|
else // if a normal user is logged in, we add the 'My Refs' and 'Options' links instead:
|
|
{
|
|
$loginLinks .= "<a href=\"search.php?formType=myRefsSearch&showQuery=0&showLinks=1&myRefsRadio=1\"" . addAccessKey("attribute", "my_refs") . " title=\"" . $loc["LinkTitle_MyRefs"] . addAccessKey("title", "my_refs") . "\">" . $loc["MyRefs"] . "</a> | ";
|
|
|
|
if (isset($_SESSION['user_permissions']) AND preg_match("/allow_modify_options/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_modify_options'...
|
|
// ... include a link to 'user_receipt.php':
|
|
$loginLinks .= "<a href=\"user_receipt.php?userID=" . $loginUserID . "\"" . addAccessKey("attribute", "my_opt") . " title=\"" . $loc["LinkTitle_Options"] . addAccessKey("title", "my_opt") . "\">" . $loc["Options"] . "</a> | ";
|
|
}
|
|
$loginLinks .= "<a href=\"user_logout.php?referer=" . rawurlencode($referer) . "\"" . addAccessKey("attribute", "login") . " title=\"" . $loc["LinkTitle_Logout"] . addAccessKey("title", "login") . "\">" . $loc["Logout"] . "</a>";
|
|
}
|
|
else
|
|
{
|
|
if (preg_match("#.*(record|import[^.]*)\.php#i", $scriptURL))
|
|
$loginStatus = "<span class=\"warning\">" . $loc["Warning_LoginToSubmitForm"] . "!</span>";
|
|
else
|
|
$loginStatus = "";
|
|
|
|
$loginWelcomeMsg = "";
|
|
|
|
$loginLinks = "<a href=\"user_login.php?referer=" . rawurlencode($referer) . "\"" . addAccessKey("attribute", "login") . " title=\"" . $loc["LinkTitle_Login"] . addAccessKey("title", "login") . "\">" . $loc["Login"] . "</a>";
|
|
}
|
|
|
|
// Although the '$referer' variable gets included as GET parameter above, we'll also save the variable as session variable:
|
|
// (this should help re-directing to the correct page if a user called 'user_login/logout.php' manually, i.e., without parameters)
|
|
saveSessionVariable("referer", $referer);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Enable 'accesskey' attribute for the specified link/form element:
|
|
// '$type' must be either "attribute" or "title", and '$key' must be the
|
|
// name of an array key from variable '$accessKeys' (in 'ini.inc.php')
|
|
function addAccessKey($type, $key)
|
|
{
|
|
global $accessKeys; // defined in 'ini.inc.php'
|
|
|
|
$accessKeyString = "";
|
|
|
|
if (isset($accessKeys) AND (!empty($accessKeys[$key]) OR ($accessKeys[$key] == "0")))
|
|
{
|
|
if ($type == "attribute") // add 'accesskey' attribute (like ' accesskey="h"') to the specified link or form element
|
|
$accessKeyString = " accesskey=\"" . $accessKeys[$key] . "\"";
|
|
|
|
elseif ($type == "title") // add access key hint (like ' [ctrl-h]') to the title attribute value of the specified link or form element
|
|
$accessKeyString = " [ctrl-" . $accessKeys[$key] . "]";
|
|
}
|
|
|
|
return $accessKeyString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get the 'user_id' for the record entry in table 'auth' whose email matches that in '$emailAddress':
|
|
function getUserID($emailAddress)
|
|
{
|
|
global $tableAuth; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
$query = "SELECT user_id FROM $tableAuth WHERE email = " . quote_smart($emailAddress);
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
$row = mysqli_fetch_array($result);
|
|
|
|
return($row["user_id"]);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// ADD RECORDS
|
|
// Adds record(s) to the database (i.e., add one or more row entries to MySQL table 'refs'):
|
|
// Notes: - the function will return the serial number(s) of all newly created record(s) in an array structure
|
|
// - structure of '$importDataArray' (sample values given in "..."):
|
|
// array(
|
|
// ['type'] => "refbase" // mandatory; indicates the array format of the 'records' element (currently only "refbase" is recognized, a standardized "bibliophile" format may be provided later on)
|
|
// ['version'] => "1.0" // mandatory; the version of the given array structure
|
|
// ['records'] => array( // mandatory; array of arrays containing the records & field data that should be imported; the sub-array element key must correspond to a refbase database field name from table 'refs'
|
|
// [0] => array( // first record
|
|
// [author] => "..." // - contents of 'author' field
|
|
// [title] => "..." // - contents of 'title' field
|
|
// ...
|
|
// )
|
|
// [1] => array( // second record
|
|
// [author] => "..." // - contents of 'author' field
|
|
// [title] => "..." // - contents of 'title' field
|
|
// ...
|
|
// )
|
|
// ...
|
|
// )
|
|
// ['creator'] => "http://refbase.net" // optional; the (preferably unique) name of the calling script/importer, use an URI if possible
|
|
// ['author'] => "Matthias Steffens" // optional; the name of the person who developed the script/importer and/or who can be contacted in case of problems
|
|
// ['contact'] => "refbase@extracts.de" // optional; the contact address of the person specified under 'author', use an email address if possible
|
|
// ['options'] => array( // optional; array with settings that control the behaviour of the 'addRecords()' function, currently there's only one option:
|
|
// [prefix_call_number] => "true" // if "true", any 'call_number' string will be prefixed with the correct call number prefix of the currently logged-in user (e.g. 'IPÖ @ msteffens @ ')
|
|
// )
|
|
// )
|
|
function addRecords($importDataArray)
|
|
{
|
|
global $loginUserID;
|
|
global $tableRefs, $tableUserData; // defined in 'db.inc.php'
|
|
|
|
global $connection;
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
$recognizedArrayFormatsAndVersions = array('refbase' => array("1.0")); // for each recognized format, this array lists its format identifier as element key and an array of known versions as element value
|
|
|
|
$serialNumbersArray = array(); // initialize array variable which will hold the serial numbers of all imported records
|
|
|
|
// Verify the structure of the '$importDataArray':
|
|
if (!empty($importDataArray['type']) AND !empty($importDataArray['version']) AND !empty($importDataArray['records'])) // the array elements 'type', 'version' and 'records' are mandatory and must not be empty
|
|
{
|
|
// Currently, we only support the default "refbase" array structure in its initial version ("1.0") (support for other more generalized array formats may come later)
|
|
if (($importDataArray['type'] == "refbase") AND (in_array($importDataArray['version'], $recognizedArrayFormatsAndVersions['refbase'])))
|
|
{
|
|
$recordsArray = $importDataArray['records']; // get the array of records that shall be imported
|
|
|
|
// First, setup some required variables:
|
|
// Get the current date (e.g. '2003-12-31'), time (e.g. '23:59:49') and user name & email address (e.g. 'Matthias Steffens (refbase@extracts.de)'):
|
|
// note that we use the same time stamp for ALL imported records (so that users can easily identify all records belonging to one import action)
|
|
list ($currentDate, $currentTime, $currentUser) = getCurrentDateTimeUser();
|
|
|
|
// LOOP OVER EACH RECORD:
|
|
foreach ($recordsArray as $recordData) // for each record...
|
|
{
|
|
// Initialize some variables (in order to avoid "undefined index" messages when the particular array elements are not available):
|
|
if (isset($recordData['author']))
|
|
$author = $recordData['author'];
|
|
else
|
|
$author = "";
|
|
|
|
if (isset($recordData['pages']))
|
|
$pages = $recordData['pages'];
|
|
else
|
|
$pages = "";
|
|
|
|
if (isset($recordData['volume']))
|
|
$volume = $recordData['volume'];
|
|
else
|
|
$volume = "";
|
|
|
|
if (isset($recordData['series_volume']))
|
|
$seriesVolume = $recordData['series_volume'];
|
|
else
|
|
$seriesVolume = "";
|
|
|
|
// Assign correct values to the calculation fields 'first_author', 'author_count', 'first_page', 'volume_numeric' and 'series_volume_numeric':
|
|
list ($firstAuthor, $authorCount, $firstPage, $volumeNumeric, $seriesVolumeNumeric) = generateCalculationFieldContent($author, $pages, $volume, $seriesVolume);
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
|
|
// INSERT - construct a query to add data as new record
|
|
$queryRefs = ""; // note: we'll prefix "INSERT INTO $tableRefs SET " *after* we've parsed all array elements to trap the case that none of the array elements did contain any data
|
|
|
|
if (!empty($recordData['author']))
|
|
$queryRefs .= "author = " . quote_smart($recordData['author']) . ", ";
|
|
|
|
if (!empty($firstAuthor))
|
|
$queryRefs .= "first_author = " . quote_smart($firstAuthor) . ", ";
|
|
|
|
if (!empty($authorCount))
|
|
$queryRefs .= "author_count = " . quote_smart($authorCount) . ", ";
|
|
|
|
if (!empty($recordData['title']))
|
|
$queryRefs .= "title = " . quote_smart($recordData['title']) . ", ";
|
|
|
|
if (!empty($recordData['year']))
|
|
$queryRefs .= "year = " . quote_smart($recordData['year']) . ", ";
|
|
|
|
if (!empty($recordData['publication']))
|
|
$queryRefs .= "publication = " . quote_smart($recordData['publication']) . ", ";
|
|
|
|
if (!empty($recordData['abbrev_journal']))
|
|
$queryRefs .= "abbrev_journal = " . quote_smart($recordData['abbrev_journal']) . ", ";
|
|
|
|
if (!empty($recordData['volume']))
|
|
$queryRefs .= "volume = " . quote_smart($recordData['volume']) . ", ";
|
|
|
|
if (!empty($volumeNumeric))
|
|
$queryRefs .= "volume_numeric = " . quote_smart($volumeNumeric) . ", ";
|
|
|
|
if (!empty($recordData['issue']))
|
|
$queryRefs .= "issue = " . quote_smart($recordData['issue']) . ", ";
|
|
|
|
if (!empty($recordData['pages']))
|
|
$queryRefs .= "pages = " . quote_smart($recordData['pages']) . ", ";
|
|
|
|
if (!empty($firstPage))
|
|
$queryRefs .= "first_page = " . quote_smart($firstPage) . ", ";
|
|
|
|
if (!empty($recordData['address']))
|
|
$queryRefs .= "address = " . quote_smart($recordData['address']) . ", ";
|
|
|
|
if (!empty($recordData['corporate_author']))
|
|
$queryRefs .= "corporate_author = " . quote_smart($recordData['corporate_author']) . ", ";
|
|
|
|
if (!empty($recordData['keywords']))
|
|
$queryRefs .= "keywords = " . quote_smart($recordData['keywords']) . ", ";
|
|
|
|
if (!empty($recordData['abstract']))
|
|
$queryRefs .= "abstract = " . quote_smart($recordData['abstract']) . ", ";
|
|
|
|
if (!empty($recordData['publisher']))
|
|
$queryRefs .= "publisher = " . quote_smart($recordData['publisher']) . ", ";
|
|
|
|
if (!empty($recordData['place']))
|
|
$queryRefs .= "place = " . quote_smart($recordData['place']) . ", ";
|
|
|
|
if (!empty($recordData['editor']))
|
|
$queryRefs .= "editor = " . quote_smart($recordData['editor']) . ", ";
|
|
|
|
if (!empty($recordData['language']))
|
|
$queryRefs .= "language = " . quote_smart($recordData['language']) . ", ";
|
|
|
|
if (!empty($recordData['summary_language']))
|
|
$queryRefs .= "summary_language = " . quote_smart($recordData['summary_language']) . ", ";
|
|
|
|
if (!empty($recordData['orig_title']))
|
|
$queryRefs .= "orig_title = " . quote_smart($recordData['orig_title']) . ", ";
|
|
|
|
if (!empty($recordData['series_editor']))
|
|
$queryRefs .= "series_editor = " . quote_smart($recordData['series_editor']) . ", ";
|
|
|
|
if (!empty($recordData['series_title']))
|
|
$queryRefs .= "series_title = " . quote_smart($recordData['series_title']) . ", ";
|
|
|
|
if (!empty($recordData['abbrev_series_title']))
|
|
$queryRefs .= "abbrev_series_title = " . quote_smart($recordData['abbrev_series_title']) . ", ";
|
|
|
|
if (!empty($recordData['series_volume']))
|
|
$queryRefs .= "series_volume = " . quote_smart($recordData['series_volume']) . ", ";
|
|
|
|
if (!empty($seriesVolumeNumeric))
|
|
$queryRefs .= "series_volume_numeric = " . quote_smart($seriesVolumeNumeric) . ", ";
|
|
|
|
if (!empty($recordData['series_issue']))
|
|
$queryRefs .= "series_issue = " . quote_smart($recordData['series_issue']) . ", ";
|
|
|
|
if (!empty($recordData['edition']))
|
|
$queryRefs .= "edition = " . quote_smart($recordData['edition']) . ", ";
|
|
|
|
if (!empty($recordData['issn']))
|
|
$queryRefs .= "issn = " . quote_smart($recordData['issn']) . ", ";
|
|
|
|
if (!empty($recordData['isbn']))
|
|
$queryRefs .= "isbn = " . quote_smart($recordData['isbn']) . ", ";
|
|
|
|
if (!empty($recordData['medium']))
|
|
$queryRefs .= "medium = " . quote_smart($recordData['medium']) . ", ";
|
|
|
|
if (!empty($recordData['area']))
|
|
$queryRefs .= "area = " . quote_smart($recordData['area']) . ", ";
|
|
|
|
if (!empty($recordData['expedition']))
|
|
$queryRefs .= "expedition = " . quote_smart($recordData['expedition']) . ", ";
|
|
|
|
if (!empty($recordData['conference']))
|
|
$queryRefs .= "conference = " . quote_smart($recordData['conference']) . ", ";
|
|
|
|
// the 'location' and 'call_number' fields are handled below
|
|
|
|
if (!empty($recordData['approved']))
|
|
$queryRefs .= "approved = " . quote_smart($recordData['approved']) . ", ";
|
|
|
|
if (!empty($recordData['file']))
|
|
$queryRefs .= "file = " . quote_smart($recordData['file']) . ", ";
|
|
|
|
// the 'serial' field is handled below
|
|
|
|
if (!empty($recordData['orig_record']))
|
|
$queryRefs .= "orig_record = " . quote_smart($recordData['orig_record']) . ", ";
|
|
|
|
if (!empty($recordData['type']))
|
|
$queryRefs .= "type = " . quote_smart($recordData['type']) . ", ";
|
|
|
|
if (!empty($recordData['thesis']))
|
|
$queryRefs .= "thesis = " . quote_smart($recordData['thesis']) . ", ";
|
|
|
|
if (!empty($recordData['notes']))
|
|
$queryRefs .= "notes = " . quote_smart($recordData['notes']) . ", ";
|
|
|
|
if (!empty($recordData['url']))
|
|
$queryRefs .= "url = " . quote_smart($recordData['url']) . ", ";
|
|
|
|
if (!empty($recordData['doi']))
|
|
$queryRefs .= "doi = " . quote_smart($recordData['doi']) . ", ";
|
|
|
|
if (!empty($recordData['contribution_id']))
|
|
$queryRefs .= "contribution_id = " . quote_smart($recordData['contribution_id']) . ", ";
|
|
|
|
if (!empty($recordData['online_publication']))
|
|
$queryRefs .= "online_publication = " . quote_smart($recordData['online_publication']) . ", ";
|
|
|
|
if (!empty($recordData['online_citation']))
|
|
$queryRefs .= "online_citation = " . quote_smart($recordData['online_citation']) . ", ";
|
|
|
|
|
|
if (!empty($queryRefs)) // go ahead, if some array elements did contain data
|
|
{
|
|
// we only honour the 'call_number' string if some other record data were passed as well:
|
|
//
|
|
// if the 'prefix_call_number' option is set to "true", any 'call_number' string will be prefixed with
|
|
// the correct call number prefix of the currently logged-in user (e.g. 'IPÖ @ msteffens @ '):
|
|
if ((isset($_SESSION['loginEmail'])) AND (isset($importDataArray['options']['prefix_call_number'])) AND ($importDataArray['options']['prefix_call_number'] == "true"))
|
|
{
|
|
$callNumberPrefix = getCallNumberPrefix(); // build a correct call number prefix for the currently logged-in user (e.g. 'IPÖ @ msteffens')
|
|
|
|
if (!empty($recordData['call_number']))
|
|
$queryRefs .= "call_number = " . quote_smart($callNumberPrefix . " @ " . $recordData['call_number']) . ", "; // add call number prefix to 'call_number' string
|
|
else
|
|
$queryRefs .= "call_number = " . quote_smart($callNumberPrefix . " @ ") . ", "; // similar to the GUI behaviour, we'll also add a call number prefix if the 'call_number' string is empty
|
|
}
|
|
else
|
|
{
|
|
if (!empty($recordData['call_number']))
|
|
$queryRefs .= "call_number = " . quote_smart($recordData['call_number']) . ", ";
|
|
}
|
|
|
|
// if no specific cite key exists in '$recordData', any existing 'call_number' string gets also copied to the
|
|
// user-specific 'cite_key' field (which will ensure that this original call number/cite key is retained as
|
|
// cite key upon export); however, note that (depending on the user's settings) the cite key may get modified
|
|
// or regenerated by function 'generateCiteKey()' below
|
|
if (isset($_SESSION['loginEmail']) AND !empty($recordData['call_number']) AND empty($recordData['cite_key']))
|
|
$recordData['cite_key'] = $recordData['call_number'];
|
|
|
|
// for the 'location' field, we accept input from the '$recordData',
|
|
// but if no data were given, we'll add the currently logged-in user to the 'location' field:
|
|
if (!empty($recordData['location']))
|
|
$queryRefs .= "location = " . quote_smart($recordData['location']) . ", ";
|
|
elseif (isset($_SESSION['loginEmail']))
|
|
$queryRefs .= "location = " . quote_smart($currentUser) . ", ";
|
|
|
|
$queryRefs .= "serial = NULL, "; // inserting 'NULL' into an auto_increment PRIMARY KEY attribute allocates the next available key value
|
|
|
|
// we accept custom values for the *date/*time/*by fields if they are in correct format (*date: 'YYYY-MM-DD'; *time: 'HH:MM:SS'; *by: 'string'),
|
|
// otherwise we'll use the current date & time as well as the currently logged-in user name & email address:
|
|
if (!empty($recordData['created_by']))
|
|
$queryRefs .= "created_by = " . quote_smart($recordData['created_by']) . ", ";
|
|
elseif (isset($_SESSION['loginEmail']))
|
|
$queryRefs .= "created_by = " . quote_smart($currentUser) . ", ";
|
|
|
|
if (!empty($recordData['created_date']) AND preg_match("/^\d{4}-\d{2}-\d{2}$/", $recordData['created_date']))
|
|
$queryRefs .= "created_date = " . quote_smart($recordData['created_date']) . ", ";
|
|
else
|
|
$queryRefs .= "created_date = " . quote_smart($currentDate) . ", ";
|
|
|
|
if (!empty($recordData['created_time']) AND preg_match("/^\d{2}:\d{2}:\d{2}$/", $recordData['created_time']))
|
|
$queryRefs .= "created_time = " . quote_smart($recordData['created_time']) . ", ";
|
|
else
|
|
$queryRefs .= "created_time = " . quote_smart($currentTime) . ", ";
|
|
|
|
if (!empty($recordData['modified_by']))
|
|
$queryRefs .= "modified_by = " . quote_smart($recordData['modified_by']) . ", ";
|
|
elseif (isset($_SESSION['loginEmail']))
|
|
$queryRefs .= "modified_by = " . quote_smart($currentUser) . ", ";
|
|
|
|
if (!empty($recordData['modified_date']) AND preg_match("/^\d{4}-\d{2}-\d{2}$/", $recordData['modified_date']))
|
|
$queryRefs .= "modified_date = " . quote_smart($recordData['modified_date']) . ", ";
|
|
else
|
|
$queryRefs .= "modified_date = " . quote_smart($currentDate) . ", ";
|
|
|
|
if (!empty($recordData['modified_time']) AND preg_match("/^\d{2}:\d{2}:\d{2}$/", $recordData['modified_time']))
|
|
$queryRefs .= "modified_time = " . quote_smart($recordData['modified_time']) . "";
|
|
else
|
|
$queryRefs .= "modified_time = " . quote_smart($currentTime);
|
|
|
|
|
|
$queryRefs = "INSERT INTO $tableRefs SET " . $queryRefs; // finalize the query by prefixing it with the actual MySQL command
|
|
|
|
// ADD RECORD:
|
|
|
|
// RUN the query on the database through the connection:
|
|
$result = queryMySQLDatabase($queryRefs);
|
|
|
|
// Get the record id that was created:
|
|
$serialNo = @ mysqli_insert_id($connection); // find out the unique ID number of the newly created record (Note: this function should be called immediately after the
|
|
// SQL INSERT statement! After any subsequent query it won't be possible to retrieve the auto_increment identifier value for THIS record!)
|
|
|
|
// ADD USER DATA:
|
|
|
|
if (isset($_SESSION['loginEmail']))
|
|
{
|
|
// Note: At the moment, the record in table 'user_data' will be always created for the currently logged-in user,
|
|
// i.e. we don't try to match any custom data given in the 'location' field with users from table 'users'
|
|
// in order to set the 'user_id' in table 'user_data' accordingly
|
|
|
|
// This is a stupid hack that maps the names of the '$recordData' array keys to those used
|
|
// by the '$formVars' array (which is required by function 'generateCiteKey()')
|
|
// (eventually, the '$formVars' array should use the MySQL field names as names for its array keys)
|
|
$formVars = buildFormVarsArray($recordData);
|
|
|
|
// Generate or extract the cite key for this record:
|
|
$citeKey = generateCiteKey($formVars);
|
|
|
|
// Construct SQL query:
|
|
$queryUserData = "INSERT INTO $tableUserData SET ";
|
|
|
|
if (!empty($recordData['marked']) AND preg_match("/^(no|yes)$/", $recordData['marked']))
|
|
$queryUserData .= "marked = " . quote_smart($recordData['marked']) . ", ";
|
|
|
|
if (!empty($recordData['copy']) AND preg_match("/^(false|true|ordered|fetch)$/", $recordData['copy']))
|
|
$queryUserData .= "copy = " . quote_smart($recordData['copy']) . ", ";
|
|
else
|
|
$queryUserData .= "copy = 'true', "; // by default, 'false' would get inserted if omitted; we insert 'true' here in order to be consistent with manual record additions
|
|
|
|
if (!empty($recordData['selected']) AND preg_match("/^(no|yes)$/", $recordData['selected']))
|
|
$queryUserData .= "selected = " . quote_smart($recordData['selected']) . ", ";
|
|
|
|
if (!empty($recordData['user_keys']))
|
|
$queryUserData .= "user_keys = " . quote_smart($recordData['user_keys']) . ", ";
|
|
|
|
if (!empty($recordData['user_notes']))
|
|
$queryUserData .= "user_notes = " . quote_smart($recordData['user_notes']) . ", ";
|
|
|
|
if (!empty($recordData['user_file']))
|
|
$queryUserData .= "user_file = " . quote_smart($recordData['user_file']) . ", ";
|
|
|
|
if (!empty($recordData['user_groups']))
|
|
$queryUserData .= "user_groups = " . quote_smart($recordData['user_groups']) . ", ";
|
|
|
|
$queryUserData .= "cite_key = " . quote_smart($citeKey) . ", ";
|
|
|
|
if (!empty($recordData['related']))
|
|
$queryUserData .= "related = " . quote_smart($recordData['related']) . ", ";
|
|
|
|
$queryUserData .= "record_id = " . quote_smart($serialNo) . ", "
|
|
. "user_id = " . quote_smart($loginUserID) . ", " // '$loginUserID' is provided as session variable
|
|
. "data_id = NULL"; // inserting 'NULL' into an auto_increment PRIMARY KEY attribute allocates the next available key value
|
|
|
|
// RUN the query on the database through the connection:
|
|
$result = queryMySQLDatabase($queryUserData);
|
|
}
|
|
|
|
// Append this record's serial number to the array of imported record serials:
|
|
$serialNumbersArray[] = $serialNo;
|
|
}
|
|
// else: '$recordData' did not contain any data, so we skip this record
|
|
}
|
|
// (END LOOP OVER EACH RECORD)
|
|
}
|
|
// else: unknown array structure, return an empty '$serialNumbersArray'
|
|
}
|
|
// else: couldn't verify structure of '$importDataArray', return an empty '$serialNumbersArray'
|
|
|
|
return $serialNumbersArray; // return list of serial numbers of all imported records
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Assign correct values to the calculation fields 'first_author', 'author_count', 'first_page', 'volume_numeric' and 'series_volume_numeric':
|
|
function generateCalculationFieldContent($author, $pages, $volume, $seriesVolume)
|
|
{
|
|
if (!empty($author))
|
|
{
|
|
// Standardize contents of the author field (which will ensure correct sorting upon Citation output):
|
|
// - shorten author's full given name(s) to initial(s)
|
|
// - remove any delimiters (such as dots and/or whitespace) from author's initials
|
|
|
|
// Call the 'reArrangeAuthorContents()' function (defined in 'include.inc.php') in order to re-order contents of the author field. Required Parameters:
|
|
// 1. input: contents of the author field
|
|
// 2. input: boolean value that specifies whether the author's family name comes first (within one author) in the source string
|
|
// ('true' means that the family name is followed by the given name (or initials), 'false' if it's the other way around)
|
|
//
|
|
// 3. input: pattern describing old delimiter that separates different authors
|
|
// 4. output: for all authors except the last author: new delimiter that separates different authors
|
|
// 5. output: for the last author: new delimiter that separates the last author from all other authors
|
|
//
|
|
// 6. input: pattern describing old delimiter that separates author name & initials (within one author)
|
|
// 7. output: for the first author: new delimiter that separates author name & initials (within one author)
|
|
// 8. output: for all authors except the first author: new delimiter that separates author name & initials (within one author)
|
|
// 9. output: new delimiter that separates multiple initials (within one author)
|
|
// 10. output: for the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
|
|
// 11. output: for all authors except the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
|
|
// 12. output: boolean value that specifies whether an author's full given name(s) shall be shortened to initial(s)
|
|
//
|
|
// 13. output: if the total number of authors is greater than the given number (integer >= 1), only the number of authors given in (14) will be included in the citation along with the string given in (15); keep empty if all authors shall be returned
|
|
// 14. output: number of authors (integer >= 1) that is included in the citation if the total number of authors is greater than the number given in (13); keep empty if not applicable
|
|
// 15. output: string that's appended to the number of authors given in (14) if the total number of authors is greater than the number given in (13); the actual number of authors can be printed by including '__NUMBER_OF_AUTHORS__' (without quotes) within the string
|
|
//
|
|
// 16. output: boolean value that specifies whether the re-ordered string shall be returned with higher ASCII chars HTML encoded
|
|
$author = reArrangeAuthorContents($author, // 1.
|
|
true, // 2.
|
|
"/ *; */", // 3.
|
|
"; ", // 4.
|
|
"; ", // 5.
|
|
"/ *, */", // 6.
|
|
", ", // 7.
|
|
", ", // 8.
|
|
"", // 9.
|
|
false, // 10.
|
|
false, // 11.
|
|
true, // 12.
|
|
"", // 13.
|
|
"", // 14.
|
|
"", // 15.
|
|
false); // 16.
|
|
|
|
// 'first_author' field:
|
|
$firstAuthor = preg_replace("/^([^;]+).*/i", "\\1", $author); // extract first author from 'author' field
|
|
$firstAuthor = trim($firstAuthor); // remove leading & trailing whitespace (if any)
|
|
$firstAuthor = preg_replace("/ *\(eds?\)$/i", "", $firstAuthor); // remove any existing editor info from the 'first_author' string, i.e., kill any trailing " (ed)" or " (eds)"
|
|
|
|
// 'author_count' field:
|
|
if (!preg_match("/;/", $author)) // if the 'author' field does NOT contain a ';' (which would delimit multiple authors) => single author
|
|
$authorCount = "1"; // indicates a single author
|
|
elseif (preg_match("/^[^;]+;[^;]+$/", $author)) // the 'author' field does contain exactly one ';' => two authors
|
|
$authorCount = "2"; // indicates two authors
|
|
elseif (preg_match("/^[^;]+;[^;]+;[^;]+/", $author)) // the 'author' field does contain at least two ';' => more than two authors
|
|
$authorCount = "3"; // indicates three (or more) authors
|
|
}
|
|
else
|
|
{
|
|
$firstAuthor = "";
|
|
$authorCount = "";
|
|
}
|
|
|
|
// 'first_page' field:
|
|
if (!empty($pages))
|
|
{
|
|
if (preg_match("/([0-9]+)/", $pages)) // if the 'pages' field contains any numeric value(s)
|
|
$firstPage = preg_replace("/^[^0-9]*([0-9]+).*/i", "\\1", $pages); // extract first page from 'pages' field
|
|
else
|
|
$firstPage = "";
|
|
}
|
|
else
|
|
$firstPage = "";
|
|
|
|
// 'volume_numeric' field:
|
|
if (!empty($volume))
|
|
{
|
|
if (preg_match("/([0-9]+)/", $volume)) // if the 'volume' field contains any numeric value(s)
|
|
$volumeNumeric = preg_replace("/^[^0-9]*([0-9]+).*/i", "\\1", $volume); // extract first number from 'volume' field
|
|
else
|
|
$volumeNumeric = "";
|
|
}
|
|
else
|
|
$volumeNumeric = "";
|
|
|
|
// 'series_volume_numeric' field:
|
|
if (!empty($seriesVolume))
|
|
{
|
|
if (preg_match("/([0-9]+)/", $seriesVolume)) // if the 'series_volume' field contains any numeric value(s)
|
|
$seriesVolumeNumeric = preg_replace("/^[^0-9]*([0-9]+).*/i", "\\1", $seriesVolume); // extract first number from 'series_volume' field
|
|
else
|
|
$seriesVolumeNumeric = "";
|
|
}
|
|
else
|
|
$seriesVolumeNumeric = "";
|
|
|
|
return array($firstAuthor, $authorCount, $firstPage, $volumeNumeric, $seriesVolumeNumeric);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Generic function that provides email sending capability:
|
|
function sendEmail($emailRecipient, $emailSubject, $emailBody)
|
|
{
|
|
global $adminLoginEmail; // these variables are specified in 'ini.inc.php'
|
|
global $contentTypeCharset;
|
|
|
|
// Setup some additional headers:
|
|
$emailHeaders = "From: " . $adminLoginEmail . "\n"
|
|
. "Return-Path: " . $adminLoginEmail . "\n"
|
|
. "X-Sender: " . $adminLoginEmail . "\n"
|
|
. "X-Mailer: PHP\n"
|
|
. "X-Priority: 3\n"
|
|
. "Content-Type: text/plain; charset=" . $contentTypeCharset;
|
|
|
|
// Send the email:
|
|
mail($emailRecipient, $emailSubject, $emailBody, $emailHeaders);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Map MySQL field names to their localized names:
|
|
//
|
|
// TODO: - ensure that the names for field 'user_groups' in tables 'refs' and 'users' are
|
|
// set correctly (user-specific groups of references vs. admin groups of users)
|
|
// - add "DropDownFieldName_*" entries for unique field names of table 'users'
|
|
function mapFieldNames($isDropDown = false)
|
|
{
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
if ($isDropDown) // field names intended for inclusion into a dropdown form element:
|
|
{
|
|
$fieldNamesArray = array("author" => $loc["DropDownFieldName_Author"],
|
|
// "author_count" => $loc[""],
|
|
// "first_author" => $loc[""],
|
|
"address" => $loc["DropDownFieldName_Address"],
|
|
"corporate_author" => $loc["DropDownFieldName_CorporateAuthor"],
|
|
"thesis" => $loc["DropDownFieldName_Thesis"],
|
|
"title" => $loc["DropDownFieldName_Title"],
|
|
"orig_title" => $loc["DropDownFieldName_OrigTitle"],
|
|
"year" => $loc["DropDownFieldName_Year"],
|
|
"publication" => $loc["DropDownFieldName_Publication"],
|
|
"abbrev_journal" => $loc["DropDownFieldName_AbbrevJournal"],
|
|
"editor" => $loc["DropDownFieldName_Editor"],
|
|
"volume" => $loc["DropDownFieldName_Volume"],
|
|
// "volume_numeric" => $loc[""],
|
|
"issue" => $loc["DropDownFieldName_Issue"],
|
|
"pages" => $loc["DropDownFieldName_Pages"],
|
|
// "first_page" => $loc[""],
|
|
"series_title" => $loc["DropDownFieldName_SeriesTitle"],
|
|
"abbrev_series_title" => $loc["DropDownFieldName_AbbrevSeriesTitle"],
|
|
"series_editor" => $loc["DropDownFieldName_SeriesEditor"],
|
|
"series_volume" => $loc["DropDownFieldName_SeriesVolume"],
|
|
// "series_volume_numeric" => $loc[""],
|
|
"series_issue" => $loc["DropDownFieldName_SeriesIssue"],
|
|
"publisher" => $loc["DropDownFieldName_Publisher"],
|
|
"place" => $loc["DropDownFieldName_Place"],
|
|
"edition" => $loc["DropDownFieldName_Edition"],
|
|
"medium" => $loc["DropDownFieldName_Medium"],
|
|
"issn" => $loc["DropDownFieldName_Issn"],
|
|
"isbn" => $loc["DropDownFieldName_Isbn"],
|
|
"language" => $loc["DropDownFieldName_Language"],
|
|
"summary_language" => $loc["DropDownFieldName_SummaryLanguage"],
|
|
"keywords" => $loc["DropDownFieldName_Keywords"],
|
|
"abstract" => $loc["DropDownFieldName_Abstract"],
|
|
"area" => $loc["DropDownFieldName_Area"],
|
|
"expedition" => $loc["DropDownFieldName_Expedition"],
|
|
"conference" => $loc["DropDownFieldName_Conference"],
|
|
"doi" => $loc["DropDownFieldName_Doi"],
|
|
"url" => $loc["DropDownFieldName_Url"],
|
|
"file" => $loc["DropDownFieldName_File"],
|
|
"notes" => $loc["DropDownFieldName_Notes"],
|
|
"location" => $loc["DropDownFieldName_Location"],
|
|
"call_number" => $loc["DropDownFieldName_CallNumber"],
|
|
"serial" => $loc["DropDownFieldName_Serial"],
|
|
"type" => $loc["DropDownFieldName_Type"],
|
|
"approved" => $loc["DropDownFieldName_Approved"],
|
|
"created_date" => $loc["DropDownFieldName_CreatedDate"],
|
|
"created_time" => $loc["DropDownFieldName_CreatedTime"],
|
|
"created_by" => $loc["DropDownFieldName_CreatedBy"],
|
|
"modified_date" => $loc["DropDownFieldName_ModifiedDate"],
|
|
"modified_time" => $loc["DropDownFieldName_ModifiedTime"],
|
|
"modified_by" => $loc["DropDownFieldName_ModifiedBy"],
|
|
"marked" => $loc["DropDownFieldName_Marked"],
|
|
"copy" => $loc["DropDownFieldName_Copy"],
|
|
"selected" => $loc["DropDownFieldName_Selected"],
|
|
"user_keys" => $loc["DropDownFieldName_UserKeys"],
|
|
"user_notes" => $loc["DropDownFieldName_UserNotes"],
|
|
"user_file" => $loc["DropDownFieldName_UserFile"],
|
|
"user_groups" => $loc["DropDownFieldName_UserGroups"],
|
|
"cite_key" => $loc["DropDownFieldName_CiteKey"],
|
|
// "related" => $loc[""]
|
|
);
|
|
}
|
|
else // field names intended as title word or column heading:
|
|
{
|
|
$fieldNamesArray = array("author" => $loc["Author"],
|
|
"author_count" => $loc["AuthorCount"],
|
|
"first_author" => $loc["AuthorFirst"],
|
|
"address" => $loc["Address"],
|
|
"corporate_author" => $loc["CorporateAuthor"],
|
|
"thesis" => $loc["Thesis"],
|
|
"title" => $loc["Title"],
|
|
"orig_title" => $loc["TitleOriginal"],
|
|
"year" => $loc["Year"],
|
|
"publication" => $loc["Publication"],
|
|
"abbrev_journal" => $loc["JournalAbbr"],
|
|
"editor" => $loc["Editor"],
|
|
"volume" => $loc["Volume"],
|
|
"volume_numeric" => $loc["VolumeNumeric"],
|
|
"issue" => $loc["Issue"],
|
|
"pages" => $loc["Pages"],
|
|
"first_page" => $loc["PagesFirst"],
|
|
"series_title" => $loc["TitleSeries"],
|
|
"abbrev_series_title" => $loc["TitleSeriesAbbr"],
|
|
"series_editor" => $loc["SeriesEditor"],
|
|
"series_volume" => $loc["SeriesVolume"],
|
|
"series_volume_numeric" => $loc["SeriesVolumeNumeric"],
|
|
"series_issue" => $loc["SeriesIssue"],
|
|
"publisher" => $loc["Publisher"],
|
|
"place" => $loc["PublisherPlace"],
|
|
"edition" => $loc["Edition"],
|
|
"medium" => $loc["Medium"],
|
|
"issn" => $loc["ISSN"],
|
|
"isbn" => $loc["ISBN"],
|
|
"language" => $loc["Language"],
|
|
"summary_language" => $loc["LanguageSummary"],
|
|
"keywords" => $loc["Keywords"],
|
|
"abstract" => $loc["Abstract"],
|
|
"area" => $loc["Area"],
|
|
"expedition" => $loc["Expedition"],
|
|
"conference" => $loc["Conference"],
|
|
"doi" => $loc["DOI"],
|
|
"url" => $loc["URL"],
|
|
"file" => $loc["File"],
|
|
"notes" => $loc["Notes"],
|
|
"location" => $loc["Location"],
|
|
"call_number" => $loc["CallNumber"],
|
|
"serial" => $loc["Serial"],
|
|
"type" => $loc["Type"],
|
|
"approved" => $loc["Approved"],
|
|
"created_date" => $loc["CreationDate"],
|
|
"created_time" => $loc["CreationTime"],
|
|
"created_by" => $loc["Creator"],
|
|
"modified_date" => $loc["ModifiedDate"],
|
|
"modified_time" => $loc["ModifiedTime"],
|
|
"modified_by" => $loc["Modifier"],
|
|
"marked" => $loc["Marked"],
|
|
"copy" => $loc["Copy"],
|
|
"selected" => $loc["Selected"],
|
|
"user_keys" => $loc["UserKeys"],
|
|
"user_notes" => $loc["UserNotes"],
|
|
"user_file" => $loc["UserFile"],
|
|
"user_groups" => $loc["UserGroups"], // see TODO note above
|
|
"cite_key" => $loc["CiteKey"],
|
|
"related" => $loc["Related"],
|
|
|
|
// field names from table 'users' (that aren't covered by any of the above):
|
|
"first_name" => $loc["FirstName"],
|
|
"last_name" => $loc["LastName"],
|
|
"institution" => $loc["Institution"],
|
|
"abbrev_institution" => $loc["InstitutionAbbr"],
|
|
"corporate_institution" => $loc["CorporateInstitution"],
|
|
"address_line_1" => $loc["AddressLine1"],
|
|
"address_line_2" => $loc["AddressLine2"],
|
|
"address_line_3" => $loc["AddressLine3"],
|
|
"zip_code" => $loc["ZipCode"],
|
|
"city" => $loc["City"],
|
|
"state" => $loc["State"],
|
|
"country" => $loc["Country"],
|
|
"phone" => $loc["Phone"],
|
|
"email" => $loc["Email"],
|
|
"last_login" => $loc["LastLogin"],
|
|
"logins" => $loc["Logins"],
|
|
"user_id" => $loc["UserID"],
|
|
// "user_groups" => $loc["UserGroups"], // see TODO note above
|
|
);
|
|
}
|
|
|
|
return $fieldNamesArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// BUILD FIELD NAME LINKS
|
|
// (i.e., build clickable column headers for each available column)
|
|
// TODO: I18n
|
|
function buildFieldNameLinks($href, $query, $newORDER, $result, $i, $showQuery, $showLinks, $rowOffset, $showRows, $wrapResults, $citeStyle, $HTMLbeforeLink, $HTMLafterLink, $formType, $submitType, $linkName, $orig_fieldname, $headerMsg, $viewType)
|
|
{
|
|
global $databaseBaseURL; // defined in 'ini.inc.php'
|
|
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
global $client;
|
|
|
|
// Setup the base URL:
|
|
if (preg_match("/^(cli|inc)/i", $client) OR ($wrapResults == "0")) // we use absolute links for CLI clients, for include mechanisms, or when returning only a partial document structure
|
|
$baseURL = $databaseBaseURL;
|
|
else
|
|
$baseURL = "";
|
|
|
|
// Map MySQL field names to localized column names:
|
|
$fieldNamesArray = mapFieldNames();
|
|
|
|
// Get all field properties of the current MySQL field:
|
|
$fieldInfoArray = getMySQLFieldInfo($result, $i);
|
|
|
|
if (empty($orig_fieldname)) // if there's no fixed original fieldname specified (as is the case for all fields but the 'Links' column)
|
|
{
|
|
// Get the attribute name:
|
|
$orig_fieldname = $fieldInfoArray["name"];
|
|
}
|
|
|
|
if (empty($linkName)) // if there's no fixed link name specified (as is the case for all fields but the 'Links' column)...
|
|
{
|
|
if (isset($fieldNamesArray[$orig_fieldname]))
|
|
{
|
|
$linkName = $fieldNamesArray[$orig_fieldname]; // ...use the attribute's localized name as link name
|
|
}
|
|
else // ...use MySQL field name as fall back:
|
|
{
|
|
// Replace substrings with spaces:
|
|
$linkName = str_replace("_"," ",$orig_fieldname);
|
|
// Form words (i.e., make the first char of a word uppercase):
|
|
$linkName = ucwords($linkName);
|
|
}
|
|
}
|
|
|
|
// Setup some variables (in order to enable sorting by clicking on column titles)
|
|
// NOTE: Column sorting with any queries that include the 'LIMIT'... parameter
|
|
// will (technically) work. However, every new query will limit the selection to a *different* list of records!! ?:-/
|
|
if (empty($newORDER)) // if there's no fixed ORDER BY string specified (as is the case for all fields but the 'Links' column)
|
|
{
|
|
if ($fieldInfoArray["numeric"] == "1") // Check if the field's data type is numeric (if so we'll append " DESC" to the ORDER clause)
|
|
$newORDER = ("ORDER BY " . $orig_fieldname . " DESC"); // Build the appropriate ORDER BY clause (sort numeric fields in DESCENDING order)
|
|
else
|
|
$newORDER = ("ORDER BY " . $orig_fieldname); // Build the appropriate ORDER BY clause
|
|
}
|
|
|
|
if ($orig_fieldname == "pages") // when original field name = 'pages' then...
|
|
{
|
|
$newORDER = preg_replace("/ORDER BY pages/i", "ORDER BY first_page DESC", $newORDER); // ...sort by 'first_page' instead
|
|
$orig_fieldname = "first_page"; // adjust '$orig_fieldname' variable accordingly
|
|
}
|
|
|
|
if ($orig_fieldname == "volume") // when original field name = 'volume' then...
|
|
{
|
|
$newORDER = preg_replace("/ORDER BY volume/i", "ORDER BY volume_numeric DESC", $newORDER); // ...sort by 'volume_numeric' instead
|
|
$orig_fieldname = "volume_numeric"; // adjust '$orig_fieldname' variable accordingly
|
|
}
|
|
|
|
if ($orig_fieldname == "series_volume") // when original field name = 'series_volume' then...
|
|
{
|
|
$newORDER = preg_replace("/ORDER BY series_volume/i", "ORDER BY series_volume_numeric DESC", $newORDER); // ...sort by 'series_volume_numeric' instead
|
|
$orig_fieldname = "series_volume_numeric"; // adjust '$orig_fieldname' variable accordingly
|
|
}
|
|
|
|
if ($orig_fieldname == "marked") // when original field name = 'marked' then...
|
|
$newORDER = preg_replace("/ORDER BY marked/i", "ORDER BY marked DESC", $newORDER); // ...sort 'marked' column in DESCENDING order (so that 'yes' sorts before 'no')
|
|
|
|
if ($orig_fieldname == "last_login") // when original field name = 'last_login' (defined in 'users' table) then...
|
|
$newORDER = preg_replace("/ORDER BY last_login/i", "ORDER BY last_login DESC", $newORDER); // ...sort 'last_login' column in DESCENDING order (so that latest date+time sorts first)
|
|
|
|
$orderBy = preg_replace("/ORDER BY /i", "", $newORDER); // remove 'ORDER BY ' phrase in order to store just the 'ORDER BY' field spec within the 'orderBy' variable
|
|
|
|
// call the 'newORDERclause()' function to replace the ORDER clause:
|
|
$queryURLNewOrder = newORDERclause($newORDER, $query);
|
|
|
|
// in the link title, we'll report the field that is actually used for sorting:
|
|
if (isset($fieldNamesArray[$orig_fieldname]))
|
|
$linkTitleFieldName = $fieldNamesArray[$orig_fieldname];
|
|
else
|
|
$linkTitleFieldName = $linkName;
|
|
|
|
// figure out if clicking on the current field name will sort in ascending or descending order:
|
|
// (note that for 1st-level sort attributes, this value will be modified again below)
|
|
if (preg_match("/ORDER BY [^ ]+ DESC/i", $newORDER)) // if 1st-level sort is in descending order...
|
|
$linkTitleSortOrder = $loc["descendingOrder"]; // ...sorting will be conducted in DESCending order
|
|
else
|
|
$linkTitleSortOrder = $loc["ascendingOrder"]; // ...sorting will be conducted in ASCending order
|
|
|
|
// toggle sort order for the 1st-level sort attribute:
|
|
if (preg_match("/ORDER BY $orig_fieldname(?! DESC)/i", $query)) // if 1st-level sort is by this attribute (in ASCending order)...
|
|
{
|
|
$queryURLNewOrder = preg_replace("/(ORDER%20BY%20$orig_fieldname)(?!%20DESC)/i", "\\1%20DESC", $queryURLNewOrder); // ...change sort order to DESCending
|
|
$linkTitleSortOrder = $loc["descendingOrder"]; // adjust the link title attribute's sort info accordingly
|
|
}
|
|
elseif (preg_match("/ORDER BY $orig_fieldname DESC/i", $query)) // if 1st-level sort is by this attribute (in DESCending order)...
|
|
{
|
|
$queryURLNewOrder = preg_replace("/(ORDER%20BY%20$orig_fieldname)%20DESC/i", "\\1", $queryURLNewOrder); // ...change sort order to ASCending
|
|
$linkTitleSortOrder = $loc["ascendingOrder"]; // adjust the link title attribute's sort info accordingly
|
|
}
|
|
|
|
// build an informative string that get's displayed when a user mouses over a link:
|
|
$linkTitle = "\"" . $loc["LinkTitle_SortByField_Prefix"] . $linkTitleFieldName . $loc["LinkTitle_SortByField_Suffix"] . ", " . $linkTitleSortOrder . "\"";
|
|
|
|
// start the table header tag & print the attribute name as link:
|
|
$tableHeaderLink = $HTMLbeforeLink
|
|
. "<a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . $queryURLNewOrder
|
|
. "&submit=" . $submitType
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $rowOffset
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\" title=" . $linkTitle . ">" . $linkName . "</a>";
|
|
|
|
// append sort indicator after the 1st-level sort attribute:
|
|
if (preg_match("/ORDER BY $orig_fieldname(?! DESC)(?=,| LIMIT|$)/i", $query)) // if 1st-level sort is by this attribute (in ASCending order)...
|
|
$tableHeaderLink .= " <img src=\"" . $baseURL . "img/sort_asc.gif\" alt=\"(up)\" title=\"" . $loc["LinkTitle_SortedByField_Prefix"] . $linkTitleFieldName . $loc["LinkTitle_SortedByField_Suffix"] . ", " . $loc["ascendingOrder"] . "\" width=\"8\" height=\"10\" hspace=\"0\" border=\"0\">"; // ...append an upward arrow image
|
|
elseif (preg_match("/ORDER BY $orig_fieldname DESC/i", $query)) // if 1st-level sort is by this attribute (in DESCending order)...
|
|
$tableHeaderLink .= " <img src=\"" . $baseURL . "img/sort_desc.gif\" alt=\"(down)\" title=\"" . $loc["LinkTitle_SortedByField_Prefix"] . $linkTitleFieldName . $loc["LinkTitle_SortedByField_Suffix"] . ", " . $loc["descendingOrder"] . "\" width=\"8\" height=\"10\" hspace=\"0\" border=\"0\">"; // ...append a downward arrow image
|
|
|
|
$tableHeaderLink .= $HTMLafterLink; // append any necessary HTML
|
|
|
|
return $tableHeaderLink;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Build SELECT clause:
|
|
// (if given, '$additionalFields' & '$customSELECTclause' must contain
|
|
// a string of comma-separated field names)
|
|
// TODO: add support for 'users.php' SELECT clauses
|
|
function buildSELECTclause($displayType, $showLinks, $additionalFields = "", $addUserSpecificFields = true, $addRequiredFields = true, $customSELECTclause = "", $browseByField = "")
|
|
{
|
|
global $defaultFieldsListViewMajor; // these variables are specified in 'ini.inc.php'
|
|
global $defaultFieldsListViewMinor;
|
|
global $additionalFieldsCitationView;
|
|
global $showAdditionalFieldsDetailsViewDefault;
|
|
global $showUserSpecificFieldsDetailsViewDefault;
|
|
|
|
if (empty($displayType))
|
|
$displayType = $_SESSION['userDefaultView']; // get the default view for the current user
|
|
|
|
$querySELECTclause = "SELECT ";
|
|
|
|
if (!empty($customSELECTclause)) // if given, honour any custom SQL SELECT clause:
|
|
{
|
|
$querySELECTclause .= $customSELECTclause;
|
|
}
|
|
else // build a new SELECT clause that's suitable for the given '$displayType':
|
|
{
|
|
// Details view:
|
|
if (preg_match("/^(Display)$/i", $displayType)) // select all fields required to display record details:
|
|
{
|
|
if ($showAdditionalFieldsDetailsViewDefault == "no") // omit additional fields:
|
|
{
|
|
$querySELECTclause .= "author, title, type, year, publication, abbrev_journal, volume, issue, pages, keywords, abstract";
|
|
}
|
|
else // display all fields:
|
|
{
|
|
$querySELECTclause .= "author, title, type, year, publication, abbrev_journal, volume, issue, pages, keywords, abstract, address, corporate_author, thesis, publisher, place, editor, language, summary_language, orig_title, series_editor, series_title, abbrev_series_title, series_volume, series_issue, edition, issn, isbn, medium, area, expedition, conference, notes, approved";
|
|
|
|
if (isset($_SESSION['loginEmail']))
|
|
$querySELECTclause .= ", location"; // we only add the 'location' field if the user is logged in
|
|
}
|
|
|
|
$querySELECTclause .= ", call_number, serial";
|
|
|
|
if ($showUserSpecificFieldsDetailsViewDefault == "no")
|
|
$addUserSpecificFields = false;
|
|
}
|
|
|
|
// Edit mode & Export:
|
|
elseif (preg_match("/^(Edit|Export)$/i", $displayType)) // select all fields required to display record details (in edit mode) or to export a record:
|
|
{
|
|
$querySELECTclause .= "author, title, type, year, publication, abbrev_journal, volume, issue, pages, keywords, abstract, address, corporate_author, thesis, publisher, place, editor, language, summary_language, orig_title, series_editor, series_title, abbrev_series_title, series_volume, series_issue, edition, issn, isbn, medium, area, expedition, conference, notes, approved";
|
|
|
|
if (isset($_SESSION['loginEmail']))
|
|
$querySELECTclause .= ", location"; // we only add the 'location' field if the user is logged in
|
|
|
|
$querySELECTclause .= ", contribution_id, online_publication, online_citation, created_date, created_time, created_by, modified_date, modified_time, modified_by, call_number, serial";
|
|
}
|
|
|
|
// Citation view & RSS output:
|
|
elseif (preg_match("/^(Cite|RSS)$/i", $displayType)) // select all fields required to build proper record citations:
|
|
{
|
|
$querySELECTclause .= "author, title, type, year, publication, abbrev_journal, volume, issue, pages, keywords, abstract, thesis, editor, publisher, place, abbrev_series_title, series_title, series_editor, series_volume, series_issue, edition, language, author_count, online_publication, online_citation, doi, serial";
|
|
|
|
if ($displayType == "RSS") // for RSS output, we add some additional fields:
|
|
$querySELECTclause .= ", created_date, created_time, created_by, modified_date, modified_time, modified_by";
|
|
|
|
if (!empty($additionalFieldsCitationView)) // append all fields from '$additionalFieldsCitationView' that aren't yet included in the SELECT clause
|
|
foreach ($additionalFieldsCitationView as $field)
|
|
if (!preg_match("/\b" . $field . "\b/", $querySELECTclause))
|
|
{
|
|
if (preg_match("/^(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related)$/", $field)) // if '$field' is one of the user-specific fields, we'll add all of them below
|
|
$addUserSpecificFields = true;
|
|
else // append field:
|
|
$querySELECTclause .= ", " . $field;
|
|
}
|
|
}
|
|
|
|
// Browse view:
|
|
elseif (preg_match("/^Browse$/i", $displayType))
|
|
{
|
|
$querySELECTclause .= escapeSQL($browseByField) . ", COUNT(*) AS records";
|
|
}
|
|
|
|
// List view:
|
|
else // produce the default columnar output style:
|
|
{
|
|
$querySELECTclause .= $defaultFieldsListViewMajor;
|
|
if (!empty($defaultFieldsListViewMinor))
|
|
{
|
|
$querySELECTclause .= ", " . $defaultFieldsListViewMinor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// All views (except Browse view):
|
|
if (!preg_match("/^Browse$/i", $displayType))
|
|
{
|
|
if (!empty($additionalFields))
|
|
{
|
|
if ($querySELECTclause != "SELECT ")
|
|
$querySELECTclause .= ", "; // add a comma as field separator, if other fields have already been added to the SELECT clause
|
|
|
|
$querySELECTclause .= $additionalFields;
|
|
}
|
|
|
|
// NOTE: Functions 'displayColumns()' and 'displayDetails()' (in 'search.php') apply some logic that prevents some or all of the
|
|
// below fields from getting displayed. This means that you must adopt these functions if you add or remove fields below.
|
|
|
|
if ($addUserSpecificFields)
|
|
{
|
|
if (isset($_SESSION['loginEmail'])) // if a user is logged in...
|
|
$querySELECTclause .= ", marked, copy, selected, user_keys, user_notes, user_file, user_groups, cite_key, related"; // add user-specific fields
|
|
}
|
|
|
|
if ($addRequiredFields)
|
|
{
|
|
// NOTE: Although it won't be visible the 'orig_record' & 'serial' columns get included in every search query
|
|
// (that's executed directly and not included into HTML as a web link or routed again thru other scripts).
|
|
// The 'orig_record' column is required in order to present visual feedback on duplicate records, and
|
|
// the 'serial' column is required in order to obtain unique checkbox names. For SQL queries passed to
|
|
// 'search.php' directly, function 'verifySQLQuery()' in 'include.inc.php' will add these columns.
|
|
$querySELECTclause .= ", orig_record, serial"; // add 'orig_record' and 'serial' columns
|
|
|
|
if ($showLinks == "1" OR (preg_match("/^(Edit|Export)$/i", $displayType)))
|
|
$querySELECTclause .= ", file, url, doi"; // add 'file', 'url' & 'doi' columns
|
|
|
|
if ($showLinks == "1" AND (!preg_match("/^(Edit|Export)$/i", $displayType)))
|
|
$querySELECTclause .= ", isbn, type"; // add 'isbn' & 'type columns (for export and edit mode, these columns have already been added above)
|
|
}
|
|
}
|
|
|
|
|
|
return $querySELECTclause;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// REPLACE ORDER CLAUSE IN SQL QUERY
|
|
function newORDERclause($newOrderBy, $query, $encodeQuery = true)
|
|
{
|
|
// replace any existing ORDER BY clause with the new one given in '$newOrderBy':
|
|
$newQuery = preg_replace("/ORDER BY .+?(?=LIMIT.*|GROUP BY.*|HAVING.*|PROCEDURE.*|FOR UPDATE.*|LOCK IN.*|$)/i", $newOrderBy, $query);
|
|
|
|
if ($encodeQuery)
|
|
$newQuery = rawurlencode($newQuery); // URL encode query
|
|
|
|
return $newQuery;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// REPLACE SELECT CLAUSE IN SQL QUERY
|
|
function newSELECTclause($newSelectClause, $query, $encodeQuery = true)
|
|
{
|
|
// replace any existing SELECT clause with the new one given in '$newSelectClause':
|
|
$newQuery = preg_replace("/SELECT .+?(?= FROM)/i", $newSelectClause, $query);
|
|
|
|
if ($encodeQuery)
|
|
$newQuery = rawurlencode($newQuery); // URL encode query
|
|
|
|
return $newQuery;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// BUILD BROWSE LINKS
|
|
// (i.e., build a TABLE row with links for "previous" & "next" browsing, as well as links to intermediate pages)
|
|
// TODO: - use divs + CSS styling (instead of a table-based layout) for _all_ output (not only for 'viewType=Mobile')
|
|
// - use function 'generateURL()' to build the link URLs
|
|
function buildBrowseLinks($href, $query, $NoColumns, $rowsFound, $showQuery, $showLinks, $showRows, $rowOffset, $previousOffset, $nextOffset, $wrapResults, $maxPageNo, $formType, $displayType, $citeStyle, $citeOrder, $orderBy, $headerMsg, $viewType)
|
|
{
|
|
global $databaseBaseURL; // these variables are defined in 'ini.inc.php'
|
|
global $displayResultsHeaderDefault;
|
|
global $displayResultsFooterDefault;
|
|
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
global $client;
|
|
|
|
// First, calculate the offset page number:
|
|
$pageOffset = ($rowOffset / $showRows);
|
|
// workaround for always rounding upward (since I don't know better! :-/):
|
|
if (preg_match("/[0-9]+\.[0-9+]/",$pageOffset)) // if the result number is not an integer..
|
|
$pageOffset = (int) $pageOffset + 1; // we convert the number into an integer and add 1
|
|
// set the offset page number to a multiple of $maxPageNo:
|
|
$pageOffset = $maxPageNo * (int) ($pageOffset / $maxPageNo);
|
|
|
|
// Plus, calculate the maximum number of pages needed:
|
|
$lastPage = ($rowsFound / $showRows);
|
|
// workaround for always rounding upward (since I don't know better! :-/):
|
|
if (preg_match("/[0-9]+\.[0-9+]/",$lastPage)) // if the result number is not an integer..
|
|
$lastPage = (int) $lastPage + 1; // we convert the number into an integer and add 1
|
|
|
|
// Setup the base URL:
|
|
if (preg_match("/^(cli|inc)/i", $client) OR ($wrapResults == "0")) // we use absolute links for CLI clients, for include mechanisms, or when returning only a partial document structure
|
|
$baseURL = $databaseBaseURL;
|
|
else
|
|
$baseURL = "";
|
|
|
|
if (preg_match("/^Mobile$/i", $viewType))
|
|
{
|
|
$BrowseLinks = "\n<div class=\"resultnav\">";
|
|
}
|
|
else
|
|
{
|
|
// Start a <TABLE>:
|
|
$BrowseLinks = "\n<table class=\"resultnav\" align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\" width=\"95%\" summary=\"This table holds browse links that link to the results pages of your query\">";
|
|
|
|
// Start a <TABLE> row:
|
|
$BrowseLinks .= "\n<tr>";
|
|
}
|
|
|
|
if (preg_match("/^Mobile$/i", $viewType))
|
|
$BrowseLinks .= "\n\t<div class=\"mainnav\"><a href=\"" . $baseURL . "index.php\"" . addAccessKey("attribute", "home") . " title=\"" . $loc["LinkTitle_Home"] . addAccessKey("title", "home") . "\">" . $loc["Home"] . "</a></div>";
|
|
elseif (preg_match("/^Print$/i", $viewType) OR preg_match("/^cli/i", $client))
|
|
$BrowseLinks .= "\n\t<td class=\"mainnav\" align=\"left\" valign=\"bottom\" width=\"225\"><a href=\"" . $baseURL . "index.php\"" . addAccessKey("attribute", "home") . " title=\"" . $loc["LinkTitle_Home"] . addAccessKey("title", "home") . "\">" . $loc["Home"] . "</a></td>";
|
|
elseif (($href == "users.php") OR !isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden")))
|
|
{
|
|
$BrowseLinks .= "\n\t<td class=\"small\" align=\"left\" valign=\"bottom\" width=\"225\">"
|
|
. "\n\t\t<a href=\"JavaScript:checkall(true,'marked%5B%5D')\" title=\"" . $loc["LinkTitle_SelectAll"] . "\">" . $loc["SelectAll"] . "</a> "
|
|
. "\n\t\t<a href=\"JavaScript:checkall(false,'marked%5B%5D')\" title=\"" . $loc["LinkTitle_DeselectAll"] . "\">" . $loc["DeselectAll"] . "</a>"
|
|
. "\n\t</td>";
|
|
}
|
|
else // don't show the select/deselect links when the results footer is hidden
|
|
{
|
|
$BrowseLinks .= "\n\t<td class=\"small\" align=\"left\" valign=\"bottom\" width=\"225\"> </td>";
|
|
}
|
|
|
|
|
|
if (preg_match("/^Mobile$/i", $viewType))
|
|
$BrowseLinks .= "\n\t<div class=\"pagenav\">";
|
|
else
|
|
$BrowseLinks .= "\n\t<td class=\"pagenav\" align=\"center\" valign=\"bottom\">";
|
|
|
|
// a) If there's a page range below the one currently shown,
|
|
// create a "[xx-xx]" link (linking directly to the previous range of pages):
|
|
if ($pageOffset > "0")
|
|
{
|
|
$previousRangeFirstPage = ($pageOffset - $maxPageNo + 1); // calculate the first page of the previous page range
|
|
|
|
$previousRangeLastPage = ($previousRangeFirstPage + $maxPageNo - 1); // calculate the last page of the previous page range
|
|
|
|
$BrowseLinks .= "\n\t\t<a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . rawurlencode($query)
|
|
. "&submit=" . $displayType
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . (($pageOffset - $maxPageNo) * $showRows)
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\" title=\"" . $loc["LinkTitle_DisplayResultsPage"] . " " . $previousRangeFirstPage . " " . $loc["LinkTitle_DisplayLinksToResultsPages"] . " " . $previousRangeFirstPage . "–" . $previousRangeLastPage . "\">[" . $previousRangeFirstPage . "–" . $previousRangeLastPage . "] </a>";
|
|
}
|
|
|
|
// b) Are there any previous pages?
|
|
if ($rowOffset > 0)
|
|
// Yes, so create a previous link
|
|
$BrowseLinks .= "\n\t\t<a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . rawurlencode($query)
|
|
. "&submit=" . $displayType
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $previousOffset
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\"" . addAccessKey("attribute", "previous") . " title=\"" . $loc["LinkTitle_DisplayPreviousResultsPage"] . addAccessKey("title", "previous") . "\"><<</a>";
|
|
else
|
|
// No, there is no previous page so don't print a link
|
|
$BrowseLinks .= "\n\t\t<<";
|
|
|
|
// c) Output the page numbers as links:
|
|
// Count through the number of pages in the results:
|
|
for($x=($pageOffset * $showRows), $page=($pageOffset + 1);
|
|
$x<$rowsFound && $page <= ($pageOffset + $maxPageNo);
|
|
$x+=$showRows, $page++)
|
|
// Is this the current page?
|
|
if ($x < $rowOffset ||
|
|
$x > ($rowOffset + $showRows - 1))
|
|
// No, so print out a link
|
|
$BrowseLinks .= " \n\t\t<a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . rawurlencode($query)
|
|
. "&submit=" . $displayType
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $x
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\" title=\"" . $loc["LinkTitle_DisplayResultsPage"] . " " . $page . "\">" . $page . "</a>";
|
|
else
|
|
// Yes, so don't print a link
|
|
$BrowseLinks .= " \n\t\t<b>$page</b>"; // current page is set in <b>BOLD</b>
|
|
|
|
$BrowseLinks .= " ";
|
|
|
|
// d) Are there any Next pages?
|
|
if ($rowsFound > $nextOffset)
|
|
// Yes, so create a next link
|
|
$BrowseLinks .= "\n\t\t<a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . rawurlencode($query)
|
|
. "&submit=" . $displayType
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $nextOffset
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\"" . addAccessKey("attribute", "next") . " title=\"" . $loc["LinkTitle_DisplayNextResultsPage"] . addAccessKey("title", "next") . "\">>></a>";
|
|
else
|
|
// No, there is no next page so don't print a link
|
|
$BrowseLinks .= "\n\t\t>>";
|
|
|
|
// e) If there's a page range above the one currently shown,
|
|
// create a "[xx-xx]" link (linking directly to the next range of pages):
|
|
if ($pageOffset < ($lastPage - $maxPageNo))
|
|
{
|
|
$nextRangeFirstPage = ($pageOffset + $maxPageNo + 1); // calculate the first page of the next page range
|
|
|
|
$nextRangeLastPage = ($nextRangeFirstPage + $maxPageNo - 1); // calculate the last page of the next page range
|
|
if ($nextRangeLastPage > $lastPage)
|
|
$nextRangeLastPage = $lastPage; // adjust if this is the last range of pages and if it doesn't go up to the max allowed no of pages
|
|
|
|
$BrowseLinks .= "\n\t\t<a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . rawurlencode($query)
|
|
. "&submit=" . $displayType
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . (($pageOffset + $maxPageNo) * $showRows)
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\" title=\"" . $loc["LinkTitle_DisplayResultsPage"] . " " . $nextRangeFirstPage . " " . $loc["LinkTitle_DisplayLinksToResultsPages"] . " " . $nextRangeFirstPage . "–" . $nextRangeLastPage . "\"> [" . $nextRangeFirstPage . "–" . $nextRangeLastPage . "]</a>";
|
|
}
|
|
|
|
if (preg_match("/^Mobile$/i", $viewType))
|
|
$BrowseLinks .= "\n\t</div>";
|
|
else
|
|
$BrowseLinks .= "\n\t</td>";
|
|
|
|
if (preg_match("/^Mobile$/i", $viewType))
|
|
$BrowseLinks .= "\n\t<div class=\"viewnav\">";
|
|
else
|
|
$BrowseLinks .= "\n\t<td class=\"viewnav\" align=\"right\" valign=\"bottom\" width=\"225\">";
|
|
|
|
// Add view links:
|
|
$viewLinksArray = array();
|
|
|
|
if (($href == "search.php") AND !preg_match("/^Browse$/i", $displayType) AND !preg_match("/^Mobile$/i", $viewType))
|
|
{
|
|
if (isset($_SESSION['user_permissions']) AND preg_match("/allow_list_view/", $_SESSION['user_permissions']))
|
|
{
|
|
if (preg_match("/^(Cite|Display)$/i", $displayType)) // display a link to List view:
|
|
{
|
|
// Replace current SELECT clause with one that's appropriate for List view:
|
|
if (isset($_SESSION['lastListViewQuery']))
|
|
$listViewSelectClause = "SELECT " . extractSELECTclause($_SESSION['lastListViewQuery']); // get SELECT clause from any previous List view query
|
|
else
|
|
$listViewSelectClause = buildSELECTclause("List", $showLinks, "", false, false); // produce the default columnar output style
|
|
|
|
$listViewQuery = newSELECTclause($listViewSelectClause, $query); // replace SELECT clause in current query and URL encode query
|
|
|
|
// f) create a 'List View' link that will show the currently displayed result set in List view:
|
|
$viewLinksArray[] = "<div class=\"leftview\"><a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . $listViewQuery
|
|
. "&submit=List"
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $rowOffset
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\"" . addAccessKey("attribute", "list") . " title=\"" . $loc["LinkTitle_DisplayListView"] . addAccessKey("title", "list") . "\">" . $loc["ListView"] . "</a></div>";
|
|
}
|
|
else
|
|
$viewLinksArray[] = "<div class=\"activeview\"><div class=\"leftview\">" . $loc["ListView"] . "</div></div>";
|
|
}
|
|
|
|
if (isset($_SESSION['user_permissions']) AND preg_match("/allow_cite/", $_SESSION['user_permissions']))
|
|
{
|
|
if (!preg_match("/^Cite$/i", $displayType)) // display a link to Citation view:
|
|
{
|
|
// Replace current SELECT clause with one that's appropriate for Citation view:
|
|
$citeViewSelectClause = buildSELECTclause("Cite", $showLinks, "", false, false); // select all fields required to build proper record citations
|
|
$citeViewQuery = newSELECTclause($citeViewSelectClause, $query); // replace SELECT clause in current query and URL encode query
|
|
|
|
// g) create a 'Citations' link that will show the currently displayed result set in Citation view:
|
|
$viewLinksArray[] = "<div class=\"middleview\"><a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . $citeViewQuery
|
|
. "&submit=Cite"
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $rowOffset
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\"" . addAccessKey("attribute", "cite") . " title=\"" . $loc["LinkTitle_DisplayCiteView"] . addAccessKey("title", "cite") . "\">" . $loc["Citations"] . "</a></div>";
|
|
}
|
|
else
|
|
$viewLinksArray[] = "<div class=\"activeview\"><div class=\"middleview\">" . $loc["Citations"] . "</div></div>";
|
|
}
|
|
|
|
if (isset($_SESSION['user_permissions']) AND preg_match("/allow_details_view/", $_SESSION['user_permissions']))
|
|
{
|
|
if (!preg_match("/^Display$/i", $displayType)) // display a link to Details view:
|
|
{
|
|
// Replace current SELECT clause with one that's appropriate for Details view:
|
|
if (isset($_SESSION['lastDetailsViewQuery']))
|
|
$detailsViewSelectClause = "SELECT " . extractSELECTclause($_SESSION['lastDetailsViewQuery']); // get SELECT clause from previous Details view query (if any)
|
|
else
|
|
$detailsViewSelectClause = buildSELECTclause("Display", $showLinks, "", false, false); // select all fields required to display record details
|
|
|
|
$detailsViewQuery = newSELECTclause($detailsViewSelectClause, $query); // replace SELECT clause in current query and URL encode query
|
|
|
|
// h) create a 'Details' link that will show the currently displayed result set in Details view:
|
|
$viewLinksArray[] = "<div class=\"rightview\"><a href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . $detailsViewQuery
|
|
. "&submit=Display"
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=" . $showLinks
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $rowOffset
|
|
. "&client=" . rawurlencode($client)
|
|
. "&viewType=" . $viewType
|
|
. "\"" . addAccessKey("attribute", "details") . " title=\"" . $loc["LinkTitle_DisplayDetailsView"] . addAccessKey("title", "details") . "\">" . $loc["Details"] . "</a></div>";
|
|
}
|
|
else
|
|
$viewLinksArray[] = "<div class=\"activeview\"><div class=\"rightview\">" . $loc["Details"] . "</div></div>";
|
|
}
|
|
|
|
if (count($viewLinksArray) > 1)
|
|
$BrowseLinks .= "\n\t\t<div class=\"resultviews\">"
|
|
. "\n\t\t\t" . implode("\n\t\t\t | ", $viewLinksArray)
|
|
. "\n\t\t</div>";
|
|
}
|
|
|
|
// Note: we omit 'Web/Print View' links for include mechanisms!
|
|
if (!preg_match("/^inc/i", $client))
|
|
{
|
|
$BrowseLinks .= "\n\t\t";
|
|
|
|
if (count($viewLinksArray) > 1)
|
|
$BrowseLinks .= " ";
|
|
|
|
if (preg_match("/^(Print|Mobile)$/i", $viewType))
|
|
{
|
|
// i) create a 'Web View' link that will show the currently displayed result set in web view:
|
|
$BrowseLinks .= "<a class=\"toggleprint\" href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . rawurlencode($query)
|
|
. "&submit=" . $displayType
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=1"
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $rowOffset
|
|
. "&viewType=Web"
|
|
. "\"" . addAccessKey("attribute", "print") . "><img src=\"" . $baseURL . "img/web.gif\" alt=\"web\" title=\"" . $loc["LinkTitle_DisplayWebView"] . addAccessKey("title", "print") . "\" width=\"16\" height=\"16\" hspace=\"0\" border=\"0\"></a>";
|
|
}
|
|
else
|
|
{
|
|
if (isset($_SESSION['user_permissions']) AND preg_match("/allow_print_view/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_print_view'...
|
|
// j) create a 'Print View' link that will show the currently displayed result set in print view:
|
|
$BrowseLinks .= "<a class=\"toggleprint\" href=\"" . $baseURL . $href
|
|
. "?sqlQuery=" . rawurlencode($query)
|
|
. "&submit=" . $displayType
|
|
. "&citeStyle=" . rawurlencode($citeStyle)
|
|
. "&citeOrder=" . $citeOrder
|
|
. "&orderBy=" . rawurlencode($orderBy)
|
|
. "&headerMsg=" . rawurlencode($headerMsg)
|
|
. "&showQuery=" . $showQuery
|
|
. "&showLinks=0"
|
|
. "&formType=" . $formType
|
|
. "&showRows=" . $showRows
|
|
. "&rowOffset=" . $rowOffset
|
|
. "&viewType=Print"
|
|
. "\"" . addAccessKey("attribute", "print") . "><img src=\"" . $baseURL . "img/print.gif\" alt=\"print\" title=\"" . $loc["LinkTitle_DisplayPrintView"] . addAccessKey("title", "print") . "\" width=\"17\" height=\"18\" hspace=\"0\" border=\"0\"></a>";
|
|
}
|
|
}
|
|
|
|
if (preg_match("/^Mobile$/i", $viewType))
|
|
{
|
|
$BrowseLinks .= "\n\t</div>"
|
|
. "\n</div>";
|
|
}
|
|
else
|
|
{
|
|
$BrowseLinks .= "\n\t</td>"
|
|
. "\n</tr>"
|
|
. "\n</table>";
|
|
}
|
|
|
|
return $BrowseLinks;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// BUILD QUICK SEARCH ELEMENTS
|
|
// (i.e., generate the "Quick Search" form)
|
|
function buildQuickSearchElements($query, $queryURL, $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $displayType)
|
|
{
|
|
global $tableRefs; // defined in 'db.inc.php'
|
|
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
global $client;
|
|
|
|
if (!preg_match("/^SELECT/i", $queryURL) OR !preg_match("/%20FROM%20" . $tableRefs . "%20/i", $queryURL)) // only include SELECT queries that query table 'refs'
|
|
$queryURL = ""; // this excludes e.g. queries that query table 'users'
|
|
|
|
$encodedCiteStyle = rawurlencode($citeStyle);
|
|
$encodedClient = rawurlencode($client);
|
|
|
|
$accessKeyAttribute = addAccessKey("attribute", "qck_search");
|
|
$accessKeyTitle = addAccessKey("title", "qck_search");
|
|
|
|
// extract the first field from the 'WHERE' clause:
|
|
if (preg_match("/ WHERE [ ()]*(\w+)/i", $query))
|
|
$firstField = preg_replace("/.+ WHERE [ ()]*(\w+).*/i", "\\1", $query);
|
|
else
|
|
$firstField = "";
|
|
|
|
// build HTML elements that allow for search suggestions for text entered by the user:
|
|
if (isset($_SESSION['userAutoCompletions']) AND ($_SESSION['userAutoCompletions'] == "yes"))
|
|
$suggestElements = buildSuggestElements("quickSearchName", "quickSearchSuggestions", "quickSearchSuggestProgress", "id-quickSearchSelector-", "\t\t\t\t\t\t");
|
|
else
|
|
$suggestElements = "";
|
|
|
|
// add the "Quick Search" form:
|
|
$quickSearchForm = <<<EOF
|
|
<form action="search.php" method="GET" name="quickSearch">
|
|
<fieldset>
|
|
<legend>$loc[QuickSearch]:</legend>
|
|
<input type="hidden" name="formType" value="quickSearch">
|
|
<input type="hidden" name="originalDisplayType" value="$displayType">
|
|
<input type="hidden" name="sqlQuery" value="$queryURL">
|
|
<input type="hidden" name="showQuery" value="$showQuery">
|
|
<input type="hidden" name="showLinks" value="$showLinks">
|
|
<input type="hidden" name="showRows" value="$showRows">
|
|
<input type="hidden" name="client" value="$encodedClient">
|
|
<input type="hidden" name="citeStyle" value="$encodedCiteStyle">
|
|
<input type="hidden" name="citeOrder" value="$citeOrder">
|
|
<div id="queryField">
|
|
<label for="quickSearchSelector">$loc[Field]:</label>
|
|
<select id="quickSearchSelector" name="quickSearchSelector" title="$loc[DescriptionSelectFieldQuickSearchForm]">
|
|
EOF;
|
|
|
|
// build correct option tags:
|
|
$userMainFieldsArray = preg_split("/ *, */", $_SESSION['userMainFields']); // get the list of "main fields" preferred by the current user
|
|
|
|
$dropDownFieldNameArray = array("main_fields" => $loc["DropDownFieldName_MainFields"]);
|
|
|
|
foreach($userMainFieldsArray as $userMainField)
|
|
{
|
|
// generate the variable name of the correct '$loc' locale for this field:
|
|
$dropDownFieldNameLocale = preg_replace_callback("/_(\w)/",
|
|
function($matches){
|
|
foreach($matches as $match){
|
|
return ucfirst($match);
|
|
}
|
|
},
|
|
$userMainField);
|
|
$dropDownFieldNameLocale = "DropDownFieldName_" . ucfirst($dropDownFieldNameLocale);
|
|
// add this field's name and localized string to the array of fields that will be included in the "Quick Search" drop-down menu:
|
|
$dropDownFieldNameArray[$userMainField] = $loc[$dropDownFieldNameLocale];
|
|
}
|
|
|
|
$optionTags = buildSelectMenuOptions($dropDownFieldNameArray, "//", "\t\t\t\t\t\t\t", true);
|
|
|
|
if (!empty($firstField) AND in_array($firstField, $userMainFieldsArray)) // if the first field from the 'WHERE' clause is one of the main fields
|
|
$quickSearchForm .= preg_replace("/<option([^>]* value=\"$firstField\")/", "<option\\1 selected", $optionTags); // we select that field by adding the 'selected' parameter to the appropriate <option> tag
|
|
else
|
|
$quickSearchForm .= preg_replace("/<option([^>]*)>" . $loc["DropDownFieldName_MainFields"] . "/", "<option\\1 selected>" . $loc["DropDownFieldName_MainFields"], $optionTags); // select the 'main fields' menu entry ...
|
|
|
|
$quickSearchForm .= <<<EOF
|
|
|
|
</select>
|
|
<label for="quickSearchName">$loc[contains]:</label>
|
|
<input type="text" id="quickSearchName" name="quickSearchName" size="11"$accessKeyAttribute title="$loc[DescriptionEnterSearchString]$accessKeyTitle">$suggestElements
|
|
</div>
|
|
<div id="querySubmit">
|
|
<input type="submit" value="$loc[ButtonTitle_Search]" title="$loc[DescriptionSearchDB]">
|
|
</div>
|
|
</fieldset>
|
|
</form>
|
|
|
|
EOF;
|
|
|
|
return $quickSearchForm;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// BUILD REFINE SEARCH ELEMENTS
|
|
// (i.e., provide options to refine the search results)
|
|
function buildRefineSearchElements($href, $queryURL, $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $dropDownFieldsArray, $dropDownFieldSelected, $displayType)
|
|
{
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
global $client;
|
|
|
|
$encodedCiteStyle = rawurlencode($citeStyle);
|
|
$encodedClient = rawurlencode($client);
|
|
|
|
$accessKeyAttribute = addAccessKey("attribute", "refine");
|
|
$accessKeyTitle = addAccessKey("title", "refine");
|
|
|
|
// build HTML elements that allow for search suggestions for text entered by the user:
|
|
if (($href == "search.php") AND (isset($_SESSION['userAutoCompletions']) AND ($_SESSION['userAutoCompletions'] == "yes")))
|
|
$suggestElements = buildSuggestElements("refineSearchName", "refineSearchSuggestions", "refineSearchSuggestProgress", "id-refineSearchSelector-", "\t\t\t\t\t");
|
|
else
|
|
$suggestElements = "";
|
|
|
|
$refineSearchForm = <<<EOF
|
|
<form action="$href" method="GET" name="refineSearch">
|
|
<fieldset>
|
|
<legend>$loc[SearchWithinResults]:</legend>
|
|
<input type="hidden" name="formType" value="refineSearch">
|
|
<input type="hidden" name="submit" value="$loc[ButtonTitle_Search]">
|
|
<input type="hidden" name="originalDisplayType" value="$displayType">
|
|
<input type="hidden" name="sqlQuery" value="$queryURL">
|
|
<input type="hidden" name="showQuery" value="$showQuery">
|
|
<input type="hidden" name="showLinks" value="$showLinks">
|
|
<input type="hidden" name="showRows" value="$showRows">
|
|
<input type="hidden" name="client" value="$encodedClient">
|
|
<input type="hidden" name="citeStyle" value="$encodedCiteStyle">
|
|
<input type="hidden" name="citeOrder" value="$citeOrder">
|
|
<div id="refineField">
|
|
<label for="refineSearchSelector">$loc[Field]:</label>
|
|
<select id="refineSearchSelector" name="refineSearchSelector" title="$loc[DescriptionSelectFieldRefineResultsForm]">
|
|
EOF;
|
|
|
|
// build correct option tags from the column items provided:
|
|
$optionTags = buildSelectMenuOptions($dropDownFieldsArray, "//", "\t\t\t\t\t\t", true);
|
|
|
|
$optionTags = preg_replace("/<option([^>]* value=\"$dropDownFieldSelected\")/", "<option\\1 selected", $optionTags); // add 'selected' attribute
|
|
|
|
$refineSearchForm .= $optionTags;
|
|
|
|
$refineSearchForm .= <<<EOF
|
|
|
|
</select>
|
|
<label for="refineSearchName">$loc[contains]:</label>
|
|
<input type="text" id="refineSearchName" name="refineSearchName" size="11"$accessKeyAttribute title="$loc[DescriptionEnterSearchString]$accessKeyTitle">$suggestElements
|
|
</div>
|
|
<div id="refineOpt">
|
|
<input type="checkbox" id="refineSearchExclude" name="refineSearchExclude" value="1" title="$loc[DescriptionExcludeResultsCheckboxRefineResultsForm]">
|
|
<label for="refineSearchExclude">$loc[ExcludeMatches]</label>
|
|
</div>
|
|
<div id="refineSubmit">
|
|
<input type="submit" name="submit" value="$loc[ButtonTitle_Search]" title="$loc[DescriptionSearchButtonRefineResultsForm]">
|
|
</div>
|
|
</fieldset>
|
|
</form>
|
|
|
|
EOF;
|
|
|
|
return $refineSearchForm;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// BUILD USER GROUP FORM ELEMENTS
|
|
// (i.e., provide options to show the user's personal reference groups -OR- the admin's user groups)
|
|
// Note: this function serves two purposes (which must not be confused!):
|
|
// - if "$href = search.php", it will modify the values of the 'user_groups' field of the 'user_data' table (where a user can assign one or more groups to particular *references*)
|
|
// - if "$href = users.php", this function will modify the values of the 'user_groups' field of the 'users' table (where the admin can assign one or more groups to particular *users*)
|
|
function buildGroupSearchElements($href, $queryURL, $query, $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $displayType)
|
|
{
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
global $client;
|
|
|
|
if (preg_match("/.+user_groups RLIKE \"[()|^.;* ]+[^;]+?[()|$.;* ]+\"/i", $query)) // if the query does contain a 'WHERE' clause that searches for a particular user group
|
|
// TODO: improve the legibility & robustness of the below regex pattern (yes, it's ugly)
|
|
$currentGroup = preg_replace("/.+user_groups RLIKE \"(?:\[:(?:space|punct):\]|[()|^.;* \]\[])+([^;]+?(?:\[\^\[:space:\]\[:punct:\]\]\*)?)(?:\[:(?:space|punct):\]|[()|$.;* \]\[])+\".*/i", "\\1", $query); // extract the particular group name
|
|
else
|
|
$currentGroup = "";
|
|
|
|
// show the 'Show My Groups' form:
|
|
// - if the admin is logged in and calls 'users.php' (since only the admin will be allowed to call 'users.php', checking '$href' is sufficient here) -OR-
|
|
// - if a user is logged in AND the 'user_permissions' session variable contains 'allow_user_groups'
|
|
if (($href == "users.php") OR (isset($_SESSION['loginEmail']) AND (isset($_SESSION['user_permissions']) AND preg_match("/allow_user_groups/", $_SESSION['user_permissions']))))
|
|
{
|
|
if (($href == "search.php" AND isset($_SESSION['userGroups'])) OR ($href == "users.php" AND isset($_SESSION['adminUserGroups']))) // if the appropriate session variable is set
|
|
{
|
|
$groupSearchDisabled = "";
|
|
$groupSearchSelectorTitle = $loc["DescriptionSelectFieldGroupsForm"];
|
|
$groupSearchButtonTitle = $loc["DescriptionShowButtonGroupsForm"];
|
|
}
|
|
else
|
|
{
|
|
$groupSearchDisabled = " disabled"; // disable the 'Show My Groups' form if the session variable holding the user's groups isnt't available
|
|
$groupSearchSelectorTitle = "(" . $loc["DescriptionSelectFieldGroupsFormDisabled"] . ")";
|
|
$groupSearchButtonTitle = "(" . $loc["DescriptionShowButtonGroupsFormDisabled"] . ")";
|
|
}
|
|
|
|
// adjust the form & dropdown labels according to the calling script (which is either 'search.php' or 'users.php')
|
|
if ($href == "search.php")
|
|
{
|
|
$formLegend = $loc["ShowMyGroup"] . ":";
|
|
$dropdownLabel = $loc["My"] . ":";
|
|
}
|
|
elseif ($href == "users.php")
|
|
{
|
|
$formLegend = $loc["ShowUserGroup"] . ":";
|
|
$dropdownLabel = $loc["Users"] . ":";
|
|
}
|
|
else // currently, '$href' will be either 'search.php' or 'users.php', but anyhow
|
|
{
|
|
$formLegend = $loc["ShowGroup"] . ":";
|
|
$dropdownLabel = "";
|
|
}
|
|
|
|
$encodedCiteStyle = rawurlencode($citeStyle);
|
|
$encodedClient = rawurlencode($client);
|
|
|
|
$groupSearchForm = <<<EOF
|
|
<form action="$href" method="GET" name="groupSearch">
|
|
<fieldset>
|
|
<legend>$formLegend</legend>
|
|
<input type="hidden" name="formType" value="groupSearch">
|
|
<input type="hidden" name="originalDisplayType" value="$displayType">
|
|
<input type="hidden" name="sqlQuery" value="$queryURL">
|
|
<input type="hidden" name="showQuery" value="$showQuery">
|
|
<input type="hidden" name="showLinks" value="$showLinks">
|
|
<input type="hidden" name="showRows" value="$showRows">
|
|
<input type="hidden" name="client" value="$encodedClient">
|
|
<input type="hidden" name="citeStyle" value="$encodedCiteStyle">
|
|
<input type="hidden" name="citeOrder" value="$citeOrder">
|
|
<div id="groupSelect">
|
|
<label for="groupSearchSelector">$dropdownLabel</label>
|
|
<select id="groupSearchSelector" name="groupSearchSelector" title="$groupSearchSelectorTitle"$groupSearchDisabled>
|
|
EOF;
|
|
|
|
if (($href == "search.php" AND isset($_SESSION['userGroups'])) OR ($href == "users.php" AND isset($_SESSION['adminUserGroups']))) // if the appropriate session variable is set
|
|
{
|
|
// build properly formatted <option> tag elements from the items listed in the appropriate session variable:
|
|
if ($href == "search.php")
|
|
$optionTags = buildSelectMenuOptions($_SESSION['userGroups'], "/ *; */", "\t\t\t\t\t\t", false);
|
|
elseif ($href == "users.php")
|
|
$optionTags = buildSelectMenuOptions($_SESSION['adminUserGroups'], "/ *; */", "\t\t\t\t\t\t", false);
|
|
|
|
if (!empty($currentGroup)) // if the current SQL query contains a 'WHERE' clause that searches for a particular user group
|
|
$optionTags = preg_replace("/<option>(?=$currentGroup<\\/option>)/i", "<option selected>", $optionTags); // we select that group by adding the 'selected' parameter to the appropriate <option> tag
|
|
|
|
$groupSearchForm .= $optionTags;
|
|
}
|
|
else
|
|
$groupSearchForm .= "<option>($loc[NoGroupsAvl])</option>";
|
|
|
|
$groupSearchForm .= <<<EOF
|
|
|
|
</select>
|
|
</div>
|
|
<div id="groupSubmit">
|
|
<input type="submit" value="$loc[ButtonTitle_Show]" title="$groupSearchButtonTitle"$groupSearchDisabled>
|
|
</div>
|
|
</fieldset>
|
|
</form>
|
|
|
|
EOF;
|
|
}
|
|
else
|
|
$groupSearchForm = "";
|
|
|
|
return $groupSearchForm;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// BUILD DISPLAY OPTIONS FORM ELEMENTS
|
|
// (i.e., provide options to show/hide columns or change the number of records displayed per page)
|
|
function buildDisplayOptionsElements($href, $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $citeStyle, $citeOrder, $dropDownFieldsArray, $dropDownFieldSelected, $fieldsToDisplay, $displayType, $headerMsg)
|
|
{
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
global $client;
|
|
|
|
if ($displayType == "Browse")
|
|
{
|
|
$submitValue = $loc["ButtonTitle_Browse"];
|
|
$submitTitle = $loc["DescriptionShowButtonDisplayOptionsFormBrowseView"];
|
|
$selectorDivID = "optShowHideField";
|
|
$selectorID = "displayOptionsSelector";
|
|
$selectorLabel = $loc["Field"] . ":";
|
|
$selectorTitle = $loc["DescriptionSelectFieldDisplayOptionsFormBrowseView"];
|
|
$showRowsLabel = $loc["ShowRecordsPerPage_SuffixBrowseView"];
|
|
$showRowsTitle = $loc["DescriptionShowRecordsPerPageBrowseView"];
|
|
}
|
|
elseif ($displayType == "Cite")
|
|
{
|
|
$submitValue = $loc["ButtonTitle_Show"];
|
|
$submitTitle = $loc["DescriptionShowButtonDisplayOptionsFormCiteView"];
|
|
$selectorDivID = "optCiteStyle";
|
|
$selectorID = "citeStyle";
|
|
$selectorLabel = $loc["Style"] . ":";
|
|
$selectorTitle = $loc["DescriptionSelectStyleDisplayOptionsFormCiteView"];
|
|
$showRowsLabel = $loc["ShowRecordsPerPage_SuffixCiteView"];
|
|
$showRowsTitle = $loc["DescriptionShowRecordsPerPage"];
|
|
}
|
|
elseif ($displayType == "Display")
|
|
{
|
|
$submitValue = $loc["ButtonTitle_Show"];
|
|
$submitTitle = $loc["DescriptionShowButtonDisplayOptionsFormDetailsView"];
|
|
$selectorDivID = "optShowHideField";
|
|
$selectorID = "displayOptionsSelector";
|
|
$selectorLabel = $loc["Field"] . ":";
|
|
$selectorTitle = $loc["DescriptionSelectFieldDisplayOptionsFormDetailsView"];
|
|
$showRowsLabel = $loc["ShowRecordsPerPage_Suffix"];
|
|
$showRowsTitle = $loc["DescriptionShowRecordsPerPage"];
|
|
}
|
|
else
|
|
{
|
|
$submitValue = $loc["ButtonTitle_Show"];
|
|
$submitTitle = $loc["DescriptionShowButtonDisplayOptionsForm"];
|
|
$selectorDivID = "optShowHideField";
|
|
$selectorID = "displayOptionsSelector";
|
|
$selectorLabel = $loc["Field"] . ":";
|
|
$selectorTitle = $loc["DescriptionSelectFieldDisplayOptionsForm"];
|
|
$showRowsLabel = $loc["ShowRecordsPerPage_Suffix"];
|
|
$showRowsTitle = $loc["DescriptionShowRecordsPerPage"];
|
|
}
|
|
|
|
if (($displayType != "Cite") AND ($fieldsToDisplay < 2))
|
|
{
|
|
$hideButtonDisabled = " disabled"; // disable the 'Hide' button if there's currently only one field being displayed (except the links column)
|
|
$hideButtonTitle = "(" . $loc["DescriptionHideButtonDisplayOptionsFormOnlyOneField"] . ")";
|
|
}
|
|
else
|
|
{
|
|
$hideButtonDisabled = "";
|
|
|
|
if ($displayType == "Display")
|
|
$hideButtonTitle = $loc["DescriptionHideButtonDisplayOptionsFormDetailsView"];
|
|
else
|
|
$hideButtonTitle = $loc["DescriptionHideButtonDisplayOptionsForm"];
|
|
}
|
|
|
|
if (($displayType == "Cite") AND (!isset($_SESSION['user_styles'])))
|
|
$citeStyleDisabled = " disabled"; // for Citation view, disable the style popup if the session variable holding the user's styles isn't available
|
|
else
|
|
$citeStyleDisabled = "";
|
|
|
|
$encodedCiteStyle = rawurlencode($citeStyle);
|
|
$encodedClient = rawurlencode($client);
|
|
$encodedHeaderMsg = rawurlencode($headerMsg);
|
|
|
|
$accessKeyAttribute = addAccessKey("attribute", "max_rows");
|
|
$accessKeyTitle = addAccessKey("title", "max_rows");
|
|
|
|
// NOTE: we embed the current value of '$rowOffset' as hidden tag within the 'displayOptions' form. By this, the current row offset can be re-applied after the user pressed the 'Show'/'Hide' button within the 'displayOptions' form.
|
|
// To avoid that browse links don't behave as expected, the actual value of '$rowOffset' will be adjusted in function 'seekInMySQLResultsToOffset()' to an exact multiple of '$showRows'!
|
|
$displayOptionsForm = <<<EOF
|
|
<form action="$href" method="GET" name="displayOptions">
|
|
<fieldset>
|
|
<legend>$loc[DisplayOptions]:</legend>
|
|
<input type="hidden" name="formType" value="displayOptions">
|
|
<input type="hidden" name="submit" value="$submitValue">
|
|
<input type="hidden" name="originalDisplayType" value="$displayType">
|
|
<input type="hidden" name="sqlQuery" value="$queryURL">
|
|
<input type="hidden" name="showQuery" value="$showQuery">
|
|
<input type="hidden" name="showLinks" value="$showLinks">
|
|
<input type="hidden" name="rowOffset" value="$rowOffset">
|
|
<input type="hidden" name="showRows" value="$showRows">
|
|
<input type="hidden" name="client" value="$encodedClient">
|
|
<input type="hidden" name="citeStyle" value="$encodedCiteStyle">
|
|
<input type="hidden" name="citeOrder" value="$citeOrder">
|
|
<input type="hidden" name="headerMsg" value="$encodedHeaderMsg">
|
|
<div id="optMain">
|
|
<div id="$selectorDivID">
|
|
<label for="$selectorID">$selectorLabel</label>
|
|
<select id="$selectorID" name="$selectorID" title="$selectorTitle"$citeStyleDisabled>
|
|
EOF;
|
|
|
|
// build correct option tags from the column items provided:
|
|
$optionTags = buildSelectMenuOptions($dropDownFieldsArray, "//", "\t\t\t\t\t\t\t", true);
|
|
|
|
$optionTags = preg_replace("/<option([^>]* value=\"$dropDownFieldSelected\")/", "<option\\1 selected", $optionTags); // add 'selected' attribute
|
|
|
|
$displayOptionsForm .= $optionTags;
|
|
|
|
$displayOptionsForm .= <<<EOF
|
|
|
|
</select>
|
|
</div>
|
|
EOF;
|
|
|
|
$displayOptionsForm .= <<<EOF
|
|
|
|
<div id="optSubmit">
|
|
<input type="submit" name="submit" value="$submitValue" title="$submitTitle">
|
|
EOF;
|
|
|
|
if (!preg_match("/^(Browse|Cite)$/i", $displayType))
|
|
$displayOptionsForm .= "\n\t\t\t\t\t\t<input type=\"submit\" name=\"submit\" value=\"" . $loc["ButtonTitle_Hide"] . "\" title=\"$hideButtonTitle\"$hideButtonDisabled>";
|
|
|
|
$displayOptionsForm .= <<<EOF
|
|
|
|
</div>
|
|
</div>
|
|
<div id="optOther">
|
|
EOF;
|
|
|
|
if ($displayType == "Cite")
|
|
{
|
|
$displayOptionsForm .= <<<EOF
|
|
|
|
<div id="optCiteOrder">
|
|
<label for="citeOrder">$loc[SortBy]:</label>
|
|
<select id="citeOrder" name="citeOrder" title="$loc[DescriptionSelectOrderDisplayOptionsFormCiteView]">
|
|
EOF;
|
|
|
|
// build correct option tags for the "Sort by" ('citeOrder') dropdown menu (and select the currently chosen option):
|
|
$citeOrderItemsArray = array("author" => $loc["DropDownFieldName_Author"],
|
|
"year" => $loc["DropDownFieldName_Year"],
|
|
"type" => $loc["DropDownFieldName_Type"],
|
|
"type-year" => $loc["DropDownFieldName_TypeYear"],
|
|
"creation-date" => $loc["DropDownFieldName_CreationDate"]);
|
|
|
|
$citeOrderOptionTags = buildSelectMenuOptions($citeOrderItemsArray, "//", "\t\t\t\t\t\t\t", true);
|
|
|
|
if (isset($citeOrderItemsArray[$citeOrder]))
|
|
$citeOrderOptionTags = preg_replace("/<option([^>]*)>(" . $citeOrderItemsArray[$citeOrder] . ")<\\/option>/", "<option\\1 selected>\\2</option>", $citeOrderOptionTags); // add 'selected' attribute to the currently chosen 'citeOrder' option
|
|
else // add & select a "(custom order)" option (which indicates that the current sort order matches none of the above 'citeOrder' options):
|
|
$citeOrderOptionTags = "\n\t\t\t\t\t\t\t<option value=\"\" selected>(" . $loc["DropDownFieldName_Custom"] . ")</option>" . $citeOrderOptionTags;
|
|
|
|
$displayOptionsForm .= $citeOrderOptionTags;
|
|
|
|
$displayOptionsForm .= <<<EOF
|
|
|
|
</select>
|
|
</div>
|
|
EOF;
|
|
}
|
|
|
|
$displayOptionsForm .= <<<EOF
|
|
|
|
<div id="optRecsPerPage">
|
|
<input type="text" id="showRows" name="showRows" value="$showRows" size="4"$accessKeyAttribute title="$showRowsTitle$accessKeyTitle">
|
|
<label for="showRows">$showRowsLabel</label>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</form>
|
|
|
|
EOF;
|
|
|
|
return $displayOptionsForm;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// BUILD SUGGEST ELEMENTS
|
|
// (i.e., provide HTML elements that will generate auto-completions or search suggestions for text entered by the user in text entry fields)
|
|
// requires the Prototype & script.aculo.us JavaScript frameworks: <http://www.prototypejs.org/> and <http://script.aculo.us/>
|
|
// more info about 'Ajax.Autocompleter': <http://github.com/madrobby/scriptaculous/wikis/ajax-autocompleter>
|
|
//
|
|
// NOTE: I don't know how to pass custom values (such as the CQL index) to the callback function. Therefore, I'm using a dirty hack here where I add
|
|
// '$CQLIndex' (i.e. an "id-" prefix plus the ID of the HTML form element that contains the selected field) at the beginning of the query parameter
|
|
// ('paramName'). This ID is required by the callback function to fetch the name of the currently selected refbase field.
|
|
function buildSuggestElements($searchFieldID, $searchSuggestionsID, $suggestProgressID, $CQLIndex, $prefix = "\t\t", $tokens = "''", $frequency = 0.8, $minChars = 2, $callBack = "addCQLIndex", $suggestURL = "opensearch.php", $paramName = "query", $parameters = "operation=suggest&recordSchema=html")
|
|
{
|
|
global $contentTypeCharset; // defined in 'ini.inc.php'
|
|
|
|
$suggestElements = <<<EOF
|
|
|
|
$prefix<span id="$suggestProgressID" class="suggestProgress" style="display:none;">...</span>
|
|
$prefix<div id="$searchSuggestionsID" class="searchSuggestions" style="display:none;"></div>
|
|
$prefix<script language="JavaScript" type="text/javascript" charset="$contentTypeCharset">
|
|
$prefix// <![CDATA[
|
|
$prefix new Ajax.Autocompleter('$searchFieldID','$searchSuggestionsID','$suggestURL',{tokens:$tokens,frequency:$frequency,minChars:$minChars,indicator:'$suggestProgressID',paramName:'$CQLIndex$paramName',parameters:'$parameters',callback:$callBack});
|
|
$prefix// ]]>
|
|
$prefix</script>
|
|
EOF;
|
|
|
|
return $suggestElements;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Build the database query from user input provided by the "Search within Results" or "Display Options" forms
|
|
// above the query results list (which, in turn, was returned by 'search.php' or 'users.php', respectively):
|
|
// TODO: - build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
|
|
function extractFormElementsRefineDisplay($queryTable, $displayType, $originalDisplayType, $query, $showLinks, $citeOrder, $userID)
|
|
{
|
|
global $tableRefs, $tableUserData, $tableUsers; // defined in 'db.inc.php'
|
|
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
$encodedDisplayType = encodeHTML($displayType); // note that we need to HTML encode '$displayType' for comparison with the HTML encoded locales
|
|
|
|
// extract form variables:
|
|
if ($encodedDisplayType == $loc["ButtonTitle_Search"]) // the user clicked the 'Search' button of the "Search within Results" form
|
|
{
|
|
$fieldSelector = $_REQUEST['refineSearchSelector']; // extract field name chosen by the user
|
|
$refineSearchName = $_REQUEST['refineSearchName']; // extract search text entered by the user
|
|
|
|
if (isset($_REQUEST['refineSearchExclude'])) // extract user option whether matched records should be included or excluded
|
|
$refineSearchActionCheckbox = $_REQUEST['refineSearchExclude']; // the user marked the checkbox next to "Exclude matches"
|
|
else
|
|
$refineSearchActionCheckbox = "0"; // the user did NOT mark the checkbox next to "Exclude matches"
|
|
}
|
|
|
|
elseif (preg_match("/^(" . $loc["ButtonTitle_Show"] . "|" . $loc["ButtonTitle_Hide"] . "|" . $loc["ButtonTitle_Browse"] . ")$/", $encodedDisplayType)) // the user clicked either the 'Browse' or 'Show'/'Hide' buttons of the "Display Options" form
|
|
// (hitting <enter> within the 'ShowRows' text entry field of the "Display Options" form will act as if the user clicked the 'Browse'/'Show' button)
|
|
{
|
|
if (isset($_REQUEST['displayOptionsSelector']))
|
|
$fieldSelector = $_REQUEST['displayOptionsSelector']; // extract field name chosen by the user
|
|
else
|
|
$fieldSelector = "";
|
|
}
|
|
else
|
|
$fieldSelector = ""; // this avoids 'Undefined variable...' messages when a user has changed the language setting on the options page, and then reloads an existing page (whose URL still has a 'submit' value in the previously used language)
|
|
|
|
// extract the fields of the SELECT clause from the current SQL query:
|
|
$previousSelectClause = extractSELECTclause($query);
|
|
|
|
// ensure to add any required fields to the SELECT clause:
|
|
if ($queryTable == $tableRefs) // 'search.php':
|
|
$addRequiredFields = true;
|
|
elseif ($queryTable == $tableUsers) // 'users.php':
|
|
$addRequiredFields = false; // we'll add any required fields to the 'users.php' SELECT clause below
|
|
// TODO: this wouldn't be necessary if function 'buildSELECTclause()' would handle the requirements of 'users.php'
|
|
|
|
$additionalFields = "";
|
|
|
|
if ($encodedDisplayType == $loc["ButtonTitle_Search"])
|
|
{
|
|
// rebuild the current SELECT clause:
|
|
$newSelectClause = buildSELECTclause($originalDisplayType, $showLinks, $additionalFields, false, $addRequiredFields, $previousSelectClause);
|
|
|
|
// replace current SELECT clause:
|
|
$query = newSELECTclause($newSelectClause, $query, false);
|
|
|
|
if ($refineSearchName != "") // if the user typed a search string into the text entry field...
|
|
{
|
|
// Depending on the chosen output action, construct an appropriate SQL query:
|
|
if ($refineSearchActionCheckbox == "0") // if the user did NOT mark the checkbox next to "Exclude matches"
|
|
{
|
|
// for the fields 'marked=no', 'copy=false' and 'selected=no', force NULL values to be matched:
|
|
if (($fieldSelector == "marked" AND $refineSearchName == "no") OR ($fieldSelector == "copy" AND $refineSearchName == "false") OR ($fieldSelector == "selected" AND $refineSearchName == "no"))
|
|
$query = preg_replace("/ WHERE /i", " WHERE ($fieldSelector RLIKE " . quote_smart($refineSearchName) . " OR $fieldSelector IS NULL) AND ", $query); // ...add search field name & value to the SQL query
|
|
else // add default 'WHERE' clause:
|
|
$query = preg_replace("/ WHERE /i", " WHERE $fieldSelector RLIKE " . quote_smart($refineSearchName) . " AND ", $query); // ...add search field name & value to the SQL query
|
|
}
|
|
else // $refineSearchActionCheckbox == "1" // if the user marked the checkbox next to "Exclude matches"
|
|
{
|
|
$query = preg_replace("/ WHERE /i", " WHERE ($fieldSelector NOT RLIKE " . quote_smart($refineSearchName) . " OR $fieldSelector IS NULL) AND ", $query); // ...add search field name & value to the SQL query
|
|
}
|
|
|
|
$query = preg_replace('/ AND serial RLIKE "\.\+"/i', '', $query); // remove any 'AND serial RLIKE ".+"' which isn't required anymore
|
|
}
|
|
// else, if the user did NOT type a search string into the text entry field, we simply keep the old WHERE clause...
|
|
}
|
|
|
|
|
|
elseif (preg_match("/^(" . $loc["ButtonTitle_Show"] . "|" . $loc["ButtonTitle_Hide"] . ")$/", $encodedDisplayType)) // the user clicked the 'Show'/'Hide' buttons of the "Display Options" form
|
|
{
|
|
if (preg_match("/^Cite$/i", $originalDisplayType)) // in case of Citation view, we regenerate the SELECT clause from scratch:
|
|
{
|
|
// generate a SELECT clause that's appropriate for Citation view (or Details view):
|
|
$newSelectClause = buildSELECTclause($originalDisplayType, $showLinks, $additionalFields, false, $addRequiredFields);
|
|
|
|
// rebuild the current ORDER clause:
|
|
if (preg_match("/^(author|year|type|type-year|creation-date)$/i", $citeOrder))
|
|
{
|
|
if ($citeOrder == "year") // sort records first by year (descending):
|
|
$newORDER = "ORDER BY year DESC, first_author, author_count, author, title";
|
|
|
|
elseif ($citeOrder == "type") // sort records first by record type and thesis type (descending):
|
|
$newORDER = "ORDER BY type DESC, thesis DESC, first_author, author_count, author, year, title";
|
|
|
|
elseif ($citeOrder == "type-year") // sort records first by record type and thesis type (descending), then by year (descending):
|
|
$newORDER = "ORDER BY type DESC, thesis DESC, year DESC, first_author, author_count, author, title";
|
|
|
|
elseif ($citeOrder == "creation-date") // sort records such that newly added/edited records get listed top of the list:
|
|
$newORDER = "ORDER BY created_date DESC, created_time DESC, modified_date DESC, modified_time DESC, serial DESC";
|
|
|
|
elseif ($citeOrder == "author") // supply the default ORDER BY pattern (which is suitable for citation in a journal etc.):
|
|
$newORDER = "ORDER BY first_author, author_count, author, year, title";
|
|
|
|
// replace current ORDER clause:
|
|
$query = newORDERclause($newORDER, $query, false);
|
|
}
|
|
// else if any other or no '$citeOrder' parameter is specified, we keep the current ORDER BY clause
|
|
// NOTE: this behaviour is different from functions 'extractFormElementsQueryResults()' and 'extractFormElementsExtract()'
|
|
// where we always use 'ORDER BY first_author, author_count, author, year, title' as default ORDER BY clause
|
|
// (to ensure correct sorting for output to bibliographic reference lists)
|
|
}
|
|
|
|
elseif (preg_match("/^Display$/i", $originalDisplayType)) // Details view
|
|
{
|
|
// NOTE: the below code for displaying & hiding of fields in Details view must be adopted if either layout or field names are changed!
|
|
|
|
$fieldsList = "";
|
|
|
|
if ($fieldSelector == "all fields")
|
|
{
|
|
// generate a SELECT clause that shows all fields in Details view:
|
|
$newSelectClause = buildSELECTclause($originalDisplayType, $showLinks, $additionalFields, true, $addRequiredFields);
|
|
}
|
|
else // add (or remove) the chosen fields from the SELECT clause:
|
|
{
|
|
if ($encodedDisplayType == $loc["ButtonTitle_Show"]) // if the user clicked the 'Show' button, add the chosen fields to the SELECT clause:
|
|
{
|
|
$matchField = "pages";
|
|
|
|
if ($fieldSelector == "keywords, abstract")
|
|
{
|
|
$fieldsList = ", keywords, abstract";
|
|
}
|
|
elseif ($fieldSelector == "additional fields")
|
|
{
|
|
$fieldsList = ", address, corporate_author, thesis, publisher, place, editor, language, summary_language, orig_title, series_editor, series_title, abbrev_series_title, series_volume, series_issue, edition, issn, isbn, medium, area, expedition, conference, notes, approved";
|
|
|
|
if (isset($_SESSION['loginEmail']))
|
|
$fieldsList .= ", location"; // we only add the 'location' field if the user is logged in
|
|
|
|
if (preg_match("/\babstract\b/i", $previousSelectClause))
|
|
$matchField = "abstract";
|
|
}
|
|
elseif ($fieldSelector == "my fields")
|
|
{
|
|
$fieldsList = ", marked, copy, selected, user_keys, user_notes, user_file, user_groups, cite_key";
|
|
|
|
if (preg_match("/\bserial\b/i", $previousSelectClause))
|
|
$matchField = "serial";
|
|
elseif (preg_match("/\babstract\b/i", $previousSelectClause))
|
|
$matchField = "abstract";
|
|
}
|
|
|
|
if ((!empty($fieldsList)) AND (!preg_match("/\b" . $fieldsList . "\b/i", $previousSelectClause))) // if none of the chosen fields are currently displayed...
|
|
$previousSelectClause = preg_replace("/(?<=\b" . $matchField . "\b)/i", $fieldsList, $previousSelectClause); // ...add the chosen fields to the current SELECT clause:
|
|
}
|
|
if ($encodedDisplayType == $loc["ButtonTitle_Hide"]) // if the user clicked the 'Hide' button, remove the chosen fields from the SELECT clause:
|
|
{
|
|
if ($fieldSelector == "keywords, abstract")
|
|
$fieldsList = "\b(keywords|abstract)\b";
|
|
elseif ($fieldSelector == "additional fields")
|
|
$fieldsList = "\b(corporate_author|thesis|address|publisher|place|editor|language|summary_language|orig_title|series_editor|series_title|abbrev_series_title|series_volume|series_issue|edition|issn|isbn|medium|area|expedition|conference|notes|approved|location)\b";
|
|
elseif ($fieldSelector == "my fields")
|
|
$fieldsList = "\b(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key)\b";
|
|
|
|
if ((!empty($fieldsList)) AND (preg_match("/\b" . $fieldsList . "\b/i", $previousSelectClause))) // ...and any of the chosen fields *are* currently displayed...
|
|
{
|
|
// ...remove the chosen fields from the fields given in the current SELECT clause:
|
|
$previousSelectClause = preg_replace("/ *, *" . $fieldsList . " */i", "", $previousSelectClause); // all columns except the first
|
|
|
|
$previousSelectClause = preg_replace("/ *" . $fieldsList . " *, */i", "", $previousSelectClause); // all columns except the last
|
|
}
|
|
}
|
|
|
|
// rebuild the current SELECT clause, but include (or exclude) the chosen fields:
|
|
$newSelectClause = buildSELECTclause($originalDisplayType, $showLinks, $additionalFields, false, $addRequiredFields, $previousSelectClause);
|
|
}
|
|
}
|
|
|
|
else // otherwise, i.e. for List view, add (or remove) the chosen field from the SELECT clause:
|
|
{
|
|
if ($encodedDisplayType == $loc["ButtonTitle_Show"]) // if the user clicked the 'Show' button...
|
|
{
|
|
if (!preg_match("/\b" . $fieldSelector . "\b/i", $previousSelectClause)) // ...and the chosen field is *not* already displayed...
|
|
$additionalFields = $fieldSelector; // ...add the chosen field to the current SELECT clause
|
|
}
|
|
elseif ($encodedDisplayType == $loc["ButtonTitle_Hide"]) // if the user clicked the 'Hide' button...
|
|
{
|
|
if (preg_match("/\b" . $fieldSelector . "\b/i", $previousSelectClause)) // ...and the chosen field *is* currently displayed...
|
|
{
|
|
// ...remove the chosen field from the fields given in the current SELECT clause:
|
|
$previousSelectClause = preg_replace("/ *, *\b" . $fieldSelector . "\b */i", "", $previousSelectClause); // all columns except the first
|
|
$previousSelectClause = preg_replace("/ *\b" . $fieldSelector . "\b *, */i", "", $previousSelectClause); // all columns except the last
|
|
}
|
|
}
|
|
|
|
// rebuild the current SELECT clause, but include (or exclude) the chosen field:
|
|
$newSelectClause = buildSELECTclause("", $showLinks, $additionalFields, false, $addRequiredFields, $previousSelectClause);
|
|
}
|
|
|
|
// replace current SELECT clause:
|
|
$query = newSELECTclause($newSelectClause, $query, false);
|
|
}
|
|
|
|
|
|
// TODO: don't manipulate the SQL query in '$query' directly, but instead use functions 'extractSELECTclause()' and 'buildSELECTclause()' (similar as above)
|
|
elseif ($encodedDisplayType == $loc["ButtonTitle_Browse"]) // if the user clicked the 'Browse' button within the "Display Options" form...
|
|
{
|
|
$previousField = preg_replace("/^SELECT (\w+).+/i", "\\1", $query); // extract the field that was previously used in Browse view
|
|
|
|
if (!preg_match("/^" . $fieldSelector . "$/i", $previousField)) // if the user did choose another field in Browse view...
|
|
{
|
|
// ...modify the SQL query to show a summary for the new field that was chosen by the user:
|
|
// (NOTE: these replace patterns aren't 100% safe and may fail if the user has modified the query using 'sql_search.php'!)
|
|
$query = preg_replace("/^SELECT $previousField/i", "SELECT $fieldSelector", $query); // use the field that was chosen by the user for Browse view
|
|
$query = preg_replace("/GROUP BY $previousField/i", "GROUP BY $fieldSelector", $query); // group data by the field that was chosen by the user
|
|
$query = preg_replace("/ORDER BY( records( DESC)?,)? $previousField/i", "ORDER BY\\1 $fieldSelector", $query); // order data by the field that was chosen by the user
|
|
}
|
|
}
|
|
|
|
|
|
// re-establish the original display type:
|
|
// (resetting '$displayType' to its original value is required for Browse view; for List view, it does also correct incorrect
|
|
// display types such as 'Search' or 'Show'/'Hide' which stem from the submit buttons in the forms of the results header)
|
|
$displayType = $originalDisplayType;
|
|
|
|
|
|
// the following changes to the SQL query are performed for both forms ("Search within Results" and "Display Options"):
|
|
if ($queryTable == $tableRefs) // 'search.php':
|
|
{
|
|
// if the chosen field is one of the user-specific fields from table 'user_data': 'marked', 'copy', 'selected', 'user_keys', 'user_notes', 'user_file', 'user_groups', 'cite_key' or 'related'
|
|
if (preg_match("/^(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related|my fields)$/i", $fieldSelector)) // 'my fields' is used in Details view as an alias for all user-specific fields
|
|
if (!preg_match("/LEFT JOIN $tableUserData/i", $query)) // ...and if the 'LEFT JOIN...' statement isn't already part of the 'FROM' clause...
|
|
$query = preg_replace("/ FROM $tableRefs/i", " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = $userID", $query); // ...add the 'LEFT JOIN...' part to the 'FROM' clause
|
|
}
|
|
elseif ($queryTable == $tableUsers) // 'users.php':
|
|
{
|
|
// TODO: this wouldn't be necessary if function 'buildSELECTclause()' would handle the requirements of 'users.php' (see also above)
|
|
$query = preg_replace("/ FROM $tableUsers/i", ", user_id FROM $tableUsers", $query); // add 'user_id' column (although it won't be visible the 'user_id' column gets included in every search query)
|
|
// (which is required in order to obtain unique checkbox names as well as for use in the 'getUserID()' function)
|
|
}
|
|
|
|
return array($query, $displayType);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// SPLIT AND MERGE AGAIN
|
|
// This function takes a string and splits it on '$splitDelim' into an array,
|
|
// then re-joins the pieces inserting '$joinDelim' as separator).
|
|
// Note: The split pattern must be specified as perl-style regular expression
|
|
// (including the leading & trailing slashes) and may include mode
|
|
// modifiers (such as '/.../i' to perform a case insensitive match)
|
|
function splitAndMerge($splitDelim, $joinDelim, $sourceString)
|
|
{
|
|
// split the string on the specified delimiter (which is interpreted as perl-style regular expression!):
|
|
$piecesArray = preg_split($splitDelim, $sourceString);
|
|
|
|
// re-join the array with the specified separator:
|
|
$newString = implode($joinDelim, $piecesArray);
|
|
|
|
return $newString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// EXTRACT PARTS FROM STRING
|
|
// This function takes a '$sourceString', splits it on '$splitDelim' and returns
|
|
// x parts from the beginning (if x > 0) or the end (if x < 0) of the string
|
|
// (x must be given in '$returnParts'); parts will be returned as a merged string
|
|
// using '$joinDelim' as delimiter.
|
|
// Note: The split pattern must be specified as perl-style regular expression
|
|
// (including the leading & trailing slashes) and may include mode
|
|
// modifiers (such as '/.../i' to perform a case insensitive match)
|
|
function extractPartsFromString($sourceString, $splitDelim, $joinDelim, $returnParts)
|
|
{
|
|
// split the string on the specified delimiter (which is interpreted as perl-style regular expression!):
|
|
$piecesArray = preg_split($splitDelim, $sourceString);
|
|
|
|
if ($returnParts > 0)
|
|
$spliceFromElementNo = 0; // splice from beginning of array
|
|
else // ($returnParts < 0)
|
|
{
|
|
$spliceFromElementNo = $returnParts; // splice from end of array
|
|
$returnParts = abs($returnParts);
|
|
}
|
|
|
|
// extracts parts from array:
|
|
$extractedPiecesArray = array_splice($piecesArray, $spliceFromElementNo, $returnParts); // 'array_splice()' returns array with extracted elements
|
|
|
|
// re-join the array with the specified separator:
|
|
$newString = implode($joinDelim, $extractedPiecesArray);
|
|
|
|
return $newString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// RE-ARRANGE AUTHOR FIELD CONTENTS
|
|
// (this function separates contents of the author field into their functional parts, i.e.:
|
|
// {
|
|
// {author_name}, {author_initial(s)}
|
|
// }
|
|
// {
|
|
// {author_name}, {author_initial(s)}
|
|
// }
|
|
// {
|
|
// ...
|
|
// }
|
|
// then, these functional pieces will be joined again according to the separators specified)
|
|
// Note: this function assumes that:
|
|
// - within one author object, there's only *one* delimiter separating author name & initials!
|
|
// Note: The split pattern must be specified as perl-style regular expression
|
|
// (including the leading & trailing slashes) and may include mode
|
|
// modifiers (such as '/.../i' to perform a case insensitive match)
|
|
function reArrangeAuthorContents($authorContents, $familyNameFirst, $oldBetweenAuthorsDelim, $newBetweenAuthorsDelimStandard, $newBetweenAuthorsDelimLastAuthor, $oldAuthorsInitialsDelim, $newAuthorsInitialsDelimFirstAuthor, $newAuthorsInitialsDelimStandard, $betweenInitialsDelim, $initialsBeforeAuthorFirstAuthor, $initialsBeforeAuthorStandard, $shortenGivenNames, $numberOfAuthorsTriggeringEtAl, $includeNumberOfAuthors, $customStringAfterFirstAuthors, $encodeHTML)
|
|
{
|
|
global $alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower, $print, $punct, $space, $upper, $word, $patternModifiers; // defined in 'transtab_unicode_charset.inc.php' and 'transtab_latin1_charset.inc.php'
|
|
|
|
$authorsArray = preg_split($oldBetweenAuthorsDelim, $authorContents); // get a list of all authors for this record
|
|
|
|
$authorCount = count($authorsArray); // check how many authors we have to deal with
|
|
$newAuthorContents = ""; // this variable will hold the final author string
|
|
$includeStringAfterFirstAuthor = false;
|
|
|
|
if (empty($numberOfAuthorsTriggeringEtAl))
|
|
$numberOfAuthorsTriggeringEtAl = $authorCount;
|
|
|
|
if (empty($includeNumberOfAuthors))
|
|
$includeNumberOfAuthors = $authorCount;
|
|
|
|
for ($i=0; $i < $authorCount; $i++)
|
|
{
|
|
$singleAuthorArray = preg_split($oldAuthorsInitialsDelim, $authorsArray[$i]); // for each author, extract author name & initials to separate list items
|
|
|
|
if (!$familyNameFirst) // if the family name comes *after* the given name (or initials) in the source string, put array elements in reverse order:
|
|
$singleAuthorArray = array_reverse($singleAuthorArray); // (Note: this only works, if the array has only *two* elements, i.e., one containing the author's name and one holding the initials!)
|
|
|
|
if (isset($singleAuthorArray[1]))
|
|
{
|
|
if ($shortenGivenNames) // if we're supposed to abbreviate given names
|
|
{
|
|
// within initials, reduce all full first names (-> defined by a starting uppercase character, followed by one ore more lowercase characters)
|
|
// to initials, i.e., only retain their first character
|
|
$singleAuthorArray[1] = preg_replace("/([$upper])[$lower]+/$patternModifiers", "\\1", $singleAuthorArray[1]);
|
|
}
|
|
|
|
// within initials, remove any dots:
|
|
$singleAuthorArray[1] = preg_replace("/([$upper])\.+/$patternModifiers", "\\1", $singleAuthorArray[1]);
|
|
|
|
// within initials, remove any spaces *between* initials:
|
|
$singleAuthorArray[1] = preg_replace("/(?<=[-$upper]) +(?=[-$upper])/$patternModifiers", "", $singleAuthorArray[1]);
|
|
|
|
// within initials, add a space after a hyphen, but only if ...
|
|
if (preg_match("/ $/", $betweenInitialsDelim)) // ... the delimiter that separates initials ends with a space
|
|
$singleAuthorArray[1] = preg_replace("/-(?=[$upper])/$patternModifiers", "- ", $singleAuthorArray[1]);
|
|
|
|
// then, separate initials with the specified delimiter:
|
|
$singleAuthorArray[1] = preg_replace("/([$upper])(?=[^$lower]+|$)/$patternModifiers", "\\1$betweenInitialsDelim", $singleAuthorArray[1]);
|
|
}
|
|
|
|
|
|
if ((($i == 0) AND $initialsBeforeAuthorFirstAuthor) OR (($i > 0) AND $initialsBeforeAuthorStandard)) // put array elements in reverse order:
|
|
$singleAuthorArray = array_reverse($singleAuthorArray); // (Note: this only works, if the array has only *two* elements, i.e., one containing the author's name and one holding the initials!)
|
|
|
|
// re-join author name & initials, using the specified delimiter, and copy the string to the end of an array:
|
|
if ($i == 0) // -> first author
|
|
$singleAuthorString = implode($newAuthorsInitialsDelimFirstAuthor, $singleAuthorArray);
|
|
else // $i > 0 // -> all authors except the first one
|
|
$singleAuthorString = implode($newAuthorsInitialsDelimStandard, $singleAuthorArray);
|
|
|
|
// append this author to the final author string:
|
|
if (($i == 0) OR ($i + 1) < $authorCount) // -> first author, or (for multiple authors) all authors except the last one
|
|
{
|
|
if ($i == 0) // -> first author
|
|
$newAuthorContents .= $singleAuthorString;
|
|
else // -> for multiple authors, all authors except the first or the last one
|
|
$newAuthorContents .= $newBetweenAuthorsDelimStandard . $singleAuthorString;
|
|
|
|
// we'll append the string in '$customStringAfterFirstAuthors' to the number of authors given in '$includeNumberOfAuthors' if the total number of authors is greater than the number given in '$numberOfAuthorsTriggeringEtAl':
|
|
if ((($i + 1) == $includeNumberOfAuthors) AND ($authorCount > $numberOfAuthorsTriggeringEtAl))
|
|
{
|
|
if (preg_match("/__NUMBER_OF_AUTHORS__/", $customStringAfterFirstAuthors))
|
|
$customStringAfterFirstAuthors = preg_replace("/__NUMBER_OF_AUTHORS__/", ($authorCount - $includeNumberOfAuthors), $customStringAfterFirstAuthors); // resolve placeholder
|
|
|
|
$includeStringAfterFirstAuthor = true;
|
|
break;
|
|
}
|
|
}
|
|
elseif (($authorCount > 1) AND (($i + 1) == $authorCount)) // -> last author (if multiple authors)
|
|
{
|
|
$newAuthorContents .= $newBetweenAuthorsDelimLastAuthor . $singleAuthorString;
|
|
}
|
|
}
|
|
|
|
// do some final clean up:
|
|
if ($encodeHTML)
|
|
$newAuthorContents = encodeHTML($newAuthorContents); // HTML encode higher ASCII characters within the newly arranged author contents
|
|
|
|
if ($includeStringAfterFirstAuthor)
|
|
$newAuthorContents .= $customStringAfterFirstAuthors; // the custom string won't get HTML encoded so that it's possible to include HTML tags (such as '<i>') within the string
|
|
|
|
$newAuthorContents = preg_replace("/ +/", " ", $newAuthorContents); // remove double spaces (which occur e.g., when both, $betweenInitialsDelim & $newAuthorsInitialsDelim..., end with a space)
|
|
$newAuthorContents = preg_replace("/ +([,.;:?!()]|$)/", "\\1", $newAuthorContents); // remove excess spaces before [,.;:?!()] and from the end of the author string
|
|
|
|
return $newAuthorContents;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// EXTRACT AUTHOR'S LAST NAME
|
|
// This function takes the contents of the author field and will extract the
|
|
// last name of a particular author (specified by position) (e.g., setting
|
|
// '$authorPosition' to "1" will return the 1st author's last name).
|
|
// Note: this function assumes that:
|
|
// 1. within one author object, there's only *one* delimiter separating
|
|
// author name & initials!
|
|
// 2. author objects are stored in the db as
|
|
// "<author_name><author_initials_delimiter><author_initials>", i.e.,
|
|
// initials follow *after* the author's name!
|
|
// Required Parameters:
|
|
// 1. pattern describing delimiter that separates different authors
|
|
// 2. pattern describing delimiter that separates author name & initials
|
|
// (within one author)
|
|
// 3. position of the author whose last name shall be extracted (e.g.,
|
|
// "1" will return the 1st author's last name)
|
|
// 4. contents of the author field
|
|
// Note: The split patterns must be specified as perl-style regular expressions
|
|
// (including the leading & trailing slashes) and may include mode
|
|
// modifiers (such as '/.../i' to perform a case insensitive match)
|
|
function extractAuthorsLastName($oldBetweenAuthorsDelim, $oldAuthorsInitialsDelim, $authorPosition, $authorContents)
|
|
{
|
|
$authorsArray = preg_split($oldBetweenAuthorsDelim, $authorContents); // get a list of all authors for this record
|
|
|
|
$authorPosition = ($authorPosition-1); // php array elements start with "0", so we decrease the authors position by 1
|
|
$singleAuthor = $authorsArray[$authorPosition]; // for the author in question, extract the full author name (last name & initials)
|
|
$singleAuthorArray = preg_split($oldAuthorsInitialsDelim, $singleAuthor); // then, extract author name & initials to separate list items
|
|
$singleAuthorsLastName = $singleAuthorArray[0]; // extract this author's last name into a new variable
|
|
|
|
return $singleAuthorsLastName;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// EXTRACT AUTHOR'S GIVEN NAME
|
|
// This function takes the contents of the author field and will extract the
|
|
// initials/given name of a particular author (specified by position) (e.g.,
|
|
// setting '$authorPosition' to "1" will return the 1st author's initials/given
|
|
// name).
|
|
// Required Parameters:
|
|
// 1. pattern describing delimiter that separates different authors
|
|
// 2. pattern describing delimiter that separates author name &
|
|
// initials/given name (within one author)
|
|
// 3. position of the author whose last name shall be extracted
|
|
// (e.g., "1" will return the 1st author's initials/given name)
|
|
// 4. contents of the author field
|
|
// Note: The split patterns must be specified as perl-style regular expressions
|
|
// (including the leading & trailing slashes) and may include mode
|
|
// modifiers (such as '/.../i' to perform a case insensitive match)
|
|
function extractAuthorsGivenName($oldBetweenAuthorsDelim, $oldAuthorsInitialsDelim, $authorPosition, $authorContents)
|
|
{
|
|
$authorsArray = preg_split($oldBetweenAuthorsDelim, $authorContents); // get a list of all authors for this record
|
|
|
|
$authorPosition = ($authorPosition-1); // php array elements start with "0", so we decrease the authors position by 1
|
|
$singleAuthor = $authorsArray[$authorPosition]; // for the author in question, extract the full author name (last name & initials/given name)
|
|
$singleAuthorArray = preg_split($oldAuthorsInitialsDelim, $singleAuthor); // then, extract author name & initials/given name to separate list items
|
|
if (!empty($singleAuthorArray[1]))
|
|
$singleAuthorsGivenName = $singleAuthorArray[1]; // extract this author's initials/given name into a new variable
|
|
else
|
|
$singleAuthorsGivenName = '';
|
|
|
|
return $singleAuthorsGivenName;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// PARSE PLACEHOLDER STRING
|
|
// this function will parse a given placeholder string into its indiviual placeholders and replaces
|
|
// them with content from the given record
|
|
function parsePlaceholderString($formVars, $placeholderString, $fallbackPlaceholderString)
|
|
{
|
|
global $alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower, $print, $punct, $space, $upper, $word, $patternModifiers; // defined in 'transtab_unicode_charset.inc.php' and 'transtab_latin1_charset.inc.php'
|
|
|
|
if (empty($placeholderString))
|
|
$placeholderString = $fallbackPlaceholderString; // if, for some odd reason, an empty placeholder string was given, we'll use the placeholder(s) given in '$fallbackPlaceholderString'
|
|
|
|
$placeholderPartsArray = preg_split("/[<>]/", $placeholderString); // split placeholder string into its individual components
|
|
|
|
$convertedPlaceholderArray = array(); // initialize array variable which will hold the transformed placeholder parts
|
|
|
|
foreach($placeholderPartsArray as $placeholderPart)
|
|
{
|
|
if (!empty($placeholderPart))
|
|
{
|
|
if (preg_match("/:\w+/", $placeholderPart)) // if the part contains a colon (":") followed by one or more word characters the part is assumed to be a placeholder (this will e.g. exclude "http://" strings)
|
|
{
|
|
// extract any custom options given within a placeholder:
|
|
if (preg_match("/:\w+\[[^][]+\]:/i", $placeholderPart)) // the placeholder contains custom options
|
|
$options = preg_replace("/.*:\w+(\[[^][]+\]):.*/i", "\\1", $placeholderPart);
|
|
else
|
|
$options = "";
|
|
|
|
// extract any prefix given within a placeholder:
|
|
if (preg_match("/^[^:]+:\w+(\[[^][]*\])?:/i", $placeholderPart)) // the placeholder contains a prefix
|
|
$prefix = preg_replace("/^([^:]+):\w+(\[[^][]*\])?:.*/i", "\\1", $placeholderPart);
|
|
else
|
|
$prefix = "";
|
|
|
|
// extract any suffix given within a placeholder:
|
|
if (preg_match("/:\w+(\[[^][]*\])?:[^:]+$/i", $placeholderPart)) // the placeholder contains a suffix
|
|
$suffix = preg_replace("/.*:\w+(?:\[[^][]*\])?:([^:]+)$/i", "\\1", $placeholderPart);
|
|
else
|
|
$suffix = "";
|
|
|
|
// call dedicated functions for the different placeholders (if required):
|
|
|
|
// '<:serial:>' placeholder:
|
|
if (preg_match("/:serial:/i", $placeholderPart))
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['serialNo'] . $suffix;
|
|
|
|
// '<:firstAuthor:>' placeholder:
|
|
elseif (preg_match("/:firstAuthor:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['authorName'])) // if the 'author' field isn't empty
|
|
{
|
|
$firstAuthor = $prefix;
|
|
// Call the 'extractAuthorsLastName()' function to extract the last name of a particular author (specified by position):
|
|
// (see function header for description of required parameters)
|
|
$firstAuthor .= extractAuthorsLastName("/ *; */",
|
|
"/ *, */",
|
|
1,
|
|
$formVars['authorName']);
|
|
$firstAuthor .= $suffix;
|
|
$convertedPlaceholderArray[] = $firstAuthor;
|
|
}
|
|
}
|
|
|
|
// '<:secondAuthor:>' placeholder:
|
|
elseif (preg_match("/:secondAuthor:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['authorName']) AND preg_match("/;/", $formVars['authorName'])) // if the 'author' field does contain at least one ';' => at least two authors
|
|
{
|
|
$secondAuthor = $prefix;
|
|
// Call the 'extractAuthorsLastName()' function to extract the last name of a particular author (specified by position):
|
|
// (see function header for description of required parameters)
|
|
$secondAuthor .= extractAuthorsLastName("/ *; */",
|
|
"/ *, */",
|
|
2,
|
|
$formVars['authorName']);
|
|
$secondAuthor .= $suffix;
|
|
$convertedPlaceholderArray[] = $secondAuthor;
|
|
}
|
|
}
|
|
|
|
// '<:authors:>' placeholder:
|
|
elseif (preg_match("/:authors(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['authorName'])) // if the 'author' field isn't empty
|
|
{
|
|
$authors = $prefix;
|
|
$authors .= extractDetailsFromAuthors($formVars['authorName'], $options);
|
|
$authors .= $suffix;
|
|
$convertedPlaceholderArray[] = $authors;
|
|
}
|
|
}
|
|
|
|
// '<:title:>' placeholder:
|
|
elseif (preg_match("/:title(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['titleName'])) // if the 'title' field isn't empty
|
|
{
|
|
$title = $prefix;
|
|
$title .= extractDetailsFromField("title", $formVars['titleName'], "/[^-$word]+/$patternModifiers", $options);
|
|
$title .= $suffix;
|
|
$convertedPlaceholderArray[] = $title;
|
|
}
|
|
}
|
|
|
|
// '<:year:>' placeholder:
|
|
elseif (preg_match("/:year(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['yearNo']) AND preg_match("/\d+/i", $formVars['yearNo'])) // if the 'year' field contains a number
|
|
{
|
|
$year = $prefix;
|
|
$year .= extractDetailsFromYear($formVars['yearNo'], $options);
|
|
$year .= $suffix;
|
|
$convertedPlaceholderArray[] = $year;
|
|
}
|
|
}
|
|
|
|
// '<:publication:>' placeholder:
|
|
elseif (preg_match("/:publication(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['publicationName'])) // if the 'publication' field isn't empty
|
|
{
|
|
$publication = $prefix;
|
|
$publication .= extractDetailsFromField("publication", $formVars['publicationName'], "/[^-$word]+/$patternModifiers", $options);
|
|
$publication .= $suffix;
|
|
$convertedPlaceholderArray[] = $publication;
|
|
}
|
|
}
|
|
|
|
// '<:abbrevJournal:>' placeholder:
|
|
elseif (preg_match("/:abbrevJournal(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['abbrevJournalName'])) // if the 'abbrev_journal' field isn't empty
|
|
{
|
|
$abbrevJournal = $prefix;
|
|
$abbrevJournal .= extractDetailsFromField("abbrev_journal", $formVars['abbrevJournalName'], "/[^-$word]+/$patternModifiers", $options);
|
|
$abbrevJournal .= $suffix;
|
|
$convertedPlaceholderArray[] = $abbrevJournal;
|
|
}
|
|
}
|
|
|
|
// '<:volume:>' placeholder:
|
|
elseif (preg_match("/:volume:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['volumeNo'])) // if the 'volume' field isn't empty
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['volumeNo'] . $suffix;
|
|
}
|
|
|
|
// '<:issue:>' placeholder:
|
|
elseif (preg_match("/:issue:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['issueNo'])) // if the 'issue' field isn't empty
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['issueNo'] . $suffix;
|
|
}
|
|
|
|
// '<:pages:>' placeholder:
|
|
elseif (preg_match("/:pages:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['pagesNo'])) // if the 'pages' field isn't empty
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['pagesNo'] . $suffix;
|
|
}
|
|
|
|
// '<:startPage:>' placeholder:
|
|
elseif (preg_match("/:startPage:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['pagesNo']) AND preg_match("/\d+/i", $formVars['pagesNo'])) // if the 'pages' field contains a number
|
|
{
|
|
$startPage = $prefix;
|
|
$startPage .= preg_replace("/^\D*?(\w*\d+\w*).*/i", "\\1", $formVars['pagesNo']); // extract starting page
|
|
$startPage .= $suffix;
|
|
$convertedPlaceholderArray[] = $startPage;
|
|
}
|
|
}
|
|
|
|
// '<:endPage:>' placeholder:
|
|
elseif (preg_match("/:endPage:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['pagesNo']) AND preg_match("/\d+/i", $formVars['pagesNo'])) // if the 'pages' field contains a number
|
|
{
|
|
$pages = preg_replace("/^\D*?(\w*\d+\w*)( *[$dash]+ *\w*\d+\w*)?.*/i$patternModifiers", "\\1\\2", $formVars['pagesNo']); // extract page range (if there's any), otherwise just the first number
|
|
$endPage = $prefix;
|
|
$endPage .= extractDetailsFromField("pages", $pages, "/\D+/", "[-1]"); // we'll use this function instead of just grabbing a matched regex pattern since it'll also work when just a number but no range is given (e.g. when startPage = endPage)
|
|
$endPage .= $suffix;
|
|
$convertedPlaceholderArray[] = $endPage;
|
|
}
|
|
}
|
|
|
|
// '<:keywords:>' placeholder:
|
|
elseif (preg_match("/:keywords(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['keywordsName'])) // if the 'keywords' field isn't empty
|
|
{
|
|
$keywords = $prefix;
|
|
$keywords .= extractDetailsFromField("keywords", $formVars['keywordsName'], "/ *[;,] */", $options);
|
|
$keywords .= $suffix;
|
|
$convertedPlaceholderArray[] = $keywords;
|
|
}
|
|
}
|
|
|
|
// '<:issn:>' placeholder:
|
|
elseif (preg_match("/:issn:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['issnName']))
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['issnName'] . $suffix;
|
|
}
|
|
|
|
// '<:isbn:>' placeholder:
|
|
elseif (preg_match("/:isbn:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['isbnName']))
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['isbnName'] . $suffix;
|
|
}
|
|
|
|
// '<:issn_isbn:>' placeholder:
|
|
elseif (preg_match("/:issn_isbn:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['issnName'])) // if both, an ISSN and ISBN number are present, the ISSN number will be preferred
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['issnName'] . $suffix;
|
|
elseif (!empty($formVars['isbnName']))
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['isbnName'] . $suffix;
|
|
}
|
|
|
|
// '<:area:>' placeholder:
|
|
elseif (preg_match("/:area(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['areaName'])) // if the 'area' field isn't empty
|
|
{
|
|
$area = $prefix;
|
|
$area .= extractDetailsFromField("area", $formVars['areaName'], "/ *[;,] */", $options);
|
|
$area .= $suffix;
|
|
$convertedPlaceholderArray[] = $area;
|
|
}
|
|
}
|
|
|
|
// '<:notes:>' placeholder:
|
|
elseif (preg_match("/:notes(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['notesName'])) // if the 'notes' field isn't empty
|
|
{
|
|
$notes = $prefix;
|
|
$notes .= extractDetailsFromField("notes", $formVars['notesName'], "/[^-$word]+/$patternModifiers", $options);
|
|
$notes .= $suffix;
|
|
$convertedPlaceholderArray[] = $notes;
|
|
}
|
|
}
|
|
|
|
// '<:userKeys:>' placeholder:
|
|
elseif (preg_match("/:userKeys(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['userKeysName'])) // if the 'user_keys' field isn't empty
|
|
{
|
|
$userKeys = $prefix;
|
|
$userKeys .= extractDetailsFromField("user_keys", $formVars['userKeysName'], "/ *[;,] */", $options);
|
|
$userKeys .= $suffix;
|
|
$convertedPlaceholderArray[] = $userKeys;
|
|
}
|
|
}
|
|
|
|
// '<:citeKey:>' placeholder:
|
|
elseif (preg_match("/:citeKey:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['citeKeyName'])) // if the 'cite_key' field isn't empty
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['citeKeyName'] . $suffix;
|
|
}
|
|
|
|
// '<:doi:>' placeholder:
|
|
elseif (preg_match("/:doi:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['doiName'])) // if the 'doi' field isn't empty
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['doiName'] . $suffix;
|
|
}
|
|
|
|
// '<:recordIdentifier:>' placeholder:
|
|
elseif (preg_match("/:recordIdentifier:/i", $placeholderPart))
|
|
{
|
|
if (!empty($formVars['citeKeyName'])) // if the 'cite_key' field isn't empty
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['citeKeyName'] . $suffix; // if available, we prefer the user-specific cite key as unique record identifier
|
|
else
|
|
$convertedPlaceholderArray[] = $prefix . $formVars['serialNo'] . $suffix; // otherwise we'll use the record's serial number
|
|
}
|
|
|
|
// '<:randomNumber:>' placeholder:
|
|
elseif (preg_match("/:randomNumber(\[[^][]*\])?:/i", $placeholderPart))
|
|
{
|
|
$randomString = $prefix;
|
|
$randomString .= generateRandomNumber($options);
|
|
$randomString .= $suffix;
|
|
$convertedPlaceholderArray[] = $randomString;
|
|
}
|
|
|
|
// else: un-recognized placeholders will be ignored
|
|
}
|
|
|
|
else // the part is assumed to be a literal string
|
|
{
|
|
$convertedPlaceholderArray[] = $placeholderPart; // add part as is to array of transformed placeholder parts
|
|
}
|
|
}
|
|
}
|
|
|
|
$convertedPlaceholderString = implode("", $convertedPlaceholderArray); // merge transformed placeholder parts
|
|
|
|
return $convertedPlaceholderString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// EXTRACT AUTHOR NAMES AND GENERATE IDENTIFIER STRING
|
|
// this function takes the contents of the author field and generates an author identifier string (see comments below for
|
|
// some examples) which is used by the file name (and cite key) auto-generation feature when replacing the <:authors:> placeholder
|
|
function extractDetailsFromAuthors($authorString, $options)
|
|
{
|
|
global $extractDetailsAuthorsDefault; // defined in 'ini.inc.php'
|
|
|
|
$returnRawAuthorString = false;
|
|
|
|
if (empty($options)) // if '$options' is empty
|
|
$options = $extractDetailsAuthorsDefault; // load the default options
|
|
|
|
if (preg_match("/^\[-?\d*\|[^][|]*\|[^][|]*\]$/i", $options)) // if the '$options' variable contains a recognized syntax (minimum spec must be: "[||]", i.e., second and third option delimiters are not optional but must be specified!)
|
|
{
|
|
// extract the individual options:
|
|
if (preg_match("/^\[-?\d+\|/i", $options)) // if the first option contains a number
|
|
{
|
|
$useMaxNoOfAuthors = preg_replace("/\[(-?\d+)\|[^][|]*\|[^][|]*\]/i", "\\1", $options); // regex note: to include a literal closing bracket (']') in a negated character class ('[^...]') it must be positioned right after the caret character ('^') such as in: '[^]...]'
|
|
|
|
if ($useMaxNoOfAuthors == 0) // the special number '0' indicates that all authors shall be retrieved
|
|
$useMaxNoOfAuthors = 250; // by assigning a very high number to '$useMaxNoOfAuthors' we should be pretty safe to catch all authors from the author field (extremely high values may choke the regular expression engine, though)
|
|
|
|
elseif ($useMaxNoOfAuthors < 0) // negative numbers have currently no meaning and will be treated as if the corresponding positive number was given
|
|
$useMaxNoOfAuthors = abs($useMaxNoOfAuthors);
|
|
}
|
|
|
|
elseif (preg_match("/^\[\|/i", $options)) // if the first option was left empty we assume that the raw author string shall be returned without any modification
|
|
$returnRawAuthorString = true;
|
|
|
|
$authorConnectorString = preg_replace("/\[-?\d*\|([^][|]*)\|[^][|]*\]/i", "\\1", $options);
|
|
|
|
$etalIdentifierString = preg_replace("/\[-?\d*\|[^][|]*\|([^][|]*)\]/i", "\\1", $options);
|
|
}
|
|
else // use yet another fallback if the given options contain a buggy syntax
|
|
{
|
|
$useMaxNoOfAuthors = 2;
|
|
$authorConnectorString = "+";
|
|
$etalIdentifierString = "_etal";
|
|
}
|
|
|
|
if ($returnRawAuthorString)
|
|
$authorDetails = $authorString; // return the raw author string without any modification
|
|
else
|
|
{
|
|
$authorDetails = ""; // initialize variable which will hold the author identifier string
|
|
|
|
// Add first author (plus additional authors if available up to the number of authors specified in '$useMaxNoOfAuthors');
|
|
// but if more authors are present as in '$useMaxNoOfAuthors', add the contents of '$etalIdentifierString' after the first(!) author ignoring all other authors.
|
|
// Example with '$extractDetailsAuthorsDefault = "[2|+|_etal]"':
|
|
// $authorString = "Steffens, M" -> $authorDetails = "Steffens"
|
|
// $authorString = "Steffens, M; Thomas, D" -> $authorDetails = "Steffens+Thomas"
|
|
// $authorString = "Steffens, M; Thomas, D; Dieckmann, GS" -> $authorDetails = "Steffens_etal"
|
|
// Example with '$extractDetailsAuthorsDefault = "[1|+|++]"':
|
|
// $authorString = "Steffens, M" -> $authorDetails = "Steffens"
|
|
// $authorString = "Steffens, M; Thomas, D" -> $authorDetails = "Steffens++"
|
|
// $authorString = "Steffens, M; Thomas, D; Dieckmann, GS" -> $authorDetails = "Steffens++"
|
|
for ($i=1; $i <= ($useMaxNoOfAuthors + 1); $i++)
|
|
{
|
|
if (preg_match("/^[^;]+(;[^;]+){" . ($i - 1) . "}/", $authorString)) // if the 'author' field does contain (at least) as many authors as specified in '$i'
|
|
{
|
|
|
|
if ($i>1)
|
|
{
|
|
if (preg_match("/^[^;]+(;[^;]+){" . $useMaxNoOfAuthors . "}/", $authorString)) // if the 'author' field does contain more authors as specified in '$useMaxNoOfAuthors'
|
|
{
|
|
$authorDetails .= $etalIdentifierString;
|
|
break;
|
|
}
|
|
else
|
|
$authorDetails .= $authorConnectorString;
|
|
}
|
|
|
|
// Call the 'extractAuthorsLastName()' function to extract the last name of a particular author (specified by position):
|
|
// (see function header for description of required parameters)
|
|
$authorDetails .= extractAuthorsLastName("/ *; */",
|
|
"/ *, */",
|
|
$i,
|
|
$authorString);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $authorDetails;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// EXTRACT YEAR
|
|
// this function takes the contents of the year field and returns the year in two-digit
|
|
// or four-digit format (depending on the given '$option' which must be either "[2]" or "[4]")
|
|
function extractDetailsFromYear($yearString, $options)
|
|
{
|
|
global $extractDetailsYearDefault; // defined in 'ini.inc.php'
|
|
|
|
if (empty($options)) // if '$options' is empty
|
|
$options = $extractDetailsYearDefault; // load the default option
|
|
|
|
if (preg_match("/^\[[24]\]$/i", $options)) // if the '$options' variable contains a recognized syntax
|
|
$yearDigitFormat = preg_replace("/^\[([24])\]$/i", "\\1", $options); // extract the individual option
|
|
else // use yet another fallback if the given option contains a buggy syntax
|
|
$yearDigitFormat = 4;
|
|
|
|
if (preg_match("/^\D*\d{4}/i", $yearString))
|
|
{
|
|
if ($yearDigitFormat == 2)
|
|
$yearDetails = preg_replace("/^\D*\d{2}(\d{2}).*/i", "\\1", $yearString);
|
|
else
|
|
$yearDetails = preg_replace("/^\D*(\d{4}).*/i", "\\1", $yearString);
|
|
}
|
|
else
|
|
$yearDetails = $yearString; // fallback
|
|
|
|
return $yearDetails;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// EXTRACT DETAILS FROM FIELD
|
|
// this function takes the contents of the title/publication/abbrev_journal/pages/keywords/area/notes/user_keys field
|
|
// and returns x words/items from the beginning (or end) of the string (depending on the given '$option' which must be
|
|
// of the form "[x]" where x is a number indicating how many words/items shall be returned; positive number: return x
|
|
// words/items from beginning of string, negative number: return x words/items from end of string)
|
|
function extractDetailsFromField($fieldName, $sourceString, $splitDelim, $options)
|
|
{
|
|
global $extractDetailsTitleDefault; // these variables are defined in 'ini.inc.php'
|
|
global $extractDetailsPublicationDefault;
|
|
global $extractDetailsAbbrevJournalDefault;
|
|
global $extractDetailsKeywordsDefault;
|
|
global $extractDetailsAreaDefault;
|
|
global $extractDetailsNotesDefault;
|
|
global $extractDetailsUserKeysDefault;
|
|
|
|
$returnRawSourceString = false;
|
|
|
|
if (empty($options)) // if '$options' is empty load the default option
|
|
{
|
|
if ($fieldName == "title")
|
|
$options = $extractDetailsTitleDefault;
|
|
elseif ($fieldName == "publication")
|
|
$options = $extractDetailsPublicationDefault;
|
|
elseif ($fieldName == "abbrev_journal")
|
|
$options = $extractDetailsAbbrevJournalDefault;
|
|
elseif ($fieldName == "pages")
|
|
$options = "[1]";
|
|
elseif ($fieldName == "keywords")
|
|
$options = $extractDetailsKeywordsDefault;
|
|
elseif ($fieldName == "area")
|
|
$options = $extractDetailsAreaDefault;
|
|
elseif ($fieldName == "notes")
|
|
$options = $extractDetailsNotesDefault;
|
|
elseif ($fieldName == "user_keys")
|
|
$options = $extractDetailsUserKeysDefault;
|
|
}
|
|
|
|
if (preg_match("/^\[(-?\d+(\|[^][|]*)?|-?\d*\|[^][|]*)\]$/i", $options)) // if the '$options' variable contains a recognized syntax
|
|
{
|
|
// extract the individual options:
|
|
if (preg_match("/^\[-?\d+/i", $options)) // if the first option contains a number
|
|
{
|
|
$extractNumberOfWords = preg_replace("/^\[(-?\d+)(\|[^][|]*)?\]$/i", "\\1", $options);
|
|
|
|
if ($extractNumberOfWords == 0) // the special number '0' indicates that all field items shall be retrieved
|
|
$extractNumberOfWords = 999; // by assigning a very high number to '$extractNumberOfWords' we should be pretty safe to catch all words/items from the given field (extremely high values may choke the regular expression engine, though)
|
|
}
|
|
|
|
elseif (preg_match("/^\[\|/i", $options)) // if the first option was left empty we assume that the raw source string shall be returned without any modification
|
|
$returnRawSourceString = true;
|
|
|
|
if (preg_match("/^\[-?\d*\|[^][|]+\]$/i", $options)) // if the second option contains some content
|
|
$joinDelim = preg_replace("/^\[-?\d*\|([^][|]+)\]$/i", "\\1", $options);
|
|
else
|
|
$joinDelim = "";
|
|
}
|
|
else // use yet another fallback if the given option contains a buggy syntax
|
|
{
|
|
$extractNumberOfWords = 1;
|
|
$joinDelim = "";
|
|
}
|
|
|
|
if (!($returnRawSourceString) AND preg_match($splitDelim, $sourceString))
|
|
$sourceStringDetails = extractPartsFromString($sourceString, $splitDelim, $joinDelim, $extractNumberOfWords);
|
|
else
|
|
$sourceStringDetails = $sourceString; // fallback
|
|
|
|
return $sourceStringDetails;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// GENERATE RANDOM NUMBER
|
|
// this function generates a random number taken from the range which is defined in '$options' (format: "[min|max]", e.g. "[0|9999]"),
|
|
// if '$options' is empty the maximum possible range will be used
|
|
function generateRandomNumber($options)
|
|
{
|
|
global $extractDetailsRandomNumberDefault; // defined in 'ini.inc.php'
|
|
|
|
if (empty($options)) // if '$options' is empty
|
|
$options = $extractDetailsRandomNumberDefault; // load the default options
|
|
|
|
if (preg_match("/^\[\d+\|\d+\]$/i", $options)) // if the '$options' variable contains a recognized syntax
|
|
{
|
|
// extract the individual options:
|
|
$minRandomNumber = preg_replace("/\[(\d+)\|.+/i", "\\1", $options); // extract first option which defines the minimum random number
|
|
$maxRandomNumber = preg_replace("/\[\d+\|(\d+)\]/i", "\\1", $options); // extract second option which defines the maximum random number
|
|
|
|
// generate random number:
|
|
$randomNumber = mt_rand($minRandomNumber, $maxRandomNumber);
|
|
}
|
|
else // no (or unrecognized) options
|
|
{
|
|
// generate random number:
|
|
$randomNumber = mt_rand(); // if called without the optional min, max arguments 'mt_rand()' returns a pseudo-random value between 0 and RAND_MAX
|
|
}
|
|
|
|
return $randomNumber;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// GET UPLOAD INFO
|
|
// Given the name of a file upload field, return a four (or five) element associative
|
|
// array containing information about the file. The element names are:
|
|
|
|
// name - original name of file on client
|
|
// type - MIME type of file (e.g.: 'image/gif')
|
|
// tmp_name - name of temporary file on server
|
|
// error - holds an error number >0 if something went wrong, otherwise 0
|
|
// (the 'error' element was added with PHP 4.2.0. Error code explanation: <http://www.php.net/file-upload.errors>)
|
|
// size - size of file in bytes
|
|
|
|
// depending what happend on upload, they will contain the following values (PHP 4.1 and above):
|
|
// no file upload upload exceeds 'upload_max_filesize' successful upload
|
|
// -------------- ------------------------------------ -----------------
|
|
// name "" [name] [name]
|
|
// type "" "" [type]
|
|
// tmp_name "" OR "none" "" [tmp_name]
|
|
// error 4 1 0
|
|
// size 0 0 [size]
|
|
|
|
// The function prefers the $_FILES array if it is available, falling back
|
|
// to $HTTP_POST_FILES and $HTTP_POST_VARS as necessary.
|
|
|
|
function getUploadInfo($name)
|
|
{
|
|
global $HTTP_POST_FILES, $HTTP_POST_VARS;
|
|
|
|
$uploadFileInfo = array(); // initialize array variable
|
|
|
|
// Look for information in PHP 4.1 $_FILES array first.
|
|
// Note: The entry in $_FILES might be present even if no file was uploaded (see above).
|
|
// Check the 'tmp_name' and/or the 'error' member to make sure there is a file.
|
|
if (isset($_FILES))
|
|
if (isset($_FILES[$name]))
|
|
$uploadFileInfo = ($_FILES[$name]);
|
|
|
|
// Look for information in PHP 4 $HTTP_POST_FILES array next.
|
|
// (Again, check the 'tmp_name' and/or the 'error' member to make sure there is a file.)
|
|
elseif (isset($HTTP_POST_FILES))
|
|
if (isset($HTTP_POST_FILES[$name]))
|
|
$uploadFileInfo = ($HTTP_POST_FILES[$name]);
|
|
|
|
// Look for PHP 3 style upload variables.
|
|
// Check the _name member, because $HTTP_POST_VARS[$name] might not
|
|
// actually be a file field.
|
|
elseif (isset($HTTP_POST_VARS[$name])
|
|
&& isset($HTTP_POST_VARS[$name . "_name"]))
|
|
{
|
|
// Map PHP 3 elements to PHP 4-style element names
|
|
$uploadFileInfo["name"] = $HTTP_POST_VARS[$name . "_name"];
|
|
$uploadFileInfo["tmp_name"] = $HTTP_POST_VARS[$name];
|
|
$uploadFileInfo["size"] = $HTTP_POST_VARS[$name . "_size"];
|
|
$uploadFileInfo["type"] = $HTTP_POST_VARS[$name . "_type"];
|
|
}
|
|
|
|
if (isset($uploadFileInfo["tmp_name"]) && ($uploadFileInfo["tmp_name"] == "none")) // on some systems (PHP versions) the 'tmp_name' element might contain 'none' if there was no file being uploaded
|
|
$uploadFileInfo["tmp_name"] = ""; // in order to standardize array output we replace 'none' with an empty string
|
|
|
|
return $uploadFileInfo;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// BUILD RELATED RECORDS LINK
|
|
// (this function generates a proper SQL query string from the contents of the user-specific 'related' field (table 'user_data') and returns a HTML link;
|
|
// clicking this link will show all records that match the serials or partial queries that were specified within the 'related' field)
|
|
function buildRelatedRecordsLink($relatedFieldString, $userID)
|
|
{
|
|
global $tableRefs, $tableUserData; // defined in 'db.inc.php'
|
|
|
|
// initialize some arrays:
|
|
$serialsArray = array(); // we'll use this array to hold all record serial numbers that we encounter
|
|
$queriesArray = array(); // this array will hold all sub-queries that were extracted from the 'related' field
|
|
|
|
// split the source string on any semi-colon ";" (optionally surrounded by whitespace) which works as our main delimiter:
|
|
$relatedFieldArray = preg_split("/ *; */", $relatedFieldString);
|
|
|
|
foreach ($relatedFieldArray as $relatedFieldArrayElement)
|
|
{
|
|
$relatedFieldArrayElement = trim($relatedFieldArrayElement); // remove any preceding or trailing whitespace
|
|
|
|
if (!empty($relatedFieldArrayElement))
|
|
{
|
|
if (is_numeric($relatedFieldArrayElement)) // if the current array element is a number, we assume its a serial number
|
|
$serialsArray[] = $relatedFieldArrayElement; // append the current array element to the end of the serials array
|
|
else
|
|
{
|
|
// replace any colon ":" (optionally surrounded by whitespace) with " RLIKE " and enclose the search value with quotes:
|
|
// (as an example, 'author:steffens, m' will be transformed to 'author RLIKE "steffens, m"')
|
|
if (preg_match("/:/",$relatedFieldArrayElement))
|
|
$relatedFieldArrayElement = preg_replace("/ *: *(.+)/"," RLIKE \"\\1\"",$relatedFieldArrayElement);
|
|
// else we assume '$relatedFieldArrayElement' to contain a valid 'WHERE' clause!
|
|
|
|
$queriesArray[] = $relatedFieldArrayElement; // append the current array element to the end of the queries array
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($serialsArray)) // if the 'related' field did contain any record serials
|
|
{
|
|
$serialsString = implode("|", $serialsArray);
|
|
$serialsString = "serial RLIKE " . quote_smart("^(" . $serialsString . ")$");
|
|
$queriesArray[] = $serialsString; // append the serial query to the end of the queries array
|
|
}
|
|
|
|
// re-join the queries array with an "OR" separator:
|
|
$queriesString = implode(" OR ", $queriesArray);
|
|
|
|
// build the full SQL query:
|
|
// TODO: build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
|
|
$relatedQuery = buildSELECTclause("", "", "", false, false);
|
|
|
|
// if any of the user-specific fields are present in the contents of the 'related' field, we'll add the 'LEFT JOIN...' part to the 'FROM' clause:
|
|
if (preg_match("/marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related/",$queriesString))
|
|
$relatedQuery .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = $userID";
|
|
else // we skip the 'LEFT JOIN...' part of the 'FROM' clause:
|
|
$relatedQuery .= " FROM $tableRefs";
|
|
|
|
$relatedQuery .= " WHERE " . $queriesString . " ORDER BY author, year DESC, publication"; // add 'WHERE' & 'ORDER BY' clause
|
|
|
|
// build the correct query URL:
|
|
$relatedRecordsLink = "search.php?sqlQuery=" . rawurlencode($relatedQuery) . "&formType=sqlSearch&showLinks=1"; // we skip unnecessary parameters ('search.php' will use it's default values for them)
|
|
|
|
return $relatedRecordsLink;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// LINKIFY FIELD ITEMS
|
|
// (this function generates 'show.php' HTML links for the items of the given field)
|
|
// NOTE: HTML links are only generated for fields that are supported by 'show.php', and
|
|
// only for those where it makes sense (e.g. the 'abstract' field doesn't get linked).
|
|
// The list of fields can be adopted in variable '$linkedFields' in 'ini.inc.php'.
|
|
function linkifyFieldItems($field, $fieldData, $userID = "", $localSearchReplaceActionsArray = array(), $encodingExceptionsArray = array(), $itemDelim = "/\s*[;]+\s*/", $joinDelim = "; ", $showQuery = "", $showLinks = "", $showRows = "", $citeStyle = "", $citeOrder = "", $wrapResults = "", $displayType = "", $viewType = "")
|
|
{
|
|
global $databaseBaseURL; // these variables are defined in 'ini.inc.php'
|
|
global $linkedFields;
|
|
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
global $client;
|
|
|
|
// Fields that may contain multiple items (delimited by '$itemDelim'):
|
|
static $multiItemFields = array("author", "keywords", "area", "notes", "location", "contribution_id",
|
|
"user_keys", "user_notes", "user_groups");
|
|
|
|
// Fields that require the 'userID' parameter:
|
|
// (note that, currently, 'show.php' only supports the fields 'marked',
|
|
// 'selected', 'user_keys', 'user_notes', 'user_groups' and 'cite_key')
|
|
static $userSpecificFields = array("marked", "copy", "selected", "user_keys", "user_notes",
|
|
"user_file", "user_groups", "cite_key");
|
|
|
|
// Display results in Details view when querying for one of the given fields:
|
|
// (see note below)
|
|
static $showFieldsInDetailsView = array("title", "serial", "cite_key");
|
|
|
|
// Check whether we're dealing with an unsupported field or if data are missing:
|
|
if (!in_array($field, $linkedFields) OR empty($fieldData) OR (in_array($field, $userSpecificFields) AND empty($userID)))
|
|
{
|
|
// Contents of unsupported fields won't get hotlinked but we'll have to HTML
|
|
// encode special chars and apply any field-specific search & replace actions:
|
|
if (!empty($fieldData))
|
|
return encodeField($field, $fieldData, $localSearchReplaceActionsArray, $encodingExceptionsArray);
|
|
else
|
|
return $fieldData;
|
|
}
|
|
else // supported field
|
|
{
|
|
$queryParametersArray = array();
|
|
|
|
// Add the 'userID' parameter for user-specific fields:
|
|
if (in_array($field, $userSpecificFields) AND !empty($userID))
|
|
$queryParametersArray["userID"] = $userID;
|
|
|
|
// Add query parameters if they're different from the defaults:
|
|
if (!empty($client))
|
|
$queryParametersArray["client"] = $client;
|
|
|
|
// NOTE: refbase usually tries to keep the user's current view. However, in
|
|
// case of the search links, I think it usually makes sense to present
|
|
// results in one of the two list-style views (i.e. List view or
|
|
// Citation view) -- and not in Details view, for example. Thus, we
|
|
// exclude Details view for regular fields. However, as an exception,
|
|
// fields listed in '$showFieldsInDetailsView' will be always displayed
|
|
// in Details view. This is done since the user most likely expects to
|
|
// see record details when he clicks on a record identifier (such as the
|
|
// 'serial' or 'cite_key' field) or the record's title.
|
|
if (in_array($field, $showFieldsInDetailsView))
|
|
$queryParametersArray["submit"] = "Display";
|
|
elseif (!empty($displayType) AND ($displayType != $_SESSION['userDefaultView']) AND (preg_match("/^(List|Cite)$/i", $displayType)))
|
|
$queryParametersArray["submit"] = $displayType;
|
|
|
|
if (!empty($viewType) AND ($viewType != "Web"))
|
|
$queryParametersArray["viewType"] = $viewType;
|
|
|
|
if ($showQuery == "1")
|
|
$queryParametersArray["showQuery"] = $showQuery;
|
|
|
|
if ($showLinks == "0")
|
|
$queryParametersArray["showLinks"] = $showLinks;
|
|
|
|
if ($wrapResults == "0")
|
|
$queryParametersArray["wrapResults"] = $wrapResults;
|
|
|
|
// We use absolute links for CLI clients, for include mechanisms, or when
|
|
// returning only a partial document structure:
|
|
if (preg_match("/^(cli|inc)/i", $client) OR ($wrapResults == "0"))
|
|
$baseURL = $databaseBaseURL;
|
|
else
|
|
$baseURL = "";
|
|
|
|
// Map MySQL field names to localized column names:
|
|
$fieldNamesArray = mapFieldNames();
|
|
|
|
$linkifiedFieldItems = array();
|
|
|
|
// Check whether we need to split field values for this field:
|
|
if (in_array($field, $multiItemFields))
|
|
$itemArray = preg_split($itemDelim, $fieldData);
|
|
else
|
|
$itemArray = array($fieldData);
|
|
|
|
// Linkify each field item:
|
|
foreach ($itemArray as $item)
|
|
{
|
|
$queryParametersArrayTemp = $queryParametersArray;
|
|
|
|
// Escape any meta characters:
|
|
$escapedItem = preg_quote($item, "");
|
|
|
|
// Adopt 'show.php' parameter name if it doesn't equal the field name:
|
|
if ($field == "serial")
|
|
$queryParametersArrayTemp["record"] = $escapedItem;
|
|
elseif ($field == "marked")
|
|
$queryParametersArrayTemp["ismarked"] = $escapedItem;
|
|
else
|
|
$queryParametersArrayTemp[$field] = $escapedItem;
|
|
|
|
// Generate item link:
|
|
$linkifiedFieldItems[] = "<a href=\"" . $baseURL . generateURL("show.php", "html", $queryParametersArrayTemp, true, $showRows, 0, $citeStyle, $citeOrder) . "\""
|
|
. " title=\"" . $loc["LinkTitle_SearchFieldItem_Prefix"] . $fieldNamesArray[$field] . $loc["LinkTitle_SearchFieldItem_Suffix"] . encodeHTML($item) . "\">"
|
|
. encodeField($field, $item, $localSearchReplaceActionsArray, $encodingExceptionsArray) // HTML encode special chars AND apply any field-specific search & replace actions
|
|
. "</a>";
|
|
}
|
|
|
|
return "<span class=\"itemlinks\">" . implode($joinDelim, $linkifiedFieldItems) . "</span>";
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// MODIFY USER GROUPS
|
|
// add (remove) selected records to (from) the specified user group
|
|
// Note: this function serves two purposes (which must not be confused!):
|
|
// - if "$queryTable = user_data", it will modify the values of the 'user_groups' field of the 'user_data' table (where a user can assign one or more groups to particular *references*)
|
|
// - if "$queryTable = users", this function will modify the values of the 'user_groups' field of the 'users' table (where the admin can assign one or more groups to particular *users*)
|
|
function modifyUserGroups($queryTable, $displayType, $recordSerialsArray, $userID, $userGroup)
|
|
{
|
|
global $tableUserData, $tableUsers; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
$userGroupQuoted = preg_quote($userGroup, "/"); // escape meta characters (including '/' that is used as delimiter for the PCRE match & replace functions below and which gets passed as second argument)
|
|
|
|
if ($queryTable == $tableUserData) // for the current user, get all entries within the 'user_data' table that refer to the selected records (listed in '$recordSerialsArray'):
|
|
$query = "SELECT record_id, user_groups FROM $tableUserData WHERE record_id RLIKE " . quote_smart("^(" . implode("|", $recordSerialsArray) . ")$") . " AND user_id = " . quote_smart($userID);
|
|
elseif ($queryTable == $tableUsers) // for the admin, get all entries within the 'users' table that refer to the selected records (listed in '$recordSerialsArray'):
|
|
$query = "SELECT user_id as record_id, user_groups FROM $tableUsers WHERE user_id RLIKE " . quote_smart("^(" . implode("|", $recordSerialsArray) . ")$");
|
|
// (note that by using 'user_id as record_id' we can use the term 'record_id' as identifier of the primary key for both tables)
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$foundSerialsArray = array(); // initialize array variable (which will hold the serial numbers of all found records)
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
{
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
{
|
|
$recordID = $row["record_id"]; // get the serial number of the current record
|
|
$foundSerialsArray[] = $recordID; // add this record's serial to the array of found serial numbers
|
|
|
|
$recordUserGroups = $row["user_groups"]; // extract the user groups that the current record belongs to
|
|
|
|
// ADD the specified user group to the 'user_groups' field:
|
|
if ($displayType == "Add" AND !preg_match("/(^|.*;) *$userGroupQuoted *(;.*|$)/", $recordUserGroups)) // if the specified group isn't listed already within the 'user_groups' field:
|
|
{
|
|
if (empty($recordUserGroups)) // and if the 'user_groups' field is completely empty
|
|
$recordUserGroups = $userGroup; // add the specified user group to the 'user_groups' field
|
|
else // if the 'user_groups' field does already contain some user content:
|
|
$recordUserGroups .= "; " . $userGroup; // append the specified user group to the 'user_groups' field
|
|
}
|
|
|
|
// REMOVE the specified user group from the 'user_groups' field:
|
|
elseif ($displayType == "Remove") // remove the specified group from the 'user_groups' field:
|
|
{
|
|
$recordUserGroups = preg_replace("/^ *$userGroupQuoted *(?=;|$)/", "", $recordUserGroups); // the specified group is listed at the very beginning of the 'user_groups' field
|
|
$recordUserGroups = preg_replace("/ *; *$userGroupQuoted *(?=;|$)/", "", $recordUserGroups); // the specified group occurs after some other group name within the 'user_groups' field
|
|
$recordUserGroups = preg_replace("/^ *; */i", "", $recordUserGroups); // remove any remaining group delimiters at the beginning of the 'user_groups' field
|
|
}
|
|
|
|
if ($queryTable == $tableUserData) // for the current record & user ID, update the matching entry within the 'user_data' table:
|
|
$queryUserData = "UPDATE $tableUserData SET user_groups = " . quote_smart($recordUserGroups) . " WHERE record_id = " . quote_smart($recordID) . " AND user_id = " . quote_smart($userID);
|
|
elseif ($queryTable == $tableUsers) // for the current user ID, update the matching entry within the 'users' table:
|
|
$queryUserData = "UPDATE $tableUsers SET user_groups = " . quote_smart($recordUserGroups) . " WHERE user_id = " . quote_smart($recordID);
|
|
|
|
|
|
$resultUserData = queryMySQLDatabase($queryUserData); // RUN the query on the database through the connection
|
|
}
|
|
}
|
|
|
|
if (($queryTable == $tableUserData) AND ($displayType == "Add"))
|
|
{
|
|
// for all selected records that have no entries in the 'user_data' table (for this user), we'll need to add a new entry containing the specified group:
|
|
$leftoverSerialsArray = array_diff($recordSerialsArray, $foundSerialsArray); // get all unique array elements of '$recordSerialsArray' which are not in '$foundSerialsArray'
|
|
|
|
foreach ($leftoverSerialsArray as $leftoverRecordID) // for each record that we haven't processed yet (since it doesn't have an entry in the 'user_data' table for this user)
|
|
{
|
|
if ($leftoverRecordID > 0) // function 'extractFormElementsQueryResults()' in 'search.php' assigns '$recordSerialsArray[]="0"' if '$recordSerialsArray' is empty
|
|
{
|
|
$foundSerialsArray[] = $leftoverRecordID; // add this record's serial to the array of found serial numbers
|
|
|
|
// for the current record & user ID, add a new entry (containing the specified group) to the 'user_data' table:
|
|
$queryUserData = "INSERT INTO $tableUserData SET "
|
|
. "user_groups = " . quote_smart($userGroup) . ", "
|
|
. "record_id = " . quote_smart($leftoverRecordID) . ", "
|
|
. "user_id = " . quote_smart($userID) . ", "
|
|
. "data_id = NULL"; // inserting 'NULL' into an auto_increment PRIMARY KEY attribute allocates the next available key value
|
|
|
|
$resultUserData = queryMySQLDatabase($queryUserData); // RUN the query on the database through the connection
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO!
|
|
// save an informative message:
|
|
// if (count($foundSerialsArray) == "1")
|
|
// $recordHeader = $loc["record"]; // use singular form if only one record was updated
|
|
// else
|
|
// $recordHeader = $loc["records"]; // use plural form if multiple records were updated
|
|
|
|
// $HeaderString = returnMsg("The groups of " . . " records were updated successfully!", "", "", "HeaderString");
|
|
|
|
getUserGroups($queryTable, $userID); // update the appropriate session variable
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get all user groups specified by the current user (or admin)
|
|
// and (if some groups were found) save them as semicolon-delimited string to a session variable:
|
|
// Note: this function serves two purposes (which must not be confused!):
|
|
// - if "$queryTable = user_data", it will fetch unique values from the 'user_groups' field of the 'user_data' table (where a user can assign one or more groups to particular *references*)
|
|
// - if "$queryTable = users", this function will fetch unique values from the 'user_groups' field of the 'users' table (where the admin can assign one or more groups to particular *users*)
|
|
function getUserGroups($queryTable, $userID)
|
|
{
|
|
global $tableUserData, $tableUsers; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// Note: 'user_groups RLIKE ".+"' will cause the database to only return user data entries where the 'user_groups' field
|
|
// is neither NULL (=> 'user_groups IS NOT NULL') nor the empty string (=> 'user_groups NOT RLIKE "^$"')
|
|
if ($queryTable == $tableUserData)
|
|
// Find all unique 'user_groups' entries in the 'user_data' table belonging to the current user:
|
|
$query = "SELECT DISTINCT user_groups FROM $tableUserData WHERE user_id = " . quote_smart($userID) . " AND user_groups RLIKE \".+\"";
|
|
elseif ($queryTable == $tableUsers)
|
|
// Find all unique 'user_groups' entries in the 'users' table:
|
|
$query = "SELECT DISTINCT user_groups FROM $tableUsers WHERE user_groups RLIKE \".+\"";
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$userGroupsArray = array(); // initialize array variable
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
{
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
{
|
|
// remove any meaningless delimiter(s) from the beginning or end of a field string:
|
|
$rowUserGroupsString = trimTextPattern($row["user_groups"], "( *; *)+", true, true);
|
|
|
|
// split the contents of the 'user_groups' field on the specified delimiter (which is interpreted as perl-style regular expression!):
|
|
$rowUserGroupsArray = preg_split("/ *; */", $rowUserGroupsString);
|
|
|
|
$userGroupsArray = array_merge($userGroupsArray, $rowUserGroupsArray); // append this row's group names to the array of found user groups
|
|
}
|
|
|
|
// remove duplicate group names from array:
|
|
$userGroupsArray = array_unique($userGroupsArray);
|
|
// sort in ascending order:
|
|
sort($userGroupsArray);
|
|
|
|
// join array of unique user groups with '; ' as separator:
|
|
$userGroupsString = implode('; ', $userGroupsArray);
|
|
|
|
// Write the resulting string of user groups into a session variable:
|
|
if ($queryTable == $tableUserData)
|
|
saveSessionVariable("userGroups", $userGroupsString);
|
|
elseif ($queryTable == $tableUsers)
|
|
saveSessionVariable("adminUserGroups", $userGroupsString);
|
|
}
|
|
else // no user groups found
|
|
{ // delete any session variable (which is now outdated):
|
|
if ($queryTable == $tableUserData)
|
|
deleteSessionVariable("userGroups");
|
|
elseif ($queryTable == $tableUsers)
|
|
deleteSessionVariable("adminUserGroups");
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get all user queries specified by the current user
|
|
// and (if some queries were found) save them as semicolon-delimited string to the session variable 'userQueries':
|
|
function getUserQueries($userID)
|
|
{
|
|
global $tableQueries; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// Find all unique query entries in the 'queries' table belonging to the current user:
|
|
// (query names should be unique anyhow, so the DISTINCT parameter wouldn't be really necessary)
|
|
$query = "SELECT DISTINCT(query_name),last_execution FROM $tableQueries WHERE user_id = " . quote_smart($userID) . " ORDER BY last_execution DESC";
|
|
// Note: we sort (in descending order) by the 'last_execution' field to get the last used query entries first;
|
|
// by that, the last used query will be always at the top of the popup menu within the 'Recall My Query' form
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$userQueriesArray = array(); // initialize array variable
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
{
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
$userQueriesArray[] = $row["query_name"]; // append this row's query name to the array of found user queries
|
|
|
|
// join array of unique user queries with '; ' as separator:
|
|
$userQueriesString = implode('; ', $userQueriesArray);
|
|
|
|
// Write the resulting string of user queries into a session variable:
|
|
saveSessionVariable("userQueries", $userQueriesString);
|
|
}
|
|
else // no user queries found
|
|
deleteSessionVariable("userQueries"); // delete any 'userQueries' session variable (which is now outdated)
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get all cite keys specified by the current user:
|
|
function getUserCiteKeys($userID)
|
|
{
|
|
global $tableRefs, $tableUserData; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// Find all cite keys in table 'user_data' belonging to the current user:
|
|
// (note that the SQL query is formulated such that only those records from table 'user_data' are returned
|
|
// which have a matching entry in table 'refs'; i.e. stray items from table 'user_data' are omitted)
|
|
$query = "SELECT cite_key FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . quote_smart($userID) . " WHERE cite_key RLIKE \".+\" ORDER BY cite_key";
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$userCiteKeysArray = array(); // initialize array variable
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
{
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
{
|
|
// If this row's cite key already exists in the global array of found cite keys ('$citeKeysArray'),
|
|
// we'll uniquify it, otherwise we'll take it as is
|
|
$citeKey = ensureUniqueCiteKey($row["cite_key"]);
|
|
|
|
// We also append the original cite key to '$userCiteKeysArray' which holds all uniquified cite keys
|
|
// as array keys and the corresponding original cite key names (including duplicate items!) as array
|
|
// values
|
|
$userCiteKeysArray[$citeKey] = $row["cite_key"];
|
|
}
|
|
}
|
|
|
|
return $userCiteKeysArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// This function checks if the given cite key already exists in the global array of found cite keys ('$citeKeysArray').
|
|
// If the given cite key already exists, an incrementing number will be added to uniquify it (the number will be increased
|
|
// until the cite key is truly unique); after ensuring that a given cite key is unique, it's added to '$citeKeysArray' and
|
|
// returned:
|
|
// Note: the global '$citeKeysArray' does NOT contain all cite keys defined in the entire refbase database; instead it holds:
|
|
// - on import: for records that just have been imported, the list of cite keys for all imported records (generated
|
|
// according to the current user's prefs) -PLUS- the list of all of the user's existing cite keys
|
|
// - on export: for records that just have been exported, the list of cite keys (generated according to the current
|
|
// user's prefs) for all exported records
|
|
function ensureUniqueCiteKey($citeKey)
|
|
{
|
|
global $citeKeysArray; // '$citeKeysArray' is made globally available from within this function
|
|
|
|
if (!isset($citeKeysArray))
|
|
$citeKeysArray = array(); // initialize array variable
|
|
|
|
if (isset($citeKeysArray[$citeKey])) // if this cite key already exists
|
|
{
|
|
if (preg_match("/(?<=_)\d+$/", $citeKey)) // if this cite key already contains a suffix such as "_2" we assume it to be the old number of occurrence
|
|
$citeKey = preg_replace("/(?<=_)(\d+)$/e", "'\\1' + 1", $citeKey); // increment the old number of occurrence (that already exists in this cite key) by 1
|
|
else
|
|
$citeKey = $citeKey . "_2"; // append a number of occurrence to this cite key
|
|
|
|
$citeKey = ensureUniqueCiteKey($citeKey); // recurse, to check again whether the generated cite key already exists
|
|
}
|
|
else
|
|
{
|
|
$citeKeysArray[$citeKey] = $citeKey; // append the cite key to the array of known cite keys
|
|
}
|
|
|
|
return $citeKey;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get all available formats/styles/types:
|
|
function getAvailableFormatsStylesTypes($dataType, $formatType) // '$dataType' must be one of the following: 'format', 'style', 'type'; '$formatType' must be either '', 'export', 'import' or 'cite'
|
|
{
|
|
global $tableDepends, $tableFormats, $tableStyles, $tableTypes; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
if ($dataType == "format")
|
|
$query = "SELECT format_name, format_id FROM $tableFormats LEFT JOIN $tableDepends ON $tableFormats.depends_id = $tableDepends.depends_id WHERE format_type = " . quote_smart($formatType) . " AND format_enabled = 'true' AND depends_enabled = 'true' ORDER BY order_by, format_name";
|
|
|
|
elseif ($dataType == "style")
|
|
$query = "SELECT style_name, style_id FROM $tableStyles LEFT JOIN $tableDepends ON $tableStyles.depends_id = $tableDepends.depends_id WHERE style_enabled = 'true' AND depends_enabled = 'true' ORDER BY order_by, style_name";
|
|
|
|
elseif ($dataType == "type")
|
|
$query = "SELECT type_name, type_id FROM $tableTypes WHERE type_enabled = 'true' ORDER BY order_by, type_name";
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$availableFormatsStylesTypesArray = array(); // initialize array variable
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
$availableFormatsStylesTypesArray[$row[$dataType . "_id"]] = $row[$dataType . "_name"]; // append this row's format/style/type name to the array of found user formats/styles/types
|
|
|
|
return $availableFormatsStylesTypesArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get all formats/styles/types that are available and were enabled by the admin for the current user:
|
|
function getEnabledUserFormatsStylesTypes($userID, $dataType, $formatType, $returnIDsAsValues) // '$dataType' must be one of the following: 'format', 'style', 'type'; '$formatType' must be either '', 'export', 'import' or 'cite'
|
|
{
|
|
global $tableDepends, $tableFormats, $tableStyles, $tableTypes, $tableUserFormats, $tableUserStyles, $tableUserTypes; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
if ($dataType == "format")
|
|
$query = "SELECT $tableFormats.format_name, $tableFormats.format_id FROM $tableFormats LEFT JOIN $tableUserFormats on $tableFormats.format_id = $tableUserFormats.format_id LEFT JOIN $tableDepends ON $tableFormats.depends_id = $tableDepends.depends_id WHERE format_type = " . quote_smart($formatType) . " AND format_enabled = 'true' AND depends_enabled = 'true' AND user_id = " . quote_smart($userID) . " ORDER BY $tableFormats.order_by, $tableFormats.format_name";
|
|
|
|
elseif ($dataType == "style")
|
|
$query = "SELECT $tableStyles.style_name, $tableStyles.style_id FROM $tableStyles LEFT JOIN $tableUserStyles on $tableStyles.style_id = $tableUserStyles.style_id LEFT JOIN $tableDepends ON $tableStyles.depends_id = $tableDepends.depends_id WHERE style_enabled = 'true' AND depends_enabled = 'true' AND user_id = " . quote_smart($userID) . " ORDER BY $tableStyles.order_by, $tableStyles.style_name";
|
|
|
|
elseif ($dataType == "type")
|
|
$query = "SELECT $tableTypes.type_name, $tableTypes.type_id FROM $tableTypes LEFT JOIN $tableUserTypes USING (type_id) WHERE type_enabled = 'true' AND user_id = " . quote_smart($userID) . " ORDER BY $tableTypes.order_by, $tableTypes.type_name";
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$enabledFormatsStylesTypesArray = array(); // initialize array variable
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
{
|
|
if ($returnIDsAsValues) // return format/style/type IDs as element values:
|
|
$enabledFormatsStylesTypesArray[] = $row[$dataType . "_id"]; // append this row's format/style/type ID to the array of found user formats/styles/types
|
|
else // return format/style/type names as element values and use the corresponding IDs as element keys:
|
|
$enabledFormatsStylesTypesArray[$row[$dataType . "_id"]] = $row[$dataType . "_name"]; // append this row's format/style/type name to the array of found user formats/styles/types
|
|
}
|
|
|
|
return $enabledFormatsStylesTypesArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get all user formats/styles/types that are available and enabled for the current user (by admins choice) AND which this user has chosen to be visible:
|
|
// and (if some formats/styles/types were found) save them each as semicolon-delimited string to the session variables 'user_export_formats', 'user_cite_formats', 'user_styles' or 'user_types', respectively:
|
|
function getVisibleUserFormatsStylesTypes($userID, $dataType, $formatType) // '$dataType' must be one of the following: 'format', 'style', 'type'; '$formatType' must be either '', 'export', 'import' or 'cite'
|
|
{
|
|
global $loginEmail;
|
|
global $adminLoginEmail; // ('$adminLoginEmail' is specified in 'ini.inc.php')
|
|
global $tableDepends, $tableFormats, $tableStyles, $tableTypes, $tableUserFormats, $tableUserStyles, $tableUserTypes; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
if ($dataType == "format")
|
|
{
|
|
// Find all enabled+visible formats in table 'user_formats' belonging to the current user:
|
|
// Note: following conditions must be matched to have a format "enabled+visible" for a particular user:
|
|
|
|
// - 'formats' table: the 'format_enabled' field must contain 'true' for the given format
|
|
// (the 'formats' table gives the admin control over which formats are available to the database users)
|
|
|
|
// - 'depends' table: the 'depends_enabled' field must contain 'true' for the 'depends_id' that matches the 'depends_id' of the given format in table 'formats'
|
|
// (the 'depends' table specifies whether there are any external tools required for a particular format and if these tools are available)
|
|
|
|
// - 'user_formats' table: there must be an entry for the given user where the 'format_id' matches the 'format_id' of the given format in table 'formats' -AND-
|
|
// the 'show_format' field must contain 'true' for the 'format_id' that matches the 'format_id' of the given format in table 'formats'
|
|
// (the 'user_formats' table specifies all of the available formats for a particular user that have been selected by this user to be included in the format popups)
|
|
$query = "SELECT format_name FROM $tableFormats LEFT JOIN $tableUserFormats on $tableFormats.format_id = $tableUserFormats.format_id LEFT JOIN $tableDepends ON $tableFormats.depends_id = $tableDepends.depends_id WHERE format_type = " . quote_smart($formatType) . " AND format_enabled = 'true' AND depends_enabled = 'true' AND user_id = " . quote_smart($userID) . " AND show_format = 'true' ORDER BY $tableFormats.order_by, $tableFormats.format_name";
|
|
}
|
|
elseif ($dataType == "style")
|
|
{
|
|
// Find all enabled+visible styles in table 'user_styles' belonging to the current user:
|
|
// (same conditions apply as for formats)
|
|
$query = "SELECT style_name FROM $tableStyles LEFT JOIN $tableUserStyles on $tableStyles.style_id = $tableUserStyles.style_id LEFT JOIN $tableDepends ON $tableStyles.depends_id = $tableDepends.depends_id WHERE style_enabled = 'true' AND depends_enabled = 'true' AND user_id = " . quote_smart($userID) . " AND show_style = 'true' ORDER BY $tableStyles.order_by, $tableStyles.style_name";
|
|
}
|
|
elseif ($dataType == "type")
|
|
{
|
|
// Find all enabled+visible types in table 'user_types' belonging to the current user:
|
|
// (opposed to formats & styles, we're not checking for any dependencies here)
|
|
$query = "SELECT type_name FROM $tableTypes LEFT JOIN $tableUserTypes USING (type_id) WHERE user_id = " . quote_smart($userID) . " AND show_type = 'true' ORDER BY $tableTypes.order_by, $tableTypes.type_name";
|
|
}
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$userFormatsStylesTypesArray = array(); // initialize array variable
|
|
|
|
// generate the name of the session variable:
|
|
if (!empty($formatType))
|
|
$sessionVariableName = "user_" . $formatType . "_" . $dataType . "s"; // yields 'user_export_formats' or 'user_cite_formats'
|
|
else
|
|
$sessionVariableName = "user_" . $dataType . "s"; // yields 'user_styles' or 'user_types'
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
{
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
$userFormatsStylesTypesArray[] = $row[$dataType . "_name"]; // append this row's format/style/type name to the array of found user formats/styles/types
|
|
|
|
// we'll only update the appropriate session variable if either a normal user is logged in -OR- the admin is logged in and views his own user options page
|
|
if (($loginEmail != $adminLoginEmail) OR (($loginEmail == $adminLoginEmail) && ($userID == getUserID($loginEmail))))
|
|
{
|
|
// join array of unique user formats/styles/types with '; ' as separator:
|
|
$userFormatsStylesTypesString = implode('; ', $userFormatsStylesTypesArray);
|
|
|
|
// Write the resulting string of user formats/styles/types into a session variable:
|
|
saveSessionVariable($sessionVariableName, $userFormatsStylesTypesString);
|
|
}
|
|
}
|
|
else // no user formats/styles/types found
|
|
// we'll only delete the appropriate session variable if either a normal user is logged in -OR- the admin is logged in and views his own user options page
|
|
if (($loginEmail != $adminLoginEmail) OR (($loginEmail == $adminLoginEmail) && ($userID == getUserID($loginEmail))))
|
|
deleteSessionVariable($sessionVariableName); // delete any 'user_export_formats'/'user_cite_formats'/'user_styles'/'user_types' session variable (which is now outdated)
|
|
|
|
return $userFormatsStylesTypesArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get all formats/styles/types that are available (or enabled for the current user) and return them as properly formatted <option> tag elements.
|
|
// Note that this function will return two pretty different things, depending on who's logged in:
|
|
// - if the admin is logged in, it will return all *available* formats/styles/types as <option> tags
|
|
// (with those items being selected which were _enabled_ by the admin for the current user)
|
|
// - if a normal user is logged in, this function will return all formats/styles/types as <option> tags which were *enabled* by the admin for the current user
|
|
// (with those items being selected which were chosen to be _visible_ by the current user)
|
|
function returnFormatsStylesTypesAsOptionTags($userID, $dataType, $formatType) // '$dataType' must be one of the following: 'format', 'style', 'type'; '$formatType' must be either '', 'export', 'import' or 'cite'
|
|
{
|
|
global $loginEmail;
|
|
global $adminLoginEmail; // ('$adminLoginEmail' is specified in 'ini.inc.php')
|
|
|
|
if ($loginEmail == $adminLoginEmail) // if the admin is logged in
|
|
$availableFormatsStylesTypesArray = getAvailableFormatsStylesTypes($dataType, $formatType); // get all available formats/styles/types
|
|
|
|
$enabledFormatsStylesTypesArray = getEnabledUserFormatsStylesTypes($userID, $dataType, $formatType, false); // get all formats/styles/types that were enabled by the admin for the current user
|
|
|
|
if ($loginEmail == $adminLoginEmail) // if the admin is logged in
|
|
{
|
|
$optionTags = buildSelectMenuOptions($availableFormatsStylesTypesArray, "/ *; */", "\t\t\t", true); // build properly formatted <option> tag elements from the items listed in '$availableFormatsStylesTypesArray'
|
|
|
|
$selectedFormatsStylesTypesArray = $enabledFormatsStylesTypesArray; // get all formats/styles/types that were enabled by the admin for the current user
|
|
}
|
|
else // if ($loginEmail != $adminLoginEmail) // if a normal user is logged in
|
|
{
|
|
$optionTags = buildSelectMenuOptions($enabledFormatsStylesTypesArray, "/ *; */", "\t\t\t", true); // build properly formatted <option> tag elements from the items listed in '$enabledFormatsStylesTypesArray'
|
|
|
|
$selectedFormatsStylesTypesArray = getVisibleUserFormatsStylesTypes($userID, $dataType, $formatType); // get all formats/styles/types that were chosen to be visible for the current user
|
|
}
|
|
|
|
foreach($selectedFormatsStylesTypesArray as $itemKey => $itemValue) // escape possible meta characters within names of formats/styles/types that shall be selected (otherwise the grep pattern below would fail)
|
|
$selectedFormatsStylesTypesArray[$itemKey] = preg_quote($itemValue);
|
|
|
|
$selectedFormatsStylesTypes = implode("|", $selectedFormatsStylesTypesArray); // merge array of formats/styles/types that shall be selected
|
|
|
|
$optionTags = preg_replace("/<option([^>]*)>($selectedFormatsStylesTypes)<\\/option>/", "<option\\1 selected>\\2</option>", $optionTags); // select all formats/styles/types that are listed within '$selectedFormatsStylesTypesArray'
|
|
|
|
return $optionTags;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Fetch the name of the citation style file that's associated with the style given in '$citeStyle'
|
|
// Note: Refbase identifies popup items by their name (and not by ID numbers) which means that the style names within the 'styles' table must be unique!
|
|
// That said, this function assumes unique style names, i.e., there's no error checking for duplicates!
|
|
function getStyleFile($citeStyle)
|
|
{
|
|
global $tableStyles; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// get the 'style_spec' for the record entry in table 'styles' whose 'style_name' matches that in '$citeStyle':
|
|
$query = "SELECT style_spec FROM $tableStyles WHERE style_name = " . quote_smart($citeStyle);
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
$row = mysqli_fetch_array($result);
|
|
|
|
return($row["style_spec"]);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Fetch the path/name of the format file that's associated with the format given in '$formatName'
|
|
function getFormatFile($formatName, $formatType) // '$formatType' must be either 'export', 'import' or 'cite'
|
|
{
|
|
global $tableFormats; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// get the 'format_spec' for the record entry in table 'formats' whose 'format_name' matches that in '$formatName':
|
|
$query = "SELECT format_spec FROM $tableFormats WHERE format_name = " . quote_smart($formatName) . " AND format_type = " . quote_smart($formatType);
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
$row = mysqli_fetch_array($result);
|
|
|
|
return($row["format_spec"]);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Fetch the path of the external utility that's required for a particular import/export format
|
|
function getExternalUtilityPath($externalUtilityName)
|
|
{
|
|
global $tableDepends; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// get the path for the record entry in table 'depends' whose field 'depends_external' matches that in '$externalUtilityName':
|
|
$query = "SELECT depends_path FROM $tableDepends WHERE depends_external = " . quote_smart($externalUtilityName);
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
$row = mysqli_fetch_array($result);
|
|
|
|
return($row["depends_path"]);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get the user (or group) permissions for the current user
|
|
// and (optionally) save all allowed user actions as semicolon-delimited string to the session variable 'user_permissions':
|
|
function getPermissions($user_OR_groupID, $permissionType, $savePermissionsToSessionVariable) // '$permissionType' must be either 'user' or 'group'; '$savePermissionsToSessionVariable' must be either 'true' or 'false'
|
|
{
|
|
global $tableUserPermissions; // defined in 'db.inc.php'
|
|
|
|
// NOTE: the group permissions feature (table 'group_permissions') has not been implemented yet, i.e., currently, only '$permissionType=user' is recognized!
|
|
// global $tableGroupPermissions;
|
|
|
|
// if ($permissionType == "group")
|
|
// $tablePermissions = $tableGroupPermissions;
|
|
// else
|
|
$tablePermissions = $tableUserPermissions;
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// Fetch all permission settings from the 'user_permissions' (or 'group_permissions') table for the current user:
|
|
$query = "SELECT allow_add, allow_edit, allow_delete, allow_download, allow_upload, allow_list_view, allow_details_view, allow_print_view, allow_browse_view, allow_sql_search, allow_user_groups, allow_user_queries, allow_rss_feeds, allow_import, allow_export, allow_cite, allow_batch_import, allow_batch_export, allow_modify_options FROM " . $tablePermissions . " WHERE " . $permissionType . "_id = " . quote_smart($user_OR_groupID);
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
if (mysqli_num_rows($result) == 1) // interpret query result: Do we have exactly one row?
|
|
{
|
|
$userPermissionsArray = array(); // initialize array variables
|
|
$userPermissionsFieldNameArray = array();
|
|
|
|
$row = mysqli_fetch_array($result); // fetch the one row into the array '$row'
|
|
|
|
$fieldsFound = mysqli_num_fields($result); // count the number of fields
|
|
|
|
for ($i=0; $i<$fieldsFound; $i++)
|
|
{
|
|
// Fetch the current attribute name:
|
|
$fieldName = getMySQLFieldInfo($result, $i, "name");
|
|
|
|
$userPermissionsArray[$fieldName] = $row[$i]; // ... append this field's permission value using the field's permission name as key
|
|
|
|
if ($row[$i] == "yes") // if the current permission is set to 'yes'...
|
|
$userPermissionsFieldNameArray[] = $fieldName; // ... append this field's permission name (as value) to the array of allowed user actions
|
|
}
|
|
|
|
// join array of allowed user actions with '; ' as separator:
|
|
$allowedUserActionsString = implode('; ', $userPermissionsFieldNameArray);
|
|
|
|
if ($savePermissionsToSessionVariable)
|
|
// Write the resulting string of allowed user actions into a session variable:
|
|
saveSessionVariable("user_permissions", $allowedUserActionsString);
|
|
|
|
return $userPermissionsArray;
|
|
}
|
|
else
|
|
{
|
|
if ($savePermissionsToSessionVariable)
|
|
// since no (or more than one) user/group was found with the given ID, we fall back to the default permissions which apply when no user is logged in, i.e.,
|
|
// we assume 'user_id' or 'group_id' is zero! (the 'start_session()' function will take care of setting up permissions when no user is logged in)
|
|
deleteSessionVariable("user_permissions"); // therefore, we delete any existing 'user_permissions' session variable (which is now outdated)
|
|
|
|
return array();
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Returns language information:
|
|
// if empty($userID): get all languages that were setup and enabled by the admin
|
|
// if !empty($userID): get the preferred language for the user with the specified userID
|
|
function getLanguages($userID)
|
|
{
|
|
global $tableLanguages, $tableUsers; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
if (empty($userID))
|
|
// Find all unique language entries in the 'languages' table that are enabled:
|
|
// (language names should be unique anyhow, so the DISTINCT parameter wouldn't be really necessary)
|
|
$query = "SELECT DISTINCT language_name FROM $tableLanguages WHERE language_enabled = 'true' ORDER BY $tableLanguages.language_name";
|
|
else
|
|
// Get the preferred language for the user with the user ID given in '$userID':
|
|
$query = "SELECT language AS language_name FROM $tableUsers WHERE user_id = " . quote_smart($userID);
|
|
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$languagesArray = array(); // initialize array variable
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
{
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
$languagesArray[] = $row["language_name"]; // append this row's language name to the array of found languages
|
|
}
|
|
|
|
return $languagesArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Return the current user's preferred interface language:
|
|
function getUserLanguage()
|
|
{
|
|
global $loginUserID; // saved as session variable on login
|
|
|
|
global $defaultLanguage; // defined in 'ini.inc.php'
|
|
|
|
if (isset($_SESSION['loginEmail'])) // if a user is logged in
|
|
{
|
|
// get the preferred language for the current user:
|
|
$userLanguagesArray = getLanguages($loginUserID);
|
|
$userLanguage = $userLanguagesArray[0];
|
|
}
|
|
else // NO user logged in
|
|
$userLanguage = $defaultLanguage; // use the default language
|
|
|
|
return $userLanguage;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get all user options for the current user:
|
|
function getUserOptions($userID)
|
|
{
|
|
global $tableUserOptions; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
if (empty($userID))
|
|
$userID = 0;
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// Fetch all options from table 'user_options' for the user with the user ID given in '$userID':
|
|
$query = "SELECT * FROM $tableUserOptions WHERE user_id = " . quote_smart($userID);
|
|
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$userOptionsArray = array(); // initialize array variable
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound == 1) // Interpret query result: Do we have exactly one row?
|
|
$userOptionsArray = @ mysqli_fetch_array($result); // fetch the one row into the array '$userOptionsArray'
|
|
|
|
return $userOptionsArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get the list of "main fields" preferred by the current user:
|
|
// and save the list of fields as comma-delimited string to the session variable 'userMainFields'
|
|
// TODO: Make *one* generic function that can replace functions 'getMainFields()',
|
|
// 'getDefaultNumberOfRecords()' and 'getPrefAutoCompletions()'
|
|
function getMainFields($userID)
|
|
{
|
|
global $loginEmail;
|
|
|
|
global $adminLoginEmail; // these variables are defined in 'ini.inc.php'
|
|
global $defaultMainFields;
|
|
|
|
$userOptionsArray = array(); // initialize array variable
|
|
|
|
// Get all user options for the current user:
|
|
// note that if the user isn't logged in (userID=0), the list of "main fields" is taken from variable
|
|
// '$defaultMainFields' in 'ini.inc.php' and not from option 'main_fields' in table 'user_options
|
|
if ($userID != 0)
|
|
$userOptionsArray = getUserOptions($userID);
|
|
|
|
// Extract the list of "main fields":
|
|
if (!empty($userOptionsArray) AND !empty($userOptionsArray['main_fields']))
|
|
$userMainFieldsString = $userOptionsArray['main_fields']; // honour the logged in user's preferred list of "main fields" (if not empty or NULL)
|
|
else
|
|
$userMainFieldsString = $defaultMainFields; // by default, we take the list of "main fields" from the global variable '$defaultMainFields'
|
|
|
|
// We'll only update the appropriate session variable if either a normal user is logged in -OR- the admin is logged in and views his own user options page
|
|
if (($loginEmail != $adminLoginEmail) OR (($loginEmail == $adminLoginEmail) && ($userID == getUserID($loginEmail))))
|
|
// Write the list of fields into a session variable:
|
|
saveSessionVariable("userMainFields", $userMainFieldsString);
|
|
|
|
$userMainFieldsArray = preg_split("/ *, */", $userMainFieldsString); // split the string of fields into its individual fields
|
|
|
|
return $userMainFieldsArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Returns the current date (e.g. '2003-12-31'), time (e.g. '23:59:49') and user name & email address (e.g. 'Matthias Steffens (refbase@extracts.de)'):
|
|
// this information is used when adding/updating/deleting records in the database
|
|
function getCurrentDateTimeUser()
|
|
{
|
|
global $loginEmail;
|
|
global $loginFirstName;
|
|
global $loginLastName;
|
|
|
|
$currentDate = date('Y-m-d'); // get the current date in a format recognized by MySQL (which is 'YYYY-MM-DD', e.g. '2003-12-31')
|
|
$currentTime = date('H:i:s'); // get the current time in a format recognized by MySQL (which is 'HH:MM:SS', e.g. '23:59:49')
|
|
$currentUser = $loginFirstName . " " . $loginLastName . " (" . $loginEmail . ")"; // we use session variables to construct the user name, e.g. 'Matthias Steffens (refbase@extracts.de)'
|
|
|
|
return array($currentDate, $currentTime, $currentUser);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Build a correct call number prefix for the currently logged-in user (e.g. 'IPÖ @ msteffens'):
|
|
function getCallNumberPrefix()
|
|
{
|
|
global $loginEmail;
|
|
global $abbrevInstitution;
|
|
|
|
// we use session variables to construct a correct call number prefix:
|
|
$loginEmailArray = preg_split("/@/", $loginEmail); // split the login email address at '@'
|
|
$loginEmailUserName = $loginEmailArray[0]; // extract the user name (which is the first element of the array '$loginEmailArray')
|
|
$callNumberPrefix = $abbrevInstitution . " @ " . $loginEmailUserName;
|
|
|
|
return $callNumberPrefix;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get the default view for the current user:
|
|
function getDefaultView($userID)
|
|
{
|
|
global $defaultView; // defined in 'ini.inc.php'
|
|
|
|
$userOptionsArray = array(); // initialize array variables
|
|
$viewsArray = array("List" => "allow_list_view",
|
|
"Cite" => "allow_cite",
|
|
"Display" => "allow_details_view",
|
|
"Browse" => "allow_browse_view");
|
|
|
|
$userDefaultView = $defaultView; // by default, we take the default view from the global variable '$defaultView'
|
|
|
|
// Note that if the user isn't logged in (userID=0), the default view is taken from variable '$defaultView'
|
|
// in 'ini.inc.php' and is not overridden by any of the '*_view' permissions ('allow_list_view', 'allow_details_view',
|
|
// 'allow_browse_view', 'allow_cite') in table 'user_permissions'
|
|
|
|
// Adopt the user's default view if he/she is NOT allowed to use the global default (given in '$defaultView'):
|
|
if (isset($viewsArray[$defaultView]) AND isset($_SESSION['user_permissions']) AND !preg_match("/" . $viewsArray[$defaultView] . "/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable does NOT contain the '*_view' permission that corresponds to '$defaultView'
|
|
{
|
|
foreach ($viewsArray as $viewType => $viewPermission) // use the next allowed view as default view
|
|
{
|
|
if (preg_match("/" . $viewPermission . "/", $_SESSION['user_permissions']))
|
|
{
|
|
$userDefaultView = $viewType;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write the name of the default view into a session variable:
|
|
saveSessionVariable("userDefaultView", $userDefaultView);
|
|
|
|
return $userDefaultView;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Returns the total number of records in the database:
|
|
function getTotalNumberOfRecords()
|
|
{
|
|
global $tableRefs; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
$query = "SELECT COUNT(serial) FROM $tableRefs"; // query the total number of records
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$row = mysqli_fetch_row($result); // fetch the current row into the array $row (it'll be always *one* row, but anyhow)
|
|
$numberOfRecords = $row[0]; // extract the contents of the first (and only) row
|
|
|
|
return $numberOfRecords;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get the default number of records per page preferred by the current user:
|
|
// TODO: Make *one* generic function that can replace functions 'getMainFields()',
|
|
// 'getDefaultNumberOfRecords()' and 'getPrefAutoCompletions()'
|
|
function getDefaultNumberOfRecords($userID)
|
|
{
|
|
global $loginEmail;
|
|
|
|
global $adminLoginEmail; // these variables are defined in 'ini.inc.php'
|
|
global $defaultNumberOfRecords;
|
|
|
|
$userOptionsArray = array(); // initialize array variable
|
|
|
|
// Get all user options for the current user:
|
|
// note that if the user isn't logged in (userID=0), we don't load the default number of records from option
|
|
// 'records_per_page' in table 'user_options' (where 'user_id = 0'). Instead, we'll return as many records as
|
|
// defined in variable '$defaultNumberOfRecords' in 'ini.inc.php'.
|
|
if ($userID != 0)
|
|
$userOptionsArray = getUserOptions($userID);
|
|
|
|
// Extract the number of records that's to be returned by default:
|
|
if (!empty($userOptionsArray) AND !empty($userOptionsArray['records_per_page']))
|
|
$showRows = $userOptionsArray['records_per_page']; // honour the logged in user's preferred number of records (if not empty or NULL)
|
|
else
|
|
$showRows = $defaultNumberOfRecords; // by default, we take the number of records from the global variable '$defaultNumberOfRecords'
|
|
|
|
// We'll only update the appropriate session variable if either a normal user is logged in -OR- the admin is logged in and views his own user options page
|
|
if (($loginEmail != $adminLoginEmail) OR (($loginEmail == $adminLoginEmail) && ($userID == getUserID($loginEmail))))
|
|
// Write results into a session variable:
|
|
saveSessionVariable("userRecordsPerPage", $showRows);
|
|
|
|
return $showRows;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get the user's preference for displaying auto-completions:
|
|
// TODO: Make *one* generic function that can replace functions 'getMainFields()',
|
|
// 'getDefaultNumberOfRecords()' and 'getPrefAutoCompletions()'
|
|
function getPrefAutoCompletions($userID)
|
|
{
|
|
global $loginEmail;
|
|
|
|
global $adminLoginEmail; // these variables are defined in 'ini.inc.php'
|
|
global $autoCompleteUserInput;
|
|
|
|
$userOptionsArray = array(); // initialize array variable
|
|
|
|
// Get all user options for the current user:
|
|
// note that if the user isn't logged in (userID=0), we don't load the pref setting from option
|
|
// 'show_auto_completions' in table 'user_options' (where 'user_id = 0'). Instead, we'll take
|
|
// the setting from variable '$autoCompleteUserInput' in 'ini.inc.php'.
|
|
if ($userID != 0)
|
|
$userOptionsArray = getUserOptions($userID);
|
|
|
|
// Extract the setting which defines whether auto-completions shall be displayed for text entered by the user:
|
|
if (!empty($userOptionsArray) AND !empty($userOptionsArray['show_auto_completions']))
|
|
$showAutoCompletions = $userOptionsArray['show_auto_completions']; // honour the logged in user's preference for displaying auto-completions (if not empty or NULL)
|
|
else
|
|
$showAutoCompletions = $autoCompleteUserInput; // by default, we take the pref setting from the global variable '$autoCompleteUserInput'
|
|
|
|
// We'll only update the appropriate session variable if either a normal user is logged in -OR- the admin is logged in and views his own user options page
|
|
if (($loginEmail != $adminLoginEmail) OR (($loginEmail == $adminLoginEmail) && ($userID == getUserID($loginEmail))))
|
|
// Write results into a session variable:
|
|
saveSessionVariable("userAutoCompletions", $showAutoCompletions);
|
|
|
|
return $showAutoCompletions;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Returns the date/time information (in format 'YYYY-MM-DD hh-mm-ss') when the database was last modified:
|
|
function getLastModifiedDateTime()
|
|
{
|
|
global $tableRefs; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
$query = "SELECT modified_date, modified_time FROM $tableRefs ORDER BY modified_date DESC, modified_time DESC, created_date DESC, created_time DESC LIMIT 1"; // get date/time info for the record that was added/edited most recently
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$row = mysqli_fetch_row($result); // fetch the current row into the array $row (it'll be always *one* row, but anyhow)
|
|
$lastModifiedDateTime = $row[0] . " " . $row[1];
|
|
|
|
return $lastModifiedDateTime;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Update the specified user permissions for the selected user(s):
|
|
function updateUserPermissions($userIDArray, $userPermissionsArray) // '$userPermissionsArray' must contain one or more key/value elements of the form array('allow_add' => 'yes', 'allow_delete' => 'no') where key is a particular 'allow_*' field name from table 'user_permissions' and value is either 'yes' or 'no'
|
|
{
|
|
global $tableUserPermissions; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
$permissionQueryArray = array();
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
// prepare the 'SET' part of the SQL query string:
|
|
foreach($userPermissionsArray as $permissionKey => $permissionValue)
|
|
$permissionQueryArray[] = $permissionKey . " = " . quote_smart($permissionValue);
|
|
|
|
if (!empty($userIDArray) AND !empty($permissionQueryArray))
|
|
{
|
|
// Update all specified permission settings in the 'user_permissions' table for the selected user(s):
|
|
$query = "UPDATE $tableUserPermissions SET " . implode(", ", $permissionQueryArray) . " WHERE user_id RLIKE " . quote_smart("^(" . implode("|", $userIDArray) . ")$");
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Generate or extract the cite key for the given record:
|
|
function generateCiteKey($formVars)
|
|
{
|
|
global $defaultCiteKeyFormat; // defined in 'ini.inc.php'
|
|
global $handleNonASCIICharsInCiteKeysDefault;
|
|
global $userOptionsArray; // '$userOptionsArray' is made globally available in file 'import_modify.php' as well as by functions 'generateExport()' and 'generateCitations()' in 'search.php'
|
|
|
|
// by default, we use any record-specific cite key that was entered manually by the user:
|
|
if (isset($formVars['citeKeyName']))
|
|
$citeKey = $formVars['citeKeyName'];
|
|
else
|
|
$citeKey = "";
|
|
|
|
|
|
// check if the user's options for auto-generation of cite keys command us to replace the manually entered cite key:
|
|
if (!empty($userOptionsArray))
|
|
{
|
|
if ($userOptionsArray['export_cite_keys'] == "yes") // if this user wants to include cite keys on import/export
|
|
{
|
|
if ($userOptionsArray['autogenerate_cite_keys'] == "yes") // if cite keys shall be auto-generated on import/export
|
|
{
|
|
if (empty($citeKey) OR ($userOptionsArray['prefer_autogenerated_cite_keys'] == "yes")) // if there's no manually entered cite key -OR- if the auto-generated cite key shall overwrite contents from the 'cite_key' field on import/export
|
|
{
|
|
if ($userOptionsArray['use_custom_cite_key_format'] == "yes") // if the user wants to use a custom cite key format
|
|
$citeKeyFormat = $userOptionsArray['cite_key_format'];
|
|
|
|
else // use the default cite key format that was specified by the admin in 'ini.inc.php'
|
|
$citeKeyFormat = $defaultCiteKeyFormat;
|
|
|
|
// auto-generate a cite key according to the given naming scheme:
|
|
$citeKey = parsePlaceholderString($formVars, $citeKeyFormat, "<:authors:><:year:>");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
$citeKey = ""; // by omitting a cite key Bibutils will take care of generation of cite keys for its export formats (BibTeX, Endnote, RIS)
|
|
}
|
|
|
|
|
|
// check how to handle non-ASCII characters:
|
|
if (!empty($userOptionsArray) AND !empty($userOptionsArray['nonascii_chars_in_cite_keys'])) // use the user's own setting
|
|
$handleNonASCIIChars = $userOptionsArray['nonascii_chars_in_cite_keys'];
|
|
else
|
|
$handleNonASCIIChars = $handleNonASCIICharsInCiteKeysDefault; // use the default setting that was specified by the admin in 'ini.inc.php'
|
|
|
|
// in addition to the handling of non-ASCII chars (given in '$handleNonASCIIChars') we'll
|
|
// strip additional characters from the generated cite keys: for cite keys, we only allow
|
|
// letters, digits, and the following characters: !$&*+-./:;<>?[]^_`|
|
|
// see e.g. the discussion of cite keys at: <http://search.cpan.org/~gward/btparse-0.34/doc/bt_language.pod>
|
|
if (!empty($citeKey))
|
|
$citeKey = handleNonASCIIAndUnwantedCharacters($citeKey, "[:alnum:]" . preg_quote("!$&*+-./:;<>?[]^_`|", "/"), $handleNonASCIIChars);
|
|
|
|
|
|
// ensure that each cite key is unique:
|
|
if (!empty($citeKey) AND !empty($userOptionsArray) AND ($userOptionsArray['export_cite_keys'] == "yes") AND ($userOptionsArray['uniquify_duplicate_cite_keys'] == "yes"))
|
|
// if the generated cite key already exists in the global array of found cite keys
|
|
// ('$citeKeysArray'), we'll uniquify it, otherwise we'll keep it as is:
|
|
$citeKey = ensureUniqueCiteKey($citeKey);
|
|
|
|
return $citeKey;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Handle non-ASCII and unwanted characters:
|
|
// this function controls the handling of any non-ASCII chars and
|
|
// unwanted characters in file/directory names and cite keys
|
|
function handleNonASCIIAndUnwantedCharacters($fileDirCitekeyName, $allowedFileDirCitekeyNameCharacters, $handleNonASCIIChars)
|
|
{
|
|
// we treat non-ASCII characters in file/directory names and cite keys depending on the setting of variable '$handleNonASCIIChars':
|
|
if ($handleNonASCIIChars == "strip")
|
|
$fileDirCitekeyName = convertToCharacterEncoding("ASCII", "IGNORE", $fileDirCitekeyName); // remove any non-ASCII characters
|
|
|
|
elseif ($handleNonASCIIChars != "keep")
|
|
// i.e., if '$handleNonASCIIChars = "keep"' we don't attempt to strip/transliterate any non-ASCII chars in the generated file/directory name or cite key;
|
|
// otherwise if '$handleNonASCIIChars = "transliterate"' (or when '$handleNonASCIIChars' contains an unrecognized/empty string)
|
|
// we'll transliterate most of the non-ASCII characters and strip all other non-ASCII chars that can't be converted into ASCII equivalents:
|
|
$fileDirCitekeyName = convertToCharacterEncoding("ASCII", "TRANSLIT", $fileDirCitekeyName);
|
|
|
|
|
|
// in addition, we remove all characters from the generated file/directory name or cite key which are not listed in variable '$allowedFileDirCitekeyNameCharacters':
|
|
if (!empty($allowedFileDirCitekeyNameCharacters))
|
|
$fileDirCitekeyName = preg_replace("/[^" . $allowedFileDirCitekeyNameCharacters . "]+/", "", $fileDirCitekeyName);
|
|
|
|
return $fileDirCitekeyName;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// this is a stupid hack that maps the names of the '$row' array keys to those used
|
|
// by the '$formVars' array (which is required by function 'generateCiteKey()')
|
|
// (eventually, the '$formVars' array should use the MySQL field names as names for its array keys)
|
|
function buildFormVarsArray($row)
|
|
{
|
|
$formVars = array(); // initialize array variable
|
|
|
|
if(isset($row['author']))
|
|
$formVars['authorName'] = $row['author'];
|
|
|
|
if(isset($row['title']))
|
|
$formVars['titleName'] = $row['title'];
|
|
|
|
if(isset($row['type']))
|
|
$formVars['typeName'] = $row['type'];
|
|
|
|
if(isset($row['year']))
|
|
$formVars['yearNo'] = $row['year'];
|
|
|
|
if(isset($row['publication']))
|
|
$formVars['publicationName'] = $row['publication'];
|
|
|
|
if(isset($row['abbrev_journal']))
|
|
$formVars['abbrevJournalName'] = $row['abbrev_journal'];
|
|
|
|
if(isset($row['volume']))
|
|
$formVars['volumeNo'] = $row['volume'];
|
|
|
|
if(isset($row['issue']))
|
|
$formVars['issueNo'] = $row['issue'];
|
|
|
|
if(isset($row['pages']))
|
|
$formVars['pagesNo'] = $row['pages'];
|
|
|
|
if(isset($row['corporate_author']))
|
|
$formVars['corporateAuthorName'] = $row['corporate_author'];
|
|
|
|
if(isset($row['thesis']))
|
|
$formVars['thesisName'] = $row['thesis'];
|
|
|
|
if(isset($row['address']))
|
|
$formVars['addressName'] = $row['address'];
|
|
|
|
if(isset($row['keywords']))
|
|
$formVars['keywordsName'] = $row['keywords'];
|
|
|
|
if(isset($row['abstract']))
|
|
$formVars['abstractName'] = $row['abstract'];
|
|
|
|
if(isset($row['publisher']))
|
|
$formVars['publisherName'] = $row['publisher'];
|
|
|
|
if(isset($row['place']))
|
|
$formVars['placeName'] = $row['place'];
|
|
|
|
if(isset($row['editor']))
|
|
$formVars['editorName'] = $row['editor'];
|
|
|
|
if(isset($row['language']))
|
|
$formVars['languageName'] = $row['language'];
|
|
|
|
if(isset($row['summary_language']))
|
|
$formVars['summaryLanguageName'] = $row['summary_language'];
|
|
|
|
if(isset($row['orig_title']))
|
|
$formVars['origTitleName'] = $row['orig_title'];
|
|
|
|
if(isset($row['series_editor']))
|
|
$formVars['seriesEditorName'] = $row['series_editor'];
|
|
|
|
if(isset($row['series_title']))
|
|
$formVars['seriesTitleName'] = $row['series_title'];
|
|
|
|
if(isset($row['abbrev_series_title']))
|
|
$formVars['abbrevSeriesTitleName'] = $row['abbrev_series_title'];
|
|
|
|
if(isset($row['series_volume']))
|
|
$formVars['seriesVolumeNo'] = $row['series_volume'];
|
|
|
|
if(isset($row['series_issue']))
|
|
$formVars['seriesIssueNo'] = $row['series_issue'];
|
|
|
|
if(isset($row['edition']))
|
|
$formVars['editionNo'] = $row['edition'];
|
|
|
|
if(isset($row['issn']))
|
|
$formVars['issnName'] = $row['issn'];
|
|
|
|
if(isset($row['isbn']))
|
|
$formVars['isbnName'] = $row['isbn'];
|
|
|
|
if(isset($row['medium']))
|
|
$formVars['mediumName'] = $row['medium'];
|
|
|
|
if(isset($row['area']))
|
|
$formVars['areaName'] = $row['area'];
|
|
|
|
if(isset($row['expedition']))
|
|
$formVars['expeditionName'] = $row['expedition'];
|
|
|
|
if(isset($row['conference']))
|
|
$formVars['conferenceName'] = $row['conference'];
|
|
|
|
if(isset($row['notes']))
|
|
$formVars['notesName'] = $row['notes'];
|
|
|
|
if(isset($row['approved']))
|
|
$formVars['approvedRadio'] = $row['approved'];
|
|
|
|
if(isset($row['location']))
|
|
$formVars['locationName'] = $row['location'];
|
|
|
|
if(isset($row['call_number']))
|
|
$formVars['callNumberName'] = $row['call_number'];
|
|
|
|
if(isset($row['serial']))
|
|
$formVars['serialNo'] = $row['serial'];
|
|
|
|
if(isset($row['online_publication']))
|
|
$formVars['onlinePublicationCheckBox'] = $row['online_publication'];
|
|
|
|
if(isset($row['online_citation']))
|
|
$formVars['onlineCitationName'] = $row['online_citation'];
|
|
|
|
if(isset($row['marked']))
|
|
$formVars['markedRadio'] = $row['marked'];
|
|
|
|
if(isset($row['copy']))
|
|
$formVars['copyName'] = $row['copy'];
|
|
|
|
if(isset($row['selected']))
|
|
$formVars['selectedRadio'] = $row['selected'];
|
|
|
|
if(isset($row['user_keys']))
|
|
$formVars['userKeysName'] = $row['user_keys'];
|
|
|
|
if(isset($row['user_notes']))
|
|
$formVars['userNotesName'] = $row['user_notes'];
|
|
|
|
if(isset($row['user_file']))
|
|
$formVars['userFileName'] = $row['user_file'];
|
|
|
|
if(isset($row['user_groups']))
|
|
$formVars['userGroupsName'] = $row['user_groups'];
|
|
|
|
if(isset($row['cite_key']))
|
|
$formVars['citeKeyName'] = $row['cite_key'];
|
|
|
|
if(isset($row['related']))
|
|
$formVars['relatedName'] = $row['related'];
|
|
|
|
if(isset($row['orig_record']))
|
|
$formVars['origRecord'] = $row['orig_record'];
|
|
|
|
if(isset($row['file']))
|
|
$formVars['fileName'] = $row['file'];
|
|
|
|
if(isset($row['url']))
|
|
$formVars['urlName'] = $row['url'];
|
|
|
|
if(isset($row['doi']))
|
|
$formVars['doiName'] = $row['doi'];
|
|
|
|
return $formVars;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Build properly formatted <option> tag elements from items listed within an array or string (and which -- in the case of strings -- are delimited by '$splitDelim').
|
|
// The string given in '$prefix' will be used to prefix each of the <option> tags (e.g., use '\t\t' to indent each of the tags by 2 tabs)
|
|
function buildSelectMenuOptions($sourceData, $splitDelim, $prefix, $useArrayKeysAsValues)
|
|
{
|
|
if (is_string($sourceData)) // split the string on the specified delimiter (which is interpreted as regular expression!):
|
|
$sourceData = preg_split($splitDelim, $sourceData);
|
|
|
|
if ($useArrayKeysAsValues)
|
|
{
|
|
$optionTags = ""; // initialize variable
|
|
|
|
// copy each item as option tag element to the end of the '$optionTags' variable:
|
|
foreach ($sourceData as $itemID => $item)
|
|
{
|
|
if (!empty($item))
|
|
$optionTags .= "\n$prefix<option value=\"$itemID\">$item</option>";
|
|
else // empty items will also get an empty value:
|
|
$optionTags .= "\n$prefix<option value=\"\"></option>";
|
|
}
|
|
}
|
|
else
|
|
$optionTags = "\n$prefix<option>" . implode("</option>\n$prefix<option>", $sourceData) . "</option>";
|
|
|
|
return $optionTags;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Produce a <select> list with unique items from the specified field
|
|
// Parameters:
|
|
// 1: Database connection
|
|
// 2. Table that contains values
|
|
// 3. The field name of the table's primary key
|
|
// 4. Table name of the user data table
|
|
// 5. The field name within the user data table that corresponds to the field in 3.
|
|
// 6. The field name of the user ID field within the user data table
|
|
// 7. The user ID of the currently logged in user (which must be provided as a session variable)
|
|
// 8. Attribute that contains values
|
|
// 9. <SELECT> element name
|
|
// 10. An additional non-database value (display string)
|
|
// 11. String that gets submitted instead of the display string given in 10.
|
|
// 12. Optional <OPTION SELECTED>
|
|
// 13. Restrict query to field... (keep empty if no restriction wanted)
|
|
// 14. ...where field contents are...
|
|
// 15. Split field contents into substrings? (yes = true, no = false)
|
|
// 16. POSIX-PATTERN to split field contents into substrings (in order to obtain actual values)
|
|
// 17. The type of the output format that shall be returned ("ARRAY", "HTML SELECT", "HTML UL" or "JSON")
|
|
// 18. The POSIX-PATTERN that matches those substrings from the field's contents that shall be included as search suggestions
|
|
// 19. Boolean that specifies whether search suggestions shall be wrapped into an enclosing HTML (or JSON) structure (yes if 'true')
|
|
function selectDistinct($connection, // 1.
|
|
$refsTableName, // 2.
|
|
$refsTablePrimaryKey, // 3.
|
|
$userDataTableName, // 4.
|
|
$userDataTablePrimaryKey, // 5.
|
|
$userDataTableUserID, // 6.
|
|
$userDataTableUserIDvalue, // 7.
|
|
$columnName, // 8.
|
|
$pulldownName, // 9.
|
|
$additionalOptionDisplay, // 10.
|
|
$additionalOption, // 11.
|
|
$defaultValue, // 12.
|
|
$RestrictToField, // 13.
|
|
$RestrictToFieldContents, // 14.
|
|
$SplitValues, // 15.
|
|
$SplitPattern, // 16.
|
|
$outputFormat = "HTML SELECT", // 17.
|
|
$searchSuggestionsPattern = "", // 18.
|
|
$wrapSearchSuggestions = true) // 19.
|
|
{
|
|
$defaultWithinResultSet = FALSE;
|
|
|
|
// Query to find distinct values of '$columnName' in '$refsTableName':
|
|
if (isset($_SESSION['loginEmail'])) // if a user is logged in
|
|
{
|
|
if ($RestrictToField == "")
|
|
$distinctQuery = "SELECT DISTINCT $columnName FROM $refsTableName LEFT JOIN $userDataTableName ON $refsTablePrimaryKey = $userDataTablePrimaryKey AND $userDataTableUserID = $userDataTableUserIDvalue ORDER BY $columnName";
|
|
else
|
|
$distinctQuery = "SELECT DISTINCT $columnName FROM $refsTableName LEFT JOIN $userDataTableName ON $refsTablePrimaryKey = $userDataTablePrimaryKey AND $userDataTableUserID = $userDataTableUserIDvalue WHERE $RestrictToField RLIKE $RestrictToFieldContents ORDER BY $columnName";
|
|
}
|
|
else // if NO user is logged in
|
|
{
|
|
if ($RestrictToField == "")
|
|
$distinctQuery = "SELECT DISTINCT $columnName FROM $refsTableName ORDER BY $columnName";
|
|
else
|
|
$distinctQuery = "SELECT DISTINCT $columnName FROM $refsTableName WHERE $RestrictToField RLIKE $RestrictToFieldContents ORDER BY $columnName";
|
|
}
|
|
|
|
// Run the distinctQuery on the database through the connection:
|
|
$resultId = queryMySQLDatabase($distinctQuery);
|
|
|
|
// Retrieve all distinct values:
|
|
$i = 0;
|
|
$resultBuffer = array();
|
|
|
|
while ($row = @ mysqli_fetch_array($resultId))
|
|
{
|
|
if ($SplitValues) // if desired, split field contents into substrings
|
|
{
|
|
// split field data on the pattern specified in '$SplitPattern':
|
|
$splittedFieldData = preg_split("#" . $SplitPattern . "#", $row[$columnName]);
|
|
// ... copy all array elements to end of '$resultBuffer':
|
|
foreach($splittedFieldData as $element)
|
|
{
|
|
$element = trim($element);
|
|
// NOTE: in case of OpenSearch search suggestions, we only include those substrings
|
|
// that match the regular expression given in '$searchSuggestionsPattern'
|
|
if (empty($searchSuggestionsPattern) OR (!empty($searchSuggestionsPattern) AND !empty($element) AND preg_match("/" . $searchSuggestionsPattern . "/i", $element)))
|
|
$resultBuffer[$i++] = $element;
|
|
}
|
|
}
|
|
else // copy field data (as is) to end of '$resultBuffer':
|
|
{
|
|
$element = trim($row[$columnName]);
|
|
if (empty($searchSuggestionsPattern) OR (!empty($searchSuggestionsPattern) AND !empty($element)))
|
|
$resultBuffer[$i++] = $element;
|
|
}
|
|
}
|
|
|
|
if ($SplitValues) // (otherwise, data are already DISTINCT and ORDERed BY!)
|
|
{
|
|
if (!empty($resultBuffer))
|
|
{
|
|
// remove duplicate values from array:
|
|
$resultBuffer = array_unique($resultBuffer);
|
|
// sort in ascending order:
|
|
sort($resultBuffer);
|
|
}
|
|
}
|
|
|
|
if ($outputFormat == "ARRAY") // return data as a PHP array:
|
|
{
|
|
return $resultBuffer;
|
|
}
|
|
else // return data as HTML or JSON:
|
|
{
|
|
$outputData = "";
|
|
|
|
if ($outputFormat == "HTML SELECT") // output data in an HTML select widget:
|
|
{
|
|
// Start the HTML select widget:
|
|
if ($wrapSearchSuggestions)
|
|
$outputData = "\n\t\t<select name=\"$pulldownName\">";
|
|
|
|
$optionTags = ""; // initialize variable
|
|
|
|
// Add any additional option element:
|
|
if (!empty($additionalOptionDisplay) AND !empty($additionalOption))
|
|
$optionTags .= "\n\t\t\t<option value=\"$additionalOption\">$additionalOptionDisplay</option>";
|
|
|
|
// Build correct option tags from the provided database values:
|
|
$optionTags .= buildSelectMenuOptions($resultBuffer, "//", "\t\t\t", false);
|
|
|
|
$outputData .= preg_replace("/<option([^>]*)>($defaultValue)<\\/option>/", "<option\\1 selected>\\2</option>", $optionTags); // add 'selected' attribute
|
|
|
|
if ($wrapSearchSuggestions)
|
|
$outputData .= "\n\t\t</select>";
|
|
}
|
|
|
|
elseif (($outputFormat == "HTML UL") AND !empty($resultBuffer)) // output data in an unordered HTML list:
|
|
{
|
|
$outputData = "<li>" . implode("</li><li>", $resultBuffer) . "</li>";
|
|
|
|
if ($wrapSearchSuggestions)
|
|
$outputData = "<ul>" . $outputData . "</ul>";
|
|
}
|
|
|
|
elseif (($outputFormat == "JSON") AND !empty($resultBuffer)) // output data in JSON format:
|
|
{
|
|
$outputData = '"' . implode('", "', $resultBuffer) . '"'; // for PHP 5 >= 5.2.0 and UTF-8 data, function 'json_encode()' could be used instead
|
|
|
|
if ($wrapSearchSuggestions)
|
|
$outputData = "[" . $outputData . "]";
|
|
}
|
|
|
|
return $outputData;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Returns values from the given field & table:
|
|
function getFieldContents($tableName, $columnName, $userID = "", $queryWhereClause = "", $orderBy = "", $getDistinctValues = true)
|
|
{
|
|
global $tableRefs, $tableUserData; // defined in 'db.inc.php'
|
|
|
|
connectToMySQLDatabase();
|
|
|
|
if ($getDistinctValues)
|
|
$distinct = "DISTINCT ";
|
|
else
|
|
$distinct = "";
|
|
|
|
// CONSTRUCT SQL QUERY:
|
|
$query = "SELECT " . $distinct . $columnName
|
|
. " FROM " . $tableName;
|
|
|
|
if (($tableName == $tableRefs) AND isset($_SESSION['loginEmail']) AND !empty($userID)) // when querying table 'refs', and if a user is logged in...
|
|
$query .= " LEFT JOIN " . $tableUserData . " ON serial = record_id AND user_id = " . quote_smart($userID);
|
|
|
|
if (!empty($queryWhereClause))
|
|
$query .= " WHERE " . $queryWhereClause;
|
|
|
|
if (!empty($orderBy))
|
|
$query .= " ORDER BY " . $orderBy;
|
|
|
|
$result = queryMySQLDatabase($query); // RUN the query on the database through the connection
|
|
|
|
$fieldContentsArray = array(); // initialize array variable
|
|
|
|
$rowsFound = @ mysqli_num_rows($result);
|
|
if ($rowsFound > 0) // If there were rows found ...
|
|
{
|
|
while ($row = @ mysqli_fetch_array($result)) // for all rows found
|
|
$fieldContentsArray[] = $row[$columnName]; // append this row's field value to the array of extracted field values
|
|
}
|
|
|
|
return $fieldContentsArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Remove a text pattern from the beginning and/or end of a string:
|
|
// This function is used to remove leading and/or trailing delimiters from a string.
|
|
// Notes: - '$removePattern' must be specified as perl-style regular expression!
|
|
// - set both variables '$trimLeft' & '$trimRight' to 'true' if you want your text pattern to get removed from BOTH sides of the source string;
|
|
// if you only want to trim the LEFT side of your source string: set '$trimLeft = true' & '$trimRight = false';
|
|
// if you only want to trim the RIGHT side of your source string: set '$trimLeft = false' & '$trimRight = true';
|
|
// Example: if '$removePattern' = ' *; *' and both, '$trimLeft' and '$trimRight', are set to 'true',
|
|
// the string '; red; green; yellow; ' would be transformed to 'red; green; yellow'.
|
|
function trimTextPattern($sourceString, $removePattern, $trimLeft, $trimRight)
|
|
{
|
|
if ($trimLeft)
|
|
$sourceString = preg_replace("/^" . $removePattern . "/", "", $sourceString); // remove text pattern from beginning of source string
|
|
|
|
if ($trimRight)
|
|
$sourceString = preg_replace("/" . $removePattern . "$/", "", $sourceString); // remove text pattern from end of source string
|
|
|
|
return $sourceString; // return the trimmed source string
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Quote variable to make safe (and escape special characters in a string for use in a SQL statement):
|
|
function quote_smart($value)
|
|
{
|
|
// Remove slashes from value if 'magic_quotes_gpc = On':
|
|
$value = stripSlashesIfMagicQuotes($value);
|
|
|
|
// Remove any leading or trailing whitespace:
|
|
$value = trim($value);
|
|
|
|
// Quote & escape special chars if not a number or a numeric string:
|
|
if (!is_numeric($value))
|
|
{
|
|
$value = "\"" . escapeSQL($value) . "\"";
|
|
}
|
|
// Quote numbers with leading zeros (which would otherwise get stripped):
|
|
elseif (preg_match("/^0+\d+$/", $value))
|
|
{
|
|
$value = "\"" . $value . "\"";
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Get the path to the currently executing script, relative to the document root:
|
|
function scriptURL()
|
|
{
|
|
if (isset($_SERVER['SCRIPT_NAME']))
|
|
{
|
|
$pathToScript = $_SERVER['SCRIPT_NAME'];
|
|
}
|
|
else
|
|
{
|
|
$pathToScript = $_SERVER['PHP_SELF'];
|
|
|
|
// Sanitize PHP_SELF:
|
|
if (preg_match('#\.php.+#', $pathToScript))
|
|
{
|
|
// Remove anything after the PHP file extension:
|
|
$pathToScript = preg_replace('#(?<=\.php).+#', '', $pathToScript);
|
|
}
|
|
}
|
|
|
|
// NOTE: When a 'show.php' URL is called from within another script via function 'fetchDataFromURL()'
|
|
// (as is the case for 'index.php'), '$_SERVER['SCRIPT_NAME']' and '$_SERVER['PHP_SELF']' do seem
|
|
// to return double slashes for path separators (e.g. "/refs//search.php"). I don't know why this
|
|
// happens. The line below fixes this:
|
|
$pathToScript = preg_replace('#//+#', '/', $pathToScript);
|
|
|
|
return $pathToScript;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Verify the given path:
|
|
//
|
|
// NOTES: - Currently, this function just ensures that the given '$path' (i.e. a
|
|
// file directory path or URL) ends with a slash. However, it would be
|
|
// nice if this function would also check whether the given path or URL
|
|
// exists, and issue a warning if not.
|
|
// - '$type' must be either "path" or "URL"
|
|
//
|
|
// TODO: - Should we attempt to auto-guess the '$type' form the given '$path'?
|
|
// - Make sure that the correct path separator gets used on Windows
|
|
function checkPath($path, $type = "path", $addTrailingSlash = true)
|
|
{
|
|
// if (preg_match("/Windows/i", getenv("OS")) // should we query 'HTTP_USER_AGENT' instead?
|
|
// $pathSeparator = '\\'; // is this actually necessary? (I vaguely remember that PHP also uses '/' on Windows)
|
|
// else
|
|
$pathSeparator = '/';
|
|
|
|
if ($addTrailingSlash)
|
|
$path = preg_replace('#(?<!^|/)$#', $pathSeparator, $path);
|
|
|
|
return $path;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Removes slashes from the input string if 'magic_quotes_gpc = On':
|
|
function stripSlashesIfMagicQuotes($sourceString)
|
|
{
|
|
$magicQuotes = ini_get("magic_quotes_gpc"); // check the value of the 'magic_quotes_gpc' directive in 'php.ini'
|
|
|
|
if ($magicQuotes) // magic_quotes_gpc = On
|
|
$sourceString = convertSlashes($sourceString);
|
|
|
|
return $sourceString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Fix escape sequences within a string (i.e., remove 'unwanted' slashes):
|
|
function convertSlashes($sourceString)
|
|
{
|
|
// $sourceString = stripslashes($sourceString);
|
|
|
|
// Note that function 'stripslashes()' cannot be used here since it may remove too many slashes!
|
|
// As an example, assume a user input in 'show.php' like this:
|
|
//
|
|
// <my cite_key> ... <is within list> ... Mock++1997Bacteria
|
|
//
|
|
// 'Mock++1997Bacteria' gets preg_quote()d in 'show.php' to 'Mock\+\+1997Bacteria'. This
|
|
// is necessary to escape any potential grep metacharacters inside the user's cite keys.
|
|
//
|
|
// So, for an input of '^(Mock\+\+1997Bacteria)$', following scenario will occur with 'magic_quotes_gpc = On':
|
|
//
|
|
// Case 1 ('convertSlashes()' uses 'stripslashes()'):
|
|
// 'show.php' -> 'quote_smart()' -> 'stripSlashesIfMagicQuotes()' -> 'convertSlashes()': ^(Mock++1997Bacteria)$ -> this step incorrectly strips the slashes!
|
|
// 'show.php' -> 'quote_smart()' -> 'escapeSQL()': ^(Mock++1997Bacteria)$
|
|
// 'show.php' -> 'quote_smart()': "^(Mock++1997Bacteria)$"
|
|
// 'search.php' receives: \"^(Mock++1997Bacteria)$\"
|
|
// 'search.php' -> 'verifySQLQuery()' -> 'stripSlashesIfMagicQuotes()' -> 'convertSlashes()': "^(Mock++1997Bacteria)$"
|
|
//
|
|
// Case 2 ('convertSlashes()' uses 'str_replace'):
|
|
// 'show.php' -> 'quote_smart()' -> 'stripSlashesIfMagicQuotes()' -> 'convertSlashes()': ^(Mock\+\+1997Bacteria)$
|
|
// 'show.php' -> 'quote_smart()' -> 'escapeSQL()': ^(Mock\\+\\+1997Bacteria)$
|
|
// 'show.php' -> 'quote_smart()': "^(Mock\\+\\+1997Bacteria)$"
|
|
// 'search.php' receives: \"^(Mock\\\\+\\\\+1997Bacteria)$\"
|
|
// 'search.php' -> 'verifySQLQuery()' -> 'stripSlashesIfMagicQuotes()' -> 'convertSlashes()': "^(Mock\\+\\+1997Bacteria)$"
|
|
//
|
|
// This means that 'stripslashes()' fails while the code below seems to work:
|
|
|
|
$sourceString = str_replace('\"', '"', $sourceString); // replace any \" with "
|
|
$sourceString = str_replace("\\'", "'", $sourceString); // replace any \' with '
|
|
$sourceString = str_replace("\\\\", "\\", $sourceString);
|
|
// $sourceString = preg_replace('/(\\\\)+/i', '\\\\', $sourceString); // instead of the previous line, this would kinda work if SQL strings aren't quote_smart()ed
|
|
|
|
return $sourceString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Perform search & replace actions on the given text input:
|
|
// ('$includesSearchPatternDelimiters' must be a boolean value that specifies whether the leading and trailing slashes
|
|
// are included within the search pattern ['true'] or not ['false'])
|
|
function searchReplaceText($searchReplaceActionsArray, $sourceString, $includesSearchPatternDelimiters)
|
|
{
|
|
// this allows to use '$loc' within the replacement pattern
|
|
// e.g. like this: array("/(.+)/e" => "\$loc['\\1']")
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
// apply the search & replace actions defined in '$searchReplaceActionsArray' to the text passed in '$sourceString':
|
|
foreach ($searchReplaceActionsArray as $searchString => $replaceString)
|
|
{
|
|
if (!$includesSearchPatternDelimiters)
|
|
$searchString = "/" . $searchString . "/"; // add search pattern delimiters
|
|
|
|
if (preg_match($searchString, $sourceString))
|
|
$sourceString = preg_replace($searchString, $replaceString, $sourceString);
|
|
}
|
|
|
|
return $sourceString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Perform case transformations on the given text input:
|
|
// ('$transformation' must be either 'lower', 'upper', 'title' or 'heading')
|
|
//
|
|
// NOTE: For UTF-8, the PHP functions 'strtolower()' and 'strtoupper()' will only work correctly
|
|
// if the server has locales installed which support UTF-8! More info is available at:
|
|
// <http://www.phpwact.org/php/i18n/charsets>
|
|
// <http://www.phpwact.org/php/i18n/utf-8>
|
|
//
|
|
// TODO: Implement function 'changeCase()' so that it always works for UTF-8
|
|
// See e.g. functions 'utf8_strtolower()' and 'utf8_strtoupper()' at
|
|
// <http://dev.splitbrain.org/view/darcs/dokuwiki/inc/utf8.php>
|
|
function changeCase($transformation, $sourceString)
|
|
{
|
|
if (preg_match("/lower/i", $transformation)) // change source text to lower case
|
|
$sourceString = strtolower($sourceString);
|
|
|
|
elseif (preg_match("/upper/i", $transformation)) // change source text to upper case
|
|
$sourceString = strtoupper($sourceString);
|
|
|
|
elseif (preg_match("/title/i", $transformation)) // change source text to title case
|
|
$sourceString = preg_replace("/\b(\w)(\w+)/e", "strtoupper('\\1').strtolower('\\2')", $sourceString); // the 'e' modifier allows to execute PHP code within the replacement pattern
|
|
|
|
elseif (preg_match("/heading/i", $transformation)) // change source text to heading case (opposed to 'title', we only touch words with more than 3 chars, and we only change the case of the first letter but not any subsequent ones)
|
|
$sourceString = preg_replace("/\b(\w)(\w{3,})/e", "strtoupper('\\1').'\\2'", $sourceString); // the 'e' modifier allows to execute PHP code within the replacement pattern
|
|
|
|
return $sourceString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Sets the system's locale information:
|
|
// On *NIX systems, use "locale -a" on the command line to display all locales
|
|
// supported on your system. See <http://www.php.net/setlocale> for more information.
|
|
function setSystemLocale($charSet = "", $systemLocales = "NONE")
|
|
{
|
|
global $contentTypeCharset; // these variables are defined in 'ini.inc.php'
|
|
global $convertExportDataToUTF8;
|
|
|
|
if (empty($charSet))
|
|
$charSet = $contentTypeCharset;
|
|
|
|
if ($systemLocales == "NONE") {
|
|
if ($charSet == "UTF-8")
|
|
$systemLocales = array('en_US.UTF-8', 'en_GB.UTF-8', 'en_CA.UTF-8', 'en_AU.UTF-8', 'en_NZ.UTF-8', 'de_DE.UTF-8', 'fr_FR.UTF-8', 'es_ES.UTF-8');
|
|
else // we assume "ISO-8859-1" by default
|
|
$systemLocales = array('en_US.ISO8859-1', 'en_GB.ISO8859-1', 'en_CA.ISO8859-1', 'en_AU.ISO8859-1', 'en_NZ.ISO8859-1', 'de_DE.ISO8859-1', 'fr_FR.ISO8859-1', 'es_ES.ISO8859-1');
|
|
}
|
|
|
|
setlocale(LC_COLLATE, $systemLocales); // set locale for string comparison (including pattern matching)
|
|
setlocale(LC_CTYPE, $systemLocales); // set locale for character classification and conversion, for example 'strtoupper()'
|
|
|
|
// get the current settings without affecting them:
|
|
$systemLocaleCollate = setlocale(LC_COLLATE, "0");
|
|
$systemLocaleCType = setlocale(LC_CTYPE, "0");
|
|
|
|
return array($systemLocaleCollate, $systemLocaleCType);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Sets the mimetype & character encoding in the header:
|
|
function setHeaderContentType($contentType, $contentTypeCharset)
|
|
{
|
|
header('Content-type: ' . $contentType . '; charset=' . $contentTypeCharset);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Set HTTP status response
|
|
|
|
// From user 'Ciantic' found at <http://www.php.net/header> (24-Dec-2005 03:07)
|
|
// This contains all HTTP status responses defined in RFC2616 section 6.1.1
|
|
// See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1>
|
|
function setHTTPStatus($statusCode)
|
|
{
|
|
// HTTP Protocol defined status codes:
|
|
static $http = array(100 => "HTTP/1.1 100 Continue",
|
|
101 => "HTTP/1.1 101 Switching Protocols",
|
|
200 => "HTTP/1.1 200 OK",
|
|
201 => "HTTP/1.1 201 Created",
|
|
202 => "HTTP/1.1 202 Accepted",
|
|
203 => "HTTP/1.1 203 Non-Authoritative Information",
|
|
204 => "HTTP/1.1 204 No Content",
|
|
205 => "HTTP/1.1 205 Reset Content",
|
|
206 => "HTTP/1.1 206 Partial Content",
|
|
300 => "HTTP/1.1 300 Multiple Choices",
|
|
301 => "HTTP/1.1 301 Moved Permanently",
|
|
302 => "HTTP/1.1 302 Found",
|
|
303 => "HTTP/1.1 303 See Other",
|
|
304 => "HTTP/1.1 304 Not Modified",
|
|
305 => "HTTP/1.1 305 Use Proxy",
|
|
307 => "HTTP/1.1 307 Temporary Redirect",
|
|
400 => "HTTP/1.1 400 Bad Request",
|
|
401 => "HTTP/1.1 401 Unauthorized",
|
|
402 => "HTTP/1.1 402 Payment Required",
|
|
403 => "HTTP/1.1 403 Forbidden",
|
|
404 => "HTTP/1.1 404 Not Found",
|
|
405 => "HTTP/1.1 405 Method Not Allowed",
|
|
406 => "HTTP/1.1 406 Not Acceptable",
|
|
407 => "HTTP/1.1 407 Proxy Authentication Required",
|
|
408 => "HTTP/1.1 408 Request Time-out",
|
|
409 => "HTTP/1.1 409 Conflict",
|
|
410 => "HTTP/1.1 410 Gone",
|
|
411 => "HTTP/1.1 411 Length Required",
|
|
412 => "HTTP/1.1 412 Precondition Failed",
|
|
413 => "HTTP/1.1 413 Request Entity Too Large",
|
|
414 => "HTTP/1.1 414 Request-URI Too Large",
|
|
415 => "HTTP/1.1 415 Unsupported Media Type",
|
|
416 => "HTTP/1.1 416 Requested range not satisfiable",
|
|
417 => "HTTP/1.1 417 Expectation Failed",
|
|
500 => "HTTP/1.1 500 Internal Server Error",
|
|
501 => "HTTP/1.1 501 Not Implemented",
|
|
502 => "HTTP/1.1 502 Bad Gateway",
|
|
503 => "HTTP/1.1 503 Service Unavailable",
|
|
504 => "HTTP/1.1 504 Gateway Time-out");
|
|
|
|
header($http[$statusCode]);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// This function takes the URL given in '$sourceURL' and retrieves the returned data:
|
|
function fetchDataFromURL($sourceURL)
|
|
{
|
|
global $errors;
|
|
|
|
$handle = fopen($sourceURL, "r"); // fetch data from URL in read mode
|
|
|
|
$sourceData = "";
|
|
|
|
if ($handle)
|
|
{
|
|
while (!feof($handle))
|
|
{
|
|
$sourceData .= fread($handle, 4096); // read data in chunks
|
|
}
|
|
fclose($handle);
|
|
}
|
|
else
|
|
{
|
|
$errorMessage = "Error occurred: Failed to open " . $sourceURL; // network error
|
|
|
|
if (!isset($errors["sourceText"]))
|
|
$errors["sourceText"] = $errorMessage;
|
|
else
|
|
$errors["sourceText"] = $errors["sourceText"] . "<br>" . $errorMessage;
|
|
}
|
|
|
|
return $sourceData;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Send '$dataString' as POST request (using the 'application/x-www-form-urlencoded'
|
|
// content type) to the given '$host'/'$path':
|
|
function sendPostRequest($host, $path, $referer, $dataString)
|
|
{
|
|
$port = 80; // server port to be used with the connection
|
|
$timeout = 600; // connection time out in seconds
|
|
$result = "";
|
|
|
|
// build header:
|
|
$header = "POST " . $path . " HTTP/1.0\r\n" // "HTTP/1.1" would return data with "Transfer-Encoding: chunked"
|
|
. "Host: " . $host . "\r\n"
|
|
. "Referer: " . $referer . "\r\n"
|
|
. "Content-Type: application/x-www-form-urlencoded\r\n"
|
|
. "Content-Length: ". strlen($dataString) ."\r\n"
|
|
. "\r\n";
|
|
|
|
// open connection:
|
|
// see <http://www.php.net/fsockopen>
|
|
$fp = fsockopen($host, $port, $errorNo, $errorMsg, $timeout);
|
|
|
|
if (!$fp)
|
|
{
|
|
$result = "Error $errorNo : $errorMsg";
|
|
}
|
|
else
|
|
{
|
|
// POST data:
|
|
fputs($fp, $header . $dataString);
|
|
|
|
// read result:
|
|
while (!feof($fp))
|
|
$result .= fgets($fp, 1024);
|
|
|
|
// close connection:
|
|
fclose($fp);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Detect character encoding:
|
|
// NOTE: - Currently, this function only distinguishes between ISO-8859-1 and UTF-8!
|
|
function detectCharacterEncoding($sourceString, $detectOrder = "")
|
|
{
|
|
// Method A:
|
|
// Function 'mb_detect_encoding()' requires PHP with multi-byte support (i.e., PHP must
|
|
// be compiled with the '--enable-mbstring' configure option).
|
|
// (see: <http://php.net/manual/en/function.mb-detect-encoding.php>)
|
|
|
|
// $charSet = "";
|
|
|
|
// if (empty($detectOrder))
|
|
// Set the default character encoding detection order:
|
|
// (see: <http://www.php.net/mb-detect-order>)
|
|
// $detectOrder = implode(", ", mb_detect_order()); // on an English system this may be e.g. "ASCII, UTF-8" which wouldn't be useful in our case
|
|
// $detectOrder = "UTF-8, ISO-8859-1"; // in case of refbase, we currently hardcode the detection order
|
|
|
|
// Detect the character encoding of the given '$sourceString' with the given '$detectOrder':
|
|
// $charSet = mb_detect_encoding($sourceString . "a", $detectOrder); // an ASCII char is appended to avoid a bug, see comment by <hoermann dot j at gmail dot com> at <http://php.net/manual/en/function.mb-detect-encoding.php>
|
|
|
|
|
|
// Method B:
|
|
// Based on function 'detectUTF8()' by user <chris at w3style dot co dot uk>
|
|
// at <http://php.net/manual/en/function.mb-detect-encoding.php>
|
|
// (see also: <http://w3.org/International/questions/qa-forms-utf-8.html>)
|
|
|
|
// Check if a string contains UTF-8 characters:
|
|
// NOTE: This regex pattern only looks for non-ASCII multibyte sequences in
|
|
// the UTF-8 range and stops once it finds at least one multibytes string.
|
|
if (preg_match('%(?:
|
|
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|
|
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|
|
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|
|
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|
|
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|
|
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|
|
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
|
|
)+%xs', $sourceString))
|
|
$charSet = "UTF-8"; // found at least one multibyte UTF-8 character
|
|
else
|
|
$charSet = "ISO-8859-1";
|
|
|
|
return $charSet;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Convert to character encoding:
|
|
// This function converts text that's represented in '$sourceCharset' into the character encoding
|
|
// given in '$targetCharset'. If '$sourceCharset' isn't given, we default to the refbase database
|
|
// encoding (which is indicated in '$contentTypeCharset'). '$transliteration' must be either
|
|
// "TRANSLIT" or "IGNORE" causing characters which are unrecognized by the target charset to get
|
|
// either transliterated or ignored, respectively.
|
|
function convertToCharacterEncoding($targetCharset, $transliteration, $sourceString, $sourceCharset = "")
|
|
{
|
|
global $contentTypeCharset; // defined in 'ini.inc.php'
|
|
global $transtab_latin1_ascii; // defined in 'transtab_latin1_ascii.inc.php'
|
|
global $transtab_unicode_ascii; // defined in 'transtab_unicode_ascii.inc.php'
|
|
global $transtab_unicode_latin1; // defined in 'transtab_unicode_latin1.inc.php'
|
|
global $transtab_unicode_refbase; // defined in 'transtab_unicode_refbase.inc.php'
|
|
|
|
if (empty($sourceCharset))
|
|
$sourceCharset = $contentTypeCharset;
|
|
|
|
// In case of ISO-8859-1/UTF-8 to ASCII conversion we attempt to transliterate non-ASCII chars,
|
|
// comparable to the fallback notations that people use commonly in email and on typewriters to
|
|
// represent unavailable characters:
|
|
if (($targetCharset == "ASCII") AND ($transliteration == "TRANSLIT"))
|
|
{
|
|
if ($sourceCharset == "UTF-8")
|
|
$convertedString = searchReplaceText($transtab_unicode_ascii, $sourceString, false);
|
|
else // we assume "ISO-8859-1" by default
|
|
$convertedString = searchReplaceText($transtab_latin1_ascii, $sourceString, false);
|
|
|
|
// Strip any additional non-ASCII characters which we weren't able to transliterate:
|
|
$convertedString = iconv($sourceCharset, "ASCII//IGNORE", $convertedString);
|
|
|
|
// Notes from <http://www.php.net/manual/en/function.iconv.php> regarding "TRANSLIT" and "IGNORE":
|
|
// - If you append the string //TRANSLIT to out_charset transliteration is activated.
|
|
// This means that when a character can't be represented in the target charset, it can
|
|
// be approximated through one or several similarly looking characters. If you append
|
|
// the string //IGNORE, characters that cannot be represented in the target charset
|
|
// are silently discarded. Otherwise, str is cut from the first illegal character.
|
|
}
|
|
|
|
// Similar to the ISO-8859-1/UTF-8 to ASCII conversion we attempt to transliterate non-latin1 chars when
|
|
// converting from UTF-8 to ISO-8859-1.
|
|
// NOTE: we don't use 'iconv("UTF-8", "ISO-8859-1//TRANSLIT", $sourceString)' here, since this seems to
|
|
// abort the conversion with an error ("Detected an illegal character in input string") if e.g. a
|
|
// greek delta character is encountered.
|
|
elseif (($targetCharset == "ISO-8859-1") AND ($transliteration == "TRANSLIT") AND ($sourceCharset == "UTF-8"))
|
|
{
|
|
// Convert Unicode entities to refbase markup (if possible):
|
|
$convertedString = searchReplaceText($transtab_unicode_refbase, $sourceString, true);
|
|
|
|
// Attempt to transliterate any remaining non-latin1 characters:
|
|
$convertedString = searchReplaceText($transtab_unicode_latin1, $convertedString, false);
|
|
|
|
// Strip any additional non-latin1 characters which we weren't able to transliterate:
|
|
$convertedString = iconv($sourceCharset, "ISO-8859-1//IGNORE", $convertedString);
|
|
}
|
|
|
|
else
|
|
$convertedString = iconv($sourceCharset, "$targetCharset//$transliteration", $sourceString);
|
|
|
|
return $convertedString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Encode HTML entities:
|
|
// (this custom function is provided so that it'll be easier to change the way how entities are HTML encoded later on)
|
|
function encodeHTML($sourceString)
|
|
{
|
|
global $contentTypeCharset; // defined in 'ini.inc.php'
|
|
|
|
// Note: Using PHP 5.0.4, I couldn't get 'htmlentities()' to work properly with UTF-8. Apparently, versions before
|
|
// PHP 4.3.11 and PHP 5.0.4 had a partially incorrect utf8 to htmlentities mapping (see <http://bugs.php.net/28067>),
|
|
// however, PHP 5.0.4 still seems buggy to me. Therefore, in case of UTF-8, we'll use 'mb_convert_encoding()' instead.
|
|
// IMPORTANT: this requires multi-byte support enabled on your PHP server!
|
|
// (i.e., PHP must be compiled with the '--enable-mbstring' configure option)
|
|
if ($contentTypeCharset == "UTF-8")
|
|
{
|
|
// encode HTML special chars
|
|
$sourceString = encodeHTMLspecialchars($sourceString);
|
|
// converts from 'UTF-8' to 'HTML-ENTITIES' (see: <http://php.net/manual/en/function.mb-convert-encoding.php>)
|
|
$encodedString = mb_convert_encoding($sourceString, 'HTML-ENTITIES', "$contentTypeCharset");
|
|
}
|
|
else
|
|
$encodedString = htmlentities($sourceString, ENT_COMPAT, "$contentTypeCharset");
|
|
// Notes from <http://www.php.net/htmlentities>:
|
|
//
|
|
// - The optional second parameter lets you define what will be done with 'single' and "double" quotes.
|
|
// It takes on one of three constants with the default being ENT_COMPAT:
|
|
// ENT_COMPAT: Will convert double-quotes and leave single-quotes alone.
|
|
// ENT_QUOTES: Will convert both double and single quotes.
|
|
// ENT_NOQUOTES: Will leave both double and single quotes unconverted.
|
|
//
|
|
// - The optional third argument defines the character set used in conversion. Support for this argument
|
|
// was added in PHP 4.1.0. Presently, the ISO-8859-1 character set is used as the default.
|
|
|
|
return $encodedString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Encode HTML special chars:
|
|
// As opposed to the 'encodeHTML()' function this function will only convert the characters supported by the
|
|
// 'htmlspecialchars()' function:
|
|
// - '&' (ampersand) becomes '&'
|
|
// - '"' (double quote) becomes '"' when ENT_NOQUOTES is not set
|
|
// - ''' (single quote) becomes ''' only when ENT_QUOTES is set
|
|
// - '<' (less than) becomes '<'
|
|
// - '>' (greater than) becomes '>'
|
|
// Note that these (and only these!) entities are also supported by XML (which is why we use this function within the XML
|
|
// generating functions 'generateRSS()', 'modsRecord()' & 'atomEntry()' and leave all other higher ASCII chars unencoded)
|
|
function encodeHTMLspecialchars($sourceString)
|
|
{
|
|
global $contentTypeCharset; // defined in 'ini.inc.php'
|
|
|
|
$encodedString = htmlspecialchars($sourceString, ENT_COMPAT, "$contentTypeCharset");
|
|
// Notes from <http://www.php.net/htmlspecialchars>:
|
|
//
|
|
// - The optional second parameter lets you define what will be done with 'single' and "double" quotes.
|
|
// It takes on one of three constants with the default being ENT_COMPAT:
|
|
// ENT_COMPAT: Will convert double-quotes and leave single-quotes alone.
|
|
// ENT_QUOTES: Will convert both double and single quotes.
|
|
// ENT_NOQUOTES: Will leave both double and single quotes unconverted.
|
|
//
|
|
// - The optional third argument defines the character set used in conversion. Support for this argument
|
|
// was added in PHP 4.1.0. Presently, the ISO-8859-1 character set is used as the default.
|
|
|
|
return $encodedString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Decode HTML entities:
|
|
// This function converts HTML entities in '$sourceString' to the character encoding given in '$targetCharset'.
|
|
// It is intended to work similar to function 'html_entity_decode()' but should also support conversion of numeric
|
|
// entities as well as UTF-8 on PHP 4. In case of refbase, '$targetCharset' should be either "UTF-8" or "ISO-8859-1".
|
|
function decodeHTML($targetCharset, $sourceString)
|
|
{
|
|
global $contentTypeCharset; // defined in 'ini.inc.php'
|
|
|
|
static $transtab_HTML;
|
|
|
|
// Method A:
|
|
// Function 'html_entity_decode()' is available since PHP 4.3.0, but UTF-8 support was only added with PHP 5?
|
|
// (see <http://www.php.net/html-entity-decode>)
|
|
// NOTE: This function doesn't convert numeric entities, so, if used, it should be combined with the code block
|
|
// underneath "Replace numeric entities" below.
|
|
// $convertedString = html_entity_decode($sourceString, ENT_QUOTES, "$targetCharset");
|
|
// W.r.t. the second parameter, see notes underneath the call to 'htmlentities()' in function 'encodeHTML()'
|
|
|
|
|
|
// Method B:
|
|
// Function 'mb_convert_encoding()' requires PHP with multi-byte support (i.e., PHP must be compiled with the
|
|
// '--enable-mbstring' configure option). Converts from 'HTML-ENTITIES' to '$targetCharset'.
|
|
// (see: <http://php.net/manual/en/function.mb-convert-encoding.php>)
|
|
// NOTE: Compared to methods A + C, this seems to yield different results! ?:-/
|
|
// $convertedString = mb_convert_encoding($sourceString, "$targetCharset", 'HTML-ENTITIES');
|
|
|
|
|
|
// Method C:
|
|
// Assembled from user contributions at <http://www.php.net/html-entity-decode>
|
|
|
|
// - Replace numeric entities:
|
|
$convertedString = preg_replace('/�*([0-9a-f]+);/ei', "charNumToCharString('$targetCharset', hexdec('\\1'))", $sourceString); // hex notation
|
|
$convertedString = preg_replace('/�*([0-9]+);/e', "charNumToCharString('$targetCharset', '\\1')", $convertedString); // decimal notation
|
|
|
|
// - Replace literal entities:
|
|
if (!isset($transtab_HTML))
|
|
{
|
|
// Get the translation table that's used by function 'htmlspecialchars()':
|
|
$transtab_HTML = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES);
|
|
$transtab_HTML = array_flip($transtab_HTML);
|
|
|
|
// Change the translation table from latin1 to UTF-8 (if necessary):
|
|
if ($targetCharset == "UTF-8")
|
|
foreach ($transtab_HTML as $key => $value)
|
|
$transtab_HTML[$key] = utf8_encode($value); // encode ISO-8859-1 char as UTF-8
|
|
}
|
|
|
|
$convertedString = strtr($convertedString, $transtab_HTML);
|
|
|
|
return $convertedString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Decode HTML special chars:
|
|
// As opposed to the 'decodeHTML()' function this function will only decode the characters supported by the
|
|
// 'htmlspecialchars()' function:
|
|
// - '&' (ampersand) becomes '&'
|
|
// - '"' (double quote) becomes '"' when ENT_NOQUOTES is not set
|
|
// - ''' (single quote) becomes ''' only when ENT_QUOTES is set
|
|
// - '<' (less than) becomes '<'
|
|
// - '>' (greater than) becomes '>'
|
|
function decodeHTMLspecialchars($sourceString)
|
|
{
|
|
static $transtab_HTMLspecialchars;
|
|
|
|
// Method A:
|
|
// Function 'htmlspecialchars_decode()' seems to be available since PHP 5.1.0.
|
|
// (see <http://www.php.net/htmlspecialchars-decode>)
|
|
// $decodedString = htmlspecialchars_decode($sourceString, ENT_QUOTES);
|
|
// W.r.t. the second parameter, see notes underneath the call to 'htmlspecialchars()' in function 'encodeHTMLspecialchars()'
|
|
|
|
|
|
// Method B:
|
|
// Assembled from user contributions at <http://www.php.net/htmlspecialchars-decode>
|
|
if (!isset($transtab_HTMLspecialchars))
|
|
{
|
|
// Get the translation table that's used by function 'htmlspecialchars()':
|
|
$transtab_HTMLspecialchars = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES);
|
|
$transtab_HTMLspecialchars = array_flip($transtab_HTMLspecialchars);
|
|
|
|
if (!isset($transtab_HTMLspecialchars['''])) // we need to add ''' since the above call to 'get_html_translation_table()' returns just '''
|
|
$transtab_HTMLspecialchars['''] = "'";
|
|
}
|
|
|
|
$decodedString = strtr($sourceString, $transtab_HTMLspecialchars);
|
|
|
|
return $decodedString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Returns the character string that corresponds to the given character code value:
|
|
// (modified after user contributions by <akniep at rayo dot info>, <aurynas dot butkus at gmail dot com>
|
|
// and <romans at void dot lv> at <http://www.php.net/html-entity-decode>)
|
|
// NOTE: - In case of refbase, '$targetCharset' should be either "UTF-8" or "ISO-8859-1"
|
|
// - For a latin1-based database, we'll convert any Unicode-only entities into the
|
|
// corresponding refbase markup (if possible), and any remaining UTF-8 characters
|
|
// will be converted to their ASCII equivalents.
|
|
function charNumToCharString($targetCharset, $num)
|
|
{
|
|
global $transtab_unicode_ascii; // defined in 'transtab_unicode_ascii.inc.php'
|
|
global $transtab_unicode_refbase; // defined in 'transtab_unicode_refbase.inc.php'
|
|
|
|
// Generates a UTF-8 string that corresponds to the given Unicode value:
|
|
if ($num < 0)
|
|
$utfChar = '';
|
|
elseif ($num < 128)
|
|
$utfChar = chr($num);
|
|
elseif ($num < 2048)
|
|
$utfChar = chr(($num >> 6) + 192) . chr(($num & 63) + 128);
|
|
elseif ($num < 65536)
|
|
$utfChar = chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
|
|
elseif ($num < 2097152)
|
|
$utfChar = chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
|
|
|
|
if (!empty($utfChar) AND $targetCharset == "ISO-8859-1")
|
|
{
|
|
// Convert Unicode entities to refbase markup (if possible):
|
|
$utfChar = searchReplaceText($transtab_unicode_refbase, $utfChar, true);
|
|
|
|
// Convert any remaining UTF-8 characters to their ASCII equivalents:
|
|
// TODO: Should we use iconv (function 'convertToCharacterEncoding()') instead?
|
|
$utfChar = searchReplaceText($transtab_unicode_ascii, $utfChar, false);
|
|
}
|
|
|
|
return $utfChar;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Encode special chars, perform charset conversions (if necessary)
|
|
// and apply any field-specific search & replace actions:
|
|
// ('$targetFormat' must be either "HTML" or "XML")
|
|
function encodeField($fieldName, $fieldValue, $localSearchReplaceActionsArray = array(), $encodingExceptionsArray = array(), $encode = true, $targetFormat = "HTML")
|
|
{
|
|
global $contentTypeCharset; // these variables are defined in 'ini.inc.php'
|
|
global $convertExportDataToUTF8;
|
|
global $searchReplaceActionsArray;
|
|
|
|
if (($encode) AND (!in_array($fieldName, $encodingExceptionsArray)))
|
|
{
|
|
if ($targetFormat == "HTML")
|
|
{
|
|
// Encode non-ASCII chars as HTML entities:
|
|
$fieldValue = encodeHTML($fieldValue);
|
|
}
|
|
elseif ($targetFormat == "XML")
|
|
{
|
|
// Only convert those special chars to entities which are supported by XML:
|
|
$fieldValue = encodeHTMLspecialchars($fieldValue);
|
|
|
|
// Convert field data to UTF-8:
|
|
if (($convertExportDataToUTF8 == "yes") AND ($contentTypeCharset != "UTF-8"))
|
|
$fieldValue = convertToCharacterEncoding("UTF-8", "IGNORE", $fieldValue);
|
|
}
|
|
}
|
|
|
|
// Apply *locally* defined search & replace 'actions' to all fields that are listed
|
|
// in the 'fields' element of the arrays contained in '$localSearchReplaceActionsArray':
|
|
foreach ($localSearchReplaceActionsArray as $fieldActionsArray)
|
|
if (in_array($fieldName, $fieldActionsArray['fields']))
|
|
$fieldValue = searchReplaceText($fieldActionsArray['actions'], $fieldValue, true);
|
|
|
|
if ($targetFormat == "HTML")
|
|
{
|
|
// Apply *globally* defined search & replace 'actions' to all fields that are listed
|
|
// in the 'fields' element of the arrays contained in '$searchReplaceActionsArray':
|
|
foreach ($searchReplaceActionsArray as $fieldActionsArray)
|
|
if (in_array($fieldName, $fieldActionsArray['fields']))
|
|
$fieldValue = searchReplaceText($fieldActionsArray['actions'], $fieldValue, true);
|
|
}
|
|
|
|
return $fieldValue;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Strip HTML and PHP tags from input string:
|
|
// See <http://www.php.net/strip_tags>
|
|
function stripTags($sourceString, $allowedTags = "")
|
|
{
|
|
$cleanedString = strip_tags($sourceString, $allowedTags);
|
|
|
|
return $cleanedString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Verify the SQL query specified by the user and modify it if security concerns are encountered:
|
|
// (this function does add/remove user-specific query code as required and will fix problems with escape sequences within the SQL query)
|
|
function verifySQLQuery($sqlQuery, $referer, $displayType, $showLinks)
|
|
{
|
|
global $loginEmail;
|
|
global $loginUserID;
|
|
global $fileVisibility; // these variables are specified in 'ini.inc.php'
|
|
global $librarySearchPattern;
|
|
global $showAdditionalFieldsDetailsViewDefault;
|
|
global $showUserSpecificFieldsDetailsViewDefault;
|
|
global $tableRefs, $tableUserData; // defined in 'db.inc.php'
|
|
|
|
global $loc; // '$loc' is made globally available in 'core.php'
|
|
|
|
// note that, if several errors occur, only the last error message will be displayed
|
|
|
|
// disallow display/querying of the 'file' field if NONE of the following conditions are met:
|
|
// - the variable '$fileVisibility' (defined in 'ini.inc.php') is set to 'everyone'
|
|
// - the variable '$fileVisibility' is set to 'login' AND the user is logged in
|
|
// - the variable '$fileVisibility' is set to 'user-specific' AND the 'user_permissions' session variable contains 'allow_download'
|
|
if (!($fileVisibility == "everyone" OR ($fileVisibility == "login" AND isset($_SESSION['loginEmail'])) OR ($fileVisibility == "user-specific" AND (isset($_SESSION['user_permissions']) AND preg_match("/allow_download/", $_SESSION['user_permissions'])))))
|
|
{
|
|
// remove 'file' field from SQL query:
|
|
$sqlQuery = stripFieldFromSQLQuery($sqlQuery, "file", true);
|
|
}
|
|
|
|
|
|
// disallow display/querying of the 'location' field if the user is NOT logged in:
|
|
// (this is mostly done to shield user email addresses from exposure to search engines and/or email harvesting robots)
|
|
if (!isset($_SESSION['loginEmail']))
|
|
{
|
|
// remove 'location' field from SQL query:
|
|
$sqlQuery = stripFieldFromSQLQuery($sqlQuery, "location", true);
|
|
}
|
|
|
|
// supply generic 'WHERE' clause if it didn't exist in the SELECT query:
|
|
if (preg_match("/^SELECT/i", $sqlQuery) AND !preg_match("/ FROM " . $tableRefs . ".* WHERE /i", $sqlQuery))
|
|
$sqlQuery = preg_replace("/(?= ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i", " WHERE serial RLIKE \".+\"", $sqlQuery, 1);
|
|
|
|
// supply generic 'ORDER BY' clause if it didn't exist in the SELECT query:
|
|
// TODO: - add a suitable 'ORDER BY' clause for Browse view and if '$citeOrder != "author"'
|
|
if (preg_match("/^SELECT/i", $sqlQuery) AND !preg_match("/ FROM " . $tableRefs . ".* ORDER BY /i", $sqlQuery) AND ($displayType != "Browse"))
|
|
$sqlQuery = preg_replace("/(?= LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i", " ORDER BY author, year DESC, publication", $sqlQuery, 1);
|
|
|
|
// handle the display & querying of user-specific fields:
|
|
if (!isset($_SESSION['loginEmail'])) // if NO user is logged in...
|
|
{
|
|
// ... and any user-specific fields are part of the SELECT or ORDER BY statement...
|
|
if ((empty($referer) OR preg_match("#.+search\.php#i",$referer)) AND (preg_match("/(SELECT |ORDER BY |, *)(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related)/i",$sqlQuery))) // if the calling script ends with 'search.php' (i.e., is NOT 'show.php' or 'sru.php', see note below!) AND any user-specific fields are part of the SELECT or ORDER BY clause
|
|
{
|
|
// if the 'SELECT' clause contains any user-specific fields:
|
|
if (preg_match("/SELECT(.(?!FROM))+?(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related)/i",$sqlQuery))
|
|
{
|
|
// return an appropriate error message:
|
|
// note: we don't write out any error message if the user-specific fields do only occur within the 'ORDER' clause (but not within the 'SELECT' clause)
|
|
$HeaderString = returnMsg($loc["Warning_DisplayUserSpecificFieldsOmitted"] . "!", "warning", "strong", "HeaderString");
|
|
}
|
|
|
|
$sqlQuery = preg_replace("/(SELECT|ORDER BY) (marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related)( DESC)?/i", "\\1 ", $sqlQuery); // ...delete any user-specific fields from beginning of 'SELECT' or 'ORDER BY' clause
|
|
$sqlQuery = preg_replace("/, *(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related)( DESC)?/i", "", $sqlQuery); // ...delete any remaining user-specific fields from 'SELECT' or 'ORDER BY' clause
|
|
$sqlQuery = preg_replace("/(SELECT|ORDER BY) *, */i", "\\1 ", $sqlQuery); // ...remove any field delimiters that directly follow the 'SELECT' or 'ORDER BY' terms
|
|
|
|
$sqlQuery = preg_replace("/SELECT *(?=FROM)/i", buildSELECTclause("", "", "", false, false) . " ", $sqlQuery); // ...supply generic 'SELECT' clause if it did ONLY contain user-specific fields
|
|
$sqlQuery = preg_replace("/ORDER BY *(?=LIMIT|GROUP BY|HAVING|PROCEDURE|FOR UPDATE|LOCK IN|$)/i", "ORDER BY author, year DESC, publication", $sqlQuery); // ...supply generic 'ORDER BY' clause if it did ONLY contain user-specific fields
|
|
}
|
|
|
|
// ... and the 'LEFT JOIN...' statement is part of the 'FROM' clause...
|
|
if ((preg_match("#.+search\.php#i",$referer)) AND (preg_match("/LEFT JOIN $tableUserData/i",$sqlQuery))) // if the calling script ends with 'search.php' (i.e., is NOT 'show.php' or 'sru.php', see note below!) AND the 'LEFT JOIN...' statement is part of the 'FROM' clause...
|
|
$sqlQuery = preg_replace("/FROM $tableRefs LEFT JOIN.+WHERE/i","FROM $tableRefs WHERE",$sqlQuery); // ...delete 'LEFT JOIN...' part from 'FROM' clause
|
|
|
|
// ... and any user-specific fields are part of the WHERE clause...
|
|
if ((preg_match("#.+search\.php#i",$referer) OR preg_match("/^RSS$/i",$displayType)) AND (preg_match("/WHERE.+(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related)/i",$sqlQuery))) // if a user who's NOT logged in tries to query user-specific fields (by use of 'sql_search.php')...
|
|
// Note that the script 'show.php' may query the user-specific field 'selected' (e.g., by URLs of the form: 'show.php?author=...&userID=...&only=selected')
|
|
// but since (in that case) the '$referer' variable is either empty or does not end with 'search.php' this if clause will not apply (which is ok since we want to allow 'show.php' to query the 'selected' field).
|
|
// The same applies in the case of 'sru.php' which may query the user-specific field 'cite_key' (e.g., by URLs like: 'sru.php?version=1.1&query=bib.citekey=...&x-info-2-auth1.0-authenticationToken=email=...')
|
|
// Note that this also implies that a user who's not logged in might perform a query such as: 'http://localhost/refs/show.php?cite_key=...&userID=...'
|
|
{
|
|
// Note: in the patterns below we'll attempt to account for parentheses but this won't catch all cases!
|
|
$sqlQuery = preg_replace("/WHERE( *\( *?)* *(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related).+?(?= (AND|OR)\b| ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i","WHERE\\1",$sqlQuery); // ...delete any user-specific fields from 'WHERE' clause
|
|
$sqlQuery = preg_replace("/( *\( *?)*( *(AND|OR)\b)? *(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related).+?(?=( *\) *?)* +((AND|OR)\b|ORDER BY|LIMIT|GROUP BY|HAVING|PROCEDURE|FOR UPDATE|LOCK IN|$))/i","\\1",$sqlQuery); // ...delete any user-specific fields from 'WHERE' clause
|
|
$sqlQuery = preg_replace("/WHERE( *\( *?)* *(AND|OR)\b/i","WHERE\\1",$sqlQuery); // ...delete any superfluous 'AND' or 'OR' that wasn't removed properly by the two regex patterns above
|
|
$sqlQuery = preg_replace("/WHERE( *\( *?)*(?= ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i","WHERE serial RLIKE \".+\"",$sqlQuery); // ...supply generic 'WHERE' clause if it did ONLY contain user-specific fields
|
|
|
|
// return an appropriate error message:
|
|
$HeaderString = returnMsg($loc["Warning_QueryUserSpecificFieldsOmitted"] . "!", "warning", "strong", "HeaderString");
|
|
}
|
|
}
|
|
|
|
else // if a user is logged in...
|
|
{
|
|
if (preg_match("/LEFT JOIN $tableUserData/i",$sqlQuery)) // if the 'LEFT JOIN...' statement is part of the 'FROM' clause...
|
|
{
|
|
// ...and any user-specific fields other(!) than the 'selected' or 'cite_key' field are part of the 'SELECT' or 'WHERE' clause...
|
|
// Note that we exclude the 'selected' field here (although it is user-specific). By that we allow the 'selected' field to be queried by every user who's logged in.
|
|
// This is done to support the 'show.php' script which may query the user-specific field 'selected' (e.g., by URLs of the form: 'show.php?author=...&userID=...&only=selected')
|
|
// Similarly, we exclude 'cite_key' here to allow every user to query other user's 'cite_key' fields using 'sru.php' (e.g., by URLs like: 'sru.php?version=1.1&query=bib.citekey=...&x-info-2-auth1.0-authenticationToken=email=...')
|
|
if (preg_match("/, (marked|copy|user_keys|user_notes|user_file|user_groups|related)/i",$sqlQuery) OR preg_match("/WHERE.+(marked|copy|user_keys|user_notes|user_file|user_groups|related)/i",$sqlQuery))
|
|
{
|
|
$sqlQuery = preg_replace("/user_id *= *[0-9]+/i","user_id = $loginUserID",$sqlQuery); // ...replace any other user ID with the ID of the currently logged in user
|
|
|
|
if (!empty($librarySearchPattern) AND !(preg_match("/^location$/i",$librarySearchPattern[0]) AND preg_match("/location RLIKE " . quote_smart($librarySearchPattern[1]) . "/i",$sqlQuery))) // don't replace the 'location' part of the WHERE clause if it stems from variable '$librarySearchPattern' in 'ini.inc.php' (NOTE: this is quite hacky! :-/)
|
|
$sqlQuery = preg_replace("/location RLIKE .+?(?= (AND|OR)\b| ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i","location RLIKE " . quote_smart($loginEmail),$sqlQuery); // ...replace any other user email address with the login email address of the currently logged in user
|
|
}
|
|
}
|
|
|
|
// if we're going to display record details for a logged in user, we have to ensure the display of the 'location' field as well as the user-specific fields (which may have been deleted from a query due to a previous logout action);
|
|
// in 'Display Details' view, the 'call_number' and 'serial' fields are the last generic fields before any user-specific fields:
|
|
if (((preg_match("/^Display$/i",$displayType) AND ($showUserSpecificFieldsDetailsViewDefault == "yes")) OR (preg_match("/^Export$/i",$displayType))) AND (preg_match("/, call_number, serial FROM $tableRefs/i",$sqlQuery))) // if the user-specific fields are missing from the SELECT statement...
|
|
$sqlQuery = preg_replace("/, call_number, serial FROM $tableRefs/i",", call_number, serial, marked, copy, selected, user_keys, user_notes, user_file, user_groups, cite_key, related FROM $tableRefs",$sqlQuery); // ...add all user-specific fields to the 'SELECT' clause
|
|
|
|
// in 'Display Details' view, the 'location' field should occur within the SELECT statement before the 'call_number' and 'serial' fields:
|
|
// if (((preg_match("/^Display$/i",$displayType) AND ($showAdditionalFieldsDetailsViewDefault == "yes")) OR (preg_match("/^Export$/i",$displayType))) AND (preg_match("/(?<!location,) call_number, serial(?=(, marked, copy, selected, user_keys, user_notes, user_file, user_groups, cite_key, related)? FROM $tableRefs)/i",$sqlQuery))) // if the 'location' field is missing from the SELECT statement...
|
|
// $sqlQuery = preg_replace("/(?<!location), call_number, serial(?=(, marked, copy, selected, user_keys, user_notes, user_file, user_groups, cite_key, related)? FROM $tableRefs)/i",", location, call_number, serial",$sqlQuery); // ...add the 'location' field to the 'SELECT' clause
|
|
// NOTE: I've commented the above code block for now, since, for '$showAdditionalFieldsDetailsViewDefault=yes' with additional fields being hidden, it causes the 'location' field to appear when clicking any of the sort/browse/view links
|
|
// The drawback is that the 'location' field isn't added to the SQL query now when a record in Details view is reloaded after an anonymous user did view the record in Details view and then decided to log in
|
|
|
|
if ((preg_match("/^(Cite|Display|Export|RSS)$/i",$displayType)) AND (!preg_match("/LEFT JOIN $tableUserData/i",$sqlQuery))) // if the 'LEFT JOIN...' statement isn't already part of the 'FROM' clause...
|
|
$sqlQuery = preg_replace("/ FROM $tableRefs/i"," FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = $loginUserID",$sqlQuery); // ...add the 'LEFT JOIN...' part to the 'FROM' clause
|
|
}
|
|
|
|
|
|
// restrict adding of columns to SELECT queries (so that 'DELETE FROM refs ...' statements won't get modified as well);
|
|
// we'll also exclude the Browse view since these links aren't needed (and would cause problems) in this view
|
|
if (preg_match("/^SELECT/i",$sqlQuery) AND ($displayType != "Browse"))
|
|
{
|
|
$sqlQuery = preg_replace("/ FROM $tableRefs/i",", orig_record FROM $tableRefs",$sqlQuery); // add 'orig_record' column (which is required in order to present visual feedback on duplicate records)
|
|
$sqlQuery = preg_replace("/ FROM $tableRefs/i",", serial FROM $tableRefs",$sqlQuery); // add 'serial' column (which is required in order to obtain unique checkbox names)
|
|
|
|
if ($showLinks == "1")
|
|
$sqlQuery = preg_replace("/ FROM $tableRefs/i",", file, url, doi, isbn, type FROM $tableRefs",$sqlQuery); // add 'file', 'url', 'doi', 'isbn' & 'type' columns
|
|
}
|
|
|
|
// fix escape sequences within the SQL query:
|
|
$query = stripSlashesIfMagicQuotes($sqlQuery);
|
|
|
|
return $query;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Removes the field given in '$field' from the SQL query and
|
|
// issues a warning if '$issueWarning == true':
|
|
// TODO: I18n
|
|
function stripFieldFromSQLQuery($sqlQuery, $field, $issueWarning = true)
|
|
{
|
|
// note that, upon multiple warnings, only the last warning message will be displayed
|
|
|
|
// if the given '$field' is part of the SELECT or ORDER BY statement...
|
|
if (preg_match("/(SELECT |ORDER BY |, *)" . $field . "/i", $sqlQuery))
|
|
{
|
|
// if the 'SELECT' clause contains '$field':
|
|
if ($issueWarning AND (preg_match("/SELECT(.(?!FROM))+?" . $field . "/i", $sqlQuery)))
|
|
{
|
|
// return an appropriate error message:
|
|
// note: we don't write out any error message if the given '$field' does only occur within the 'ORDER' clause (but not within the 'SELECT' clause)
|
|
$HeaderString = returnMsg("Display of '" . $field . "' field was omitted!", "warning", "strong", "HeaderString");
|
|
}
|
|
|
|
$sqlQuery = preg_replace("/(SELECT|ORDER BY) " . $field . "( DESC)?/i", "\\1 ", $sqlQuery); // ...delete '$field' from beginning of 'SELECT' or 'ORDER BY' clause
|
|
$sqlQuery = preg_replace("/, *" . $field . "( DESC)?/i", "", $sqlQuery); // ...delete any other occurrences of '$field' from 'SELECT' or 'ORDER BY' clause
|
|
$sqlQuery = preg_replace("/(SELECT|ORDER BY) *, */i", "\\1 ", $sqlQuery); // ...remove any field delimiters that directly follow the 'SELECT' or 'ORDER BY' terms
|
|
|
|
$sqlQuery = preg_replace("/SELECT *(?=FROM)/i", buildSELECTclause("", "", "", false, false) . " ", $sqlQuery); // ...supply generic 'SELECT' clause if it did ONLY contain the given '$field'
|
|
$sqlQuery = preg_replace("/ORDER BY *(?=LIMIT|GROUP BY|HAVING|PROCEDURE|FOR UPDATE|LOCK IN|$)/i", "ORDER BY author, year DESC, publication", $sqlQuery); // ...supply generic 'ORDER BY' clause if it did ONLY contain the given '$field'
|
|
}
|
|
|
|
// if the given '$field' is part of the WHERE clause...
|
|
if (preg_match("/WHERE.+" . $field ."/i", $sqlQuery)) // this simple pattern works since we have already stripped any instance(s) of the given '$field' from the ORDER BY clause
|
|
{
|
|
// Note: in the patterns below we'll attempt to account for parentheses but this won't catch all cases!
|
|
$sqlQuery = preg_replace("/WHERE( *\( *?)* *" . $field . ".+?(?= (AND|OR)\b| ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i", "WHERE\\1", $sqlQuery); // ...delete '$field' from 'WHERE' clause
|
|
$sqlQuery = preg_replace("/( *\( *?)*( *(AND|OR)\b)? *" . $field . ".+?(?=( *\) *?)* +((AND|OR)\b|ORDER BY|LIMIT|GROUP BY|HAVING|PROCEDURE|FOR UPDATE|LOCK IN|$))/i", "\\1", $sqlQuery); // ...delete '$field' from 'WHERE' clause
|
|
$sqlQuery = preg_replace("/WHERE( *\( *?)* *(AND|OR)\b/i","WHERE\\1",$sqlQuery); // ...delete any superfluous 'AND' that wasn't removed properly by the two regex patterns above
|
|
$sqlQuery = preg_replace("/WHERE( *\( *?)*(?= ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i", "WHERE serial RLIKE \".+\"", $sqlQuery); // ...supply generic 'WHERE' clause if it did ONLY contain the given '$field'
|
|
|
|
if ($issueWarning)
|
|
{
|
|
// return an appropriate error message:
|
|
$HeaderString = returnMsg("Querying of '" . $field . "' field was omitted!", "warning", "strong", "HeaderString");
|
|
}
|
|
}
|
|
|
|
return $sqlQuery;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// this function uses 'mysqli_real_escape_string()' to:
|
|
// - prepend backslashes to \, ', "
|
|
// - replace the characters \x00, \n, \r, and \x1a with a MySQL acceptable representation
|
|
// for queries (e.g., the newline character is replaced with the litteral string '\n')
|
|
function escapeSQL($sourceString)
|
|
{
|
|
|
|
global $connection;
|
|
$sourceString = mysqli_real_escape_string($connection, $sourceString);
|
|
|
|
return $sourceString;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// generate a UNIX date/time stamp (integer) from a MySQL-formatted date (YYYY-MM-DD)
|
|
// and time (HH:MM:SS) (or the current date/time if no specific date/time was given):
|
|
function generateUNIXTimeStamp($date = "", $time = "")
|
|
{
|
|
if (!empty($date))
|
|
$dateArray = preg_split("/-/", $date); // split MySQL-formatted date string (e.g. "2004-09-27") into its pieces (year, month, day)
|
|
else
|
|
$dateArray = array(date('Y'), date('m'), date('d')); // use current year, month & day
|
|
|
|
if (!empty($time))
|
|
$timeArray = preg_split("/:/", $time); // split MySQL-formatted time string (e.g. "23:58:23") into its pieces (hours, minutes, seconds)
|
|
else
|
|
$timeArray = array(date('H'), date('i'), date('s')); // use current hour, minute & second
|
|
|
|
// return the Unix timestamp corresponding to the arguments given; the timestamp is a long integer
|
|
// containing the number of seconds between the Unix Epoch (January 1 1970 00:00:00 GMT) and the time specified:
|
|
$timeStamp = mktime($timeArray[0], $timeArray[1], $timeArray[2], $dateArray[1], $dateArray[2], $dateArray[0]);
|
|
|
|
return $timeStamp;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// generate an ISO date/time stamp (string) according to ISO-8601,
|
|
// the international standard for date and time representations:
|
|
// (ISO-8601 date/time example: "2008-01-11T18:30:21+0100";
|
|
// more info: <http://en.wikipedia.org/wiki/ISO_8601>
|
|
// <http://www.cl.cam.ac.uk/~mgk25/iso-time.html>)
|
|
function generateISO8601TimeStamp($date = "", $time = "")
|
|
{
|
|
$timeStamp = generateUNIXTimeStamp($date, $time);
|
|
|
|
$iso8601date = date('Y-m-d\TH:i:s', $timeStamp); // PHP 4+5
|
|
// for PHP4 support, we manually insert a colon in the TZ designation:
|
|
$timezone = date("O", $timeStamp); // get timezone
|
|
$iso8601date .= substr($timezone, 0, -2) . ":" . substr($timezone, -2, 2); // append timezone
|
|
|
|
// $iso8601date = date('c', $timeStamp); // PHP 5
|
|
|
|
return $iso8601date;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// generate a RFC-2822 formatted date/time stamp (string):
|
|
// (RFC-2822 date/time example: "Fri, 11 Jan 2008 18:30:21 +0100")
|
|
function generateRFC2822TimeStamp($date = "", $time = "")
|
|
{
|
|
$timeStamp = generateUNIXTimeStamp($date, $time);
|
|
|
|
$rfc2822date = date('r', $timeStamp);
|
|
|
|
return $rfc2822date;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// generate an email address from MySQL 'created_by' fields that conforms
|
|
// to the RFC-2822 specifications (<http://www.faqs.org/rfcs/rfc2822.html>):
|
|
function generateRFC2822EmailAddress($createdBy)
|
|
{
|
|
// Note that the following patterns don't attempt to do fancy parsing of email addresses but simply assume the string format
|
|
// of the 'created_by' field (table 'refs'). If you change the string format, you must modify these patterns as well!
|
|
$authorName = preg_replace("/(.+?)\([^)]+\)/", "\\1", $createdBy);
|
|
$authorEmail = preg_replace("/.+?\(([^)]+)\)/", "\\1", $createdBy);
|
|
|
|
$rfc2822address = encodeHTMLspecialchars($authorName . "<" . $authorEmail . ">");
|
|
|
|
return $rfc2822address;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Takes a SQL query and tries to describe it in natural language:
|
|
// (Note that, currently, this function doesn't attempt to cover all kinds of SQL queries [which would be a task by its own!]
|
|
// but rather sticks to what is needed in the context of refbase: I.e., right now, only the 'WHERE' clause will be translated)
|
|
function explainSQLQuery($sourceSQLQuery)
|
|
{
|
|
// fix escape sequences within the SQL query:
|
|
$translatedSQL = stripSlashesIfMagicQuotes($sourceSQLQuery);
|
|
// $translatedSQL = str_replace('\"','"',$sourceSQLQuery); // replace any \" with "
|
|
// $translatedSQL = preg_replace('/(\\\\)+/','\\\\',$translatedSQL);
|
|
|
|
// define an array of search & replace actions:
|
|
// (Note that the order of array elements IS important since it defines when a search/replace action gets executed)
|
|
$sqlSearchReplacePatterns = array(" != " => " is not equal to ",
|
|
" = " => " is equal to ",
|
|
" > " => " is greater than ",
|
|
" >= " => " is equal to or greater than ",
|
|
" < " => " is less than ",
|
|
" <= " => " is equal to or less than ",
|
|
"NOT RLIKE \"\\^([^\"]+?)\\$\"" => "is not equal to '\\1'",
|
|
"NOT RLIKE \"\\^" => "does not start with '",
|
|
"NOT RLIKE \"([^\"]+?)\\$\"" => "does not end with '\\1'",
|
|
"NOT RLIKE" => "does not contain",
|
|
"RLIKE \"\\^([^\"]+?)\\$\"" => "is equal to '\\1'",
|
|
"RLIKE \"\\^" => "starts with '",
|
|
"RLIKE \"([^\"]+?)\\$\"" => "ends with '\\1'",
|
|
"RLIKE" => "contains",
|
|
"AND" => "and");
|
|
|
|
// Perform search & replace actions on the SQL query:
|
|
$translatedSQL = searchReplaceText($sqlSearchReplacePatterns, $translatedSQL, false);
|
|
|
|
$translatedSQL = str_replace('"',"'",$translatedSQL); // replace any remaining " with '
|
|
|
|
return $translatedSQL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Extract the 'SELECT' clause from an SQL query:
|
|
function extractSELECTclause($query)
|
|
{
|
|
$querySELECTclause = preg_replace("/^.*?SELECT (.+?) FROM .*?$/i", "\\1", $query);
|
|
|
|
return $querySELECTclause;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Extract the 'WHERE' clause from an SQL query:
|
|
function extractWHEREclause($query)
|
|
{
|
|
// Note: we include the SQL commands SELECT/INSERT/UPDATE/DELETE/CREATE/ALTER/DROP/FILE in an attempt to sanitize a given WHERE clause from SQL injection attacks
|
|
$queryWHEREclause = preg_replace("/^.*? WHERE (.+?)(?= ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|[ ;]+(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|FILE)\b|$).*?$/i", "\\1", $query);
|
|
|
|
return $queryWHEREclause;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Extract the 'ORDER BY' clause from an SQL query:
|
|
function extractORDERBYclause($query)
|
|
{
|
|
// Note: we include the SQL commands SELECT/INSERT/UPDATE/DELETE/CREATE/ALTER/DROP/FILE in an attempt to sanitize a given ORDER BY clause from SQL injection attacks
|
|
$queryORDERBYclause = preg_replace("/^.*? ORDER BY (.+?)(?= LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|[ ;]+(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|FILE)\b|$).*?$/i", "\\1", $query);
|
|
|
|
return $queryORDERBYclause;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// This function walks a '$searchArray' and appends its items to the WHERE clause:
|
|
// (the array hierarchy will be maintained, i.e. if the '_query' item is itself
|
|
// an array of query items these sub-items will get properly nested in parentheses)
|
|
// Example '$searchArray':
|
|
// Array
|
|
// (
|
|
// [0] => Array
|
|
// (
|
|
// [_boolean] =>
|
|
// [_query] => location RLIKE "user@refbase.net"
|
|
// )
|
|
// [1] => Array
|
|
// (
|
|
// [_boolean] => AND
|
|
// [_query] => Array
|
|
// (
|
|
// [0] => Array
|
|
// (
|
|
// [_boolean] => OR
|
|
// [_query] => author RLIKE "steffens"
|
|
// )
|
|
// [1] => Array
|
|
// (
|
|
// [_boolean] => OR
|
|
// [_query] => title RLIKE "refbase"
|
|
// )
|
|
// [2] => Array
|
|
// (
|
|
// [_boolean] => OR
|
|
// [_query] => keywords RLIKE "refbase"
|
|
// )
|
|
// )
|
|
// )
|
|
// )
|
|
function appendToWhereClause($searchArray)
|
|
{
|
|
global $query;
|
|
|
|
foreach ($searchArray as $searchArrayItem)
|
|
{
|
|
if (!preg_match("/\($/", $query)) // add whitespace & any given boolean search operator if this item isn't the first one within a sub-array of query items
|
|
{
|
|
$query .= " ";
|
|
|
|
if (!empty($searchArrayItem["_boolean"]))
|
|
$query .= $searchArrayItem["_boolean"] . " ";
|
|
}
|
|
|
|
if (is_array($searchArrayItem["_query"])) // recursively parse any sub-arrays of query items and nest them in parentheses
|
|
{
|
|
$query .= "("; // NOTE: the parentheses must be on their own code lines to allow for correct recursion
|
|
$query .= appendToWhereClause($searchArrayItem["_query"]);
|
|
$query .= ")";
|
|
}
|
|
else
|
|
{
|
|
$query .= $searchArrayItem["_query"];
|
|
}
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Generate an URL pointing to a RSS feed or any of the supported export/citation formats for the given query:
|
|
// '$urlType' must be one of these: - RSS XML
|
|
// - export formats: ADS, BibTeX, Endnote, ISI, RIS, Atom XML, MODS XML, OAI_DC XML, ODF XML, SRW_DC XML, SRW_MODS XML, Word XML
|
|
// - citation formats: RTF, PDF, LaTeX, Markdown, ASCII, LaTeX .bbl
|
|
// - default format: html (session variable 'userDefaultView' specifies the default display type)
|
|
function generateURL($baseURL, $urlType, $queryParametersArray, $encodeAmpersands = false, $showRows = 0, $rowOffset = 0, $citeStyle = "", $citeOrder = "")
|
|
{
|
|
global $defaultCiteStyle; // defined in 'ini.inc.php'
|
|
|
|
// NOTE: This code block is a hack that fixes an inconsistency in the refbase API, where "RSS XML" is generated by 'rss.php'
|
|
// while all other formats are available via 'show.php'. Eventually, "RSS XML" should be also made available as proper
|
|
// export format so that it can be generated via 'show.php' URLs.
|
|
if (($baseURL == "show.php") AND ($urlType == "RSS XML"))
|
|
$baseURL = "rss.php";
|
|
|
|
if (empty($urlType))
|
|
$urlType = "html";
|
|
|
|
// NOTE: The record offset ('$rowOffset') as well as the number of records to be returned ('$showRows') will only work for "html"
|
|
// output, any of the citation formats or the export formats "Atom XML", "SRW_DC XML" and "SRW_MODS XML" - the other export formats will
|
|
// currently always export the entire result set. Also, 'rss.php' supports '$showRows', but not '$rowOffset', '$citeStyle' or '$citeOrder'.
|
|
if (!empty($rowOffset))
|
|
{
|
|
if (preg_match("#^((opensearch|sru|show|rss)\.php)$#i", $baseURL))
|
|
$queryParametersArray["startRecord"] = ($rowOffset + 1);
|
|
else
|
|
$queryParametersArray["rowOffset"] = $rowOffset;
|
|
}
|
|
|
|
if (!empty($showRows) AND ($showRows != $_SESSION['userRecordsPerPage']))
|
|
{
|
|
if (preg_match("#^((opensearch|sru)\.php)$#i", $baseURL))
|
|
$queryParametersArray["maximumRecords"] = $showRows;
|
|
else
|
|
$queryParametersArray["showRows"] = $showRows;
|
|
}
|
|
|
|
// Add parameters required by 'search.php' or the 'show.php' API:
|
|
if (preg_match("#^((search|show)\.php)$#i", $baseURL))
|
|
{
|
|
// - all formats:
|
|
if (!empty($citeOrder) AND ($citeOrder != "author")) // 'citeOrder=author' is the default sort order
|
|
$queryParametersArray["citeOrder"] = $citeOrder;
|
|
|
|
// - all formats that (may) contain formatted citations:
|
|
if (preg_match("/^(html|Atom XML|OAI_DC XML|SRW_DC XML|RTF|PDF|LaTeX|Markdown|ASCII|LaTeX \.bbl)$/i", $urlType))
|
|
{
|
|
if (!empty($citeStyle) AND ($citeStyle != $defaultCiteStyle))
|
|
$queryParametersArray["citeStyle"] = $citeStyle;
|
|
}
|
|
|
|
// - export formats:
|
|
if (preg_match("/^(ADS|BibTeX|Endnote|RIS|ISI|Atom XML|MODS XML|OAI_DC XML|ODF XML|SRW_DC XML|SRW_MODS XML|Word XML)$/i", $urlType))
|
|
{
|
|
if (!isset($queryParametersArray["exportType"]))
|
|
{
|
|
if (preg_match("/XML/i", $urlType))
|
|
$queryParametersArray["exportType"] = "xml";
|
|
else
|
|
$queryParametersArray["exportType"] = "file";
|
|
}
|
|
|
|
$queryParametersArray["submit"] = "Export";
|
|
|
|
$queryParametersArray["exportFormat"] = $urlType;
|
|
}
|
|
|
|
// - citation formats:
|
|
elseif (preg_match("/^(RTF|PDF|LaTeX|Markdown|ASCII|LaTeX \.bbl)$/i", $urlType))
|
|
{
|
|
$queryParametersArray["submit"] = "Cite";
|
|
|
|
$queryParametersArray["citeType"] = $urlType;
|
|
}
|
|
}
|
|
|
|
// Add parameters required by 'opensearch.php':
|
|
elseif ($baseURL == "opensearch.php")
|
|
{
|
|
$queryParametersArray["recordSchema"] = $urlType;
|
|
}
|
|
|
|
// Build query URL:
|
|
$queryURL = "";
|
|
|
|
if ($encodeAmpersands)
|
|
$ampersandChar = "&"; // we need to encode the ampersand character (that delimits 'param=value' pairs) if the generated URL is to be included in HTML or XML output
|
|
else
|
|
$ampersandChar = "&";
|
|
|
|
foreach ($queryParametersArray as $varname => $value)
|
|
$queryURL .= $ampersandChar . $varname . "=" . rawurlencode($value);
|
|
|
|
$queryURL = trimTextPattern($queryURL, $ampersandChar, true, false); // remove again ampersand character from beginning of query URL
|
|
|
|
|
|
return $baseURL . "?" . $queryURL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Generate RSS XML data from a particular result set (upto the limit given in '$showRows'):
|
|
//
|
|
// TODO: include OpenSearch elements in RSS output
|
|
// (see examples at <http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_response_elements>)
|
|
function generateRSS($result, $showRows, $rssChannelDescription)
|
|
{
|
|
global $officialDatabaseName; // these variables are defined in 'ini.inc.php'
|
|
global $databaseBaseURL;
|
|
global $feedbackEmail;
|
|
global $defaultCiteStyle;
|
|
global $contentTypeCharset;
|
|
global $logoImageURL;
|
|
|
|
global $transtab_refbase_html; // defined in 'transtab_refbase_html.inc.php'
|
|
|
|
// Note that we only convert those entities that are supported by XML (by use of the 'encodeHTMLspecialchars()' function).
|
|
// All other higher ASCII chars are left unencoded and valid feed output is only possible if the '$contentTypeCharset' variable is set correctly in 'ini.inc.php'.
|
|
// (The only exception is the item description which will contain HTML tags & entities that were defined by '$transtab_refbase_html' or by the 'reArrangeAuthorContents()' function)
|
|
|
|
// Define inline text markup to be used by the 'citeRecord()' function:
|
|
$markupPatternsArray = array("bold-prefix" => "<b>",
|
|
"bold-suffix" => "</b>",
|
|
"italic-prefix" => "<i>",
|
|
"italic-suffix" => "</i>",
|
|
"underline-prefix" => "<u>",
|
|
"underline-suffix" => "</u>",
|
|
"endash" => "–",
|
|
"emdash" => "—",
|
|
"ampersand" => "&", // ampersands in author contents get encoded in function 'reArrangeAuthorContents()' (since the last param in the 'citeRecord()' function call below is set to 'true')
|
|
"double-quote" => """,
|
|
"single-quote" => "'",
|
|
"less-than" => "<",
|
|
"greater-than" => ">",
|
|
"newline" => "\n<br>\n"
|
|
);
|
|
|
|
$currentDateTimeStamp = generateRFC2822TimeStamp(); // get the current date & time (in UNIX/RFC-2822 time stamp format => "date('r')" or "date('D, j M Y H:i:s O')")
|
|
|
|
// write RSS header:
|
|
$rssData = "<?xml version=\"1.0\" encoding=\"" . $contentTypeCharset . "\"?>"
|
|
. "\n<rss version=\"2.0\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">";
|
|
|
|
// write channel info:
|
|
$rssData .= "\n\t<channel>"
|
|
. "\n\t\t<title>" . encodeHTMLspecialchars($officialDatabaseName) . "</title>"
|
|
. "\n\t\t<link>" . $databaseBaseURL . "</link>"
|
|
. "\n\t\t<description>" . encodeHTMLspecialchars($rssChannelDescription) . "</description>"
|
|
. "\n\t\t<language>en</language>"
|
|
. "\n\t\t<pubDate>" . $currentDateTimeStamp . "</pubDate>"
|
|
. "\n\t\t<lastBuildDate>" . $currentDateTimeStamp . "</lastBuildDate>"
|
|
. "\n\t\t<webMaster>" . $feedbackEmail . "</webMaster>";
|
|
|
|
// write image data:
|
|
$rssData .= "\n\n\t\t<image>"
|
|
. "\n\t\t\t<url>" . $databaseBaseURL . $logoImageURL . "</url>"
|
|
. "\n\t\t\t<title>" . encodeHTMLspecialchars($officialDatabaseName) . "</title>"
|
|
. "\n\t\t\t<link>" . $databaseBaseURL . "</link>"
|
|
. "\n\t\t</image>";
|
|
|
|
// fetch results: upto the limit specified in '$showRows', fetch a row into the '$row' array and write out a RSS item:
|
|
for ($rowCounter=0; (($rowCounter < $showRows) && ($row = @ mysqli_fetch_array($result))); $rowCounter++)
|
|
{
|
|
$origTitle = $row['title']; // save the original title contents before applying any search & replace actions
|
|
|
|
// Perform search & replace actions on the text of the 'title' field:
|
|
// (the array '$transtab_refbase_html' in 'transtab_refbase_html.inc.php' defines which search & replace actions will be employed)
|
|
$row['title'] = searchReplaceText($transtab_refbase_html, $row['title'], true);
|
|
// this will provide for correct rendering of italic, super/sub-script and greek letters in item descriptions (which are enclosed by '<![CDATA[...]]>' to ensure well-formed XML);
|
|
// item titles are still served in raw format, though, since the use of HTML in item titles breaks many news readers
|
|
|
|
$citeStyleFile = getStyleFile($defaultCiteStyle); // fetch the name of the citation style file that's associated with the style given in '$defaultCiteStyle' (which, in turn, is defined in 'ini.inc.php')
|
|
|
|
// include the found citation style file *once*:
|
|
include_once "cite/" . $citeStyleFile; // instead of 'include_once' we could also use: 'if ($rowCounter == 0) { include "cite/" . $citeStyleFile; }'
|
|
|
|
// Generate a proper citation for this record, ordering attributes according to the chosen output style & record type:
|
|
$record = citeRecord($row, $defaultCiteStyle, "", $markupPatternsArray, true); // function 'citeRecord()' is defined in the citation style file given in '$citeStyleFile' (which, in turn, must reside in the 'styles' directory of the refbase root directory)
|
|
|
|
// To avoid advertising email adresses in public RSS output, we remove the email address from contents of the 'modified_by' field which
|
|
// get displayed in item descriptions. However, note that email adresses are NOT stripped from contents of the 'created_by' field
|
|
// since a valid RSS feed must include an email address in the '<author>' element.
|
|
// The following pattern does not attempt to do fancy parsing of email addresses but simply assumes the string format
|
|
// of the 'modified_by' field (table 'refs'). If you change the string format, you must modify this pattern as well!
|
|
$editorName = preg_replace("/(.+?) \([^)]+\)/", "\\1", $row['modified_by']);
|
|
|
|
// append a RSS item for the current record:
|
|
$rssData .= "\n\n\t\t<item>"
|
|
|
|
. "\n\t\t\t<title>" . encodeHTMLspecialchars($origTitle) . "</title>" // we avoid embedding HTML in the item title and use the raw title instead
|
|
|
|
. "\n\t\t\t<link>" . $databaseBaseURL . "show.php?record=" . $row['serial'] . "</link>"
|
|
|
|
. "\n\t\t\t<description><![CDATA[" . $record
|
|
|
|
. "\n\t\t\t<br><br>Edited by " . encodeHTMLspecialchars($editorName) . " on " . generateRFC2822TimeStamp($row['modified_date'], $row['modified_time']) . ".]]></description>"
|
|
|
|
. "\n\t\t\t<guid isPermaLink=\"true\">" . $databaseBaseURL . "show.php?record=" . $row['serial'] . "</guid>"
|
|
|
|
. "\n\t\t\t<pubDate>" . generateRFC2822TimeStamp($row['created_date'], $row['created_time']) . "</pubDate>"
|
|
|
|
. "\n\t\t\t<author>" . generateRFC2822EmailAddress($row['created_by']) . "</author>"
|
|
|
|
. "\n\t\t</item>";
|
|
}
|
|
|
|
// finish RSS data:
|
|
$rssData .= "\n\n\t</channel>"
|
|
. "\n</rss>\n";
|
|
|
|
return $rssData;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Create new table with parsed table data
|
|
// This function will create a new table with separate rows for all sub-items
|
|
// (which are delimited by '$delim') from the given '$field' (from table 'refs'
|
|
// or 'user_data'). This is done to support the Browse view feature for fields
|
|
// that contain a string of multiple values separated by a delimiter.
|
|
// (for each of the multi-item fields this function is executed only once by
|
|
// 'update.php', thereafter 'modify.php' will keep these 'ref_...' tables in
|
|
// sync with the main tables)
|
|
// Note: The split pattern must be specified as perl-style regular expression
|
|
// (including the leading & trailing slashes) and may include mode
|
|
// modifiers (such as '/.../i' to perform a case insensitive match)
|
|
function createNewTableWithParsedTableData($fieldName, $delim)
|
|
{
|
|
global $loginUserID; // saved as session variable on login
|
|
global $tableRefs, $tableUserData; // defined in 'db.inc.php'
|
|
|
|
if (preg_match("/^(user_keys|user_notes|user_file|user_groups)$/", $fieldName)) // for all user-specific fields that can contain multiple items (we ignore the 'related' field here since it won't get used for Browse view)
|
|
{
|
|
$query = "SELECT $fieldName, record_id, user_id FROM $tableUserData"; // WHERE user_id = " . $loginUserID
|
|
$userIDTableSpec = "ref_user_id MEDIUMINT UNSIGNED NOT NULL, ";
|
|
}
|
|
else
|
|
{
|
|
$query = "SELECT $fieldName, serial FROM $tableRefs";
|
|
$userIDTableSpec = "";
|
|
}
|
|
|
|
$result = queryMySQLDatabase($query);
|
|
|
|
$fieldValuesArray = array(); // initialize array variable which will hold the splitted sub-items
|
|
|
|
// split field values on the given delimiter:
|
|
for ($i=0; $row = @ mysqli_fetch_array($result); $i++)
|
|
{
|
|
$fieldSubValuesArray = preg_split($delim, $row[$fieldName]); // split field contents on '$delim' (which is interpreted as perl-style regular expression!)
|
|
foreach ($fieldSubValuesArray as $fieldSubValue)
|
|
{
|
|
// // NOTE: we include empty values so that any Browse view query will also display the number of records where the given field is empty
|
|
// if (!empty($fieldSubValue))
|
|
// {
|
|
$fieldSubValue = trim($fieldSubValue);
|
|
|
|
if ($fieldName == "author")
|
|
$fieldSubValue = trimTextPattern($fieldSubValue, " *\(eds?\)", false, true); // remove any existing editor info from the 'author' string, i.e., kill any trailing " (ed)" or " (eds)"
|
|
|
|
// copy the individual item (as string, ready for database insertion) to the array:
|
|
if (preg_match("/^(user_keys|user_notes|user_file|user_groups)$/", $fieldName))
|
|
$fieldValuesArray[] = "(NULL, \"". addslashes($fieldSubValue) . "\", $row[record_id], $row[user_id])";
|
|
else
|
|
$fieldValuesArray[] = "(NULL, \"". addslashes($fieldSubValue) . "\", $row[serial])";
|
|
// }
|
|
}
|
|
}
|
|
|
|
// build correct 'ref_...' table and field names:
|
|
list($tableName, $fieldName) = buildRefTableAndFieldNames($fieldName);
|
|
|
|
// NOTE: the below query will only work if the current MySQL user is allowed to CREATE tables ('Create_priv = Y')
|
|
// therefore, the CREATE statements should be moved to 'update.sql'!
|
|
$queryArray[] = "CREATE TABLE " . $tableName . " ("
|
|
. $fieldName . "_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, "
|
|
. $fieldName . " VARCHAR(255), "
|
|
. "ref_id MEDIUMINT UNSIGNED NOT NULL, "
|
|
. $userIDTableSpec
|
|
. "INDEX (" . $fieldName . "_id, " . $fieldName . ", ref_id))";
|
|
|
|
// TODO: Sanitize with quote_smart
|
|
foreach ($fieldValuesArray as $fieldValue)
|
|
$queryArray[] = "INSERT INTO " . $tableName . " VALUES " . $fieldValue;
|
|
|
|
// inserting all values at once may cause 'URL too long' server errors:
|
|
// $fieldValuesString = implode(", ", $fieldValuesArray); // merge array
|
|
// $queryArray[] = "INSERT INTO " . $tableName . " VALUES " . $fieldValuesString;
|
|
|
|
// RUN the queries on the database through the connection:
|
|
foreach($queryArray as $query)
|
|
$result = queryMySQLDatabase($query);
|
|
|
|
return $tableName;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Build correct 'ref_...' table and field names:
|
|
function buildRefTableAndFieldNames($fieldName)
|
|
{
|
|
if ($fieldName == "address")
|
|
{
|
|
$tableName = "ref_addresses";
|
|
$fieldName = "ref_address";
|
|
}
|
|
elseif (!preg_match("/s$/i", $fieldName)) // field name does NOT end with an 's' (such as in 'author')
|
|
{
|
|
$tableName = "ref_" . $fieldName . "s"; // e.g. 'ref_authors'
|
|
$fieldName = "ref_" . $fieldName; // e.g. 'ref_author'
|
|
}
|
|
else // field name ends with an 's' (such as in 'keywords')
|
|
{
|
|
$tableName = "ref_" . $fieldName; // e.g. 'ref_keywords'
|
|
$fieldName = "ref_" . preg_replace("/^(\w+)s$/i", "\\1", $fieldName); // strip 's' from end of field name -> produces e.g. 'ref_keyword'
|
|
}
|
|
|
|
return array($tableName, $fieldName);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
?>
|