Merge branch 'opencultureconsulting:master' into master
This commit is contained in:
commit
4b8f92e970
|
@ -0,0 +1,12 @@
|
||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
|
@ -0,0 +1,121 @@
|
||||||
|
###
|
||||||
|
# https://github.com/gitattributes/gitattributes/blob/master/Common.gitattributes
|
||||||
|
###
|
||||||
|
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
#
|
||||||
|
# The above will handle all files NOT found below
|
||||||
|
#
|
||||||
|
|
||||||
|
# Documents
|
||||||
|
*.bibtex text diff=bibtex
|
||||||
|
*.doc diff=astextplain
|
||||||
|
*.DOC diff=astextplain
|
||||||
|
*.docx diff=astextplain
|
||||||
|
*.DOCX diff=astextplain
|
||||||
|
*.dot diff=astextplain
|
||||||
|
*.DOT diff=astextplain
|
||||||
|
*.pdf diff=astextplain
|
||||||
|
*.PDF diff=astextplain
|
||||||
|
*.rtf diff=astextplain
|
||||||
|
*.RTF diff=astextplain
|
||||||
|
*.md text diff=markdown
|
||||||
|
*.mdx text diff=markdown
|
||||||
|
*.tex text diff=tex
|
||||||
|
*.adoc text
|
||||||
|
*.textile text
|
||||||
|
*.mustache text
|
||||||
|
*.csv text eol=crlf
|
||||||
|
*.tab text
|
||||||
|
*.tsv text
|
||||||
|
*.txt text
|
||||||
|
*.sql text
|
||||||
|
*.epub diff=astextplain
|
||||||
|
|
||||||
|
# Graphics
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.tif binary
|
||||||
|
*.tiff binary
|
||||||
|
*.ico binary
|
||||||
|
# SVG treated as text by default.
|
||||||
|
*.svg text
|
||||||
|
# If you want to treat it as binary,
|
||||||
|
# use the following line instead.
|
||||||
|
# *.svg binary
|
||||||
|
*.eps binary
|
||||||
|
|
||||||
|
# Scripts
|
||||||
|
*.bash text eol=lf
|
||||||
|
*.fish text eol=lf
|
||||||
|
*.ksh text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.zsh text eol=lf
|
||||||
|
# These are explicitly windows files and should use crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
|
||||||
|
# Serialisation
|
||||||
|
*.json text
|
||||||
|
*.toml text
|
||||||
|
*.xml text
|
||||||
|
*.yaml text
|
||||||
|
*.yml text
|
||||||
|
|
||||||
|
# Archives
|
||||||
|
*.7z binary
|
||||||
|
*.gz binary
|
||||||
|
*.tar binary
|
||||||
|
*.tgz binary
|
||||||
|
*.zip binary
|
||||||
|
|
||||||
|
# Text files where line endings should be preserved
|
||||||
|
*.patch -text
|
||||||
|
|
||||||
|
#
|
||||||
|
# Exclude files from exporting
|
||||||
|
#
|
||||||
|
|
||||||
|
.gitattributes export-ignore
|
||||||
|
.gitignore export-ignore
|
||||||
|
.gitkeep export-ignore
|
||||||
|
|
||||||
|
###
|
||||||
|
# https://github.com/gitattributes/gitattributes/blob/master/PHP.gitattributes
|
||||||
|
###
|
||||||
|
|
||||||
|
# PHP files
|
||||||
|
*.php text eol=lf diff=php
|
||||||
|
*.phpt text eol=lf diff=php
|
||||||
|
*.phtml text eol=lf diff=html
|
||||||
|
*.twig text eol=lf
|
||||||
|
*.phar binary
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
phpcs.xml text eol=lf
|
||||||
|
phpunit.xml text eol=lf
|
||||||
|
phpstan.neon text eol=lf
|
||||||
|
psalm.xml text eol=lf
|
||||||
|
|
||||||
|
###
|
||||||
|
# Open Culture Consulting custom additions
|
||||||
|
###
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
.editorconfig text eol=lf
|
||||||
|
*.dist.xml text eol=lf
|
||||||
|
*.xml.dist text eol=lf
|
||||||
|
*.neon text eol=lf
|
||||||
|
|
||||||
|
# Generated documentation
|
||||||
|
doc/* linguist-generated=true
|
||||||
|
|
||||||
|
# Exclude files from exporting
|
||||||
|
.github/* export-ignore
|
||||||
|
.phpdoc/* export-ignore
|
||||||
|
phpdoc.dist.xml export-ignore
|
|
@ -0,0 +1,9 @@
|
||||||
|
/.phpdoc/cache/
|
||||||
|
/.vscode/
|
||||||
|
/vendor/
|
||||||
|
.php-cs-fixer.php
|
||||||
|
phpcs.xml
|
||||||
|
phpdoc.xml
|
||||||
|
phpstan.neon
|
||||||
|
psalm.xml
|
||||||
|
TODO
|
|
@ -24,33 +24,34 @@ namespace OCC\OAI2;
|
||||||
|
|
||||||
class Exception extends \Exception {
|
class Exception extends \Exception {
|
||||||
|
|
||||||
|
private array $errorTable = [
|
||||||
|
'badArgument' => [
|
||||||
|
'text' => 'The request includes illegal arguments, is missing required arguments, includes a repeated argument, or values for arguments have an illegal syntax.',
|
||||||
|
],
|
||||||
|
'badResumptionToken' => [
|
||||||
|
'text' => 'The value of the resumptionToken argument is invalid or expired.',
|
||||||
|
],
|
||||||
|
'badVerb' => [
|
||||||
|
'text' => 'Value of the verb argument is not a legal OAI-PMH verb, the verb argument is missing, or the verb argument is repeated.',
|
||||||
|
],
|
||||||
|
'cannotDisseminateFormat' => [
|
||||||
|
'text' => 'The metadata format identified by the value given for the metadataPrefix argument is not supported by the item or by the repository.',
|
||||||
|
],
|
||||||
|
'idDoesNotExist' => [
|
||||||
|
'text' => 'The value of the identifier argument is unknown or illegal in this repository.',
|
||||||
|
],
|
||||||
|
'noRecordsMatch' => [
|
||||||
|
'text' => 'The combination of the values of the from, until, set and metadataPrefix arguments results in an empty list.',
|
||||||
|
],
|
||||||
|
'noMetadataFormats' => [
|
||||||
|
'text' => 'There are no metadata formats available for the specified item.',
|
||||||
|
],
|
||||||
|
'noSetHierarchy' => [
|
||||||
|
'text' => 'The repository does not support sets.',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
public function __construct($code) {
|
public function __construct($code) {
|
||||||
$this->errorTable = [
|
|
||||||
'badArgument' => [
|
|
||||||
'text' => 'The request includes illegal arguments, is missing required arguments, includes a repeated argument, or values for arguments have an illegal syntax.',
|
|
||||||
],
|
|
||||||
'badResumptionToken' => [
|
|
||||||
'text' => 'The value of the resumptionToken argument is invalid or expired.',
|
|
||||||
],
|
|
||||||
'badVerb' => [
|
|
||||||
'text' => 'Value of the verb argument is not a legal OAI-PMH verb, the verb argument is missing, or the verb argument is repeated.',
|
|
||||||
],
|
|
||||||
'cannotDisseminateFormat' => [
|
|
||||||
'text' => 'The metadata format identified by the value given for the metadataPrefix argument is not supported by the item or by the repository.',
|
|
||||||
],
|
|
||||||
'idDoesNotExist' => [
|
|
||||||
'text' => 'The value of the identifier argument is unknown or illegal in this repository.',
|
|
||||||
],
|
|
||||||
'noRecordsMatch' => [
|
|
||||||
'text' => 'The combination of the values of the from, until, set and metadataPrefix arguments results in an empty list.',
|
|
||||||
],
|
|
||||||
'noMetadataFormats' => [
|
|
||||||
'text' => 'There are no metadata formats available for the specified item.',
|
|
||||||
],
|
|
||||||
'noSetHierarchy' => [
|
|
||||||
'text' => 'The repository does not support sets.',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
parent::__construct($this->errorTable[$code]['text']);
|
parent::__construct($this->errorTable[$code]['text']);
|
||||||
$this->code = $code;
|
$this->code = $code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,11 @@ namespace OCC\OAI2;
|
||||||
|
|
||||||
class Response {
|
class Response {
|
||||||
|
|
||||||
public $doc; // DOMDocument. Handle of current XML Document object
|
public \DOMDocument $doc; // DOMDocument. Handle of current XML Document object
|
||||||
|
|
||||||
|
private string $verb = '';
|
||||||
|
|
||||||
|
private \DOMElement $verbNode;
|
||||||
|
|
||||||
public function __construct($uri, $verb, $request_args) {
|
public function __construct($uri, $verb, $request_args) {
|
||||||
if (substr($uri, -1, 1) == '/') {
|
if (substr($uri, -1, 1) == '/') {
|
||||||
|
@ -74,7 +78,7 @@ class Response {
|
||||||
* @param string $nodeName The name of appending node.
|
* @param string $nodeName The name of appending node.
|
||||||
* @param string $value The content of appending node.
|
* @param string $value The content of appending node.
|
||||||
*/
|
*/
|
||||||
public function addToVerbNode($nodeName, $value = null) {
|
public function addToVerbNode($nodeName, $value = '') {
|
||||||
if (!isset($this->verbNode) && !empty($this->verb)) {
|
if (!isset($this->verbNode) && !empty($this->verb)) {
|
||||||
$this->verbNode = $this->addChild($this->doc->documentElement, $this->verb);
|
$this->verbNode = $this->addChild($this->doc->documentElement, $this->verb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,12 @@ class Server {
|
||||||
private $max_records = 100;
|
private $max_records = 100;
|
||||||
private $token_prefix = '/tmp/oai2-';
|
private $token_prefix = '/tmp/oai2-';
|
||||||
private $token_valid = 86400;
|
private $token_valid = 86400;
|
||||||
|
private $uri = '';
|
||||||
|
private $identifyResponse;
|
||||||
|
private $listMetadataFormatsCallback;
|
||||||
|
private $listRecordsCallback;
|
||||||
|
private $getRecordCallback;
|
||||||
|
private Response $response;
|
||||||
|
|
||||||
public function __construct($uri, $args, $identifyResponse, $callbacks, $config) {
|
public function __construct($uri, $args, $identifyResponse, $callbacks, $config) {
|
||||||
$this->uri = $uri;
|
$this->uri = $uri;
|
||||||
|
@ -242,7 +248,7 @@ class Server {
|
||||||
if ($records_count - $deliveredRecords > $maxItems) {
|
if ($records_count - $deliveredRecords > $maxItems) {
|
||||||
$deliveredRecords += $maxItems;
|
$deliveredRecords += $maxItems;
|
||||||
$restoken = $this->createResumptionToken($deliveredRecords, $metadataPrefix, $from, $until);
|
$restoken = $this->createResumptionToken($deliveredRecords, $metadataPrefix, $from, $until);
|
||||||
$expirationDatetime = gmstrftime('%Y-%m-%dT%TZ', time()+$this->token_valid);
|
$expirationDatetime = date('Y-m-d\TH:i:s\Z', time()+$this->token_valid);
|
||||||
} elseif (isset($this->args['resumptionToken'])) {
|
} elseif (isset($this->args['resumptionToken'])) {
|
||||||
// Last delivery, return empty resumptionToken
|
// Last delivery, return empty resumptionToken
|
||||||
$restoken = null;
|
$restoken = null;
|
||||||
|
@ -297,10 +303,14 @@ class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function formatTimestamp($datestamp) {
|
private function formatTimestamp($datestamp) {
|
||||||
if (is_array($time = strptime($datestamp, '%Y-%m-%dT%H:%M:%SZ')) || is_array($time = strptime($datestamp, '%Y-%m-%d'))) {
|
$time = date_parse_from_format('Y-m-d\TH:i:s\Z', $datestamp);
|
||||||
return gmmktime($time['tm_hour'], $time['tm_min'], $time['tm_sec'], $time['tm_mon'] + 1, $time['tm_mday'], $time['tm_year']+1900);
|
if ($time['error_count'] > 0) {
|
||||||
} else {
|
$time = date_parse_from_format('Y-m-d', $datestamp);
|
||||||
|
}
|
||||||
|
if ($time['error_count'] > 0) {
|
||||||
return null;
|
return null;
|
||||||
|
} else {
|
||||||
|
return gmmktime($time['hour'], $time['minute'], $time['second'], $time['month'] + 1, $time['day'], $time['year']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +319,7 @@ class Server {
|
||||||
if ($datetime === false) {
|
if ($datetime === false) {
|
||||||
$datetime = \DateTime::createFromFormat('Y-m-d', $date);
|
$datetime = \DateTime::createFromFormat('Y-m-d', $date);
|
||||||
}
|
}
|
||||||
return ($datetime !== false) && !array_sum($datetime->getLastErrors());
|
return ($datetime !== false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
12
README.md
12
README.md
|
@ -1,20 +1,20 @@
|
||||||
# Simple OAI-PMH 2.0 Data Provider
|
# Simple OAI-PMH 2.0 Data Provider
|
||||||
|
|
||||||
This is a stand-alone and easy to install data provider implementing the [Open Archives Initiative's Protocol for Metadata Harvesting (OAI-PMH)](https://openarchives.org/pmh/). It serves records in any metadata format from directories of XML files using the directory name as `metadataPrefix`, the filename as `identifier` and the filemtime as datestamp. 0-byte files are considered deleted records and handled accordingly. Resumption tokens are managed using files. Sets are currently not supported.
|
This is a stand-alone and easy to install data provider implementing the [Open Archives Initiative's Protocol for Metadata Harvesting (OAI-PMH)](https://openarchives.org/pmh/). It serves records in any metadata format from directories of XML files using the directory name as `metadataPrefix`, the filename as `identifier` and the filemtime as timestamp. 0-byte files are considered deleted records and handled accordingly. Resumption tokens are managed using files. Sets are currently not supported.
|
||||||
|
|
||||||
Just put the records as XML files in the data directory, adjust a few configuration settings and you are ready to go!
|
Just put the records as XML files in the data directory, adjust a few configuration settings and you are ready to go!
|
||||||
|
|
||||||
A demo installation can be found [here](https://demo.opencultureconsulting.com/oai_pmh/?verb=Identify).
|
A demo installation can be found [here](https://demo.opencultureconsulting.com/oai_pmh/?verb=Identify).
|
||||||
|
|
||||||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/7a12022611d047ad9ef9a0c3aadb986a)](https://www.codacy.com/gh/opencultureconsulting/oai_pmh)
|
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/7a12022611d047ad9ef9a0c3aadb986a)](https://www.codacy.com/gh/opencultureconsulting/simple-oai-pmh)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Run `composer create-project opencultureconsulting/oai_pmh <path>`.
|
1. Run `composer create-project opencultureconsulting/simple-oai-pmh <path>`.
|
||||||
|
|
||||||
2. Create a data directory in a not publicly accessible location outside of `<path>`. Create a subdirectory inside the specified data directory for every format (i. e. `metadataPrefix`) you want to provide.
|
2. Create a data directory in a location not publicly accessible (i. e. outside of `<path>`). Create a subdirectory inside the specified data directory for every format (i. e. `metadataPrefix`) you want to provide.
|
||||||
|
|
||||||
3. Copy `Configuration/Main.template.php` to `Configuration/Main.php` and adjust the settings according to your preferences. Don't forget pointing `$config['dataDirectory']` to your newly created data directory.
|
3. Copy `Configuration/Main.template.php` to `Configuration/Main.php` and edit the settings according to your preferences. Don't forget pointing `$config['dataDirectory']` to your newly created data directory.
|
||||||
|
|
||||||
4. Put the records into the respective directories according to their format. Each record has to be a separate XML file with its `identifier` as filename (e. g. the file *12345678.xml* can be adressed using the `identifier` *12345678*). Optionally you can maintain deletions by keeping 0-byte files for deleted records.
|
4. Put the records into the respective directories according to their format. Each record has to be a separate XML file with its `identifier` as filename (e. g. the file *12345678.xml* can be adressed using the `identifier` *12345678*). Optionally you can maintain deletions by keeping 0-byte files for deleted records.
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ A demo installation can be found [here](https://demo.opencultureconsulting.com/o
|
||||||
|
|
||||||
1. Backup `Configuration/Main.php`!
|
1. Backup `Configuration/Main.php`!
|
||||||
|
|
||||||
2. Delete `<path>` and re-install by running `composer create-project opencultureconsulting/oai_pmh <path>`.
|
2. Delete `<path>` and re-install by running `composer create-project opencultureconsulting/simple-oai-pmh <path>`.
|
||||||
|
|
||||||
3. Move your configuration back into `Configuration/Main.php`.
|
3. Move your configuration back into `Configuration/Main.php`.
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@
|
||||||
<xsl:apply-templates select="/oai:OAI-PMH"/>
|
<xsl:apply-templates select="/oai:OAI-PMH"/>
|
||||||
<xsl:call-template name="quicklinks"/>
|
<xsl:call-template name="quicklinks"/>
|
||||||
<p class="info">You are viewing an HTML version of the XML OAI-PMH response. To see the underlying XML as it appears to any OAI-PMH harvester use your web browser's <em>view source</em> option or disable XSLT processing.</p>
|
<p class="info">You are viewing an HTML version of the XML OAI-PMH response. To see the underlying XML as it appears to any OAI-PMH harvester use your web browser's <em>view source</em> option or disable XSLT processing.</p>
|
||||||
<p class="info">This XSL script was originally written by Christopher Gutteridge at <a href="https://www.southampton.ac.uk/">University of Southampton</a> for the <a href="https://www.eprints.org/">EPrints</a> project and was later adapted by Sebastian Meyer at <a href="https://www.opencultureconsulting.com/">Open Culture Consulting</a> to be more generally applicable to other OAI-PMH interfaces. It is available on <a href="https://github.com/opencultureconsulting/oai_pmh">GitHub</a> for free!</p>
|
<p class="info">This XSL script was originally written by Christopher Gutteridge at <a href="https://www.southampton.ac.uk/">University of Southampton</a> for the <a href="https://www.eprints.org/">EPrints</a> project and was later adapted by Sebastian Meyer at <a href="https://www.opencultureconsulting.com/">Open Culture Consulting</a> to be more generally applicable to other OAI-PMH interfaces. It is available on <a href="https://github.com/opencultureconsulting/simple-oai-pmh">GitHub</a> for free!</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "opencultureconsulting/oai_pmh",
|
"name": "opencultureconsulting/simple-oai-pmh",
|
||||||
"description": "This is a stand-alone and easy to install data provider implementing the Open Archives Initiative's Protocol for Metadata Harvesting (OAI-PMH).",
|
"description": "This is a stand-alone and easy to install data provider implementing the Open Archives Initiative's Protocol for Metadata Harvesting (OAI-PMH).",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
"code4lib",
|
"code4lib",
|
||||||
"repository"
|
"repository"
|
||||||
],
|
],
|
||||||
"homepage": "https://github.com/opencultureconsulting/oai_pmh",
|
"homepage": "https://github.com/opencultureconsulting/simple-oai-pmh",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"license": ["GPL-3.0-or-later"],
|
"license": ["GPL-3.0-or-later"],
|
||||||
"authors": [
|
"authors": [
|
||||||
|
@ -41,14 +41,17 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/opencultureconsulting/oai_pmh/issues",
|
"issues": "https://github.com/opencultureconsulting/simple-oai-pmh/issues",
|
||||||
"source": "https://github.com/opencultureconsulting/oai_pmh",
|
"source": "https://github.com/opencultureconsulting/simple-oai-pmh",
|
||||||
"docs": "https://github.com/opencultureconsulting/oai_pmh/blob/master/README.md"
|
"docs": "https://github.com/opencultureconsulting/simple-oai-pmh/blob/master/README.md"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.0",
|
"php": "7.4.*|8.0.*|8.1.*|8.2.*",
|
||||||
"ext-xml": "*"
|
"ext-xml": "*"
|
||||||
},
|
},
|
||||||
|
"replace": {
|
||||||
|
"opencultureconsulting/oai_pmh": "self.version"
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"OCC\\OAI2\\": "Classes/"
|
"OCC\\OAI2\\": "Classes/"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "af0a24a6f06b7a8dc4ecd3084647403e",
|
||||||
|
"packages": [],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": {
|
||||||
|
"php": "7.4.*|8.0.*|8.1.*|8.2.*",
|
||||||
|
"ext-xml": "*"
|
||||||
|
},
|
||||||
|
"platform-dev": [],
|
||||||
|
"plugin-api-version": "2.6.0"
|
||||||
|
}
|
Loading…
Reference in New Issue