Source for file PHPConfig.php
Documentation is available at PHPConfig.php
* Class for GUI-based configuration of a php.ini file
* This class is based on the PHP-Gtk2 extension and provides a
* user-friendly interface for editing php.ini files. All the possible
* configuration options have been defined in a separate XML file .
* This allows for easy addition of directives as PHP is
* The class can parse any existing ini file, or create new ones. Parsing
* of existing files is currently a little inefficient, suggestions for
* improvement are welcome. New files and files previously generated by
* Gtk2_PHPConfig are parsed at a good speed though.
* The interface displays all available configuration sections on the left
* pane, and their corresponding options in the top right pane. The bottom
* right pane displays the description of the option selected and the
* facility to change the value of that option.
* @todo Implement Christian's suggestion of asking for confirmation when a
* file is overwritten while doing a "save as"
* @todo Add facility to add directives, apart from additions to XML
* @todo Clicking Cancel on the File-Open dialog generates a notice
* @author Anant Narayanan <anant@php.net>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear.php.net/package/Gtk2_PHPConfig
* @author Anant Narayanan <anant@php.net>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear.php.net/package/Gtk2_PHPConfig
* Tree that displays the available configuration sections.
* Tree that displays the current section's corresponding options.
* Description of the currently selected option.
* Comments associated with the currently selected option.
* The entry box that will accept the value of the current option from
* The file name of the php.ini file currently open. Will be set to
* null if a new file is to be generated.
* The XML definition file holding descriptions of all possible php.ini
* The XPath object to the XML definition file.
* A flag that determined whether the current file is saved or not.
* A buffer used to temporarily store the contents of the currently
* open file when the save as option is used
* The "buffer" array that stores the current values of all the
* The progress window that displays the percentage by which a file
* The extension modules loaded/unloaded in the current file parsed.
const TITLE = "The PHP Configuration GUI";
* Array Index - Current Value of a directive
* Array Index - Default Value of a directive
* Array Index - Line number of directive
* Array Index - Comments in a directive
* Array Index - InLine comments of directive
* Extension Option - Extension is enabled
* Extension Option - Extension is disabled
* Sets the classes' properties and calls the creation of the GUI
* @param string $fileName Filename of the ini file to be edited.
* Will be null if a new file is to be created.
include_once "PEAR/Config.php";
$this->xmlDefs = new DomDocument ();
$dataDir = PEAR_Config ::singleton ()->get ("data_dir") .
DIRECTORY_SEPARATOR . "Gtk2_PHPConfig";
$this->xmlDefs->load ($dataDir. "/phpinidefs.xml");
* Creates the user interface to facilitate editing of the ini files.
* Also calls other functions that parse the XML definition file and
* then displays the configuration options.
/* Creating the layout boxes */
$MainVBox = new GtkVBox ();
$TopHPane = new GtkHPaned ();
$TopHPane->set_position (200 );
$rightVPane = new GtkVPaned ();
/* Displaying the configuration sections */
// add sectionList to a scrolled window
$leftScroll = new GtkScrolledWindow ();
$leftScroll->set_policy (Gtk ::POLICY_NEVER , Gtk ::POLICY_AUTOMATIC );
$leftScroll->add ($sectionList);
/* Creating the tree that will display configuration options */
$model = new GtkListStore (Gobject ::TYPE_STRING ,
$tree = new GtkTreeView ($model);
$rightScroll = new GtkScrolledWindow ();
$rightScroll->set_policy (Gtk ::POLICY_AUTOMATIC , Gtk ::POLICY_AUTOMATIC );
$rightScroll->add ($tree);
$rightScroll->set_size_request (-1 , 400 );
$bottomHBox = new GtkHBox ();
$rightVPane->pack1 ($rightScroll);
$rightVPane->pack2 ($bottomHBox);
$TopHPane->add1 ($leftScroll);
$TopHPane->add2 ($rightVPane);
$MainVBox->pack_start ($this->buildMenu(), false , false );
$MainVBox->pack_start ($TopHPane, true , true );
/* Initialise the main window */
$this->set_size_request (800 , 600 );
$this->set_position (Gtk ::WIN_POS_CENTER );
$this->connect_simple ("delete-event", array ($this, "quit"));
* Creates and returns the menu for the GUI
* @return GtkMenuBar The Menu bar of the GUI
$theMenu = new GtkMenuBar ();
$menuAccel = new GtkAccelGroup ();
$this->add_accel_group ($menuAccel);
$fileMenu = new GtkMenu ();
$fileNew = new GtkImageMenuItem (Gtk ::STOCK_NEW , $menuAccel);
$fileNew->connect_simple ("activate", array ($this, "newFile"));
$fileMenu->append ($fileNew);
$fileOpen = new GtkImageMenuItem (Gtk ::STOCK_OPEN , $menuAccel);
$fileOpen->connect_simple ("activate", array ($this, "openFile"));
$fileMenu->append ($fileOpen);
$fileSep = new GtkSeparatorMenuItem ();
$fileMenu->append ($fileSep);
$fileSave = new GtkImageMenuItem (Gtk ::STOCK_SAVE , $menuAccel);
$fileSave->connect_simple ("activate", array ($this, "saveFile"));
$fileMenu->append ($fileSave);
$fileSaveAs = new GtkImageMenuItem (Gtk ::STOCK_SAVE_AS , $menuAccel);
$fileSaveAs->connect_simple ("activate", array ($this, "onSaveFileAs"));
$fileMenu->append ($fileSaveAs);
$fileQuit = new GtkImageMenuItem (Gtk ::STOCK_QUIT , $menuAccel);
$fileQuit->connect_simple ("activate", array ($this, "quit"));
$fileMenu->append ($fileQuit);
$fileButton = new GtkMenuItem ("_File");
$fileButton->set_submenu ($fileMenu);
$theMenu->append ($fileButton);
* Creates and the description and comment boxes.
* @return GtkVBox The descriptiona and comment boxes.
/* Layout for the description and value setting boxes */
$descVBox = new GtkVBox ();
$descTitle = new GtkFrame ("Description");
$descWindow = new GtkScrolledWindow ();
$descWindow->set_policy (Gtk ::POLICY_AUTOMATIC , Gtk ::POLICY_AUTOMATIC );
$description = new GtkTextBuffer ();
$descShow = new GtkTextView ($description);
$descShow->set_wrap_mode (Gtk ::WRAP_WORD );
$descShow->set_size_request (-1 , 150 );
$descWindow->add ($descShow);
$commentTitle = new GtkFrame ("Comments");
$commentWindow = new GtkScrolledWindow ();
$commentWindow->set_policy (Gtk ::POLICY_AUTOMATIC , Gtk ::POLICY_AUTOMATIC );
$comments = new GtkTextBuffer ();
$commentShow = new GtkTextView ($comments);
$commentShow->set_wrap_mode (Gtk ::WRAP_WORD );
$commentWindow->add ($commentShow);
$descVBox->pack_start ($descTitle, false , false );
$descTitle->add ($descWindow);
$descVBox->pack_start ($commentTitle, false , false );
$commentTitle->add ($commentWindow);
* Creates and returns the value setting box
* @return GtkVBox The Value setting box.
$valueVBox = new GtkVBox ();
$valueLabel = new GtkLabel ("Set a value for the option");
$entryBox = new GtkHBox ();
$valueEntry = new GtkEntry ();
$valueEntry->connect_simple ("activate", array ($this, "onValueSubmit"));
$valueUnset = new GtkButton (null );
$unsetIcon = GtkImage ::new_from_stock (Gtk ::STOCK_CANCEL ,
$valueUnset->set_image ($unsetIcon);
$entryBox->pack_start ($valueEntry, true , true );
$entryBox->pack_start ($valueUnset, false , false );
$valueSubmit = new GtkButton ("Set Value");
$commentLabel = new GtkLabel ("Comments are also added\n" .
"Use the red cross to unset.");
$setIcon = GtkImage ::new_from_stock (Gtk ::STOCK_OK ,
$valueSubmit->set_image ($setIcon);
$valueSubmit->connect_simple ("clicked", array ($this, "onValueSubmit"));
$valueUnset->connect_simple ("clicked", array ($this, "onValueUnset"));
/* Adding all the widgets and finalising layout */
$valueVBox->pack_start ($valueLabel, false , false );
$valueVBox->pack_start ($entryBox, false , false );
$valueVBox->pack_start ($valueSubmit, false , false );
$valueVBox->pack_start ($commentLabel, false , false );
* Generates a list of available configuration sections after parsing
* the XML definition file.
/* Creating a new model to store configuration sections */
$model = new GtkListStore (Gobject ::TYPE_STRING );
foreach ($listItems as $item) {
$model->append (array ($item));
$tree = new GtkTreeView ($model);
$renderer = new GtkCellRendererText ();
$tree->append_column (new GtkTreeViewColumn ("Sections",
$itemSelect = $tree->get_selection ();
$itemSelect->set_mode (Gtk ::SELECTION_SINGLE );
$itemSelect->connect ("changed", array ($this,"onSectionSelect"));
* Sets the description of the configuration option currently selected
* and displays it along with comments, if any.
* @param object $selected selected object
list ($model, $iter) = $selected->get_selected ();
list ($sModel, $sIter) = $this->sectionTree->get_selection ()->get_selected ();
$option = $model->get_value ($iter, 0 );
$section = $sModel->get_value ($sIter, 0 );
/* Querying XML definition file for configuration options
* corresponding to the currently selected confugration section
if ($section == "Dynamic Extensions") {
$desc = $this->xpath->query ('/php-config-options/section/option[@id="extension"]/desc')->item (0 )->nodeValue;
$desc = $this->xpath->query ('/php-config-options/section/option[@id="'. $option. '"]/desc')->item (0 )->nodeValue;
$defvalue = $this->xpath->query ('/php-config-options/section/option[@id="'. $option. '"]/default')->item (0 )->nodeValue;
* Retreives and displays the set of configuration options associated
* with the currently selected configuration section.
* @param GtkTreeSelection $selected Selection object corresponding to the
* currently selected configuration section.
list ($model, $iter) = $selected->get_selected ();
$section = $model->get_value ($iter, 0 );
/* Filling the model with corresponding configuration options */
foreach ($optionList as $option) {
$optionModel->append (array ($option[0 ], $option[1 ], $option[2 ]));
$cell = new GtkCellRendererText ();
//what to name the column?
if ($section = "Dynamic Extensions") {
$nameColumn = new GtkTreeViewColumn ("Extension", $cell, "text", 0 );
$nameColumn = new GtkTreeViewColumn ("Option", $cell, "text", 0 );
$currColumn = new GtkTreeViewColumn ("Current Value", $cell, "text", 1 );
$defColumn = new GtkTreeViewColumn ("Default Value", $cell, "text", 2 );
$nameColumn->set_sort_column_id (0 );
$nameColumn->set_resizable (true );
$currColumn->set_sort_column_id (1 );
$currColumn->set_resizable (true );
$defColumn->set_sort_column_id (2 );
$defColumn->set_resizable (true );
$optionSelect = $this->optionTree->get_selection ();
$optionSelect->set_mode (Gtk ::SELECTION_SINGLE );
$optionSelect->connect ("changed", array ($this, "onOptionSelect"));
/* Initial description is empty */
* Returns an array of possible configuration sections after parsing the
$sectionNodes = $this->xmlDefs->getElementsByTagName ("section");
foreach ($sectionNodes as $sectionNode) {
$sectionName = $sectionNode->getAttribute ("name");
$sections[] = $sectionName;
* Returns an array of possible configuration options corresponding to
* a particular configuration section.
* @param string $section Name of the configuration section for
* which the configuration options must be
if ($section== "Dynamic Extensions") {
foreach ($this->extensions as $extName=> $extData) {
$extData[self ::DIR_CURRENT ],
$this->xpath->query ('/php-config-options/section[@name="' .
foreach ($optionNodes as $optionNode) {
$optionName = $optionNode->getAttribute ("id");
* Saves the current state of configuration into a file. Filename will
* be prompted for if a new file is to be generated.
* @param bool $saveas is this a 'saveas' operation. default to false.
foreach ($toWrite as $option=> $value) {
/* Empty or Disabled configuration options are not written
$lineNumber = $value[self ::DIR_NUMBER ];
if (trim($value[self ::COMMENT_INLINE ]) == "") {
$inline = " ;". $value[self ::COMMENT_INLINE ]. "\n";
if ($value[self ::DIR_CURRENT ] != "Disabled" &&
trim($value[self ::DIR_CURRENT ]) != "") {
if (trim($value[self ::COMMENT_NORMAL ]) != "") {
$theFile[$lineNumber] = "\n;/ ". str_replace("\n", "\n;/ ",
$value[self ::COMMENT_NORMAL ]). "\n";
$theFile[$lineNumber] = $option . " = " .
$value[self ::DIR_CURRENT ] . $inline;
} elseif ($value[self ::DIR_CURRENT ] == "Disabled" ||
trim($value[self ::DIR_CURRENT ]) == "") {
$theFile[$lineNumber] = ";"
. $value[self ::DIR_DEFAULT ] . $inline;
$lineNumber = $value[self ::DIR_NUMBER ];
if (trim($value[self ::COMMENT_INLINE ]) == "") {
$inline = " ;". $value[self ::COMMENT_INLINE ]. "\n";
if ($value[self ::DIR_CURRENT ] == self ::EXT_ENABLED ) {
$theFile[$lineNumber] = "extension = ". $extName. $inline;
$theFile[$lineNumber] = ";extension = ". $extName. $inline;
/* New file to be saved, prompt for filename */
$filePrompt = new GtkFileChooserDialog ("Save file as:",
Gtk ::FILE_CHOOSER_ACTION_SAVE ,
if ($filePrompt->run () == Gtk ::RESPONSE_ACCEPT ) {
* Called in case a new file is to be generated after a filename has
* been prompted for. Sets the filename property to the filename chosen
* by the user and calls the saveFile() function.
* @param GtkFileSelection $filePrompt File selection dialog
* @param bool $saveas is this a 'saveas' operation.
$this->fileName = $filePrompt->get_filename ();
* Called in case the "Save As..." option is selected. The function
* will prompt for a filename to save the file as.
* Sets the new user-defined value for the configuration option in the
list ($model, $iter) = $selection->get_selected ();
$option = $model->get_value ($iter, 0 );
$section = $sModel->get_value ($sIter, 0 );
$model->set ($iter, 1 , $value);
/* Retreive the comments, if any, in the buffer */
$comments = $comments->get_text ($comments->get_start_iter (),
$comments->get_end_iter ());
if ($section == "Dynamic Extensions") {
$this->extensions[$option][self ::DIR_CURRENT ] = $value;
if (trim($comments) != "") {
$this->extensions[$option][self ::COMMENT_NORMAL ] = $comments;
$this->optionIndex[$option][self ::DIR_CURRENT ] = $value;
if (trim($comments) != "") {
$this->extensions[$option][self ::COMMENT_NORMAL ] = $comments;
/* Set saved flag to false */
* Unsets the value of the currently selected configuration directive to
* disabled so that it does not appear in the configuration file.
list ($model, $iter) = $selection->get_selected ();
list ($sModel, $sIter) = $this->sectionTree->get_selection ()->get_selected ();
$option = $model->get_value ($iter, 0 );
$section = $sModel->get_value ($sIter, 0 );
$model->set ($iter, 1 , "Disabled");
if ($section == "Dynamic Extensions") {
$this->extensions[$option][self ::DIR_CURRENT ] = self ::EXT_DISABLED;
$this->optionIndex[$option][self ::DIR_CURRENT ] = "Disabled";
* Parses the XML definition file and returns the initial state of the
* buffer. Additionally, if an existing file is opened, parses that
* file and modifies the buffer to reflect the current state of that
$optionNodes = $this->xmlDefs->getElementsByTagName ("option");
foreach ($optionNodes as $node) {
$options[] = array ($node->getAttribute ("id"),
$node->getElementsByTagName ("default")->item (0 )->nodeValue );
foreach ($options as $no => $optionData) {
$total = count($options);
$optionName = $optionData[0 ];
$optionDef = $optionData[1 ];
/* Set all configuration options to disabled. These values
* will be rewritten after parsing the INI file
$index[$optionName] = array (self ::DIR_CURRENT=> "Disabled",
self ::DIR_DEFAULT => $optionDef,
self ::COMMENT_NORMAL => "",
self ::COMMENT_INLINE => "",
/* Set all configuration options to default values since a
* new file is to be generated
$optionName = $optionData[0 ];
$optionDef = $optionData[1 ];
$index[$optionName] = array (self ::DIR_CURRENT => $optionDef,
self ::DIR_DEFAULT => $optionDef,
self ::COMMENT_NORMAL => "",
self ::COMMENT_INLINE => "",
foreach ($status as $no=> $line) {
foreach ($options as $opNo => $data) {
if (strpos($line, "extension") !== false ) {
if (substr($line, 0 , 9 ) == "extension") {
$extStatus = self ::EXT_ENABLED;
} elseif (substr($line, 1 , 9 ) == "extension") {
$extStatus = self ::EXT_DISABLED;
if (trim($check[0 ]) == "extension" ||
trim($check[0 ]) == ";extension") {
$remComments = explode(";", $extValue);
$extName = trim($remComments[0 ]);
$extensions[$extName][self ::COMMENT_INLINE ] =
$extensions[$extName][self ::COMMENT_INLINE ] = "";
$extensions[$extName][self ::DIR_CURRENT ] =
$extensions[$extName][self ::DIR_NUMBER ] = $no;
if (strpos($line, $data[0 ])!==false ) {
$optionName = trim($data[0 ]);
$optionShown = substr($line, 0 , $optionLength);
$optionHidden = substr($line, 1 , $optionLength);
if ($optionShown == $optionName) {
$whereis = strpos($line, "=");
$directive = substr($line, 0 , $whereis);
/* Check if this is not part of a bigger extension */
$index[$optionName][self ::DIR_CURRENT ] =
$index[$optionName][self ::COMMENT_NORMAL ] =
$index[$optionName][self ::DIR_NUMBER ] =
$index[$optionName][self ::COMMENT_INLINE ] =
} elseif ($optionHidden == $optionName
&& $optionHidden != "extension") {
$index[$optionName][self ::DIR_CURRENT ] == "Disabled";
$index[$optionName][self ::COMMENT_NORMAL ] = "";
$index[$optionName][self ::DIR_NUMBER ] = $no;
} elseif (substr($line, 0 , 2 ) == ";/" && $optionHi) {
if (substr($line, 2 , 1 ) == " ") {
/* Performance enhancing trick */
* Creates and displays a progress bar that indicates
* by what amount a file has been parsed.
while (Gtk ::events_pending ()) {
$progressWin = new GtkWindow ();
$progressWin->set_modal (true );
$progressWin->set_transient_for ($this);
$progressWin->set_title ("Parsing File...");
$progressBar = new GtkProgressBar ();
$progressBar->set_orientation (Gtk ::PROGRESS_LEFT_TO_RIGHT );
$progressWin->add ($progressBar);
$this->progress->set_size_request (300 , 50 );
$this->progress->set_position (Gtk ::WIN_POS_CENTER );
* Updates the progress by the fraction received as an argument by
* @param int $fraction The fraction by which the progress bar must
while (Gtk ::events_pending ()) {
$theBar->set_fraction ($fraction);
$percent = round(($fraction*100 )). "%";
$theBar->set_text ($percent);
* Prompts for saving of file that is currently opened and opens a
* dialog that prompts for the next file the user wishes to open.
$filePrompt = new GtkFileChooserDialog ("Open Existing file:", $this,
Gtk ::FILE_CHOOSER_ACTION_OPEN , array (Gtk ::STOCK_CANCEL ,
if ($filePrompt->run () == Gtk ::RESPONSE_ACCEPT ) {
$this->fileName = $filePrompt->get_filename ();
* Creates a new file to be edited after prompting for saving of the
* existing file that is open.
* Checks whether the existing open file is saved or not. If not,
* prompts the user to save it.
* @return bool Returns true if users wants to quit, false
/* Display confirmation dialog since buffer is not saved */
$saveDialog = new GtkMessageDialog ($this,
"Do you want to save your existing INI file?");
$saveDialog->add_button (Gtk ::STOCK_CANCEL , Gtk ::RESPONSE_CANCEL );
$saveDialog->add_button (Gtk ::STOCK_NO , Gtk ::RESPONSE_NO );
$saveDialog->add_button (Gtk ::STOCK_YES , Gtk ::RESPONSE_YES );
$response = $saveDialog->run ();
if ($response == Gtk ::RESPONSE_YES ) {
} elseif ($response == Gtk ::RESPONSE_NO ) {
} elseif ($response == Gtk ::RESPONSE_CANCEL ) {
* Sets the title of the window as required.
* @return string The title of the window.
$title = self ::TITLE. " - New File (Default Values) ". $asterisk;
$title = self ::TITLE. " - ". $this->fileName. " ". $asterisk;
$this->set_title ($title);
* Quits the main Gtk loop after checking whether the current state of
* the buffer has been saved to a file or not.
Documentation generated on Sun, 24 Oct 2010 11:30:03 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.
|