24 import(
'lib.pkp.classes.oai.OAIStruct');
25 import(
'lib.pkp.classes.oai.OAIUtils');
47 $this->params = array();
49 if (isset(
$GLOBALS[
'HTTP_RAW_POST_DATA']) && !empty(
$GLOBALS[
'HTTP_RAW_POST_DATA'])) {
52 }
else if (!empty($_SERVER[
'QUERY_STRING'])) {
56 $this->params = array_merge($_GET, $_POST);
63 ob_start(
'ob_gzhandler');
78 case 'ListIdentifiers':
81 case 'ListMetadataFormats':
91 $this->
error(
'badVerb',
'Illegal OAI verb');
144 function records($metadataPrefix, $from, $until, $set, $offset, $limit, &$total) {
153 function identifiers($metadataPrefix, $from, $until, $set, $offset, $limit, &$total) {
163 function sets($offset, $limit, &$total) {
190 HookRegistry::call(
'OAI::metadataFormats', array($namesOnly, $identifier, &$formats));
205 if (!$this->
checkParams(array(
'identifier',
'metadataPrefix'))) {
209 $identifier = $this->
getParam(
'identifier');
210 $metadataPrefix = $this->
getParam(
'metadataPrefix');
214 $this->
error(
'badArgument',
'Identifier is not in a valid format');
219 if (($record = $this->
record($identifier)) ===
false) {
220 $this->
error(
'idDoesNotExist',
'No matching identifier in this repository');
225 if (!in_array($metadataPrefix, $this->
metadataFormats(
true, $identifier))) {
226 $this->
error(
'cannotDisseminateFormat',
'The requested metadataPrefix is not supported by this repository');
231 $response =
"\t<GetRecord>\n" .
233 "\t\t\t<header" .(($record->status == OAIRECORD_STATUS_DELETED)?
" status=\"deleted\">\n":
">\n") .
234 "\t\t\t\t<identifier>" . $record->identifier .
"</identifier>\n" .
235 "\t\t\t\t<datestamp>" . $record->datestamp .
"</datestamp>\n";
237 foreach ($record->sets as $setSpec) {
238 $response .=
"\t\t\t\t<setSpec>$setSpec</setSpec>\n";
240 $response .=
"\t\t\t</header>\n";
241 if (!empty($record->data)) {
242 $response .=
"\t\t\t<metadata>\n";
245 $response .=
"\t\t\t</metadata>\n";
247 $response .=
"\t\t</record>\n" .
267 $response =
"\t<Identify>\n" .
269 "\t\t<baseURL>" . $this->config->baseUrl .
"</baseURL>\n" .
270 "\t\t<protocolVersion>" . $this->protocolVersion .
"</protocolVersion>\n" .
271 "\t\t<adminEmail>" . $info->adminEmail .
"</adminEmail>\n" .
272 "\t\t<earliestDatestamp>" .
OAIUtils::UTCDate($info->earliestDatestamp) .
"</earliestDatestamp>\n" .
273 "\t\t<deletedRecord>persistent</deletedRecord>\n" .
274 "\t\t<granularity>" . $this->config->granularity .
"</granularity>\n";
275 if (extension_loaded(
'zlib')) {
277 $response .=
"\t\t<compression>gzip</compression>\n" .
278 "\t\t<compression>deflate</compression>\n";
280 $response .=
"\t\t<description>\n" .
281 "\t\t\t<oai-identifier\n" .
282 "\t\t\t\txmlns=\"http://www.openarchives.org/OAI/2.0/oai-identifier\"\n" .
283 "\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" .
284 "\t\t\t\txsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/oai-identifier\n" .
285 "\t\t\t\t\thttp://www.openarchives.org/OAI/2.0/oai-identifier.xsd\">\n" .
286 "\t\t\t\t<scheme>oai</scheme>\n" .
287 "\t\t\t\t<repositoryIdentifier>" . $this->config->repositoryId .
"</repositoryIdentifier>\n" .
288 "\t\t\t\t<delimiter>" . $info->delimiter .
"</delimiter>\n" .
289 "\t\t\t\t<sampleIdentifier>" . $info->sampleIdentifier .
"</sampleIdentifier>\n" .
290 "\t\t\t</oai-identifier>\n" .
291 "\t\t</description>\n";
292 $response .=
"\t\t<description>\n" .
294 "\t\t\t\txmlns=\"http://oai.dlib.vt.edu/OAI/metadata/toolkit\"\n" .
295 "\t\t\t\txsi:schemaLocation=\"http://oai.dlib.vt.edu/OAI/metadata/toolkit\n" .
296 "\t\t\t\t\thttp://oai.dlib.vt.edu/OAI/metadata/toolkit.xsd\">\n" .
297 "\t\t\t\t<title>" . $info->toolkitTitle .
"</title>\n" .
298 "\t\t\t\t<author>\n" .
299 "\t\t\t\t\t<name>Public Knowledge Project</name>\n" .
300 "\t\t\t\t\t<email>pkp.contact@gmail.com</email>\n" .
301 "\t\t\t\t</author>\n" .
302 "\t\t\t\t<version>" . $info->toolkitVersion .
"</version>\n" .
303 "\t\t\t\t<URL>" . $info->toolkitURL .
"</URL>\n" .
304 "\t\t\t</toolkit>\n" .
305 "\t\t</description>\n";
306 $response .=
"\t</Identify>\n";
321 if (!$this->
checkParams(array(
'resumptionToken'))) {
327 $this->
error(
'badResumptionToken',
'The requested resumptionToken is invalid or has expired');
332 $offset = $token->offset;
336 if (!$this->
checkParams(array(
'metadataPrefix'), array(
'from',
'until',
'set'))) {
340 $metadataPrefix = $this->
getParam(
'metadataPrefix');
345 $this->
error(
'cannotDisseminateFormat',
'The requested metadataPrefix is not supported by this repository');
350 if (isset($set) && $this->config->maxSets == 0) {
351 $this->
error(
'noSetHierarchy',
'This repository does not support sets');
365 $records = $this->
identifiers($metadataPrefix, $from, $until, $set, $offset, $this->config->maxIdentifiers, $total);
366 if (empty($records)) {
367 $this->
error(
'noRecordsMatch',
'No matching records in this repository');
372 $response =
"\t<ListIdentifiers>\n";
375 for ($i = 0, $num =
count($records); $i < $num; $i++) {
376 $record = $records[$i];
377 $response .=
"\t\t<header" .(($record->status == OAIRECORD_STATUS_DELETED)?
" status=\"deleted\">\n":
">\n") .
378 "\t\t\t<identifier>" . $record->identifier .
"</identifier>\n" .
379 "\t\t\t<datestamp>" . $record->datestamp .
"</datestamp>\n";
381 foreach ($record->sets as $setSpec) {
384 $response .=
"\t\t</header>\n";
388 if ($offset != 0 && $offset < $total) {
392 $response .=
"\t\t<resumptionToken expirationDate=\"" .
OAIUtils::UTCDate($token->expire) .
"\"\n" .
393 "\t\t\tcompleteListSize=\"$total\"\n" .
394 "\t\t\tcursor=\"$cursor\">" . $token->id .
"</resumptionToken>\n";
396 }
else if (isset($token)) {
398 $response .=
"\t\t<resumptionToken completeListSize=\"$total\" cursor=\"$cursor\" />\n";
401 $response .=
"\t</ListIdentifiers>\n";
412 if (!$this->
checkParams(array(), array(
'identifier'))) {
419 $this->
error(
'idDoesNotExist',
'No matching identifier in this repository');
430 if (empty($formats) || !is_array($formats)) {
431 $this->
error(
'noMetadataFormats',
'No metadata formats are available');
436 $response =
"\t<ListMetadataFormats>\n";
439 foreach ($formats as $format) {
440 $response .=
"\t\t<metadataFormat>\n" .
441 "\t\t\t<metadataPrefix>" . $format->prefix .
"</metadataPrefix>\n" .
442 "\t\t\t<schema>" . $format->schema .
"</schema>\n" .
443 "\t\t\t<metadataNamespace>" . $format->namespace .
"</metadataNamespace>\n" .
444 "\t\t</metadataFormat>\n";
447 $response .=
"\t</ListMetadataFormats>\n";
462 if (!$this->
checkParams(array(
'resumptionToken'))) {
468 $this->
error(
'badResumptionToken',
'The requested resumptionToken is invalid or has expired');
473 $offset = $token->offset;
478 if (!$this->
checkParams(array(
'metadataPrefix'), array(
'from',
'until',
'set'))) {
482 $metadataPrefix = $this->
getParam(
'metadataPrefix');
487 $this->
error(
'cannotDisseminateFormat',
'The requested metadataPrefix is not supported by this repository');
492 if (isset($set) && $this->config->maxSets == 0) {
493 $this->
error(
'noSetHierarchy',
'This repository does not support sets');
507 $records = $this->
records($metadataPrefix, $from, $until, $set, $offset, $this->config->maxRecords, $total);
508 if (empty($records)) {
509 $this->
error(
'noRecordsMatch',
'No matching records in this repository');
514 $response =
"\t<ListRecords>\n";
517 for ($i = 0, $num =
count($records); $i < $num; $i++) {
518 $record = $records[$i];
519 $response .=
"\t\t<record>\n" .
520 "\t\t\t<header" .(($record->status == OAIRECORD_STATUS_DELETED)?
" status=\"deleted\">\n":
">\n") .
521 "\t\t\t\t<identifier>" . $record->identifier .
"</identifier>\n" .
522 "\t\t\t\t<datestamp>" . $record->datestamp .
"</datestamp>\n";
524 foreach ($record->sets as $setSpec) {
527 $response .=
"\t\t\t</header>\n";
528 if (!empty($record->data)) {
529 $response .=
"\t\t\t<metadata>\n";
532 $response .=
"\t\t\t</metadata>\n";
534 $response .=
"\t\t</record>\n";
538 if ($offset != 0 && $offset < $total) {
542 $response .=
"\t\t<resumptionToken expirationDate=\"" .
OAIUtils::UTCDate($token->expire) .
"\"\n" .
543 "\t\t\tcompleteListSize=\"$total\"\n" .
544 "\t\t\tcursor=\"$cursor\">" . $token->id .
"</resumptionToken>\n";
546 }
else if(isset($token)) {
548 $response .=
"\t\t<resumptionToken completeListSize=\"$total\" cursor=\"$cursor\" />\n";
551 $response .=
"\t</ListRecords>\n";
566 if (!$this->
checkParams(array(
'resumptionToken'))) {
572 $this->
error(
'badResumptionToken',
'The requested resumptionToken is invalid or has expired');
577 $offset = $token->offset;
591 $sets = $this->
sets($offset, $this->config->maxRecords, $total);
593 $this->
error(
'noSetHierarchy',
'This repository does not support sets');
598 $response =
"\t<ListSets>\n";
601 for ($i = 0, $num =
count($sets); $i < $num; $i++) {
603 $response .=
"\t\t<set>\n" .
607 if (isset($set->description)) {
608 $response .=
"\t\t\t<setDescription>\n" .
609 "\t\t\t\t<oai_dc:dc\n" .
610 "\t\t\t\t\txmlns:oai_dc=\"http://www.openarchives.org/OAI/2.0/oai_dc/\"\n" .
611 "\t\t\t\t\txmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" .
612 "\t\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" .
613 "\t\t\t\t\txsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/oai_dc/\n" .
614 "\t\t\t\t\t\thttp://www.openarchives.org/OAI/2.0/oai_dc.xsd\">\n" .
615 "\t\t\t\t\t<dc:description>" .
OAIUtils::prepOutput($set->description) .
"</dc:description>\n" .
616 "\t\t\t\t</oai_dc:dc>\n" .
617 "\t\t\t</setDescription>\n";
620 $response .=
"\t\t</set>\n";
624 if ($offset != 0 && $offset < $total) {
628 $response .=
"\t\t<resumptionToken expirationDate=\"" .
OAIUtils::UTCDate($token->expire) .
"\"\n" .
629 "\t\t\tcompleteListSize=\"$total\"\n" .
630 "\t\t\tcursor=\"$cursor\">" . $token->id .
"</resumptionToken>\n";
632 }
else if (isset($token)) {
634 $response .=
"\t\t<resumptionToken completeListSize=\"$total\" cursor=\"$cursor\" />\n";
637 $response .=
"\t</ListSets>\n";
650 function error($code, $message) {
651 if (in_array($code, array(
'badVerb',
'badArgument'))) {
652 $printParams =
false;
658 $this->
response(
"\t<error code=\"$code\">$message</error>", $printParams);
666 function response($response, $printParams =
true) {
668 header(
'Content-Type: text/xml');
670 echo
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
671 "<?xml-stylesheet type=\"text/xsl\" href=\"" . $request->getBaseUrl() .
"/lib/pkp/xml/oai2.xsl\" ?>\n" .
672 "<OAI-PMH xmlns=\"http://www.openarchives.org/OAI/2.0/\"\n" .
673 "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" .
674 "\txsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/\n" .
675 "\t\thttp://www.openarchives.org/OAI/2.0/OAI-PMH.xsd\">\n" .
681 foreach($this->params as $k => $v) {
697 return isset($this->params[$name]) ? $this->params[$name] :
null;
722 return isset($this->params[$name]);
740 function checkParams($required = array(), $optional = array()) {
742 $requiredParams = array_merge(array(
'verb'), $required);
743 $validParams = array_merge($requiredParams, $optional);
746 foreach ($requiredParams as $k) {
748 $this->
error(
'badArgument',
"Missing $k parameter");
751 }
else if (is_array($this->
getParam($k))) {
752 $this->
error(
'badArgument',
"Multiple values are not allowed for the $k parameter");
758 foreach ($optional as $k) {
760 $this->
error(
'badArgument',
"Multiple values are not allowed for the $k parameter");
767 foreach ($this->params as $k => $v) {
768 if (!in_array($k, $validParams)) {
771 $this->
error(
'badArgument',
"$k is an illegal parameter");
788 $metadata = $formats[$format]->toXml($record);
804 if ($from ==
'invalid') {
805 $this->
error(
'badArgument',
'Illegal from parameter');
808 }
else if($from ==
'invalid_granularity') {
809 $this->
error(
'badArgument',
'Illegal granularity for from parameter');
817 if($until ==
'invalid') {
818 $this->
error(
'badArgument',
'Illegal until parameter');
821 }
else if($until ==
'invalid_granularity') {
822 $this->
error(
'badArgument',
'Illegal granularity for until parameter');
827 if (isset($from) && $from > $until) {
828 $this->
error(
'badArgument',
'until parameter must be greater than or equal to from parameter');
833 if (isset($from) && strlen(
$params[
'from']) != strlen(
$params[
'until'])) {
834 $this->
error(
'badArgument',
'until and from parameters must be of the same granularity');
838 if (strlen(
$params[
'until']) == 10) {