cdm-dataportal / modules / cdm_dataportal / cdm_api / cdm_api.module @ b5e773ef
History | View | Annotate | Download (31.7 KB)
1 |
<?php |
---|---|
2 |
// $Id$ |
3 |
|
4 |
/** |
5 |
* @file |
6 |
* Functions which are required or useful when accessing and processing CDM Data Store Webservices |
7 |
* |
8 |
* Naming conventions: |
9 |
* ---------------------- |
10 |
* |
11 |
* - all webservice access methods are prefixed with cdm_ws |
12 |
* |
13 |
* |
14 |
* Copyright (C) 2007 EDIT |
15 |
* European Distributed Institute of Taxonomy |
16 |
* http://www.e-taxonomy.eu |
17 |
*/ |
18 |
require_once ('xml2json.php'); |
19 |
require_once ('commons.php'); |
20 |
require_once ('uuids.php'); |
21 |
require_once ('webservice_uris.php'); |
22 |
require_once ('cdm_node.php'); |
23 |
|
24 |
define(DEFAULT_TAXONTREE_RANKLIMIT, '');//TODO Genus UUID |
25 |
|
26 |
|
27 |
/** |
28 |
* Implementation of hook_requirements() |
29 |
*/ |
30 |
function cdm_api_requirements() { |
31 |
|
32 |
$requirements['cdm_api'] = array( |
33 |
'title' => t('CDM API') |
34 |
); |
35 |
|
36 |
if( function_exists('curl_init') ){ |
37 |
$requirements['cdm_api']['description'] = ''; // description below title is not jet in use |
38 |
$requirements['cdm_api']['value'] = 'CURL php extension is available and will be used by the cdm api. HTTP requests thus will be up to 20x faster'; |
39 |
} else { |
40 |
$requirements['cdm_api']['value'] = 'CURL php extension is missing. If CURL lib is installed HTTP requests will be up to 20x faster'; |
41 |
} |
42 |
|
43 |
//FIXME: once _get_content_fsockopen is implemented change severity to REQUIREMENT_WARNING, |
44 |
$requirements['cdm_api']['severity'] = (function_exists('curl_init') ? REQUIREMENT_OK : REQUIREMENT_INFO); |
45 |
|
46 |
return $requirements; |
47 |
} |
48 |
|
49 |
|
50 |
/** |
51 |
* Implementation of hook_menu() |
52 |
*/ |
53 |
function cdm_api_menu($may_cache) { |
54 |
$items = array(); |
55 |
if ($may_cache) { |
56 |
$items[] = array( |
57 |
// usage: url('cdm_api/proxy/'.urlencode($content_url)."/$theme"); |
58 |
'path' => 'cdm_api/proxy', |
59 |
'callback' => 'proxy_content', |
60 |
'access' => true, |
61 |
'type' => MENU_CALLBACK, |
62 |
); |
63 |
|
64 |
$items[] = array( |
65 |
// usage: url('cdm_api/proxy/'.urlencode($content_url)."/$theme"); |
66 |
'path' => 'cdm_api/setvalue/session', |
67 |
'callback' => 'setvalue_session', |
68 |
'access' => true, |
69 |
'type' => MENU_CALLBACK, |
70 |
); |
71 |
|
72 |
} |
73 |
|
74 |
return $items; |
75 |
} |
76 |
|
77 |
/** |
78 |
* Configures the settings form for the CDM-API module. |
79 |
* |
80 |
* @return Array Drupal settings form |
81 |
*/ |
82 |
function cdm_api_settings_form(){ |
83 |
|
84 |
$form['cdm_webservice'] = array( |
85 |
'#type' => 'fieldset', |
86 |
'#title' => t('CDM Web Service'), |
87 |
'#collapsible' => FALSE, |
88 |
'#collapsed' => FALSE, |
89 |
); |
90 |
|
91 |
$form['cdm_webservice']['cdm_webservice_url'] = array( |
92 |
'#type' => 'textfield', |
93 |
'#title' => t('CDM Web Service URL'), |
94 |
'#description' => t('The URL of CDM Webservice which delivers the data to be published.'), |
95 |
'#default_value' => variable_get('cdm_webservice_url', NULL), |
96 |
); |
97 |
|
98 |
$form['cdm_webservice']['taxontree_ranklimit'] = array( |
99 |
'#type' => 'select', |
100 |
'#title' => t('Rank of highest displayed taxon'), |
101 |
'#default_value' => variable_get('taxontree_ranklimit', DEFAULT_TAXONTREE_RANKLIMIT_UUID), |
102 |
'#options' => cdm_rankVocabulary_as_option(), |
103 |
'#description' => t('The rank of the highest displayed taxon in the taxontree.'), |
104 |
); |
105 |
|
106 |
$form['cdm_webservice']['cdm_webservice_cache'] = array( |
107 |
'#type' => 'checkbox', |
108 |
'#title' => t('Enable Caching'), |
109 |
'#default_value' => variable_get('cdm_webservice_cache', 1), |
110 |
'#description' => t('Enable caching of webservice responses on simple requests, ' |
111 |
.'that is requests which only have one parameter generally a UUID or a concatenation of UUIDs') |
112 |
); |
113 |
|
114 |
$form['cdm_webservice']['proxy'] = array( |
115 |
'#type' => 'fieldset', |
116 |
'#title' => t('Proxy'), |
117 |
'#collapsible' => TRUE, |
118 |
'#collapsed' => TRUE |
119 |
); |
120 |
|
121 |
$form['cdm_webservice']['proxy']['cdm_webservice_proxy_url'] = array( |
122 |
'#type' => 'textfield', |
123 |
'#title' => t('Proxy URL'), |
124 |
'#description' => t('If this proxy url is set the cdm api tries |
125 |
to connect the web service over the given proxy server. |
126 |
Otherwise proxy usage is deactivated.'), |
127 |
'#default_value' => variable_get('cdm_webservice_proxy_url', false), |
128 |
); |
129 |
|
130 |
$form['cdm_webservice']['proxy']['cdm_webservice_proxy_port'] = array( |
131 |
'#type' => 'textfield', |
132 |
'#title' => t('Proxy Port'), |
133 |
'#default_value' => variable_get('cdm_webservice_proxy_port', '80'), |
134 |
); |
135 |
|
136 |
$form['cdm_webservice']['proxy']['cdm_webservice_proxy_usr'] = array( |
137 |
'#type' => 'textfield', |
138 |
'#title' => t('Login'), |
139 |
'#default_value' => variable_get('cdm_webservice_proxy_usr', false), |
140 |
); |
141 |
|
142 |
$form['cdm_webservice']['proxy']['cdm_webservice_proxy_pwd'] = array( |
143 |
'#type' => 'textfield', |
144 |
'#title' => t('Password'), |
145 |
'#default_value' => variable_get('cdm_webservice_proxy_pwd', false), |
146 |
); |
147 |
|
148 |
$form['cdm_webservice']['cdm_webservice_debug'] = array( |
149 |
'#type' => 'checkbox', |
150 |
'#title' => t('Debug CDM Web Service'), |
151 |
'#default_value' => variable_get('cdm_webservice_debug', 1), |
152 |
'#description' => t('Enable CDM Web Service debugging messages. Only visible for the super administrator or for users having the permission <em>administer cdm_api</em>!') |
153 |
); |
154 |
|
155 |
return $form; |
156 |
} |
157 |
|
158 |
/** |
159 |
* Implementation of hook_cron(). |
160 |
* |
161 |
* Expire outdated cache entries |
162 |
*/ |
163 |
function cdm_api_cron() { |
164 |
cache_clear_all(NULL, 'cache_cdm_ws'); |
165 |
} |
166 |
|
167 |
function cdm_api_perm() { |
168 |
return array( |
169 |
'administer cdm_api' |
170 |
); |
171 |
} |
172 |
|
173 |
// ----------------------------------------------------------- // |
174 |
|
175 |
|
176 |
/** |
177 |
* Converts an array of TagedText items into a sequence of corresponding html tags whereas |
178 |
* each item will provided with a class attribute which set to the key of the TaggedText item. |
179 |
* |
180 |
* @param array $taggedtxt |
181 |
* @param String $tag |
182 |
* @param String $glue the string by which the chained text tokens are concatenated together. |
183 |
* Default is a blank character |
184 |
* @return String of HTML |
185 |
*/ |
186 |
function cdm_taggedtext2html(array &$taggedtxt, $tag = 'span', $glue = ' ', $skiptags = array()){ |
187 |
$out = ''; |
188 |
$i = 0; |
189 |
foreach($taggedtxt as $tt){ |
190 |
if(!in_array($tt->type, $skiptags) && strlen($tt->text) > 0){ |
191 |
$out .= (strlen($out) > 0 && ++$i < count($taggedtxt)? $glue : '').'<'.$tag.' class="'.$tt->type.'">'.t($tt->text).'</'.$tag.'>'; |
192 |
} |
193 |
} |
194 |
return $out; |
195 |
} |
196 |
|
197 |
/** |
198 |
* Finds the text tagged with $$tag_type in an array of taggedText instances |
199 |
* |
200 |
* @param array $taggedtxt |
201 |
* @param string $tag_type |
202 |
* @return the text mapped by $tag_type or an empty string |
203 |
*/ |
204 |
function cdm_taggedtext_value(array &$taggedtxt = array(), $tag_type){ |
205 |
foreach($taggedtxt as $tagtxt){ |
206 |
if($tagtxt->type == $tag_type) |
207 |
return $tagtxt->text; |
208 |
} |
209 |
return ''; |
210 |
} |
211 |
|
212 |
/** |
213 |
* media Array [4] |
214 |
* representations Array [3] |
215 |
* mimeType image/jpeg |
216 |
* representationParts Array [1] |
217 |
* duration 0 |
218 |
* heigth 0 |
219 |
* size 0 |
220 |
* uri http://wp5.e-taxonomy.eu/dataportal/cichorieae/media/protolog/jpeg/Acanthocephalus_p1.jpg |
221 |
* uuid 15c687f1-f79d-4b79-992f-7ba0f55e610b |
222 |
* width 0 |
223 |
* suffix jpg |
224 |
* uuid 930b7d51-e7b6-4350-b21e-8124b14fe29b |
225 |
* title |
226 |
* uuid 17e514f1-7a8e-4daa-87ea-8f13f8742cf9 |
227 |
* |
228 |
* @param unknown_type $media |
229 |
* @param array $mimeTypes |
230 |
* @param unknown_type $width |
231 |
* @param unknown_type $height |
232 |
* @return unknown |
233 |
*/ |
234 |
function cdm_preferred_media_representations($media, array $mimeTypes, $width = 400, $height = 300){ |
235 |
/** |
236 |
|
237 |
* |
238 |
*/ |
239 |
$prefRepr = array(); |
240 |
if(!isset($media->representations[0])){ |
241 |
return $prefRepr; |
242 |
} |
243 |
|
244 |
while(count($mimeTypes) > 0){ |
245 |
// getRepresentationByMimeType |
246 |
$mimeType = array_shift($mimeTypes); |
247 |
foreach($media->representations as $representation){ |
248 |
if($representation->mimeType == $mimeType){ |
249 |
// preffered mimetype found -> erase all remaining mimetypes to end loop |
250 |
$mimeTypes = array(); |
251 |
$dwa = 0; |
252 |
// look for part with the best matching size |
253 |
foreach($representation->parts as $part){ |
254 |
$dw = $part->width * $part->height - $height * $width; |
255 |
if($dw < 0){ |
256 |
$dw *= -1; |
257 |
} |
258 |
$dwa+= $dw; |
259 |
} |
260 |
$dwa = (count($representation->parts)>0) ? $dwa / count($representation->parts) : 0; |
261 |
$prefRepr[$dwa.'_'.$mimeTypeKey] = $representation; |
262 |
} |
263 |
} |
264 |
} |
265 |
// sort |
266 |
krsort($prefRepr); |
267 |
// return |
268 |
return $prefRepr; |
269 |
} |
270 |
|
271 |
/** |
272 |
* expects an ISO 8601 time representations of a org.joda.time.Partial |
273 |
* of the form yyyy-MM-dd and returns the year as String. |
274 |
* In case the year is unknown (= ????) null is returned. |
275 |
* |
276 |
* @param ISO 8601 time representations of a org.joda.time.Partial |
277 |
* @return String |
278 |
*/ |
279 |
function partialToYear($partial){ |
280 |
if(is_string($partial)){ |
281 |
$year = substr($partial, 0, 4); |
282 |
if($year != '??'){ |
283 |
return $year; |
284 |
} |
285 |
} |
286 |
return; |
287 |
} |
288 |
/** |
289 |
* expects an ISO 8601 time representations of a org.joda.time.Partial |
290 |
* of the form yyyy-MM-dd and returns the month as String. |
291 |
* In case the month is unknown (= ???) null is returned. |
292 |
* |
293 |
* @param ISO 8601 time representations of a org.joda.time.Partial |
294 |
* @return String |
295 |
*/ |
296 |
function partialToMonth($partial){ |
297 |
if(is_string($partial)){ |
298 |
$month = substr($partial, 5, 2); |
299 |
if($month != '??'){ |
300 |
return $month; |
301 |
} |
302 |
} |
303 |
return; |
304 |
} |
305 |
/** |
306 |
* expects an ISO 8601 time representations of a org.joda.time.Partial |
307 |
* of the form yyyy-MM-dd and returns the day as String. |
308 |
* In case the day is unknown (= ???) null is returned. |
309 |
* |
310 |
* @param ISO 8601 time representations of a org.joda.time.Partial |
311 |
* @return String |
312 |
*/ |
313 |
function partialToDay($partial){ |
314 |
if(is_string($partial)){ |
315 |
$day = substr($partial, 7, 2); |
316 |
if($day != '??'){ |
317 |
return $day; |
318 |
} |
319 |
} |
320 |
return; |
321 |
} |
322 |
|
323 |
/** |
324 |
* |
325 |
* @param $uri_pattern |
326 |
* @param $pathParameters an array of path elements, or a single element |
327 |
* @param $query A query string to append to the URL. |
328 |
* @return unknown_type |
329 |
*/ |
330 |
function cdm_compose_url($uri_pattern, $pathParameters = array(), $query = NULL ){ |
331 |
|
332 |
$request_params = ''; |
333 |
$path_params = ''; |
334 |
|
335 |
/* (1) |
336 |
* substitute all place holders ($0, $1, ..) in the |
337 |
* $uri_pattern by the according element of the $pathParameters array |
338 |
*/ |
339 |
static $helperArray = array(); |
340 |
if($pathParameters && !is_array($pathParameters)){ |
341 |
$helperArray[0] = $pathParameters; |
342 |
$pathParameters = $helperArray; |
343 |
} |
344 |
|
345 |
$i = 0; |
346 |
while(strpos($uri_pattern, "$".$i) !== FALSE){ |
347 |
if(count($pathParameters) <= $i){ |
348 |
drupal_set_message('cdm_compose_url(): missing pathParameters', 'debug'); |
349 |
} |
350 |
$uri_pattern = str_replace("$".$i, rawurlencode($pathParameters[$i]), $uri_pattern); |
351 |
++$i; |
352 |
} |
353 |
|
354 |
/* (2) |
355 |
* Append all remaining element of the $pathParameters array as path elements |
356 |
*/ |
357 |
if(count($pathParameters) > $i){ |
358 |
// strip trailing slashes |
359 |
if(strrchr($uri_pattern, '/') == strlen($uri_pattern)){ |
360 |
$uri_pattern = substr($uri_pattern, 0, strlen($uri_pattern) - 1); |
361 |
} |
362 |
while(count($pathParameters) > $i){ |
363 |
$uri_pattern .= '/' . rawurlencode($pathParameters[$i]); |
364 |
++$i; |
365 |
} |
366 |
} |
367 |
|
368 |
/* (3) |
369 |
* Append the query string supplied by $query |
370 |
*/ |
371 |
if (isset($query)) { |
372 |
$uri_pattern .= (strpos($uri_pattern, '?') !== FALSE ? '&' : '?') . $query; |
373 |
} |
374 |
|
375 |
$path = $ws_name.$uri_pattern; |
376 |
|
377 |
$uri = variable_get('cdm_webservice_url', '').$path; |
378 |
return $uri; |
379 |
} |
380 |
|
381 |
|
382 |
function proxy_content($uri, $theme = null){ |
383 |
|
384 |
$args = func_get_args(); |
385 |
|
386 |
$uriEncoded = array_shift($args); |
387 |
$uri = urldecode($uriEncoded); |
388 |
$theme = array_shift($args); |
389 |
|
390 |
//find comma sepatated string in all args |
391 |
foreach($args as &$arg){ |
392 |
if(strpos($arg, ',')){ |
393 |
$arg = explode(',', $arg); |
394 |
} |
395 |
} |
396 |
|
397 |
$request_method = strtoupper($_SERVER["REQUEST_METHOD"]); |
398 |
|
399 |
if($request_method == "POST"){ |
400 |
|
401 |
$parameters = $_POST; |
402 |
|
403 |
$post_data = array(); |
404 |
foreach ($parameters as $k=>$v) |
405 |
{ |
406 |
$post_data[] = "$k=".utf8_encode($v); |
407 |
} |
408 |
$post_data = implode(',', $post_data); |
409 |
|
410 |
// testing |
411 |
$data = cdm_http_request($uri, "POST", $post_data); |
412 |
print $data; |
413 |
|
414 |
}else if(strpos($theme, '/') > 0){ // must be a mimetype |
415 |
header('Content-Type: '.$theme); |
416 |
$data = _http_request_binary($uri); |
417 |
print $data; |
418 |
exit; |
419 |
} else { |
420 |
// in all other cases perform a simple get request |
421 |
//TODO reconsider caching logic in this function |
422 |
if(!$theme){ |
423 |
// print out JSON, the cache cannot be used since it contains objects |
424 |
$data = cdm_http_request($uri); |
425 |
print $data; |
426 |
exit; |
427 |
} else { |
428 |
$obj = cdm_ws_get($uri, null, null, null, TRUE); |
429 |
array_unshift($args, $theme, $obj); |
430 |
print call_user_func_array('theme', $args); |
431 |
} |
432 |
} |
433 |
} |
434 |
|
435 |
function setvalue_session(){ |
436 |
|
437 |
if(strlen(arg(3)) > 0){ |
438 |
$keys = explode('|', arg(3)); |
439 |
} |
440 |
$val = arg(4); |
441 |
|
442 |
// prevent from malicous tags |
443 |
$val = strip_tags($val); |
444 |
|
445 |
$var = &$_SESSION; |
446 |
$i = 0; |
447 |
foreach($keys as $key){ |
448 |
$hasMoreKeys = ++$i < count($var); |
449 |
if($hasMoreKeys && (!isset($var[$key]) || !is_array($var[$key]))){ |
450 |
$var[$key] = array(); |
451 |
} |
452 |
$var = &$var[$key]; |
453 |
} |
454 |
$var = $val; |
455 |
} |
456 |
|
457 |
function uri_uriByProxy($uri, $theme = false){ |
458 |
// usage: url('cdm_api/proxy/'.urlencode($content_url)."/$theme");) |
459 |
return url('cdm_api/proxy/'.urlencode($uri).($theme?"/$theme":'')); |
460 |
} |
461 |
|
462 |
function cdm_compose_annotations_url($cdmBase){ |
463 |
|
464 |
if(!$cdmBase->uuid){ |
465 |
return; |
466 |
} |
467 |
|
468 |
$ws_base_uri = null; |
469 |
switch($cdmBase->class){ |
470 |
case 'TaxonBase': |
471 |
case 'Taxon': |
472 |
case 'Synonym': |
473 |
$ws_base_uri = CDM_WS_TAXON; |
474 |
break; |
475 |
case 'TaxonNameBase': |
476 |
case 'NonViralName': |
477 |
case 'BacterialName': |
478 |
case 'BotanicalName': |
479 |
case 'CultivarPlantName': |
480 |
case 'ZoologicalName': |
481 |
case 'ViralName': |
482 |
$ws_base_uri = CDM_WS_NAME; |
483 |
break; |
484 |
case 'Media': |
485 |
$ws_base_uri = CDM_WS_MEDIA; |
486 |
break; |
487 |
case 'ReferenceBase': |
488 |
$ws_base_uri = CDM_WS_REFERENCE; |
489 |
break; |
490 |
case 'Distribution': |
491 |
case 'TextData': |
492 |
case 'TaxonInteraction': |
493 |
case 'QuantitativeData': |
494 |
case 'IndividualsAssociation': |
495 |
case 'Distribution': |
496 |
case 'CommonTaxonName': |
497 |
case 'CategoricalData': |
498 |
$ws_base_uri = CDM_WS_DESCRIPTIONELEMENT; |
499 |
break; |
500 |
default: trigger_error('Unsupported CDM Class - no annotations available for ' . $cdmBase->class, E_USER_ERROR); |
501 |
return; |
502 |
} |
503 |
return cdm_compose_url($ws_base_uri, array($cdmBase->uuid, 'annotation')); |
504 |
} |
505 |
|
506 |
/** |
507 |
* Enter description here... |
508 |
* |
509 |
* @param String $resourceURI |
510 |
* @param pageSize |
511 |
* the maximum number of entities returned per page (can be null |
512 |
* to return all entities in a single page) |
513 |
* @param pageNumber |
514 |
* the number of the page to be returned, the first page has the |
515 |
* pageNumber = 1 |
516 |
* @return unknown |
517 |
*/ |
518 |
function cdm_ws_page($resourceURI, $pageSize, $pageNumber){ |
519 |
return cdm_ws_get($resourceURI, null, queryString(array("page" => $pageNumber, 'pageSize'=>$pageSize))); |
520 |
} |
521 |
|
522 |
//function cdm_ws_taxonomy_compose_resourcePath($path = null){ |
523 |
// $viewrank = _cdm_taxonomy_compose_viewrank(); |
524 |
// return CDM_WS_PORTAL_TAXONOMY . '/' . ($viewrank ? $viewrank : '' ) . ($path ? '/' . $path : '') ; |
525 |
//} |
526 |
|
527 |
|
528 |
/** |
529 |
* Enter description here... |
530 |
* |
531 |
* @param unknown_type $secUuid |
532 |
* @param unknown_type $path |
533 |
* @return unknown |
534 |
*/ |
535 |
function cdm_compose_taxonomy_path($taxonUuid = null){ |
536 |
//return cdm_ws_get(cdm_ws_taxonomy_compose_resourcePath($path)); |
537 |
|
538 |
$viewUuid = variable_get('cdm_taxonomictree_uuid', false); |
539 |
$rankUuid = variable_get('taxontree_ranklimit', DEFAULT_TAXONTREE_RANKLIMIT); |
540 |
|
541 |
if($taxonUuid){ |
542 |
return cdm_compose_url(CDM_WS_PORTAL_TAXONOMY_CHILDNODES_OF_TAXON, array($viewUuid, $taxonUuid)); |
543 |
} else { |
544 |
if($rankUuid){ |
545 |
return cdm_compose_url(CDM_WS_PORTAL_TAXONOMY_CHILDNODES_AT_RANK, array($viewUuid, $rankUuid)); |
546 |
} else { |
547 |
return cdm_compose_url(CDM_WS_PORTAL_TAXONOMY, array($viewUuid)); |
548 |
} |
549 |
} |
550 |
} |
551 |
|
552 |
function cdm_ws_taxonomy($taxonUuid = null){ |
553 |
//return cdm_ws_get(cdm_ws_taxonomy_compose_resourcePath($path)); |
554 |
return cdm_ws_get(cdm_compose_taxonomy_path($taxonUuid), null, null, null, TRUE); |
555 |
} |
556 |
|
557 |
/** |
558 |
* Enter description here... |
559 |
* |
560 |
* @param UUID $secUuid |
561 |
* @param String $path |
562 |
* @return unknown |
563 |
*/ |
564 |
function cdm_ws_taxonomy_pathFromRoot($taxonUuid){ |
565 |
//$viewrank = _cdm_taxonomy_compose_viewrank(); |
566 |
//return cdm_ws_get(CDM_WS_PORTAL_TAXONOMY . ($viewrank ? '/' .$viewrank : '' ) . '/' . $path . '/path' ); |
567 |
|
568 |
$viewUuid = variable_get('cdm_taxonomictree_uuid', false); |
569 |
$rankUuid = variable_get('taxontree_ranklimit', DEFAULT_TAXONTREE_RANKLIMIT); |
570 |
|
571 |
if($rankUuid){ |
572 |
return cdm_ws_get(CDM_WS_PORTAL_TAXONOMY_PATH_FROM_TO_RANK, array($viewUuid, $taxonUuid, $rankUuid)); |
573 |
} else { |
574 |
return cdm_ws_get(CDM_WS_PORTAL_TAXONOMY_PATH_FROM, array($viewUuid, $taxonUuid)); |
575 |
} |
576 |
} |
577 |
|
578 |
/** |
579 |
* Enter description here... |
580 |
* |
581 |
* @param UUID $viewUuid |
582 |
* @param String $rank |
583 |
* @return unknown |
584 |
*/ |
585 |
//function _cdm_taxonomy_compose_viewrank(){ |
586 |
// $viewUuid = variable_get('cdm_taxonomictree_uuid', false); |
587 |
// if(!$viewUuid){ |
588 |
// return; |
589 |
// } |
590 |
// $rank = variable_get('taxontree_ranklimit', DEFAULT_TAXONTREE_RANKLIMIT); |
591 |
// return $viewUuid . (empty($rank) ? '' : ','.$rank); |
592 |
//} |
593 |
|
594 |
|
595 |
function cdm_rankVocabulary_as_option(){ |
596 |
global $rankVocabularyOptions; |
597 |
if(!$rankVocabularyOptions){ |
598 |
$vocab = cdm_ws_get(CDM_WS_TERMVOCABULARY, UUID_RANK); |
599 |
$rankVocabularyOptions = array(); |
600 |
foreach($vocab->terms as $term){ |
601 |
$rankVocabularyOptions[$term->uuid] = t($term->representation_L10n); |
602 |
} |
603 |
array_reverse($rankVocabularyOptions); |
604 |
} |
605 |
return $rankVocabularyOptions; |
606 |
} |
607 |
|
608 |
|
609 |
function cdm_ws_descriptions_by_featuretree($featureTree, $descriptions, $isDescriptionsSeparated = false){ |
610 |
|
611 |
if(!$featureTree){ |
612 |
drupal_set_message('No \'FeatureTree\' has been set so far. ' |
613 |
.'In order to see the species profiles of your taxa, please select a \'FeatureTree\' in the '.l('CDM Dataportal Settings', 'admin/settings/cdm_dataportal/general'), 'warning'); |
614 |
return false; |
615 |
} |
616 |
|
617 |
$mergedTrees = array(); |
618 |
|
619 |
if($isDescriptionsSeparated){ |
620 |
// merge any description into a sparate feature tree |
621 |
foreach($descriptions as $desc){ |
622 |
$mergedNodes = _mergeFeatureTreeDesciptions($featureTree->root->children, $desc->elements); |
623 |
|
624 |
$mergedTree = clone $featureTree; |
625 |
$mergedTree->root->children = $mergedNodes; |
626 |
$mergedTrees[] = $mergedTree; |
627 |
} |
628 |
} else { |
629 |
// combine all descripions into one feature tree |
630 |
foreach($descriptions as $desc){ |
631 |
$mergedNodes = _mergeFeatureTreeDesciptions($featureTree->root->children, $desc->elements); |
632 |
$featureTree->root->children = $mergedNodes; |
633 |
} |
634 |
$mergedTrees[] = $featureTree; |
635 |
} |
636 |
|
637 |
return $mergedTrees; |
638 |
} |
639 |
|
640 |
function _mergeFeatureTreeDesciptions($featureNodes, $descriptionElements){ |
641 |
|
642 |
foreach($featureNodes as &$node){ |
643 |
|
644 |
// append corresponding elements to an additional node field: $node->descriptionElements |
645 |
foreach($descriptionElements as $element){ |
646 |
if($element->feature->uuid == $node->feature->uuid){ |
647 |
if(!isset($node->descriptionElements)){ |
648 |
$node->descriptionElements = array(); |
649 |
} |
650 |
$node->descriptionElements[] = $element; |
651 |
} |
652 |
} |
653 |
|
654 |
// recurse into node children |
655 |
if(is_array($node->children)){ |
656 |
foreach($node->children as $nodes){ |
657 |
$mergedChildNodes = _mergeFeatureTreeDesciptions($nodes, $descriptionElements); |
658 |
$node->children = $mergedChildNodes; |
659 |
} |
660 |
} |
661 |
|
662 |
} |
663 |
return $featureNodes; |
664 |
} |
665 |
|
666 |
|
667 |
/** |
668 |
* Send a HTTP GET request to the RESTService and deserializes |
669 |
* and returns the response as object. |
670 |
* The response objects coming from the webservice configured in the 'cdm_webservice_url' variable |
671 |
* are beeing cached in a level 1 (L1) and or in a level 2 (L2) cache. |
672 |
* |
673 |
* Since the L1 cache is implemented as static variable of the cdm_ws_get() function, |
674 |
* this cache persists only per each single page executiuon. Any object coming from the webservice is stored into it by default. |
675 |
* Incontrast to this default cacheich mechanism the L2 cache only is used if the 'cdm_webservice_cache' varialby is set to TRUE |
676 |
* which can be set using the modules administrative settings section. Object stored in this L2 cache are serialized and stored |
677 |
* using the drupal cache in the '{prefix}cache_cdm_ws' cache table. So the objects are sored in a database will persist as |
678 |
* log as the drupal cache is not beeing cleared and are availabel across multiple sript executions. |
679 |
* |
680 |
* @param $uri |
681 |
* @param $pathParameters an array of path parameters |
682 |
* @param $query A query string to be appended to the URL. |
683 |
* @param $method the HTTP method to use, valuid values are "GET" or "POST"; |
684 |
* @param $absoluteURI |
685 |
* @return unknown_type |
686 |
*/ |
687 |
function cdm_ws_get($uri, $pathParameters = array(), $query = null, $method="GET", $absoluteURI = false){ |
688 |
|
689 |
static $cacheL1; |
690 |
if(!isset($cacheL1)){ |
691 |
$cacheL1 = array(); |
692 |
} |
693 |
|
694 |
// transform the given uri path or patthern into a proper webservice uri |
695 |
if(!$absoluteURI){ |
696 |
$uri = cdm_compose_url($uri, $pathParameters, $query); |
697 |
} |
698 |
|
699 |
$is_cdm_ws_uri = _is_cdm_ws_uri($uri); |
700 |
$use_cacheL2 = variable_get('cdm_webservice_cache', 1); |
701 |
|
702 |
$cacheL1_obj = $cacheL1[$uri]; |
703 |
//print $cacheL1_obj; |
704 |
$set_cacheL1 = false; |
705 |
if($is_cdm_ws_uri && !$cacheL1_obj){ |
706 |
$set_cacheL1 = true; |
707 |
} |
708 |
|
709 |
// only cache cdm webservice URIs |
710 |
$set_cacheL2 = $use_cacheL2 && $is_cdm_ws_uri && $set_cacheL1; |
711 |
$cacheL2_entry = false; |
712 |
|
713 |
if($use_cacheL2){ |
714 |
// try to get object from cacheL2 |
715 |
$cacheL2_entry = cache_get($uri, 'cache_cdm_ws'); |
716 |
} |
717 |
|
718 |
if($cacheL1_obj){ |
719 |
// |
720 |
// The object has been found in the L1 cache |
721 |
// |
722 |
$obj = $cacheL1_obj; |
723 |
_add_debugMessageStr('Using cacheL1 for: '.$uri); |
724 |
} else if($cacheL2_entry) { |
725 |
// |
726 |
// The object has been found in the L2 cache |
727 |
// |
728 |
$obj = unserialize($cacheL2_entry->data); |
729 |
if(variable_get('cdm_webservice_debug', 1) && user_access('administer')){ |
730 |
_add_status_message_toggler(); |
731 |
_add_debugMessageStr('Using cacheL2 for: '.$uri); |
732 |
} |
733 |
} else { |
734 |
// |
735 |
// Get the object from the webservice and cache it |
736 |
// |
737 |
$time_get_start = microtime(true); |
738 |
// request data from webservice JSON or XML |
739 |
$datastr = cdm_http_request($uri, $method); |
740 |
$time_get = microtime(true) - $time_get_start; |
741 |
|
742 |
$time_parse_start = microtime(true); |
743 |
// parse data and create object |
744 |
$obj = cdm_load_obj($datastr); |
745 |
|
746 |
$time_parse = microtime(true) - $time_parse_start; |
747 |
if(variable_get('cdm_webservice_debug', 1) && user_access('administer')){ |
748 |
$success_msg = $obj || $datastr == "[]" ? 'valid':'invalid'; |
749 |
_add_debugMessage($uri, $time_get, $time_parse, strlen($datastr), $success_msg); |
750 |
} |
751 |
if($set_cacheL2) { |
752 |
// store the object in cacheL2 |
753 |
cache_set($uri, 'cache_cdm_ws', serialize($obj), CACHE_TEMPORARY); |
754 |
} |
755 |
|
756 |
} |
757 |
if($obj){ |
758 |
// store the object in cacheL1 |
759 |
if($set_cacheL1) { |
760 |
$cacheL1[$uri] = $obj; |
761 |
} |
762 |
} |
763 |
|
764 |
return $obj; |
765 |
} |
766 |
function _add_debugMessageStr($msg){ |
767 |
_add_status_message_toggler(); |
768 |
drupal_set_message($message, 'debug'); |
769 |
|
770 |
} |
771 |
function _add_debugMessage($uri, $time_get, $time_parse, $datasize, $success_msg){ |
772 |
|
773 |
static $cummulated_time_parse; |
774 |
static $cummulated_time_get; |
775 |
_add_status_message_toggler(); |
776 |
|
777 |
$cummulated_time_get += $time_get; |
778 |
$cummulated_time_parse += $time_parse; |
779 |
|
780 |
// decompose uri into path and query element |
781 |
$uri_parts = explode("?", $uri); |
782 |
if(count($uri_parts) == 2){ |
783 |
$path = $uri_parts[0]; |
784 |
$query = $uri_parts[1]; |
785 |
} else { |
786 |
$path = $uri; |
787 |
} |
788 |
|
789 |
$message = '<span class="uri">'.$uri.'</span><br />'; |
790 |
$message .= '[fetched in: '.sprintf('%3.3f', $time_get).'s('.sprintf('%3.3f', $cummulated_time_get).'s); '; |
791 |
$message .= 'parsed in '.sprintf('%3.3f', $time_parse).' s('.sprintf('%3.3f', $cummulated_time_parse).'s); '; |
792 |
$message .= 'size:'.sprintf('%3.1f', ($datasize / 1024)).' kb of '.$success_msg.' data: '; |
793 |
if(_is_cdm_ws_uri($path)){ |
794 |
$message .= '<a href="'.url($path.'.xml', $query).'" target="data" class="'.$success_msg.'">xml</a>,'; |
795 |
$message .= '<a href="'.url($path.'.json', $query).'" target="data" class="'.$success_msg.'">json</a>'; |
796 |
} else { |
797 |
$message .= '<a href="'.url($path, $query).'" target="data" class="'.$success_msg.'">open</a>'; |
798 |
} |
799 |
$message .= '] '; |
800 |
drupal_set_message($message, 'debug'); |
801 |
|
802 |
} |
803 |
|
804 |
|
805 |
function cdm_load_obj($datastr){ |
806 |
|
807 |
// NOTICE: the cdm dataportal currently does not support xml so the line below are commented out |
808 |
/* |
809 |
// if the web service delivers XML convert it into json |
810 |
if(variable_get('cdm_webservice_type', 'json') == 'xml'){ |
811 |
$datastr = xml2json::transformXmlStringToJson($datastr); |
812 |
} |
813 |
*/ |
814 |
|
815 |
$obj = json_decode($datastr); |
816 |
|
817 |
if(!(is_object($obj) || is_array($obj)) ){ |
818 |
ob_start(); |
819 |
$obj_dump = ob_get_contents(); |
820 |
ob_clean(); |
821 |
return false; |
822 |
} |
823 |
|
824 |
return $obj; |
825 |
} |
826 |
|
827 |
/** |
828 |
* |
829 |
* @param $uri |
830 |
* @param $method the HTTP method to use, valuid values are "GET" or "POST"; efaults to "GET" even if null, |
831 |
* false or any invalid value is supplied. |
832 |
* @param $parameters |
833 |
* @param $header |
834 |
* @return the response data |
835 |
*/ |
836 |
function cdm_http_request($uri, $method="GET", $parameters = array(), $header = false){ |
837 |
global $locale; // drupal variable containing the current locale i.e. language |
838 |
|
839 |
if($method != "GET" && $method != "POST"){ |
840 |
$method = "GET"; |
841 |
} |
842 |
|
843 |
$header = array(); |
844 |
if(!$header && _is_cdm_ws_uri($uri)){ |
845 |
$header['Accept'] = (variable_get('cdm_webservice_type', 'json') == 'json' ? 'application/json' : 'text/xml'); |
846 |
$header['Accept-Language'] = $locale; |
847 |
$header['Accept-Charset'] = 'UTF-8'; |
848 |
} |
849 |
|
850 |
if(false && function_exists('curl_init')){ |
851 |
// !!!!! CURL Disabled due to problems with forllowing redirects (CURLOPT_FOLLOWLOCATION=1) and safe_mode = on |
852 |
// use the CURL lib if installed it is supposed to be 20x faster |
853 |
return _http_request_using_curl($uri, $header, $method, $parameters); |
854 |
} else { |
855 |
return _http_request_using_fsockopen($uri, $header, $method, $parameters); |
856 |
} |
857 |
} |
858 |
|
859 |
function _http_request_using_fsockopen($uri, $header = array(), $method = "GET"){ |
860 |
$response = drupal_http_request($uri, $header, $method); |
861 |
return $response->data; |
862 |
} |
863 |
|
864 |
|
865 |
/** |
866 |
* Return string content from a remote file |
867 |
* |
868 |
* @param string $uri |
869 |
* @return string |
870 |
* |
871 |
* @author Luiz Miguel Axcar (lmaxcar@yahoo.com.br) |
872 |
*/ |
873 |
function _http_request_using_curl($uri, $headers = array(), $method = "GET", $parameters = array()) |
874 |
{ |
875 |
$ch = curl_init(); |
876 |
|
877 |
curl_setopt ($ch, CURLOPT_URL, $uri); |
878 |
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1); |
879 |
curl_setopt ($ch, CURLOPT_MAXREDIRS, 5); |
880 |
|
881 |
// set proxy settings |
882 |
if(variable_get('cdm_webservice_proxy_url', false)){ |
883 |
curl_setopt($ch, CURLOPT_PROXY, variable_get('cdm_webservice_proxy_url', '')); |
884 |
curl_setopt($ch, CURLOPT_PROXYPORT, variable_get('cdm_webservice_proxy_port', '80')); |
885 |
if(variable_get('cdm_webservice_proxy_usr', false)){ |
886 |
curl_setopt ($ch, CURLOPT_PROXYUSERPWD, variable_get('cdm_webservice_proxy_usr', '').':'.variable_get('cdm_webservice_proxy_pwd', '')); |
887 |
} |
888 |
} |
889 |
|
890 |
// modify headers array to be used by curl |
891 |
foreach($headers as $header_key=>$header_val){ |
892 |
$curl_headers[] = $header_key.': '.$header_val; |
893 |
} |
894 |
if(isset($curl_headers)){ |
895 |
curl_setopt ($ch, CURLOPT_HTTPHEADER, $curl_headers); |
896 |
} |
897 |
|
898 |
// set method if not default |
899 |
if($method != "GET"){ |
900 |
if($method == "POST"){ |
901 |
|
902 |
curl_setopt ($ch, CURLOPT_POST, 1); |
903 |
curl_setopt ($ch, CURLOPT_POSTFIELDS, $parameters); |
904 |
|
905 |
}else{ |
906 |
// other obscure http methods get passed to curl directly |
907 |
// TODO generic parameter/body handling |
908 |
curl_setopt ($ch, CURLOPT_CUSTOMREQUEST, $method); |
909 |
} |
910 |
} |
911 |
|
912 |
ob_start(); |
913 |
curl_exec($ch); |
914 |
$info = curl_getinfo($ch); |
915 |
if(curl_errno($ch)){ |
916 |
watchdog('CDM_API', '_http_request_curl() - '.curl_error($ch).'; REQUEST-METHOD:'.$method.' URL: '.substr($uri.' ', 0, 150), WATCHDOG_ERROR); |
917 |
if(variable_get('cdm_webservice_debug', 1) && user_access('administer') ){ |
918 |
drupal_set_message('_http_request_curl() - '.curl_error($ch).'; REQUEST-METHOD:'.$method.' URL: '.substr($uri.' ', 0, 150), 'error'); |
919 |
} |
920 |
} |
921 |
curl_close ($ch); |
922 |
$string = ob_get_contents(); |
923 |
ob_end_clean(); |
924 |
|
925 |
return $string; |
926 |
} |
927 |
|
928 |
function cdm_api_secref_cache_prefetch(&$secUuids){ |
929 |
global $secref_cache; |
930 |
if(!is_array($secref_cache)){ |
931 |
$secref_cache = array(); |
932 |
} |
933 |
$uniqueUuids = array_unique($secUuids); |
934 |
$i = 0; |
935 |
$param = ''; |
936 |
while($i++ < count($uniqueUuids)){ |
937 |
$param .= $secUuids[$i].','; |
938 |
if(strlen($param) + 37 > 2000){ |
939 |
_cdm_api_secref_cache_add($param); |
940 |
$param = ''; |
941 |
} |
942 |
} |
943 |
if($param){ |
944 |
_cdm_api_secref_cache_add($param); |
945 |
} |
946 |
} |
947 |
|
948 |
function cdm_api_secref_cache_get($secUuid){ |
949 |
global $secref_cache; |
950 |
if(!is_array($secref_cache)){ |
951 |
$secref_cache = array(); |
952 |
} |
953 |
if(!array_key_exists($secUuid, $secref_cache)){ |
954 |
_cdm_api_secref_cache_add($secUuid); |
955 |
} |
956 |
return $secref_cache[$secUuid]; |
957 |
} |
958 |
|
959 |
function cdm_api_secref_cache_clear(){ |
960 |
global $secref_cache; |
961 |
$secref_cache = array(); |
962 |
} |
963 |
|
964 |
function _cdm_api_secref_cache_add($secUuidsStr){ |
965 |
global $secref_cache; |
966 |
$ref = cdm_ws_get(CDM_WS_REFERENCE, $secUuidsStr); |
967 |
// batch fetching not jet reimplemented thus: |
968 |
/*$assocRefSTOs = array(); |
969 |
if($refSTOs) { |
970 |
foreach($refSTOs as $ref){ |
971 |
$assocRefSTOs[$ref->uuid] = $ref; |
972 |
} |
973 |
$secref_cache = array_merge($secref_cache, $assocRefSTOs); |
974 |
}*/ |
975 |
$secref_cache[$ref->uuid] = $ref; |
976 |
} |
977 |
|
978 |
function _is_cdm_ws_uri($uri){ |
979 |
return str_beginsWith($uri, variable_get('cdm_webservice_url', '#EMPTY#')); |
980 |
} |
981 |
|
982 |
function queryString($elements) { |
983 |
$query = ''; |
984 |
foreach($elements as $key=>$value){ |
985 |
if(is_array($value)){ |
986 |
foreach($value as $v){ |
987 |
$query .= (strlen($query) > 0 ? '&' : '').$key.'='.urlencode($v); |
988 |
} |
989 |
} else{ |
990 |
$query .= (strlen($query) > 0 ? '&' : '').$key.'='.urlencode($value); |
991 |
} |
992 |
} |
993 |
return $query; |
994 |
} |
995 |
|
996 |
/** |
997 |
* implementation of the magic method __clone to allow deep cloning of objects and arrays |
998 |
*/ |
999 |
function __clone(){ |
1000 |
foreach($this as $name => $value){ |
1001 |
if(gettype($value)=='object' || gettype($value)=='array'){ |
1002 |
$this->$name= clone($this->$name); |
1003 |
} |
1004 |
} |
1005 |
} |
1006 |
|
1007 |
/** |
1008 |
* Make a complete deep copy of an array replacing |
1009 |
* references with deep copies until a certain depth is reached |
1010 |
* ($maxdepth) whereupon references are copied as-is... |
1011 |
* [From http://us3.php.net/manual/en/ref.array.php] |
1012 |
* @param $array |
1013 |
* @param $copy |
1014 |
* @param $maxdepth |
1015 |
* @param $depth |
1016 |
* @return unknown_type |
1017 |
*/ |
1018 |
function array_deep_copy (&$array, &$copy, $maxdepth=50, $depth=0) { |
1019 |
if($depth > $maxdepth) { $copy = $array; return; } |
1020 |
if(!is_array($copy)) $copy = array(); |
1021 |
foreach($array as $k => &$v) { |
1022 |
if(is_array($v)) { array_deep_copy($v,$copy[$k],$maxdepth,++$depth); |
1023 |
} else { |
1024 |
$copy[$k] = $v; |
1025 |
} |
1026 |
} |
1027 |
} |
1028 |
|
1029 |
/** |
1030 |
* Implementation of theme_status_messages($display = NULL) |
1031 |
* @see includes/theme.inc |
1032 |
* |
1033 |
* @param $display |
1034 |
* @return unknown_type |
1035 |
*/ |
1036 |
function _add_status_message_toggler() { |
1037 |
static $isAdded; |
1038 |
if(!$isAdded){ |
1039 |
|
1040 |
drupal_add_js( |
1041 |
'$(document).ready(function(){ |
1042 |
|
1043 |
$(\'.messages.debug\').before( \'<h6 class="messages_toggler debug">Debug Messages (klick to toggle)</h6>\' ); |
1044 |
$(\'.messages_toggler\').click(function(){ |
1045 |
$(this).next().slideToggle(\'fast\'); |
1046 |
return false; |
1047 |
}).next().hide(); |
1048 |
|
1049 |
});' |
1050 |
, 'inline'); |
1051 |
$isAdded = TRUE; |
1052 |
} |
1053 |
} |