made a copy
[atutor.git] / include / classes / UrlRewrite / UrlRewrite.class.php
1 <?php
2 /************************************************************************/
3 /* ATutor                                                                                                                               */
4 /************************************************************************/
5 /* Copyright (c) 2002-2008 by Greg Gay, Joel Kronenberg & Heidi Hazelton*/
6 /* Adaptive Technology Resource Centre / University of Toronto                  */
7 /* http://atutor.ca                                                                                                             */
8 /*                                                                                                                                              */
9 /* This program is free software. You can redistribute it and/or                */
10 /* modify it under the terms of the GNU General Public License                  */
11 /* as published by the Free Software Foundation.                                                */
12 /************************************************************************/
13 // $Id$
14
15 //Include all the classes for external rewrite rules
16 require_once('ForumsUrl.class.php');
17 require_once('ContentUrl.class.php');
18 require_once('FileStorageUrl.class.php');
19 require_once('TestsUrl.class.php');
20 require_once('GlossaryUrl.class.php');
21
22 /**
23 * UrlRewrite
24 * Class for rewriting pretty urls.
25 * @access       public
26 * @author       Harris Wong
27 * @package      UrlRewrite
28 */
29 class UrlRewrite  {
30         // local variables
31         var $path;              //the path of this script
32         var $filename;  //script name
33         var $query;             //the queries of the REQUEST
34         var $isEmpty;   //true if path, filename, and query are empty
35
36         // constructor
37         function UrlRewrite($path, $filename, $query) {
38                 if ($path=='' && $filename=='' && $query==''){
39                         $this->isEmpty = true;
40                 } else {
41                         $this->isEmpty = false;
42                 }
43                 $this->path = $path;
44                 $this->filename = $filename;
45                 $this->query = $query;
46         }
47
48         /** 
49          * Returns the link that points to this object as a page.
50          * @access public
51          */
52         function redirect(){
53                 //redirect to that url.
54                 return '/'.$this->getPage();
55         }
56
57         /** 
58          * Parser for the pathinfo, return an array with mapped key values similar to the querystring.
59          * @access      public
60          * @return      array   key=>value, where keys and values have the same meaning as the ones in the query strings.
61          */
62         function parsePrettyQuery(){
63                 global $_config;
64                 $result = array();
65
66                 //return empty array if query is empty
67                 if (empty($this->query)){
68                         return $result;
69                 }
70
71                 //if course_dir_name is disabled from admin. 
72                 if ($_config['pretty_url']==0){
73                         return $this->query;
74                 }
75
76                 //If the first char is /, cut it
77                 if (strpos($this->query, '/') == 0){
78                         $query_parts = explode('/', substr($this->query, 1));
79                 } else {
80                         $query_parts = explode('/', $this->query);
81                 }
82
83                 //dynamically create the array
84                 //assumption: pathinfo ALWAYS in the format of key1/value1/key2/value2/key3/value3/etc...
85                 foreach ($query_parts as $array_index=>$key_value){
86                         if($array_index%2 == 0 && $query_parts[$array_index]!=''){
87                                 $result[$key_value] = $query_parts[$array_index+1];
88                         }
89                 }
90                 return $result;
91         }
92
93
94         /**
95          * Parser for the querystrings url
96          * @access      public
97          * @param       string  querystring
98          * @return      array   an array of mapped keys and values like the querystrings.
99          *
100          * NOTE:        Stopped using this function since we've decided to dynamically create the URL. 
101          *                      See: parsePrettyQuery()
102          */
103         function parseQuery($query){
104                 //return empty array if query is empty
105                 if (empty($query)){
106                         return array();
107                 }
108
109                 parse_str($this->query, $result);
110                 return $result;
111         }
112
113
114         /**
115          * Construct the pretty url based on the given query.
116          * @access      public
117          * @param       string  the pathinfo query
118          * @return      string  pretty url
119          */
120         function constructPrettyUrl($query){
121                 global $_config; 
122                 $bookmark  = '';
123
124                 if (empty($query)){
125                         return '';
126                 }
127
128                 //Take out bookmark, and store it.
129                 if (($pos = strpos($query, '#'))!==FALSE){
130                         $bookmark = substr($query, $pos);
131                         $query = substr($query, 0, $pos);
132                 }
133
134                 //If this is already a pretty url,but without mod_apache rule
135                 //unwrap it and reconstruct
136                 if (is_array($query)){
137                         $new_query = '';
138                         foreach($query as $fk=>$fv){
139                                 if      (preg_match('/\.php/', $fv)==1){
140                                         continue;       //skip the php file
141                                 }
142
143                                 //check if this is part of the rule, if so,add it, o/w ignore
144                                 if (array_search($fv, $this->rule)!==FALSE){
145                                         $new_query .= $fv . '=' . $query[$fk+1] . SEP;
146                                 } elseif (preg_match('/([0-9]+)\.html/', $fv, $matches)==1){
147                                         $new_query .= 'page=' . $matches[1] . SEP;
148                                 }
149                         }
150                         $query = $new_query;    //done
151                 }
152
153                 //do not change query if pretty url is disabled
154                 if ($_config['pretty_url'] == 0){
155                         $pretty_url = $query;
156                 } else {
157                         $pretty_url = '';               //init url
158                         $query_parts = explode(SEP, $query);
159                         foreach ($query_parts as $index=>$attributes){
160                                 if(empty($attributes)){
161                                         //skip the ones that are empty.
162                                         continue;
163                                 }
164                                 list($key, $value) = preg_split('/\=/', $attributes, 2);
165                                 $pretty_url .= $key . '/' . $value .'/';
166                         }
167                 }
168
169                 //finally, append bookmark if not emptied
170                 if ($bookmark!=''){
171                         $pretty_url .= $bookmark;
172                 }
173
174                 return $pretty_url;
175         }
176
177
178         /**
179          * This function is used to convert the input URL to a pretty URL.
180          * @param       int             course id
181          * @param       string  normal URL, WITHOUT the <prototal>://<host>
182          * @return      pretty url
183          */
184         function convertToPrettyUrl($course_id, $url){
185                 global $_config, $db;
186                 $pretty_url = '';
187
188                 if (strpos($url, '?')!==FALSE){
189                         list($front, $end) = preg_split('/\?/', $url);
190                 } else {
191                         $front = $url;
192                         $end = '';
193                 }
194
195                 $front_array = explode('/', $front);
196
197                 //find out what kind of link this is, pretty url? relative url? or PHP_SELF url?
198                 $dir_deep        = substr_count(AT_INCLUDE_PATH, '..');
199                 $url_parts       = explode('/', $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']);
200                 $host_dir        = implode('/', array_slice($url_parts, 0, count($url_parts) - $dir_deep-1));
201                 //The link is a bounce link
202                 if(preg_match('/bounce.php\?course=([\d]+)$/', $url, $matches)==1){
203                         if (!empty($course_id)) {
204                                 $pretty_url = $course_id;               //course_id should be assigned by vitals depending on the system pref.
205                         } else {
206                                 $pretty_url = $matches[1];              //happens when course dir name is disabled
207                         }
208                 } elseif(in_array(AT_PRETTY_URL_HANDLER, $front_array)===TRUE){
209                         //The relative link is a pretty URL
210                         $front_result = array();
211                         //spit out the URL in between AT_PRETTY_URL_HANDLER to *.php
212                         //note, pretty url is defined to be AT_PRETTY_URL_HANDLER/course_slug/type/location/...
213                         //ie. AT_PRETTY_URL_HANDLER/1/forum/view.php/...
214                         while (($needle = array_search(AT_PRETTY_URL_HANDLER, $front_array)) !== FALSE){
215                                 $front_array = array_slice($front_array, $needle + 1);
216                         }
217                         $front_array = array_slice($front_array, $needle + 1);  //+2 because we want the entries after the course_slug
218
219                         //Handle url differently IF mod_rewrite is enabled, and if there are no query strings at the back,
220                         //then we will have to reuse the current pathinfo to reconstruct the query.
221                         if ($_config['apache_mod_rewrite'] > 0 && $end==''){
222                                 $end = $front_array;    //let the class handles it
223                         } 
224
225                         /* Overwrite pathinfo
226                          * ie. /go.php/1/forum/view.php/fid/1/pid/17/?fid=1&pid=17&page=5
227                          * In the above case, cut off the original pathinfo, and replace it with the new querystrings
228                          * If querystring is empty, then use the old one, ie. /go.php/1/forum/view.php/fid/1/pid/17/.
229                          */
230                         foreach($front_array as $fk=>$fv){
231                                 array_push($front_result, $fv);
232                                 if      (!empty($end) && preg_match('/\.php/', $fv)==1){
233                                         break;
234                                 }
235                         }
236                         $front = implode('/', $front_result);
237                 } elseif (strpos($front, $host_dir)!==FALSE){
238                         //Not a relative link, it contains the full PHP_SELF path.
239                         $front = substr($front, strlen($host_dir)+1);  //stripe off the slash after the host_dir as well
240                 } elseif ($course_id == ''){
241                         //if this is my start page
242                         return $url;
243                 }
244                 //Turn querystring to pretty URL
245                 if ($pretty_url==''){
246                         //Get the original course id back
247                         $sql    = "SELECT course_id FROM ".TABLE_PREFIX."courses WHERE course_dir_name='$course_id'";
248                         $result = mysql_query($sql, $db);
249                         $row = mysql_fetch_assoc($result);
250                         $course_orig = $course_id;
251
252                         if ($row['course_id']!=''){
253                                 $course_orig = $row['course_id'];
254                         } 
255
256                         //Add course id in if both course_id or course_dir_name are not there
257                         if (preg_match('/^\/?('.$course_id.'|'.$course_orig.')\//', $front)==0){
258                                 $pretty_url = $course_id.'/';
259                         }
260
261                         //check if there are any rules overwriting the original rules
262                         //TODO: have a better way to do this
263                         //              extend modularity into this.
264                         $obj =& $this;  //default
265                         //Overwrite the UrlRewrite obj if there are any private rules
266                         if ($_config['apache_mod_rewrite'] > 0){
267                                 //take out '.php' if any exists. (Apply only to non-modules, otherwise it might cause problems)
268                                 if (preg_match('/^mods/', $front)!=1){
269                                         if ($end=='' && preg_match('/index\.php$/', $front)==1){
270                                                 $pretty_url .= preg_replace('/index.php/', '', $front);
271                                         } else {
272                                                 $pretty_url .= preg_replace('/\.php/', '', $front);
273                                         }
274                                 } else {
275                                         $pretty_url .= $front;
276                                 }
277
278                                 if (preg_match('/forum\/(index|view|list)\.php/', $front)==1) {
279                                         $pretty_url = $course_id.'/forum';
280                                         $obj = new ForumsUrl();
281                                 } elseif (preg_match('/(content\.php)(\/cid(\/\d+))?/', $front, $matches)==1){
282                                         $pretty_url = $course_id.'/content';
283                                         //if there are other pretty url queries at the back, append it
284                                         //Note: this is to fix the hopping content problem between diff courses
285                                         if (isset($matches[3]) && $matches[3] != ''){
286                                                 $pretty_url .= $matches[3];
287                                         }
288                                         $obj = new ContentUrl();
289                                 } elseif (preg_match('/file_storage\/((index|revisions|comments)\.php)?/', $front, $matches)==1){
290                                         $pretty_url = $course_id.'/file_storage';
291                                         $obj = new FileStorageUrl($matches[1]);
292                                 } elseif (preg_match('/tools\/test_intro\.php/', $front)==1){
293                                         $pretty_url = $course_id.'/tests_surveys';
294                                         $obj = new TestsUrl();
295                                 } elseif (preg_match('/glossary\/index\.php/', $front)==1){
296                                         $pretty_url = $course_id.'/glossary';
297                                         $obj = new GlossaryUrl();
298                                 }
299                         } else {
300                                 $pretty_url .= $front;
301                         }
302
303                         if ($end != ''){
304                                 //if pretty url is turned off, use '?' to separate the querystring.
305                                 ($_config['pretty_url'] == 0)? $qs_sep = '?': $qs_sep = '/';
306                                  $pretty_url .= $qs_sep.$obj->constructPrettyUrl($end);
307                         }
308                 }
309
310                 //if mod_rewrite is switched on, defined in constants.inc.php
311                 if ($_config['apache_mod_rewrite'] > 0){
312                         return $pretty_url;
313                 }
314                 return AT_PRETTY_URL_HANDLER.'/'.$pretty_url;
315         }
316
317
318         /**
319          * Return the paths where this script is
320          */
321         function getPath(){
322                 if ($this->path != ''){
323                         return substr($this->path, 1).'/';
324                 }
325                 return '';
326         }
327
328         /**
329          * Return the script name
330          */
331         function getFileName(){
332                 return $this->filename;
333         }
334
335         /**
336          * 
337          */
338         function getPage(){
339                 return $this->getPath().$this->getFileName();
340         }
341
342         /**
343          * Return true if path, filename, and query are empty.
344          */
345         function isEmpty(){
346                 return $this->isEmpty;
347         }
348 }
349 ?>