One Hat Cyber Team
Your IP :
216.73.216.182
Server IP :
203.175.9.166
Server :
Linux tanggamus.iixcp.rumahweb.net 5.14.0-427.28.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Aug 2 03:44:10 EDT 2024 x86_64
Server Software :
LiteSpeed
PHP Version :
7.4.33
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
home
/
cite5577
/
www
/
lib
/
pkp
/
classes
/
oai
/
View File Name :
OAI.inc.php
<?php /** * @defgroup oai OAI * Implements an OAI (Open Archives Initiative) OAI-PMH interface. See * http://www.openarchives.org for information on OAI-PMH. */ /** * @file classes/oai/OAI.inc.php * * Copyright (c) 2014-2021 Simon Fraser University * Copyright (c) 2000-2021 John Willinsky * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING. * * @class OAI * @ingroup oai * @see OAIDAO * * @brief Class to process and respond to OAI requests. */ import('lib.pkp.classes.oai.OAIStruct'); import('lib.pkp.classes.oai.OAIUtils'); abstract class OAI { /** @var OAIConfig configuration parameters */ var $config; /** @var array list of request parameters */ var $params; /** @var string version of the OAI protocol supported by this class */ var $protocolVersion = '2.0'; /** * Constructor. * Initializes object and parses user input. * @param $config OAIConfig repository configuration */ function __construct($config) { $this->config = $config; // Initialize parameters from GET or POST variables $this->params = array(); if (isset($GLOBALS['HTTP_RAW_POST_DATA']) && !empty($GLOBALS['HTTP_RAW_POST_DATA'])) { OAIUtils::parseStr($GLOBALS['HTTP_RAW_POST_DATA'], $this->params); } else if (!empty($_SERVER['QUERY_STRING'])) { OAIUtils::parseStr($_SERVER['QUERY_STRING'], $this->params); } else { $this->params = array_merge($_GET, $_POST); } // Clean input variables OAIUtils::prepInput($this->params); // Encode data with gzip, deflate, or none, depending on browser support ob_start('ob_gzhandler'); } /** * Execute the requested OAI protocol request * and output the response. */ function execute() { switch ($this->getParam('verb')) { case 'GetRecord': $this->GetRecord(); break; case 'Identify': $this->Identify(); break; case 'ListIdentifiers': $this->ListIdentifiers(); break; case 'ListMetadataFormats': $this->ListMetadataFormats(); break; case 'ListRecords': $this->ListRecords(); break; case 'ListSets': $this->ListSets(); break; default: $this->error('badVerb', 'Illegal OAI verb'); break; } } // // Abstract implementation-specific functions // (to be overridden in subclass) // /** * Return information about the repository. * @return OAIRepository */ abstract function repositoryInfo(); /** * Check if identifier is in the valid format. * @param $identifier string * @return boolean */ function validIdentifier($identifier) { return false; } /** * Check if identifier exists. * @param $identifier string * @return boolean */ function identifierExists($identifier) { return false; } /** * Return OAI record for specified identifier. * @param $identifier string * @return OAIRecord (or false, if identifier is invalid) */ abstract function record($identifier); /** * Return set of OAI records. * @param $metadataPrefix string specified metadata prefix * @param $from int minimum timestamp * @param $until int maximum timestamp * @param $set string specified set * @param $offset int current record offset * @param $limit int maximum number of records to return * @param $total int output parameter, set to total number of records * @return array OAIRecord */ function records($metadataPrefix, $from, $until, $set, $offset, $limit, &$total) { return array(); } /** * Return set of OAI identifiers. * @see getRecords * @return array OAIIdentifier */ function identifiers($metadataPrefix, $from, $until, $set, $offset, $limit, &$total) { return array(); } /** * Return set of OAI sets. * @param $offset int current set offset * @param $limit int Maximum number of sets to return * @param $total int output parameter, set to total number of sets */ function sets($offset, $limit, &$total) { return array(); } /** * Retrieve a resumption token. * @param $tokenId string * @return OAIResumptionToken|false */ abstract function resumptionToken($tokenId); /** * Save a resumption token. * @param $offset int current offset * @param $params array request parameters * @return OAIResumptionToken the saved token */ abstract function saveResumptionToken($offset, $params); /** * Return array of supported metadata formats. * @param $namesOnly boolean return array of format prefix names only * @param $identifier string return formats for specific identifier * @return array */ function metadataFormats($namesOnly = false, $identifier = null) { $formats = array(); HookRegistry::call('OAI::metadataFormats', array($namesOnly, $identifier, &$formats)); return $formats; } // // Protocol request handlers // /** * Handle OAI GetRecord request. * Retrieves an individual record from the repository. */ function GetRecord() { // Validate parameters if (!$this->checkParams(array('identifier', 'metadataPrefix'))) { return; } $identifier = $this->getParam('identifier'); $metadataPrefix = $this->getParam('metadataPrefix'); // Check that identifier is in valid format if ($this->validIdentifier($identifier) === false) { $this->error('badArgument', 'Identifier is not in a valid format'); return; } // Get metadata for requested identifier if (($record = $this->record($identifier)) === false) { $this->error('idDoesNotExist', 'No matching identifier in this repository'); return; } // Check that the requested metadata format is supported for this identifier if (!in_array($metadataPrefix, $this->metadataFormats(true, $identifier))) { $this->error('cannotDisseminateFormat', 'The requested metadataPrefix is not supported by this repository'); return; } // Display response $response = "\t<GetRecord>\n" . "\t\t<record>\n" . "\t\t\t<header" .(($record->status == OAIRECORD_STATUS_DELETED)?" status=\"deleted\">\n":">\n") . "\t\t\t\t<identifier>" . $record->identifier ."</identifier>\n" . "\t\t\t\t<datestamp>" . $record->datestamp . "</datestamp>\n"; // Output set memberships foreach ($record->sets as $setSpec) { $response .= "\t\t\t\t<setSpec>$setSpec</setSpec>\n"; } $response .= "\t\t\t</header>\n"; if (!empty($record->data)) { $response .= "\t\t\t<metadata>\n"; // Output metadata $response .= $this->formatMetadata($metadataPrefix, $record); $response .= "\t\t\t</metadata>\n"; } $response .= "\t\t</record>\n" . "\t</GetRecord>\n"; $this->response($response); } /** * Handle OAI Identify request. * Retrieves information about a repository. */ function Identify() { // Validate parameters if (!$this->checkParams()) { return; } $info = $this->repositoryInfo(); // Format body of response $response = "\t<Identify>\n" . "\t\t<repositoryName>" . OAIUtils::prepOutput($info->repositoryName) . "</repositoryName>\n" . "\t\t<baseURL>" . $this->config->baseUrl . "</baseURL>\n" . "\t\t<protocolVersion>" . $this->protocolVersion . "</protocolVersion>\n" . "\t\t<adminEmail>" . $info->adminEmail . "</adminEmail>\n" . "\t\t<earliestDatestamp>" . OAIUtils::UTCDate($info->earliestDatestamp) . "</earliestDatestamp>\n" . "\t\t<deletedRecord>persistent</deletedRecord>\n" . "\t\t<granularity>" . $this->config->granularity . "</granularity>\n"; if (extension_loaded('zlib')) { // Show compression options if server supports Zlib $response .= "\t\t<compression>gzip</compression>\n" . "\t\t<compression>deflate</compression>\n"; } $response .= "\t\t<description>\n" . "\t\t\t<oai-identifier\n" . "\t\t\t\txmlns=\"http://www.openarchives.org/OAI/2.0/oai-identifier\"\n" . "\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" . "\t\t\t\txsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/oai-identifier\n" . "\t\t\t\t\thttp://www.openarchives.org/OAI/2.0/oai-identifier.xsd\">\n" . "\t\t\t\t<scheme>oai</scheme>\n" . "\t\t\t\t<repositoryIdentifier>" . $this->config->repositoryId . "</repositoryIdentifier>\n" . "\t\t\t\t<delimiter>" . $info->delimiter . "</delimiter>\n" . "\t\t\t\t<sampleIdentifier>" . $info->sampleIdentifier . "</sampleIdentifier>\n" . "\t\t\t</oai-identifier>\n" . "\t\t</description>\n"; $response .= "\t\t<description>\n" . "\t\t\t<toolkit\n" . "\t\t\t\txmlns=\"http://oai.dlib.vt.edu/OAI/metadata/toolkit\"\n" . "\t\t\t\txsi:schemaLocation=\"http://oai.dlib.vt.edu/OAI/metadata/toolkit\n" . "\t\t\t\t\thttp://oai.dlib.vt.edu/OAI/metadata/toolkit.xsd\">\n" . "\t\t\t\t<title>" . $info->toolkitTitle . "</title>\n" . "\t\t\t\t<author>\n" . "\t\t\t\t\t<name>Public Knowledge Project</name>\n" . "\t\t\t\t\t<email>pkp.contact@gmail.com</email>\n" . "\t\t\t\t</author>\n" . "\t\t\t\t<version>" . $info->toolkitVersion . "</version>\n" . "\t\t\t\t<URL>" . $info->toolkitURL . "</URL>\n" . "\t\t\t</toolkit>\n" . "\t\t</description>\n"; $response .= "\t</Identify>\n"; $this->response($response); } /** * Handle OAI ListIdentifiers request. * Retrieves headers of records from the repository. */ function ListIdentifiers() { $offset = 0; // Check for resumption token if ($this->paramExists('resumptionToken')) { // Validate parameters if (!$this->checkParams(array('resumptionToken'))) { return; } // Get parameters from resumption token if (($token = $this->resumptionToken($this->getParam('resumptionToken'))) === false) { $this->error('badResumptionToken', 'The requested resumptionToken is invalid or has expired'); return; } $this->setParams($token->params); $offset = $token->offset; } // Validate parameters if (!$this->checkParams(array('metadataPrefix'), array('from', 'until', 'set'))) { return; } $metadataPrefix = $this->getParam('metadataPrefix'); $set = $this->getParam('set'); // Check that the requested metadata format is supported if (!in_array($metadataPrefix, $this->metadataFormats(true))) { $this->error('cannotDisseminateFormat', 'The requested metadataPrefix is not supported by this repository'); return; } // If a set was passed in check if repository supports sets if (isset($set) && $this->config->maxSets == 0) { $this->error('noSetHierarchy', 'This repository does not support sets'); return; } // Get UNIX timestamps for from and until dates, if applicable if (!$this->extractDateParams($this->getParams(), $from, $until)) { return; } // Store current offset and total records for resumption token, if needed $cursor = $offset; $total = 0; // Get list of matching identifiers $records = $this->identifiers($metadataPrefix, $from, $until, $set, $offset, $this->config->maxIdentifiers, $total); if (empty($records)) { $this->error('noRecordsMatch', 'No matching records in this repository'); return; } // Format body of response $response = "\t<ListIdentifiers>\n"; // Output identifiers for ($i = 0, $num = count($records); $i < $num; $i++) { $record = $records[$i]; $response .= "\t\t<header" .(($record->status == OAIRECORD_STATUS_DELETED)?" status=\"deleted\">\n":">\n") . "\t\t\t<identifier>" . $record->identifier . "</identifier>\n" . "\t\t\t<datestamp>" . $record->datestamp . "</datestamp>\n"; // Output set memberships foreach ($record->sets as $setSpec) { $response .= "\t\t\t<setSpec>" . OAIUtils::prepOutput($setSpec) . "</setSpec>\n"; } $response .= "\t\t</header>\n"; } $offset += $num; if ($offset != 0 && $offset < $total) { // Partial result, save resumption token $token = $this->saveResumptionToken($offset, $this->getParams()); $response .= "\t\t<resumptionToken expirationDate=\"" . OAIUtils::UTCDate($token->expire) . "\"\n" . "\t\t\tcompleteListSize=\"$total\"\n" . "\t\t\tcursor=\"$cursor\">" . $token->id . "</resumptionToken>\n"; } else if (isset($token)) { // Current request completes a previous incomplete list, add empty resumption token $response .= "\t\t<resumptionToken completeListSize=\"$total\" cursor=\"$cursor\" />\n"; } $response .= "\t</ListIdentifiers>\n"; $this->response($response); } /** * Handle OAI ListMetadataFormats request. * Retrieves metadata formats supported by the repository. */ function ListMetadataFormats() { // Validate parameters if (!$this->checkParams(array(), array('identifier'))) { return; } // Get list of metadata formats for selected identifier, or all formats if no identifier was passed if ($this->paramExists('identifier')) { if (!$this->identifierExists($this->getParam('identifier'))) { $this->error('idDoesNotExist', 'No matching identifier in this repository'); return; } else { $formats = $this->metadataFormats(false, $this->getParam('identifier')); } } else { $formats = $this->metadataFormats(); } if (empty($formats) || !is_array($formats)) { $this->error('noMetadataFormats', 'No metadata formats are available'); return; } // Format body of response $response = "\t<ListMetadataFormats>\n"; // output metadata formats foreach ($formats as $format) { $response .= "\t\t<metadataFormat>\n" . "\t\t\t<metadataPrefix>" . $format->prefix . "</metadataPrefix>\n" . "\t\t\t<schema>" . $format->schema . "</schema>\n" . "\t\t\t<metadataNamespace>" . $format->namespace . "</metadataNamespace>\n" . "\t\t</metadataFormat>\n"; } $response .= "\t</ListMetadataFormats>\n"; $this->response($response); } /** * Handle OAI ListRecords request. * Retrieves records from the repository. */ function ListRecords() { $offset = 0; // Check for resumption token if ($this->paramExists('resumptionToken')) { // Validate parameters if (!$this->checkParams(array('resumptionToken'))) { return; } // get parameters from resumption token if (($token = $this->resumptionToken($this->getParam('resumptionToken'))) === false) { $this->error('badResumptionToken', 'The requested resumptionToken is invalid or has expired'); return; } $this->setParams($token->params); $offset = $token->offset; } // Validate parameters if (!$this->checkParams(array('metadataPrefix'), array('from', 'until', 'set'))) { return; } $metadataPrefix = $this->getParam('metadataPrefix'); $set = $this->getParam('set'); // Check that the requested metadata format is supported if (!in_array($metadataPrefix, $this->metadataFormats(true))) { $this->error('cannotDisseminateFormat', 'The requested metadataPrefix is not supported by this repository'); return; } // If a set was passed check if repository supports sets if (isset($set) && $this->config->maxSets == 0) { $this->error('noSetHierarchy', 'This repository does not support sets'); return; } // Get UNIX timestamps for from and until dates, if applicable if (!$this->extractDateParams($this->getParams(), $from, $until)) { return; } // Store current offset and total records for resumption token, if needed $cursor = $offset; $total = 0; // Get list of matching records $records = $this->records($metadataPrefix, $from, $until, $set, $offset, $this->config->maxRecords, $total); if (empty($records)) { $this->error('noRecordsMatch', 'No matching records in this repository'); return; } // Format body of response $response = "\t<ListRecords>\n"; // Output records for ($i = 0, $num = count($records); $i < $num; $i++) { $record = $records[$i]; $response .= "\t\t<record>\n" . "\t\t\t<header" .(($record->status == OAIRECORD_STATUS_DELETED)?" status=\"deleted\">\n":">\n") . "\t\t\t\t<identifier>" . $record->identifier . "</identifier>\n" . "\t\t\t\t<datestamp>" . $record->datestamp . "</datestamp>\n"; // Output set memberships foreach ($record->sets as $setSpec) { $response .= "\t\t\t\t<setSpec>" . OAIUtils::prepOutput($setSpec) . "</setSpec>\n"; } $response .= "\t\t\t</header>\n"; if (!empty($record->data)) { $response .= "\t\t\t<metadata>\n"; // Output metadata $response .= $this->formatMetadata($this->getParam('metadataPrefix'), $record); $response .= "\t\t\t</metadata>\n"; } $response .= "\t\t</record>\n"; } $offset += $num; if ($offset != 0 && $offset < $total) { // Partial result, save resumption token $token = $this->saveResumptionToken($offset, $this->getParams()); $response .= "\t\t<resumptionToken expirationDate=\"" . OAIUtils::UTCDate($token->expire) . "\"\n" . "\t\t\tcompleteListSize=\"$total\"\n" . "\t\t\tcursor=\"$cursor\">" . $token->id . "</resumptionToken>\n"; } else if(isset($token)) { // Current request completes a previous incomplete list, add empty resumption token $response .= "\t\t<resumptionToken completeListSize=\"$total\" cursor=\"$cursor\" />\n"; } $response .= "\t</ListRecords>\n"; $this->response($response); } /** * Handle OAI ListSets request. * Retrieves sets from a repository. */ function ListSets() { $offset = 0; // Check for resumption token if ($this->paramExists('resumptionToken')) { // Validate parameters if (!$this->checkParams(array('resumptionToken'))) { return; } // Get parameters from resumption token if (($token = $this->resumptionToken($this->getParam('resumptionToken'))) === false) { $this->error('badResumptionToken', 'The requested resumptionToken is invalid or has expired'); return; } $this->setParams($token->params); $offset = $token->offset; } // Validate parameters if (!$this->checkParams()) { return; } // Store current offset and total sets for resumption token, if needed $cursor = $offset; $total = 0; // Get list of matching sets $sets = $this->sets($offset, $this->config->maxRecords, $total); if (empty($sets)) { $this->error('noSetHierarchy', 'This repository does not support sets'); return; } // Format body of response $response = "\t<ListSets>\n"; // Output sets for ($i = 0, $num = count($sets); $i < $num; $i++) { $set = $sets[$i]; $response .= "\t\t<set>\n" . "\t\t\t<setSpec>" . OAIUtils::prepOutput($set->spec) . "</setSpec>\n" . "\t\t\t<setName>" . OAIUtils::prepOutput($set->name) . "</setName>\n"; // output set description, if applicable if (isset($set->description)) { $response .= "\t\t\t<setDescription>\n" . "\t\t\t\t<oai_dc:dc\n" . "\t\t\t\t\txmlns:oai_dc=\"http://www.openarchives.org/OAI/2.0/oai_dc/\"\n" . "\t\t\t\t\txmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" . "\t\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" . "\t\t\t\t\txsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/oai_dc/\n" . "\t\t\t\t\t\thttp://www.openarchives.org/OAI/2.0/oai_dc.xsd\">\n" . "\t\t\t\t\t<dc:description>" . OAIUtils::prepOutput($set->description) . "</dc:description>\n" . "\t\t\t\t</oai_dc:dc>\n" . "\t\t\t</setDescription>\n"; } $response .= "\t\t</set>\n"; } $offset += $num; if ($offset != 0 && $offset < $total) { // Partial result, set resumption token $token = $this->saveResumptionToken($offset, $this->getParams()); $response .= "\t\t<resumptionToken expirationDate=\"" . OAIUtils::UTCDate($token->expire) . "\"\n" . "\t\t\tcompleteListSize=\"$total\"\n" . "\t\t\tcursor=\"$cursor\">" . $token->id . "</resumptionToken>\n"; } else if (isset($token)) { // current request completes a previous incomplete list, add empty resumption token $response .= "\t\t<resumptionToken completeListSize=\"$total\" cursor=\"$cursor\" />\n"; } $response .= "\t</ListSets>\n"; $this->response($response); } // // Private helper functions // /** * Display OAI error response. */ function error($code, $message) { if (in_array($code, array('badVerb', 'badArgument'))) { $printParams = false; } else { $printParams = true; } $this->response("\t<error code=\"$code\">$message</error>", $printParams); } /** * Output OAI response. * @param $response string text of response message. * @param $printParams boolean display request parameters */ function response($response, $printParams = true) { $request = Application::get()->getRequest(); header('Content-Type: text/xml'); echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" . "<?xml-stylesheet type=\"text/xsl\" href=\"" . $request->getBaseUrl() . "/lib/pkp/xml/oai2.xsl\" ?>\n" . "<OAI-PMH xmlns=\"http://www.openarchives.org/OAI/2.0/\"\n" . "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" . "\txsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/\n" . "\t\thttp://www.openarchives.org/OAI/2.0/OAI-PMH.xsd\">\n" . "\t<responseDate>" . OAIUtils::UTCDate() . "</responseDate>\n" . "\t<request"; // print request params, if applicable if($printParams) { foreach($this->params as $k => $v) { echo " $k=\"" . OAIUtils::prepOutput($v) . "\""; } } echo ">" . OAIUtils::prepOutput($this->config->baseUrl) . "</request>\n" . $response . "</OAI-PMH>\n"; } /** * Returns the value of the specified parameter. * @param $name string * @return string */ function getParam($name) { return isset($this->params[$name]) ? $this->params[$name] : null; } /** * Returns an associative array of all request parameters. * @return array */ function getParams() { return $this->params; } /** * Set the request parameters. * @param $params array */ function setParams($params) { $this->params = $params; } /** * Returns true if the requested parameter is set, false if it is not set. * @param $name string * @return boolean */ function paramExists($name) { return isset($this->params[$name]); } /** * Return a list of ignorable GET parameters. * @return array */ function getNonPathInfoParams() { return array(); } /** * Check request parameters. * Outputs error response if an invalid parameter is found. * @param $required array required parameters for the current request * @param $optional array optional parameters for the current request * @return boolean */ function checkParams($required = array(), $optional = array()) { // Get allowed parameters for current request $requiredParams = array_merge(array('verb'), $required); $validParams = array_merge($requiredParams, $optional); // Check for missing or duplicate required parameters foreach ($requiredParams as $k) { if(!$this->paramExists($k)) { $this->error('badArgument', "Missing $k parameter"); return false; } else if (is_array($this->getParam($k))) { $this->error('badArgument', "Multiple values are not allowed for the $k parameter"); return false; } } // Check for duplicate optional parameters foreach ($optional as $k) { if ($this->paramExists($k) && is_array($this->getParam($k))) { $this->error('badArgument', "Multiple values are not allowed for the $k parameter"); return false; } } // Check for illegal parameters $request = Application::get()->getRequest(); foreach ($this->params as $k => $v) { if (!in_array($k, $validParams)) { // Ignore the "path" and "context" parameters if path_info is disabled. if ($request->isPathInfoEnabled() || !in_array($k, $this->getNonPathInfoParams())) { $this->error('badArgument', "$k is an illegal parameter"); return false; } } } return true; } /** * Returns formatted metadata response in specified format. * @param $format string * @param $metadata OAIMetadata * @return string */ function formatMetadata($format, $record) { $formats = $this->metadataFormats(); $metadata = $formats[$format]->toXml($record); return $metadata; } /** * Checks if from and until parameters have been passed. * If passed, validate and convert to UNIX timestamps. * @param $params array request parameters * @param $from int from timestamp (output parameter) * @param $until int until timestamp (output parameter) * @return boolean */ function extractDateParams($params, &$from, &$until) { if (isset($params['from'])) { $from = OAIUtils::UTCtoTimestamp($params['from'], $this->config->granularity); if ($from == 'invalid') { $this->error('badArgument', 'Illegal from parameter'); return false; } else if($from == 'invalid_granularity') { $this->error('badArgument', 'Illegal granularity for from parameter'); return false; } } if(isset($params['until'])) { $until = OAIUtils::UTCtoTimestamp($params['until'], $this->config->granularity); if($until == 'invalid') { $this->error('badArgument', 'Illegal until parameter'); return false; } else if($until == 'invalid_granularity') { $this->error('badArgument', 'Illegal granularity for until parameter'); return false; } // Check that until value is greater than or equal to from value if (isset($from) && $from > $until) { $this->error('badArgument', 'until parameter must be greater than or equal to from parameter'); return false; } // Check that granularities are equal if (isset($from) && strlen($params['from']) != strlen($params['until'])) { $this->error('badArgument', 'until and from parameters must be of the same granularity'); return false; } if (strlen($params['until']) == 10) { // Until date is inclusive $until += 86399; } } return true; } }