/
rewriterule.php
247 lines (214 loc) · 7.14 KB
/
rewriterule.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
<?php
/**
* Habari RewriteRule Class
*
* @package Habari
*
* Helper class to encapsulate rewrite rule data
*
*/
class RewriteRule extends QueryRecord
{
const RULE_SYSTEM = 0;
const RULE_THEME = 1;
const RULE_PLUGIN = 2;
const RULE_CUSTOM = 5;
public $entire_match = NULL; // Entire matched string from the URL
public $named_arg_values = array(); // Values of named arguments filled during URL::parse()
private $m_named_args = NULL; // Named arguments matches
/**
* Returns the defined database columns for a rewrite rule.
* @return array Array of columns in the rewrite_rules table
*/
public static function default_fields()
{
return array(
'rule_id' => 0,
'name' => '',
'parse_regex' => '/.^/',
'build_str' => '',
'handler' => '',
'action' => '',
'priority' => 0,
'is_active' => 0,
'rule_class' => RewriteRule::RULE_CUSTOM,
'description' => '',
'parameters' => '',
);
}
/**
* Constructor for the rewrite_rule class.
* @param array $paramarray an associative array or querystring of initial field values
*/
public function __construct( $paramarray = array() )
{
// Defaults
$this->fields = array_merge(
self::default_fields(),
$this->fields );
parent::__construct( $paramarray );
$this->exclude_fields( 'rule_id' );
}
/**
* Match the stub against this rule
* Also sets internal structures based on a successful match
* @param string The URL stub to match against
* @return boolean True if this rule matches the stub, false if not
*/
public function match( $stub )
{
if( preg_match( $this->parse_regex, $stub, $pattern_matches ) > 0 ) {
$this->entire_match = array_shift( $pattern_matches ); // The entire matched string is returned at index 0
$named_args = $this->named_args; // Direct call shows a PHP notice
if($parameters = unserialize($this->parameters)) {
$this->named_arg_values = array_merge($this->named_arg_values, $parameters);
}
foreach ( $named_args as $keys ) {
foreach ( $keys as $key ) {
if ( !empty( $pattern_matches[$key] ) ) {
$this->named_arg_values[$key]= urldecode( str_replace( '%252F', '%2F', $pattern_matches[$key] ) );
}
}
}
if ( preg_match( '/^\\{\\$(\\w+)\\}$/', $this->action, $matches ) > 0 ) {
$this->action = $this->named_arg_values[$matches[1]];
}
return true;
}
return false;
}
/**
* Builds a URL using this rule based on the passed in data
* @param array $args An associative array of arguments to use for replacement in the rule
* @param boolean $useall If true (default), then all passed parameters that are not part of the built URL are tacked onto the URL as querystring
* @return string The URL created from the substituted arguments
*/
public function build( $args, $useall = true, $noamp = false )
{
$named_args = $this->named_args; // Direct call prints a PHP notice
$named_args_combined = array_flip( array_merge( $named_args['required'], $named_args['optional'] ) );
$args_defined = array_intersect_key( $args, $named_args_combined );
$args_query = array_diff( $args, $args_defined );
$args = Plugins::filter( 'rewrite_args', $args, $this->name );
// Replace defined arguments with their value
$searches = array();
$replacements = array();
foreach ( $named_args as $keys ) {
foreach ( $keys as $key ) {
if ( !empty( $args[$key] ) ) {
$searches[]= '/{\$'.$key.'}/';
$replacements[]= str_replace( '%2F', '%252F', urlencode( $args[$key] ) );
}
}
}
// Remove undefined arguments
$searches[]= '/\([^\(\)]*\$+[^\(\)]*\)/';
$replacements[]= '';
// Remove parens left from defined optional arguments
$searches[]= '/\(|\)/';
$replacements[]= '';
$return_url = preg_replace( $searches, $replacements, $this->build_str );
// Append any remaining args as query string arguments
if ( $useall ) {
$args = array_diff_key( $args, $named_args_combined );
$query_seperator = ( $noamp ) ? '&' : '&';
$return_url.= ( count( $args ) == 0 ) ? '' : '?' . http_build_query( $args, '', $query_seperator );
}
return $return_url;
}
/**
* Returns a distance from 0 indicating the appropriateness of the rule
* based on the passed-in arguments.
* @param array $args An array of arguments
* @return integer Returns 0 for an exact match, a higher number for less of a match
* @todo Enable this logic
*/
public function arg_match( $args )
{
return 0; // Let's let this logic linger for a little while
/* This needs further testing once that logic is established */
$named_args = $this->named_args; // Direct call prints a PHP notice
$named_args_combined = array_flip( array_merge( $named_args['required'], $named_args['optional'] ) );
$args = Plugins::filter( 'rewrite_args', $args, $this->name );
$diffargs = array_diff_key( $args, $named_args_combined );
$sameargs = array_intersect_key( $args, $named_args_combined );
$rating = count( $named_args_combined ) - count( $sameargs ) + count( $diffargs );
return $rating;
}
/**
* Magic property getter for this class
* @param string $name The name of the class property to return
* @returns mixed The value of that field in this object
*/
public function __get( $name )
{
switch( $name ) {
case 'named_args':
if( empty( $this->m_named_args ) ) {
preg_match_all( '/(?<!\()\{\$(\w+?)\}(?!\))/', $this->build_str, $required );
preg_match_all( '/(?<=\()[^\(\)]*\{\$(\\w+?)\}[^\(\)]*(?=\))/', $this->build_str, $optional );
$this->m_named_args['required']= $required[1];
$this->m_named_args['optional']= $optional[1];
}
return $this->m_named_args;
default:
return parent::__get( $name );
}
}
/**
* Saves a new rewrite rule to the rewrite_rules table
*/
public function insert()
{
return parent::insertRecord( DB::table( 'rewrite_rules' ) );
}
/**
* Updates an existing rule in the rewrite_rules table
*/
public function update()
{
return parent::updateRecord( DB::table( 'rewrite_rules' ), array( 'rule_id' => $this->rule_id ) );
}
/**
* Deletes an existing rule
*/
public function delete()
{
return parent::deleteRecord( DB::table( 'rewrite_rules' ), array( 'rule_id' => $this->rule_id ) );
}
/**
* Create an old-style rewrite rule
* @param string $build_str
* @param string $handler
* @param string $action
* @return RewriteRule The created rule
*/
public static function create_url_rule( $build_str, $handler, $action )
{
$arr = split( '/', $build_str );
$searches[]= '/^([^"\']+)$/';
$searches[]= '/^["\'](.+)["\']$/';
$replacements[]= '(.+)';
$replacements[]= '\1';
$re_arr = preg_replace( $searches, $replacements, $arr );
$searches[]= '/^([^"\']+)$/';
$searches[]= '/^["\'](.+)["\']$/';
$replacements[]= '{$\1}';
$replacements[]= '\1';
$str_arr = preg_replace( $searches, $replacements, $arr );
$regex = '/^' . implode( '\/', $re_arr ) . '\/?$/i';
$build_str = implode( '/', $str_arr );
return new RewriteRule( array(
'name' => $action,
'parse_regex' => $regex,
'build_str' => $build_str,
'handler' => $handler,
'action' => $action,
'priority' => 1,
'is_active' => 1,
'rule_class' => RewriteRule::RULE_CUSTOM,
'description' => 'Custom old-style rule.',
) );
}
}
?>