home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / ms-load.php < prev    next >
Encoding:
PHP Script  |  2017-10-03  |  18.8 KB  |  552 lines

  1. <?php
  2. /**
  3.  * These functions are needed to load Multisite.
  4.  *
  5.  * @since 3.0.0
  6.  *
  7.  * @package WordPress
  8.  * @subpackage Multisite
  9.  */
  10.  
  11. /**
  12.  * Whether a subdomain configuration is enabled.
  13.  *
  14.  * @since 3.0.0
  15.  *
  16.  * @return bool True if subdomain configuration is enabled, false otherwise.
  17.  */
  18. function is_subdomain_install() {
  19.     if ( defined('SUBDOMAIN_INSTALL') )
  20.         return SUBDOMAIN_INSTALL;
  21.  
  22.     return ( defined( 'VHOST' ) && VHOST == 'yes' );
  23. }
  24.  
  25. /**
  26.  * Returns array of network plugin files to be included in global scope.
  27.  *
  28.  * The default directory is wp-content/plugins. To change the default directory
  29.  * manually, define `WP_PLUGIN_DIR` and `WP_PLUGIN_URL` in `wp-config.php`.
  30.  *
  31.  * @access private
  32.  * @since 3.1.0
  33.  *
  34.  * @return array Files to include.
  35.  */
  36. function wp_get_active_network_plugins() {
  37.     $active_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
  38.     if ( empty( $active_plugins ) )
  39.         return array();
  40.  
  41.     $plugins = array();
  42.     $active_plugins = array_keys( $active_plugins );
  43.     sort( $active_plugins );
  44.  
  45.     foreach ( $active_plugins as $plugin ) {
  46.         if ( ! validate_file( $plugin ) // $plugin must validate as file
  47.             && '.php' == substr( $plugin, -4 ) // $plugin must end with '.php'
  48.             && file_exists( WP_PLUGIN_DIR . '/' . $plugin ) // $plugin must exist
  49.             )
  50.         $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
  51.     }
  52.     return $plugins;
  53. }
  54.  
  55. /**
  56.  * Checks status of current blog.
  57.  *
  58.  * Checks if the blog is deleted, inactive, archived, or spammed.
  59.  *
  60.  * Dies with a default message if the blog does not pass the check.
  61.  *
  62.  * To change the default message when a blog does not pass the check,
  63.  * use the wp-content/blog-deleted.php, blog-inactive.php and
  64.  * blog-suspended.php drop-ins.
  65.  *
  66.  * @since 3.0.0
  67.  *
  68.  * @return true|string Returns true on success, or drop-in file to include.
  69.  */
  70. function ms_site_check() {
  71.  
  72.     /**
  73.      * Filters checking the status of the current blog.
  74.      *
  75.      * @since 3.0.0
  76.      *
  77.      * @param bool null Whether to skip the blog status check. Default null.
  78.     */
  79.     $check = apply_filters( 'ms_site_check', null );
  80.     if ( null !== $check )
  81.         return true;
  82.  
  83.     // Allow super admins to see blocked sites
  84.     if ( is_super_admin() )
  85.         return true;
  86.  
  87.     $blog = get_site();
  88.  
  89.     if ( '1' == $blog->deleted ) {
  90.         if ( file_exists( WP_CONTENT_DIR . '/blog-deleted.php' ) )
  91.             return WP_CONTENT_DIR . '/blog-deleted.php';
  92.         else
  93.             wp_die( __( 'This site is no longer available.' ), '', array( 'response' => 410 ) );
  94.     }
  95.  
  96.     if ( '2' == $blog->deleted ) {
  97.         if ( file_exists( WP_CONTENT_DIR . '/blog-inactive.php' ) ) {
  98.             return WP_CONTENT_DIR . '/blog-inactive.php';
  99.         } else {
  100.             $admin_email = str_replace( '@', ' AT ', get_site_option( 'admin_email', 'support@' . get_network()->domain ) );
  101.             wp_die(
  102.                 /* translators: %s: admin email link */
  103.                 sprintf( __( 'This site has not been activated yet. If you are having problems activating your site, please contact %s.' ),
  104.                     sprintf( '<a href="mailto:%s">%s</a>', $admin_email )
  105.                 )
  106.             );
  107.         }
  108.     }
  109.  
  110.     if ( $blog->archived == '1' || $blog->spam == '1' ) {
  111.         if ( file_exists( WP_CONTENT_DIR . '/blog-suspended.php' ) )
  112.             return WP_CONTENT_DIR . '/blog-suspended.php';
  113.         else
  114.             wp_die( __( 'This site has been archived or suspended.' ), '', array( 'response' => 410 ) );
  115.     }
  116.  
  117.     return true;
  118. }
  119.  
  120. /**
  121.  * Retrieve the closest matching network for a domain and path.
  122.  *
  123.  * @since 3.9.0
  124.  *
  125.  * @internal In 4.4.0, converted to a wrapper for WP_Network::get_by_path()
  126.  *
  127.  * @param string   $domain   Domain to check.
  128.  * @param string   $path     Path to check.
  129.  * @param int|null $segments Path segments to use. Defaults to null, or the full path.
  130.  * @return WP_Network|false Network object if successful. False when no network is found.
  131.  */
  132. function get_network_by_path( $domain, $path, $segments = null ) {
  133.     return WP_Network::get_by_path( $domain, $path, $segments );
  134. }
  135.  
  136. /**
  137.  * Retrieves the closest matching site object by its domain and path.
  138.  *
  139.  * This will not necessarily return an exact match for a domain and path. Instead, it
  140.  * breaks the domain and path into pieces that are then used to match the closest
  141.  * possibility from a query.
  142.  *
  143.  * The intent of this method is to match a site object during bootstrap for a
  144.  * requested site address
  145.  *
  146.  * @since 3.9.0
  147.  * @since 4.7.0 Updated to always return a `WP_Site` object.
  148.  *
  149.  * @global wpdb $wpdb WordPress database abstraction object.
  150.  *
  151.  * @param string   $domain   Domain to check.
  152.  * @param string   $path     Path to check.
  153.  * @param int|null $segments Path segments to use. Defaults to null, or the full path.
  154.  * @return WP_Site|false Site object if successful. False when no site is found.
  155.  */
  156. function get_site_by_path( $domain, $path, $segments = null ) {
  157.     $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) );
  158.  
  159.     /**
  160.      * Filters the number of path segments to consider when searching for a site.
  161.      *
  162.      * @since 3.9.0
  163.      *
  164.      * @param int|null $segments The number of path segments to consider. WordPress by default looks at
  165.      *                           one path segment following the network path. The function default of
  166.      *                           null only makes sense when you know the requested path should match a site.
  167.      * @param string   $domain   The requested domain.
  168.      * @param string   $path     The requested path, in full.
  169.      */
  170.     $segments = apply_filters( 'site_by_path_segments_count', $segments, $domain, $path );
  171.  
  172.     if ( null !== $segments && count( $path_segments ) > $segments ) {
  173.         $path_segments = array_slice( $path_segments, 0, $segments );
  174.     }
  175.  
  176.     $paths = array();
  177.  
  178.     while ( count( $path_segments ) ) {
  179.         $paths[] = '/' . implode( '/', $path_segments ) . '/';
  180.         array_pop( $path_segments );
  181.     }
  182.  
  183.     $paths[] = '/';
  184.  
  185.     /**
  186.      * Determine a site by its domain and path.
  187.      *
  188.      * This allows one to short-circuit the default logic, perhaps by
  189.      * replacing it with a routine that is more optimal for your setup.
  190.      *
  191.      * Return null to avoid the short-circuit. Return false if no site
  192.      * can be found at the requested domain and path. Otherwise, return
  193.      * a site object.
  194.      *
  195.      * @since 3.9.0
  196.      *
  197.      * @param null|bool|WP_Site $site     Site value to return by path.
  198.      * @param string            $domain   The requested domain.
  199.      * @param string            $path     The requested path, in full.
  200.      * @param int|null          $segments The suggested number of paths to consult.
  201.      *                                    Default null, meaning the entire path was to be consulted.
  202.      * @param array             $paths    The paths to search for, based on $path and $segments.
  203.      */
  204.     $pre = apply_filters( 'pre_get_site_by_path', null, $domain, $path, $segments, $paths );
  205.     if ( null !== $pre ) {
  206.         if ( false !== $pre && ! $pre instanceof WP_Site ) {
  207.             $pre = new WP_Site( $pre );
  208.         }
  209.         return $pre;
  210.     }
  211.  
  212.     /*
  213.      * @todo
  214.      * caching, etc. Consider alternative optimization routes,
  215.      * perhaps as an opt-in for plugins, rather than using the pre_* filter.
  216.      * For example: The segments filter can expand or ignore paths.
  217.      * If persistent caching is enabled, we could query the DB for a path <> '/'
  218.      * then cache whether we can just always ignore paths.
  219.      */
  220.  
  221.     // Either www or non-www is supported, not both. If a www domain is requested,
  222.     // query for both to provide the proper redirect.
  223.     $domains = array( $domain );
  224.     if ( 'www.' === substr( $domain, 0, 4 ) ) {
  225.         $domains[] = substr( $domain, 4 );
  226.     }
  227.  
  228.     $args = array(
  229.         'domain__in' => $domains,
  230.         'path__in' => $paths,
  231.         'number' => 1,
  232.     );
  233.  
  234.     if ( count( $domains ) > 1 ) {
  235.         $args['orderby']['domain_length'] = 'DESC';
  236.     }
  237.  
  238.     if ( count( $paths ) > 1 ) {
  239.         $args['orderby']['path_length'] = 'DESC';
  240.     }
  241.  
  242.     $result = get_sites( $args );
  243.     $site = array_shift( $result );
  244.  
  245.     if ( $site ) {
  246.         return $site;
  247.     }
  248.  
  249.     return false;
  250. }
  251.  
  252. /**
  253.  * Identifies the network and site of a requested domain and path and populates the
  254.  * corresponding network and site global objects as part of the multisite bootstrap process.
  255.  *
  256.  * Prior to 4.6.0, this was a procedural block in `ms-settings.php`. It was wrapped into
  257.  * a function to facilitate unit tests. It should not be used outside of core.
  258.  *
  259.  * Usually, it's easier to query the site first, which then declares its network.
  260.  * In limited situations, we either can or must find the network first.
  261.  *
  262.  * If a network and site are found, a `true` response will be returned so that the
  263.  * request can continue.
  264.  *
  265.  * If neither a network or site is found, `false` or a URL string will be returned
  266.  * so that either an error can be shown or a redirect can occur.
  267.  *
  268.  * @since 4.6.0
  269.  * @access private
  270.  *
  271.  * @global WP_Network $current_site The current network.
  272.  * @global WP_Site    $current_blog The current site.
  273.  *
  274.  * @param string $domain    The requested domain.
  275.  * @param string $path      The requested path.
  276.  * @param bool   $subdomain Optional. Whether a subdomain (true) or subdirectory (false) configuration.
  277.  *                          Default false.
  278.  * @return bool|string True if bootstrap successfully populated `$current_blog` and `$current_site`.
  279.  *                     False if bootstrap could not be properly completed.
  280.  *                     Redirect URL if parts exist, but the request as a whole can not be fulfilled.
  281.  */
  282. function ms_load_current_site_and_network( $domain, $path, $subdomain = false ) {
  283.     global $current_site, $current_blog;
  284.  
  285.     // If the network is defined in wp-config.php, we can simply use that.
  286.     if ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) ) {
  287.         $current_site = new stdClass;
  288.         $current_site->id = defined( 'SITE_ID_CURRENT_SITE' ) ? SITE_ID_CURRENT_SITE : 1;
  289.         $current_site->domain = DOMAIN_CURRENT_SITE;
  290.         $current_site->path = PATH_CURRENT_SITE;
  291.         if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) {
  292.             $current_site->blog_id = BLOG_ID_CURRENT_SITE;
  293.         } elseif ( defined( 'BLOGID_CURRENT_SITE' ) ) { // deprecated.
  294.             $current_site->blog_id = BLOGID_CURRENT_SITE;
  295.         }
  296.  
  297.         if ( 0 === strcasecmp( $current_site->domain, $domain ) && 0 === strcasecmp( $current_site->path, $path ) ) {
  298.             $current_blog = get_site_by_path( $domain, $path );
  299.         } elseif ( '/' !== $current_site->path && 0 === strcasecmp( $current_site->domain, $domain ) && 0 === stripos( $path, $current_site->path ) ) {
  300.             // If the current network has a path and also matches the domain and path of the request,
  301.             // we need to look for a site using the first path segment following the network's path.
  302.             $current_blog = get_site_by_path( $domain, $path, 1 + count( explode( '/', trim( $current_site->path, '/' ) ) ) );
  303.         } else {
  304.             // Otherwise, use the first path segment (as usual).
  305.             $current_blog = get_site_by_path( $domain, $path, 1 );
  306.         }
  307.  
  308.     } elseif ( ! $subdomain ) {
  309.         /*
  310.          * A "subdomain" installation can be re-interpreted to mean "can support any domain".
  311.          * If we're not dealing with one of these installations, then the important part is determining
  312.          * the network first, because we need the network's path to identify any sites.
  313.          */
  314.         if ( ! $current_site = wp_cache_get( 'current_network', 'site-options' ) ) {
  315.             // Are there even two networks installed?
  316.             $networks = get_networks( array( 'number' => 2 ) );
  317.             if ( count( $networks ) === 1 ) {
  318.                 $current_site = array_shift( $networks );
  319.                 wp_cache_add( 'current_network', $current_site, 'site-options' );
  320.             } elseif ( empty( $networks ) ) {
  321.                 // A network not found hook should fire here.
  322.                 return false;
  323.             }
  324.         }
  325.  
  326.         if ( empty( $current_site ) ) {
  327.             $current_site = WP_Network::get_by_path( $domain, $path, 1 );
  328.         }
  329.  
  330.         if ( empty( $current_site ) ) {
  331.             /**
  332.              * Fires when a network cannot be found based on the requested domain and path.
  333.              *
  334.              * At the time of this action, the only recourse is to redirect somewhere
  335.              * and exit. If you want to declare a particular network, do so earlier.
  336.              *
  337.              * @since 4.4.0
  338.              *
  339.              * @param string $domain       The domain used to search for a network.
  340.              * @param string $path         The path used to search for a path.
  341.              */
  342.             do_action( 'ms_network_not_found', $domain, $path );
  343.  
  344.             return false;
  345.         } elseif ( $path === $current_site->path ) {
  346.             $current_blog = get_site_by_path( $domain, $path );
  347.         } else {
  348.             // Search the network path + one more path segment (on top of the network path).
  349.             $current_blog = get_site_by_path( $domain, $path, substr_count( $current_site->path, '/' ) );
  350.         }
  351.     } else {
  352.         // Find the site by the domain and at most the first path segment.
  353.         $current_blog = get_site_by_path( $domain, $path, 1 );
  354.         if ( $current_blog ) {
  355.             $current_site = WP_Network::get_instance( $current_blog->site_id ? $current_blog->site_id : 1 );
  356.         } else {
  357.             // If you don't have a site with the same domain/path as a network, you're pretty screwed, but:
  358.             $current_site = WP_Network::get_by_path( $domain, $path, 1 );
  359.         }
  360.     }
  361.  
  362.     // The network declared by the site trumps any constants.
  363.     if ( $current_blog && $current_blog->site_id != $current_site->id ) {
  364.         $current_site = WP_Network::get_instance( $current_blog->site_id );
  365.     }
  366.  
  367.     // No network has been found, bail.
  368.     if ( empty( $current_site ) ) {
  369.         /** This action is documented in wp-includes/ms-settings.php */
  370.         do_action( 'ms_network_not_found', $domain, $path );
  371.  
  372.         return false;
  373.     }
  374.  
  375.     // During activation of a new subdomain, the requested site does not yet exist.
  376.     if ( empty( $current_blog ) && wp_installing() ) {
  377.         $current_blog = new stdClass;
  378.         $current_blog->blog_id = $blog_id = 1;
  379.         $current_blog->public = 1;
  380.     }
  381.  
  382.     // No site has been found, bail.
  383.     if ( empty( $current_blog ) ) {
  384.         // We're going to redirect to the network URL, with some possible modifications.
  385.         $scheme = is_ssl() ? 'https' : 'http';
  386.         $destination = "$scheme://{$current_site->domain}{$current_site->path}";
  387.  
  388.         /**
  389.          * Fires when a network can be determined but a site cannot.
  390.          *
  391.          * At the time of this action, the only recourse is to redirect somewhere
  392.          * and exit. If you want to declare a particular site, do so earlier.
  393.          *
  394.          * @since 3.9.0
  395.          *
  396.          * @param object $current_site The network that had been determined.
  397.          * @param string $domain       The domain used to search for a site.
  398.          * @param string $path         The path used to search for a site.
  399.          */
  400.         do_action( 'ms_site_not_found', $current_site, $domain, $path );
  401.  
  402.         if ( $subdomain && ! defined( 'NOBLOGREDIRECT' ) ) {
  403.             // For a "subdomain" installation, redirect to the signup form specifically.
  404.             $destination .= 'wp-signup.php?new=' . str_replace( '.' . $current_site->domain, '', $domain );
  405.         } elseif ( $subdomain ) {
  406.             // For a "subdomain" installation, the NOBLOGREDIRECT constant
  407.             // can be used to avoid a redirect to the signup form.
  408.             // Using the ms_site_not_found action is preferred to the constant.
  409.             if ( '%siteurl%' !== NOBLOGREDIRECT ) {
  410.                 $destination = NOBLOGREDIRECT;
  411.             }
  412.         } elseif ( 0 === strcasecmp( $current_site->domain, $domain ) ) {
  413.             /*
  414.              * If the domain we were searching for matches the network's domain,
  415.              * it's no use redirecting back to ourselves -- it'll cause a loop.
  416.              * As we couldn't find a site, we're simply not installed.
  417.              */
  418.             return false;
  419.         }
  420.  
  421.         return $destination;
  422.     }
  423.  
  424.     // Figure out the current network's main site.
  425.     if ( empty( $current_site->blog_id ) ) {
  426.         $current_site->blog_id = get_main_site_id( $current_site->id );
  427.     }
  428.  
  429.     return true;
  430. }
  431.  
  432. /**
  433.  * Displays a failure message.
  434.  *
  435.  * Used when a blog's tables do not exist. Checks for a missing $wpdb->site table as well.
  436.  *
  437.  * @access private
  438.  * @since 3.0.0
  439.  * @since 4.4.0 The `$domain` and `$path` parameters were added.
  440.  *
  441.  * @global wpdb $wpdb WordPress database abstraction object.
  442.  *
  443.  * @param string $domain The requested domain for the error to reference.
  444.  * @param string $path   The requested path for the error to reference.
  445.  */
  446. function ms_not_installed( $domain, $path ) {
  447.     global $wpdb;
  448.  
  449.     if ( ! is_admin() ) {
  450.         dead_db();
  451.     }
  452.  
  453.     wp_load_translations_early();
  454.  
  455.     $title = __( 'Error establishing a database connection' );
  456.  
  457.     $msg  = '<h1>' . $title . '</h1>';
  458.     $msg .= '<p>' . __( 'If your site does not display, please contact the owner of this network.' ) . '';
  459.     $msg .= ' ' . __( 'If you are the owner of this network please check that MySQL is running properly and all tables are error free.' ) . '</p>';
  460.     $query = $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->esc_like( $wpdb->site ) );
  461.     if ( ! $wpdb->get_var( $query ) ) {
  462.         $msg .= '<p>' . sprintf(
  463.             /* translators: %s: table name */
  464.             __( '<strong>Database tables are missing.</strong> This means that MySQL is not running, WordPress was not installed properly, or someone deleted %s. You really should look at your database now.' ),
  465.             '<code>' . $wpdb->site . '</code>'
  466.         ) . '</p>';
  467.     } else {
  468.         $msg .= '<p>' . sprintf(
  469.             /* translators: 1: site url, 2: table name, 3: database name */
  470.             __( '<strong>Could not find site %1$s.</strong> Searched for table %2$s in database %3$s. Is that right?' ),
  471.             '<code>' . rtrim( $domain . $path, '/' ) . '</code>',
  472.             '<code>' . $wpdb->blogs . '</code>',
  473.             '<code>' . DB_NAME . '</code>'
  474.         ) . '</p>';
  475.     }
  476.     $msg .= '<p><strong>' . __( 'What do I do now?' ) . '</strong> ';
  477.     /* translators: %s: Codex URL */
  478.     $msg .= sprintf( __( 'Read the <a href="%s" target="_blank">bug report</a> page. Some of the guidelines there may help you figure out what went wrong.' ),
  479.         __( 'https://codex.wordpress.org/Debugging_a_WordPress_Network' )
  480.     );
  481.     $msg .= ' ' . __( 'If you’re still stuck with this message, then check that your database contains the following tables:' ) . '</p><ul>';
  482.     foreach ( $wpdb->tables('global') as $t => $table ) {
  483.         if ( 'sitecategories' == $t )
  484.             continue;
  485.         $msg .= '<li>' . $table . '</li>';
  486.     }
  487.     $msg .= '</ul>';
  488.  
  489.     wp_die( $msg, $title, array( 'response' => 500 ) );
  490. }
  491.  
  492. /**
  493.  * This deprecated function formerly set the site_name property of the $current_site object.
  494.  *
  495.  * This function simply returns the object, as before.
  496.  * The bootstrap takes care of setting site_name.
  497.  *
  498.  * @access private
  499.  * @since 3.0.0
  500.  * @deprecated 3.9.0 Use get_current_site() instead.
  501.  *
  502.  * @param object $current_site
  503.  * @return object
  504.  */
  505. function get_current_site_name( $current_site ) {
  506.     _deprecated_function( __FUNCTION__, '3.9.0', 'get_current_site()' );
  507.     return $current_site;
  508. }
  509.  
  510. /**
  511.  * This deprecated function managed much of the site and network loading in multisite.
  512.  *
  513.  * The current bootstrap code is now responsible for parsing the site and network load as
  514.  * well as setting the global $current_site object.
  515.  *
  516.  * @access private
  517.  * @since 3.0.0
  518.  * @deprecated 3.9.0
  519.  *
  520.  * @global object $current_site
  521.  *
  522.  * @return object
  523.  */
  524. function wpmu_current_site() {
  525.     global $current_site;
  526.     _deprecated_function( __FUNCTION__, '3.9.0' );
  527.     return $current_site;
  528. }
  529.  
  530. /**
  531.  * Retrieve an object containing information about the requested network.
  532.  *
  533.  * @since 3.9.0
  534.  * @deprecated 4.7.0 Use `get_network()`
  535.  * @see get_network()
  536.  *
  537.  * @internal In 4.6.0, converted to use get_network()
  538.  *
  539.  * @param object|int $network The network's database row or ID.
  540.  * @return WP_Network|false Object containing network information if found, false if not.
  541.  */
  542. function wp_get_network( $network ) {
  543.     _deprecated_function( __FUNCTION__, '4.7.0', 'get_network()' );
  544.  
  545.     $network = get_network( $network );
  546.     if ( null === $network ) {
  547.         return false;
  548.     }
  549.  
  550.     return $network;
  551. }
  552.