print17
[auf_bulletin.git] / oai.php
1 <?php
2 /**
3 * Fichier OAI - script du dépot OAI
4 *
5 * Ce fichier reéoit les commande OAI et fait renvoit le XML associé
6 *
7 * Mostly taken and often adapted from OAI V2 Data-Provider, Heinrich Stamerjohanns,
8 * stamer@uni-oldenburg.de, http://physnet.uni-oldenburg.de/oai
9 *
10 * Code fortement repris/inspire de celui d''OAI V2 Data-Provider' par Heinrich Stamerjohanns :
11 * stamer@uni-oldenburg.de, http://physnet.uni-oldenburg.de/oai
12 *
13 * PHP versions 4 et 5
14 *
15 * LODEL - Logiciel d'Edition ELectronique.
16 *
17 * Copyright (c) 2001-2002, Ghislain Picard, Marin Dacos
18 * Copyright (c) 2003, Ghislain Picard, Marin Dacos, Luc Santeramo, Nicolas Nutten, Anne Gentil-Beccot
19 * Copyright (c) 2004, Ghislain Picard, Marin Dacos, Luc Santeramo, Anne Gentil-Beccot, Bruno Cénou
20 * Copyright (c) 2005, Ghislain Picard, Marin Dacos, Luc Santeramo, Gautier Poupeau, Jean Lamy, Bruno Cénou
21 * Copyright (c) 2006, Marin Dacos, Luc Santeramo, Bruno Cénou, Jean Lamy, Mikaël Cixous, Sophie Malafosse
22 * Copyright (c) 2007, Marin Dacos, Bruno Cénou, Sophie Malafosse, Pierre-Alain Mignot
23 * Copyright (c) 2008, Marin Dacos, Bruno Cénou, Pierre-Alain Mignot, Inès Secondat de Montesquieu, Jean-François Rivière
24 * Copyright (c) 2009, Marin Dacos, Bruno Cénou, Pierre-Alain Mignot, Inès Secondat de Montesquieu, Jean-François Rivière
25 *
26 * Home page: http://www.lodel.org
27 *
28 * E-Mail: lodel@lodel.org
29 *
30 * All Rights Reserved
31 *
32 * This program is free software; you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation; either version 2 of the License, or
35 * (at your option) any later version.
36 *
37 * This program is distributed in the hope that it will be useful,
38 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 * GNU General Public License for more details.
41 *
42 * You should have received a copy of the GNU General Public License
43 * along with this program; if not, write to the Free Software
44 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
45 *
46 * @author Ghislain Picard
47 * @author Jean Lamy
48 * @author Bruno Cénou
49 * @author Loéc Bontonou
50 * @copyright 2001-2002, Ghislain Picard, Marin Dacos
51 * @copyright 2003, Ghislain Picard, Marin Dacos, Luc Santeramo, Nicolas Nutten, Anne Gentil-Beccot
52 * @copyright 2004, Ghislain Picard, Marin Dacos, Luc Santeramo, Anne Gentil-Beccot, Bruno Cénou
53 * @copyright 2005, Ghislain Picard, Marin Dacos, Luc Santeramo, Gautier Poupeau, Jean Lamy, Bruno Cénou
54 * @copyright 2006, Marin Dacos, Luc Santeramo, Bruno Cénou, Jean Lamy, Mikaël Cixous, Sophie Malafosse
55 * @copyright 2007, Marin Dacos, Bruno Cénou, Sophie Malafosse, Pierre-Alain Mignot
56 * @copyright 2008, Marin Dacos, Bruno Cénou, Pierre-Alain Mignot, Inès Secondat de Montesquieu, Jean-François Rivière
57 * @copyright 2009, Marin Dacos, Bruno Cénou, Pierre-Alain Mignot, Inès Secondat de Montesquieu, Jean-François Rivière
58 * @licence http://www.gnu.org/copyleft/gpl.html
59 * @version CVS:$Id:
60 * @package lodel/source
61 */
62 require 'siteconfig.php';
63
64 try
65 {
66 include 'auth.php';
67 authenticate();
68
69 define('TOKENVALID', 24); // tokens lifetime in hours
70 define('MAXIDS', 10); // max delivered identifiers
71 define('MAXRECORDS', 10); // max delivered records
72 $metadataformats = array ('oai_dc'); // only Dublin Core at the moment
73
74 $dateformat = '';
75
76 function getOut($hostname)
77 {
78 header ("http/1.0 403 Forbidden");
79 echo "Host $hostname is not allowed";
80 log_access($hostname, 1);
81 exit();
82 }
83
84 /*function log_access($hostname, $denied = 0){
85 global $db;
86 $db->execute(lq("INSERT INTO #_TP_oailogs (host, date, denied) VALUES ('$hostname', ".date('YmdHis').", $denied)"));
87 }*/
88
89 function log_access($hostname, $denied = 0)
90 {
91 global $db;
92 $db->execute(lq("INSERT INTO #_TP_oailogs (host, denied) VALUES ('". $hostname. "','". $denied. "')")) or trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
93 }
94
95
96
97
98 /**
99 * Generates OAI error messages.
100 *
101 * Genere les messages d'erreur OAI.
102 *
103 * @param string $code le code d'erreur
104 * @param string $argument l'argument passé. Par défaut vide
105 * @param string $value la valeur de l'argument. Par défaut vide
106 * @return une chaine xml d'erreur <error code="">message</error>
107 */
108 function oai_error ($code, $argument = '', $value = '')
109 {
110 global $request;
111 global $request_err;
112
113 switch ($code) {
114 case 'badArgument' :
115 if($argument == 'granularity'){
116 $text = 'mismatched granularities in from/until.';
117 break;
118 }
119 $text = "The argument '$argument' (value='$value') included in the request is not valid.";
120 break;
121 case 'badGranularity' :
122 $text = "The value '$value' of the argument '$argument' is not valid.";
123 $code = 'badArgument';
124 break;
125 case 'badResumptionToken' :
126 $text = "The resumptionToken '$value' does not exist or has already expired.";
127 break;
128 case 'badRequestMethod' :
129 $text = "The request method '$argument' is unknown.";
130 $code = 'badVerb';
131 break;
132 case 'badVerb' :
133 $text = "The verb '$argument' provided in the request is illegal.";
134 break;
135 case 'cannotDisseminateFormat' :
136 $text = "The metadata format '$value' given by $argument is not supported by this repository.";
137 break;
138 case 'exclusiveArgument' :
139 $text = 'The usage of resumptionToken as an argument allows no other arguments.';
140 $code = 'badArgument';
141 break;
142 case 'idDoesNotExist' :
143 $text = "The value '$value' of the identifier is illegal for this repository.";
144 break;
145 case 'missingArgument' :
146 $text = "The required argument '$argument' is missing in the request.";
147 $code = 'badArgument';
148 break;
149 case 'noRecordsMatch' :
150 $text = 'The combination of the given values results in an empty list.';
151 break;
152 case 'noMetadataFormats' :
153 $text = 'There are no metadata formats available for the specified item.';
154 break;
155 case 'noVerb' :
156 $text = 'The request does not provide any verb.';
157 $code = 'badVerb';
158 break;
159 case 'noSetHierarchy' :
160 $text = 'This repository does not support sets.';
161 break;
162 case 'sameArgument' :
163 $text = 'Do not use them same argument more than once.';
164 $code = 'badArgument';
165 break;
166 case 'sameVerb' :
167 $text = 'Do not use verb more than once.';
168 $code = 'badVerb';
169 break;
170 default:
171 $text = "Unknown error: code: '$code', argument: '$argument', value: '$value'";
172 $code = 'badArgument';
173 }
174
175 $error .= '<error code="'. xmlstr($code, 'utf-8', false). '">'. xmlstr($text, 'utf-8', false). '</error>'. "\n";
176 return $error;
177 }
178
179 /**
180 * Transforme une chaine pour l'inclure dans un fichier XML
181 *
182 * @param string $string la chaine de caractéres
183 * @param string $charset le jeu de caractére de la chaine (utf-8 par défaut).
184 * @param boolean $xmlescaped un boolean indiquant si le xml doit étre échappé ou non. Par défaut é false.
185 * @return la chaéne XML
186 */
187 function xmlstr ($string, $charset = 'utf-8', $xmlescaped = false)
188 {
189 $string = stripslashes($string);
190 // just remove invalid characters
191 $pattern = "/[\x-\x8\xb-\xc\xe-\x1f]/";
192 $string = preg_replace($pattern, '', $string);
193
194 // escape only if string is not escaped
195 if (!$xmlescaped) {
196 $xmlstr = htmlspecialchars($string, ENT_QUOTES);
197 }
198
199 if ($charset != 'utf-8') {
200 $xmlstr = utf8_encode($xmlstr);
201 }
202 return $xmlstr;
203 }
204
205 /**
206 * Extracts a token's infos from the database.
207 * If the token doesn't exist, the error is handled in the 'verbs_processing' function.
208 *
209 * Extrait de la bd les infos concernant le token.
210 * Si le token n'existe pas, l'erreur est traitee par la suite dans la fonction "verbs_processing".
211 *
212 * @param string $token le token
213 * @return un resultset SQL
214 */
215 function get_token_info($token)
216 {
217 global $db;
218 $result = $db->getrow(lq("SELECT * FROM #_TP_oaitokens WHERE token ='". $token. "'"));
219 if ($result === false) {
220 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
221 }
222 return $result;
223 }
224
225 /**
226 * Deletes a token from table oaitokens once it has been used.
227 *
228 * Une fois un token exploite, il est retire de la table oaitokens.
229 * @param string $token le token
230 * @return rien
231 */
232 function del_token($token)
233 {
234 global $db;
235 $result = $db->execute(lq("DELETE FROM #_TP_oaitokens WHERE token ='". $token. "'"));
236 if ($result === false) {
237 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
238 }
239 }
240
241 /**
242 * Inserts new token in table oaitokens.
243 *
244 * Insere un nouveau token dans la table oaitokens.
245 *
246 * @param string $token le token
247 * @param string $where la clause where
248 * @param string $metadataprefix le format de métadonnées de la requéte
249 * @param integer $deliveredrecords le nombre d'enregistrements délivrés
250 * @param datetime $expirationdatetime le datetime d'expiration du token.
251 */
252 function insert_token($token, $where, $metadataprefix, $deliveredrecords, $expirationdatetime)
253 {
254 global $db;
255 $q = "INSERT INTO #_TP_oaitokens (token, query, metadataprefix, deliveredrecords, expirationdatetime)";
256
257 $q .= " VALUES('".$token. "', '".addslashes($where). "', '". $metadataprefix. "', '". $deliveredrecords. "', '". $expirationdatetime. "')";
258
259 $result = $db->execute(lq($q));
260
261 if ($result === false) {
262 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
263 }
264 }
265
266
267
268 /**
269 * Deletes outdated tokens from table oaitokens.
270 *
271 * Supprime les tokens dont la date de validite est depassee.
272 */
273 function clean_expired_tokens()
274 {
275 global $db;
276 $result = $db->execute(lq("DELETE FROM #_TP_oaitokens WHERE expirationdatetime < ". date('YmdHis', time() - (TOKENVALID*3600))));
277 if ($result === false) {
278 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
279 }
280 }
281
282 /**
283 * Transforme une date SQL en timestamp unix
284 * @param string $date la date au format datetime de MySQL
285 * @return le timestamp unix
286 */
287 function sql2TS($date)
288 {
289 $date = str_replace(array(' ', '-', ':'), '', $date);
290 return mktime(substr($date, 8, 2), substr($date, 10, 2), substr($date, 12, 2), substr($date, 4, 2), substr($date, 6, 2), substr($date, 0, 4));
291 }
292
293 /**
294 * dc types are defined in lodel's database using the template : "dc.name"
295 * to fit the OAI protocol, we have to rename them using the template "dc:name"
296 *
297 * les types dc sont definis dans la base de donnees en utilisant la forme "dc.nom",
298 * on les renomme en "dc:nom" pour coller au protocole OAI
299 *
300 * @param string $str la chaine é modifier
301 * @return la chaine modifiée
302 */
303 function dc_rename($str)
304 {
305 return preg_replace("/dc./", "dc:", $str);
306 }
307
308
309 /**
310 * Only a limited set of characters is available for sets' names.
311 * This filter replaces the unapropriate characters by valid ones.
312 *
313 * Les noms de sets ne peuvent comporter qu'un ensemble limite de caracteres.
314 * Ce filtre remplace les caracteres inappropries.
315 *
316 * @param string $str la chaine é modifier
317 * @return la chaine modifiée
318 */
319 function strip_set($str)
320 {
321 $str = makeSortKey($str);
322 return preg_replace("/[^a-zA-Z0-9_.!~*\'()]/", "_", $str);
323 }
324
325 /**
326 * Uses $id_class_fields to get the name of an entity's dc.description field,
327 * extract its content from the database and return it.
328 *
329 * A partir de la table mettant en relation un id d'entite avec le nom de sa
330 * classe et celui du champ dc.description correspondant, on renvoit le contenu
331 * de ce champ dc.descrition.
332 *
333 * @param integer l'identifiant de l'entité
334 * @return un resultSet SQL
335 */
336 function get_dc_description($id)
337 {
338 global $id_class_fields;
339 global $db;
340 if ($id_class_fields[$id]['dc.description']) {
341 $class_table = "#_TP_".$id_class_fields[$id]['class'];
342 $field = $id_class_fields[$id]['dc.description'];
343 $result =$db->getOne(lq("SELECT $field FROM $class_table WHERE identity = '$id'"));
344 if ($result===false) {
345 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
346 }
347 }
348 return $result;
349 }
350
351
352
353 /**
354 * Uses $id_class_fields to get the name of an entity's dc.language field,
355 * extract its content from the database and return it.
356 *
357 * A partir de la table mettant en relation un id d'entite avec le nom de sa
358 * classe et celui du champ dc.language correspondant, on renvoit le contenu
359 * de ce champ dc.language.
360 *
361 * @param integer l'identifiant de l'entité
362 * @return un resultSet SQL
363 */
364 function get_dc_language($id)
365 {
366 global $id_class_fields;
367 global $db;
368
369 if ($id_class_fields[$id]['dc.language']) {
370 $class_table = "#_TP_".$id_class_fields[$id]['class'];
371 $field = $id_class_fields[$id]['dc.language'];
372 $result = $db->getone(lq("SELECT $class_table.$field FROM $class_table WHERE $class_table.identity = $id"));
373 if ($result===false) {
374 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
375 }
376 }
377 return $result;
378 }
379
380 /**
381 * Tests the 'verb' argument.
382 */
383 function verbs_processing()
384 {
385 global $args;
386 global $context;
387 global $errors;
388 global $db;
389 global $metadataformats;
390 global $format;
391 global $resumptionToken;
392
393 if ($args['verb']) {
394 $format = strtolower($args['verb']);
395 switch ($args['verb']) {
396 case 'Identify':
397 unset($args['verb']);
398 illegal_parameters();
399 break;
400 case 'ListMetadataFormats':
401 unset($args['verb']);
402 if ($args['identifier']) {
403 check_identifier($args['identifier']);
404 unset($args['identifier']);
405 }
406 illegal_parameters();
407 break;
408 case 'ListSets':
409 unset($args['verb']);
410 if($args['resumptionToken']) {
411 $resumptionToken = $args['resumptionToken'];
412 unset($args['resumptionToken']);
413 }
414 illegal_parameters();
415 break;
416 case 'GetRecord':
417 unset($args['verb']);
418 if (!$args['identifier']) {
419 $errors .= oai_error('missingArgument', 'identifier');
420 } else {
421 check_identifier($args['identifier']);
422 unset($args['identifier']);
423 }
424 if (!$args['metadataPrefix']) {
425 $errors .= oai_error('missingArgument', 'metadataPrefix');
426 } else {
427 check_mdp($args['metadataPrefix']);
428 unset($args['metadataPrefix']);
429 }
430 illegal_parameters();
431 break;
432 case 'ListIdentifiers':
433 check_records();
434 illegal_parameters();
435 break;
436 case 'ListRecords':
437 check_records();
438 illegal_parameters();
439 break;
440 default:
441 $errors .= oai_error('badVerb', $args['verb']);
442 } /*switch */
443
444 if(!$errors){
445 $context['oai_where'] .= "AND #_TP_entities.id ".sql_in_array($context['oai_ids'])." AND #_TP_types.oaireferenced >0 AND #_TP_entities.idtype = #_TP_types.id AND #_TP_entities.status >0 AND #_TP_types.status >0 AND #_TP_entities.creationdate<".date('Ymd');
446 $context['oai_where'] = substr($context['oai_where'], 4);
447
448 if($format == 'listidentifiers' || $format == 'listrecords') {
449 $MAX = $format == 'listidentifiers' ? $context['oai_maxids'] : $context['oai_maxrecords'];
450
451 $query = "SELECT #_TP_entities.id FROM #_entitiestypesjoin_ WHERE ".$context[oai_where];
452 $result =$db->execute(lq($query));
453 if ($result === false) {
454 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
455 }
456 $context['oai_nbtot'] = $result->RowCount();
457
458 $tokenValid = TOKENVALID*3600;
459 $exp_date = time()+$tokenValid;
460 $my_expirationdatetime = date('YmdHis', $exp_date);
461 $expirationdatetime = gmstrftime('%Y-%m-%dT%TZ', $exp_date);
462
463 if (isset($resumptionToken)) {
464 $info = get_token_info($resumptionToken);
465 if (is_array($info) && sql2TS($info['expirationdatetime']) > (time() - $tokenValid)) {
466 $deliveredrecords = $info['deliveredrecords'];
467 $context['oai_where'] = $info['query'];
468 $metadataPrefix = $info['metadataprefix'];
469 unset($errors);
470 del_token($resumptionToken);
471 } else {
472 $errors = oai_error('badResumptionToken', '', $resumptionToken);
473 // echo $info['expirationdatetime'];
474 }
475 }
476 // Will we need a ResumptionToken?
477 $context['oai_offset'] = isset($deliveredrecords) ? $deliveredrecords : 0;
478 $query .= " LIMIT ". $context['oai_offset'].", $MAX";
479 $result =$db->execute(lq($query));
480 if ($result === false) {
481 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
482 }
483
484 $deliveredrecords += $result->RowCount();
485
486 if ($context['oai_nbtot'] - $deliveredrecords > 0) {
487 $token = uniqid(8);
488 insert_token($token, $context['oai_where'], $metadataPrefix, $deliveredrecords, $my_expirationdatetime);
489 $context['oai_restoken'] =
490 ' <resumptionToken expirationDate="'.$expirationdatetime.'"
491 completeListSize="'.$context['oai_nbtot'].'"
492 cursor="'.$deliveredrecords.'">'.$token."</resumptionToken>\n";
493 }
494 // Last delivery, return empty ResumptionToken
495
496 if($context['oai_nbtot'] == 0) {
497 $errors = oai_error('noRecordsMatch');
498 } elseif ($context['oai_nbtot'] <= $deliveredrecords) {
499 del_token($token);
500 $context['oai_restoken'] =
501 ' <resumptionToken completeListSize="'.$context['oai_nbtot'].'"
502 cursor="'.$deliveredrecords.'"></resumptionToken>'."\n";
503 }
504 }
505 }
506 } else {
507 $errors = oai_error('noVerb');
508 }
509 }
510
511
512
513 /**
514 * ListRecords and ListIdentifiers accept the same parameters, the shared
515 * tests are regrouped in this function.
516 *
517 * ListRecords et ListIdentifiers acceptent les meme parametres, les tests
518 * communs sont donc regroupes dans cette fonction.
519 */
520 function check_records ()
521 {
522 global $args;
523 global $context;
524 global $errors;
525 global $db;
526 global $metadataformats;
527 global $resumptionToken;
528
529 unset($args['verb']);
530 if ((!$args['metadataPrefix']) && (!$args['resumptionToken'])) {
531 $errors .= oai_error('missingArgument', 'metadataPrefix');
532 } elseif($args['resumptionToken'] && (count($args)>1)) {
533 $errors .= oai_error('exclusiveArgument');
534 } else {
535 // patterns to test date granularity
536 $longdate = "/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/";
537 $shortdate = "/^\\d{4}-\\d{2}-\\d{2}$/";
538
539 if ($args['from']) {
540 $from = $args['from'];
541 if (preg_match($longdate, $from)) {
542 $context['oai_where'] .= "AND (creationdate>= '". $from. "' || modificationdate >= '". $from. "')";
543 } elseif (preg_match($shortdate, $from)) {
544 $context['oai_where'] .= "AND (creationdate>= '". $from. "' || modificationdate >= '". $from. "')";
545 $context['short_date'] = true;
546 } else {
547 $errors .= oai_error('badArgument', 'from', $from);
548 unset($from);
549 }
550 unset($args['from']);
551 }
552
553 if ($args['until']) {
554 $until = $args['until'];
555 if (preg_match($longdate, $until)) {
556 $context['oai_where'] .= "AND creationdate <= '".$until."'";
557 } elseif (preg_match($shortdate, $until)) {
558 $context['oai_where'] .= "AND creationdate <= '".$until."'";
559 $context['short_date'] = true;
560 } else {
561 $errors .= oai_error('badArgument', 'until', $until);
562 unset($until);
563 }
564 unset($args['until']);
565 }
566
567 if ($args['metadataPrefix']) {
568 check_mdp($args['metadataPrefix']);
569 unset($args['metadataPrefix']);
570 }
571
572 if($args['set']) {
573 $set = $args['set'];
574 $context['oai_ids'] = array();
575
576 $result =$db->execute(lq("SELECT id FROM #_TP_entities, #_TP_relations WHERE id2 = '".substr($args['set'], 4)."'"));
577 if ($result === false) {
578 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
579 }
580
581 while (!$result->EOF) {
582 $row = $result->fields;
583 $context['oai_ids'][] = $row['id'];
584 $result->MoveNext();
585 }
586 unset($args['set']);
587 }
588 if($args['resumptionToken']) {
589 $resumptionToken = $args['resumptionToken'];
590 unset($args['resumptionToken']);
591 }
592 if(isset($from)&&isset($until)&&strlen($from)!=strlen($until)){
593 $errors .= oai_error('badArgument', 'granularity', '');
594 }
595 }
596 }
597
598 /**
599 * Tests the 'metadataPrefix' argument.
600 *
601 * Verifie la validite de l'information liee a l'argument 'metadataPrefix'.
602 *
603 * @param string $val la valeur é vérifier
604 */
605 function check_mdp ($val)
606 {
607 global $errors;
608 global $metadataformats;
609
610 if (in_array($val, $metadataformats)) {
611 $metadataPrefix = $val;
612 } else {
613 $errors .= oai_error('cannotDisseminateFormat', 'metadataPrefix', $val);
614 }
615 }
616
617 /**
618 * Tests the 'Identifier' argument.
619 *
620 * Verifie la validite de l'information liee a l'argument 'Identifier'.
621 *
622 * @param string $val la valeur de l'identifier OAI
623 */
624 function check_identifier ($val)
625 {
626 global $context;
627 global $errors;
628 global $metadataformats;
629
630 $identifier = $val;
631 // remove the OAI part to get the identifier
632 $id = str_replace($context['oai_prefix'], '', $identifier);
633 if (in_array($id, $context['oai_ids'])) {
634 $context['oai_ids'] = array();
635 $context['oai_ids'][] = $id;
636 } else {
637 $errors .= oai_error('idDoesNotExist', '', $identifier);
638 }
639 }
640
641 /**
642 * Tests for illegal parameters and generate the appropriate error messages.
643 *
644 * Traite la presence d'arguments illegaux en generant le message d'erreur approprie.
645 */
646 function illegal_parameters()
647 {
648 global $args;
649 global $errors;
650
651 if ($args) {
652 foreach ($args as $key=>$val) {
653 $errors .= oai_error('badArgument', $key, $val);
654 }
655 }
656 }
657
658 //----------- DEBUT DU SCRIPT -----------//
659
660 /**
661 * Check if the required options are defined (oai_identifier, oai_allow,
662 * oai_deny) and store their values.
663 *
664 * Verification de l'existence des options requises (oai_identifier, oai_allow,
665 * oai_deny) et recuperation de leur valeur.
666 * Le groupe d'option oai est aussi requis
667 */
668 $result = getoption(array('oai.oai_identifier', 'oai.oai_allow', 'oai.oai_deny'));
669
670 if($result['oai.oai_identifier']) {
671 $context['oai_identifier'] = $result['oai.oai_identifier'];
672 }
673
674 if($result['oai.oai_allow']){
675 $allowed = $result['oai.oai_allow'];
676 }
677
678 if($result['oai.oai_deny']){
679 $denied = $result['oai.oai_deny'];
680 }
681
682 if(!isset($allowed) && !isset($denied)){
683 echo "<code>Acces list of your OAI repository is not configured, please check site options.<br />";
684 echo "In order to enable this you must configure an optiongroup called <em>oai</em> ".
685 "containing 2 options : <em>oai_allow</em> and <em>oai_deny</em>. By default,".
686 " <em>oai_allow</em> should be set to '*'</code>";
687 exit;
688 }
689
690 $oai_allowed = explode(',', $allowed);
691 $oai_denied = explode(',', $denied);
692
693 if (!isset($_SERVER['REMOTE_HOST'])) {
694 $hostname = gethostbyaddr($_SERVER['REMOTE_ADDR']);
695 }
696 else {
697 $hostname = $_SERVER['REMOTE_HOST'];
698 }
699
700 /**
701 * Identifies the request's emitter and check its rights.
702 *
703 * Identification de l'emetteur de la requete et verification de ses droits.
704 */
705 if(in_array($_SERVER['REMOTE_ADDR'], $oai_denied) || in_array($hostname, $oai_denied) || (count($oai_denied) == 1 && $oai_denied[0] == '*' && !in_array($_SERVER['REMOTE_ADDR'], $oai_allowed) && !in_array($hostname, $oai_allowed))) {
706 getOut($hostname);
707 }
708
709 if(!(in_array($_SERVER['REMOTE_ADDR'], $oai_allowed) || in_array($hostname, $oai_allowed) || (count($oai_allowed) == 1 && $oai_allowed[0] == '*'))){
710 getOut($hostname);
711 }
712
713 log_access($hostname);
714 $oai_open = "<?xml version=\"1.0\" encoding=\"utf-8\"?><OAI-PMH xmlns=\"http://www.openarchives.org/OAI/2.0/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd\">
715 <responseDate>". gmstrftime('%Y-%m-%dT%TZ', time()). "</responseDate>
716 <request>". dirname($context['currenturl']). '/oai20.'. $context['extensionscripts']. "</request>";
717
718 $oai_close = "</OAI-PMH>\n";
719
720 /* A sortir dans les options du site ? *************************************************/
721 $context['oai_prefix'] = isset($context['oai_identifier']) ? $context['oai_identifier'] : 'oai:'. str_replace(array('http://', '/'), array('', '.'), dirname($context['currenturl'])). ':';
722 $context['oai_maxids'] = MAXIDS;
723 $context['oai_maxrecords'] = MAXRECORDS;
724 /***************************************************************************************/
725
726 /**
727 * List of OAI-referenced entities.
728 *
729 * Construit la liste des entites referencees par l'OAI.
730 */
731 $result = $db->execute(lq("SELECT #_TP_entities.id FROM #_entitiestypesjoin_ WHERE #_TP_entities.idtype = #_TP_types.id AND #_TP_types.oaireferenced = 1"));
732 if ($result === false) {
733 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
734 }
735
736 while (!$result->EOF) {
737 $row = $result->fields;
738 $context['oai_ids'][] = $row['id'];
739 $result->MoveNext();
740 }
741
742 if(!$context['oai_ids']) {
743 $errors .= oai_error('noRecordsMatch');
744 header("Content-type: application/xml");
745 echo _indent($oai_open. $errors. $oai_close);
746 exit;
747 }
748
749 /**
750 * Creates a table associating an entity's id with its class name and its associated
751 * fields which are equivalent to dc.description or dc.language.
752 *
753 * Creation de la table indiquant pour chaque entite referencee son nom de
754 * classe et les noms de champs equivalents a dc.description et dc.language.
755 */
756
757 $id_class_fields = array();
758 $result = $db->execute(lq("SELECT #_TP_entities.id, #_TP_types.class, #_TP_tablefields.name, #_TP_tablefields.g_name
759 FROM #_entitiestypesjoin_, #_TP_tablefieldgroups, #_TP_tablefields
760 WHERE (#_TP_tablefields.g_name = 'dc.description' || #_TP_tablefields.g_name = 'dc.language')
761 AND #_TP_tablefields.class = #_TP_types.class
762 AND #_TP_types.oaireferenced = '1'
763 AND #_TP_entities.idtype = #_TP_types.id"));
764 if ($result === false) {
765 trigger_error("SQL ERROR :<br />".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR);
766 }
767
768 while (!$result->EOF) {
769 $row = $result->fields;
770 $id = $row['id'];
771 $id_class_fields[$id]['class'] = $row['class'];
772 $id_class_fields[$id][$row['g_name']] = $row['name'];
773 $result->MoveNext();
774 }
775
776 /**
777 * Stores the request's parameters.
778 *
779 * Recuperation des parametres de la requete.
780 */
781 if ($_SERVER['REQUEST_METHOD'] == 'GET') {
782 $args = $_GET;
783 $getarr = explode('&', $_SERVER['QUERY_STRING']);
784 } elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
785 $args = $_POST;
786 } else {
787 $errors .= oai_error('badRequestMethod', $_SERVER['REQUEST_METHOD']);
788 }
789
790 /**
791 * Detects duplicate arguments in GET request.
792 *
793 * Detecte les arguments dupliques dans une requete passee par GET.
794 */
795 if (isset($getarr)) {
796 if (count($getarr) != count($args)) {
797 $errors .= oai_error('sameArgument');
798 }
799 }
800
801 /**
802 * Call to the 'clean_request_variable' function in func.php to remove potential
803 * risks of injection in the request's arguments.
804 *
805 * Utilisation de la fonction "clean_request_variable" de func.php pour supprimer
806 * tout risque d'injection dans les arguments de la requete.
807 */
808 array_walk($args, 'clean_request_variable');
809 $context['oai_args'] = '';
810 if (is_array($args)) {
811 foreach ($args as $key => $val) {
812 $context['oai_args'] .= ' '.$key.'="'.htmlspecialchars(stripslashes($val)).'"';
813 }
814 }
815
816 /**
817 * Process the request.
818 *
819 * Traitement des arguments de la requete.
820 */
821 verbs_processing();
822
823 /**
824 * If error messages were generated, they are displayed and the program ends.
825 *
826 * Si des messages d'erreur ont ete generes, ils sont affiches et l'execution du
827 * programme se termine.
828 */
829 if(isset($errors)) {
830 header("Content-type: application/xml");
831 echo _indent($oai_open.$errors.$oai_close);
832 exit;
833 }
834
835
836
837 /**
838 * Generates response date, required by the protocol.
839 *
840 * Generation de la date de reponse, requise par le protocole.
841 */
842
843 $context['oai_responsedate'] = gmstrftime('%Y-%m-%dT%TZ', time());
844
845
846 /**
847 * Displays the response.
848 *
849 * Affichage de la reponse.
850 */
851
852 $base = 'oai20';
853 //$view->renderCached($context,$base);
854 View::getView()->render($base);
855
856
857 /**
858 * Suppress outdated tokens.
859 *
860 * Suppression des tokens dont la date limite de validite a ete atteinte.
861 */
862
863 clean_expired_tokens();
864 }
865 catch(LodelException $e)
866 {
867 echo $e->getContent();
868 exit();
869 }
870 ?>