File manager - Edit - /home/kamsoftco/public_html/wpadmin.srindustries.net.in/wp-content/plugins/wp-graphql/src/Request.php
Back
<?php namespace WPGraphQL; use GraphQL\Error\DebugFlag; use GraphQL\Error\Error; use GraphQL\GraphQL; use GraphQL\Server\OperationParams; use GraphQL\Server\ServerConfig; use GraphQL\Server\StandardServer; use WPGraphQL\Server\ValidationRules\DisableIntrospection; use WPGraphQL\Server\ValidationRules\QueryDepth; use WPGraphQL\Server\ValidationRules\RequireAuthentication; use WPGraphQL\Server\WPHelper; use WPGraphQL\Utils\DebugLog; use WPGraphQL\Utils\QueryAnalyzer; /** * Class Request * * Proxies a request to graphql-php, applying filters and transforming request * data as needed. * * @package WPGraphQL * * phpcs:disable -- PHPStan annotation. * @phpstan-import-type RootValueResolver from \GraphQL\Server\ServerConfig * @phpstan-import-type SerializableResult from \GraphQL\Executor\ExecutionResult * phpcs:enable */ class Request { /** * App context for this request. * * @var \WPGraphQL\AppContext */ public $app_context; /** * Request data. * * @var array<string,mixed>|\GraphQL\Server\OperationParams */ public $data; /** * Cached global post. * * @var ?\WP_Post */ public $global_post; /** * Cached global wp_the_query. * * @var ?\WP_Query */ private $global_wp_the_query; /** * GraphQL operation parameters for this request. * Will be an array of OperationParams if this is a batch request. * * @var \GraphQL\Server\OperationParams|\GraphQL\Server\OperationParams[] */ public $params; /** * Schema for this request. * * @var \WPGraphQL\WPSchema */ public $schema; /** * Debug log for WPGraphQL Requests * * @var \WPGraphQL\Utils\DebugLog */ public $debug_log; /** * The Type Registry the Schema is built with * * @var \WPGraphQL\Registry\TypeRegistry */ public $type_registry; /** * Validation rules for execution. * * @var array<string,\GraphQL\Validator\Rules\ValidationRule> */ protected $validation_rules; /** * The default field resolver function. Default null * * @var callable|null */ protected $field_resolver; /** * The root value of the request. Default null; * * @var mixed|RootValueResolver */ protected $root_value; /** * @var \WPGraphQL\Utils\QueryAnalyzer */ protected $query_analyzer; /** * Authentication error stored during before_execute(). * If set, the request should return this error instead of executing the query. * * @var \WP_Error|bool|null */ protected $authentication_error = null; /** * Constructor * * @param array<string,mixed> $data The request data (for Non-HTTP requests). * * @return void * * @throws \Exception */ public function __construct( array $data = [] ) { /** * Whether it's a GraphQL Request (http or internal) * * @since 0.0.5 */ if ( ! defined( 'GRAPHQL_REQUEST' ) ) { define( 'GRAPHQL_REQUEST', true ); } /** * Filter "is_graphql_request" to return true */ \WPGraphQL::set_is_graphql_request( true ); /** * Action – intentionally with no context – to indicate a GraphQL Request has started. * This is a great place for plugins to hook in and modify things that should only * occur in the context of a GraphQL Request. The base class hooks into this action to * kick off the schema creation, so types are not set up until this action has run! */ do_action( 'init_graphql_request' ); // Start tracking debug log messages $this->debug_log = new DebugLog(); // Set request data for passed-in (non-HTTP) requests. $this->data = $data; // Get the Type Registry $this->type_registry = \WPGraphQL::get_type_registry(); // Get the App Context $this->app_context = \WPGraphQL::get_app_context(); $this->validation_rules = $this->get_validation_rules(); $this->field_resolver = $this->get_field_resolver(); // Inject the type registry into the app context. $this->app_context->type_registry = $this->type_registry; // The query analyzer tracks nodes, models, list types and more // to return in headers and debug messages to help developers understand // what was resolved, how to cache it, etc. $this->query_analyzer = new QueryAnalyzer( $this ); $this->query_analyzer->init(); } /** * Get the instance of the Query Analyzer */ public function get_query_analyzer(): QueryAnalyzer { return $this->query_analyzer; } /** * @return callable|null */ protected function get_field_resolver() { return $this->field_resolver; } /** * Return the validation rules to use in the request * * @return array<string,\GraphQL\Validator\Rules\ValidationRule> */ protected function get_validation_rules(): array { $validation_rules = GraphQL::getStandardValidationRules(); $validation_rules['require_authentication'] = new RequireAuthentication(); $validation_rules['disable_introspection'] = new DisableIntrospection(); $validation_rules['query_depth'] = new QueryDepth(); /** * Return the validation rules to use in the request * * @param array<string,\GraphQL\Validator\Rules\ValidationRule> $validation_rules The validation rules to use in the request * @param \WPGraphQL\Request $request The Request instance */ return apply_filters( 'graphql_validation_rules', $validation_rules, $this ); } /** * Returns the root value to use in the request. * * @return mixed|RootValueResolver|null */ protected function get_root_value() { /** * Set the root value based on what was passed to the request */ $root_value = is_array( $this->data ) && ! empty( $this->data['root_value'] ) ? $this->data['root_value'] : null; /** * Return the filtered root value * * @param mixed|RootValueResolver $root_value The root value the Schema should use to resolve with. Default null. * @param \WPGraphQL\Request $request The Request instance */ return apply_filters( 'graphql_root_value', $root_value, $this ); } /** * Apply filters and do actions before GraphQL execution * * @throws \GraphQL\Error\Error */ private function before_execute(): void { /** * Store the global post so that it can be reset after GraphQL execution * * This allows for a GraphQL query to be used in the middle of post content, such as in a Shortcode * without disrupting the flow of the post as the global POST before and after GraphQL execution will be * the same. */ if ( ! empty( $GLOBALS['post'] ) ) { $this->global_post = $GLOBALS['post']; } if ( ! empty( $GLOBALS['wp_query'] ) && $GLOBALS['wp_the_query'] instanceof \WP_Query ) { $this->global_wp_the_query = clone $GLOBALS['wp_the_query']; } /** * Reset authentication error state for this execution. * * This ensures each batch item starts with clean auth state, preventing * errors from one batch item incorrectly persisting to subsequent items. * * @since 2.5.4 */ $this->authentication_error = null; /** * Check for authentication errors via the graphql_authentication_errors filter. * * Note: For HTTP requests, all CSRF protection and nonce validation is * handled by Router::validate_http_request_authentication() before this * code runs. This call allows plugins to hook in and indicate auth errors. * * @since 2.5.4 CSRF protection and nonce validation moved to Router. */ $auth_error = $this->has_authentication_errors(); if ( false !== $auth_error ) { // Store the authentication error for later use in execute methods $this->authentication_error = $auth_error; } /** * Update AppContext->viewer to reflect the current user after auth check. * * If the user was downgraded due to missing nonce (CSRF protection), * the viewer should reflect the guest user, not the originally authenticated user. * * @since 2.6.0 */ $this->app_context->viewer = wp_get_current_user(); /** * If the request is a batch request it will come back as an array */ if ( is_array( $this->params ) ) { // If the request is a batch request, but batch requests are disabled, // bail early if ( ! $this->is_batch_queries_enabled() ) { throw new Error( esc_html__( 'Batch Queries are not supported', 'wp-graphql' ) ); } $batch_limit = get_graphql_setting( 'batch_limit', 10 ); $batch_limit = absint( $batch_limit ) ? absint( $batch_limit ) : 10; // If batch requests are enabled, but a limit is set and the request exceeds the limit // fail now if ( $batch_limit < count( $this->params ) ) { // translators: First placeholder is the max number of batch operations allowed in a GraphQL request. The 2nd placeholder is the number of operations requested in the current request. throw new Error( sprintf( esc_html__( 'Batch requests are limited to %1$d operations. This request contained %2$d', 'wp-graphql' ), absint( $batch_limit ), count( $this->params ) ) ); } /** * Execute batch queries * * @param \GraphQL\Server\OperationParams[] $params The operation params of the batch request */ do_action( 'graphql_execute_batch_queries', $this->params ); // Process the batched requests array_walk( $this->params, [ $this, 'do_action' ] ); } else { $this->do_action( $this->params ); } // Get the Schema $this->schema = \WPGraphQL::get_schema(); /** * This action runs before execution of a GraphQL request (regardless if it's a single or batch request) * * @param \WPGraphQL\Request $request The instance of the Request being executed */ do_action( 'graphql_before_execute', $this ); } /** * Checks authentication errors via the graphql_authentication_errors filter. * * As of 2.6.0, all CSRF protection and nonce validation for HTTP requests is * handled by Router::validate_http_request_authentication() BEFORE any GraphQL * hooks fire. This method now only provides: * - Plugin integration via the graphql_authentication_errors filter * * False means no errors and execution continues. * True or WP_Error prevents execution of the GraphQL request. * * @since 0.0.5 * @since 2.6.0 CSRF protection and nonce validation moved to Router. * * @return bool|\WP_Error False if no errors, true or WP_Error if there are errors. * * @see Router::validate_http_request_authentication() */ protected function has_authentication_errors() { return $this->filtered_authentication_errors( false ); } /** * Filter Authentication errors. Allows plugins that authenticate to hook in and prevent * execution if Authentication errors exist. * * @param bool $authentication_errors Whether there are authentication errors with the request. * * @return bool */ protected function filtered_authentication_errors( $authentication_errors = false ) { /** * If false, there are no authentication errors. If true, execution of the * GraphQL request will be prevented and an error will be thrown. * * @param bool $authentication_errors Whether there are authentication errors with the request * @param \WPGraphQL\Request $request Instance of the Request */ return apply_filters( 'graphql_authentication_errors', $authentication_errors, $this ); } /** * Performs actions and runs filters after execution completes * * @template T from (SerializableResult|SerializableResult[])|(\GraphQL\Executor\ExecutionResult|array<int,\GraphQL\Executor\ExecutionResult>) * * @param T $response The response from execution. Array for batch requests, single object for individual requests. * * @return T */ private function after_execute( $response ) { /** * Authentication check has been moved to before_execute() as of 2.6.0. * This ensures auth is validated BEFORE query execution, not after. * * @since 2.6.0 Auth check moved to before_execute() * @see https://github.com/wp-graphql/wp-graphql/issues/3447 */ /** * If the params and the $response are both arrays * treat this as a batch request and map over the array to apply the * after_execute_actions, otherwise apply them to the current response */ if ( is_array( $this->params ) && is_array( $response ) ) { $filtered_response = []; foreach ( $response as $key => $resp ) { $filtered_response[] = $this->after_execute_actions( $resp, (int) $key ); } } else { $filtered_response = $this->after_execute_actions( $response, null ); } /** * Reset the global post after execution * * This allows for a GraphQL query to be used in the middle of post content, such as in a Shortcode * without disrupting the flow of the post as the global POST before and after GraphQL execution will be * the same. * * We cannot use wp_reset_postdata here because it just resets the post from the global query which can * be anything the because the resolvers themself can set it to whatever. So we just manually reset the * post with setup_postdata we cached before this request. */ if ( ! empty( $this->global_wp_the_query ) ) { $GLOBALS['wp_the_query'] = $this->global_wp_the_query; // phpcs:ignore WordPress.WP.GlobalVariablesOverride wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query } if ( ! empty( $this->global_post ) ) { $GLOBALS['post'] = $this->global_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride setup_postdata( $this->global_post ); } /** * Run an action after GraphQL Execution * * @param mixed[] $filtered_response The response of the entire operation. Could be a single operation or a batch operation * @param \WPGraphQL\Request $request Instance of the Request being executed */ do_action( 'graphql_after_execute', $filtered_response, $this ); /** * Return the filtered response */ return $filtered_response; } /** * Apply filters and do actions after GraphQL execution * * @param mixed|array<string,mixed>|object $response The response for your GraphQL request * @param int|null $key The array key of the params for batch requests * * @return mixed|array<string,mixed>|object */ private function after_execute_actions( $response, $key = null ) { /** * Determine which params (batch or single request) to use when passing through to the actions */ $query = null; $operation = null; $variables = null; $query_id = null; if ( $this->params instanceof OperationParams ) { $operation = $this->params->operation; $query = $this->params->query; $query_id = $this->params->queryId; $variables = $this->params->variables; } elseif ( is_array( $this->params ) ) { $operation = $this->params[ $key ]->operation ?? ''; $query = $this->params[ $key ]->query ?? ''; $query_id = $this->params[ $key ]->queryId ?? null; $variables = $this->params[ $key ]->variables ?? null; } /** * Run an action. This is a good place for debug tools to hook in to log things, etc. * * @param mixed|array<string,mixed>|object $response The response your GraphQL request * @param \WPGraphQL\WPSchema $schema The schema object for the root request * @param ?string $operation The name of the operation * @param ?string $query The query that GraphQL executed * @param ?array<string,mixed> $variables Variables to passed to your GraphQL query * @param \WPGraphQL\Request $request Instance of the Request * * @since 0.0.4 */ do_action( 'graphql_execute', $response, $this->schema, $operation, $query, $variables, $this ); /** * Add the debug log to the request */ if ( ! empty( $response ) ) { $logs = $this->debug_log->get_logs(); if ( is_array( $response ) ) { $response['extensions']['debug'] = $logs; } else { $response->extensions['debug'] = $logs; } } /** * Filter the $response of the GraphQL execution. This allows for the response to be filtered * before it's returned, allowing granular control over the response at the latest point. * * POSSIBLE USAGE EXAMPLES: * This could be used to ensure that certain fields never make it to the response if they match * certain criteria, etc. For example, this filter could be used to check if a current user is * allowed to see certain things, and if they are not, the $response could be filtered to remove * the data they should not be allowed to see. * * Or, perhaps some systems want the response to always include some additional piece of data in * every response, regardless of the request that was sent to it, this could allow for that * to be hooked in and included in the $response. * * @param mixed|array<string,mixed>|object $response The response for your GraphQL query * @param \WPGraphQL\WPSchema $schema The schema object for the root request * @param ?string $operation The name of the operation * @param ?string $query The query that GraphQL executed * @param ?array<string,mixed> $variables Variables to passed to your GraphQL query * @param \WPGraphQL\Request $request Instance of the Request * @param ?string $query_id The query id that GraphQL executed * * @since 0.0.5 */ $filtered_response = apply_filters( 'graphql_request_results', $response, $this->schema, $operation, $query, $variables, $this, $query_id ); /** * Run an action after the response has been filtered, as the response is being returned. * This is a good place for debug tools to hook in to log things, etc. * * @param mixed|array<string,mixed>|object $filtered_response The filtered response for the GraphQL request * @param mixed|array<string,mixed>|object $response The response for your GraphQL request * @param \WPGraphQL\WPSchema $schema The schema object for the root request * @param ?string $operation The name of the operation * @param ?string $query The query that GraphQL executed * @param ?array<string,mixed> $variables Variables to passed to your GraphQL query * @param \WPGraphQL\Request $request Instance of the Request * @param ?string $query_id The query id that GraphQL executed */ do_action( 'graphql_return_response', $filtered_response, $response, $this->schema, $operation, $query, $variables, $this, $query_id ); /** * Filter "is_graphql_request" back to false. */ \WPGraphQL::set_is_graphql_request( false ); return $filtered_response; } /** * Run action for a request. * * @param \GraphQL\Server\OperationParams $params OperationParams for the request. */ private function do_action( OperationParams $params ): void { /** * Run an action for each request. * * @param ?string $query The GraphQL query * @param ?string $operation The name of the operation * @param ?array<string,mixed> $variables Variables to be passed to your GraphQL request * @param \GraphQL\Server\OperationParams $params The Operation Params. This includes any extra params, * such as extensions or any other modifications to the request body */ do_action( 'do_graphql_request', $params->query, $params->operation, $params->variables, $params ); } /** * Execute an internal request (graphql() function call). * * @return mixed[] * @phpstan-return SerializableResult|SerializableResult[]|mixed[] * @throws \Exception */ public function execute() { $helper = new WPHelper(); if ( ! $this->data instanceof OperationParams ) { $this->params = $helper->parseRequestParams( 'POST', $this->data, [] ); } else { $this->params = $this->data; } if ( is_array( $this->params ) ) { return array_map( function ( $data ) { $this->data = $data; return $this->execute(); }, $this->params ); } // If $this->params isn't an array or an OperationParams instance, then something probably went wrong. if ( ! $this->params instanceof OperationParams ) { throw new \Exception( 'Invalid request params.' ); } /** * Initialize the GraphQL Request */ $this->before_execute(); /** * If there was an authentication error, return it as a GraphQL error response * instead of executing the query. * * IMPORTANT: This intentionally happens BEFORE the `pre_graphql_execute_request` filter. * Authentication failures should fail fast for security reasons: * - Don't give plugins a chance to interfere with or "undo" auth failures * - Avoid unnecessary filter processing for failed requests * - Ensure consistent, predictable auth error handling * * Plugins that need to observe ALL requests (including auth failures) should use * earlier hooks like `graphql_before_execute` or `do_graphql_request`. */ if ( null !== $this->authentication_error ) { $error_message = is_wp_error( $this->authentication_error ) ? $this->authentication_error->get_error_message() : __( 'Authentication Error', 'wp-graphql' ); return $this->after_execute( [ 'errors' => [ [ 'message' => esc_html( $error_message ), ], ], ] ); } /** * Filter this to be anything other than null to short-circuit the request. * * @param ?SerializableResult $response * @param self $request */ $response = apply_filters( 'pre_graphql_execute_request', null, $this ); if ( null === $response ) { /** * @var \GraphQL\Server\OperationParams $params */ $params = $this->params; /** * Allow the query string to be determined by a filter. Ex, when params->queryId is present, query can be retrieved. * * @param string $query * @param \GraphQL\Server\OperationParams $params */ $query = apply_filters( 'graphql_execute_query_params', $params->query ?? '', $params ); $result = GraphQL::executeQuery( $this->schema, $query, $this->get_root_value(), $this->app_context, $params->variables ?? null, $params->operation ?? null, $this->field_resolver, $this->validation_rules ); /** * Return the result of the request */ $response = $result->toArray( $this->get_debug_flag() ); } /** * Ensure the response is returned as a proper, populated array. Otherwise add an error. */ if ( empty( $response ) || ! is_array( $response ) ) { $response = [ 'errors' => __( 'The GraphQL request returned an invalid response', 'wp-graphql' ), ]; } /** * If the request is a batch request it will come back as an array */ return $this->after_execute( $response ); } /** * Execute an HTTP request. * * @return SerializableResult|(\GraphQL\Executor\ExecutionResult|array<int,\GraphQL\Executor\ExecutionResult>) * @throws \Exception */ public function execute_http() { if ( ! $this->is_valid_http_content_type() ) { return $this->get_invalid_content_type_response(); } /** * Parse HTTP request. */ $helper = new WPHelper(); $this->params = $helper->parseHttpRequest(); /** * Initialize the GraphQL Request */ $this->before_execute(); /** * If there was an authentication error, return it as a GraphQL error response * instead of executing the query. This ensures consistent error handling. */ if ( null !== $this->authentication_error ) { $error_message = is_wp_error( $this->authentication_error ) ? $this->authentication_error->get_error_message() : __( 'Authentication Error', 'wp-graphql' ); return $this->after_execute( [ 'errors' => [ [ 'message' => esc_html( $error_message ), ], ], ] ); } /** * Get the response. */ $response = apply_filters( 'pre_graphql_execute_request', null, $this ); /** * If no cached response, execute the query */ if ( null === $response ) { $server = $this->get_server(); $response = $server->executeRequest( $this->params ); } return $this->after_execute( $response ); } /** * Validates the content type for HTTP POST requests */ private function is_valid_http_content_type(): bool { if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) { return true; } $content_type = $this->get_content_type(); if ( empty( $content_type ) ) { return false; } $is_valid = 0 === stripos( $content_type, 'application/json' ); /** * Allow graphql to validate custom content types for HTTP POST requests * * @param bool $is_valid Whether the content type is valid * @param string $content_type The content type header value that was received * * @since 2.1.0 */ return (bool) apply_filters( 'graphql_is_valid_http_content_type', $is_valid, $content_type ); } /** * Gets the content type from the request headers */ private function get_content_type(): string { if ( isset( $_SERVER['CONTENT_TYPE'] ) ) { return sanitize_text_field( $_SERVER['CONTENT_TYPE'] ); } if ( isset( $_SERVER['HTTP_CONTENT_TYPE'] ) ) { return sanitize_text_field( $_SERVER['HTTP_CONTENT_TYPE'] ); } return ''; } /** * Returns the error response for invalid content type * * @return array{errors: array{array{message: string}}} */ private function get_invalid_content_type_response(): array { $content_type = $this->get_content_type(); /** * Filter the status code to return when the content type is invalid * * @param int $status_code The status code to return. Default 415. * @param string $content_type The content type header value that was received. */ $filtered_status_code = apply_filters( 'graphql_invalid_content_type_status_code', 415, $content_type ); // Set the status code to the filtered value if it's a valid status code. if ( is_numeric( $filtered_status_code ) ) { $filtered_status_code = (int) $filtered_status_code; if ( $filtered_status_code > 100 && $filtered_status_code < 599 ) { Router::$http_status_code = $filtered_status_code; } } return [ 'errors' => [ [ // translators: %s is the content type header value that was received 'message' => sprintf( esc_html__( 'HTTP POST requests must have Content-Type: application/json header. Received: %s', 'wp-graphql' ), $content_type ), ], ], ]; } /** * Get the operation params for the request. * * @return \GraphQL\Server\OperationParams|\GraphQL\Server\OperationParams[] */ public function get_params() { return $this->params; } /** * Returns the debug flag value * * @return int */ public function get_debug_flag() { $flag = DebugFlag::INCLUDE_DEBUG_MESSAGE; if ( 0 !== get_current_user_id() ) { // Flag 2 shows the trace data, which should require user to be logged in to see by default $flag = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE; } return true === \WPGraphQL::debug() ? $flag : DebugFlag::NONE; } /** * Determines if batch queries are enabled for the server. * * Default is to have batch queries enabled. */ private function is_batch_queries_enabled(): bool { $batch_queries_enabled = true; $batch_queries_setting = get_graphql_setting( 'batch_queries_enabled', 'on' ); if ( 'off' === $batch_queries_setting ) { $batch_queries_enabled = false; } /** * Filter whether batch queries are supported or not * * @param bool $batch_queries_enabled Whether Batch Queries should be enabled * @param \GraphQL\Server\OperationParams|\GraphQL\Server\OperationParams[] $params Request operation params */ return (bool) apply_filters( 'graphql_is_batch_queries_enabled', $batch_queries_enabled, $this->params ); } /** * Create the GraphQL server that will process the request. */ private function get_server(): StandardServer { $debug_flag = $this->get_debug_flag(); $config = new ServerConfig(); $config ->setDebugFlag( $debug_flag ) ->setSchema( $this->schema ) ->setContext( $this->app_context ) ->setValidationRules( $this->validation_rules ) ->setQueryBatching( $this->is_batch_queries_enabled() ); if ( ! empty( $this->get_root_value() ) ) { $config->setRootValue( $this->get_root_value() ); } if ( ! empty( $this->field_resolver ) ) { $config->setFieldResolver( $this->field_resolver ); } /** * Run an action when the server config is created. The config can be acted * upon directly to override default values or implement new features, e.g., * $config->setValidationRules(). * * @param \GraphQL\Server\ServerConfig $config Server config * @param \GraphQL\Server\OperationParams|\GraphQL\Server\OperationParams[] $params Request operation params * * @since 0.2.0 */ do_action( 'graphql_server_config', $config, $this->params ); return new StandardServer( $config ); } }
| ver. 1.4 |
Github
|
.
| PHP 8.2.30 | Generation time: 0.19 |
proxy
|
phpinfo
|
Settings