Flyspray PHP Cross Reference Customer Relationship Management

Source: /setup/index.php - 1181 lines - 46547 bytes - Summary - Text - Print

   1  <?php
   2  // +----------------------------------------------------------------------

   3  // | Installer - there is still a lot to clean up, but it works

   4  // +----------------------------------------------------------------------

   5  // | Copyright (C) 2005 by Jeffery Fernandez <developer@jefferyfernandez.id.au>

   6  // | Copyright (C) 2006-2007  by Cristian Rodriguez <judas.iscariote@flyspray.org> and Florian Schmitz <floele@gmail.com>

   7  // +----------------------------------------------------------------------

   8  
   9  @set_time_limit(0);
  10  session_start();
  11  //do it fastest as possible.

  12  ini_set('memory_limit', '64M');
  13  
  14  
  15  if (is_readable ('../flyspray.conf.php') && count(parse_ini_file('../flyspray.conf.php')) > 0)
  16  {
  17     die('Flyspray already installed. Use the <a href="upgrade.php">upgrader</a> to upgrade your Flyspray, or delete flyspray.conf.php to run setup.
  18          You can *not* use the setup on an existing database.');
  19  }
  20  
  21  $borked = str_replace('a', 'b', array( -1 => -1 ) );
  22  
  23  if(!isset($borked[-1])) {
  24      die("Flyspray cannot run here, sorry :-( PHP 4.4.x/5.0.x is buggy on your 64-bit system; you must upgrade to PHP 5.1.x\n" .
  25          "or higher. ABORTING. (http://bugs.php.net/bug.php?id=34879 for details)\n");
  26  }
  27  
  28  // define basic stuff first.

  29  
  30  define('IN_FS', 1 );
  31  define('APPLICATION_NAME', 'Flyspray');
  32  define('BASEDIR', dirname(__FILE__));
  33  define('APPLICATION_PATH', dirname(BASEDIR));
  34  define('OBJECTS_PATH', APPLICATION_PATH . '/includes');
  35  define('TEMPLATE_FOLDER', BASEDIR . '/templates/');
  36  $conf['general']['syntax_plugin'] = '';
  37  
  38  require_once  OBJECTS_PATH . '/fix.inc.php';
  39  require_once  OBJECTS_PATH . '/class.gpc.php';
  40  require_once  OBJECTS_PATH . '/class.flyspray.php';
  41  require_once  OBJECTS_PATH . '/class.tpl.php';
  42  require_once  BASEDIR . '/array_combine.php';
  43  // ---------------------------------------------------------------------

  44  // Application Web locations

  45  // ---------------------------------------------------------------------

  46  define('APPLICATION_SETUP_INDEX', Flyspray::absoluteURI());
  47  
  48  class Setup extends Flyspray
  49  {
  50     public $mPhpRequired;
  51     public $mSupportedDatabases;
  52     public $mAvailableDatabases;
  53  
  54     public $mProceed;
  55     public $mPhpVersionStatus;
  56     public $mDatabaseStatus;
  57     public $xmlStatus;
  58     public $mConfigText;
  59     public $mHtaccessText;
  60     public $mWriteStatus;
  61  
  62     public $mDbConnection;
  63     public $mProductName;
  64  
  65     /**

  66      * @var string To store the data filter type

  67      */
  68     public $mDataFilter;
  69  
  70     /**

  71      * @var array To store the type of database setup (install or Upgrade).

  72      */
  73  
  74     public $mAttachmentsTable;
  75     public $mCommentsTable;
  76  
  77     public $mServerSoftware;
  78     public $mMinPasswordLength;
  79     public $mAdminUsername;
  80     public $mAdminPassword;
  81     /**

  82      * @var object to store the adodb datadict object.

  83      */
  84     public $mDataDict;
  85  
  86     public $mXmlSchema;
  87  
  88     public function __construct()
  89     {
  90        // Look for ADOdb

  91        $this->mAdodbPath         = APPLICATION_PATH . '/adodb/adodb.inc.php';
  92        $this->mProductName       = 'Flyspray';
  93        $this->mMinPasswordLength    = 8;
  94  
  95        // Initialise flag for proceeding to next step.

  96        $this->mProceed                = false;
  97        $this->mPhpRequired            = '5.2.0';
  98        $this->xmlStatus = function_exists('xml_parser_create');
  99        $this->sapiStatus = (php_sapi_name() != 'cgi');
 100  
 101        // If the database is supported in Flyspray, the function to check in PHP.

 102        $this->mSupportedDatabases    =
 103                             array(
 104                                   'MySQLi' => array(true,'mysqli_connect','mysqli'),
 105                                   'MySQL' => array(true, 'mysql_connect', 'mysql'),
 106                                   'Postgres' => array(true, 'pg_connect', 'pgsql'),
 107                                );
 108        $this->mAvailableDatabases    = array();
 109  
 110        // Process the page actions

 111        $this->ProcessActions();
 112     }
 113  
 114     /**

 115     * Function to check the permission of the config file

 116     * @param void

 117     * @return string An html formatted boolean answer

 118     */
 119     public function CheckWriteability($path)
 120     {
 121        // Get the full path to the file

 122        $file = APPLICATION_PATH .'/' . $path;
 123  
 124        // In case it is flyspray.conf.php, the file does not exist

 125        // so we can't tell that it is writeable. So we attempt to create an empty one

 126        if ($path == 'flyspray.conf.php') {
 127          $fp = @fopen($file, 'wb');
 128          @fclose($fp);
 129        }
 130        // Let's try at least...

 131        @chmod($file, 0666);
 132        $this->mWriteStatus[$path] = $this->IsWriteable($file);
 133  
 134        // Return an html formated writeable/un-writeable string

 135        return $this->ReturnStatus($this->mWriteStatus[$path], $type = 'writeable');
 136     }
 137  
 138     /**

 139     * Function to check the availability of the Database support

 140     * @param void

 141     * @return void

 142     */
 143     public function CheckDatabaseSupport()
 144     {
 145        $status = array();
 146  
 147        foreach ($this->mSupportedDatabases as $which => $database)
 148        {
 149        // Checking if the database has libraries built into PHP. Returns true/false

 150        $this->mAvailableDatabases[$which]['status'] = function_exists($database[1]);
 151  
 152        // If the Application(Flyspray) supports the available database supported in PHP

 153        $this->mAvailableDatabases[$which]['supported'] = ($database[0] === $this->mAvailableDatabases[$which]['status'])
 154           ?  $this->mAvailableDatabases[$which]['status']
 155           :  false;
 156  
 157        // Just transferring the value for ease of veryfying Database support.

 158        $status[] = $this->mAvailableDatabases[$which]['supported'];
 159  
 160        // Generating the output to be displayed

 161        $this->mAvailableDatabases[$which]['status_output'] =
 162           $this->ReturnStatus($this->mAvailableDatabases[$which]['status'], $type = 'available');
 163        }
 164  
 165        // Check if any one database support exists.

 166        // Update the status of database availability

 167        $this->mDatabaseStatus = in_array('1', $status);
 168     }
 169  
 170  
 171     /**

 172      * CheckPreStatus

 173      * we proceed or not ?

 174      * @access public

 175      * @return bool

 176      */
 177     public function CheckPreStatus()
 178     {
 179        $this->mProceed = ($this->mDatabaseStatus && $this->mPhpVersionStatus && $this->xmlStatus);
 180  
 181        return $this->mProceed;
 182     }
 183  
 184  
 185     /**

 186     * Function to check the version of PHP available compared to the

 187     * Applications requirements

 188     * @param void

 189     * @return string An html formatted boolean answer

 190     */
 191     public function CheckPhpCompatibility()
 192     {
 193        // Check the PHP version. Recommended version is 4.3.9 and above

 194        $this->mPhpVersionStatus = version_compare(PHP_VERSION, $this->mPhpRequired, '>=');
 195  
 196        // Return an html formated Yes/No string

 197        return $this->ReturnStatus($this->mPhpVersionStatus, $type = 'yes');
 198     }
 199  
 200     /**

 201     * Function to check the posted data from forms.

 202     * @param array $expectedFields Array of field names which needs processing

 203     * If the array of filed names don't exist in the Posted data, then this function

 204     * will accumulate error messages in the $_SESSION[PASS_PHRASE]['page_message'] array.

 205     * return boolean/array $data will be returned if successful

 206     */
 207     public function CheckPostedData($expectedFields, $pageHeading)
 208     {
 209         if(!is_array($expectedFields)){
 210             $expectedFields = array();
 211         }
 212         
 213        // Grab the posted data and trim it.

 214        $data = array_filter($_POST, array(&$this, "TrimArgs"));
 215  
 216  
 217        // Loop through the required values and check data

 218        foreach($expectedFields as $key => $value)
 219        {
 220  
 221           // If the data is Required and is empty or not set

 222           if (!isset($data[$key]) || empty($data[$key]))
 223           {
 224              if ($expectedFields[$key][2] == true)
 225              {
 226                 // Acumulate error messages

 227                 $_SESSION['page_message'][] = "<strong>{$expectedFields[$key][0]}</strong>  is required";
 228              }
 229           }
 230           // Check for variable types

 231           elseif (!$this->VerifyVariableTypes($expectedFields[$key][1], $data[$key]))
 232           {
 233              $_SESSION['page_message'][] = "<strong>{$expectedFields[$key][0]}</strong> has to be a {$expectedFields[$key][1]}";
 234           }
 235        }
 236  
 237        // If there were messages, return false

 238        if (isset($_SESSION['page_message']))
 239        {
 240           $_SESSION['page_heading'] = $pageHeading;
 241           return false;
 242        }
 243        else
 244        {
 245           return $data;
 246        }
 247     }
 248  
 249     public function DisplayAdministration()
 250     {
 251        // Trim the empty values in the $_POST array

 252        $data = array_filter($_POST, array($this, "TrimArgs"));
 253  
 254        $templates =
 255        array(
 256              'admin_body' => array(
 257                          'path' => TEMPLATE_FOLDER,
 258                          'template' => 'administration.tpl',
 259                          'vars' => array(
 260                                      'product_name' => $this->mProductName,
 261                                      'message' => $this->GetPageMessage(),
 262                                      'admin_email' => $this->GetAdminInput('admin_email', $this->GetParamValue($data, 'admin_email', ''), 'Admin Email'),
 263                                      'pass_phrase' => $this->GetParamValue($data, 'pass_phrase', ''),
 264                                      'admin_username' => $this->GetAdminInput('admin_username', $this->GetParamValue($data, 'admin_username', ''), 'Admin Username'),
 265                                      'admin_password' => $this->GetAdminInput('admin_password', $this->GetParamValue($data, 'admin_password', substr(md5(mt_rand()), 0, $this->mMinPasswordLength)), 'Admin Password'),
 266                                      'db_type' => $this->GetParamValue($data, 'db_type', ''),
 267                                      'db_hostname' => $this->GetParamValue($data, 'db_hostname', ''),
 268                                      'db_username' => $this->GetParamValue($data, 'db_username', ''),
 269                                      'db_password' => $this->GetParamValue($data, 'db_password', ''),
 270                                      'db_name' => $this->GetParamValue($data, 'db_name', ''),
 271                                      'db_prefix' => $this->GetParamValue($data, 'db_prefix', ''),
 272                                      'daemonise' => $this->GetReminderDaemonSelection($this->GetParamValue($data, 'reminder_daemon', '0')),
 273                                   ),
 274                       ),
 275  
 276              'structure' =>  array(
 277                             'path' => TEMPLATE_FOLDER,
 278                             'template' => 'structure.tpl',
 279                             'vars' => array(
 280                                         'title' => 'Administration setup for',
 281                                         'headers' => '',
 282                                         'index' => APPLICATION_SETUP_INDEX,
 283                                         'version' => $this->version,
 284                                         ),
 285                             'block' => array('body' => 'admin_body')
 286                             )
 287           );
 288  
 289        // Output the final template.

 290        $this->OutputPage($templates);
 291     }
 292  
 293  
 294     public function DisplayCompletion()
 295     {
 296        // Trim the empty values in the $_POST array

 297        $data = array_filter($_POST, array($this, "TrimArgs"));
 298  
 299        $templates =
 300        array(
 301              'complete_body' => array(
 302                          'path' => TEMPLATE_FOLDER,
 303                          'template' => 'complete_install.tpl',
 304                          'vars' => array(
 305                                      'product_name' => $this->mProductName,
 306                                      'message' => $this->GetPageMessage(),
 307                                      'config_writeable' => $this->mWriteStatus['flyspray.conf.php'],
 308                                      'config_text' => $this->mConfigText,
 309                                      'admin_username' => $this->mAdminUsername,
 310                                      'admin_password' => $this->mAdminPassword,
 311                                      'site_index' => dirname($_SERVER['REQUEST_URI']) . '/../',
 312                                      'complete_action' => 'index.php',
 313                                      'daemonise' => true,
 314                                   ),
 315                       ),
 316  
 317              'structure' =>  array(
 318                             'path' => TEMPLATE_FOLDER,
 319                             'template' => 'structure.tpl',
 320                             'vars' => array(
 321                                         'title' => 'Setup confirmation for',
 322                                         'headers' => '',
 323                                         'index' => APPLICATION_SETUP_INDEX,
 324                                         'version' => $this->version,
 325                                         ),
 326                             'block' => array('body' => 'complete_body')
 327                             )
 328           );
 329  
 330        // Output the final template.

 331        $this->OutputPage($templates);
 332     }
 333  
 334     public function DisplayDatabaseSetup()
 335     {
 336  
 337        // Trim the empty values in the $_POST array

 338        $data = array_filter($_POST, array($this, "TrimArgs"));
 339        $this->CheckDatabaseSupport();
 340  
 341        // Make sure that the user can't choose a DB which is not supported

 342        foreach ($this->mSupportedDatabases as $db => $arr) {
 343          if (!$this->mAvailableDatabases[$db]['supported']) {
 344              unset($this->mSupportedDatabases[$db]);
 345          }
 346        }
 347  
 348        $templates =
 349        array(
 350              'database_body' => array(
 351                                'path' => TEMPLATE_FOLDER,
 352                                'template' => 'database.tpl',
 353                                'vars' => array(
 354                                            'product_name' => $this->mProductName,
 355                                            'message' => $this->GetPageMessage(),
 356                                            'databases' => $this->mSupportedDatabases,
 357                                            'db_type' => $this->GetParamValue($data, 'db_type', ''),
 358                                            'db_hostname' => $this->GetParamValue($data, 'db_hostname', 'localhost'),
 359                                            'db_username' => $this->GetParamValue($data, 'db_username', ''),
 360                                            'db_password' => $this->GetParamValue($data, 'db_password', ''),
 361                                            'db_name' => $this->GetParamValue($data, 'db_name', ''),
 362                                            'db_prefix' => $this->GetParamValue($data, 'db_prefix', 'flyspray_'),
 363                                            'version' => $this->version,
 364                                         ),
 365                             ),
 366              'structure' =>  array(
 367                             'path' => TEMPLATE_FOLDER,
 368                             'template' => 'structure.tpl',
 369                             'vars' => array(
 370                                         'title' => 'Database setup for',
 371                                         'headers' => '',
 372                                         'index' => APPLICATION_SETUP_INDEX,
 373                                         'version' => $this->version,
 374                                         ),
 375                             'block' => array('body' => 'database_body')
 376                             )
 377           );
 378  
 379        // Output the final template.

 380        $this->OutputPage($templates);
 381     }
 382  
 383  
 384     public function DisplayPreInstall()
 385     {
 386        // Check the Database support on the server.

 387        $this->CheckDatabaseSupport();
 388  
 389        $templates =
 390        array(
 391              'index_body' => array(
 392                          'path' => TEMPLATE_FOLDER,
 393                          'template' => 'pre_install.tpl',
 394                          'vars' => array(
 395                                      'product_name' => $this->mProductName,
 396                                      'required_php' => $this->mPhpRequired,
 397                                      'php_output' => $this->CheckPhpCompatibility(),
 398                                      'database_output' => $this->GetDatabaseOutput(),
 399                                      'config_output' => $this->CheckWriteability('flyspray.conf.php'),
 400                                      'cache_output' => $this->CheckWriteability('cache'),
 401                                      'att_output' => $this->CheckWriteability('attachments'),
 402                                      'config_status' => $this->mWriteStatus['flyspray.conf.php'],
 403                                      'xmlStatus' => $this->xmlStatus,
 404                                      'sapiStatus' => $this->sapiStatus,
 405                                      'php_settings' => $this->GetPhpSettings(),
 406                                      'status' => $this->CheckPreStatus(),
 407                                      'message' => $this->GetPageMessage(),
 408                                   ),
 409                       ),
 410  
 411              'structure' =>  array(
 412                             'path' => TEMPLATE_FOLDER,
 413                             'template' => 'structure.tpl',
 414                             'vars' => array(
 415                                         'title' => 'Pre-Installation Check for',
 416                                         'headers' => '',
 417                                         'index' => APPLICATION_SETUP_INDEX,
 418                                         'version' => $this->version,
 419                                         ),
 420                             'block' => array('body' => 'index_body')
 421                             )
 422           );
 423  
 424        // Output the final template.

 425        $this->OutputPage($templates);
 426     }
 427  
 428     public function DisplayLicense()
 429     {
 430        $templates =
 431        array(
 432              'license_body' => array(
 433                          'path' => TEMPLATE_FOLDER,
 434                          'template' => 'license.tpl',
 435                          'vars' => array(
 436                                      'product_name' => $this->mProductName,
 437                                      'message' => $this->GetPageMessage(),
 438                                   ),
 439                       ),
 440  
 441              'structure' =>  array(
 442                             'path' => TEMPLATE_FOLDER,
 443                             'template' => 'structure.tpl',
 444                             'vars' => array(
 445                                         'title' => 'Licence Agreement for',
 446                                         'headers' => '',
 447                                         'index' => APPLICATION_SETUP_INDEX,
 448                                         'version' => $this->version,
 449                                         ),
 450                             'block' => array('body' => 'license_body')
 451                             )
 452           );
 453  
 454        // Output the final template.

 455        $this->OutputPage($templates);
 456     }
 457  
 458  
 459  
 460     public function GetAdminInput($field, $value, $label)
 461     {
 462           $input_field    = "
 463           <tr>
 464              <td align=\"right\">$label</td>
 465              <td align=\"center\"><input class=\"inputbox\" type=\"text\" name=\"$field\" value=\"$value\" size=\"30\" /></td>
 466           </tr>";
 467        return $input_field;
 468     }
 469  
 470  
 471     public function GetDatabaseOutput()
 472     {
 473        $output = '';
 474        // Loop through the supported databases array

 475        foreach ($this->mSupportedDatabases as $which => $database)
 476        {
 477        $output .= "
 478        <tr>
 479           <td> - $which support</td>
 480           <td align=\"left\"><strong>{$this->mAvailableDatabases[$which]['status_output']}</strong></td>
 481           <td align=\"center\"><strong>". $this->ReturnStatus($this->mAvailableDatabases[$which]['supported'], $type = 'support')  . "</strong></td>
 482        </tr>";
 483  
 484        }
 485        // Return the html formatted results

 486        return $output;
 487     }
 488  
 489  
 490  
 491     /**

 492     * Function to get the php ini config values

 493     * @param string $option The ini setting name to check the status for

 494     * @return string The status of the setting either "On" or "OFF"

 495     */
 496     public function GetIniSetting($option)
 497     {
 498        return (ini_get($option) == '1' ? 'ON' : 'OFF');
 499     }
 500  
 501     /**

 502     * Function to get the error messages and generate an error output for the template

 503     * @string $heading The value for the Error message heading

 504     *                  The error message is stored in the $_SESSION Global array

 505     *                  $_SESSION[PASS_PHRASE]['page_message']. If there is no value in

 506     *                  this array, then there will be no error message outputed.

 507     * @return string $message The message which needs outputting

 508     */
 509     public function GetPageMessage()
 510     {
 511        // If there is an error

 512        if (isset($_SESSION['page_message']) || isset($_SESSION['page_heading']))
 513        {
 514           $message = '';
 515           if (isset($_SESSION['page_heading'])) {
 516              $message = '<h1 class="error">' . $_SESSION['page_heading'] . '</h1>';
 517           }
 518  
 519          if (isset($_SESSION['page_message'])) {
 520              // Get an html formated list

 521              $message .= '<div class="box"><div class="shade">' . $this->OutputHtmlList($_SESSION['page_message'],'ul') . '</div></div>';
 522          }
 523  
 524  
 525           // Destroy the session value

 526           unset($_SESSION['page_heading']);
 527           unset($_SESSION['page_message']);
 528  
 529           return $message;
 530        }
 531        else
 532        {
 533           return '';
 534        }
 535     }
 536  
 537  
 538     /**

 539     * Utility function to return a value from a named array or a specified default

 540     * @param array &$arr The array to get the values from

 541     * @param string $name The name of the key to check the value for

 542     * @param string $default The default value if the value is not set with the array

 543     * @return string $value The value to be returned

 544     */
 545     public function GetParamValue(&$arr, $name, $default=null )
 546     {
 547        $value = isset($arr[$name]) ? $arr[$name] : $default;
 548        return $value;
 549     }
 550  
 551     /**

 552     * Function to get a listing of recommended and actual settings

 553     * for php.

 554     * @param void

 555     * @return string $output HTML formatted string.

 556     */
 557     public function GetPhpSettings()
 558     {
 559        // Array of the setting name, php ini name and the recommended value

 560        $test_settings =
 561        array(
 562              array ('Safe Mode','safe_mode','OFF'),
 563              array ('File Uploads','file_uploads','ON'),
 564              array ('Magic Quotes GPC','magic_quotes_gpc','OFF'),
 565              array ('Register Globals','register_globals','OFF'),
 566              //array ('Output Buffering','output_buffering','OFF'),

 567              );
 568  
 569        if (substr(php_sapi_name(), 0, 3) == 'cgi') {
 570            $test_settings[] = array ('CGI fix pathinfo','cgi.fix_pathinfo','On');
 571        }
 572  
 573        $output = '';
 574  
 575        foreach ($test_settings as $recommended)
 576        {
 577        $actual_setting = $this->GetIniSetting($recommended[1]);
 578  
 579        $result = ($actual_setting == $recommended[2] )
 580           ?  '<span class="green"><strong>' . $recommended[2] . '</strong></span>'
 581           :  '<span class="red"><strong>' . $actual_setting . '</strong></span>';
 582  
 583        $output .=
 584        "
 585        <tr>
 586           <td>{$recommended[0]}</td><td align=\"center\"><strong>{$recommended[2]}</strong></td><td align=\"center\">{$result}</td>
 587        </tr>
 588        ";
 589        }
 590        return $output;
 591     }
 592  
 593      public function GetReminderDaemonSelection($value)
 594      {
 595          $selection    = '';
 596  
 597          if ($value == 1) {
 598  
 599                  $selection .= '<input type="radio" name="reminder_daemon" value="1" checked="checked" /> Enable';
 600                  $selection .= '<input type="radio" name="reminder_daemon" value="0" /> Disable';
 601          } else {
 602  
 603                  $selection .= '<input type="radio" name="reminder_daemon" value="1" /> Enable';
 604                  $selection .= '<input type="radio" name="reminder_daemon" value="0" checked="checked" /> Disable';
 605          }
 606              return $selection;
 607  
 608      }
 609  
 610  
 611     /**

 612     * Function to check if a particular folder/file is writeable.

 613     * @param string $fileSystem Path to check

 614     * $return boolean true/false

 615     */
 616     public function IsWriteable($fileSystem)
 617     {
 618        // Clear the cache

 619        clearstatcache();
 620  
 621        // Return the status of the permission

 622        return is_writable($fileSystem);
 623     }
 624  
 625      /**

 626     * Function to Output an Ordered/Un-ordered list from an array. Default list type is un-ordered.

 627     * @param array() $list_array An array list of data to be made into a list.

 628     * @return string $list An HTML list

 629     */
 630     public function OutputHtmlList($list_array = array(), $list_type = 'ul')
 631     {
 632        $list = "<$list_type>";
 633        foreach ($list_array as $list_item)
 634        {
 635           $list .= '<li>' . $list_item .'</li>';
 636        }
 637        $list .= "</$list_type>";
 638  
 639        return $list;
 640     }
 641  
 642  
 643     /**

 644     * Function to act on all the actions during Flyspray Setup

 645     * The Post variables are extracted for deciding which function to call.

 646     */
 647    public function ProcessActions()
 648     {
 649        $action = 'index';
 650        $what = '';
 651  
 652        extract($_POST);
 653  
 654        switch($action)
 655        {
 656           case 'licence':
 657              $this->DisplayLicense();
 658           break;
 659  
 660           case 'database':
 661              $this->DisplayDatabaseSetup();
 662           break;
 663  
 664           case 'administration':
 665              // Prepare the required data

 666              $required_data =
 667              array(
 668                    'db_hostname' => array('Database hostname', 'string', true),
 669                    'db_type' =>  array('Database type', 'string', true),
 670                    'db_username' => array('Database username', 'string', true),
 671                    'db_password' => array('Database password', 'string', false),
 672                    'db_name' => array('Database name', 'string', true),
 673                    'db_prefix' => array('Table prefix', 'string', false),
 674                 );
 675              if ($data = $this->CheckPostedData($required_data, $message = 'Configuration Error'))
 676              {
 677                 // Process the database checks and install tables

 678                 if ($this->ProcessDatabaseSetup($data))
 679                 {
 680                    // Proceed to Administration part

 681                    $this->DisplayAdministration();
 682                 }
 683                 else
 684                 {
 685                    $_POST['action'] = 'database';
 686                    $this->DisplayDatabaseSetup();
 687                 }
 688              }
 689              else
 690              {
 691                 $_POST['action'] = 'database';
 692                 $this->DisplayDatabaseSetup();
 693              }
 694           break;
 695  
 696           case 'complete':
 697              // Prepare the required data

 698              $required_data =
 699              array(
 700                 'db_hostname' => array('Database hostname', 'string', true),
 701                 'db_type' =>  array('Database type', 'string', true),
 702                 'db_username' => array('Database username', 'string', true),
 703                 'db_password' => array('Database password', 'string', false),
 704                 'db_name' => array('Database name', 'string', true),
 705                 'db_prefix' => array('Table prefix', 'string', false),
 706                 'admin_username' => array('Administrator\'s username', 'string', true),
 707                 'admin_password' => array("Administrator's Password must be minimum {$this->mMinPasswordLength} characters long and", 'password', true),
 708                 'admin_email' => array('Administrator\'s email address', 'email address', true),
 709                 'reminder_daemon' => array('Reminder Daemon', 'option', false),
 710                 );
 711              if ($data = $this->CheckPostedData($required_data, $message = 'Missing config values'))
 712              {
 713                 // Set a page heading in case of errors.

 714                 $_SESSION['page_heading'] = 'Administration Processing';
 715  
 716                 if ($this->ProcessAdminConfig($data))
 717                 {
 718                    $this->DisplayCompletion($data);
 719                 }
 720                 else
 721                 {
 722                    $_POST['action'] = 'administration';
 723                    $this->DisplayAdministration();
 724                 }
 725              }
 726              else
 727              {
 728                 $_POST['action'] = 'administration';
 729                 $this->DisplayAdministration();
 730              }
 731           break;
 732  
 733           default:
 734              $this->DisplayPreInstall();
 735           break;
 736        }
 737     }
 738  
 739  
 740  
 741     public function ProcessAdminConfig($data)
 742     {
 743        // Extract the varibales to local namespace

 744        extract($data);
 745  
 746        $config_intro    =
 747        "; <?php die( 'Do not access this page directly.' ); ?>
 748  
 749        ; This is the Flysplay configuration file. It contains the basic settings
 750        ; needed for Flyspray to operate. All other preferences are stored in the
 751        ; database itself and are managed directly within the Flyspray admin interface.
 752        ; You should consider putting this file somewhere that isn't accessible using
 753        ; a web browser, and editing header.php to point to wherever you put this file.\n";
 754        $config_intro    = str_replace("\t", "", $config_intro);
 755  
 756        // Create a random cookie salt

 757        $cookiesalt = md5(uniqid(mt_rand(), true));
 758  
 759        // check to see if to enable the Reminder Daemon.

 760        $daemonise    = ( (isset($data['reminder_daemon'])) && ($data['reminder_daemon'] == 1) )
 761                      ? 1
 762                      : 0;
 763        $db_prefix = (isset($data['db_prefix']) ? $data['db_prefix'] : '');
 764  
 765        $config    = array();
 766        $config[] = "[database]";
 767        $config[] = "dbtype = \"$db_type\"                    ; Type of database (\"mysql\", \"mysqli\" or \"pgsql\" are currently supported)";
 768        $config[] = "dbhost = \"$db_hostname\"                ; Name or IP of your database server";
 769        $config[] = "dbname = \"$db_name\"                    ; The name of the database";
 770        $config[] = "dbuser = \"$db_username\"                ; The user to access the database";
 771        $config[] = "dbpass = \"$db_password\"                ; The password to go with that username above";
 772        $config[] = "dbprefix = \"$db_prefix\"                ; The prefix to the {$this->mProductName} tables";
 773        $config[] = "\n";
 774        $config[] = '[general]';
 775        $config[] = "cookiesalt = \"$cookiesalt\"            ; Randomisation value for cookie encoding";
 776        $config[] = 'output_buffering = "on"                ; Available options: "on" or "gzip"';
 777        $config[] = "passwdcrypt = \"md5\"                    ; Available options: \"crypt\", \"md5\", \"sha1\" (Deprecated, do not change the default)";
 778        $config[] = "dot_path = \"\" ; Path to the dot executable (for graphs either dot_public or dot_path must be set)";
 779        $config[] = "dot_format = \"png\" ; \"png\" or \"svg\"";
 780        $config[] = "address_rewriting = \"0\"    ; Boolean. 0 = off, 1 = on.";
 781        $config[] = "reminder_daemon = \"$daemonise\"        ; Boolean. 0 = off, 1 = on (cron job), 2 = on (PHP).";
 782        $config[] = "doku_url = \"http://en.wikipedia.org/wiki/\"      ; URL to your external wiki for [[dokulinks]] in FS";
 783        $config[] = "syntax_plugin = \"none\"                               ; Plugin name for Flyspray's syntax (use any non-existing plugin name for deafult syntax)";
 784        $config[] = "update_check = \"1\"                               ; Boolean. 0 = off, 1 = on.";
 785        $config[] = "\n";
 786        $config[] = "[attachments]";
 787        $config[] = "zip = \"application/zip\" ; MIME-type for ZIP files";
 788  
 789        $config_text = $config_intro . implode( "\n", $config );
 790  
 791        if (is_writable('../flyspray.conf.php') && ($fp = fopen('../flyspray.conf.php', "wb")))
 792        {
 793           fputs($fp, $config_text, strlen($config_text));
 794           fclose($fp);
 795           $this->mWriteStatus['flyspray.conf.php'] = true;
 796        }
 797        else
 798        {
 799           $this->mConfigText = $config_text;
 800           $this->mWriteStatus['flyspray.conf.php'] = false;
 801        }
 802  
 803  
 804        // Setting the database for the ADODB connection

 805        require_once($this->mAdodbPath);
 806  
 807        $this->mDbConnection =& NewADOConnection(strtolower($db_type));
 808        $this->mDbConnection->Connect($db_hostname, $db_username, $db_password, $db_name);
 809        $this->mDbConnection->SetCharSet('utf8');
 810  
 811        // Get the users table name.

 812        $users_table    = (isset($db_prefix) ? $db_prefix : '') . 'users';
 813  
 814        $sql    = "SELECT * FROM $users_table WHERE user_id = '1'";
 815  
 816        // Check if we already have an Admin user.

 817        $result = $this->mDbConnection->Execute($sql);
 818        if ($result)
 819        {
 820           // If the record exists, we update it.

 821           $row = $result->FetchRow();
 822           $this->mAdminUsername = $row['user_name'];
 823           $this->mAdminPassword = $row['user_pass'];
 824        }
 825  
 826       $md5_password    = md5($admin_password);
 827       $update_user    = "
 828       UPDATE
 829          $users_table
 830       SET
 831          user_name = ?,
 832          user_pass = ?,
 833          email_address = ?
 834       WHERE
 835       user_id = '1'";
 836  
 837       $update_params = array($admin_username, $md5_password, $admin_email);
 838  
 839       $result = $this->mDbConnection->Execute($update_user, $update_params);
 840  
 841       if (!$result)
 842       {
 843          $errorno = $this->mDbConnection->MetaError();
 844          $_SESSION['page_heading'] = 'Failed to update Admin users details.';
 845          $_SESSION['page_message'][] = ucfirst($this->mDbConnection->MetaErrorMsg($errorno)) . ': '. $this->mDbConnection->ErrorMsg($errorno);
 846          return false;
 847       }
 848       else
 849       {
 850          $this->mAdminUsername = $admin_username;
 851          $this->mAdminPassword = $admin_password;
 852       }
 853  
 854        return true;
 855     }
 856  
 857  
 858     public function ProcessDatabaseSetup($data)
 859     {
 860        require_once($this->mAdodbPath);
 861  
 862        // Perform a number of fatality checks, then die gracefully

 863        if (!defined('_ADODB_LAYER'))
 864        {
 865           trigger_error('ADODB Libraries missing or not correct version');
 866        }
 867  
 868        // Setting the database type for the ADODB connection

 869        $this->mDbConnection =& NewADOConnection(strtolower($data['db_type']));
 870  
 871        /* check hostname/username/password */

 872  
 873        if (!$this->mDbConnection->Connect(array_get($data, 'db_hostname'), array_get($data, 'db_username'), array_get($data, 'db_password'), array_get($data, 'db_name')))
 874        {
 875           $_SESSION['page_heading'] = 'Database Processing';
 876           switch($error_number = $this->mDbConnection->MetaError())
 877           {
 878              case '-1':
 879              // We are using the unknown error code(-1) because ADOdb library may not have the error defined.

 880              // It could be totally some weird error.

 881              $_SESSION['page_message'][] = $this->mDbConnection->ErrorMsg();
 882              return false;
 883              break;
 884  
 885              case '-24':
 886              // Could not connect to database with the hostname provided

 887              $_SESSION['page_message'][] = ucfirst($this->mDbConnection->MetaErrorMsg($error_number)) . ': ' . ucfirst($this->mDbConnection->ErrorMsg($error_number));
 888              $_SESSION['page_message'][] = 'Usually the database host name is "localhost". In some occassions, it maybe an internal ip-address or another host name to your webserver.';
 889              $_SESSION['page_message'][] = 'Double check with your hosting provider or System Administrator.';
 890              return false;
 891              break;
 892  
 893              case '-25':
 894              // Database does not exist, try to create one

 895              $this->mDbConnection =& NewADOConnection(strtolower($data['db_type']));
 896              $this->mDbConnection->Connect(array_get($data, 'db_hostname'), array_get($data, 'db_username'), array_get($data, 'db_password'));
 897              $dict = NewDataDictionary($this->mDbConnection);
 898              $sqlarray = $dict->CreateDatabase(array_get($data, 'db_name'));
 899              if (!$dict->ExecuteSQLArray($sqlarray)) {
 900                  $_SESSION['page_message'][] = ucfirst($this->mDbConnection->MetaErrorMsg($error_number)) . ': ' . ucfirst($this->mDbConnection->ErrorMsg($error_number));
 901                  $_SESSION['page_message'][] = 'Your database does not exist and could not be created. Either create the database yourself, choose an existing database or
 902                                                 use a database user with sufficient permissions to create a database.';
 903                  return false;
 904              } else {
 905                  $this->mDbConnection->SelectDB(array_get($data, 'db_name'));
 906                  unset($_SESSION['page_heading']);
 907                  break;
 908              }
 909  
 910              case '-26':
 911              // Username passwords don't match for the hostname provided

 912              $_SESSION['page_message'][] = ucfirst($this->mDbConnection->MetaErrorMsg($error_number)) . ': ' . ucfirst($this->mDbConnection->ErrorMsg($error_number));
 913              $_SESSION['page_message'][] = "Apparently you haven't set up the right permissions for the database hostname provided.";
 914              $_SESSION['page_message'][] = 'Double check the provided credentials or contact your System Administrator for further assistance.';
 915              return false;
 916              break;
 917  
 918              default:
 919              $_SESSION['page_message'][] = "Please verify your username/password/database details (error=$error_number)" . $this->mDbConnection->MetaErrorMsg($error_number);
 920              return false;
 921              break;
 922           }
 923        }
 924        // Check that table prefix is OK, some DBs don't like it

 925        $prefix = array_get($data, 'db_prefix');
 926        if (strlen($prefix) > 0 && is_numeric($prefix[0])) {
 927          $_SESSION['page_heading'] = 'Database Processing';
 928          $_SESSION['page_message'][] = 'The table prefix may not start with a number.';
 929          return false;
 930        }
 931  
 932         // Setting the Fetch mode of the database connection.

 933        $this->mDbConnection->SetFetchMode(ADODB_FETCH_BOTH);
 934        $this->mDbConnection->SetCharSet('utf8');
 935          //creating the datadict object for further operations

 936         $this->mDataDict = & NewDataDictionary($this->mDbConnection);
 937  
 938         include_once dirname($this->mAdodbPath) . '/adodb-xmlschema03.inc.php';
 939  
 940         $this->mXmlSchema =  new adoSchema($this->mDbConnection);
 941  
 942         // Populate the database with the new tables and return the result (boolean)

 943         if (!$this->PopulateDb($data))
 944         {
 945            return false;
 946         }
 947  
 948        return true;
 949     }
 950  
 951     /**

 952     * Function to populate the database with the sql constructs which is in an sql file

 953     * @param array $data The actual database configuration values

 954     * @return boolean

 955     */
 956  
 957     public function PopulateDb($data)
 958     {
 959        // Check available upgrade scripts, use the script of very latest  version

 960        $folders = glob_compat(BASEDIR . '/upgrade/[0-9]*');
 961        usort($folders, 'version_compare'); // start with lowest version

 962        $folders = array_reverse($folders); // start with highest version

 963        $sql_file    = APPLICATION_PATH . '/setup/upgrade/' . reset($folders) . '/flyspray-install.xml';
 964        
 965        $upgradeInfo = APPLICATION_PATH . '/setup/upgrade/' . reset($folders) . '/upgrade.info';
 966        $upgradeInfo = parse_ini_file($upgradeInfo, true);
 967        
 968         // Check if the install/upgrade file exists

 969        if (!is_readable($sql_file)) {
 970  
 971            $_SESSION['page_message'][] = 'SQL file required for importing structure and data is missing.';
 972            return false;
 973        }
 974  
 975         // Extract the variables to local namespace

 976         extract($data);
 977         if (!isset($db_prefix)) {
 978              $db_prefix = '';
 979         }
 980         
 981         if(is_numeric($db_prefix)) {
 982             $_SESSION['page_message'][] = 'database prefix cannot be numeric only';
 983             return false;
 984         }
 985  
 986          // Set the prefix for database objects ( before parsing)

 987        $this->mXmlSchema->setPrefix( (isset($db_prefix) ? $db_prefix : ''), false);
 988        $this->mXmlSchema->ParseSchema($sql_file);
 989  
 990        $this->mXmlSchema->ExecuteSchema();
 991        
 992        // Last but not least global prefs update

 993          if (isset($upgradeInfo['fsprefs'])) {
 994              $existing = $this->mDbConnection->GetCol("SELECT pref_name FROM {$db_prefix}prefs");
 995              // Add what is missing

 996              foreach ($upgradeInfo['fsprefs'] as $name => $value) {
 997                  if (!in_array($name, $existing)) {
 998                      $this->mDbConnection->Execute("INSERT INTO {$db_prefix}prefs (pref_name, pref_value) VALUES (?, ?)", array($name, $value));
 999                  }
1000              }
1001              // Delete what is too much

1002              foreach ($existing as $name) {
1003                  if (!isset($upgradeInfo['fsprefs'][$name])) {
1004                      $this->mDbConnection->Execute("DELETE FROM {$db_prefix}prefs WHERE pref_name = ?", array($name));
1005                  }
1006              }
1007          }
1008      
1009        $this->mDbConnection->Execute("UPDATE {$db_prefix}prefs SET pref_value = ? WHERE pref_name = 'fs_ver'", array($this->version));
1010  
1011        if (($error_no = $this->mDbConnection->MetaError()))
1012        {
1013           $_SESSION['page_heading'] = 'Database Processing';
1014           switch ($error_no)
1015           {
1016              case '-5':
1017              // If there are tables with the same name

1018              $_SESSION['page_message'][] = 'Table ' .$this->mDbConnection->MetaErrorMsg($this->mDbConnection->MetaError());
1019              $_SESSION['page_message'][] = 'There probably are tables in the database which have the same prefix you provided.';
1020              $_SESSION['page_message'][] = 'It is advised to change the prefix provided or you can drop the existing tables if you don\'t need them. Make a backup if you are not certain.';
1021              return false;
1022              break;
1023  
1024              case '-1':
1025              // We are using the unknown error code(-1) because ADOdb library may not have the error defined.

1026              $_SESSION['page_message'][] = $this->mDbConnection->ErrorMsg();
1027              return false;
1028              break;
1029  
1030              default:
1031              $_SESSION['page_message'][] = $this->mDbConnection->ErrorMsg() . ': ' . $this->mDbConnection->ErrorNo();
1032              $_SESSION['page_message'][] = 'Unknown error, please notify Developer quoting the error number';
1033              return false;
1034              break;
1035            }
1036         }
1037  
1038         return true;
1039     }
1040  
1041  
1042  
1043  
1044     /**

1045     * Function to return status of boolean results in html format

1046     * @param boolean $boolean The status of the result in True/False form

1047     * @param string $type The type of html format to return

1048     * @return string Depending on the type of format to return

1049     */
1050     public function ReturnStatus($boolean, $type = 'yes')
1051     {
1052        // Do a switch on the type of status

1053        switch($type)
1054        {
1055        case 'yes':
1056           return ($boolean)
1057           ?  '<span class="green">Yes</span>'
1058           :  '<span class="red">No</span>';
1059           break;
1060  
1061        case 'available':
1062           return ($boolean)
1063           ?  '<span class="green">Available</span>'
1064           :  '<span class="red">Missing</span>';
1065           break;
1066  
1067        case 'writeable':
1068           return ($boolean)
1069           ?  '<span class="green">Writeable</span>'
1070           :  '<span class="red">Un-writeable</span>';
1071           break;
1072  
1073        case 'on':
1074           return ($boolean)
1075           ?  '<span class="green">ON</span>'
1076           :  '<span class="red">OFF</span>';
1077           break;
1078        case 'support':
1079           return ($boolean)
1080           ?  '<span class="green">Supported</span>'
1081           :  '<span class="red">X</span>';
1082           break;
1083        default:
1084           return ($boolean)
1085           ?  '<span class="green">True</span>'
1086           :  '<span class="red">False</span>';
1087           break;
1088        }
1089     }
1090  
1091     /**

1092        * To verify if a string was empty or not.

1093        *

1094        * Usually used to validate user input. If the user has inputted empty data

1095        * or just blank spaces, we need to trim of such empty data and see if

1096        * anything else is left after trimming. If there is data remaining, then

1097        * the return value will be greater than 0 else it will be 0 (zero) which

1098        * equates to a true/false scenario

1099        *

1100        * @param string $arg The data to be checked

1101        *

1102        * @return The result of the check.

1103        */
1104     public function TrimArgs($arg)
1105     {
1106        return strlen(trim($arg));
1107     }
1108  
1109     public function VerifyVariableTypes($type, $value)
1110     {
1111        $message = '';
1112        switch($type)
1113        {
1114              case 'string':
1115                  return is_string($value);
1116              break;
1117  
1118              case 'number':
1119                  return is_numeric($value);
1120              break;
1121  
1122              case 'email address':
1123               include_once  OBJECTS_PATH . '/external/Validate.php';
1124               return Validate::email($value);
1125               break;
1126  
1127              case 'boolean':
1128                  return (bool) $value;
1129              break;
1130  
1131              case 'password':
1132                  return (strlen($value) >= $this->mMinPasswordLength);
1133              break;
1134  
1135              case 'folder':
1136                   return is_dir($value);
1137              break;
1138  
1139              default:
1140                  return true;
1141               break;
1142        }
1143     }
1144  
1145     /**

1146     * Function to output the templates

1147     * @param array $templates The collection of templates with their associated variables

1148     *

1149     */
1150     public function OutputPage($templates = array())
1151     {
1152        if (sizeof($templates) == 0)
1153        {
1154           trigger_error("Templates not configured properly", E_USER_ERROR);
1155        }
1156  
1157        // Define a set of common variables which plugin to the structure template.

1158        $page = new Tpl;
1159        $body = '';
1160  
1161        // Loop through the templates array to dynamically create objects and assign variables to them.

1162        /// XXX: this is not a common way to use our template class, but I didn't want to rewrite

1163        ///      the whole setup only to change the templating engine

1164        foreach($templates as $name => $module)
1165        {
1166          foreach ($module['vars'] as $var_name => $value) {
1167              $page->assign($var_name, $value);
1168          }
1169  
1170          if ($name == 'structure') {
1171              $page->assign('body', $body);
1172              $page->display('structure.tpl');
1173          } else {
1174              $body .= $page->fetch($module['template']);
1175          }
1176        }
1177     }
1178  }
1179  
1180  //start the installer, it handles the rest inside the class

1181  new Setup();

title

Description

title

Description

title

Description

title

title

Body