web/wp-includes/class-wp.php
changeset 194 32102edaa81b
child 204 09a1c134465b
equal deleted inserted replaced
193:2f6f6f7551ca 194:32102edaa81b
       
     1 <?php
       
     2 /**
       
     3  * WordPress environment setup class.
       
     4  *
       
     5  * @package WordPress
       
     6  * @since 2.0.0
       
     7  */
       
     8 class WP {
       
     9 	/**
       
    10 	 * Public query variables.
       
    11 	 *
       
    12 	 * Long list of public query variables.
       
    13 	 *
       
    14 	 * @since 2.0.0
       
    15 	 * @access public
       
    16 	 * @var array
       
    17 	 */
       
    18 	var $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type');
       
    19 
       
    20 	/**
       
    21 	 * Private query variables.
       
    22 	 *
       
    23 	 * Long list of private query variables.
       
    24 	 *
       
    25 	 * @since 2.0.0
       
    26 	 * @var array
       
    27 	 */
       
    28 	var $private_query_vars = array('offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in');
       
    29 
       
    30 	/**
       
    31 	 * Extra query variables set by the user.
       
    32 	 *
       
    33 	 * @since 2.1.0
       
    34 	 * @var array
       
    35 	 */
       
    36 	var $extra_query_vars = array();
       
    37 
       
    38 	/**
       
    39 	 * Query variables for setting up the WordPress Query Loop.
       
    40 	 *
       
    41 	 * @since 2.0.0
       
    42 	 * @var array
       
    43 	 */
       
    44 	var $query_vars;
       
    45 
       
    46 	/**
       
    47 	 * String parsed to set the query variables.
       
    48 	 *
       
    49 	 * @since 2.0.0
       
    50 	 * @var string
       
    51 	 */
       
    52 	var $query_string;
       
    53 
       
    54 	/**
       
    55 	 * Permalink or requested URI.
       
    56 	 *
       
    57 	 * @since 2.0.0
       
    58 	 * @var string
       
    59 	 */
       
    60 	var $request;
       
    61 
       
    62 	/**
       
    63 	 * Rewrite rule the request matched.
       
    64 	 *
       
    65 	 * @since 2.0.0
       
    66 	 * @var string
       
    67 	 */
       
    68 	var $matched_rule;
       
    69 
       
    70 	/**
       
    71 	 * Rewrite query the request matched.
       
    72 	 *
       
    73 	 * @since 2.0.0
       
    74 	 * @var string
       
    75 	 */
       
    76 	var $matched_query;
       
    77 
       
    78 	/**
       
    79 	 * Whether already did the permalink.
       
    80 	 *
       
    81 	 * @since 2.0.0
       
    82 	 * @var bool
       
    83 	 */
       
    84 	var $did_permalink = false;
       
    85 
       
    86 	/**
       
    87 	 * Add name to list of public query variables.
       
    88 	 *
       
    89 	 * @since 2.1.0
       
    90 	 *
       
    91 	 * @param string $qv Query variable name.
       
    92 	 */
       
    93 	function add_query_var($qv) {
       
    94 		if ( !in_array($qv, $this->public_query_vars) )
       
    95 			$this->public_query_vars[] = $qv;
       
    96 	}
       
    97 
       
    98 	/**
       
    99 	 * Set the value of a query variable.
       
   100 	 *
       
   101 	 * @since 2.3.0
       
   102 	 *
       
   103 	 * @param string $key Query variable name.
       
   104 	 * @param mixed $value Query variable value.
       
   105 	 */
       
   106 	function set_query_var($key, $value) {
       
   107 		$this->query_vars[$key] = $value;
       
   108 	}
       
   109 
       
   110 	/**
       
   111 	 * Parse request to find correct WordPress query.
       
   112 	 *
       
   113 	 * Sets up the query variables based on the request. There are also many
       
   114 	 * filters and actions that can be used to further manipulate the result.
       
   115 	 *
       
   116 	 * @since 2.0.0
       
   117 	 *
       
   118 	 * @param array|string $extra_query_vars Set the extra query variables.
       
   119 	 */
       
   120 	function parse_request($extra_query_vars = '') {
       
   121 		global $wp_rewrite;
       
   122 
       
   123 		$this->query_vars = array();
       
   124 		$post_type_query_vars = array();
       
   125 
       
   126 		if ( is_array($extra_query_vars) )
       
   127 			$this->extra_query_vars = & $extra_query_vars;
       
   128 		else if (! empty($extra_query_vars))
       
   129 			parse_str($extra_query_vars, $this->extra_query_vars);
       
   130 
       
   131 		// Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
       
   132 
       
   133 		// Fetch the rewrite rules.
       
   134 		$rewrite = $wp_rewrite->wp_rewrite_rules();
       
   135 
       
   136 		if ( ! empty($rewrite) ) {
       
   137 			// If we match a rewrite rule, this will be cleared.
       
   138 			$error = '404';
       
   139 			$this->did_permalink = true;
       
   140 
       
   141 			if ( isset($_SERVER['PATH_INFO']) )
       
   142 				$pathinfo = $_SERVER['PATH_INFO'];
       
   143 			else
       
   144 				$pathinfo = '';
       
   145 			$pathinfo_array = explode('?', $pathinfo);
       
   146 			$pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
       
   147 			$req_uri = $_SERVER['REQUEST_URI'];
       
   148 			$req_uri_array = explode('?', $req_uri);
       
   149 			$req_uri = $req_uri_array[0];
       
   150 			$self = $_SERVER['PHP_SELF'];
       
   151 			$home_path = parse_url(home_url());
       
   152 			if ( isset($home_path['path']) )
       
   153 				$home_path = $home_path['path'];
       
   154 			else
       
   155 				$home_path = '';
       
   156 			$home_path = trim($home_path, '/');
       
   157 
       
   158 			// Trim path info from the end and the leading home path from the
       
   159 			// front. For path info requests, this leaves us with the requesting
       
   160 			// filename, if any. For 404 requests, this leaves us with the
       
   161 			// requested permalink.
       
   162 			$req_uri = str_replace($pathinfo, '', $req_uri);
       
   163 			$req_uri = trim($req_uri, '/');
       
   164 			$req_uri = preg_replace("|^$home_path|", '', $req_uri);
       
   165 			$req_uri = trim($req_uri, '/');
       
   166 			$pathinfo = trim($pathinfo, '/');
       
   167 			$pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
       
   168 			$pathinfo = trim($pathinfo, '/');
       
   169 			$self = trim($self, '/');
       
   170 			$self = preg_replace("|^$home_path|", '', $self);
       
   171 			$self = trim($self, '/');
       
   172 
       
   173 			// The requested permalink is in $pathinfo for path info requests and
       
   174 			//  $req_uri for other requests.
       
   175 			if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
       
   176 				$request = $pathinfo;
       
   177 			} else {
       
   178 				// If the request uri is the index, blank it out so that we don't try to match it against a rule.
       
   179 				if ( $req_uri == $wp_rewrite->index )
       
   180 					$req_uri = '';
       
   181 				$request = $req_uri;
       
   182 			}
       
   183 
       
   184 			$this->request = $request;
       
   185 
       
   186 			// Look for matches.
       
   187 			$request_match = $request;
       
   188 			if ( empty( $request_match ) ) {
       
   189 				// An empty request could only match against ^$ regex
       
   190 				if ( isset( $rewrite['$'] ) ) {
       
   191 					$this->matched_rule = '$';
       
   192 					$query = $rewrite['$'];
       
   193 					$matches = array('');
       
   194 				}
       
   195 			} else if ( $req_uri != 'wp-app.php' ) {
       
   196 				foreach ( (array) $rewrite as $match => $query ) {
       
   197 					// If the requesting file is the anchor of the match, prepend it to the path info.
       
   198 					if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request )
       
   199 						$request_match = $req_uri . '/' . $request;
       
   200 
       
   201 					if ( preg_match("#^$match#", $request_match, $matches) ||
       
   202 						preg_match("#^$match#", urldecode($request_match), $matches) ) {
       
   203 
       
   204 						if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
       
   205 							// this is a verbose page match, lets check to be sure about it
       
   206 							if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) )
       
   207 						 		continue;
       
   208 						}
       
   209 
       
   210 						// Got a match.
       
   211 						$this->matched_rule = $match;
       
   212 						break;
       
   213 					}
       
   214 				}
       
   215 			}
       
   216 
       
   217 			if ( isset( $this->matched_rule ) ) {
       
   218 				// Trim the query of everything up to the '?'.
       
   219 				$query = preg_replace("!^.+\?!", '', $query);
       
   220 
       
   221 				// Substitute the substring matches into the query.
       
   222 				$query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
       
   223 
       
   224 				$this->matched_query = $query;
       
   225 
       
   226 				// Parse the query.
       
   227 				parse_str($query, $perma_query_vars);
       
   228 
       
   229 				// If we're processing a 404 request, clear the error var
       
   230 				// since we found something.
       
   231 				unset( $_GET['error'] );
       
   232 				unset( $error );
       
   233 			}
       
   234 
       
   235 			// If req_uri is empty or if it is a request for ourself, unset error.
       
   236 			if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
       
   237 				unset( $_GET['error'] );
       
   238 				unset( $error );
       
   239 
       
   240 				if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
       
   241 					unset( $perma_query_vars );
       
   242 
       
   243 				$this->did_permalink = false;
       
   244 			}
       
   245 		}
       
   246 
       
   247 		$this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);
       
   248 
       
   249 		foreach ( $GLOBALS['wp_post_types'] as $post_type => $t )
       
   250 			if ( $t->query_var )
       
   251 				$post_type_query_vars[$t->query_var] = $post_type;
       
   252 
       
   253 		foreach ( $this->public_query_vars as $wpvar ) {
       
   254 			if ( isset( $this->extra_query_vars[$wpvar] ) )
       
   255 				$this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
       
   256 			elseif ( isset( $_POST[$wpvar] ) )
       
   257 				$this->query_vars[$wpvar] = $_POST[$wpvar];
       
   258 			elseif ( isset( $_GET[$wpvar] ) )
       
   259 				$this->query_vars[$wpvar] = $_GET[$wpvar];
       
   260 			elseif ( isset( $perma_query_vars[$wpvar] ) )
       
   261 				$this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
       
   262 
       
   263 			if ( !empty( $this->query_vars[$wpvar] ) ) {
       
   264 				if ( ! is_array( $this->query_vars[$wpvar] ) ) {
       
   265 					$this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
       
   266 				} else {
       
   267 					foreach ( $this->query_vars[$wpvar] as $vkey => $v ) {
       
   268 						if ( !is_object( $v ) ) {
       
   269 							$this->query_vars[$wpvar][$vkey] = (string) $v;
       
   270 						}
       
   271 					}
       
   272 				}
       
   273 
       
   274 				if ( isset($post_type_query_vars[$wpvar] ) ) {
       
   275 					$this->query_vars['post_type'] = $post_type_query_vars[$wpvar];
       
   276 					$this->query_vars['name'] = $this->query_vars[$wpvar];
       
   277 				}
       
   278 			}
       
   279 		}
       
   280 
       
   281 		// Convert urldecoded spaces back into +
       
   282 		foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t )
       
   283 			if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) )
       
   284 				$this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] );
       
   285 
       
   286 		// Limit publicly queried post_types to those that are publicly_queryable
       
   287 		if ( isset( $this->query_vars['post_type']) ) {
       
   288 			$queryable_post_types = get_post_types( array('publicly_queryable' => true) );
       
   289 			if ( ! is_array( $this->query_vars['post_type'] ) ) {
       
   290 				if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
       
   291 					unset( $this->query_vars['post_type'] );
       
   292 			} else {
       
   293 				$this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
       
   294 			}
       
   295 		}
       
   296 
       
   297 		foreach ( (array) $this->private_query_vars as $var) {
       
   298 			if ( isset($this->extra_query_vars[$var]) )
       
   299 				$this->query_vars[$var] = $this->extra_query_vars[$var];
       
   300 		}
       
   301 
       
   302 		if ( isset($error) )
       
   303 			$this->query_vars['error'] = $error;
       
   304 
       
   305 		$this->query_vars = apply_filters('request', $this->query_vars);
       
   306 
       
   307 		do_action_ref_array('parse_request', array(&$this));
       
   308 	}
       
   309 
       
   310 	/**
       
   311 	 * Send additional HTTP headers for caching, content type, etc.
       
   312 	 *
       
   313 	 * Sets the X-Pingback header, 404 status (if 404), Content-type. If showing
       
   314 	 * a feed, it will also send last-modified, etag, and 304 status if needed.
       
   315 	 *
       
   316 	 * @since 2.0.0
       
   317 	 */
       
   318 	function send_headers() {
       
   319 		$headers = array('X-Pingback' => get_bloginfo('pingback_url'));
       
   320 		$status = null;
       
   321 		$exit_required = false;
       
   322 
       
   323 		if ( is_user_logged_in() )
       
   324 			$headers = array_merge($headers, wp_get_nocache_headers());
       
   325 		if ( !empty($this->query_vars['error']) && '404' == $this->query_vars['error'] ) {
       
   326 			$status = 404;
       
   327 			if ( !is_user_logged_in() )
       
   328 				$headers = array_merge($headers, wp_get_nocache_headers());
       
   329 			$headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
       
   330 		} else if ( empty($this->query_vars['feed']) ) {
       
   331 			$headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
       
   332 		} else {
       
   333 			// We're showing a feed, so WP is indeed the only thing that last changed
       
   334 			if ( !empty($this->query_vars['withcomments'])
       
   335 				|| ( empty($this->query_vars['withoutcomments'])
       
   336 					&& ( !empty($this->query_vars['p'])
       
   337 						|| !empty($this->query_vars['name'])
       
   338 						|| !empty($this->query_vars['page_id'])
       
   339 						|| !empty($this->query_vars['pagename'])
       
   340 						|| !empty($this->query_vars['attachment'])
       
   341 						|| !empty($this->query_vars['attachment_id'])
       
   342 					)
       
   343 				)
       
   344 			)
       
   345 				$wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
       
   346 			else
       
   347 				$wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
       
   348 			$wp_etag = '"' . md5($wp_last_modified) . '"';
       
   349 			$headers['Last-Modified'] = $wp_last_modified;
       
   350 			$headers['ETag'] = $wp_etag;
       
   351 
       
   352 			// Support for Conditional GET
       
   353 			if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
       
   354 				$client_etag = stripslashes(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
       
   355 			else $client_etag = false;
       
   356 
       
   357 			$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
       
   358 			// If string is empty, return 0. If not, attempt to parse into a timestamp
       
   359 			$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
       
   360 
       
   361 			// Make a timestamp for our most recent modification...
       
   362 			$wp_modified_timestamp = strtotime($wp_last_modified);
       
   363 
       
   364 			if ( ($client_last_modified && $client_etag) ?
       
   365 					 (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
       
   366 					 (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
       
   367 				$status = 304;
       
   368 				$exit_required = true;
       
   369 			}
       
   370 		}
       
   371 
       
   372 		$headers = apply_filters('wp_headers', $headers, $this);
       
   373 
       
   374 		if ( ! empty( $status ) )
       
   375 			status_header( $status );
       
   376 		foreach( (array) $headers as $name => $field_value )
       
   377 			@header("{$name}: {$field_value}");
       
   378 
       
   379 		if ( $exit_required )
       
   380 			exit();
       
   381 
       
   382 		do_action_ref_array('send_headers', array(&$this));
       
   383 	}
       
   384 
       
   385 	/**
       
   386 	 * Sets the query string property based off of the query variable property.
       
   387 	 *
       
   388 	 * The 'query_string' filter is deprecated, but still works. Plugins should
       
   389 	 * use the 'request' filter instead.
       
   390 	 *
       
   391 	 * @since 2.0.0
       
   392 	 */
       
   393 	function build_query_string() {
       
   394 		$this->query_string = '';
       
   395 		foreach ( (array) array_keys($this->query_vars) as $wpvar) {
       
   396 			if ( '' != $this->query_vars[$wpvar] ) {
       
   397 				$this->query_string .= (strlen($this->query_string) < 1) ? '' : '&';
       
   398 				if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars.
       
   399 					continue;
       
   400 				$this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]);
       
   401 			}
       
   402 		}
       
   403 
       
   404 		// query_string filter deprecated. Use request filter instead.
       
   405 		if ( has_filter('query_string') ) {  // Don't bother filtering and parsing if no plugins are hooked in.
       
   406 			$this->query_string = apply_filters('query_string', $this->query_string);
       
   407 			parse_str($this->query_string, $this->query_vars);
       
   408 		}
       
   409 	}
       
   410 
       
   411 	/**
       
   412 	 * Set up the WordPress Globals.
       
   413 	 *
       
   414 	 * The query_vars property will be extracted to the GLOBALS. So care should
       
   415 	 * be taken when naming global variables that might interfere with the
       
   416 	 * WordPress environment.
       
   417 	 *
       
   418 	 * @global string $query_string Query string for the loop.
       
   419 	 * @global int $more Only set, if single page or post.
       
   420 	 * @global int $single If single page or post. Only set, if single page or post.
       
   421 	 *
       
   422 	 * @since 2.0.0
       
   423 	 */
       
   424 	function register_globals() {
       
   425 		global $wp_query;
       
   426 		// Extract updated query vars back into global namespace.
       
   427 		foreach ( (array) $wp_query->query_vars as $key => $value) {
       
   428 			$GLOBALS[$key] = $value;
       
   429 		}
       
   430 
       
   431 		$GLOBALS['query_string'] = $this->query_string;
       
   432 		$GLOBALS['posts'] = & $wp_query->posts;
       
   433 		$GLOBALS['post'] = (isset($wp_query->post)) ? $wp_query->post : null;
       
   434 		$GLOBALS['request'] = $wp_query->request;
       
   435 
       
   436 		if ( is_single() || is_page() ) {
       
   437 			$GLOBALS['more'] = 1;
       
   438 			$GLOBALS['single'] = 1;
       
   439 		}
       
   440 	}
       
   441 
       
   442 	/**
       
   443 	 * Set up the current user.
       
   444 	 *
       
   445 	 * @since 2.0.0
       
   446 	 */
       
   447 	function init() {
       
   448 		wp_get_current_user();
       
   449 	}
       
   450 
       
   451 	/**
       
   452 	 * Set up the Loop based on the query variables.
       
   453 	 *
       
   454 	 * @uses WP::$query_vars
       
   455 	 * @since 2.0.0
       
   456 	 */
       
   457 	function query_posts() {
       
   458 		global $wp_the_query;
       
   459 		$this->build_query_string();
       
   460 		$wp_the_query->query($this->query_vars);
       
   461  	}
       
   462 
       
   463  	/**
       
   464  	 * Set the Headers for 404, if nothing is found for requested URL.
       
   465 	 *
       
   466 	 * Issue a 404 if a request doesn't match any posts and doesn't match
       
   467 	 * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already
       
   468 	 * issued, and if the request was not a search or the homepage.
       
   469 	 *
       
   470 	 * Otherwise, issue a 200.
       
   471 	 *
       
   472 	 * @since 2.0.0
       
   473  	 */
       
   474 	function handle_404() {
       
   475 		global $wp_query;
       
   476 
       
   477 		// If we've already issued a 404, bail.
       
   478 		if ( is_404() )
       
   479 			return;
       
   480 
       
   481 		// Never 404 for the admin, robots, or if we found posts.
       
   482 		if ( is_admin() || is_robots() || $wp_query->posts ) {
       
   483 			status_header( 200 );
       
   484 			return;
       
   485 		}
       
   486 
       
   487 		// We will 404 for paged queries, as no posts were found.
       
   488 		if ( ! is_paged() ) {
       
   489 
       
   490 			// Don't 404 for these queries if they matched an object.
       
   491 			if ( ( is_tag() || is_category() || is_tax() || is_author() || is_post_type_archive() ) && $wp_query->get_queried_object() ) {
       
   492 				status_header( 200 );
       
   493 				return;
       
   494 			}
       
   495 
       
   496 			// Don't 404 for these queries either.
       
   497 			if ( is_home() || is_search() ) {
       
   498 				status_header( 200 );
       
   499 				return;
       
   500 			}
       
   501 		}
       
   502 
       
   503 		// Guess it's time to 404.
       
   504 		$wp_query->set_404();
       
   505 		status_header( 404 );
       
   506 		nocache_headers();
       
   507 	}
       
   508 
       
   509 	/**
       
   510 	 * Sets up all of the variables required by the WordPress environment.
       
   511 	 *
       
   512 	 * The action 'wp' has one parameter that references the WP object. It
       
   513 	 * allows for accessing the properties and methods to further manipulate the
       
   514 	 * object.
       
   515 	 *
       
   516 	 * @since 2.0.0
       
   517 	 *
       
   518 	 * @param string|array $query_args Passed to {@link parse_request()}
       
   519 	 */
       
   520 	function main($query_args = '') {
       
   521 		$this->init();
       
   522 		$this->parse_request($query_args);
       
   523 		$this->send_headers();
       
   524 		$this->query_posts();
       
   525 		$this->handle_404();
       
   526 		$this->register_globals();
       
   527 		do_action_ref_array('wp', array(&$this));
       
   528 	}
       
   529 
       
   530 }
       
   531 
       
   532 /**
       
   533  * Helper class to remove the need to use eval to replace $matches[] in query strings.
       
   534  *
       
   535  * @since 2.9.0
       
   536  */
       
   537 class WP_MatchesMapRegex {
       
   538 	/**
       
   539 	 * store for matches
       
   540 	 *
       
   541 	 * @access private
       
   542 	 * @var array
       
   543 	 */
       
   544 	var $_matches;
       
   545 
       
   546 	/**
       
   547 	 * store for mapping result
       
   548 	 *
       
   549 	 * @access public
       
   550 	 * @var string
       
   551 	 */
       
   552 	var $output;
       
   553 
       
   554 	/**
       
   555 	 * subject to perform mapping on (query string containing $matches[] references
       
   556 	 *
       
   557 	 * @access private
       
   558 	 * @var string
       
   559 	 */
       
   560 	var $_subject;
       
   561 
       
   562 	/**
       
   563 	 * regexp pattern to match $matches[] references
       
   564 	 *
       
   565 	 * @var string
       
   566 	 */
       
   567 	var $_pattern = '(\$matches\[[1-9]+[0-9]*\])'; // magic number
       
   568 
       
   569 	/**
       
   570 	 * constructor
       
   571 	 *
       
   572 	 * @param string $subject subject if regex
       
   573 	 * @param array  $matches data to use in map
       
   574 	 * @return self
       
   575 	 */
       
   576 	function WP_MatchesMapRegex($subject, $matches) {
       
   577 		$this->_subject = $subject;
       
   578 		$this->_matches = $matches;
       
   579 		$this->output = $this->_map();
       
   580 	}
       
   581 
       
   582 	/**
       
   583 	 * Substitute substring matches in subject.
       
   584 	 *
       
   585 	 * static helper function to ease use
       
   586 	 *
       
   587 	 * @access public
       
   588 	 * @param string $subject subject
       
   589 	 * @param array  $matches data used for substitution
       
   590 	 * @return string
       
   591 	 */
       
   592 	public static function apply($subject, $matches) {
       
   593 		$oSelf = new WP_MatchesMapRegex($subject, $matches);
       
   594 		return $oSelf->output;
       
   595 	}
       
   596 
       
   597 	/**
       
   598 	 * do the actual mapping
       
   599 	 *
       
   600 	 * @access private
       
   601 	 * @return string
       
   602 	 */
       
   603 	function _map() {
       
   604 		$callback = array(&$this, 'callback');
       
   605 		return preg_replace_callback($this->_pattern, $callback, $this->_subject);
       
   606 	}
       
   607 
       
   608 	/**
       
   609 	 * preg_replace_callback hook
       
   610 	 *
       
   611 	 * @access public
       
   612 	 * @param  array $matches preg_replace regexp matches
       
   613 	 * @return string
       
   614 	 */
       
   615 	function callback($matches) {
       
   616 		$index = intval(substr($matches[0], 9, -1));
       
   617 		return ( isset( $this->_matches[$index] ) ? urlencode($this->_matches[$index]) : '' );
       
   618 	}
       
   619 
       
   620 }