00001 <?php
00012 require_once("WSCORE2.php");
00013 require_once("soc1c.php");
00014 require_once("ais_soap1c.php");
00015
00016 function debug($msg) {
00017 $fp = fopen('/www/ws/soc/debug-log/debug.log','a');
00018 fwrite($fp, date('Y-m-d H:i:s') . ' -> ' . $msg . PHP_EOL);
00019 fclose($fp);
00020 }
00021
00036 class SOC_API1C extends SOC_Widget {
00043 function __construct($conf) {
00044 SOC_Widget::SOC_Widget($conf);
00045 $this->version_msg = "SOC API1C";
00046 $this->cache = new SOC_Cache2($this);
00047 $this->cache->open();
00048 $this->service = "";
00049 if ($this->get("soc_path")) {
00050 $filename = $this->get("soc_path") . '/data/dept-urls.json';
00051 } else {
00052 $filename = "data/dept-urls.json";
00053 }
00054 if (file_exists($filename)) {
00055 $this->dept_info = json_decode(file_get_contents($filename), true);
00056 } else {
00057 $this->dept_info = array();
00058 }
00059 }
00060
00064 public function close () {
00065 return $this->cache->close();
00066 }
00067
00074 function _restParse ($restful_args) {
00075 $args = explode('/',trim($restful_args));
00076 if (count($args) < 2) {
00077 $this->error("Not sure what you want me to do [$restful_args]");
00078 }
00079 $i = 1;
00080 if (isset($args[$i])) {
00081 $object = strtolower($args[$i]);
00082
00083 switch($object) {
00084 case 'help':
00085 $this->format = "html";
00086 $this->content_type = "text/html";
00087 break;
00088 default:
00089
00090
00091 $this->content_type = "application/json";
00092 $this->format = "json";
00093 break;
00094 }
00095 }
00096
00097
00098 if (isset($args[$i])) {
00099 $object = strtolower($args[$i]);
00100 $this->service = $object;
00101 switch($object) {
00102 case 'session':
00103 $this->service = 'session';
00104 $i++;
00105 if (isset($args[$i])) {
00106 $this->set("active_session",$args[$i]);
00107 } else {
00108 $this->error("Must include a session code. e.g. 001, 002, 003");
00109 }
00110 $i++;
00111 if (isset($args[$i])) {
00112 $this->set("active_term",$args[$i]);
00113 } else {
00114 $this->error("Must include a term code. e.g. 20091 for Spring 2009, 20092 for Summer 2009, 20093 for Fall 2009");
00115 }
00116 break;
00117 case 'classes':
00118 $this->service = 'classes';
00119 $i++;
00120 if (isset($args[$i])) {
00121 $this->set("active_dept",$args[$i]);
00122 $i++;
00123 } else {
00124 $this->error("You need to provide a department for your request. e.g. ".$this->get("soc_uri")."/api1c/classes/hist/20091 would request classes offered by the History department for Spring 2009");
00125 }
00126 if (isset($args[$i])) {
00127 $this->set("active_term",$args[$i]);
00128 $i++;
00129 } else {
00130 $this->error("You need to provide a term for your request. e.g. ".$this->get("soc_uri")."/api1c/classes/hist/20091 would request classes offered by the History department for Spring 2009");
00131 }
00132 break;
00133 case 'departments':
00134 case 'depts':
00135 $this->service = 'departments';
00136 $i++;
00137 if (isset($args[$i])) {
00138 $this->set("active_term",$args[$i]);
00139 $i++;
00140 } else {
00141 $this->error("You need to provide a term with the department requested. e.g. ".$this->get("soc_uri")."/api1c/depts/20091 would request department information for Spring 2009");
00142 }
00143 break;
00144 case 'terms':
00145 $this->service = 'terms';
00146 $i++;
00147 break;
00148 case 'bio':
00149 $this->service = 'bio';
00150 $i++;
00151 if (isset($args[$i])) {
00152 $this->set("eid",$args[$i]);
00153 } else {
00154 $this->error("Must include an employee number");
00155 }
00156 break;
00157 case 'booklist':
00158 $this->service = 'booklist';
00159 $i++;
00160 if (isset($args[$i])) {
00161 $this->set('section',$args[$i]);
00162 $i++;
00163 } else {
00164 $this->error("Must include a section number for the book list e.g. /api1c/booklist/21012/20093 would be a book list for section 21012 in Fall 2009");
00165 }
00166 if (isset($args[$i])) {
00167 $this->set("active_term",$args[$i]);
00168 $i++;
00169 } else {
00170 $this->error("Must include a term number for the book list e.g. /api1c/booklist/21012/20093 would be a book list for section 21012 in Fall 2009");
00171 }
00172 break;
00173 case 'help':
00174 default:
00175 $this->content = $this->help();
00176 $i++;
00177 break;
00178 }
00179 }
00180 unset($args);
00181 if ($this->errorCount() == 0) {
00182 return true;
00183 }
00184 return false;
00185 }
00186
00193 function getSession ($session, $term) {
00194 $soap = new AIS_SOAP_WS($this);
00195 $xml = $soap->xmlFromSoap("GetSessionInfo", $term, $session);
00196 if ($soap->errorCount()) {
00197 $this->error("Can't get session data from AIS SOAP Service.\n" . $soap->errors());
00198 return false;
00199 }
00200
00201 if ($xml !== false) {
00202
00203 try {
00204 $dom = new SimpleXMLElement($xml);
00205 $json = json_encode($dom);
00206 } catch (Exception $e) {
00207 $this->error("SimpleXMLElement can't parse active sessions for $session, $term [$xml] ".$e->getMessage()."\n".$soap->errors());
00208 unset($soap);
00209 return false;
00210 }
00211 unset($dom);
00212 unset($soap);
00213 $this->cache->setCache("/session/$session/$term", $json);
00214 return true;
00215 }
00216 $this->error ("Can't find information for session $session in term $term");
00217 unset($soap);
00218 return false;
00219 }
00220
00226 public function getCacheForTerm($term) {
00227 if (trim($term) === '') {
00228 $this->error("Need to set term for Cache");
00229 return false;
00230 }
00231 $sql = "SELECT uri FROM soc_cache WHERE uri LIKE '%$term' AND uri NOT LIKE '/booklist%' AND uri NOT LIKE '/classes%' ORDER BY soc_cache.modified ASC";
00232 $url_list = array();
00233 $this->cache->execute($sql);
00234 while ($row = $this->cache->getRow()) {
00235 if (isset($row['uri'])) {
00236 $url_list[] = $row['uri'];
00237 }
00238 }
00239 $this->cache->release();
00240 if ($this->cache->errorCount() === 0) {
00241 return $url_list;
00242 }
00243 $this->error("Can't find data for $term.");
00244 return false;
00245 }
00246
00254 public function getBooklist($section, $term) {
00255 if ($this->get("booklist_url") === false) {
00256 $this->error("Book list URL not configured");
00257 return false;
00258 }
00259 $uri = $this->get("booklist_url");
00260 $booklist = substr($term,2).'-'.$section;
00261
00262 $json = false;
00263 if (trim($uri) !== '') {
00264 if (strpos($uri,'file://') === 0) {
00265
00266
00267 $json = @file_get_contents(substr($uri,7) . '/'. $booklist . '.json');
00268 } else {
00269 $uri = $uri.'/'.$booklist.'.json';
00270
00271 $ch = curl_init();
00272
00273
00274 curl_setopt($ch, CURLOPT_USERAGENT, "soc-api1c");
00275 curl_setopt($ch, CURLOPT_REFERER, "http://web-app.usc.edu/ws/soc/models/api1c.php");
00276
00277
00278 curl_setopt($ch, CURLOPT_URL, $uri);
00279
00280 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
00281
00282
00283 $json = curl_exec($ch);
00284
00285 curl_close($ch);
00286
00287 }
00288 }
00289
00290 if ($json !== false) {
00291 if (strpos($json, "<!DOC") !== false || strpos($json,"404 Not Found") !==
00292 false) {
00293 $this->error($booklist . " not available.");
00294 return false;
00295 }
00296
00297 $test = json_decode($json, true);
00298 if (function_exists('json_last_error')) {
00299 switch(json_last_error()) {
00300 case JSON_ERROR_DEPTH:
00301 $this->error($booklist . ' maximum stack depth exceeded.');
00302 return false;
00303 case JSON_ERROR_CTRL_CHAR:
00304 $this->error($booklist . ' unexpected control character found.');
00305 return false;
00306 case JSON_ERROR_SYNTAX:
00307 $this->error($booklist . ' syntax error, malformed JSON.');
00308 return false;
00309 }
00310 } else if (is_array($test) === false) {
00311 $this->error($booklist . " was improperly formatted." . print_r($test,
00312 true));
00313 return false;
00314 }
00315 unset($test);
00316 $this->cache->setCache('/booklist/'.$section.'/'.$term,$json);
00317 return $json;
00318 }
00319 $this->error("Booklist $booklist requested was an empty string.");
00320 return false;
00321 }
00322
00328 public function getBioUrl($id) {
00329 $obj = new AIS_SOAP_WS($this);
00330 $xml = $obj->xmlFromSoap("GetBioLink",NULL,$id);
00331 if ($obj->errorCount() == 0 && trim($xml) !== '<BioURL />' && $xml !== false && trim($xml) != "") {
00332 libxml_use_internal_errors(true);
00333 $sxml = simplexml_load_string($xml);
00334 if (! $sxml) {
00335 $this->error("XML parse error(s). GetBioLink(". strlen($xml) . "): [<pre>". $xml . "</pre>]");
00336 $xmlerrors = libxml_get_errors();
00337 foreach ($xmlerrors as $xerror) {
00338 $msg = 'ERROR line: ' . $xml[$xerror->line - 1] . " ";
00339 $msg .= str_repeat('-', $xerror->column) . ": ";
00340 $msg .= $xerror->message;
00341 $this->error($msg);
00342 }
00343 libxml_clear_errors();
00344 return false;
00345 }
00346 $bio_link = urldecode($sxml."");
00347 unset($sxml);
00348 unset($xml);
00349 if (trim($bio_link) != "") {
00350 return $bio_link;
00351 }
00352 }
00353 unset($obj);
00354 return false;
00355 }
00356
00357 function getDeptInfo($abbreviation) {
00358 foreach ($this->dept_info as $info) {
00359 if (isset($info["abbreviation"]) && $info["abbreviation"] === $abbreviation) {
00360 return $info;
00361 }
00362 }
00363 return false;
00364 }
00365
00373 function getClasses ($dept, $term) {
00374 $soap = new AIS_SOAP_WS($this);
00375
00376 $xml = mb_convert_encoding($soap->xmlFromSoap("GetCourseList",$term, $dept), 'UTF-8');
00377
00378 if ($xml == false || $soap->errorCount() > 0) {
00379 $this->error("Can't get Course Lists from AIS SOAP Service. for $dept, $term\n".$soap->errors());
00380 unset($soap);
00381 return false;
00382 }
00383 unset($soap);
00384 $uri = "/classes/$dept/$term";
00385
00386
00387
00388 libxml_use_internal_errors(true);
00389 $sxml = simplexml_load_string($xml);
00390 if (! $sxml) {
00391 $this->error("XML parse error(s). GetCourseList: [".$xml."]");
00392 $xmlerrors = libxml_get_errors();
00393 foreach ($xmlerrors as $xerror) {
00394 $msg = 'line: ' . $xml[$xerror->line - 1] . " ";
00395 $msg .= str_repeat('-', $xerror->column) . ": ";
00396 $msg .= $xerror->message;
00397 $this->error($msg);
00398 }
00399 libxml_clear_errors();
00400 return false;
00401 }
00402
00403
00404
00405 if ($sxml !== false) {
00406
00407
00408 $DeptInfo = false;
00409 if (isset($sxml->Dept_Info)) {
00410 $info = $this->getDeptInfo(trim($sxml->Dept_Info->abbreviation));
00411 if (isset($info['uri'])) {
00412 $sxml->Dept_Info->dept_url = $info['uri'];
00413 $DeptInfo = $sxml->Dept_Info;
00414 }
00415 }
00416 $HasDistanceLearning = 'N';
00417
00418 for($i = 0; $i < count($sxml->OfferedCourses->course); $i++ ) {
00419 for($j = 0; $j < count($sxml->OfferedCourses->course[$i]->ConcurrentCourse); $j++) {
00420 for ($k = 0; $k < count($sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData); $k++ ) {
00421
00422
00423 if (isset($sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->comment) && trim($sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->comment) != '') {
00424 $sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->IsDistanceLearning = 'Y';
00425 $HasDistanceLearning = 'Y';
00426 } else {
00427 $sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->IsDistanceLearning = 'N';
00428 }
00429
00430 for ($l = 0; $l < count($sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->instructor);$l++) {
00431 $bio_url = false;
00432
00433 if (isset($sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->instructor[$l]->id)) {
00434 $uscemployeeid =
00435 $sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->instructor[$l]->id;
00436 $bio_url = $this->getBioUrl($uscemployeeid);
00437 }
00438 if ($bio_url !== false) {
00439 $sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->instructor[$l]->bio_url =
00440 trim($bio_url);
00441 } else {
00442 unset($sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->instructor[$l]->bio_url);
00443 }
00444 unset($sxml->OfferedCourses->course[$i]->ConcurrentCourse[$j]->CourseData->SectionData[$k]->instructor[$l]->id);
00445 }
00446 }
00447 }
00448
00449 $HasDistanceLearning = 'N';
00450
00451
00452 for ($j = 0; $j < count($sxml->OfferedCourses->course[$i]->CourseData->SectionData); $j++ ) {
00453
00454
00455 if (isset($sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->comment) && trim($sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->comment) != '') {
00456 $sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->IsDistanceLearning = 'Y';
00457 $HasDistanceLearning = 'Y';
00458 } else {
00459 $sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->IsDistanceLearning = 'N';
00460 }
00461
00462 for ($k = 0; $k < count($sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->instructor); $k++) {
00463 $uscemployeeid = $sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->instructor[$k]->id;
00464
00465 $bio_url = $this->getBioUrl($uscemployeeid);
00466 if ($bio_url !== false) {
00467 $sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->instructor[$k]->bio_url = trim($bio_url);
00468 } else {
00469 unset($sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->instructor[$k]->bio_url);
00470 }
00471 unset($sxml->OfferedCourses->course[$i]->CourseData->SectionData[$j]->instructor[$k]->id);
00472 }
00473 }
00474 }
00475
00476
00477 try {
00478 $json_text = json_encode($sxml);
00479 } catch (Exception $e) {
00480 $this->error($e->getMessage()." Caching $uri: [$json_text]");
00481 }
00482 if ($this->errorCount() > 0) {
00483 return false;
00484 }
00485 $this->cache->setCache(strtolower($uri), $json_text);
00486 unset($sxml);
00487 unset($xml);
00488 unset($json_text);
00489 return true;
00490 }
00491 $this->error ("Can't find classes for $dept in term $term; xml [$xml]");
00492 return false;
00493 }
00494
00500 function getDepartments ($term) {
00501 $soap = new AIS_SOAP_WS($this);
00502 $xml = $soap->xmlFromSoap("GetDeptList", $term, NULL);
00503 if ($soap->errorCount()) {
00504 $this->error("Can't get Dept. Lists from AIS SOAP Service.\n".$soap->errors() . " xml:[<pre>$xml</pre>]");
00505 unset($soap);
00506 return false;
00507 }
00508 unset($soap);
00509 $uri = "/departments/$term";
00510
00511 if ($xml !== false) {
00512
00513 try {
00514
00515 $sxml = new SimpleXMLElement(str_replace(" & ", " & ", $xml));
00516 $json = json_encode($sxml);
00517 $this->cache->setCache(strtolower($uri), $json);
00518 unset($sxml);
00519 unset($xml);
00520 return true;
00521 } catch (Exception $e) {
00522 $this->error("SimpleXMLElement can't parse active depts for $term [$xml] ".$e->getMessage()."\n");
00523 }
00524 }
00525 return false;
00526 }
00527
00532 function getTerms () {
00533
00534 $soap = new AIS_SOAP_WS($this);
00535 $xml = $soap->xmlFromSoap("GetSOCTerms",NULL,NULL);
00536 if ($soap->errorCount()) {
00537 $this->error("Can't get Term List from AIS SOAP Service.\n".$soap->errors());
00538 unset($soap);
00539 return false;
00540 }
00541 if ($xml !== false) {
00542
00543 $dom = new SimpleXMLElement($xml);
00544 $json = json_encode($dom);
00545 $this->cache->setCache(strtolower("/terms"), $json);
00546 unset($dom);
00547 unset($xml);
00548 return true;
00549 }
00550 $this->error("Can't populate $rest_args");
00551 return false;
00552 }
00553
00564 function eventLoop($get,$post,$session,$server,$file) {
00565 if (isset($server['PATH_INFO'])) {
00566 $this->_restParse($server['PATH_INFO']);
00567 } else {
00568 $rest_args = "/help";
00569 $this->_restParse("/help");
00570 }
00571
00572 switch($this->service) {
00573 case 'session':
00574 $term = $this->get("active_term");
00575 $session = $this->get("active_session");
00576
00577 $uri = "/session/".$session."/".$term;
00578 if ($this->get("cache_replace")) {
00579 $this->getSession($session, $term);
00580 }
00581 $this->content = $this->cache->getCache(strtolower($uri));
00582 if ($this->content === false) {
00583
00584 $this->getSession($session, $term);
00585 $this->content = $this->cache->getCache(strtolower($uri));
00586 if ($this->content === false) {
00587 $this->content = $this->errors();
00588 }
00589 }
00590 break;
00591 case 'classes':
00592 $term = $this->get("active_term");
00593 $dept = $this->get("active_dept");
00594
00595 $uri = "/classes/".$dept."/".$term;
00596 if ($this->get("cache_replace")) {
00597 $this->getClasses($dept, $term);
00598 }
00599 $this->content = $this->cache->getCache($uri);
00600 if ($this->content === false) {
00601
00602 $this->getClasses($dept, $term);
00603 $this->content = $this->cache->getCache($uri);
00604 if ($this->content === false) {
00605 $this->content = $this->errors("ERROR: can't read cache for " . $dept . ' ' . $term);
00606 }
00607 }
00608 break;
00609 case 'departments':
00610 $term = $this->get("active_term");
00611
00612 $uri = "/departments/".$term;
00613 if ($this->get("cache_replace")) {
00614 $this->getDepartments($term);
00615 }
00616 $this->content = $this->cache->getCache($uri);
00617 if ($this->content === false) {
00618 $this->getDepartments($term);
00619 $this->content = $this->cache->getCache($uri);
00620 if ($this->content === false) {
00621 $this->content = $this->errors();
00622 }
00623 }
00624 break;
00625 case 'terms':
00626 $uri = "/terms";
00627 if ($this->get("cache_replace")) {
00628 $this->getTerms();
00629 }
00630 $this->content = $this->cache->getCache($uri);
00631 if ($this->content === false) {
00632 $this->getTerms();
00633 $this->content = $this->cache->getCache($uri);
00634 if ($this->content === false) {
00635 $this->content = $this->errors();
00636 }
00637 }
00638 break;
00639 case 'bio':
00640 $eid = $this->get("eid");
00641 $uri = "/bio/".$this->get("eid");
00642 if ($this->get("cache_replace")) {
00643
00644 $bio_url = $this->getBioUrl($eid);
00645 $bio_url !== false ? $this->cache->setCache(strtolower($uri), $bio_url) : $this->error("Can't find Bio URL");
00646 }
00647 $this->content = $this->cache->getCache($uri);
00648 if ($this->content === false) {
00649 $bio_url = $this->getBioUrl($eid);
00650 $bio_url !== false ? $this->cache->setCache(strtolower($uri), $bio_url) : $this->error("Can't find Bio URL");
00651 if ($this->errorCount() == 0) {
00652 $this->content = $this->cache->getCache(strtolower($uri));
00653 } else {
00654 $this->content = $this->errors();
00655 }
00656 }
00657 break;
00658 case "booklist":
00659 $section = $this->get("section");
00660 $term = $this->get('active_term');
00661 $uri = "/booklist/".$section.'/'.$term;
00662 if ($this->get("cache_replace")) {
00663 $booklist_content = $this->getBooklist($section, $term);
00664 $booklist_content !== false ? $this->cache->setCache(strtolower($uri), $booklist_content) : '';
00665 }
00666 $this->content = $this->cache->getCache($uri);
00667 if ($this->content === false) {
00668 $booklist_content = $this->getBooklist($section, $term);
00669 $booklist_content !== false ? $this->cache->setCache(strtolower($uri), $booklist_content) : '';
00670 if ($this->errorCount() == 0) {
00671 $this->content = $this->cache->getCache(strtolower($uri));
00672 } else {
00673 $this->content = $this->errors();
00674 }
00675 }
00676 break;
00677 case "";
00678 case 'help':
00679 break;
00680 default:
00681 $this->error ("'".$this->service."' not supported.");
00682 break;
00683 }
00684 if ($this->errorCount() == 0) {
00685 return true;
00686 }
00687 return false;
00688 }
00689
00694 function contentType() {
00695 if (isset($this->content_type)) {
00696 return "Content-Type: ".$this->content_type;
00697 }
00698 return "Content-Type: text/plain";
00699 }
00700
00706 function render() {
00707 if (isset($this->content)) {
00708 return $this->content;
00709 }
00710 return false;
00711 }
00712
00717 function help() {
00718 $soc_uri = SOC_Widget::get('soc_uri');
00719 $content=<<<EOF
00720 <h1>USC - ITS Web services</h1>
00721 <h2>Schedule of Classes Web Services API</h2>
00722 <p />
00723 <h3>Developer</h3>
00724 <ul>
00725 <li><a href='$soc_uri/help/README.txt'>README</a> (includes example URI)</li>
00726 <li><a href='$soc_uri/docs/html'>Source Code Documentation</a></li>
00727 </ul>
00728
00729 <p />
00730
00731 <h3>Installation and Analysis</h3>
00732 <ul>
00733 EOF;
00734
00735 $txt_files = glob(SOC_Widget::get('soc_path')."/*.txt");
00736 foreach ($txt_files as $filename) {
00737 if (strpos($filename,"README.txt") === false && strpos($filename,"Participants.txt") === false && strpos($filename,"INSTALLATION.txt") === false) {
00738 $link = str_replace(array($this->attributes['soc_path']."/"),
00739 array($this->attributes['soc_uri']."/help/"), $filename);
00740 $label = str_replace(array($this->attributes['soc_path']."/",".txt","_"),array("",""," "),$filename);
00741 $content .= "\t<li><a href='$link'>$label</a></li>\n";
00742 }
00743 }
00744 $content .=<<<EOF
00745 </ul>
00746
00747 <h3>AIS/REG source data</h3>
00748 <ul>
00749 <li><a href='http://cmsdev-jhh102.usc.edu/soc-ws/soc-ws.asmx'>REG/SOC SOAP service documentation</a></li>
00750 </ul>
00751
00752 EOF;
00753 return $content;
00754 }
00755 }
00756 ?>