time(), 'message' => isset( $err['message'] ) ? substr( (string) $err['message'], 0, 500 ) : '', 'file' => isset( $err['file'] ) ? (string) $err['file'] : '', 'line' => isset( $err['line'] ) ? (int) $err['line'] : 0, 'version' => defined( 'AISITEARK_VERSION' ) ? AISITEARK_VERSION : '', ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $exists = $wpdb->get_var( $wpdb->prepare( "SELECT option_id FROM {$wpdb->options} WHERE option_name = %s LIMIT 1", AISITEARK_SAFE_MODE ) ); if ( $exists ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery $wpdb->update( $wpdb->options, array( 'option_value' => $why ), array( 'option_name' => AISITEARK_SAFE_MODE ) ); } else { // phpcs:ignore WordPress.DB.DirectDatabaseQuery $wpdb->insert( $wpdb->options, array( 'option_name' => AISITEARK_SAFE_MODE, 'option_value' => $why, 'autoload' => 'yes' ) ); } } /** * Shutdown handler: did WE just kill this request while the site was loading? * * @return void */ function aisiteark_fatal_fuse() { if ( empty( $GLOBALS['aisiteark_loading'] ) ) { return; // Past load — a job failing is not a site outage. } $err = error_get_last(); if ( ! $err || ! in_array( (int) $err['type'], array( E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ), true ) ) { return; // Clean shutdown, or a mere warning/notice. } $file = isset( $err['file'] ) ? str_replace( '\\', '/', (string) $err['file'] ) : ''; $dir = str_replace( '\\', '/', AISITEARK_DIR ); if ( '' === $file || 0 !== strpos( $file, $dir ) ) { return; // Someone else's fatal — never switch off another plugin's problem. } aisiteark_self_disable( $err ); } register_shutdown_function( 'aisiteark_fatal_fuse' ); /** * Our load finished without dying — disarm, so later job failures don't disable backups. * * @return void */ function aisiteark_disarm_fuse() { $GLOBALS['aisiteark_loading'] = false; } add_action( 'plugins_loaded', 'aisiteark_disarm_fuse', 99 ); /* ------------------------------------------------------------------------- * Autoloader — maps the AtoZ\SiteArk\ namespace to WordPress-style filenames. * * AtoZ\SiteArk\Activator => includes/class-activator.php * AtoZ\SiteArk\Helpers\Settings => includes/helpers/class-settings.php * AtoZ\SiteArk\Providers\Storage\... => includes/providers/storage/class-...php * AtoZ\SiteArk\Admin\Admin => admin/class-admin.php * ---------------------------------------------------------------------- */ spl_autoload_register( function ( $class ) { $prefix = 'AtoZ\\SiteArk\\'; if ( 0 !== strpos( $class, $prefix ) ) { return; } $relative = substr( $class, strlen( $prefix ) ); $parts = explode( '\\', $relative ); $name = array_pop( $parts ); $file = 'class-' . str_replace( '_', '-', strtolower( $name ) ) . '.php'; $base = AISITEARK_DIR . 'includes/'; if ( ! empty( $parts ) && 'Admin' === $parts[0] ) { $base = AISITEARK_DIR . 'admin/'; array_shift( $parts ); } elseif ( ! empty( $parts ) && 'Front' === $parts[0] ) { $base = AISITEARK_DIR . 'public/'; array_shift( $parts ); } $sub = ''; foreach ( $parts as $part ) { $sub .= strtolower( str_replace( '_', '-', $part ) ) . '/'; } $path = $base . $sub . $file; if ( is_readable( $path ) ) { require_once $path; } } ); /* ------------------------------------------------------------------------- * Activation / deactivation * ---------------------------------------------------------------------- */ /** * Activation. Clears any previous fuse trip (a reinstall is the documented repair, so a * deliberate reactivation means "try me again"), and refuses to run the activator at all on * a half-installed copy rather than fataling the Plugins screen. * * @return void */ function aisiteark_activate() { delete_option( AISITEARK_SAFE_MODE ); // A deliberate reactivation means "try me again". if ( aisiteark_missing_core_files() ) { return; } \AtoZ\SiteArk\Activator::activate(); } register_activation_hook( __FILE__, 'aisiteark_activate' ); register_deactivation_hook( __FILE__, array( 'AtoZ\SiteArk\Deactivator', 'deactivate' ) ); /* ------------------------------------------------------------------------- * Bootstrap * ---------------------------------------------------------------------- */ /** * Files this plugin cannot boot without that are missing from disk. * * Guards against a HALF-INSTALLED plugin folder — an update whose request timed out * between "delete the old folder" and "extract the new one", a partial FTP upload, or a * host's file sync hiccupping. WordPress only checks that the MAIN plugin file exists; if * one of our other files is missing, the first reference to a class inside it throws an * uncaught Error that white-screens the ENTIRE SITE ("Class AtoZ\SiteArk\Helpers\Plan * not found"). A backup plugin taking the whole site down is never an acceptable failure * mode, so we detect it and stay inert with an actionable notice instead. * * @return string[] Missing plugin-relative paths (empty when the install is intact). */ function aisiteark_missing_core_files() { static $missing = null; if ( null !== $missing ) { return $missing; } $missing = array(); foreach ( array( 'includes/class-siteark.php', 'includes/helpers/class-plan.php', 'includes/helpers/class-settings.php', ) as $rel ) { if ( ! is_readable( AISITEARK_DIR . $rel ) ) { $missing[] = $rel; } } return $missing; } /** * Tell an administrator how to repair a half-installed copy, since the plugin itself is * deliberately doing nothing until it is whole again. * * @return void */ function aisiteark_incomplete_notice() { if ( ! current_user_can( 'activate_plugins' ) ) { return; } // The fuse tripped on an earlier request: we are in safe mode to keep the site up. $fuse = get_option( AISITEARK_SAFE_MODE ); if ( is_array( $fuse ) ) { echo '
' . esc_html__( 'AI-SiteArk has switched itself into safe mode.', 'ai-siteark' ) . ' ' . esc_html__( 'It hit a fatal error while your site was loading, so it stopped running rather than let your site go down. Your site is fine and your backups are untouched — but backups and restores are paused until this is fixed. Reinstall AI-SiteArk (Plugins → Add New → Upload Plugin), which repairs an interrupted or damaged update, then deactivate and reactivate it to clear safe mode.', 'ai-siteark' ) . '
' . esc_html( (string) $fuse['message'] ) . '
' . esc_html__( 'AI-SiteArk is not fully installed.', 'ai-siteark' ) . ' ' . esc_html__( 'Some of its files are missing — an update was most likely interrupted. AI-SiteArk has switched itself off to keep your site running. Reinstall it (Plugins → Add New → Upload Plugin) to restore backups and restores. Your existing backups are untouched.', 'ai-siteark' ) . '