danielebarchiesi@4: danielebarchiesi@4: * @license http://arc.semsol.org/license danielebarchiesi@4: * @package ARC2 danielebarchiesi@4: * @version 2010-11-16 danielebarchiesi@4: */ danielebarchiesi@4: danielebarchiesi@4: ARC2::inc('Class'); danielebarchiesi@4: danielebarchiesi@4: class ARC2_SPARQLScriptProcessor extends ARC2_Class { danielebarchiesi@4: danielebarchiesi@4: function __construct($a, &$caller) { danielebarchiesi@4: parent::__construct($a, $caller); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function __init() { danielebarchiesi@4: parent::__init(); danielebarchiesi@4: $this->max_operations = $this->v('sparqlscript_max_operations', 0, $this->a); danielebarchiesi@4: $this->max_queries = $this->v('sparqlscript_max_queries', 0, $this->a); danielebarchiesi@4: $this->return = 0; danielebarchiesi@4: $this->script_hash = ''; danielebarchiesi@4: $this->env = array( danielebarchiesi@4: 'endpoint' => '', danielebarchiesi@4: 'vars' => array(), danielebarchiesi@4: 'output' => '', danielebarchiesi@4: 'operation_count' => 0, danielebarchiesi@4: 'query_count' => 0, danielebarchiesi@4: 'query_log' => array() danielebarchiesi@4: ); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function reset() { danielebarchiesi@4: $this->__init(); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processScript($s) { danielebarchiesi@4: $this->script_hash = abs(crc32($s)); danielebarchiesi@4: $parser = $this->getParser(); danielebarchiesi@4: $parser->parse($s); danielebarchiesi@4: $blocks = $parser->getScriptBlocks(); danielebarchiesi@4: if ($parser->getErrors()) return 0; danielebarchiesi@4: foreach ($blocks as $block) { danielebarchiesi@4: $this->processBlock($block); danielebarchiesi@4: if ($this->return) return 0; danielebarchiesi@4: if ($this->getErrors()) return 0; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getResult() { danielebarchiesi@4: if ($this->return) { danielebarchiesi@4: return $this->getVarValue('__return_value__'); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: return $this->env['output']; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function getParser() { danielebarchiesi@4: ARC2::inc('SPARQLScriptParser'); danielebarchiesi@4: return new ARC2_SPARQLScriptParser($this->a, $this); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function setVar($name, $val, $type = 'literal', $meta = '') { danielebarchiesi@4: /* types: literal, var, rows, bool, doc, http_response, undefined, ? */ danielebarchiesi@4: $this->env['vars'][$name] = array( danielebarchiesi@4: 'value_type' => $type, danielebarchiesi@4: 'value' => $val, danielebarchiesi@4: 'meta' => $meta ? $meta : array() danielebarchiesi@4: ); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getVar($name) { danielebarchiesi@4: return isset($this->env['vars'][$name]) ? $this->env['vars'][$name] : ''; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getVarValue($name) { danielebarchiesi@4: return ($v = $this->getVar($name)) ? (isset($v['value']) ? $v['value'] : $v ) : ''; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function replacePlaceholders($val, $context = '', $return_string = 1, $loop = 0) { danielebarchiesi@4: do { danielebarchiesi@4: $old_val = $val; danielebarchiesi@4: if (preg_match_all('/(\{(?:[^{}]+|(?R))*\})/', $val, $m)) { danielebarchiesi@4: foreach ($m[1] as $match) { danielebarchiesi@4: if (strpos($val, '$' . $match) === false) {/* just some container brackets, recurse */ danielebarchiesi@4: $val = str_replace($match, '{' . $this->replacePlaceholders(substr($match, 1, -1), $context, $return_string, $loop + 1) . '}', $val); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $ph = substr($match, 1, -1); danielebarchiesi@4: $sub_val = $this->getPlaceholderValue($ph); danielebarchiesi@4: if (is_array($sub_val)) { danielebarchiesi@4: $sub_val = $this->getArraySerialization($sub_val, $context); danielebarchiesi@4: } danielebarchiesi@4: $val = str_replace('${' . $ph . '}', $sub_val, $val); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } while (($old_val != $val) && ($loop < 10)); danielebarchiesi@4: return $val; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getPlaceholderValue($ph) { danielebarchiesi@4: /* simple vars */ danielebarchiesi@4: if (isset($this->env['vars'][$ph])) { danielebarchiesi@4: return $this->v('value', $this->env['vars'][$ph], $this->env['vars'][$ph]); danielebarchiesi@4: } danielebarchiesi@4: /* GET/POST */ danielebarchiesi@4: if (preg_match('/^(GET|POST)\.([^\.]+)(.*)$/', $ph, $m)) { danielebarchiesi@4: $vals = strtoupper($m[1]) == 'GET' ? $_GET : $POST; danielebarchiesi@4: $r = isset($vals[$m[2]]) ? $vals[$m[2]] : ''; danielebarchiesi@4: return $m[3] ? $this->getPropertyValue(array('value' => $r, 'value_type' => '?'), ltrim($m[3], '.')) : $r; danielebarchiesi@4: } danielebarchiesi@4: /* NOW */ danielebarchiesi@4: if (preg_match('/^NOW(.*)$/', $ph, $m)) { danielebarchiesi@4: $rest = $m[1]; danielebarchiesi@4: /* may have sub-phs */ danielebarchiesi@4: $rest = $this->replacePlaceholders($rest); danielebarchiesi@4: $r_struct = array( danielebarchiesi@4: 'y' => date('Y'), danielebarchiesi@4: 'mo' => date('m'), danielebarchiesi@4: 'd' => date('d'), danielebarchiesi@4: 'h' => date('H'), danielebarchiesi@4: 'mi' => date('i'), danielebarchiesi@4: 's' => date('s') danielebarchiesi@4: ); danielebarchiesi@4: if (preg_match('/(\+|\-)\s*([0-9]+)(y|mo|d|h|mi|s)[a-z]*(.*)/is', trim($rest), $m2)) { danielebarchiesi@4: eval('$r_struct[$m2[3]] ' . $m2[1] . '= (int)' . $m2[2] . ';'); danielebarchiesi@4: $rest = $m2[4]; danielebarchiesi@4: } danielebarchiesi@4: $uts = mktime($r_struct['h'], $r_struct['mi'], $r_struct['s'], $r_struct['mo'], $r_struct['d'], $r_struct['y']); danielebarchiesi@4: $uts -= date('Z', $uts); /* timezone offset */ danielebarchiesi@4: $r = date('Y-m-d\TH:i:s\Z', $uts); danielebarchiesi@4: if (preg_match('/^\.(.+)$/', $rest, $m)) { danielebarchiesi@4: return $this->getPropertyValue(array('value' => $r), $m[1]); danielebarchiesi@4: } danielebarchiesi@4: return $r; danielebarchiesi@4: } danielebarchiesi@4: /* property */ danielebarchiesi@4: if (preg_match('/^([^\.]+)\.(.+)$/', $ph, $m)) { danielebarchiesi@4: list($var, $path) = array($m[1], $m[2]); danielebarchiesi@4: if (isset($this->env['vars'][$var])) { danielebarchiesi@4: return $this->getPropertyValue($this->env['vars'][$var], $path); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: return ''; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getPropertyValue($obj, $path) { danielebarchiesi@4: $val = isset($obj['value']) ? $obj['value'] : $obj; danielebarchiesi@4: $path = $this->replacePlaceholders($path, 'property_value', 0); danielebarchiesi@4: /* reserved */ danielebarchiesi@4: if ($path == 'size') { danielebarchiesi@4: if ($obj['value_type'] == 'rows') return count($val); danielebarchiesi@4: if ($obj['value_type'] == 'literal') return strlen($val); danielebarchiesi@4: } danielebarchiesi@4: if (preg_match('/^replace\([\'\"](\/.*\/[a-z]*)[\'\"],\s*[\'\"](.*)[\'\"]\)$/is', $path, $m)) { danielebarchiesi@4: return @preg_replace($m[1], str_replace('$', '\\', $m[2]), $val); danielebarchiesi@4: } danielebarchiesi@4: if (preg_match('/^match\([\'\"](\/.*\/[a-z]*)[\'\"]\)$/is', $path, $m)) { danielebarchiesi@4: return @preg_match($m[1], $val, $m) ? $m : ''; danielebarchiesi@4: } danielebarchiesi@4: if (preg_match('/^urlencode\([\'\"]?(get|post|.*)[\'\"]?\)$/is', $path, $m)) { danielebarchiesi@4: return (strtolower($m[1]) == 'post') ? rawurlencode($val) : urlencode($val); danielebarchiesi@4: } danielebarchiesi@4: if (preg_match('/^toDataURI\([^\)]*\)$/is', $path, $m)) { danielebarchiesi@4: return 'data:text/plain;charset=utf-8,' . rawurlencode($val); danielebarchiesi@4: } danielebarchiesi@4: if (preg_match('/^fromDataURI\([^\)]*\)$/is', $path, $m)) { danielebarchiesi@4: return rawurldecode(str_replace('data:text/plain;charset=utf-8,', '', $val)); danielebarchiesi@4: } danielebarchiesi@4: if (preg_match('/^toPrettyDate\([^\)]*\)$/is', $path, $m)) { danielebarchiesi@4: $uts = strtotime(preg_replace('/(T|\+00\:00)/', ' ', $val)); danielebarchiesi@4: return date('D j M H:i', $uts); danielebarchiesi@4: } danielebarchiesi@4: if (preg_match('/^render\(([^\)]*)\)$/is', $path, $m)) { danielebarchiesi@4: $src_format = trim($m[1], '"\''); danielebarchiesi@4: return $this->render($val, $src_format); danielebarchiesi@4: } danielebarchiesi@4: /* struct */ danielebarchiesi@4: if (is_array($val)) { danielebarchiesi@4: if (isset($val[$path])) return $val[$path]; danielebarchiesi@4: $exp_path = $this->expandPName($path); danielebarchiesi@4: if (isset($val[$exp_path])) return $val[$exp_path]; danielebarchiesi@4: if (preg_match('/^([^\.]+)\.(.+)$/', $path, $m)) { danielebarchiesi@4: list($var, $path) = array($m[1], $m[2]); danielebarchiesi@4: if (isset($val[$var])) { danielebarchiesi@4: return $this->getPropertyValue(array('value' => $val[$var]), $path); danielebarchiesi@4: } danielebarchiesi@4: /* qname */ danielebarchiesi@4: $exp_var = $this->expandPName($var); danielebarchiesi@4: if (isset($val[$exp_var])) { danielebarchiesi@4: return $this->getPropertyValue(array('value' => $val[$exp_var]), $path); danielebarchiesi@4: } danielebarchiesi@4: return ''; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: /* meta */ danielebarchiesi@4: if (preg_match('/^\_/', $path) && isset($obj['meta']) && isset($obj['meta'][substr($path, 1)])) { danielebarchiesi@4: return $obj['meta'][substr($path, 1)]; danielebarchiesi@4: } danielebarchiesi@4: return ''; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function render($val, $src_format = '') { danielebarchiesi@4: if ($src_format) { danielebarchiesi@4: $mthd = 'render' . $this->camelCase($src_format); danielebarchiesi@4: if (method_exists($this, $mthd)) { danielebarchiesi@4: return $this->$mthd($val); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: return 'No rendering method found for "' . $src_format. '"'; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: /* try RDF */ danielebarchiesi@4: return $this->getArraySerialization($val); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function renderObjects($os) { danielebarchiesi@4: $r = ''; danielebarchiesi@4: foreach ($os as $o) { danielebarchiesi@4: $r .= $r ? ', ' : ''; danielebarchiesi@4: $r .= $o['value']; danielebarchiesi@4: } danielebarchiesi@4: return $r; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function getArraySerialization($v, $context) { danielebarchiesi@4: $v_type = ARC2::getStructType($v);/* string|array|triples|index */ danielebarchiesi@4: $pf = ARC2::getPreferredFormat(); danielebarchiesi@4: /* string */ danielebarchiesi@4: if ($v_type == 'string') return $v; danielebarchiesi@4: /* simple array (e.g. from SELECT) */ danielebarchiesi@4: if ($v_type == 'array') { danielebarchiesi@4: return join(', ', $v); danielebarchiesi@4: $m = method_exists($this, 'toLegacy' . $pf) ? 'toLegacy' . $pf : 'toLegacyXML'; danielebarchiesi@4: } danielebarchiesi@4: /* rdf */ danielebarchiesi@4: if (($v_type == 'triples') || ($v_type == 'index')) { danielebarchiesi@4: $m = method_exists($this, 'to' . $pf) ? 'to' . $pf : ($context == 'query' ? 'toNTriples' : 'toRDFXML'); danielebarchiesi@4: } danielebarchiesi@4: /* else */ danielebarchiesi@4: return $this->$m($v); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processBlock($block) { danielebarchiesi@4: if ($this->max_operations && ($this->env['operation_count'] >= $this->max_operations)) return $this->addError('Number of ' . $this->max_operations . ' allowed operations exceeded.'); danielebarchiesi@4: if ($this->return) return 0; danielebarchiesi@4: $this->env['operation_count']++; danielebarchiesi@4: $type = $block['type']; danielebarchiesi@4: $m = 'process' . $this->camelCase($type) . 'Block'; danielebarchiesi@4: if (method_exists($this, $m)) { danielebarchiesi@4: return $this->$m($block); danielebarchiesi@4: } danielebarchiesi@4: return $this->addError('Unsupported block type "' . $type . '"'); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processEndpointDeclBlock($block) { danielebarchiesi@4: $this->env['endpoint'] = $block['endpoint']; danielebarchiesi@4: return $this->env; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processQueryBlock($block) { danielebarchiesi@4: if ($this->max_queries && ($this->env['query_count'] >= $this->max_queries)) return $this->addError('Number of ' . $this->max_queries . ' allowed queries exceeded.'); danielebarchiesi@4: $this->env['query_count']++; danielebarchiesi@4: $ep_uri = $this->replacePlaceholders($this->env['endpoint'], 'endpoint'); danielebarchiesi@4: /* q */ danielebarchiesi@4: $prologue = 'BASE <' . $block['base']. '>'; danielebarchiesi@4: $q = $this->replacePlaceholders($block['query'], 'query'); danielebarchiesi@4: /* prefixes */ danielebarchiesi@4: $ns = isset($this->a['ns']) ? array_merge($this->a['ns'], $block['prefixes']) : $block['prefixes']; danielebarchiesi@4: $q = $prologue . "\n" . $this->completeQuery($q, $ns); danielebarchiesi@4: $this->env['query_log'][] = '(' . $ep_uri . ') ' . $q; danielebarchiesi@4: if ($store = $this->getStore($ep_uri)) { danielebarchiesi@4: $sub_r = $this->v('is_remote', '', $store) ? $store->query($q, '', $ep_uri) : $store->query($q); danielebarchiesi@4: /* ignore socket errors */ danielebarchiesi@4: if (($errs = $this->getErrors()) && preg_match('/socket/', $errs[0])) { danielebarchiesi@4: $this->warnings[] = $errs[0]; danielebarchiesi@4: $this->errors = array(); danielebarchiesi@4: $sub_r = array(); danielebarchiesi@4: } danielebarchiesi@4: return $sub_r; danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: return $this->addError("no store (" . $ep_uri . ")"); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getStore($ep_uri) { danielebarchiesi@4: /* local store */ danielebarchiesi@4: if ((!$ep_uri || $ep_uri == ARC2::getScriptURI()) && ($this->v('sparqlscript_default_endpoint', '', $this->a) == 'local')) { danielebarchiesi@4: if (!isset($this->local_store)) $this->local_store = ARC2::getStore($this->a);/* @@todo error checking */ danielebarchiesi@4: return $this->local_store; danielebarchiesi@4: } danielebarchiesi@4: elseif ($ep_uri) { danielebarchiesi@4: ARC2::inc('RemoteStore'); danielebarchiesi@4: $conf = array_merge($this->a, array('remote_store_endpoint' => $ep_uri, 'reader_timeout' => 10)); danielebarchiesi@4: return new ARC2_RemoteStore($conf, $this); danielebarchiesi@4: } danielebarchiesi@4: return 0; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processAssignmentBlock($block) { danielebarchiesi@4: $sub_type = $block['sub_type']; danielebarchiesi@4: $m = 'process' . $this->camelCase($sub_type) . 'AssignmentBlock'; danielebarchiesi@4: if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"'); danielebarchiesi@4: return $this->$m($block); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processQueryAssignmentBlock($block) { danielebarchiesi@4: $qr = $this->processQueryBlock($block['query']); danielebarchiesi@4: if ($this->getErrors() || !isset($qr['query_type'])) return 0; danielebarchiesi@4: $qt = $qr['query_type']; danielebarchiesi@4: $vts = array('ask' => 'bool', 'select' => 'rows', 'desribe' => 'doc', 'construct' => 'doc'); danielebarchiesi@4: $r = array( danielebarchiesi@4: 'value_type' => isset($vts[$qt]) ? $vts[$qt] : $qt . ' result', danielebarchiesi@4: 'value' => ($qt == 'select') ? $this->v('rows', array(), $qr['result']) : $qr['result'], danielebarchiesi@4: ); danielebarchiesi@4: $this->env['vars'][$block['var']['value']] = $r; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processStringAssignmentBlock($block) { danielebarchiesi@4: $r = array('value_type' => 'literal', 'value' => $this->replacePlaceholders($block['string']['value'])); danielebarchiesi@4: $this->env['vars'][$block['var']['value']] = $r; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processVarAssignmentBlock($block) { danielebarchiesi@4: if (isset($this->env['vars'][$block['var2']['value']])) { danielebarchiesi@4: $this->env['vars'][$block['var']['value']] = $this->env['vars'][$block['var2']['value']]; danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $this->env['vars'][$block['var']['value']] = array('value_type' => 'undefined', 'value' => ''); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processPlaceholderAssignmentBlock($block) { danielebarchiesi@4: $ph_val = $this->getPlaceholderValue($block['placeholder']['value']); danielebarchiesi@4: $this->env['vars'][$block['var']['value']] = array('value_type' => 'undefined', 'value' => $ph_val); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processVarMergeAssignmentBlock($block) { danielebarchiesi@4: $val1 = isset($this->env['vars'][$block['var2']['value']]) ? $this->env['vars'][$block['var2']['value']] : array('value_type' => 'undefined', 'value' => ''); danielebarchiesi@4: $val2 = isset($this->env['vars'][$block['var3']['value']]) ? $this->env['vars'][$block['var3']['value']] : array('value_type' => 'undefined', 'value' => ''); danielebarchiesi@4: if (is_array($val1) && is_array($val2)) { danielebarchiesi@4: $this->env['vars'][$block['var']['value']] = array('value_type' => $val2['value_type'], 'value' => array_merge($val1['value'], $val2['value'])); danielebarchiesi@4: } danielebarchiesi@4: elseif (is_numeric($val1) && is_numeric($val2)) { danielebarchiesi@4: $this->env['vars'][$block['var']['value']] = $val1 + $val2; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processFunctionCallAssignmentBlock($block) { danielebarchiesi@4: $sub_r = $this->processFunctionCallBlock($block['function_call']); danielebarchiesi@4: if ($this->getErrors()) return 0; danielebarchiesi@4: $this->env['vars'][$block['var']['value']] = $sub_r; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processReturnBlock($block) { danielebarchiesi@4: $sub_type = $block['sub_type']; danielebarchiesi@4: $m = 'process' . $this->camelCase($sub_type) . 'AssignmentBlock'; danielebarchiesi@4: if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"'); danielebarchiesi@4: $sub_r = $this->$m($block); danielebarchiesi@4: $this->return = 1; danielebarchiesi@4: return $sub_r; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processIfblockBlock($block) { danielebarchiesi@4: if ($this->testCondition($block['condition'])) { danielebarchiesi@4: $blocks = $block['blocks']; danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $blocks = $block['else_blocks']; danielebarchiesi@4: } danielebarchiesi@4: foreach ($blocks as $block) { danielebarchiesi@4: $sub_r = $this->processBlock($block); danielebarchiesi@4: if ($this->getErrors()) return 0; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function testCondition($cond) { danielebarchiesi@4: $m = 'test' . $this->camelCase($cond['type']) . 'Condition'; danielebarchiesi@4: if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"'); danielebarchiesi@4: return $this->$m($cond); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function testVarCondition($cond) { danielebarchiesi@4: $r = 0; danielebarchiesi@4: $vn = $cond['value']; danielebarchiesi@4: if (isset($this->env['vars'][$vn])) $r = $this->env['vars'][$vn]['value']; danielebarchiesi@4: $op = $this->v('operator', '', $cond); danielebarchiesi@4: if ($op == '!') $r = !$r; danielebarchiesi@4: return $r ? true : false; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function testPlaceholderCondition($cond) { danielebarchiesi@4: $val = $this->getPlaceholderValue($cond['value']); danielebarchiesi@4: $r = $val ? true : false; danielebarchiesi@4: $op = $this->v('operator', '', $cond); danielebarchiesi@4: if ($op == '!') $r = !$r; danielebarchiesi@4: return $r; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function testExpressionCondition($cond) { danielebarchiesi@4: $m = 'test' . $this->camelCase($cond['sub_type']) . 'ExpressionCondition'; danielebarchiesi@4: if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"'); danielebarchiesi@4: return $this->$m($cond); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function testRelationalExpressionCondition($cond) { danielebarchiesi@4: $op = $cond['operator']; danielebarchiesi@4: if ($op == '=') $op = '=='; danielebarchiesi@4: $val1 = $this->getPatternValue($cond['patterns'][0]); danielebarchiesi@4: $val2 = $this->getPatternValue($cond['patterns'][1]); danielebarchiesi@4: eval('$result = ($val1 ' . $op . ' $val2) ? 1 : 0;'); danielebarchiesi@4: return $result; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function testAndExpressionCondition($cond) { danielebarchiesi@4: foreach ($cond['patterns'] as $pattern) { danielebarchiesi@4: if (!$this->testCondition($pattern)) return false; danielebarchiesi@4: } danielebarchiesi@4: return true; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getPatternValue($pattern) { danielebarchiesi@4: $m = 'get' . $this->camelCase($pattern['type']) . 'PatternValue'; danielebarchiesi@4: if (!method_exists($this, $m)) return ''; danielebarchiesi@4: return $this->$m($pattern); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getLiteralPatternValue($pattern) { danielebarchiesi@4: return $pattern['value']; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function getPlaceholderPatternValue($pattern) { danielebarchiesi@4: return $this->getPlaceholderValue($pattern['value']); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processForblockBlock($block) { danielebarchiesi@4: $set = $this->v($block['set'], array('value' => array()), $this->env['vars']); danielebarchiesi@4: $entries = isset($set['value']) ? $set['value'] : $set; danielebarchiesi@4: $iterator = $block['iterator']; danielebarchiesi@4: $blocks = $block['blocks']; danielebarchiesi@4: if (!is_array($entries)) return 0; danielebarchiesi@4: $rc = count($entries); danielebarchiesi@4: foreach ($entries as $i => $entry) { danielebarchiesi@4: $val_type = $this->v('value_type', 'set', $set) . ' entry'; danielebarchiesi@4: $this->env['vars'][$iterator] = array( danielebarchiesi@4: 'value' => $entry, danielebarchiesi@4: 'value_type' => $val_type, danielebarchiesi@4: 'meta' => array( danielebarchiesi@4: 'pos' => $i, danielebarchiesi@4: 'odd_even' => ($i % 2) ? 'even' : 'odd' danielebarchiesi@4: ) danielebarchiesi@4: ); danielebarchiesi@4: foreach ($blocks as $block) { danielebarchiesi@4: $this->processBlock($block); danielebarchiesi@4: if ($this->getErrors()) return 0; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processLiteralBlock($block) { danielebarchiesi@4: $this->env['output'] .= $this->replacePlaceholders($block['value'], 'output'); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function processFunctionCallBlock($block) { danielebarchiesi@4: $uri = $this->replacePlaceholders($block['uri'], 'function_call'); danielebarchiesi@4: /* built-ins */ danielebarchiesi@4: if (strpos($uri, $this->a['ns']['sps']) === 0) { danielebarchiesi@4: return $this->processBuiltinFunctionCallBlock($block); danielebarchiesi@4: } danielebarchiesi@4: /* remote functions */ danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processBuiltinFunctionCallBlock($block) { danielebarchiesi@4: $fnc_uri = $this->replacePlaceholders($block['uri'], 'function_call'); danielebarchiesi@4: $fnc_name = substr($fnc_uri, strlen($this->a['ns']['sps'])); danielebarchiesi@4: if (preg_match('/^(get|post)$/i', $fnc_name, $m)) { danielebarchiesi@4: return $this->processHTTPCall($block, strtoupper($m[1])); danielebarchiesi@4: } danielebarchiesi@4: if ($fnc_name == 'eval') { danielebarchiesi@4: return $this->processEvalCall($block); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processEvalCall($block) { danielebarchiesi@4: if (!$block['args']) return 0; danielebarchiesi@4: $arg = $block['args'][0]; danielebarchiesi@4: $script = ''; danielebarchiesi@4: if ($arg['type'] == 'placeholder') $script = $this->getPlaceholderValue($arg['value']); danielebarchiesi@4: if ($arg['type'] == 'literal') $script = $arg['value']; danielebarchiesi@4: if ($arg['type'] == 'var') $script = $this->getVarValue($arg['value']); danielebarchiesi@4: //echo "\n" . $script . $arg['type']; danielebarchiesi@4: $this->processScript($script); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: function processHTTPCall($block, $mthd = 'GET') { danielebarchiesi@4: ARC2::inc('Reader'); danielebarchiesi@4: $reader = new ARC2_Reader($this->a, $this); danielebarchiesi@4: $url = $this->replacePlaceholders($block['args'][0]['value'], 'function_call'); danielebarchiesi@4: if ($mthd != 'GET') { danielebarchiesi@4: $reader->setHTTPMethod($mthd); danielebarchiesi@4: $reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded"); danielebarchiesi@4: } danielebarchiesi@4: $to = $this->v('remote_call_timeout', 0, $this->a); danielebarchiesi@4: $reader->activate($url, '', 0, $to); danielebarchiesi@4: $format = $reader->getFormat(); danielebarchiesi@4: $resp = ''; danielebarchiesi@4: while ($d = $reader->readStream()) { danielebarchiesi@4: $resp .= $d; danielebarchiesi@4: } danielebarchiesi@4: $reader->closeStream(); danielebarchiesi@4: unset($this->reader); danielebarchiesi@4: return array('value_type' => 'http_response', 'value' => $resp); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: function extractVars($pattern, $input = '') { danielebarchiesi@4: $vars = array(); danielebarchiesi@4: /* replace PHs, track ()s */ danielebarchiesi@4: $regex = $pattern; danielebarchiesi@4: $vars = array(); danielebarchiesi@4: if (preg_match_all('/([\?\$]\{([^\}]+)\}|\([^\)]+\))/', $regex, $m)) { danielebarchiesi@4: $matches = $m[1]; danielebarchiesi@4: $pre_vars = $m[2]; danielebarchiesi@4: foreach ($matches as $i => $match) { danielebarchiesi@4: $vars[] = $pre_vars[$i]; danielebarchiesi@4: if ($pre_vars[$i]) {/* placeholder */ danielebarchiesi@4: $regex = str_replace($match, '(.+)', $regex); danielebarchiesi@4: } danielebarchiesi@4: else {/* parentheses, but may contain placeholders */ danielebarchiesi@4: $sub_regex = $match; danielebarchiesi@4: while (preg_match('/([\?\$]\{([^\}]+)\})/', $sub_regex, $m)) { danielebarchiesi@4: $sub_regex = str_replace($m[1], '(.+)', $sub_regex); danielebarchiesi@4: $vars[] = $m[2]; danielebarchiesi@4: } danielebarchiesi@4: $regex = str_replace($match, $sub_regex, $regex); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: /* eval regex */ danielebarchiesi@4: if (@preg_match('/' . $regex . '/is', $input, $m)) { danielebarchiesi@4: $vals = $m; danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: return 0; danielebarchiesi@4: } danielebarchiesi@4: for ($i = 0; $i < count($vars); $i++) { danielebarchiesi@4: if ($vars[$i]) { danielebarchiesi@4: $this->setVar($vars[$i], isset($vals[$i + 1]) ? $vals[$i + 1] : ''); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: return 1; danielebarchiesi@4: } danielebarchiesi@4: /* no placeholders */ danielebarchiesi@4: return ($pattern == $input) ? 1 : 0; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /* */ danielebarchiesi@4: danielebarchiesi@4: }