[ Index ] |
PHP Cross Reference of GlotPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Base controller class 4 */ 5 class GP_Route { 6 7 public $api = false; 8 9 public $errors = array(); 10 public $notices = array(); 11 12 var $request_running = false; 13 var $template_path = null; 14 15 var $fake_request = false; 16 var $exited = false; 17 var $exit_message; 18 var $redirected = false; 19 var $redirected_to = null; 20 var $rendered_template = false; 21 var $loaded_template = null; 22 var $template_output = null; 23 var $headers = array(); 24 var $class_name; 25 var $http_status; 26 var $last_method_called; 27 28 public function __construct() { 29 30 } 31 32 public function die_with_error( $message, $status = 500 ) { 33 $this->status_header( $status ); 34 $this->exit_( $message ); 35 } 36 37 public function before_request() { 38 /** 39 * Fires before a route method is called. 40 * 41 * @since 1.0.0 42 * 43 * @param string $class_name The class name of the route. 44 * @param string $last_method_called The route method that will be called. 45 */ 46 do_action( 'gp_before_request', $this->class_name, $this->last_method_called ); 47 } 48 49 public function after_request() { 50 // we can't unregister a shutdown function 51 // this check prevents this method from being run twice 52 if ( ! $this->request_running ) { 53 return; 54 } 55 // set errors and notices 56 if ( ! headers_sent() ) { 57 $this->set_notices_and_errors(); 58 } 59 60 /** 61 * Fires after a route method was called. 62 * 63 * @since 1.0.0 64 * 65 * @param string $class_name The class name of the route. 66 * @param string $last_method_called The route method that will be called. 67 */ 68 do_action( 'gp_after_request', $this->class_name, $this->last_method_called ); 69 } 70 71 /** 72 * Validates a thing and add its errors to the route's errors. 73 * 74 * @param object $thing a GP_Thing instance to validate 75 * @return bool whether the thing is valid 76 */ 77 public function validate( $thing ) { 78 $verdict = $thing->validate(); 79 $this->errors = array_merge( $this->errors, $thing->errors ); 80 return $verdict; 81 } 82 83 /** 84 * Same as validate(), but redirects to $url if the thing isn't valid. 85 * 86 * Note: this method calls $this->exit_() after the redirect and the code after it won't 87 * be executed. 88 * 89 * @param object $thing a GP_Thing instance to validate 90 * @param string $url where to redirect if the thing doesn't validate 91 * @return bool whether the thing is valid 92 */ 93 public function invalid_and_redirect( $thing, $url = null ) { 94 $valid = $this->validate( $thing ); 95 if ( ! $valid ) { 96 $this->redirect( $url ); 97 return true; 98 } 99 return false; 100 } 101 102 /** 103 * Checks whether a user is allowed to do an action. 104 * 105 * @since 2.3.0 Added the `$extra` parameter. 106 * 107 * @param string $action The action. 108 * @param string|null $object_type Optional. Type of an object. Default null. 109 * @param int|null $object_id Optional. ID of an object. Default null. 110 * @param array|null $extra Optional. Extra information for deciding the outcome. 111 * @return bool The verdict. 112 */ 113 public function can( $action, $object_type = null, $object_id = null, $extra = null ) { 114 return GP::$permission->current_user_can( $action, $object_type, $object_id, $extra ); 115 } 116 117 /** 118 * Redirects and exits if the current user isn't allowed to do an action. 119 * 120 * @since 1.0.0 121 * 122 * @param string $action The action. 123 * @param string|null $object_type Optional. Type of an object. Default null. 124 * @param int|null $object_id Optional. ID of an object. Default null. 125 * @param string|null $url Optional. URL to redirect to. Default: referrer or index page, if referrer is missing. 126 * @return bool Whether a redirect happened. 127 */ 128 public function cannot_and_redirect( $action, $object_type = null, $object_id = null, $url = null ) { 129 $can = $this->can( $action, $object_type, $object_id ); 130 if ( ! $can ) { 131 $this->redirect_with_error( __( 'You are not allowed to do that!', 'glotpress' ), $url ); 132 return true; 133 } 134 return false; 135 } 136 137 /** 138 * Verifies a nonce for a route. 139 * 140 * @since 2.0.0 141 * 142 * @param string $action Context for the created nonce. 143 * @return bool False if the nonce is invalid, true if valid. 144 */ 145 public function verify_nonce( $action ) { 146 if ( empty( $_REQUEST['_gp_route_nonce'] ) ) { 147 return false; 148 } 149 150 if ( ! wp_verify_nonce( $_REQUEST['_gp_route_nonce'], $action ) ) { 151 return false; 152 } 153 154 return true; 155 } 156 157 /** 158 * Verifies a nonce for a route and redirects in case the nonce is invalid. 159 * 160 * @since 2.0.0 161 * 162 * @param string $action Context for the created nonce. 163 * @param string|null $url The URL to redirect. Default: 'null', the referrer. 164 * @return bool False if the nonce is valid, true if the redirect has happened. 165 */ 166 public function invalid_nonce_and_redirect( $action, $url = null ) { 167 if ( $this->verify_nonce( $action ) ) { 168 return false; 169 } 170 171 $this->redirect_with_error( __( 'An error has occurred. Please try again.', 'glotpress' ), $url ); 172 return true; 173 } 174 175 /** 176 * Determines whether a user can perfom an action and redirects in case of a failure. 177 * 178 * @since 1.0.0 179 * 180 * @param string $action The action. 181 * @param string|null $object_type Optional. Type of an object. Default null. 182 * @param int|null $object_id Optional. ID of an object. Default null. 183 * @param string|null $message Error message in case of a failure. 184 * Default: 'You are not allowed to do that!'. 185 * @param array|null $extra Pass-through parameter to can(). 186 * @return false 187 */ 188 public function can_or_forbidden( $action, $object_type = null, $object_id = null, $message = null, $extra = null ) { 189 if ( ! isset( $message ) ) { 190 $message = __( 'You are not allowed to do that!', 'glotpress' ); 191 } 192 if ( ! $this->can( $action, $object_type, $object_id, $extra ) ) { 193 $this->die_with_error( $message, 403 ); 194 } 195 return false; 196 } 197 198 public function logged_in_or_forbidden() { 199 if ( ! is_user_logged_in() ) { 200 $this->die_with_error( 'Forbidden', 403 ); 201 } 202 } 203 204 public function redirect_with_error( $message, $url = null ) { 205 $this->errors[] = $message; 206 $this->redirect( $url ); 207 } 208 209 public function redirect( $url = null ) { 210 if ( $this->fake_request ) { 211 $this->redirected = true; 212 $this->redirected_to = $url; 213 return; 214 } 215 216 $this->set_notices_and_errors(); 217 218 if ( is_null( $url ) ) { 219 $url = $this->get_http_referer(); 220 } 221 222 /* 223 * TODO: do not redirect to projects, but to /. 224 * Currently it goes to /projects, because / redirects too and the notice is gone. 225 */ 226 if ( ! $url ) { 227 $url = gp_url( '/projects' ); 228 } 229 230 wp_safe_redirect( $url ); 231 $this->tmpl( 'redirect', compact( 'url' ) ); 232 } 233 234 /** 235 * Retrieves referer from '_wp_http_referer' or HTTP referer. 236 * 237 * Unlike `wp_get_referer()`, it doesn't check if the referer is 238 * the same as the current request URL. 239 * 240 * @since 2.0.0 241 * 242 * @return false|string False on failure. Referer URL on success. 243 */ 244 private function get_http_referer() { 245 if ( ! function_exists( 'wp_validate_redirect' ) ) { 246 return false; 247 } 248 249 $ref = wp_get_raw_referer(); 250 if ( $ref ) { 251 return wp_validate_redirect( $ref, false ); 252 } 253 254 return false; 255 } 256 257 /** 258 * Sets HTTP headers for content download. 259 * 260 * @param string $filename The name of the file. 261 * @param string $last_modified Optional. Date when the file was last modified. Default: ''. 262 */ 263 public function headers_for_download( $filename, $last_modified = '' ) { 264 $this->header( 'Content-Description: File Transfer' ); 265 $this->header( 'Pragma: public' ); 266 $this->header( 'Expires: 0' ); 267 268 if ( $last_modified ) { 269 $this->header( sprintf( 'Last-Modified: %s', $last_modified ) ); 270 } 271 272 $this->header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' ); 273 $this->header( "Content-Disposition: attachment; filename=\"$filename\"" ); 274 $this->header( 'Content-Type: application/octet-stream' ); 275 $this->header( 'Connection: close' ); 276 } 277 278 public function set_notices_and_errors() { 279 if ( $this->fake_request ) { 280 return; 281 } 282 283 foreach ( $this->notices as $notice ) { 284 gp_notice_set( $notice ); 285 } 286 $this->notices = array(); 287 288 foreach ( $this->errors as $error ) { 289 gp_notice_set( $error, 'error' ); 290 } 291 $this->errors = array(); 292 } 293 294 /** 295 * Loads a template. 296 * 297 * @param string $template Template name to load. 298 * @param array $args Associative array with arguements, which will be exported in the template PHP file. 299 * @param bool|string $honor_api If this is true or 'api' and the route is processing an API request 300 * the template name will be suffixed with .api. The actual file loaded will be template.api.php. 301 */ 302 public function tmpl( $template, $args = array(), $honor_api = true ) { 303 if ( $this->fake_request ) { 304 $this->rendered_template = true; 305 $this->loaded_template = $template; 306 } 307 $this->set_notices_and_errors(); 308 if ( $this->api && false !== $honor_api && 'no-api' !== $honor_api ) { 309 $template = $template . '.api'; 310 $this->header( 'Content-Type: application/json' ); 311 } else { 312 $this->header( 'Content-Type: text/html; charset=utf-8' ); 313 } 314 if ( $this->fake_request ) { 315 $this->template_output = gp_tmpl_get_output( $template, $args, $this->template_path ); 316 return true; 317 } 318 319 return gp_tmpl_load( $template, $args, $this->template_path ); 320 } 321 322 public function die_with_404( $args = array() ) { 323 $this->status_header( 404 ); 324 $this->tmpl( 325 '404', 326 $args + array( 327 'title' => __( 'Not Found', 'glotpress' ), 328 'http_status' => 404, 329 ) 330 ); 331 $this->exit_(); 332 } 333 334 public function exit_( $message = 0 ) { 335 if ( $this->fake_request ) { 336 $this->exited = true; 337 $this->exit_message = $message; 338 return; 339 } 340 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- May contain HTML. 341 exit( $message ); 342 } 343 344 public function header( $string ) { 345 if ( $this->fake_request ) { 346 list( $header, $value ) = explode( ':', $string, 2 ); 347 $this->headers[ $header ] = $value; 348 } else { 349 header( $string ); 350 } 351 } 352 353 public function status_header( $status ) { 354 if ( $this->fake_request ) { 355 $this->http_status = $status; 356 return; 357 } 358 return status_header( $status ); 359 } 360 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:01:07 2024 | Cross-referenced by PHPXref 0.7.1 |