00001 <?php
00007 namespace Habari;
00008
00009 define( 'MIN_PHP_VERSION', '5.3.3' );
00010
00014 class InstallHandler extends ActionHandler
00015 {
00016
00022 public function act_begin_install()
00023 {
00024
00025 $this->theme = Themes::create( 'installer', 'RawPHPEngine', HABARI_PATH . '/system/installer/' );
00026
00030 $this->theme->locales = Locale::list_all();
00031 if ( isset( $_POST['locale'] ) && $_POST['locale'] != null ) {
00032 Locale::set( $_POST['locale'] );
00033 }
00034 else {
00035 Locale::set( Config::get('locale', 'en-us' ) );
00036 }
00037 $this->theme->locale = Locale::get();
00038 $this->handler_vars['locale'] = Locale::get();
00039
00043 if ( ! $this->check_htaccess() ) {
00044 $this->handler_vars['file_contents'] = htmlentities( implode( "\n", $this->htaccess() ) );
00045 $this->display( 'htaccess' );
00046 }
00047
00048
00049 if ( isset( $_POST['ajax_action'] ) ) {
00050 switch ( $_POST['ajax_action'] ) {
00051 case 'check_mysql_credentials':
00052 self::ajax_check_mysql_credentials();
00053 exit;
00054 break;
00055 case 'check_pgsql_credentials':
00056 self::ajax_check_pgsql_credentials();
00057 exit;
00058 break;
00059 case 'check_sqlite_credentials':
00060 self::ajax_check_sqlite_credentials();
00061 exit;
00062 break;
00063 }
00064 }
00065
00066 $this->form_defaults();
00067
00068 if ( ! $this->meets_all_requirements() ) {
00069 $this->display( 'requirements' );
00070 }
00071
00075 Plugins::register( Method::create( '\Habari\InstallHandler', 'ajax_check_mysql_credentials' ), 'ajax_', 'check_mysql_credentials' );
00076 Plugins::register( Method::create( '\Habari\InstallHandler', 'ajax_check_pgsql_credentials' ), 'ajax_', 'check_pgsql_credentials' );
00077
00081 if ( ( ! file_exists( Site::get_dir( 'config_file' ) ) ) && ( ! isset( $_POST['admin_username'] ) ) ) {
00082
00083 $this->display( 'db_setup' );
00084 }
00085
00086
00087 if ( file_exists( Site::get_dir( 'config_file' ) ) ) {
00088 include( Site::get_dir( 'config_file' ) );
00089
00090
00091 if ( !Config::exists( 'db_connection' ) && isset( $db_connection ) ) {
00092
00093
00094
00095 Config::set( 'db_connection', $db_connection );
00096
00097
00098 $this->set_handler_vars_from_db_connection();
00099
00100
00101 if ( $this->write_config_file( true ) ) {
00102
00103 Utils::redirect( Site::get_url( 'site' ) );
00104 }
00105 }
00106
00107 if ( Config::exists( 'db_connection' ) ) {
00108 $this->set_handler_vars_from_db_connection();
00109 }
00110
00111
00112
00113 if ( Config::exists( 'blog_data' ) ) {
00114 $blog_data = Config::get('blog_data');
00115 foreach ( $blog_data as $blog_datum => $value ) {
00116 $this->handler_vars[$blog_datum] = $value;
00117 }
00118 }
00119 }
00120
00121
00122
00123 $this->handler_vars = $this->handler_vars->merge( $_POST );
00124
00125
00126 if ( ( '' == $this->handler_vars['admin_username'] )
00127 || ( '' == $this->handler_vars['admin_pass1'] )
00128 || ( '' == $this->handler_vars['admin_pass2'] )
00129 || ( '' == $this->handler_vars['admin_email'] )
00130 ) {
00131
00132 $this->display( 'db_setup' );
00133 }
00134
00135 $db_type = $this->handler_vars['db_type'];
00136 if ( (!Config::exists('db_connection') || Config::get( 'db_connection' )->connection_string == '') && ($db_type == 'mysql' || $db_type == 'pgsql') ) {
00137 $this->handler_vars['db_host'] = $_POST["{$db_type}_db_host"];
00138 $this->handler_vars['db_user'] = $_POST["{$db_type}_db_user"];
00139 $this->handler_vars['db_pass'] = $_POST->raw( "{$db_type}_db_pass" );
00140 $this->handler_vars['db_schema'] = $_POST["{$db_type}_db_schema"];
00141 }
00142
00143
00144
00145
00146 if ( $this->handler_vars['admin_pass1'] !== $this->handler_vars['admin_pass2'] ) {
00147 $this->theme->assign( 'form_errors', array( 'password_mismatch' => _t( 'Password mis-match.' ) ) );
00148 $this->display( 'db_setup' );
00149 }
00150
00151
00152 if ( !ctype_print($this->handler_vars['admin_email']) ) {
00153 $this->theme->assign( 'form_errors', array( 'admin_email' => _t( 'Only printable characters are allowed.' ) ) );
00154 $this->display( 'db_setup' );
00155 }
00156
00157
00158 if ( isset( $this->handler_vars['table_prefix'] ) && ( preg_replace( '/[^a-zA-Z_]/', '', $this->handler_vars['table_prefix'] ) !== $this->handler_vars['table_prefix'] ) ) {
00159 $this->theme->assign( 'form_errors', array( 'table_prefix' => _t( 'Allowed characters are A-Z, a-z and "_".' ) ) );
00160 $this->display( 'db_setup' );
00161 }
00162
00163
00164 if ( ! call_user_func( array( $this, "check_{$db_type}" ) ) ) {
00165 $this->display( 'db_setup' );
00166 }
00167
00168
00169 if ( ! $this->write_config_file() ) {
00170 $this->theme->assign( 'form_errors', array( 'write_file'=>_t( 'Could not write config.php file…' ) ) );
00171 $this->display( 'db_setup' );
00172 }
00173
00174
00175 if ( ! $this->install_db() ) {
00176
00177
00178 $this->display( 'db_setup' );
00179 }
00180
00181
00182 if ( count( $_POST ) > 0 ) {
00183 $this->activate_theme();
00184 $this->activate_plugins();
00185 }
00186
00187
00188
00189
00190 if ( $db_type == 'sqlite' ) {
00191 if ( !$this->secure_sqlite() ) {
00192 $this->theme->sqlite_contents = implode( "\n", $this->sqlite_contents() );
00193 $this->display( 'sqlite' );
00194 }
00195 }
00196
00197 EventLog::log( _t( 'Habari successfully installed.' ), 'info', 'default', 'habari' );
00198 Utils::redirect( Site::get_url( 'site' ) );
00199 }
00200
00204 public function get_plugins()
00205 {
00206 $all_plugins = Plugins::list_all();
00207 $recommended_list = array(
00208 'coredashmodules.plugin.php',
00209 'coreblocks.plugin.php',
00210 'habarisilo.plugin.php',
00211 'pingback.plugin.php',
00212 'spamchecker.plugin.php',
00213 'undelete.plugin.php',
00214 'autop.plugin.php'
00215 );
00216
00217 foreach ( $all_plugins as $file ) {
00218 $plugin = array();
00219 $plugin_id = Plugins::id_from_file( $file );
00220 $plugin['plugin_id'] = $plugin_id;
00221 $plugin['file'] = $file;
00222
00223 $error = '';
00224 if ( Utils::php_check_file_syntax( $file, $error ) ) {
00225 $plugin['debug'] = false;
00226
00227 $plugin['active'] = false;
00228 $plugin['verb'] = _t( 'Activate' );
00229 $plugin['actions'] = array();
00230 $plugin['info'] = Plugins::load_info( $file );
00231 $plugin['recommended'] = in_array( basename( $file ), $recommended_list );
00232 $plugin['requires'] = isset($plugin['info']->requires) ? self::get_feature_list($plugin['info']->requires->children()) : '';
00233 $plugin['provides'] = isset($plugin['info']->provides) ? self::get_feature_list($plugin['info']->provides->children()) : '';
00234 $plugin['conflicts'] = isset($plugin['info']->conflicts) ? self::get_feature_list($plugin['info']->conflicts->children()) : '';
00235 }
00236 else {
00237
00238
00239 continue;
00240 }
00241
00242 $plugins[$plugin_id] = $plugin;
00243 }
00244
00245 return $plugins;
00246 }
00247
00251 public function get_themes()
00252 {
00253 $all_themes = Themes::get_all_data();
00254
00255 return $all_themes;
00256 }
00257
00263 private function display( $template_name )
00264 {
00265 foreach ( $this->handler_vars as $key=>$value ) {
00266 $this->theme->assign( $key, $value );
00267 }
00268
00269 $this->theme->assign( 'themes', $this->get_themes() );
00270
00271 $this->theme->assign( 'plugins', $this->get_plugins() );
00272
00273 $this->theme->display( $template_name );
00274
00275 exit;
00276 }
00277
00278
00279
00280
00281 public function form_defaults()
00282 {
00283 $formdefaults['db_type'] = 'mysql';
00284 $formdefaults['db_host'] = 'localhost';
00285 $formdefaults['db_user'] = '';
00286 $formdefaults['db_pass'] = '';
00287 $formdefaults['db_file'] = 'habari.db';
00288 $formdefaults['db_schema'] = 'habari';
00289 $formdefaults['table_prefix'] = isset( Config::get( 'db_connection' )->prefix ) ? Config::get( 'db_connection' )->prefix : 'habari__';
00290 $formdefaults['admin_username'] = 'admin';
00291 $formdefaults['admin_pass1'] = '';
00292 $formdefaults['admin_pass2'] = '';
00293 $formdefaults['blog_title'] = 'My Habari';
00294 $formdefaults['admin_email'] = '';
00295
00296 foreach ( $formdefaults as $key => $value ) {
00297 if ( !isset( $this->handler_vars[$key] ) ) {
00298 $this->handler_vars[$key] = $value;
00299 }
00300 }
00301 }
00302
00309 private function meets_all_requirements()
00310 {
00311
00312
00313
00314 $required_extensions = array(
00315 'date' => 'http://php.net/datetime',
00316 'pdo' => 'http://php.net/pdo',
00317 'hash' => 'http://php.net/hash',
00318 'json' => 'http://php.net/json',
00319 'mbstring' => 'http://php.net/mbstring',
00320 'pcre' => 'http://php.net/pcre',
00321 'session' => 'http://php.net/session',
00322 'simplexml' => 'http://php.net/simplexml',
00323 'spl' => 'http://php.net/spl',
00324 'tokenizer' => 'http://php.net/tokenizer',
00325 );
00326 $requirements_met = true;
00327
00328
00329 $php_version_ok = version_compare( phpversion(), MIN_PHP_VERSION, '>=' );
00330 $this->theme->assign( 'php_version_ok', $php_version_ok );
00331 $this->theme->assign( 'PHP_OS', PHP_OS );;
00332 $this->theme->assign( 'PHP_VERSION', phpversion() );
00333 if ( ! $php_version_ok ) {
00334 $requirements_met = false;
00335 }
00336
00337 $mod_rewrite = true;
00338 if ( function_exists( 'apache_get_modules' ) && !in_array( 'mod_rewrite', apache_get_modules() ) ) {
00339 $requirements_met = false;
00340 $mod_rewrite = false;
00341 }
00342 $this->theme->assign( 'mod_rewrite', $mod_rewrite );
00343
00344 $missing_extensions = array();
00345 foreach ( $required_extensions as $ext_name => $ext_url ) {
00346 if ( !extension_loaded( $ext_name ) ) {
00347 $missing_extensions[$ext_name] = $ext_url;
00348 $requirements_met = false;
00349 }
00350 }
00351 $this->theme->assign( 'missing_extensions', $missing_extensions );
00352
00353 if ( extension_loaded( 'pdo' ) ) {
00354
00355 $pdo_drivers = \PDO::getAvailableDrivers();
00356 if ( ! empty( $pdo_drivers ) ) {
00357 $pdo_drivers = array_combine( $pdo_drivers, $pdo_drivers );
00358
00359 $pdo_schemas = array_map( 'basename', Utils::glob( HABARI_PATH . '/system/schema/*', GLOB_ONLYDIR ) );
00360 $pdo_schemas = array_combine( $pdo_schemas, $pdo_schemas );
00361
00362 $pdo_drivers = array_intersect_key(
00363 $pdo_drivers,
00364 $pdo_schemas
00365 );
00366 $pdo_missing_drivers = array_diff(
00367 $pdo_schemas,
00368 $pdo_drivers
00369 );
00370
00371 $pdo_drivers_ok = count( $pdo_drivers );
00372 $this->theme->assign( 'pdo_drivers_ok', $pdo_drivers_ok );
00373 $this->theme->assign( 'pdo_drivers', $pdo_drivers );
00374 $this->theme->assign( 'pdo_missing_drivers', $pdo_missing_drivers );
00375 }
00376 else {
00377 $pdo_drivers_ok = false;
00378 $this->theme->assign( 'pdo_drivers_ok', $pdo_drivers_ok );
00379 }
00380 if ( ! $pdo_drivers_ok ) {
00381 $requirements_met = false;
00382 }
00383 }
00384 else {
00385 $this->theme->assign( 'pdo_drivers_ok', false );
00386 $this->theme->assign( 'pdo_drivers', array() );
00387 $requirements_met = false;
00388 }
00389
00390 if ( $requirements_met && ! @preg_match( '/\p{L}/u', 'a' ) ) {
00391 $requirements_met = false;
00392 }
00393
00400 $this->theme->assign( 'local_writable', true );
00401
00402 return $requirements_met;
00403 }
00404
00412 private function install_db()
00413 {
00414 $db_host = $this->handler_vars['db_host'];
00415 $db_type = $this->handler_vars['db_type'];
00416 $db_schema = $this->handler_vars['db_schema'];
00417 $db_user = $this->handler_vars['db_user'];
00418 $db_pass = $this->handler_vars['db_pass'];
00419
00420 switch ( $db_type ) {
00421 case 'mysql':
00422 case 'pgsql':
00423
00424 if ( empty( $db_user ) ) {
00425 $this->theme->assign( 'form_errors', array( "{$db_type}_db_user"=>_t( 'User is required.' ) ) );
00426 return false;
00427 }
00428 if ( empty( $db_schema ) ) {
00429 $this->theme->assign( 'form_errors', array( "{$db_type}_db_schema"=>_t( 'Name for database is required.' ) ) );
00430 return false;
00431 }
00432 if ( empty( $db_host ) ) {
00433 $this->theme->assign( 'form_errors', array( "{$db_type}_db_host"=>_t( 'Host is required.' ) ) );
00434 return false;
00435 }
00436 break;
00437 case 'sqlite':
00438
00439
00440 if ( ! $this->check_sqlite() ) {
00441 return false;
00442 }
00443 break;
00444 }
00445
00446 if ( isset( $this->handler_vars['table_prefix'] ) ) {
00447
00448 Config::set( 'db_connection', array( 'prefix' => $this->handler_vars['table_prefix'], ) );
00449 }
00450
00451 if ( ! $this->connect_to_existing_db() ) {
00452 $this->theme->assign( 'form_errors', array( "{$db_type}_db_user"=>_t( 'Problem connecting to supplied database credentials' ) ) );
00453 return false;
00454 }
00455
00456 DB::begin_transaction();
00457
00458 $create_table_queries = $this->get_create_table_queries(
00459 $this->handler_vars['db_type'],
00460 $this->handler_vars['table_prefix'],
00461 $this->handler_vars['db_schema']
00462 );
00463 DB::clear_errors();
00464 DB::dbdelta( $create_table_queries, true, true, true );
00465
00466 if ( DB::has_errors() ) {
00467 $error = DB::get_last_error();
00468 $this->theme->assign( 'form_errors', array( 'db_host'=>_t( 'Could not create schema tables… %s', array( $error['message'] ) ) ) );
00469 DB::rollback();
00470 return false;
00471 }
00472
00473
00474
00475 if ( ! Options::get( 'installed' ) ) {
00476 if ( ! $this->create_default_options() ) {
00477 $this->theme->assign( 'form_errors', array( 'options'=>_t( 'Problem creating default options' ) ) );
00478 DB::rollback();
00479 return false;
00480 }
00481 }
00482
00483
00484 if ( ! $this->create_tags_vocabulary() ) {
00485 $this->theme->assign( 'form_errors', array( 'options'=>_t( 'Problem creating tags vocabulary' ) ) );
00486 DB::rollback();
00487 return false;
00488 }
00489
00490
00491 if ( ! $this->create_base_post_types() ) {
00492 $this->theme->assign( 'form_errors', array( 'options'=>_t( 'Problem creating base post types' ) ) );
00493 DB::rollback();
00494 return false;
00495 }
00496
00497 if ( ! $this->create_base_comment_types() ) {
00498 $this->theme->assign( 'form_errors', array( 'options'=>_t( 'Problem creating base comment types and statuses' ) ) );
00499 DB::rollback();
00500 return false;
00501 }
00502
00503
00504
00505 $all_users = Users::get_all();
00506 if ( count( $all_users ) < 1 ) {
00507 $user = $this->create_admin_user();
00508 if ( ! $user ) {
00509 $this->theme->assign( 'form_errors', array( 'admin_user'=>_t( 'Problem creating admin user.' ) ) );
00510 DB::rollback();
00511 return false;
00512 }
00513 $admin_group = $this->create_admin_group( $user );
00514 if ( ! $admin_group ) {
00515 $this->theme->assign( 'form_errors', array( 'admin_user'=>_t( 'Problem creating admin group.' ) ) );
00516 DB::rollback();
00517 return false;
00518 }
00519
00520 ACL::rebuild_permissions( $user );
00521 }
00522
00523
00524 if ( ! Posts::get( array( 'count' => 1 ) ) ) {
00525 if ( ! $this->create_first_post() ) {
00526 $this->theme->assign( 'form_errors', array( 'post'=>_t( 'Problem creating first post.' ) ) );
00527 DB::rollback();
00528 return false;
00529 }
00530 }
00531
00532
00533 if ( !DB::in_transaction() ) {
00534 DB::begin_transaction();
00535 }
00536
00537
00538 Version::save_dbversion();
00539
00540
00541 DB::commit();
00542 return true;
00543 }
00544
00549 public function check_mysql()
00550 {
00551
00552 $pdo = 'mysql:host=' . $this->handler_vars['db_host'] . ';dbname=' . $this->handler_vars['db_schema'];
00553 if ( isset( $this->handler_vars['table_prefix'] ) ) {
00554
00555 Config::set( 'db_connection', array( 'prefix' => $this->handler_vars['table_prefix'], ) );
00556 }
00557 try {
00558 $connect = DB::connect( $pdo, $this->handler_vars['db_user'], html_entity_decode( $this->handler_vars['db_pass'] ) );
00559 return true;
00560 }
00561 catch( \PDOException $e ) {
00562 if ( strpos( $e->getMessage(), '[1045]' ) ) {
00563 $this->theme->assign( 'form_errors', array( 'mysql_db_pass' => _t( 'Access denied. Make sure these credentials are valid.' ) ) );
00564 }
00565 else if ( strpos( $e->getMessage(), '[1049]' ) ) {
00566 $this->theme->assign( 'form_errors', array( 'mysql_db_schema' => _t( 'That database does not exist.' ) ) );
00567 }
00568 else if ( strpos( $e->getMessage(), '[2005]' ) ) {
00569 $this->theme->assign( 'form_errors', array( 'mysql_db_host' => _t( 'Could not connect to host.' ) ) );
00570 }
00571 else {
00572 $this->theme->assign( 'form_errors', array( 'mysql_db_host' => $e->getMessage() ) );
00573 }
00574 return false;
00575 }
00576 }
00577
00582 public function check_pgsql()
00583 {
00584
00585 $pdo = 'pgsql:host=' . $this->handler_vars['db_host'] . ';dbname=' . $this->handler_vars['db_schema'];
00586 if ( isset( $this->handler_vars['table_prefix'] ) ) {
00587
00588 Config::set( 'db_connection', array( 'prefix' => $this->handler_vars['table_prefix'], ) );
00589 }
00590 try {
00591 $connect = DB::connect( $pdo, $this->handler_vars['db_user'], html_entity_decode( $this->handler_vars['db_pass'] ) );
00592 return true;
00593 }
00594 catch( \PDOException $e ) {
00595 if ( strpos( $e->getMessage(), '[1045]' ) ) {
00596 $this->theme->assign( 'form_errors', array( 'pgsql_db_pass' => _t( 'Access denied. Make sure these credentials are valid.' ) ) );
00597 }
00598 else if ( strpos( $e->getMessage(), '[1049]' ) ) {
00599 $this->theme->assign( 'form_errors', array( 'pgsql_db_schema' => _t( 'That database does not exist.' ) ) );
00600 }
00601 else if ( strpos( $e->getMessage(), '[2005]' ) ) {
00602 $this->theme->assign( 'form_errors', array( 'pgsql_db_host' => _t( 'Could not connect to host.' ) ) );
00603 }
00604 else {
00605 $this->theme->assign( 'form_errors', array( 'pgsql_db_host' => $e->getMessage() ) );
00606 }
00607 return false;
00608 }
00609 }
00610
00615 private function check_sqlite()
00616 {
00617 $db_file = $this->handler_vars['db_file'];
00618 if ( $db_file == basename( $db_file ) ) {
00619 $db_file = Site::get_path( 'user', true ) . $db_file;
00620 }
00621 if ( file_exists( $db_file ) && is_writable( $db_file ) && is_writable( dirname( $db_file ) ) ) {
00622
00623 return true;
00624 }
00625
00626
00627 if ( file_exists( $db_file ) ) {
00628
00629 if ( ! is_writable( $db_file ) ) {
00630 $this->theme->assign( 'form_errors', array( 'db_file'=>_t( 'Cannot write to %s. The SQLite data file is not writable by the web server.', array( $db_file ) ) ) );
00631 return false;
00632 }
00633 if ( ! is_writable( dirname( $db_file ) ) ) {
00634 $this->theme->assign( 'form_errors', array( 'db_file'=>_t( 'Cannot write to %s directory. SQLite requires that the directory that holds the DB file be writable by the web server.', array( $db_file ) ) ) );
00635 return false;
00636 }
00637 }
00638
00639 if ( ! file_exists( $db_file ) ) {
00640
00641
00642 if ( ! is_writable( dirname( $db_file ) ) ) {
00643 $this->theme->assign( 'form_errors', array( 'db_file'=>_t( 'Cannot write to %s directory. The SQLite data file does not exist, and it cannot be created in the specified directory. SQLite requires that the directory containing the database file be writable by the web server.', array( $db_file ) ) ) );
00644 return false;
00645 }
00646 }
00647 return true;
00648 }
00649
00656 private function connect_to_existing_db()
00657 {
00658 if ( $config = $this->get_config_file() ) {
00659 $config = preg_replace( '/<\\?php(.*)\\?'.'>/ims', '$1', $config );
00660
00661 eval( $config );
00662
00663
00664 try {
00665 DB::connect();
00666 return true;
00667 }
00668 catch( \PDOException $e ) {
00669 $this->theme->assign( 'form_errors', array( 'db_user'=>_t( 'Problem connecting to supplied database credentials' ) ) );
00670 return false;
00671
00672 }
00673 }
00674
00675 return false;
00676 }
00677
00683 private function create_admin_user()
00684 {
00685 $admin_username = $this->handler_vars['admin_username'];
00686 $admin_email = $this->handler_vars['admin_email'];
00687 $admin_pass = $this->handler_vars['admin_pass1'];
00688
00689 if ( $admin_pass{0} == '{' ) {
00690
00691 $password = $admin_pass;
00692
00693
00694 $algo = strtolower( substr( $admin_pass, 1, 3 ) );
00695 if ( ( 'ssh' != $algo ) && ( 'sha' != $algo ) ) {
00696
00697
00698 $password = Utils::crypt( $admin_pass );
00699 }
00700 }
00701 else {
00702 $password = Utils::crypt( $admin_pass );
00703 }
00704
00705
00706 $user = User::create( array (
00707 'username' => $admin_username,
00708 'email' => $admin_email,
00709 'password' => $password
00710 ) );
00711
00712 return $user;
00713 }
00714
00721 private function create_admin_group( $user )
00722 {
00723
00724 $group = UserGroup::create( array( 'name' => _t( 'admin' ) ) );
00725 if ( ! $group ) {
00726 return false;
00727 }
00728 $group->add( $user->id );
00729 return $group;
00730 }
00731
00732 private function create_anonymous_group()
00733 {
00734
00735 $group = UserGroup::create( array( 'name' => _t( 'anonymous' ) ) );
00736 if ( ! $group ) {
00737 return false;
00738 }
00739 $group->grant( 'post_entry', 'read' );
00740 $group->grant( 'post_page', 'read' );
00741
00742
00743 $group->add( 0 );
00744 }
00745
00749 private function create_default_options()
00750 {
00751
00752 EventLog::register_type( 'default', 'habari' );
00753 EventLog::register_type( 'user', 'habari' );
00754 EventLog::register_type( 'authentication', 'habari' );
00755 EventLog::register_type( 'content', 'habari' );
00756 EventLog::register_type( 'comment', 'habari' );
00757
00758
00759 $defaults = array(
00760 'installed' => true,
00761 'title' => $this->handler_vars['blog_title'],
00762 'pagination' => 5,
00763 'atom_entries' => 5,
00764 'theme_name' => 'Charcoal',
00765 'theme_dir' => 'charcoal',
00766 'comments_require_id' => 1,
00767 'locale' => $this->handler_vars['locale'],
00768 'timezone' => 'UTC',
00769 'dateformat' => 'Y-m-d',
00770 'timeformat' => 'g:i a',
00771 'log_min_severity' => 3,
00772 'spam_percentage' => 100,
00773
00774
00775
00776 'GUID' => sha1( Utils::nonce() ),
00777 'private-GUID' => sha1( Utils::nonce() ),
00778 'public-GUID' => sha1( Utils::nonce() ),
00779 );
00780
00781
00782 foreach ( $this->handler_vars as $id => $value ) {
00783 if ( preg_match( '/option_(.+)/u', $id, $matches ) ) {
00784 $defaults[$matches[1]] = $value;
00785 }
00786 }
00787
00788
00789 foreach($defaults as $key => $value) {
00790 Options::set($key, $value);
00791 }
00792
00793
00794 CronTab::add_daily_cron( 'trim_log', Method::create( '\Habari\EventLog', 'trim' ), _t( 'Trim the log table' ) );
00795
00796
00797 CronTab::add_daily_cron( 'update_check', Method::create( '\Habari\Update', 'cron' ), _t( 'Perform a check for plugin updates.' ) );
00798
00799
00800 CronTab::add_hourly_cron( 'session_gc', Method::create( '\Habari\Session', 'gc' ), _t( 'Perform session garbage collection.' ) );
00801
00802 return true;
00803 }
00804
00808 private function create_base_post_types()
00809 {
00810
00811
00812 Post::add_new_type( 'entry' );
00813 Post::add_new_type( 'page' );
00814
00815
00816
00817
00818 Post::add_new_status( 'draft' );
00819 Post::add_new_status( 'published' );
00820 Post::add_new_status( 'scheduled', true );
00821
00822 return true;
00823 }
00824
00828 private function create_tags_vocabulary()
00829 {
00830 $vocabulary = new Vocabulary( array( 'name' => 'tags', 'description' => 'Habari\'s tags implementation', 'features' => array( 'multiple', 'free' ) ) );
00831 $vocabulary->insert();
00832
00833 return true;
00834 }
00835
00839 private function create_first_post()
00840 {
00841 $users = Users::get();
00842 Post::create( array(
00843 'title' => 'Habari',
00844 'content' => _t( 'This site is running <a href="http://habariproject.org/">Habari</a>, a state-of-the-art publishing platform! Habari is a community-driven project created and supported by people from all over the world. Please visit <a href="http://habariproject.org/">http://habariproject.org/</a> to find out more!' ),
00845 'user_id' => $users[0]->id,
00846 'status' => Post::status( 'published' ),
00847 'content_type' => Post::type( 'entry' ),
00848 'tags' => 'habari',
00849 ) );
00850
00851 return true;
00852 }
00853
00861 private function get_create_table_queries( $db_type, $table_prefix, $db_schema )
00862 {
00863
00864 $file_path = HABARI_PATH . "/system/schema/{$db_type}/schema.sql";
00865 $schema_sql = trim( file_get_contents( $file_path ), "\r\n " );
00866 $schema_sql = str_replace( '{$schema}', $db_schema, $schema_sql );
00867 $schema_sql = str_replace( '{$prefix}', $table_prefix, $schema_sql );
00868
00869
00870
00871
00872
00873
00874 $schema_sql = str_replace( array( "\r\n", "\r", ), array( "\n", "\n" ), $schema_sql );
00875 $schema_sql = preg_replace( "/;\n([^\n])/", ";\n\n$1", $schema_sql );
00876 $schema_sql = preg_replace( "/\n{3,}/", "\n\n", $schema_sql );
00877 $queries = preg_split( '/(\\r\\n|\\r|\\n)\\1/', $schema_sql );
00878 return $queries;
00879 }
00880
00881
00887 private function get_create_schema_and_user_queries()
00888 {
00889 $db_host = $this->handler_vars['db_host'];
00890 $db_type = $this->handler_vars['db_type'];
00891 $db_schema = $this->handler_vars['db_schema'];
00892 $db_user = $this->handler_vars['db_user'];
00893 $db_pass = $this->handler_vars['db_pass'];
00894
00895 $queries = array();
00896 switch ( $db_type ) {
00897 case 'mysql':
00898 $queries[] = 'CREATE DATABASE ' . $db_schema . ';';
00899 $queries[] = 'GRANT ALL ON ' . $db_schema . '.* TO \'' . $db_user . '\'@\'' . $db_host . '\' ' .
00900 'IDENTIFIED BY \'' . $db_pass . '\';';
00901 break;
00902 case 'pgsql':
00903 $queries[] = 'CREATE DATABASE ' . $db_schema . ';';
00904 $queries[] = 'GRANT ALL ON DATABASE ' . $db_schema . ' TO ' . $db_user . ';';
00905 break;
00906 default:
00907 die( _t( 'currently unsupported.' ) );
00908 }
00909 return $queries;
00910 }
00911
00917 private function get_config_file()
00918 {
00919 if ( ! ( $file_contents = file_get_contents( HABARI_PATH . "/system/schema/" . $this->handler_vars['db_type'] . "/config.php" ) ) ) {
00920 return false;
00921 }
00922
00923 $vars = array();
00924 foreach ( $this->handler_vars as $k => $v ) {
00925 $vars[$k] = addslashes( $v );
00926 }
00927 $keys = array();
00928 foreach ( array_keys( $vars ) as $v ) {
00929 $keys[] = Utils::map_array( $v );
00930 }
00931
00932 $file_contents = str_replace(
00933 $keys,
00934 $vars,
00935 $file_contents
00936 );
00937 return $file_contents;
00938 }
00939
00947 private function write_config_file( $ignore_registry = false )
00948 {
00949 // first, check if a config.php file exists
00950 if ( file_exists( Site::get_dir( 'config_file' ) ) ) {
00951 // set the defaults for comparison
00952 $db_host = $this->handler_vars['db_host'];
00953 $db_file = $this->handler_vars['db_file'];
00954 $db_type = $this->handler_vars['db_type'];
00955 $db_schema = $this->handler_vars['db_schema'];
00956 $db_user = $this->handler_vars['db_user'];
00957 $db_pass = $this->handler_vars['db_pass'];
00958 $table_prefix = $this->handler_vars['table_prefix'];
00959
00960 // set the connection string
00961 switch ( $db_type ) {
00962 case 'mysql':
00963 $connection_string = "$db_type:host=$db_host;dbname=$db_schema";
00964 break;
00965 case 'pgsql':
00966 $connection_string = "$db_type:host=$db_host dbname=$db_schema";
00967 break;
00968 case 'sqlite':
00969 $connection_string = "$db_type:$db_file";
00970 break;
00971 }
00972
00973 // load the config.php file
00974 include( Site::get_dir( 'config_file' ) );
00975
00976 // and now we compare the values defined there to
00977 // the values POSTed to the installer
00978 if ( !$ignore_registry && Config::exists( 'db_connection' ) &&
00979 ( Config::get( 'db_connection' )->connection_string == $connection_string )
00980 && ( Config::get( 'db_connection' )->username == $db_user )
00981 && ( Config::get( 'db_connection' )->password == $db_pass )
00982 && ( Config::get( 'db_connection' )->prefix == $table_prefix )
00983 ) {
00984 // the values are the same, so don't bother
00985
00986 return true;
00987 }
00988 }
00989 if ( ! ( $file_contents = file_get_contents( HABARI_PATH . "/system/schema/" . $this->handler_vars['db_type'] . "/config.php" ) ) ) {
00990 return false;
00991 }
00992 if ( $file_contents = html_entity_decode( $this->get_config_file() ) ) {
00993 if ( $file = @fopen( Site::get_dir( 'config_file' ), 'w' ) ) {
00994 if ( fwrite( $file, $file_contents, strlen( $file_contents ) ) ) {
00995 fclose( $file );
00996 return true;
00997 }
00998 }
00999 $this->handler_vars['config_file'] = Site::get_dir( 'config_file' );
01000 $this->handler_vars['file_contents'] = Utils::htmlspecialchars( $file_contents );
01001 $this->display( 'config' );
01002 return false;
01003 }
01004 return false;
01005 }
01006
01007
01008 public function activate_theme()
01009 {
01010 $theme_dir = $this->handler_vars['theme'];
01011
01012
01013 if ( ! $u = User::get_by_name( $this->handler_vars['admin_username'] ) ) {
01014
01015 die( _t( 'No admin user found' ) );
01016 }
01017 $u->remember();
01018
01019 $themes = Themes::get_all_data();
01020 $theme = $themes[$theme_dir];
01021 Themes::activate_theme((string)$theme['info']->name, $theme_dir);
01022
01023
01024 Session::clear_userid( $_SESSION['user_id'] );
01025 unset( $_SESSION['user_id'] );
01026 }
01027
01028 public function activate_plugins()
01029 {
01030
01031 $plugin_ids = array();
01032 foreach ( $this->handler_vars as $id => $activate ) {
01033 if ( preg_match( '/plugin_([a-f0-9]{8})/u', $id, $matches ) && $activate ) {
01034 $plugin_ids[] = $matches[1];
01035 }
01036 elseif ( preg_match( '/plugin_(.+)/u', $id, $matches ) && $activate ) {
01037 $plugin_ids[] = $matches[1];
01038 }
01039 }
01040
01041
01042 if ( ! $u = User::get_by_name( $this->handler_vars['admin_username'] ) ) {
01043
01044 die( _t( 'No admin user found' ) );
01045 }
01046 $u->remember();
01047
01048
01049 $plugin_files = Plugins::list_all();
01050 foreach ( $plugin_files as $file ) {
01051 if ( in_array( basename($file), $plugin_ids ) ) {
01052 Plugins::activate_plugin( $file );
01053 continue;
01054 }
01055 $id = Plugins::id_from_file( $file );
01056 if ( in_array( $id, $plugin_ids ) ) {
01057 Plugins::activate_plugin( $file );
01058 }
01059 }
01060
01061
01062 Session::clear_userid( $_SESSION['user_id'] );
01063 unset( $_SESSION['user_id'] );
01064 }
01065
01069 public function htaccess()
01070 {
01071 $htaccess = array(
01072 'open_block' => '### HABARI START',
01073 'engine_on' => 'RewriteEngine On',
01074 'rewrite_cond_f' => 'RewriteCond %{REQUEST_FILENAME} !-f',
01075 'rewrite_cond_d' => 'RewriteCond %{REQUEST_FILENAME} !-d',
01076 'rewrite_favicon' => 'RewriteCond %{REQUEST_URI} !=/favicon.ico',
01077 'rewrite_base' => '#RewriteBase /',
01078 'rewrite_rule' => 'RewriteRule . index.php [PT]',
01079 'hide_habari' => 'RewriteRule ^(system/(classes|handlers|locale|schema|$)) index.php [PT]',
01080
01081 'close_block' => '### HABARI END',
01082 );
01083 $rewrite_base = trim( dirname( $_SERVER['SCRIPT_NAME'] ), '/\\' );
01084 if ( $rewrite_base != '' ) {
01085 $htaccess['rewrite_base'] = 'RewriteBase "/' . $rewrite_base . '"';
01086 }
01087
01088 return $htaccess;
01089 }
01090
01095 public function check_htaccess()
01096 {
01097
01098 $this->handler_vars['no_mod_rewrite'] = false;
01099
01100
01101 if ( strpos( $_SERVER['REQUEST_URI'], 'check_mod_rewrite' ) !== false ) {
01102 echo 'ok';
01103 exit;
01104 }
01105
01106 if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache' ) ) {
01107
01108
01109 return true;
01110 }
01111
01112 $result = false;
01113 if ( file_exists( HABARI_PATH . '/.htaccess' ) ) {
01114 $htaccess = file_get_contents( HABARI_PATH . '/.htaccess' );
01115 if ( false === strpos( $htaccess, 'HABARI' ) ) {
01116
01117
01118 $result = $this->write_htaccess( true );
01119 }
01120 else {
01121
01122 $result = true;
01123 }
01124 }
01125 else {
01126
01127 $result = $this->write_htaccess();
01128 }
01129 if ( $result ) {
01130
01131
01132
01133 $test_ajax_url = Site::get_url( 'site' ) . '/check_mod_rewrite';
01134 $rr = new RemoteRequest( $test_ajax_url, 'POST', 5 );
01135 try {
01136 $rr_result = $rr->execute();
01137 }
01138 catch ( \Exception $e ) {
01139 $result = $this->write_htaccess( true, true, true );
01140 }
01141 }
01142 return $result;
01143 }
01144
01152 public function write_htaccess( $exists = false, $update = false, $rewritebase = true )
01153 {
01154 $htaccess = $this->htaccess();
01155 if ( $rewritebase ) {
01156 $rewrite_base = trim( dirname( $_SERVER['SCRIPT_NAME'] ), '/\\' );
01157 $htaccess['rewrite_base'] = 'RewriteBase "/' . $rewrite_base . '"';
01158 }
01159 $file_contents = "\n" . implode( "\n", $htaccess ) . "\n";
01160
01161 if ( ! $exists ) {
01162 if ( ! is_writable( HABARI_PATH ) ) {
01163
01164 return false;
01165 }
01166 }
01167 else {
01168 if ( ! is_writable( HABARI_PATH . '/.htaccess' ) ) {
01169
01170 return false;
01171 }
01172 }
01173 if ( $update ) {
01174
01175
01176 $htaccess = file_get_contents( HABARI_PATH . '/.htaccess' );
01177 $file_contents = preg_replace( '%### HABARI START.*?### HABARI END%ims', $file_contents, $htaccess );
01178
01179 $fmode = 'w';
01180 }
01181 else {
01182
01183 $fmode = 'a';
01184 }
01185
01186 if ( $fh = fopen( HABARI_PATH . '/.htaccess', $fmode ) ) {
01187 if ( false === fwrite( $fh, $file_contents ) ) {
01188 return false;
01189 }
01190 fclose( $fh );
01191 }
01192 else {
01193 return false;
01194 }
01195
01196 return true;
01197 }
01198
01202 public function sqlite_contents()
01203 {
01204 $db_file = basename( $this->handler_vars['db_file'] );
01205 $contents = array(
01206 '### HABARI SQLITE START',
01207 '<Files "' . $db_file . '">',
01208 'Order deny,allow',
01209 'deny from all',
01210 '</Files>',
01211 '### HABARI SQLITE END'
01212 );
01213
01214 return $contents;
01215 }
01216
01222 public function secure_sqlite()
01223 {
01224 if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache' ) ) {
01225
01226
01227 return true;
01228 }
01229 if ( !file_exists( HABARI_PATH . '/.htaccess' ) ) {
01230
01231 return false;
01232 }
01233 if ( !is_writable( HABARI_PATH . DIRECTORY_SEPARATOR . '.htaccess' ) ) {
01234
01235 return false;
01236 }
01237
01238
01239 $sqlite_contents = $this->sqlite_contents();
01240 $files_contents = "\n" . implode( "\n", $sqlite_contents ) . "\n";
01241
01242
01243 $current_files_contents = file_get_contents( HABARI_PATH . DIRECTORY_SEPARATOR . '.htaccess' );
01244 if ( false === strpos( $current_files_contents, $files_contents ) ) {
01245
01246 if ( $fh = fopen( HABARI_PATH . DIRECTORY_SEPARATOR . '.htaccess', 'a' ) ) {
01247 if ( false === fwrite( $fh, $files_contents ) ) {
01248
01249 return false;
01250 }
01251 fclose( $fh );
01252 }
01253 else {
01254
01255 return false;
01256 }
01257 }
01258
01259 return true;
01260 }
01261
01262 private function upgrade_db_pre ( $current_version )
01263 {
01264
01265
01266
01267 $upgrade_functions = get_class_methods( $this );
01268
01269 $upgrades = array();
01270
01271 foreach ( $upgrade_functions as $fn ) {
01272
01273
01274 if ( preg_match( '%^upgrade_db_pre_([0-9]+)$%i', $fn, $matches ) ) {
01275
01276 $upgrade_version = intval( $matches[1] );
01277
01278 if ( $upgrade_version > $current_version ) {
01279
01280 $upgrades[ sprintf( '%010s_1', $upgrade_version ) ] = $fn;
01281
01282 }
01283
01284 }
01285
01286 }
01287
01288
01289 ksort( $upgrades );
01290
01291
01292 foreach ( $upgrades as $upgrade ) {
01293
01294 $result =& call_user_func( array( $this, $upgrade ) );
01295
01296
01297 if ( $result === false ) {
01298 break;
01299 }
01300
01301 }
01302
01303 }
01304
01305 private function upgrade_db_post ( $current_version )
01306 {
01307
01308
01309
01310 $upgrade_functions = get_class_methods( $this );
01311
01312 $upgrades = array();
01313
01314 foreach ( $upgrade_functions as $fn ) {
01315
01316
01317 if ( preg_match( '%^upgrade_db_post_([0-9]+)$%i', $fn, $matches ) ) {
01318
01319 $upgrade_version = intval( $matches[1] );
01320
01321 if ( $upgrade_version > $current_version ) {
01322
01323 $upgrades[ sprintf( '%010s_1', $upgrade_version ) ] = $fn;
01324
01325 }
01326
01327 }
01328
01329 }
01330
01331
01332 ksort( $upgrades );
01333
01334 foreach ( $upgrades as $upgrade ) {
01335
01336 $result = call_user_func( array( $this, $upgrade ) );
01337
01338
01339 if ( $result === false ) {
01340 break;
01341 }
01342
01343 }
01344
01345 }
01346
01347 private function upgrade_db_pre_1345 ()
01348 {
01349
01350
01351
01352
01353 $query = 'select id, tag_slug, tag_text from {tags} where tag_slug in ( select tag_slug from {tags} group by tag_slug having count(*) > 1 ) order by id';
01354 $tags = DB::get_results( $query );
01355
01356
01357 if ( count( $tags ) > 0 ) {
01358
01359 $slug_to_id = array();
01360 $fix_tags = array();
01361
01362 foreach ( $tags as $tag_row ) {
01363
01364
01365 if ( !isset( $fix_tags[ $tag_row->tag_slug ] ) ) {
01366 $slug_to_id[ $tag_row->tag_slug ] = $tag_row->id;
01367 $fix_tags[ $tag_row->tag_slug ] = array();
01368 }
01369 else {
01370 $fix_tags[ $tag_row->tag_slug ][ $tag_row->id ] = $tag_row->tag_text;
01371 }
01372
01373 }
01374
01375 foreach ( $fix_tags as $tag_slug => $tag_texts ) {
01376
01377 Tags::rename( $slug_to_id[ $tag_slug ], array_keys( $tag_texts ) );
01378
01379 }
01380
01381 }
01382
01383 return true;
01384
01385 }
01386
01391 public function upgrade_db()
01392 {
01393 if ( Options::get( 'db_upgrading' ) ) {
01394
01395 $this->display_currently_upgrading();
01396 }
01397
01398
01399 Options::set( 'db_upgrading', true );
01400
01401
01402 list( $schema, $remainder )= explode( ':', Config::get( 'db_connection' )->connection_string );
01403 switch ( $schema ) {
01404 case 'sqlite':
01405 $db_name = '';
01406 break;
01407 case 'mysql':
01408 case 'pgsql':
01409 $pairs = $this->parse_dsn( $remainder );
01410
01411 $db_name = $pairs['dbname'];
01412 break;
01413 }
01414
01415 Cache::purge();
01416
01417
01418 $version = Options::get( 'db_version' );
01419
01420
01421 $this->upgrade_db_pre( $version );
01422
01423
01424 DB::upgrade_pre( $version );
01425
01426
01427 $queries = $this->get_create_table_queries( $schema, Config::get( 'db_connection' )->prefix, $db_name );
01428
01429 DB::dbdelta( $queries );
01430
01431
01432 $this->upgrade_db_post( $version );
01433
01434
01435 DB::upgrade_post( $version );
01436
01437 Version::save_dbversion();
01438 Options::delete( 'db_upgrading' );
01439 }
01440
01441 private function display_currently_upgrading()
01442 {
01443
01444 $error_template = "<html><head><title>%s</title></head><body><h1>%s</h1><p>%s</p></body></html>";
01445
01446
01447 $error_page = sprintf( $error_template,
01448 _t( "Site Maintenance" ),
01449 _t( "Habari is currently being upgraded." ),
01450 _t( "Try again in a little while." )
01451 );
01452
01453
01454 header( 'HTTP/1.1 503 Service Unavailable', true, 503 );
01455 die( $error_page );
01456 }
01457
01458 private function upgrade_db_post_1310 ()
01459 {
01460
01461
01462 if ( ! CronTab::get_cronjob( 'truncate_log' ) ) {
01463 CronTab::add_daily_cron( 'truncate_log', Method::create( '\Habari\Utils', 'truncate_log' ), _t( 'Truncate the log table' ) );
01464 }
01465
01466 return true;
01467
01468 }
01469
01470 private function upgrade_db_post_1794 ()
01471 {
01472
01473 Post::add_new_status( 'scheduled', true );
01474
01475 return true;
01476
01477 }
01478
01479 private function upgrade_db_post_1845 ()
01480 {
01481
01482
01483 $base_path = array_map( function($s) {return str_replace('\\', '/', $s);}, array( HABARI_PATH ) );
01484 $activated = Options::get( 'active_plugins' );
01485 if ( is_array( $activated ) ) {
01486 foreach ( $activated as $plugin ) {
01487 $index = array_search( $plugin, $activated );
01488 $plugin = str_replace( $base_path, '', $plugin );
01489 $activated[$index] = $plugin;
01490 }
01491 Options::set( 'active_plugins', $activated );
01492 }
01493
01494 return true;
01495
01496 }
01497
01498 private function upgrade_db_post_2264()
01499 {
01500
01501 $admin_group = UserGroup::get_by_name( 'admin' );
01502 if ( ! ( $admin_group instanceOf UserGroup ) ) {
01503 $admin_group = UserGroup::create( array( 'name' => 'admin' ) );
01504 }
01505
01506
01507 $users = Users::get_all();
01508 $ids = array();
01509 foreach ( $users as $user ) {
01510 $ids[] = $user->id;
01511 }
01512 $admin_group->add( $ids );
01513
01514 return true;
01515 }
01516
01517 private function upgrade_db_post_2707 ()
01518 {
01519
01520
01521 if ( !Options::get( 'timezone' ) ) {
01522 Options::set( 'timezone', 'UTC' );
01523 }
01524
01525 if ( !Options::get( 'dateformat' ) ) {
01526 Options::set( 'dateformat', 'Y-m-d' );
01527 }
01528
01529 if ( !Options::get( 'timeformat' ) ) {
01530 Options::set( 'timeformat', 'H:i:s' );
01531 }
01532
01533 return true;
01534
01535 }
01536
01537 private function upgrade_db_post_2786 ()
01538 {
01539
01540
01541 DB::query( 'DELETE FROM {tag2post} WHERE post_id NOT IN ( SELECT DISTINCT id FROM {posts} )' );
01542
01543
01544 DB::query( 'DELETE FROM {tags} WHERE id NOT IN ( SELECT DISTINCT tag_id FROM {tag2post} )' );
01545
01546 return true;
01547
01548 }
01549
01550 private function upgrade_db_post_3030()
01551 {
01552
01553 $group = UserGroup::create( array( 'name' => 'admin' ) );
01554 if ( ! $group ) {
01555 return false;
01556 }
01557
01558
01559 ACL::create_default_tokens();
01560
01561
01562 $group->grant( 'super_user' );
01563
01564
01565 $all_users = Users::get_all();
01566 foreach ( $all_users as $user ) {
01567 $group->add( $user );
01568 }
01569
01570
01571 $this->create_anonymous_group();
01572 }
01573
01574 private function upgrade_db_post_3124()
01575 {
01576 ACL::rebuild_permissions();
01577 }
01578
01579 private function upgrade_db_post_3158()
01580 {
01581
01582 foreach ( Post::list_active_post_types() as $name => $posttype ) {
01583 ACL::destroy_token( 'own_post_' . Utils::slugify( $name ) );
01584 }
01585
01586 ACL::destroy_token( 'own_posts_any' );
01587 ACL::create_token( 'own_posts', _t( 'Permissions on one\'s own posts' ), 'Content', true );
01588 }
01589
01590 private function upgrade_db_post_3236()
01591 {
01592
01593 $atom_entries = Options::get( 'atom_entries' );
01594 if ( empty( $atom_entries ) ) {
01595 Options::set( 'atom_entries', '5' );
01596 }
01597
01598 $authenticated_group = UserGroup::get_by_name( _t( 'authenticated' ) );
01599 if ( ! $authenticated_group instanceof UserGroup ) {
01600 $authenticated_group = UserGroup::create( array( 'name' => _t( 'authenticated' ) ) );
01601 }
01602 $authenticated_group->grant( 'post_entry', 'read' );
01603 $authenticated_group->grant( 'post_page', 'read' );
01604 $authenticated_group->grant( 'comment' );
01605
01606 }
01607
01608 private function upgrade_db_post_3539()
01609 {
01610
01611
01612 $hide = Options::get( 'dashboard__hide_spam_count' );
01613
01614
01615 if ( $hide == true ) {
01616
01617 $users = Users::get();
01618
01619 foreach ( $users as $user ) {
01620
01621 $user->info->dashboard_hide_spam_count = 1;
01622 $user->update();
01623
01624 }
01625
01626 }
01627
01628 Options::delete( 'dashboard__hide_spam_count' );
01629
01630 return true;
01631
01632 }
01633
01634 private function upgrade_db_post_3698()
01635 {
01636 ACL::create_token( 'manage_self', _t( 'Edit own profile' ), 'Administration' );
01637 }
01638
01639 private function upgrade_db_post_3701()
01640 {
01641 ACL::create_token( 'manage_dash_modules', _t( 'Manage dashboard modules' ), 'Administration' );
01642 }
01643
01644 private function upgrade_db_post_3749()
01645 {
01646 $type_id = Vocabulary::object_type_id( 'post' );
01647
01648 $vocabulary = Vocabulary::create( array( 'name' => 'tags', 'description' => 'Habari\'s tags implementation', 'features' => array( 'multiple', 'free' ) ) );
01649
01650 $new_tag = null;
01651 $post_ids = array();
01652 $prefix = Config::get( 'db_connection' )->prefix;
01653
01654 $results = DB::get_results( "SELECT id, tag_text, tag_slug from {$prefix}tags" );
01655
01656 foreach ( $results as $tag ) {
01657 $new_tag = $vocabulary->add_term( $tag->tag_text );
01658 $post_ids = DB::get_column( "SELECT post_id FROM {$prefix}tag2post WHERE tag_id = ?", array( $tag->id ) );
01659 foreach ( $post_ids as $id ) {
01660 DB::insert( "{object_terms}", array( 'term_id' => $new_tag->id, 'object_id' => $id, 'object_type_id' => $type_id ) );
01661 }
01662 }
01663 }
01664
01665 private function upgrade_db_post_4291()
01666 {
01667
01668 $active_plugins = Plugins::list_active();
01669 $all_plugins = Installhandler::get_plugins();
01670
01671 $legacy_plugins = array();
01672 foreach ( $all_plugins as $plugin ) {
01673 if ( !isset( $plugin[ 'info' ] ) ) {
01674 $key = array_search( $plugin[ 'file' ], $active_plugins );
01675 $legacy_plugins[ $key ] = $plugin[ 'file' ];
01676 }
01677 }
01678 $valid_plugins = array_diff_key( Options::get( 'active_plugins' ), $legacy_plugins );
01679
01680
01681 $new_plugins = array();
01682 if ( is_array( $valid_plugins ) ) {
01683 foreach ( $valid_plugins as $filename ) {
01684 if ( !file_exists( $filename ) ) {
01685
01686 $filename = HABARI_PATH . $filename;
01687 }
01688 if ( file_exists( $filename ) ) {
01689
01690 require_once( $filename );
01691 $class = Plugins::class_from_filename( $filename );
01692 $short_file = substr( $filename, strlen( HABARI_PATH ) );
01693 if ( $class ) {
01694 $new_plugins[ $class ] = $short_file;
01695 }
01696 }
01697 }
01698 }
01699
01700 Options::set( 'active_plugins', $new_plugins );
01701 }
01702
01703 private function upgrade_db_post_4382()
01704 {
01705
01706
01707 Options::set( 'log_min_severity', 3 );
01708
01709 }
01710
01711 private function upgrade_db_post_4571()
01712 {
01713
01714
01715 CronTab::delete_cronjob( 'truncate_log' );
01716
01717
01718 CronTab::add_daily_cron( 'trim_log', Method::create( '\Habari\EventLog', 'trim' ), _t( 'Trim the log table' ) );
01719
01720 }
01721
01722 private function upgrade_db_post_4588()
01723 {
01724
01725
01726 CronTab::add_daily_cron( 'update_check', Method::create( '\Habari\Update', 'cron' ), _t( 'Perform a check for plugin updates.' ) );
01727
01728 }
01729
01730 private function upgrade_db_post_4763()
01731 {
01732
01733
01734 Options::delete( 'base_url' );
01735
01736 }
01737
01738 private function upgrade_db_post_4770()
01739 {
01740
01741 ACL::create_token( 'post_unpublished', _t( "Permissions to other users' unpublished posts" ), _t( 'Content' ), true );
01742
01743
01744 $groups = UserGroups::get_all();
01745 foreach ( $groups as $group ) {
01746 if ( !ACL::group_can( $group->id, 'super_user', 'read' ) ) {
01747 $group->deny( 'post_unpublished' );
01748 }
01749 }
01750 }
01751
01752 private function upgrade_db_post_4980 ( ) {
01753
01754 Options::set( 'spam_percentage', 100 );
01755
01756 }
01757
01758 private function upgrade_db_post_5096 ( ) {
01759
01760 DB::exec( 'drop table {tags}' );
01761 DB::exec( 'drop table {tag2post}' );
01762
01763 }
01764
01765 private function upgrade_db_post_5097()
01766 {
01767
01768
01769
01770
01771 if ( ! ACL::token_exists( 'manage_dash_modules' ) ) {
01772 $this->upgrade_db_post_3701();
01773 }
01774 }
01775
01776 private function upgrade_db_post_5105 ( ) {
01777
01778
01779
01780 $private = sha1( Utils::nonce() );
01781 $public = sha1( Utils::nonce() );
01782
01783
01784 Options::set( 'private-GUID', Options::get( 'GUID' ) );
01785
01786
01787 Cache::purge();
01788
01789
01790 Options::set( 'private-GUID', $private );
01791 Options::set( 'public-GUID', $public );
01792
01793 }
01794
01795 private function upgrade_db_post_5106 ( ) {
01796
01797
01798
01799 $results = DB::get_results( 'SELECT name, value, type FROM {options} where type = :type', array( 'type' => 0 ), 'QueryRecord' );
01800
01801 foreach ( $results as $result ) {
01802
01803 Options::set( $result->name, $result->value );
01804 }
01805
01806
01807
01808 }
01809
01810 private function upgrade_db_post_5107 ( ) {
01811
01812
01813 CronTab::delete_cronjob( 'trim_log' );
01814 CronTab::delete_cronjob( 'update_check' );
01815
01816
01817 $crons = DB::get_results( 'SELECT * FROM {crontab} WHERE name = ?', array( 'update_check_single' ), '\Habari\CronJob' );
01818
01819 foreach ( $crons as $cron ) {
01820 $cron->delete();
01821 }
01822
01823
01824 CronTab::add_daily_cron( 'trim_log', Method::create( '\Habari\EventLog', 'trim' ), _t( 'Trim the log table' ) );
01825
01826
01827 CronTab::add_daily_cron( 'update_check', Method::create( '\Habari\Update', 'cron' ), _t( 'Perform a check for plugin updates.' ) );
01828
01829 }
01830
01831 public function upgrade_db_post_5111 ( ) {
01832
01833
01834 CronTab::add_hourly_cron( 'session_gc', Method::create( '\Habari\Session', 'gc' ), _t( 'Perform session garbage collection.' ) );
01835
01836 }
01837
01838 public function upgrade_db_post_5112 ( ) {
01839
01840 $this->create_base_comment_types();
01841
01842
01843 DB::query('UPDATE {comments} SET status = status + 30, type = type + 30');
01844
01845
01846 $updates = array('unapproved' => 0, 'approved' => 1, 'spam' => 2, 'deleted' => 3);
01847 foreach($updates as $name => $oldvalue) {
01848 DB::query(
01849 'UPDATE {comments} SET status = :newstatus WHERE status = :oldstatus',
01850 array(
01851 'newstatus' => Comment::status($name),
01852 'oldstatus' => 30 + $oldvalue,
01853 )
01854 );
01855 }
01856
01857
01858 $updates = array('comment' => 0, 'pingback' => 1, 'trackback' => 2);
01859 foreach($updates as $name => $oldvalue) {
01860 DB::query(
01861 'UPDATE {comments} SET type = :newtype WHERE type = :oldtype',
01862 array(
01863 'newtype' => Comment::type($name),
01864 'oldtype' => 30 + $oldvalue
01865 )
01866 );
01867 }
01868 }
01869
01874 public function ajax_check_mysql_credentials()
01875 {
01876 $xml = new \SimpleXMLElement( '<response></response>' );
01877
01878 if ( !isset( $_POST['host'] ) ) {
01879 $xml->addChild( 'status', 0 );
01880 $xml_error = $xml->addChild( 'error' );
01881 $xml_error->addChild( 'id', '#mysqldatabasehost' );
01882 $xml_error->addChild( 'message', _t( 'The database host field was left empty.' ) );
01883 }
01884 if ( !isset( $_POST['database'] ) ) {
01885 $xml->addChild( 'status', 0 );
01886 $xml_error = $xml->addChild( 'error' );
01887 $xml_error->addChild( 'id', '#mysqldatabasename' );
01888 $xml_error->addChild( 'message', _t( 'The database name field was left empty.' ) );
01889 }
01890 if ( !isset( $_POST['user'] ) ) {
01891 $xml->addChild( 'status', 0 );
01892 $xml_error = $xml->addChild( 'error' );
01893 $xml_error->addChild( 'id', '#mysqldatabaseuser' );
01894 $xml_error->addChild( 'message', _t( 'The database user field was left empty.' ) );
01895 }
01896 if ( isset( $_POST['table_prefix'] ) && ( preg_replace( '/[^a-zA-Z_]/', '', $_POST['table_prefix'] ) !== $_POST['table_prefix'] ) ) {
01897 $xml->addChild( 'status', 0 );
01898 $xml_error = $xml->addChild( 'error' );
01899 $xml_error->addChild( 'id', '#tableprefix' );
01900 $xml_error->addChild( 'message', _t( 'Allowed characters are A-Z, a-z and "_".' ) );
01901 }
01902 if ( !isset( $xml_error ) ) {
01903
01904 $pdo = 'mysql:host=' . $_POST['host'] . ';dbname=' . $_POST['database'];
01905 try {
01906 $connect = DB::connect( $pdo, $_POST['user'], $_POST->raw( 'pass' ) );
01907 $xml->addChild( 'status', 1 );
01908 }
01909 catch( \Exception $e ) {
01910 $xml->addChild( 'status', 0 );
01911 $xml_error = $xml->addChild( 'error' );
01912 if ( strpos( $e->getMessage(), '[1045]' ) ) {
01913 $xml_error->addChild( 'id', '#mysqldatabaseuser' );
01914 $xml_error->addChild( 'id', '#mysqldatabasepass' );
01915 $xml_error->addChild( 'message', _t( 'Access denied. Make sure these credentials are valid.' ) );
01916 }
01917 else if ( strpos( $e->getMessage(), '[1049]' ) ) {
01918 $xml_error->addChild( 'id', '#mysqldatabasename' );
01919 $xml_error->addChild( 'message', _t( 'That database does not exist.' ) );
01920 }
01921 else if ( strpos( $e->getMessage(), '[2005]' ) ) {
01922 $xml_error->addChild( 'id', '#mysqldatabasehost' );
01923 $xml_error->addChild( 'message', _t( 'Could not connect to host.' ) );
01924 }
01925 else {
01926 $xml_error->addChild( 'id', '#mysqldatabaseuser' );
01927 $xml_error->addChild( 'id', '#mysqldatabasepass' );
01928 $xml_error->addChild( 'id', '#mysqldatabasename' );
01929 $xml_error->addChild( 'id', '#mysqldatabasehost' );
01930 $xml_error->addChild( 'message', $e->getMessage() );
01931 }
01932 }
01933 }
01934 $xml = $xml->asXML();
01935 ob_clean();
01936 header( "Content-type: application/xml" );
01937 header( "Cache-Control: no-cache" );
01938 print $xml;
01939 }
01940
01945 public function ajax_check_pgsql_credentials()
01946 {
01947 $xml = new \SimpleXMLElement( '<response></response>' );
01948
01949 if ( !isset( $_POST['host'] ) ) {
01950 $xml->addChild( 'status', 0 );
01951 $xml_error = $xml->addChild( 'error' );
01952 $xml_error->addChild( 'id', '#pgsqldatabasehost' );
01953 $xml_error->addChild( 'message', _t( 'The database host field was left empty.' ) );
01954 }
01955 if ( !isset( $_POST['database'] ) ) {
01956 $xml->addChild( 'status', 0 );
01957 $xml_error = $xml->addChild( 'error' );
01958 $xml_error->addChild( 'id', '#pgsqldatabasename' );
01959 $xml_error->addChild( 'message', _t( 'The database name field was left empty.' ) );
01960 }
01961 if ( !isset( $_POST['user'] ) ) {
01962 $xml->addChild( 'status', 0 );
01963 $xml_error = $xml->addChild( 'error' );
01964 $xml_error->addChild( 'id', '#pgsqldatabaseuser' );
01965 $xml_error->addChild( 'message', _t( 'The database user field was left empty.' ) );
01966 }
01967 if ( isset( $_POST['table_prefix'] ) && ( preg_replace( '/[^a-zA-Z_]/', '', $_POST['table_prefix'] ) !== $_POST['table_prefix'] ) ) {
01968 $xml->addChild( 'status', 0 );
01969 $xml_error = $xml->addChild( 'error' );
01970 $xml_error->addChild( 'id', '#tableprefix' );
01971 $xml_error->addChild( 'message', _t( 'Allowed characters are A-Z, a-z and "_".' ) );
01972 }
01973 if ( !isset( $xml_error ) ) {
01974
01975 $pdo = 'pgsql:host=' . $_POST['host'] . ' dbname=' . $_POST['database'];
01976 try {
01977 $connect = DB::connect( $pdo, $_POST['user'], $_POST->raw( 'pass' ) );
01978 $xml->addChild( 'status', 1 );
01979 }
01980 catch( \Exception $e ) {
01981 $xml->addChild( 'status', 0 );
01982 $xml_error = $xml->addChild( 'error' );
01983 if ( strpos( $e->getMessage(), '[1045]' ) ) {
01984 $xml_error->addChild( 'id', '#pgsqldatabaseuser' );
01985 $xml_error->addChild( 'id', '#pgsqldatabasepass' );
01986 $xml_error->addChild( 'message', _t( 'Access denied. Make sure these credentials are valid.' ) );
01987 }
01988 else if ( strpos( $e->getMessage(), '[1049]' ) ) {
01989 $xml_error->addChild( 'id', '#pgsqldatabasename' );
01990 $xml_error->addChild( 'message', _t( 'That database does not exist.' ) );
01991 }
01992 else if ( strpos( $e->getMessage(), '[2005]' ) ) {
01993 $xml_error->addChild( 'id', '#pgsqldatabasehost' );
01994 $xml_error->addChild( 'message', _t( 'Could not connect to host.' ) );
01995 }
01996 else {
01997 $xml_error->addChild( 'id', '#pgsqldatabaseuser' );
01998 $xml_error->addChild( 'id', '#pgsqldatabasepass' );
01999 $xml_error->addChild( 'id', '#pgsqldatabasename' );
02000 $xml_error->addChild( 'id', '#pgsqldatabasehost' );
02001 $xml_error->addChild( 'message', $e->getMessage() );
02002 }
02003 }
02004 }
02005 $xml = $xml->asXML();
02006 ob_clean();
02007 header( "Content-type: application/xml" );
02008 header( "Cache-Control: no-cache" );
02009 print $xml;
02010 }
02011
02016 public function ajax_check_sqlite_credentials()
02017 {
02018 $db_file = $_POST['file'];
02019 $xml = new \SimpleXMLElement( '<response></response>' );
02020
02021 if ( !isset( $db_file ) ) {
02022 $xml->addChild( 'status', 0 );
02023 $xml_error = $xml->addChild( 'error' );
02024 $xml_error->addChild( 'id', '#databasefile' );
02025 $xml_error->addChild( 'message', _t( 'The database file was left empty.' ) );
02026 }
02027 if ( !isset( $xml_error ) ) {
02028 if ( $db_file == basename( $db_file ) ) {
02029 $db_file = Site::get_path( 'user', true ) . $db_file;
02030 }
02031 if ( ! is_writable( dirname( $db_file ) ) ) {
02032 $xml->addChild( 'status', 0 );
02033 $xml_error = $xml->addChild( 'error' );
02034 $xml_error->addChild( 'id', '#databasefile' );
02035 $xml_error->addChild( 'message', _t( 'Cannot write to %s directory. SQLite requires that the directory that holds the DB file be writable by the web server.', array( dirname( $db_file ) ) ) );
02036 }
02037 elseif ( file_exists( Site::get_path( 'user', true ) . $db_file ) && ( ! is_writable( Site::get_path( 'user', true ) . $db_file ) ) ) {
02038 $xml->addChild( 'status', 0 );
02039 $xml_error = $xml->addChild( 'error' );
02040 $xml_error->addChild( 'id', '#databasefile' );
02041
02042 $xml_error->addChild( 'message', _t( 'Cannot write to %s. The SQLite data file is not writable by the web server.', array( $db_file ) ) );
02043 }
02044 else {
02045
02046 $pdo = 'sqlite:' . $db_file;
02047 $connect = DB::connect( $pdo, null, null );
02048
02049
02050 DB::disconnect();
02051
02052 switch ( $connect ) {
02053 case true:
02054
02055 $xml->addChild( 'status', 1 );
02056 break;
02057 default:
02058
02059 $xml->addChild( 'status', 0 );
02060 $xml_error = $xml->addChild( 'error' );
02061
02062 $xml_error->addChild( 'id', '#databasefile' );
02063 $xml_error->addChild( 'message', $connect->getMessage() );
02064 }
02065 }
02066 }
02067 $xml = $xml->asXML();
02068 ob_clean();
02069 header( "Content-type: application/xml" );
02070 header( "Cache-Control: no-cache" );
02071 print $xml;
02072 }
02073
02079 private function set_handler_vars_from_db_connection()
02080 {
02081 list( $this->handler_vars['db_type'], $remainder )= explode( ':', Config::get( 'db_connection' )->connection_string );
02082 switch ( $this->handler_vars['db_type'] ) {
02083 case 'sqlite':
02084
02085
02086 $this->handler_vars['db_file'] = $remainder;
02087 break;
02088 case 'mysql':
02089 case 'pgsql':
02090 $pairs = $this->parse_dsn( $remainder );
02091
02092 $host = $pairs['host'];
02093
02094 if ( isset( $pairs['port'] ) ) {
02095 $host .= ';port=' . $pairs['port'];
02096 }
02097
02098 $this->handler_vars['db_host'] = $host;
02099 $this->handler_vars['db_schema'] = $pairs['dbname'];
02100
02101 break;
02102 }
02103 $this->handler_vars['db_user'] = Config::get( 'db_connection' )->username;
02104 $this->handler_vars['db_pass'] = Config::get( 'db_connection' )->password;
02105 $this->handler_vars['table_prefix'] = Config::get( 'db_connection' )->prefix;
02106 }
02107
02108 private function parse_dsn ( $dsn ) {
02109
02110
02111 $dsn = str_replace( '; ', ';', $dsn );
02112
02113
02114 $dsn = str_replace( ' ', ';', $dsn );
02115
02116
02117 $temp_pairs = explode( ';', $dsn );
02118
02119
02120 $pairs = array();
02121 foreach ( $temp_pairs as $temp_pair ) {
02122 list( $k, $v ) = explode( '=', $temp_pair );
02123 $pairs[ $k ] = $v;
02124 }
02125
02126 return $pairs;
02127
02128 }
02129
02135 public static function get_feature_list($features) {
02136 $output = array();
02137 foreach($features as $feature) {
02138 $output[(string)$feature] = (string)$feature;
02139 }
02140 return implode(',', $output);
02141 }
02142
02146 private function create_base_comment_types()
02147 {
02148 Comment::add_type('comment');
02149 Comment::add_type('pingback');
02150 Comment::add_type('trackback');
02151
02152 Comment::add_status('unapproved', true);
02153 Comment::add_status('approved', true);
02154 Comment::add_status('spam', true);
02155 Comment::add_status('deleted', true);
02156
02157 return true;
02158 }
02159
02160 }
02161 ?>