Open Journal Systems  3.3.0
DataciteExportPlugin.inc.php
1 <?php
2 
16 import('classes.plugins.DOIPubIdExportPlugin');
17 
18 // DataCite API
19 define('DATACITE_API_RESPONSE_OK', 201);
20 define('DATACITE_API_URL', 'https://mds.datacite.org/');
21 
22 // Test DOI prefix
23 define('DATACITE_API_TESTPREFIX', '10.5072');
24 
25 // Export file types.
26 define('DATACITE_EXPORT_FILE_XML', 0x01);
27 define('DATACITE_EXPORT_FILE_TAR', 0x02);
28 
29 
31 
35  function getName() {
36  return 'DataciteExportPlugin';
37  }
38 
42  function getDisplayName() {
43  return __('plugins.importexport.datacite.displayName');
44  }
45 
49  function getDescription() {
50  return __('plugins.importexport.datacite.description');
51  }
52 
56  function getSubmissionFilter() {
57  return 'article=>datacite-xml';
58  }
59 
63  function getIssueFilter() {
64  return 'issue=>datacite-xml';
65  }
66 
71  return 'galley=>datacite-xml';
72  }
73 
78  return 'datacite';
79  }
80 
85  return 'DataciteSettingsForm';
86  }
87 
92  return 'DataciteExportDeployment';
93  }
94 
98  function executeExportAction($request, $objects, $filter, $tab, $objectsFileNamePart, $noValidation = null) {
99  $context = $request->getContext();
100  $path = array('plugin', $this->getName());
101 
102  import('lib.pkp.classes.file.FileManager');
103  $fileManager = new FileManager();
104 
105  // Export
106  if ($request->getUserVar(EXPORT_ACTION_EXPORT)) {
107  $result = $this->_checkForTar();
108  if ($result === true) {
109  $exportedFiles = array();
110  foreach ($objects as $object) {
111  // Get the XML
112  $exportXml = $this->exportXML($object, $filter, $context, $noValidation);
113  // Write the XML to a file.
114  // export file name example: datacite-20160723-160036-articles-1-1.xml
115  $objectFileNamePart = $objectsFileNamePart . '-' . $object->getId();
116  $exportFileName = $this->getExportFileName($this->getExportPath(), $objectFileNamePart, $context, '.xml');
117  $fileManager->writeFile($exportFileName, $exportXml);
118  $exportedFiles[] = $exportFileName;
119  }
120  // If we have more than one export file we package the files
121  // up as a single tar before going on.
122  assert(count($exportedFiles) >= 1);
123  if (count($exportedFiles) > 1) {
124  // tar file name: e.g. datacite-20160723-160036-articles-1.tar.gz
125  $finalExportFileName = $this->getExportFileName($this->getExportPath(), $objectFileNamePart, $context, '.tar.gz');
126  $this->_tarFiles($this->getExportPath(), $finalExportFileName, $exportedFiles);
127  // remove files
128  foreach ($exportedFiles as $exportedFile) {
129  $fileManager->deleteByPath($exportedFile);
130  }
131  } else {
132  $finalExportFileName = array_shift($exportedFiles);
133  }
134  $fileManager->downloadByPath($finalExportFileName);
135  $fileManager->deleteByPath($finalExportFileName);
136  } else {
137  if (is_array($result)) {
138  foreach($result as $error) {
139  assert(is_array($error) && count($error) >= 1);
140  $this->_sendNotification(
141  $request->getUser(),
142  $error[0],
143  NOTIFICATION_TYPE_ERROR,
144  (isset($error[1]) ? $error[1] : null)
145  );
146  }
147  }
148  // redirect back to the right tab
149  $request->redirect(null, null, null, $path, null, $tab);
150  }
151  } elseif ($request->getUserVar(EXPORT_ACTION_DEPOSIT)) {
152  $resultErrors = array();
153  foreach ($objects as $object) {
154  // Get the XML
155  $exportXml = $this->exportXML($object, $filter, $context, $noValidation);
156  // Write the XML to a file.
157  // export file name example: datacite-20160723-160036-articles-1-1.xml
158  $objectFileNamePart = $objectsFileNamePart . '-' . $object->getId();
159  $exportFileName = $this->getExportFileName($this->getExportPath(), $objectFileNamePart, $context, '.xml');
160  $fileManager->writeFile($exportFileName, $exportXml);
161  // Deposit the XML file.
162  $result = $this->depositXML($object, $context, $exportFileName);
163  if (is_array($result)) {
164  $resultErrors[] = $result;
165  }
166  // Remove all temporary files.
167  $fileManager->deleteByPath($exportFileName);
168  }
169  // send notifications
170  if (empty($resultErrors)) {
171  $this->_sendNotification(
172  $request->getUser(),
173  $this->getDepositSuccessNotificationMessageKey(),
174  NOTIFICATION_TYPE_SUCCESS
175  );
176  } else {
177  foreach($resultErrors as $errors) {
178  foreach ($errors as $error) {
179  assert(is_array($error) && count($error) >= 1);
180  $this->_sendNotification(
181  $request->getUser(),
182  $error[0],
183  NOTIFICATION_TYPE_ERROR,
184  (isset($error[1]) ? $error[1] : null)
185  );
186  }
187  }
188  }
189  // redirect back to the right tab
190  $request->redirect(null, null, null, $path, null, $tab);
191  } else {
192  return parent::executeExportAction($request, $objects, $filter, $tab, $objectsFileNamePart);
193  }
194  }
195 
199  function depositXML($object, $context, $filename) {
200  $request = Application::get()->getRequest();
201  // Get the DOI and the URL for the object.
202  $doi = $object->getStoredPubId('doi');
203  assert(!empty($doi));
204  if ($this->isTestMode($context)) {
205  $doi = PKPString::regexp_replace('#^[^/]+/#', DATACITE_API_TESTPREFIX . '/', $doi);
206  }
207  $url = $this->_getObjectUrl($request, $context, $object);
208  assert(!empty($url));
209 
210  // Prepare HTTP session.
211  import('lib.pkp.classes.helpers.PKPCurlHelper');
212  $curlCh = PKPCurlHelper::getCurlObject();
213 
214  curl_setopt($curlCh, CURLOPT_RETURNTRANSFER, true);
215  curl_setopt($curlCh, CURLOPT_POST, true);
216  // Set up basic authentication.
217  $username = $this->getSetting($context->getId(), 'username');
218  $password = $this->getSetting($context->getId(), 'password');
219  curl_setopt($curlCh, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
220  curl_setopt($curlCh, CURLOPT_USERPWD, "$username:$password");
221  // Transmit meta-data.
222  assert(is_readable($filename));
223  $payload = file_get_contents($filename);
224  assert($payload !== false && !empty($payload));
225  curl_setopt($curlCh, CURLOPT_URL, DATACITE_API_URL . 'metadata');
226  curl_setopt($curlCh, CURLOPT_HTTPHEADER, array('Content-Type: application/xml;charset=UTF-8'));
227  curl_setopt($curlCh, CURLOPT_POSTFIELDS, $payload);
228  $result = true;
229  $response = curl_exec($curlCh);
230  if ($response === false) {
231  $result = array(array('plugins.importexport.common.register.error.mdsError', "Registering DOI $doi: No response from server."));
232  } else {
233  $status = curl_getinfo($curlCh, CURLINFO_HTTP_CODE);
234  if ($status != DATACITE_API_RESPONSE_OK) {
235  $result = array(array('plugins.importexport.common.register.error.mdsError', "Registering DOI $doi: $status - $response"));
236  }
237  }
238  // Mint a DOI.
239  if ($result === true) {
240  $payload = "doi=$doi\nurl=$url";
241  curl_setopt($curlCh, CURLOPT_URL, DATACITE_API_URL . 'doi');
242  curl_setopt($curlCh, CURLOPT_HTTPHEADER, array('Content-Type: text/plain;charset=UTF-8'));
243  curl_setopt($curlCh, CURLOPT_POSTFIELDS, $payload);
244  $response = curl_exec($curlCh);
245  if ($response === false) {
246  $result = array(array('plugins.importexport.common.register.error.mdsError', 'Registering DOI $doi: No response from server.'));
247  } else {
248  $status = curl_getinfo($curlCh, CURLINFO_HTTP_CODE);
249  if ($status != DATACITE_API_RESPONSE_OK) {
250  $result = array(array('plugins.importexport.common.register.error.mdsError', "Registering DOI $doi: $status - $response"));
251  }
252  }
253  }
254  curl_close($curlCh);
255  if ($result === true) {
256  $object->setData($this->getDepositStatusSettingName(), EXPORT_STATUS_REGISTERED);
257  $this->saveRegisteredDoi($context, $object, DATACITE_API_TESTPREFIX);
258  }
259  return $result;
260  }
261 
265  function executeCLICommand($scriptName, $command, $context, $outputFile, $objects, $filter, $objectsFileNamePart) {
266  import('lib.pkp.classes.file.FileManager');
267  $fileManager = new FileManager();
268  switch ($command) {
269  case 'export':
270  $result = $this->_checkForTar();
271  if ($result === true) {
272  $exportedFiles = array();
273  foreach ($objects as $object) {
274  // Get the XML
275  $exportXml = $this->exportXML($object, $filter, $context);
276  // Write the XML to a file.
277  // export file name example: datacite-20160723-160036-articles-1-1.xml
278  $objectFileNamePart = $objectsFileNamePart . '-' . $object->getId();
279  $exportFileName = $this->getExportFileName($this->getExportPath(), $objectFileNamePart, $context, '.xml');
280  $fileManager->writeFile($exportFileName, $exportXml);
281  $exportedFiles[] = $exportFileName;
282  }
283  // If we have more than one export file we package the files
284  // up as a single tar before going on.
285  assert(count($exportedFiles) >= 1);
286  if (count($exportedFiles) > 1) {
287  // tar file name: e.g. datacite-20160723-160036-articles-1.tar.gz
288  $finalExportFileName = $this->getExportFileName($this->getExportPath(), $objectFileNamePart, $context, '.tar.gz');
289  $finalExportFileType = DATACITE_EXPORT_FILE_TAR;
290  $this->_tarFiles($this->getExportPath(), $finalExportFileName, $exportedFiles);
291  } else {
292  $finalExportFileName = array_shift($exportedFiles);
293  $finalExportFileType = DATACITE_EXPORT_FILE_XML;
294  }
295  $outputFileExtension = ($finalExportFileType == DATACITE_EXPORT_FILE_TAR ? '.tar.gz' : '.xml');
296  if (substr($outputFile , -strlen($outputFileExtension)) != $outputFileExtension) {
297  $outputFile .= $outputFileExtension;
298  }
299  $fileManager->copyFile($finalExportFileName, $outputFile);
300  foreach ($exportedFiles as $exportedFile) {
301  $fileManager->deleteByPath($exportedFile);
302  }
303  $fileManager->deleteByPath($finalExportFileName);
304  } else {
305  echo __('plugins.importexport.common.cliError') . "\n";
306  echo __('manager.plugins.tarCommandNotFound') . "\n\n";
307  $this->usage($scriptName);
308  }
309  break;
310  case 'register':
311  $resultErrors = array();
312  foreach ($objects as $object) {
313  // Get the XML
314  $exportXml = $this->exportXML($object, $filter, $context);
315  // Write the XML to a file.
316  // export file name example: datacite-20160723-160036-articles-1-1.xml
317  $objectFileNamePart = $objectsFileNamePart . '-' . $object->getId();
318  $exportFileName = $this->getExportFileName($this->getExportPath(), $objectFileNamePart, $context, '.xml');
319  $fileManager->writeFile($exportFileName, $exportXml);
320  // Deposit the XML file.
321  $result = $this->depositXML($object, $context, $exportFileName);
322  if (is_array($result)) {
323  $resultErrors[] = $result;
324  }
325  // Remove all temporary files.
326  $fileManager->deleteByPath($exportFileName);
327  }
328  if (empty($resultErrors)) {
329  echo __('plugins.importexport.common.register.success') . "\n";
330  } else {
331  echo __('plugins.importexport.common.cliError') . "\n";
332  foreach($resultErrors as $errors) {
333  foreach ($errors as $error) {
334  assert(is_array($error) && count($error) >= 1);
335  $errorMessage = __($error[0], array('param' => (isset($error[1]) ? $error[1] : null)));
336  echo "*** $errorMessage\n";
337  }
338  }
339  echo "\n";
340  $this->usage($scriptName);
341  }
342  break;
343  }
344  }
345 
351  function _checkForTar() {
352  $tarBinary = Config::getVar('cli', 'tar');
353  if (empty($tarBinary) || !is_executable($tarBinary)) {
354  $result = array(
355  array('manager.plugins.tarCommandNotFound')
356  );
357  } else {
358  $result = true;
359  }
360  return $result;
361  }
362 
369  function _tarFiles($targetPath, $targetFile, $sourceFiles) {
370  assert((boolean) $this->_checkForTar());
371  // GZip compressed result file.
372  $tarCommand = Config::getVar('cli', 'tar') . ' -czf ' . escapeshellarg($targetFile);
373  // Do not reveal our internal export path by exporting only relative filenames.
374  $tarCommand .= ' -C ' . escapeshellarg($targetPath);
375  // Do not reveal our webserver user by forcing root as owner.
376  $tarCommand .= ' --owner 0 --group 0 --';
377  // Add each file individually so that other files in the directory
378  // will not be included.
379  foreach($sourceFiles as $sourceFile) {
380  assert(dirname($sourceFile) . '/' === $targetPath);
381  if (dirname($sourceFile) . '/' !== $targetPath) continue;
382  $tarCommand .= ' ' . escapeshellarg(basename($sourceFile));
383  }
384  // Execute the command.
385  exec($tarCommand);
386  }
387 
394  function _getObjectUrl($request, $context, $object) {
395  $router = $request->getRouter();
396  // Retrieve the article of article files.
397  if (is_a($object, 'ArticleGalley')) {
398  $articleId = $object->getSubmissionId();
399  $cache = $this->getCache();
400  if ($cache->isCached('articles', $articleId)) {
401  $article = $cache->get('articles', $articleId);
402  } else {
403  $article = Services::get('submission')->get($articleId);
404  }
405  assert(is_a($article, 'Submission'));
406  }
407  $url = null;
408  switch (true) {
409  case is_a($object, 'Issue'):
410  $url = $router->url($request, $context->getPath(), 'issue', 'view', $object->getBestIssueId(), null, null, true);
411  break;
412  case is_a($object, 'Submission'):
413  $url = $router->url($request, $context->getPath(), 'article', 'view', $object->getBestId(), null, null, true);
414  break;
415  case is_a($object, 'ArticleGalley'):
416  $url = $router->url($request, $context->getPath(), 'article', 'view', array($article->getBestId(), $object->getBestGalleyId()), null, null, true);
417  break;
418  }
419  if ($this->isTestMode($context)) {
420  // Change server domain for testing.
421  $url = PKPString::regexp_replace('#://[^\s]+/index.php#', '://example.com/index.php', $url);
422  }
423  return $url;
424  }
425 
426 }
427 
428 
DataciteExportPlugin\getSubmissionFilter
getSubmissionFilter()
Definition: DataciteExportPlugin.inc.php:56
PubObjectsExportPlugin\getCache
getCache()
Definition: PubObjectsExportPlugin.inc.php:44
DataciteExportPlugin\getExportDeploymentClassName
getExportDeploymentClassName()
Definition: DataciteExportPlugin.inc.php:91
PKPString\regexp_replace
static regexp_replace($pattern, $replacement, $subject, $limit=-1)
Definition: PKPString.inc.php:279
PubObjectsExportPlugin\getDepositStatusSettingName
getDepositStatusSettingName()
Definition: PubObjectsExportPlugin.inc.php:521
DataciteExportPlugin\executeExportAction
executeExportAction($request, $objects, $filter, $tab, $objectsFileNamePart, $noValidation=null)
Definition: DataciteExportPlugin.inc.php:98
PubObjectsExportPlugin\_sendNotification
_sendNotification($user, $message, $notificationType, $param=null)
Definition: PubObjectsExportPlugin.inc.php:709
DataciteExportPlugin\getRepresentationFilter
getRepresentationFilter()
Definition: DataciteExportPlugin.inc.php:70
DOIPubIdExportPlugin
Basis class for DOI XML metadata export plugins.
Definition: DOIPubIdExportPlugin.inc.php:24
DataciteExportPlugin\getDisplayName
getDisplayName()
Definition: DataciteExportPlugin.inc.php:42
DataciteExportPlugin\depositXML
depositXML($object, $context, $filename)
Definition: DataciteExportPlugin.inc.php:199
PKPCurlHelper\getCurlObject
static getCurlObject($url=null, $useProxySettings=true)
Definition: PKPCurlHelper.inc.php:23
PubObjectsExportPlugin\isTestMode
isTestMode($context)
Definition: PubObjectsExportPlugin.inc.php:513
PubObjectsExportPlugin\exportXML
exportXML($objects, $filter, $context, $noValidation=null)
Definition: PubObjectsExportPlugin.inc.php:385
DataciteExportPlugin\executeCLICommand
executeCLICommand($scriptName, $command, $context, $outputFile, $objects, $filter, $objectsFileNamePart)
Definition: DataciteExportPlugin.inc.php:265
DOIPubIdExportPlugin\saveRegisteredDoi
saveRegisteredDoi($context, $object, $testPrefix='10.1234')
Definition: DOIPubIdExportPlugin.inc.php:96
DataciteExportPlugin\getSettingsFormClassName
getSettingsFormClassName()
Definition: DataciteExportPlugin.inc.php:84
ImportExportPlugin\getExportFileName
getExportFileName($basePath, $objectsFileNamePart, $context, $extension='.xml')
Definition: ImportExportPlugin.inc.php:152
Plugin\getSetting
getSetting($contextId, $name)
Definition: Plugin.inc.php:473
Config\getVar
static getVar($section, $key, $default=null)
Definition: Config.inc.php:35
ImportExportPlugin\getExportPath
getExportPath()
Definition: ImportExportPlugin.inc.php:140
DataciteExportPlugin\getName
getName()
Definition: DataciteExportPlugin.inc.php:35
DataciteExportPlugin\_getObjectUrl
_getObjectUrl($request, $context, $object)
Definition: DataciteExportPlugin.inc.php:394
PubObjectsExportPlugin\usage
usage($scriptName)
Definition: PubObjectsExportPlugin.inc.php:530
DataciteExportPlugin\_tarFiles
_tarFiles($targetPath, $targetFile, $sourceFiles)
Definition: DataciteExportPlugin.inc.php:369
Plugin\$request
$request
Definition: Plugin.inc.php:68
DataciteExportPlugin\getPluginSettingsPrefix
getPluginSettingsPrefix()
Definition: DataciteExportPlugin.inc.php:77
DataciteExportPlugin\getIssueFilter
getIssueFilter()
Definition: DataciteExportPlugin.inc.php:63
PKPApplication\get
static get()
Definition: PKPApplication.inc.php:235
DataciteExportPlugin\getDescription
getDescription()
Definition: DataciteExportPlugin.inc.php:49
FileManager
Class defining basic operations for file management.
Definition: FileManager.inc.php:35
DataciteExportPlugin\_checkForTar
_checkForTar()
Definition: DataciteExportPlugin.inc.php:351
DataciteExportPlugin
DataCite export/registration plugin.
Definition: DataciteExportPlugin.inc.php:30
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49