/** * parse a string containing html elements * * this function decodes html's special characters except for the content * (when it too is not being parsed). * this function is more fragile than html_parse_elem() when it comes to * malformatted input. * @param string $html input string * @param bool $recursive also parse children elements * @return array parsed representation */ function html_parse($html, $recursive = false) { global $single_tags; // from html.inc.php $ret = array(); $pos = 0; $open_tag = false; $open_pos = false; // can probably be done with -1 and some slightly easier code below $close_pos = false; $num_open = 0; while ($pos < strlen($html)) { if ($html[$pos] == '<') { if (($next = strpos($html, '>', $pos + 1)) === false) { // error: unclosed < $pos++; continue; } // handle uppercase tags as well $tag = strtolower(trim(substr($html, $pos + 1, $next - $pos - 1))); if (substr($tag, 0, 1) !== '/') { // opening tag if ($num_open == 0) { $a = expl_whitesp($tag, true); $open_tag = $a[0]; $open_pos = $pos; } // handle single tags if (in_array($tag, $single_tags)) { if ($num_open == 0) { // check if there was something between the last $close_pos and $open_pos $text = ''; if ($close_pos === false && 0 < $open_pos) { $text = trim(substr($html, 0, $open_pos)); } elseif ($close_pos !== false && $close_pos + 1 < $open_pos) { $text = trim(substr($html, $close_pos + 1, $open_pos - $close_pos - 1)); } if (0 < strlen($text)) { $ret[] = $text; } $close_pos = $next; $ret[] = html_parse_elem(substr($html, $open_pos, $close_pos - $open_pos + 1), $recursive); } } else { $num_open++; } } else { // closing tag $num_open--; if ($num_open == 0) { // check if opening and closing tag match if ($open_tag != substr($tag, 1)) { // error: opening and closing tag do not match $pos++; continue; } // check if there was something between the last $close_pos and $open_pos $text = ''; if ($close_pos === false && 0 < $open_pos) { $text = trim(substr($html, 0, $open_pos)); } elseif ($close_pos !== false && $close_pos + 1 < $open_pos) { $text = trim(substr($html, $close_pos + 1, $open_pos - $close_pos - 1)); } if (0 < strlen($text)) { $ret[] = $text; } $close_pos = $next; $ret[] = html_parse_elem(substr($html, $open_pos, $close_pos - $open_pos + 1), $recursive); } } } $pos++; } // check if there was something after the last $close_pos $text = ''; if ($close_pos === false && 1 < $pos) { $text = trim($html); } elseif ($close_pos !== false && $close_pos + 1 < $pos) { $text = trim(substr($html, $close_pos + 1)); } if (0 < strlen($text)) { $ret[] = $text; } return $ret; }
/** * save the state of a html element corresponding to an object to disk * * this function takes the object lock. * @param array $args arguments * key 'html' one html element * @return array response * true if successful */ function save_state($args) { if (empty($args['html'])) { return response('Required argument "html" missing or empty', 400); } require_once 'html.inc.php'; require_once 'html_parse.inc.php'; $elem = html_parse_elem($args['html']); if (!elem_has_class($elem, 'object')) { return response('Error saving state as class "object" is not set', 400); } elseif (!object_exists(elem_attr($elem, 'id'))) { return response('Error saving state as object does not exist', 404); } // LOCK $L = _obj_lock(elem_attr($elem, 'id'), LOCK_TIME); if ($L === false) { return response('Could not acquire lock to ' . quot($args['name']) . ' in ' . LOCK_TIME . 'ms', 500); } $obj = load_object(array('name' => elem_attr($elem, 'id'))); if ($obj['#error']) { // UNLOCK _obj_unlock($L); return response('Error saving state, cannot load ' . quot(elem_attr($elem, 'id')), 500); } else { $obj = $obj['#data']; } $ret = invoke_hook_while('save_state', false, array('elem' => $elem, 'obj' => $obj)); // UNLOCK _obj_unlock($L); if (count($ret) == 0) { return response('Error saving state as nobody claimed element', 500); } else { $temp = array_keys($ret); log_msg('info', 'save_state: ' . quot($obj['name']) . ' was handled by ' . quot($temp[0])); return response(true); } }