diff --git a/lib/oaipmh/COPYRIGHT.txt b/lib/oaipmh/COPYRIGHT.txt
new file mode 100644
index 0000000..79e709e
--- /dev/null
+++ b/lib/oaipmh/COPYRIGHT.txt
@@ -0,0 +1,14 @@
+Copyright (c) 2011 Jianfeng Li
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
diff --git a/lib/oaipmh/ands_rifcs.php b/lib/oaipmh/ands_rifcs.php
new file mode 100644
index 0000000..41625bd
--- /dev/null
+++ b/lib/oaipmh/ands_rifcs.php
@@ -0,0 +1,260 @@
+oai_pmh = $ands_response_doc;
+ $this->working_node = $metadata_node;
+ $this->create_regObjects();
+ }
+
+ /**
+ * A worker function for easily adding a newly created node to current XML Doc.
+ * @param $mom_node Type: DOMElement. Node the new child will be attached to.
+ * @param $name Type: sting. The name of the child node is being added.
+ * @param $value Type: sting. The text content of the child node is being added. The default is ''.
+ * @return DOMElement. The added child node
+ */
+ protected function addChild($mom_node,$name, $value='') {
+ return $this->oai_pmh->addChild($mom_node,$name, $value);
+ }
+
+ /** Create a registryObjects node to hold individual registryObject's.
+ * This is only a holder node.
+ */
+ protected function create_regObjects() {
+ $this->working_node = $this->oai_pmh->addChild($this->working_node,'registryObjects');
+ $this->working_node->setAttribute('xmlns',"http://ands.org.au/standards/rif-cs/registryObjects");
+ $this->working_node->setAttribute('xmlns:xsi',"http://www.w3.org/2001/XMLSchema-instance");
+ $this->working_node->setAttribute('xsi:schemaLocation','http://ands.org.au/standards/rif-cs/registryObjects http://services.ands.org.au/documentation/rifcs/1.2.0/schema/registryObjects.xsd');
+ }
+
+ /** Create a single registryObject node. Each set has its own structure but they all have an attribute of group, a key node and an originatingSource node. The newly created node will be used as the working node.
+ *
+ * \param $group string, group attribute of the new registryObject node .
+ * \param $key string, key node, used as an identifier.
+ * \param $originatingSource string, an url of the data provider.
+ */
+ protected function create_regObject($group, $key, $originatingSource) {
+ $regObj_node = $this->addChild($this->working_node,'registryObject');
+ $regObj_node->setAttribute('group',$group);
+ $this->addChild($regObj_node,'key',$key);
+ $this->addChild($regObj_node,'originatingSource',$originatingSource);
+ $this->working_node = $regObj_node;
+ }
+
+ /** RIF-CS node is the content node of RIF-CS metadata node which starts from regObjects.
+ * Each set supportted in RIF-CS has its own content model. The created node will be used as the
+ * root node of this record for following nodes will be created.
+ *
+ * \param $set_name string, the name of set. For ANDS, they are Activity, Party and Collection
+ * \param $set_type string, the type of set. For example, Activity can have project as a type.
+ */
+ protected function create_rifcs_node($set_name, $set_type) {
+ $this->working_node = $this->addChild($this->working_node, $set_name);
+ $this->working_node->setAttribute('type', $set_type);
+ }
+
+ /**
+ * Create a top level name node.
+ * @param $name_type string. Text for the types, can be either primary or abbreviated. Default: primary
+ *
+ * @return DOMElement $added_name_node.
+ * The newly created node, it will be used for further expansion by adding namePart.
+ */
+ protected function create_name_node($name_type = 'primary') {
+ $c = $this->addChild($this->working_node, 'name');
+ $c->setAttribute('type', $name_type);
+ return $c;
+ }
+
+ /**
+ * Create a namePart of a name node.
+ * @param $name_node
+ * Type: DOMElement. Node of name_node created previously
+ *
+ * @param $value
+ * Type: string. Text fror this namePart
+ *
+ * @param $part_type Type: string, used for group:person record. Types can be: titile, given, family
+ *
+ */
+ protected function create_namePart($name_node, $value, $part_type = '') {
+ $c = $this->addChild($name_node, 'namePart', $value);
+ if (!empty($part_type)) {
+ $c->setAttribute('type', $part_type);
+ }
+ }
+
+ /** Create related object. One RIF-CS can have more than one related object nodes,
+ * each object is described by one node.
+ * \param $key
+ * Type: string. The identifier of the related object.
+ * \param $relation_type
+ * Type: string. Type of relationship.
+ *
+ */
+ protected function create_relatedObject($key,$relation_type) {
+ $c = $this->addChild($this->working_node, 'relatedObject');
+ $this->addChild($c,'key',$key);
+ $c = $this->addChild($c, 'relation');
+ // Mimick ANDS with enpty value to get both tags for relation. Only for better display
+ // $c = $this->addChild($c, 'relation',' ');
+ $c->setAttribute('type', $relation_type);
+ }
+
+ /** Create description node. One RIF-CS can have more than one description nodes.
+ * Each description node has only one description.
+ * \param $value Type: string. The content of the description.
+ * \param $des_type Type: string. Type of the description. Types can be brief, full, acessRights and note. Default is 'brief'.
+ */
+ protected function create_description_node($value, $des_type='brief') {
+ $c = $this->addChild($this->working_node, 'description', $value);
+ $c->setAttribute('type', $des_type);
+ }
+
+ /** Create local or other type of identifier inside of RIF-CS metadata node
+ * \param $key
+ * Type string. The indentifier itself.
+ * \param $i_type
+ * Type string. Type of identifier. Can be abn, uri, local, etc.. Default is local.
+ */
+ protected function create_identifier_node($key, $i_type='local') {
+ $c = $this->addChild($this->working_node, 'identifier',$key);
+ $c->setAttribute('type', $i_type);
+ }
+
+ /** Location node is a holder node for either address or spatial nodes
+ * \return DOMElement node, for adding address or spatial nodes.
+ */
+ protected function create_location_node() {
+ return $this->addChild($this->working_node, 'location');
+ }
+
+ /** Address node is a holder node for phiscal or electrical nodes.
+ * \param $location_node Type: DOMElement. Location node created previously.
+ * \return DOMElement
+ */
+ protected function create_address_node($location_node) {
+ return $this->addChild($location_node, 'address');
+ }
+
+ /** Electrical address node. Used for email, url, etc
+ * \param $addr_node Type: DOMElement. Previously created address node.
+ * \param $e_node Type: string. The content of the adding node.
+ * \param $e_type Type: string. Default is email.
+ */
+ protected function create_e_node($addr_node, $e_node, $e_type = 'email') {
+ $c = $this->addChild($addr_node, 'electronic');
+ $c->setAttribute('type', $e_type);
+ $this->addChild($c,'value',$e_node);
+ }
+
+ /** Physical node is a holder node for phone or fax nodes.
+ * \param $addr_node Type: DOMelement. Address node created before to which the new phiscial->addressPart will be attached.
+ * \param $number Type: string. Telephone or fax number as a string.
+ * \param $fone_fax Type: string. Either telehoneNumber or faxNumber.
+ */
+ protected function create_physcial_fone_fax($addr_node, $number,$fone_fax='telephoneNumber') {
+ $c = $this->addChild($addr_node, 'physical');
+ $c = $this->addChild($c, 'addressPart', $number);
+ $c->setAttribute('type', $fone_fax);
+ }
+
+ /** create address node under location node, either streetAddress or postalAddress.
+ * But they are in text (one block) format.
+ * \param $addr_node Type: DOMelement. Address node created before to which the new phiscial->addressPart will be attached.
+ * \param $txt_addr string, full street address in text block format
+ * \param $phys_type string, default is 'streetAddress', can be 'postalAddress'
+ */
+ protected function create_physcial_addr_txt($addr_node, $txt_addr,$phys_type='streetAddress') {
+ $c = $this->addChild($addr_node, 'physical');
+ $c->setAttribute('type', $phys_type);
+ $c = $this->addChild($c, 'addressPart', $txt_addr);
+ $c->setAttribute('type', 'text');
+ }
+
+ /** Create spatial node under a location node.
+ * \param $location_node Type: DOMElement. Location node where spatial node is being added to.
+ * \param $value Type: string. The value of spatial information. Default is local latitude and longitude.
+ * \param $sp_type Type: string. Type of spaitial informaion. Default is kmlPolyCoords.
+ */
+ protected function create_spatial_node($location_node, $value = '138.6396,-34.97063', $sp_type = 'kmlPolyCoords') {
+ $c = $this->addChild($location_node, 'spatial',$value);
+ $c->setAttribute('type',$sp_type);
+ }
+
+ /** Create temporal coverage node for collection or activity records.
+ * \param $values Type: 2-D array. The values of temporal coverage. It can has maximal two elements: one from 'dateFrom' and another for 'dateTo'.
+ * Either can be ommited according to RIF-CS schema. Each element of $values is an array and has keys: date, type and format.
+ * ['date'] is a string represents date. It has to be in W3CDTF or UTC format.
+ * ['type'] has to be either 'dateFrom' or 'dateTo'.
+ * ['format'] is optional and its default is 'W3CDTF'. UTC format requires date has to be in UTC: dateTtimeZ.
+ * It throws an exception if the input parameter is not an array.
+ */
+ protected function create_coverage_tempo($values) {
+ // Non array is not acceptable.
+ if (!is_array($values)) { throw new Exception('The input of temporal coverage has to be an array of arraies with keys.');}
+ $c = $this->addChild($this->working_node,'coverage');
+ $t = $this->addChild($c,'temporal');
+ foreach($values as $value) $this->create_coverage_tempo_date($t, $value);
+ }
+
+ /** Create temporal coverage node for collection or activity records.
+ * \param $t Type: DOMElement. The \\\ node to which \ nodes will be attached to.
+ * \param $value Type: array. The value of temporal coverage. It has maxmimal three elements with keys: type, date and format.
+ * It throws an exception if the input parameter is not an array.
+ * \see create_coverage_tempo
+ */
+ private function create_coverage_tempo_date($t, $value) {
+ if (!is_array($value)) { throw new Exception('The input of temporal coverage has to be an array with keys.');}
+ $d = $this->addChild($t,'date',$value['date']);
+ $d->setAttribute('type',$value['type']);
+ if (isset($value['format'])) $d->setAttribute('dateFormat',$value['format']);
+ else $d->setAttribute('dateFormat','W3CDTF');
+ }
+
+ /** Create a subject node for a researcher, project, project, etc
+ * \param $value Type: string. A string representing the new namePart.
+ * \param $subject_type Type: string. A string representing the type of subject. The default value is anzsrc-for.
+ */
+ protected function create_subject_node($value, $subject_type = 'anzsrc-for') {
+ if (empty($value)) return;
+ $c = $this->addChild($this->working_node,'subject',$value);
+ $c->setAttribute('type',$subject_type);
+ }
+} // end of class ANDS_RIFCS
+
diff --git a/lib/oaipmh/ands_tpa.php b/lib/oaipmh/ands_tpa.php
new file mode 100644
index 0000000..e86c031
--- /dev/null
+++ b/lib/oaipmh/ands_tpa.php
@@ -0,0 +1,349 @@
+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(%d) 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/lib/oaipmh/getrecord.php b/lib/oaipmh/getrecord.php
new file mode 100644
index 0000000..2c8cc2b
--- /dev/null
+++ b/lib/oaipmh/getrecord.php
@@ -0,0 +1,80 @@
+$metadataPrefix and $identifier need to be provided through global array variable $args
+ * by their indexes 'metadataPrefix' and 'identifier'.
+ * The reset of information will be extracted from database based those two parameters.
+ */
+
+debug_message("\nI am debuging". __FILE__) ;
+
+$metadataPrefix = $args['metadataPrefix'];
+// myhandler is a php file which will be included to generate metadata node.
+// $inc_record = $METADATAFORMATS[$metadataPrefix]['myhandler'];
+
+if (is_array($METADATAFORMATS[$metadataPrefix])
+ && isset($METADATAFORMATS[$metadataPrefix]['myhandler'])) {
+ $inc_record = $METADATAFORMATS[$metadataPrefix]['myhandler'];
+} else {
+ $errors[] = oai_error('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix);
+}
+
+$identifier = $args['identifier'];
+$query = selectallQuery($metadataPrefix, $identifier);
+
+debug_message("Query: $query") ;
+
+$res = $db->query($query);
+
+if ($res===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ die($db->errorInfo());
+ } else {
+ $errors[] = oai_error('idDoesNotExist', '', $identifier);
+ }
+} elseif (!$res->rowCount()) { // based on PHP manual, it might only work for some DBs
+ $errors[] = oai_error('idDoesNotExist', '', $identifier);
+}
+
+
+if (!empty($errors)) {
+ oai_exit();
+}
+
+$record = $res->fetch(PDO::FETCH_ASSOC);
+if ($record===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ }
+ $errors[] = oai_error('idDoesNotExist', '', $identifier);
+}
+
+$identifier = $record[$SQL['identifier']];;
+
+$datestamp = formatDatestamp($record[$SQL['datestamp']]);
+
+if (isset($record[$SQL['deleted']]) && ($record[$SQL['deleted']] == 'true') &&
+ ($deletedRecord == 'transient' || $deletedRecord == 'persistent')) {
+ $status_deleted = TRUE;
+} else {
+ $status_deleted = FALSE;
+}
+
+$outputObj = new ANDS_Response_XML($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) {
+ include($inc_record); // where the metadata node is generated.
+ create_metadata($outputObj, $cur_record, $identifier, $record[$SQL['set']], $db);
+} else {
+ $cur_header->setAttribute("status","deleted");
+}
+?>
diff --git a/lib/oaipmh/identify.php b/lib/oaipmh/identify.php
new file mode 100644
index 0000000..1811bff
--- /dev/null
+++ b/lib/oaipmh/identify.php
@@ -0,0 +1,139 @@
+ $val) {
+ $outputObj->add2_verbNode($key, $val);
+}
+
+foreach($adminEmail as $val) {
+ $outputObj->add2_verbNode("adminEmail", $val);
+}
+
+if(isset($compression)) {
+ foreach($compression as $val) {
+ $outputObj->add2_verbNode("compression", $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 ($show_identifier && $repositoryIdentifier && $delimiter && $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);
+}
+?>
diff --git a/lib/oaipmh/index.php b/lib/oaipmh/index.php
new file mode 100644
index 0000000..862f00a
--- /dev/null
+++ b/lib/oaipmh/index.php
@@ -0,0 +1,141 @@
+Query functions
+ * to reflect it and even develop your own code.
+ *- Check your oai site through a web browser. e.g. : \code http://localhost/oai/ \endcode
+ *- SELinux needs special treatments for database connection and other permission.
+ *
+ * \section struct_sec Structure
+The system includes files for individual functionality and utility classes and functions to get it work.
+- Controller
+ - oai2.php
+- Individual functionalities:
+ - identify.php: identifies the data provider. Responses to Identify.
+ - listmetadataformats.php: lists supported metadata formats, e.g. dc or rif-cs. Responses to ListMetadataFormats.
+ - listsets.php: lists supported sets, e.g. Activity, Collection or Party. Responses to ListSets.
+ - listrecords.php: lists a group of records without details. Responses to ListRecords. It also serves to ListIdentifiers which only returns identifiers.
+ - getrecord.php: gets an individual record. Responses to GetRecord.
+- Utility classes
+ - xml_creater.php which includes classess ANDS_XML, ANDS_Error_XML, ANDS_Response_XML
+- Utility functions
+ - oaidp-util.php
+ - Support to different metadataformats in your own systems. Two examples provided with the package are: record_dc.php and record_rif.php. They are helpers and need information from the real records. They need to be devloped for your particular system.
+- Configurations
+ - oaidp-config.php
+
+ *
+ * \author Jianfeng Li
+ * \version 1.1
+ * \date 2010-2011
+ */
+
+/**
+ * \file
+ * \brief
+ * Default starting point of OAI Data Provider for a human to check.
+ *
+ * OAI Data Provider is not designed for human to retrieve data but it is possible to use this page to test and check the functionality of current implementation.
+ * This page provides a summary of the OAI-PMH and the implementation.
+ *
+*/
+
+$MY_URI = 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME'];
+$pos = strrpos($MY_URI, '/');
+$MY_URI = substr($MY_URI, 0, $pos). '/oai2.php';
+
+?>
+
+
+php-oai2 Data Provider
+
+
+
+
This implementation completely complies to OAI-PMH 2.0, including the support of on-the-fly output compression which may significantly
+reduce the amount of data being transfered.
+
+
This package has been inspired by PHP OAI Data Provider developed by Heinrich Stamerjohanns at University of Oldenburg.
+ Some of the functions and algorithms used in this code were transplanted from his implementation.
+
+
Database is supported through PDO, so almost any popular SQL-database which has PDO driver can be used without any change in the code.
+
+
It uses DOM extension,an extension included in every PHP installation since version 5, for generating XML files. With PHP 5 or above no extra extension is needed.
+
+
The repository can be quite easily configured by just editing oai2/oaidp-config.php, most possible values and options are explained.
+For requirements and instructions to install and configure, please reference the documentation.
+
+
Once you have setup your Data Provider, you can the easiliy check the generated answers (it will be XML) of your Data Provider
+by clicking on the test links below.
+
+
For simple visual tests set $SHOW_QUERY_ERROR to TRUE and $CONTENT_TYPE to text/plain, so you can easily read the generated XML responses in your browser.
+
+
Remember, GetRecord needs identifier to work.
+So please change it use your own or you should see a response with error message.
+For other tests on your own provider or other providers, please use the Repository Explorer.
+
+
+Jianfeng Li
+The Plant Accelerator
+University of Adelaide
+
+
+
+
+
+
diff --git a/lib/oaipmh/listmetadataformats.php b/lib/oaipmh/listmetadataformats.php
new file mode 100644
index 0000000..7c1bf3c
--- /dev/null
+++ b/lib/oaipmh/listmetadataformats.php
@@ -0,0 +1,67 @@
+idFormatQuery.
+ * \sa idFormatQuery
+ */
+
+/**
+ * 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'.
+ *
+ */
+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']);
+}
+
+if (isset($args['identifier'])) {
+ $identifier = $args['identifier'];
+ $query = idFormatQuery($identifier);
+ $res = $db->query($query);
+ if ($res==false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ die($db->errorInfo());
+ } else {
+ $errors[] = oai_error('idDoesNotExist','', $identifier);
+ }
+ } else {
+ $record = $res->fetch();
+ if($record===false) {
+ $errors[] = oai_error('idDoesNotExist', '', $identifier);
+ } else {
+ $mf = explode(",",$record[$SQL['metadataPrefix']]);
+ }
+ }
+}
+
+//break and clean up on error
+if (!empty($errors)) oai_exit();
+
+$outputObj = new ANDS_Response_XML($args);
+if (isset($mf)) {
+ foreach($mf as $key) {
+ $val = $METADATAFORMATS[$key];
+ addMetedataFormat($outputObj,$key, $val);
+ }
+} elseif (is_array($METADATAFORMATS)) {
+ foreach($METADATAFORMATS as $key=>$val) {
+ addMetedataFormat($outputObj,$key, $val);
+ }
+}
+else { // a very unlikely event
+ $errors[] = oai_error('noMetadataFormats');
+ oai_exit();
+}
+?>
diff --git a/lib/oaipmh/listrecords.php b/lib/oaipmh/listrecords.php
new file mode 100644
index 0000000..0cf5226
--- /dev/null
+++ b/lib/oaipmh/listrecords.php
@@ -0,0 +1,190 @@
+$args by keywords.
+ */
+
+debug_message("\nI am debuging". __FILE__) ;
+
+// Resume previous session?
+if (isset($args['resumptionToken'])) {
+ $readings = readResumToken($args['resumptionToken']);
+
+ if ($readings == false) {
+ $errors[] = oai_error('badResumptionToken', '', $args['resumptionToken']);
+ } else {
+ debug_var_dump('readings',$readings);
+ list($deliveredrecords, $extquery, $metadataPrefix) = $readings;
+ }
+} else { // no, we start a new session
+ $deliveredrecords = 0;
+ $extquery = '';
+
+ $metadataPrefix = $args['metadataPrefix'];
+
+ if (isset($args['from'])) {
+ $from = checkDateFormat($args['from']);
+ $extquery .= fromQuery($from);
+ }
+
+ if (isset($args['until'])) {
+ $until = checkDateFormat($args['until']);
+ $extquery .= untilQuery($until);
+ }
+
+ if (isset($args['set'])) {
+ if (is_array($SETS)) {
+ $extquery .= setQuery($args['set']);
+ } else {
+ $errors[] = oai_error('noSetHierarchy');
+ }
+ }
+}
+
+if (!empty($errors)) {
+ oai_exit();
+}
+
+// Load the handler
+if (is_array($METADATAFORMATS[$metadataPrefix])
+ && isset($METADATAFORMATS[$metadataPrefix]['myhandler'])) {
+ $inc_record = $METADATAFORMATS[$metadataPrefix]['myhandler'];
+ include($inc_record);
+} else {
+ $errors[] = oai_error('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix);
+}
+
+if (!empty($errors)) {
+ oai_exit();
+}
+
+if (empty($errors)) {
+ $query = selectallQuery($metadataPrefix) . $extquery . " ORDER BY " . $SQL['identifier'] . " ASC ";
+
+ // workaround for mysql
+ if (isset($deliveredrecords)){
+ $query .= " LIMIT " . MAXRECORDS . " OFFSET $deliveredrecords ";
+ }
+
+ debug_message("Query: $query") ;
+
+ $res = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
+ $r = $res->execute();
+ if ($r===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ print_r($db->errorInfo());
+ exit();
+ } else {
+ $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) {
+ echo "Cannot find records: $query\n";
+ $errors[] = oai_error('noRecordsMatch');
+ }
+ }
+}
+
+if (!empty($errors)) {
+ oai_exit();
+}
+
+// Will we need a new ResumptionToken?
+if($args['verb']=='ListRecords') {
+ $maxItems = MAXRECORDS;
+} elseif($args['verb']=='ListIdentifiers') {
+ $maxItems = MAXIDS;
+} else {
+ exit("Check ".__FILE__." ".__LINE__.", there is something wrong.");
+}
+$maxrec = min($num_rows - $deliveredrecords, $maxItems);
+
+if ($num_rows - $deliveredrecords > $maxItems) {
+ $cursor = (int)$deliveredrecords + $maxItems;
+ $restoken = createResumToken($cursor, $extquery, $metadataPrefix);
+ $expirationdatetime = gmstrftime('%Y-%m-%dT%TZ', time()+TOKEN_VALID);
+}
+// Last delivery, return empty ResumptionToken
+elseif (isset($args['resumptionToken'])) {
+ $restoken = $args['resumptionToken']; // just used as an indicator
+ unset($expirationdatetime);
+}
+
+
+// this don't work on mysql
+/*
+if (isset($args['resumptionToken'])) {
+ debug_message("Try to resume because a resumptionToken supplied.") ;
+ $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($args);
+while ($countrec++ < $maxrec) {
+ $record = $res->fetch(PDO::FETCH_ASSOC);
+ //print_r($record);
+ if ($record===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.",". __LINE__." ";
+ print_r($db->errorInfo());
+ exit();
+ }
+ }
+
+ $identifier = $record[$SQL['identifier']];
+ $datestamp = formatDatestamp($record[$SQL['datestamp']]);
+ $setspec = $record[$SQL['set']];
+
+ // debug_var_dump('record', $record);
+ if (isset($record[$SQL['deleted']]) && ($record[$SQL['deleted']] === true) &&
+ ($deletedRecord == 'transient' || $deletedRecord == 'persistent')) {
+ $status_deleted = TRUE;
+ } else {
+ $status_deleted = FALSE;
+ }
+
+ //debug_var_dump('status_deleted', $status_deleted);
+ if($args['verb']=='ListRecords') {
+ $cur_record = $outputObj->create_record();
+ $cur_header = $outputObj->create_header($oaiprefix.'-'.$identifier, $datestamp,$setspec,$cur_record);
+ // return the metadata record itself
+ if (!$status_deleted) {
+ debug_var_dump('inc_record',$inc_record);
+ create_metadata($outputObj, $cur_record, $identifier, $setspec, $db);
+ }
+ } else { // for ListIdentifiers, only identifiers will be returned.
+ $cur_header = $outputObj->create_header($oaiprefix.'-'.$identifier, $datestamp,$setspec);
+ }
+ if ($status_deleted) {
+ $cur_header->setAttribute("status","deleted");
+ }
+}
+
+// ResumptionToken
+if (isset($restoken)) {
+ if(isset($expirationdatetime)) {
+ $outputObj->create_resumpToken($restoken,$expirationdatetime,$num_rows,$cursor);
+ } else {
+ $outputObj->create_resumpToken('',null,$num_rows,$deliveredrecords);
+ }
+}
+
+// end ListRecords
+if (SHOW_QUERY_ERROR) {echo "Debug listrecord.php reached to the end.\n\n";}
+?>
diff --git a/lib/oaipmh/listsets.php b/lib/oaipmh/listsets.php
new file mode 100644
index 0000000..8c47918
--- /dev/null
+++ b/lib/oaipmh/listsets.php
@@ -0,0 +1,30 @@
+add2_verbNode("set");
+ foreach($set as $key => $val) {
+ if($key=='setDescription') {
+ $desNode = $outputObj->addChild($setNode,$key);
+ $des = $outputObj->doc->createDocumentFragment();
+ $des->appendXML($val);
+ $desNode->appendChild($des);
+ } else {
+ $outputObj->addChild($setNode,$key,$val);
+ }
+ }
+ }
+} else {
+ $errors[] = oai_error('noSetHierarchy');
+ oai_exit();
+}
+
+?>
diff --git a/lib/oaipmh/oaidp-config.php b/lib/oaipmh/oaidp-config.php
new file mode 100644
index 0000000..edbd712
--- /dev/null
+++ b/lib/oaipmh/oaidp-config.php
@@ -0,0 +1,305 @@
+$adminEmail: the e-mail addresses of administrators of the repository.
+ *
+ * - $repositoryIdentifier : For a data provider there is only one. For repositories to comply with the oai
+ * format it has to be unique identifiers for items records. Basically using domainname will be fine.
+ * See: http://www.openarchives.org/OAI/2.0/guidelines-oai-identifier.htm.
+ *
+ * - $SETS: An array with key words . List of supported SETs.
+ *
+ * - $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.
+ *
+ * - $SQL: Settings for database and queries from database
+ *
+ * - $DSN: DSN for connecting your database. Reference PDO for details.
+ *
+ * The rest of settings will not normally need to be adjusted. Read source code for details.
+*/
+
+/**
+ * Whether to show error message for dubug.
+ * For installation, testing and debuging set SHOW_QUERY_ERROR to TRUE
+ * If set to TRUE, application will die and display query and database error message
+ * as soon as there is a problem. Do not set this to TRUE on a production site,
+ * since it will show error messages to everybody.
+ * If set FALSE, will create XML-output, no matter what happens.
+ */
+// If everything is running ok, you should use this
+define('SHOW_QUERY_ERROR',FALSE);
+
+/**
+ * \property CONTENT_TYPE
+ * The content-type the WWW-server delivers back. For debug-puposes, "text/plain"
+ * is easier to view. On a production site you should use "text/xml".
+ */
+#define('CONTENT_TYPE','Content-Type: text/plain');
+// If everything is running ok, you should use this
+define('CONTENT_TYPE', 'Content-Type: text/xml');
+
+/**
+ * Identifier settings. It needs to have proper values to reflect the settings of the data provider.
+ *
+ * - $identifyResponse['repositoryName'] : compulsory. A human readable name for the repository;
+ * - $identifyResponse['baseURL'] : compulsory. The base URL of the repository;
+ * - $identifyResponse['protocolVersion'] : compulsory. The version of the OAI-PMH supported by the repository;
+ * - $identifyResponse['earliestDatestamp'] : compulsory. A UTCdatetime that is the guaranteed lower limit of all datestamps recording changes, modifications, or deletions in the repository. A repository must not use datestamps lower than the one specified by the content of the earliestDatestamp element. earliestDatestamp must be expressed at the finest granularity supported by the repository.
+ * - $identifyResponse['deletedRecord'] : the manner in which the repository supports the notion of deleted records. Legitimate values are no ; transient ; persistent with meanings defined in the section on deletion.
+ * - $identifyResponse['granularity'] : the finest harvesting granularity supported by the repository. The legitimate values are YYYY-MM-DD and YYYY-MM-DDThh:mm:ssZ with meanings as defined in ISO8601.
+ *
+ */
+$identifyResponse = array();
+
+// MUST (only one)
+// please adjust
+$identifyResponse["repositoryName"] = $_SERVER['SERVER_NAME'];
+
+// For ANDS to harvest of RIF-CS, originatingSource is plantaccelerator.org.au
+// $dataSource = "plantaccelerator.org.au";
+define('DATASOURCE',$_SERVER['SERVER_NAME']);
+
+// do not change
+define('MY_URI','http://'.$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']);
+// You can use a static URI as well.
+// $baseURL = "http://my.server.org/oai/oai2.php";
+$identifyResponse["baseURL"] = MY_URI;
+
+// By default SLIMS_SERVER_NAME is taken from the $_SERVER array. If it is different than your
+// expected name, please change its value to your actual server name such as: my.server.name.com
+define('SLIMS_SERVER_NAME', $_SERVER['SERVER_NAME']);
+
+define('SLIMS_BASE_URL', 'http://'.SLIMS_SERVER_NAME.dirname($_SERVER['SCRIPT_NAME']));
+
+// do not change
+$identifyResponse["protocolVersion"] = '2.0';
+
+// MUST (only one)
+// the earliest datestamp in your repository,
+// please adjust
+// Only date is needed even later it will be formatted according to the granularity.
+$identifyResponse["earliestDatestamp"] = '2011-01-01';
+
+// How your repository handles deletions
+// no: The repository does not maintain status about deletions.
+// It MUST NOT reveal a deleted status.
+// persistent: The repository persistently keeps track about deletions
+// with no time limit. It MUST consistently reveal the status
+// of a deleted record over time.
+// transient: The repository does not guarantee that a list of deletions is
+// maintained. It MAY reveal a deleted status for records.
+//
+// If your database keeps track of deleted records change accordingly.
+// Currently if $record['deleted'] is set to 'true', $status_deleted is set.
+// Some lines in listidentifiers.php, listrecords.php, getrecords.php
+// must be changed to fit the condition for your database.
+$identifyResponse["deletedRecord"] = 'no';
+$deletedRecord = $identifyResponse["deletedRecord"]; // a shorthand for checking the configuration of Deleted Records
+
+// MAY (only one)
+//granularity is days
+//$granularity = 'YYYY-MM-DD';
+// granularity is seconds
+$identifyResponse["granularity"] = 'YYYY-MM-DDThh:mm:ssZ';
+
+// this is appended if your granularity is seconds.
+// do not change
+if (strcmp($identifyResponse["granularity"],'YYYY-MM-DDThh:mm:ssZ')==0) {
+ $identifyResponse["earliestDatestamp"] = $identifyResponse["earliestDatestamp"].'T00:00:00Z';
+}
+
+// MUST (multiple)
+// please adjust
+$adminEmail = array('some.one@contact.com');
+
+/** Compression methods supported. Optional (multiple). Default: null.
+*
+* Currently only gzip is supported (you need output buffering turned on,
+* and php compiled with libgz).
+* The client MUST send "Accept-Encoding: gzip" to actually receive
+*/
+// $compression = array('gzip');
+$compression = null;
+
+// MUST (only one)
+// You may choose any name, but for repositories to comply with the oai
+// format it has to be unique identifiers for items records.
+// see: http://www.openarchives.org/OAI/2.0/guidelines-oai-identifier.htm
+// Basically use domainname
+// please adjust
+$repositoryIdentifier = $_SERVER['SERVER_NAME'];
+
+// For RIF-CS, especially with ANDS, each registryObject much has a group for the ownership of data.
+// For detail please see ANDS guide on its web site. Each data provider should have only one REG_OBJ_GROUP
+// for this purpose.
+define('REG_OBJ_GROUP','Something agreed on');
+
+// If Identifier needs to show NODE description. It is defined in identify.php
+// You may include details about your community and friends (other
+// data-providers).
+// Please check identify.php for other possible containers
+// in the Identify response
+$show_identifier = false;
+// MUST (only one)
+// should not be changed. Only useful when NODE description is included in the response to Identifier
+$delimiter = ':';
+
+
+/** Maximum mumber of the records to deliver
+ * (verb is ListRecords)
+ * If there are more records to deliver
+ * a ResumptionToken will be generated.
+ */
+define('MAXRECORDS',100);
+
+/** Maximum mumber of identifiers to deliver
+ * (verb is ListIdentifiers)
+ * If there are more identifiers to deliver
+ * a ResumptionToken will be generated.
+ */
+define('MAXIDS',100);
+
+/** After 24 hours resumptionTokens become invalid. Unit is second. */
+define('TOKEN_VALID',24*3600);
+$expirationdatetime = gmstrftime('%Y-%m-%dT%TZ', time()+TOKEN_VALID);
+/** Where token is saved and path is included */
+define('TOKEN_PREFIX','/tmp/ANDS_DBPD-');
+
+// 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'=>'phdthesis', 'setName'=>'PHD Thesis', 'setDescription'=>'
+ This set contains metadata describing electronic music recordings made during the 1950ies
+ ') //,
+ // array('setSpec'=>'math', 'setName'=>'Mathematics') ,
+ // array('setSpec'=>'phys', 'setName'=>'Physics')
+ */);
+
+// 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/',
+ 'myhandler'=>'record_rif.php'
+ ),*/
+ '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/',
+ 'myhandler'=>'record_dc.php',
+ '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__);}
+
+// The shorthand of xml schema namespace, no need to change this
+define('XMLSCHEMA', 'http://www.w3.org/2001/XMLSchema-instance');
+
+//
+// DATABASE SETUP
+//
+
+// change according to your local DB setup.
+$DB_HOST = DB_HOST;
+$DB_USER = DB_USERNAME;
+$DB_PASSWD = DB_PASSWORD;
+$DB_NAME = DB_NAME;
+
+// 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";
+$DSN = "mysql:host=$DB_HOST;dbname=$DB_NAME";
+// Example for Oracle
+// $DSN = "oci8://$DB_USER:$DB_PASSWD@$DB_NAME";
+
+//$DSN = "pgsql:host=$DB_HOST;port=5432;dbname=$DB_NAME;user=$DB_USER;password=$DB_PASSWD";
+
+// the charset you store your metadata in your database
+// currently only utf-8 and iso8859-1 are supported
+$charset = "iso8859-1";
+
+// 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'] = 'biblio';
+
+// 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'] = 'biblio_id';
+
+$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 = 'slims';
+
+// 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'] = 'input_date';
+
+// 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'] = 'publish_year';
+?>
diff --git a/lib/oaipmh/oaidp-util.php b/lib/oaipmh/oaidp-util.php
new file mode 100644
index 0000000..d1858b5
--- /dev/null
+++ b/lib/oaipmh/oaidp-util.php
@@ -0,0 +1,348 @@
+return parameter sets to true.
+ * \param $msg Type: string Message needs to be shown
+ * \see SHOW_QUERY_ERROR in oaidp-config.php
+ */
+function debug_message($msg) {
+ if (!SHOW_QUERY_ERROR) return;
+ echo $msg,"\n";
+}
+
+/** Check if provided correct arguments for a request.
+ *
+ * Only number of parameters is checked.
+ * metadataPrefix has to be checked before it is used.
+ * set has to be checked before it is used.
+ * resumptionToken has to be checked before it is used.
+ * from and until can easily checked here because no extra information
+ * is needed.
+ */
+function checkArgs($args, $checkList) {
+// global $errors, $TOKEN_VALID, $METADATAFORMATS;
+ global $errors, $METADATAFORMATS;
+// $verb = $args['verb'];
+ unset($args["verb"]);
+
+ debug_print_r('checkList',$checkList);
+ debug_print_r('args',$args);
+
+ // "verb" has been checked before, no further check is needed
+ if(isset($checkList['required'])) {
+ for($i = 0; $i < count($checkList["required"]); $i++) {
+ debug_message("Checking: par$i: ". $checkList['required'][$i] . " in ");
+ debug_var_dump("isset(\$args[\$checkList['required'][\$i]])",isset($args[$checkList['required'][$i]]));
+ // echo "key exists". array_key_exists($checkList["required"][$i],$args)."\n";
+ if(isset($args[$checkList['required'][$i]])==false) {
+ // echo "caught\n";
+ $errors[] = oai_error('missingArgument', $checkList["required"][$i]);
+ } else {
+ // if metadataPrefix is set, it is in required section
+ if(isset($args['metadataPrefix'])) {
+ $metadataPrefix = $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']))) {
+ $errors[] = oai_error('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix);
+ }
+ }
+ unset($args[$checkList["required"][$i]]);
+ }
+ }
+ }
+ debug_message('Before return');
+ debug_print_r('errors',$errors);
+ if (!empty($errors)) return;
+
+ // check to see if there is unwanted
+ foreach($args as $key => $val) {
+ debug_message("checkArgs: $key");
+ if(!in_array($key, $checkList["ops"])) {
+ debug_message("Wrong\n".print_r($checkList['ops'],true));
+ //$errors[] = oai_error('badArgument', $key, $val); // ignore it...
+ }
+ switch ($key) {
+ case 'from':
+ case 'until':
+ if(!checkDateFormat($val)) {
+ $errors[] = oai_error('badGranularity', $key, $val);
+ }
+ break;
+
+ case 'resumptionToken':
+ // only check for expairation
+ // if((int)$val+TOKEN_VALID < time())
+
+ // only check for value
+ if (empty($val))
+ $errors[] = oai_error('badResumptionToken');
+ break;
+ }
+ }
+}
+
+/** Validates an identifier. The pattern is: '/^[-a-z\.0-9]+$/i' which means
+ * it accepts -, letters and numbers.
+ * Used only by function oai_error code idDoesNotExist.
+ * \param $url Type: string
+ */
+function is_valid_uri($url)
+{
+ return((bool)preg_match('/^[-a-z\.0-9]+$/i', $url));
+}
+
+/** Validates attributes come with the query.
+ * It accepts letters, numbers, ':', '_', '.' and -.
+ * Here there are few more match patterns than is_valid_uri(): ':_'.
+ * \param $attrb Type: string
+ */
+ function is_valid_attrb($attrb) {
+ return preg_match("/^[_a-zA-Z0-9\-\:\.\+\>\%]+$/",$attrb);
+ }
+
+/** All datestamps used in this system are GMT even
+ * return value from database has no TZ information
+ */
+function formatDatestamp($datestamp)
+{
+ return date("Y-m-d\TH:i:s\Z",strtotime($datestamp));
+}
+
+/** The database uses datastamp without time-zone information.
+ * It needs to clean all time-zone informaion from time string and reformat it
+ */
+function checkDateFormat($date) {
+ $date = str_replace(array("T","Z")," ",$date);
+ $time_val = strtotime($date);
+ if (SHOW_QUERY_ERROR) { echo "timeval: $time_val\n"; }
+ if(!$time_val) return false;
+ if(strstr($date,":")) {
+ return date("Y-m-d H:i:s",$time_val);
+ } else {
+ return date("Y-m-d",$time_val);
+ }
+}
+
+/** Retrieve all defined 'setSpec' from configuraiton of $SETS.
+ * It is used by ANDS_TPA::create_obj_node();
+*/
+function prepare_set_names() {
+ global $SETS;
+ $n = count($SETS);
+ $a = array_fill(0,$n,'');
+ for ($i = 0; $i <$n; $i++) {
+ $a[$i] = $SETS[$i]['setSpec'];
+ }
+ return $a;
+}
+
+/** Finish a request when there is an error: send back errors. */
+function oai_exit()
+{
+// global $CONTENT_TYPE;
+ header(CONTENT_TYPE);
+ global $args,$errors,$compress;
+ $e = new ANDS_Error_XML($args,$errors);
+ if ($compress) {
+ ob_start('ob_gzhandler');
+ }
+
+ $e->display();
+
+ if ($compress) {
+ ob_end_flush();
+ }
+
+ exit();
+}
+
+// ResumToken section
+/** Generate a string based on the current Unix timestamp in microseconds for creating resumToken file name. */
+function get_token()
+{
+ list($usec, $sec) = explode(" ", microtime());
+ return ((int)($usec*1000) + (int)($sec*1000));
+}
+
+/** Create a token file.
+ * It has three parts which is separated by '#': cursor, extension of query, metadataPrefix.
+ * Called by listrecords.php.
+ */
+function createResumToken($cursor, $extquery, $metadataPrefix) {
+
+ /*
+ $token = get_token();
+ $fp = fopen (TOKEN_PREFIX.$token, 'w');
+ if($fp==false) {
+ exit("Cannot write. Writer permission needs to be changed.");
+ }
+ fputs($fp, "$cursor#");
+ fputs($fp, "$extquery#");
+ fputs($fp, "$metadataPrefix#");
+ fclose($fp);
+ return $token;
+ */
+
+ $token = $cursor . "__" . urlencode($extquery) . "__" . $metadataPrefix;
+ return $token;
+}
+
+/** Read a saved ResumToken */
+function readResumToken($resumptionToken) {
+
+ /*
+ $rtVal = false;
+ $fp = fopen($resumptionToken, 'r');
+ if ($fp!=false) {
+ $filetext = fgets($fp, 255);
+ $textparts = explode('#', $filetext);
+ fclose($fp);
+ unlink ($resumptionToken);
+ $rtVal = array((int)$textparts[0], $textparts[1], $textparts[2]);
+ }
+ return $rtVal;
+ */
+
+ $parts = explode("__", urldecode($resumptionToken));
+ return $parts;
+}
+
+// Here are a couple of queries which might need to be adjusted to
+// your needs. Normally, if you have correctly named the columns above,
+// this does not need to be done.
+
+/** this function should generate a query which will return
+ * all records
+ * the useless condition id_column = id_column is just there to ease
+ * further extensions to the query, please leave it as it is.
+ */
+function selectallQuery ($metadPrefix = "oai_dc", $id = '')
+{
+ global $SQL;
+ $query = "SELECT " . $SQL['identifier'] . "," . $SQL['datestamp'] . "," . $SQL['set'] .
+ " FROM ".$SQL['table'] . " WHERE 1 ";
+ if ($id != '') {
+ $query .= " AND ".$SQL['identifier']." ='$id'";
+ }
+ return $query;
+}
+
+/** this function will return metadataFormat of a record */
+function idFormatQuery($id)
+{
+ global $SQL;
+ return 'select '.$SQL['metadataPrefix'].' FROM '.$SQL['table']. " WHERE ".$SQL['identifier']." = '".$id."'";
+}
+
+/** this function will return identifier and datestamp for all records
+ * not very useful
+ */
+function idQuery ($metadPrefix = "rif", $id = '')
+{
+ global $SQL;
+
+ if ($SQL['set'] != '') {
+ $query = 'select '.$SQL['identifier'].','.$SQL['datestamp'].','.$SQL['set'].' FROM '.$SQL['table']. " WHERE ".$SQL['metadataPrefix']." LIKE '%$metadPrefix%'";
+ } else {
+ $query = 'select '.$SQL['identifier'].','.$SQL['datestamp'].' FROM '.$SQL['table']. " WHERE ".$SQL['metadataPrefix']." LIKE '%$metadPrefix%'";
+ }
+
+ if ($id != '') {
+ $query .= " AND ".$SQL['identifier']." = '$id'";
+ }
+
+ return $query;
+}
+
+/** filter for until, appends to the end of SQL query */
+function untilQuery($until)
+{
+ global $SQL;
+
+ return ' AND '.$SQL['datestamp']." <= '$until'";
+}
+
+/** filter for from , appends to the end of SQL query */
+function fromQuery($from)
+{
+ global $SQL;
+
+ return ' AND '.$SQL['datestamp']." >= '$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 1 " . $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/lib/oaipmh/record_dc.php b/lib/oaipmh/record_dc.php
new file mode 100644
index 0000000..496d3e5
--- /dev/null
+++ b/lib/oaipmh/record_dc.php
@@ -0,0 +1,170 @@
+create_metadata($cur_record);
+
+ $oai_node = $outputObj->addChild($metadata_node, "oai_dc:dc");
+ $oai_node->setAttribute("xmlns:oai_dc","http://www.openarchives.org/OAI/2.0/oai_dc/");
+ $oai_node->setAttribute("xmlns:dc","http://purl.org/dc/elements/1.1/");
+ $oai_node->setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
+ $oai_node->setAttribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd");
+
+ $record = get_record($identifier, $db);
+ $authors = get_authors($identifier, $db);
+ $subjects = get_subjects($identifier, $db);
+
+ $outputObj->addChild($oai_node,'dc:title', xml_safe($record['title']));
+ foreach ($authors as $author){
+ $outputObj->addChild($oai_node,'dc:creator', xml_safe($author['author_name']));
+ }
+ foreach ($subjects as $subject){
+ $outputObj->addChild($oai_node,'dc:subject', xml_safe($subject['topic']));
+ }
+ $outputObj->addChild($oai_node,'dc:publisher', xml_safe($record['publisher_name']));
+ $outputObj->addChild($oai_node,'dc:date', date_safe($record['publish_year']));
+ $outputObj->addChild($oai_node,'dc:language', $record['language_id']);
+ $outputObj->addChild($oai_node,'dc:format', $record['gmd_name']);
+ $outputObj->addChild($oai_node,'dc:identifier', SLIMS_BASE_URL.'/index.php?p=show_detail&id='. $record['biblio_id']);
+ if (!empty($record['isbn_issn'])) $outputObj->addChild($oai_node,'dc:identifier_isbn', xml_safe($record['isbn_issn']));
+ if (!empty($record['notes'])) $outputObj->addChild($oai_node,'dc:description', xml_safe($record['notes']));
+ if (!empty($record['publish_place'])) $outputObj->addChild($oai_node,'dc:location', xml_safe($record['publish_place']));
+ if (!empty($record['image'])) $outputObj->addChild($oai_node,'dc:identifier', SLIMS_BASE_URL.'/lib/phpthumb/phpThumb.php?src=../../images/docs/'. xml_safe($record['image']));
+ if (!empty($record['series_title'])) $outputObj->addChild($oai_node,'dc:series', xml_safe($record['series_title']));
+ if (!empty($record['collation'])) $outputObj->addChild($oai_node,'dc:description', xml_safe($record['collation']));
+ if (!empty($record['classification'])) $outputObj->addChild($oai_node,'dc:subject', xml_safe($record['classification']));
+
+ //print_r($record);
+ //print_r($authors);
+ //print_r($subjects);
+}
+
+function xml_safe($string){
+ return preg_replace('/[\x00-\x1f]/','',htmlspecialchars($string));
+}
+
+function date_safe($string){
+ if (preg_match("/(\d{4})/", $string, $matches)){
+ return $matches[0];
+ } else {
+ return xml_safe($string);
+ }
+}
+
+function get_record ($identifier, $db){
+ $query = 'SELECT b.*, l.language_name, p.publisher_name, pl.place_name AS \'publish_place\', gmd.gmd_name, fr.frequency FROM biblio AS b
+ LEFT JOIN mst_gmd AS gmd ON b.gmd_id=gmd.gmd_id
+ LEFT JOIN mst_language AS l ON b.language_id=l.language_id
+ LEFT JOIN mst_publisher AS p ON b.publisher_id=p.publisher_id
+ LEFT JOIN mst_place AS pl ON b.publish_place_id=pl.place_id
+ LEFT JOIN mst_frequency AS fr ON b.frequency_id=fr.frequency_id
+ WHERE biblio_id=' . $identifier;
+
+ $res = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
+ $r = $res->execute();
+ if ($r===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ print_r($db->errorInfo());
+ exit();
+ } else {
+ return array();
+ }
+ } else {
+ $record = $res->fetch(PDO::FETCH_ASSOC);
+ return $record;
+ }
+}
+
+function get_authors ($identifier, $db) {
+ $query = 'SELECT a.*,ba.level FROM mst_author AS a'
+ .' LEFT JOIN biblio_author AS ba ON a.author_id=ba.author_id WHERE ba.biblio_id='.$identifier;
+
+ $res = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
+ $r = $res->execute();
+ if ($r===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ print_r($db->errorInfo());
+ exit();
+ } else {
+ return array();
+ }
+ } else {
+ $records = array();
+ $hasNext = 1;
+ while($hasNext){
+ $record = $res->fetch(PDO::FETCH_ASSOC);
+ if ($record){
+ array_push($records, $record);
+ } else {
+ $hasNext = 0;
+ }
+ }
+
+ return $records;
+ }
+}
+
+function get_subjects($identifier, $db) {
+ $query = 'SELECT t.topic, t.topic_type, t.auth_list, bt.level FROM mst_topic AS t
+ LEFT JOIN biblio_topic AS bt ON t.topic_id=bt.topic_id WHERE bt.biblio_id='.$identifier.' ORDER BY t.auth_list';
+
+ $res = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
+ $r = $res->execute();
+ if ($r===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ print_r($db->errorInfo());
+ exit();
+ } else {
+ return array();
+ }
+ } else {
+ $records = array();
+ $hasNext = 1;
+ while($hasNext){
+ $record = $res->fetch(PDO::FETCH_ASSOC);
+ if ($record){
+ array_push($records, $record);
+ } else {
+ $hasNext = 0;
+ }
+ }
+
+ return $records;
+ }
+}
+
+function get_digital_files($identifier, $db) {
+
+ // digital files
+ $attachment_q = $this->obj_db->query('SELECT att.*, f.* FROM biblio_attachment AS att
+ LEFT JOIN files AS f ON att.file_id=f.file_id WHERE att.biblio_id='.$this->detail_id.' AND att.access_type=\'public\' LIMIT 20');
+ if ($attachment_q->num_rows > 0) {
+ while ($attachment_d = $attachment_q->fetch_assoc()) {
+ $_xml_output .= ''."\n";
+ }
+ }
+}
diff --git a/lib/oaipmh/record_dc.php~ b/lib/oaipmh/record_dc.php~
new file mode 100644
index 0000000..496d3e5
--- /dev/null
+++ b/lib/oaipmh/record_dc.php~
@@ -0,0 +1,170 @@
+create_metadata($cur_record);
+
+ $oai_node = $outputObj->addChild($metadata_node, "oai_dc:dc");
+ $oai_node->setAttribute("xmlns:oai_dc","http://www.openarchives.org/OAI/2.0/oai_dc/");
+ $oai_node->setAttribute("xmlns:dc","http://purl.org/dc/elements/1.1/");
+ $oai_node->setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
+ $oai_node->setAttribute("xsi:schemaLocation", "http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd");
+
+ $record = get_record($identifier, $db);
+ $authors = get_authors($identifier, $db);
+ $subjects = get_subjects($identifier, $db);
+
+ $outputObj->addChild($oai_node,'dc:title', xml_safe($record['title']));
+ foreach ($authors as $author){
+ $outputObj->addChild($oai_node,'dc:creator', xml_safe($author['author_name']));
+ }
+ foreach ($subjects as $subject){
+ $outputObj->addChild($oai_node,'dc:subject', xml_safe($subject['topic']));
+ }
+ $outputObj->addChild($oai_node,'dc:publisher', xml_safe($record['publisher_name']));
+ $outputObj->addChild($oai_node,'dc:date', date_safe($record['publish_year']));
+ $outputObj->addChild($oai_node,'dc:language', $record['language_id']);
+ $outputObj->addChild($oai_node,'dc:format', $record['gmd_name']);
+ $outputObj->addChild($oai_node,'dc:identifier', SLIMS_BASE_URL.'/index.php?p=show_detail&id='. $record['biblio_id']);
+ if (!empty($record['isbn_issn'])) $outputObj->addChild($oai_node,'dc:identifier_isbn', xml_safe($record['isbn_issn']));
+ if (!empty($record['notes'])) $outputObj->addChild($oai_node,'dc:description', xml_safe($record['notes']));
+ if (!empty($record['publish_place'])) $outputObj->addChild($oai_node,'dc:location', xml_safe($record['publish_place']));
+ if (!empty($record['image'])) $outputObj->addChild($oai_node,'dc:identifier', SLIMS_BASE_URL.'/lib/phpthumb/phpThumb.php?src=../../images/docs/'. xml_safe($record['image']));
+ if (!empty($record['series_title'])) $outputObj->addChild($oai_node,'dc:series', xml_safe($record['series_title']));
+ if (!empty($record['collation'])) $outputObj->addChild($oai_node,'dc:description', xml_safe($record['collation']));
+ if (!empty($record['classification'])) $outputObj->addChild($oai_node,'dc:subject', xml_safe($record['classification']));
+
+ //print_r($record);
+ //print_r($authors);
+ //print_r($subjects);
+}
+
+function xml_safe($string){
+ return preg_replace('/[\x00-\x1f]/','',htmlspecialchars($string));
+}
+
+function date_safe($string){
+ if (preg_match("/(\d{4})/", $string, $matches)){
+ return $matches[0];
+ } else {
+ return xml_safe($string);
+ }
+}
+
+function get_record ($identifier, $db){
+ $query = 'SELECT b.*, l.language_name, p.publisher_name, pl.place_name AS \'publish_place\', gmd.gmd_name, fr.frequency FROM biblio AS b
+ LEFT JOIN mst_gmd AS gmd ON b.gmd_id=gmd.gmd_id
+ LEFT JOIN mst_language AS l ON b.language_id=l.language_id
+ LEFT JOIN mst_publisher AS p ON b.publisher_id=p.publisher_id
+ LEFT JOIN mst_place AS pl ON b.publish_place_id=pl.place_id
+ LEFT JOIN mst_frequency AS fr ON b.frequency_id=fr.frequency_id
+ WHERE biblio_id=' . $identifier;
+
+ $res = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
+ $r = $res->execute();
+ if ($r===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ print_r($db->errorInfo());
+ exit();
+ } else {
+ return array();
+ }
+ } else {
+ $record = $res->fetch(PDO::FETCH_ASSOC);
+ return $record;
+ }
+}
+
+function get_authors ($identifier, $db) {
+ $query = 'SELECT a.*,ba.level FROM mst_author AS a'
+ .' LEFT JOIN biblio_author AS ba ON a.author_id=ba.author_id WHERE ba.biblio_id='.$identifier;
+
+ $res = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
+ $r = $res->execute();
+ if ($r===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ print_r($db->errorInfo());
+ exit();
+ } else {
+ return array();
+ }
+ } else {
+ $records = array();
+ $hasNext = 1;
+ while($hasNext){
+ $record = $res->fetch(PDO::FETCH_ASSOC);
+ if ($record){
+ array_push($records, $record);
+ } else {
+ $hasNext = 0;
+ }
+ }
+
+ return $records;
+ }
+}
+
+function get_subjects($identifier, $db) {
+ $query = 'SELECT t.topic, t.topic_type, t.auth_list, bt.level FROM mst_topic AS t
+ LEFT JOIN biblio_topic AS bt ON t.topic_id=bt.topic_id WHERE bt.biblio_id='.$identifier.' ORDER BY t.auth_list';
+
+ $res = $db->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
+ $r = $res->execute();
+ if ($r===false) {
+ if (SHOW_QUERY_ERROR) {
+ echo __FILE__.','.__LINE__." ";
+ echo "Query: $query \n";
+ print_r($db->errorInfo());
+ exit();
+ } else {
+ return array();
+ }
+ } else {
+ $records = array();
+ $hasNext = 1;
+ while($hasNext){
+ $record = $res->fetch(PDO::FETCH_ASSOC);
+ if ($record){
+ array_push($records, $record);
+ } else {
+ $hasNext = 0;
+ }
+ }
+
+ return $records;
+ }
+}
+
+function get_digital_files($identifier, $db) {
+
+ // digital files
+ $attachment_q = $this->obj_db->query('SELECT att.*, f.* FROM biblio_attachment AS att
+ LEFT JOIN files AS f ON att.file_id=f.file_id WHERE att.biblio_id='.$this->detail_id.' AND att.access_type=\'public\' LIMIT 20');
+ if ($attachment_q->num_rows > 0) {
+ while ($attachment_d = $attachment_q->fetch_assoc()) {
+ $_xml_output .= ''."\n";
+ }
+ }
+}
diff --git a/lib/oaipmh/record_rif.php b/lib/oaipmh/record_rif.php
new file mode 100644
index 0000000..c7be32e
--- /dev/null
+++ b/lib/oaipmh/record_rif.php
@@ -0,0 +1,34 @@
+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";
+ }
+}
+
diff --git a/lib/oaipmh/xml_creater.php b/lib/oaipmh/xml_creater.php
new file mode 100644
index 0000000..a1380af
--- /dev/null
+++ b/lib/oaipmh/xml_creater.php
@@ -0,0 +1,327 @@
+"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
+ * $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 = "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 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
+ */
+class ANDS_XML {
+
+ public $doc; /**< Type: DOMDocument. Handle of current XML Document object */
+
+ /**
+ * Constructs an ANDS_XML object.
+ *
+ * @param $par_array Type: array.
+ * Array of request parameters for creating an ANDS_XML object.
+ * \see create_request.
+ */
+ function __construct($par_array) {
+ $this->doc = new DOMDocument("1.0","UTF-8");
+ // oai_node equals to $this->doc->documentElement;
+ $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);
+ $this->create_request($par_array);
+ }
+
+ /**
+ * 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;
+ }
+
+
+ /**
+ * Create an OAI request node.
+ *
+ * @param $par_array Type: array
+ * The attributes of a request node. They describe the verb of the request and other associated parameters used in the request.
+ * Keys of the array define attributes, and values are their content.
+ */
+
+ function create_request($par_array) {
+ $request = $this->addChild($this->doc->documentElement,"request",MY_URI);
+ foreach($par_array as $key => $value) {
+ $request->setAttribute($key,$value);
+ }
+ }
+
+ /**
+ * Display a doc in a readable, well-formatted way for display or saving
+ */
+ function display() {
+ $pr = new DOMDocument();
+ $pr->preserveWhiteSpace = false;
+ $pr->formatOutput = true;
+ $pr->loadXML($this->doc->saveXML());
+ echo $pr->saveXML();
+ }
+}
+
+/**
+ * Generate an XML response when a request cannot be finished
+ *
+ * It has only one derived member function
+ */
+class ANDS_Error_XML extends ANDS_XML {
+ function __construct($par_array, $error_array) {
+ parent::__construct($par_array);
+
+ $oai_node = $this->doc->documentElement;
+ foreach($error_array as $e) {
+ list($code, $value) = explode("|", $e);
+ $node = $this->addChild($oai_node,"error",$value);
+ $node->setAttribute("code",$code);
+ }
+ }
+}
+
+/**
+ * Generate an XML response to a request if no error has occured
+ *
+ * This is the class to further develop to suits a publication need
+ */
+class ANDS_Response_XML extends ANDS_XML {
+ public $verbNode; /**< Type: DOMElement. Verb node itself. */
+ protected $verb; /**< Type: string. The verb in the request */
+
+ function __construct($par_array) {
+ parent::__construct($par_array);
+ $this->verb = $par_array["verb"];
+ $this->verbNode = $this->addChild($this->doc->documentElement,$this->verb);
+ }
+
+/** Add direct child nodes to verb node (OAI-PMH), e.g. response to ListMetadataFormats.
+ * Different verbs can have different required child nodes.
+ * \see create_record, create_header
+ * \see http://www.openarchives.org/OAI/2.0/openarchivesprotocol.htm.
+ *
+ * \param $nodeName Type: string. The name of appending node.
+ * \param $value Type: string. The content of appending node.
+ */
+ function add2_verbNode($nodeName, $value=null) {
+ return $this->addChild($this->verbNode,$nodeName,$value);
+ }
+
+ /**
+ * Create an empty \ node. Other nodes will be appended to it later.
+ */
+ function create_record() {
+ return $this->add2_verbNode("record");
+ }
+
+ /** Headers are enclosed inside of \ to the query of ListRecords, ListIdentifiers and etc.
+ *
+ * \param $identifier Type: string. The identifier string for node \.
+ * \param $timestamp Type: timestamp. Timestapme in UTC format for node \.
+ * \param $ands_class Type: mix. Can be an array or just a string. Content of \.
+ * \param $add_to_node Type: DOMElement. Default value is null.
+ * In normal cases, $add_to_node is the \ node created previously. When it is null, the newly created header node is attatched to $this->verbNode.
+ * Otherwise it will be attatched to the desired node defined in $add_to_node.
+ */
+ function create_header($identifier,$timestamp,$ands_class, $add_to_node=null) {
+ if(is_null($add_to_node)) {
+ $header_node = $this->add2_verbNode("header");
+ } else {
+ $header_node = $this->addChild($add_to_node,"header");
+ }
+ $this->addChild($header_node,"identifier",$identifier);
+ $this->addChild($header_node,"datestamp",$timestamp);
+ if (is_array($ands_class)) {
+ foreach ($ands_class as $setspec) {
+ $this->addChild($header_node,"setSpec",$setspec);
+ }
+ } else { $this->addChild($header_node,"setSpec",$ands_class); }
+ return $header_node;
+ }
+
+ /** Create metadata node for holding metadata. This is always added to \ node.
+ *
+ * \param $mom_record_node DOMElement. A node acts as the parent node.
+ *
+ * @return $meta_node Type: DOMElement.
+ * The newly created registryObject node which will be used for further expansion.
+ * metadata node itself is maintained by internally by the Class.
+ */
+ function create_metadata($mom_record_node) {
+ $meta_node = $this->addChild($mom_record_node,"metadata");
+ return $meta_node;
+ }
+
+ /** If there are too many records request could not finished a resumpToken is generated to let harvester know
+ *
+ * \param $token Type: string. A random number created somewhere?
+ * \param $expirationdatetime Type: string. A string representing time.
+ * \param $num_rows Type: integer. Number of records retrieved.
+ * \param $cursor Type: string. Cursor can be used for database to retrieve next time.
+ */
+ function create_resumpToken($token, $expirationdatetime, $num_rows, $cursor=null) {
+ $resump_node = $this->addChild($this->verbNode,"resumptionToken",$token);
+ if(isset($expirationdatetime)) {
+ $resump_node->setAttribute("expirationDate",$expirationdatetime);
+ }
+ $resump_node->setAttribute("completeListSize",$num_rows);
+ $resump_node->setAttribute("cursor",$cursor);
+ }
+}
+
diff --git a/oai2.php b/oai2.php
new file mode 100644
index 0000000..7d8b7fd
--- /dev/null
+++ b/oai2.php
@@ -0,0 +1,190 @@
+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.
+ */
+
+// Report all errors except E_NOTICE
+// This is the default value set in php.ini
+// If anything else, try them.
+// error_reporting (E_ALL ^ E_NOTICE);
+
+/**
+ * An array for collecting erros which can be reported later. It will be checked before a new action is taken.
+ */
+$errors = array();
+
+ini_set('session.use_cookies', '0');
+
+// key to authenticate
+define('INDEX_AUTH', '1');
+
+// required file
+require 'sysconfig.inc.php';
+define('OAI_LIB', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR.
+ 'lib'.DIRECTORY_SEPARATOR.
+ 'oaipmh'.DIRECTORY_SEPARATOR);
+
+require_once(OAI_LIB.'oaidp-config.php');
+require_once(OAI_LIB.'oaidp-util.php');
+require_once(OAI_LIB.'ands_tpa.php');
+
+
+/**
+ * Supported attributes associate to verbs.
+ */
+$attribs = array ('from', 'identifier', 'metadataPrefix', 'set', 'resumptionToken', 'until');
+
+if (in_array($_SERVER['REQUEST_METHOD'],array('GET','POST'))) {
+ $args = $_REQUEST;
+} else {
+ $errors[] = oai_error('badRequestMethod', $_SERVER['REQUEST_METHOD']);
+}
+
+
+// Always using htmlentities() function to encodes the HTML entities submitted by others.
+// No one can be trusted.
+foreach ($args as $key => $val) {
+ $checking = urlencode(stripslashes($val));
+ if (!is_valid_attrb($checking)) {
+ $errors[] = oai_error('badArgument', $checking);
+ } else {$args[$key] = $checking; }
+}
+if (!empty($errors)) { oai_exit(); }
+
+foreach($attribs as $val) {
+ unset($$val);
+}
+
+
+
+// Create a PDO object
+try {
+ //$db = new PDO($DSN);
+ $db = new PDO($DSN, $DB_USER, $DB_PASSWD);
+} catch (PDOException $e) {
+ exit('Connection failed: ' . $e->getMessage());
+}
+
+// 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.
+
+
+// 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;
+ }
+}
+
+if (SHOW_QUERY_ERROR) {
+ echo "Args:\n"; print_r($args);
+}
+
+if (isset($args['verb'])) {
+ switch ($args['verb']) {
+
+ case 'Identify':
+ // we never use compression in Identify
+ $compress = FALSE;
+ if(count($args)>1) {
+ foreach($args as $key => $val) {
+ if(strcmp($key,"verb")!=0) {
+ $errors[] = oai_error('badArgument', $key, $val);
+ }
+ }
+ }
+ if (empty($errors)) include OAI_LIB.'identify.php';
+ break;
+
+ case 'ListMetadataFormats':
+ $checkList = array("ops"=>array("identifier"));
+ checkArgs($args, $checkList);
+ if (empty($errors)) include OAI_LIB.'listmetadataformats.php';
+ break;
+
+ case 'ListSets':
+ if(isset($args['resumptionToken']) && count($args) > 2) {
+ $errors[] = oai_error('exclusiveArgument');
+ }
+ $checkList = array("ops"=>array("resumptionToken"));
+ checkArgs($args, $checkList);
+ if (empty($errors)) include OAI_LIB.'listsets.php';
+ break;
+
+ case 'GetRecord':
+ $checkList = array("required"=>array("metadataPrefix","identifier"));
+ checkArgs($args, $checkList);
+ if (empty($errors)) include OAI_LIB.'getrecord.php';
+ break;
+
+ case 'ListIdentifiers':
+ case 'ListRecords':
+ if(isset($args['resumptionToken'])) {
+ if (count($args) > 2) {
+ $errors[] = oai_error('exclusiveArgument');
+ }
+ $checkList = array("ops"=>array("resumptionToken"));
+ } else {
+ $checkList = array("required"=>array("metadataPrefix"),"ops"=>array("from","until","set"));
+ }
+ checkArgs($args, $checkList);
+ if (empty($errors)) include OAI_LIB.'listrecords.php';
+ break;
+
+ default:
+ // we never use compression with errors
+ $compress = FALSE;
+ $errors[] = oai_error('badVerb', $args['verb']);
+ } /*switch */
+} else {
+ $errors[] = oai_error('noVerb');
+}
+
+if (!empty($errors)) { oai_exit(); }
+
+if ($compress) {
+ ob_start('ob_gzhandler');
+}
+
+header(CONTENT_TYPE);
+
+if(isset($outputObj)) {
+ $outputObj->display();
+} else {
+ exit("There is a bug in codes");
+}
+
+ if ($compress) {
+ ob_end_flush();
+ }
+
+?>