diff --git a/ands_tpa.php b/ands_tpa.php deleted file mode 100644 index 16a4dff..0000000 --- a/ands_tpa.php +++ /dev/null @@ -1,348 +0,0 @@ -create_metadata($cur_record); - * $obj_node = new ANDS_TPA($outputObj, $metadata_node, $db); - * try { - * $obj_node->create_obj_node($record[$SQL['set']], $identifier); - * } catch (Exception $e) { - * echo 'Caught exception: ', $e->getMessage(), " when adding $identifier\n"; - * } - * \endcode - * \see Code in action can be seen in record_rif.php - */ - -class ANDS_TPA extends ANDS_RIFCS { - //! Type: PDO. The database connection of the data source. - //! \see __construct. - private $db; - - /** - * Constructor - * The first two parameters are used by its parent class ANDS_RIFCS. The third is its own private property. - * - * \param $ands_response_doc ANDS_Response_XML. A XML Doc acts as the parent node. - * \param $metadata_node DOMElement. The meta node which all subsequent nodes will be added to. - * \param $db Type: PDO. The database connection of the data source. - */ - function __construct($ands_response_doc, $metadata_node, $db) { - parent::__construct($ands_response_doc, $metadata_node); - $this->db = $db; - } - - - /** - * This is the general entrence of creating actual content. It calls different functions for different type of RIF-CS model. - * When anything goes wrong, e.g. found no record, or $set_name is not recognised, an exception will be thrown. - * And for this implementation, data are stored in a database therefore a PDO is needed. But the source can be any. - * - * \param $set_name Type: string. The name of set is going to be created. Can be one of activity, collection or party. - * \param $key Type: string. The main identifier used in ANDS system. There can be other identifier. - * - * \see create_activity, create_collection, create_party - */ - function create_obj_node($set_name, $key) { - $db = $this->db; - $set_name = strtolower($set_name); - if (in_array($set_name,prepare_set_names())) { - try { - // Get ori_id and which the original table is: - $query = "select ori_table_name, ori_id from oai_headers where oai_identifier = '".$key."'"; - $res = exec_pdo_query($db, $query); - $record = $res->fetch(PDO::FETCH_ASSOC); - } catch (PDOException $e) { - echo "$key returned no record.\n"; - echo $e->getMessage(); - } - - $processor = 'create_'.substr($set_name,6); - $this->create_regObject(REG_OBJ_GROUP, $key, MY_URI); - $this->$processor($record['ori_table_name'],$record['ori_id']); - $this->create_identifier_node($key); - $this->create_identifier_node('table='.$record['ori_table_name'].'+id='.$record['ori_id']); - } else { - throw new Exception('Wrong set name was used: '.$set_name); - } - } - - /** The processor for creating metadata node of Activity. Called from create_obj_node. - * \param $table_name Type: string. The table name will be used to retrieve data from. - * \param $id_project Type: integer. Internal project id associated to this activity-project. - * \see Function create_obj_node. - */ - private function create_activity($table_name, $id_project) { - $db = $this->db; -# // Get ori_id and which the original table is: -# $query = "select ori_table_name, ori_id from oai_headers where oai_identifier = '".$key."'"; -# $res = exec_pdo_query($db, $query); -# $record = $res->fetch(PDO::FETCH_ASSOC); -# // $id_project will e used later, so save it: -# $id_project = $record['ori_id']; - // Get the content using the previously obtained infor: - $query = sprintf("select inter_no,start_date, end_date,pub_descrip from %s where id_project = %s",$table_name,$id_project); - - try { - $res = exec_pdo_query($db,$query); - $record = $res->fetch(PDO::FETCH_ASSOC); - } catch (Exception $e) { - echo $e->getMessage(); - } - - $this->create_rifcs_node('activity','project'); - $c = $this->create_name_node(); - $this->create_namePart($c,'The Plant Accelerator Project '.$record['inter_no']); - // Test codes for rich format. -# // \n works -# $this->create_description_node(sprintf("Line one:%s,\nLine two:%s.\nThird",'a','b')); - $this->create_description_node(str_replace("\r\n","\n",$record['pub_descrip'])); - - $this->create_description_node('The experiment was carried out between '.$record['start_date'].' and '.$record['end_date'],'note'); - $query = sprintf("select idr,stype from list_prj_ids_v2 where stype in ('dataset','person')",$id_project); - // echo $query; - try { - $res = $db->query($query,PDO::FETCH_ASSOC); - if ($res==false) { - throw new Exception($query."\nIt found nothing.\n"); - } - foreach ($res as $record) { - switch ($record['stype']) { - case 'dataset': - $this->create_relatedObject($record['idr'],'hasOutput'); - break; - case 'person': - $this->create_relatedObject($record['idr'],'isManagedBy'); - break; - } - } - // The Plant Accelerator always participates in Activity - $this->create_relatedObject('0874ad60-ab4d-11df-aebd-0002a5d5c51b','hasParticipant'); - } catch (PDOException $e) { - process_pdo_error($query, $e); - }// end of try-catch block - } // end of function create_activity($key, $id_project) - - /** The processor for creating metadata node of Collection. Called from create_obj_node. - * \param $table_name Type: string. The table name will be used to retrieve data from. - * \param $id_collect Type: integer. Internal collection id associated to this collection-dataset. - * \see Function create_obj_node. - */ - private function create_collection($table_name, $id_collect) { - $db = $this->db; - try { - $query = sprintf("select plant,variety,start_date,end_date,img_freq,anzsrc from %s where id_collect = %s",$table_name,$id_collect); - $res = exec_pdo_query($db, $query); - $dataset = $res->fetch(PDO::FETCH_ASSOC); - - $res = exec_pdo_query($db, $query); - $record = $res->fetch(PDO::FETCH_ASSOC); - - $query = 'select id_rep, inter_no, id_project from tpa_project_ids where id_collect = '.$id_collect; - $res = exec_pdo_query($db, $query); - $prj_info = $res->fetch(PDO::FETCH_ASSOC); - - $query = 'select email from tpa_person where id_rep = '.$prj_info['id_rep']; - $res = exec_pdo_query($db, $query); - $email = $res->fetch(PDO::FETCH_ASSOC); - } catch (PDOException $e) { - echo $query.' was failed\n'; - echo $e->getMessage(); - } - - $this->create_rifcs_node('collection','dataset'); - // Get the project inter_no as the name of this dataset - $c = $this->create_name_node(); - $this->create_namePart($c,'Data set of Plant Accelerator Project '.$prj_info['inter_no']); - - // locatin node: contact person - $l_node = $this->create_location_node(); - $a_node = $this->create_address_node($l_node); - $this->create_e_node($a_node, $email['email']); - // location node: TPA's physical address - $l_node = $this->create_location_node(); - $a_node = $this->create_address_node($l_node); - $this->create_physcial_addr_txt($a_node, 'The Plant Accelerator, Hartley Grove, Urrbrae, SA 5064') ; - // Temporal coverage of colletion - $dates = array(array('date'=>$dataset['start_date'],'type'=>'dateFrom'),array('date'=>$dataset['end_date'],'type'=>'dateTo')); - $this->create_coverage_tempo($dates); - // subject - $this->create_subject_node($dataset['aznsrc']); - // relatedOjbects - $query = sprintf("select idr,stype from list_prj_ids_v2(%d) where stype in ('project','person')",$prj_info['id_project']); - try { - $res = $db->query($query,PDO::FETCH_ASSOC); - if ($res==false) { - throw new Exception($query."\nIt found nothing.\n"); - } - foreach ($res as $record) { - switch ($record['stype']) { - case 'project': - $this->create_relatedObject($record['idr'],'isOutputOf'); - break; - case 'person': - $this->create_relatedObject($record['idr'],'isOwnedBy'); - break; - } - } - } catch (PDOException $e) { - process_pdo_error($query, $e); - }// end of try-catch block - - // right of accessing - $this->create_description_node('For information on rights and access to this dataset, please contact the owner.','accessRights'); - - // image data: - $imgs = ''; $ex_conf = ''; - $dic = array('im_type_rgb'=>'RGB','im_type_nir'=>'NIR','im_type_fir'=>'FIR','im_type_nir_roots'=>'NIR Roots','im_type_fluo'=>'Fluorescence'); - $query = 'select im_type_rgb,im_type_nir,im_type_fir,im_type_nir_roots,im_type_fluo, lines, treatments, replicates, total from ands_collection where id_collect = '. $id_collect; - $res = $db->query($query,PDO::FETCH_ASSOC); - if ($res==false) { - throw new Exception($query."\nIt found nothing.\n"); - } - $info = $res->fetch(); - foreach ($info as $item => $v) { - switch ($item) { - case 'im_type_rgb': - case 'im_type_nir': - case 'im_type_fir': - case 'im_type_nir_roots': - case 'im_type_fluo': - if (!empty($v)) { $imgs .= $dic[$item].', '; } - break; - default: - if (!empty($v)) { $ex_conf .= ' '.$item.' = '.$v.', '; } - break; - } - } - if (empty($imgs)) $imgs = "Images data of RGB, FIR, NIR, NIR Roots and Fluorescence cameras., "; - $imgs = substr($imgs,0,-2); - if (!empty($ex_conf)) $imgs = $imgs."\n".substr($ex_conf,0,-2); - $this->create_description_node($imgs); - // imaging frequency - $this->create_description_node('Imaging frequency: '.$dataset['img_freq'],'note'); - } // end of function create_collection($key,$id_collect) - - /** The processor for creating metadata node of Party. Called from create_obj_node. As party-person is different to party-group, there are two sub-functions are called accordingly. - * \param $table_name Type: string. The table name will be used to retrieve data from. - * \param $id_party Type: integer. Internal party id associated to this party. - * \see Function create_obj_node. - */ - private function create_party($table_name, $id_party) { - $db = $this->db; - $query = sprintf("SELECT set_type FROM oai_headers WHERE ori_table_name = '%s' AND ori_id = %s",$table_name,$id_party); - $res = exec_pdo_query($db, $query); - $party_type = $res->fetch(PDO::FETCH_ASSOC); - - if (in_array($party_type['set_type'],array('person','group'))) { - $this->create_rifcs_node('party',$party_type['set_type']); - - if ($party_type['set_type']=='person') { - $this->create_person($table_name, $id_party); - } elseif ($party_type['set_type']=='group') { - $this->create_group($table_name, $id_party); } - } else { - throw new Exception('Unsupported set_type: '.$party_type['set_type']); - } - } // end of function create_part($key,$id_party) - - /** The processor for creating metadata node of Party. Called from create_obj_node. As party-person is different to party-group, there are two sub-functions are called accordingly. - * \param $table_name Type: string. The table name will be used to retrieve data from. - * \param $id_party Type: integer. Internal party id associated to this party-person. - * \see Function create_party. - */ - private function create_person($table_name, $id_party) { - $db = $this->db; - $query = sprintf("SELECT id_org, title, first_name, family_name, tel, fax, email, www, address, post_code, city,state,country,duty FROM %s WHERE id_rep = %s",$table_name, $id_party); - $res = exec_pdo_query($db, $query); - $info = $res->fetch(PDO::FETCH_ASSOC); - $c = $this->create_name_node(); - if (!empty($info['title'])) $this->create_namePart($c,$info['title'],'title'); - $this->create_namePart($c,$info['family_name'],'family'); - $this->create_namePart($c,$info['first_name'],'given'); - - // locatin node: contact person - $l_node = $this->create_location_node(); - $a_node = $this->create_address_node($l_node); - $this->create_e_node($a_node, $info['email']); - if (!empty($info['www'])) $this->create_e_node($a_node, $info['www'],'url'); - $this->create_physcial_fone_fax($a_node, $info['tel'],'telephoneNumber'); - if (!empty($info['fax'])) $this->create_physcial_fone_fax($a_node, $info['fax'],'faxNumber'); - $add_txt = trim($info['address']).', '.$info['city'].' '.$info['state'].' '.$info['post_code'].', '.$info['country']; - // the strlength of ', , ' is 6 - if (strlen($add_txt)>6) $this->create_physcial_addr_txt($a_node,$add_txt); - - // related objects: - // their group: id_customer is a foreign key of tpa_organisation - $query = sprintf("SELECT get_identifier('tpa_organisation',%s)",$info['id_org']); - $res = exec_pdo_query($db, $query); - $info = $res->fetch(PDO::FETCH_NUM); - $this->create_relatedObject($info[0],'isMemberOf'); - - // their activities - $query = "SELECT list_persons_objs($id_party,'project')"; - $res = exec_pdo_query($db, $query); - $info = $res->fetch(PDO::FETCH_NUM); - foreach ($info as $item) { - $this->create_relatedObject($item,'isManagerOf'); - } - // their collections - $query = "SELECT list_persons_objs($id_party,'dataset')"; - $res = exec_pdo_query($db, $query); - $info = $res->fetch(PDO::FETCH_NUM); - foreach ($info as $item) { - $this->create_relatedObject($item,'isOwnerOf'); - } - } - - /** The processor for creating metadata node of Party. Called from create_obj_node. As party-person is different to party-group, there are two sub-functions are called accordingly. - * \param $table_name Type: string. The table name will be used to retrieve data from. - * \param $id_party Type: integer. Internal party id associated to this party-group. - * \see Function create_party. - */ - private function create_group($table_name, $id_party) { - $db = $this->db; - // echo 'table: ',$table_name,' party: ',$id_party,"\n"; - $query = sprintf("SELECT customer_name, abn, post_code, address, city, state, country, tel, fax, email, www, description FROM %s WHERE id_org = %s",$table_name, $id_party); - //echo $query; - $res = exec_pdo_query($db, $query); - $info = $res->fetch(PDO::FETCH_ASSOC); - $c = $this->create_name_node(); - $this->create_namePart($c,$info['customer_name']); - if (!empty($info['abn'])) $this->create_identifier_node($info['abn'],'abn'); - - if (!empty($info['description'])) $this->create_description_node($info['description']); - - $l_node = $this->create_location_node(); - $a_node = $this->create_address_node($l_node); - $this->create_physcial_fone_fax($a_node, $info['tel'],'telephoneNumber'); - $this->create_physcial_fone_fax($a_node, $info['fax'],'faxNumber'); - $add_txt = trim($info['address']).', '.$info['city'].' '.$info['state'].' '.$info['post_code'].', '.$info['country']; - $this->create_physcial_addr_txt($a_node,$add_txt); - - // related objects: - // their members: - $query = "SELECT list_pub_members($id_party)"; - $res = exec_pdo_query($db, $query); - $info = $res->fetch(PDO::FETCH_NUM); - foreach ($info as $item) { - $this->create_relatedObject($item,'hasMember'); - } - } -} // end of class ANDS_TPA diff --git a/config/database.php b/config/database.php deleted file mode 100644 index fbf170b..0000000 --- a/config/database.php +++ /dev/null @@ -1,76 +0,0 @@ -$SQL: Settings for database and queries from database - * - * - $DSN: DSN for connecting your database. Reference PDO for details. - * - */ - -// Data Source Name: This is the universal connection string -// if you use something other than mysql edit accordingly. -// Example for MySQL -// $DSN = "mysql://$DB_USER:$DB_PASSWD@$DB_HOST/$DB_NAME"; -// Example for Oracle -// $DSN = "oci8://$DB_USER:$DB_PASSWD@$DB_NAME"; - -$DSN = "mysql:host={$DB_HOST};dbname={$DB_NAME};port=3306;"; - -// the charset you store your metadata in your database -// currently only utf-8 and iso8859-1 are supported -$charset = "utf8"; - -// if entities such as < > ' " in your metadata has already been escaped -// then set this to true (e.g. you store < as < in your DB) -$xmlescaped = false; - -// We store multiple entries for one element in a single row -// in the database. SQL['split'] lists the delimiter for these entries. -// If you do not do this, do not define $SQL['split'] -// $SQL['split'] = ';'; - -// the name of the table where your store your metadata's header -$SQL['table'] = 'oai_headers'; - -// the name of the column where you store the unique identifiers -// pointing to your item. -// this is your internal identifier for the item -$SQL['identifier'] = 'oai_identifier'; - -$SQL['metadataPrefix'] = 'oai_metadataprefix'; - -// If you want to expand the internal identifier in some way -// use this (but not for OAI stuff, see next line) -$idPrefix = ''; - -// this is your external (OAI) identifier for the item -// this will be expanded to -// oai:$repositoryIdentifier:$idPrefix$SQL['identifier'] -// should not be changed -// -// Commented out 24/11/10 14:19:09 -// $oaiprefix = "oai".$delimiter.$repositoryIdentifier.$delimiter.$idPrefix; -$oaiprefix = ""; - -// adjust anIdentifier with sample contents an identifier -// $sampleIdentifier = $oaiprefix.'anIdentifier'; - -// the name of the column where you store your datestamps -$SQL['datestamp'] = 'datestamp'; - -// the name of the column where you store information whether -// a record has been deleted. Leave it as it is if you do not use -// this feature. -$SQL['deleted'] = 'deleted'; - -// to be able to quickly retrieve the sets to which one item belongs, -// the setnames are stored for each item -// the name of the column where you store sets -$SQL['set'] = 'oai_set'; diff --git a/config/metadataformats.php b/config/metadataformats.php deleted file mode 100644 index 58e8b40..0000000 --- a/config/metadataformats.php +++ /dev/null @@ -1,35 +0,0 @@ -$METADATAFORMATS: List of supported metadata formats. It is a two-dimensional array with keys. - * Each supported format is one element of this array at the first dimension. - * The key is the name of a metadata format. - * The exact number of items within each format associated array depends on the nature of a metadata format. - * Most definitions are done here but handlers themselves are defined in separated files because only the names of PHP script are listed here. - * - metadataPrefix - * - schema - * - metadataNamespace - * - myhandler - * - other optional items: record_prefix, record_namespace and etc. - */ -// define all supported metadata formats, has to be an array -// -// myhandler is the name of the file that handles the request for the -// specific metadata format. -// [record_prefix] describes an optional prefix for the metadata -// [record_namespace] describe the namespace for this prefix - - -$METADATAFORMATS = array ( - 'rif' => array('metadataPrefix'=>'rif', - 'schema'=>'http://services.ands.org.au/sandbox/orca/schemata/registryObjects.xsd', - 'metadataNamespace'=>'http://ands.org.au/standards/rif-cs/registryObjects/', - ), - 'oai_dc' => array('metadataPrefix'=>'oai_dc', - 'schema'=>'http://www.openarchives.org/OAI/2.0/oai_dc.xsd', - 'metadataNamespace'=>'http://www.openarchives.org/OAI/2.0/oai_dc/', - 'record_prefix'=>'dc', - 'record_namespace' => 'http://purl.org/dc/elements/1.1/' - ) -); - -if (!is_array($METADATAFORMATS)) { exit("Configuration of METADATAFORMAT has been wrongly set. Correct your ".__FILE__);} diff --git a/config/sets.php b/config/sets.php deleted file mode 100644 index 7ae85a7..0000000 --- a/config/sets.php +++ /dev/null @@ -1,28 +0,0 @@ -$SETS: An array with key words . List of supported SETs. - * - */ - -// define all supported sets in your repository -$SETS = array ( - array('setSpec'=>'class:activity', 'setName'=>'Activities'), - array('setSpec'=>'class:collection', 'setName'=>'Collections'), - array('setSpec'=>'class:party', 'setName'=>'Parties'), - /* - array('setSpec'=>'math', 'setName'=>'Mathematics') , - array('setSpec'=>'phys', 'setName'=>'Physics'), - - array('setSpec'=>'phdthesis', - 'setName'=>'PHD Thesis', - 'setDescription'=>' - This set contains metadata describing - electronic music recordings made during the 1950ies - ') - */ -); diff --git a/oai2.php b/oai2.php index c1ab64f..1d1e6a1 100644 --- a/oai2.php +++ b/oai2.php @@ -8,62 +8,15 @@ * @see http://www.openarchives.org/OAI/2.0/openarchivesprotocol.htm * * It needs other files: - * - oaidp-config.php : Configuration of provider * - oaidp-util.php : Utility functions * - xml_creater.php : XML generating functions * - * \todo Remember: to define your own classess for generating metadata records. - * In common cases, you have to implement your own code to act fully and correctly. - * For generic usage, you can try the ANDS_Response_XML defined in xml_creater.php. */ -/** - * Supported attributes associate to verbs. - */ - -if (in_array($_SERVER['REQUEST_METHOD'],array('GET','POST'))) { - $args = $_REQUEST; -} else { - $errors[] = oai_error('badRequestMethod', $_SERVER['REQUEST_METHOD']); -} +define('MY_URI', 'dev2.moodle.ufsc.br'); require_once('oaidp-util.php'); - -// Always using htmlentities() function to encodes the HTML entities submitted by others. -// No one can be trusted. -foreach ($args as $key => $val) { - $checking = htmlspecialchars(stripslashes($val)); - if (!is_valid_attrb($checking)) { - $errors[] = oai_error('badArgument', $checking); - } else {$args[$key] = $checking; } -} -if (!empty($errors)) { - oai_exit(); -} - -$attribs = array ('from', 'identifier', 'metadataPrefix', 'set', 'resumptionToken', 'until'); -foreach($attribs as $val) { - unset($$val); -} - -require_once('oaidp-config.php'); -require_once('config/metadataformats.php'); -require_once('config/sets.php'); -require_once('config/database.php'); - -// For generic usage or just trying: -// require_once('xml_creater.php'); -// In common cases, you have to implement your own code to act fully and correctly. -require_once('ands_tpa.php'); - -// Default, there is no compression supported -$compress = FALSE; -if (isset($compression) && is_array($compression)) { - if (in_array('gzip', $compression) && ini_get('output_buffering')) { - $compress = TRUE; - } -} - +require_once('xml_creater.php'); require_once('oai2server.php'); /** @@ -94,6 +47,73 @@ $identifyResponse["deletedRecord"] = 'no'; // How your repository handles deleti // maintained. It MAY reveal a deleted status for records. $identifyResponse["granularity"] = 'YYYY-MM-DDThh:mm:ssZ'; -$repositoryIdentifier = 'dev2.moodle.ufsc.br.'; +$oai2 = new OAI2Server($_REQUEST, $identifyResponse, + array( + 'ListMetadataFormats' => + function($identifier = '') { + // throws new OAI2Exception('idDoesNotExist', '', $identifier) + return + array('rif' => array('metadataPrefix'=>'rif', + 'schema'=>'http://services.ands.org.au/sandbox/orca/schemata/registryObjects.xsd', + 'metadataNamespace'=>'http://ands.org.au/standards/rif-cs/registryObjects/', + ), + 'oai_dc' => array('metadataPrefix'=>'oai_dc', + 'schema'=>'http://www.openarchives.org/OAI/2.0/oai_dc.xsd', + 'metadataNamespace'=>'http://www.openarchives.org/OAI/2.0/oai_dc/', + 'record_prefix'=>'dc', + 'record_namespace' => 'http://purl.org/dc/elements/1.1/')); + }, -$oai2 = new OAI2Server($args, $repositoryIdentifier, $identifyResponse); + 'ListSets' => + function($resumptionToken = '') { + return + array ( + array('setSpec'=>'class:collection', 'setName'=>'Collections'), + array('setSpec'=>'math', 'setName'=>'Mathematics') , + array('setSpec'=>'phys', 'setName'=>'Physics'), + array('setSpec'=>'phdthesis', 'setName'=>'PHD Thesis', + 'setDescription'=> + ' '. + ' This set contains metadata describing '. + ' electronic music recordings made during the 1950ies '. + ' ')); + }, + + 'ListRecords' => + function($metadataPrefix, $from = '', $until = '', $set = '', $count = false, $deliveredRecords = 0, $maxItems = 0) { + // throws new OAI2Exception('noRecordsMatch') + // throws new OAI2Exception('noSetHierarchy') + if ($count) { + return 10; + } + return array(); + }, + + 'GetRecord' => + function($identifier, $metadataPrefix) { + // throws new OAI2Exception('idDoesNotExist', '', $identifier) if record not found + + return array('identifier' => 'dev.testing.pmh', + 'datestamp' => date('Y-m-d-H:s'), + 'set' => 'class:activity', + 'metadata' => array( + 'container_name' => 'oai_dc:dc', + 'container_attributes' => array( + 'xmlns:oai_dc' => "http://www.openarchives.org/OAI/2.0/oai_dc/", + 'xmlns:dc' => "http://purl.org/dc/elements/1.1/", + 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", + 'xsi:schemaLocation' => + 'http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd' + ), + 'fields' => array( + 'dc:title' => 'Testing records', + 'dc:author' => 'Neis' + ) + )); + }, + ) +); diff --git a/oai2exception.php b/oai2exception.php new file mode 100644 index 0000000..600fc3e --- /dev/null +++ b/oai2exception.php @@ -0,0 +1,78 @@ +errorTable = array( + 'badArgument' => array( + 'text' => "Attribute '{$argument}' is not allowed to appear in element 'request'.", + ), + 'badGranularity' => array( + 'text' => "The value '{$value}' of attribute '{$argument}' on element 'request' is not valid with respect to its type, 'UTCdatetimeType'.", + 'code' => 'badArgument', + ), + + 'badResumptionToken' => array( + 'text' => "The resumptionToken '{$value}' does not exist or has already expired.", + ), + 'badRequestMethod' => array( + 'text' => "The request method '{$argument}' is unknown.", + 'code' => 'badVerb', + ), + 'badVerb' => array( + 'text' => "The value '{$argument}' of attribute 'verb' on element 'request' is not valid with respect to its type, 'verbType'", + ), + 'cannotDisseminateFormat' => array( + 'text' => "The metadata format '{$value}' given by {$argument} is not supported by this repository.", + ), + 'exclusiveArgument' => array( + 'text' => 'The usage of resumptionToken as an argument allows no other arguments.', + 'code' => 'badArgument', + ), + 'idDoesNotExist' => array( + 'text' => "The value '{$value}' of the identifier does not exist in this repository.", + /* + if (!is_valid_uri($value)) { + 'code' = 'badArgument', + 'text' .= ' Invalidated URI has been detected.', + } + */ + ), + 'missingArgument' => array( + 'text' => "The required argument '{$argument}' is missing in the request.", + 'code' => 'badArgument', + ), + 'noRecordsMatch' => array( + 'text' => 'The combination of the given values results in an empty list.', + ), + 'noMetadataFormats' => array( + 'text' => 'There are no metadata formats available for the specified item.', + ), + 'noVerb' => array( + 'text' => 'The request does not provide any verb.', + 'code' => 'badVerb', + ), + 'noSetHierarchy' => array( + 'text' => 'This repository does not support sets.', + ), + 'sameArgument' => array( + 'text' => 'Do not use the same argument more than once.', + 'code' => 'badArgument', + ), + 'sameVerb' => array( + 'text' => 'Do not use verb more than once.', + 'code' => 'badVerb', + ), + 'notImp' => array( + 'text' => 'Not yet implemented.', + 'code' => 'debug', + ), + ''=> array( + 'text' => "Unknown error: code: '{'code'}', argument: '{$argument}', value: '{$value}'", + 'code' => 'badArgument', + ) + ); + parent::__construct($this->errorTable[$code]['text'], $code); + } +} diff --git a/oai2server.php b/oai2server.php index d9f52e0..7875c50 100644 --- a/oai2server.php +++ b/oai2server.php @@ -1,95 +1,75 @@ args = $args; - $this->repositoryIdentier = $repositoryIdentifier; $this->identifyResponse = $identifyResponse; + $this->listMetadataFormatsCallback = $callbacks['ListMetadataFormats']; + $this->listSetsCallback = $callbacks['ListSets']; + $this->listRecordsCallback = $callbacks['ListRecords']; + $this->getRecordCallback = $callbacks['GetRecord']; $this->respond(); } private function respond() { if (!isset($this->args['verb']) || empty($this->args['verb'])) { - $this->errors[] = oai_error('noVerb'); + $this->errors[] = new OAI2Exception('noVerb'); } else { switch ($this->args['verb']) { - case 'Identify': - // we never use compression in Identify - $compress = FALSE; - $this->outputObj = $this->identify(); - break; + case 'Identify': $this->identify(); break; - case 'ListMetadataFormats': - $this->outputObj = $this->listMetadataFormats(); - break; + case 'ListMetadataFormats': $this->listMetadataFormats(); break; - case 'ListSets': - $this->outputObj = $this->listSets(); - break; + case 'ListSets': $this->listSets(); break; case 'ListIdentifiers': - case 'ListRecords': - $this->outputObj = $this->listRecords(); - break; + case 'ListRecords': $this->listRecords(); break; - case 'GetRecord': - $this->outputObj = $this->getRecord(); - break; + case 'GetRecord': $this->getRecord(); break; - default: - // we never use compression with errors - $compress = FALSE; - $this->errors[] = oai_error('badVerb', $this->args['verb']); + default: $this->errors[] = new OAI2Exception('badVerb', $this->args['verb']); } } if (empty($this->errors)) { - $this->display(); + + if (isset($this->outputObj)) { + header(CONTENT_TYPE); + $this->outputObj->display(); + } else { + exit("Nothing to output. May be a bug."); + } } else { $this->errorResponse(); } } - function errorResponse() { - $e = new ANDS_Error_XML($this->args,$this->errors); + private function errorResponse() { + $e = new OAI2XMLError($this->args,$this->errors); header(CONTENT_TYPE); $e->display(); exit(); } - function display() { - if (isset($this->outputObj)) { - - if ($compress) { - ob_start('ob_gzhandler'); - } - - header(CONTENT_TYPE); - $this->outputObj->display(); - - if ($compress) { - ob_end_flush(); - } - - } else { - exit("Nothing to output. May be a bug."); - } - } - /** * Response to Verb Identify * @@ -97,193 +77,47 @@ class OAI2Server { * * http://www.openarchives.org/OAI/2.0/guidelines-oai-identifier.htm for details */ - public function identify($show_identifier, $repositoryIdentifier, $delimiter, $sampleIdentifier) { + public function identify() { if (count($this->args) > 1) { foreach($args as $key => $val) { if(strcmp($key,"verb")!=0) { - $this->errors[] = oai_error('badArgument', $key, $val); + $this->errors[] = new OAI2Exception('badArgument', $key, $val); } } } - $outputObj = new ANDS_Response_XML($this->args); + $this->outputObj = new ANDS_Response_XML($this->args); foreach($this->identifyResponse as $key => $val) { - $outputObj->add2_verbNode($key, $val); + $this->outputObj->add2_verbNode($key, $val); } - - // A description MAY be included. - // Use this if you choose to comply with a specific format of unique identifiers - // for items. - // See http://www.openarchives.org/OAI/2.0/guidelines-oai-identifier.htm - // for details - - // As they will not be changed, using string for simplicity. - $output = ''; - if ($this->show_identifier && $this->repositoryIdentifier && $this->delimiter && $this->sampleIdentifier) { - $output .= - ' - - oai - '.$repositoryIdentifier.' - '.$delimiter.' - '.$sampleIdentifier.' - - '."\n"; - } - - // A description MAY be included. - // This example from arXiv.org is used by the e-prints community, please adjust - // see http://www.openarchives.org/OAI/2.0/guidelines-eprints.htm for details - - // To include, change 'false' to 'true'. - if (false) { - $output .= - ' - - - Author self-archived e-prints - - - - - - '."\n"; - } - - // If you want to point harvesters to other repositories, you can list their - // base URLs. Usage of friends container is RECOMMENDED. - // see http://www.openarchives.org/OAI/2.0/guidelines-friends.htm - // for details - - // To include, change 'false' to 'true'. - if (false) { - $output .= - ' - - http://naca.larc.nasa.gov/oai2.0/ - http://techreports.larc.nasa.gov/ltrs/oai2.0/ - http://physnet.uni-oldenburg.de/oai/oai2.php - http://cogprints.soton.ac.uk/perl/oai - http://ub.uni-duisburg.de:8080/cgi-oai/oai.pl - http://rocky.dlib.vt.edu/~jcdlpix/cgi-bin/OAI1.1/jcdlpix.pl - - '."\n"; - } - - // If you want to provide branding information, adjust accordingly. - // Usage of friends container is OPTIONAL. - // see http://www.openarchives.org/OAI/2.0/guidelines-branding.htm - // for details - - // To include, change 'false' to 'true'. - if (false) { - $output .= - ' - - - http://my.site/icon.png - http://my.site/homepage.html - MySite(tm) - 88 - 31 - - http://some.where/DCrender.xsl - http://another.place/MARCrender.css - - '."\n"; - } - - if(strlen($output)>10) { - $des = $outputObj->doc->createDocumentFragment(); - $des->appendXML($output); - $outputObj->verbNode->appendChild($des); - } - - return $outputObj; } /** * Response to Verb ListMetadataFormats * - * The information of supported metadata formats : - * try database table $SQL['table'] - * else try $METADATAFORMATS array from config-metadataformats.php + * The information of supported metadata formats */ public function listMetadataFormats() { - global $DSN, $DB_USER, $DB_PASSWD, $METADATAFORMATS, $SQL; $checkList = array("ops"=>array("identifier")); $this->checkArgs($checkList); - // Create a PDO object try { - $db = new PDO($DSN, $DB_USER, $DB_PASSWD); - } catch (PDOException $e) { - exit('Connection failed: ' . $e->getMessage()); - } - - if (isset($this->args['identifier'])) { - - $identifier = $this->args['identifier']; - $query = 'select '.$SQL['metadataPrefix'].' FROM '.$SQL['table']. " WHERE ".$SQL['identifier']." = '".$id."'"; - $res = $db->query($query); - - if ($res==false) { - if (SHOW_QUERY_ERROR) { - echo __FILE__.','.__LINE__."
"; - echo "Query: $query
\n"; - die($db->errorInfo()); - } else { - $this->errors[] = oai_error('idDoesNotExist','', $identifier); - } - } else { - $record = $res->fetch(); - if($record===false) { - $this->errors[] = oai_error('idDoesNotExist', '', $identifier); - } else { - $mf = explode(",",$record[$SQL['metadataPrefix']]); + if ($formats = call_user_func($this->listMetadataFormatsCallback, $this->args['identifier'])) { + $this->outputObj = new ANDS_Response_XML($this->args); + foreach($formats as $key => $val) { + $cmf = $this->outputObj->add2_verbNode("metadataFormat"); + $this->outputObj->addChild($cmf,'metadataPrefix',$key); + $this->outputObj->addChild($cmf,'schema',$val['schema']); + $this->outputObj->addChild($cmf,'metadataNamespace',$val['metadataNamespace']); } + return $outputObj; } + $this->errors[] = new OAI2Exception('noMetadataFormats'); + } catch (OAI2Exception $e) { + $this->errors[] = $e; } - - //break and clean up on error - if (!empty($this->errors)) { - $this->errorResponse(); - } - - $outputObj = new ANDS_Response_XML($this->args); - if (isset($mf)) { - foreach($mf as $key) { - $val = $METADATAFORMATS[$key]; - $this->addMetedataFormat($outputObj,$key, $val); - } - } elseif (is_array($METADATAFORMATS)) { - foreach($METADATAFORMATS as $key=>$val) { - $this->addMetedataFormat($outputObj,$key, $val); - } - } else { // a very unlikely event - $this->errors[] = oai_error('noMetadataFormats'); - $this->errorResponse(); - } - - return $outputObj; } /** @@ -293,36 +127,34 @@ class OAI2Server { * This variable is filled in config-sets.php */ public function listSets() { - global $SETS; - - $sets = $SETS; if (isset($this->args['resumptionToken']) && count($this->args) > 2) { - $this->errors[] = oai_error('exclusiveArgument'); + $this->errors[] = new OAI2Exception('exclusiveArgument'); } $checkList = array("ops"=>array("resumptionToken")); $this->checkArgs($checkList); - if (is_array($sets)) { - $outputObj = new ANDS_Response_XML($this->args); + if ($sets = call_user_func($this->listSetsCallback)) { + + $this->outputObj = new ANDS_Response_XML($this->args); foreach($sets as $set) { - $setNode = $outputObj->add2_verbNode("set"); + + $setNode = $this->outputObj->add2_verbNode("set"); + foreach($set as $key => $val) { if($key=='setDescription') { - $desNode = $outputObj->addChild($setNode,$key); - $des = $outputObj->doc->createDocumentFragment(); + $desNode = $this->outputObj->addChild($setNode,$key); + $des = $this->outputObj->doc->createDocumentFragment(); $des->appendXML($val); $desNode->appendChild($des); } else { - $outputObj->addChild($setNode,$key,$val); + $this->outputObj->addChild($setNode,$key,$val); } } } } else { - $this->errors[] = oai_error('noSetHierarchy'); - oai_exit(); + $this->errors[] = new OAI2Exception('noSetHierarchy'); } - return $outputObj; } /** @@ -335,62 +167,44 @@ class OAI2Server { * The reset of information will be extracted from database based those two parameters. */ public function getRecord() { - global $METADATAFORMATS, $DSN, $DB_USER, $DB_PASSWD, $SQL; $checkList = array("required"=>array("metadataPrefix","identifier")); $this->checkArgs($checkList); $metadataPrefix = $this->args['metadataPrefix']; - if (!isset($METADATAFORMATS[$metadataPrefix])) { - $this->errors[] = oai_error('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix); + $metadataFormats = call_user_func($this->listMetadataFormatsCallback); + + if (!isset($metadataFormats[$metadataPrefix])) { + $this->errors[] = new OAI2Exception('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix); } - // Create a PDO object try { - $db = new PDO($DSN, $DB_USER, $DB_PASSWD); - } catch (PDOException $e) { - exit('Connection failed: ' . $e->getMessage()); + if ($record = call_user_func($this->getRecordCallback, $this->args['identifier'], $metadataPrefix)) { + + $identifier = $record['identifier']; + + $datestamp = formatDatestamp($record['datestamp']); + + $set = $record['set']; + + $status_deleted = (isset($record['deleted']) && ($record['deleted'] == 'true') && + (($this->identifyResponse['deletedRecord'] == 'transient') || + ($this->identifyResponse['deletedRecord'] == 'persistent'))); + + $this->outputObj = new ANDS_Response_XML($this->args); + $cur_record = $this->outputObj->create_record(); + $cur_header = $this->outputObj->create_header($identifier, $datestamp, $set, $cur_record); + if ($status_deleted) { + $cur_header->setAttribute("status","deleted"); + } else { + $this->add_metadata($cur_record, $record); + + } + } + } catch (OAI2Exception $e) { + $this->errors[] = $e; } - - $identifier = $this->args['identifier']; - $query = selectallQuery($metadataPrefix, $identifier); - - $res = $db->query($query); - - if ($res===false) { - $this->errors[] = oai_error('idDoesNotExist', '', $identifier); - } elseif (!$res->rowCount()) { // based on PHP manual, it might only work for some DBs - $this->errors[] = oai_error('idDoesNotExist', '', $identifier); - } - - if (!empty($this->errors)) { - oai_exit(); - } - - $record = $res->fetch(PDO::FETCH_ASSOC); - if ($record===false) { - $this->errors[] = oai_error('idDoesNotExist', '', $identifier); - } - - $identifier = $record[$SQL['identifier']];; - - $datestamp = formatDatestamp($record[$SQL['datestamp']]); - - $status_deleted = (isset($record[$SQL['deleted']]) && ($record[$SQL['deleted']] == 'true') && - ($this->identifyResponse['deletedRecord'] == 'transient' || $this->identifyResponse['deletedRecord'] == 'persistent')); - - $outputObj = new ANDS_Response_XML($this->args); - $cur_record = $outputObj->create_record(); - $cur_header = $outputObj->create_header($identifier, $datestamp,$record[$SQL['set']],$cur_record); - // return the metadata record itself - if ($status_deleted) { - $cur_header->setAttribute("status","deleted"); - } else { - call_user_func(array($this, "{$metadataPrefix}_create_metadata"), - $outputObj, $cur_record, $identifier, $record[$SQL['set']], $db); - } - return $outputObj; } /** @@ -402,13 +216,10 @@ class OAI2Server { * Only 'metadataPrefix' is compulsory. All conditions are accessible through global array variable $args by keywords. */ public function listRecords() { - global $SQL, $METADATAFORMATS, $DSN, $DB_USER, $DB_PASSWD, $SETS; - $sets = $SETS; - - if(isset($this->args['resumptionToken'])) { + if (isset($this->args['resumptionToken'])) { if (count($this->args) > 2) { - $this->errors[] = oai_error('exclusiveArgument'); + $this->errors[] = new OAI2Exception('exclusiveArgument'); } $checkList = array("ops"=>array("resumptionToken")); } else { @@ -416,203 +227,103 @@ class OAI2Server { } $this->checkArgs($checkList); + $metadataFormats = call_user_func($this->listMetadataFormatsCallback, $this->args); + if (!isset($metadataFormats[$this->args['metadataPrefix']])) { + $this->errors[] = new OAI2Exception('cannotDisseminateFormat', 'metadataPrefix', $this->args['metadataPrefix']); + } + // Resume previous session? if (isset($this->args['resumptionToken'])) { + if (!file_exists(TOKEN_PREFIX.$this->args['resumptionToken'])) { - $this->errors[] = oai_error('badResumptionToken', '', $this->args['resumptionToken']); + $this->errors[] = new OAI2Exception('badResumptionToken', '', $this->args['resumptionToken']); } else { - $readings = readResumToken(TOKEN_PREFIX.$this->args['resumptionToken']); - if ($readings == false) { - $this->errors[] = oai_error('badResumptionToken', '', $this->args['resumptionToken']); - } else { - list($deliveredrecords, $extquery, $metadataPrefix) = $readings; - } - } - } else { // no, we start a new session - $deliveredrecords = 0; - $extquery = ''; + if ($readings = $this->readResumptionToken(TOKEN_PREFIX.$this->args['resumptionToken'])) { + list($deliveredRecords, $metadataPrefix, $from, $until, $set) = $readings; + } else { + $this->errors[] = new OAI2Exception('badResumptionToken', '', $this->args['resumptionToken']); + } + + } + + } else { + $deliveredRecords = 0; $metadataPrefix = $this->args['metadataPrefix']; - - if (isset($args['from'])) { - $from = checkDateFormat($this->args['from']); - $extquery .= fromQuery($from); - } - - if (isset($args['until'])) { - $until = checkDateFormat($this->args['until']); - $extquery .= untilQuery($until); - } - - if (isset($args['set'])) { - if (is_array($sets)) { - $extquery .= setQuery($this->args['set']); - } else { - $this->errors[] = oai_error('noSetHierarchy'); - } - } - } - - if (!isset($METADATAFORMATS[$metadataPrefix])) { - $this->errors[] = oai_error('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix); + $from = isset($this->args['from']) ? $this->args['from'] : ''; + $until = isset($this->args['until']) ? $this->args['until'] : ''; + $set = isset($this->args['set']) ? $this->args['set'] : ''; } if (!empty($this->errors)) { $this->errorResponse(); } - // Create a PDO object + $maxItems = 1000; try { - $db = new PDO($DSN, $DB_USER, $DB_PASSWD); - } catch (PDOException $e) { - exit('Connection failed: ' . $e->getMessage()); - } - $query = selectallQuery($metadataPrefix) . $extquery; + $records_count = call_user_func($this->listRecordsCallback, $metadataPrefix, $from, $until, $set, true); - $res = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); - $r = $res->execute(); - if ($r===false) { - $this->errors[] = oai_error('noRecordsMatch'); - } else { - $r = $res->setFetchMode(PDO::FETCH_ASSOC); - if ($r===false) { - exit("FetchMode is not supported"); - } - $num_rows = rowCount($metadataPrefix, $extquery, $db); - if ($num_rows==0) { - $this->errors[] = oai_error('noRecordsMatch'); - } - } + $records = call_user_func($this->listRecordsCallback, $metadataPrefix, $from, $until, $set, false, $deliveredRecords, $maxItems); - if (!empty($this->errors)) { - $this->errorResponse(); - } + $this->outputObj = new ANDS_Response_XML($this->args); + foreach ($records as $record) { - // Will we need a new ResumptionToken? - if($this->args['verb']=='ListRecords') { - $maxItems = MAXRECORDS; - } elseif($this->args['verb']=='ListIdentifiers') { - $maxItems = MAXIDS; - } else { - exit("Check ".__FILE__." ".__LINE__.", there is something wrong."); - } - $maxrec = min($num_rows - $deliveredrecords, $maxItems); + $identifier = $record['identifier']; + $datestamp = formatDatestamp($record['datestamp']); + $setspec = $record[$SQL['set']]; - if ($num_rows - $deliveredrecords > $maxItems) { - $cursor = (int)$deliveredrecords + $maxItems; - $restoken = createResumToken($cursor, $extquery, $metadataPrefix); - $expirationdatetime = gmstrftime('%Y-%m-%dT%TZ', time()+TOKEN_VALID); - } elseif (isset($args['resumptionToken'])) { - // Last delivery, return empty ResumptionToken - $restoken = $args['resumptionToken']; // just used as an indicator - unset($expirationdatetime); - } + $status_deleted = (isset($record['deleted']) && ($record['deleted'] === true) && + (($this->identifyResponse['deletedRecord'] == 'transient') || + ($this->identifyResponse['deletedRecord'] == 'persistent'))); - if (isset($this->args['resumptionToken'])) { - $record = $res->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_ABS, $deliveredrecords); - } - // Record counter - $countrec = 0; - - // Publish a batch to $maxrec number of records - $outputObj = new ANDS_Response_XML($this->args); - while ($countrec++ < $maxrec) { - $record = $res->fetch(PDO::FETCH_ASSOC); - if ($record===false) { - if (SHOW_QUERY_ERROR) { - echo __FILE__.",". __LINE__."
"; - print_r($db->errorInfo()); - exit(); + if($this->args['verb'] == 'ListRecords') { + $cur_record = $this->outputObj->create_record(); + $cur_header = $this->outputObj->create_header($identifier, $datestamp,$setspec,$cur_record); + if (!$status_deleted) { + $this->add_metadata($cur_record, $record); + } + } else { // for ListIdentifiers, only identifiers will be returned. + $cur_header = $this->outputObj->create_header($identifier, $datestamp,$setspec); + } + if ($status_deleted) { + $cur_header->setAttribute("status","deleted"); } } - $identifier = $oaiprefix.$record[$SQL['identifier']]; - $datestamp = formatDatestamp($record[$SQL['datestamp']]); - $setspec = $record[$SQL['set']]; + // Will we need a new ResumptionToken? + if ($records_count - $deliveredRecords > $maxItems) { - $status_deleted = (isset($record[$SQL['deleted']]) && ($record[$SQL['deleted']] === true) && - ($this->identifyResponse['deletedRecord'] == 'transient' || $this->identifyResponse['deletedRecord'] == 'persistent')); + $deliveredRecords += $maxItems; + $restoken = $this->createResumptionToken($deliveredRecords); - if($this->args['verb']=='ListRecords') { - $cur_record = $outputObj->create_record(); - $cur_header = $outputObj->create_header($identifier, $datestamp,$setspec,$cur_record); - // return the metadata record itself - if (!$status_deleted) { - call_user_func(array($this, "{$metadataPrefix}_create_metadata"), - $outputObj, $cur_record, $identifier, $setspec, $db); - } - } else { // for ListIdentifiers, only identifiers will be returned. - $cur_header = $outputObj->create_header($identifier, $datestamp,$setspec); + $expirationDatetime = gmstrftime('%Y-%m-%dT%TZ', time()+TOKEN_VALID); + + } elseif (isset($args['resumptionToken'])) { + // Last delivery, return empty ResumptionToken + $restoken = null; + $expirationDatetime = null; } - if ($status_deleted) { - $cur_header->setAttribute("status","deleted"); + + if (isset($restoken)) { + $this->outputObj->create_resumpToken($restoken,$expirationDatetime,$records_count,$deliveredRecords); } - } - // ResumptionToken - if (isset($restoken)) { - if(isset($expirationdatetime)) { - $outputObj->create_resumpToken($restoken,$expirationdatetime,$num_rows,$cursor); - } else { - $outputObj->create_resumpToken('',null,$num_rows,$deliveredrecords); - } - } - return $outputObj; - } - - /** - * Add a metadata format node to an ANDS_Response_XML - * \param &$outputObj - * type: ANDS_Response_XML. The ANDS_Response_XML object for output. - * \param $key - * type string. The name of new node. - * \param $val - * type: array. Values accessable through keywords 'schema' and 'metadataNamespace'. - * - */ - private function addMetedataFormat(&$outputObj,$key,$val) { - $cmf = $outputObj->add2_verbNode("metadataFormat"); - $outputObj->addChild($cmf,'metadataPrefix',$key); - $outputObj->addChild($cmf,'schema',$val['schema']); - $outputObj->addChild($cmf,'metadataNamespace',$val['metadataNamespace']); - } - - private function rif_create_metadata($outputObj, $cur_record, $identifier, $setspec, $db) { - - $metadata_node = $outputObj->create_metadata($cur_record); - $obj_node = new ANDS_TPA($outputObj, $metadata_node, $db); - try { - $obj_node->create_obj_node($setspec, $identifier); - } catch (Exception $e) { - echo 'Caught exception: ', $e->getMessage(), " when adding $identifier\n"; + } catch (OAI2Exception $e) { + $this->errors[] = $e; } } - private function oai_dc_create_metadata($outputObj, $cur_record, $identifier, $setspec, $db) { + private function add_metadata($cur_record, $record) { - $sql = "SELECT dc_title, dc_creator, dc_subject, dc_description, dc_contributor, dc_publisher, - dc_date , dc_type , dc_format , dc_identifier , dc_source , dc_language, - dc_relation , dc_coverage , dc_rights - FROM oai_records - WHERE oai_set = '{$setspec}' - AND oai_identifier = '{$identifier}'"; + $meta_node = $this->outputObj->addChild($cur_record ,"metadata"); - $res = exec_pdo_query($db,$sql); - $record = $res->fetch(PDO::FETCH_ASSOC); - - $meta_node = $outputObj->addChild($cur_record ,"metadata"); - - $schema_node = $outputObj->addChild($meta_node, 'oai_dc:dc'); - $schema_node->setAttribute('xmlns:oai_dc', "http://www.openarchives.org/OAI/2.0/oai_dc/"); - $schema_node->setAttribute('xmlns:dc',"http://purl.org/dc/elements/1.1/"); - $schema_node->setAttribute('xmlns:xsi',"http://www.w3.org/2001/XMLSchema-instance"); - $schema_node->setAttribute('xsi:schemaLocation', - 'http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd'); - foreach ($record as $r => $v) { - if (!empty($v)) { - $outputObj->addChild($schema_node, str_replace('_', ':', $r), $v); - } + $schema_node = $this->outputObj->addChild($meta_node, $record['metadata']['container_name']); + foreach ($record['metadata']['container_attributes'] as $name => $value) { + $schema_node->setAttribute($name, $value); + } + foreach ($record['metadata']['fields'] as $name => $value) { + $this->outputObj->addChild($schema_node, $name, $value); } } @@ -626,7 +337,8 @@ class OAI2Server { * is needed. */ private function checkArgs($checkList) { - global $METADATAFORMATS; + + $metadataFormats = call_user_func($this->listMetadataFormatsCallback); // "verb" has been checked before, no further check is needed $verb = $this->args["verb"]; @@ -637,17 +349,14 @@ class OAI2Server { if(isset($checkList['required'])) { for($i = 0; $i < count($checkList["required"]); $i++) { - if(isset($test_args[$checkList['required'][$i]])==false) { - $this->errors[] = oai_error('missingArgument', $checkList["required"][$i]); + if (isset($test_args[$checkList['required'][$i]]) == false) { + $this->errors[] = new OAI2Exception('missingArgument', $checkList["required"][$i]); } else { // if metadataPrefix is set, it is in required section if(isset($test_args['metadataPrefix'])) { $metadataPrefix = $test_args['metadataPrefix']; - // Check if the format is supported, it has enough infor (an array), last if a handle has been defined. - if (!array_key_exists($metadataPrefix, $METADATAFORMATS) || - !(is_array($METADATAFORMATS[$metadataPrefix]) || - !isset($METADATAFORMATS[$metadataPrefix]['myhandler']))) { - $this->errors[] = oai_error('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix); + if (!isset($metadataFormats[$metadataPrefix])) { + $this->errors[] = new OAI2Exception('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix); } } unset($test_args[$checkList["required"][$i]]); @@ -655,28 +364,61 @@ class OAI2Server { } } - if (!empty($this->errors)) return; - // check to see if there is unwanted foreach($test_args as $key => $val) { if(!in_array($key, $checkList["ops"])) { - $this->errors[] = oai_error('badArgument', $key, $val); + $this->errors[] = new OAI2Exception('badArgument', $key, $val); } switch ($key) { case 'from': case 'until': if(!checkDateFormat($val)) { - $this->errors[] = oai_error('badGranularity', $key, $val); + $this->errors[] = new OAI2Exception('badGranularity', $key, $val); } break; case 'resumptionToken': - // only check for expairation + // only check for expiration if((int)$val+TOKEN_VALID < time()) - $this->errors[] = oai_error('badResumptionToken'); + $this->errors[] = new OAI2Exception('badResumptionToken'); break; } } + + if (!empty($this->errors)) { + $this->errorResponse(); + } + } + + private function createResumptionToken($delivered_records) { + + list($usec, $sec) = explode(" ", microtime()); + $token = ((int)($usec*1000) + (int)($sec*1000)); + + $fp = fopen (TOKEN_PREFIX.$token, 'w'); + if($fp==false) { + exit("Cannot write. Writer permission needs to be changed."); + } + fputs($fp, "$delivered_records#"); + fputs($fp, "$metadataPrefix#"); + fputs($fp, "{$this->args['from']}#"); + fputs($fp, "{$this->args['until']}#"); + fputs($fp, "{$this->args['set']}#"); + fclose($fp); + return $token; + } + + private function readResumptionToken($resumptionToken) { + $rtVal = false; + $fp = fopen($resumptionToken, 'r'); + if ($fp != false) { + $filetext = fgets($fp, 255); + $textparts = explode('#', $filetext); + fclose($fp); + unlink($resumptionToken); + $rtVal = array_values($textparts); + } + return $rtVal; } } diff --git a/oai2xml.php b/oai2xml.php new file mode 100644 index 0000000..4fa7b1c --- /dev/null +++ b/oai2xml.php @@ -0,0 +1,67 @@ +doc = new DOMDocument("1.0","UTF-8"); + $oai_node = $this->doc->createElement("OAI-PMH"); + $oai_node->setAttribute("xmlns","http://www.openarchives.org/OAI/2.0/"); + $oai_node->setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); + $oai_node->setAttribute("xsi:schemaLocation","http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd"); + $this->addChild($oai_node,"responseDate",gmdate("Y-m-d\TH:i:s\Z")); + $this->doc->appendChild($oai_node); + + $request = $this->addChild($this->doc->documentElement,"request",MY_URI); + foreach($request_args as $key => $value) { + $request->setAttribute($key,$value); + } + } + + function display() { + $pr = new DOMDocument(); + $pr->preserveWhiteSpace = false; + $pr->formatOutput = true; + $pr->loadXML($this->doc->saveXML()); + echo $pr->saveXML(); + } + + /** + * Add a child node to a parent node on a XML Doc: a worker function. + * + * @param $mom_node + * Type: DOMNode. The target node. + * + * @param $name + * Type: string. The name of child nade is being added + * + * @param $value + * Type: string. Text for the adding node if it is a text node. + * + * @return DOMElement $added_node + * The newly created node, can be used for further expansion. + * If no further expansion is expected, return value can be igored. + */ + + function addChild($mom_node,$name, $value='') { + $added_node = $this->doc->createElement($name,$value); + $added_node = $mom_node->appendChild($added_node); + return $added_node; + } +} + +class OAI2XMLError extends OAI2XML { + + function __construct($request_args, $errors) { + parent::__construct($request_args); + + $oai_node = $this->doc->documentElement; + foreach($errors as $e) { + $node = $this->addChild($oai_node,"error",$e->getMessage()); + $node->setAttribute("code",$e->getCode()); + } + } + +} diff --git a/oaidp-config.php b/oaidp-config.php deleted file mode 100644 index be37d47..0000000 --- a/oaidp-config.php +++ /dev/null @@ -1,77 +0,0 @@ -= '$from'"; -} - -/** filter for sets, appends to the end of SQL query */ -function setQuery($set) { - global $SQL; - // strip off "class:" which is not saved in database - if(strstr($set,"class:")) $set = substr($set,6); - return ' AND '.$SQL['set']." LIKE '%$set%'"; -} - -/** for accurately to assess how many records satisfy conditions for all DBs */ -function rowCount($metadataPrefix, $extQuery, $db) { - global $SQL; - $n = 0; - $sql = "SELECT COUNT(*) FROM ".$SQL['table'] . " WHERE ".$SQL['metadataPrefix']." LIKE '%$metadataPrefix%'" . $extQuery; - if ($res = $db->query($sql)) { - $n = $res->fetchColumn(); - } - return $n; -} - -/** A worker function for processing an error when a query was executed - * \param $query string, original query - * \param $e PDOException, the PDOException object - */ -function process_pdo_error($query, $e) { - echo $query.' was failed\n'; - echo $e->getMessage(); -} - -/** When query return no result, throw an Exception of Not found. - * \param $db PDO - * \param $query string - * \return $res PDOStatement - */ -function exec_pdo_query($db, $query) { - $res = $db->query($query); - if ($res===false) { - throw new Exception($query.":\nIt found nothing.\n"); - } else return $res; -} diff --git a/xml_creater.php b/xml_creater.php index b46ec80..a2f0382 100644 --- a/xml_creater.php +++ b/xml_creater.php @@ -1,145 +1,15 @@ "ListRecords","resumptionToken"=>"9CD1DA87F59C3E960871F4F3C9D093887C17D174"); - * // Example 1: Error response - * $error_array[] = oai_error("badVerb","Rubish"); - * $error_array[] = oai_error("sameVerb"); - * $e = new ANDS_Error_XML($par_array,$error_array); - * $e->display(); - * - - * // Example 2: Normal response without error codes + * Example: Normal response without error codes * $par_array = array("verb"=>"ListRecords","resumptionToken"=>"9CD1DA87F59C3E960871F4F3C9D093887C17D174"); * $test = new ANDS_Response_XML($par_array); * $record_node = $test->create_record(); * $test->create_header("function: identifier string",gmdate("Y-m-d\TH:i:s\Z"),"collection",$record_node); * $test->create_metadata($record_node); * $test->display(); - * \endcode - * - * \see http://www.openarchives.org/OAI/openarchivesprotocol.html#ErrorConditions */ -/* -http://www.openarchives.org/OAI/openarchivesprotocol.html#ErrorConditions - -badArgument: - The request includes illegal arguments, is missing required arguments, includes a repeated argument, or values for arguments have an illegal syntax. Applied to all verbs. - -badResumptionToken: - The value of the resumptionToken argument is invalid or expired. Applied to: ListIdentifiers, ListRecords, ListSets - -badVerb: - Value of the verb argument is not a legal OAI-PMH verb, the verb argument is missing, or the verb argument is repeated. N/A - -cannotDisseminateFormat: - The metadata format identified by the value given for the metadataPrefix argument is not supported by the item or by the repository. Applied to GetRecord, ListIdentifiers, ListRecords - -idDoesNotExist: - The value of the identifier argument is unknown or illegal in this repository. Applied to GetRecord, ListMetadataFormats - -noRecordsMatch: - The combination of the values of the from, until, set and metadataPrefix arguments results in an empty list. Applied to ListIdentifiers, ListRecords - -noMetadataFormats: - There are no metadata formats available for the specified item. Applied to ListMetadataFormats. - -noSetHierarchy: - The repository does not support sets. Applied to ListSets, ListIdentifiers, ListRecords - -*/ - -/** utility funciton to mapping error codes to readable messages */ -function oai_error($code, $argument = '', $value = '') { - - switch ($code) { - case 'badArgument' : - $text = "Attribute '{$argument}' is not allowed to appear in element 'request'."; - break; - - case 'badGranularity' : - $text = "The value '{$value}' of attribute '{$argument}' on element 'request' is not valid with respect to its type, 'UTCdatetimeType'."; - $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 value '{$argument}' of attribute 'verb' on element 'request' is not valid with respect to its type, 'verbType'"; - 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 does not exist in this repository."; - if (!is_valid_uri($value)) { - $code = 'badArgument'; - $text .= ' Invalidated URI has been detected.'; - } - 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 the same argument more than once.'; - $code = 'badArgument'; - break; - - case 'sameVerb' : - $text = 'Do not use verb more than once.'; - $code = 'badVerb'; - break; - - case 'notImp' : - $text = 'Not yet implemented.'; - $code = 'debug'; - break; - - default: - $text = "Unknown error: code: '{$code}', argument: '{$argument}', value: '{$value}'"; - $code = 'badArgument'; - } - return $code."|".$text; -} /** * A wraper of DOMDocument for data provider