Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
25 - 1
<?php
2
/*
3
Copyright (c) 2010 Kevin M Burns Jr, http://kevburnsjr.com/
4
 
5
Permission is hereby granted, free of charge, to any person obtaining
6
a copy of this software and associated documentation files (the
7
"Software"), to deal in the Software without restriction, including
8
without limitation the rights to use, copy, modify, merge, publish,
9
distribute, sublicense, and/or sell copies of the Software, and to
10
permit persons to whom the Software is furnished to do so, subject to
11
the following conditions:
12
 
13
The above copyright notice and this permission notice shall be
14
included in all copies or substantial portions of the Software.
15
 
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
*/
24
 
25
/**
26
 * A URI Template Parser which is used by the apiREST class to resolve the REST requests
27
 * Blogpost: http://lab.kevburnsjr.com/php-uri-template-parser
28
 * Source: http://github.com/KevBurnsJr/php-uri-template-parser
29
 */
30
class URI_Template_Parser {
31
 
32
  public static $operators = array('+', ';', '?', '/', '.');
33
  public static $reserved_operators = array('|', '!', '@');
34
  public static $explode_modifiers = array('+', '*');
35
  public static $partial_modifiers = array(':', '^');
36
 
37
  public static $gen_delims = array(':', '/', '?', '#', '[', ']', '@');
38
  public static $gen_delims_pct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40');
39
  public static $sub_delims = array('!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=');
40
  public static $sub_delims_pct = array('%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D');
41
  public static $reserved;
42
  public static $reserved_pct;
43
 
44
  public function __construct($template) {
45
    self::$reserved = array_merge(self::$gen_delims, self::$sub_delims);
46
    self::$reserved_pct = array_merge(self::$gen_delims_pct, self::$sub_delims_pct);
47
    $this->template = $template;
48
  }
49
 
50
  public function expand($data) {
51
    // Modification to make this a bit more performant (since gettype is very slow)
52
    if (! is_array($data)) {
53
      $data = (array)$data;
54
    }
55
    /*
56
    // Original code, which uses a slow gettype() statement, kept in place for if the assumption that is_array always works here is incorrect
57
    switch (gettype($data)) {
58
      case "boolean":
59
      case "integer":
60
      case "double":
61
      case "string":
62
      case "object":
63
        $data = (array)$data;
64
        break;
65
    }
66
*/
67
 
68
    // Resolve template vars
69
    preg_match_all('/\{([^\}]*)\}/', $this->template, $em);
70
 
71
    foreach ($em[1] as $i => $bare_expression) {
72
      preg_match('/^([\+\;\?\/\.]{1})?(.*)$/', $bare_expression, $lm);
73
      $exp = new StdClass();
74
      $exp->expression = $em[0][$i];
75
      $exp->operator = $lm[1];
76
      $exp->variable_list = $lm[2];
77
      $exp->varspecs = explode(',', $exp->variable_list);
78
      $exp->vars = array();
79
      foreach ($exp->varspecs as $varspec) {
80
        preg_match('/^([a-zA-Z0-9_]+)([\*\+]{1})?([\:\^][0-9-]+)?(\=[^,]+)?$/', $varspec, $vm);
81
        $var = new StdClass();
82
        $var->name = $vm[1];
83
        $var->modifier = isset($vm[2]) && $vm[2] ? $vm[2] : null;
84
        $var->modifier = isset($vm[3]) && $vm[3] ? $vm[3] : $var->modifier;
85
        $var->default = isset($vm[4]) ? substr($vm[4], 1) : null;
86
        $exp->vars[] = $var;
87
      }
88
 
89
      // Add processing flags
90
      $exp->reserved = false;
91
      $exp->prefix = '';
92
      $exp->delimiter = ',';
93
      switch ($exp->operator) {
94
        case '+':
95
          $exp->reserved = 'true';
96
          break;
97
        case ';':
98
          $exp->prefix = ';';
99
          $exp->delimiter = ';';
100
          break;
101
        case '?':
102
          $exp->prefix = '?';
103
          $exp->delimiter = '&';
104
          break;
105
        case '/':
106
          $exp->prefix = '/';
107
          $exp->delimiter = '/';
108
          break;
109
        case '.':
110
          $exp->prefix = '.';
111
          $exp->delimiter = '.';
112
          break;
113
      }
114
      $expressions[] = $exp;
115
    }
116
 
117
    // Expansion
118
    $this->expansion = $this->template;
119
 
120
    foreach ($expressions as $exp) {
121
      $part = $exp->prefix;
122
      $exp->one_var_defined = false;
123
      foreach ($exp->vars as $var) {
124
        $val = '';
125
        if ($exp->one_var_defined && isset($data[$var->name])) {
126
          $part .= $exp->delimiter;
127
        }
128
        // Variable present
129
        if (isset($data[$var->name])) {
130
          $exp->one_var_defined = true;
131
          $var->data = $data[$var->name];
132
 
133
          $val = self::val_from_var($var, $exp);
134
 
135
        // Variable missing
136
        } else {
137
          if ($var->default) {
138
            $exp->one_var_defined = true;
139
            $val = $var->default;
140
          }
141
        }
142
        $part .= $val;
143
      }
144
      if (! $exp->one_var_defined) $part = '';
145
      $this->expansion = str_replace($exp->expression, $part, $this->expansion);
146
    }
147
 
148
    return $this->expansion;
149
  }
150
 
151
  private function val_from_var($var, $exp) {
152
    $val = '';
153
    if (is_array($var->data)) {
154
      $i = 0;
155
      if ($exp->operator == '?' && ! $var->modifier) {
156
        $val .= $var->name . '=';
157
      }
158
      foreach ($var->data as $k => $v) {
159
        $del = $var->modifier ? $exp->delimiter : ',';
160
        $ek = rawurlencode($k);
161
        $ev = rawurlencode($v);
162
 
163
        // Array
164
        if ($k !== $i) {
165
          if ($var->modifier == '+') {
166
            $val .= $var->name . '.';
167
          }
168
          if ($exp->operator == '?' && $var->modifier || $exp->operator == ';' && $var->modifier == '*' || $exp->operator == ';' && $var->modifier == '+') {
169
            $val .= $ek . '=';
170
          } else {
171
            $val .= $ek . $del;
172
          }
173
 
174
        // List
175
        } else {
176
          if ($var->modifier == '+') {
177
            if ($exp->operator == ';' && $var->modifier == '*' || $exp->operator == ';' && $var->modifier == '+' || $exp->operator == '?' && $var->modifier == '+') {
178
              $val .= $var->name . '=';
179
            } else {
180
              $val .= $var->name . '.';
181
            }
182
          }
183
        }
184
        $val .= $ev . $del;
185
        $i ++;
186
      }
187
      $val = trim($val, $del);
188
 
189
    // Strings, numbers, etc.
190
    } else {
191
      if ($exp->operator == '?') {
192
        $val = $var->name . (isset($var->data) ? '=' : '');
193
      } else if ($exp->operator == ';') {
194
        $val = $var->name . ($var->data ? '=' : '');
195
      }
196
      $val .= rawurlencode($var->data);
197
      if ($exp->operator == '+') {
198
        $val = str_replace(self::$reserved_pct, self::$reserved, $val);
199
      }
200
    }
201
    return $val;
202
  }
203
 
204
  public function match($uri) {}
205
 
206
  public function __toString() {
207
    return $this->template;
208
  }
209
}