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