PluginProbe ʕ •ᴥ•ʔ
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.6
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.6
27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 19.1 19.10 19.11 19.12 19.13 19.14 19.2 19.3 19.4 19.5 19.5.1 19.6 19.6.1 19.7 19.7.1 19.7.2 19.8 19.9 20.0 20.1 20.10 20.11 20.12 20.13 20.2 20.2.1 20.3 20.4 20.5 20.6 20.7 20.8 20.9 21.0 21.1 21.2 21.3 21.4 21.5 21.6 21.7 21.8 21.8.1 21.9 21.9.1 22.0 22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 22.9 23.0 23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8 23.9 24.0 24.1 24.2 24.3 24.4 24.5 24.6 24.7 24.8 24.8.1 24.9 25.0 25.1 25.2 25.3 25.3.1 25.4 25.5 25.6 25.7 25.8 25.9 26.0 26.1 26.1.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 27.0 27.1 27.1.1 27.2 27.3 27.4
wordpress-seo / admin / class-my-yoast-proxy.php
wordpress-seo / admin Last commit date
ajax 5 years ago capabilities 4 years ago endpoints 5 years ago exceptions 7 years ago filters 4 years ago formatter 4 years ago google_search_console 5 years ago import 4 years ago listeners 8 years ago menu 4 years ago metabox 4 years ago notifiers 4 years ago pages 4 years ago roles 5 years ago ryte 4 years ago services 5 years ago statistics 5 years ago taxonomy 4 years ago tracking 4 years ago views 4 years ago watchers 5 years ago admin-settings-changed-listener.php 5 years ago ajax.php 4 years ago class-admin-asset-analysis-worker-location.php 5 years ago class-admin-asset-dev-server-location.php 5 years ago class-admin-asset-location.php 8 years ago class-admin-asset-manager.php 4 years ago class-admin-asset-seo-location.php 4 years ago class-admin-asset-yoast-components-l10n.php 4 years ago class-admin-editor-specific-replace-vars.php 5 years ago class-admin-gutenberg-compatibility-notification.php 5 years ago class-admin-help-panel.php 5 years ago class-admin-init.php 4 years ago class-admin-recommended-replace-vars.php 6 years ago class-admin-user-profile.php 6 years ago class-admin-utils.php 5 years ago class-admin.php 4 years ago class-asset.php 5 years ago class-bulk-description-editor-list-table.php 5 years ago class-bulk-editor-list-table.php 4 years ago class-bulk-title-editor-list-table.php 6 years ago class-collector.php 6 years ago class-config.php 4 years ago class-customizer.php 5 years ago class-database-proxy.php 5 years ago class-export.php 5 years ago class-expose-shortlinks.php 4 years ago class-gutenberg-compatibility.php 4 years ago class-helpscout.php 5 years ago class-meta-columns.php 4 years ago class-my-yoast-proxy.php 5 years ago class-option-tab.php 4 years ago class-option-tabs-formatter.php 5 years ago class-option-tabs.php 5 years ago class-paper-presenter.php 5 years ago class-plugin-availability.php 5 years ago class-plugin-conflict.php 4 years ago class-premium-popup.php 5 years ago class-premium-upsell-admin-block.php 4 years ago class-primary-term-admin.php 5 years ago class-product-upsell-notice.php 5 years ago class-remote-request.php 5 years ago class-schema-person-upgrade-notification.php 4 years ago class-suggested-plugins.php 4 years ago class-yoast-columns.php 5 years ago class-yoast-dashboard-widget.php 4 years ago class-yoast-form.php 4 years ago class-yoast-input-validation.php 5 years ago class-yoast-network-admin.php 5 years ago class-yoast-network-settings-api.php 4 years ago class-yoast-notification-center.php 4 years ago class-yoast-notification.php 5 years ago class-yoast-notifications.php 5 years ago class-yoast-plugin-conflict.php 4 years ago index.php 10 years ago interface-collection.php 7 years ago interface-installable.php 8 years ago
class-my-yoast-proxy.php
210 lines
1 <?php
2 /**
3 * WPSEO plugin file.
4 *
5 * @package WPSEO\Admin
6 */
7
8 /**
9 * Loads the MyYoast proxy.
10 *
11 * This class registers a proxy page on `admin.php`. Which is reached with the `page=PAGE_IDENTIFIER` parameter.
12 * It will read external files and serves them like they are located locally.
13 */
14 class WPSEO_MyYoast_Proxy implements WPSEO_WordPress_Integration {
15
16 /**
17 * The page identifier used in WordPress to register the MyYoast proxy page.
18 *
19 * @var string
20 */
21 const PAGE_IDENTIFIER = 'wpseo_myyoast_proxy';
22
23 /**
24 * The cache control's max age. Used in the header of a successful proxy response.
25 *
26 * @var int
27 */
28 const CACHE_CONTROL_MAX_AGE = DAY_IN_SECONDS;
29
30 /**
31 * Registers the hooks when the user is on the right page.
32 *
33 * @codeCoverageIgnore
34 *
35 * @return void
36 */
37 public function register_hooks() {
38 if ( ! $this->is_proxy_page() ) {
39 return;
40 }
41
42 // Register the page for the proxy.
43 add_action( 'admin_menu', [ $this, 'add_proxy_page' ] );
44 add_action( 'admin_init', [ $this, 'handle_proxy_page' ] );
45 }
46
47 /**
48 * Registers the proxy page. It does not actually add a link to the dashboard.
49 *
50 * @codeCoverageIgnore
51 *
52 * @return void
53 */
54 public function add_proxy_page() {
55 add_dashboard_page( '', '', 'read', self::PAGE_IDENTIFIER, '' );
56 }
57
58 /**
59 * Renders the requested proxy page and exits to prevent the WordPress UI from loading.
60 *
61 * @codeCoverageIgnore
62 *
63 * @return void
64 */
65 public function handle_proxy_page() {
66 $this->render_proxy_page();
67
68 // Prevent the WordPress UI from loading.
69 exit;
70 }
71
72 /**
73 * Renders the requested proxy page.
74 *
75 * This is separated from the exits to be able to test it.
76 *
77 * @return void
78 */
79 public function render_proxy_page() {
80 $proxy_options = $this->determine_proxy_options();
81 if ( $proxy_options === [] ) {
82 // Do not accept any other file than implemented.
83 $this->set_header( 'HTTP/1.0 501 Requested file not implemented' );
84 return;
85 }
86
87 // Set the headers before serving the remote file.
88 $this->set_header( 'Content-Type: ' . $proxy_options['content_type'] );
89 $this->set_header( 'Cache-Control: max-age=' . self::CACHE_CONTROL_MAX_AGE );
90
91 try {
92 echo $this->get_remote_url_body( $proxy_options['url'] );
93 }
94 catch ( Exception $e ) {
95 /*
96 * Reset the file headers because the loading failed.
97 *
98 * Note: Due to supporting PHP 5.2 `header_remove` can not be used here.
99 * Overwrite the headers instead.
100 */
101 $this->set_header( 'Content-Type: text/plain' );
102 $this->set_header( 'Cache-Control: max-age=0' );
103
104 $this->set_header( 'HTTP/1.0 500 ' . $e->getMessage() );
105 }
106 }
107
108 /**
109 * Tries to load the given url via `wp_remote_get`.
110 *
111 * @codeCoverageIgnore
112 *
113 * @param string $url The url to load.
114 *
115 * @return string The body of the response.
116 *
117 * @throws Exception When `wp_remote_get` returned an error.
118 * @throws Exception When the response code is not 200.
119 */
120 protected function get_remote_url_body( $url ) {
121 $response = wp_remote_get( $url );
122
123 if ( $response instanceof WP_Error ) {
124 throw new Exception( 'Unable to retrieve file from MyYoast' );
125 }
126
127 if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
128 throw new Exception( 'Received unexpected response from MyYoast' );
129 }
130
131 return wp_remote_retrieve_body( $response );
132 }
133
134 /**
135 * Determines the proxy options based on the file and plugin version arguments.
136 *
137 * When the file is known it returns an array like this:
138 * <code>
139 * $array = array(
140 * 'content_type' => 'the content type'
141 * 'url' => 'the url, possibly with the plugin version'
142 * )
143 * </code>
144 *
145 * @return array Empty for an unknown file. See format above for known files.
146 */
147 protected function determine_proxy_options() {
148 if ( $this->get_proxy_file() === 'research-webworker' ) {
149 return [
150 'content_type' => 'text/javascript; charset=UTF-8',
151 'url' => 'https://my.yoast.com/api/downloads/file/analysis-worker?plugin_version=' . $this->get_plugin_version(),
152 ];
153 }
154
155 return [];
156 }
157
158 /**
159 * Checks if the current page is the MyYoast proxy page.
160 *
161 * @codeCoverageIgnore
162 *
163 * @return bool True when the page request parameter equals the proxy page.
164 */
165 protected function is_proxy_page() {
166 return filter_input( INPUT_GET, 'page' ) === self::PAGE_IDENTIFIER;
167 }
168
169 /**
170 * Returns the proxy file from the HTTP request parameters.
171 *
172 * @codeCoverageIgnore
173 *
174 * @return string The sanitized file request parameter.
175 */
176 protected function get_proxy_file() {
177 return filter_input( INPUT_GET, 'file', FILTER_SANITIZE_STRING );
178 }
179
180 /**
181 * Returns the plugin version from the HTTP request parameters.
182 *
183 * @codeCoverageIgnore
184 *
185 * @return string The sanitized plugin_version request parameter.
186 */
187 protected function get_plugin_version() {
188 $plugin_version = filter_input( INPUT_GET, 'plugin_version', FILTER_SANITIZE_STRING );
189 // Replace slashes to secure against requiring a file from another path.
190 $plugin_version = str_replace( [ '/', '\\' ], '_', $plugin_version );
191
192 return $plugin_version;
193 }
194
195 /**
196 * Sets the HTTP header.
197 *
198 * This is a tiny helper function to enable better testing.
199 *
200 * @codeCoverageIgnore
201 *
202 * @param string $header The header to set.
203 *
204 * @return void
205 */
206 protected function set_header( $header ) {
207 header( $header );
208 }
209 }
210