execute(lq("INSERT INTO #_TP_oailogs (host, date, denied) VALUES ('$hostname', ".date('YmdHis').", $denied)")); }*/ function log_access($hostname, $denied = 0) { global $db; $db->execute(lq("INSERT INTO #_TP_oailogs (host, denied) VALUES ('". $hostname. "','". $denied. "')")) or trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } /** * Generates OAI error messages. * * Genere les messages d'erreur OAI. * * @param string $code le code d'erreur * @param string $argument l'argument passé. Par défaut vide * @param string $value la valeur de l'argument. Par défaut vide * @return une chaine xml d'erreur message */ function oai_error ($code, $argument = '', $value = '') { global $request; global $request_err; switch ($code) { case 'badArgument' : if($argument == 'granularity'){ $text = 'mismatched granularities in from/until.'; break; } $text = "The argument '$argument' (value='$value') included in the request is not valid."; break; case 'badGranularity' : $text = "The value '$value' of the argument '$argument' is not valid."; $code = 'badArgument'; break; case 'badResumptionToken' : $text = "The resumptionToken '$value' does not exist or has already expired."; break; case 'badRequestMethod' : $text = "The request method '$argument' is unknown."; $code = 'badVerb'; break; case 'badVerb' : $text = "The verb '$argument' provided in the request is illegal."; break; case 'cannotDisseminateFormat' : $text = "The metadata format '$value' given by $argument is not supported by this repository."; break; case 'exclusiveArgument' : $text = 'The usage of resumptionToken as an argument allows no other arguments.'; $code = 'badArgument'; break; case 'idDoesNotExist' : $text = "The value '$value' of the identifier is illegal for this repository."; break; case 'missingArgument' : $text = "The required argument '$argument' is missing in the request."; $code = 'badArgument'; break; case 'noRecordsMatch' : $text = 'The combination of the given values results in an empty list.'; break; case 'noMetadataFormats' : $text = 'There are no metadata formats available for the specified item.'; break; case 'noVerb' : $text = 'The request does not provide any verb.'; $code = 'badVerb'; break; case 'noSetHierarchy' : $text = 'This repository does not support sets.'; break; case 'sameArgument' : $text = 'Do not use them same argument more than once.'; $code = 'badArgument'; break; case 'sameVerb' : $text = 'Do not use verb more than once.'; $code = 'badVerb'; break; default: $text = "Unknown error: code: '$code', argument: '$argument', value: '$value'"; $code = 'badArgument'; } $error .= ''. xmlstr($text, 'utf-8', false). ''. "\n"; return $error; } /** * Transforme une chaine pour l'inclure dans un fichier XML * * @param string $string la chaine de caractéres * @param string $charset le jeu de caractére de la chaine (utf-8 par défaut). * @param boolean $xmlescaped un boolean indiquant si le xml doit étre échappé ou non. Par défaut é false. * @return la chaéne XML */ function xmlstr ($string, $charset = 'utf-8', $xmlescaped = false) { $string = stripslashes($string); // just remove invalid characters $pattern = "/[\x-\x8\xb-\xc\xe-\x1f]/"; $string = preg_replace($pattern, '', $string); // escape only if string is not escaped if (!$xmlescaped) { $xmlstr = htmlspecialchars($string, ENT_QUOTES); } if ($charset != 'utf-8') { $xmlstr = utf8_encode($xmlstr); } return $xmlstr; } /** * Extracts a token's infos from the database. * If the token doesn't exist, the error is handled in the 'verbs_processing' function. * * Extrait de la bd les infos concernant le token. * Si le token n'existe pas, l'erreur est traitee par la suite dans la fonction "verbs_processing". * * @param string $token le token * @return un resultset SQL */ function get_token_info($token) { global $db; $result = $db->getrow(lq("SELECT * FROM #_TP_oaitokens WHERE token ='". $token. "'")); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } return $result; } /** * Deletes a token from table oaitokens once it has been used. * * Une fois un token exploite, il est retire de la table oaitokens. * @param string $token le token * @return rien */ function del_token($token) { global $db; $result = $db->execute(lq("DELETE FROM #_TP_oaitokens WHERE token ='". $token. "'")); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } } /** * Inserts new token in table oaitokens. * * Insere un nouveau token dans la table oaitokens. * * @param string $token le token * @param string $where la clause where * @param string $metadataprefix le format de métadonnées de la requéte * @param integer $deliveredrecords le nombre d'enregistrements délivrés * @param datetime $expirationdatetime le datetime d'expiration du token. */ function insert_token($token, $where, $metadataprefix, $deliveredrecords, $expirationdatetime) { global $db; $q = "INSERT INTO #_TP_oaitokens (token, query, metadataprefix, deliveredrecords, expirationdatetime)"; $q .= " VALUES('".$token. "', '".addslashes($where). "', '". $metadataprefix. "', '". $deliveredrecords. "', '". $expirationdatetime. "')"; $result = $db->execute(lq($q)); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } } /** * Deletes outdated tokens from table oaitokens. * * Supprime les tokens dont la date de validite est depassee. */ function clean_expired_tokens() { global $db; $result = $db->execute(lq("DELETE FROM #_TP_oaitokens WHERE expirationdatetime < ". date('YmdHis', time() - (TOKENVALID*3600)))); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } } /** * Transforme une date SQL en timestamp unix * @param string $date la date au format datetime de MySQL * @return le timestamp unix */ function sql2TS($date) { $date = str_replace(array(' ', '-', ':'), '', $date); 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)); } /** * dc types are defined in lodel's database using the template : "dc.name" * to fit the OAI protocol, we have to rename them using the template "dc:name" * * les types dc sont definis dans la base de donnees en utilisant la forme "dc.nom", * on les renomme en "dc:nom" pour coller au protocole OAI * * @param string $str la chaine é modifier * @return la chaine modifiée */ function dc_rename($str) { return preg_replace("/dc./", "dc:", $str); } /** * Only a limited set of characters is available for sets' names. * This filter replaces the unapropriate characters by valid ones. * * Les noms de sets ne peuvent comporter qu'un ensemble limite de caracteres. * Ce filtre remplace les caracteres inappropries. * * @param string $str la chaine é modifier * @return la chaine modifiée */ function strip_set($str) { $str = makeSortKey($str); return preg_replace("/[^a-zA-Z0-9_.!~*\'()]/", "_", $str); } /** * Uses $id_class_fields to get the name of an entity's dc.description field, * extract its content from the database and return it. * * A partir de la table mettant en relation un id d'entite avec le nom de sa * classe et celui du champ dc.description correspondant, on renvoit le contenu * de ce champ dc.descrition. * * @param integer l'identifiant de l'entité * @return un resultSet SQL */ function get_dc_description($id) { global $id_class_fields; global $db; if ($id_class_fields[$id]['dc.description']) { $class_table = "#_TP_".$id_class_fields[$id]['class']; $field = $id_class_fields[$id]['dc.description']; $result =$db->getOne(lq("SELECT $field FROM $class_table WHERE identity = '$id'")); if ($result===false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } } return $result; } /** * Uses $id_class_fields to get the name of an entity's dc.language field, * extract its content from the database and return it. * * A partir de la table mettant en relation un id d'entite avec le nom de sa * classe et celui du champ dc.language correspondant, on renvoit le contenu * de ce champ dc.language. * * @param integer l'identifiant de l'entité * @return un resultSet SQL */ function get_dc_language($id) { global $id_class_fields; global $db; if ($id_class_fields[$id]['dc.language']) { $class_table = "#_TP_".$id_class_fields[$id]['class']; $field = $id_class_fields[$id]['dc.language']; $result = $db->getone(lq("SELECT $class_table.$field FROM $class_table WHERE $class_table.identity = $id")); if ($result===false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } } return $result; } /** * Tests the 'verb' argument. */ function verbs_processing() { global $args; global $context; global $errors; global $db; global $metadataformats; global $format; global $resumptionToken; if ($args['verb']) { $format = strtolower($args['verb']); switch ($args['verb']) { case 'Identify': unset($args['verb']); illegal_parameters(); break; case 'ListMetadataFormats': unset($args['verb']); if ($args['identifier']) { check_identifier($args['identifier']); unset($args['identifier']); } illegal_parameters(); break; case 'ListSets': unset($args['verb']); if($args['resumptionToken']) { $resumptionToken = $args['resumptionToken']; unset($args['resumptionToken']); } illegal_parameters(); break; case 'GetRecord': unset($args['verb']); if (!$args['identifier']) { $errors .= oai_error('missingArgument', 'identifier'); } else { check_identifier($args['identifier']); unset($args['identifier']); } if (!$args['metadataPrefix']) { $errors .= oai_error('missingArgument', 'metadataPrefix'); } else { check_mdp($args['metadataPrefix']); unset($args['metadataPrefix']); } illegal_parameters(); break; case 'ListIdentifiers': check_records(); illegal_parameters(); break; case 'ListRecords': check_records(); illegal_parameters(); break; default: $errors .= oai_error('badVerb', $args['verb']); } /*switch */ if(!$errors){ $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'); $context['oai_where'] = substr($context['oai_where'], 4); if($format == 'listidentifiers' || $format == 'listrecords') { $MAX = $format == 'listidentifiers' ? $context['oai_maxids'] : $context['oai_maxrecords']; $query = "SELECT #_TP_entities.id FROM #_entitiestypesjoin_ WHERE ".$context[oai_where]; $result =$db->execute(lq($query)); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } $context['oai_nbtot'] = $result->RowCount(); $tokenValid = TOKENVALID*3600; $exp_date = time()+$tokenValid; $my_expirationdatetime = date('YmdHis', $exp_date); $expirationdatetime = gmstrftime('%Y-%m-%dT%TZ', $exp_date); if (isset($resumptionToken)) { $info = get_token_info($resumptionToken); if (is_array($info) && sql2TS($info['expirationdatetime']) > (time() - $tokenValid)) { $deliveredrecords = $info['deliveredrecords']; $context['oai_where'] = $info['query']; $metadataPrefix = $info['metadataprefix']; unset($errors); del_token($resumptionToken); } else { $errors = oai_error('badResumptionToken', '', $resumptionToken); // echo $info['expirationdatetime']; } } // Will we need a ResumptionToken? $context['oai_offset'] = isset($deliveredrecords) ? $deliveredrecords : 0; $query .= " LIMIT ". $context['oai_offset'].", $MAX"; $result =$db->execute(lq($query)); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } $deliveredrecords += $result->RowCount(); if ($context['oai_nbtot'] - $deliveredrecords > 0) { $token = uniqid(8); insert_token($token, $context['oai_where'], $metadataPrefix, $deliveredrecords, $my_expirationdatetime); $context['oai_restoken'] = ' '.$token."\n"; } // Last delivery, return empty ResumptionToken if($context['oai_nbtot'] == 0) { $errors = oai_error('noRecordsMatch'); } elseif ($context['oai_nbtot'] <= $deliveredrecords) { del_token($token); $context['oai_restoken'] = ' '."\n"; } } } } else { $errors = oai_error('noVerb'); } } /** * ListRecords and ListIdentifiers accept the same parameters, the shared * tests are regrouped in this function. * * ListRecords et ListIdentifiers acceptent les meme parametres, les tests * communs sont donc regroupes dans cette fonction. */ function check_records () { global $args; global $context; global $errors; global $db; global $metadataformats; global $resumptionToken; unset($args['verb']); if ((!$args['metadataPrefix']) && (!$args['resumptionToken'])) { $errors .= oai_error('missingArgument', 'metadataPrefix'); } elseif($args['resumptionToken'] && (count($args)>1)) { $errors .= oai_error('exclusiveArgument'); } else { // patterns to test date granularity $longdate = "/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/"; $shortdate = "/^\\d{4}-\\d{2}-\\d{2}$/"; if ($args['from']) { $from = $args['from']; if (preg_match($longdate, $from)) { $context['oai_where'] .= "AND (creationdate>= '". $from. "' || modificationdate >= '". $from. "')"; } elseif (preg_match($shortdate, $from)) { $context['oai_where'] .= "AND (creationdate>= '". $from. "' || modificationdate >= '". $from. "')"; $context['short_date'] = true; } else { $errors .= oai_error('badArgument', 'from', $from); unset($from); } unset($args['from']); } if ($args['until']) { $until = $args['until']; if (preg_match($longdate, $until)) { $context['oai_where'] .= "AND creationdate <= '".$until."'"; } elseif (preg_match($shortdate, $until)) { $context['oai_where'] .= "AND creationdate <= '".$until."'"; $context['short_date'] = true; } else { $errors .= oai_error('badArgument', 'until', $until); unset($until); } unset($args['until']); } if ($args['metadataPrefix']) { check_mdp($args['metadataPrefix']); unset($args['metadataPrefix']); } if($args['set']) { $set = $args['set']; $context['oai_ids'] = array(); $result =$db->execute(lq("SELECT id FROM #_TP_entities, #_TP_relations WHERE id2 = '".substr($args['set'], 4)."'")); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } while (!$result->EOF) { $row = $result->fields; $context['oai_ids'][] = $row['id']; $result->MoveNext(); } unset($args['set']); } if($args['resumptionToken']) { $resumptionToken = $args['resumptionToken']; unset($args['resumptionToken']); } if(isset($from)&&isset($until)&&strlen($from)!=strlen($until)){ $errors .= oai_error('badArgument', 'granularity', ''); } } } /** * Tests the 'metadataPrefix' argument. * * Verifie la validite de l'information liee a l'argument 'metadataPrefix'. * * @param string $val la valeur é vérifier */ function check_mdp ($val) { global $errors; global $metadataformats; if (in_array($val, $metadataformats)) { $metadataPrefix = $val; } else { $errors .= oai_error('cannotDisseminateFormat', 'metadataPrefix', $val); } } /** * Tests the 'Identifier' argument. * * Verifie la validite de l'information liee a l'argument 'Identifier'. * * @param string $val la valeur de l'identifier OAI */ function check_identifier ($val) { global $context; global $errors; global $metadataformats; $identifier = $val; // remove the OAI part to get the identifier $id = str_replace($context['oai_prefix'], '', $identifier); if (in_array($id, $context['oai_ids'])) { $context['oai_ids'] = array(); $context['oai_ids'][] = $id; } else { $errors .= oai_error('idDoesNotExist', '', $identifier); } } /** * Tests for illegal parameters and generate the appropriate error messages. * * Traite la presence d'arguments illegaux en generant le message d'erreur approprie. */ function illegal_parameters() { global $args; global $errors; if ($args) { foreach ($args as $key=>$val) { $errors .= oai_error('badArgument', $key, $val); } } } //----------- DEBUT DU SCRIPT -----------// /** * Check if the required options are defined (oai_identifier, oai_allow, * oai_deny) and store their values. * * Verification de l'existence des options requises (oai_identifier, oai_allow, * oai_deny) et recuperation de leur valeur. * Le groupe d'option oai est aussi requis */ $result = getoption(array('oai.oai_identifier', 'oai.oai_allow', 'oai.oai_deny')); if($result['oai.oai_identifier']) { $context['oai_identifier'] = $result['oai.oai_identifier']; } if($result['oai.oai_allow']){ $allowed = $result['oai.oai_allow']; } if($result['oai.oai_deny']){ $denied = $result['oai.oai_deny']; } if(!isset($allowed) && !isset($denied)){ echo "Acces list of your OAI repository is not configured, please check site options.
"; echo "In order to enable this you must configure an optiongroup called oai ". "containing 2 options : oai_allow and oai_deny. By default,". " oai_allow should be set to '*'
"; exit; } $oai_allowed = explode(',', $allowed); $oai_denied = explode(',', $denied); if (!isset($_SERVER['REMOTE_HOST'])) { $hostname = gethostbyaddr($_SERVER['REMOTE_ADDR']); } else { $hostname = $_SERVER['REMOTE_HOST']; } /** * Identifies the request's emitter and check its rights. * * Identification de l'emetteur de la requete et verification de ses droits. */ 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))) { getOut($hostname); } if(!(in_array($_SERVER['REMOTE_ADDR'], $oai_allowed) || in_array($hostname, $oai_allowed) || (count($oai_allowed) == 1 && $oai_allowed[0] == '*'))){ getOut($hostname); } log_access($hostname); $oai_open = " ". gmstrftime('%Y-%m-%dT%TZ', time()). " ". dirname($context['currenturl']). '/oai20.'. $context['extensionscripts']. ""; $oai_close = "\n"; /* A sortir dans les options du site ? *************************************************/ $context['oai_prefix'] = isset($context['oai_identifier']) ? $context['oai_identifier'] : 'oai:'. str_replace(array('http://', '/'), array('', '.'), dirname($context['currenturl'])). ':'; $context['oai_maxids'] = MAXIDS; $context['oai_maxrecords'] = MAXRECORDS; /***************************************************************************************/ /** * List of OAI-referenced entities. * * Construit la liste des entites referencees par l'OAI. */ $result = $db->execute(lq("SELECT #_TP_entities.id FROM #_entitiestypesjoin_ WHERE #_TP_entities.idtype = #_TP_types.id AND #_TP_types.oaireferenced = 1")); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } while (!$result->EOF) { $row = $result->fields; $context['oai_ids'][] = $row['id']; $result->MoveNext(); } if(!$context['oai_ids']) { $errors .= oai_error('noRecordsMatch'); header("Content-type: application/xml"); echo _indent($oai_open. $errors. $oai_close); exit; } /** * Creates a table associating an entity's id with its class name and its associated * fields which are equivalent to dc.description or dc.language. * * Creation de la table indiquant pour chaque entite referencee son nom de * classe et les noms de champs equivalents a dc.description et dc.language. */ $id_class_fields = array(); $result = $db->execute(lq("SELECT #_TP_entities.id, #_TP_types.class, #_TP_tablefields.name, #_TP_tablefields.g_name FROM #_entitiestypesjoin_, #_TP_tablefieldgroups, #_TP_tablefields WHERE (#_TP_tablefields.g_name = 'dc.description' || #_TP_tablefields.g_name = 'dc.language') AND #_TP_tablefields.class = #_TP_types.class AND #_TP_types.oaireferenced = '1' AND #_TP_entities.idtype = #_TP_types.id")); if ($result === false) { trigger_error("SQL ERROR :
".$GLOBALS['db']->ErrorMsg(), E_USER_ERROR); } while (!$result->EOF) { $row = $result->fields; $id = $row['id']; $id_class_fields[$id]['class'] = $row['class']; $id_class_fields[$id][$row['g_name']] = $row['name']; $result->MoveNext(); } /** * Stores the request's parameters. * * Recuperation des parametres de la requete. */ if ($_SERVER['REQUEST_METHOD'] == 'GET') { $args = $_GET; $getarr = explode('&', $_SERVER['QUERY_STRING']); } elseif ($_SERVER['REQUEST_METHOD'] == 'POST') { $args = $_POST; } else { $errors .= oai_error('badRequestMethod', $_SERVER['REQUEST_METHOD']); } /** * Detects duplicate arguments in GET request. * * Detecte les arguments dupliques dans une requete passee par GET. */ if (isset($getarr)) { if (count($getarr) != count($args)) { $errors .= oai_error('sameArgument'); } } /** * Call to the 'clean_request_variable' function in func.php to remove potential * risks of injection in the request's arguments. * * Utilisation de la fonction "clean_request_variable" de func.php pour supprimer * tout risque d'injection dans les arguments de la requete. */ array_walk($args, 'clean_request_variable'); $context['oai_args'] = ''; if (is_array($args)) { foreach ($args as $key => $val) { $context['oai_args'] .= ' '.$key.'="'.htmlspecialchars(stripslashes($val)).'"'; } } /** * Process the request. * * Traitement des arguments de la requete. */ verbs_processing(); /** * If error messages were generated, they are displayed and the program ends. * * Si des messages d'erreur ont ete generes, ils sont affiches et l'execution du * programme se termine. */ if(isset($errors)) { header("Content-type: application/xml"); echo _indent($oai_open.$errors.$oai_close); exit; } /** * Generates response date, required by the protocol. * * Generation de la date de reponse, requise par le protocole. */ $context['oai_responsedate'] = gmstrftime('%Y-%m-%dT%TZ', time()); /** * Displays the response. * * Affichage de la reponse. */ $base = 'oai20'; //$view->renderCached($context,$base); View::getView()->render($base); /** * Suppress outdated tokens. * * Suppression des tokens dont la date limite de validite a ete atteinte. */ clean_expired_tokens(); } catch(LodelException $e) { echo $e->getContent(); exit(); } ?>