Ejemplo n.º 1
0
 /**
  * (Really) dispatch an URL to the correct handlers.
  *
  * This method does the actual magic, such as URL parsing, matching and
  * command invocation. You can optionally provide a custom URL and tell the
  * dispatcher that some parts of the URL should be skipped when handling
  * this request.
  *
  * \param $url
  * \param $prefix
  * \see AnewtURLDispatcher::dispatch
  */
 private function real_dispatch($url = null, $prefix = null)
 {
     /* Use the current URL if no explicit url was given */
     if (is_null($url)) {
         $url = AnewtRequest::relative_url();
     }
     /* Figure out the right base location if no prefix was given. If the URL
      * starts with the PHP script name, we assume no htaccess file has been
      * setup to beautify the website URLs. In this case the relevant parts
      * of the URL are added after the PHP script name. Example URL of such
      * a setup is http://.../dispatch.php/a/b/c/. Otherwise, it is quite
      * likely a htaccess file is used to point all requests to a script that
      * invokes the dispatcher. We assume this script is placed in the
      * toplevel directory, so we use that directory as the prefix. */
     if (is_null($prefix)) {
         if (str_has_prefix($url, $_SERVER['SCRIPT_NAME'])) {
             $prefix = $_SERVER['SCRIPT_NAME'];
         } else {
             $prefix = dirname($_SERVER['SCRIPT_NAME']);
         }
     }
     assert('is_string($url)');
     assert('is_string($prefix)');
     /* Strip off the GET parameters from the URL */
     $get_params = '';
     $question_mark_pos = strpos($url, '?');
     if ($question_mark_pos !== false) {
         $get_params = substr($url, $question_mark_pos);
         $url = substr($url, 0, $question_mark_pos);
     }
     /* Redirect GET requests when trailing slash is required but missing */
     if (!str_has_suffix($url, '/') && $this->force_trailing_slash && AnewtRequest::is_get() && !preg_match('#^.*\\.[^\\/]*$#', $url)) {
         redirect(sprintf('%s/%s', $url, $get_params), HTTP_STATUS_MOVED_PERMANENTLY);
     }
     /* Strip off prefix and slashes */
     $this->request_url_full = $url;
     $url = str_strip_prefix($url, $prefix);
     $url = str_strip_prefix($url, '/');
     $url = str_strip_suffix($url, '/');
     $this->request_url = $url;
     /* Try to find a matching route and extract the parameters */
     $found_route = false;
     $command = null;
     $parameters = array();
     $url_parts = strlen($url) > 0 ? explode('/', $url) : array();
     foreach ($this->routes as $route) {
         $route_type = array_shift($route);
         $route_command = array_shift($route);
         $route_parameters = array();
         /* Type I: Routes using regular expression */
         if ($route_type == ANEWT_URL_DISPATCHER_ROUTE_TYPE_REGEX) {
             list($pattern) = $route;
             /* Try both with and without trailing slash */
             if (preg_match($pattern, $url, $route_parameters) || preg_match($pattern, sprintf('%s/', $url), $route_parameters)) {
                 /* We don't care about $parameters[0] (it contains the full match) */
                 array_shift($route_parameters);
                 $route_parameters = array_map('urldecode', $route_parameters);
                 $command = $route_command;
                 $parameters = $route_parameters;
                 $found_route = true;
                 break;
             }
         } elseif ($route_type == ANEWT_URL_DISPATCHER_ROUTE_TYPE_URL_PARTS) {
             list($route_url, $additional_constraints) = $route;
             /* Route URL can be a string or an array */
             if (is_string($route_url)) {
                 $route_url = str_strip_prefix($route_url, '/');
                 $route_url = str_strip_suffix($route_url, '/');
                 $route_url_parts = strlen($route_url) > 0 ? explode('/', $route_url) : array();
             } elseif (is_numeric_array($route_url)) {
                 $route_url_parts = $route_url;
             } else {
                 throw new AnewtException('Invalid url route: %s', $route_url);
             }
             /* Match the URL parts against the route URL parts */
             if (count($url_parts) != count($route_url_parts)) {
                 continue;
             }
             $constraints = array_merge($this->url_part_constraints, $additional_constraints);
             for ($i = 0; $i < count($url_parts); $i++) {
                 /* If the URL starts with a ':' character it is
                  * a parameter... */
                 if ($route_url_parts[$i][0] === ':') {
                     $parameter_name = substr($route_url_parts[$i], 1);
                     $parameter_value = $url_parts[$i];
                     /* If there is a constraint for this parameter, the
                      * value must match the constraint. If not, this route
                      * cannot be used. */
                     if (array_key_exists($parameter_name, $constraints)) {
                         $pattern = $constraints[$parameter_name];
                         if (!preg_match($pattern, $parameter_value)) {
                             continue 2;
                         }
                     }
                     $route_parameters[$parameter_name] = urldecode($parameter_value);
                 } elseif ($url_parts[$i] !== $route_url_parts[$i]) {
                     continue 2;
                 }
             }
             /* If this code is reached, we found a matching route with all
              * the constraints on the URL parts satisfied. */
             $command = $route_command;
             $parameters = $route_parameters;
             $found_route = true;
             break;
         } else {
             assert('false; // not reached');
         }
     }
     /* If no route matches, try an automatic route. Only the first URL part
      * is considered for this. */
     if (!$found_route && $this->use_automatic_commands) {
         $url_parts = explode('/', $url, 2);
         if ($url_parts) {
             $command = array($this, sprintf('command_%s', $url_parts[0]));
             list($found_route, $error_message_to_ignore) = $this->is_valid_command($command);
         }
     }
     /* As a last resort try the default handler, if one was set. */
     $default_command = $this->default_command;
     if (!$found_route && !is_null($default_command)) {
         $command = $default_command;
         $command = $this->validate_command($command);
         $found_route = true;
     }
     /* If we still don't have a command, we give up. Too bad... not found */
     if (!$found_route) {
         throw new AnewtHTTPException(HTTP_STATUS_NOT_FOUND);
     }
     /* Check the command for validity. In most cases we already know the
      * command exists since that is already checked in the add_route_*()
      * methods or in the code above, except for lazily loaded commands, so
      * we try to load them and check for validity afterwards. */
     if (is_array($command) && is_string($command[0])) {
         $this->include_command_class($command[0]);
         $command = $this->validate_command($command);
     }
     /* Finally... run the command and the pre and post command hooks. */
     $this->pre_command($parameters);
     call_user_func($command, $parameters);
     $this->post_command($parameters);
 }
Ejemplo n.º 2
0
 /**
  * Fill form automatically from query data. If the form uses the GET method
  * the data comes from <code>$_GET</code>. If the form uses the POST method
  * the data comes from <code>$_POST</code>.
  *
  * The return value (see also fill() for an explanation) can be used to
  * detect incomplete \c $_GET or \c $_POST values. This may happen when
  * handling different form flavours with different controls using a single
  * form, e.g. a simple and advanced search form pointing to the same page in
  * which an instance of the advanced flavour of the form handles the
  * submitted data. It may also happen when users are messing with the
  * submitted data. You may then decide to process() the form only if all
  * values were provided. Example:
  * <code>if ($form->autofill() && $form->process()) { ...} else { ...}</code>
  *
  * \return
  *   True if this fill could be automatically filled from \c $_GET or \c
  *   $_POST, false if this was not the case.
  *
  * \see AnewtForm::fill()
  */
 function autofill()
 {
     $form_method = $this->_get('method');
     if (AnewtRequest::is_get() && $form_method == ANEWT_FORM_METHOD_GET) {
         return $this->fill($_GET);
     } elseif (AnewtRequest::is_post() && $form_method == ANEWT_FORM_METHOD_POST) {
         return $this->fill($_POST);
     }
     return false;
 }