private function handleTable(&$array) { // So sayeth the spec: ... // There is no RTF table group; instead, tables are specified as paragraph properties. // A table is represented as a sequence of table rows. A table row is a continuous sequence of paragraphs // partitioned into cells. The table row begins with the \trowd control word and ends with the \row control word. // Every paragraph that is contained in a table row must have the \intbl control word specified or inherited from // the previous paragraph. A cell may have more than one paragraph in it; the cell is terminated by a cell mark // (the \cell control word), and the row is terminated by a row mark (the \row control word). // ... // But of course, not all RTF emitters actually do this. self::$in_table = true; $widths = []; $rows = []; $gaph = 0; while ($array && $array[0] == "\\trowd") { $row = []; array_shift($array); while ($array && $array[0] != "\\row") { if ($array[0] != "\\cell" && strncmp($array[0], "\\cellx", 5) == 0) { $commands = Rtf::SplitCommand(array_shift($array)); if (isset($commands[1])) { $ws = array_sum($widths); $widths[] = $commands[1] / 20 - $ws; } } else { if (strncmp($array[0], "\\trgaph", 7) == 0) { $commands = Rtf::SplitCommand(array_shift($array)); if (isset($commands[1])) { $gaph = $commands[1] / 20; } } else { $row[] = array_shift($array); } } } array_shift($array); $columns = []; while ($row) { $column = []; while ($row && $row[0] != "\\cell") { $column[] = array_shift($row); } $columns[] = $column; array_shift($row); } $rows[] = $columns; } $num_columns = max(mapcar("count", $rows)); $row_number = 0; // Theoretically we now have an array of rows - each of which is theoretically an array of cells. $output = [$gaph ? "<table style='border-collapse: separate; border-spacing: {$gaph}pt'>" : "<table>"]; $this->pushTag("table"); $this->pushTag("tbody"); foreach ($rows as $row) { if (count($row) != $num_columns && $row_number) { $output[] = $this->popTag("tbody"); $output[] = $this->popTag("table"); $output[] = $this->pushTag("table"); $output[] = $this->pushTag("tbody"); } $output[] = $this->pushTag("tr"); foreach ($row as $cell) { $cell_contents = []; $block = new RTFBlock(); foreach ($cell as $element) { if ($element[0] != "\\") { $cell_contents[] = $block->outputText($element); } else { $cell_contents[] = $block->getHTML([$element]); } } $width = array_shift($widths); $cell_contents[] = $block->endOutput(); $contents = join("", flatten($cell_contents)); // it would be cleaner to do this with classes, but we can't guarantee that CSS classes are going to be // available because we're intentionally not emitting a full HTML document. But since we really only care // about right alignment, let's hack in a cell-wide alignment if some of the cell text is right-aligned. // Of course this will fail 'orribly if some of the cell text is also supposed to _not_ be so aligned. $block->pushTag("td"); $output[] = "<td style='vertical-align: top; padding: 0.25em; " . ($width ? " width: {$width}pt;" : "") . (strpos($contents, "text-align: right") !== false ? " text-align: right;" : "") . "'>"; $output[] = $contents; $output[] = $block->popTag("td"); } $output[] = $this->popTag("tr"); $row_number++; if (count($row) != $num_columns && $row_number != count($rows)) { $output[] = $this->popTag("tbody"); $output[] = $this->popTag("table"); $output[] = $this->pushTag("table"); $output[] = $this->pushTag("tbody"); } } $output[] = $this->popTag("tbody"); $output[] = $this->popTag("table"); self::$in_table = false; return $output; }
public function run() { $function = $this->_router->dispatch($this->_uri, $_SERVER['REQUEST_METHOD']); if ($function) { $vars = []; foreach ($function[1] as $key => $val) { $vars[$key] = is_array($val) ? mapcar("urldecode", $val) : urldecode($val); } $this->_variables = array_merge($vars, $_GET, $_POST, $_FILES); if ($this->_content_type) { header("Content-Type: {$this->_content_type}"); } $func_name = $function[0]; if (is_string($func_name)) { $pipe = strpos($func_name, "|"); if ($pipe !== false) { $this->doAutoload(substr($func_name, 0, $pipe)); $func_name = substr($func_name, $pipe + 1); } } if ($this->_cookie && session_status() != PHP_SESSION_ACTIVE) { session_name($this->_cookie); session_start(); } if (function_exists($func_name)) { print call_user_func($func_name, $this); } else { header("HTTP/1.0 404 Not Found"); print $this->jigsaw($this->_404, ["page" => $func_name]); } } else { header("HTTP/1.0 404 Not Found"); print $this->jigsaw($this->_404, ["page" => $function]); } }