You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5902 lines
320 KiB

  1. <?php
  2. // turn on warnings and notice during developement
  3. include('initialize/PhpErrorSettings.inc.php');
  4. // Project: Web Reference Database (refbase) <http://www.refbase.net>
  5. // Copyright: Matthias Steffens <mailto:refbase@extracts.de> and the file's
  6. // original author(s).
  7. //
  8. // This code is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY. Please see the GNU General Public
  10. // License for more details.
  11. //
  12. // File: ./search.php
  13. // Repository: $HeadURL: file:///svn/p/refbase/code/branches/bleeding-edge/search.php $
  14. // Author(s): Matthias Steffens <mailto:refbase@extracts.de>
  15. //
  16. // Created: 30-Jul-02, 17:40
  17. // Modified: $Date: 2017-04-13 02:00:18 +0000 (Thu, 13 Apr 2017) $
  18. // $Author: karnesky $
  19. // $Revision: 1416 $
  20. // This is the main script that handles the search query and displays the query results.
  21. // Supports three different output styles: 1) List view, with fully configurable columns -> displayColumns() function
  22. // 2) Details view, shows all fields -> displayDetails() function; 3) Citation view -> generateCitations() function
  23. // TODO: - Refactor so that query builder will use a few common functions
  24. // - I18n
  25. // Incorporate some include files:
  26. include 'initialize/db.inc.php'; // 'db.inc.php' is included to hide username and password
  27. include 'includes/header.inc.php'; // include header
  28. include 'includes/results_header.inc.php'; // include results header
  29. include 'includes/footer.inc.php'; // include footer
  30. include 'includes/include.inc.php'; // include common functions
  31. include 'includes/cite.inc.php'; // include citation functions
  32. include 'includes/export.inc.php'; // include export functions
  33. include 'includes/execute.inc.php'; // include functions that deal with execution of shell commands
  34. include 'includes/atomxml.inc.php'; // include functions that deal with Atom XML
  35. include 'includes/modsxml.inc.php'; // include functions that deal with MODS XML
  36. include 'includes/oaidcxml.inc.php'; // include functions that deal with OAI_DC XML
  37. include 'includes/odfxml.inc.php'; // include functions that deal with ODF XML
  38. include 'includes/opensearch.inc.php'; // include functions that return an OpenSearch response
  39. include 'includes/openurl.inc.php';
  40. include 'includes/srwxml.inc.php'; // include functions that deal with SRW XML
  41. include 'initialize/ini.inc.php'; // include common variables
  42. // --------------------------------------------------------------------
  43. // Extract the ID of the client from which the query originated:
  44. // this identifier is used to identify queries that originated from the refbase command line clients ("cli-refbase-1.1", "cli-refbase_import-1.0") or from a bookmarklet (e.g., "jsb-refbase-1.0")
  45. // (note that 'client' parameter has to be extracted *before* the call to the 'start_session()' function, since it's value is required by this function)
  46. if (isset($_REQUEST['client']))
  47. $client = $_REQUEST['client'];
  48. else
  49. $client = "";
  50. // START A SESSION:
  51. // call the 'start_session()' function (from 'include.inc.php') which will also read out available session variables:
  52. start_session(true);
  53. // Read out POST data that were saved as a session variable:
  54. // NOTE: this is done by 'show.php' if the original request was a POST (as is the case for the refbase command line client)
  55. // in order to retain large param/value strings (that would exceed the maximum string limit for GET requests)
  56. if (isset($_SESSION['postData']))
  57. {
  58. foreach ($_SESSION['postData'] as $varname => $value)
  59. {
  60. $_POST[$varname] = $value;
  61. $_REQUEST[$varname] = $value;
  62. }
  63. deleteSessionVariable("postData"); // function 'deleteSessionVariable()' is defined in 'include.inc.php'
  64. }
  65. // --------------------------------------------------------------------
  66. // Initialize preferred display language:
  67. // (note that 'locales.inc.php' has to be included *after* the call to the 'start_session()' function)
  68. include 'includes/locales.inc.php'; // include the locales
  69. // --------------------------------------------------------------------
  70. // EXTRACT FORM VARIABLES
  71. // [ Extract form variables sent through POST/GET by use of the '$_REQUEST' variable ]
  72. // [ !! NOTE !!: for details see <http://www.php.net/release_4_2_1.php> & <http://www.php.net/manual/en/language.variables.predefined.php> ]
  73. // Extract the form used for searching:
  74. $formType = $_REQUEST['formType'];
  75. // Extract the type of display requested by the user. Normally, this will be one of the following:
  76. // - '' => if the 'submit' parameter is empty, this will produce the default view
  77. // - 'List' => display records using the columnar output style ('displayColumns()' function)
  78. // - 'Display' => display details for all found records ('displayDetails()' function)
  79. // - 'Cite' => build a proper citation for all found records ('generateCitations()' function)
  80. // - 'Browse' => browse unique values from a given database field ('displayColumns()' function)
  81. // Note that the 'submit' parameter can be also one of the following:
  82. // - 'Export' => generate and return selected records in the bibliographic format specified by the user ('generateExport()' function)
  83. // - 'RSS' => these value gets included within the 'RSS' link (in the page header) and will cause 'search.php' to return results as RSS feed
  84. // - 'Search', 'Show' or 'Hide' => these values change/refine the search results or their appearance on screen (how many entries & which columns get displayed)
  85. // - 'Add', 'Remove' => these values will trigger actions that act on the selected records
  86. if (isset($_REQUEST['submit']) AND !empty($_REQUEST['submit']))
  87. $displayType = $_REQUEST['submit'];
  88. else
  89. $displayType = $_SESSION['userDefaultView']; // get the default view for the current user
  90. // extract the original value of the '$displayType' variable:
  91. // (which was included as a hidden form tag within the 'groupSearch' form of a search results page, the 'queryResults' form in Details view, and the 'duplicateSearch' form)
  92. if (isset($_REQUEST['originalDisplayType']))
  93. $originalDisplayType = $_REQUEST['originalDisplayType'];
  94. else
  95. $originalDisplayType = "";
  96. // we need to check if the user is allowed to view records with the specified display type:
  97. if ($displayType == "List")
  98. {
  99. if (isset($_SESSION['user_permissions']) AND !preg_match("/allow_list_view/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable does NOT contain 'allow_list_view'...
  100. {
  101. // return an appropriate error message:
  102. $HeaderString = returnMsg($loc["NoPermission"] . $loc["NoPermission_ForDisplayColumns"] . "!", "warning", "strong", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php'
  103. if (!preg_match("/^cli/i", $client))
  104. header("Location: index.php"); // redirect to main page ('index.php')
  105. exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  106. }
  107. }
  108. elseif ($displayType == "Display")
  109. {
  110. if (isset($_SESSION['user_permissions']) AND !preg_match("/allow_details_view/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable does NOT contain 'allow_details_view'...
  111. {
  112. // return an appropriate error message:
  113. $HeaderString = returnMsg($loc["NoPermission"] . $loc["NoPermission_ForDisplayDetails"] . "!", "warning", "strong", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php'
  114. if (!preg_match("/^cli/i", $client))
  115. header("Location: index.php"); // redirect to main page ('index.php')
  116. exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  117. }
  118. }
  119. elseif ($displayType == "Cite")
  120. {
  121. if (isset($_SESSION['user_permissions']) AND !preg_match("/allow_cite/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable does NOT contain 'allow_cite'...
  122. {
  123. // return an appropriate error message:
  124. $HeaderString = returnMsg($loc["NoPermission"] . $loc["NoPermission_ForCite"] . "!", "warning", "strong", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php'
  125. if (!preg_match("/^cli/i", $client))
  126. {
  127. if (preg_match("#/extract\.php#i", $referer)) // if the query was submitted by 'extract.php' (variable '$referer' is globally defined in function 'start_session()' in 'include.inc.php')
  128. header("Location: " . $referer); // redirect to calling page
  129. else
  130. header("Location: index.php"); // redirect to main page ('index.php')
  131. }
  132. exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  133. }
  134. }
  135. elseif ($displayType == "Export")
  136. {
  137. if (isset($_SESSION['user_permissions']) AND !preg_match("/allow_export|allow_batch_export/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable does NOT contain either 'allow_export' or 'allow_batch_export'...
  138. {
  139. // return an appropriate error message:
  140. $HeaderString = returnMsg($loc["NoPermission"] . $loc["NoPermission_ForExport"] . "!", "warning", "strong", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php'
  141. if (!preg_match("/^cli/i", $client))
  142. header("Location: index.php"); // redirect to main page ('index.php')
  143. exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  144. }
  145. }
  146. if ($formType == "sqlSearch" AND preg_match("#/sql_search\.php#i", $referer))
  147. {
  148. // NOTES: - currently, we restrict this if clause to requests from 'sql_search.php'
  149. // - note that this if clause is in NO way fool-proof since it won't apply if:
  150. // - the SQL query gets sent from another (custom) script
  151. // - the '$referer' variable is empty or defaults to 'index.php'
  152. // - the SQL query contained in the 'search.php' request gets edited directly
  153. // - the other approach would be to disallow SQL searches (if the user has no permission to do so) from any but a few
  154. // selected scripts; however, at least the scripts 'search.php', 'opensearch.php', 'show.php', 'user_login.php' and
  155. // 'query_history.php' must be allowed
  156. // - in that case, 'show.php' should save the URL of the current 'show.php' request to the 'referer' session variable;
  157. // since function 'start_session()' prefers '$_SESSION['referer']' over '$_SERVER['HTTP_REFERER']', this means that
  158. // '$referer' then contains a 'show.php' URL and not e.g. a '*_search.php' URL; this, in turn, prevents the
  159. // "NoPermission_ForSQL" warning if a user clicked the "Show All" link in the header of any of the '*_search.php' pages
  160. // - however, since refbase currently relies heavily on embedded SQL queries, disallowing SQL searches from any but a few
  161. // selected scripts may fail in unforeseen cases; it would also prevent users to embed 'search.php' links in foreign pages
  162. // - since it would be always possible to edit the 'search.php' request directly, we currently just disallow SQL searches via
  163. // the GUI (i.e. the 'sql_search.php' form); BUT:
  164. // - note that further measures (e.g. to prevent cross-site scripting (XSS) attacks or access to unwanted SQL queries & tables)
  165. // are done below
  166. // TODO: is there a way to disallow manual SQL searches (if the user has no permission to do so) which still allows searches from
  167. // 'opensearch.php' & 'show.php' etc and which does not rely on any passed referrer?
  168. if (isset($_SESSION['user_permissions']) AND !preg_match("/allow_sql_search/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable does NOT contain 'allow_sql_search'...
  169. {
  170. // return an appropriate error message:
  171. $HeaderString = returnMsg($loc["NoPermission"] . $loc["NoPermission_ForSQL"] . "!", "warning", "strong", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php'
  172. if (!preg_match("/^cli/i", $client))
  173. {
  174. if (preg_match("#/sql_search\.php#i", $referer)) // if the sql query was entered in the form provided by 'sql_search.php'
  175. header("Location: " . $referer); // redirect to calling page
  176. else
  177. header("Location: index.php"); // redirect to main page ('index.php')
  178. }
  179. exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  180. }
  181. }
  182. // For a given display type, extract the view type requested by the user (either 'Mobile', 'Print', 'Web' or ''):
  183. // ('' will produce the default 'Web' output style)
  184. if (isset($_REQUEST['viewType']))
  185. $viewType = ucfirst(strtolower($_REQUEST['viewType'])); // we normalize the case of passed values
  186. else
  187. $viewType = "";
  188. // Extract other variables from the request:
  189. if (isset($_REQUEST['sqlQuery']))
  190. $sqlQuery = $_REQUEST['sqlQuery'];
  191. else
  192. $sqlQuery = "";
  193. if (preg_match("/%20/", $sqlQuery)) // if '$sqlQuery' still contains URL encoded data... ('%20' is the URL encoded form of a space, see note below!)
  194. $sqlQuery = rawurldecode($sqlQuery); // URL decode SQL query (it was URL encoded before incorporation into hidden tags of the 'groupSearch', 'refineSearch', 'displayOptions' and 'queryResults' forms to avoid any HTML syntax errors)
  195. // NOTE: URL encoded data that are included within a *link* will get URL decoded automatically *before* extraction via '$_REQUEST'!
  196. // 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)!
  197. if (isset($_REQUEST['showQuery']) AND ($_REQUEST['showQuery'] == "1"))
  198. $showQuery = "1";
  199. else
  200. $showQuery = "0"; // don't show the SQL query by default
  201. if (isset($_REQUEST['showLinks']) AND ($_REQUEST['showLinks'] == "0"))
  202. $showLinks = "0";
  203. else
  204. $showLinks = "1"; // show the links column by default
  205. if (isset($_REQUEST['showRows']) AND preg_match("/^[0-9]+$/", $_REQUEST['showRows'])) // NOTE: we cannot use "^[1-9]+[0-9]*$" here since 'maximumRecords=0' is used in 'opensearch.php' and 'sru.php' queries to return just the number of found records (and not the full record data)
  206. $showRows = $_REQUEST['showRows'];
  207. else
  208. $showRows = $_SESSION['userRecordsPerPage']; // get the default number of records per page preferred by the current user
  209. if (isset($_REQUEST['rowOffset']))
  210. {
  211. // Note: Besides passing the current value of '$rowOffset' within GET queries, this parameter was also included as a hidden tag into the 'queryResults' form.
  212. // This was done, so that the correct offset could be re-applied after the user pressed either of the 'Add' or 'Remove' buttons.
  213. // However, '$rowOffset' MUST NOT be set if the user clicked the 'Display' or 'Cite' button within the 'queryResults' form!
  214. // Therefore, we'll trap this case here:
  215. if (($formType != "queryResults") OR ($formType == "queryResults" AND !preg_match("/^(Display|Cite)$/", $displayType)))
  216. $rowOffset = $_REQUEST['rowOffset'];
  217. else // if ($formType == "queryResults" AND preg_match("/^(Display|Cite)$/", $displayType))
  218. $rowOffset = 0;
  219. }
  220. else
  221. $rowOffset = 0;
  222. if (isset($_REQUEST['wrapResults']) AND ($_REQUEST['wrapResults'] == "0"))
  223. $wrapResults = "0"; // 'wrapResults=0' causes refbase to output only a partial document structure containing solely the search results (e.g. for HTML, everything is omitted except for the <table> block containing the search results)
  224. else
  225. $wrapResults = "1"; // we'll output a full document (HTML, RTF, LaTeX, etc) structure unless the 'wrapResults' parameter is set explicitly to "0"
  226. // In order to generalize routines we have to query further variables here:
  227. if (isset($_REQUEST['citeStyle']) AND !empty($_REQUEST['citeStyle']))
  228. $citeStyle = $_REQUEST['citeStyle']; // get the cite style chosen by the user (only occurs in 'extract.php' form and in query result lists)
  229. else
  230. $citeStyle = $defaultCiteStyle; // if no cite style was given, we'll use the default cite style which is defined by the '$defaultCiteStyle' variable in 'ini.inc.php'
  231. if (preg_match("/%20/", $citeStyle)) // if '$citeStyle' still contains URL encoded data... ('%20' is the URL encoded form of a space, see note below!)
  232. $citeStyle = rawurldecode($citeStyle); // ...URL decode 'citeStyle' statement (it was URL encoded before incorporation into a hidden tag of the 'sqlSearch' form to avoid any HTML syntax errors)
  233. // NOTE: URL encoded data that are included within a *link* will get URL decoded automatically *before* extraction via '$_REQUEST'!
  234. // 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)!
  235. if (isset($_REQUEST['exportFormat']) AND !empty($_REQUEST['exportFormat']))
  236. $exportFormat = $_REQUEST['exportFormat']; // get the export format style chosen by the user (only occurs in 'extract.php' form and in query result lists)
  237. else
  238. $exportFormat = $defaultExportFormat; // if no export format was given, we'll use the default export format which is defined by the '$defaultExportFormat' variable in 'ini.inc.php'
  239. if (preg_match("/%20/", $exportFormat)) // if '$exportFormat' still contains URL encoded data... ('%20' is the URL encoded form of a space, see note below!)
  240. $exportFormat = rawurldecode($exportFormat); // ...URL decode 'exportFormat' statement (it was URL encoded before incorporation into a hidden tag of the 'sqlSearch' form to avoid any HTML syntax errors)
  241. // NOTE: URL encoded data that are included within a *link* will get URL decoded automatically *before* extraction via '$_REQUEST'!
  242. // 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)!
  243. // Standardize XML export format names:
  244. // NOTE: the below regex patterns are potentially too lax and might cause misbehaviour in case any custom export formats have been added
  245. if (preg_match("/^Atom/i", $exportFormat))
  246. $exportFormat = "Atom XML";
  247. elseif (preg_match("/^MODS/i", $exportFormat))
  248. $exportFormat = "MODS XML";
  249. elseif (preg_match("/^(OAI_)?DC/i", $exportFormat))
  250. $exportFormat = "OAI_DC XML";
  251. elseif (preg_match("/^ODF/i", $exportFormat))
  252. $exportFormat = "ODF XML";
  253. elseif (preg_match("/^SRW_DC/i", $exportFormat))
  254. $exportFormat = "SRW_DC XML";
  255. elseif (preg_match("/^SRW/i", $exportFormat))
  256. $exportFormat = "SRW_MODS XML";
  257. elseif (preg_match("/^Word/i", $exportFormat))
  258. $exportFormat = "Word XML";
  259. if (isset($_REQUEST['citeOrder']))
  260. $citeOrder = $_REQUEST['citeOrder']; // get information how the data should be sorted (only occurs in 'extract.php'/'sql_search' forms and in query result lists). If this param is set to 'year', records will be listed in blocks sorted by year.
  261. else
  262. $citeOrder = "";
  263. // get information how citation data shall be returned:
  264. // - 'html' => return citations as HTML with mime type 'text/html'
  265. // - 'RTF' => return citations as RTF data with mime type 'application/rtf'
  266. // - 'PDF' => return citations as PDF data with mime type 'application/pdf'
  267. // - 'LaTeX' => return citations as LaTeX data with mime type 'application/x-latex'
  268. // - 'Markdown' => return citations as Markdown TEXT data with mime type 'text/plain'
  269. // - 'ASCII' => return citations as TEXT data with mime type 'text/plain'
  270. // - 'LaTeX .bbl' => return citations as LaTeX .bbl file (for use with LaTeX/BibTeX) with mime type 'application/x-latex'
  271. if (isset($_REQUEST['citeType']) AND preg_match("/^(html|RTF|PDF|LaTeX|Markdown|ASCII|LaTeX \.bbl)$/i", $_REQUEST['citeType']) AND !preg_match("/^(Add|Remove)$/i", $displayType)) // we always return HTML if the user clicked either the 'Add' or the 'Remove' button
  272. $citeType = $_REQUEST['citeType'];
  273. else
  274. $citeType = "html";
  275. // get information how exported data shall be returned:
  276. // - 'text' => return data with mime type 'text/plain'
  277. // - 'html' => return data with mime type 'text/html'
  278. // - 'xml' => return data with mime type 'application/xml'
  279. // - 'rss' => return data with mime type 'application/rss+xml'
  280. // - 'file' => return data as downloadable file
  281. // - 'email' => send data as email (to the user's login email address)
  282. if (isset($_REQUEST['exportType']) AND preg_match("/^(text|html|xml|rss|file|email)$/i", $_REQUEST['exportType']))
  283. $exportType = $_REQUEST['exportType'];
  284. else
  285. $exportType = "html";
  286. if (isset($_REQUEST['exportStylesheet']))
  287. $exportStylesheet = $_REQUEST['exportStylesheet']; // extract any stylesheet information that has been specified for XML export formats
  288. else
  289. $exportStylesheet = "";
  290. if (isset($_REQUEST['orderBy']))
  291. $orderBy = $_REQUEST['orderBy']; // extract the current ORDER BY parameter so that it can be re-applied when displaying details (only occurs in query result lists)
  292. else
  293. $orderBy = "";
  294. if (preg_match("/%20/", $orderBy)) // if '$orderBy' still contains URL encoded data... ('%20' is the URL encoded form of a space, see note below!)
  295. $orderBy = rawurldecode($orderBy); // ...URL decode 'orderBy' statement (it was URL encoded before incorporation into a hidden tag of the 'queryResults' form to avoid any HTML syntax errors)
  296. // NOTE: URL encoded data that are included within a *link* will get URL decoded automatically *before* extraction via '$_REQUEST'!
  297. // 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)!
  298. if ($orderBy == '') // if there's no ORDER BY parameter...
  299. $orderBy = "author, year DESC, publication"; // ...use the default ORDER BY clause
  300. if (isset($_REQUEST['headerMsg']))
  301. $headerMsg = $_REQUEST['headerMsg']; // get any custom header message (we strip any HTML tags from the custom header message below)
  302. // Note: this feature is provided in 'search.php' so that it's possible to include an information string within a link. This info string could
  303. // e.g. describe who's publications are being displayed (e.g.: "Publications of Matthias Steffens:"). I.e., a link pointing to a persons own
  304. // publications can include the appropriate owner information (it will show up as header message)
  305. else
  306. $headerMsg = "";
  307. if (preg_match("/%20/", $headerMsg)) // if '$headerMsg' still contains URL encoded data... ('%20' is the URL encoded form of a space, see notes above!)
  308. $headerMsg = rawurldecode($headerMsg); // ...URL decode 'headerMsg' statement (it was URL encoded before incorporation into a hidden tag of the 'displayOptions' form to avoid any HTML syntax errors)
  309. if (!empty($headerMsg))
  310. $headerMsg = stripTags($headerMsg); // strip any HTML tags from the custom header message to prevent cross-site scripting (XSS) attacks (function 'stripTags()' is defined in 'include.inc.php')
  311. if (isset($_SESSION['oldQuery']))
  312. $oldQuery = $_SESSION['oldQuery']; // get the query URL of the formerly displayed results page
  313. else
  314. $oldQuery = array();
  315. if (isset($_SESSION['queryHistory']))
  316. $queryHistory = $_SESSION['queryHistory']; // get any saved links to previous search results
  317. else
  318. $queryHistory = array();
  319. // Extract checkbox variable values from the request:
  320. if (isset($_REQUEST['marked']))
  321. $recordSerialsArray = $_REQUEST['marked']; // extract the values of all checked checkboxes (i.e., the serials of all selected records)
  322. else
  323. $recordSerialsArray = array();
  324. if (isset($_REQUEST['recordsSelectionRadio']))
  325. $recordsSelectionRadio = $_REQUEST['recordsSelectionRadio']; // for query results pages, extract user option whether we're supposed to process ALL records or just the ones that have been SELECTED on the current page
  326. else
  327. $recordsSelectionRadio = "1"; // process ALL records
  328. // check if the user did mark any checkboxes (and set up variables accordingly, they will be used within the 'displayDetails()', 'generateCitations()' and 'modifyUserGroups()' functions)
  329. if (preg_match("#[/_]search\.php#i", $referer) AND ($recordsSelectionRadio == "0") AND empty($recordSerialsArray)) // the "Selected Records" option was chosen, but NO checkboxes were marked
  330. $nothingChecked = true;
  331. else // the "All Found Records" option was chosen -OR- the "Selected Records" option was chosen and some checkboxes were marked -OR- the query resulted from another script like 'opensearch.php', 'show.php' or 'rss.php' (which has no checkboxes to mark!)
  332. $nothingChecked = false;
  333. // --------------------------------------------------------------------
  334. // VERIFY SQL QUERY:
  335. // Note that for user-generated SQL queries, further verification is done in function 'verifySQLQuery()'
  336. $notPermitted = false;
  337. // Prevent cross-site scripting (XSS) attacks:
  338. // Note that this is just a rough measure, everything that slips thru will get HTML encoded before output
  339. $htmlTagsArray = array("a", "applet", "base", "basefont", "bgsound", "blink", "body", "br", "div", "embed", "head", "html", "frame", "frameset", "ilayer", "iframe", "img", "input", "layer", "ilayer", "link", "meta", "script", "span", "style", "object", "table", "title", "xml");
  340. if (!empty($sqlQuery) AND preg_match("/(<|&lt;?|&#0*60;?|&#x0*3C;?|%3C|\\\\x3c|\\\\u003c)\/*(" . join("|", $htmlTagsArray) . ")/i", $sqlQuery)) // if the SQL query contains any unwanted HTML tags
  341. {
  342. $sqlQuery = preg_replace("/(<|&lt;?|&#0*60;?|&#x0*3C;?|%3C|\\\\x3c|\\\\u003c)\/*(" . join("|", $htmlTagsArray) . ").*?(>|&gt;?|&#0*62;?|&#x0*3E;?|%3E|\\\\x3e|\\\\u003e)*/i", "", $sqlQuery);
  343. $notPermitted = true;
  344. $HeaderString = $loc["NoPermission"] . $loc["NoPermission_ForThisQuery"] . "!";
  345. }
  346. // For a normal user we only allow the use of SELECT queries (the admin is allowed to do everything that is allowed by his GRANT privileges):
  347. // NOTE: This does only provide for minimal security!
  348. // To avoid further security risks you should grant the MySQL user (who's specified in 'db.inc.php') only those
  349. // permissions that are required to access the literature database. This can be done by use of a GRANT statement:
  350. // GRANT SELECT,INSERT,UPDATE,DELETE ON MYSQL_DATABASE_NAME_GOES_HERE.* TO MYSQL_USER_NAME_GOES_HERE@localhost IDENTIFIED BY 'MYSQL_PASSWORD_GOES_HERE';
  351. // if the SQL query isn't build from scratch but is accepted from user input (which is the case for the forms 'sqlSearch', 'duplicateSearch' and 'refineSearch'):
  352. if (!empty($sqlQuery) AND preg_match("/(sql|duplicate|refine)Search/i", $formType)) // the user used 'sql_search.php', 'duplicate_search.php' -OR- the "Search within Results" form above the query results list (that was produced by 'search.php')
  353. {
  354. if ((!isset($loginEmail)) OR ((isset($loginEmail)) AND ($loginEmail != $adminLoginEmail))) // if the user isn't logged in -OR- any normal user is logged in...
  355. {
  356. $all_fields = "author|author_count|online_citation|doi|online_publication|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|contribution_id|online_publication|online_citation|created_date|created_time|created_by|modified_date|modified_time|modified_by|serial|call_number|marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related";
  357. if (isset($loginEmail))
  358. $all_fields .= "|location";
  359. $tablesArray = array($tableAuth, $tableDeleted, $tableDepends, $tableFormats, $tableLanguages, $tableQueries, $tableRefs, $tableStyles, $tableTypes, $tableUserData, $tableUserFormats, $tableUserOptions, $tableUserPermissions, $tableUserStyles, $tableUserTypes, $tableUsers);
  360. $forbiddenSQLCommandsArray = array("DROP DATABASE", "DROP TABLE"); // the refbase MySQL user shouldn't have permissions for these commands anyhow, but by listing & checking for them here, we can return a more appropriate error message
  361. // ...and the user did use anything other than a SELECT query:
  362. if (!preg_match("/^SELECT/i", $sqlQuery) OR preg_match("/" . join("|", $forbiddenSQLCommandsArray) . "/i", $sqlQuery))
  363. {
  364. $notPermitted = true;
  365. $HeaderString = $loc["NoPermission_ForSQLOtherThanSELECT"] . "!";
  366. }
  367. // ...or the user tries to SELECT stuff they really shouldn't
  368. elseif (!preg_match("/^SELECT ((" . $all_fields . "),* *)+ FROM/i", $sqlQuery))
  369. {
  370. $notPermitted = true;
  371. $HeaderString = $loc["NoPermission"] . $loc["NoPermission_ForThisQuery"] . "!";
  372. }
  373. // ...or the user tries to hack the SQL query (by providing e.g. the string "FROM refs" within the SELECT statement) -OR- if the user attempts to query anything other than the 'refs' or 'user_data' table:
  374. elseif ((preg_match("/FROM .*(" . join("|", $tablesArray) . ").+ FROM /i", $sqlQuery)) OR (!preg_match("/FROM $tableRefs( LEFT JOIN $tableUserData ON serial ?= ?record_id AND user_id ?= ?\d*)?(?= WHERE| ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i", $sqlQuery)))
  375. {
  376. $notPermitted = true;
  377. $HeaderString = $loc["NoPermission"] . $loc["NoPermission_ForThisQuery"] . "!";
  378. }
  379. }
  380. // note that besides the above validation, in case of 'duplicate_search.php' the SQL query will be further restricted so that generally only SELECT queries can be executed (this is handled by function 'findDuplicates()')
  381. }
  382. if ($notPermitted)
  383. {
  384. // return an appropriate error message:
  385. $HeaderString = returnMsg($HeaderString, "warning", "strong", "HeaderString"); // function 'returnMsg()' is defined in 'include.inc.php'
  386. if (!preg_match("/^cli/i", $client))
  387. {
  388. if (preg_match("#/(sql|duplicate)_search\.php#i", $referer)) // if the sql query was entered in the form provided by 'sql_search.php' or 'duplicate_search.php'
  389. header("Location: " . $referer); // relocate back to the calling page
  390. else // if the user didn't come from 'sql_search.php' or 'duplicate_search.php' (e.g., if he attempted to hack parameters of a GET query directly)
  391. header("Location: index.php"); // relocate back to the main page
  392. }
  393. exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  394. }
  395. // --------------------------------------------------------------------
  396. // (1) OPEN CONNECTION, (2) SELECT DATABASE
  397. connectToMySQLDatabase(); // function 'connectToMySQLDatabase()' is defined in 'include.inc.php'
  398. // --------------------------------------------------------------------
  399. if (isset($_REQUEST["loginEmail"]))
  400. $loginEmail = $_REQUEST["loginEmail"]; // extract the email address of the currently logged in user
  401. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  402. $userID = getUserID($loginEmail); // ...get the user's 'user_id' using his/her 'loginEmail' (function 'getUserID()' is defined in 'include.inc.php')
  403. else
  404. $userID = 0; // set variable to zero (a user with '$userID = 0' definitely doesn't exist) in order to prevent 'Undefined variable...' messages
  405. // --------------------------------------------------------------------
  406. // CONSTRUCT SQL QUERY from user input provided by any of the search forms:
  407. // --- Form 'sql_search.php': ------------------
  408. if ($formType == "sqlSearch") // the user either used the 'sql_search.php' form for searching -OR- used scripts like 'show.php' or 'rss.php' (which also use 'formType=sqlSearch')...
  409. {
  410. // verify the SQL query specified by the user and modify it if security concerns are encountered:
  411. // (this function does add/remove user-specific query code as required and will fix problems with escape sequences within the SQL query)
  412. $query = verifySQLQuery($sqlQuery, $referer, $displayType, $showLinks); // function 'verifySQLQuery()' is defined in 'include.inc.php' (since it's also used by 'rss.php')
  413. }
  414. // --- Form 'duplicate_search.php': ---------------
  415. elseif ($formType == "duplicateSearch") // the user used the 'duplicate_search.php' form for searching...
  416. {
  417. // find duplicate records within results of the given SQL query (using settings extracted from the 'duplicateSearch' form
  418. // in 'duplicate_search.php') and return a modified database query that only matches these duplicate entries:
  419. list($sqlQuery, $displayType) = findDuplicates($sqlQuery, $originalDisplayType);
  420. // by passing the generated SQL query thru the 'verifySQLQuery()' function we ensure that necessary fields are added as needed:
  421. // (this function does add/remove user-specific query code as required and will fix problems with escape sequences within the SQL query)
  422. $query = verifySQLQuery($sqlQuery, $referer, $displayType, $showLinks); // function 'verifySQLQuery()' is defined in 'include.inc.php' (since it's also used by 'rss.php')
  423. }
  424. // --- Form 'simple_search.php': ---------------
  425. elseif ($formType == "simpleSearch") // the user used the 'simple_search.php' form for searching...
  426. {
  427. $query = extractFormElementsSimple($showLinks, $userID);
  428. }
  429. // --- Form 'library_search.php': --------------
  430. elseif ($formType == "librarySearch") // the user used the 'library_search.php' form for searching...
  431. {
  432. $query = extractFormElementsLibrary($showLinks, $userID);
  433. }
  434. // --- Form 'advanced_search.php': -------------
  435. elseif ($formType == "advancedSearch") // the user used the 'advanced_search.php' form for searching...
  436. {
  437. $query = extractFormElementsAdvanced($showLinks, $loginEmail, $userID);
  438. }
  439. // --- Form within 'search.php': ---------------
  440. elseif ($formType == "refineSearch" OR $formType == "displayOptions") // the user used the "Search within Results" (or "Display Options") form above the query results list (that was produced by 'search.php')
  441. {
  442. list($query, $displayType) = extractFormElementsRefineDisplay($tableRefs, $displayType, $originalDisplayType, $sqlQuery, $showLinks, $citeOrder, $userID); // function 'extractFormElementsRefineDisplay()' is defined in 'include.inc.php' since it's also used by 'users.php'
  443. }
  444. // --- Form within 'search.php': ---------------
  445. elseif ($formType == "queryResults") // the user clicked one of the buttons under the query results list (that was produced by 'search.php')
  446. {
  447. list($query, $displayType) = extractFormElementsQueryResults($displayType, $originalDisplayType, $showLinks, $citeOrder, $orderBy, $userID, $sqlQuery, $referer, $recordSerialsArray, $recordsSelectionRadio);
  448. }
  449. // --- Form 'extract.php': ---------------------
  450. elseif ($formType == "extractSearch") // the user used the 'extract.php' form for searching...
  451. {
  452. $query = extractFormElementsExtract($showLinks, $citeOrder, $userID);
  453. }
  454. // --- My Refs Search Form within 'index.php': -------------------
  455. elseif ($formType == "myRefsSearch") // the user used the 'Show My Refs' search form on the main page ('index.php') for searching...
  456. {
  457. $query = extractFormElementsMyRefs($showLinks, $loginEmail, $userID);
  458. }
  459. // --- Quick Search Form within 'index.php': ---------------------
  460. elseif ($formType == "quickSearch") // the user used the 'Quick Search' form on the main page ('index.php') for searching...
  461. {
  462. list($query, $displayType) = extractFormElementsQuick($sqlQuery, $showLinks, $userID, $displayType, $originalDisplayType);
  463. }
  464. // --- Browse My Refs Form within 'index.php': -------------------
  465. elseif ($formType == "myRefsBrowse") // the user used the 'Browse My Refs' form on the main page ('index.php') for searching...
  466. {
  467. $query = extractFormElementsBrowseMyRefs($showLinks, $loginEmail, $userID);
  468. }
  469. // --- My Groups Search Form within 'index.php': ---------------------
  470. elseif ($formType == "groupSearch") // the user used the 'Show My Group' form on the main page ('index.php') or above the query results list (that was produced by 'search.php')
  471. {
  472. list($query, $displayType) = extractFormElementsGroup($sqlQuery, $showLinks, $userID, $displayType, $originalDisplayType);
  473. }
  474. // --------------------------------------------------------------------
  475. // this is to support the '$fileVisibilityException' feature from 'ini.inc.php':
  476. if (preg_match("/^SELECT/i", $query) AND ($displayType != "Browse") AND !empty($fileVisibilityException) AND !preg_match("/SELECT.+$fileVisibilityException[0].+FROM/i", $query)) // restrict adding of columns to SELECT queries (so that 'DELETE FROM refs ...' statements won't get modified as well);
  477. {
  478. $query = preg_replace("/(, orig_record)?(, serial)?(, file, url, doi, isbn, type)? FROM $tableRefs/i", ", $fileVisibilityException[0]\\1\\2\\3 FROM $tableRefs",$query); // add column that's given in '$fileVisibilityException'
  479. $addCounterMax = 1; // this will ensure that the added column won't get displayed within the 'displayColumns()' and 'displayDetails()' functions
  480. }
  481. else
  482. $addCounterMax = 0;
  483. // (3) RUN QUERY, (4) DISPLAY EXPORT FILE OR HEADER & RESULTS
  484. // (3) RUN the query on the database through the connection:
  485. $result = queryMySQLDatabase($query); // function 'queryMySQLDatabase()' is defined in 'include.inc.php'
  486. // (4) If the display type is 'Export', display the exported file...
  487. if (($displayType == "Export"))
  488. {
  489. // Find out how many rows are available:
  490. $rowsFound = @ mysqli_num_rows($result); // for all other display types, the '$rowsFound' variable is set within function 'seekInMySQLResultsToOffset()' (see below)
  491. if ($rowsFound > 0) // If there were rows found ...
  492. {
  493. generateExport($result, $rowOffset, $showRows, $exportFormat, $exportType, $exportStylesheet, $displayType, $viewType, $userID); // export records using the export format specified in '$exportFormat'
  494. // For export, we disconnect from the database and exit this php file:
  495. disconnectFromMySQLDatabase(); // function 'disconnectFromMySQLDatabase()' is defined in 'include.inc.php'
  496. exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  497. }
  498. // else, if nothing was found, we proceed & return the "No records selected..." feedback (thru the 'displayColumns()' function)
  499. }
  500. // ...else, display HTML:
  501. // (4a) DISPLAY header:
  502. // First, build the appropriate SQL query in order to embed it into the 'your query' URL:
  503. if ($showLinks == "1")
  504. $query = preg_replace("/, file, url, doi, isbn, type FROM $tableRefs/i", " FROM $tableRefs", $query); // strip 'file', 'url', 'doi', 'isbn' & 'type columns from SQL query
  505. $query = preg_replace("/, serial FROM $tableRefs/i", " FROM $tableRefs", $query); // strip 'serial' column from SQL query
  506. $query = preg_replace("/, orig_record FROM $tableRefs/i", " FROM $tableRefs", $query); // strip 'orig_record' column from SQL query
  507. if (!empty($fileVisibilityException))
  508. $query = preg_replace("/, $fileVisibilityException[0] FROM $tableRefs/i", " FROM $tableRefs", $query); // strip column that's given in '$fileVisibilityException' (defined in 'ini.inc.php')
  509. if (preg_match("/(simple|advanced|library|quick)Search/", $formType)) // if $formType is "simpleSearch", "advancedSearch", "librarySearch" or "quickSearch" and there is more than one WHERE clause (indicated by '...AND...'):
  510. $query = preg_replace('/WHERE serial RLIKE "\.\+" AND/i', 'WHERE', $query); // strip first WHERE clause (which was added only due to an internal workaround)
  511. $queryURL = rawurlencode($query); // URL encode SQL query
  512. if (!preg_match("/^SELECT/i", $query)) // for queries other than SELECT queries (e.g. UPDATE, DELETE or INSERT queries that were executed by the admin via use of 'sql_search.php')
  513. $affectedRows = ($result ? mysqli_affected_rows ($connection) : 0); // get the number of rows that were modified (or return 0 if an error occurred)
  514. // If the previous query (which is stored in the 'oldQuery' session variable) is different
  515. // from the current query, we append it to the 'queryHistory' session variable:
  516. if (!empty($oldQuery))
  517. {
  518. // Extract the 'WHERE' clause from the current & the previous SQL query:
  519. $queryWhereClause = extractWHEREclause($query); // function 'extractWHEREclause()' is defined in 'include.inc.php'
  520. $oldQueryWhereClause = extractWHEREclause($oldQuery["sqlQuery"]);
  521. if ($queryWhereClause != $oldQueryWhereClause)
  522. {
  523. $oldQueryURL = generateURL("search.php", "html", $oldQuery, true); // function 'generateURL()' is defined in 'include.inc.php'
  524. $oldQueryTitle = encodeHTML(explainSQLQuery($oldQueryWhereClause)); // functions 'encodeHTML()' and 'explainSQLQuery()' are defined in 'include.inc.php'
  525. $queryHistory[] = "<a href=\"" . $oldQueryURL . "\">" . $oldQueryTitle . "</a>";
  526. if (count($queryHistory) > 30) // we only keep the 30 most recent queries
  527. array_shift($queryHistory); // remove the first array element (i.e. remove the oldest query) if there are more than 30 saved queries
  528. saveSessionVariable("queryHistory", $queryHistory);
  529. }
  530. }
  531. // Second, save the generated query to a session variable:
  532. // NOTE: we exclude queries for export formats & citation formats other than HTML
  533. // (otherwise the history list would contain links to non-HTML content such as RTF or BibTeX files)
  534. if (($displayType != "Export") AND preg_match("/^html$/i", $citeType))
  535. {
  536. $queryParametersArray = array("sqlQuery" => $query,
  537. "client" => $client,
  538. "formType" => "sqlSearch",
  539. "submit" => $displayType,
  540. "viewType" => $viewType,
  541. "showQuery" => $showQuery,
  542. "showLinks" => $showLinks,
  543. "showRows" => $showRows,
  544. "rowOffset" => $rowOffset,
  545. "wrapResults" => $wrapResults,
  546. "citeOrder" => $citeOrder,
  547. "citeStyle" => $citeStyle,
  548. "exportFormat" => $exportFormat,
  549. "exportType" => $exportType,
  550. "exportStylesheet" => $exportStylesheet,
  551. "citeType" => $citeType,
  552. "headerMsg" => $headerMsg
  553. );
  554. saveSessionVariable("oldQuery", $queryParametersArray);
  555. }
  556. // Third, find out how many rows are available and (if there were rows found) seek to the current offset:
  557. // Note that the 'seekInMySQLResultsToOffset()' function will also (re-)assign values to the variables
  558. // '$rowOffset', '$showRows', '$rowsFound', '$previousOffset', '$nextOffset' and '$showMaxRow'.
  559. list($result, $rowOffset, $showRows, $rowsFound, $previousOffset, $nextOffset, $showMaxRow) = seekInMySQLResultsToOffset($result, $rowOffset, $showRows, $displayType, $citeType); // function 'seekInMySQLResultsToOffset()' is defined in 'include.inc.php'
  560. // If the current result set contains multiple records, we save the generated query URL to yet another session variable:
  561. // (after a record has been successfully added/edited/deleted, this query will be included as a link ["Display previous search results"] in the feedback header message
  562. // if the SQL query in 'oldQuery' is different from that one stored in 'oldMultiRecordQuery', i.e. if 'oldQuery' points to a single record)
  563. if (($rowsFound > 1) AND ($displayType != "Export") AND preg_match("/^html$/i", $citeType)) // as above, we exclude queries for export formats & citation formats other than HTML
  564. saveSessionVariable("oldMultiRecordQuery", $queryParametersArray);
  565. // Fourth, setup an array of arrays holding URL and title information for all RSS/Atom feeds available on this page:
  566. // (appropriate <link...> tags will be included in the HTML header for every URL specified)
  567. $rssURLArray = array();
  568. if (isset($_SESSION['user_permissions']) AND preg_match("/allow_rss_feeds/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_rss_feeds'...
  569. {
  570. // ...extract the 'WHERE' clause from the SQL query to include it within the feed URL:
  571. $queryWhereClause = extractWHEREclause($query); // function 'extractWHEREclause()' is defined in 'include.inc.php'
  572. // generate an URL pointing to the RSS/Atom feed that matches the current query:
  573. $rssURL = generateURL("show.php", $defaultFeedFormat, array("where" => $queryWhereClause), true, $showRows); // function 'generateURL()' is defined in 'include.inc.php', variable '$defaultFeedFormat' is defined in 'ini.inc.php'
  574. // build a title string that matches the current query:
  575. // (alternatively we could always use: "records matching current query")
  576. $rssTitle = "records where " . encodeHTML(explainSQLQuery($queryWhereClause)); // functions 'encodeHTML()' and 'explainSQLQuery()' are defined in 'include.inc.php'
  577. $rssURLArray[] = array("href" => $rssURL,
  578. "title" => $rssTitle);
  579. }
  580. // Finally, build the appropriate header string (which is required as parameter to the 'showPageHeader()' function):
  581. if (!isset($_SESSION['HeaderString'])) // if there's no stored message available
  582. {
  583. if (!empty($headerMsg)) // if there's a custom header message available, e.g. one that describes who's literature is being displayed...
  584. {
  585. // ...we use that string as header message ('$headerMsg' could contain something like: "Literature of **Matthias Steffens**:"):
  586. // Perform search & replace actions on the provided header message (which will e.g. convert '**...**' to '<b>...</b>' etc):
  587. // (the array '$transtab_refbase_html' in 'transtab_refbase_html.inc.php' defines which search & replace actions will be employed)
  588. $HeaderString = searchReplaceText($transtab_refbase_html, encodeHTML($headerMsg), true); // functions 'searchReplaceText()' and 'encodeHTML()' are defined in 'include.inc.php'
  589. }
  590. else // provide the default message:
  591. {
  592. if (preg_match("/^SELECT/i", $query)) // for SELECT queries:
  593. {
  594. if ($rowsFound == 1)
  595. {
  596. if ($displayType == "Browse")
  597. $HeaderStringPart = " item ";
  598. else
  599. $HeaderStringPart = " record ";
  600. }
  601. else
  602. {
  603. if ($displayType == "Browse")
  604. $HeaderStringPart = " items ";
  605. else
  606. $HeaderStringPart = " records ";
  607. }
  608. $HeaderStringPart .= "found matching ";
  609. /* Removed 2016-Nov-5 to sanitizie HeaderString
  610. if (isset($_SESSION['user_permissions']) AND preg_match("/allow_sql_search/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_sql_search'...
  611. // ...generate a link to 'sql_search.php' with a custom SQL query that matches the current result set & display options:
  612. $HeaderString = $HeaderStringPart
  613. . "<a href=\"sql_search.php?customQuery=1"
  614. . "&amp;sqlQuery=" . $queryURL
  615. . "&amp;showQuery=" . $showQuery
  616. . "&amp;showLinks=" . $showLinks
  617. . "&amp;showRows=" . $showRows
  618. . "&amp;submit=" . $displayType
  619. . "&amp;citeStyle=" . rawurlencode($citeStyle)
  620. . "&amp;citeOrder=" . $citeOrder
  621. . "\"" . addAccessKey("attribute", "sql_query") . " title=\"modify your current query" . addAccessKey("title", "sql_query") . "\">your query</a>"; // function 'addAccessKey()' is defined in 'include.inc.php'
  622. else // use of 'sql_search.php' isn't allowed for this user */
  623. $HeaderString = $HeaderStringPart . "your query"; // so we omit the link
  624. /* Removed 2016-Nov-5 to sanitizie HeaderString
  625. // add query links:
  626. $queryLinksArray = array();
  627. if (isset($_SESSION['loginEmail']) AND (isset($_SESSION['user_permissions']) AND preg_match("/allow_user_queries/", $_SESSION['user_permissions']))) // if a user is logged in AND the 'user_permissions' session variable contains 'allow_user_queries'...
  628. {
  629. // ...we'll show a link to save the current query:
  630. $queryLinksArray[] = "<a href=\"query_manager.php?customQuery=1"
  631. . "&amp;sqlQuery=" . $queryURL
  632. . "&amp;showQuery=" . $showQuery
  633. . "&amp;showLinks=" . $showLinks
  634. . "&amp;showRows=" . $showRows
  635. . "&amp;displayType=" . $displayType
  636. . "&amp;citeStyle=" . rawurlencode($citeStyle)
  637. . "&amp;citeOrder=" . $citeOrder
  638. . "&amp;viewType=" . $viewType
  639. . "\"" . addAccessKey("attribute", "save_query") . " title=\"save your current query" . addAccessKey("title", "save_query") . "\">save</a>";
  640. }
  641. if (isset($_SESSION['user_permissions']) AND preg_match("/allow_rss_feeds/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_rss_feeds'...
  642. {
  643. // ...we'll display a link that will generate a dynamic RSS feed for the current query:
  644. $queryLinksArray[] = "<a href=\"" . $rssURL . "\" title=\"track newly added records matching your current query by subscribing to this RSS feed\">RSS</a>";
  645. }
  646. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  647. {
  648. // ...we'll show a link to find any duplicates within the current query results:
  649. $queryLinksArray[] = "<a href=\"duplicate_search.php?customQuery=1"
  650. . "&amp;sqlQuery=" . $queryURL
  651. . "&amp;showLinks=" . $showLinks
  652. . "&amp;showRows=" . $showRows
  653. . "&amp;originalDisplayType=" . $displayType
  654. . "&amp;citeStyle=" . rawurlencode($citeStyle)
  655. . "&amp;citeOrder=" . $citeOrder
  656. . "\"" . addAccessKey("attribute", "dups") . " title=\"find duplicates that match your current query" . addAccessKey("title", "dups") . "\">dups</a>";
  657. }
  658. if (isset($_SESSION['queryHistory']))
  659. {
  660. // ...include a link to display the query history (if any) for the user's current session:
  661. $queryLinksArray[] = "<a href=\"query_history.php"
  662. . "\"" . addAccessKey("attribute", "history") . " title=\"recall a previous query from your current session" . addAccessKey("title", "history") . "\">history</a>";
  663. }
  664. if (!empty($queryLinksArray))
  665. $HeaderString .= " (" . implode("&nbsp;|&nbsp;", $queryLinksArray) . ")";
  666. if ($showQuery == "1")
  667. $HeaderString .= ":\n<br>\n<br>\n<code>" . encodeHTML($query) . "</code>"; // function 'encodeHTML()' is defined in 'include.inc.php'
  668. else // $showQuery == "0" or wasn't specified */
  669. $HeaderString .= ":";
  670. if ($rowsFound > 0)
  671. $HeaderString = ($rowOffset + 1) . "-" . $showMaxRow . " of " . $rowsFound . $HeaderString;
  672. elseif ($rowsFound == 0)
  673. $HeaderString = $rowsFound . $HeaderString;
  674. else
  675. $HeaderString = $HeaderString; // well, this is actually bad coding but I do it for clearity reasons...
  676. }
  677. else // for queries other than SELECT queries (e.g. UPDATE, DELETE or INSERT queries that were executed by the admin via use of 'sql_search.php') display the number of rows that were modified:
  678. {
  679. if ($affectedRows == 1)
  680. $HeaderStringPart = " record was ";
  681. else
  682. $HeaderStringPart = " records were ";
  683. $HeaderString = $affectedRows . $HeaderStringPart . "affected by "
  684. . "<a href=\"sql_search.php?customQuery=1"
  685. . "&amp;sqlQuery=" . $queryURL
  686. . "&amp;showQuery=" . $showQuery
  687. . "&amp;showLinks=" . $showLinks
  688. . "&amp;showRows=" . $showRows
  689. . "&amp;submit=" . $displayType
  690. . "&amp;citeStyle=" . rawurlencode($citeStyle)
  691. . "&amp;citeOrder=" . $citeOrder
  692. . "\">your query</a>:";
  693. if ($showQuery == "1")
  694. $HeaderString .= "\n<br>\n<br>\n<code>" . encodeHTML($query) . "</code>";
  695. }
  696. }
  697. }
  698. else
  699. {
  700. $HeaderString = $_SESSION['HeaderString']; // extract 'HeaderString' session variable (only necessary if register globals is OFF!)
  701. // Note: though we clear the session variable, the current message is still available to this script via '$HeaderString':
  702. deleteSessionVariable("HeaderString"); // function 'deleteSessionVariable()' is defined in 'include.inc.php'
  703. }
  704. // Now, show the login status:
  705. showLogin(); // function 'showLogin()' is defined in 'include.inc.php'
  706. if (!preg_match("/^cli/i", $client) AND ($wrapResults != "0") AND (!(($displayType == "Cite") AND (!preg_match("/^html$/i", $citeType))) OR ($rowsFound == 0))) // we exclude the HTML page header for citation formats other than HTML if something was found
  707. {
  708. // Then, call the 'displayHTMLhead()' and 'showPageHeader()' functions (which are defined in 'header.inc.php'):
  709. displayHTMLhead(encodeHTML($officialDatabaseName) . " -- Query Results", "index,follow", "Results from the " . encodeHTML($officialDatabaseName), "", true, "", $viewType, $rssURLArray);
  710. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^inc/i", $client))) // Note: we omit the visible header in print/mobile view ('viewType=Print' or 'viewType=Mobile') and for include mechanisms!
  711. showPageHeader($HeaderString);
  712. }
  713. // (4b) DISPLAY results:
  714. if ($displayType == "Display") // display full record details (Details view)
  715. displayDetails($result, $rowsFound, $query, $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $previousOffset, $nextOffset, $wrapResults, $nothingChecked, $citeStyle, $citeOrder, $orderBy, $showMaxRow, $headerMsg, $userID, $displayType, $viewType, $addCounterMax, $formType);
  716. elseif ($displayType == "Cite") // return found records as citations (Citation view)
  717. generateCitations($result, $rowsFound, $query, $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $previousOffset, $nextOffset, $wrapResults, $nothingChecked, $citeStyle, $citeOrder, $citeType, $orderBy, $headerMsg, $userID, $viewType);
  718. else // produce the columnar output style (List view or Browse view)
  719. displayColumns($result, $rowsFound, $query, $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $previousOffset, $nextOffset, $wrapResults, $nothingChecked, $citeStyle, $citeOrder, $headerMsg, $userID, $displayType, $viewType, $addCounterMax, $formType);
  720. // --------------------------------------------------------------------
  721. // (5) CLOSE CONNECTION
  722. disconnectFromMySQLDatabase(); // function 'disconnectFromMySQLDatabase()' is defined in 'include.inc.php'
  723. // --------------------------------------------------------------------
  724. // SHOW THE RESULTS IN AN HTML <TABLE> (columnar layout)
  725. function displayColumns($result, $rowsFound, $query, $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $previousOffset, $nextOffset, $wrapResults, $nothingChecked, $citeStyle, $citeOrder, $headerMsg, $userID, $displayType, $viewType, $addCounterMax, $formType)
  726. {
  727. global $searchReplaceActionsArray; // these variables are defined in 'ini.inc.php'
  728. global $databaseBaseURL;
  729. global $defaultDropDownFieldsEveryone;
  730. global $defaultDropDownFieldsLogin;
  731. global $displayResultsHeaderDefault;
  732. global $displayResultsFooterDefault;
  733. global $showFieldItemLinks;
  734. global $showLinkTypesInListView;
  735. global $maximumBrowseLinks;
  736. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  737. global $loc; // '$loc' is made globally available in 'core.php'
  738. global $client;
  739. if (preg_match("/.+LIMIT *[0-9]+/i",$query)) // query does contain the 'LIMIT' parameter
  740. $orderBy = preg_replace("/.+ORDER BY (.+) LIMIT.+/i","\\1",$query); // extract 'ORDER BY'... parameter (without including any 'LIMIT' parameter)
  741. else // query does not contain the 'LIMIT' parameter
  742. $orderBy = preg_replace("/.+ORDER BY (.+)/i","\\1",$query); // extract 'ORDER BY'... parameter
  743. if (($formType != "queryResults") OR (($formType == "queryResults") AND !($nothingChecked))) // some checkboxes were marked within the 'queryResults' form (or the request stems from a different script without checkboxes)
  744. {
  745. // If the query has results ...
  746. if ($rowsFound > 0)
  747. {
  748. // BEGIN RESULTS HEADER --------------------
  749. // 1) First, initialize some variables that we'll need later on
  750. if ($showLinks == "1" AND $displayType != "Browse") // we exclude the Browse view since it has a special type of 'Links' column and the 'file', 'url', 'doi', 'isbn' & 'type columns weren't included in the query
  751. $CounterMax = 5; // When displaying a 'Links' column truncate the last five columns (i.e., hide the 'file', 'url', 'doi', 'isbn' & 'type columns)
  752. else
  753. $CounterMax = 0; // Otherwise don't hide any columns
  754. // count the number of fields
  755. $fieldsFound = mysqli_num_fields($result);
  756. if ($displayType != "Browse")
  757. {
  758. // hide those last columns that were added by the script and not by the user
  759. $fieldsToDisplay = $fieldsFound-(2+$CounterMax+$addCounterMax); // (2+$CounterMax) -> $CounterMax is increased by 2 in order to hide the 'orig_record' & 'serial' columns (which were added to make checkboxes & dup warning work)
  760. // $addCounterMax is set to 1 when the field given in '$fileVisibilityException[0]' (defined in 'ini.inc.php') was added to the query, otherwise '$addCounterMax = 0'
  761. }
  762. else // for Browse view the 'orig_record' & 'serial' columns weren't included in the query
  763. $fieldsToDisplay = $fieldsFound;
  764. // Calculate the number of all visible columns (which is needed as colspan value inside some TD tags)
  765. if ($showLinks == "1")
  766. $NoColumns = (1+$fieldsToDisplay+1); // add checkbox & Links column
  767. else
  768. $NoColumns = (1+$fieldsToDisplay); // add checkbox column
  769. // Save the current List view query to a session variable:
  770. saveSessionVariable("lastListViewQuery", $query);
  771. // Defines field-specific search & replace 'actions' that will be applied to all those refbase
  772. // fields that are listed in the corresponding 'fields' element:
  773. // (These search and replace actions will be performed *in addition* to those specified globally
  774. // in '$searchReplaceActionsArray' (defined in 'ini.inc.php'). Same rules apply as for
  775. // '$searchReplaceActionsArray'.)
  776. $fieldSpecificSearchReplaceActionsArray = array(
  777. array(
  778. 'fields' => array("thesis", "approved", "marked", "copy", "selected"), // see also note for '$encodingExceptionsArray' below
  779. 'actions' => array("/(.+)/e" => "\$loc['\\1']") // use localized field values (e.g., in case of german we display 'ja' instead of 'yes', etc)
  780. ),
  781. array(
  782. 'fields' => array("type"),
  783. 'actions' => array("/(.+)/e" => "\$loc['type\\1']") // for the 'type' field, prefix variable with 'type' to match to localized value
  784. )
  785. );
  786. // NOTE: We substitute contents of the given fields with localized field values from variable
  787. // '$loc' (see '$fieldSpecificSearchReplaceActionsArray'). Since the locales in '$loc'
  788. // are already HTML encoded, we have to exclude these fields from any further HTML encoding.
  789. static $encodingExceptionsArray = array("thesis", "approved", "marked", "copy", "selected", "type");
  790. // Note: we omit the results header, browse links & query form for CLI clients, and when outputting only a partial document structure ('wrapResults=0')
  791. if (!preg_match("/^cli/i", $client) AND ($wrapResults != "0"))
  792. {
  793. // Note: we also omit the results header in print/mobile view! ('viewType=Print' or 'viewType=Mobile')
  794. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!isset($displayResultsHeaderDefault[$displayType]) OR (isset($displayResultsHeaderDefault[$displayType]) AND ($displayResultsHeaderDefault[$displayType] != "hidden"))))
  795. {
  796. if ($displayType == "Browse")
  797. $selectedField = preg_replace("/^SELECT (\w+).*/i","\\1", $query); // extract the field that's currently used in Browse view (so that we can re-select it in the drop-downs of the 'refineSearch' and 'displayOptions' forms)
  798. elseif (preg_match("/ WHERE [ ()]*(\w+)/i", $query)) // extract the first field from the 'WHERE' clause:
  799. $selectedField = preg_replace("/.+ WHERE [ ()]*(\w+).*/i", "\\1", $query);
  800. else
  801. $selectedField = "author"; // otherwise we'll select the 'author' field by default
  802. // Map MySQL field names to localized column names:
  803. $fieldNamesArray = mapFieldNames(true); // function 'mapFieldNames()' is defined in 'include.inc.php'
  804. $localizedDropDownFieldsArray = array();
  805. if (isset($_SESSION['loginEmail']) AND !empty($defaultDropDownFieldsLogin)) // if a user is logged in -AND- there were any additional fields specified...
  806. $dropDownFieldsArray = array_merge($defaultDropDownFieldsEveryone, $defaultDropDownFieldsLogin); // ...add these additional fields to the list of fields visible in the dropdown menus of the results header
  807. else
  808. $dropDownFieldsArray = $defaultDropDownFieldsEveryone;
  809. foreach ($dropDownFieldsArray as $field)
  810. {
  811. if (isset($fieldNamesArray[$field]))
  812. $localizedDropDownFieldsArray[$field] = $fieldNamesArray[$field];
  813. else // no localized field name exists, so we use the original field name
  814. $localizedDropDownFieldsArray[$field] = $field;
  815. }
  816. // 2) Build forms containing options to show the user's groups, refine the search results or change the displayed columns:
  817. // TODO for 2b+2c: should we allow users to choose via the web interface which columns are included in the popup menus?
  818. // 2a) Build a FORM with a popup containing the user's groups:
  819. $formElementsGroup = buildGroupSearchElements("search.php", $queryURL, $query, $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $displayType); // function 'buildGroupSearchElements()' is defined in 'include.inc.php'
  820. // 2b) Build a FORM containing options to refine the search results:
  821. // Call the 'buildRefineSearchElements()' function (defined in 'include.inc.php') which does the actual work:
  822. $formElementsRefine = buildRefineSearchElements("search.php", $queryURL, $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $localizedDropDownFieldsArray, $selectedField, $displayType);
  823. // 2c) Build a FORM containing display options (show/hide columns or change the number of records displayed per page):
  824. // Call the 'buildDisplayOptionsElements()' function (defined in 'include.inc.php') which does the actual work:
  825. $formElementsDisplayOptions = buildDisplayOptionsElements("search.php", $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $citeStyle, $citeOrder, $localizedDropDownFieldsArray, $selectedField, $fieldsToDisplay, $displayType, $headerMsg);
  826. echo displayResultsHeader("search.php", $formElementsGroup, $formElementsRefine, $formElementsDisplayOptions, $displayType); // function 'displayResultsHeader()' is defined in 'results_header.inc.php'
  827. // and insert a divider line (which separates the results header from the browse links & results data below):
  828. echo "\n<hr class=\"resultsheader\" align=\"center\" width=\"93%\">";
  829. }
  830. // 3) Build a TABLE with links for "previous" & "next" browsing, as well as links to intermediate pages
  831. // call the 'buildBrowseLinks()' function (defined in 'include.inc.php'):
  832. $BrowseLinks = buildBrowseLinks("search.php", $query, $NoColumns, $rowsFound, $showQuery, $showLinks, $showRows, $rowOffset, $previousOffset, $nextOffset, $wrapResults, $maximumBrowseLinks, "sqlSearch", $displayType, $citeStyle, $citeOrder, $orderBy, $headerMsg, $viewType);
  833. echo $BrowseLinks;
  834. // 4) Start a FORM
  835. if ((!preg_match("/^Print$/i", $viewType)) AND (!isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden"))))
  836. {
  837. echo "\n<form action=\"search.php\" method=\"GET\" name=\"queryResults\">"
  838. . "\n<input type=\"hidden\" name=\"formType\" value=\"queryResults\">"
  839. . "\n<input type=\"hidden\" name=\"submit\" value=\"Cite\">" // provide a default value for the 'submit' form tag (then, if any form element is selected, hitting <enter> will act as if the user clicked the 'Cite' button)
  840. . "\n<input type=\"hidden\" name=\"originalDisplayType\" value=\"$displayType\">" // embed the original value of the '$displayType' variable
  841. . "\n<input type=\"hidden\" name=\"orderBy\" value=\"" . rawurlencode($orderBy) . "\">" // embed the current ORDER BY parameter so that it can be re-applied when displaying details
  842. . "\n<input type=\"hidden\" name=\"showQuery\" value=\"$showQuery\">" // embed the current value of '$showQuery' so that it's available on 'display details' (batch display) & 'cite'
  843. . "\n<input type=\"hidden\" name=\"showLinks\" value=\"$showLinks\">" // embed the current value of '$showLinks' so that it's available on 'display details' (batch display) & 'cite'
  844. . "\n<input type=\"hidden\" name=\"showRows\" value=\"$showRows\">" // embed the current value of '$showRows' so that it's available on 'display details' (batch display) & 'cite'
  845. . "\n<input type=\"hidden\" name=\"rowOffset\" value=\"$rowOffset\">" // embed the current value of '$rowOffset' so that it can be re-applied after the user pressed either of the 'Add' or 'Remove' buttons within the 'queryResults' form
  846. // Note: the inclusion of '$rowOffset' here is only meant to support reloading of the same results page again after a user clicked the 'Add' or 'Remove' buttons
  847. // However, '$rowOffset' MUST NOT be set if the user clicked the 'Display' or 'Cite' button! Therefore we'll trap for this case at the top of the script.
  848. . "\n<input type=\"hidden\" name=\"sqlQuery\" value=\"$queryURL\">"; // embed the current sqlQuery so that it can be re-applied after the user pressed either of the 'Add' or 'Remove' buttons within the 'queryResults' form
  849. }
  850. }
  851. // 5) And start a TABLE, with column headers
  852. echo "\n<table id=\"columns\" class=\"results\" align=\"center\" border=\"0\" cellpadding=\"7\" cellspacing=\"0\" width=\"95%\" summary=\"This table holds the database results for your query\">";
  853. // for the column headers, start a TABLE ROW ...
  854. echo "\n<tr>";
  855. // ... print a marker ('x') column (which will hold the checkboxes within the results part)
  856. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0")) // Note: we omit the marker column in print/mobile view ('viewType=Print' or 'viewType=Mobile'), for CLI clients, and when outputting only a partial document structure ('wrapResults=0')!
  857. echo "\n\t<th align=\"left\" valign=\"top\">&nbsp;</th>";
  858. // for each of the attributes in the result set...
  859. for ($i=0; $i<$fieldsToDisplay; $i++)
  860. {
  861. // ... and print out each of the attribute names
  862. // in that row as a separate TH (Table Header)...
  863. $HTMLbeforeLink = "\n\t<th align=\"left\" valign=\"top\">"; // start the table header tag
  864. $HTMLafterLink = "</th>"; // close the table header tag
  865. // call the 'buildFieldNameLinks()' function (defined in 'include.inc.php'), which will return a properly formatted table header tag holding the current field's name
  866. // as well as the URL encoded query with the appropriate ORDER clause:
  867. $tableHeaderLink = buildFieldNameLinks("search.php", $query, "", $result, $i, $showQuery, $showLinks, $rowOffset, $showRows, $wrapResults, $citeStyle, $HTMLbeforeLink, $HTMLafterLink, "sqlSearch", $displayType, "", "", $headerMsg, $viewType);
  868. echo $tableHeaderLink; // print the attribute name as link
  869. }
  870. if (($showLinks == "1") AND ($displayType != "Browse"))
  871. {
  872. $newORDER = ("ORDER BY url DESC, doi DESC"); // Build the appropriate ORDER BY clause to facilitate sorting by Links column
  873. $HTMLbeforeLink = "\n\t<th align=\"left\" valign=\"top\">"; // start the table header tag
  874. $HTMLafterLink = "</th>"; // close the table header tag
  875. // call the 'buildFieldNameLinks()' function (defined in 'include.inc.php'), which will return a properly formatted table header tag holding the current field's name
  876. // as well as the URL encoded query with the appropriate ORDER clause:
  877. $tableHeaderLink = buildFieldNameLinks("search.php", $query, $newORDER, $result, $i, $showQuery, $showLinks, $rowOffset, $showRows, $wrapResults, $citeStyle, $HTMLbeforeLink, $HTMLafterLink, "sqlSearch", $displayType, $loc["Links"], "url", $headerMsg, $viewType);
  878. echo $tableHeaderLink; // print the attribute name as link
  879. }
  880. elseif (($showLinks == "1") AND ($displayType == "Browse"))
  881. {
  882. echo "\n\t<th align=\"left\" valign=\"top\">" // start the table header tag
  883. . "Show" // in Browse view we simply provide a static column header
  884. . "</th>"; // close the table header tag
  885. }
  886. // Finish the row
  887. echo "\n</tr>";
  888. // END RESULTS HEADER ----------------------
  889. // BEGIN RESULTS DATA COLUMNS --------------
  890. // Fetch one page of results (or less if on the last page)
  891. // (i.e., upto the limit specified in $showRows) fetch a row into the $row array and ...
  892. for ($rowCounter=0; (($rowCounter < $showRows) && ($row = @ mysqli_fetch_array($result))); $rowCounter++)
  893. {
  894. if (is_integer($rowCounter / 2)) // if we currently are at an even number of rows
  895. $rowClass = "even";
  896. else
  897. $rowClass = "odd";
  898. // ... start a TABLE ROW ...
  899. echo "\n<tr class=\"" . $rowClass . "\">";
  900. // ... print a column with a checkbox
  901. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0")) // Note: we omit the marker column in print/mobile view ('viewType=Print' or 'viewType=Mobile'), for CLI clients, and when outputting only a partial document structure ('wrapResults=0')!
  902. {
  903. echo "\n\t<td align=\"center\" valign=\"top\" width=\"10\">";
  904. // print a checkbox form element:
  905. if (!isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden")))
  906. {
  907. echo "\n\t\t<input type=\"checkbox\" onclick=\"updateAllRecs();\" name=\"marked[]\" value=\"";
  908. if ($displayType == "Browse")
  909. echo $row[0];
  910. else
  911. echo $row["serial"];
  912. echo "\" title=\"" . $loc["selectRecord"] . "\">";
  913. }
  914. if (!empty($row["orig_record"]))
  915. {
  916. if (!isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden")))
  917. echo "\n\t\t<br>";
  918. if ($row["orig_record"] < 0)
  919. echo "\n\t\t<img src=\"img/ok.gif\" alt=\"(" . $loc["original"] . ")\" title=\"" . $loc["originalRecord"] . "\" width=\"14\" height=\"16\" hspace=\"0\" border=\"0\">";
  920. else // $row["orig_record"] > 0
  921. echo "\n\t\t<img src=\"img/caution.gif\" alt=\"(" . $loc["duplicate"] . ")\" title=\"" . $loc["duplicateRecord"] . "\" width=\"5\" height=\"16\" hspace=\"0\" border=\"0\">";
  922. }
  923. if ($displayType != "Browse")
  924. {
  925. // add <abbr> block which works as a microformat that allows applications to identify objects on web pages; see <http://unapi.info/specs/> for more info
  926. echo "\n\t\t<div class=\"unapi\"><abbr class=\"unapi-id\" title=\"" . $databaseBaseURL . "show.php?record=" . $row["serial"] . "\"></abbr></div>";
  927. }
  928. echo "\n\t</td>";
  929. }
  930. // ... and print out each of the attributes
  931. // in that row as a separate TD (Table Data)
  932. for ($i=0; $i<$fieldsToDisplay; $i++)
  933. {
  934. // fetch the current attribute name:
  935. $orig_fieldname = getMySQLFieldInfo($result, $i, "name"); // function 'getMySQLFieldInfo()' is defined in 'include.inc.php'
  936. if (($displayType == "Browse") AND ($i == 0)) // in Browse view we save the first field name to yet another variable (since it'll be needed when generating correct queries in the Links column)
  937. $browseFieldName = $orig_fieldname;
  938. echo "\n\t<td valign=\"top\">";
  939. if (!empty($row[$i]))
  940. {
  941. // make field items into clickable search links:
  942. if (in_array($displayType, $showFieldItemLinks))
  943. // Note: function 'linkifyFieldItems()' will also call function 'encodeField()' to HTML
  944. // encode non-ASCII chars and to apply any field-specific search & replace actions
  945. echo linkifyFieldItems($orig_fieldname, $row[$i], $userID, $fieldSpecificSearchReplaceActionsArray, $encodingExceptionsArray, "/\s*[;]+\s*/", "; ", $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $wrapResults, $displayType, $viewType); // function 'linkifyFieldItems()' is defined in 'include.inc.php'
  946. else // don't hotlink field items
  947. echo encodeField($orig_fieldname, $row[$i], $fieldSpecificSearchReplaceActionsArray, $encodingExceptionsArray); // function 'encodeField()' is defined in 'include.inc.php'
  948. }
  949. echo "</td>";
  950. }
  951. // embed appropriate links (if available):
  952. if (($showLinks == "1") AND ($displayType != "Browse")) // we exclude Browse view since it will need a different type of link query (see below)
  953. {
  954. echo "\n\t<td valign=\"top\">";
  955. // print out available links:
  956. // for List view, we'll use the '$showLinkTypesInListView' array that's defined in 'ini.inc.php'
  957. // to specify which links shall be displayed (if available and if 'showLinks == 1')
  958. // (for links of type DOI/URL/ISBN/XREF, only one link will be printed; order of preference: DOI, URL, ISBN, XREF)
  959. echo printLinks($showLinkTypesInListView, $row, $showQuery, $showLinks, $wrapResults, $userID, $viewType, $orderBy);
  960. echo "\n\t</td>";
  961. }
  962. // for Browse view we'll incorporate links that will show all records whose field (given in '$orig_fieldname') matches the current value (given in '$row[0]'):
  963. elseif (($showLinks == "1") AND ($displayType == "Browse"))
  964. {
  965. // ...extract the 'WHERE' clause from the SQL query to include it within the link URL:
  966. $queryWhereClause = extractWHEREclause($query); // function 'extractWHEREclause()' is defined in 'include.inc.php'
  967. $queryWhereClause = preg_replace('/^serial RLIKE "\.\+"/i', '', $queryWhereClause); // strip generic WHERE clause if present
  968. // Construct the SQL query:
  969. // TODO: build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
  970. $browseViewShowRecordsQuery = buildSELECTclause("", $showLinks, "", false, false); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  971. $browseViewShowRecordsQuery .= " FROM " . $tableRefs; // add FROM clause
  972. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  973. $browseViewShowRecordsQuery .= " LEFT JOIN " . $tableUserData . " ON serial = record_id AND user_id = " . quote_smart($userID); // add LEFT JOIN part to FROM clause
  974. $browseViewShowRecordsQuery .= " WHERE "; // add WHERE clause
  975. if (!empty($queryWhereClause))
  976. $browseViewShowRecordsQuery .= $queryWhereClause . " AND ";
  977. $browseViewShowRecordsQuery .= $browseFieldName;
  978. if (!empty($row[0]))
  979. $browseViewShowRecordsQuery .= " = \"" . $row[0] . "\"";
  980. else
  981. $browseViewShowRecordsQuery .= " IS NULL";
  982. $browseViewShowRecordsQuery .= " ORDER BY author, year DESC, publication"; // add the default ORDER BY clause
  983. echo "\n\t<td valign=\"top\">";
  984. echo "\n\t\t<a href=\"search.php?sqlQuery=" . rawurlencode($browseViewShowRecordsQuery)
  985. . "&amp;formType=sqlSearch"
  986. . "&amp;showQuery=" . $showQuery
  987. . "&amp;showLinks=" . $showLinks
  988. . "&amp;showRows=" . $showRows
  989. . "&amp;submit="
  990. . "&amp;viewType=" . $viewType
  991. . "\"><img src=\"img/details.gif\" alt=\"records\" title=\"show records\" width=\"9\" height=\"17\" hspace=\"0\" border=\"0\"></a>&nbsp;&nbsp;";
  992. echo "\n\t</td>";
  993. }
  994. // Finish the row
  995. echo "\n</tr>";
  996. }
  997. // Finish the table
  998. echo "\n</table>";
  999. // END RESULTS DATA COLUMNS ----------------
  1000. // BEGIN RESULTS FOOTER --------------------
  1001. // Note: we omit the results footer, browse links & query form in print/mobile view ('viewType=Print' or 'viewType=Mobile'), for CLI clients, and when outputting only a partial document structure ('wrapResults=0')!
  1002. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0"))
  1003. {
  1004. // Again, insert the (already constructed) BROWSE LINKS
  1005. // (i.e., a TABLE with links for "previous" & "next" browsing, as well as links to intermediate pages)
  1006. echo $BrowseLinks;
  1007. // Build a results footer with form elements to cite, group or export all/selected records:
  1008. if (!isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden")))
  1009. {
  1010. if (isset($_SESSION['user_permissions']) AND ((isset($_SESSION['loginEmail']) AND preg_match("/allow_cite|allow_user_groups|allow_export|allow_batch_export/", $_SESSION['user_permissions'])) OR (!isset($_SESSION['loginEmail']) AND preg_match("/allow_cite|allow_export|allow_batch_export/", $_SESSION['user_permissions'])))) // if the 'user_permissions' session variable does contain any of the following: 'allow_cite' -AND- if logged in, aditionally: 'allow_user_groups', 'allow_export', 'allow_batch_export'...
  1011. // ...Insert a divider line (which separates the results data from the forms in the footer):
  1012. echo "\n<hr class=\"resultsfooter\" align=\"center\" width=\"93%\">";
  1013. // Call the 'buildResultsFooter()' function (which does the actual work):
  1014. $ResultsFooter = buildResultsFooter($showRows, $citeStyle, $citeOrder, $displayType, $headerMsg);
  1015. echo $ResultsFooter;
  1016. }
  1017. }
  1018. // END RESULTS FOOTER ----------------------
  1019. // Finally, finish the form
  1020. if ((!preg_match("/^Print$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0") AND (!isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden"))))
  1021. echo "\n</form>";
  1022. }
  1023. else
  1024. {
  1025. // Report that nothing was found:
  1026. $nothingFoundFeedback = nothingFound(false); // This is a clumsy workaround: by pretending that there were some records marked by the user ($nothingChecked = false) we force the 'nothingFound()' function to output "Sorry, but your query didn't produce any results!" instead of "No records selected..."
  1027. echo $nothingFoundFeedback;
  1028. }// end if $rowsFound body
  1029. }
  1030. else // if the user clicked either the 'Add' or the 'Remove' button on a search results page but did not mark some checkboxes in front of the records, we display a "No records selected..." warning:
  1031. {
  1032. // Report that nothing was selected:
  1033. $nothingFoundFeedback = nothingFound($nothingChecked);
  1034. echo $nothingFoundFeedback;
  1035. }
  1036. }
  1037. // --------------------------------------------------------------------
  1038. // SHOW THE RESULTS IN AN HTML <TABLE> (horizontal layout)
  1039. function displayDetails($result, $rowsFound, $query, $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $previousOffset, $nextOffset, $wrapResults, $nothingChecked, $citeStyle, $citeOrder, $orderBy, $showMaxRow, $headerMsg, $userID, $displayType, $viewType, $addCounterMax, $formType)
  1040. {
  1041. global $filesBaseURL; // these variables are defined in 'ini.inc.php'
  1042. global $searchReplaceActionsArray;
  1043. global $databaseBaseURL;
  1044. global $defaultDropDownFieldsEveryone;
  1045. global $defaultDropDownFieldsLogin;
  1046. global $displayResultsHeaderDefault;
  1047. global $displayResultsFooterDefault;
  1048. global $showFieldItemLinks;
  1049. global $fileVisibility;
  1050. global $fileVisibilityException;
  1051. global $maximumBrowseLinks;
  1052. global $openURLResolver;
  1053. global $isbnURLFormat;
  1054. global $loc; // '$loc' is made globally available in 'core.php'
  1055. global $client;
  1056. if (($formType != "queryResults") OR (($formType == "queryResults") AND !($nothingChecked))) // some checkboxes were marked within the 'queryResults' form (or the request stems from a different script without checkboxes)
  1057. {
  1058. // If the query has results ...
  1059. if ($rowsFound > 0)
  1060. {
  1061. // BEGIN RESULTS HEADER --------------------
  1062. // 1) First, initialize some variables that we'll need later on
  1063. if ($showLinks == "1")
  1064. $CounterMax = 5; // When displaying a 'Links' column truncate the last five columns (i.e., hide the 'file', 'url', 'doi', 'isbn' & 'type columns)
  1065. else
  1066. $CounterMax = 0; // Otherwise don't hide any columns
  1067. if (isset($_SESSION['loginEmail']) AND (preg_match("/SELECT .*?\brelated\b.*? FROM /i", $query))) // if a user is logged in, and the 'related' field is part of the SQL SELECT clause...
  1068. $CounterMax = ($CounterMax + 1); // ...we'll also need to hide the 'related' column (which isn't displayed in Details view but is only used to generate a link to related records)
  1069. // count the number of fields
  1070. $fieldsFound = mysqli_num_fields($result);
  1071. // hide those last columns that were added by the script and not by the user
  1072. $fieldsToDisplay = $fieldsFound-(2+$CounterMax+$addCounterMax); // (2+$CounterMax) -> $CounterMax is increased by 2 in order to hide the 'orig_record' & 'serial' columns (which were added to make checkboxes & dup warning work)
  1073. // $addCounterMax is set to 1 when the field given in '$fileVisibilityException[0]' (defined in 'ini.inc.php') was added to the query, otherwise '$addCounterMax = 0'
  1074. // In summary, when displaying a 'Links' column AND with a user being logged in AND with '$addCounterMax = 1', we hide the following fields: 'related, (the field given in '$fileVisibilityException[0]'), orig_record, serial, file, url, doi, isbn, type' (i.e., truncate the last nine columns)
  1075. // Calculate the number of all visible columns (which is needed as colspan value inside some TD tags)
  1076. if ($showLinks == "1") // in 'display details' layout, we simply set it to a fixed no of columns:
  1077. $NoColumns = 8; // 8 columns: checkbox, 3 x (field name + field contents), links
  1078. else
  1079. $NoColumns = 7; // 7 columns: checkbox, field name, field contents
  1080. // Save the current Details view query to a session variable:
  1081. saveSessionVariable("lastDetailsViewQuery", $query);
  1082. // Defines field-specific search & replace 'actions' that will be applied to all those refbase
  1083. // fields that are listed in the corresponding 'fields' element:
  1084. // (These search and replace actions will be performed *in addition* to those specified globally
  1085. // in '$searchReplaceActionsArray' (defined in 'ini.inc.php'). Same rules apply as for
  1086. // '$searchReplaceActionsArray'.)
  1087. $fieldSpecificSearchReplaceActionsArray = array(
  1088. array(
  1089. 'fields' => array("abstract"),
  1090. 'actions' => array("/[\r\n]+/" => "<br><br>") // for the 'abstract' field, transform runs of newline ('\n') or return ('\r') characters into two <br> tags
  1091. ),
  1092. array(
  1093. 'fields' => array("thesis", "approved", "marked", "copy", "selected"), // see also note for '$encodingExceptionsArray' below
  1094. 'actions' => array("/(.+)/e" => "\$loc['\\1']") // use localized field values (e.g., in case of german we display 'ja' instead of 'yes', etc)
  1095. ),
  1096. array(
  1097. 'fields' => array("type"),
  1098. 'actions' => array("/(.+)/e" => "\$loc['type\\1']") // for the 'type' field, prefix variable with 'type' to match to localized value
  1099. )
  1100. );
  1101. // NOTE: We substitute contents of the given fields with localized field values from variable
  1102. // '$loc' (see '$fieldSpecificSearchReplaceActionsArray'). Since the locales in '$loc'
  1103. // are already HTML encoded, we have to exclude these fields from any further HTML encoding.
  1104. static $encodingExceptionsArray = array("thesis", "approved", "marked", "copy", "selected", "type");
  1105. // Note: we omit the results header, browse links & query form for CLI clients, and when outputting only a partial document structure ('wrapResults=0')
  1106. if (!preg_match("/^cli/i", $client) AND ($wrapResults != "0"))
  1107. {
  1108. // Note: we also omit the results header in print/mobile view! ('viewType=Print' or 'viewType=Mobile')
  1109. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!isset($displayResultsHeaderDefault[$displayType]) OR (isset($displayResultsHeaderDefault[$displayType]) AND ($displayResultsHeaderDefault[$displayType] != "hidden"))))
  1110. {
  1111. // Extract the first field from the 'WHERE' clause:
  1112. if (preg_match("/ WHERE [ ()]*(\w+)/i", $query))
  1113. $selectedField = preg_replace("/.+ WHERE [ ()]*(\w+).*/i", "\\1", $query);
  1114. else
  1115. $selectedField = "author"; // in the 'Search within Results" form, we'll select the 'author' field by default
  1116. // Map MySQL field names to localized column names:
  1117. $fieldNamesArray = mapFieldNames(true); // function 'mapFieldNames()' is defined in 'include.inc.php'
  1118. $localizedDropDownFieldsArray = array();
  1119. if (isset($_SESSION['loginEmail']) AND !empty($defaultDropDownFieldsLogin)) // if a user is logged in -AND- there were any additional fields specified...
  1120. $dropDownFieldsArray = array_merge($defaultDropDownFieldsEveryone, $defaultDropDownFieldsLogin); // ...add these additional fields to the list of fields visible in the dropdown menus of the results header
  1121. else
  1122. $dropDownFieldsArray = $defaultDropDownFieldsEveryone;
  1123. foreach ($dropDownFieldsArray as $field)
  1124. {
  1125. if (isset($fieldNamesArray[$field]))
  1126. $localizedDropDownFieldsArray[$field] = $fieldNamesArray[$field];
  1127. else // no localized field name exists, so we use the original field name
  1128. $localizedDropDownFieldsArray[$field] = $field;
  1129. }
  1130. // Define option values for the display options dropdown menu:
  1131. $displayOptionsDropDownItemsArray = array("all fields" => $loc["DropDownFieldName_AllFields"],
  1132. "keywords, abstract" => $loc["DropDownFieldName_KeywordsAbstract"],
  1133. "additional fields" => $loc["DropDownFieldName_AdditionalFields"]);
  1134. if (isset($_SESSION['loginEmail'])) // if a user is logged in
  1135. $displayOptionsDropDownItemsArray["my fields"] = $loc["DropDownFieldName_MyFields"];
  1136. // 2) Build forms containing options to show the user's groups, refine the search results or change the displayed columns:
  1137. // TODO for 2b+2c: should we allow users to choose via the web interface which columns are included in the popup menus?
  1138. // 2a) Build a FORM with a popup containing the user's groups:
  1139. $formElementsGroup = buildGroupSearchElements("search.php", $queryURL, $query, $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $displayType); // function 'buildGroupSearchElements()' is defined in 'include.inc.php'
  1140. // 2b) Build a FORM containing options to refine the search results:
  1141. // Call the 'buildRefineSearchElements()' function (defined in 'include.inc.php') which does the actual work:
  1142. $formElementsRefine = buildRefineSearchElements("search.php", $queryURL, $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $localizedDropDownFieldsArray, $selectedField, $displayType);
  1143. // 2c) Build a FORM containing display options (show/hide columns or change the number of records displayed per page):
  1144. // Call the 'buildDisplayOptionsElements()' function (defined in 'include.inc.php') which does the actual work:
  1145. $formElementsDisplayOptions = buildDisplayOptionsElements("search.php", $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $citeStyle, $citeOrder, $displayOptionsDropDownItemsArray, "", $fieldsToDisplay, $displayType, $headerMsg);
  1146. echo displayResultsHeader("search.php", $formElementsGroup, $formElementsRefine, $formElementsDisplayOptions, $displayType); // function 'displayResultsHeader()' is defined in 'results_header.inc.php'
  1147. // and insert a divider line (which separates the results header from the browse links & results data below):
  1148. echo "\n<hr class=\"resultsheader\" align=\"center\" width=\"93%\">";
  1149. }
  1150. // 3) Build a TABLE with links for "previous" & "next" browsing, as well as links to intermediate pages
  1151. // call the 'buildBrowseLinks()' function (defined in 'include.inc.php'):
  1152. $BrowseLinks = buildBrowseLinks("search.php", $query, $NoColumns, $rowsFound, $showQuery, $showLinks, $showRows, $rowOffset, $previousOffset, $nextOffset, $wrapResults, $maximumBrowseLinks, "sqlSearch", "Display", $citeStyle, $citeOrder, $orderBy, $headerMsg, $viewType);
  1153. echo $BrowseLinks;
  1154. // 4) Start a FORM
  1155. if ((!preg_match("/^Print$/i", $viewType)) AND (!isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden"))))
  1156. {
  1157. echo "\n<form action=\"search.php\" method=\"GET\" name=\"queryResults\">"
  1158. . "\n<input type=\"hidden\" name=\"formType\" value=\"queryResults\">"
  1159. . "\n<input type=\"hidden\" name=\"submit\" value=\"Cite\">" // provide a default value for the 'submit' form tag (then, if any form element is selected, hitting <enter> will act as if the user clicked the 'Cite' button)
  1160. . "\n<input type=\"hidden\" name=\"originalDisplayType\" value=\"$displayType\">" // embed the original value of the '$displayType' variable
  1161. . "\n<input type=\"hidden\" name=\"orderBy\" value=\"" . rawurlencode($orderBy) . "\">" // embed the current ORDER BY parameter so that it can be re-applied when displaying details
  1162. . "\n<input type=\"hidden\" name=\"showQuery\" value=\"$showQuery\">" // embed the current value of '$showQuery' so that it's available on 'display details' (batch display) & 'cite'
  1163. . "\n<input type=\"hidden\" name=\"showLinks\" value=\"$showLinks\">" // embed the current value of '$showLinks' so that it's available on 'display details' (batch display) & 'cite'
  1164. . "\n<input type=\"hidden\" name=\"showRows\" value=\"$showRows\">" // embed the current value of '$showRows' so that it's available on 'display details' (batch display) & 'cite'
  1165. . "\n<input type=\"hidden\" name=\"rowOffset\" value=\"$rowOffset\">" // embed the current value of '$rowOffset' so that it can be re-applied after the user pressed either of the 'Add' or 'Remove' buttons within the 'queryResults' form
  1166. // Note: the inclusion of '$rowOffset' here is only meant to support reloading of the same results page again after a user clicked the 'Add' or 'Remove' buttons
  1167. // However, '$rowOffset' MUST NOT be set if the user clicked the 'Display' or 'Cite' button! Therefore we'll trap for this case at the top of the script.
  1168. . "\n<input type=\"hidden\" name=\"sqlQuery\" value=\"$queryURL\">"; // embed the current sqlQuery so that it can be re-applied after the user pressed either of the 'Add' or 'Remove' buttons within the 'queryResults' form
  1169. }
  1170. }
  1171. // 5) And start a TABLE, with column headers
  1172. echo "\n<table id=\"details\" class=\"results\" align=\"center\" border=\"0\" cellpadding=\"5\" cellspacing=\"0\" width=\"95%\" summary=\"This table holds the database results for your query\">";
  1173. // for the column headers, start a TABLE ROW ...
  1174. echo "\n<tr>";
  1175. // ... print a marker ('x') column (which will hold the checkboxes within the results part)
  1176. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0")) // Note: we omit the marker column in print/mobile view ('viewType=Print' or 'viewType=Mobile'), for CLI clients, and when outputting only a partial document structure ('wrapResults=0')!
  1177. echo "\n\t<th align=\"left\" valign=\"top\">&nbsp;</th>";
  1178. // ... print a record header
  1179. if (($showMaxRow-$rowOffset) == "1") // '$showMaxRow-$rowOffset' gives the number of displayed records for a particular page) // '($rowsFound == "1" || $showRows == "1")' wouldn't trap the case of a single record on the last of multiple results pages!
  1180. $recordHeader = $loc["Record"]; // use singular form if there's only one record to display
  1181. else
  1182. $recordHeader = $loc["Records"]; // use plural form if there are multiple records to display
  1183. echo "\n\t<th align=\"left\" valign=\"top\" colspan=\"6\">$recordHeader</th>";
  1184. if ($showLinks == "1")
  1185. {
  1186. $newORDER = ("ORDER BY url DESC, doi DESC"); // Build the appropriate ORDER BY clause to facilitate sorting by Links column
  1187. $HTMLbeforeLink = "\n\t<th align=\"left\" valign=\"top\">"; // start the table header tag
  1188. $HTMLafterLink = "</th>"; // close the table header tag
  1189. // call the 'buildFieldNameLinks()' function (defined in 'include.inc.php'), which will return a properly formatted table header tag holding the current field's name
  1190. // as well as the URL encoded query with the appropriate ORDER clause:
  1191. $tableHeaderLink = buildFieldNameLinks("search.php", $query, $newORDER, $result, "", $showQuery, $showLinks, $rowOffset, $showRows, $wrapResults, $citeStyle, $HTMLbeforeLink, $HTMLafterLink, "sqlSearch", "Display", $loc["Links"], "url", $headerMsg, $viewType);
  1192. echo $tableHeaderLink; // print the attribute name as link
  1193. }
  1194. // Finish the row
  1195. echo "\n</tr>";
  1196. // END RESULTS HEADER ----------------------
  1197. // BEGIN RESULTS DATA COLUMNS --------------
  1198. // Fetch one page of results (or less if on the last page)
  1199. // (i.e., upto the limit specified in $showRows) fetch a row into the $row array and ...
  1200. for ($rowCounter=0; (($rowCounter < $showRows) && ($row = @ mysqli_fetch_array($result))); $rowCounter++)
  1201. {
  1202. // ... print out each of the attributes
  1203. // in that row as a separate TR (Table Row)
  1204. $recordData = ""; // make sure that buffer variable is empty
  1205. for ($i=0; $i<$fieldsToDisplay; $i++)
  1206. {
  1207. // fetch the current attribute name:
  1208. $orig_fieldname = getMySQLFieldInfo($result, $i, "name"); // function 'getMySQLFieldInfo()' is defined in 'include.inc.php'
  1209. // for all the fields specified (-> all fields to the left):
  1210. if (preg_match("/^(author|title|year|volume|corporate_author|address|keywords|abstract|publisher|language|series_editor|series_volume|issn|area|notes|location|call_number|marked|user_keys|user_notes|user_groups|created_date|modified_date)$/", $orig_fieldname))
  1211. {
  1212. $recordData .= "\n<tr>"; // ...start a new TABLE row
  1213. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0")) // Note: we omit the marker column in print/mobile view ('viewType=Print' or 'viewType=Mobile'), for CLI clients, and when outputting only a partial document structure ('wrapResults=0')!
  1214. {
  1215. if ($i == 0) // ... print a column with a checkbox if it's the first row of attribute data:
  1216. $recordData .= "\n\t<td align=\"left\" valign=\"top\" width=\"10\"><input type=\"checkbox\" onclick=\"updateAllRecs();\" name=\"marked[]\" value=\"" . $row["serial"] . "\" title=\"" . $loc["selectRecord"] . "\"></td>";
  1217. else // ... otherwise simply print an empty TD tag:
  1218. $recordData .= "\n\t<td valign=\"top\" width=\"10\">&nbsp;</td>";
  1219. }
  1220. }
  1221. // ... and print out each of the ATTRIBUTE NAMES:
  1222. // in that row as a bold link...
  1223. if (preg_match("/^(author|title|type|year|publication|abbrev_journal|volume|issue|pages|call_number|serial)$/", $orig_fieldname)) // print a colored background (grey, by default)
  1224. {
  1225. $HTMLbeforeLink = "\n\t<td valign=\"top\" width=\"75\" class=\"mainfieldsbg\"><b>"; // start the (bold) TD tag
  1226. $HTMLafterLink = "</b></td>"; // close the (bold) TD tag
  1227. }
  1228. elseif (preg_match("/^(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key)$/", $orig_fieldname)) // print a colored background (light orange, by default) for all the user specific fields
  1229. {
  1230. $HTMLbeforeLink = "\n\t<td valign=\"top\" width=\"75\" class=\"userfieldsbg\"><b>"; // start the (bold) TD tag
  1231. $HTMLafterLink = "</b></td>"; // close the (bold) TD tag
  1232. }
  1233. else // no colored background (by default)
  1234. {
  1235. $HTMLbeforeLink = "\n\t<td valign=\"top\" width=\"75\" class=\"otherfieldsbg\"><b>"; // start the (bold) TD tag
  1236. $HTMLafterLink = "</b></td>"; // close the (bold) TD tag
  1237. }
  1238. // call the 'buildFieldNameLinks()' function (defined in 'include.inc.php'), which will return a properly formatted table data tag holding the current field's name
  1239. // as well as the URL encoded query with the appropriate ORDER clause:
  1240. $recordData .= buildFieldNameLinks("search.php", $query, "", $result, $i, $showQuery, $showLinks, $rowOffset, $showRows, $wrapResults, $citeStyle, $HTMLbeforeLink, $HTMLafterLink, "sqlSearch", "Display", "", "", $headerMsg, $viewType);
  1241. // print the ATTRIBUTE DATA:
  1242. // first, calculate the correct colspan value for all the fields specified:
  1243. if (preg_match("/^(author|address|keywords|abstract|location|user_keys)$/", $orig_fieldname))
  1244. $ColspanFields = 5; // supply an appropriate colspan value
  1245. elseif (preg_match("/^(title|corporate_author|notes|call_number|user_notes|user_groups)$/", $orig_fieldname))
  1246. $ColspanFields = 3; // supply an appropriate colspan value
  1247. // then, start the TD tag, for all the fields specified:
  1248. if (preg_match("/^(author|title|corporate_author|address|keywords|abstract|notes|location|call_number|user_keys|user_notes|user_groups)$/", $orig_fieldname)) // WITH colspan attribute:
  1249. {
  1250. if (preg_match("/^(author|title|call_number)$/", $orig_fieldname)) // print a colored background (grey, by default)
  1251. $recordData .= "\n\t<td valign=\"top\" colspan=\"$ColspanFields\" class=\"mainfieldsbg\">"; // ...with colspan attribute & appropriate value
  1252. elseif (preg_match("/^(user_keys|user_notes|user_file|user_groups)$/", $orig_fieldname)) // print a colored background (light orange, by default) for all the user specific fields
  1253. $recordData .= "\n\t<td valign=\"top\" colspan=\"$ColspanFields\" class=\"userfieldsbg\">"; // ...with colspan attribute & appropriate value
  1254. else // no colored background (by default)
  1255. $recordData .= "\n\t<td valign=\"top\" colspan=\"$ColspanFields\" class=\"otherfieldsbg\">"; // ...with colspan attribute & appropriate value
  1256. }
  1257. else // for all other fields WITHOUT colspan attribute:
  1258. {
  1259. if (preg_match("/^(type|year|publication|abbrev_journal|volume|issue|pages|serial)$/", $orig_fieldname)) // print a colored background (grey, by default)
  1260. $recordData .= "\n\t<td valign=\"top\" class=\"mainfieldsbg\">"; // ...without colspan attribute
  1261. elseif (preg_match("/^(marked|copy|selected|user_file|cite_key)$/", $orig_fieldname)) // print a colored background (light orange, by default) for all the user specific fields
  1262. $recordData .= "\n\t<td valign=\"top\" class=\"userfieldsbg\">"; // ...without colspan attribute
  1263. else // no colored background (by default)
  1264. $recordData .= "\n\t<td valign=\"top\" class=\"otherfieldsbg\">"; // ...without colspan attribute
  1265. }
  1266. // print the attribute data:
  1267. if (!empty($row[$i]))
  1268. {
  1269. if (preg_match("/^(author|title|year)$/", $orig_fieldname)) // print author, title & year fields in bold
  1270. $recordData .= "<b>";
  1271. // make field items into clickable search links:
  1272. if (in_array($displayType, $showFieldItemLinks))
  1273. // Note: function 'linkifyFieldItems()' will also call function 'encodeField()' to HTML
  1274. // encode non-ASCII chars and to apply any field-specific search & replace actions
  1275. $recordData .= linkifyFieldItems($orig_fieldname, $row[$i], $userID, $fieldSpecificSearchReplaceActionsArray, $encodingExceptionsArray, "/\s*[;]+\s*/", "; ", $showQuery, $showLinks, $showRows, $citeStyle, $citeOrder, $wrapResults, $displayType, $viewType); // function 'linkifyFieldItems()' is defined in 'include.inc.php'
  1276. else // don't hotlink field items
  1277. $recordData .= encodeField($orig_fieldname, $row[$i], $fieldSpecificSearchReplaceActionsArray, $encodingExceptionsArray); // function 'encodeField()' is defined in 'include.inc.php'
  1278. if (preg_match("/^(author|title|year)$/", $orig_fieldname))
  1279. $recordData .= "</b>";
  1280. }
  1281. $recordData .= "</td>"; // finish the TD tag
  1282. // for all the fields specified (-> all fields to the right):
  1283. if (preg_match("/^(author|type|abbrev_journal|pages|thesis|address|keywords|abstract|editor|orig_title|abbrev_series_title|edition|medium|conference|approved|location|serial|selected|user_keys|user_file|cite_key|created_by|modified_by)$/", $orig_fieldname))
  1284. {
  1285. if ($showLinks == "1")
  1286. {
  1287. // ...embed appropriate links (if available):
  1288. if ($i == 0) // ... print a column with links if it's the first row of attribute data:
  1289. {
  1290. 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
  1291. $baseURL = $databaseBaseURL;
  1292. else
  1293. $baseURL = "";
  1294. $recordData .= "\n\t<td valign=\"top\" width=\"50\" rowspan=\"2\">"; // note that this table cell spans the next row!
  1295. $linkArray = array(); // initialize array variable that will hold all available links
  1296. if (isset($_SESSION['user_permissions']) AND preg_match("/allow_edit/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_edit'...
  1297. // ... display a link that opens the edit form for this record:
  1298. $linkArray[] = "\n\t\t<a href=\"" . $baseURL . "record.php"
  1299. . "?serialNo=" . $row["serial"]
  1300. . "&amp;recordAction=edit"
  1301. . "\"><img src=\"" . $baseURL . "img/edit.gif\" alt=\"" . $loc["edit"] . "\" title=\"" . $loc["LinkTitle_EditRecord"] . "\" width=\"11\" height=\"17\" hspace=\"0\" border=\"0\"></a>";
  1302. // show a link to any corresponding FILE if one of the following conditions is met:
  1303. // - the variable '$fileVisibility' (defined in 'ini.inc.php') is set to 'everyone'
  1304. // - the variable '$fileVisibility' is set to 'login' AND the user is logged in
  1305. // - the variable '$fileVisibility' is set to 'user-specific' AND the 'user_permissions' session variable contains 'allow_download'
  1306. // - the array variable '$fileVisibilityException' (defined in 'ini.inc.php') contains a pattern (in array element 1) that matches the contents of the field given (in array element 0)
  1307. 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']))) OR (!empty($fileVisibilityException) AND preg_match($fileVisibilityException[1], $row[$fileVisibilityException[0]])))
  1308. {
  1309. if (!empty($row["file"]))// if the 'file' field is NOT empty
  1310. {
  1311. if (isset($_SESSION['user_permissions']) AND preg_match("/allow_edit/", $_SESSION['user_permissions']))
  1312. $prefix = "&nbsp;";
  1313. else
  1314. $prefix = "";
  1315. if (preg_match("#^(https?|ftp|file)://#i", $row["file"])) // if the 'file' field contains a full URL (starting with "http://", "https://", "ftp://" or "file://")
  1316. $URLprefix = ""; // we don't alter the URL given in the 'file' field
  1317. else // if the 'file' field contains only a partial path (like 'polarbiol/10240001.pdf') or just a file name (like '10240001.pdf')
  1318. $URLprefix = $filesBaseURL; // use the base URL of the standard files directory as prefix ('$filesBaseURL' is defined in 'ini.inc.php')
  1319. if (preg_match("/\.pdf$/i", $row["file"])) // if the 'file' field contains a link to a PDF file
  1320. $linkArray[] = $prefix . "\n\t\t<a href=\"" . $URLprefix . encodeHTML($row["file"]) . "\"><img src=\"" . $baseURL . "img/file_PDF.gif\" alt=\"" . $loc["pdf"] . "\" title=\"" . $loc["LinkTitle_DownloadPDFFile"] . "\" width=\"17\" height=\"17\" hspace=\"0\" border=\"0\"></a>"; // display a PDF file icon as download link
  1321. else
  1322. $linkArray[] = $prefix . "\n\t\t<a href=\"" . $URLprefix . encodeHTML($row["file"]) . "\"><img src=\"" . $baseURL . "img/file.gif\" alt=\"" . $loc["file"] . "\" title=\"" . $loc["LinkTitle_DownloadFile"] . "\" width=\"11\" height=\"15\" hspace=\"0\" border=\"0\"></a>"; // display a generic file icon as download link
  1323. }
  1324. }
  1325. // generate a link from the URL field:
  1326. if (!empty($row["url"])) // 'htmlentities()' is used to convert any '&' into '&amp;'
  1327. $linkArray[] = "\n\t\t<a href=\"" . encodeHTML($row["url"]) . "\"><img src=\"" . $baseURL . "img/www.gif\" alt=\"" . $loc["url"] . "\" title=\"" . $loc["LinkTitle_GotoWebPage"] . "\" width=\"17\" height=\"20\" hspace=\"0\" border=\"0\"></a>";
  1328. // generate a link from the DOI field:
  1329. if (!empty($row["doi"]))
  1330. $linkArray[] = "\n\t\t<a href=\"http://dx.doi.org/" . rawurlencode($row["doi"]) . "\"><img src=\"" . $baseURL . "img/doi.gif\" alt=\"" . $loc["doi"] . "\" title=\"" . $loc["LinkTitle_GotoWebPageViaDOI"] . "\" width=\"17\" height=\"20\" hspace=\"0\" border=\"0\"></a>";
  1331. // generate a link from the RELATED field:
  1332. if (isset($_SESSION['loginEmail'])) // if a user is logged in, show a link to any related records (if available):
  1333. {
  1334. if (!empty($row["related"]))
  1335. {
  1336. $relatedRecordsLink = buildRelatedRecordsLink($row["related"], $userID); // function 'buildRelatedRecordsLink()' is defined in 'include.inc.php'
  1337. $linkArray[] = "\n\t\t<a href=\"" . $baseURL . $relatedRecordsLink . "\"><img src=\"" . $baseURL . "img/related.gif\" alt=\"" . $loc["related"] . "\" title=\"" . $loc["LinkTitle_DisplayRelatedRecords"] . "\" width=\"19\" height=\"16\" hspace=\"0\" border=\"0\"></a>";
  1338. }
  1339. }
  1340. // if an ISBN number exists for the current record, provide a link to an ISBN resolver:
  1341. if (!empty($isbnURLFormat) AND !empty($row["isbn"]))
  1342. {
  1343. // this is a stupid hack that maps the names of the '$row' array keys to those used
  1344. // by the '$formVars' array (which is required by function 'parsePlaceholderString()')
  1345. // (eventually, the '$formVars' array should use the MySQL field names as names for its array keys)
  1346. $formVars = buildFormVarsArray($row); // function 'buildFormVarsArray()' is defined in 'include.inc.php'
  1347. // auto-generate an ISBN link according to the naming scheme given in '$isbnURLFormat' (in 'ini.inc.php'):
  1348. $isbnURL = parsePlaceholderString($formVars, $isbnURLFormat, ""); // function 'parsePlaceholderString()' is defined in 'include.inc.php'
  1349. $encodedURL = encodeHTML($isbnURL); // 'htmlentities()' is used to convert higher ASCII chars into its entities and any '&' into '&amp;'
  1350. $encodedURL = str_replace(" ", "%20", $encodedURL); // ensure that any spaces are also properly urlencoded
  1351. if (!empty($isbnURL))
  1352. $linkArray[] = "\n\t\t<a href=\"" . $encodedURL . "\"><img src=\"" . $baseURL . "img/isbn.gif\" alt=\"" . $loc["isbn"] . "\" title=\"" . $loc["LinkTitle_FindBookDetailsViaISBN"] . "\" width=\"17\" height=\"20\" hspace=\"0\" border=\"0\"></a>";
  1353. }
  1354. // provide a link to an OpenURL resolver:
  1355. if (!empty($openURLResolver))
  1356. {
  1357. $openURL = openURL($row); // function 'openURL()' is defined in 'openurl.inc.php'
  1358. $linkArray[] = "\n\t\t<a href=\"" . $openURL . "\"><img src=\"" . $baseURL . "img/xref.gif\" alt=\"" . $loc["openurl"] . "\" title=\"" . $loc["LinkTitle_FindRecordDetailsViaOpenURL"] . "\" width=\"18\" height=\"20\" hspace=\"0\" border=\"0\"></a>";
  1359. }
  1360. // insert COinS (ContextObjects in Spans):
  1361. $linkArray[] = "\n\t\t" . coins($row); // function 'coins()' is defined in 'openurl.inc.php'
  1362. // merge links with delimiters appropriate for display in the Links column:
  1363. $recordData .= mergeLinks($linkArray);
  1364. $recordData .= "\n\t</td>";
  1365. }
  1366. // ... for the second row (which consists of the second and third field), we don't print any table column tag at all since the links (printed in the first row) span this second row!
  1367. elseif ($i > 3) // ... for the third row up to the last row, simply print an empty TD tag:
  1368. $recordData .= "\n\t<td valign=\"top\" width=\"50\">&nbsp;</td>";
  1369. }
  1370. $recordData .= "\n</tr>"; // ...and finish the row
  1371. }
  1372. }
  1373. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0")) // supply an appropriate colspan value
  1374. $ColspanFields = $NoColumns;
  1375. else // print view, CLI client, or partial document structure (i.e., no marker column)
  1376. $ColspanFields = ($NoColumns - 1);
  1377. // Print out an URL that links directly to this record:
  1378. $recordData .= "\n<tr>" // start a new TR (Table Row)
  1379. . "\n\t<td colspan=\"$ColspanFields\" align=\"center\" class=\"smaller\"><a href=\"" . $databaseBaseURL . "show.php?record=" . $row["serial"] . "\" title=\"" . $loc["LinkTitle_Permalink"] . "\">" . $loc["PermalinkLong"] . "</a>"
  1380. . "<div class=\"unapi\"><abbr class=\"unapi-id\" title=\"" . $databaseBaseURL . "show.php?record=" . $row["serial"] . "\"></abbr></div></td>" // re <abbr> tag see <http://unapi.info/specs/>
  1381. . "\n</tr>";
  1382. // Append a divider line if it's not the last (or only) record on the page:
  1383. if ((($rowCounter+1) < $showRows) && (($rowCounter+1) < $rowsFound))
  1384. if (!(($showMaxRow == $rowsFound) && (($rowCounter+1) == ($showMaxRow-$rowOffset)))) // if we're NOT on the *last* page processing the *last* record... ('$showMaxRow-$rowOffset' gives the number of displayed records for a particular page)
  1385. $recordData .= "\n<tr>"
  1386. . "\n\t<td colspan=\"$ColspanFields\">&nbsp;</td>"
  1387. . "\n</tr>"
  1388. . "\n<tr>"
  1389. . "\n\t<td colspan=\"$ColspanFields\"><hr class=\"results\" align=\"left\" width=\"100%\"></td>"
  1390. . "\n</tr>"
  1391. . "\n<tr>"
  1392. . "\n\t<td colspan=\"$ColspanFields\">&nbsp;</td>"
  1393. . "\n</tr>";
  1394. echo $recordData;
  1395. }
  1396. // Finish the table
  1397. echo "\n</table>";
  1398. // END RESULTS DATA COLUMNS ----------------
  1399. // BEGIN RESULTS FOOTER --------------------
  1400. // Note: we omit the results footer, browse links & query form in print/mobile view ('viewType=Print' or 'viewType=Mobile'), for CLI clients, and when outputting only a partial document structure ('wrapResults=0')!
  1401. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0"))
  1402. {
  1403. // Again, insert the (already constructed) BROWSE LINKS
  1404. // (i.e., a TABLE with links for "previous" & "next" browsing, as well as links to intermediate pages)
  1405. echo $BrowseLinks;
  1406. // Build a results footer with form elements to cite, group or export all/selected records:
  1407. if (!isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden")))
  1408. {
  1409. if (isset($_SESSION['user_permissions']) AND ((isset($_SESSION['loginEmail']) AND preg_match("/allow_cite|allow_user_groups|allow_export|allow_batch_export/", $_SESSION['user_permissions'])) OR (!isset($_SESSION['loginEmail']) AND preg_match("/allow_cite|allow_export|allow_batch_export/", $_SESSION['user_permissions'])))) // if the 'user_permissions' session variable does contain any of the following: 'allow_cite' -AND- if logged in, aditionally: 'allow_user_groups', 'allow_export', 'allow_batch_export'...
  1410. // ...Insert a divider line (which separates the results data from the forms in the footer):
  1411. echo "\n<hr class=\"resultsfooter\" align=\"center\" width=\"93%\">";
  1412. // Call the 'buildResultsFooter()' function (which does the actual work):
  1413. $ResultsFooter = buildResultsFooter($showRows, $citeStyle, $citeOrder, $displayType, $headerMsg);
  1414. echo $ResultsFooter;
  1415. }
  1416. }
  1417. // END RESULTS FOOTER ----------------------
  1418. // Finally, finish the form
  1419. if ((!preg_match("/^Print$/i", $viewType)) AND (!preg_match("/^cli/i", $client)) AND ($wrapResults != "0") AND (!isset($displayResultsFooterDefault[$displayType]) OR (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] != "hidden"))))
  1420. echo "\n</form>";
  1421. }
  1422. else
  1423. {
  1424. // Report that nothing was found:
  1425. $nothingFoundFeedback = nothingFound(false); // This is a clumsy workaround: by pretending that there were some records marked by the user ($nothingChecked = false) we force the 'nothingFound()' function to output "Sorry, but your query didn't produce any results!" instead of "No records selected..."
  1426. echo $nothingFoundFeedback;
  1427. }// end if $rowsFound body
  1428. }
  1429. else // if the user clicked one of the buttons in the 'queryResults' form on a search results page but did not mark some checkboxes in front of the records, we display a "No records selected..." warning:
  1430. {
  1431. // Report that nothing was selected:
  1432. $nothingFoundFeedback = nothingFound($nothingChecked);
  1433. echo $nothingFoundFeedback;
  1434. }
  1435. }
  1436. // --------------------------------------------------------------------
  1437. // EXPORT RECORDS using the specified export format
  1438. function generateExport($result, $rowOffset, $showRows, $exportFormat, $exportType, $exportStylesheet, $displayType, $viewType, $userID)
  1439. {
  1440. global $officialDatabaseName; // these variables are defined in 'ini.inc.php'
  1441. global $contentTypeCharset;
  1442. global $convertExportDataToUTF8;
  1443. global $defaultExportFormat;
  1444. global $userOptionsArray;
  1445. global $loc; // '$loc' is made globally available in 'core.php'
  1446. // get all user options for the current user:
  1447. // (note that '$userOptionsArray' is made globally available)
  1448. $userOptionsArray = getUserOptions($userID); // function 'getUserOptions()' is defined in 'include.inc.php'
  1449. // fetch the path/name of the export format file that's associated with the export format given in '$exportFormat':
  1450. $exportFormatFile = getFormatFile($exportFormat, "export"); // function 'getFormatFile()' is defined in 'include.inc.php()'
  1451. if (empty($exportFormatFile))
  1452. {
  1453. $exportFormat = $defaultExportFormat; // if the given export format could not be found, we'll use the default export format which is defined by the '$defaultExportFormat' variable in 'ini.inc.php'
  1454. $exportFormatFile = getFormatFile($exportFormat, "export");
  1455. }
  1456. // include the found export format file *once*:
  1457. include_once "export/" . $exportFormatFile; // instead of 'include_once' we could also use: 'if ($rowCounter == 0) { include "export/" . $exportFormatFile; }'
  1458. // export found records using the specified export format:
  1459. $exportText = exportRecords($result, $rowOffset, $showRows, $exportStylesheet, $displayType); // function 'exportRecords()' is defined in the export format file given in '$exportFormatFile' (which, in turn, must reside in the 'export' directory of the refbase root directory)
  1460. // adjust the mime type and return exported data based on the key given in '$exportType':
  1461. if (preg_match("/text/i", $exportType))
  1462. $exportContentType = "text/plain";
  1463. elseif (preg_match("/^(html|email)$/i", $exportType))
  1464. $exportContentType = "text/html";
  1465. elseif (preg_match("/xml/i", $exportType))
  1466. {
  1467. // NOTE: Firefox >=2.x, Safari >=2.x and IE >=7.x break client-side XSL for RSS and Atom feeds!
  1468. // See e.g.: <http://decafbad.com/blog/2006/11/02/firefox-20-breaks-client-side-xsl-for-rss-and-atom-feeds>
  1469. // TODO: Re-evaluate: As a consequence, we apply a VERY dirty hack in 'atomxml.inc.php' that prevents the feed sniffing
  1470. // and subsequent browser applied default XSLT stylesheet that has been implemented by FireFox 2, Safari 2
  1471. // and Internet Explorer 7. To prevent the feed sniffing we insert a comment before the feed
  1472. // element that is larger than 512 bytes. See: <http://feedme.mind-it.info/pivot/entry.php?id=9>
  1473. //
  1474. // For some browsers (such as the Camino browser <http://caminobrowser.org/>) it's possible to set the content type
  1475. // to 'application/xml' which (while incorrect for Atom/RSS) will cause the browser to trigger their XML+XSLT renderer
  1476. // if the Atom/RSS feed was requested together with a stylesheet.
  1477. //
  1478. // If the content type is set to 'application/atom+xml', Firefox 2 and Safari 2 will always apply their own default
  1479. // XSLT stylesheet and ignore any client-side XSL transformation!
  1480. if (preg_match("/Atom/i", $exportFormat) AND empty($exportStylesheet))
  1481. $exportContentType = "application/atom+xml"; // NOTE: using Safari 3 on OS X 10.4, this seems to cause misbehavior; Firefox seems to work fine, though
  1482. else
  1483. $exportContentType = "application/xml";
  1484. }
  1485. elseif (preg_match("/rss/i", $exportType))
  1486. $exportContentType = "application/rss+xml";
  1487. elseif (preg_match("/file/i", $exportType)) // attempt to set mime type & download file name according to the chosen export format:
  1488. {
  1489. $exportContentType = "text/plain"; // set the default mime type
  1490. // Note that we do some "quick'n dirty" guessing for some export formats here (e.g., we assume/require that an XML export format name
  1491. // contains 'XML' within its name!). This is in NO way fool proof and should be handled in a better way!
  1492. if (preg_match("/XML/i", $exportFormat)) // if the export format name contains 'XML'
  1493. {
  1494. if (preg_match("/Atom/i", $exportFormat)) // if the export format name contains 'Atom'
  1495. $exportContentType = "application/atom+xml"; // see note above
  1496. else
  1497. $exportContentType = "application/xml";
  1498. if (preg_match("/Atom/i", $exportFormat)) // if the export format name contains 'Atom'
  1499. $exportFileName = "atom_export.xml";
  1500. elseif (preg_match("/SRW_DC/i", $exportFormat)) // if the export format name contains 'SRW_DC'
  1501. $exportFileName = "srw_dc_export.xml";
  1502. elseif (preg_match("/SRW_MODS/i", $exportFormat)) // if the export format name contains 'SRW_MODS'
  1503. $exportFileName = "srw_mods_export.xml";
  1504. elseif (preg_match("/SRW/i", $exportFormat)) // if the export format name contains 'SRW' (fallback)
  1505. $exportFileName = "srw_export.xml";
  1506. elseif (preg_match("/^MODS/i", $exportFormat)) // if the export format name starts with 'MODS' (NOTE: the regex pattern must not match "SRW_MODS XML")
  1507. $exportFileName = "mods_export.xml";
  1508. elseif (preg_match("/^(OAI_)?DC/i", $exportFormat)) // if the export format starts contains 'OAI_DC' or 'DC' (NOTE: the regex pattern must not match "SRW_DC XML")
  1509. $exportFileName = "oaidc_export.xml";
  1510. elseif (preg_match("/ODF|OpenDocument/i", $exportFormat)) // if the export format name contains 'ODF' or 'OpenDocument'
  1511. {
  1512. if (preg_match("/file/i", $exportType)) {
  1513. $exportContentType="application/vnd.oasis.opendocument.spreadsheet";
  1514. $exportFileName="odf_export.ods";
  1515. }
  1516. else {
  1517. $exportFileName = "content.xml";
  1518. }
  1519. }
  1520. elseif (preg_match("/Word/i", $exportFormat)) // if the export format name contains 'Word'
  1521. $exportFileName = "msword_export.xml";
  1522. else
  1523. $exportFileName = "export.xml";
  1524. }
  1525. elseif (preg_match("/ADS|BibTeX|Endnote|ISI|RIS/i", $exportFormat)) // if the export format name contains either 'ADS', 'BibTeX', 'Endnote', 'ISI' or 'RIS'
  1526. {
  1527. if (preg_match("/ADS/i", $exportFormat))
  1528. $exportFileName = "ads_export.txt";
  1529. elseif (preg_match("/BibTeX/i", $exportFormat))
  1530. $exportFileName = "bibtex_export.bib";
  1531. elseif (preg_match("/Endnote/i", $exportFormat))
  1532. $exportFileName = "endnote_export.enw";
  1533. elseif (preg_match("/ISI/i", $exportFormat))
  1534. $exportFileName = "isi_export.txt";
  1535. elseif (preg_match("/RIS/i", $exportFormat))
  1536. $exportFileName = "ris_export.ris";
  1537. }
  1538. else
  1539. $exportFileName = "exported_records.txt"; // set the default download file name
  1540. }
  1541. // if variable '$convertExportDataToUTF8' is set to "yes" in 'ini.inc.php', we'll convert latin1 data to UTF-8
  1542. // when exporting to XML; therefore, we'll need to temporarily set the value of the global '$contentTypeCharset'
  1543. // variable to UTF-8 which will ensure proper HTML output
  1544. if (($convertExportDataToUTF8 == "yes") AND ($contentTypeCharset != "UTF-8"))
  1545. {
  1546. $oldContentTypeCharset = $contentTypeCharset; // remember the actual database charset
  1547. $oldOfficialDatabaseName = $officialDatabaseName; // remember the database name as originally encoded
  1548. // if the database charset is not "UTF-8" then we'll also need to temporarily convert any higher ASCII chars in variables which get included within the HTML output
  1549. $officialDatabaseName = convertToCharacterEncoding("UTF-8", "IGNORE", $officialDatabaseName); // function 'convertToCharacterEncoding()' is defined in 'include.inc.php'
  1550. $contentTypeCharset = "UTF-8"; // for XML output we'll temporarily set the value of '$contentTypeCharset' to "UTF-8"
  1551. }
  1552. // set the appropriate mimetype & set the character encoding to the one given in '$contentTypeCharset':
  1553. setHeaderContentType($exportContentType, $contentTypeCharset); // function 'setHeaderContentType()' is defined in 'include.inc.php'
  1554. if (preg_match("/file/i", $exportType)) // instruct the browser to download the resulting XML file:
  1555. header('Content-Disposition: attachment; filename="' . $exportFileName . '"'); // Note that this doesn't seem to work with all browsers (notably not with Safari & OmniWeb on MacOSX Panther, but it does work with Mozilla & Camino as well as Safari on Tiger)
  1556. elseif (preg_match("/^(html|email)$/i", $exportType)) // output data as HTML, wrapped into <pre>...</pre> tags:
  1557. {
  1558. if (preg_match("/email/i", $exportType)) // send exported data to the user's login email address:
  1559. {
  1560. $emailRecipient = $_SESSION['loginEmail'];
  1561. $emailSubject = "Your records from the " . $officialDatabaseName . " (exported to " . $exportFormat . " format)";
  1562. $emailBody = $exportText;
  1563. sendEmail($emailRecipient, $emailSubject, $emailBody); // function 'sendEmail()' is defined in 'include.inc.php'
  1564. }
  1565. // call the 'displayHTMLhead()' function (defined in 'header.inc.php'):
  1566. displayHTMLhead(encodeHTML($officialDatabaseName) . " -- Exported Data", "index,follow", "Data exported from the " . encodeHTML($officialDatabaseName), "", false, "", $viewType, array());
  1567. $exportText = "\n\t<pre>\n" . encodeHTML($exportText) . "\n\t</pre>\n</body>\n</html>\n";
  1568. if ($exportType == "email")
  1569. $exportText = "\n\t<p>"
  1570. . "\n\t\t<a href=\"javascript:history.back()\" title=\"" . $loc["LinkTitle_GoBackToResults"] . "\">" . $loc["Go Back"] . "</a>"
  1571. . "\n\t</p>"
  1572. . "\n\t<p>"
  1573. . "\n\t\t<b>The data below have been sent to <a href=\"mailto:" . $_SESSION['loginEmail'] . "\">" . $_SESSION['loginEmail'] . "</a>:</b>"
  1574. . "\n\t</p>"
  1575. . $exportText;
  1576. }
  1577. if (($convertExportDataToUTF8 == "yes") AND ($contentTypeCharset != "UTF-8"))
  1578. {
  1579. $contentTypeCharset = $oldContentTypeCharset; // restore the actual database charset
  1580. $officialDatabaseName = $oldOfficialDatabaseName; // restore the database name as originally encoded
  1581. }
  1582. if ( (preg_match("/ODF|OpenDocument/i", $exportFormat)) && (preg_match("/file/i", $exportType)) ) {
  1583. // This is a dirty hack to zip and return an ODF file.
  1584. // It may be desired to retun other non-textual formats in the future & to return these as attachments by email in the future.
  1585. // If this becomes needed, we should refactor the output.
  1586. $zipfile = zipODF($exportText); // function 'zipODF()' is defined in 'odfxml.inc.php'
  1587. echo $zipfile -> file();
  1588. }
  1589. else {
  1590. // we'll present the output within the _same_ browser window:
  1591. // (note that we don't use a popup window here, since this may be blocked by particular browsers)
  1592. echo $exportText;
  1593. }
  1594. }
  1595. // --------------------------------------------------------------------
  1596. // CITE RECORDS using the specified citation style and format
  1597. function generateCitations($result, $rowsFound, $query, $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $previousOffset, $nextOffset, $wrapResults, $nothingChecked, $citeStyle, $citeOrder, $citeType, $orderBy, $headerMsg, $userID, $viewType)
  1598. {
  1599. global $contentTypeCharset; // these variables are defined in 'ini.inc.php'
  1600. global $defaultCiteStyle;
  1601. global $client;
  1602. global $userOptionsArray;
  1603. // get all user options for the current user:
  1604. // (note that '$userOptionsArray' is made globally available)
  1605. $userOptionsArray = getUserOptions($userID); // function 'getUserOptions()' is defined in 'include.inc.php'
  1606. // if the query has results ...
  1607. if ($rowsFound > 0)
  1608. {
  1609. // Save the current Citation view query to a session variable:
  1610. // saveSessionVariable("lastCitationViewQuery", $query);
  1611. // fetch the name of the citation style file that's associated with the style given in '$citeStyle':
  1612. $citeStyleFile = getStyleFile($citeStyle); // function 'getStyleFile()' is defined in 'include.inc.php'
  1613. if (empty($citeStyleFile))
  1614. {
  1615. $citeStyle = $defaultCiteStyle; // if the given cite style could not be found, we'll use the default cite style which is defined by the '$defaultCiteStyle' variable in 'ini.inc.php'
  1616. $citeStyleFile = getStyleFile($citeStyle);
  1617. }
  1618. // include the found citation style file *once*:
  1619. include_once "cite/" . $citeStyleFile;
  1620. // fetch the name of the citation format file that's associated with the format given in '$citeType':
  1621. $citeFormatFile = getFormatFile($citeType, "cite"); // function 'getFormatFile()' is defined in 'include.inc.php()'
  1622. if (empty($citeFormatFile))
  1623. {
  1624. if (preg_match("/^cli/i", $client)) // if the query originated from a command line client such as the refbase CLI clients ("cli-refbase-1.1", "cli-refbase_import-1.0")
  1625. $citeType = "ASCII";
  1626. else
  1627. $citeType = "html";
  1628. $citeFormatFile = getFormatFile($citeType, "cite");
  1629. }
  1630. // include the found citation format file *once*:
  1631. include_once "cite/" . $citeFormatFile;
  1632. $citationData = citeRecords($result, $rowsFound, $query, $queryURL, $showQuery, $showLinks, $rowOffset, $showRows, $previousOffset, $nextOffset, $wrapResults, $citeStyle, $citeOrder, $citeType, $orderBy, $headerMsg, $userID, $viewType);
  1633. if (preg_match("/^RTF$/i", $citeType)) // output references as RTF file
  1634. {
  1635. $citeContentType = "application/rtf";
  1636. $citeFileName = "citations.rtf";
  1637. }
  1638. elseif (preg_match("/^PDF$/i", $citeType)) // output references as PDF file
  1639. {
  1640. $citeContentType = "application/pdf";
  1641. $citeFileName = "citations.pdf";
  1642. }
  1643. elseif (preg_match("/^LaTeX$/i", $citeType)) // output references as LaTeX file
  1644. {
  1645. $citeContentType = "application/x-latex";
  1646. $citeFileName = "citations.tex";
  1647. }
  1648. elseif (preg_match("/^LaTeX \.bbl$/i", $citeType)) // output references as LaTeX .bbl file (for use with LaTeX/BibTeX)
  1649. {
  1650. $citeContentType = "application/x-latex";
  1651. $citeFileName = "citations.bbl";
  1652. }
  1653. elseif (preg_match("/^Markdown$/i", $citeType)) // output references as Markdown TEXT (a plain text formatting syntax)
  1654. {
  1655. $citeContentType = "text/plain";
  1656. $citeFileName = "citations.txt";
  1657. }
  1658. elseif (preg_match("/^ASCII$/i", $citeType)) // output references as plain TEXT
  1659. {
  1660. $citeContentType = "text/plain";
  1661. $citeFileName = "citations.txt";
  1662. }
  1663. else // by default, we'll output references in HTML format
  1664. {
  1665. $citeContentType = "text/html";
  1666. $citeFileName = "citations.html";
  1667. }
  1668. if (!preg_match("/^html$/i", $citeType))
  1669. // set the appropriate mimetype & set the character encoding to the one given in '$contentTypeCharset' (which is defined in 'ini.inc.php'):
  1670. setHeaderContentType($citeContentType, $contentTypeCharset); // function 'setHeaderContentType()' is defined in 'include.inc.php'
  1671. if (preg_match("/^application/i", $citeContentType))
  1672. // instruct the browser to download the resulting output as file:
  1673. header('Content-Disposition: attachment; filename="' . $citeFileName . '"'); // Note that this doesn't seem to work with all browsers (notably not with Safari & OmniWeb on MacOSX Panther, but it does work with Mozilla & Camino as well as Safari on Tiger)
  1674. echo $citationData;
  1675. }
  1676. else
  1677. {
  1678. $nothingFoundFeedback = nothingFound($nothingChecked);
  1679. echo $nothingFoundFeedback;
  1680. }
  1681. }
  1682. // --------------------------------------------------------------------
  1683. // BUILD RESULTS FOOTER
  1684. function buildResultsFooter($showRows, $citeStyle, $citeOrder, $displayType, $headerMsg)
  1685. {
  1686. global $useVisualEffects; // these variables are defined in 'ini.inc.php'
  1687. global $allowAnonymousGUIExport;
  1688. global $displayResultsFooterDefault;
  1689. global $loc; // defined in 'locales/core.php'
  1690. if (isset($_SESSION['user_permissions']) AND ((isset($_SESSION['loginEmail']) AND preg_match("/allow_cite|allow_user_groups|allow_export|allow_batch_export/", $_SESSION['user_permissions'])) OR (!isset($_SESSION['loginEmail']) AND preg_match("/allow_cite|allow_export|allow_batch_export/", $_SESSION['user_permissions'])))) // only the results footer if the 'user_permissions' session variable does contain any of the following: 'allow_cite' -AND- if logged in, aditionally: 'allow_user_groups', 'allow_export', 'allow_batch_export'...
  1691. {
  1692. $resultsFooterToggleText = "";
  1693. if (preg_match("/allow_cite/", $_SESSION['user_permissions']))
  1694. $resultsFooterToggleText .= "Cite";
  1695. if (preg_match("/allow_user_groups/", $_SESSION['user_permissions']))
  1696. {
  1697. if (preg_match("/allow_cite/", $_SESSION['user_permissions']))
  1698. {
  1699. if (preg_match("/allow_export|allow_batch_export/", $_SESSION['user_permissions']))
  1700. $resultsFooterToggleText .= ", ";
  1701. else
  1702. $resultsFooterToggleText .= " & ";
  1703. }
  1704. $resultsFooterToggleText .= "Group";
  1705. }
  1706. if (!isset($_SESSION['loginEmail']) AND ($allowAnonymousGUIExport == "yes") OR (isset($_SESSION['loginEmail']) AND preg_match("/allow_export|allow_batch_export/", $_SESSION['user_permissions'])))
  1707. {
  1708. if (preg_match("/allow_cite|allow_user_groups/", $_SESSION['user_permissions']))
  1709. $resultsFooterToggleText .= " & ";
  1710. $resultsFooterToggleText .= "Export";
  1711. }
  1712. $resultsFooterToggleText .= " Options";
  1713. if (isset($displayResultsFooterDefault[$displayType]) AND ($displayResultsFooterDefault[$displayType] == "open"))
  1714. {
  1715. $resultsFooterDisplayStyle = "block";
  1716. $resultsFooterToggleImage = "img/open.gif";
  1717. $resultsFooterInitialToggleText = "";
  1718. }
  1719. else
  1720. {
  1721. $resultsFooterDisplayStyle = "none";
  1722. $resultsFooterToggleImage = "img/closed.gif";
  1723. $resultsFooterInitialToggleText = encodeHTML($resultsFooterToggleText);
  1724. }
  1725. if ($useVisualEffects == "yes")
  1726. $toggleVisibilityFunction = "toggleVisibilitySlide";
  1727. else
  1728. $toggleVisibilityFunction = "toggleVisibility";
  1729. $ResultsFooterRow = "\n<div class=\"resultsfooter\">";
  1730. $ResultsFooterRow .= "\n<div class=\"showhide\">"
  1731. . "\n\t<a href=\"javascript:" . $toggleVisibilityFunction . "('resultactions','resultsFooterToggleimg','resultsFooterToggletxt','" . rawurlencode($resultsFooterToggleText) . "')\"" . addAccessKey("attribute", "footer") . " title=\"" . $loc["LinkTitle_ToggleVisibility"] . addAccessKey("title", "footer") . "\">"
  1732. . "\n\t\t<img id=\"resultsFooterToggleimg\" class=\"toggleimg\" src=\"" . $resultsFooterToggleImage . "\" alt=\"" . $loc["LinkTitle_ToggleVisibility"] . "\" width=\"9\" height=\"9\" hspace=\"0\" border=\"0\">"
  1733. . "\n\t\t<span id=\"resultsFooterToggletxt\" class=\"toggletxt\">" . $resultsFooterInitialToggleText . "</span>"
  1734. . "\n\t</a>"
  1735. . "\n</div>";
  1736. $ResultsFooterRow .= "\n<div id=\"resultactions\" style=\"display: " . $resultsFooterDisplayStyle . ";\">";
  1737. $ResultsFooterRow .= "\n\t<div id=\"selectresults\">"
  1738. . "\n\t\t<input type=\"radio\" id=\"allRecs\" name=\"recordsSelectionRadio\" value=\"1\" onfocus=\"checkall(false,'marked%5B%5D')\" title=\"cite/group/export all records of the current result set\" checked>"
  1739. . "\n\t\t<label for=\"allRecs\">All Found Records</label>"
  1740. . "\n\t\t<input type=\"radio\" id=\"selRecs\" name=\"recordsSelectionRadio\" value=\"0\" onfocus=\"checkall(true,'marked%5B%5D')\" title=\"cite/group/export only those records which you've selected on this page\">"
  1741. . "\n\t\t<label for=\"selRecs\">Selected Records:</label>"
  1742. . "\n\t</div>";
  1743. // Cite functionality:
  1744. if (isset($_SESSION['user_permissions']) AND preg_match("/allow_cite/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_cite', show form elements to build a reference list for the chosen records:
  1745. {
  1746. if (!isset($_SESSION['user_styles']))
  1747. $citeStyleDisabled = " disabled"; // disable the style popup (and other form elements) if the session variable holding the user's styles isn't available
  1748. else
  1749. $citeStyleDisabled = "";
  1750. if (!isset($_SESSION['user_cite_formats']))
  1751. $citeFormatDisabled = " disabled"; // disable the cite format popup if the session variable holding the user's cite formats isn't available
  1752. else
  1753. $citeFormatDisabled = "";
  1754. $ResultsFooterRow .= "\n\t<fieldset id=\"citerefs\">"
  1755. . "\n\t\t<legend>Save Citations:</legend>"
  1756. . "\n\t\t<input type=\"hidden\" name=\"citeStyle\" value=\"" . rawurlencode($citeStyle) . "\">"
  1757. . "\n\t\t<input type=\"hidden\" name=\"citeOrder\" value=\"$citeOrder\">"
  1758. . "\n\t\t<input type=\"hidden\" name=\"headerMsg\" value=\"" . rawurlencode($headerMsg) . "\">"
  1759. . "\n\t\t<label for=\"citeType\">Format:</label>"
  1760. . "\n\t\t<select id=\"citeType\" name=\"citeType\" title=\"choose how your reference list shall be returned\"$citeStyleDisabled$citeFormatDisabled>";
  1761. if (isset($_SESSION['user_cite_formats']))
  1762. {
  1763. $optionTags = buildSelectMenuOptions($_SESSION['user_cite_formats'], "/ *; */", "\t\t\t", false); // build properly formatted <option> tag elements from the items listed in the 'user_cite_formats' session variable
  1764. $ResultsFooterRow .= $optionTags;
  1765. }
  1766. else
  1767. $ResultsFooterRow .= "\n\t\t\t<option>(no formats available)</option>";
  1768. $ResultsFooterRow .= "\n\t\t</select>"
  1769. . "\n\t\t<input type=\"submit\" name=\"submit\" value=\"Cite\"" . addAccessKey("attribute", "biblio") . " title=\"build a list of references for all chosen records" . addAccessKey("title", "biblio") . "\"$citeStyleDisabled>"
  1770. . "\n\t</fieldset>";
  1771. // Assign the 'selected' param to one of the main non-HTML citation output options (RTF, PDF, LaTeX):
  1772. if (preg_match("#<option>RTF</option>#i", $ResultsFooterRow))
  1773. $ResultsFooterRow = preg_replace("#<option>RTF</option>#i", "<option selected>RTF</option>", $ResultsFooterRow);
  1774. elseif (preg_match("#<option>PDF</option>#i", $ResultsFooterRow))
  1775. $ResultsFooterRow = preg_replace("#<option>PDF</option>#i", "<option selected>PDF</option>", $ResultsFooterRow);
  1776. elseif (preg_match("#<option>LaTeX</option>#i", $ResultsFooterRow))
  1777. $ResultsFooterRow = preg_replace("#<option>LaTeX</option>#i", "<option selected>LaTeX</option>", $ResultsFooterRow);
  1778. }
  1779. // User groups functionality:
  1780. if (isset($_SESSION['loginEmail']) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_user_groups/", $_SESSION['user_permissions'])) // if a user is logged in AND the 'user_permissions' session variable contains 'allow_user_groups', show form elements to add/remove the chosen records to/from a user's group:
  1781. {
  1782. if (!isset($_SESSION['userGroups']))
  1783. {
  1784. $groupSearchDisabled = " disabled"; // disable the (part of the) 'Add to/Remove from group' form elements if the session variable holding the user's groups isnt't available
  1785. $groupSearchPopupMenuChecked = "";
  1786. $groupSearchTextInputChecked = " checked";
  1787. $groupSearchSelectorTitle = "(to setup a new group with all chosen records, enter a group name &amp; click the 'Add' button)";
  1788. $groupSearchTextInputTitle = "specify a new group name here, then click the 'Add' button";
  1789. }
  1790. else
  1791. {
  1792. $groupSearchDisabled = "";
  1793. $groupSearchPopupMenuChecked = " checked";
  1794. $groupSearchTextInputChecked = "";
  1795. $groupSearchSelectorTitle = "choose the group to (from) which the chosen records shall be added (removed)";
  1796. $groupSearchTextInputTitle = "specify a new group name here, then click the 'Add' button";
  1797. }
  1798. $ResultsFooterRow .= "\n\t<fieldset id=\"grouprefs\">"
  1799. . "\n\t\t<legend>Add to (Remove from) Group:</legend>"
  1800. . "\n\t\t<div id=\"myGroup\">"
  1801. . "\n\t\t\t<input type=\"radio\" id=\"myGroupRadio\" name=\"userGroupActionRadio\" value=\"1\" title=\"add (remove) the chosen records to (from) an existing group\"$groupSearchDisabled$groupSearchPopupMenuChecked>"
  1802. . "\n\t\t\t<label for=\"userGroupSelector\">My:</label>"
  1803. . "\n\t\t\t<select id=\"userGroupSelector\" name=\"userGroupSelector\" onfocus=\"toggleRadio('myGroupRadio', 'newGroupRadio', false)\" title=\"$groupSearchSelectorTitle\"$groupSearchDisabled>";
  1804. if (isset($_SESSION['userGroups']))
  1805. {
  1806. $optionTags = buildSelectMenuOptions($_SESSION['userGroups'], "/ *; */", "\t\t\t\t", false); // build properly formatted <option> tag elements from the items listed in the 'userGroups' session variable
  1807. $ResultsFooterRow .= $optionTags;
  1808. }
  1809. else
  1810. {
  1811. $ResultsFooterRow .= "\n\t\t\t\t<option>(no groups available)</option>";
  1812. }
  1813. $ResultsFooterRow .= "\n\t\t\t</select>"
  1814. . "\n\t\t</div>"
  1815. . "\n\t\t<div id=\"newGroup\">"
  1816. . "\n\t\t\t<input type=\"radio\" id=\"newGroupRadio\" name=\"userGroupActionRadio\" value=\"0\" title=\"setup a new group with the chosen records\"$groupSearchTextInputChecked>"
  1817. . "\n\t\t\t<label for=\"userGroupName\">New:</label>"
  1818. . "\n\t\t\t<input type=\"text\" id=\"userGroupName\" name=\"userGroupName\" value=\"\" size=\"12\" onfocus=\"toggleRadio('myGroupRadio', 'newGroupRadio', true)\" title=\"$groupSearchTextInputTitle\">"
  1819. . "\n\t\t</div>"
  1820. . "\n\t\t<div id=\"addRemoveGroup\">"
  1821. . "\n\t\t\t<input type=\"submit\" name=\"submit\" value=\"Add\" title=\"add the chosen records to the specified group\">"
  1822. . "\n\t\t\t<input type=\"submit\" name=\"submit\" value=\"Remove\" title=\"remove the chosen records from the specified group\"$groupSearchDisabled>"
  1823. . "\n\t\t</div>"
  1824. . "\n\t</fieldset>";
  1825. }
  1826. // Export functionality:
  1827. if ((!isset($_SESSION['loginEmail']) AND ($allowAnonymousGUIExport == "yes")) OR (isset($_SESSION['loginEmail']) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_export|allow_batch_export/", $_SESSION['user_permissions']))) // if a user is logged in AND the 'user_permissions' session variable contains either 'allow_export' or 'allow_batch_export', show form elements to export the chosen records:
  1828. {
  1829. if (!isset($_SESSION['user_export_formats']))
  1830. $exportFormatDisabled = " disabled"; // disable the format popup if the session variable holding the user's export formats isn't available
  1831. else
  1832. $exportFormatDisabled = "";
  1833. $ResultsFooterRow .= "\n\t<fieldset id=\"exportrefs\">"
  1834. . "\n\t\t<legend>Export Records:</legend>"
  1835. . "\n\t\t<input type=\"hidden\" name=\"exportType\" value=\"file\">"
  1836. . "\n\t\t<label for=\"exportFormat\">Format:</label>"
  1837. . "\n\t\t<select id=\"exportFormat\" name=\"exportFormat\" title=\"choose the export format for your references\"$exportFormatDisabled>";
  1838. if (isset($_SESSION['user_export_formats']))
  1839. {
  1840. $optionTags = buildSelectMenuOptions($_SESSION['user_export_formats'], "/ *; */", "\t\t\t", false); // build properly formatted <option> tag elements from the items listed in the 'user_export_formats' session variable
  1841. $ResultsFooterRow .= $optionTags;
  1842. }
  1843. else
  1844. $ResultsFooterRow .= "\n\t\t\t<option>(no formats available)</option>";
  1845. $ResultsFooterRow .= "\n\t\t</select>"
  1846. . "\n\t\t<input type=\"submit\" name=\"submit\" value=\"Export\"" . addAccessKey("attribute", "export") . " title=\"export all chosen records" . addAccessKey("title", "export") . "\"$exportFormatDisabled>"
  1847. . "\n\t</fieldset>";
  1848. }
  1849. $ResultsFooterRow .= "\n</div>"
  1850. . "\n</div>";
  1851. }
  1852. else
  1853. $ResultsFooterRow = ""; // return an empty string if the 'user_permissions' session variable does NOT contain any of the following: 'allow_cite', 'allow_user_groups', 'allow_export', 'allow_batch_export'
  1854. return $ResultsFooterRow;
  1855. }
  1856. // --------------------------------------------------------------------
  1857. // EXTRACT FORM VARIABLES SENT THROUGH GET OR POST
  1858. // (!! NOTE !!: for details see <http://www.php.net/release_4_2_1.php> & <http://www.php.net/manual/en/language.variables.predefined.php>)
  1859. // Find duplicate records within results of the given SQL query (using settings extracted from the 'duplicateSearch' form
  1860. // in 'duplicate_search.php') and return a modified database query that only matches these duplicate entries:
  1861. function findDuplicates($sqlQuery, $originalDisplayType)
  1862. {
  1863. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  1864. 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'
  1865. // re-assign the correct display type (i.e. the view that was active when the user clicked the 'dups' link in the header):
  1866. if (!empty($originalDisplayType))
  1867. $displayType = $originalDisplayType;
  1868. // Extract form variables provided by the 'duplicateSearch' form in 'duplicate_search.php':
  1869. if (isset($_REQUEST['matchFieldsSelector']))
  1870. {
  1871. if (is_string($_REQUEST['matchFieldsSelector'])) // we accept a string containing a (e.g. comma delimited) list of field names
  1872. $selectedFieldsArray = preg_split("/[^a-z_]+/", $_REQUEST['matchFieldsSelector'], -1, PREG_SPLIT_NO_EMPTY); // (the 'PREG_SPLIT_NO_EMPTY' flag causes only non-empty pieces to be returned)
  1873. else // the field list is already provided as array:
  1874. $selectedFieldsArray = $_REQUEST['matchFieldsSelector'];
  1875. }
  1876. else
  1877. $selectedFieldsArray = array();
  1878. if (isset($_REQUEST['ignoreWhitespace']) AND ($_REQUEST['ignoreWhitespace'] == "1"))
  1879. $ignoreWhitespace = "1";
  1880. else
  1881. $ignoreWhitespace = "0";
  1882. if (isset($_REQUEST['ignorePunctuation']) AND ($_REQUEST['ignorePunctuation'] == "1"))
  1883. $ignorePunctuation = "1";
  1884. else
  1885. $ignorePunctuation = "0";
  1886. if (isset($_REQUEST['ignoreCharacterCase']) AND ($_REQUEST['ignoreCharacterCase'] == "1"))
  1887. $ignoreCharacterCase = "1";
  1888. else
  1889. $ignoreCharacterCase = "0";
  1890. if (isset($_REQUEST['ignoreAuthorInitials']) AND ($_REQUEST['ignoreAuthorInitials'] == "1"))
  1891. $ignoreAuthorInitials = "1";
  1892. else
  1893. $ignoreAuthorInitials = "0";
  1894. if (isset($_REQUEST['nonASCIIChars']))
  1895. $nonASCIIChars = $_REQUEST['nonASCIIChars'];
  1896. else
  1897. $nonASCIIChars = "keep";
  1898. // VALIDATE FORM DATA:
  1899. $errors = array();
  1900. // Validate the field selector:
  1901. if (empty($selectedFieldsArray))
  1902. $errors["matchFieldsSelector"] = "You must select at least one field:";
  1903. // Validate the 'SQL Query' field:
  1904. if (empty($sqlQuery))
  1905. $errors["sqlQuery"] = "You must specify a query string:"; // 'sqlQuery' must not be empty
  1906. elseif (!preg_match("/^SELECT/i", $sqlQuery))
  1907. $errors["sqlQuery"] = "You can only execute SELECT queries:";
  1908. // Check if there were any errors:
  1909. if (count($errors) > 0)
  1910. {
  1911. // In case of an error, we write all form variables back to the '$formVars' array
  1912. // (which 'duplicate_search.php' requires to reload form values):
  1913. foreach($_REQUEST as $varname => $value)
  1914. $formVars[$varname] = $value;
  1915. // Since checkbox form fields do only get included in the '$_REQUEST' array if they were marked,
  1916. // we have to add appropriate array elements for all checkboxes that weren't set:
  1917. if (!isset($formVars["ignoreWhitespace"]))
  1918. $formVars["ignoreWhitespace"] = "0";
  1919. if (!isset($formVars["ignorePunctuation"]))
  1920. $formVars["ignorePunctuation"] = "0";
  1921. if (!isset($formVars["ignoreCharacterCase"]))
  1922. $formVars["ignoreCharacterCase"] = "0";
  1923. if (!isset($formVars["ignoreAuthorInitials"]))
  1924. $formVars["ignoreAuthorInitials"] = "0";
  1925. if (!isset($formVars["showLinks"]))
  1926. $formVars["showLinks"] = "0";
  1927. // Write back session variables:
  1928. saveSessionVariable("errors", $errors); // function 'saveSessionVariable()' is defined in 'include.inc.php'
  1929. saveSessionVariable("formVars", $formVars);
  1930. // There are errors. Relocate back to 'duplicate_search.php':
  1931. header("Location: duplicate_search.php");
  1932. exit; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !EXIT! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1933. }
  1934. // CONSTRUCT SQL QUERY (1. DUPLICATE SEARCH):
  1935. // To identify any duplicates within the results of the original query, we build a new query based on the original SQL query:
  1936. $query = $sqlQuery;
  1937. // Replace SELECT list of columns with those from '$selectedFieldsArray' (plus the 'serial' column):
  1938. $selectedFieldsString = implode(", ", $selectedFieldsArray);
  1939. $query = newSELECTclause("SELECT " . $selectedFieldsString . ", serial", $query, false); // function 'newSELECTclause()' is defined in 'include.inc.php'
  1940. // Replace any existing ORDER BY clause with the list of columns given in '$selectedFieldsArray':
  1941. $query = newORDERclause("ORDER BY " . $selectedFieldsString, $query, false); // function 'newORDERclause()' is defined in 'include.inc.php'
  1942. // Fix escape sequences within the SQL query:
  1943. $query = stripSlashesIfMagicQuotes($query);
  1944. // RUN the query on the database through the connection:
  1945. $result = queryMySQLDatabase($query); // function 'queryMySQLDatabase()' is defined in 'include.inc.php'
  1946. // PROCESS RESULTS:
  1947. $recordSerialsArray = array();
  1948. $duplicateRecordSerialsArray = array();
  1949. $rowsFound = @ mysqli_num_rows($result);
  1950. // Identify any records with matching field data:
  1951. if ($rowsFound > 0) // if there were rows found ...
  1952. {
  1953. // Count the number of fields:
  1954. $fieldsFound = mysqli_num_fields($result);
  1955. // Loop over each row in the result set:
  1956. for ($rowCounter=0; $row = @ mysqli_fetch_array($result); $rowCounter++)
  1957. {
  1958. $recordIdentifier = ""; // make sure our buffer variable is empty
  1959. // For each row, loop over each field (except for the last one which is the 'serial' field):
  1960. for ($i=0; $i < ($fieldsFound - 1); $i++)
  1961. {
  1962. // fetch the current attribute name:
  1963. $fieldName = getMySQLFieldInfo($result, $i, "name"); // function 'getMySQLFieldInfo()' is defined in 'include.inc.php'
  1964. // normalize author names:
  1965. if (($fieldName == "author") AND ($ignoreAuthorInitials == "1"))
  1966. {
  1967. // this is a stupid hack that maps the names of the '$row' array keys to those used
  1968. // by the '$formVars' array (which is required by function 'parsePlaceholderString()')
  1969. // (eventually, the '$formVars' array should use the MySQL field names as names for its array keys)
  1970. $formVars = buildFormVarsArray($row); // function 'buildFormVarsArray()' is defined in 'include.inc.php'
  1971. // ignore initials in author names:
  1972. $row[$i] = parsePlaceholderString($formVars, "<:authors[0||]:>", ""); // function 'parsePlaceholderString()' is defined in 'include.inc.php'
  1973. }
  1974. $recordIdentifier .= $row[$i]; // merge all field values to form a unique record identifier string
  1975. }
  1976. // Normalize record identifier string:
  1977. if ($ignoreWhitespace == "1") // ignore whitespace
  1978. $recordIdentifier = preg_replace("/\s+/", "", $recordIdentifier);
  1979. if ($ignorePunctuation == "1") // ignore punctuation
  1980. $recordIdentifier = preg_replace("/[$punct]+/$patternModifiers", "", $recordIdentifier);
  1981. if ($ignoreCharacterCase == "1") // ignore character case
  1982. $recordIdentifier = strtolower($recordIdentifier);
  1983. if ($nonASCIIChars == "strip") // strip non-ASCII characters
  1984. $recordIdentifier = handleNonASCIIAndUnwantedCharacters($recordIdentifier, "\S\s", "strip"); // function 'parsePlaceholderString()' is defined in 'include.inc.php'
  1985. elseif ($nonASCIIChars == "transliterate") // transliterate non-ASCII characters
  1986. $recordIdentifier = handleNonASCIIAndUnwantedCharacters($recordIdentifier, "\S\s", "transliterate");
  1987. // Check whether the record identifier string has occurred already:
  1988. if (isset($recordSerialsArray[$recordIdentifier])) // this record identifier string has already been seen
  1989. $recordSerialsArray[$recordIdentifier][] = $row["serial"]; // add this record's serial number to the array of record serials which share the same record identifier string
  1990. else // new record identifier string
  1991. $recordSerialsArray[$recordIdentifier] = array($row["serial"]); // add a new array element for this record's identifier string (and store its serial number as value within a sub-array)
  1992. }
  1993. // Collect all array elements from '$recordSerialsArray' where their sub-array contains more than one serial number:
  1994. foreach($recordSerialsArray as $recordSerials)
  1995. {
  1996. if (count($recordSerials) > 1)
  1997. foreach($recordSerials as $recordSerial)
  1998. $duplicateRecordSerialsArray[] = $recordSerial; // add this record's serial number to the array of duplicate record serials
  1999. }
  2000. }
  2001. else // nothing found!
  2002. {
  2003. // TODO!
  2004. }
  2005. if (empty($duplicateRecordSerialsArray))
  2006. $duplicateRecordSerialsArray[] = "0"; // if no duplicate records were found, the non-existing serial number '0' will result in a "nothing found" feedback
  2007. // CONSTRUCT SQL QUERY (2. DUPLICATES DISPLAY):
  2008. // To display any duplicates that were found within the results of the original query, we build again a new query based on the original SQL query:
  2009. $query = $sqlQuery;
  2010. // Replace WHERE clause:
  2011. // TODO: maybe make this into a generic function? (compare with function 'extractWHEREclause()' in 'include.inc.php')
  2012. $duplicateRecordSerialsString = implode("|", $duplicateRecordSerialsArray);
  2013. $query = preg_replace("/(?<=WHERE )(.+?)(?= ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|[ ;]+(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|FILE)\b|$)/i", "serial RLIKE \"^(" . $duplicateRecordSerialsString . ")$\"", $query);
  2014. // Replace any existing ORDER BY clause with the list of columns given in '$selectedFieldsArray':
  2015. $query = newORDERclause("ORDER BY " . $selectedFieldsString, $query, false);
  2016. return array($query, $displayType);
  2017. }
  2018. // --------------------------------------------------------------------
  2019. // Build the database query from user input provided by the 'simple_search.php' form:
  2020. // TODO: build the complete SQL query using functions 'buildFROMclause()', 'buildWHEREclause()' and 'buildORDERclause()'
  2021. function extractFormElementsSimple($showLinks, $userID)
  2022. {
  2023. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  2024. // Build SELECT clause:
  2025. if ($_SESSION['userDefaultView'] == "List") // honour the user's selection of fields to be displayed in List View
  2026. {
  2027. // Defines a list of all checkbox names that are available in "Simple Search"
  2028. // and their corresponding column names from MySQL table 'refs':
  2029. $columnsArray = array("showAuthor" => "author",
  2030. "showTitle" => "title",
  2031. "showYear" => "year",
  2032. "showPublication" => "publication",
  2033. "showVolume" => "volume",
  2034. "showPages" => "pages"
  2035. );
  2036. // Add columns given in '$columnsArray' to the list of fields available in the
  2037. // List View SELECT clause if they were marked in the search form interface:
  2038. $selectClauseColumnsArray = addToSelectClause($columnsArray);
  2039. $query = buildSELECTclause($_SESSION['userDefaultView'], $showLinks, "", false, true, implode(", ", $selectClauseColumnsArray));
  2040. }
  2041. else
  2042. $query = buildSELECTclause($_SESSION['userDefaultView'], $showLinks);
  2043. // Build FROM clause:
  2044. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  2045. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . $userID;
  2046. else // NO user logged in
  2047. $query .= " FROM $tableRefs";
  2048. // Build WHERE clause:
  2049. $query .= " WHERE serial RLIKE \".+\""; // add initial WHERE clause
  2050. // ... if the user has specified an author, add the value of '$authorName' as an AND clause:
  2051. $authorName = $_REQUEST['authorName'];
  2052. if ($authorName != "")
  2053. {
  2054. $authorSelector = $_REQUEST['authorSelector'];
  2055. if ($authorSelector == "contains")
  2056. $query .= " AND author RLIKE " . quote_smart($authorName);
  2057. elseif ($authorSelector == "does not contain")
  2058. $query .= " AND author NOT RLIKE " . quote_smart($authorName);
  2059. elseif ($authorSelector == "is equal to")
  2060. $query .= " AND author = " . quote_smart($authorName);
  2061. elseif ($authorSelector == "is not equal to")
  2062. $query .= " AND author != " . quote_smart($authorName);
  2063. elseif ($authorSelector == "starts with")
  2064. $query .= " AND author RLIKE " . quote_smart("^" . $authorName);
  2065. elseif ($authorSelector == "ends with")
  2066. $query .= " AND author RLIKE " . quote_smart($authorName . "$");
  2067. }
  2068. // ... if the user has specified a title, add the value of '$titleName' as an AND clause:
  2069. $titleName = $_REQUEST['titleName'];
  2070. if ($titleName != "")
  2071. {
  2072. $titleSelector = $_REQUEST['titleSelector'];
  2073. if ($titleSelector == "contains")
  2074. $query .= " AND title RLIKE " . quote_smart($titleName);
  2075. elseif ($titleSelector == "does not contain")
  2076. $query .= " AND title NOT RLIKE " . quote_smart($titleName);
  2077. elseif ($titleSelector == "is equal to")
  2078. $query .= " AND title = " . quote_smart($titleName);
  2079. elseif ($titleSelector == "is not equal to")
  2080. $query .= " AND title != " . quote_smart($titleName);
  2081. elseif ($titleSelector == "starts with")
  2082. $query .= " AND title RLIKE " . quote_smart("^" . $titleName);
  2083. elseif ($titleSelector == "ends with")
  2084. $query .= " AND title RLIKE " . quote_smart($titleName . "$");
  2085. }
  2086. // ... if the user has specified a year, add the value of '$yearNo' as an AND clause:
  2087. $yearNo = $_REQUEST['yearNo'];
  2088. if ($yearNo != "")
  2089. {
  2090. $yearSelector = $_REQUEST['yearSelector'];
  2091. if ($yearSelector == "contains")
  2092. $query .= " AND year RLIKE " . quote_smart($yearNo);
  2093. elseif ($yearSelector == "does not contain")
  2094. $query .= " AND year NOT RLIKE " . quote_smart($yearNo);
  2095. elseif ($yearSelector == "is equal to")
  2096. $query .= " AND year = " . quote_smart($yearNo);
  2097. elseif ($yearSelector == "is not equal to")
  2098. $query .= " AND year != " . quote_smart($yearNo);
  2099. elseif ($yearSelector == "starts with")
  2100. $query .= " AND year RLIKE " . quote_smart("^" . $yearNo);
  2101. elseif ($yearSelector == "ends with")
  2102. $query .= " AND year RLIKE " . quote_smart($yearNo . "$");
  2103. elseif ($yearSelector == "is greater than")
  2104. $query .= " AND year > " . quote_smart($yearNo);
  2105. elseif ($yearSelector == "is less than")
  2106. $query .= " AND year < " . quote_smart($yearNo);
  2107. elseif ($yearSelector == "is within range")
  2108. {
  2109. if (preg_match("/\d+/", $yearNo)) // if '$yearNo' does contain at least one number
  2110. {
  2111. // extract first number:
  2112. $yearNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $yearNo);
  2113. $query .= " AND year >= " . quote_smart($yearNoStart);
  2114. if (preg_match("/^\D*\d+\D+\d+/", $yearNo)) // if '$yearNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  2115. {
  2116. // extract the second number:
  2117. $yearNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $yearNo);
  2118. $query .= " AND year <= " . quote_smart($yearNoEnd);
  2119. }
  2120. }
  2121. else // fallback if no number is given:
  2122. $query .= " AND year RLIKE " . quote_smart($yearNo);
  2123. }
  2124. elseif ($yearSelector == "is within list")
  2125. {
  2126. // replace any non-digit chars with "|":
  2127. $yearNo = preg_replace("/\D+/", "|", $yearNo);
  2128. // strip "|" from beginning/end of string (if any):
  2129. $yearNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $yearNo);
  2130. $query .= " AND year RLIKE " . quote_smart("^(" . $yearNo . ")$");
  2131. }
  2132. }
  2133. // ... if the user has specified a publication, add the value of '$publicationName' as an AND clause:
  2134. $publicationRadio = $_REQUEST['publicationRadio'];
  2135. if ($publicationRadio == "1")
  2136. {
  2137. $publicationName = $_REQUEST['publicationName'];
  2138. if ($publicationName != "All" && $publicationName != "")
  2139. {
  2140. $publicationSelector = $_REQUEST['publicationSelector'];
  2141. if ($publicationSelector == "contains")
  2142. $query .= " AND publication RLIKE " . quote_smart($publicationName);
  2143. elseif ($publicationSelector == "does not contain")
  2144. $query .= " AND publication NOT RLIKE " . quote_smart($publicationName);
  2145. elseif ($publicationSelector == "is equal to")
  2146. $query .= " AND publication = " . quote_smart($publicationName);
  2147. elseif ($publicationSelector == "is not equal to")
  2148. $query .= " AND publication != " . quote_smart($publicationName);
  2149. elseif ($publicationSelector == "starts with")
  2150. $query .= " AND publication RLIKE " . quote_smart("^" . $publicationName);
  2151. elseif ($publicationSelector == "ends with")
  2152. $query .= " AND publication RLIKE " . quote_smart($publicationName . "$");
  2153. }
  2154. }
  2155. elseif ($publicationRadio == "0")
  2156. {
  2157. $publicationName2 = $_REQUEST['publicationName2'];
  2158. if ($publicationName2 != "")
  2159. {
  2160. $publicationSelector2 = $_REQUEST['publicationSelector2'];
  2161. if ($publicationSelector2 == "contains")
  2162. $query .= " AND publication RLIKE " . quote_smart($publicationName2);
  2163. elseif ($publicationSelector2 == "does not contain")
  2164. $query .= " AND publication NOT RLIKE " . quote_smart($publicationName2);
  2165. elseif ($publicationSelector2 == "is equal to")
  2166. $query .= " AND publication = " . quote_smart($publicationName2);
  2167. elseif ($publicationSelector2 == "is not equal to")
  2168. $query .= " AND publication != " . quote_smart($publicationName2);
  2169. elseif ($publicationSelector2 == "starts with")
  2170. $query .= " AND publication RLIKE " . quote_smart("^" . $publicationName2);
  2171. elseif ($publicationSelector2 == "ends with")
  2172. $query .= " AND publication RLIKE " . quote_smart($publicationName2 . "$");
  2173. }
  2174. }
  2175. // ... if the user has specified a volume, add the value of '$volumeNo' as an AND clause:
  2176. $volumeNo = $_REQUEST['volumeNo'];
  2177. if ($volumeNo != "")
  2178. {
  2179. $volumeSelector = $_REQUEST['volumeSelector'];
  2180. if ($volumeSelector == "contains")
  2181. $query .= " AND volume RLIKE " . quote_smart($volumeNo);
  2182. elseif ($volumeSelector == "does not contain")
  2183. $query .= " AND volume NOT RLIKE " . quote_smart($volumeNo);
  2184. elseif ($volumeSelector == "is equal to")
  2185. $query .= " AND volume = " . quote_smart($volumeNo);
  2186. elseif ($volumeSelector == "is not equal to")
  2187. $query .= " AND volume != " . quote_smart($volumeNo);
  2188. elseif ($volumeSelector == "starts with")
  2189. $query .= " AND volume RLIKE " . quote_smart("^" . $volumeNo);
  2190. elseif ($volumeSelector == "ends with")
  2191. $query .= " AND volume RLIKE " . quote_smart($volumeNo . "$");
  2192. elseif ($volumeSelector == "is greater than")
  2193. $query .= " AND volume_numeric > " . quote_smart($volumeNo);
  2194. elseif ($volumeSelector == "is less than")
  2195. $query .= " AND volume_numeric < " . quote_smart($volumeNo);
  2196. elseif ($volumeSelector == "is within range")
  2197. {
  2198. if (preg_match("/\d+/", $volumeNo)) // if '$volumeNo' does contain at least one number
  2199. {
  2200. // extract first number:
  2201. $volumeNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $volumeNo);
  2202. $query .= " AND volume_numeric >= " . quote_smart($volumeNoStart);
  2203. if (preg_match("/^\D*\d+\D+\d+/", $volumeNo)) // if '$volumeNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  2204. {
  2205. // extract the second number:
  2206. $volumeNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $volumeNo);
  2207. $query .= " AND volume_numeric <= " . quote_smart($volumeNoEnd);
  2208. }
  2209. }
  2210. else // fallback if no number is given:
  2211. $query .= " AND volume RLIKE " . quote_smart($volumeNo);
  2212. }
  2213. elseif ($volumeSelector == "is within list")
  2214. {
  2215. // replace any non-digit chars with "|":
  2216. $volumeNo = preg_replace("/\D+/", "|", $volumeNo);
  2217. // strip "|" from beginning/end of string (if any):
  2218. $volumeNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $volumeNo);
  2219. $query .= " AND volume RLIKE " . quote_smart("^(" . $volumeNo . ")$");
  2220. }
  2221. }
  2222. // ... if the user has specified some pages, add the value of '$pagesNo' as an AND clause:
  2223. $pagesNo = $_REQUEST['pagesNo'];
  2224. if ($pagesNo != "")
  2225. {
  2226. $pagesSelector = $_REQUEST['pagesSelector'];
  2227. if ($pagesSelector == "contains")
  2228. $query .= " AND pages RLIKE " . quote_smart($pagesNo);
  2229. elseif ($pagesSelector == "does not contain")
  2230. $query .= " AND pages NOT RLIKE " . quote_smart($pagesNo);
  2231. elseif ($pagesSelector == "is equal to")
  2232. $query .= " AND pages = " . quote_smart($pagesNo);
  2233. elseif ($pagesSelector == "is not equal to")
  2234. $query .= " AND pages != " . quote_smart($pagesNo);
  2235. elseif ($pagesSelector == "starts with")
  2236. $query .= " AND pages RLIKE " . quote_smart("^" . $pagesNo);
  2237. elseif ($pagesSelector == "ends with")
  2238. $query .= " AND pages RLIKE " . quote_smart($pagesNo . "$");
  2239. }
  2240. // Construct the ORDER BY clause:
  2241. // TODO?: quote_smart (haven't yey tested)
  2242. // A) extract first level sort option:
  2243. $sortSelector1 = $_REQUEST['sortSelector1'];
  2244. // when field name = 'pages' then sort by 'first_page' instead:
  2245. $sortSelector1 = str_replace("pages", "first_page", $sortSelector1);
  2246. $sortRadio1 = $_REQUEST['sortRadio1'];
  2247. if ($sortRadio1 == "0") // sort ascending
  2248. $query .= " ORDER BY $sortSelector1";
  2249. else // sort descending
  2250. $query .= " ORDER BY $sortSelector1 DESC";
  2251. // B) extract second level sort option:
  2252. $sortSelector2 = $_REQUEST['sortSelector2'];
  2253. // when field name = 'pages' then sort by 'first_page' instead:
  2254. $sortSelector2 = str_replace("pages", "first_page", $sortSelector2);
  2255. $sortRadio2 = $_REQUEST['sortRadio2'];
  2256. if ($sortRadio2 == "0") // sort ascending
  2257. $query .= ", $sortSelector2";
  2258. else // sort descending
  2259. $query .= ", $sortSelector2 DESC";
  2260. // C) extract third level sort option:
  2261. $sortSelector3 = $_REQUEST['sortSelector3'];
  2262. // when field name = 'pages' then sort by 'first_page' instead:
  2263. $sortSelector3 = str_replace("pages", "first_page", $sortSelector3);
  2264. $sortRadio3 = $_REQUEST['sortRadio3'];
  2265. if ($sortRadio3 == "0") // sort ascending
  2266. $query .= ", $sortSelector3";
  2267. else // sort descending
  2268. $query .= ", $sortSelector3 DESC";
  2269. return $query;
  2270. }
  2271. // --------------------------------------------------------------------
  2272. // Build the database query from user input provided by the 'library_search.php' form:
  2273. // TODO: build the complete SQL query using functions 'buildFROMclause()', 'buildWHEREclause()' and 'buildORDERclause()'
  2274. function extractFormElementsLibrary($showLinks, $userID)
  2275. {
  2276. global $librarySearchPattern; // defined in 'ini.inc.php'
  2277. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  2278. // Build SELECT clause:
  2279. if ($_SESSION['userDefaultView'] == "List") // honour the user's selection of fields to be displayed in List View
  2280. {
  2281. // Defines a list of all checkbox names that are available in "Library Search"
  2282. // and their corresponding column names from MySQL table 'refs':
  2283. $columnsArray = array("showAuthor" => "author",
  2284. "showTitle" => "title",
  2285. "showYear" => "year",
  2286. "showEditor" => "editor",
  2287. "showSeriesTitle" => "series_title",
  2288. "showVolume" => "series_volume",
  2289. "showPages" => "pages",
  2290. "showPublisher" => "publisher",
  2291. "showPlace" => "place",
  2292. "showCallNumber" => "call_number",
  2293. "showKeywords" => "keywords",
  2294. "showNotes" => "notes"
  2295. );
  2296. // Add columns given in '$columnsArray' to the list of fields available in the
  2297. // List View SELECT clause if they were marked in the search form interface:
  2298. $selectClauseColumnsArray = addToSelectClause($columnsArray);
  2299. $query = buildSELECTclause($_SESSION['userDefaultView'], $showLinks, "", false, true, implode(", ", $selectClauseColumnsArray));
  2300. }
  2301. else
  2302. $query = buildSELECTclause($_SESSION['userDefaultView'], $showLinks);
  2303. // Build FROM clause:
  2304. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  2305. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . $userID;
  2306. else // NO user logged in
  2307. $query .= " FROM $tableRefs";
  2308. // Build WHERE clause:
  2309. // Note: we'll restrict the query to records where the pattern given in array element '$librarySearchPattern[1]' (defined in 'ini.inc.php')
  2310. // matches the contents of the field given in array element '$librarySearchPattern[0]'
  2311. $query .= " WHERE serial RLIKE \".+\" AND " . $librarySearchPattern[0] . " RLIKE " . quote_smart($librarySearchPattern[1]); // add initial WHERE clause
  2312. // ... if the user has specified an author, add the value of '$authorName' as an AND clause:
  2313. $authorName = $_REQUEST['authorName'];
  2314. if ($authorName != "")
  2315. {
  2316. $authorSelector = $_REQUEST['authorSelector'];
  2317. if ($authorSelector == "contains")
  2318. $query .= " AND author RLIKE " . quote_smart($authorName);
  2319. elseif ($authorSelector == "does not contain")
  2320. $query .= " AND author NOT RLIKE " . quote_smart($authorName);
  2321. elseif ($authorSelector == "is equal to")
  2322. $query .= " AND author = " . quote_smart($authorName);
  2323. elseif ($authorSelector == "is not equal to")
  2324. $query .= " AND author != " . quote_smart($authorName);
  2325. elseif ($authorSelector == "starts with")
  2326. $query .= " AND author RLIKE " . quote_smart("^" . $authorName);
  2327. elseif ($authorSelector == "ends with")
  2328. $query .= " AND author RLIKE " . quote_smart($authorName . "$");
  2329. }
  2330. // ... if the user has specified a title, add the value of '$titleName' as an AND clause:
  2331. $titleName = $_REQUEST['titleName'];
  2332. if ($titleName != "")
  2333. {
  2334. $titleSelector = $_REQUEST['titleSelector'];
  2335. if ($titleSelector == "contains")
  2336. $query .= " AND title RLIKE " . quote_smart($titleName);
  2337. elseif ($titleSelector == "does not contain")
  2338. $query .= " AND title NOT RLIKE " . quote_smart($titleName);
  2339. elseif ($titleSelector == "is equal to")
  2340. $query .= " AND title = " . quote_smart($titleName);
  2341. elseif ($titleSelector == "is not equal to")
  2342. $query .= " AND title != " . quote_smart($titleName);
  2343. elseif ($titleSelector == "starts with")
  2344. $query .= " AND title RLIKE " . quote_smart("^" . $titleName);
  2345. elseif ($titleSelector == "ends with")
  2346. $query .= " AND title RLIKE " . quote_smart($titleName . "$");
  2347. }
  2348. // ... if the user has specified a year, add the value of '$yearNo' as an AND clause:
  2349. $yearNo = $_REQUEST['yearNo'];
  2350. if ($yearNo != "")
  2351. {
  2352. $yearSelector = $_REQUEST['yearSelector'];
  2353. if ($yearSelector == "contains")
  2354. $query .= " AND year RLIKE " . quote_smart($yearNo);
  2355. elseif ($yearSelector == "does not contain")
  2356. $query .= " AND year NOT RLIKE " . quote_smart($yearNo);
  2357. elseif ($yearSelector == "is equal to")
  2358. $query .= " AND year = " . quote_smart($yearNo);
  2359. elseif ($yearSelector == "is not equal to")
  2360. $query .= " AND year != " . quote_smart($yearNo);
  2361. elseif ($yearSelector == "starts with")
  2362. $query .= " AND year RLIKE " .quote_smart("^" . $yearNo);
  2363. elseif ($yearSelector == "ends with")
  2364. $query .= " AND year RLIKE " . quote_smart($yearNo . "$");
  2365. elseif ($yearSelector == "is greater than")
  2366. $query .= " AND year > " . quote_smart($yearNo);
  2367. elseif ($yearSelector == "is less than")
  2368. $query .= " AND year < " . quote_smart($yearNo);
  2369. elseif ($yearSelector == "is within range")
  2370. {
  2371. if (preg_match("/\d+/", $yearNo)) // if '$yearNo' does contain at least one number
  2372. {
  2373. // extract first number:
  2374. $yearNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $yearNo);
  2375. $query .= " AND year >= " . quote_smart($yearNoStart);
  2376. if (preg_match("/^\D*\d+\D+\d+/", $yearNo)) // if '$yearNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  2377. {
  2378. // extract the second number:
  2379. $yearNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $yearNo);
  2380. $query .= " AND year <= " . quote_smart($yearNoEnd);
  2381. }
  2382. }
  2383. else // fallback if no number is given:
  2384. $query .= " AND year RLIKE " . quote_smart($yearNo);
  2385. }
  2386. elseif ($yearSelector == "is within list")
  2387. {
  2388. // replace any non-digit chars with "|":
  2389. $yearNo = preg_replace("/\D+/", "|", $yearNo);
  2390. // strip "|" from beginning/end of string (if any):
  2391. $yearNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $yearNo);
  2392. $query .= " AND year RLIKE " . quote_smart("^(" . $yearNo . ")$");
  2393. }
  2394. }
  2395. // ... if the user has specified an editor, add the value of '$editorName' as an AND clause:
  2396. $editorName = $_REQUEST['editorName'];
  2397. if ($editorName != "")
  2398. {
  2399. $editorSelector = $_REQUEST['editorSelector'];
  2400. if ($editorSelector == "contains")
  2401. $query .= " AND editor RLIKE " . quote_smart($editorName);
  2402. elseif ($editorSelector == "does not contain")
  2403. $query .= " AND editor NOT RLIKE " . quote_smart($editorName);
  2404. elseif ($editorSelector == "is equal to")
  2405. $query .= " AND editor = " . quote_smart($editorName);
  2406. elseif ($editorSelector == "is not equal to")
  2407. $query .= " AND editor != " . quote_smart($editorName);
  2408. elseif ($editorSelector == "starts with")
  2409. $query .= " AND editor RLIKE " . quote_smart("^" . $editorName);
  2410. elseif ($editorSelector == "ends with")
  2411. $query .= " AND editor RLIKE " . quote_smart($editorName . "$");
  2412. }
  2413. // ... if the user has specified a series title, add the value of '$seriesTitleName' as an AND clause:
  2414. $seriesTitleRadio = $_REQUEST['seriesTitleRadio'];
  2415. if ($seriesTitleRadio == "1")
  2416. {
  2417. $seriesTitleName = $_REQUEST['seriesTitleName'];
  2418. if ($seriesTitleName != "All" && $seriesTitleName != "")
  2419. {
  2420. $seriesTitleSelector = $_REQUEST['seriesTitleSelector'];
  2421. if ($seriesTitleSelector == "contains")
  2422. $query .= " AND series_title RLIKE " . quote_smart($seriesTitleName);
  2423. elseif ($seriesTitleSelector == "does not contain")
  2424. $query .= " AND series_title NOT RLIKE " . quote_smart($seriesTitleName);
  2425. elseif ($seriesTitleSelector == "is equal to")
  2426. $query .= " AND series_title = " . quote_smart($seriesTitleName);
  2427. elseif ($seriesTitleSelector == "is not equal to")
  2428. $query .= " AND series_title != " . quote_smart($seriesTitleName);
  2429. elseif ($seriesTitleSelector == "starts with")
  2430. $query .= " AND series_title RLIKE " . quote_smart("^" . $seriesTitleName);
  2431. elseif ($seriesTitleSelector == "ends with")
  2432. $query .= " AND series_title RLIKE " . quote_smart($seriesTitleName . "$");
  2433. }
  2434. }
  2435. elseif ($seriesTitleRadio == "0")
  2436. {
  2437. $seriesTitleName2 = $_REQUEST['seriesTitleName2'];
  2438. if ($seriesTitleName2 != "")
  2439. {
  2440. $seriesTitleSelector2 = $_REQUEST['seriesTitleSelector2'];
  2441. if ($seriesTitleSelector2 == "contains")
  2442. $query .= " AND series_title RLIKE " . quote_smart($seriesTitleName2);
  2443. elseif ($seriesTitleSelector2 == "does not contain")
  2444. $query .= " AND series_title NOT RLIKE " . quote_smart($seriesTitleName2);
  2445. elseif ($seriesTitleSelector2 == "is equal to")
  2446. $query .= " AND series_title = " . quote_smart($seriesTitleName2);
  2447. elseif ($seriesTitleSelector2 == "is not equal to")
  2448. $query .= " AND series_title != " . quote_smart($seriesTitleName2);
  2449. elseif ($seriesTitleSelector2 == "starts with")
  2450. $query .= " AND series_title RLIKE " . quote_smart("^" .$seriesTitleName2);
  2451. elseif ($seriesTitleSelector2 == "ends with")
  2452. $query .= " AND series_title RLIKE " . quote_smart($seriesTitleName2 . "$");
  2453. }
  2454. }
  2455. // ... if the user has specified a series volume, add the value of '$volumeNo' as an AND clause:
  2456. $volumeNo = $_REQUEST['volumeNo'];
  2457. if ($volumeNo != "")
  2458. {
  2459. $volumeSelector = $_REQUEST['volumeSelector'];
  2460. if ($volumeSelector == "contains")
  2461. $query .= " AND series_volume RLIKE " . quote_smart($volumeNo);
  2462. elseif ($volumeSelector == "does not contain")
  2463. $query .= " AND series_volume NOT RLIKE " . quote_smart($volumeNo);
  2464. elseif ($volumeSelector == "is equal to")
  2465. $query .= " AND series_volume = " . quote_smart($volumeNo);
  2466. elseif ($volumeSelector == "is not equal to")
  2467. $query .= " AND series_volume != " . quote_smart($volumeNo);
  2468. elseif ($volumeSelector == "starts with")
  2469. $query .= " AND series_volume RLIKE " . quote_smart("^" . $volumeNo);
  2470. elseif ($volumeSelector == "ends with")
  2471. $query .= " AND series_volume RLIKE " . quote_smart($volumeNo . "$");
  2472. elseif ($volumeSelector == "is greater than")
  2473. $query .= " AND series_volume_numeric > " . quote_smart($volumeNo);
  2474. elseif ($volumeSelector == "is less than")
  2475. $query .= " AND series_volume_numeric < " . quote_smart($volumeNo);
  2476. elseif ($volumeSelector == "is within range")
  2477. {
  2478. if (preg_match("/\d+/", $volumeNo)) // if '$volumeNo' does contain at least one number
  2479. {
  2480. // extract first number:
  2481. $volumeNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $volumeNo);
  2482. $query .= " AND series_volume_numeric >= " . quote_smart($volumeNoStart);
  2483. if (preg_match("/^\D*\d+\D+\d+/", $volumeNo)) // if '$volumeNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  2484. {
  2485. // extract the second number:
  2486. $volumeNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $volumeNo);
  2487. $query .= " AND series_volume_numeric <= " . quote_smart($volumeNoEnd);
  2488. }
  2489. }
  2490. else // fallback if no number is given:
  2491. $query .= " AND series_volume RLIKE " . quote_smart($volumeNo);
  2492. }
  2493. elseif ($volumeSelector == "is within list")
  2494. {
  2495. // replace any non-digit chars with "|":
  2496. $volumeNo = preg_replace("/\D+/", "|", $volumeNo);
  2497. // strip "|" from beginning/end of string (if any):
  2498. $volumeNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $volumeNo);
  2499. $query .= " AND series_volume RLIKE " . quote_smart("^(" . $volumeNo . ")$");
  2500. }
  2501. }
  2502. // ... if the user has specified some pages, add the value of '$pagesNo' as an AND clause:
  2503. $pagesNo = $_REQUEST['pagesNo'];
  2504. if ($pagesNo != "")
  2505. {
  2506. $pagesSelector = $_REQUEST['pagesSelector'];
  2507. if ($pagesSelector == "contains")
  2508. $query .= " AND pages RLIKE " . quote_smart($pagesNo);
  2509. elseif ($pagesSelector == "does not contain")
  2510. $query .= " AND pages NOT RLIKE " . quote_smart($pagesNo);
  2511. elseif ($pagesSelector == "is equal to")
  2512. $query .= " AND pages = " . quote_smart($pagesNo);
  2513. elseif ($pagesSelector == "is not equal to")
  2514. $query .= " AND pages != " . quote_smart($pagesNo);
  2515. elseif ($pagesSelector == "starts with")
  2516. $query .= " AND pages RLIKE " . quote_smart("^" . $pagesNo);
  2517. elseif ($pagesSelector == "ends with")
  2518. $query .= " AND pages RLIKE " . quote_smart($pagesNo . "$");
  2519. }
  2520. // ... if the user has specified a publisher, add the value of '$publisherName' as an AND clause:
  2521. $publisherName = $_REQUEST['publisherName'];
  2522. if ($publisherName != "")
  2523. {
  2524. $publisherSelector = $_REQUEST['publisherSelector'];
  2525. if ($publisherSelector == "contains")
  2526. $query .= " AND publisher RLIKE " . quote_smart($publisherName);
  2527. elseif ($publisherSelector == "does not contain")
  2528. $query .= " AND publisher NOT RLIKE " . quote_smart($publisherName);
  2529. elseif ($publisherSelector == "is equal to")
  2530. $query .= " AND publisher = " . quote_smart($publisherName);
  2531. elseif ($publisherSelector == "is not equal to")
  2532. $query .= " AND publisher != " . quote_smart($publisherName);
  2533. elseif ($publisherSelector == "starts with")
  2534. $query .= " AND publisher RLIKE " . quote_smart("^" . $publisherName);
  2535. elseif ($publisherSelector == "ends with")
  2536. $query .= " AND publisher RLIKE " . quote_smart($publisherName . "$");
  2537. }
  2538. // ... if the user has specified a place, add the value of '$placeName' as an AND clause:
  2539. $placeName = $_REQUEST['placeName'];
  2540. if ($placeName != "")
  2541. {
  2542. $placeSelector = $_REQUEST['placeSelector'];
  2543. if ($placeSelector == "contains")
  2544. $query .= " AND place RLIKE " . quote_smart($placeName);
  2545. elseif ($placeSelector == "does not contain")
  2546. $query .= " AND place NOT RLIKE " . quote_smart($placeName);
  2547. elseif ($placeSelector == "is equal to")
  2548. $query .= " AND place = " . quote_smart($placeName);
  2549. elseif ($placeSelector == "is not equal to")
  2550. $query .= " AND place != " . quote_smart($placeName);
  2551. elseif ($placeSelector == "starts with")
  2552. $query .= " AND place RLIKE " . quote_smart("^" . $placeName);
  2553. elseif ($placeSelector == "ends with")
  2554. $query .= " AND place RLIKE " . quote_smart($placeName . "$");
  2555. }
  2556. // ... if the user has specified a call number, add the value of '$callNumberName' as an AND clause:
  2557. $callNumberName = $_REQUEST['callNumberName'];
  2558. if ($callNumberName != "")
  2559. {
  2560. $callNumberSelector = $_REQUEST['callNumberSelector'];
  2561. if ($callNumberSelector == "contains")
  2562. $query .= " AND call_number RLIKE " . quote_smart($callNumberName);
  2563. elseif ($callNumberSelector == "does not contain")
  2564. $query .= " AND call_number NOT RLIKE " . quote_smart($callNumberName);
  2565. elseif ($callNumberSelector == "is equal to")
  2566. $query .= " AND call_number = " . quote_smart($callNumberName);
  2567. elseif ($callNumberSelector == "is not equal to")
  2568. $query .= " AND call_number != " . quote_smart($callNumberName);
  2569. elseif ($callNumberSelector == "starts with")
  2570. $query .= " AND call_number RLIKE " . quote_smart("^" . $callNumberName);
  2571. elseif ($callNumberSelector == "ends with")
  2572. $query .= " AND call_number RLIKE " . quote_smart($callNumberName . "$");
  2573. }
  2574. // ... if the user has specified some keywords, add the value of '$keywordsName' as an AND clause:
  2575. $keywordsName = $_REQUEST['keywordsName'];
  2576. if ($keywordsName != "")
  2577. {
  2578. $keywordsSelector = $_REQUEST['keywordsSelector'];
  2579. if ($keywordsSelector == "contains")
  2580. $query .= " AND keywords RLIKE " . quote_smart($keywordsName);
  2581. elseif ($keywordsSelector == "does not contain")
  2582. $query .= " AND keywords NOT RLIKE " . quote_smart($keywordsName);
  2583. elseif ($keywordsSelector == "is equal to")
  2584. $query .= " AND keywords = " . quote_smart($keywordsName);
  2585. elseif ($keywordsSelector == "is not equal to")
  2586. $query .= " AND keywords != " . quote_smart($keywordsName);
  2587. elseif ($keywordsSelector == "starts with")
  2588. $query .= " AND keywords RLIKE " . quote_smart("^" . $keywordsName);
  2589. elseif ($keywordsSelector == "ends with")
  2590. $query .= " AND keywords RLIKE " . quote_smart($keywordsName . "$");
  2591. }
  2592. // ... if the user has specified some notes, add the value of '$notesName' as an AND clause:
  2593. $notesName = $_REQUEST['notesName'];
  2594. if ($notesName != "")
  2595. {
  2596. $notesSelector = $_REQUEST['notesSelector'];
  2597. if ($notesSelector == "contains")
  2598. $query .= " AND notes RLIKE " . quote_smart($notesName);
  2599. elseif ($notesSelector == "does not contain")
  2600. $query .= " AND notes NOT RLIKE " . quote_smart($notesName);
  2601. elseif ($notesSelector == "is equal to")
  2602. $query .= " AND notes = " . quote_smart($notesName);
  2603. elseif ($notesSelector == "is not equal to")
  2604. $query .= " AND notes != " . quote_smart($notesName);
  2605. elseif ($notesSelector == "starts with")
  2606. $query .= " AND notes RLIKE " . quote_smart("^" . $notesName);
  2607. elseif ($notesSelector == "ends with")
  2608. $query .= " AND notes RLIKE " . quote_smart($notesName . "$");
  2609. }
  2610. // Construct the ORDER BY clause:
  2611. // A) extract first level sort option:
  2612. $sortSelector1 = $_REQUEST['sortSelector1'];
  2613. // when field name = 'pages' then sort by 'first_page' instead:
  2614. $sortSelector1 = str_replace("pages", "first_page", $sortSelector1);
  2615. $sortRadio1 = $_REQUEST['sortRadio1'];
  2616. if ($sortRadio1 == "0") // sort ascending
  2617. $query .= " ORDER BY $sortSelector1";
  2618. else // sort descending
  2619. $query .= " ORDER BY $sortSelector1 DESC";
  2620. // B) extract second level sort option:
  2621. $sortSelector2 = $_REQUEST['sortSelector2'];
  2622. // when field name = 'pages' then sort by 'first_page' instead:
  2623. $sortSelector2 = str_replace("pages", "first_page", $sortSelector2);
  2624. $sortRadio2 = $_REQUEST['sortRadio2'];
  2625. if ($sortRadio2 == "0") // sort ascending
  2626. $query .= ", $sortSelector2";
  2627. else // sort descending
  2628. $query .= ", $sortSelector2 DESC";
  2629. // C) extract third level sort option:
  2630. $sortSelector3 = $_REQUEST['sortSelector3'];
  2631. // when field name = 'pages' then sort by 'first_page' instead:
  2632. $sortSelector3 = str_replace("pages", "first_page", $sortSelector3);
  2633. $sortRadio3 = $_REQUEST['sortRadio3'];
  2634. if ($sortRadio3 == "0") // sort ascending
  2635. $query .= ", $sortSelector3";
  2636. else // sort descending
  2637. $query .= ", $sortSelector3 DESC";
  2638. return $query;
  2639. }
  2640. // --------------------------------------------------------------------
  2641. // Build the database query from user input provided by the 'advanced_search.php' form:
  2642. // TODO: build the complete SQL query using functions 'buildFROMclause()', 'buildWHEREclause()' and 'buildORDERclause()'
  2643. function extractFormElementsAdvanced($showLinks, $loginEmail, $userID)
  2644. {
  2645. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  2646. // Build SELECT clause:
  2647. if ($_SESSION['userDefaultView'] == "List") // honour the user's selection of fields to be displayed in List View
  2648. {
  2649. // Defines a list of all checkbox names that are available in "Advanced Search"
  2650. // and their corresponding column names from MySQL tables 'refs' & 'user_data':
  2651. $columnsArray = array("showAuthor" => "author",
  2652. "showAddress" => "address",
  2653. "showCorporateAuthor" => "corporate_author",
  2654. "showThesis" => "thesis",
  2655. "showTitle" => "title",
  2656. "showOrigTitle" => "orig_title",
  2657. "showYear" => "year",
  2658. "showPublication" => "publication",
  2659. "showAbbrevJournal" => "abbrev_journal",
  2660. "showEditor" => "editor",
  2661. "showVolume" => "volume",
  2662. "showIssue" => "issue",
  2663. "showPages" => "pages",
  2664. "showSeriesTitle" => "series_title",
  2665. "showAbbrevSeriesTitle" => "abbrev_series_title",
  2666. "showSeriesEditor" => "series_editor",
  2667. "showSeriesVolume" => "series_volume",
  2668. "showSeriesIssue" => "series_issue",
  2669. "showPublisher" => "publisher",
  2670. "showPlace" => "place",
  2671. "showEdition" => "edition",
  2672. "showMedium" => "medium",
  2673. "showISSN" => "issn",
  2674. "showISBN" => "isbn",
  2675. "showLanguage" => "language",
  2676. "showSummaryLanguage" => "summary_language",
  2677. "showKeywords" => "keywords",
  2678. "showAbstract" => "abstract",
  2679. "showArea" => "area",
  2680. "showExpedition" => "expedition",
  2681. "showConference" => "conference",
  2682. "showDOI" => "doi",
  2683. "showURL" => "url",
  2684. "showLocation" => "location",
  2685. "showCallNumber" => "call_number",
  2686. "showFile" => "file",
  2687. "showCopy" => "copy",
  2688. "showNotes" => "notes",
  2689. "showUserKeys" => "user_keys",
  2690. "showUserNotes" => "user_notes",
  2691. "showUserFile" => "user_file",
  2692. "showUserGroups" => "user_groups",
  2693. "showCiteKey" => "cite_key",
  2694. "showSerial" => "serial",
  2695. "showType" => "type",
  2696. "showMarked" => "marked",
  2697. "showSelected" => "selected",
  2698. "showApproved" => "approved",
  2699. "showCreatedDate" => "created_date",
  2700. "showCreatedTime" => "created_time",
  2701. "showCreatedBy" => "created_by",
  2702. "showModifiedDate" => "modified_date",
  2703. "showModifiedTime" => "modified_time",
  2704. "showModifiedBy" => "modified_by"
  2705. );
  2706. // Add columns given in '$columnsArray' to the list of fields available in the
  2707. // List View SELECT clause if they were marked in the search form interface:
  2708. $selectClauseColumnsArray = addToSelectClause($columnsArray);
  2709. $query = buildSELECTclause($_SESSION['userDefaultView'], $showLinks, "", false, true, implode(", ", $selectClauseColumnsArray));
  2710. }
  2711. else
  2712. $query = buildSELECTclause($_SESSION['userDefaultView'], $showLinks);
  2713. // Build FROM clause:
  2714. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  2715. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . $userID;
  2716. else // NO user logged in
  2717. $query .= " FROM $tableRefs";
  2718. // Build WHERE clause:
  2719. $query .= " WHERE serial RLIKE \".+\""; // add initial WHERE clause
  2720. // ... if the user has specified an author, add the value of '$authorName' as an AND clause:
  2721. $authorName = $_REQUEST['authorName'];
  2722. if ($authorName != "")
  2723. {
  2724. $authorSelector = $_REQUEST['authorSelector'];
  2725. if ($authorSelector == "contains")
  2726. $query .= " AND author RLIKE " . quote_smart($authorName);
  2727. elseif ($authorSelector == "does not contain")
  2728. $query .= " AND author NOT RLIKE " . quote_smart($authorName);
  2729. elseif ($authorSelector == "is equal to")
  2730. $query .= " AND author = " . quote_smart($authorName);
  2731. elseif ($authorSelector == "is not equal to")
  2732. $query .= " AND author != " . quote_smart($authorName);
  2733. elseif ($authorSelector == "starts with")
  2734. $query .= " AND author RLIKE " . quote_smart("^" . $authorName);
  2735. elseif ($authorSelector == "ends with")
  2736. $query .= " AND author RLIKE " . quote_smart($authorName . "$");
  2737. }
  2738. // ... if the user has specified an address, add the value of '$addressName' as an AND clause:
  2739. $addressName = $_REQUEST['addressName'];
  2740. if ($addressName != "")
  2741. {
  2742. $addressSelector = $_REQUEST['addressSelector'];
  2743. if ($addressSelector == "contains")
  2744. $query .= " AND address RLIKE " . quote_smart($addressName);
  2745. elseif ($addressSelector == "does not contain")
  2746. $query .= " AND address NOT RLIKE " . quote_smart($addressName);
  2747. elseif ($addressSelector == "is equal to")
  2748. $query .= " AND address = " . quote_smart($addressName);
  2749. elseif ($addressSelector == "is not equal to")
  2750. $query .= " AND address != " . quote_smart($addressName);
  2751. elseif ($addressSelector == "starts with")
  2752. $query .= " AND address RLIKE " . quote_smart("^" . $addressName);
  2753. elseif ($addressSelector == "ends with")
  2754. $query .= " AND address RLIKE " . quote_smart($addressName . "$");
  2755. }
  2756. // ... if the user has specified a corporate author, add the value of '$corporateAuthorName' as an AND clause:
  2757. $corporateAuthorName = $_REQUEST['corporateAuthorName'];
  2758. if ($corporateAuthorName != "")
  2759. {
  2760. $corporateAuthorSelector = $_REQUEST['corporateAuthorSelector'];
  2761. if ($corporateAuthorSelector == "contains")
  2762. $query .= " AND corporate_author RLIKE " . quote_smart($corporateAuthorName);
  2763. elseif ($corporateAuthorSelector == "does not contain")
  2764. $query .= " AND corporate_author NOT RLIKE " . quote_smart($corporateAuthorName);
  2765. elseif ($corporateAuthorSelector == "is equal to")
  2766. $query .= " AND corporate_author = " . quote_smart($corporateAuthorName);
  2767. elseif ($corporateAuthorSelector == "is not equal to")
  2768. $query .= " AND corporate_author != " . quote_smart($corporateAuthorName);
  2769. elseif ($corporateAuthorSelector == "starts with")
  2770. $query .= " AND corporate_author RLIKE " . quote_smart("^" . $corporateAuthorName);
  2771. elseif ($corporateAuthorSelector == "ends with")
  2772. $query .= " AND corporate_author RLIKE " . quote_smart($corporateAuthorName . "$");
  2773. }
  2774. // ... if the user has specified a thesis, add the value of '$thesisName' as an AND clause:
  2775. $thesisRadio = $_REQUEST['thesisRadio'];
  2776. if ($thesisRadio == "1")
  2777. {
  2778. $thesisName = $_REQUEST['thesisName'];
  2779. if ($thesisName != "All" && $thesisName != "")
  2780. {
  2781. $thesisSelector = $_REQUEST['thesisSelector'];
  2782. if ($thesisSelector == "contains")
  2783. $query .= " AND thesis RLIKE " . quote_smart($thesisName);
  2784. elseif ($thesisSelector == "does not contain")
  2785. $query .= " AND thesis NOT RLIKE " . quote_smart($thesisName);
  2786. elseif ($thesisSelector == "is equal to")
  2787. $query .= " AND thesis = " . quote_smart($thesisName);
  2788. elseif ($thesisSelector == "is not equal to")
  2789. $query .= " AND thesis != " . quote_smart($thesisName);
  2790. elseif ($thesisSelector == "starts with")
  2791. $query .= " AND thesis RLIKE " . quote_smart("^" . $thesisName);
  2792. elseif ($thesisSelector == "ends with")
  2793. $query .= " AND thesis RLIKE " . quote_smart($thesisName . "$");
  2794. }
  2795. }
  2796. elseif ($thesisRadio == "0")
  2797. {
  2798. $thesisName2 = $_REQUEST['thesisName2'];
  2799. if ($thesisName2 != "")
  2800. {
  2801. $thesisSelector2 = $_REQUEST['thesisSelector2'];
  2802. if ($thesisSelector2 == "contains")
  2803. $query .= " AND thesis RLIKE " . quote_smart($thesisName2);
  2804. elseif ($thesisSelector2 == "does not contain")
  2805. $query .= " AND thesis NOT RLIKE " . quote_smart($thesisName2);
  2806. elseif ($thesisSelector2 == "is equal to")
  2807. $query .= " AND thesis = " . quote_smart($thesisName2);
  2808. elseif ($thesisSelector2 == "is not equal to")
  2809. $query .= " AND thesis != " . quote_smart($thesisName2);
  2810. elseif ($thesisSelector2 == "starts with")
  2811. $query .= " AND thesis RLIKE " . quote_smart("^" . $thesisName2);
  2812. elseif ($thesisSelector2 == "ends with")
  2813. $query .= " AND thesis RLIKE " . quote_smart($thesisName2 . "$");
  2814. }
  2815. }
  2816. // ... if the user has specified a title, add the value of '$titleName' as an AND clause:
  2817. $titleName = $_REQUEST['titleName'];
  2818. if ($titleName != "")
  2819. {
  2820. $titleSelector = $_REQUEST['titleSelector'];
  2821. if ($titleSelector == "contains")
  2822. $query .= " AND title RLIKE " . quote_smart($titleName);
  2823. elseif ($titleSelector == "does not contain")
  2824. $query .= " AND title NOT RLIKE " . quote_smart($titleName);
  2825. elseif ($titleSelector == "is equal to")
  2826. $query .= " AND title = " . quote_smart($titleName);
  2827. elseif ($titleSelector == "is not equal to")
  2828. $query .= " AND title != " . quote_smart($titleName);
  2829. elseif ($titleSelector == "starts with")
  2830. $query .= " AND title RLIKE " . quote_smart("^" . $titleName);
  2831. elseif ($titleSelector == "ends with")
  2832. $query .= " AND title RLIKE " . quote_smart($titleName . "$");
  2833. }
  2834. // ... if the user has specified an original title, add the value of '$origTitleName' as an AND clause:
  2835. $origTitleName = $_REQUEST['origTitleName'];
  2836. if ($origTitleName != "")
  2837. {
  2838. $origTitleSelector = $_REQUEST['origTitleSelector'];
  2839. if ($origTitleSelector == "contains")
  2840. $query .= " AND orig_title RLIKE " . quote_smart($origTitleName);
  2841. elseif ($origTitleSelector == "does not contain")
  2842. $query .= " AND orig_title NOT RLIKE " . quote_smart($origTitleName);
  2843. elseif ($origTitleSelector == "is equal to")
  2844. $query .= " AND orig_title = " . quote_smart($origTitleName);
  2845. elseif ($origTitleSelector == "is not equal to")
  2846. $query .= " AND orig_title != " . quote_smart($origTitleName);
  2847. elseif ($origTitleSelector == "starts with")
  2848. $query .= " AND orig_title RLIKE " . quote_smart("^" . $origTitleName);
  2849. elseif ($origTitleSelector == "ends with")
  2850. $query .= " AND orig_title RLIKE " . quote_smart($origTitleName . "$");
  2851. }
  2852. // ... if the user has specified a year, add the value of '$yearNo' as an AND clause:
  2853. $yearNo = $_REQUEST['yearNo'];
  2854. if ($yearNo != "")
  2855. {
  2856. $yearSelector = $_REQUEST['yearSelector'];
  2857. if ($yearSelector == "contains")
  2858. $query .= " AND year RLIKE " . quote_smart($yearNo);
  2859. elseif ($yearSelector == "does not contain")
  2860. $query .= " AND year NOT RLIKE " . quote_smart($yearNo);
  2861. elseif ($yearSelector == "is equal to")
  2862. $query .= " AND year = " . quote_smart($yearNo);
  2863. elseif ($yearSelector == "is not equal to")
  2864. $query .= " AND year != " . quote_smart($yearNo);
  2865. elseif ($yearSelector == "starts with")
  2866. $query .= " AND year RLIKE " . quote_smart("^" . $yearNo);
  2867. elseif ($yearSelector == "ends with")
  2868. $query .= " AND year RLIKE " . quote_smart($yearNo . "$");
  2869. elseif ($yearSelector == "is greater than")
  2870. $query .= " AND year > " . quote_smart($yearNo);
  2871. elseif ($yearSelector == "is less than")
  2872. $query .= " AND year < " . quote_smart($yearNo);
  2873. elseif ($yearSelector == "is within range")
  2874. {
  2875. if (preg_match("/\d+/", $yearNo)) // if '$yearNo' does contain at least one number
  2876. {
  2877. // extract first number:
  2878. $yearNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $yearNo);
  2879. $query .= " AND year >= " . quote_smart($yearNoStart);
  2880. if (preg_match("/^\D*\d+\D+\d+/", $yearNo)) // if '$yearNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  2881. {
  2882. // extract the second number:
  2883. $yearNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $yearNo);
  2884. $query .= " AND year <= " . quote_smart($yearNoEnd);
  2885. }
  2886. }
  2887. else // fallback if no number is given:
  2888. $query .= " AND year RLIKE " . quote_smart($yearNo);
  2889. }
  2890. elseif ($yearSelector == "is within list")
  2891. {
  2892. // replace any non-digit chars with "|":
  2893. $yearNo = preg_replace("/\D+/", "|", $yearNo);
  2894. // strip "|" from beginning/end of string (if any):
  2895. $yearNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $yearNo);
  2896. $query .= " AND year RLIKE " . quote_smart("^(" . $yearNo . ")$");
  2897. }
  2898. }
  2899. // ... if the user has specified a publication, add the value of '$publicationName' as an AND clause:
  2900. $publicationRadio = $_REQUEST['publicationRadio'];
  2901. if ($publicationRadio == "1")
  2902. {
  2903. $publicationName = $_REQUEST['publicationName'];
  2904. if ($publicationName != "All" && $publicationName != "")
  2905. {
  2906. $publicationSelector = $_REQUEST['publicationSelector'];
  2907. if ($publicationSelector == "contains")
  2908. $query .= " AND publication RLIKE " . quote_smart($publicationName);
  2909. elseif ($publicationSelector == "does not contain")
  2910. $query .= " AND publication NOT RLIKE " . quote_smart($publicationName);
  2911. elseif ($publicationSelector == "is equal to")
  2912. $query .= " AND publication = " . quote_smart($publicationName);
  2913. elseif ($publicationSelector == "is not equal to")
  2914. $query .= " AND publication != " . quote_smart($publicationName);
  2915. elseif ($publicationSelector == "starts with")
  2916. $query .= " AND publication RLIKE " . quote_smart("^" . $publicationName);
  2917. elseif ($publicationSelector == "ends with")
  2918. $query .= " AND publication RLIKE " . quote_smart($publicationName . "$");
  2919. }
  2920. }
  2921. elseif ($publicationRadio == "0")
  2922. {
  2923. $publicationName2 = $_REQUEST['publicationName2'];
  2924. if ($publicationName2 != "")
  2925. {
  2926. $publicationSelector2 = $_REQUEST['publicationSelector2'];
  2927. if ($publicationSelector2 == "contains")
  2928. $query .= " AND publication RLIKE " . quote_smart($publicationName2);
  2929. elseif ($publicationSelector2 == "does not contain")
  2930. $query .= " AND publication NOT RLIKE " . quote_smart($publicationName2);
  2931. elseif ($publicationSelector2 == "is equal to")
  2932. $query .= " AND publication = " . quote_smart($publicationName2);
  2933. elseif ($publicationSelector2 == "is not equal to")
  2934. $query .= " AND publication != " . quote_smart($publicationName2);
  2935. elseif ($publicationSelector2 == "starts with")
  2936. $query .= " AND publication RLIKE " . quote_smart("^" . $publicationName2);
  2937. elseif ($publicationSelector2 == "ends with")
  2938. $query .= " AND publication RLIKE " . quote_smart($publicationName2 . "$");
  2939. }
  2940. }
  2941. // ... if the user has specified an abbreviated journal, add the value of '$abbrevJournalName' as an AND clause:
  2942. $abbrevJournalRadio = $_REQUEST['abbrevJournalRadio'];
  2943. if ($abbrevJournalRadio == "1")
  2944. {
  2945. $abbrevJournalName = $_REQUEST['abbrevJournalName'];
  2946. if ($abbrevJournalName != "All" && $abbrevJournalName != "")
  2947. {
  2948. $abbrevJournalSelector = $_REQUEST['abbrevJournalSelector'];
  2949. if ($abbrevJournalSelector == "contains")
  2950. $query .= " AND abbrev_journal RLIKE " . quote_smart($abbrevJournalName);
  2951. elseif ($abbrevJournalSelector == "does not contain")
  2952. $query .= " AND abbrev_journal NOT RLIKE " . quote_smart($abbrevJournalName);
  2953. elseif ($abbrevJournalSelector == "is equal to")
  2954. $query .= " AND abbrev_journal = " . quote_smart($abbrevJournalName);
  2955. elseif ($abbrevJournalSelector == "is not equal to")
  2956. $query .= " AND abbrev_journal != " . quote_smart($abbrevJournalName);
  2957. elseif ($abbrevJournalSelector == "starts with")
  2958. $query .= " AND abbrev_journal RLIKE " . quote_smart("^" . $abbrevJournalName);
  2959. elseif ($abbrevJournalSelector == "ends with")
  2960. $query .= " AND abbrev_journal RLIKE " . quote_smart($abbrevJournalName . "$");
  2961. }
  2962. }
  2963. elseif ($abbrevJournalRadio == "0")
  2964. {
  2965. $abbrevJournalName2 = $_REQUEST['abbrevJournalName2'];
  2966. if ($abbrevJournalName2 != "")
  2967. {
  2968. $abbrevJournalSelector2 = $_REQUEST['abbrevJournalSelector2'];
  2969. if ($abbrevJournalSelector2 == "contains")
  2970. $query .= " AND abbrev_journal RLIKE " . quote_smart($abbrevJournalName2);
  2971. elseif ($abbrevJournalSelector2 == "does not contain")
  2972. $query .= " AND abbrev_journal NOT RLIKE " . quote_smart($abbrevJournalName2);
  2973. elseif ($abbrevJournalSelector2 == "is equal to")
  2974. $query .= " AND abbrev_journal = " . quote_smart($abbrevJournalName2);
  2975. elseif ($abbrevJournalSelector2 == "is not equal to")
  2976. $query .= " AND abbrev_journal != " . quote_smart($abbrevJournalName2);
  2977. elseif ($abbrevJournalSelector2 == "starts with")
  2978. $query .= " AND abbrev_journal RLIKE " . quote_smart("^" . $abbrevJournalName2);
  2979. elseif ($abbrevJournalSelector2 == "ends with")
  2980. $query .= " AND abbrev_journal RLIKE " . quote_smart($abbrevJournalName2 . "$");
  2981. }
  2982. }
  2983. // ... if the user has specified an editor, add the value of '$editorName' as an AND clause:
  2984. $editorName = $_REQUEST['editorName'];
  2985. if ($editorName != "")
  2986. {
  2987. $editorSelector = $_REQUEST['editorSelector'];
  2988. if ($editorSelector == "contains")
  2989. $query .= " AND editor RLIKE " . quote_smart($editorName);
  2990. elseif ($editorSelector == "does not contain")
  2991. $query .= " AND editor NOT RLIKE " . quote_smart($editorName);
  2992. elseif ($editorSelector == "is equal to")
  2993. $query .= " AND editor = " . quote_smart($editorName);
  2994. elseif ($editorSelector == "is not equal to")
  2995. $query .= " AND editor != " . quote_smart($editorName);
  2996. elseif ($editorSelector == "starts with")
  2997. $query .= " AND editor RLIKE " . quote_smart("^" . $editorName);
  2998. elseif ($editorSelector == "ends with")
  2999. $query .= " AND editor RLIKE " . quote_smart($editorName . "$");
  3000. }
  3001. // ... if the user has specified a volume, add the value of '$volumeNo' as an AND clause:
  3002. $volumeNo = $_REQUEST['volumeNo'];
  3003. if ($volumeNo != "")
  3004. {
  3005. $volumeSelector = $_REQUEST['volumeSelector'];
  3006. if ($volumeSelector == "contains")
  3007. $query .= " AND volume RLIKE " . quote_smart($volumeNo);
  3008. elseif ($volumeSelector == "does not contain")
  3009. $query .= " AND volume NOT RLIKE " . quote_smart($volumeNo);
  3010. elseif ($volumeSelector == "is equal to")
  3011. $query .= " AND volume = " . quote_smart($volumeNo);
  3012. elseif ($volumeSelector == "is not equal to")
  3013. $query .= " AND volume != " . quote_smart($volumeNo);
  3014. elseif ($volumeSelector == "starts with")
  3015. $query .= " AND volume RLIKE " . quote_smart("^" . $volumeNo);
  3016. elseif ($volumeSelector == "ends with")
  3017. $query .= " AND volume RLIKE " . quote_smart($volumeNo . "$");
  3018. elseif ($volumeSelector == "is greater than")
  3019. $query .= " AND volume_numeric > " . quote_smart($volumeNo);
  3020. elseif ($volumeSelector == "is less than")
  3021. $query .= " AND volume_numeric < " . quote_smart($volumeNo);
  3022. elseif ($volumeSelector == "is within range")
  3023. {
  3024. if (preg_match("/\d+/", $volumeNo)) // if '$volumeNo' does contain at least one number
  3025. {
  3026. // extract first number:
  3027. $volumeNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $volumeNo);
  3028. $query .= " AND volume_numeric >= " . quote_smart($volumeNoStart);
  3029. if (preg_match("/^\D*\d+\D+\d+/", $volumeNo)) // if '$volumeNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  3030. {
  3031. // extract the second number:
  3032. $volumeNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $volumeNo);
  3033. $query .= " AND volume_numeric <= " . quote_smart($volumeNoEnd);
  3034. }
  3035. }
  3036. else // fallback if no number is given:
  3037. $query .= " AND volume RLIKE " . quote_smart($volumeNo);
  3038. }
  3039. elseif ($volumeSelector == "is within list")
  3040. {
  3041. // replace any non-digit chars with "|":
  3042. $volumeNo = preg_replace("/\D+/", "|", $volumeNo);
  3043. // strip "|" from beginning/end of string (if any):
  3044. $volumeNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $volumeNo);
  3045. $query .= " AND volume RLIKE " . quote_smart("^(" . $volumeNo . ")$");
  3046. }
  3047. }
  3048. // ... if the user has specified an issue, add the value of '$issueNo' as an AND clause:
  3049. $issueNo = $_REQUEST['issueNo'];
  3050. if ($issueNo != "")
  3051. {
  3052. $issueSelector = $_REQUEST['issueSelector'];
  3053. if ($issueSelector == "contains")
  3054. $query .= " AND issue RLIKE " . quote_smart($issueNo);
  3055. elseif ($issueSelector == "does not contain")
  3056. $query .= " AND issue NOT RLIKE " . quote_smart($issueNo);
  3057. elseif ($issueSelector == "is equal to")
  3058. $query .= " AND issue = " . quote_smart($issueNo);
  3059. elseif ($issueSelector == "is not equal to")
  3060. $query .= " AND issue != " . quote_smart($issueNo);
  3061. elseif ($issueSelector == "starts with")
  3062. $query .= " AND issue RLIKE " . quote_smart("^" . $issueNo);
  3063. elseif ($issueSelector == "ends with")
  3064. $query .= " AND issue RLIKE " . quote_smart($issueNo . "$");
  3065. }
  3066. // ... if the user has specified some pages, add the value of '$pagesNo' as an AND clause:
  3067. $pagesNo = $_REQUEST['pagesNo'];
  3068. if ($pagesNo != "")
  3069. {
  3070. $pagesSelector = $_REQUEST['pagesSelector'];
  3071. if ($pagesSelector == "contains")
  3072. $query .= " AND pages RLIKE " . quote_smart($pagesNo);
  3073. elseif ($pagesSelector == "does not contain")
  3074. $query .= " AND pages NOT RLIKE " . quote_smart($pagesNo);
  3075. elseif ($pagesSelector == "is equal to")
  3076. $query .= " AND pages = " . quote_smart($pagesNo);
  3077. elseif ($pagesSelector == "is not equal to")
  3078. $query .= " AND pages != " . quote_smart($pagesNo);
  3079. elseif ($pagesSelector == "starts with")
  3080. $query .= " AND pages RLIKE " . quote_smart("^" . $pagesNo);
  3081. elseif ($pagesSelector == "ends with")
  3082. $query .= " AND pages RLIKE " . quote_smart($pagesNo . "$");
  3083. }
  3084. // ... if the user has specified a series title, add the value of '$seriesTitleName' as an AND clause:
  3085. $seriesTitleRadio = $_REQUEST['seriesTitleRadio'];
  3086. if ($seriesTitleRadio == "1")
  3087. {
  3088. $seriesTitleName = $_REQUEST['seriesTitleName'];
  3089. if ($seriesTitleName != "All" && $seriesTitleName != "")
  3090. {
  3091. $seriesTitleSelector = $_REQUEST['seriesTitleSelector'];
  3092. if ($seriesTitleSelector == "contains")
  3093. $query .= " AND series_title RLIKE " . quote_smart($seriesTitleName);
  3094. elseif ($seriesTitleSelector == "does not contain")
  3095. $query .= " AND series_title NOT RLIKE " . quote_smart($seriesTitleName);
  3096. elseif ($seriesTitleSelector == "is equal to")
  3097. $query .= " AND series_title = " . quote_smart($seriesTitleName);
  3098. elseif ($seriesTitleSelector == "is not equal to")
  3099. $query .= " AND series_title != " . quote_smart($seriesTitleName);
  3100. elseif ($seriesTitleSelector == "starts with")
  3101. $query .= " AND series_title RLIKE " . quote_smart("^" . $seriesTitleName);
  3102. elseif ($seriesTitleSelector == "ends with")
  3103. $query .= " AND series_title RLIKE " . quote_smart($seriesTitleName . "$");
  3104. }
  3105. }
  3106. elseif ($seriesTitleRadio == "0")
  3107. {
  3108. $seriesTitleName2 = $_REQUEST['seriesTitleName2'];
  3109. if ($seriesTitleName2 != "")
  3110. {
  3111. $seriesTitleSelector2 = $_REQUEST['seriesTitleSelector2'];
  3112. if ($seriesTitleSelector2 == "contains")
  3113. $query .= " AND series_title RLIKE " . quote_smart($seriesTitleName2);
  3114. elseif ($seriesTitleSelector2 == "does not contain")
  3115. $query .= " AND series_title NOT RLIKE " . quote_smart($seriesTitleName2);
  3116. elseif ($seriesTitleSelector2 == "is equal to")
  3117. $query .= " AND series_title = " . quote_smart($seriesTitleName2);
  3118. elseif ($seriesTitleSelector2 == "is not equal to")
  3119. $query .= " AND series_title != " . quote_smart($seriesTitleName2);
  3120. elseif ($seriesTitleSelector2 == "starts with")
  3121. $query .= " AND series_title RLIKE " . quote_smart("^" . $seriesTitleName2);
  3122. elseif ($seriesTitleSelector2 == "ends with")
  3123. $query .= " AND series_title RLIKE " . quote_smart($seriesTitleName2 . "$");
  3124. }
  3125. }
  3126. // ... if the user has specified an abbreviated series title, add the value of '$abbrevSeriesTitleName' as an AND clause:
  3127. $abbrevSeriesTitleRadio = $_REQUEST['abbrevSeriesTitleRadio'];
  3128. if ($abbrevSeriesTitleRadio == "1")
  3129. {
  3130. $abbrevSeriesTitleName = $_REQUEST['abbrevSeriesTitleName'];
  3131. if ($abbrevSeriesTitleName != "All" && $abbrevSeriesTitleName != "")
  3132. {
  3133. $abbrevSeriesTitleSelector = $_REQUEST['abbrevSeriesTitleSelector'];
  3134. if ($abbrevSeriesTitleSelector == "contains")
  3135. $query .= " AND abbrev_series_title RLIKE " . quote_smart($abbrevSeriesTitleName);
  3136. elseif ($abbrevSeriesTitleSelector == "does not contain")
  3137. $query .= " AND abbrev_series_title NOT RLIKE " . quote_smart($abbrevSeriesTitleName);
  3138. elseif ($abbrevSeriesTitleSelector == "is equal to")
  3139. $query .= " AND abbrev_series_title = " . quote_smart($abbrevSeriesTitleName);
  3140. elseif ($abbrevSeriesTitleSelector == "is not equal to")
  3141. $query .= " AND abbrev_series_title != " . quote_smart($abbrevSeriesTitleName);
  3142. elseif ($abbrevSeriesTitleSelector == "starts with")
  3143. $query .= " AND abbrev_series_title RLIKE " . quote_smart("^" . $abbrevSeriesTitleName);
  3144. elseif ($abbrevSeriesTitleSelector == "ends with")
  3145. $query .= " AND abbrev_series_title RLIKE " . quote_smart($abbrevSeriesTitleName . "$");
  3146. }
  3147. }
  3148. elseif ($abbrevSeriesTitleRadio == "0")
  3149. {
  3150. $abbrevSeriesTitleName2 = $_REQUEST['abbrevSeriesTitleName2'];
  3151. if ($abbrevSeriesTitleName2 != "")
  3152. {
  3153. $abbrevSeriesTitleSelector2 = $_REQUEST['abbrevSeriesTitleSelector2'];
  3154. if ($abbrevSeriesTitleSelector2 == "contains")
  3155. $query .= " AND abbrev_series_title RLIKE " . quote_smart($abbrevSeriesTitleName2);
  3156. elseif ($abbrevSeriesTitleSelector2 == "does not contain")
  3157. $query .= " AND abbrev_series_title NOT RLIKE " . quote_smart($abbrevSeriesTitleName2);
  3158. elseif ($abbrevSeriesTitleSelector2 == "is equal to")
  3159. $query .= " AND abbrev_series_title = " . quote_smart($abbrevSeriesTitleName2);
  3160. elseif ($abbrevSeriesTitleSelector2 == "is not equal to")
  3161. $query .= " AND abbrev_series_title != " . quote_smart($abbrevSeriesTitleName2);
  3162. elseif ($abbrevSeriesTitleSelector2 == "starts with")
  3163. $query .= " AND abbrev_series_title RLIKE " . quote_smart("^" . $abbrevSeriesTitleName2);
  3164. elseif ($abbrevSeriesTitleSelector2 == "ends with")
  3165. $query .= " AND abbrev_series_title RLIKE " . quote_smart($abbrevSeriesTitleName2 . "$");
  3166. }
  3167. }
  3168. // ... if the user has specified a series editor, add the value of '$seriesEditorName' as an AND clause:
  3169. $seriesEditorName = $_REQUEST['seriesEditorName'];
  3170. if ($seriesEditorName != "")
  3171. {
  3172. $seriesEditorSelector = $_REQUEST['seriesEditorSelector'];
  3173. if ($seriesEditorSelector == "contains")
  3174. $query .= " AND series_editor RLIKE " . quote_smart($seriesEditorName);
  3175. elseif ($seriesEditorSelector == "does not contain")
  3176. $query .= " AND series_editor NOT RLIKE " . quote_smart($seriesEditorName);
  3177. elseif ($seriesEditorSelector == "is equal to")
  3178. $query .= " AND series_editor = " . quote_smart($seriesEditorName);
  3179. elseif ($seriesEditorSelector == "is not equal to")
  3180. $query .= " AND series_editor != " . quote_smart($seriesEditorName);
  3181. elseif ($seriesEditorSelector == "starts with")
  3182. $query .= " AND series_editor RLIKE " . quote_smart("^" . $seriesEditorName);
  3183. elseif ($seriesEditorSelector == "ends with")
  3184. $query .= " AND series_editor RLIKE " . quote_smart($seriesEditorName . "$");
  3185. }
  3186. // ... if the user has specified a series volume, add the value of '$seriesVolumeNo' as an AND clause:
  3187. $seriesVolumeNo = $_REQUEST['seriesVolumeNo'];
  3188. if ($seriesVolumeNo != "")
  3189. {
  3190. $seriesVolumeSelector = $_REQUEST['seriesVolumeSelector'];
  3191. if ($seriesVolumeSelector == "contains")
  3192. $query .= " AND series_volume RLIKE " . quote_smart($seriesVolumeNo);
  3193. elseif ($seriesVolumeSelector == "does not contain")
  3194. $query .= " AND series_volume NOT RLIKE " . quote_smart($seriesVolumeNo);
  3195. elseif ($seriesVolumeSelector == "is equal to")
  3196. $query .= " AND series_volume = " . quote_smart($seriesVolumeNo);
  3197. elseif ($seriesVolumeSelector == "is not equal to")
  3198. $query .= " AND series_volume != " . quote_smart($seriesVolumeNo);
  3199. elseif ($seriesVolumeSelector == "starts with")
  3200. $query .= " AND series_volume RLIKE " . quote_smart("^" . $seriesVolumeNo);
  3201. elseif ($seriesVolumeSelector == "ends with")
  3202. $query .= " AND series_volume RLIKE " . quote_smart($seriesVolumeNo . "$");
  3203. elseif ($seriesVolumeSelector == "is greater than")
  3204. $query .= " AND series_volume_numeric > " . quote_smart($seriesVolumeNo);
  3205. elseif ($seriesVolumeSelector == "is less than")
  3206. $query .= " AND series_volume_numeric < " . quote_smart($seriesVolumeNo);
  3207. elseif ($seriesVolumeSelector == "is within range")
  3208. {
  3209. if (preg_match("/\d+/", $seriesVolumeNo)) // if '$seriesVolumeNo' does contain at least one number
  3210. {
  3211. // extract first number:
  3212. $seriesVolumeNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $seriesVolumeNo);
  3213. $query .= " AND series_volume_numeric >= " . quote_smart($seriesVolumeNoStart);
  3214. if (preg_match("/^\D*\d+\D+\d+/", $seriesVolumeNo)) // if '$seriesVolumeNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  3215. {
  3216. // extract the second number:
  3217. $seriesVolumeNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $seriesVolumeNo);
  3218. $query .= " AND series_volume_numeric <= " . quote_smart($seriesVolumeNoEnd);
  3219. }
  3220. }
  3221. else // fallback if no number is given:
  3222. $query .= " AND series_volume RLIKE " . quote_smart($seriesVolumeNo);
  3223. }
  3224. elseif ($seriesVolumeSelector == "is within list")
  3225. {
  3226. // replace any non-digit chars with "|":
  3227. $seriesVolumeNo = preg_replace("/\D+/", "|", $seriesVolumeNo);
  3228. // strip "|" from beginning/end of string (if any):
  3229. $seriesVolumeNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $seriesVolumeNo);
  3230. $query .= " AND series_volume RLIKE " . quote_smart("^(" . $seriesVolumeNo . ")$");
  3231. }
  3232. }
  3233. // ... if the user has specified a series issue, add the value of '$seriesIssueNo' as an AND clause:
  3234. $seriesIssueNo = $_REQUEST['seriesIssueNo'];
  3235. if ($seriesIssueNo != "")
  3236. {
  3237. $seriesIssueSelector = $_REQUEST['seriesIssueSelector'];
  3238. if ($seriesIssueSelector == "contains")
  3239. $query .= " AND series_issue RLIKE " . quote_smart($seriesIssueNo);
  3240. elseif ($seriesIssueSelector == "does not contain")
  3241. $query .= " AND series_issue NOT RLIKE " . quote_smart($seriesIssueNo);
  3242. elseif ($seriesIssueSelector == "is equal to")
  3243. $query .= " AND series_issue = " . quote_smart($seriesIssueNo);
  3244. elseif ($seriesIssueSelector == "is not equal to")
  3245. $query .= " AND series_issue != " . quote_smart($seriesIssueNo);
  3246. elseif ($seriesIssueSelector == "starts with")
  3247. $query .= " AND series_issue RLIKE " . quote_smart("^" . $seriesIssueNo);
  3248. elseif ($seriesIssueSelector == "ends with")
  3249. $query .= " AND series_issue RLIKE " . quote_smart($seriesIssueNo . "$");
  3250. }
  3251. // ... if the user has specified a publisher, add the value of '$publisherName' as an AND clause:
  3252. $publisherRadio = $_REQUEST['publisherRadio'];
  3253. if ($publisherRadio == "1")
  3254. {
  3255. $publisherName = $_REQUEST['publisherName'];
  3256. if ($publisherName != "All" && $publisherName != "")
  3257. {
  3258. $publisherSelector = $_REQUEST['publisherSelector'];
  3259. if ($publisherSelector == "contains")
  3260. $query .= " AND publisher RLIKE " . quote_smart($publisherName);
  3261. elseif ($publisherSelector == "does not contain")
  3262. $query .= " AND publisher NOT RLIKE " . quote_smart($publisherName);
  3263. elseif ($publisherSelector == "is equal to")
  3264. $query .= " AND publisher = " . quote_smart($publisherName);
  3265. elseif ($publisherSelector == "is not equal to")
  3266. $query .= " AND publisher != " . quote_smart($publisherName);
  3267. elseif ($publisherSelector == "starts with")
  3268. $query .= " AND publisher RLIKE " . quote_smart("^" . $publisherName);
  3269. elseif ($publisherSelector == "ends with")
  3270. $query .= " AND publisher RLIKE " . quote_smart($publisherName . "$");
  3271. }
  3272. }
  3273. elseif ($publisherRadio == "0")
  3274. {
  3275. $publisherName2 = $_REQUEST['publisherName2'];
  3276. if ($publisherName2 != "")
  3277. {
  3278. $publisherSelector2 = $_REQUEST['publisherSelector2'];
  3279. if ($publisherSelector2 == "contains")
  3280. $query .= " AND publisher RLIKE " . quote_smart($publisherName2);
  3281. elseif ($publisherSelector2 == "does not contain")
  3282. $query .= " AND publisher NOT RLIKE " . quote_smart($publisherName2);
  3283. elseif ($publisherSelector2 == "is equal to")
  3284. $query .= " AND publisher = " . quote_smart($publisherName2);
  3285. elseif ($publisherSelector2 == "is not equal to")
  3286. $query .= " AND publisher != " . quote_smart($publisherName2);
  3287. elseif ($publisherSelector2 == "starts with")
  3288. $query .= " AND publisher RLIKE " . quote_smart("^" . $publisherName2);
  3289. elseif ($publisherSelector2 == "ends with")
  3290. $query .= " AND publisher RLIKE " . quote_smart($publisherName2 . "$");
  3291. }
  3292. }
  3293. // ... if the user has specified a place, add the value of '$placeName' as an AND clause:
  3294. $placeRadio = $_REQUEST['placeRadio'];
  3295. if ($placeRadio == "1")
  3296. {
  3297. $placeName = $_REQUEST['placeName'];
  3298. if ($placeName != "All" && $placeName != "")
  3299. {
  3300. $placeSelector = $_REQUEST['placeSelector'];
  3301. if ($placeSelector == "contains")
  3302. $query .= " AND place RLIKE " . quote_smart($placeName);
  3303. elseif ($placeSelector == "does not contain")
  3304. $query .= " AND place NOT RLIKE " . quote_smart($placeName);
  3305. elseif ($placeSelector == "is equal to")
  3306. $query .= " AND place = " . quote_smart($placeName);
  3307. elseif ($placeSelector == "is not equal to")
  3308. $query .= " AND place != " . quote_smart($placeName);
  3309. elseif ($placeSelector == "starts with")
  3310. $query .= " AND place RLIKE " . quote_smart("^" . $placeName);
  3311. elseif ($placeSelector == "ends with")
  3312. $query .= " AND place RLIKE " . quote_smart($placeName . "$");
  3313. }
  3314. }
  3315. elseif ($placeRadio == "0")
  3316. {
  3317. $placeName2 = $_REQUEST['placeName2'];
  3318. if ($placeName2 != "")
  3319. {
  3320. $placeSelector2 = $_REQUEST['placeSelector2'];
  3321. if ($placeSelector2 == "contains")
  3322. $query .= " AND place RLIKE " . quote_smart($placeName2);
  3323. elseif ($placeSelector2 == "does not contain")
  3324. $query .= " AND place NOT RLIKE " . quote_smart($placeName2);
  3325. elseif ($placeSelector2 == "is equal to")
  3326. $query .= " AND place = " . quote_smart($placeName2);
  3327. elseif ($placeSelector2 == "is not equal to")
  3328. $query .= " AND place != " . quote_smart($placeName2);
  3329. elseif ($placeSelector2 == "starts with")
  3330. $query .= " AND place RLIKE " . quote_smart("^" . $placeName2);
  3331. elseif ($placeSelector2 == "ends with")
  3332. $query .= " AND place RLIKE " . quote_smart($placeName2 . "$");
  3333. }
  3334. }
  3335. // ... if the user has specified an edition, add the value of '$editionNo' as an AND clause:
  3336. $editionNo = $_REQUEST['editionNo'];
  3337. if ($editionNo != "")
  3338. {
  3339. $editionSelector = $_REQUEST['editionSelector'];
  3340. if ($editionSelector == "contains")
  3341. $query .= " AND edition RLIKE " . quote_smart($editionNo);
  3342. elseif ($editionSelector == "does not contain")
  3343. $query .= " AND edition NOT RLIKE " . quote_smart($editionNo);
  3344. elseif ($editionSelector == "is equal to")
  3345. $query .= " AND edition = " . quote_smart($editionNo);
  3346. elseif ($editionSelector == "is not equal to")
  3347. $query .= " AND edition != " . quote_smart($editionNo);
  3348. elseif ($editionSelector == "starts with")
  3349. $query .= " AND edition RLIKE " . quote_smart("^" . $editionNo);
  3350. elseif ($editionSelector == "ends with")
  3351. $query .= " AND edition RLIKE " . quote_smart($editionNo . "$");
  3352. elseif ($editionSelector == "is greater than")
  3353. $query .= " AND edition > " . quote_smart($editionNo);
  3354. elseif ($editionSelector == "is less than")
  3355. $query .= " AND edition < " . quote_smart($editionNo);
  3356. elseif ($editionSelector == "is within range")
  3357. {
  3358. if (preg_match("/\d+/", $editionNo)) // if '$editionNo' does contain at least one number
  3359. {
  3360. // extract first number:
  3361. $editionNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $editionNo);
  3362. $query .= " AND edition >= " . quote_smart($editionNoStart);
  3363. if (preg_match("/^\D*\d+\D+\d+/", $editionNo)) // if '$editionNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  3364. {
  3365. // extract the second number:
  3366. $editionNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $editionNo);
  3367. $query .= " AND edition <= " . quote_smart($editionNoEnd);
  3368. }
  3369. }
  3370. else // fallback if no number is given:
  3371. $query .= " AND edition RLIKE " . quote_smart($editionNo);
  3372. }
  3373. elseif ($editionSelector == "is within list")
  3374. {
  3375. // replace any non-digit chars with "|":
  3376. $editionNo = preg_replace("/\D+/", "|", $editionNo);
  3377. // strip "|" from beginning/end of string (if any):
  3378. $editionNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $editionNo);
  3379. $query .= " AND edition RLIKE " . quote_smart("^(" . $editionNo . ")$");
  3380. }
  3381. }
  3382. // ... if the user has specified a medium, add the value of '$mediumName' as an AND clause:
  3383. $mediumName = $_REQUEST['mediumName'];
  3384. if ($mediumName != "")
  3385. {
  3386. $mediumSelector = $_REQUEST['mediumSelector'];
  3387. if ($mediumSelector == "contains")
  3388. $query .= " AND medium RLIKE " . quote_smart($mediumName);
  3389. elseif ($mediumSelector == "does not contain")
  3390. $query .= " AND medium NOT RLIKE " . quote_smart($mediumName);
  3391. elseif ($mediumSelector == "is equal to")
  3392. $query .= " AND medium = " . quote_smart($mediumName);
  3393. elseif ($mediumSelector == "is not equal to")
  3394. $query .= " AND medium != " . quote_smart($mediumName);
  3395. elseif ($mediumSelector == "starts with")
  3396. $query .= " AND medium RLIKE " . quote_smart("^" . $mediumName);
  3397. elseif ($mediumSelector == "ends with")
  3398. $query .= " AND medium RLIKE " . quote_smart($mediumName . "$");
  3399. }
  3400. // ... if the user has specified an ISSN, add the value of '$issnName' as an AND clause:
  3401. $issnName = $_REQUEST['issnName'];
  3402. if ($issnName != "")
  3403. {
  3404. $issnSelector = $_REQUEST['issnSelector'];
  3405. if ($issnSelector == "contains")
  3406. $query .= " AND issn RLIKE " . quote_smart($issnName);
  3407. elseif ($issnSelector == "does not contain")
  3408. $query .= " AND issn NOT RLIKE " . quote_smart($issnName);
  3409. elseif ($issnSelector == "is equal to")
  3410. $query .= " AND issn = " . quote_smart($issnName);
  3411. elseif ($issnSelector == "is not equal to")
  3412. $query .= " AND issn != " . quote_smart($issnName);
  3413. elseif ($issnSelector == "starts with")
  3414. $query .= " AND issn RLIKE " . quote_smart("^" . $issnName);
  3415. elseif ($issnSelector == "ends with")
  3416. $query .= " AND issn RLIKE " . quote_smart($issnName . "$");
  3417. }
  3418. // ... if the user has specified an ISBN, add the value of '$isbnName' as an AND clause:
  3419. $isbnName = $_REQUEST['isbnName'];
  3420. if ($isbnName != "")
  3421. {
  3422. $isbnSelector = $_REQUEST['isbnSelector'];
  3423. if ($isbnSelector == "contains")
  3424. $query .= " AND isbn RLIKE " . quote_smart($isbnName);
  3425. elseif ($isbnSelector == "does not contain")
  3426. $query .= " AND isbn NOT RLIKE " . quote_smart($isbnName);
  3427. elseif ($isbnSelector == "is equal to")
  3428. $query .= " AND isbn = " . quote_smart($isbnName);
  3429. elseif ($isbnSelector == "is not equal to")
  3430. $query .= " AND isbn != " . quote_smart($isbnName);
  3431. elseif ($isbnSelector == "starts with")
  3432. $query .= " AND isbn RLIKE " . quote_smart("^" . $isbnName);
  3433. elseif ($isbnSelector == "ends with")
  3434. $query .= " AND isbn RLIKE " . quote_smart($isbnName . "$");
  3435. }
  3436. // ... if the user has specified a language, add the value of '$languageName' as an AND clause:
  3437. $languageRadio = $_REQUEST['languageRadio'];
  3438. if ($languageRadio == "1")
  3439. {
  3440. $languageName = $_REQUEST['languageName'];
  3441. if ($languageName != "All" && $languageName != "")
  3442. {
  3443. $languageSelector = $_REQUEST['languageSelector'];
  3444. if ($languageSelector == "contains")
  3445. $query .= " AND language RLIKE " . quote_smart($languageName);
  3446. elseif ($languageSelector == "does not contain")
  3447. $query .= " AND language NOT RLIKE " . quote_smart($languageName);
  3448. elseif ($languageSelector == "is equal to")
  3449. $query .= " AND language = " . quote_smart($languageName);
  3450. elseif ($languageSelector == "is not equal to")
  3451. $query .= " AND language != " . quote_smart($languageName);
  3452. elseif ($languageSelector == "starts with")
  3453. $query .= " AND language RLIKE " . quote_smart("^" . $languageName);
  3454. elseif ($languageSelector == "ends with")
  3455. $query .= " AND language RLIKE " . quote_smart($languageName . "$");
  3456. }
  3457. }
  3458. elseif ($languageRadio == "0")
  3459. {
  3460. $languageName2 = $_REQUEST['languageName2'];
  3461. if ($languageName2 != "")
  3462. {
  3463. $languageSelector2 = $_REQUEST['languageSelector2'];
  3464. if ($languageSelector2 == "contains")
  3465. $query .= " AND language RLIKE " . quote_smart($languageName2);
  3466. elseif ($languageSelector2 == "does not contain")
  3467. $query .= " AND language NOT RLIKE " . quote_smart($languageName2);
  3468. elseif ($languageSelector2 == "is equal to")
  3469. $query .= " AND language = " . quote_smart($languageName2);
  3470. elseif ($languageSelector2 == "is not equal to")
  3471. $query .= " AND language != " . quote_smart($languageName2);
  3472. elseif ($languageSelector2 == "starts with")
  3473. $query .= " AND language RLIKE " . quote_smart("^" . $languageName2);
  3474. elseif ($languageSelector2 == "ends with")
  3475. $query .= " AND language RLIKE " . quote_smart($languageName2 . "$");
  3476. }
  3477. }
  3478. // ... if the user has specified a summary language, add the value of '$summaryLanguageName' as an AND clause:
  3479. $summaryLanguageRadio = $_REQUEST['summaryLanguageRadio'];
  3480. if ($summaryLanguageRadio == "1")
  3481. {
  3482. $summaryLanguageName = $_REQUEST['summaryLanguageName'];
  3483. if ($summaryLanguageName != "All" && $summaryLanguageName != "")
  3484. {
  3485. $summaryLanguageSelector = $_REQUEST['summaryLanguageSelector'];
  3486. if ($summaryLanguageSelector == "contains")
  3487. $query .= " AND summary_language RLIKE " . quote_smart($summaryLanguageName);
  3488. elseif ($summaryLanguageSelector == "does not contain")
  3489. $query .= " AND summary_language NOT RLIKE " . quote_smart($summaryLanguageName);
  3490. elseif ($summaryLanguageSelector == "is equal to")
  3491. $query .= " AND summary_language = " . quote_smart($summaryLanguageName);
  3492. elseif ($summaryLanguageSelector == "is not equal to")
  3493. $query .= " AND summary_language != " . quote_smart($summaryLanguageName);
  3494. elseif ($summaryLanguageSelector == "starts with")
  3495. $query .= " AND summary_language RLIKE " . quote_smart("^" . $summaryLanguageName);
  3496. elseif ($summaryLanguageSelector == "ends with")
  3497. $query .= " AND summary_language RLIKE " . quote_smart($summaryLanguageName . "$");
  3498. }
  3499. }
  3500. elseif ($summaryLanguageRadio == "0")
  3501. {
  3502. $summaryLanguageName2 = $_REQUEST['summaryLanguageName2'];
  3503. if ($summaryLanguageName2 != "")
  3504. {
  3505. $summaryLanguageSelector2 = $_REQUEST['summaryLanguageSelector2'];
  3506. if ($summaryLanguageSelector2 == "contains")
  3507. $query .= " AND summary_language RLIKE " . quote_smart($summaryLanguageName2);
  3508. elseif ($summaryLanguageSelector2 == "does not contain")
  3509. $query .= " AND summary_language NOT RLIKE " . quote_smart($summaryLanguageName2);
  3510. elseif ($summaryLanguageSelector2 == "is equal to")
  3511. $query .= " AND summary_language = " . quote_smart($summaryLanguageName2);
  3512. elseif ($summaryLanguageSelector2 == "is not equal to")
  3513. $query .= " AND summary_language != " . quote_smart($summaryLanguageName2);
  3514. elseif ($summaryLanguageSelector2 == "starts with")
  3515. $query .= " AND summary_language RLIKE " . quote_smart("^" . $summaryLanguageName2);
  3516. elseif ($summaryLanguageSelector2 == "ends with")
  3517. $query .= " AND summary_language RLIKE " . quote_smart($summaryLanguageName2 . "$");
  3518. }
  3519. }
  3520. // ... if the user has specified some keywords, add the value of '$keywordsName' as an AND clause:
  3521. $keywordsName = $_REQUEST['keywordsName'];
  3522. if ($keywordsName != "")
  3523. {
  3524. $keywordsSelector = $_REQUEST['keywordsSelector'];
  3525. if ($keywordsSelector == "contains")
  3526. $query .= " AND keywords RLIKE " . quote_smart($keywordsName);
  3527. elseif ($keywordsSelector == "does not contain")
  3528. $query .= " AND keywords NOT RLIKE " . quote_smart($keywordsName);
  3529. elseif ($keywordsSelector == "is equal to")
  3530. $query .= " AND keywords = " . quote_smart($keywordsName);
  3531. elseif ($keywordsSelector == "is not equal to")
  3532. $query .= " AND keywords != " . quote_smart($keywordsName);
  3533. elseif ($keywordsSelector == "starts with")
  3534. $query .= " AND keywords RLIKE " . quote_smart("^" . $keywordsName);
  3535. elseif ($keywordsSelector == "ends with")
  3536. $query .= " AND keywords RLIKE " . quote_smart($keywordsName . "$");
  3537. }
  3538. // ... if the user has specified an abstract, add the value of '$abstractName' as an AND clause:
  3539. $abstractName = $_REQUEST['abstractName'];
  3540. if ($abstractName != "")
  3541. {
  3542. $abstractSelector = $_REQUEST['abstractSelector'];
  3543. if ($abstractSelector == "contains")
  3544. $query .= " AND abstract RLIKE " . quote_smart($abstractName);
  3545. elseif ($abstractSelector == "does not contain")
  3546. $query .= " AND abstract NOT RLIKE " . quote_smart($abstractName);
  3547. elseif ($abstractSelector == "is equal to")
  3548. $query .= " AND abstract = " . quote_smart($abstractName);
  3549. elseif ($abstractSelector == "is not equal to")
  3550. $query .= " AND abstract != " . quote_smart($abstractName);
  3551. elseif ($abstractSelector == "starts with")
  3552. $query .= " AND abstract RLIKE " . quote_smart("^" . $abstractName);
  3553. elseif ($abstractSelector == "ends with")
  3554. $query .= " AND abstract RLIKE " . quote_smart($abstractName . "$");
  3555. }
  3556. // ... if the user has specified an area, add the value of '$areaName' as an AND clause:
  3557. $areaRadio = $_REQUEST['areaRadio'];
  3558. if ($areaRadio == "1")
  3559. {
  3560. $areaName = $_REQUEST['areaName'];
  3561. if ($areaName != "All" && $areaName != "")
  3562. {
  3563. $areaSelector = $_REQUEST['areaSelector'];
  3564. if ($areaSelector == "contains")
  3565. $query .= " AND area RLIKE " . quote_smart($areaName);
  3566. elseif ($areaSelector == "does not contain")
  3567. $query .= " AND area NOT RLIKE " . quote_smart($areaName);
  3568. elseif ($areaSelector == "is equal to")
  3569. $query .= " AND area = " . quote_smart($areaName);
  3570. elseif ($areaSelector == "is not equal to")
  3571. $query .= " AND area != " . quote_smart($areaName);
  3572. elseif ($areaSelector == "starts with")
  3573. $query .= " AND area RLIKE " . quote_smart("^" . $areaName);
  3574. elseif ($areaSelector == "ends with")
  3575. $query .= " AND area RLIKE " . quote_smart($areaName . "$");
  3576. }
  3577. }
  3578. elseif ($areaRadio == "0")
  3579. {
  3580. $areaName2 = $_REQUEST['areaName2'];
  3581. if ($areaName2 != "")
  3582. {
  3583. $areaSelector2 = $_REQUEST['areaSelector2'];
  3584. if ($areaSelector2 == "contains")
  3585. $query .= " AND area RLIKE " . quote_smart($areaName2);
  3586. elseif ($areaSelector2 == "does not contain")
  3587. $query .= " AND area NOT RLIKE " . quote_smart($areaName2);
  3588. elseif ($areaSelector2 == "is equal to")
  3589. $query .= " AND area = " . quote_smart($areaName2);
  3590. elseif ($areaSelector2 == "is not equal to")
  3591. $query .= " AND area != " . quote_smart($areaName2);
  3592. elseif ($areaSelector2 == "starts with")
  3593. $query .= " AND area RLIKE " . quote_smart("^" . $areaName2);
  3594. elseif ($areaSelector2 == "ends with")
  3595. $query .= " AND area RLIKE " . quote_smart($areaName2 . "$");
  3596. }
  3597. }
  3598. // ... if the user has specified an expedition, add the value of '$expeditionName' as an AND clause:
  3599. $expeditionName = $_REQUEST['expeditionName'];
  3600. if ($expeditionName != "")
  3601. {
  3602. $expeditionSelector = $_REQUEST['expeditionSelector'];
  3603. if ($expeditionSelector == "contains")
  3604. $query .= " AND expedition RLIKE " . quote_smart($expeditionName);
  3605. elseif ($expeditionSelector == "does not contain")
  3606. $query .= " AND expedition NOT RLIKE " . quote_smart($expeditionName);
  3607. elseif ($expeditionSelector == "is equal to")
  3608. $query .= " AND expedition = " . quote_smart($expeditionName);
  3609. elseif ($expeditionSelector == "is not equal to")
  3610. $query .= " AND expedition != " . quote_smart($expeditionName);
  3611. elseif ($expeditionSelector == "starts with")
  3612. $query .= " AND expedition RLIKE " . quote_smart("^" . $expeditionName);
  3613. elseif ($expeditionSelector == "ends with")
  3614. $query .= " AND expedition RLIKE " . quote_smart($expeditionName . "$");
  3615. }
  3616. // ... if the user has specified a conference, add the value of '$conferenceName' as an AND clause:
  3617. $conferenceName = $_REQUEST['conferenceName'];
  3618. if ($conferenceName != "")
  3619. {
  3620. $conferenceSelector = $_REQUEST['conferenceSelector'];
  3621. if ($conferenceSelector == "contains")
  3622. $query .= " AND conference RLIKE " . quote_smart($conferenceName);
  3623. elseif ($conferenceSelector == "does not contain")
  3624. $query .= " AND conference NOT RLIKE " . quote_smart($conferenceName);
  3625. elseif ($conferenceSelector == "is equal to")
  3626. $query .= " AND conference = " . quote_smart($conferenceName);
  3627. elseif ($conferenceSelector == "is not equal to")
  3628. $query .= " AND conference != " . quote_smart($conferenceName);
  3629. elseif ($conferenceSelector == "starts with")
  3630. $query .= " AND conference RLIKE " . quote_smart("^" . $conferenceName);
  3631. elseif ($conferenceSelector == "ends with")
  3632. $query .= " AND conference RLIKE " . quote_smart($conferenceName . "$");
  3633. }
  3634. // ... if the user has specified a DOI, add the value of '$doiName' as an AND clause:
  3635. $doiName = $_REQUEST['doiName'];
  3636. if ($doiName != "")
  3637. {
  3638. $doiSelector = $_REQUEST['doiSelector'];
  3639. if ($doiSelector == "contains")
  3640. $query .= " AND doi RLIKE " . quote_smart($doiName);
  3641. elseif ($doiSelector == "does not contain")
  3642. $query .= " AND doi NOT RLIKE " . quote_smart($doiName);
  3643. elseif ($doiSelector == "is equal to")
  3644. $query .= " AND doi = " . quote_smart($doiName);
  3645. elseif ($doiSelector == "is not equal to")
  3646. $query .= " AND doi != " . quote_smart($doiName);
  3647. elseif ($doiSelector == "starts with")
  3648. $query .= " AND doi RLIKE " . quote_smart("^" . $doiName);
  3649. elseif ($doiSelector == "ends with")
  3650. $query .= " AND doi RLIKE " . quote_smart($doiName . "$");
  3651. }
  3652. // ... if the user has specified an URL, add the value of '$urlName' as an AND clause:
  3653. $urlName = $_REQUEST['urlName'];
  3654. if ($urlName != "")
  3655. {
  3656. $urlSelector = $_REQUEST['urlSelector'];
  3657. if ($urlSelector == "contains")
  3658. $query .= " AND url RLIKE " . quote_smart($urlName);
  3659. elseif ($urlSelector == "does not contain")
  3660. $query .= " AND url NOT RLIKE " . quote_smart($urlName);
  3661. elseif ($urlSelector == "is equal to")
  3662. $query .= " AND url = " . quote_smart($urlName);
  3663. elseif ($urlSelector == "is not equal to")
  3664. $query .= " AND url != " . quote_smart($urlName);
  3665. elseif ($urlSelector == "starts with")
  3666. $query .= " AND url RLIKE " . quote_smart("^" . $urlName);
  3667. elseif ($urlSelector == "ends with")
  3668. $query .= " AND url RLIKE " . quote_smart($urlName . "$");
  3669. }
  3670. // ... if the user has specified a location, add the value of '$locationName' as an AND clause:
  3671. if (isset($_REQUEST['locationRadio'])) // the location text entry form is not available if the user is not logged in
  3672. {
  3673. $locationRadio = $_REQUEST['locationRadio'];
  3674. if ($locationRadio == "1")
  3675. {
  3676. $locationName = $_REQUEST['locationName'];
  3677. if ($locationName != "All" && $locationName != "")
  3678. {
  3679. $locationSelector = $_REQUEST['locationSelector'];
  3680. if ($locationSelector == "contains")
  3681. $query .= " AND location RLIKE " . quote_smart($locationName);
  3682. elseif ($locationSelector == "does not contain")
  3683. $query .= " AND location NOT RLIKE " . quote_smart($locationName);
  3684. elseif ($locationSelector == "is equal to")
  3685. $query .= " AND location = " . quote_smart($locationName);
  3686. elseif ($locationSelector == "is not equal to")
  3687. $query .= " AND location != " . quote_smart($locationName);
  3688. elseif ($locationSelector == "starts with")
  3689. $query .= " AND location RLIKE " . quote_smart("^" . $locationName);
  3690. elseif ($locationSelector == "ends with")
  3691. $query .= " AND location RLIKE " . quote_smart($locationName . "$");
  3692. }
  3693. }
  3694. elseif ($locationRadio == "0")
  3695. {
  3696. $locationName2 = $_REQUEST['locationName2'];
  3697. if ($locationName2 != "")
  3698. {
  3699. $locationSelector2 = $_REQUEST['locationSelector2'];
  3700. if ($locationSelector2 == "contains")
  3701. $query .= " AND location RLIKE " . quote_smart($locationName2);
  3702. elseif ($locationSelector2 == "does not contain")
  3703. $query .= " AND location NOT RLIKE " . quote_smart($locationName2);
  3704. elseif ($locationSelector2 == "is equal to")
  3705. $query .= " AND location = " . quote_smart($locationName2);
  3706. elseif ($locationSelector2 == "is not equal to")
  3707. $query .= " AND location != " . quote_smart($locationName2);
  3708. elseif ($locationSelector2 == "starts with")
  3709. $query .= " AND location RLIKE " . quote_smart("^" . $locationName2);
  3710. elseif ($locationSelector2 == "ends with")
  3711. $query .= " AND location RLIKE " . quote_smart($locationName2 . "$");
  3712. }
  3713. }
  3714. }
  3715. // ... if the user has specified a call number, add the value of '$callNumberName' as an AND clause:
  3716. $callNumberName = $_REQUEST['callNumberName'];
  3717. if ($callNumberName != "")
  3718. {
  3719. $callNumberSelector = $_REQUEST['callNumberSelector'];
  3720. if ($callNumberSelector == "contains")
  3721. $query .= " AND call_number RLIKE " . quote_smart($callNumberName);
  3722. elseif ($callNumberSelector == "does not contain")
  3723. $query .= " AND call_number NOT RLIKE " . quote_smart($callNumberName);
  3724. elseif ($callNumberSelector == "is equal to")
  3725. $query .= " AND call_number = " . quote_smart($callNumberName);
  3726. elseif ($callNumberSelector == "is not equal to")
  3727. $query .= " AND call_number != " . quote_smart($callNumberName);
  3728. elseif ($callNumberSelector == "starts with")
  3729. $query .= " AND call_number RLIKE " . quote_smart("^" . $callNumberName);
  3730. elseif ($callNumberSelector == "ends with")
  3731. $query .= " AND call_number RLIKE " . quote_smart($callNumberName . "$");
  3732. }
  3733. // ... if the user has specified a file, add the value of '$fileName' as an AND clause:
  3734. if (isset($_REQUEST['fileName'])) // the file text entry form may be hidden if the user has no permission to see any files
  3735. {
  3736. $fileName = $_REQUEST['fileName'];
  3737. if ($fileName != "")
  3738. {
  3739. $fileSelector = $_REQUEST['fileSelector'];
  3740. if ($fileSelector == "contains")
  3741. $query .= " AND file RLIKE " . quote_smart($fileName);
  3742. elseif ($fileSelector == "does not contain")
  3743. $query .= " AND file NOT RLIKE " . quote_smart($fileName);
  3744. elseif ($fileSelector == "is equal to")
  3745. $query .= " AND file = " . quote_smart($fileName);
  3746. elseif ($fileSelector == "is not equal to")
  3747. $query .= " AND file != " . quote_smart($fileName);
  3748. elseif ($fileSelector == "starts with")
  3749. $query .= " AND file RLIKE " . quote_smart("^" . $fileName);
  3750. elseif ($fileSelector == "ends with")
  3751. $query .= " AND file RLIKE " . quote_smart($fileName . "$");
  3752. }
  3753. }
  3754. if (isset($loginEmail)) // if a user is logged in and...
  3755. {
  3756. // ... if the user has specified a copy status, add the value of '$copyName' as an AND clause:
  3757. $copyName = $_REQUEST['copyName'];
  3758. if ($copyName != "All" && $copyName != "")
  3759. {
  3760. $copySelector = $_REQUEST['copySelector'];
  3761. if ($copySelector == "is equal to")
  3762. $query .= " AND copy = " . quote_smart($copyName);
  3763. elseif ($copySelector == "is not equal to")
  3764. $query .= " AND copy != " . quote_smart($copyName);
  3765. }
  3766. }
  3767. // ... if the user has specified some notes, add the value of '$notesName' as an AND clause:
  3768. $notesName = $_REQUEST['notesName'];
  3769. if ($notesName != "")
  3770. {
  3771. $notesSelector = $_REQUEST['notesSelector'];
  3772. if ($notesSelector == "contains")
  3773. $query .= " AND notes RLIKE " . quote_smart($notesName);
  3774. elseif ($notesSelector == "does not contain")
  3775. $query .= " AND notes NOT RLIKE " . quote_smart($notesName);
  3776. elseif ($notesSelector == "is equal to")
  3777. $query .= " AND notes = " . quote_smart($notesName);
  3778. elseif ($notesSelector == "is not equal to")
  3779. $query .= " AND notes != " . quote_smart($notesName);
  3780. elseif ($notesSelector == "starts with")
  3781. $query .= " AND notes RLIKE " . quote_smart("^" . $notesName);
  3782. elseif ($notesSelector == "ends with")
  3783. $query .= " AND notes RLIKE " . quote_smart($notesName . "$");
  3784. }
  3785. if (isset($loginEmail)) // if a user is logged in and...
  3786. {
  3787. // ... if the user has specified some user keys, add the value of '$userKeysName' as an AND clause:
  3788. $userKeysRadio = $_REQUEST['userKeysRadio'];
  3789. if ($userKeysRadio == "1")
  3790. {
  3791. $userKeysName = $_REQUEST['userKeysName'];
  3792. if ($userKeysName != "All" && $userKeysName != "")
  3793. {
  3794. $userKeysSelector = $_REQUEST['userKeysSelector'];
  3795. if ($userKeysSelector == "contains")
  3796. $query .= " AND user_keys RLIKE " . quote_smart($userKeysName);
  3797. elseif ($userKeysSelector == "does not contain")
  3798. $query .= " AND user_keys NOT RLIKE " . quote_smart($userKeysName);
  3799. elseif ($userKeysSelector == "is equal to")
  3800. $query .= " AND user_keys = " . quote_smart($userKeysName);
  3801. elseif ($userKeysSelector == "is not equal to")
  3802. $query .= " AND user_keys != " . quote_smart($userKeysName);
  3803. elseif ($userKeysSelector == "starts with")
  3804. $query .= " AND user_keys RLIKE " . quote_smart("^" . $userKeysName);
  3805. elseif ($userKeysSelector == "ends with")
  3806. $query .= " AND user_keys RLIKE " . quote_smart($userKeysName . "$");
  3807. }
  3808. }
  3809. elseif ($userKeysRadio == "0")
  3810. {
  3811. $userKeysName2 = $_REQUEST['userKeysName2'];
  3812. if ($userKeysName2 != "")
  3813. {
  3814. $userKeysSelector2 = $_REQUEST['userKeysSelector2'];
  3815. if ($userKeysSelector2 == "contains")
  3816. $query .= " AND user_keys RLIKE " . quote_smart($userKeysName2);
  3817. elseif ($userKeysSelector2 == "does not contain")
  3818. $query .= " AND user_keys NOT RLIKE " . quote_smart($userKeysName2);
  3819. elseif ($userKeysSelector2 == "is equal to")
  3820. $query .= " AND user_keys = " . quote_smart($userKeysName2);
  3821. elseif ($userKeysSelector2 == "is not equal to")
  3822. $query .= " AND user_keys != " . quote_smart($userKeysName2);
  3823. elseif ($userKeysSelector2 == "starts with")
  3824. $query .= " AND user_keys RLIKE " . quote_smart("^" . $userKeysName2);
  3825. elseif ($userKeysSelector2 == "ends with")
  3826. $query .= " AND user_keys RLIKE " . quote_smart($userKeysName2 . "$");
  3827. }
  3828. }
  3829. // ... if the user has specified some user notes, add the value of '$userNotesName' as an AND clause:
  3830. $userNotesName = $_REQUEST['userNotesName'];
  3831. if ($userNotesName != "")
  3832. {
  3833. $userNotesSelector = $_REQUEST['userNotesSelector'];
  3834. if ($userNotesSelector == "contains")
  3835. $query .= " AND user_notes RLIKE " . quote_smart($userNotesName);
  3836. elseif ($userNotesSelector == "does not contain")
  3837. $query .= " AND user_notes NOT RLIKE " . quote_smart($userNotesName);
  3838. elseif ($userNotesSelector == "is equal to")
  3839. $query .= " AND user_notes = " . quote_smart($userNotesName);
  3840. elseif ($userNotesSelector == "is not equal to")
  3841. $query .= " AND user_notes != " . quote_smart($userNotesName);
  3842. elseif ($userNotesSelector == "starts with")
  3843. $query .= " AND user_notes RLIKE " . quote_smart("^" . $userNotesName);
  3844. elseif ($userNotesSelector == "ends with")
  3845. $query .= " AND user_notes RLIKE " . quote_smart($userNotesName . "$");
  3846. }
  3847. // ... if the user has specified a user file, add the value of '$userFileName' as an AND clause:
  3848. $userFileName = $_REQUEST['userFileName'];
  3849. if ($userFileName != "")
  3850. {
  3851. $userFileSelector = $_REQUEST['userFileSelector'];
  3852. if ($userFileSelector == "contains")
  3853. $query .= " AND user_file RLIKE " . quote_smart($userFileName);
  3854. elseif ($userFileSelector == "does not contain")
  3855. $query .= " AND user_file NOT RLIKE " . quote_smart($userFileName);
  3856. elseif ($userFileSelector == "is equal to")
  3857. $query .= " AND user_file = " . quote_smart($userFileName);
  3858. elseif ($userFileSelector == "is not equal to")
  3859. $query .= " AND user_file != " . quote_smart($userFileName);
  3860. elseif ($userFileSelector == "starts with")
  3861. $query .= " AND user_file RLIKE " . quote_smart("^" . $userFileName);
  3862. elseif ($userFileSelector == "ends with")
  3863. $query .= " AND user_file RLIKE " . quote_smart($userFileName . "$");
  3864. }
  3865. // ... if the user has specified some user groups, add the value of '$userGroupsName' as an AND clause:
  3866. $userGroupsRadio = $_REQUEST['userGroupsRadio'];
  3867. if ($userGroupsRadio == "1")
  3868. {
  3869. $userGroupsName = $_REQUEST['userGroupsName'];
  3870. if ($userGroupsName != "All" && $userGroupsName != "")
  3871. {
  3872. $userGroupsSelector = $_REQUEST['userGroupsSelector'];
  3873. if ($userGroupsSelector == "contains")
  3874. $query .= " AND user_groups RLIKE " . quote_smart($userGroupsName);
  3875. elseif ($userGroupsSelector == "does not contain")
  3876. $query .= " AND user_groups NOT RLIKE " . quote_smart($userGroupsName);
  3877. elseif ($userGroupsSelector == "is equal to")
  3878. $query .= " AND user_groups = " . quote_smart($userGroupsName);
  3879. elseif ($userGroupsSelector == "is not equal to")
  3880. $query .= " AND user_groups != " . quote_smart($userGroupsName);
  3881. elseif ($userGroupsSelector == "starts with")
  3882. $query .= " AND user_groups RLIKE " . quote_smart("^" . $userGroupsName);
  3883. elseif ($userGroupsSelector == "ends with")
  3884. $query .= " AND user_groups RLIKE " . quote_smart($userGroupsName . "$");
  3885. }
  3886. }
  3887. elseif ($userGroupsRadio == "0")
  3888. {
  3889. $userGroupsName2 = $_REQUEST['userGroupsName2'];
  3890. if ($userGroupsName2 != "")
  3891. {
  3892. $userGroupsSelector2 = $_REQUEST['userGroupsSelector2'];
  3893. if ($userGroupsSelector2 == "contains")
  3894. $query .= " AND user_groups RLIKE " . quote_smart($userGroupsName2);
  3895. elseif ($userGroupsSelector2 == "does not contain")
  3896. $query .= " AND user_groups NOT RLIKE " . quote_smart($userGroupsName2);
  3897. elseif ($userGroupsSelector2 == "is equal to")
  3898. $query .= " AND user_groups = " . quote_smart($userGroupsName2);
  3899. elseif ($userGroupsSelector2 == "is not equal to")
  3900. $query .= " AND user_groups != " . quote_smart($userGroupsName2);
  3901. elseif ($userGroupsSelector2 == "starts with")
  3902. $query .= " AND user_groups RLIKE " . quote_smart("^" . $userGroupsName2);
  3903. elseif ($userGroupsSelector2 == "ends with")
  3904. $query .= " AND user_groups RLIKE " . quote_smart($userGroupsName2 . "$");
  3905. }
  3906. }
  3907. // ... if the user has specified a cite key, add the value of '$citeKeyName' as an AND clause:
  3908. $citeKeyName = $_REQUEST['citeKeyName'];
  3909. if ($citeKeyName != "")
  3910. {
  3911. $citeKeySelector = $_REQUEST['citeKeySelector'];
  3912. if ($citeKeySelector == "contains")
  3913. $query .= " AND cite_key RLIKE " . quote_smart($citeKeyName);
  3914. elseif ($citeKeySelector == "does not contain")
  3915. $query .= " AND cite_key NOT RLIKE " . quote_smart($citeKeyName);
  3916. elseif ($citeKeySelector == "is equal to")
  3917. $query .= " AND cite_key = " . quote_smart($citeKeyName);
  3918. elseif ($citeKeySelector == "is not equal to")
  3919. $query .= " AND cite_key != " . quote_smart($citeKeyName);
  3920. elseif ($citeKeySelector == "starts with")
  3921. $query .= " AND cite_key RLIKE " . quote_smart("^" . $citeKeyName);
  3922. elseif ($citeKeySelector == "ends with")
  3923. $query .= " AND cite_key RLIKE " . quote_smart($citeKeyName . "$");
  3924. }
  3925. }
  3926. // ... if the user has specified a serial, add the value of '$serialNo' as an AND clause:
  3927. $serialNo = $_REQUEST['serialNo'];
  3928. if ($serialNo != "")
  3929. {
  3930. $serialSelector = $_REQUEST['serialSelector'];
  3931. if ($serialSelector == "contains")
  3932. $query .= " AND serial RLIKE " . quote_smart($serialNo);
  3933. elseif ($serialSelector == "does not contain")
  3934. $query .= " AND serial NOT RLIKE " . quote_smart($serialNo);
  3935. elseif ($serialSelector == "is equal to")
  3936. $query .= " AND serial = " . quote_smart($serialNo);
  3937. elseif ($serialSelector == "is not equal to")
  3938. $query .= " AND serial != " . quote_smart($serialNo);
  3939. elseif ($serialSelector == "starts with")
  3940. $query .= " AND serial RLIKE " . quote_smart("^" . $serialNo);
  3941. elseif ($serialSelector == "ends with")
  3942. $query .= " AND serial RLIKE " . quote_smart($serialNo . "$");
  3943. elseif ($serialSelector == "is greater than")
  3944. $query .= " AND serial > " . quote_smart($serialNo);
  3945. elseif ($serialSelector == "is less than")
  3946. $query .= " AND serial < " . quote_smart($serialNo);
  3947. elseif ($serialSelector == "is within range")
  3948. {
  3949. if (preg_match("/\d+/", $serialNo)) // if '$serialNo' does contain at least one number
  3950. {
  3951. // extract first number:
  3952. $serialNoStart = preg_replace("/^\D*(\d+).*/", "\\1", $serialNo);
  3953. $query .= " AND serial >= " . quote_smart($serialNoStart);
  3954. if (preg_match("/^\D*\d+\D+\d+/", $serialNo)) // if '$serialNo' does contain at least two numbers (which are separated by one or more non-digit characters)
  3955. {
  3956. // extract the second number:
  3957. $serialNoEnd = preg_replace("/^\D*\d+\D+(\d+).*/", "\\1", $serialNo);
  3958. $query .= " AND serial <= " . quote_smart($serialNoEnd);
  3959. }
  3960. }
  3961. else // fallback if no number is given:
  3962. $query .= " AND serial RLIKE " . quote_smart($serialNo); // this will never produce any results since serial is always numeric but we keep it here for reasons of consistency
  3963. }
  3964. elseif ($serialSelector == "is within list")
  3965. {
  3966. // replace any non-digit chars with "|":
  3967. $serialNo = preg_replace("/\D+/", "|", $serialNo);
  3968. // strip "|" from beginning/end of string (if any):
  3969. $serialNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $serialNo);
  3970. $query .= " AND serial RLIKE " . quote_smart("^(" . $serialNo . ")$");
  3971. }
  3972. }
  3973. // ... if the user has specified a type, add the value of '$typeName' as an AND clause:
  3974. $typeRadio = $_REQUEST['typeRadio'];
  3975. if ($typeRadio == "1")
  3976. {
  3977. $typeName = $_REQUEST['typeName'];
  3978. if ($typeName != "All" && $typeName != "")
  3979. {
  3980. $typeSelector = $_REQUEST['typeSelector'];
  3981. if ($typeSelector == "contains")
  3982. $query .= " AND type RLIKE " . quote_smart($typeName);
  3983. elseif ($typeSelector == "does not contain")
  3984. $query .= " AND type NOT RLIKE " . quote_smart($typeName);
  3985. elseif ($typeSelector == "is equal to")
  3986. $query .= " AND type = " . quote_smart($typeName);
  3987. elseif ($typeSelector == "is not equal to")
  3988. $query .= " AND type != " . quote_smart($typeName);
  3989. elseif ($typeSelector == "starts with")
  3990. $query .= " AND type RLIKE " . quote_smart("^" . $typeName);
  3991. elseif ($typeSelector == "ends with")
  3992. $query .= " AND type RLIKE " . quote_smart($typeName . "$");
  3993. }
  3994. }
  3995. elseif ($typeRadio == "0")
  3996. {
  3997. $typeName2 = $_REQUEST['typeName2'];
  3998. if ($typeName2 != "")
  3999. {
  4000. $typeSelector2 = $_REQUEST['typeSelector2'];
  4001. if ($typeSelector2 == "contains")
  4002. $query .= " AND type RLIKE " . quote_smart($typeName2);
  4003. elseif ($typeSelector2 == "does not contain")
  4004. $query .= " AND type NOT RLIKE " . quote_smart($typeName2);
  4005. elseif ($typeSelector2 == "is equal to")
  4006. $query .= " AND type = " . quote_smart($typeName2);
  4007. elseif ($typeSelector2 == "is not equal to")
  4008. $query .= " AND type != " . quote_smart($typeName2);
  4009. elseif ($typeSelector2 == "starts with")
  4010. $query .= " AND type RLIKE " . quote_smart("^" . $typeName2);
  4011. elseif ($typeSelector2 == "ends with")
  4012. $query .= " AND type RLIKE " . quote_smart($typeName2 . "$");
  4013. }
  4014. }
  4015. if (isset($loginEmail)) // if a user is logged in and...
  4016. {
  4017. // ... if the user has selected a radio button for 'Marked', add the corresponding value for 'marked' as an AND clause:
  4018. if (isset($_REQUEST['markedRadio']))
  4019. {
  4020. $markedRadio = $_REQUEST['markedRadio'];
  4021. if ($markedRadio == "1")
  4022. $query .= " AND marked = \"yes\"";
  4023. elseif ($markedRadio == "0")
  4024. $query .= " AND marked = \"no\"";
  4025. }
  4026. // ... if the user has selected a radio button for 'Selected', add the corresponding value for 'selected' as an AND clause:
  4027. if (isset($_REQUEST['selectedRadio']))
  4028. {
  4029. $selectedRadio = $_REQUEST['selectedRadio'];
  4030. if ($selectedRadio == "1")
  4031. $query .= " AND selected = \"yes\"";
  4032. elseif ($selectedRadio == "0")
  4033. $query .= " AND selected = \"no\"";
  4034. }
  4035. }
  4036. // ... if the user has selected a radio button for 'Approved', add the corresponding value for 'approved' as an AND clause:
  4037. if (isset($_REQUEST['approvedRadio']))
  4038. {
  4039. $approvedRadio = $_REQUEST['approvedRadio'];
  4040. if ($approvedRadio == "1")
  4041. $query .= " AND approved = \"yes\"";
  4042. elseif ($approvedRadio == "0")
  4043. $query .= " AND approved = \"no\"";
  4044. }
  4045. // ... if the user has specified a created date, add the value of '$createdDateNo' as an AND clause:
  4046. $createdDateNo = $_REQUEST['createdDateNo'];
  4047. if ($createdDateNo != "")
  4048. {
  4049. $createdDateSelector = $_REQUEST['createdDateSelector'];
  4050. if ($createdDateSelector == "contains")
  4051. $query .= " AND created_date RLIKE " . quote_smart($createdDateNo);
  4052. elseif ($createdDateSelector == "does not contain")
  4053. $query .= " AND created_date NOT RLIKE " . quote_smart($createdDateNo);
  4054. elseif ($createdDateSelector == "is equal to")
  4055. $query .= " AND created_date = " . quote_smart($createdDateNo);
  4056. elseif ($createdDateSelector == "is not equal to")
  4057. $query .= " AND created_date != " . quote_smart($createdDateNo);
  4058. elseif ($createdDateSelector == "starts with")
  4059. $query .= " AND created_date RLIKE " . quote_smart("^" . $createdDateNo);
  4060. elseif ($createdDateSelector == "ends with")
  4061. $query .= " AND created_date RLIKE " . quote_smart($createdDateNo . "$");
  4062. elseif ($createdDateSelector == "is greater than")
  4063. $query .= " AND created_date > " . quote_smart($createdDateNo);
  4064. elseif ($createdDateSelector == "is less than")
  4065. $query .= " AND created_date < " . quote_smart($createdDateNo);
  4066. elseif ($createdDateSelector == "is within range")
  4067. {
  4068. if (preg_match("/\d{4}/", $createdDateNo)) // if '$createdDateNo' does contain at least one date spec (which, as a minimum, is defined by a four-digit year)
  4069. {
  4070. // extract first date spec:
  4071. $createdDateNoStart = preg_replace("/^[^\d-]*(\d{4}(?:-\d{2})?(?:-\d{2})?).*/", "\\1", $createdDateNo); // extracts e.g. "2005-10-27", "2005-10" or just "2005" (in that order)
  4072. $query .= " AND created_date >= " . quote_smart($createdDateNoStart);
  4073. if (preg_match("/^[^\d-]*\d{4}(?:-\d{2})?(?:-\d{2})?[^\d-]+\d{4}(?:-\d{2})?(?:-\d{2})?/", $createdDateNo)) // if '$createdDateNo' does contain at least two date specs (which are separated by one or more non-digit/non-hyphen characters)
  4074. {
  4075. // extract the second date spec:
  4076. $createdDateNoEnd = preg_replace("/^[^\d-]*\d{4}(?:-\d{2})?(?:-\d{2})?[^\d-]+(\d{4}(?:-\d{2})?(?:-\d{2})?).*/", "\\1", $createdDateNo);
  4077. $query .= " AND created_date <= " . quote_smart($createdDateNoEnd);
  4078. }
  4079. }
  4080. else // fallback if no recognized date spec is given:
  4081. $query .= " AND created_date RLIKE " . quote_smart($createdDateNo);
  4082. }
  4083. elseif ($createdDateSelector == "is within list")
  4084. {
  4085. // replace any non-digit/non-hyphen chars with "|":
  4086. $createdDateNo = preg_replace("/[^\d-]+/", "|", $createdDateNo);
  4087. // strip "|" from beginning/end of string (if any):
  4088. $createdDateNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $createdDateNo);
  4089. $query .= " AND created_date RLIKE " . quote_smart("^(" . $createdDateNo . ")$");
  4090. }
  4091. }
  4092. // ... if the user has specified a created time, add the value of '$createdTimeNo' as an AND clause:
  4093. $createdTimeNo = $_REQUEST['createdTimeNo'];
  4094. if ($createdTimeNo != "")
  4095. {
  4096. $createdTimeSelector = $_REQUEST['createdTimeSelector'];
  4097. if ($createdTimeSelector == "contains")
  4098. $query .= " AND created_time RLIKE " . quote_smart($createdTimeNo);
  4099. elseif ($createdTimeSelector == "does not contain")
  4100. $query .= " AND created_time NOT RLIKE " . quote_smart($createdTimeNo);
  4101. elseif ($createdTimeSelector == "is equal to")
  4102. $query .= " AND created_time = " . quote_smart($createdTimeNo);
  4103. elseif ($createdTimeSelector == "is not equal to")
  4104. $query .= " AND created_time != " . quote_smart($createdTimeNo);
  4105. elseif ($createdTimeSelector == "starts with")
  4106. $query .= " AND created_time RLIKE " . quote_smart("^" . $createdTimeNo);
  4107. elseif ($createdTimeSelector == "ends with")
  4108. $query .= " AND created_time RLIKE " . quote_smart($createdTimeNo . "$");
  4109. elseif ($createdTimeSelector == "is greater than")
  4110. $query .= " AND created_time > " . quote_smart($createdTimeNo);
  4111. elseif ($createdTimeSelector == "is less than")
  4112. $query .= " AND created_time < " . quote_smart($createdTimeNo);
  4113. elseif ($createdTimeSelector == "is within range")
  4114. {
  4115. if (preg_match("/\d{2}:\d{2}/", $createdTimeNo)) // if '$createdTimeNo' does contain at least one time spec (which, as a minimum, is defined by a HH:MM)
  4116. {
  4117. // extract first time spec:
  4118. $createdTimeNoStart = preg_replace("/^[^\d:]*(\d{2}:\d{2}(?::\d{2})?).*/", "\\1", $createdTimeNo); // extracts e.g. "23:59:59" or just "23:59" (in that order)
  4119. $query .= " AND created_time >= " . quote_smart($createdTimeNoStart);
  4120. if (preg_match("/^[^\d:]*\d{2}:\d{2}(?::\d{2})?[^\d:]+\d{2}:\d{2}(?::\d{2})?/", $createdTimeNo)) // if '$createdTimeNo' does contain at least two date specs (which are separated by one or more non-digit/non-colon characters)
  4121. {
  4122. // extract the second time spec:
  4123. $createdTimeNoEnd = preg_replace("/^[^\d:]*\d{2}:\d{2}(?::\d{2})?[^\d:]+(\d{2}:\d{2}(?::\d{2})?).*/", "\\1", $createdTimeNo);
  4124. $query .= " AND created_time <= " . quote_smart($createdTimeNoEnd);
  4125. }
  4126. }
  4127. else // fallback if no recognized time spec is given:
  4128. $query .= " AND created_time RLIKE " . quote_smart($createdTimeNo);
  4129. }
  4130. elseif ($createdTimeSelector == "is within list")
  4131. {
  4132. // replace any non-digit/non-colon chars with "|":
  4133. $createdTimeNo = preg_replace("/[^\d:]+/", "|", $createdTimeNo);
  4134. // strip "|" from beginning/end of string (if any):
  4135. $createdTimeNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $createdTimeNo);
  4136. $query .= " AND created_time RLIKE " . quote_smart("^(" . $createdTimeNo . ")$");
  4137. }
  4138. }
  4139. // ... if the user has specified a created by, add the value of '$createdByName' as an AND clause:
  4140. if (isset($_REQUEST['createdByRadio'])) // the "created by" text entry form is not available if the user is not logged in
  4141. {
  4142. $createdByRadio = $_REQUEST['createdByRadio'];
  4143. if ($createdByRadio == "1")
  4144. {
  4145. $createdByName = $_REQUEST['createdByName'];
  4146. if ($createdByName != "All" && $createdByName != "")
  4147. {
  4148. $createdBySelector = $_REQUEST['createdBySelector'];
  4149. if ($createdBySelector == "contains")
  4150. $query .= " AND created_by RLIKE " . quote_smart($createdByName);
  4151. elseif ($createdBySelector == "does not contain")
  4152. $query .= " AND created_by NOT RLIKE " . quote_smart($createdByName);
  4153. elseif ($createdBySelector == "is equal to")
  4154. $query .= " AND created_by = " . quote_smart($createdByName);
  4155. elseif ($createdBySelector == "is not equal to")
  4156. $query .= " AND created_by != " . quote_smart($createdByName);
  4157. elseif ($createdBySelector == "starts with")
  4158. $query .= " AND created_by RLIKE " . quote_smart("^" . $createdByName);
  4159. elseif ($createdBySelector == "ends with")
  4160. $query .= " AND created_by RLIKE " . quote_smart($createdByName . "$");
  4161. }
  4162. }
  4163. elseif ($createdByRadio == "0")
  4164. {
  4165. $createdByName2 = $_REQUEST['createdByName2'];
  4166. if ($createdByName2 != "")
  4167. {
  4168. $createdBySelector2 = $_REQUEST['createdBySelector2'];
  4169. if ($createdBySelector2 == "contains")
  4170. $query .= " AND created_by RLIKE " . quote_smart($createdByName2);
  4171. elseif ($createdBySelector2 == "does not contain")
  4172. $query .= " AND created_by NOT RLIKE " . quote_smart($createdByName2);
  4173. elseif ($createdBySelector2 == "is equal to")
  4174. $query .= " AND created_by = " . quote_smart($createdByName2);
  4175. elseif ($createdBySelector2 == "is not equal to")
  4176. $query .= " AND created_by != " . quote_smart($createdByName2);
  4177. elseif ($createdBySelector2 == "starts with")
  4178. $query .= " AND created_by RLIKE " . quote_smart("^" . $createdByName2);
  4179. elseif ($createdBySelector2 == "ends with")
  4180. $query .= " AND created_by RLIKE " . quote_smart($createdByName2 . "$");
  4181. }
  4182. }
  4183. }
  4184. // ... if the user has specified a modified date, add the value of '$modifiedDateNo' as an AND clause:
  4185. $modifiedDateNo = $_REQUEST['modifiedDateNo'];
  4186. if ($modifiedDateNo != "")
  4187. {
  4188. $modifiedDateSelector = $_REQUEST['modifiedDateSelector'];
  4189. if ($modifiedDateSelector == "contains")
  4190. $query .= " AND modified_date RLIKE " . quote_smart($modifiedDateNo);
  4191. elseif ($modifiedDateSelector == "does not contain")
  4192. $query .= " AND modified_date NOT RLIKE " . quote_smart($modifiedDateNo);
  4193. elseif ($modifiedDateSelector == "is equal to")
  4194. $query .= " AND modified_date = " . quote_smart($modifiedDateNo);
  4195. elseif ($modifiedDateSelector == "is not equal to")
  4196. $query .= " AND modified_date != " . quote_smart($modifiedDateNo);
  4197. elseif ($modifiedDateSelector == "starts with")
  4198. $query .= " AND modified_date RLIKE " . quote_smart("^" . $modifiedDateNo);
  4199. elseif ($modifiedDateSelector == "ends with")
  4200. $query .= " AND modified_date RLIKE " . quote_smart($modifiedDateNo . "$");
  4201. elseif ($modifiedDateSelector == "is greater than")
  4202. $query .= " AND modified_date > " . quote_smart($modifiedDateNo);
  4203. elseif ($modifiedDateSelector == "is less than")
  4204. $query .= " AND modified_date < " . quote_smart($modifiedDateNo);
  4205. elseif ($modifiedDateSelector == "is within range")
  4206. {
  4207. if (preg_match("/\d{4}/", $modifiedDateNo)) // if '$modifiedDateNo' does contain at least one date spec (which, as a minimum, is defined by a four-digit year)
  4208. {
  4209. // extract first date spec:
  4210. $modifiedDateNoStart = preg_replace("/^[^\d-]*(\d{4}(?:-\d{2})?(?:-\d{2})?).*/", "\\1", $modifiedDateNo); // extracts e.g. "2005-10-27", "2005-10" or just "2005" (in that order)
  4211. $query .= " AND modified_date >= " . quote_smart($modifiedDateNoStart);
  4212. if (preg_match("/^[^\d-]*\d{4}(?:-\d{2})?(?:-\d{2})?[^\d-]+\d{4}(?:-\d{2})?(?:-\d{2})?/", $modifiedDateNo)) // if '$modifiedDateNo' does contain at least two date specs (which are separated by one or more non-digit/non-hyphen characters)
  4213. {
  4214. // extract the second date spec:
  4215. $modifiedDateNoEnd = preg_replace("/^[^\d-]*\d{4}(?:-\d{2})?(?:-\d{2})?[^\d-]+(\d{4}(?:-\d{2})?(?:-\d{2})?).*/", "\\1", $modifiedDateNo);
  4216. $query .= " AND modified_date <= " . quote_smart($modifiedDateNoEnd);
  4217. }
  4218. }
  4219. else // fallback if no recognized date spec is given:
  4220. $query .= " AND modified_date RLIKE " . quote_smart($modifiedDateNo);
  4221. }
  4222. elseif ($modifiedDateSelector == "is within list")
  4223. {
  4224. // replace any non-digit/non-hyphen chars with "|":
  4225. $modifiedDateNo = preg_replace("/[^\d-]+/", "|", $modifiedDateNo);
  4226. // strip "|" from beginning/end of string (if any):
  4227. $modifiedDateNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $modifiedDateNo);
  4228. $query .= " AND modified_date RLIKE " . quote_smart("^(" . $modifiedDateNo . ")$");
  4229. }
  4230. }
  4231. // ... if the user has specified a modified time, add the value of '$modifiedTimeNo' as an AND clause:
  4232. $modifiedTimeNo = $_REQUEST['modifiedTimeNo'];
  4233. if ($modifiedTimeNo != "")
  4234. {
  4235. $modifiedTimeSelector = $_REQUEST['modifiedTimeSelector'];
  4236. if ($modifiedTimeSelector == "contains")
  4237. $query .= " AND modified_time RLIKE " . quote_smart($modifiedTimeNo);
  4238. elseif ($modifiedTimeSelector == "does not contain")
  4239. $query .= " AND modified_time NOT RLIKE " . quote_smart($modifiedTimeNo);
  4240. elseif ($modifiedTimeSelector == "is equal to")
  4241. $query .= " AND modified_time = " . quote_smart($modifiedTimeNo);
  4242. elseif ($modifiedTimeSelector == "is not equal to")
  4243. $query .= " AND modified_time != " . quote_smart($modifiedTimeNo);
  4244. elseif ($modifiedTimeSelector == "starts with")
  4245. $query .= " AND modified_time RLIKE " . quote_smart("^" . $modifiedTimeNo);
  4246. elseif ($modifiedTimeSelector == "ends with")
  4247. $query .= " AND modified_time RLIKE " . quote_smart($modifiedTimeNo . "$");
  4248. elseif ($modifiedTimeSelector == "is greater than")
  4249. $query .= " AND modified_time > " . quote_smart($modifiedTimeNo);
  4250. elseif ($modifiedTimeSelector == "is less than")
  4251. $query .= " AND modified_time < " . quote_smart($modifiedTimeNo);
  4252. elseif ($modifiedTimeSelector == "is within range")
  4253. {
  4254. if (preg_match("/\d{2}:\d{2}/", $modifiedTimeNo)) // if '$modifiedTimeNo' does contain at least one time spec (which, as a minimum, is defined by a HH:MM)
  4255. {
  4256. // extract first time spec:
  4257. $modifiedTimeNoStart = preg_replace("/^[^\d:]*(\d{2}:\d{2}(?::\d{2})?).*/", "\\1", $modifiedTimeNo); // extracts e.g. "23:59:59" or just "23:59" (in that order)
  4258. $query .= " AND modified_time >= " . quote_smart($modifiedTimeNoStart);
  4259. if (preg_match("/^[^\d:]*\d{2}:\d{2}(?::\d{2})?[^\d:]+\d{2}:\d{2}(?::\d{2})?/", $modifiedTimeNo)) // if '$modifiedTimeNo' does contain at least two date specs (which are separated by one or more non-digit/non-colon characters)
  4260. {
  4261. // extract the second time spec:
  4262. $modifiedTimeNoEnd = preg_replace("/^[^\d:]*\d{2}:\d{2}(?::\d{2})?[^\d:]+(\d{2}:\d{2}(?::\d{2})?).*/", "\\1", $modifiedTimeNo);
  4263. $query .= " AND modified_time <= " . quote_smart($modifiedTimeNoEnd);
  4264. }
  4265. }
  4266. else // fallback if no recognized time spec is given:
  4267. $query .= " AND modified_time RLIKE " . quote_smart($modifiedTimeNo);
  4268. }
  4269. elseif ($modifiedTimeSelector == "is within list")
  4270. {
  4271. // replace any non-digit/non-colon chars with "|":
  4272. $modifiedTimeNo = preg_replace("/[^\d:]+/", "|", $modifiedTimeNo);
  4273. // strip "|" from beginning/end of string (if any):
  4274. $modifiedTimeNo = preg_replace("/^\|?(.+?)\|?$/", "\\1", $modifiedTimeNo);
  4275. $query .= " AND modified_time RLIKE " . quote_smart("^(" . $modifiedTimeNo . ")$");
  4276. }
  4277. }
  4278. // ... if the user has specified a modified by, add the value of '$modifiedByName' as an AND clause:
  4279. if (isset($_REQUEST['modifiedByRadio'])) // the "modified by" text entry form is not available if the user is not logged in
  4280. {
  4281. $modifiedByRadio = $_REQUEST['modifiedByRadio'];
  4282. if ($modifiedByRadio == "1")
  4283. {
  4284. $modifiedByName = $_REQUEST['modifiedByName'];
  4285. if ($modifiedByName != "All" && $modifiedByName != "")
  4286. {
  4287. $modifiedBySelector = $_REQUEST['modifiedBySelector'];
  4288. if ($modifiedBySelector == "contains")
  4289. $query .= " AND modified_by RLIKE " . quote_smart($modifiedByName);
  4290. elseif ($modifiedBySelector == "does not contain")
  4291. $query .= " AND modified_by NOT RLIKE " . quote_smart($modifiedByName);
  4292. elseif ($modifiedBySelector == "is equal to")
  4293. $query .= " AND modified_by = " . quote_smart($modifiedByName);
  4294. elseif ($modifiedBySelector == "is not equal to")
  4295. $query .= " AND modified_by != " . quote_smart($modifiedByName);
  4296. elseif ($modifiedBySelector == "starts with")
  4297. $query .= " AND modified_by RLIKE " . quote_smart("^" . $modifiedByName);
  4298. elseif ($modifiedBySelector == "ends with")
  4299. $query .= " AND modified_by RLIKE " . quote_smart($modifiedByName . "$");
  4300. }
  4301. }
  4302. elseif ($modifiedByRadio == "0")
  4303. {
  4304. $modifiedByName2 = $_REQUEST['modifiedByName2'];
  4305. if ($modifiedByName2 != "")
  4306. {
  4307. $modifiedBySelector2 = $_REQUEST['modifiedBySelector2'];
  4308. if ($modifiedBySelector2 == "contains")
  4309. $query .= " AND modified_by RLIKE " . quote_smart($modifiedByName2);
  4310. elseif ($modifiedBySelector2 == "does not contain")
  4311. $query .= " AND modified_by NOT RLIKE " . quote_smart($modifiedByName2);
  4312. elseif ($modifiedBySelector2 == "is equal to")
  4313. $query .= " AND modified_by = " . quote_smart($modifiedByName2);
  4314. elseif ($modifiedBySelector2 == "is not equal to")
  4315. $query .= " AND modified_by != " . quote_smart($modifiedByName2);
  4316. elseif ($modifiedBySelector2 == "starts with")
  4317. $query .= " AND modified_by RLIKE " . quote_smart("^" . $modifiedByName2);
  4318. elseif ($modifiedBySelector2 == "ends with")
  4319. $query .= " AND modified_by RLIKE " . quote_smart($modifiedByName2 . "$");
  4320. }
  4321. }
  4322. }
  4323. // Construct the ORDER BY clause:
  4324. $query .= " ORDER BY ";
  4325. // A) extract first level sort option:
  4326. $sortSelector1 = $_REQUEST['sortSelector1'];
  4327. if ($sortSelector1 != "")
  4328. {
  4329. // when field name = 'pages' then sort by 'first_page' instead:
  4330. $sortSelector1 = str_replace("pages", "first_page", $sortSelector1);
  4331. $sortRadio1 = $_REQUEST['sortRadio1'];
  4332. if ($sortRadio1 == "0") // sort ascending
  4333. $query .= "$sortSelector1";
  4334. else // sort descending
  4335. $query .= "$sortSelector1 DESC";
  4336. }
  4337. // B) extract second level sort option:
  4338. $sortSelector2 = $_REQUEST['sortSelector2'];
  4339. if ($sortSelector2 != "")
  4340. {
  4341. // when field name = 'pages' then sort by 'first_page' instead:
  4342. $sortSelector2 = str_replace("pages", "first_page", $sortSelector2);
  4343. $sortRadio2 = $_REQUEST['sortRadio2'];
  4344. if ($sortRadio2 == "0") // sort ascending
  4345. $query .= ", $sortSelector2";
  4346. else // sort descending
  4347. $query .= ", $sortSelector2 DESC";
  4348. }
  4349. // C) extract third level sort option:
  4350. $sortSelector3 = $_REQUEST['sortSelector3'];
  4351. if ($sortSelector3 != "")
  4352. {
  4353. // when field name = 'pages' then sort by 'first_page' instead:
  4354. $sortSelector3 = str_replace("pages", "first_page", $sortSelector3);
  4355. $sortRadio3 = $_REQUEST['sortRadio3'];
  4356. if ($sortRadio3 == "0") // sort ascending
  4357. $query .= ", $sortSelector3";
  4358. else // sort descending
  4359. $query .= ", $sortSelector3 DESC";
  4360. }
  4361. // Since the sort popup menus use empty fields as delimiters between groups of fields
  4362. // we'll have to trap the case that the user hasn't chosen any field names for sorting:
  4363. if (preg_match("/ORDER BY $/i", $query))
  4364. $query .= "author, year DESC, publication"; // use the default ORDER BY clause
  4365. // Finally, fix the wrong syntax where its says "ORDER BY, author, title, ..." instead of "ORDER BY author, title, ...":
  4366. $query = preg_replace("/ORDER BY , /i","ORDER BY ",$query);
  4367. return $query;
  4368. }
  4369. // --------------------------------------------------------------------
  4370. // Note: function 'extractFormElementsRefineDisplay()' is defined in 'include.inc.php' since it's also used by 'users.php'
  4371. // --------------------------------------------------------------------
  4372. // Build the database query from records selected by the user within the query results list (which, in turn, was returned by 'search.php'):
  4373. function extractFormElementsQueryResults($displayType, $originalDisplayType, $showLinks, $citeOrder, $orderBy, $userID, $sqlQuery, $referer, $recordSerialsArray, $recordsSelectionRadio)
  4374. {
  4375. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  4376. // Process ALL found records:
  4377. if ($recordsSelectionRadio == "1") // if the user checked the radio button next to the "All Found Records" option [this is the default]
  4378. {
  4379. // extract the 'WHERE' clause from the SQL query:
  4380. $queryWhereClause = extractWHEREclause($sqlQuery); // function 'extractWHEREclause()' is defined in 'include.inc.php'
  4381. if (preg_match("/^(Add|Remove)$/i", $displayType)) // the user clicked either the 'Add' or the 'Remove' button
  4382. // get the serial numbers of all found records (which is required by function 'modifyUserGroups()'):
  4383. $recordSerialsArray = getFieldContents($tableRefs, "serial", $userID, $queryWhereClause); // function 'getFieldContents()' is defined in 'include.inc.php'
  4384. }
  4385. // Process SELECTED records only:
  4386. else // $recordsSelectionRadio == "0" // if the user checked the radio button next to the "Selected Records" option
  4387. {
  4388. if (empty($recordSerialsArray)) // the user did NOT check any checkboxes
  4389. $recordSerialsArray[] = "0"; // since '0' doesn't exist as serial number, this will result in a "nothing found" feedback
  4390. $queryWhereClause = "serial RLIKE " . quote_smart("^(" . implode("|", $recordSerialsArray) . ")$");
  4391. }
  4392. if (isset($_SESSION['loginEmail']) AND (isset($_SESSION['user_permissions']) AND preg_match("/allow_user_groups/", $_SESSION['user_permissions']))) // if a user is logged in AND the 'user_permissions' session variable contains 'allow_user_groups', extract form elements which add/remove the selected records to/from a user's group:
  4393. {
  4394. $userGroupActionRadio = $_REQUEST['userGroupActionRadio']; // extract user option whether we're supposed to process an existing group name or any custom/new group name that was specified by the user
  4395. // Extract the chosen user group from the request:
  4396. // first, we need to check whether the user did choose an existing group name from the popup menu
  4397. // -OR- if he/she did enter a custom group name in the text entry field:
  4398. if ($userGroupActionRadio == "1") // if the user checked the radio button next to the group popup menu ('userGroupSelector') [this is the default]
  4399. {
  4400. if (isset($_REQUEST['userGroupSelector']))
  4401. $userGroup = $_REQUEST['userGroupSelector']; // extract the value of the 'userGroupSelector' popup menu
  4402. else
  4403. $userGroup = "";
  4404. }
  4405. else // $userGroupActionRadio == "0" // if the user checked the radio button next to the group text entry field ('userGroupName')
  4406. {
  4407. if (isset($_REQUEST['userGroupName']))
  4408. $userGroup = $_REQUEST['userGroupName']; // extract the value of the 'userGroupName' text entry field
  4409. else
  4410. $userGroup = "";
  4411. }
  4412. }
  4413. // Depending on the chosen output format, construct an appropriate SQL query:
  4414. // TODO: build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
  4415. if (preg_match("/^Cite$/i", $displayType)) // (if any form element is selected, hitting <enter> will act as if the user clicked the 'Cite' button)
  4416. {
  4417. $query = buildSELECTclause($displayType, $showLinks); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  4418. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  4419. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . quote_smart($userID) . " WHERE " . $queryWhereClause;
  4420. else // NO user logged in
  4421. $query .= " FROM $tableRefs WHERE " . $queryWhereClause;
  4422. if ($citeOrder == "year") // sort records first by year (descending), then in the usual way:
  4423. $query .= " ORDER BY year DESC, first_author, author_count, author, title";
  4424. elseif ($citeOrder == "type") // sort records first by record type (and thesis type), then in the usual way:
  4425. $query .= " ORDER BY type DESC, thesis DESC, first_author, author_count, author, year, title";
  4426. elseif ($citeOrder == "type-year") // sort records first by record type (and thesis type), then by year (descending), then in the usual way:
  4427. $query .= " ORDER BY type DESC, thesis DESC, year DESC, first_author, author_count, author, title";
  4428. elseif ($citeOrder == "creation-date") // sort records such that newly added/edited records get listed top of the list:
  4429. $query .= " ORDER BY created_date DESC, created_time DESC, modified_date DESC, modified_time DESC, serial DESC";
  4430. else // if any other or no '$citeOrder' parameter is specified, we supply the default ORDER BY pattern (which is suitable for citation in a journal etc.):
  4431. $query .= " ORDER BY first_author, author_count, author, year, title";
  4432. }
  4433. elseif (preg_match("/^(Display|Export)$/i", $displayType))
  4434. {
  4435. $query = buildSELECTclause($displayType, $showLinks); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  4436. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  4437. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . quote_smart($userID) . " WHERE " . $queryWhereClause . " ORDER BY $orderBy";
  4438. else // NO user logged in
  4439. $query .= " FROM $tableRefs WHERE " . $queryWhereClause . " ORDER BY $orderBy";
  4440. }
  4441. elseif (isset($_SESSION['loginEmail']) AND preg_match("/^(Add|Remove)$/i", $displayType)) // if a user (who's logged in) clicked the 'Add' or 'Remove' button...
  4442. {
  4443. if (preg_match("/^(Add|Remove)$/i", $displayType) AND !empty($userGroup)) // the user clicked either the 'Add' or the 'Remove' button
  4444. modifyUserGroups($tableUserData, $displayType, $recordSerialsArray, $userID, $userGroup); // add (remove) selected records to (from) the specified user group (function 'modifyUserGroups()' is defined in 'include.inc.php')
  4445. // re-apply the current sqlQuery:
  4446. $query = 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)
  4447. $query = preg_replace("/ FROM $tableRefs/i",", serial FROM $tableRefs", $query); // add 'serial' column (which is required in order to obtain unique checkbox names)
  4448. if ($showLinks == "1")
  4449. $query = preg_replace("/ FROM $tableRefs/i",", file, url, doi, isbn, type FROM $tableRefs", $query); // add 'file', 'url', 'doi', 'isbn' & 'type columns
  4450. // re-assign the correct display type if the user clicked the 'Add' or 'Remove' button of the 'queryResults' form:
  4451. $displayType = $originalDisplayType;
  4452. }
  4453. return array($query, $displayType);
  4454. }
  4455. // --------------------------------------------------------------------
  4456. // Build the database query from user input provided by the 'extract.php' form:
  4457. function extractFormElementsExtract($showLinks, $citeOrder, $userID)
  4458. {
  4459. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  4460. global $loc; // '$loc' is made globally available in 'core.php'
  4461. // Extract form elements (that are unique to the 'extract.php' form):
  4462. $sourceText = $_REQUEST['sourceText']; // get the source text that contains the record serial numbers/cite keys
  4463. $startDelim = $_REQUEST['startDelim']; // get the start delimiter that precedes record serial numbers/cite keys
  4464. $endDelim = $_REQUEST['endDelim']; // get the end delimiter that follows record serial numbers/cite keys
  4465. $startDelim = preg_quote($startDelim); // escape any potential meta-characters
  4466. $endDelim = preg_quote($endDelim); // escape any potential meta-characters
  4467. // Extract record serial numbers/cite keys from source text:
  4468. $sourceText = "_" . $sourceText; // Note: by adding a character at the beginning of '$sourceText' we circumvent a problem with the regex pattern below which will strip everything up to the 2nd serial number/cite key if '$sourceText' starts with '$startDelim'
  4469. $recordSerialsKeysString = preg_replace("/^.*?(?=$startDelim.+?$endDelim|$)/s", "", $sourceText); // remove any text preceeding the first serial number/cite key
  4470. $recordSerialsKeysString = preg_replace("/$startDelim(.+?)$endDelim.*?(?=$startDelim.+?$endDelim|$)/s", "\\1_#_�_~_", $recordSerialsKeysString); // replace any text between serial numbers/cite keys (or between a serial number/cite key and the end of the text) with "_#_�_~_"; additionally, remove the delimiters enclosing the serial numbers/cite keys
  4471. // Note: we do a quick'n dirty approach here, by inserting the string "_#_�_~_" as string delimiter between serial numbers/cite keys. Of course, this will only work as long the string "_#_�_~_" doesn't occur within '$sourceText'.
  4472. $recordSerialsKeysString = preg_replace("/(_#_�_~_)?\n?$/s", "", $recordSerialsKeysString); // remove any trailing chars (like \n or "_#_�_~_") at end of line
  4473. $recordSerialsKeysArray = preg_split("/_#_�_~_/", $recordSerialsKeysString, -1, PREG_SPLIT_NO_EMPTY); // split string containing the serial numbers/cite keys on the string delimiter "_#_�_~_" (the 'PREG_SPLIT_NO_EMPTY' flag causes only non-empty pieces to be returned)
  4474. $recordSerialsKeysArray = array_unique($recordSerialsKeysArray); // remove any duplicate serial numbers/cite keys from the list of extracted record identifiers
  4475. $recordSerialsArray = array();
  4476. $escapedRecordKeysArray = array();
  4477. $foundRecordSerialsKeysArray = array();
  4478. $missingRecordSerialsKeysArray = array();
  4479. foreach($recordSerialsKeysArray as $recordSerialKey)
  4480. {
  4481. if (preg_match("/^\d+$/", $recordSerialKey)) // every identifier which only contains digits is treated as a serial number! (In other words: cite keys must contain at least one non-digit character)
  4482. $recordSerialsArray[] = $recordSerialKey;
  4483. elseif (!empty($recordSerialKey)) // identifier is treated as cite key
  4484. {
  4485. $escapedRecordKey = preg_quote($recordSerialKey); // escape any potential meta-characters within cite key
  4486. $escapedRecordKeysArray[] = $escapedRecordKey;
  4487. }
  4488. }
  4489. $recordSerialsString = implode("|", $recordSerialsArray); // merge array of serial numbers again into a string, using "|" as delimiter
  4490. $escapedRecordKeysString = implode("|", $escapedRecordKeysArray); // merge array of cite keys again into a string, using "|" as delimiter
  4491. // Construct the SQL query:
  4492. // TODO: build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
  4493. // for the selected records, select all fields that are visible in Citation view:
  4494. $query = buildSELECTclause("Cite", $showLinks); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  4495. $query .= " FROM $tableRefs"; // add FROM clause
  4496. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  4497. $query .= " LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . quote_smart($userID); // add LEFT JOIN part to FROM clause
  4498. // add WHERE clause:
  4499. $query .= " WHERE";
  4500. if (!empty($recordSerialsArray) OR (empty($recordSerialsArray) AND empty($escapedRecordKeysArray)) OR (empty($recordSerialsArray) AND !isset($_SESSION['loginEmail']))) // the second condition ensures a valid SQL query if no serial numbers or cite keys were found, same for the third condition if a user isn't logged in and '$sourceText' did only contain cite keys
  4501. $query .= " serial RLIKE " . quote_smart("^(" . $recordSerialsString . ")$"); // add any serial numbers to WHERE clause
  4502. if (!empty($recordSerialsArray) AND (!empty($escapedRecordKeysArray) AND isset($_SESSION['loginEmail'])))
  4503. $query .= " OR";
  4504. if (!empty($escapedRecordKeysArray) AND isset($_SESSION['loginEmail']))
  4505. $query .= " cite_key RLIKE " . quote_smart("^(" . $escapedRecordKeysString . ")$"); // add any cite keys to WHERE clause
  4506. // add ORDER BY clause:
  4507. if ($citeOrder == "year") // sort records first by year (descending), then in the usual way:
  4508. $query .= " ORDER BY year DESC, first_author, author_count, author, title";
  4509. elseif ($citeOrder == "type") // sort records first by record type (and thesis type), then in the usual way:
  4510. $query .= " ORDER BY type DESC, thesis DESC, first_author, author_count, author, year, title";
  4511. elseif ($citeOrder == "type-year") // sort records first by record type (and thesis type), then by year (descending), then in the usual way:
  4512. $query .= " ORDER BY type DESC, thesis DESC, year DESC, first_author, author_count, author, title";
  4513. elseif ($citeOrder == "creation-date") // sort records such that newly added/edited records get listed top of the list:
  4514. $query .= " ORDER BY created_date DESC, created_time DESC, modified_date DESC, modified_time DESC, serial DESC";
  4515. else // if any other or no '$citeOrder' parameter is specified, we supply the default ORDER BY pattern (which is suitable for citation in a journal etc.):
  4516. $query .= " ORDER BY first_author, author_count, author, year, title";
  4517. // Check whether the extracted serial numbers and cite keys exist in the database:
  4518. $result = queryMySQLDatabase($query); // RUN the query on the database through the connection (function 'queryMySQLDatabase()' is defined in 'include.inc.php')
  4519. if (@ mysqli_num_rows($result) > 0) // if there were rows found ...
  4520. {
  4521. // Loop over each row in the result set:
  4522. for ($rowCounter=0; $row = @ mysqli_fetch_array($result); $rowCounter++)
  4523. {
  4524. if (!in_array($row["serial"], $foundRecordSerialsKeysArray) OR (!empty($row["cite_key"]) AND !in_array($row["cite_key"], $foundRecordSerialsKeysArray))) // if this record identifier hasn't been seen yet
  4525. {
  4526. // add this record's serial number and cite key to the array of found record serials and cite keys:
  4527. $foundRecordSerialsKeysArray[] = $row["serial"];
  4528. if (!empty($row["cite_key"]))
  4529. $foundRecordSerialsKeysArray[] = $row["cite_key"];
  4530. }
  4531. }
  4532. }
  4533. $missingRecordSerialsKeysArray = array_diff($recordSerialsKeysArray, $foundRecordSerialsKeysArray); // get all unique array elements of '$recordSerialsKeysArray' which are not in '$foundRecordSerialsKeysArray'
  4534. sort($missingRecordSerialsKeysArray);
  4535. if (!empty($escapedRecordKeysArray) AND !isset($_SESSION['loginEmail'])) // a user can only use cite keys as record identifiers when he's logged in
  4536. $messageSuffix = "<br>" . $loc["Warning_LoginToUseCiteKeysAsIdentifiers"] . "!";
  4537. else
  4538. $messageSuffix = "";
  4539. if (!empty($missingRecordSerialsKeysArray) OR (!empty($escapedRecordKeysArray) AND !isset($_SESSION['loginEmail']))) // if some record identifiers could not be found in the database -OR- if a user tries to use cite keys while not being logged in
  4540. // return an appropriate error message:
  4541. $HeaderString = returnMsg("Following record identifiers could not be found: " . implode(", ", $missingRecordSerialsKeysArray), "warning", "strong", "HeaderString", "", $messageSuffix); // function 'returnMsg()' is defined in 'include.inc.php'
  4542. return $query;
  4543. }
  4544. // --------------------------------------------------------------------
  4545. // Build the database query from user input provided by the "Quick Search" form on the main page ('index.php'):
  4546. // TODO: build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
  4547. function extractFormElementsQuick($sqlQuery, $showLinks, $userID, $displayType, $originalDisplayType)
  4548. {
  4549. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  4550. global $defaultFieldsListViewMajor; // these variables are specified in 'ini.inc.php'
  4551. global $defaultFieldsListViewMinor;
  4552. global $query;
  4553. $quickSearchSelector = $_REQUEST['quickSearchSelector']; // extract field name chosen by the user
  4554. $quickSearchName = $_REQUEST['quickSearchName']; // extract search text entered by the user
  4555. $userMainFieldsArray = preg_split("/ *, */", $_SESSION['userMainFields']); // get the list of "main fields" preferred by the current user
  4556. if (!empty($originalDisplayType))
  4557. {
  4558. // NOTE: if the user submits the 'quickSearch' form from Browse view, we currently don't display
  4559. // the new search results in Browse view but switch to the user's default view instead
  4560. if ($originalDisplayType == "Browse")
  4561. // note that, as long as the 'quickSearch' form doesn't transmit a 'submit' parameter, the next line
  4562. // isn't strictly necessary (since then '$displayType' will already contain the user's default view)
  4563. $displayType = $_SESSION['userDefaultView']; // get the default view for the current user
  4564. else // re-assign the correct display type (i.e. the view that was active when the user clicked the 'Search' button of the 'quickSearch' form):
  4565. $displayType = $originalDisplayType;
  4566. }
  4567. // Build SELECT clause:
  4568. if (preg_match("/^(Cite|Display)$/i", $displayType))
  4569. {
  4570. if ((preg_match("/^Display$/i", $displayType)) AND (isset($_SESSION['lastDetailsViewQuery']))) // get SELECT clause from previous Details view query (if any):
  4571. {
  4572. $previousSelectClause = extractSELECTclause($_SESSION['lastDetailsViewQuery']); // function 'extractSELECTclause()' is defined in 'include.inc.php'
  4573. $query = buildSELECTclause($displayType, $showLinks, "", false, true, $previousSelectClause); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  4574. }
  4575. else // generate a new SELECT clause that's appropriate for Citation view (or Details view):
  4576. $query = buildSELECTclause($displayType, $showLinks);
  4577. }
  4578. else // output found records in List view:
  4579. {
  4580. if ($quickSearchSelector == "main_fields") // if we're supposed to query all of the "main fields" at once
  4581. {
  4582. $additionalFields = $defaultFieldsListViewMinor; // note that for the "main fields" option, we simply display the default list of columns
  4583. }
  4584. else
  4585. {
  4586. // if the default list of "major" fields (to be displayed in List view) doesn't already contain the chosen field name...
  4587. // (which is e.g. the case for the 'keywords' & 'abstract' fields)
  4588. if (!preg_match("/" . $quickSearchSelector . "/", $defaultFieldsListViewMajor))
  4589. $additionalFields = $quickSearchSelector; // ...add chosen field to SELECT query
  4590. else
  4591. $additionalFields = $defaultFieldsListViewMinor; // ...otherwise, add further default columns
  4592. }
  4593. $query = buildSELECTclause("", $showLinks, $additionalFields, false, true, $defaultFieldsListViewMajor);
  4594. }
  4595. // Build FROM clause:
  4596. if (isset($_SESSION['loginEmail'])) // if a user is logged in...
  4597. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . $userID;
  4598. else // NO user logged in
  4599. $query .= " FROM $tableRefs";
  4600. // Build WHERE clause:
  4601. $query .= " WHERE";
  4602. // we construct a hierarchical '$searchArray' from the given search field name(s) & value;
  4603. // this array then gets merged into a full SQL WHERE clause by function 'appendToWhereClause()'
  4604. $searchArray = array();
  4605. $searchArray[] = array("_boolean" => "",
  4606. "_query" => "serial RLIKE \".+\"");
  4607. if ($quickSearchName != "") // if the user typed a search string into the text entry field...
  4608. {
  4609. if ($quickSearchSelector == "main_fields")
  4610. {
  4611. $searchSubArray = array();
  4612. foreach($userMainFieldsArray as $userMainField)
  4613. $searchSubArray[] = array("_boolean" => "OR",
  4614. "_query" => $userMainField . " RLIKE " . quote_smart($quickSearchName));
  4615. $searchArray[] = array("_boolean" => "AND",
  4616. "_query" => $searchSubArray);
  4617. }
  4618. else
  4619. $searchArray[] = array("_boolean" => "AND",
  4620. "_query" => $quickSearchSelector . " RLIKE " . quote_smart($quickSearchName));
  4621. }
  4622. appendToWhereClause($searchArray); // function 'appendToWhereClause()' is defined in 'include.inc.php'
  4623. // Build ORDER BY clause:
  4624. $query .= " ORDER BY ";
  4625. if (($originalDisplayType != "Browse") AND (!empty($sqlQuery)))
  4626. // use the custom ORDER BY clause chosen by the user:
  4627. $query .= extractORDERBYclause($sqlQuery); // function 'extractORDERBYclause()' is defined in 'include.inc.php'
  4628. else
  4629. // add the default ORDER BY clause:
  4630. $query .= "author, year DESC, publication";
  4631. return array($query, $displayType);
  4632. }
  4633. // --------------------------------------------------------------------
  4634. // Build the database query from user input provided by the "Show My Group" form on the main page ('index.php') or above the query results list (that was produced by 'search.php'):
  4635. // TODO: build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
  4636. function extractFormElementsGroup($sqlQuery, $showLinks, $userID, $displayType, $originalDisplayType)
  4637. {
  4638. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  4639. $groupSearchSelector = $_REQUEST['groupSearchSelector']; // extract the user group chosen by the user
  4640. $groupSearchSelector = preg_quote($groupSearchSelector, "/"); // escape possible meta characters within group names (otherwise the RLIKE SQL query that's generated below might fail)
  4641. if (!empty($originalDisplayType))
  4642. {
  4643. // NOTE: if the user submits the 'groupSearch' form from Browse view, we currently don't display
  4644. // the group's entries in Browse view but switch to the user's default view instead
  4645. if ($originalDisplayType == "Browse")
  4646. // note that, as long as the 'groupSearch' form doesn't transmit a 'submit' parameter, the next line
  4647. // isn't strictly necessary (since then '$displayType' will already contain the user's default view)
  4648. $displayType = $_SESSION['userDefaultView']; // get the default view for the current user
  4649. else // re-assign the correct display type (i.e. the view that was active when the user clicked the 'Show' button of the 'groupSearch' form):
  4650. $displayType = $originalDisplayType;
  4651. }
  4652. if (preg_match("/^(Cite|Display)$/i", $displayType))
  4653. {
  4654. if ((preg_match("/^Display$/i", $displayType)) AND (isset($_SESSION['lastDetailsViewQuery']))) // get SELECT clause from previous Details view query (if any):
  4655. {
  4656. $previousSelectClause = extractSELECTclause($_SESSION['lastDetailsViewQuery']); // function 'extractSELECTclause()' is defined in 'include.inc.php'
  4657. $query = buildSELECTclause($displayType, $showLinks, "", false, true, $previousSelectClause); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  4658. }
  4659. else // generate a new SELECT clause that's appropriate for Citation view (or Details view):
  4660. $query = buildSELECTclause($displayType, $showLinks);
  4661. }
  4662. // output found records in List view:
  4663. elseif (($originalDisplayType != "Browse") AND (!empty($sqlQuery))) // if we're not in Browse view and there's a previous SQL query available (as is the case if the group search originated from a search results page - and not from the main page 'index.php')
  4664. {
  4665. // use the custom set of colums chosen by the user:
  4666. $previousSelectClause = extractSELECTclause($sqlQuery);
  4667. $query = buildSELECTclause("", $showLinks, "", false, true, $previousSelectClause);
  4668. }
  4669. else
  4670. {
  4671. // use the default SELECT statement:
  4672. $query = buildSELECTclause("", $showLinks, "user_groups", false, true);
  4673. }
  4674. if (($originalDisplayType != "Browse") AND (!empty($sqlQuery)))
  4675. // use the custom ORDER BY clause chosen by the user:
  4676. $queryOrderBy = extractORDERBYclause($sqlQuery); // function 'extractORDERBYclause()' is defined in 'include.inc.php'
  4677. else
  4678. // add the default ORDER BY clause:
  4679. $queryOrderBy = "author, year DESC, publication";
  4680. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . $userID; // add FROM clause
  4681. $query .= " WHERE user_groups RLIKE " . quote_smart("(^|.*;) *" . $groupSearchSelector. " *(;.*|$)"); // add WHERE clause
  4682. $query .= " ORDER BY " . $queryOrderBy; // add ORDER BY clause
  4683. return array($query, $displayType);
  4684. }
  4685. // --------------------------------------------------------------------
  4686. // Build the database query from user input provided by the "Show My Refs" form on the
  4687. // main page ('index.php') which searches the user specific fields from table 'user_data':
  4688. // Note: Although the "Show My Refs" form on 'index.php' is of method="POST" we do accept
  4689. // GET queries as well in order to allow for the 'My Refs' links provided by the
  4690. // 'showLogin()' function (from 'include.inc.php').
  4691. function extractFormElementsMyRefs($showLinks, $loginEmail, $userID)
  4692. {
  4693. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  4694. $myRefsRadio = $_REQUEST['myRefsRadio']; // will be "1" if the user wants to display ALL of his records, otherwise it will be "0"
  4695. // extract form popup 'marked/not marked':
  4696. if (isset($_REQUEST['findMarked']))
  4697. $findMarked = $_REQUEST['findMarked']; // will be "1" if the user wants to search the 'marked' field
  4698. else
  4699. $findMarked = "";
  4700. if (isset($_REQUEST['markedSelector']))
  4701. $markedSelector = $_REQUEST['markedSelector']; // extract 'marked' field value chosen by the user
  4702. else
  4703. $markedSelector = "";
  4704. // extract form popup 'selected/not selected':
  4705. if (isset($_REQUEST['findSelected']))
  4706. $findSelected = $_REQUEST['findSelected']; // will be "1" if the user wants to search the 'selected' field
  4707. else
  4708. $findSelected = "";
  4709. if (isset($_REQUEST['selectedSelector']))
  4710. $selectedSelector = $_REQUEST['selectedSelector']; // extract 'selected' field value chosen by the user
  4711. else
  4712. $selectedSelector = "";
  4713. // extract form popup 'copy = true/fetch/ordered/false':
  4714. if (isset($_REQUEST['findCopy']))
  4715. $findCopy = $_REQUEST['findCopy']; // will be "1" if the user wants to search the 'copy' field
  4716. else
  4717. $findCopy = "";
  4718. if (isset($_REQUEST['copySelector']))
  4719. $copySelector = $_REQUEST['copySelector']; // extract 'copy' field value chosen by the user
  4720. else
  4721. $copySelector = "";
  4722. // extract form text entry field 'key':
  4723. if (isset($_REQUEST['findUserKeys']))
  4724. $findUserKeys = $_REQUEST['findUserKeys']; // will be "1" if the user wants to search the 'user_keys' field
  4725. else
  4726. $findUserKeys = "";
  4727. if (isset($_REQUEST['userKeysName']))
  4728. $userKeysName = $_REQUEST['userKeysName']; // extract user keys entered by the user
  4729. else
  4730. $userKeysName = "";
  4731. // extract form text entry field 'note':
  4732. if (isset($_REQUEST['findUserNotes']))
  4733. $findUserNotes = $_REQUEST['findUserNotes']; // will be "1" if the user wants to search the 'user_notes' field
  4734. else
  4735. $findUserNotes = "";
  4736. if (isset($_REQUEST['userNotesName']))
  4737. $userNotesName = $_REQUEST['userNotesName']; // extract user notes entered by the user
  4738. else
  4739. $userNotesName = "";
  4740. // extract form text entry field 'file':
  4741. if (isset($_REQUEST['findUserFile']))
  4742. $findUserFile = $_REQUEST['findUserFile']; // will be "1" if the user wants to search the 'user_file' field
  4743. else
  4744. $findUserFile = "";
  4745. if (isset($_REQUEST['userFileName']))
  4746. $userFileName = $_REQUEST['userFileName']; // extract file specification entered by the user
  4747. else
  4748. $userFileName = "";
  4749. if ($myRefsRadio == "0") // if the user only wants to display a subset of his records:
  4750. {
  4751. $additionalFieldsArray = array();
  4752. if ($findMarked == "1") // if the user wants to search the 'marked' field...
  4753. $additionalFieldsArray[] = "marked"; // ...add 'marked' field to SELECT query
  4754. if ($findSelected == "1") // if the user wants to search the 'selected' field...
  4755. $additionalFieldsArray[] = "selected"; // ...add 'selected' field to SELECT query
  4756. if ($findCopy == "1") // if the user wants to search the 'copy' field...
  4757. $additionalFieldsArray[] = "copy"; // ...add 'copy' field to SELECT query
  4758. if ($findUserKeys == "1") // if the user wants to search the 'user_keys' field...
  4759. $additionalFieldsArray[] = "user_keys"; // ...add 'user_keys' to SELECT query
  4760. if ($findUserNotes == "1") // if the user wants to search the 'user_notes' field...
  4761. $additionalFieldsArray[] = "user_notes"; // ...add 'user_notes' to SELECT query
  4762. if ($findUserFile == "1") // if the user wants to search the 'user_file' field...
  4763. $additionalFieldsArray[] = "user_file"; // ...add 'user_file' to SELECT query
  4764. $additionalFields = implode(", ", $additionalFieldsArray); // merge array of additional fields into a string, using ", " as delimiter
  4765. }
  4766. else
  4767. $additionalFields = "";
  4768. // construct the SQL query:
  4769. // TODO: build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
  4770. $query = buildSELECTclause("", $showLinks, $additionalFields, false, true); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  4771. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . $userID . " WHERE location RLIKE \"$loginEmail\""; // add FROM & (initial) WHERE clause
  4772. if ($myRefsRadio == "0") // if the user only wants to display a subset of his records:
  4773. {
  4774. if ($findMarked == "1") // if the user wants to search the 'marked' field...
  4775. {
  4776. if ($markedSelector == "marked")
  4777. $query .= " AND marked = \"yes\""; // ...add 'marked' field name & value to the sql query
  4778. else // $markedSelector == "not marked" (i.e., 'marked' is either 'no' -or- NULL)
  4779. $query .= " AND (marked = \"no\" OR marked IS NULL)"; // ...add 'marked' field name & value to the sql query
  4780. }
  4781. if ($findSelected == "1") // if the user wants to search the 'selected' field...
  4782. {
  4783. if ($selectedSelector == "selected")
  4784. $query .= " AND selected = \"yes\""; // ...add 'selected' field name & value to the sql query
  4785. else // $selectedSelector == "not selected" (i.e., 'selected' is either 'no' -or- NULL)
  4786. $query .= " AND (selected = \"no\" OR selected IS NULL)"; // ...add 'selected' field name & value to the sql query
  4787. }
  4788. if ($findCopy == "1") // if the user wants to search the 'copy' field...
  4789. {
  4790. if ($copySelector == "true")
  4791. $query .= " AND copy = \"true\""; // ...add 'copy' field name & value to the sql query
  4792. elseif ($copySelector == "ordered")
  4793. $query .= " AND copy = \"ordered\""; // ...add 'copy' field name & value to the sql query
  4794. elseif ($copySelector == "fetch")
  4795. $query .= " AND copy = \"fetch\""; // ...add 'copy' field name & value to the sql query
  4796. else // 'copy' is either 'false' -or- NULL
  4797. $query .= " AND (copy = \"false\" OR copy IS NULL)"; // ...add 'copy' field name & value to the sql query
  4798. }
  4799. if ($findUserKeys == "1") // if the user wants to search the 'user_keys' field...
  4800. if ($userKeysName != "") // if the user typed a search string into the text entry field...
  4801. $query .= " AND user_keys RLIKE " . quote_smart($userKeysName); // ...add 'user_keys' field name & value to the sql query
  4802. if ($findUserNotes == "1") // if the user wants to search the 'user_notes' field...
  4803. if ($userNotesName != "") // if the user typed a search string into the text entry field...
  4804. $query .= " AND user_notes RLIKE " . quote_smart($userNotesName); // ...add 'user_notes' field name & value to the sql query
  4805. if ($findUserFile == "1") // if the user wants to search the 'user_file' field...
  4806. if ($userFileName != "") // if the user typed a search string into the text entry field...
  4807. $query .= " AND user_file RLIKE " . quote_smart($userFileName); // ...add 'user_file' field name & value to the sql query
  4808. }
  4809. $query .= " ORDER BY author, year DESC, publication"; // add the default ORDER BY clause
  4810. return $query;
  4811. }
  4812. // --------------------------------------------------------------------
  4813. // Build the database query from user input provided by the "Browse My Refs" form on the
  4814. // main page ('index.php') which lets the user browse a particular field:
  4815. function extractFormElementsBrowseMyRefs($showLinks, $loginEmail, $userID)
  4816. {
  4817. // IMPORTANT NOTE: Browse functionality is NOT fully implemented yet!!
  4818. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  4819. $browseFieldSelector = $_REQUEST['browseFieldSelector']; // extract field name chosen by the user
  4820. // construct the SQL query:
  4821. // TODO: build the complete SQL query using functions 'buildFROMclause()' and 'buildORDERclause()'
  4822. // if the chosen field can contain multiple items...
  4823. // TODO: we really should check here if the corresponding 'ref_...' table exists!
  4824. if (preg_match("/^(author|keywords|editor|language|summary_language|area|location|user_keys|user_groups)$/i", $browseFieldSelector))
  4825. {
  4826. list($refTableName, $browseFieldName) = buildRefTableAndFieldNames($browseFieldSelector); // get correct table name and field name for the 'ref_...' table that matches the chosen field
  4827. $browseFieldColumnName = " AS " . preg_replace("/^ref_(\w+)$/i", "\\1", $browseFieldName); // strip the 'ref_' prefix for the column name
  4828. $queryRefTableLeftJoinPart = " LEFT JOIN $refTableName ON serial = ref_id"; // ...add the appropriate 'LEFT JOIN...' part to the 'FROM' clause
  4829. if (preg_match("/^(user_keys|user_groups)$/i", $browseFieldSelector))
  4830. $queryRefTableLeftJoinPart .= " AND ref_user_id = " . quote_smart($userID); // add the user's user_id as additional condition to this 'LEFT JOIN...' part
  4831. }
  4832. else
  4833. {
  4834. $browseFieldName = $browseFieldSelector;
  4835. $browseFieldColumnName = "";
  4836. $queryRefTableLeftJoinPart = "";
  4837. }
  4838. $query = buildSELECTclause("Browse", $showLinks, "", false, false, "", $browseFieldName . $browseFieldColumnName); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  4839. // if a user specific field was chosen...
  4840. if (preg_match("/^(marked|copy|selected|user_keys|user_notes|user_file|user_groups|cite_key|related)$/i", $browseFieldSelector))
  4841. $query .= " FROM $tableRefs LEFT JOIN $tableUserData ON serial = record_id AND user_id = " . $userID; // add FROM clause and the appropriate 'LEFT JOIN...' part
  4842. else
  4843. $query .= " FROM $tableRefs"; // add FROM clause
  4844. $query .= $queryRefTableLeftJoinPart; // add additional 'LEFT JOIN...' part (if required)
  4845. $query .= " WHERE location RLIKE " . quote_smart($loginEmail); // add (initial) WHERE clause
  4846. $query .= " GROUP BY $browseFieldName"; // add the GROUP BY clause
  4847. $query .= " ORDER BY records DESC, $browseFieldName"; // add the default ORDER BY clause
  4848. return $query;
  4849. }
  4850. // --------------------------------------------------------------------
  4851. // Add columns given in '$columnsArray' to the list of fields available in the
  4852. // List View SELECT clause if they were marked in the search form interface:
  4853. function addToSelectClause($columnsArray)
  4854. {
  4855. $selectClauseColumnsArray = array();
  4856. foreach ($columnsArray as $checkboxName => $columnName)
  4857. {
  4858. // If the user has checked the checkbox next to this column,
  4859. // add it to the SELECT clause:
  4860. if (isset($_REQUEST[$checkboxName]) AND ($_REQUEST[$checkboxName] == "1"))
  4861. $selectClauseColumnsArray[$columnName] = $columnName;
  4862. }
  4863. // force add 'author' column if the user hasn't checked any of the column checkboxes:
  4864. if (empty($selectClauseColumnsArray))
  4865. $selectClauseColumnsArray['author'] = "author";
  4866. return $selectClauseColumnsArray;
  4867. }
  4868. // --------------------------------------------------------------------
  4869. // NOTHING FOUND
  4870. // informs the user that no results were found for the current query/action
  4871. function nothingFound($nothingChecked)
  4872. {
  4873. global $loc; // '$loc' is made globally available in 'core.php'
  4874. global $client;
  4875. if (preg_match("/^cli/i", $client)) // if the query originated from a command line client such as the refbase CLI clients ("cli-refbase-1.1", "cli-refbase_import-1.0")
  4876. {
  4877. $nothingFoundFeedback = "Nothing found!\n\n"; // return plain text
  4878. }
  4879. else // return HTML
  4880. {
  4881. $nothingFoundFeedback = "\n<table id=\"error\" class=\"results\" align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\" width=\"95%\" summary=\"This table holds the database results for your query\">";
  4882. if ($nothingChecked)
  4883. // Inform the user that no records were selected:
  4884. $nothingFoundFeedback .= "\n<tr>\n\t<td valign=\"top\">No records selected! Please select one or more records by clicking the appropriate checkboxes.&nbsp;&nbsp;<a href=\"javascript:history.back()\" title=\"" . $loc["LinkTitle_GoBackToResults"] . "\">" . $loc["Go Back"] . "</a></td>\n</tr>";
  4885. else // $nothingChecked == false (i.e., the user did check some checkboxes) -OR- the query resulted from another script like 'show.php' (which has no checkboxes to mark!)
  4886. {
  4887. // Report that nothing was found:
  4888. $nothingFoundFeedback .= "\n<tr>\n\t<td valign=\"top\">Sorry, but your query didn't produce any results!";
  4889. if (!preg_match("/^inc/i", $client))
  4890. $nothingFoundFeedback .= "&nbsp;&nbsp;<a href=\"javascript:history.back()\" title=\"" . $loc["LinkTitle_GoBackToResults"] . "\">" . $loc["Go Back"] . "</a></td>\n</tr>";
  4891. }
  4892. $nothingFoundFeedback .= "\n</table>";
  4893. }
  4894. return $nothingFoundFeedback;
  4895. }
  4896. // --------------------------------------------------------------------
  4897. // PRINT LINKS
  4898. // this function prints out available links in List view and Citation view
  4899. // (for links of type DOI/URL/ISBN/XREF, only one link will be printed; order of preference: DOI, URL, ISBN, XREF)
  4900. function printLinks($showLinkTypes, $row, $showQuery, $showLinks, $wrapResults, $userID, $viewType, $orderBy)
  4901. {
  4902. global $databaseBaseURL; // these variables are defined in 'ini.inc.php'
  4903. global $filesBaseURL;
  4904. global $fileVisibility;
  4905. global $fileVisibilityException;
  4906. global $openURLResolver;
  4907. global $isbnURLFormat;
  4908. global $tableRefs, $tableUserData; // defined in 'db.inc.php'
  4909. global $loc; // '$loc' is made globally available in 'core.php'
  4910. global $client;
  4911. // Note: for proper placement of links within the Links column we don't use the 'mergeLinks()' function here (as is done for Details view),
  4912. // since spacing before links is handled individually for each link type
  4913. $links = ""; // make sure that our buffer variable is empty
  4914. // count the number of available link elements:
  4915. $linkElementCounterLoggedOut = 0;
  4916. // if the 'user_permissions' session variable contains 'allow_details_view'...
  4917. if (in_array("details", $showLinkTypes) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_details_view/", $_SESSION['user_permissions']))
  4918. $linkElementCounterLoggedOut = ($linkElementCounterLoggedOut + 1);
  4919. // if the 'user_permissions' session variable contains 'allow_edit'...
  4920. if (in_array("edit", $showLinkTypes) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_edit/", $_SESSION['user_permissions']))
  4921. $linkElementCounterLoggedOut = ($linkElementCounterLoggedOut + 1);
  4922. // if either the URL or the DOI field contain something
  4923. if ((in_array("url", $showLinkTypes) AND !empty($row["url"])) OR (in_array("doi", $showLinkTypes) AND !empty($row["doi"])))
  4924. $linkElementCounterLoggedOut = ($linkElementCounterLoggedOut + 1);
  4925. // in case an ISBN number was given
  4926. elseif (in_array("isbn", $showLinkTypes) AND !empty($isbnURLFormat) AND !empty($row["isbn"])) // provide a link to an ISBN resolver
  4927. $linkElementCounterLoggedOut = ($linkElementCounterLoggedOut + 1);
  4928. // if we're supposed to auto-generate an OpenURL link
  4929. elseif (in_array("xref", $showLinkTypes) AND !empty($openURLResolver))
  4930. $linkElementCounterLoggedOut = ($linkElementCounterLoggedOut + 1);
  4931. $linkElementCounterLoggedIn = $linkElementCounterLoggedOut;
  4932. // if a user is logged in and a FILE is associated with the current record
  4933. if (in_array("file", $showLinkTypes) 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']))) OR (!empty($fileVisibilityException) AND preg_match($fileVisibilityException[1], $row[$fileVisibilityException[0]]))))
  4934. if (!empty($row["file"]))// if the 'file' field is NOT empty
  4935. $linkElementCounterLoggedIn = ($linkElementCounterLoggedIn + 1);
  4936. if (preg_match("/^inc/i", $client)) // we open links in a new browser window if refbase data are included somewhere else:
  4937. $target = " target=\"_blank\"";
  4938. else
  4939. $target = "";
  4940. 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
  4941. $baseURL = $databaseBaseURL;
  4942. else
  4943. $baseURL = "";
  4944. if (in_array("details", $showLinkTypes) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_details_view/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_details_view'...
  4945. {
  4946. // display a link that opens the Details view for this record:
  4947. // NOTE: we use a 'show.php' URL here since it is much shorter and easier to bookmark as a permanent link; however,
  4948. // this means one additional redirect; the old code that directly generates a 'search.php' URL is commented out below
  4949. // TODO: verify that the time lag introduced by the redirect action is generally acceptable!
  4950. $queryParametersArray = array("record" => $row["serial"]);
  4951. // we only add further parameters to the 'show.php' URL if their current value differs from the defaults used by 'show.php' or 'search.php':
  4952. if (!empty($viewType) AND !preg_match("/^Web$/i", $viewType))
  4953. $queryParametersArray["viewType"] = $viewType;
  4954. if ($showQuery == "1")
  4955. $queryParametersArray["showQuery"] = $showQuery;
  4956. if ($showLinks == "0") // this is kinda superfluous since, for '$showLinks=0', the link isn't shown in the first place
  4957. $queryParametersArray["showLinks"] = $showLinks;
  4958. $links .= "\n\t\t<a href=\"" . $baseURL . generateURL("show.php", "html", $queryParametersArray, true) . "\"" . $target . ">"
  4959. . "<img src=\"" . $baseURL . "img/details.gif\" alt=\"" . $loc["details"] . "\" title=\"" . $loc["LinkTitle_ShowDetails"] . "\" width=\"9\" height=\"17\" hspace=\"0\" border=\"0\"></a>";
  4960. // Old code that directly generates a 'search.php' URL which points to Details view for this record:
  4961. // // Construct the SQL query:
  4962. // // TODO: build the complete SQL query first (using functions 'buildFROMclause()' and 'buildORDERclause()'), then rawurlencode and add to link
  4963. // $showDetailsQuery = buildSELECTclause("Display", $showLinks, "", false, false); // function 'buildSELECTclause()' is defined in 'include.inc.php'
  4964. //
  4965. // // ... display a link that opens the Details view for this record:
  4966. // if (isset($_SESSION['loginEmail'])) // if a user is logged in, show user specific fields:
  4967. // $links .= "\n\t\t<a href=\"" . $baseURL . "search.php"
  4968. // . "?sqlQuery=" . rawurlencode($showDetailsQuery) . "%20FROM%20" . $tableRefs . "%20LEFT%20JOIN%20" . $tableUserData . "%20ON%20serial%20%3D%20record_id%20AND%20user_id%20%3D%20" . $userID . "%20";
  4969. // else // if NO user logged in, don't display any user specific fields and hide the 'location' field:
  4970. // $links .= "\n\t\t<a href=\"" . $baseURL . "search.php"
  4971. // . "?sqlQuery=" . rawurlencode($showDetailsQuery) . "%20FROM%20" . $tableRefs . "%20";
  4972. //
  4973. // $links .= "WHERE%20serial%20RLIKE%20%22%5E%28" . $row["serial"]
  4974. // . "%29%24%22%20ORDER%20BY%20" . rawurlencode($orderBy)
  4975. // . "&amp;formType=sqlSearch"
  4976. // . "&amp;showQuery=" . $showQuery
  4977. // . "&amp;showLinks=" . $showLinks
  4978. // . "&amp;submit=Display"
  4979. // . "&amp;viewType=" . $viewType
  4980. // . "\"" . $target . ">"
  4981. // . "<img src=\"" . $baseURL . "img/details.gif\" alt=\"" . $loc["details"] . "\" title=\"" . $loc["LinkTitle_ShowDetails"] . "\" width=\"9\" height=\"17\" hspace=\"0\" border=\"0\"></a>";
  4982. }
  4983. if ((($linkElementCounterLoggedOut > 0) OR (isset($_SESSION['loginEmail']) AND $linkElementCounterLoggedIn > 0)) AND (in_array("details", $showLinkTypes) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_details_view/", $_SESSION['user_permissions'])))
  4984. $links .= "&nbsp;&nbsp;";
  4985. if (in_array("edit", $showLinkTypes) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_edit/", $_SESSION['user_permissions'])) // if the 'user_permissions' session variable contains 'allow_edit'...
  4986. // ... display a link that opens the edit form for this record:
  4987. $links .= "\n\t\t<a href=\"" . $baseURL . "record.php"
  4988. . "?serialNo=" . $row["serial"]
  4989. . "&amp;recordAction=edit"
  4990. . "\"" . $target . ">"
  4991. . "<img src=\"" . $baseURL . "img/edit.gif\" alt=\"" . $loc["edit"] . "\" title=\"" . $loc["LinkTitle_EditRecord"] . "\" width=\"11\" height=\"17\" hspace=\"0\" border=\"0\"></a>";
  4992. if ((($linkElementCounterLoggedOut > 1) OR (isset($_SESSION['loginEmail']) AND $linkElementCounterLoggedIn > 1)) AND (in_array("edit", $showLinkTypes) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_edit/", $_SESSION['user_permissions'])))
  4993. {
  4994. if (in_array("details", $showLinkTypes) AND isset($_SESSION['user_permissions']) AND preg_match("/allow_details_view/", $_SESSION['user_permissions']))
  4995. $links .= "\n\t\t<br>";
  4996. else
  4997. $links .= "&nbsp;&nbsp;";
  4998. }
  4999. // show a link to any corresponding file if one of the following conditions is met:
  5000. // - the variable '$fileVisibility' (defined in 'ini.inc.php') is set to 'everyone'
  5001. // - the variable '$fileVisibility' is set to 'login' AND the user is logged in
  5002. // - the variable '$fileVisibility' is set to 'user-specific' AND the 'user_permissions' session variable contains 'allow_download'
  5003. // - the array variable '$fileVisibilityException' (defined in 'ini.inc.php') contains a pattern (in array element 1) that matches the contents of the field given (in array element 0)
  5004. if (in_array("file", $showLinkTypes) 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']))) OR (!empty($fileVisibilityException) AND preg_match($fileVisibilityException[1], $row[$fileVisibilityException[0]]))))
  5005. {
  5006. if (!empty($row["file"]))// if the 'file' field is NOT empty
  5007. {
  5008. if (preg_match("#^(https?|ftp|file)://#i", $row["file"])) // if the 'file' field contains a full URL (starting with "http://", "https://", "ftp://" or "file://")
  5009. $URLprefix = ""; // we don't alter the URL given in the 'file' field
  5010. else // if the 'file' field contains only a partial path (like 'polarbiol/10240001.pdf') or just a file name (like '10240001.pdf')
  5011. {
  5012. // use the base URL of the standard files directory as prefix:
  5013. if (preg_match('#^/#', $filesBaseURL)) // absolute path -> file dir is located outside of refbase root dir
  5014. {
  5015. 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
  5016. $URLprefix = 'http://' . $_SERVER['HTTP_HOST'] . $filesBaseURL; // note that '$baseURL' cannot be used here since we need to prefix '$filesBaseURL' only with the host URL (and not the '$databaseBaseURL')
  5017. else
  5018. $URLprefix = $filesBaseURL;
  5019. }
  5020. else // relative path -> file dir is located within refbase root dir
  5021. $URLprefix = $baseURL . $filesBaseURL;
  5022. }
  5023. if (preg_match("/\.pdf$/i", $row["file"])) // if the 'file' field contains a link to a PDF file
  5024. $links .= "\n\t\t<a href=\"" . $URLprefix . encodeHTML($row["file"]) . "\"" . $target . "><img src=\"" . $baseURL . "img/file_PDF.gif\" alt=\"" . $loc["pdf"] . "\" title=\"" . $loc["LinkTitle_DownloadPDFFile"] . "\" width=\"17\" height=\"17\" hspace=\"0\" border=\"0\"></a>"; // display a PDF file icon as download link
  5025. else
  5026. $links .= "\n\t\t<a href=\"" . $URLprefix . encodeHTML($row["file"]) . "\"" . $target . "><img src=\"" . $baseURL . "img/file.gif\" alt=\"" . $loc["file"] . "\" title=\"" . $loc["LinkTitle_DownloadFile"] . "\" width=\"11\" height=\"15\" hspace=\"0\" border=\"0\"></a>"; // display a generic file icon as download link
  5027. }
  5028. }
  5029. // if a DOI number exists for this record, we'll prefer it as link, otherwise we use the URL (if available):
  5030. // (note, that in List view, we'll use the same icon, no matter if the DOI or the URL is used for the link)
  5031. if (in_array("doi", $showLinkTypes) AND !empty($row["doi"]))
  5032. $links .= "\n\t\t<a href=\"http://dx.doi.org/" . rawurlencode($row["doi"]) . "\"" . $target . "><img src=\"" . $baseURL . "img/link.gif\" alt=\"" . $loc["doi"] . "\" title=\"" . $loc["LinkTitle_GotoWebPageViaDOI"] . "\" width=\"11\" height=\"8\" hspace=\"0\" border=\"0\"></a>";
  5033. elseif (in_array("url", $showLinkTypes) AND !empty($row["url"])) // 'htmlentities()' is used to convert any '&' into '&amp;'
  5034. $links .= "\n\t\t<a href=\"" . encodeHTML($row["url"]) . "\"" . $target . "><img src=\"" . $baseURL . "img/link.gif\" alt=\"" . $loc["url"] . "\" title=\"" . $loc["LinkTitle_GotoWebPage"] . "\" width=\"11\" height=\"8\" hspace=\"0\" border=\"0\"></a>";
  5035. // if an ISBN number exists for the current record, provide a link to an ISBN resolver:
  5036. elseif (in_array("isbn", $showLinkTypes) AND !empty($isbnURLFormat) AND !empty($row["isbn"]))
  5037. {
  5038. // this is a stupid hack that maps the names of the '$row' array keys to those used
  5039. // by the '$formVars' array (which is required by function 'parsePlaceholderString()')
  5040. // (eventually, the '$formVars' array should use the MySQL field names as names for its array keys)
  5041. $formVars = buildFormVarsArray($row); // function 'buildFormVarsArray()' is defined in 'include.inc.php'
  5042. // auto-generate an ISBN link according to the naming scheme given in '$isbnURLFormat' (in 'ini.inc.php'):
  5043. $isbnURL = parsePlaceholderString($formVars, $isbnURLFormat, ""); // function 'parsePlaceholderString()' is defined in 'include.inc.php'
  5044. $encodedURL = encodeHTML($isbnURL); // 'htmlentities()' is used to convert higher ASCII chars into its entities and any '&' into '&amp;'
  5045. $encodedURL = str_replace(" ", "%20", $encodedURL); // ensure that any spaces are also properly urlencoded
  5046. if (!empty($isbnURL))
  5047. $links .= "\n\t\t<a href=\"" . $encodedURL . "\"" . $target . "><img src=\"" . $baseURL . "img/resolve.gif\" alt=\"" . $loc["isbn"] . "\" title=\"" . $loc["LinkTitle_FindBookDetailsViaISBN"] . "\" width=\"11\" height=\"8\" hspace=\"0\" border=\"0\"></a>";
  5048. }
  5049. // if still no link was generated, we'll provide a link to an OpenURL resolver:
  5050. elseif (in_array("xref", $showLinkTypes) AND !empty($openURLResolver))
  5051. {
  5052. $openURL = openURL($row); // function 'openURL()' is defined in 'openurl.inc.php'
  5053. $links .= "\n\t\t<a href=\"" . $openURL . "\"" . $target . "><img src=\"" . $baseURL . "img/resolve.gif\" alt=\"" . $loc["openurl"] . "\" title=\"" . $loc["LinkTitle_FindRecordDetailsViaOpenURL"] . "\" width=\"11\" height=\"8\" hspace=\"0\" border=\"0\"></a>";
  5054. }
  5055. // insert COinS (ContextObjects in Spans):
  5056. $links .= "\n\t\t" . coins($row); // function 'coins()' is defined in 'openurl.inc.php'
  5057. return $links;
  5058. }
  5059. // --------------------------------------------------------------------
  5060. // MERGE LINKS
  5061. // this function will merge links with delimiters appropriate for display in the Links column
  5062. function mergeLinks($linkArray)
  5063. {
  5064. $totalLinkCount = count($linkArray); // check how many links we're dealing with
  5065. $linkString = "";
  5066. if (!empty($linkArray)) // if some links are present
  5067. {
  5068. if ($totalLinkCount == 1) // only one link
  5069. {
  5070. $linkString = "&nbsp;&nbsp;" . $linkArray[0];
  5071. }
  5072. else // multiple links
  5073. {
  5074. for ($linkCounter=0; $linkCounter < ($totalLinkCount - 1); $linkCounter++) // first array element has offset '0' so we decrement '$totalLinkCount' by 1
  5075. {
  5076. if (is_integer(($linkCounter + 1)/2)) // even number
  5077. $suffix = "<br>"; // a set of two links is printed per row
  5078. else // uneven number
  5079. $suffix = "&nbsp;";
  5080. $linkString .= $linkArray[$linkCounter] . $suffix;
  5081. }
  5082. $linkString .= $linkArray[($totalLinkCount - 1)]; // append last link
  5083. }
  5084. }
  5085. return $linkString;
  5086. }
  5087. // --------------------------------------------------------------------
  5088. // DISPLAY THE HTML FOOTER:
  5089. // call the 'showPageFooter()' and 'displayHTMLfoot()' functions (which are defined in 'footer.inc.php')
  5090. if (!preg_match("/^cli/i", $client) AND ($wrapResults != "0") AND (!(($displayType == "Cite") AND (!preg_match("/^html$/i", $citeType))) OR ($rowsFound == 0))) // we exclude the HTML page footer for citation formats other than HTML if something was found
  5091. {
  5092. if ((!preg_match("/^(Print|Mobile)$/i", $viewType)) AND (!preg_match("/^inc/i", $client))) // Note: we omit the visible footer in print/mobile view ('viewType=Print' or 'viewType=Mobile') and for include mechanisms!
  5093. showPageFooter($HeaderString);
  5094. displayHTMLfoot();
  5095. }
  5096. // --------------------------------------------------------------------
  5097. ?>