// Copyright: Matthias Steffens 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: ./modify.php // Repository: $HeadURL: file:///svn/p/refbase/code/branches/bleeding-edge/modify.php $ // Author(s): Matthias Steffens // // Created: 18-Dec-02, 23:08 // Modified: $Date: 2017-04-13 02:00:18 +0000 (Thu, 13 Apr 2017) $ // $Author: karnesky $ // $Revision: 1416 $ // This php script will perform adding, editing & deleting of records. // It then calls 'receipt.php' which displays links to the modified/added record // as well as to the previous search results page (if any). // TODO: I18n // Incorporate some include files: include 'initialize/db.inc.php'; // 'db.inc.php' is included to hide username and password include 'includes/include.inc.php'; // include common functions include 'initialize/ini.inc.php'; // include common variables // -------------------------------------------------------------------- // START A SESSION: // call the 'start_session()' function (from 'include.inc.php') which will also read out available session variables: start_session(true); // -------------------------------------------------------------------- // Initialize preferred display language: // (note that 'locales.inc.php' has to be included *after* the call to the 'start_session()' function) include 'includes/locales.inc.php'; // include the locales // -------------------------------------------------------------------- // Clear any errors that might have been found previously: $errors = array(); // We check the '$_GET['proc']' variable in addition to '$_POST' in order to catch the case where the POSTed data are // greater than the value given in 'post_max_size' (in 'php.ini'). This may happen if the user uploads a large file. // Relevant quote from : // "If the size of post data is greater than post_max_size, the $_POST and $_FILES superglobals are empty. // This can be tracked in various ways, e.g. by passing the $_GET variable to the script processing the data, // i.e.
, and then checking if $_GET['processed'] is set." if (isset($_GET['proc']) AND empty($_POST)) { $maxPostDataSize = ini_get("post_max_size"); // inform the user that the maximum post data size was exceeded: $HeaderString = returnMsg($loc["Warning_PostDataSizeMustNotExceed"] . " " . $maxPostDataSize . "!", "warning", "strong", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php' header("Location: " . $referer); // redirect to 'record.php' (variable '$referer' is globally defined in function 'start_session()' in 'include.inc.php') exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } // Write the (POST) form variables into an array: foreach($_POST as $varname => $value) $formVars[$varname] = trim($value); // remove any leading or trailing whitespace from the field's contents & copy the trimmed string to the '$formVars' array // $formVars[$varname] = trim(clean($value, 50)); // the use of the clean function would be more secure! // -------------------------------------------------------------------- // Extract form variables sent through POST: // Note: Although we could use the '$formVars' array directly below (e.g.: $formVars['pageLoginStatus'] etc., like in 'user_validation.php'), we'll read out // all variables individually again. This is done to enhance readability. (A smarter way of doing so seems be the use of the 'extract()' function, but that // may expose yet another security hole...) // Extract the page's login status (which indicates the user's login status at the time the page was loaded): $pageLoginStatus = $formVars['pageLoginStatus']; // First of all, check if this script was called by something else than 'record.php': if (!preg_match("#/record\.php\?.+#", $referer)) { // return an appropriate error message: $HeaderString = returnMsg($loc["Warning_InvalidCallToScript"] . " '" . scriptURL() . "'!", "warning", "strong", "HeaderString"); // functions 'returnMsg()' and 'scriptURL()' are defined in 'include.inc.php' header("Location: " . $referer); // redirect to calling page exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } // If the referring page is 'record.php' (i.e., if this script was called by 'record.php'), check if the user is logged in: elseif ((!isset($_SESSION['loginEmail'])) OR ($pageLoginStatus != "logged in")) // if the user isn't logged in -OR- the page's login status still does NOT state "logged in" (since the page wasn't reloaded after the user logged in elsewhere) { // the user is logged in BUT the page's login status still does NOT state "logged in" (since the page wasn't reloaded after the user logged IN elsewhere): if ((isset($_SESSION['loginEmail'])) AND ($pageLoginStatus != "logged in")) { // return an appropriate error message: $HeaderString = returnMsg($loc["Warning_PageStatusOutDated"] . "!", "warning", "strong", "HeaderString", "", "
" . $loc["Warning_RecordDataReloaded"] . ":"); // function 'returnMsg()' is defined in 'include.inc.php' header("Location: " . $referer); // redirect to 'record.php' exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } // the user is NOT logged in BUT the page's login status still states that he's "logged in" (since the page wasn't reloaded after the user logged OUT elsewhere): if ((!isset($_SESSION['loginEmail'])) AND ($pageLoginStatus == "logged in")) { // return an appropriate error message: $HeaderString = returnMsg($loc["Warning_NotLoggedInAnymore"] . "!", "warning", "strong", "HeaderString", "", "
" . $loc["Warning_TimeOutPleaseLoginAgain"] . ":"); // function 'returnMsg()' is defined in 'include.inc.php' } // else if the user isn't logged in yet: ((!isset($_SESSION['loginEmail'])) AND ($pageLoginStatus != "logged in")) header("Location: user_login.php?referer=" . rawurlencode($referer)); // ask the user to login first, then he'll get directed back to 'record.php' exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } // if we made it here, the user is regularly logged in: (isset($_SESSION['loginEmail'] == true) AND ($pageLoginStatus == "logged in") // Extract the form used by the user: $formType = $formVars['formType']; // Extract the type of action requested by the user (either 'add', 'edit' or ''): $recordAction = $formVars['recordAction']; // $recordAction == '' will be treated equal to 'add': if (empty($recordAction)) $recordAction = "add"; // we set it explicitly here so that we can employ this variable within message strings, etc // Determine the button that was hit by the user (either 'Add Record', 'Edit Record', 'Delete Record' or ''): // '$submitAction' is only used to determine any 'delet' action! (where '$submitAction' = 'Delete Record') // (otherwise, only '$recordAction' controls how to proceed) $submitAction = $formVars['submit']; if (encodeHTML($submitAction) == $loc["ButtonTitle_DeleteRecord"]) // note that we need to HTML encode '$submitAction' for comparison with the HTML encoded locales $recordAction = "delet"; // *delete* record // now, check if the (logged in) user is allowed to perform the current record action (i.e., add, edit or delete a record): $notPermitted = false; // if the (logged in) user... if ($recordAction == "edit") // ...wants to edit the current record... { if (isset($_SESSION['user_permissions']) AND !preg_match("/allow_edit/", $_SESSION['user_permissions'])) // ...BUT the 'user_permissions' session variable does NOT contain 'allow_edit'... { $notPermitted = true; $HeaderString = $loc["NoPermission"] . $loc["NoPermission_ForEditRecord"] . "!"; } } elseif ($recordAction == "delet") // ...wants to delete the current record... { if (isset($_SESSION['user_permissions']) AND !preg_match("/allow_delete/", $_SESSION['user_permissions'])) // ...BUT the 'user_permissions' session variable does NOT contain 'allow_delete'... { $notPermitted = true; $HeaderString = $loc["NoPermission"] . $loc["NoPermission_ForDeleteRecord"] . "!"; } } else // if ($recordAction == "add" OR $recordAction == "") // ...wants to add the current record... { if (isset($_SESSION['user_permissions']) AND !preg_match("/allow_add/", $_SESSION['user_permissions'])) // ...BUT the 'user_permissions' session variable does NOT contain 'allow_add'... { $notPermitted = true; $HeaderString = $loc["NoPermission"] . $loc["NoPermission_ForAddRecords"] . "!"; } } if ($notPermitted) { // return an appropriate error message: $HeaderString = returnMsg($HeaderString, "warning", "strong", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php' header("Location: " . $referer); // redirect to 'record.php' exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } // if we made it here, we assume that the user is allowed to perform the current record action // Get the query URL of the formerly displayed results page: if (isset($_SESSION['oldQuery'])) $oldQuery = $_SESSION['oldQuery']; else $oldQuery = array(); // Get the query URL of the last multi-record query: if (isset($_SESSION['oldMultiRecordQuery'])) $oldMultiRecordQuery = $_SESSION['oldMultiRecordQuery']; else $oldMultiRecordQuery = ""; // (1) OPEN CONNECTION, (2) SELECT DATABASE connectToMySQLDatabase(); // function 'connectToMySQLDatabase()' is defined in 'include.inc.php' // Extract all form values provided by 'record.php': if (isset($formVars['authorName'])) $authorName = $formVars['authorName']; else $authorName = ""; if (isset($formVars['isEditorCheckBox'])) $isEditorCheckBox = $formVars['isEditorCheckBox']; else $isEditorCheckBox = ""; if (isset($formVars['titleName'])) $titleName = $formVars['titleName']; else $titleName = ""; if (isset($formVars['yearNo'])) $yearNo = $formVars['yearNo']; else $yearNo = ""; if (isset($formVars['publicationName'])) $publicationName = $formVars['publicationName']; else $publicationName = ""; if (isset($formVars['abbrevJournalName'])) $abbrevJournalName = $formVars['abbrevJournalName']; else $abbrevJournalName = ""; if (isset($formVars['volumeNo'])) $volumeNo = $formVars['volumeNo']; else $volumeNo = ""; if (isset($formVars['issueNo'])) $issueNo = $formVars['issueNo']; else $issueNo = ""; if (isset($formVars['pagesNo'])) $pagesNo = $formVars['pagesNo']; else $pagesNo = ""; if (isset($formVars['addressName'])) $addressName = $formVars['addressName']; else $addressName = ""; if (isset($formVars['corporateAuthorName'])) $corporateAuthorName = $formVars['corporateAuthorName']; else $corporateAuthorName = ""; if (isset($formVars['keywordsName'])) $keywordsName = $formVars['keywordsName']; else $keywordsName = ""; if (isset($formVars['abstractName'])) $abstractName = $formVars['abstractName']; else $abstractName = ""; if (isset($formVars['publisherName'])) $publisherName = $formVars['publisherName']; else $publisherName = ""; if (isset($formVars['placeName'])) $placeName = $formVars['placeName']; else $placeName = ""; if (isset($formVars['editorName'])) $editorName = $formVars['editorName']; else $editorName = ""; if (isset($formVars['languageName'])) $languageName = $formVars['languageName']; else $languageName = ""; if (isset($formVars['summaryLanguageName'])) $summaryLanguageName = $formVars['summaryLanguageName']; else $summaryLanguageName = ""; if (isset($formVars['origTitleName'])) $origTitleName = $formVars['origTitleName']; else $origTitleName = ""; if (isset($formVars['seriesEditorName'])) $seriesEditorName = $formVars['seriesEditorName']; else $seriesEditorName = ""; if (isset($formVars['seriesTitleName'])) $seriesTitleName = $formVars['seriesTitleName']; else $seriesTitleName = ""; if (isset($formVars['abbrevSeriesTitleName'])) $abbrevSeriesTitleName = $formVars['abbrevSeriesTitleName']; else $abbrevSeriesTitleName = ""; if (isset($formVars['seriesVolumeNo'])) $seriesVolumeNo = $formVars['seriesVolumeNo']; else $seriesVolumeNo = ""; if (isset($formVars['seriesIssueNo'])) $seriesIssueNo = $formVars['seriesIssueNo']; else $seriesIssueNo = ""; if (isset($formVars['editionNo'])) $editionNo = $formVars['editionNo']; else $editionNo = ""; if (isset($formVars['issnName'])) $issnName = $formVars['issnName']; else $issnName = ""; if (isset($formVars['isbnName'])) $isbnName = $formVars['isbnName']; else $isbnName = ""; if (isset($formVars['mediumName'])) $mediumName = $formVars['mediumName']; else $mediumName = ""; if (isset($formVars['areaName'])) $areaName = $formVars['areaName']; else $areaName = ""; if (isset($formVars['expeditionName'])) $expeditionName = $formVars['expeditionName']; else $expeditionName = ""; if (isset($formVars['conferenceName'])) $conferenceName = $formVars['conferenceName']; else $conferenceName = ""; if (isset($formVars['notesName'])) $notesName = $formVars['notesName']; else $notesName = ""; if (isset($formVars['approvedRadio'])) $approvedRadio = $formVars['approvedRadio']; else $approvedRadio = ""; if (isset($formVars['locationName'])) $locationName = $formVars['locationName']; else $locationName = ""; $callNumberName = $formVars['callNumberName']; if (preg_match("/%40|%20/", $callNumberName)) // if '$callNumberName' still contains URL encoded data... ('%40' is the URL encoded form of the character '@', '%20' a space, see note below!) $callNumberName = rawurldecode($callNumberName); // ...URL decode 'callNumberName' variable contents (it was URL encoded before incorporation into a hidden tag of the 'record' form to avoid any HTML syntax errors) // NOTE: URL encoded data that are included within a *link* will get URL decoded automatically *before* extraction via '$_POST'! // But, opposed to that, URL encoded data that are included within a form by means of a *hidden form tag* will NOT get URL decoded automatically! Then, URL decoding has to be done manually (as is done here)! if (isset($formVars['callNumberNameUserOnly'])) $callNumberNameUserOnly = $formVars['callNumberNameUserOnly']; else $callNumberNameUserOnly = ""; if (isset($formVars['serialNo'])) $serialNo = $formVars['serialNo']; else $serialNo = ""; if (isset($formVars['typeName'])) { $types = array('Journal Article','Abstract','Book Chapter','Book Whole','Conference Article','Conference Volume','Journal','Magazine Article','Manual','Manuscript','Map','Miscellaneous','Newspaper Article','Patent','Report','Software'); if (in_array($formVars['typeName'],$types)) $typeName = $formVars['typeName']; else $typeName = ""; } else $typeName = ""; if (isset($formVars['thesisName'])) $thesisName = $formVars['thesisName']; else $thesisName = ""; if (isset($formVars['markedRadio'])) $markedRadio = $formVars['markedRadio']; else $markedRadio = ""; if (isset($formVars['copyName'])) $copyName = $formVars['copyName']; else $copyName = ""; if (isset($formVars['selectedRadio'])) $selectedRadio = $formVars['selectedRadio']; else $selectedRadio = ""; if (isset($formVars['userKeysName'])) $userKeysName = $formVars['userKeysName']; else $userKeysName = ""; if (isset($formVars['userNotesName'])) $userNotesName = $formVars['userNotesName']; else $userNotesName = ""; if (isset($formVars['userFileName'])) $userFileName = $formVars['userFileName']; else $userFileName = ""; if (isset($formVars['userGroupsName'])) $userGroupsName = $formVars['userGroupsName']; else $userGroupsName = ""; if (isset($formVars['citeKeyName'])) $citeKeyName = $formVars['citeKeyName']; else $citeKeyName = ""; if (isset($formVars['relatedName'])) $relatedName = $formVars['relatedName']; else $relatedName = ""; // if the current user has no permission to download (and hence view) any files, 'record.php' does only show an empty string // in the 'file' field (no matter if a file exists for the given record or not). Thus, we need to make sure that the empty // form value won't overwrite any existing contents of the 'file' field on UPDATE and that the correct field value gets // transferred to table 'deleted' on DELETE: // Therefore, we re-fetch the contents 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 (preg_match("/^(edit|delet)$/", $recordAction) AND (!($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'])))))) // user has NO permission to download (and view) any files { $queryFile = "SELECT file FROM $tableRefs WHERE serial = " . quote_smart($serialNo); $result = queryMySQLDatabase($queryFile); // RUN the query on the database through the connection $row = @ mysqli_fetch_array($result); $fileName = $row["file"]; } else // user has permission to download (and view) any files $fileName = $formVars['fileName']; if (isset($formVars['urlName'])) $urlName = $formVars['urlName']; else $urlName = ""; if (isset($formVars['doiName'])) $doiName = $formVars['doiName']; else $doiName = ""; if (isset($formVars['contributionIDName'])) $contributionID = $formVars['contributionIDName']; else $contributionID = ""; $contributionID = rawurldecode($contributionID); // URL decode 'contributionID' variable contents (it was URL encoded before incorporation into a hidden tag of the 'record' form to avoid any HTML syntax errors) [see above!] if (isset($formVars['contributionIDCheckBox'])) $contributionIDCheckBox = $formVars['contributionIDCheckBox']; else $contributionIDCheckBox = ""; if (isset($formVars['locationSelectorName'])) $locationSelectorName = $formVars['locationSelectorName']; else $locationSelectorName = ""; if (isset($formVars['onlinePublicationCheckBox'])) $onlinePublicationCheckBox = $formVars['onlinePublicationCheckBox']; else $onlinePublicationCheckBox = ""; if (isset($formVars['onlineCitationName'])) $onlineCitationName = $formVars['onlineCitationName']; else $onlineCitationName = ""; if (isset($formVars['createdDate'])) $createdDate = $formVars['createdDate']; else $createdDate = ""; if (isset($formVars['createdTime'])) $createdTime = $formVars['createdTime']; else $createdTime = ""; if (isset($formVars['createdBy'])) $createdBy = $formVars['createdBy']; else $createdBy = ""; if (isset($formVars['modifiedDate'])) $modifiedDate = $formVars['modifiedDate']; else $modifiedDate = ""; if (isset($formVars['modifiedTime'])) $modifiedTime = $formVars['modifiedTime']; else $modifiedTime = ""; if (isset($formVars['modifiedBy'])) $modifiedBy = $formVars['modifiedBy']; else $modifiedBy = ""; if (isset($formVars['origRecord'])) $origRecord = $formVars['origRecord']; else $origRecord = ""; // check if a file was uploaded: // (note that to have file uploads work, HTTP file uploads must be allowed within your 'php.ini' configuration file // by setting the 'file_uploads' parameter to 'On'!) // extract file information into a four (or five) element associative array containing the following information about the file: // name - original name of file on client // type - MIME type of file // tmp_name - name of temporary file on server // error - holds an error number >0 if something went wrong, otherwise 0 (I don't know when this element was added. It may not be present in your PHP version... ?:-/) // 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] $uploadFile = getUploadInfo("uploadFile"); // function 'getUploadInfo()' is defined in 'include.inc.php' // -------------------------------------------------------------------- // VALIDATE data fields: // NOTE: for all fields that are validated here must exist error parsing code (of the form: " . fieldError("languageName", $errors) . ") // in front of the respective form field in 'record.php'! Otherwise the generated error won't be displayed! // Validate fields that MUST not be empty: // Validate the 'Call Number' field: if (preg_match("/[@;]/", $callNumberNameUserOnly)) $errors["callNumberNameUserOnly"] = "Your call number cannot contain the characters '@' and ';' (since they function as delimiters):"; // the user's personal reference ID cannot contain the characters '@' and ';' since they are used as delimiters (within or between call numbers) elseif ($recordAction == "edit" AND !empty($callNumberNameUserOnly) AND !preg_match("/$loginEmail/", $locationName) AND !preg_match("/^(add|remove)$/", $locationSelectorName)) // if the user specified some reference ID within an 'edit' action -BUT- there's no existing call number for this user within the contents of the 'location' field -AND- the user doesn't want to add it either... $errors["callNumberNameUserOnly"] = "You cannot specify a call number unless you add this record to your personal literature set! This can be done by setting the 'Location Field' popup below to 'add'."; // warn the user that he/she has to set the Location Field popup to 'add' if he want's to add this record to his personal literature set // Validate the 'uploadFile' field: // (whose file name characters must be within [a-zA-Z0-9+_.-] and which must not exceed // the 'upload_max_filesize' specified within your 'php.ini' configuration file) if (!empty($uploadFile) && !empty($uploadFile["name"])) // if the user attempted to upload a file { // The 'is_uploaded_file()' function returns 'true' if the file indicated by '$uploadFile["tmp_name"]' was uploaded via HTTP POST. This is useful to help ensure // that a malicious user hasn't tried to trick the script into working on files upon which it should not be working - for instance, /etc/passwd. if (is_uploaded_file($uploadFile["tmp_name"])) { if (empty($uploadFile["tmp_name"])) // no tmp file exists => we assume that the maximum upload file size was exceeded! // or check via 'error' element instead: "if ($uploadFile["error"] == 1)" (the 'error' element exists since PHP 4.2.0) { $maxFileSize = ini_get("upload_max_filesize"); $fileError = "File size must not be greater than " . $maxFileSize . ":"; $errors["uploadFile"] = $fileError; // inform the user that the maximum upload file size was exceeded } else // a tmp file exists... { // prevent hackers from gaining access to the systems 'passwd' file (this should be prevented by the 'is_uploaded_file()' function but anyhow): if (preg_match("/^passwd$/i", $uploadFile["name"])) // file name must not be 'passwd' $errors["uploadFile"] = "This file name is not allowed!"; // check for invalid file name extensions: if (preg_match("#\.(exe|com|bat|zip|php|phps|php3|phtml|phtm|cgi)$#i", $uploadFile["name"])) // file name has an invalid file name extension (adjust the regex pattern if you want more relaxed file name validation) $errors["uploadFile"] = "You cannot upload this type of file!"; // file name must not end with .exe, .com, .bat, .zip, .php, .phps, .php3, .phtml, .phtm or .cgi if ($renameUploadedFiles != "yes") // if we do NOT rename files according to a standard naming scheme (variable '$renameUploadedFiles' is defined in 'ini.inc.php') { // check for invalid file name characters: if (!preg_match("/^[" . $allowedFileNameCharacters . "]+$/", $uploadFile["name"])) // file name contains invalid characters (variable '$allowedFileNameCharacters' is defined in 'ini.inc.php') $errors["uploadFile"] = "File name characters can only be within " . $allowedFileNameCharacters; // characters of file name must be within range given in '$allowedFileNameCharacters' // previous error message was a bit more user-friendly: "File name characters can only be alphanumeric ('a-zA-Z0-9'), plus ('+'), minus ('-'), substring ('_') or a dot ('.'):" } } } else { // I'm not sure if this actually works --RAK switch($uploadFile["error"]) { case 0: // no error; possible file attack! $errors["uploadFile"] = "There was a problem with your upload."; break; case 1: // uploaded file exceeds the 'upload_max_filesize' directive in 'php.ini' $maxFileSize = ini_get("upload_max_filesize"); $fileError = "File size must not be greater than " . $maxFileSize . ":"; $errors["uploadFile"] = $fileError; break; case 2: // uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form (Note: refbase doesn't currently specify MAX_FILE_SIZE but anyhow...) $errors["uploadFile"] = "The file you are trying to upload is too big."; break; case 3: // uploaded file was only partially uploaded $errors["uploadFile"] = "The file you are trying to upload was only partially uploaded."; break; case 4: // no file was uploaded $errors["uploadFile"] = "You must select a file for upload."; break; case 6: $errors["uploadFile"] = "Missing a temporary folder."; break; default: // a default error, just in case! :) $errors["uploadFile"] = "There was a problem with your upload."; break; } } } // CAUTION: validation of other fields is currently disabled, since, IMHO, there are too many open questions how to implement this properly // and without frustrating the user! Uncomment the commented code below to enable the current validation features: // // Validate fields that SHOULD not be empty: // // Validate the 'Author' field: // if (empty($authorName)) // $errors["authorName"] = "Is there really no author info for this record? Enter NULL to force empty:"; // Author should not be a null string // // // Validate the 'Title' field: // if (empty($titleName)) // $errors["titleName"] = "Is there really no title info for this record? Enter NULL to force empty:"; // Title should not be a null string // // // Validate the 'Year' field: // if (empty($yearNo)) // $errors["yearNo"] = "Is there really no year info for this record? Enter NULL to force empty:"; // Year should not be a null string // // // Validate the 'Publication' field: // if (empty($publicationName)) // $errors["publicationName"] = "Is there really no publication info for this record? Enter NULL to force empty:"; // Publication should not be a null string // // // Validate the 'Abbrev Journal' field: // if (empty($abbrevJournalName)) // $errors["abbrevJournalName"] = "Is there really no abbreviated journal info for this record? Enter NULL to force empty:"; // Abbrev Journal should not be a null string // // // Validate the 'Volume' field: // if (empty($volumeNo)) // $errors["volumeNo"] = "Is there really no volume info for this record? Enter NULL to force empty:"; // Volume should not be a null string // // // Validate the 'Pages' field: // if (empty($pagesNo)) // $errors["pagesNo"] = "Is there really no pages info for this record? Enter NULL to force empty:"; // Pages should not be a null string // // // // Validate fields that MUST not be empty: // // Validate the 'Language' field: // if (empty($languageName)) // $errors["languageName"] = "The language field cannot be blank:"; // Language cannot be a null string // // // // Remove 'NULL' values that were entered by the user in order to force empty values for required text fields: // // (for the required number fields 'yearNo' & 'volumeNo' inserting 'NULL' will cause '0000' or '0' as value, respectively) // if ($authorName == "NULL") // $authorName = ""; // // if ($titleName == "NULL") // $titleName = ""; // // if ($publicationName == "NULL") // $publicationName = ""; // // if ($abbrevJournalName == "NULL") // $abbrevJournalName = ""; // // if ($pagesNo == "NULL") // $pagesNo = ""; // -------------------------------------------------------------------- // Now the script has finished the validation, check if there were any errors: if (count($errors) > 0) { // Write back session variables: saveSessionVariable("errors", $errors); // function 'saveSessionVariable()' is defined in 'include.inc.php' saveSessionVariable("formVars", $formVars); // There are errors. Relocate back to the record entry form: header("Location: " . $referer); exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } // -------------------------------------------------------------------- // If we made it here, then the data is considered valid! // CONSTRUCT SQL QUERY: // 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)'): list ($currentDate, $currentTime, $currentUser) = getCurrentDateTimeUser(); // function 'getCurrentDateTimeUser()' is defined in 'include.inc.php' // Build a correct call number prefix for the currently logged-in user (e.g. 'IPÖ @ msteffens'): $callNumberPrefix = getCallNumberPrefix(); // function 'getCallNumberPrefix()' is defined in 'include.inc.php' // provide some magic that figures out what do to depending on the state of the 'is Editor' check box // and the content of the 'author', 'editor' and 'type' fields: if ($isEditorCheckBox == "1" OR preg_match("/^(Book Whole|Conference Volume|Journal|Manuscript|Map)$/", $typeName)) // if the user did mark the 'is Editor' checkbox -OR- if the record type is either 'Book Whole', 'Conference Volume', 'Journal', 'Map' or 'Manuscript'... if (!empty($editorName) AND empty($authorName)) // ...and if the 'Editor' field has some content while the 'Author' field is blank... { $authorName = $editorName; // duplicate field contents from 'editor' to 'author' field $isEditorCheckBox = "1"; // since the user entered something in the 'editor' field (but not the 'author' field), we need to make sure that the 'is Editor' is marked } if ($isEditorCheckBox == "1" AND preg_match("/^(Book Whole|Conference Volume|Journal|Manuscript|Map)$/", $typeName)) // if the user did mark the 'is Editor' checkbox -AND- the record type is either 'Book Whole', 'Conference Volume', 'Journal', 'Map' or 'Manuscript'... { $authorName = preg_replace("/ *\(eds?\)$/i","",$authorName); // ...remove any existing editor info from the 'author' string, i.e., kill any trailing " (ed)" or " (eds)" if (!empty($authorName)) // if the 'Author' field has some content... $editorName = $authorName; // ...duplicate field contents from 'author' to 'editor' field (CAUTION: this will overwrite any existing contents in the 'editor' field!) if (!empty($authorName)) // if 'author' field isn't empty { if (!preg_match("/;/", $authorName)) // if the 'author' field does NOT contain a ';' (which would delimit multiple authors) => single author $authorName .= " (ed)"; // append " (ed)" to the end of the 'author' string else // the 'author' field does contain at least one ';' => multiple authors $authorName .= " (eds)"; // append " (eds)" to the end of the 'author' string } } else // the 'is Editor' checkbox is NOT checked -OR- the record type is NOT 'Book Whole', 'Conference Volume', 'Journal', 'Map' or 'Manuscript'... { if (preg_match("/ *\(eds?\)$/", $authorName)) // if 'author' field ends with either " (ed)" or " (eds)" $authorName = preg_replace("/ *\(eds?\)$/i","",$authorName); // remove any existing editor info from the 'author' string, i.e., kill any trailing " (ed)" or " (eds)" if ($authorName == $editorName) // if the 'Author' field contents equal the 'Editor' field contents... $editorName = ""; // ...clear contents of 'editor' field (that is, we assume that the user did uncheck the 'is Editor' checkbox, which was previously marked) } // Assign correct values to the calculation fields 'first_author', 'author_count', 'first_page', 'volume_numeric' and 'series_volume_numeric': // function 'generateCalculationFieldContent()' is defined in 'include.inc.php' // NOTE: this function call won't be necessary anymore when we've also moved database INSERTs and DELETEs to dedicated functions (which would take care of calculation fields then) -> compare with 'addRecords()' function list ($firstAuthor, $authorCount, $firstPage, $volumeNumericNo, $seriesVolumeNumericNo) = generateCalculationFieldContent($authorName, $pagesNo, $volumeNo, $seriesVolumeNo); // manage 'location' field data: if ((($locationSelectorName == "add") OR ($locationSelectorName == "")) AND (!preg_match("/$loginEmail/", $locationName))) // add the current user to the 'location' field (if he/she isn't listed already within the 'location' field): // note: if the current user is NOT logged in -OR- if any normal user is logged in, the value for '$locationSelectorName' will be always '' when performing an INSERT, // since the popup is fixed to 'add' and disabled (which, in turn, will result in an empty value to be returned) { // if the 'location' field is either completely empty -OR- does only contain the information string (that shows up on 'add' for normal users): if (preg_match("/^(" . $loc["your name & email address will be filled in automatically"] . ")?$/", encodeHTML($locationName))) // note that we need to HTML encode '$locationName' for comparison with the HTML encoded locales $locationName = preg_replace("/^.*$/i", "$currentUser", $locationName); else // if the 'location' field does already contain some user content: $locationName = preg_replace("/^(.+)$/i", "\\1; $currentUser", $locationName); } elseif ($locationSelectorName == "remove") // remove the current user from the 'location' field: { // the only pattern that's really unique is the users email address, the user's name may change (since it can be modified by the user). This is why we dont use '$currentUser' here: $locationName = preg_replace("/^[^;]*\( *$loginEmail *\) *; */i", "", $locationName); // the current user is listed at the very beginning of the 'location' field $locationName = preg_replace("/ *;[^;]*\( *$loginEmail *\) */i", "", $locationName); // the current user occurs after some other user within the 'location' field $locationName = preg_replace("/^[^;]*\( *$loginEmail *\) *$/i", "", $locationName); // the current user is the only one listed within the 'location' field } // else if '$locationSelectorName' == "don't touch" -OR- if the user is already listed within the 'location' field, we just accept the contents of the 'location' field as entered by the user // manage 'call_number' field data: if ($loginEmail != $adminLoginEmail) // if any normal user is logged in (not the admin): { if (preg_match("/$loginEmail/", $locationName)) // we only process the user's call number information if the current user is listed within the 'location' field: { // Note that, for normal users, we process the user's call number information even if the '$locationSelectorName' is NOT set to 'add'. // This is done, since the user should be able to update his/her personal reference ID while the '$locationSelectorName' is set to 'don't touch'. // If the '$locationSelectorName' is set to 'remove', then any changes made to the personal reference ID will be discarded anyhow. // build a correct call number string for the current user & record: if ($callNumberNameUserOnly == "") // if the user didn't enter any personal reference ID for this record... $callNumberNameUserOnly = $callNumberPrefix . " @ "; // ...insert the user's call number prefix only else // if the user entered (or modified) his/her personal reference ID for this record... $callNumberNameUserOnly = $callNumberPrefix . " @ " . $callNumberNameUserOnly; // ...prefix the entered reference ID with the user's call number prefix // insert or update the user's call number within the full contents of the 'call_number' field: if ($callNumberName == "") // if the 'call_number' field is empty... $callNumberName = $callNumberNameUserOnly; // ...insert the user's call number prefix elseif (preg_match("/$callNumberPrefix/", $callNumberName)) // if the user's call number prefix occurs within the contents of the 'call_number' field... $callNumberName = preg_replace("/$callNumberPrefix *@ *[^@;]*/i", "$callNumberNameUserOnly", $callNumberName); // ...replace the user's *own* call number within the full contents of the 'call_number' field else // if the 'call_number' field does already have some content -BUT- there's no existing call number prefix for the current user... $callNumberName = $callNumberName . "; " . $callNumberNameUserOnly; // ...append the user's call number to any existing call numbers } } else // if the admin is logged in: if ($locationSelectorName == "add") // we only add the admin's call number information if he/she did set the '$locationSelectorName' to 'add' { if ($callNumberName == "") // if there's no call number info provided by the admin... $callNumberName = $callNumberPrefix . " @ "; // ...insert the admin's call number prefix elseif (!preg_match("/@/", $callNumberName)) // if there's a call number provided by the admin that does NOT contain any '@' already... $callNumberName = $callNumberPrefix . " @ " . $callNumberName; // ...then we assume the admin entered a personal refernce ID for this record which should be prefixed with his/her call number prefix // the contents of the 'call_number' field do contain the '@' character, i.e. we assume one or more full call numbers to be present elseif (!preg_match("/$callNumberPrefix/", $callNumberName)) // if the admin's call number prefix does NOT already occur within the contents of the 'call_number' field... { if (preg_match("/; *[^ @;][^@;]*$/", $callNumberName)) // for the admin we offer autocompletion of the call number prefix if he/she just enters his/her reference ID after the last full call number (separated by '; ') // e.g., the string 'IPÖ @ mschmid @ 123; 1778' will be autocompleted to 'IPÖ @ mschmid @ 123; IPÖ @ msteffens @ 1778' (with 'msteffens' being the admin user) $callNumberName = preg_replace("/^(.+); *([^@;]+)$/i", "\\1; $callNumberPrefix @ \\2", $callNumberName); // insert the admin's call number prefix before any reference ID that stand's at the end of the string of call numbers else $callNumberName = $callNumberName . "; " . $callNumberPrefix . " @ "; // ...append the admin's call number prefix to any existing call numbers } } // otherwise we simply use the information as entered by the admin if ($locationSelectorName == "remove") // remove the current user's call number from the 'call_number' field: { $callNumberName = preg_replace("/^ *$callNumberPrefix *@ *[^@;]*; */i", "", $callNumberName); // the user's call number is listed at the very beginning of the 'call_number' field $callNumberName = preg_replace("/ *; *$callNumberPrefix *@ *[^@;]*/i", "", $callNumberName); // the user's call number occurs after some other call number within the 'call_number' field $callNumberName = preg_replace("/^ *$callNumberPrefix *@ *[^@;]*$/i", "", $callNumberName); // the user's call number is the only one listed within the 'call_number' field } // handle file uploads: if (preg_match("/^(edit|delet)$/", $recordAction)) // we exclude '$recordAction = "add"' here, since file name generation needs to be done *after* the record has been created and a serial number is available { if (!empty($uploadFile) && !empty($uploadFile["tmp_name"])) // if there was a file uploaded successfully // process information of any file that was uploaded, auto-generate a file name if required and move the file to the appropriate directory: $fileName = handleFileUploads($uploadFile, $formVars); } // check if we need to set the 'contribution_id' field: // (we'll make use of the session variable '$abbrevInstitution' here) if ($contributionIDCheckBox == "1") // the user want's to add this record to the list of publications that were published by a member of his institution { if (!empty($contributionID)) // if the 'contribution_id' field is NOT empty... { if (!preg_match("/$abbrevInstitution/", $contributionID)) // ...and the current user's 'abbrev_institution' value isn't listed already within the 'contribution_id' field $contributionID = $contributionID . "; " . $abbrevInstitution; // append the user's 'abbrev_institution' value to the end of the 'contribution_id' field } else // the 'contribution_id' field is empty $contributionID = $abbrevInstitution; // insert the current user's 'abbrev_institution' value } else // if present, remove the current user's abbreviated institution name from the 'contribution_id' field: { if (preg_match("/$abbrevInstitution/", $contributionID)) // if the current user's 'abbrev_institution' value is listed within the 'contribution_id' field, we'll remove it: { $contributionID = preg_replace("/^ *$abbrevInstitution *[^;]*; */i", "", $contributionID); // the user's abbreviated institution name is listed at the very beginning of the 'contribution_id' field $contributionID = preg_replace("/ *; *$abbrevInstitution *[^;]*/i", "", $contributionID); // the user's abbreviated institution name occurs after some other institutional abbreviation within the 'contribution_id' field $contributionID = preg_replace("/^ *$abbrevInstitution *[^;]*$/i", "", $contributionID); // the user's abbreviated institution name is the only one listed within the 'contribution_id' field } } // check if we need to set the 'online_publication' field: if ($onlinePublicationCheckBox == "1") // the user did mark the "Online publication" checkbox $onlinePublication = "yes"; else $onlinePublication = "no"; // remove any meaningless delimiter(s) from the beginning or end of a field string: // Note: - this cleanup is only done for fields that may contain sub-elements, which are the fields: // 'author', 'keywords', 'place', 'language', 'summary_language', 'area', 'user_keys' and 'user_groups' // - currently, only the semicolon (optionally surrounded by whitespace) is supported as sub-element delimiter $authorName = trimTextPattern($authorName, "( *; *)+", true, true); // function 'trimTextPattern()' is defined in 'include.inc.php' $keywordsName = trimTextPattern($keywordsName, "( *; *)+", true, true); $placeName = trimTextPattern($placeName, "( *; *)+", true, true); $languageName = trimTextPattern($languageName, "( *; *)+", true, true); $summaryLanguageName = trimTextPattern($summaryLanguageName, "( *; *)+", true, true); $areaName = trimTextPattern($areaName, "( *; *)+", true, true); $userKeysName = trimTextPattern($userKeysName, "( *; *)+", true, true); $userGroupsName = trimTextPattern($userGroupsName, "( *; *)+", true, true); $queryDeleted = ""; // initialize the '$queryDeleted' variable in order to prevent 'Undefined variable...' messages // Is this an update? if ($recordAction == "edit") // alternative method to check for an 'edit' action: if (preg_match("/^[0-9]+$/",$serialNo)) // a valid serial number must be an integer // yes, the form already contains a valid serial number, so we'll have to update the relevant record: { // UPDATE - construct queries to update the relevant record $queryRefs = "UPDATE $tableRefs SET " . "author = " . quote_smart($authorName) . ", " . "first_author = " . quote_smart($firstAuthor) . ", " . "author_count = " . quote_smart($authorCount) . ", " . "title = " . quote_smart($titleName) . ", " . "year = " . quote_smart($yearNo) . ", " . "publication = " . quote_smart($publicationName) . ", " . "abbrev_journal = " . quote_smart($abbrevJournalName) . ", " . "volume = " . quote_smart($volumeNo) . ", " . "volume_numeric = " . quote_smart($volumeNumericNo) . ", " . "issue = " . quote_smart($issueNo) . ", " . "pages = " . quote_smart($pagesNo) . ", " . "first_page = " . quote_smart($firstPage) . ", " . "address = " . quote_smart($addressName) . ", " . "corporate_author = " . quote_smart($corporateAuthorName) . ", " . "keywords = " . quote_smart($keywordsName) . ", " . "abstract = " . quote_smart($abstractName) . ", " . "publisher = " . quote_smart($publisherName) . ", " . "place = " . quote_smart($placeName) . ", " . "editor = " . quote_smart($editorName) . ", " . "language = " . quote_smart($languageName) . ", " . "summary_language = " . quote_smart($summaryLanguageName) . ", " . "orig_title = " . quote_smart($origTitleName) . ", " . "series_editor = " . quote_smart($seriesEditorName) . ", " . "series_title = " . quote_smart($seriesTitleName) . ", " . "abbrev_series_title = " . quote_smart($abbrevSeriesTitleName) . ", " . "series_volume = " . quote_smart($seriesVolumeNo) . ", " . "series_volume_numeric = " . quote_smart($seriesVolumeNumericNo) . ", " . "series_issue = " . quote_smart($seriesIssueNo) . ", " . "edition = " . quote_smart($editionNo) . ", " . "issn = " . quote_smart($issnName) . ", " . "isbn = " . quote_smart($isbnName) . ", " . "medium = " . quote_smart($mediumName) . ", " . "area = " . quote_smart($areaName) . ", " . "expedition = " . quote_smart($expeditionName) . ", " . "conference = " . quote_smart($conferenceName) . ", " . "location = " . quote_smart($locationName) . ", " . "call_number = " . quote_smart($callNumberName) . ", " . "approved = " . quote_smart($approvedRadio) . ", " . "file = " . quote_smart($fileName) . ", " . "type = " . quote_smart($typeName) . ", " . "thesis = " . quote_smart($thesisName) . ", " . "notes = " . quote_smart($notesName) . ", " . "url = " . quote_smart($urlName) . ", " . "doi = " . quote_smart($doiName) . ", " . "contribution_id = " . quote_smart($contributionID) . ", " . "online_publication = " . quote_smart($onlinePublication) . ", " . "online_citation = " . quote_smart($onlineCitationName) . ", " . "modified_date = " . quote_smart($currentDate) . ", " . "modified_time = " . quote_smart($currentTime) . ", " . "modified_by = " . quote_smart($currentUser) . " " . "WHERE serial = " . quote_smart($serialNo); // first, we need to check if there's already an entry for the current record & user within the 'user_data' table: // CONSTRUCT SQL QUERY: $query = "SELECT data_id FROM $tableUserData WHERE record_id = " . quote_smart($serialNo) . " AND user_id = " . quote_smart($loginUserID); // '$loginUserID' is provided as session variable // (3) RUN the query on the database through the connection: $result = queryMySQLDatabase($query); // function 'queryMySQLDatabase()' is defined in 'include.inc.php' if (mysqli_num_rows($result) == 1) // if there's already an existing user_data entry, we perform an UPDATE action: $queryUserData = "UPDATE $tableUserData SET " . "marked = " . quote_smart($markedRadio) . ", " . "copy = " . quote_smart($copyName) . ", " . "selected = " . quote_smart($selectedRadio) . ", " . "user_keys = " . quote_smart($userKeysName) . ", " . "user_notes = " . quote_smart($userNotesName) . ", " . "user_file = " . quote_smart($userFileName) . ", " . "user_groups = " . quote_smart($userGroupsName) . ", " . "cite_key = " . quote_smart($citeKeyName) . ", " . "related = " . quote_smart($relatedName) . " " . "WHERE record_id = " . quote_smart($serialNo) . " AND user_id = " . quote_smart($loginUserID); // '$loginUserID' is provided as session variable else // otherwise we perform an INSERT action: $queryUserData = "INSERT INTO $tableUserData SET " . "marked = " . quote_smart($markedRadio) . ", " . "copy = " . quote_smart($copyName) . ", " . "selected = " . quote_smart($selectedRadio) . ", " . "user_keys = " . quote_smart($userKeysName) . ", " . "user_notes = " . quote_smart($userNotesName) . ", " . "user_file = " . quote_smart($userFileName) . ", " . "user_groups = " . quote_smart($userGroupsName) . ", " . "cite_key = " . quote_smart($citeKeyName) . ", " . "related = " . quote_smart($relatedName) . ", " . "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 } elseif ($recordAction == "delet") // (Note that if you delete the mother record within the 'refs' table, the corresponding child entry within the 'user_data' table will remain!) { // Instead of deleting data, deleted records will be moved to the "deleted" table. Data will be stored within the "deleted" table // until they are removed manually. This is to provide the admin with a simple recovery method in case a user did delete some data by accident... // INSERT - construct queries to add data as new record $queryDeleted = "INSERT INTO $tableDeleted SET " . "author = " . quote_smart($authorName) . ", " . "first_author = " . quote_smart($firstAuthor) . ", " . "author_count = " . quote_smart($authorCount) . ", " . "title = " . quote_smart($titleName) . ", " . "year = " . quote_smart($yearNo) . ", " . "publication = " . quote_smart($publicationName) . ", " . "abbrev_journal = " . quote_smart($abbrevJournalName) . ", " . "volume = " . quote_smart($volumeNo) . ", " . "volume_numeric = " . quote_smart($volumeNumericNo) . ", " . "issue = " . quote_smart($issueNo) . ", " . "pages = " . quote_smart($pagesNo) . ", " . "first_page = " . quote_smart($firstPage) . ", " . "address = " . quote_smart($addressName) . ", " . "corporate_author = " . quote_smart($corporateAuthorName) . ", " . "keywords = " . quote_smart($keywordsName) . ", " . "abstract = " . quote_smart($abstractName) . ", " . "publisher = " . quote_smart($publisherName) . ", " . "place = " . quote_smart($placeName) . ", " . "editor = " . quote_smart($editorName) . ", " . "language = " . quote_smart($languageName) . ", " . "summary_language = " . quote_smart($summaryLanguageName) . ", " . "orig_title = " . quote_smart($origTitleName) . ", " . "series_editor = " . quote_smart($seriesEditorName) . ", " . "series_title = " . quote_smart($seriesTitleName) . ", " . "abbrev_series_title = " . quote_smart($abbrevSeriesTitleName) . ", " . "series_volume = " . quote_smart($seriesVolumeNo) . ", " . "series_volume_numeric = " . quote_smart($seriesVolumeNumericNo) . ", " . "series_issue = " . quote_smart($seriesIssueNo) . ", " . "edition = " . quote_smart($editionNo) . ", " . "issn = " . quote_smart($issnName) . ", " . "isbn = " . quote_smart($isbnName) . ", " . "medium = " . quote_smart($mediumName) . ", " . "area = " . quote_smart($areaName) . ", " . "expedition = " . quote_smart($expeditionName) . ", " . "conference = " . quote_smart($conferenceName) . ", " . "location = " . quote_smart($locationName) . ", " . "call_number = " . quote_smart($callNumberName) . ", " . "approved = " . quote_smart($approvedRadio) . ", " . "file = " . quote_smart($fileName) . ", " . "serial = " . quote_smart($serialNo) . ", " // it's important to keep the old PRIMARY KEY (since user specific data may be still associated with this record id) . "type = " . quote_smart($typeName) . ", " . "thesis = " . quote_smart($thesisName) . ", " . "notes = " . quote_smart($notesName) . ", " . "url = " . quote_smart($urlName) . ", " . "doi = " . quote_smart($doiName) . ", " . "contribution_id = " . quote_smart($contributionID) . ", " . "online_publication = " . quote_smart($onlinePublication) . ", " . "online_citation = " . quote_smart($onlineCitationName) . ", " . "created_date = " . quote_smart($createdDate) . ", " . "created_time = " . quote_smart($createdTime) . ", " . "created_by = " . quote_smart($createdBy) . ", " . "modified_date = " . quote_smart($modifiedDate) . ", " . "modified_time = " . quote_smart($modifiedTime) . ", " . "modified_by = " . quote_smart($modifiedBy) . ", " . "orig_record = " . quote_smart($origRecord) . ", " . "deleted_date = " . quote_smart($currentDate) . ", " // store information about when and by whom this record was deleted... . "deleted_time = " . quote_smart($currentTime) . ", " . "deleted_by = " . quote_smart($currentUser); // since data have been moved from table 'refs' to table 'deleted', its now safe to delete the data from table 'refs': $queryRefs = "DELETE FROM $tableRefs WHERE serial = " . quote_smart($serialNo); } else // if the form does NOT contain a valid serial number, we'll have to add the data: { // INSERT - construct queries to add data as new record $queryRefs = "INSERT INTO $tableRefs SET " . "author = " . quote_smart($authorName) . ", " . "first_author = " . quote_smart($firstAuthor) . ", " . "author_count = " . quote_smart($authorCount) . ", " . "title = " . quote_smart($titleName) . ", " . "year = " . quote_smart($yearNo) . ", " . "publication = " . quote_smart($publicationName) . ", " . "abbrev_journal = " . quote_smart($abbrevJournalName) . ", " . "volume = " . quote_smart($volumeNo) . ", " . "volume_numeric = " . quote_smart($volumeNumericNo) . ", " . "issue = " . quote_smart($issueNo) . ", " . "pages = " . quote_smart($pagesNo) . ", " . "first_page = " . quote_smart($firstPage) . ", " . "address = " . quote_smart($addressName) . ", " . "corporate_author = " . quote_smart($corporateAuthorName) . ", " . "keywords = " . quote_smart($keywordsName) . ", " . "abstract = " . quote_smart($abstractName) . ", " . "publisher = " . quote_smart($publisherName) . ", " . "place = " . quote_smart($placeName) . ", " . "editor = " . quote_smart($editorName) . ", " . "language = " . quote_smart($languageName) . ", " . "summary_language = " . quote_smart($summaryLanguageName) . ", " . "orig_title = " . quote_smart($origTitleName) . ", " . "series_editor = " . quote_smart($seriesEditorName) . ", " . "series_title = " . quote_smart($seriesTitleName) . ", " . "abbrev_series_title = " . quote_smart($abbrevSeriesTitleName) . ", " . "series_volume = " . quote_smart($seriesVolumeNo) . ", " . "series_volume_numeric = " . quote_smart($seriesVolumeNumericNo) . ", " . "series_issue = " . quote_smart($seriesIssueNo) . ", " . "edition = " . quote_smart($editionNo) . ", " . "issn = " . quote_smart($issnName) . ", " . "isbn = " . quote_smart($isbnName) . ", " . "medium = " . quote_smart($mediumName) . ", " . "area = " . quote_smart($areaName) . ", " . "expedition = " . quote_smart($expeditionName) . ", " . "conference = " . quote_smart($conferenceName) . ", " . "location = " . quote_smart($locationName) . ", " . "call_number = " . quote_smart($callNumberName) . ", " . "approved = " . quote_smart($approvedRadio) . ", " . "file = " . quote_smart($fileName) . ", " // for new records the 'file' field will be updated once more after record creation, since the serial number of the newly created record may be required when generating a file name for any uploaded file . "serial = NULL, " // inserting 'NULL' into an auto_increment PRIMARY KEY attribute allocates the next available key value . "type = " . quote_smart($typeName) . ", " . "thesis = " . quote_smart($thesisName) . ", " . "notes = " . quote_smart($notesName) . ", " . "url = " . quote_smart($urlName) . ", " . "doi = " . quote_smart($doiName) . ", " . "contribution_id = " . quote_smart($contributionID) . ", " . "online_publication = " . quote_smart($onlinePublication) . ", " . "online_citation = " . quote_smart($onlineCitationName) . ", " . "created_date = " . quote_smart($currentDate) . ", " . "created_time = " . quote_smart($currentTime) . ", " . "created_by = " . quote_smart($currentUser) . ", " . "modified_date = " . quote_smart($currentDate) . ", " . "modified_time = " . quote_smart($currentTime) . ", " . "modified_by = " . quote_smart($currentUser); // '$queryUserData' will be set up after '$queryRefs' has been conducted (see below), since the serial number of the newly created 'refs' record is required for the '$queryUserData' query } // Apply some clean-up to the SQL query: // - if a field of type=NUMBER is empty, we set it back to NULL (otherwise the empty string would be converted to "0") // - if the 'thesis' field is empty, we also set it back to NULL (this ensures correct sorting when outputting citations with '$citeOrder="type"' or '$citeOrder="type-year"') if (preg_match("/(year|volume_numeric|first_page|series_volume_numeric|edition|orig_record|thesis) = [\"']0?[\"']/", $queryRefs)) $queryRefs = preg_replace("/(year|volume_numeric|first_page|series_volume_numeric|edition|orig_record|thesis) = [\"']0?[\"']/", "\\1 = NULL", $queryRefs); if (preg_match("/(year|volume_numeric|first_page|series_volume_numeric|edition|orig_record|thesis) = [\"']0?[\"']/", $queryDeleted)) $queryDeleted = preg_replace("/(year|volume_numeric|first_page|series_volume_numeric|edition|orig_record|thesis) = [\"']0?[\"']/", "\\1 = NULL", $queryDeleted); // -------------------------------------------------------------------- // (3) RUN QUERY, (4) DISPLAY HEADER & RESULTS // (3) RUN the query on the database through the connection: if ($recordAction == "edit") { $result = queryMySQLDatabase($queryRefs); // function 'queryMySQLDatabase()' is defined in 'include.inc.php' $result = queryMySQLDatabase($queryUserData); // function 'queryMySQLDatabase()' is defined in 'include.inc.php' getUserGroups($tableUserData, $loginUserID); // update the 'userGroups' session variable (function 'getUserGroups()' is defined in 'include.inc.php') } elseif ($recordAction == "add") { $result = queryMySQLDatabase($queryRefs); // function 'queryMySQLDatabase()' is defined in 'include.inc.php' // 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!) $formVars['serialNo'] = $serialNo; // for '$recordAction = "add"' we update the original '$formVars' array element to ensure a correct serial number when generating the file name via the 'parsePlaceholderString()' function // handle file uploads: // for '$recordAction = "add"' file name generation needs to be done *after* the record has been created and a serial number is available if (!empty($uploadFile) && !empty($uploadFile["tmp_name"])) // if there was a file uploaded successfully { // process information of any file that was uploaded, auto-generate a file name if required and move the file to the appropriate directory: $fileName = handleFileUploads($uploadFile, $formVars); $queryRefsUpdateFileName = "UPDATE $tableRefs SET file = " . quote_smart($fileName) . " WHERE serial = " . quote_smart($serialNo); $result = queryMySQLDatabase($queryRefsUpdateFileName); // function 'queryMySQLDatabase()' is defined in 'include.inc.php' } $queryUserData = "INSERT INTO $tableUserData SET " . "marked = " . quote_smart($markedRadio) . ", " . "copy = " . quote_smart($copyName) . ", " . "selected = " . quote_smart($selectedRadio) . ", " . "user_keys = " . quote_smart($userKeysName) . ", " . "user_notes = " . quote_smart($userNotesName) . ", " . "user_file = " . quote_smart($userFileName) . ", " . "user_groups = " . quote_smart($userGroupsName) . ", " . "cite_key = " . quote_smart($citeKeyName) . ", " . "related = " . quote_smart($relatedName) . ", " . "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 $result = queryMySQLDatabase($queryUserData); // function 'queryMySQLDatabase()' is defined in 'include.inc.php' getUserGroups($tableUserData, $loginUserID); // update the 'userGroups' session variable (function 'getUserGroups()' is defined in 'include.inc.php') // Send EMAIL announcement: if ($sendEmailAnnouncements == "yes") // ('$sendEmailAnnouncements' is specified in 'ini.inc.php') { // first, build an appropriate author string: // Call the 'extractAuthorsLastName()' function (defined in 'include.inc.php') to extract the last name of a particular author (specified by position). 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 $authorString = extractAuthorsLastName("/ *; */", // get last name of first author "/ *, */", 1, $authorName); if ($authorCount == "2") // two authors { $authorString .= " & "; $authorString .= extractAuthorsLastName("/ *; */", // get last name of second author "/ *, */", 2, $authorName); } if ($authorCount == "3") // at least three authors $authorString .= " et al"; // send a notification email to the mailing list email address '$mailingListEmail' (specified in 'ini.inc.php'): $emailRecipient = "Literature Database Announcement List <" . $mailingListEmail . ">"; $emailSubject = "New entry: " . $authorString . " " . $yearNo; if (!empty($publicationName)) { $emailSubject .= " (" . $publicationName; if (!empty($volumeNo)) $emailSubject .= " " . $volumeNo . ")"; else $emailSubject .= ")"; } $emailBody = "The following record has been added to the " . $officialDatabaseName . ":" . "\n\n author: " . $authorName . "\n title: " . $titleName . "\n year: " . $yearNo . "\n publication: " . $publicationName . "\n volume: " . $volumeNo . "\n issue: " . $issueNo . "\n pages: " . $pagesNo . "\n\n added by: " . $loginFirstName . " " . $loginLastName . "\n details: " . $databaseBaseURL . "show.php?record=" . $serialNo // ('$databaseBaseURL' is specified in 'ini.inc.php') . "\n"; sendEmail($emailRecipient, $emailSubject, $emailBody); } } else // '$recordAction' is "delet" (Note that if you delete the mother record within the 'refs' table, the corresponding child entry within the 'user_data' table will remain!) { $result = queryMySQLDatabase($queryDeleted); // function 'queryMySQLDatabase()' is defined in 'include.inc.php' $result = queryMySQLDatabase($queryRefs); // function 'queryMySQLDatabase()' is defined in 'include.inc.php' } // Build correct header message: $headerMsg = "The record no. " . $serialNo . " has been successfully " . $recordAction . "ed."; // Append a "Display previous search results" link to the feedback header message if it will be displayed above a single record that was added/edited last: if (!empty($oldMultiRecordQuery)) { // Remove any previous 'headerMsg' parameter from the saved query URL: unset($oldMultiRecordQuery["headerMsg"]); // After a record has been successfully added/edited/deleted, we include a link to the last multi-record query in the feedback header message if: // 1) the SQL query in 'oldQuery' is different from that one stored in 'oldMultiRecordQuery', i.e. if 'oldQuery' points to a single record -OR- // 2) one or more new records have been added/imported if ((!empty($oldQuery) AND ($oldQuery["sqlQuery"] != $oldMultiRecordQuery["sqlQuery"]) AND ($recordAction != "delet")) OR ($recordAction == "add")) { // Generate a 'search.php' URL that points to the last multi-record query: $oldMultiRecordQueryURL = generateURL("search.php", "html", $oldMultiRecordQuery, true); // function 'generateURL()' is defined in 'include.inc.php' // Append a link to the previous search results to the feedback header message: $headerMsg .= " Display previous search results."; } } // Save the header message to a session variable: // NOTE: Opposed to single-record feedback (or the 'receipt.php' feedback), we don't include the header message within the 'headerMsg' URL parameter when // displaying the message above the last multi-record query. If we save the header message to a session variable ("HeaderString") this causes the // receiving script ("search.php") to display it just once; if we'd instead include the header message within the 'headerMsg' parameter, it would // be displayed above results of the last multi-record query even when the user browses to another search results page or changes the sort order. $HeaderString = returnMsg($headerMsg, "", "", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php' if ($recordAction == "add") { // Display the newly added record: header("Location: show.php?record=" . $serialNo . "&headerMsg=" . rawurlencode($headerMsg)); } elseif (($recordAction == "delet") AND !empty($oldMultiRecordQuery)) { // Generate a 'search.php' URL that points to the last multi-record query: $oldMultiRecordQueryURL = generateURL("search.php", "html", $oldMultiRecordQuery, false); // Display the previous search results: header("Location: $oldMultiRecordQueryURL"); } elseif (($recordAction != "delet") AND !empty($oldQuery)) { // Remove any previous 'headerMsg' parameter from the saved query URL: unset($oldQuery["headerMsg"]); // Generate a 'search.php' URL that points to the formerly displayed results page: $queryURL = generateURL("search.php", "html", $oldQuery, false); // Route back to the previous results display: // (i.e., after submission of the edit mask, we now go straight back to the results list that was displayed previously, // no matter what display type it was (List view, Citation view, or Details view)) header("Location: $queryURL"); } else // old method that uses 'receipt.php' for feedback: { // (4) Call 'receipt.php' which displays links to the modifyed/added record as well as to the previous search results page (if any) // (routing feedback output to a different script page will avoid any reload problems effectively!) header("Location: receipt.php?recordAction=" . $recordAction . "&serialNo=" . $serialNo . "&headerMsg=" . rawurlencode($headerMsg)); } // -------------------------------------------------------------------- // (5) CLOSE CONNECTION // (5) CLOSE the database connection: disconnectFromMySQLDatabase(); // function 'disconnectFromMySQLDatabase()' is defined in 'include.inc.php' // -------------------------------------------------------------------- // Handle file uploads: // process information of any file that was uploaded, auto-generate a file name if required // and move the file to the appropriate directory function handleFileUploads($uploadFile, $formVars) { global $filesBaseDir; // these variables are defined in 'ini.inc.php' global $moveFilesIntoSubDirectories; global $dirNamingScheme; global $renameUploadedFiles; global $fileNamingScheme; global $handleNonASCIIChars; global $allowedFileNameCharacters; global $allowedDirNameCharacters; global $changeCaseInFileNames; global $changeCaseInDirNames; $tmpFilePath = $uploadFile["tmp_name"]; // Generate file name: if ($renameUploadedFiles == "yes") // rename file according to a standard naming scheme { if (preg_match("/.+\.[^.]+$/i", $uploadFile["name"])) // preserve any existing file name extension $fileNameExtension = preg_replace("/.+(\.[^.]+)$/i", "\\1", $uploadFile["name"]); else $fileNameExtension = ""; // auto-generate a file name according to the naming scheme given in '$fileNamingScheme': $newFileName = parsePlaceholderString($formVars, $fileNamingScheme, "<:serial:>"); // function 'parsePlaceholderString()' is defined in 'include.inc.php' // handle non-ASCII and unwanted characters: $newFileName = handleNonASCIIAndUnwantedCharacters($newFileName, $allowedFileNameCharacters, $handleNonASCIIChars); // function 'handleNonASCIIAndUnwantedCharacters()' is defined in 'include.inc.php' // add original file name extension: $newFileName .= $fileNameExtension; } else // take the file name as given by the user: $newFileName = $uploadFile["name"]; // Generate directory structure: if ($moveFilesIntoSubDirectories != "never") { // remove any slashes (i.e., directory delimiter(s)) from the beginning or end of '$dirNamingScheme': $dirNamingScheme = trimTextPattern($dirNamingScheme, "[\/\\\\]+", true, true); // function 'trimTextPattern()' is defined in 'include.inc.php' $dirNamingSchemePartsArray = preg_split("#[/\\\\]+#", $dirNamingScheme); // split on slashes to separate between multiple sub-directories $subDirNamesArray = array(); // initialize array variable which will hold the generated sub-directory names // auto-generate a directory name according to the naming scheme given in '$dirNamingScheme' // and handle non-ASCII chars plus unwanted characters: foreach($dirNamingSchemePartsArray as $dirNamingSchemePart) { // parse given placeholder string: $subDirName = parsePlaceholderString($formVars, $dirNamingSchemePart, ""); // function 'parsePlaceholderString()' is defined in 'include.inc.php' // handle non-ASCII and unwanted characters: $subDirName = handleNonASCIIAndUnwantedCharacters($subDirName, $allowedDirNameCharacters, $handleNonASCIIChars); // function 'handleNonASCIIAndUnwantedCharacters()' is defined in 'include.inc.php' if (!empty($subDirName)) $subDirNamesArray[] = $subDirName; } if (!empty($subDirNamesArray)) $subDirName = implode("/", $subDirNamesArray) . "/"; // merge any individual sub-directory names and append a slash to generate final sub-directory structure else $subDirName = ""; } else $subDirName = ""; // Perform any case transformations: // change case of file name: if (preg_match("/^(lower|upper)$/i", $changeCaseInFileNames)) $newFileName = changeCase($changeCaseInFileNames, $newFileName); // function 'changeCase()' is defined in 'include.inc.php' // change case of DIR name: if (preg_match("/^(lower|upper)$/i", $changeCaseInDirNames) && !empty($subDirName)) $subDirName = changeCase($changeCaseInDirNames, $subDirName); // Generate full destination path: // - if '$moveFilesIntoSubDirectories = "existing"' and there's an existing sub-directory (within the default files directory '$filesBaseDir') // whose name equals '$subDirName' we'll copy the new file into that sub-directory // - if '$moveFilesIntoSubDirectories = "always"' and '$subDirName' isn't empty, we'll generate an appropriately named sub-directory if it // doesn't exist yet // - otherwise we just copy the file to the root-level of '$filesBaseDir': if (!empty($subDirName) && (($moveFilesIntoSubDirectories == "existing" AND is_dir($filesBaseDir . $subDirName)) OR ($moveFilesIntoSubDirectories == "always"))) { $destFilePath = $filesBaseDir . $subDirName . $newFileName; // new file will be copied into sub-directory within '$filesBaseDir'... // copy the new subdir name & file name to the 'file' field variable: // Note: if a user uploads a file and there was already a file specified within the 'file' field, the old file will NOT get removed // from the files directory! Automatic file removal is omitted on purpose since it's way more difficult to recover an // inadvertently deleted file than to delete it manually. However, future versions should introduce a smarter way of handling // orphaned files... $fileName = $subDirName . $newFileName; if ($moveFilesIntoSubDirectories == "always" AND !is_dir($filesBaseDir . $subDirName)) // make sure the directory we're moving the file to exists before proceeding: recursiveMkdir($filesBaseDir . $subDirName); } else { $destFilePath = $filesBaseDir . $newFileName; // new file will be copied to root-level of '$filesBaseDir'... $fileName = $newFileName; // copy the new file name to the 'file' field variable (see note above!) } // Copy uploaded file from temporary location to the default file directory specified in '$filesBaseDir': // (for more on PHP file uploads see ) move_uploaded_file($tmpFilePath, $destFilePath); return $fileName; } // -------------------------------------------------------------------- // recursively create directories: // this function creates the specified directory using mkdir() // (adopted from user-contributed function at ) function recursiveMkdir($path) { if (!is_dir($path)) // the directory doesn't exist { // recurse, passing the parent directory so that it gets created // (note that dirname returns the parent directory of the last item of the path // regardless of whether the last item is a directory or a file) recursiveMkdir(dirname($path)); mkdir($path, 0770); // create directory // alternatively, if the above line doesn't work for you, you might want to try: // $oldumask = umask(0); // mkdir($path, 0755); // create directory // umask($oldumask); } } // -------------------------------------------------------------------- ?>