Subversion Repositories PHPX

Compare Revisions

Last modification

Ignore whitespace Rev 1 → Rev 2

/trunk/features.class.php
0,0 → 1,456
<?php
 
require_once 'global.inc';
 
/**
* A list of language features with URNs definitions
* for reference links.
*/
class FeatureList
{
public $versions = array();
/**
* Versions of implementations that are considered safe.
* A feature is considered safe if it does not require
* an implementation version above these versions.
*
* @var Array[string=>string]
*/
public $safeVersions = array();
/**
* URNs that can be used for reference links.
*
* @var Array[string=>string]
*/
protected $urns = array();
/**
* The list of language features
*
* @var array[Features]
*/
protected $items = array();
/**
* Determines the number of printed items the table headings should be repeated
*
* @var int
*/
protected $headerRepeat = 25;
 
/**
* Initializes the FeatureList object
*
* @param array|Object $a
* @return FeatureList
*/
public function __construct($a)
{
$aVars = get_class_vars(__CLASS__);
while ((list($key, $value) = each($aVars)))
{
if (isset($a[$key]))
{
$this->$key = $a[$key];
}
}
/* Inform items of ourself so that URNs can be used for links */
if (is_array($this->items))
{
foreach ($this->items as &$item)
{
$item->setList(&$this);
}
}
/* resolve URN references that are URNs */
if (is_array($this->urns))
{
foreach ($this->urns as &$urn)
{
if (($url = $this->resolveURN($urn)))
{
$urn = $url;
}
}
}
}
public function printHeaders()
{
foreach ($this->versions as $ver)
{
?>
<th><?php echo $ver; ?></th>
<?php
}
}
/**
* Prints the list of features.
*
* @see Feature::printMe()
*/
public function printItems()
{
$counter = 0;
$headerRepeat = $this->headerRepeat;
$repeatHeaders = ($headerRepeat > 1);
foreach ($this->items as $feature)
{
if ($feature instanceof Feature)
{
if ($repeatHeaders
&& $counter > 1
&& $counter % $headerRepeat === 0)
{
?>
<tr class="header">
<th>Feature</th>
<?php $this->printHeaders(); ?>
</tr>
<?php
}
$feature->printMe();
$counter++;
}
}
}
/**
* Resolves a URN according to the value of the
* object's <code>$urn</code> property.
*
* @param string $urn
* URN to be resolved
* @return string|boolean
* The resolved URN if successful,
* <code>false</code> otherwise.
*/
public function resolveURN($urn)
{
if (is_array($this->urns))
{
$reURN = '|^(.+?):(?!//)|';
if (preg_match($reURN, $urn, $m) && isset($this->urns[$m[1]]))
{
return preg_replace($reURN, $this->urns[$m[1]], $urn);
}
}
 
return $urn;
}
}
 
/**
* A language feature.
*/
class Feature
{
/**
* Fragment identifiers to be defined for quickly accessing
* the feature description.
*
* @var Array[String]
*/
protected $anchors = array();
/**
* Value of the explanatory <code>title</code> attribute for the feature.
*
* @var string
*/
protected $title = '';
/**
* Name or example code of the feature
*
* @var string
*/
protected $content = '';
/**
* Description of the feature. Displayed directly if code is missing,
* otherwise used as `title' attribute value.
*
* @var string
*/
protected $descr = '';
/**
* Versions that support this feature
*
* @var Array
*/
protected $versions = array();
/**
* Reference to the FeatureList that this feature belongs to
*
* @var FeatureList
*/
protected $list = null;
public function setList($oList)
{
$this->list =& $oList;
}
 
/**
* Creates a new Feature object, using values from the passed parameters
* array.
*
* @param array|Object $params
* @return Feature
*/
public function __construct($params = array())
{
while ((list($key, $value) = each($params)))
{
// if ($key != 'versions')
// {
if (property_exists(__CLASS__, $key))
{
$this->$key = $value;
}
// }
// else
// {
// $o =& $this->$key;
//
// while ((list($key2, $value2) = each($value)))
// {
// $o[$key2] = $value2;
// }
// }
}
}
/**
* Returns <code>' class="safe"'</code> if the feature
* can be considered safe. The required information
* is stored in the <code>safeVersions</code> property
* of the associated <code>FeatureList</code> object.
*
* @return string
* @see FeatureList::defaultSafeVersions
*/
protected function getSafeStr()
{
if (!is_null($this->list))
{
foreach ($this->list->safeVersions as $impl => &$safeVer)
{
$thisImplVer =& $this->versions[$impl];
if (is_array($thisImplVer))
{
if (isset($thisImplVer['tested']) && !is_bool($thisImplVer['tested']))
{
$thisImplVer =& $thisImplVer['tested'];
}
else
{
$thisImplVer =& $thisImplVer[0];
}
}
/* DEBUG */
// echo " $impl=$thisImplVer ";
if ($thisImplVer === '-' || $thisImplVer > $safeVer)
{
return '';
}
}
return ' class="safe"';
}
else
{
return '';
}
}
protected function getTitleStr()
{
if (!empty($this->title))
{
return " title=\"{$this->title}\"";
}
else
{
return '';
}
}
protected function getAnchors()
{
$result = array();
foreach ($this->anchors as $anchor)
{
$result[] = "<a name=\"{$anchor}\"";
if (preg_match('/^[a-z][a-z0-9_:.-]*/i', $anchor))
{
$result[] = " id=\"{$anchor}\"";
}
$result[] = '></a>';
}
return join('', $result);
}
 
protected function getAssumed($v)
{
if (is_array($v) && isset($v['assumed']) && $v['assumed'])
{
return ' class="assumed"';
}
return '';
}
 
protected function getTested($v)
{
if (is_array($v) && isset($v['tested']) && $v['tested'])
{
return ' class="tested"';
}
return '';
}
/**
* Returns the version of a feature.
*
* @param string|VersionInfo $vInfo
* @return mixed
*/
protected function getVer($vInfo)
{
if (is_array($vInfo))
{
/* TODO: Return all versions: documented, assumed, and tested */
$vNumber = (isset($vInfo['tested'])
&& gettype($vInfo['tested']) !== 'boolean')
? $vInfo['tested']
: $vInfo[0];
$section = isset($vInfo['section'])
? ' <span class="section" title="Specification section">['
. $vInfo['section'] . ']</span>'
: '';
if (isset($vInfo['urn']))
{
if ($this->list instanceof FeatureList)
{
$url = $this->list->resolveURN($vInfo['urn']);
$vNumber = '<a href="' . $url . '">' . $vNumber
. ($section ? $section : '') . '</a>';
}
}
else if ($section)
{
$vNumber .= $section;
}
 
return $vNumber === '-' ? '<span title="No">&#8722;</span>' : $vNumber;
}
else
{
return $vInfo === '-' ? '<span title="No">&#8722;</span>' : $vInfo;
}
}
protected static function shl($s)
{
/* stub */
}
public function printMe()
{
?>
<tr<?php echo $this->getSafeStr(); ?>>
<th<?php echo $this->getTitleStr(); ?>><?php
echo $this->getAnchors();
echo /*preg_replace_callback(
'#(<code>)(.+?)(</code>)#',
array('self', 'shl'),*/
preg_replace('/&hellip;/', '&#8230;', $this->content)/*)*/;
?></th>
<?php
$versions = $this->versions;
if (!is_null($this->list))
{
$versions =& $this->list->versions;
}
 
static $row = 0;
$row++;
$column = 0;
foreach ($versions as $key => $value)
{
$column++;
$id = "td$row-$column";
$ver = $this->versions[$key];
?>
<td id="<?php echo $id; ?>"<?php
echo $this->getAssumed($ver) . $this->getTested($ver);
if (!$key)
{
if (!empty($ver))
{
echo ' title="Test code: ' . htmlspecialchars(stripslashes($ver)) . '"';
}
else
{
echo ' title="Not applicable: No automated test case'
. ' is available for this feature. Please click'
. ' the feature code in the first column to run'
. ' a manual test."';
}
}
?>><?php
if ($key)
{
echo $this->getVer($ver);
}
else
{
if (!empty($ver))
{
?><script type="text/javascript">
// <![CDATA[
var s = test(<?php echo $ver; ?>, '<span title="Yes">+</span>', '<span title="No">&#8722;</span>');
tryThis("document.write(s);",
"document.getElementById('<?php echo $id; ?>').appendChild("
+ "document.createTextNode(s));");
// ]]>
</script><?php
}
else
{
echo '<abbr>N/A</abbr>';
}
}
?></td>
<?php
}
?>
</tr>
<?php
}
}
?>
/trunk/global.inc
0,0 → 1,436
<?php
 
/* @section Helper functions */
 
/**
* Retrieves the value of an element of an associative array.
*
* This is designed for $_GET and other HTTP variables but
* also works for common associative arrays.
*
* @param $key: string
* Key identifier. The default is the empty string.
* @param $array: string
* Array identifier. The default is '_GET'. If there is
* no such array, the identifier is prefixed with 'HTTP'
* and suffixed with '_VARS' (to support the deprecated
* HTTP_GET_VARS etc. arrays as of PHP &lt; 4.1). If
* there is still no array with that identifier, return
* the empty string.
* @param $default: string
* Default return value if the element specified with
* $key is not available in the array. The default
* is the empty string.
* @return
* The value of the element of that array with that key or
* the empty string if there is no such element or array.
* @author
* Copyright (C) 2004, 2005 Thomas Lahn &lt;php@PointedEars.de&gt;
*/
function getVars($key = '', $array = '_GET', $default = '', $noEntities = false)
{
global ${$array};
if (!isset(${'HTTP'.$array.'_VARS'})) global ${'HTTP'.$array.'_VARS'};
/*
echo "<pre>getVars: \$$array"."['$key']: return '"
.(isset(${$array}) && isset(${$array}[$key])
? ${$array}[$key]
: (isset(${'HTTP'.$array.'_VARS'}) && isset(${'HTTP'.$array.'_VARS'}[$key])
? ${'HTTP'.$array.'_VARS'}[$key]
: $default)) . "'</pre><br>\n";
*/
$result = (isset(${$array}) && isset(${$array}[$key])
? ${$array}[$key]
: (isset(${'HTTP'.$array.'_VARS'}) && isset(${'HTTP'.$array.'_VARS'}[$key])
? ${'HTTP'.$array.'_VARS'}[$key]
: $default));
 
// TODO: Escape HTML entities
/*
if (!$noEntities)
{
$result = htmlentities($result);
}
*/
return $result;
}
 
/**
* Converts the argument to a visible (X)HTML hyperlink
* where its URI target is created from the argument.
* Supported are e-mail addresses, domain names with
* optional paths, and valid URIs.
*
* @param $text
* Argument to be converted.
* @return
* The converted argument if it applies to a supported
* scheme, the unconverted argument otherwise.
*
* @author (C) 2001-04-04T02:03
* mark.young@vdhinc.com at http://php.net/manual/en/ref.strings.php
*
* Minor correction to my HTMLEncode function.
*
* @author 2002-08-29T09:00
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Added target="_blank"
* - Added support for ftp(s)-URIs: (ht|f)
* - Added support for search strings (?...=...&...=...), either
* with or without HTML entities: \?=(&\w;|&)
* - Removed enclosing nl2br call because of preformatted display
*
* @author 2003-12-30T14:18
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Removed target="_blank".
* - Added PHPdoc.
*
* @author 2004-01-12T12:45
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Added support for #fragment_identifiers in URIs.
* - Added support for bugs and comments.
*
* @author 2004-01-13T01:29
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Added support for bug aliases.
*
* @author 2004-01-26T20:43
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Do not convert URIs in A elements.
* - Do not allow URIs with "&" before search-string.
* - camelCased function identifier. Only classes
* and constructors should start with uppercase.
*
* @author 2004-01-27T14:07
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Allow to convert URIs preceded by "&gt;" but not followed by "&lt;/a&gt;".
* - Allow ";" to be part of the search string
*
* @author 2004-01-29T14:10
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Require valid domain name for "bar" on conversion of "foo@bar" and
* "www.bar".
* - Be case-insensitive except of bug aliases
* - Escaped "-" in character classes if not meant as range metacharacter.
* - Corrected year.
*
* @author 2004-02-14T17:37
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Accept only valid Internet domain names
* - Accept "%" within path and query part (to escape ASCII characters)
*
* @author 2004-02-27T19:21
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Allow unescaped ":" in URI components, since it apparently does not
* "conflict with the reserved purpose" (RFC 2396, section 2.2.; here:
* scheme component)
* - Allow slashes, dots and dashes in URI components
* - Removed invalid [...(...|...)...]
*
* @author 2004-03-01T21:48
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Allow IPv4 addresses
*
* @author 2004-03-08T02:20
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Allow "+" and "," in query part
* - Optimized character classes
*
* @author (C) 2004-04-23T10:03
* Thomas Lahn &lt;PointedEars@selfhtml.de&gt; at localhost
*
* - Rewrite to use RFC 2822 and 2369 syntax
*/
function htmlEncode($text)
{
// see RFC 2822 "Internet Message Format"
$local_part = '[^()<>@,;:\\"\-\[\] \x00-\x1A\x7F]+';
// see RFC 2396 "Uniform Resource Identifiers (URI): Generic Syntax"
// $digit = '\d'; // 0-9; def. not required
// $hex = '\da-f'; // "hex" for case-insensitive match; def. N/R
$alpha = 'a-z'; // "alpha" for case-insensitive match
$alphanum = $alpha.'\d'; // "alphanum" for case-insensitive match
$mark = "\-_.!~*\'()";
$reserved = ';/?:@&=+$,';
$unreserved = $alphanum.$mark;
$escaped = '%[\da-f]'; // contains $hex
// added (?!gt;) to allow "&lt;URI&gt;"
$uric = '(['.$reserved.$alphanum.$mark.'](?!gt;)|'.$escaped.')';
$uric_no_slash = '(['.$unreserved.';\?:@&=+$,](?!gt;)|'.$escaped.')';
$pchar = '(['.$unreserved.':@&=+$,](?!gt;)|'.$escaped.')';
$param = $pchar;
$segment = $pchar.'*(;'.$param.')*';
$abs_path = '/' . $segment . '(/'.$segment.')*';
$userinfo = '(['.$unreserved.';:&=+$,](?!gt;)|'.$escaped.')*';
$domainlabel = '(['.$alphanum.']'
. '|['.$alphanum.'](['.$alphanum.']|-)*['.$alphanum.']'
. ')';
$toplabel = '(['.$alpha.']'
. '|['.$alpha.'](['.$alphanum.']|-)*['.$alphanum. '])';
$hostname = '('.$domainlabel. '\.)*' . $toplabel . '\.?';
$ipv4_address = '\d+\.\d+\.\d+\.\d+';
$host = '(' . $hostname . '|' . $ipv4_address . ')';
$port = '\d*';
$hostport = $host . '(:' . $port . ')?';
$server_req = '(' . $userinfo . ')?' . $hostport; // server is required
$reg_name = '([' . $unreserved . '$,;:@&=+](?!gt;)|' . $escaped . ')+';
$authority = '(' . $server_req . '|' . $reg_name . ')';
$net_path = '//' . $authority . '('.$abs_path.')?';
$query = $uric.'*';
$scheme = '(ht|f)tps?';
$hier_part = '(' . $net_path .'|' . $abs_path . ')(\?' . $query . ')?';
$opaque_part = $uric_no_slash . $uric.'*';
$absolute_uri = $scheme . ':(' . $hier_part . '|' . $opaque_part . ')';
$fragment = $uric.'*';
// absolute URIs only
$uri_reference = $absolute_uri . '(#' . $fragment . ')?';
// echo '<br>'.htmlentities($local_part . '@' . $host).'<br>';
 
$searcharray = array(
"'(?i)(" . $local_part . '@' . $host . ")'i",
"'(?i)((?:(?!://).{3}|^.{0,2}))(www\." . $hostname
. '|' . $ipv4_address . ")'i",
"'(?i)(?<!href=\")(" . $uri_reference . ")(?!</a>)'i",
"'(((?i)bug)\s+#?([\dA-Z_]+)\s+((?i)comment|Kommentar)\s+#?(\d+))'",
"'(((?i)bug)\s+#?([\dA-Z_]+))'",
"'(((?i)comment|Kommentar)\s+#?(\d+))'"
);
 
$replacearray = array(
"<a href=\"mailto:\\1\">\\1</a>",
"\\1http://\\2",
"<a href=\"\\1\">\\1</a>",
"<a href=\"./?bug=\\3#c\\5\">\\1</a>",
"<a href=\"./?bug=\\3#details\">\\1</a>",
"<a href=\"#c\\3\">\\1</a>"
);
return preg_replace($searcharray, $replacearray, $text);
}
 
/**
* Converts the argument into a visible (X)HTML hyperlink if a condition
* applies.
*
* @author
* (C) 2003, 2004 Thomas Lahn &lt;selfhtml.de@PointedEars.de&gt;
* @param $s
* Content to be converted. Required.
* @param $sCond
* Condition to be true for the content to be converted.
* The default is <code>true</code>.
* @param $sURI
* Target URI of the hyperlink. The default is the
* value of $s.
* @param $sName
* Value of the <code>name</code> attribute of the
* <code>a</code> element. Unused if not provided
* or empty.
* @param $sTitle
* Value of the <code>title</code> attribute of the
* <code>a</code> element. Unused if not provided
* or empty.
* @param $sClass
* Value of the <code>class</code> attribute of the
* <code>a</code> element. Unused if not provided
* or empty.
* @return
* The converted argument if the condition applies,
* the unconverted argument otherwise.
*/
function makeLinkIf(
$s,
$sCond = true,
$sURI = NULL,
$sTarget = '',
$sName = '',
$sTitle = '',
$sClass = '')
{
return ($sCond || $sName
? '<a' . ($sCond
? " href=\"" . (is_null($sURI) ? $s : $sURI)
. "\"".($sTarget ? " target=\"$sTarget\"" : '')
: ''
)
. ($sName ? " name=\"$sName\"" : '')
. ($sTitle ? " title=\"$sTitle\"" : '')
. ($sClass ? " class=\"$sClass\"" : '')
. '>'
: ''
)
. $s
. ($sCond || $sName ? '</a>' : '');
}
 
/**
* Returns a visible (X)HTML hyperlink that uses the mailto: URI scheme.
*
* @author (C) 2003 Thomas Lahn &lt;selfhtml.de@PointedEars.de&gt;
*
* @author (C) 2003-12-30 Thomas Lahn &lt;selfhtml.de@PointedEars.de&gt;
* - Corrected `$email ($name)'.
* - Now uses rawurlencode(...).
* - Added PHPdoc.
*
* @author (C) 2004-11-30 Thomas Lahn &lt;selfhtml.de@PointedEars.de&gt;
* - Don't rawurlencode(...) parens for comments.
*
* @param $sAddress
* E-mail address. The default is <selfhtml.de@PointedEars.de>.
* @param $sTitle
* Value of the <code>title</code> attribute of the
* <code>a</code> element. Unused if not provided
* or empty. The default is 'PointedEars'.
* @param $sToName
* Name to be used in the To header of the e-mail.
* Note that @link{rawurlencode()} is used to escape
* special characters automatically.
* The default is "Thomas 'PointedEars' Lahn".
*
* @return
* The converted argument if the condition applies,
* the unconverted argument otherwise.
*/
function mailto_link(
$sAddress = 'selfhtml.de@PointedEars.de',
$sTitle = 'PointedEars',
$sToName = "Thomas 'PointedEars' Lahn",
$sSubject = 'SELFbug',
$sImgPath = '../../media/mail.gif'
)
{
//width="14" height="15" // image size detection not yet implemented
return ($sImgPath != ''
? '<img src="' . $sImgPath . '" border="0" alt="@">&nbsp;'
: '')
. '<a href="mailto:'
. ($sAddress != ''
? $sAddress
: 'selfhtml.de@PointedEars.de')
. ($sToName != ''
? ' (' . rawurlencode($sToName) . ')'
: '')
. ($sSubject != ''
? '?subject=' . rawurlencode($sSubject)
: '')
. '">' . (($sTitle != '') ? $sTitle : $sAddress) . '</a>';
}
 
// map bug states to numbers so that they become comparable
function array_values_to_keys($a)
{
$aNew = array();
foreach ($a as $key => $value)
{
$aNew[$value] = count($aNew);
}
return $aNew;
}
 
/**
* Converts a string or an array of strings to an associative
* bitmask array with the string(s) as key(s).
*
* Converts the argument to a bitmask array where each member's
* value is a power of 2, so that arbitrary member values can be
* added to an integer on which bitwise operations with the member
* value or a combination of member values are possible.
*
* @author (c) 2003 Thomas Lahn &lt;SELFbug@PointedEars.de&gt;
* @param $aArray
* String or array of strings to be converted.
*/
function getBitmaskArray($aArray)
{
$a = array();
if (is_array($aArray))
{
for ($i = 0; $i < count($aArray); $i++)
{
$a[$aArray[$i]] = pow(2, $i);
}
}
else
$a[$aArray] = 1;
return $a;
}
 
/**
* Returns the contents of a file as if include() was used.
*
* @param string $filename Path of the file to retrieve
* @return string File contents
*/
function get_include_content($filename)
{
if (is_file($filename))
{
ob_start();
include $filename;
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
return '';
}
/**
* Replaces each group of expressions in a string with the same
* corresponding string.
*
* @param Array[Array[string] | string, string] $map
* @param string $subject
* @return string
* A copy of $subject with the provided mapping applied.
*/
function preg_replace_group($map = array(), $subject = '')
{
if ($subject)
{
for ($i = 0, $len = count($map); $i < $len; $i++)
{
$subject = preg_replace($map[$i][0], $map[$i][1], $subject);
}
}
 
return $subject;
}
 
/**
* Randomly encodes a string of characters.
*
* @param string $s
* String to be encoded
* @param string $format = 'sgml'
* Encoding format. Currently only SGML-based encoding of
* ASCII characters with character references is supported.
* @return string
*/
function randomEsc($s = '', $format = 'sgml')
{
$f = function_exists('mt_rand') ? 'mt_rand' : 'rand';
return preg_replace_callback('/[\\x00-\\x7F]/',
create_function('$m', "return $f(0, 1)" . '? $m[0] : "&#" . ord($m[0]) . ";";'),
$s);
}
 
?>