Helpdesk da PluGzOne, baseado no osTicket
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

196 lines
6.7 KiB

<?php
/*********************************************************************
class.dispatcher.php
Dispatcher that will read files with URL lists in them and attempt to
match the URL requested to a function that should be invoked to handle
the request.
Jared Hancock
Copyright (c) 2006-2013 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
/**
* URL resolver and dispatcher. It's meant to be quite lightweight, so the
* functions aren't separated
*/
class Dispatcher {
function __construct($file=false) {
$this->urls = array();
$this->file = $file;
}
function resolve($url, $args=null) {
if ($this->file) { $this->lazy_load(); }
# Support HTTP method emulation with the _method GET argument
if (isset($_GET['_method'])) {
$_SERVER['REQUEST_METHOD'] = strtoupper($_GET['_method']);
unset($_GET['_method']);
}
foreach ($this->urls as $matcher) {
if ($matcher->matches($url)) {
return $matcher->dispatch($url, $args);
}
}
Http::response(400, __("URL not supported"));
}
/**
* Returns the url for the given function and arguments (arguments
* aren't declared, but will be handled
*/
function reverse($func) { }
/**
* Add the url to the list of supported URLs
*/
function append($url, $prefix=false) {
if ($prefix) { $url->setPrefix($prefix); }
array_push($this->urls, $url);
}
/**
* Add the urls from another dispatcher onto this one
*/
function extend($dispatcher) {
foreach ($dispatcher->urls as $url) { $this->append($url); }
/* allow inlining / chaining */ return $this;
}
/* static */ function include_urls($file, $absolute=false, $lazy=true) {
if (!$absolute) {
# Fetch the working path of the caller
$bt = debug_backtrace();
$file = dirname($bt[0]["file"]) . "/" . $file;
}
if ($lazy) return new Dispatcher($file);
else return (include $file);
}
/**
* The include_urls() method will create a new Dispatcher and set the
* $this->file to where the file to be loaded is located. When this
* dispatcher is first accessed, the file will be loaded.
*/
function lazy_load() {
$this->extend(include $this->file);
$this->file=false;
}
}
class UrlMatcher {
function __construct($regex, $func, $args=false, $method=false) {
# Add the slashes for the Perl syntax
$this->regex = "@" . $regex . "@";
$this->func = $func;
$this->args = ($args) ? $args : array();
$this->prefix = false;
$this->method = $method;
}
function setPrefix($prefix) { $this->prefix = $prefix; }
function matches($url) {
if ($this->method && $_SERVER['REQUEST_METHOD'] != $this->method) {
return false;
}
return preg_match($this->regex, $url, $this->matches) == 1;
}
function dispatch($url, $prev_args=null) {
# Remove named values from the match array
$f = array_filter(array_keys($this->matches), 'is_numeric');
$this->matches = array_intersect_key($this->matches, array_flip($f));
if (@get_class($this->func) == "Dispatcher") {
# Trim the leading match off the $url and call the
# sub-dispatcher. This will be the case for lines in the URL
# file like
# url("^/blah", Dispatcher::include_urls("blah/urls.conf.php"))
# Also, pass arguments matched so far (if any) to the receiving
# resolve() method by merging the $prev_args into $this->matches
# (excluding $this->matches[0], which is the matched URL at this
# level)
return $this->func->resolve(
substr($url, strlen($this->matches[0])),
array_merge(($prev_args) ? $prev_args : array(),
array_slice($this->matches, 1)));
}
# Drop the first item of the matches array (which is the whole
# matched url). Then merge in any initial arguments.
unset($this->matches[0]);
# Prepend received arguments (from a parent Dispatcher). This is
# different from the static args, which are postpended
if (is_array($prev_args))
$args = array_merge($prev_args, $this->matches);
else $args = $this->matches;
# Add in static args specified in the constructor
$args = array_merge($args, $this->args);
# Apply the $prefix given
list($class, $func) = $this->apply_prefix();
if ($class) {
# Create instance of the class, which is the first item,
# then call the method which is the second item
$func = array(new $class, $func);
}
if (!is_callable($func))
Http::response(500, __('Dispatcher compile error. Function not callable'));
return call_user_func_array($func, $args);
}
/**
* For the $prefix recieved by the constuctor, prepend it to the
* received $class, if any, then make an import if necessary. Lastly,
* return the appropriate $class, and $func that should be invoked to
* dispatch the URL.
*/
function apply_prefix() {
if (is_array($this->func)) { list($class, $func) = $this->func; }
else { $func = $this->func; $class = ""; }
if (is_object($class))
return array(false, $this->func);
if ($this->prefix)
$class = $this->prefix . $class;
if (strpos($class, ":")) {
list($file, $class) = explode(":", $class, 2);
include $file;
}
return array($class, $func);
}
}
function patterns($prefix) {
$disp = new Dispatcher();
for ($i=1, $k=func_num_args(); $i<$k; $i++) {
# NOTE: that $prefix is added to each url rather than to the
# dispatcher as a whole so that urls can be copied from one
# dispatcher to another (via the ->extend() method) and
# completely maintain their integrity
$disp->append(func_get_arg($i), $prefix);
}
return $disp;
}
function url($regex, $func, $args=false, $method=false) {
return new UrlMatcher($regex, $func, $args, $method);
}
function url_post($regex, $func, $args=false) {
return url($regex, $func, $args, "POST");
}
function url_get($regex, $func, $args=false) {
return url($regex, $func, $args, "GET");
}
function url_delete($regex, $func, $args=false) {
return url($regex, $func, $args, "DELETE");
}
?>