Search:

CWIS Developers Documentation

  • Main Page
  • Classes
  • Files
  • File List
  • File Members

OAIServer.php

Go to the documentation of this file.
00001 <?PHP
00002 
00003 #
00004 #   FILE:  Scout--OAIServer.php
00005 #
00006 #   METHODS PROVIDED:
00007 #       OAIServer()
00008 #           - constructor
00009 #
00010 #   AUTHOR:  Edward Almasy
00011 #
00012 #   Copyright 2002-2004 Internet Scout Project
00013 #   http://scout.wisc.edu
00014 #
00015 
00016 class OAIServer {
00017 
00018     # ---- PUBLIC INTERFACE --------------------------------------------------
00019 
00020     # object constructor
00021     function OAIServer(&$DB, $RepDescr, &$ItemFactory, $SetsSupported = FALSE, $OaisqSupported = FALSE)
00022     {
00023         # save DB handle for our use
00024         $this->DB =& $DB;
00025 
00026         # save repository description
00027         $this->RepDescr = $RepDescr;
00028 
00029         # save supported option settings
00030         $this->SetsSupported = $SetsSupported;
00031         $this->OaisqSupported = $OaisqSupported;
00032 
00033         # normalize repository description values
00034         $this->RepDescr["IDPrefix"] = 
00035                     preg_replace("/[^0-9a-z]/i", "", $this->RepDescr["IDPrefix"]);
00036 
00037         # save item factory
00038         $this->ItemFactory =& $ItemFactory;
00039 
00040         # load OAI request type and arguments
00041         $this->LoadArguments();
00042 
00043         # set default indent size
00044         $this->IndentSize = 4;
00045 
00046         # start with empty list of formats
00047         $this->FormatDescrs = array();
00048 
00049         # initialize description of mandatory format
00050         $OaidcNamespaceList = array(
00051             "oai_dc" => "http://www.openarchives.org/OAI/2.0/oai_dc/",
00052             "dc" => "http://purl.org/dc/elements/1.1/",
00053             );
00054         $OaidcElements = array(
00055             "dc:title",
00056             "dc:creator",
00057             "dc:subject",
00058             "dc:description",
00059             "dc:publisher",
00060             "dc:contributor",
00061             "dc:date",
00062             "dc:type",
00063             "dc:format",
00064             "dc:identifier",
00065             "dc:source",
00066             "dc:language",
00067             "dc:relation",
00068             "dc:coverage",
00069             "dc:rights",
00070             );
00071         $OaidcQualifiers = array();
00072         $this->AddFormat("oai_dc", "oai_dc:dc", 
00073                          "http://www.openarchives.org/OAI/2.0/oai_dc/"
00074                          ." http://www.openarchives.org/OAI/2.0/oai_dc.xsd",
00075                          NULL,
00076                          $OaidcNamespaceList, $OaidcElements, $OaidcQualifiers);
00077     }
00078 
00079     # add metadata format to export
00080     function AddFormat($Name, $TagName, $SchemaLocation, $SchemaVersion, $NamespaceList, $ElementList, $QualifierList)
00081     {
00082         # find highest current format ID
00083         $HighestFormatId = 0;
00084         foreach ($this->FormatDescrs as $FormatName => $FormatDescr)
00085         {
00086             if ($FormatDescr["FormatId"] > $HighestFormatId)
00087             {
00088                 $HighestFormatId = $FormatDescr["FormatId"];
00089             }
00090         }
00091 
00092         # set new format ID to next value
00093         $this->FormatDescrs[$Name]["FormatId"] = $HighestFormatId + 1;
00094         
00095         # store values
00096         $this->FormatDescrs[$Name]["TagName"] = $TagName;
00097         $this->FormatDescrs[$Name]["SchemaLocation"] = $SchemaLocation;
00098         $this->FormatDescrs[$Name]["SchemaVersion"] = $SchemaVersion;
00099         $this->FormatDescrs[$Name]["ElementList"] = $ElementList;
00100         $this->FormatDescrs[$Name]["QualifierList"] = $QualifierList;
00101         $this->FormatDescrs[$Name]["NamespaceList"] = $NamespaceList;
00102         
00103         # start out with empty mappings list
00104         if (!isset($this->FieldMappings[$Name]))
00105         {
00106             $this->FieldMappings[$Name] = array();
00107         }
00108     }
00109 
00110     # return list of formats
00111     function FormatList()
00112     {
00113         $FList = array();
00114         foreach ($this->FormatDescrs as $FormatName => $FormatDescr)
00115         {
00116             $FList[$FormatDescr["FormatId"]] = $FormatName;
00117         }
00118         return $FList;
00119     }
00120 
00121     # return list of elements for a given format
00122     function FormatElementList($FormatName)
00123     {
00124         return $this->FormatDescrs[$FormatName]["ElementList"];
00125     }
00126     
00127     # return list of qualifiers for a given format
00128     function FormatQualifierList($FormatName)
00129     {
00130         return $this->FormatDescrs[$FormatName]["QualifierList"];
00131     }
00132     
00133     # get/set mapping of local field to OAI field
00134     function GetFieldMapping($FormatName, $LocalFieldName)
00135     {
00136         # return stored value
00137         if (isset($this->FieldMappings[$FormatName][$LocalFieldName]))
00138         {
00139             return $this->FieldMappings[$FormatName][$LocalFieldName];
00140         }
00141         else
00142         {
00143             return NULL;
00144         }
00145     }
00146     function SetFieldMapping($FormatName, $LocalFieldName, $OAIFieldName)
00147     {
00148         $this->FieldMappings[$FormatName][$LocalFieldName] = $OAIFieldName;
00149     }
00150 
00151     # get/set mapping of local qualifier to OAI qualifier
00152     function GetQualifierMapping($FormatName, $LocalQualifierName)
00153     {
00154         # return stored value
00155         if (isset($this->QualifierMappings[$FormatName][$LocalQualifierName]))
00156         {
00157             return $this->QualifierMappings[$FormatName][$LocalQualifierName];
00158         }
00159         else
00160         {
00161             return NULL;
00162         }
00163     }
00164     function SetQualifierMapping($FormatName, $LocalQualifierName, $OAIQualifierName)
00165     {
00166         $this->QualifierMappings[$FormatName][$LocalQualifierName] = $OAIQualifierName;
00167     }
00168 
00169     function GetResponse()
00170     {
00171         # call appropriate method based on request type
00172         switch (strtoupper($this->Args["verb"]))
00173         {
00174             case "IDENTIFY":
00175                 $Response = $this->ProcessIdentify();
00176                 break;
00177 
00178             case "GETRECORD":
00179                 $Response = $this->ProcessGetRecord();
00180                 break;
00181 
00182             case "LISTIDENTIFIERS":
00183                 $Response = $this->ProcessListRecords(FALSE);
00184                 break;
00185 
00186             case "LISTRECORDS":
00187                 $Response = $this->ProcessListRecords(TRUE);
00188                 break;
00189 
00190             case "LISTMETADATAFORMATS":
00191                 $Response = $this->ProcessListMetadataFormats();
00192                 break;
00193 
00194             case "LISTSETS":
00195                 $Response = $this->ProcessListSets();
00196                 break;
00197 
00198             default:
00199                 # return "bad argument" response
00200                 $Response = $this->GetResponseBeginTags();
00201                 $Response .= $this->GetRequestTag();
00202                 $Response .= $this->GetErrorTag("badVerb", "Bad or unknown request type.");
00203                 $Response .= $this->GetResponseEndTags();
00204                 break;
00205         }
00206 
00207         # return generated response to caller
00208         return $Response;
00209     }
00210 
00211 
00212     # ---- PRIVATE INTERFACE -------------------------------------------------
00213     
00214     var $DB;
00215     var $Args;
00216     var $RepDescr;
00217     var $ItemFactory;
00218     var $FormatDescrs;
00219     var $FormatFields;
00220     var $FieldMappings;
00221     var $QualifierMappings;
00222     var $IndentSize;
00223     var $SetsSupported;
00224     var $OaisqSupported;
00225 
00226     
00227     # ---- response generation methods
00228 
00229     function ProcessIdentify()
00230     {
00231         # initialize response
00232         $Response = $this->GetResponseBeginTags();
00233 
00234         # add request info tag
00235         $Response .= $this->GetRequestTag("Identify");
00236 
00237         # open response type tag
00238         $Response .= $this->FormatTag("Identify");
00239 
00240         # add repository info tags
00241         $Response .= $this->FormatTag("repositoryName", $this->RepDescr["Name"]);
00242         $Response .= $this->FormatTag("baseURL", $this->RepDescr["BaseURL"]);
00243         $Response .= $this->FormatTag("protocolVersion", "2.0");
00244         foreach ($this->RepDescr["AdminEmail"] as $AdminEmail)
00245         {
00246             $Response .= $this->FormatTag("adminEmail", $AdminEmail);
00247         }
00248         $Response .= $this->FormatTag("earliestDatestamp", $this->RepDescr["EarliestDate"]);
00249         $Response .= $this->FormatTag("deletedRecord", "no");
00250         $Response .= $this->FormatTag("granularity", 
00251                                       (strtoupper($this->RepDescr["DateGranularity"]) == "DATETIME")
00252                                           ? "YYYY-MM-DDThh:mm:ssZ" : "YYYY-MM-DD");
00253 
00254         # add repository description section
00255         $Response .= $this->FormatTag("description");
00256         $Attribs = array(
00257                 "xmlns" => "http://www.openarchives.org/OAI/2.0/oai-identifier",
00258                 "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
00259                 "xsi:schemaLocation" => "http://www.openarchives.org/OAI/2.0/oai-identifier http://www.openarchives.org/OAI/2.0/oai-identifier.xsd",
00260                 );
00261         $Response .= $this->FormatTag("oai-identifier", NULL, $Attribs);
00262         $Response .= $this->FormatTag("scheme", "oai");
00263         $Response .= $this->FormatTag("repositoryIdentifier", $this->RepDescr["IDDomain"]);
00264         $Response .= $this->FormatTag("delimiter", ":");
00265         $Response .= $this->FormatTag("sampleIdentifier", $this->EncodeIdentifier("12345"));
00266         $Response .= $this->FormatTag();
00267         $Response .= $this->FormatTag();
00268 
00269         # close response type tag
00270         $Response .= $this->FormatTag();
00271 
00272         # close out response
00273         $Response .= $this->GetResponseEndTags();
00274 
00275         # return response to caller
00276         return $Response;
00277     }
00278 
00279     function ProcessGetRecord()
00280     {
00281         # initialize response
00282         $Response = $this->GetResponseBeginTags();
00283         
00284         # if arguments were bad
00285         if (isset($this->Args["identifier"]))
00286         {
00287             $ItemId = $this->DecodeIdentifier($this->Args["identifier"]);
00288         }
00289         else
00290         {
00291             $ItemId = NULL;
00292         }
00293         if (isset($this->Args["metadataPrefix"]))
00294         {
00295             $MetadataFormat = $this->Args["metadataPrefix"];
00296         }
00297         else
00298         {
00299             $MetadataFormat = NULL;
00300         }
00301         if (($ItemId == NULL) || ($MetadataFormat == NULL) || !is_array($this->FieldMappings[$MetadataFormat]))
00302         {
00303             # add request info tag with no attributes
00304             $Response .= $this->GetRequestTag("GetRecord");
00305             
00306             # add error tag
00307             $Response .= $this->GetErrorTag("badArgument", "Bad argument found.");
00308         }
00309         else
00310         {
00311             # add request info tag
00312             $ReqArgList = array("identifier", "metadataPrefix");
00313             $Response .= $this->GetRequestTag("GetRecord", $ReqArgList);
00314 
00315             # attempt to load item corresponding to record
00316             $Item = $this->ItemFactory->GetItem($ItemId);
00317 
00318             # if no item found
00319             if ($Item == NULL)
00320             {
00321                 # add error tag
00322                 $Response .= $this->GetErrorTag("idDoesNotExist", "No item found for specified ID.");
00323             }
00324             else
00325             {
00326                 # open response type tag
00327                 $Response .= $this->FormatTag("GetRecord");
00328 
00329                 # add tags for record
00330                 $Response .= $this->GetRecordTags($Item, $MetadataFormat);
00331 
00332                 # close response type tag
00333                 $Response .= $this->FormatTag();
00334             }
00335         }
00336 
00337         # close out response
00338         $Response .= $this->GetResponseEndTags();
00339 
00340         # return response to caller
00341         return $Response;
00342     }
00343 
00344     function ProcessListRecords($IncludeMetadata)
00345     {
00346         # set request type
00347         if ($IncludeMetadata)
00348         {
00349             $Request = "ListRecords";
00350         }
00351         else
00352         {
00353             $Request = "ListIdentifiers";
00354         }
00355         
00356         # initialize response
00357         $Response = $this->GetResponseBeginTags();
00358         
00359         # if resumption token supplied
00360         if (isset($this->Args["resumptionToken"]))
00361         {
00362             # set expected argument lists
00363             $ReqArgList = array("resumptionToken");
00364             $OptArgList = NULL;
00365             
00366             # parse into list parameters
00367             $Args = $this->DecodeResumptionToken($this->Args["resumptionToken"]);
00368         }
00369         else
00370         {
00371             # set expected argument lists
00372             $ReqArgList = array("metadataPrefix");
00373             $OptArgList = array("from", "until", "set");
00374             
00375             # get list parameters from incoming arguments
00376             $Args = $this->Args;
00377             
00378             # set list starting point to beginning
00379             $Args["ListStartPoint"] = 0;
00380         }
00381 
00382         # if resumption token was supplied and was bad
00383         if ($Args == NULL)
00384         {
00385             # add request info tag
00386             $Response .= $this->GetRequestTag($Request, $ReqArgList, $OptArgList);
00387 
00388             # add error tag indicating bad resumption token
00389             $Response .= $this->GetErrorTag("badResumptionToken", "Bad resumption token.");
00390             
00391             # if other parameter also supplied
00392             if (count($this->Args) > 2)
00393             {
00394                 # add error tag indicating exclusive argument error
00395                 $Response .= $this->GetErrorTag("badArgument", "Resumption token is exclusive argument.");
00396             }
00397         }
00398         # else if resumption token supplied and other arguments also supplied
00399         elseif (isset($this->Args["resumptionToken"]) && (count($this->Args) > 2))
00400         {
00401             # add error tag indicating exclusive argument error
00402             $Response .= $this->GetRequestTag();
00403             $Response .= $this->GetErrorTag("badArgument", "Resumption token is exclusive argument.");
00404         }
00405         # else if metadata format was not specified
00406         elseif (empty($Args["metadataPrefix"]))
00407         {
00408             # add request info tag with no attributes
00409             $Response .= $this->GetRequestTag($Request);
00410             
00411             # add error tag indicating bad argument
00412             $Response .= $this->GetErrorTag("badArgument", "No metadata format specified.");
00413         }
00414         # else if from or until date is specified but bad
00415         elseif ((isset($Args["from"]) && $this->DateIsInvalid($Args["from"]))
00416                 || (isset($Args["until"]) && $this->DateIsInvalid($Args["until"])))
00417         {
00418             # add request info tag with no attributes
00419             $Response .= $this->GetRequestTag($Request);
00420             
00421             # add error tag indicating bad argument
00422             $Response .= $this->GetErrorTag("badArgument", "Bad date format.");
00423         }
00424         else
00425         {
00426             # add request info tag
00427             $Response .= $this->GetRequestTag($Request, $ReqArgList, $OptArgList);
00428 
00429             # if set requested and we do not support sets
00430             if (isset($Args["set"]) && ($this->SetsSupported != TRUE))
00431             {
00432                 # add error tag indicating that we don't support sets
00433                 $Response .= $this->GetErrorTag("noSetHierarchy", "This repository does not support sets.");
00434             }
00435             # else if requested metadata format is not supported
00436             elseif (empty($this->FormatDescrs[$Args["metadataPrefix"]]))
00437             {
00438                 # add error tag indicating that format is not supported
00439                 $Response .= $this->GetErrorTag("cannotDisseminateFormat", "Metadata format \"".$Args["metadataPrefix"]."\" not supported by this repository.");
00440             }
00441             else
00442             {
00443                 # if set requested
00444                 if (isset($Args["set"]))
00445                 {
00446                     # if OAI-SQ supported and set represents OAI-SQ query
00447                     if ($this->OaisqSupported && $this->IsOaisqQuery($Args["set"]))
00448                     {
00449                         # parse OAI-SQ search parameters out of set name
00450                         $SearchParams = $this->ParseOaisqQuery($Args["set"], $Args["metadataPrefix"]);
00451                         
00452                         # if search parameters found
00453                         if (count($SearchParams))
00454                         {
00455                             # perform search for items that match OAI-SQ request
00456                             $ItemIds = $this->ItemFactory->SearchForItems(
00457                                 $SearchParams,
00458                                 (isset($Args["from"]) ? $Args["from"] : NULL),
00459                                 (isset($Args["until"]) ? $Args["until"] : NULL));
00460                         }
00461                         else
00462                         {
00463                             # no items match
00464                             $ItemIds = array();
00465                         }
00466                     }
00467                     else
00468                     {
00469                         # get list of items in set that matches incoming criteria
00470                         $ItemIds = $this->ItemFactory->GetItemsInSet(
00471                             $Args["set"],
00472                             (isset($Args["from"]) ? $Args["from"] : NULL),
00473                             (isset($Args["until"]) ? $Args["until"] : NULL));
00474                     }
00475                 }
00476                 else
00477                 {
00478                     # get list of items that matches incoming criteria
00479                     $ItemIds = $this->ItemFactory->GetItems(
00480                         (isset($Args["from"]) ? $Args["from"] : NULL),
00481                         (isset($Args["until"]) ? $Args["until"] : NULL));
00482                 }
00483 
00484                 # if no items found
00485                 if (count($ItemIds) == 0)
00486                 {
00487                     # add error tag indicating that no records found that match spec
00488                     $Response .= $this->GetErrorTag("noRecordsMatch", "No records were found that match the specified parameters.");
00489                 }
00490                 else
00491                 {
00492                     # open response type tag
00493                     $Response .= $this->FormatTag($Request);
00494                     
00495                     # initialize count of processed items
00496                     $ListIndex = 0;
00497                     
00498                     # for each item
00499                     foreach ($ItemIds as $ItemId)
00500                     {
00501                         # if item is within range
00502                         if ($ListIndex >= $Args["ListStartPoint"])
00503                         {
00504                             # retrieve item
00505                             $Item = $this->ItemFactory->GetItem($ItemId);
00506 
00507                             # add record for item
00508                             $Response .= $this->GetRecordTags($Item, $Args["metadataPrefix"], $IncludeMetadata);
00509                         }
00510                         
00511                         # increment count of processed items
00512                         $ListIndex++;
00513                         
00514                         # stop processing if we have processed max number of items in a pass
00515                         $MaxItemsPerPass = 20;
00516                         if (($ListIndex - $Args["ListStartPoint"]) >= $MaxItemsPerPass) {  break;  }
00517                     }
00518                     
00519                     # if items left unprocessed
00520                     if ($ListIndex < count($ItemIds))
00521                     {
00522                         # add resumption token tag
00523                         $Token = $this->EncodeResumptionToken((isset($Args["from"]) ? $Args["from"] : NULL), 
00524                                                               (isset($Args["until"]) ? $Args["until"] : NULL), 
00525                                                               (isset($Args["metadataPrefix"]) ? $Args["metadataPrefix"] : NULL), 
00526                                                               (isset($Args["set"]) ? $Args["set"] : NULL), 
00527                                                               $ListIndex);
00528                         $Response .= $this->FormatTag("resumptionToken", $Token);
00529                     }
00530                     else
00531                     {
00532                         # if we started with a resumption token tag
00533                         if (isset($this->Args["resumptionToken"]))
00534                         {
00535                             # add empty resumption token tag to indicate end of set
00536                             $Response .= $this->FormatTag("resumptionToken", "");
00537                         }
00538                     }
00539 
00540                     # close response type tag
00541                     $Response .= $this->FormatTag();
00542                 }
00543             }
00544         }
00545 
00546         # close out response
00547         $Response .= $this->GetResponseEndTags();
00548 
00549         # return response to caller
00550         return $Response;
00551     }
00552 
00553     function ProcessListMetadataFormats()
00554     {
00555         # initialize response
00556         $Response = $this->GetResponseBeginTags();
00557 
00558         # if arguments were bad
00559         $Arg = isset($this->Args["identifier"]) ? $this->Args["identifier"] : NULL;
00560         $ItemId = $this->DecodeIdentifier($Arg);
00561         if (isset($this->Args["identifier"]) && ($ItemId == NULL))
00562         {
00563             # add error tag
00564             $Response .= $this->GetRequestTag();
00565             $Response .= $this->GetErrorTag("idDoesNotExist", "Identifier unknown or illegal.");
00566         }
00567         else
00568         {
00569             # add request info tag
00570             $OptArgList = array("identifier");
00571             $Response .= $this->GetRequestTag("ListMetadataFormats", NULL, $OptArgList);
00572 
00573             # open response type tag
00574             $Response .= $this->FormatTag("ListMetadataFormats");
00575 
00576             # for each supported format
00577             foreach ($this->FormatDescrs as $FormatName => $FormatDescr)
00578             {
00579                 # open format tag
00580                 $Response .= $this->FormatTag("metadataFormat");
00581 
00582                 # add tags describing format
00583                 $Response .= $this->FormatTag("metadataPrefix", $FormatName);
00584                 $Pieces = preg_split("/[\s]+/", $FormatDescr["SchemaLocation"]);
00585                 $Response .= $this->FormatTag("schema", $Pieces[1]);
00586                 $Response .= $this->FormatTag("metadataNamespace", $FormatDescr["NamespaceList"][$FormatName]);
00587 
00588                 # close format tag
00589                 $Response .= $this->FormatTag();
00590             }
00591 
00592             # close response type tag
00593             $Response .= $this->FormatTag();
00594         }
00595 
00596         # close out response
00597         $Response .= $this->GetResponseEndTags();
00598 
00599         # return response to caller
00600         return $Response;
00601     }
00602 
00603     function ProcessListSets()
00604     {
00605         # initialize response
00606         $Response = $this->GetResponseBeginTags();
00607 
00608         # add request info tag
00609         $OptArgList = array("resumptionToken");
00610         $Response .= $this->GetRequestTag("ListSets", NULL, $OptArgList);
00611 
00612         # retrieve list of supported sets
00613         $SetList = $this->SetsSupported ? $this->ItemFactory->GetListOfSets() : array();
00614 
00615         # if sets not supported or we have no sets
00616         if ((!$this->SetsSupported) || (!count($SetList) && !$this->OaisqSupported))
00617         {
00618             # add error tag indicating that we do not support sets
00619             $Response .= $this->GetErrorTag("noSetHierarchy", "This repository does not support sets.");
00620         }
00621         else
00622         {
00623             # open response type tag
00624             $Response .= $this->FormatTag("ListSets");
00625 
00626             # if OAI-SQ is enabled
00627             if ($this->OaisqSupported)
00628             {
00629                 # add OAI-SQ to list of sets
00630                 $SetList["OAI-SQ"] = "OAI-SQ";
00631                 $SetList["OAI-SQ-F"] = "OAI-SQ-F";
00632             }
00633             
00634             # for each supported set
00635             foreach ($SetList as $SetName => $SetSpec)
00636             {
00637                 # open set tag
00638                 $Response .= $this->FormatTag("set");
00639                 
00640                 # add set spec and set name
00641                 $Response .= $this->FormatTag("setSpec", $SetSpec);
00642                 $Response .= $this->FormatTag("setName", $SetName);
00643                 
00644                 # close set tag
00645                 $Response .= $this->FormatTag();
00646             }
00647 
00648             # close response type tag
00649             $Response .= $this->FormatTag();
00650         }
00651 
00652         # close out response
00653         $Response .= $this->GetResponseEndTags();
00654 
00655         # return response to caller
00656         return $Response;
00657     }
00658 
00659     
00660     # ---- common private methods
00661     
00662     function GetResponseBeginTags()
00663     {
00664         # start with XML declaration
00665         $Tags = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
00666 
00667         # add OAI-PMH root element begin tag
00668         $Tags .= "<OAI-PMH xmlns=\"http://www.openarchives.org/OAI/2.0/\"\n"
00669                 ."        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
00670                 ."        xsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/\n"
00671                 ."            http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd\">\n";
00672 
00673         # add response timestamp
00674         $Tags .= "    <responseDate>".date("Y-m-d\\TH:i:s\\Z")."</responseDate>\n";
00675 
00676         # return tags to caller
00677         return $Tags;
00678     }
00679 
00680     function GetResponseEndTags()
00681     {
00682         # close out OAI-PMH root element
00683         $Tags = "</OAI-PMH>\n";
00684 
00685         # return tags to caller
00686         return $Tags;
00687     }
00688 
00689     function GetRequestTag($RequestType = NULL, $ReqArgList = NULL, $OptArgList = NULL)
00690     {
00691         # build attribute array
00692         $AttributeList = array();
00693         if ($RequestType !== NULL)
00694         {
00695             $AttributeList["verb"] = $RequestType;
00696         }
00697         if ($ReqArgList != NULL)
00698         {
00699             foreach ($ReqArgList as $ArgName)
00700             {
00701                 if (isset($this->Args[$ArgName]))
00702                 {
00703                     $AttributeList[$ArgName] = $this->Args[$ArgName];
00704                 }
00705             }
00706         }
00707         if ($OptArgList != NULL)
00708         {
00709             foreach ($OptArgList as $ArgName)
00710             {
00711                 if (isset($this->Args[$ArgName]))
00712                 {
00713                     $AttributeList[$ArgName] = $this->Args[$ArgName];
00714                 }
00715             }
00716         }
00717 
00718         # generate formatted tag
00719         $Tag = $this->FormatTag("request",
00720                                 $this->RepDescr["BaseURL"],
00721                                 $AttributeList);
00722 
00723         # return tag to caller
00724         return $Tag;
00725     }
00726 
00727     function GetErrorTag($ErrorCode, $ErrorMessage)
00728     {
00729         return $this->FormatTag("error", $ErrorMessage, array("code" => $ErrorCode));
00730     }
00731 
00732     function GetRecordTags($Item, $MetadataFormat, $IncludeMetadata = TRUE)
00733     {
00734         # if more than identifiers requested
00735         if ($IncludeMetadata)
00736         {
00737             # open record tag
00738             $Tags = $this->FormatTag("record");
00739         }
00740         else
00741         {
00742             # just initialize tag string with empty value
00743             $Tags = "";
00744         }
00745 
00746         # add header with identifier, datestamp, and set tags
00747         $Tags .= $this->FormatTag("header");
00748         $Tags .= $this->FormatTag("identifier", 
00749                                   $this->EncodeIdentifier($Item->GetId()));
00750         $Tags .= $this->FormatTag("datestamp", $Item->GetDatestamp());
00751         $Sets = $Item->GetSets();
00752         foreach ($Sets as $Set)
00753         {
00754             $Tags .= $this->FormatTag("setSpec", $Set);
00755         }
00756         $Tags .= $this->FormatTag();
00757 
00758         # if more than identifiers requested
00759         if ($IncludeMetadata)
00760         {
00761             # open metadata tag
00762             $Tags .= $this->FormatTag("metadata");
00763 
00764             # set up attributes for metadata format tag
00765             $MFAttribs["xsi:schemaLocation"] = $this->FormatDescrs[$MetadataFormat]["SchemaLocation"];
00766             if (strlen($this->FormatDescrs[$MetadataFormat]["SchemaVersion"]) > 0)
00767             {
00768                 $MFAttribs["schemaVersion"] = $this->FormatDescrs[$MetadataFormat]["SchemaVersion"];
00769             }
00770             $MFAttribs["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance";
00771             foreach ($this->FormatDescrs[$MetadataFormat]["NamespaceList"] as $NamespaceName => $NamespaceURI)
00772             {
00773                 $MFAttribs["xmlns:".$NamespaceName] = $NamespaceURI;
00774             }
00775 
00776             # open metadata format tag
00777             $Tags .= $this->FormatTag($this->FormatDescrs[$MetadataFormat]["TagName"], NULL, $MFAttribs);
00778 
00779             # for each field mapping for this metadata format
00780             foreach ($this->FieldMappings[$MetadataFormat] as $LocalFieldName => $OAIFieldName)
00781             {
00782                 # if field looks like it has been mapped
00783                 if (strlen($OAIFieldName) > 0)
00784                 {
00785                     # retrieve content for field
00786                     $Content = $Item->GetValue($LocalFieldName);
00787                     
00788                     # retrieve qualifiers for content
00789                     $Qualifier = $Item->GetQualifier($LocalFieldName);
00790 
00791                     # if content is array
00792                     if (is_array($Content))
00793                     {
00794                         # for each element of array
00795                         foreach ($Content as $ContentIndex => $ContentValue)
00796                         {
00797                             # if element has content
00798                             if (strlen($ContentValue) > 0)
00799                             {
00800                                 # generate tag for element
00801                                 if (isset($Qualifier[$ContentIndex]) && strlen($Qualifier[$ContentIndex]))
00802                                 {
00803                                     if (isset($this->QualifierMappings[$MetadataFormat][$Qualifier[$ContentIndex]])
00804                                             && (strlen($this->QualifierMappings[$MetadataFormat][$Qualifier[$ContentIndex]]) > 0))
00805                                     {
00806                                         $ContentAttribs["xsi:type"] = $this->QualifierMappings[$MetadataFormat][$Qualifier[$ContentIndex]];
00807                                     }
00808                                 }
00809                                 else
00810                                 {
00811                                     $ContentAttribs = NULL;
00812                                 }
00813                                 $Tags .= $this->FormatTag($OAIFieldName, 
00814                                                           utf8_encode(htmlspecialchars(preg_replace("/[\\x00-\\x1F]+/", "", $ContentValue))),
00815                                                           $ContentAttribs);
00816                             }
00817                         }
00818                     }
00819                     else
00820                     {
00821                         # if field has content
00822                         if (strlen($Content) > 0)
00823                         {
00824                             # generate tag for field
00825                             if (strlen($Qualifier) > 0)
00826                             {
00827                                 if (isset($this->QualifierMappings[$MetadataFormat][$Qualifier])
00828                                         && (strlen($this->QualifierMappings[$MetadataFormat][$Qualifier]) > 0))
00829                                 {
00830                                     $ContentAttribs["xsi:type"] = $this->QualifierMappings[$MetadataFormat][$Qualifier];
00831                                 }
00832                             }
00833                             else
00834                             {
00835                                 $ContentAttribs = NULL;
00836                             }
00837                             $Tags .= $this->FormatTag($OAIFieldName, 
00838                                                       utf8_encode(htmlspecialchars(preg_replace("/[\\x00-\\x1F]+/", "", $Content))),
00839                                                       $ContentAttribs);
00840                         }
00841                     }
00842                 }
00843             }
00844 
00845             # close metadata format tag
00846             $Tags .= $this->FormatTag();
00847 
00848             # close metadata tag
00849             $Tags .= $this->FormatTag();
00850 
00851             # if there is additional search info about this item
00852             $SearchInfo = $Item->GetSearchInfo();
00853             if (count($SearchInfo))
00854             {
00855                 # open about and search info tags
00856                 $Tags .= $this->FormatTag("about");
00857                 $Attribs = array(
00858                         "xmlns" => "http://scout.wisc.edu/XML/searchInfo/",
00859                         "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
00860                         "xsi:schemaLocation" => "http://scout.wisc.edu/XML/searchInfo/ http://scout.wisc.edu/XML/searchInfo.xsd",
00861                         );
00862                 $Tags .= $this->FormatTag("searchInfo", NULL, $Attribs);
00863 
00864                 # for each piece of additional info
00865                 foreach ($SearchInfo as $InfoName => $InfoValue)
00866                 {
00867                     # add tag for info
00868                     $Tags .= $this->FormatTag($InfoName,
00869                             utf8_encode(htmlspecialchars(preg_replace("/[\\x00-\\x1F]+/", "", $InfoValue))));
00870                 }
00871 
00872                 # close about and search info tags
00873                 $Tags .= $this->FormatTag();
00874                 $Tags .= $this->FormatTag();
00875             }
00876         }
00877 
00878         # if more than identifiers requested
00879         if ($IncludeMetadata)
00880         {
00881             # close record tag
00882             $Tags .= $this->FormatTag();
00883         }
00884 
00885         # return tags to caller
00886         return $Tags;
00887     }
00888 
00889     function EncodeIdentifier($ItemId)
00890     {
00891         # return encoded value to caller
00892         return "oai:".$this->RepDescr["IDDomain"]
00893                 .":".$this->RepDescr["IDPrefix"]."-".$ItemId;
00894     }
00895 
00896     function DecodeIdentifier($Identifier)
00897     {
00898         # assume that decode will fail
00899         $Id = NULL;
00900 
00901         # split ID into component pieces
00902         $Pieces = split(":", $Identifier);
00903 
00904         # if pieces look okay
00905         if (($Pieces[0] == "oai") && ($Pieces[1] == $this->RepDescr["IDDomain"]))
00906         {
00907             # split final piece
00908             $Pieces = split("-", $Pieces[2]);
00909 
00910             # if identifier prefix looks okay
00911             if ($Pieces[0] == $this->RepDescr["IDPrefix"])
00912             {
00913                 # decoded value is final piece
00914                 $Id = $Pieces[1];
00915             }
00916         }
00917 
00918         # return decoded value to caller
00919         return $Id;
00920     }
00921     
00922     function EncodeResumptionToken($StartingDate, $EndingDate, $MetadataFormat, $SetSpec, $ListStartPoint)
00923     {
00924         # concatenate values to create token
00925         $Token = $StartingDate."-_-".$EndingDate."-_-".$MetadataFormat."-_-"
00926                 .$SetSpec."-_-".$ListStartPoint;
00927         
00928         # return token to caller
00929         return $Token;
00930     }
00931     
00932     function DecodeResumptionToken($ResumptionToken)
00933     {
00934         # split into component pieces
00935         $Pieces = preg_split("/-_-/", $ResumptionToken);
00936         
00937         # if we were unable to split token
00938         if (count($Pieces) != 5)
00939         {
00940             # return NULL list
00941             $Args = NULL;
00942         }
00943         else
00944         {
00945             # assign component pieces to list parameters
00946             if (strlen($Pieces[0]) > 0) {  $Args["from"] = $Pieces[0];  }
00947             if (strlen($Pieces[1]) > 0) {  $Args["until"] = $Pieces[1];  }
00948             if (strlen($Pieces[2]) > 0) {  $Args["metadataPrefix"] = $Pieces[2];  }
00949             if (strlen($Pieces[3]) > 0) {  $Args["set"] = $Pieces[3];  }
00950             if (strlen($Pieces[4]) > 0) {  $Args["ListStartPoint"] = $Pieces[4];  }
00951         }
00952         
00953         # return list parameter array to caller
00954         return $Args;
00955     }
00956     
00957     function DateIsInvalid($Date)
00958     {
00959         # if date is null or matches required format
00960         if (empty($Date) || preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/", $Date))
00961         {
00962             # date is okay
00963             return FALSE;
00964         }
00965         else
00966         {
00967             # date is not okay
00968             return TRUE;
00969         }
00970     }
00971 
00972     function FormatTag($Name = NULL, $Content = NULL, $Attributes = NULL, $NewIndentLevel = NULL)
00973     {
00974         static $IndentLevel = 1;
00975         static $OpenTagStack = array();
00976 
00977         # reset indent level if requested
00978         if ($NewIndentLevel !== NULL)
00979         {
00980             $IndentLevel = $NewIndentLevel;
00981         }
00982 
00983         # if tag name supplied
00984         if ($Name !== NULL)
00985         {
00986             # start out with appropriate indent
00987             $Tag = str_repeat(" ", ($IndentLevel * $this->IndentSize));
00988 
00989             # open begin tag
00990             $Tag .= "<".$Name;
00991 
00992             # if attributes supplied
00993             if ($Attributes !== NULL)
00994             {
00995                 # add attributes
00996                 foreach ($Attributes as $AttributeName => $AttributeValue)
00997                 {
00998                     $Tag .= " ".$AttributeName."=\"".$AttributeValue."\"";
00999                 }
01000             }
01001 
01002             # if content supplied
01003             if ($Content !== NULL)
01004             {
01005                 # close begin tag
01006                 $Tag .= ">";
01007 
01008                 # add content
01009                 $Tag .= $Content;
01010 
01011                 # add end tag
01012                 $Tag .= "</".$Name.">\n";
01013             }
01014             else
01015             {
01016                 # close begin tag
01017                 $Tag .= ">\n";
01018 
01019                 # increase indent level
01020                 $IndentLevel++;
01021 
01022                 # add tag to open tag stack
01023                 array_push($OpenTagStack, $Name);
01024             }
01025         }
01026         else
01027         {
01028             # decrease indent level
01029             if ($IndentLevel > 0) {  $IndentLevel--;  }
01030 
01031             # pop last entry off of open tag stack
01032             $LastName = array_pop($OpenTagStack);
01033 
01034             # start out with appropriate indent
01035             $Tag = str_repeat(" ", ($IndentLevel * $this->IndentSize));
01036 
01037             # add end tag to match last open tag
01038             $Tag .= "</".$LastName.">\n";
01039         }
01040 
01041         # return formatted tag to caller
01042         return $Tag;
01043     }
01044 
01045     function LoadArguments()
01046     {
01047         # if request type available via POST variables
01048         if (isset($_POST["verb"]))
01049         {
01050             # retrieve arguments from POST variables
01051             $this->Args = $_POST;
01052         }
01053         # else if request type available via GET variables
01054         elseif (isset($_GET["verb"]))
01055         {
01056             # retrieve arguments from GET variables
01057             $this->Args = $_GET;
01058 
01059             # strip off page designator GET parameter
01060             if (isset($this->Args["P"])) {  unset($this->Args["P"]);  }
01061         }
01062         else
01063         {
01064             # ERROR OUT
01065             # ???
01066         }
01067     }
01068     
01069     # ---- methods to support OAI-SQ
01070     
01071     function IsOaisqQuery($SetString)
01072     {
01073         return ((strpos($SetString, "OAI-SQ|") === 0) 
01074                 || (strpos($SetString, "OAI-SQ!") === 0)
01075                 || (strpos($SetString, "OAI-SQ-F|") === 0)
01076                 || (strpos($SetString, "OAI-SQ-F!") === 0)
01077         ) ? TRUE : FALSE;
01078     }
01079 
01080     function TranslateOaisqEscapes($Pieces)
01081     {
01082         # for each piece
01083     for ($Index = 0;  $Index < count($Pieces);  $Index++)
01084     {
01085         # replace escaped chars with equivalents
01086         $Pieces[$Index] = preg_replace_callback(
01087                 "/~[a-fA-F0-9]{2,2}/", 
01088             create_function(
01089             '$Matches',
01090             'for ($Index = 0;  $Index < count($Matches);  $Index++)'
01091                 .'{'
01092                 .'    $Replacements = chr(intval(substr($Matches[$Index], 1, 2), 16));'
01093                 .'}'
01094                 .'return $Replacements;'
01095             ),
01096             $Pieces[$Index]);
01097     }
01098 
01099     # return translated array of pieces to caller
01100     return $Pieces;
01101     }
01102     
01103     function ParseOaisqQuery($SetString, $FormatName)
01104     {
01105         # if OAI-SQ fielded search requested
01106         if (strpos($SetString, "OAI-SQ-F") === 0)
01107         {
01108             # split set string into field names and values
01109             $Pieces = explode(substr($SetString, 8, 1), $SetString);
01110 
01111             # discard first piece (OAI-SQ designator)
01112             array_shift($Pieces);
01113 
01114         # if set string contains escaped characters
01115         if (preg_match("/~[a-fA-F0-9]{2,2}/", $SetString))
01116         {
01117             $Pieces = $this->TranslateOaisqEscapes($Pieces);
01118         }
01119 
01120             # for every two pieces
01121             $SearchParams = array();
01122             $NumPairedPieces = round(count($Pieces) / 2) * 2;
01123             for ($Index = 0;  $Index < $NumPairedPieces;  $Index += 2)
01124             {
01125                 # retrieve local field mapping
01126                 $LocalFieldName = array_search($Pieces[$Index], $this->FieldMappings[$FormatName]);
01127 
01128                 # if local field mapping found
01129                 if (strlen($LocalFieldName))
01130                 {
01131                     # add mapped values to search parameters
01132                     $SearchParams[$LocalFieldName] = $Pieces[$Index + 1];
01133                 }
01134             }
01135         }
01136         else
01137         {
01138             # split set string to trim off query designator
01139             $Pieces = explode(substr($SetString, 6, 1), $SetString, 2);
01140 
01141         # if set string contains escaped characters
01142         if (preg_match("/~[a-fA-F0-9]{2,2}/", $SetString))
01143         {
01144             $Pieces = $this->TranslateOaisqEscapes($Pieces);
01145         }
01146 
01147             # remainder of set string is keyword search string
01148             $SearchParams["X-KEYWORD-X"] = $Pieces[1];
01149         }
01150         
01151         # return array of search parameters to caller
01152         return $SearchParams;
01153     }
01154 }
01155 
01156 class OAIItemFactory {
01157     
01158     # ---- PUBLIC INTERFACE --------------------------------------------------
01159 
01160     # object constructor
01161     function OAIItemFactory()
01162     {
01163     }
01164     
01165     function GetItem($ItemId) {  exit("OAIItemFactory method GetItem() not implemented");  }
01166     function GetItems($StartingDate = NULL, $EndingDate = NULL)
01167     {  
01168         exit("OAIItemFactory method GetItems() not implemented");  
01169     }
01170     
01171     # retrieve IDs of items that matches set spec (only needed if sets supported)
01172     function GetItemsInSet($SetSpec, $StartingDate = NULL, $EndingDate = NULL)
01173     {  
01174         exit("OAIItemFactory method GetItemsInSet() not implemented");  
01175     }
01176     
01177     # return array containing all set specs (with human-readable set names as keys) 
01178     # (only needed if sets supported)
01179     function GetListOfSets()
01180     {  
01181         exit("OAIItemFactory method GetListOfSets() not implemented");  
01182     }
01183     
01184     # retrieve IDs of items that match search parameters (only needed if OAI-SQ supported)
01185     function SearchForItems($SearchParams, $StartingDate = NULL, $EndingDate = NULL)
01186     {  
01187         exit("OAIItemFactory method SearchForItems() not implemented");  
01188     }
01189 }
01190 
01191 class OAIItem {
01192     
01193     # ---- PUBLIC INTERFACE --------------------------------------------------
01194 
01195     # object constructor
01196     function OAIItem($ItemId, $ExtraItemInfo = NULL)
01197     {
01198     }
01199     
01200     function GetId()                     {  exit("OAIItem method GetId() not implemented");  }
01201     function GetDatestamp()              {  exit("OAIItem method GetDatestamp() not implemented");  }
01202     function GetValue($ElementName)      {  exit("OAIItem method GetValue() not implemented");  }
01203     function GetQualifier($ElementName)  {  exit("OAIItem method GetQualifiers() not implemented");  }
01204     function GetSets()                   {  exit("OAIItem method GetSets() not implemented");  }
01205     function GetSearchInfo()             {  return array();  }
01206     function Status()                    {  exit("OAIItem method Status() not implemented");  }
01207 }
01208 
01209 
01210 ?>

CWIS logo doxygen
Copyright 2010 Internet Scout