[ Index ]

PHP Cross Reference of GlotPress

title

Body

[close]

/gp-includes/ -> route.php (source)

   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  }


Generated: Sat Apr 27 01:01:04 2024 Cross-referenced by PHPXref 0.7.1