1<?php
2
3// jsmol.php
4// Bob Hanson hansonr@stolaf.edu 1/11/2013
5//
6// 10 NOV 2018 -- print($output) should be echo($output) to prevent trailing \r\n
7// 27 MAR 2018 -- security upgrade
8// 31 MAR 2016 -- https://cactus -> https://cactus
9// 09 Nov 2015 -- bug fix for www.pdb --> www.rcsb
10// 23 Mar 2015 -- checking for missing :// in queries
11// 2 Feb 2014 -- stripped of any exec calls and image options-- this was for JSmol image option - abandoned
12// 30 Oct 2013 -- saveFile should not convert " to _
13// 30 Sep 2013 -- adjusted error handling to only report E_ERROR not E_WARNING
14// 7 Sep 2013 -- adding PHP error handling
15//
16//////// note to administrators:
17//
18// from http://us3.php.net/file_get_contents:
19//
20// A URL can be used as a filename with this function if the fopen wrappers
21// have been enabled. See fopen() for more details on how to specify the
22// filename. See the Supported Protocols and Wrappers for links to information
23// about what abilities the various wrappers have, notes on their usage, and
24// information on any predefined variables they may provide.
25///////
26//
27// Server-side Jmol delivers:
28//   simple relay for cross-domain files
29//
30//   options:
31//
32//   call
33//         "saveFile"
34//             returns posted data in "data=" with mime type "mimetype=" to file name "filename="
35//         "getInfoFromDatabase"
36//             returns XML data
37//             requires database="=" (RCSB REST service)
38//         "getRawDataFromDatabase"
39//               "_"
40//                  just use $query
41//               (anything else)
42//                  use $database.$query
43//
44//   encoding
45//         ""        no encoding (default)
46//         "base64"  BASE64-encoded binary files for Chrome synchronous AJAX
47//                      prepends ";base64," to encoded output
48//
49// simple server tests:
50//
51// http://foo.wherever/jsmol.php?call=getRawDataFromDatabase&database=_&query=http://chemapps.stolaf.edu/jmol/data/t.pdb.gz
52// http://goo.wherever/jsmol.php?call=getRawDataFromDatabase&database=_&query=http://chemapps.stolaf.edu/jmol/data/t.pdb.gz&encoding=base64
53
54
55$myerror = "";
56
57function handleError($severity, $msg, $filename, $linenum) {
58  global $myerror;
59  switch($severity) {
60  case E_ERROR:
61    $myerror = "PHP error:$severity $msg $filename $linenum";
62    break;
63  }
64  return true;
65}
66
67set_error_handler("handleError");
68
69function getValueSimple($json, $key, $default) {
70 if ($json == "") {
71	$val = $_REQUEST[$key];
72 } else {
73 // just do a crude check for "key"..."value"  -- nothing more than that;
74 // only for very simple key/value pairs; mostly because we don't have the JSON
75 // module set up for our server.
76
77	list($junk,$info) = explode('"'.$key.'"', $json, 2);
78	list($junk,$val) = explode('"', $info, 3);
79	if ($val == "") {
80		$val = str_replace('"','_',$_REQUEST[$key]);
81	}
82 }
83 if ($val == "") {
84   $val = $default;
85 }
86 return $val;
87}
88
89if ($_GET['isform']=="true") {
90	$values = "";
91} else {
92	$values= file_get_contents("php://input");
93}
94$encoding = getValueSimple($values, "encoding", "");
95$call = getValueSimple($values, "call", "getRawDataFromDatabase");
96$query = getValueSimple($values, "query", "https://cactus.nci.nih.gov/chemical/structure/ethanol/file?format=sdf&get3d=True");
97$database = getValueSimple($values, "database", "_");
98$test = getValueSimple($values,"test","");
99$imagedata = "";
100$contentType = "";
101$output = "";
102$isBinary = false;
103$filename = "";
104
105if ($call == "getInfoFromDatabase") {
106  // TODO: add PDBe annotation business here
107	if ($database == '=') {
108		$restQueryUrl = "http://www.rcsb.org/pdb/rest/search";
109		$restReportUrl = "http://www.rcsb.org/pdb/rest/customReport";
110		$xml = "<orgPdbQuery><queryType>org.pdb.query.simple.AdvancedKeywordQuery</queryType><description>Text Search</description><keywords>$query</keywords></orgPdbQuery>";
111		$context = stream_context_create(array('http' => array(
112			'method' => 'POST',
113			'header' => 'Content-Type: application/x-www-form-urlencoded',
114			'content' => $xml))
115		);
116		$output = file_get_contents($restQueryUrl, false, $context);
117		$n = strlen($output)/5;
118		if ($n == 0) {
119			$output = "ERROR: \"$query\" not found";
120		} else {
121			if (strlen($query) == 4 && $n != 1) {
122				$QQQQ = strtoupper($query);
123				if (strpos("123456789", substr($QQQQ, 0, 1)) == 0 && strpos($output, $QQQQ) > 0) {
124					$output = "$QQQQ\n".$output.str_replace("$QQQQ\n", "",$output);
125				}
126			}
127			if ($n > 50) {
128				$output = substr($output, 0, 250);
129			}
130			$output = str_replace("\n",",",$output);
131			//http://www.rcsb.org/pdb/rest/customReport?pdbids=1crn,1d66,1blu,&customReportColumns=structureId,structureTitle
132			$output = $restReportUrl."?pdbids=".$output."&customReportColumns=structureId,structureTitle";
133			$output = "<result query=\"$query\" count=\"$n\">".file_get_contents($output)."</result>";
134		}
135	} else {
136	  $myerror = "jsmol.php cannot use $call with $database";
137	}
138
139} else if ($call == "getRawDataFromDatabase") {
140	$isBinary = (strpos($query, ".gz") >= 0);
141		if ($database != "_")
142			$query = $database.$query;
143		if (strpos(strtolower($query), 'https://') !== 0 && strpos(strtolower($query), 'http://') !== 0) {
144      $output = "invalid url";
145    } else if (strpos($query, '?POST?') > 0) {
146			list($query,$data) = explode('?POST?', $query, 2);
147			$context = stream_context_create(array('http' => array(
148				'method' => 'POST',
149				'header' => 'Content-Type: application/x-www-form-urlencoded',
150				'content' => $data))
151			);
152			$output = file_get_contents($query, false, $context);
153		} else {
154  		$output = file_get_contents($query);
155      if ($test != "") {
156        $output = $query."<br>".$output;
157      }
158		}
159} else if ($call == "saveFile") {
160	$imagedata = $_REQUEST["data"];//getValueSimple($values, "data", ""); don't want to convert " to _ here
161	$filename = getValueSimple($values, "filename", "");
162	$contentType = getValueSimple($values, "mimetype", "application/octet-stream");
163	if ($encoding == "base64") {
164		$imagedata = base64_decode($imagedata);
165		$encoding = "";
166	}
167} else {
168	$myerror = "jsmol.php unrecognized call: $call";
169}
170
171ob_start();
172
173 if ($myerror != "") {
174   $output = $myerror;
175 } else {
176   if ($imagedata != "") {
177  	$output = $imagedata;
178  	header('Content-Type: '.$contentType);
179  	if ($filename != "") {
180  	  header('Content-Description: File Transfer');
181  		header("Content-Disposition: attachment; filename=\"$filename\"");
182      header('Content-Transfer-Encoding: binary');
183      header('Expires: 0');
184      header('Cache-Control: must-revalidate');
185      header('Pragma: public');
186  	}
187   } else {
188  	header('Access-Control-Allow-Origin: *');
189  	if ($isBinary) {
190  		header('Content-Type: text/plain; charset=x-user-defined');
191    } else if (strpos($output, '<html') > 0) {
192      header('Content-type: text/html; charset=utf-8');
193  	} else {
194  		header('Content-Type: application/json');
195  	}
196   }
197   if ($encoding == "base64") {
198  	 $output = ";base64,".base64_encode($output);
199   }
200 }
201 header('Last-Modified: '.date('r'));
202 header('Accept-Ranges: bytes');
203 header('Content-Length: '.strlen($output));
204 echo($output);
205ob_end_flush();
206?>
207
208