[Fusionforge-commits] r15447 - in branches/Branch_5_1/src: common/include docs www/include

Thorsten Glaser mirabilos at fusionforge.org
Wed May 2 09:52:02 CEST 2012


Author: mirabilos
Date: 2012-05-02 09:52:00 +0200 (Wed, 02 May 2012)
New Revision: 15447

Added:
   branches/Branch_5_1/src/docs/README.html:elements
   branches/Branch_5_1/src/docs/README.html:utils
Modified:
   branches/Branch_5_1/src/common/include/utils.php
   branches/Branch_5_1/src/www/include/html.php
Log:
port a few utility functions from Evolvis (and their documentation)
to make it easier to port over fixes from it


Modified: branches/Branch_5_1/src/common/include/utils.php
===================================================================
--- branches/Branch_5_1/src/common/include/utils.php	2012-04-29 17:30:31 UTC (rev 15446)
+++ branches/Branch_5_1/src/common/include/utils.php	2012-05-02 07:52:00 UTC (rev 15447)
@@ -5,7 +5,7 @@
  * Copyright 1999-2001, VA Linux Systems, Inc.
  * Copyright 2009-2010, Roland Mas
  * Copyright 2009-2010, Franck Villaume - Capgemini
- * Copyright (c) 2010, 2011
+ * Copyright (c) 2010, 2011, 2012
  *	Thorsten Glaser <t.glaser at tarent.de>
  * Copyright (C) 2010-2011 Alain Peyrat - Alcatel-Lucent
  *
@@ -368,15 +368,7 @@
  *
  */
 function util_unconvert_htmlspecialchars($string) {
-	if (strlen($string) < 1) {
-		return '';
-	} else {
-		//$trans = get_html_translation_table(HTMLENTITIES, ENT_QUOTES);
-		$trans = get_html_translation_table(HTML_ENTITIES);
-		$trans = array_flip ($trans);
-		$str = strtr ($string, $trans);
-		return $str;
-	}
+	return html_entity_decode($string, ENT_QUOTES, "UTF-8");
 }
 
 /**
@@ -1476,12 +1468,47 @@
 	return $s;
 }
 
+function util_html_encode($s) {
+	return htmlspecialchars($s, ENT_QUOTES, "UTF-8");
+}
+
 /* secure a (possibly already HTML encoded) string */
 function util_html_secure($s) {
-	return htmlentities(html_entity_decode($s, ENT_QUOTES, "UTF-8"),
-	    ENT_QUOTES, "UTF-8");
+	return util_html_encode(util_unconvert_htmlspecialchars($s));
 }
 
+/* return integral value (ℕ₀) of passed string if it matches, or false */
+function util_nat0(&$s) {
+	if (!isset($s)) {
+		/* unset variable */
+		return false;
+	}
+	if (is_array($s)) {
+		if (count($s) == 1) {
+			/* one-element array */
+			return util_nat0($s[0]);
+		}
+		/* not one element, or element not at [0] */
+		return false;
+	}
+	if (!is_numeric($s)) {
+		/* not numeric */
+		return false;
+	}
+	$num = (int)$s;
+	if ($num >= 0) {
+		/* number element of ℕ₀ */
+		$text = (string)$num;
+		if ($text == $s) {
+			/* number matches its textual representation */
+			return ($num);
+		}
+		/* doesn't match, like 0123 or 1.2 or " 1" */
+	}
+	/* or negative */
+	return false;
+}
+
 /**
  * Codendi compatibility code.
  *
@@ -1491,9 +1518,39 @@
 	return forge_check_global_perm('forge_admin');
 }
 
+/**
+ * util_gethref() - Construct a hypertext reference
+ *
+ * @param	string	$baseurl
+ *		(optional) base URL (absolute or relative);
+ *			urlencoded, but not htmlencoded
+ *		(default (falsy): PHP_SELF)
+ * @param	array	$args
+ *		(optional) associative array of unencoded query parameters;
+ *			false values are ignored
+ * @param	bool	$ashtml
+ *		(optional) htmlencode the result?
+ *		(default: true)
+ * @param	string	$sep
+ *		(optional) argument separator ('&' or ';')
+ *		(default: '&')
+ * @return	string
+ *		URL, possibly htmlencoded
+ */
+function util_gethref($baseurl=false, $args=array(), $ashtml=true, $sep='&') {
+	$rv = $baseurl ? $baseurl : getStringFromServer('PHP_SELF');
+	$pfx = '?';
+	foreach ($args as $k => $v) {
+		if ($v === false) {
+			continue;
+		}
+		$rv .= $pfx . urlencode($k) . '=' . urlencode($v);
+		$pfx = $sep;
+	}
+	return ($ashtml ? util_html_encode($rv) : $rv);
+}
+
 // Local Variables:
 // mode: php
 // c-file-style: "bsd"
 // End:
-
-?>

Added: branches/Branch_5_1/src/docs/README.html:elements
===================================================================
--- branches/Branch_5_1/src/docs/README.html:elements	                        (rev 0)
+++ branches/Branch_5_1/src/docs/README.html:elements	2012-05-02 07:52:00 UTC (rev 15447)
@@ -0,0 +1,142 @@
+Documentation of new HTML element creation functions
+────────────────────────────────────────────────────
+
+Functions defined in src/www/include/html.php → available: always.
+
+
+‣ Element emission functions (do not echo anything)
+
+
+• string html_eo(string $name, optional(empty) array $attrs)
+
+	html_eo('b')
+	⇒ '<b>'
+
+	html_eo('td', array('colspan' => 2))
+	⇒ '<td colspan="2">'
+
+	html_eo('div', array('class' => array('ff', 'important')))
+	⇒ '<div class="ff important">'
+
+	html_eo('img', array(
+		'src' => '…',
+		'ref' => false,
+		'class' => array(),
+		'alt' => "",
+	    ))
+	⇒ '<img src="…" alt="">'
+
+  Generate an XHTML E̲lement O̲pen tag for $name, with attributes
+  defined by key/value pairs properly inserted. Attribute values
+  are coerced into strings from integers (by casting) or arrays
+  (by concatenating the array elements with spaces); if the value
+  is === false or an empty array (count($attrs[n]) == 0), the
+  attribute is not output at all, but for empty values it is; see
+  the img example (admittedly bad, you’d use html_e() for "img").
+
+• string html_e(string $name, optional(empty) array $attrs,
+    optional(empty) string $content, optional(true) bool $shortform)
+
+	html_e('br')
+	⇒ '<br />'
+
+	html_e('a', array('href' => '/foo.php?a=1&b=2'), 'täxt')
+	⇒ '<a href="/foo.php?a=1&b=2">täxt</a>'
+
+	html_e('script', array(
+		'type' => 'text/javascript',
+		'src' => '/js/foo.js',
+	    ), "", false)
+	⇒ '<script type="text/javascript" src="/js/foo.js"></script>'
+	/* needed because <script ... /> does not work */
+
+	html_e('tr', array(), html_e('td', array(), 'bla'))
+	⇒ '<tr><td>bla</td></tr>'
+
+  As with html_eo() the first two arguments define the tag to open.
+  The third argument will be placed between the opening and closing
+  tags but – in contrast to attribute values – not entity-encoded.
+  If the third argument is empty, either a self-closing (default)
+  tag, or, if the fourth argument is false, an open-close sequence,
+  is emitted.
+
+
+‣ Autoclose stack functions
+
+	$spos = html_ap();
+	$s = html_ao('p');
+	if ($foo) {
+		$s .= html_ao('strong');
+	}
+	$s .= html_ao('a', array('href' => '/'));
+	$s .= somefunc();
+	$s .= html_ac($spos);
+	⇒ '<p><strong><a href="/">somefuncreturnvalue</a></strong></p>'
+	⇒ '<p><a href="/">somefuncreturnvalue</a></p>'
+
+• integer html_ap(void)
+
+  Return the a̲utoclose stack’s current p̲osition.
+
+• string html_ao(string $name, optional(empty) array $attrs)
+
+  Works the same as html_eo() but pushes $name onto the a̲utoclose
+  element stack when o̲pening it.
+
+• string html_ac(integer $spos)
+
+  Return a set of closing elements until the a̲utoc̲lose stack
+  has reached the position it had when html_ap() returned $spos.
+
+  If $spos === false: an empty string is returned, for html_aonce().
+
+  If $spos < current stack position, an Exception is raised.
+
+• string html_aonce(ByRef integer $sptr, string $name,
+    optional(empty) array $attrs)
+
+	$spos = false;
+	foreach ($row in $rows) {
+		echo html_aonce('table');
+		echo html_e('tr', array(), html_e('td', array(),
+		    util_html_secure($row['data'])));
+	}
+	echo html_ac($spos);
+	⇒ ''  // if $rows is empty
+	⇒ '<table><tr><td>content1</td></tr><tr><td>content2</td></tr></table>'
+
+  If $sptr is not false, do nothing. Otherwise, set it to
+  the current html_ap() then do html_ao($name, $attrs).
+
+  This function can easily be used to open an enclosing element
+  with mandatory inner elements, such as a table, only once except
+  if no table row were to be generated.
+
+‣ Autoclose stack copy functions
+
+	$spos = html_ap();
+	echo html_ao('tr', array('bgcolor' => '#FF0000'));
+	echo html_ao('td');
+	echo "content 1";
+	$scopy = html_a_copy($spos);
+	echo html_ac($spos);
+	echo html_e('tr', array(), html_e('td', array(), "intermediate"));
+	echo html_a_apply($scopy);
+	echo "content 2";
+	echo html_ac($spos);
+	echo html_a_apply($scopy);
+	echo "content 3";
+	echo html_ac($spos);
+
+	⇒ <tr bgcolor="#FF0000"><td>content 1</td></tr>
+	  <tr><td>intermediate</td></tr>
+	  <tr bgcolor="#FF0000"><td>content 2</td></tr>
+	  <tr bgcolor="#FF0000"><td>content 3</td></tr>
+
+• opaque html_a_copy(integer $spos)
+• string html_a_apply(opaque $scopy)
+
+  Before autoclosing the stack down to a level $spos, you can
+  retrieve a copy of the stack in an opaque format, which can
+  later be used to (re-)open the same elements, with the same
+  attributes, even in a different nesting state.

Added: branches/Branch_5_1/src/docs/README.html:utils
===================================================================
--- branches/Branch_5_1/src/docs/README.html:utils	                        (rev 0)
+++ branches/Branch_5_1/src/docs/README.html:utils	2012-05-02 07:52:00 UTC (rev 15447)
@@ -0,0 +1,102 @@
+Documentation of common HTML utility functions
+──────────────────────────────────────────────
+
+Functions defined in src/common/include/utils.php → available: always.
+
+
+• string util_html_encode(string $s)
+
+	util_html_secure('a=1&b=2')
+	⇒ 'a=1&b=2'        // HTML-encoded
+
+	util_html_secure('a=1&b=2')
+	⇒ 'a=1&amp;b=2'    // changed!
+
+  Encode a string for use in XHTML even if it is already encoded.
+
+• string util_html_secure(string $s)
+
+	util_html_secure('a=1&b=2')
+	⇒ 'a=1&b=2'    // HTML-encoded
+
+	util_html_secure('a=1&b=2')
+	⇒ 'a=1&b=2'    // unchanged
+
+  Encode a string for use in XHTML if it is not already encoded.
+  (So, if you use this for output sanitising, other than a slight
+  performance penalty no harm is done if the output was already
+  sane.)
+
+• string util_unconvert_htmlspecialchars(string $s)
+
+	util_unconvert_htmlspecialchars('a=1&b=2')
+	⇒ 'a=1&b=2'    // unchanged
+
+	util_unconvert_htmlspecialchars('a=1&b=2')
+	⇒ 'a=1&b=2'    // HTML-decoded
+
+  Undo util_html_encode; be careful, this can decode partially.
+
+
+• string util_gethref(optional(false) string $baseurl,
+    optional(empty) array $args, optional(true) bool $ashtml,
+    optional('&') string $sep)
+
+	util_gethref("/x.php", array(
+		'foo' => 'a+b&c',
+		'bar' => 'd+b&e',
+	    ));
+	⇒ "/x.php?foo=a%2Bb%26c&bar=d%2Bb%26e"
+
+	util_gethref("/x.php", array(
+		'foo' => 'a+b&c',
+		'bar' => 'd+b&e',
+	    ), false);
+	⇒ /x.php?foo=a%2Bb%26c&bar=d%2Bb%26e
+
+	util_gethref("/x.php", array(
+		'foo' => 'a+b&c',
+		'bar' => 'd+b&e',
+	    ), true, ';')
+	⇒ "/x.php?foo=a%2Bb%26c;bar=d%2Bb%26e"
+
+  Construct an URI for use with util_make_url, session_redirect,
+  html_e('a', array('href' => …)), and similar. The first argument
+  ($baseurl) is passed through as-is but, if falsy, defaults to
+  getStringFromServer('PHP_SELF'); the arguments (both keys and
+  values) are urlencoded (entries while values is false are not
+  emitted at all) and appended, with a question mark in front and
+  the $sep separator in between.
+
+  If $ashtml is true (default), the result will then be run through
+  util_html_encode; set this to false when using in html_e href as
+  value (since html_e will html-encode itself).
+
+• string util_make_url(string $path)
+
+	util_make_url('/foo.php?a=1&b=2')
+	⇒ 'https://forge.domain.com/fusionforge/foo.php?a=1&b=2'
+
+  Return an absolute URI for the path in question, containing the
+  system-defined protocol, hostname and (if defined) webroot prefix.
+
+  Both html-encoded and not html-encoded return values of util_gethref
+  are safe to pass as arguments, if their baseurl was only a path.
+
+• integer|false util_nat0(ByRef string $s)
+
+  If and only if $s is the normalised positive integer (ℕ₀)
+  representation of a number, return that number; false otherwise.
+  Limited by system constraints, i.e. usually [0;2³¹-1].
+
+
+‣ common non-HTML utility functions
+
+
+• mixed util_ifsetor(ByRef mixed $val, optional(false) mixed $default)
+
+  If isset($val), return $val, otherwise (no warning) $default.
+
+• string debug_string_backtrace(void)
+
+  Return the current debugging backtrace as string.

Modified: branches/Branch_5_1/src/www/include/html.php
===================================================================
--- branches/Branch_5_1/src/www/include/html.php	2012-04-29 17:30:31 UTC (rev 15446)
+++ branches/Branch_5_1/src/www/include/html.php	2012-05-02 07:52:00 UTC (rev 15447)
@@ -850,9 +850,210 @@
 	return $hashstr;
 }
 
+/* TODO: think about beautifying output */
+
+/**
+ * html_eo() - Return proper element XHTML start tag
+ *
+ * @param	string	$name
+ *			element name
+ * @param	array	$attrs
+ *		(optional) associative array of element attributes
+ *			values: arrays are space-imploded;
+ *			    false values and empty arrays ignored
+ * @return	string
+ *		XHTML string suitable for echo'ing
+ */
+function html_eo($name, $attrs=array()) {
+	$rv = '<' . $name;
+	foreach ($attrs as $key => $value) {
+		if (is_array($value)) {
+			$value = count($value) ? implode(" ", $value) : false;
+		}
+		if ($value === false) {
+			continue;
+		}
+		$rv .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
+	}
+	$rv .= '>';
+	return $rv;
+}
+
+/**
+ * html_e() - Return proper element XHTML start/end sequence
+ *
+ * @param	string	$name
+ *			element name
+ * @param	array	$attrs
+ *		(optional) associative array of element attributes
+ *			values: arrays are space-imploded;
+ *			    false values and empty arrays ignored
+ * @param	string	$content
+ *		(optional) XHTML to be placed inside
+ * @param	bool	$shortform
+ *		(optional) allow short open-close form
+ *		(default: true)
+ * @return	string
+ *		XHTML string suitable for echo'ing
+ */
+function html_e($name, $attrs=array(), $content="", $shortform=true) {
+	$rv = '<' . $name;
+	foreach ($attrs as $key => $value) {
+		if (is_array($value)) {
+			$value = count($value) ? implode(" ", $value) : false;
+		}
+		if ($value === false) {
+			continue;
+		}
+		$rv .= ' ' . $key . '="' . htmlspecialchars($value) . '"';
+	}
+	if ($content === "" && $shortform) {
+		$rv .= ' />';
+	} else {
+		$rv .= '>' . $content . '</' . $name . '>';
+	}
+	return $rv;
+}
+
+$html_autoclose_stack = array();
+$html_autoclose_pos = 0;
+
+/**
+ * html_ap() - Return XHTML element autoclose stack position
+ *
+ * @return	integer
+ */
+function html_ap() {
+	global $html_autoclose_pos;
+
+	return $html_autoclose_pos;
+}
+
+/**
+ * html_ao() - Return proper element XHTML start tag, with autoclose
+ *
+ * @param	string	$name
+ *			element name
+ * @param	array	$attrs
+ *		(optional) associative array of element attributes
+ *			values: arrays are space-imploded;
+ *			    false values and empty arrays ignored
+ * @return	string
+ *		XHTML string suitable for echo'ing
+ */
+function html_ao($name, $attrs=array()) {
+	global $html_autoclose_pos, $html_autoclose_stack;
+
+	$html_autoclose_stack[$html_autoclose_pos++] = array(
+		'name' => $name,
+		'attr' => $attrs,
+	    );
+	return html_eo($name, $attrs);
+}
+
+/**
+ * html_aonce() - Return once proper element XHTML start tag, with autoclose
+ *
+ * @param	ref	&$sptr
+			initialise this to false; will be modified
+ * @param	string	$name
+ *			element name
+ * @param	array	$attrs
+ *		(optional) associative array of element attributes
+ *			values: arrays are space-imploded;
+ *			    false values and empty arrays ignored
+ * @return	string
+ *		XHTML string suitable for echo'ing
+ */
+function html_aonce(&$sptr, $name, $attrs=array()) {
+	if ($sptr !== false) {
+		/* already run */
+		return "";
+	}
+	$sptr = html_ap();
+	return html_ao($name, $attrs);
+}
+
+/**
+ * html_ac() - Return proper element XHTML end tags, autoclosing
+ *
+ * @param	integer	$spos
+ *			stack position to return to
+ *			(nothing is done if === false)
+ * @return	string
+ *		XHTML string suitable for echo'ing
+ */
+function html_ac($spos) {
+	global $html_autoclose_pos, $html_autoclose_stack;
+
+	if ($spos === false) {
+		/* support for html_aonce() */
+		return "";
+	}
+
+	if ($html_autoclose_pos < $spos) {
+		$e = "html_autoclose stack underflow; closing down to " .
+		    $spos . " but we're down to " . $html_autoclose_pos .
+		    " already!";
+		throw new Exception($e);
+	}
+
+	$rv = "";
+	while ($html_autoclose_pos > $spos) {
+		--$html_autoclose_pos;
+		$rv .= '</' . $html_autoclose_stack[$html_autoclose_pos]['name'] . '>';
+		unset($html_autoclose_stack[$html_autoclose_pos]);
+	}
+	return $rv;
+}
+
+/**
+ * html_a_copy() - Return a copy of part of the autoclose stack
+ *
+ * @param	integer	$spos
+ *			stack position caller will return to
+ * @return	opaque
+ *		argument suitable for html_a_apply()
+ */
+function html_a_copy($spos) {
+	global $html_autoclose_pos, $html_autoclose_stack;
+
+	if ($spos === false) {
+		return array();
+	}
+
+	if ($spos > $html_autoclose_pos) {
+		$e = "html_autoclose stack underflow; closing down to " .
+		    $spos . " but we're down to " . $html_autoclose_pos .
+		    " already!";
+		throw new Exception($e);
+	}
+
+	$rv = array();
+	while ($spos < $html_autoclose_pos) {
+		$rv[] = $html_autoclose_stack[$spos++];
+	}
+	return $rv;
+}
+
+/**
+ * html_a_apply() - Reopen tags based on an autoclose stack copy
+ *
+ * @param	opaque	$scopy
+ *			return value from html_a_copy()
+ * @return	string
+ *		XHTML string suitable for echo'ing
+ */
+function html_a_apply($scopy) {
+	/* array_reduce() would be useful here... IF IT WORKED, FFS! */
+	$rv = "";
+	foreach ($scopy as $value) {
+		$rv .= html_ao($value['name'], $value['attr']);
+	}
+	return $rv;
+}
+
 // Local Variables:
 // mode: php
 // c-file-style: "bsd"
 // End:
-
-?>




More information about the Fusionforge-commits mailing list