<?php
require_once('prod_ini_settings.php');
// display a listing of the PHP manual page info regarding php.ini settings
// sort the listing by any column, with sub-sorts by any other column

// This version uses a local tab-delimited text file for input.
// Next version will use the current php.net manual page, if available,
// otherwise a local tab-delimited text file will be used.

// Displays a heading at the top of the listing, with user-specified sort order
// using integers 1, 2, 3, 4 to indicate sort priority (grouping) for the cols
// example 1) 1,2,3,4 means
//  sort by col 1, then sort by col 2, then by col 3, then by col 4

// example 2) 2,4,1,3 means
//  sort by col 3, then sort by col 1, then by col 4, then by col 2

// Undefined sort priorities are not allowed.  I.e., ',3,1,4' or '4,,1,'
// are not permitted.  Missing or out of range values result in the default
// priority specification '1,2,3,4'.
// E.g., '36, 3, 1, 4'; '4, 35, -1, 1'; '4, 36, 1, 97'; '4, 2, 1, 0'
// are all replaced with '1,2,3,4'.

// Non-mutually-exclusive input is replaced, left to right, with unused valid
// values. See the following examples for treatment of such input:
// '3, 3, 1, 4' is replaced with '3, 2, 1, 4'
// '4, 1, 3, 1' is replaced with '4, 1, 3, 2'
// '3, 3, 2, 2' is replaced with '3, 1, 2, 4'

/*Design
1. read text file of current php.ini settings manual page info into array
2. display column headings and default column sort priorities
3. accept and validate form input
4. sort array per form input
5. display the data accordingly
(if form is submitted again, perform steps 3 through 5)
*/
// initialize variables
$ini_table_name = array();
$ini_table_default = array();
$ini_table_changeable = array();
$ini_table_changelog = array();
$name = $default = $changeable = $changelog = '';

// read text file of current php.ini settings manual page info into array
$fp = fopen('ini_table.txt', 'rb');
// need to check for failure and handle it!

// read column headings
list($name, $default, $changeable, $changelog) = fscanf($fp, '%s %s %s %s');
// need to handle possibility of fscanf failure

// read table data
$i = 0;
while (!feof($fp)) {
    // read line into arrays; preserve whitespace in changelog field if non-empty
    $line = fgets($fp); // what if fgets fails?
    $tabs = substr_count($line, "\t"); // 2 tabs: changelog empty; 3: non-empty
    sscanf($line, '%s %s %s',
        $ini_table_name[$i], $ini_table_default[$i],
        $ini_table_changeable[$i]);
    $ini_table_changelog[$i] = (3 === $tabs) ?
        substr($line, strrpos($line, "\t")) : '';
    $i++;
}
fclose($fp);

// sort priorities (sort by col1, then by col2, etc.)
// key is priority, value is the displayed column
// i.e., $sort_priority[1] yields the first column by which to sort, while
// $sort_priority[3] yields the third highest column by which to sort

// Get sort priority from form input, or use defaults if not specified
// Validate input before using the supplied values.  If anything is wrong,
// use default values '1,2,3,4'.
if ((4 === count($_GET)) and isset($_GET['priority1'], $_GET['priority2'],
    $_GET['priority3'], $_GET['priority4']))
{
    $p1 =& $_GET['priority1']; $p2 =& $_GET['priority2'];
    $p3 =& $_GET['priority3']; $p4 =& $_GET['priority4'];
    $p1 = (int)$p1; $p2 = (int)$p2;
    $p3 = (int)$p3; $p4 = (int)$p4;
    // if out of range values are supplied, set to '1,2,3,4'
    if ($p1 < 1 or $p1 > 4 or $p2 < 1 or $p2 > 4
        or $p3 < 1 or $p3 > 4 or $p4 < 1 or $p4 > 4)
    {
        $p1 = 1; $p2 = 2; $p3 = 3; $p4 = 4;
    }
    // Replace non-mutually-exclusive inputs with suitable values
    // see what values are not used in the original input set
    $non_mutex_keys = array();
    $input = array(1 => $p1, $p2, $p3, $p4);
    $avail = array(4 => 4, 3 => 3, 2 => 2, 1 => 1);
    foreach ($input as $k => $v) {
        if (isset($avail[$v])) {
            unset($avail[$v]);
        } else { // duplicate sort priority value found
            $non_mutex_keys[] = $k; // save index for later assignment
        }
    }
    // replace the duplicates, from left to right, with remaining valid values
    if (!empty($avail)) {
        foreach ($non_mutex_keys as $index) {
            ${'p' . (string)$index} = array_pop($avail);
        }
    }
    // establish the sort priorities
    $sort_priority = array();
    $sort_priority[$p1] = 'name';
    $sort_priority[$p2] = 'default';
    $sort_priority[$p3] = 'changeable';
    $sort_priority[$p4] = 'changelog';
} else { // if values have been tampered with, set to '1,2,3,4'
    $sort_priority = array(1 => 'name', 2=> 'default', 3 => 'changeable',
        4 => 'changelog');
}

// sort the array according to the form settings
array_multisort(
    ${'ini_table_' . $sort_priority[1]},
    ${'ini_table_' . $sort_priority[2]},
    ${'ini_table_' . $sort_priority[3]},
    ${'ini_table_' . $sort_priority[4]});
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD><TITLE>PHP: Sortable Table of php.ini Directives</TITLE></HEAD>
<BODY>
<TABLE width="100%" border="1">
<CAPTION>Legend for the PHP_INI_* constants that appear in the php.ini
directives table below.  Source: PHP Manual Appendix (Currently Appendix G)
<CAPTION />
<TR><TH>Constant</TH>
    <TH>Value</TH>
    <TH>Meaning</TH>
</TR>
<TR><TD>PHP_INI_USER</TD>
    <TD>1</TD>
    <TD>Entry can be set in user scripts or in Windows registry</TD>
</TR>
<TR><TD>PHP_INI_PERDIR</TD>
    <TD>2</TD>
    <TD>Entry can be set in php.ini, .htaccess or httpd.conf</TD>
</TR>
<TR><TD>PHP_INI_SYSTEM</TD>
    <TD>4</TD>
    <TD>Entry can be set in php.ini or httpd.conf</TD>
</TR>
<TR><TD>PHP_INI_ALL</TD>
    <TD>7</TD>
    <TD>Entry can be set anywhere</TD>
</TR>
</TABLE>

<P>Below is a <STRONG>sortable table of php.ini directives</STRONG>.&nbsp;&nbsp;
Use the radio buttons to sort the table by the columns of your choice.&nbsp;&nbsp;
The numbers below the column headings indicate the current sort priority
(grouping) for the displayed data.&nbsp;&nbsp;
I.e., (1,2,3,4) means Column 1 is sorted first, followed by Column 2, then
Column 3, then Column 4.&nbsp;&nbsp;
(2,4,1,3) means Column 3 is sorted first, followed by Column 1, then
Column 4, then Column 2.&nbsp;&nbsp;
If you apply the same 'group by' level to multiple columns, that input
is automatically corrected by replacing the non-mutually-exclusive values,
left to right, with unused (remaining) valid values.&nbsp;&nbsp;See the
following examples for treatment of such input:<BR />
(3, 3, 1, 4) is replaced with '3, 2, 1, 4'<BR />
(4, 1, 3, 1) is replaced with '4, 1, 3, 2'<BR />
(3, 3, 2, 2) is replaced with '3, 1, 2, 4'<BR />
For your convenience, during this session, the most recently used sort
priority is preserved in the radio buttons.&nbsp;&nbsp;No cookies are stored
on your computer to do this.&nbsp;&nbsp;The default 'group by' settings will
appear the next time you visit this site.
</P>

<?php
// display column headings and sort priority form
$p1 = array_search('name', $sort_priority);
$p2 = array_search('default', $sort_priority);
$p3 = array_search('changeable', $sort_priority);
$p4 = array_search('changelog', $sort_priority);

echo '<TABLE width="100%" border="2" rules="all">' .
    '<CAPTION>This table lists the php.ini directives you can set to configure your PHP setup.</CAPTION>' .
    "<THEAD><TR><TH>$name</TH><TH>$default</TH><TH>$changeable</TH><TH>" .
    "$changelog</TH></TR>";
echo '<TR><TH>' .$p1. '</TH><TH>' .$p2. '</TH><TH>' .
    $p3. '</TH><TH>' .$p4. '</TH></TR></THEAD>' .
    '<TR><FORM action="' .basename(__FILE__). '" method="get" ' .
    'title="Select a sort priority for each column">';

for ($col = 1; $col < 5; $col++) {
    echo '<TD title="Sort Priority for Column ' .$col. '">';
    for ($i = 1; $i < 5; $i++) {
        echo "<INPUT type=\"radio\" name=\"priority$col\" value=\"$i\"" .
        // radio buttons match the most recently applied sort priorities
            (($i === ${"p$col"}) ? ' checked' : '') . ' />'. $i .
        // text to indicate how to use the radio buttons
            ((1===$i) ? ' (Sort this column first)' : '') .
            ((4===$i) ? ' (Sort this column last)' : '') . '<BR />';
    }
    echo '</TD>';
}
?>

</TR>
<TR><TD colspan="4" style="text-align: center">
    <INPUT type="submit" value="Apply Sort" title="Apply Sort">
    <INPUT type="reset" value="Reset to Default Priorities"
    title="Reset to Default Priorities">
    </TD>
</TR>
</FORM>

<?php
// display table data
$i = 0;
$c = count($ini_table_name);
while ($i < $c) {
    echo '<TR><TD>' . $ini_table_name[$i] . '</TD><TD>'
        . $ini_table_default[$i] . '</TD><TD>'
        . $ini_table_changeable[$i] . '</TD><TD>'
        . $ini_table_changelog[$i] . '</TD></TR>';
    $i++;
}
echo '</TABLE>';
?>
</BODY></HTML>