Dotclear

source: inc/public/lib.urlhandlers.php @ 876:83427286bd34

Revision 876:83427286bd34, 12.6 KB checked in by Dsls <dsls@…>, 13 years ago (diff)

New "plugin" urlHandler. Enables plugins to expose public side files, by adding them to <plugin>/public directory.

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2011 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) { return; }
13
14class dcUrlHandlers extends urlHandler
15{
16     public $args;
17     
18     public function getURLFor($type,$value='') {
19          $core =& $GLOBALS['core'];
20          $url = $core->callBehavior("publicGetURLFor",$type,$value);
21          if (!$url) {
22               $url = $this->getBase($type);
23               if ($value) {
24                    if ($url) {
25                         $url .= '/';
26                    }
27                    $url .= $value;
28               }
29          }
30          return $url;
31     }
32     
33     public function register($type,$url,$representation,$handler)
34     {
35          $core =& $GLOBALS['core'];
36          $t = new ArrayObject(array($type,$url,$representation,$handler));
37          $core->callBehavior("publicRegisterURL",$t);
38          parent::register($t[0],$t[1],$t[2],$t[3]);
39     }
40     
41     public static function p404()
42     {
43          throw new Exception ("Page not found",404);
44     }
45     
46     public static function default404($args,$type,$e)
47     {
48          if ($e->getCode() != 404) {
49               throw $e;
50          }
51          $_ctx =& $GLOBALS['_ctx'];
52          $core = $GLOBALS['core'];
53         
54          header('Content-Type: text/html; charset=UTF-8');
55          http::head(404,'Not Found');
56          $core->url->type = '404';
57          $_ctx->current_tpl = '404.html';
58          $_ctx->content_type = 'text/html';
59         
60          echo $core->tpl->getData($_ctx->current_tpl);
61         
62          # --BEHAVIOR-- publicAfterDocument
63          $core->callBehavior('publicAfterDocument',$core);
64          exit;
65     }
66     
67     protected static function getPageNumber(&$args)
68     {
69          if (preg_match('#(^|/)page/([0-9]+)$#',$args,$m)) {
70               $n = (integer) $m[2];
71               if ($n > 0) {
72                    $args = preg_replace('#(^|/)page/([0-9]+)$#','',$args);
73                    return $n;
74               }
75          }
76         
77          return false;
78     }
79     
80     protected static function serveDocument($tpl,$content_type='text/html',$http_cache=true,$http_etag=true)
81     {
82          $_ctx =& $GLOBALS['_ctx'];
83          $core =& $GLOBALS['core'];
84         
85          if ($_ctx->nb_entry_per_page === null) {
86               $_ctx->nb_entry_per_page = $core->blog->settings->system->nb_post_per_page;
87          }
88         
89          $tpl_file = $core->tpl->getFilePath($tpl);
90         
91          if (!$tpl_file) {
92               throw new Exception('Unable to find template ');
93          }
94         
95          $result = new ArrayObject;
96         
97          $_ctx->current_tpl = $tpl;
98          $_ctx->content_type = $content_type;
99          $_ctx->http_cache = $http_cache;
100          $_ctx->http_etag = $http_etag;
101          $core->callBehavior('urlHandlerBeforeGetData',$_ctx);
102         
103          if ($_ctx->http_cache) {
104               $GLOBALS['mod_files'][] = $tpl_file;
105               http::cache($GLOBALS['mod_files'],$GLOBALS['mod_ts']);
106          }
107
108          header('Content-Type: '.$_ctx->content_type.'; charset=UTF-8');
109          $result['content'] = $core->tpl->getData($_ctx->current_tpl);
110          $result['content_type'] = $_ctx->content_type;
111          $result['tpl'] = $_ctx->current_tpl;
112          $result['blogupddt'] = $core->blog->upddt;
113         
114          # --BEHAVIOR-- urlHandlerServeDocument
115          $core->callBehavior('urlHandlerServeDocument',$result);
116         
117          if ($_ctx->http_cache && $_ctx->http_etag) {
118               http::etag($result['content'],http::getSelfURI());
119          }
120          echo $result['content'];
121     }
122     
123     public function getDocument()
124     {
125          $core =& $GLOBALS['core'];
126         
127          $type = $args = '';
128         
129          if ($this->mode == 'path_info')
130          {
131               $part = substr($_SERVER['PATH_INFO'],1);
132          }
133          else
134          {
135               $part = '';
136               
137               $qs = $this->parseQueryString();
138               
139               # Recreates some _GET and _REQUEST pairs
140               if (!empty($qs))
141               {
142                    foreach ($_GET as $k => $v) {
143                         if (isset($_REQUEST[$k])) {
144                              unset($_REQUEST[$k]);
145                         }
146                    }
147                    $_GET = $qs;
148                    $_REQUEST = array_merge($qs,$_REQUEST);
149                   
150                    list($k,$v) = each($qs);
151                    if ($v === null) {
152                         $part = $k;
153                         unset($_GET[$k]);
154                         unset($_REQUEST[$k]);
155                    }
156               }
157          }
158         
159          $_SERVER['URL_REQUEST_PART'] = $part;
160         
161          $this->getArgs($part,$type,$this->args);
162         
163          # --BEHAVIOR-- urlHandlerGetArgsDocument
164          $core->callBehavior('urlHandlerGetArgsDocument',$this);
165         
166          if (!$type)
167          {
168               $this->type = 'default';
169               $this->callDefaultHandler($this->args);
170          }
171          else
172          {
173               $this->type = $type;
174               $this->callHandler($type,$this->args);
175          }
176     }
177     
178     public static function home($args)
179     {
180          $n = self::getPageNumber($args);
181         
182          if ($args && !$n)
183          {
184               # "Then specified URL went unrecognized by all URL handlers and
185               # defaults to the home page, but is not a page number.
186               self::p404();
187          }
188          else
189          {
190               $core =& $GLOBALS['core'];
191               
192               if ($n) {
193                    $GLOBALS['_page_number'] = $n;
194                    $core->url->type = $n > 1 ? 'default-page' : 'default';
195               }
196               
197               if (empty($_GET['q'])) {
198                    self::serveDocument('home.html');
199                    $core->blog->publishScheduledEntries();
200               } else {
201                    self::search();
202               }
203          }
204     }
205     
206     public static function search()
207     {
208          $_ctx =& $GLOBALS['_ctx'];
209          $core =& $GLOBALS['core'];
210         
211          $core->url->type='search';
212         
213          $GLOBALS['_search'] = !empty($_GET['q']) ? rawurldecode($_GET['q']) : '';
214          if ($GLOBALS['_search']) {
215               $params = new ArrayObject(array('search' => $GLOBALS['_search']));
216               $core->callBehavior('publicBeforeSearchCount',$params);
217               $GLOBALS['_search_count'] = $core->blog->getPosts($params,true)->f(0);
218          }
219         
220          self::serveDocument('search.html');
221     }
222     
223     public static function lang($args)
224     {
225          $_ctx =& $GLOBALS['_ctx'];
226          $core =& $GLOBALS['core'];
227         
228          $n = self::getPageNumber($args);
229          $params = new ArrayObject(array(
230               'lang' => $args));
231         
232          $core->callBehavior('publicLangBeforeGetLangs',$params,$args);
233         
234          $_ctx->langs = $core->blog->getLangs($params);
235         
236          if ($_ctx->langs->isEmpty()) {
237               # The specified language does not exist.
238               self::p404();
239          }
240          else
241          {
242               if ($n) {
243                    $GLOBALS['_page_number'] = $n;
244               }
245               $_ctx->cur_lang = $args;
246               self::home(null);
247          }
248     }
249     
250     public static function archive($args)
251     {
252          $_ctx =& $GLOBALS['_ctx'];
253          $core =& $GLOBALS['core'];
254         
255          $year = $month = $cat_url = null;
256          # Nothing or year and month
257          if ($args == '')
258          {
259               self::serveDocument('archive.html');
260          }
261          elseif (preg_match('|^/([0-9]{4})/([0-9]{2})$|',$args,$m))
262          {
263               $params = new ArrayObject(array(
264                    'year' => $m[1],
265                    'month' => $m[2],
266                    'type' => 'month'));
267               
268               $core->callBehavior('publicArchiveBeforeGetDates',$params,$args);
269               
270               $_ctx->archives = $core->blog->getDates($params);
271               
272               if ($_ctx->archives->isEmpty()) {
273                    # There is no entries for the specified period.
274                    self::p404();
275               }
276               else
277               {
278                    self::serveDocument('archive_month.html');
279               }
280          }
281          else {
282               # The specified URL is not a date.
283               self::p404();
284          }
285     }
286     
287     public static function post($args)
288     {
289          if ($args == '') {
290               # No entry was specified.
291               self::p404();
292          }
293          else
294          {
295               $_ctx =& $GLOBALS['_ctx'];
296               $core =& $GLOBALS['core'];
297               
298               $core->blog->withoutPassword(false);
299               
300               $params = new ArrayObject(array(
301                    'post_url' => $args));
302               
303               $core->callBehavior('publicPostBeforeGetPosts',$params,$args);
304
305               $_ctx->posts = $core->blog->getPosts($params);
306               
307               $core->blog->withoutPassword(true);
308               
309               if ($_ctx->posts->isEmpty())
310               {
311                    # The specified entry does not exist.
312                    self::p404();
313               }
314               else
315               {
316                    $post_id = $_ctx->posts->post_id;
317                    $post_password = $_ctx->posts->post_password;
318                   
319                    # Password protected entry
320                    if ($post_password != '' && !$_ctx->preview)
321                    {
322                         # Get passwords cookie
323                         if (isset($_COOKIE['dc_passwd'])) {
324                              $pwd_cookie = unserialize($_COOKIE['dc_passwd']);
325                         } else {
326                              $pwd_cookie = array();
327                         }
328                         
329                         # Check for match
330                         if ((!empty($_POST['password']) && $_POST['password'] == $post_password)
331                         || (isset($pwd_cookie[$post_id]) && $pwd_cookie[$post_id] == $post_password))
332                         {
333                              $pwd_cookie[$post_id] = $post_password;
334                              setcookie('dc_passwd',serialize($pwd_cookie),0,'/');
335                         }
336                         else
337                         {
338                              self::serveDocument('password-form.html','text/html',false);
339                              return;
340                         }
341                    }
342                   
343                    # The entry
344                    self::serveDocument('post.html');
345               }
346          }
347     }
348     
349     public static function preview($args)
350     {
351          $core = $GLOBALS['core'];
352          $_ctx = $GLOBALS['_ctx'];
353         
354          if (!preg_match('#^(.+?)/([0-9a-z]{40})/(.+?)$#',$args,$m)) {
355               # The specified Preview URL is malformed.
356               self::p404();
357          }
358          else
359          {
360               $user_id = $m[1];
361               $user_key = $m[2];
362               $post_url = $m[3];
363               if (!$core->auth->checkUser($user_id,null,$user_key)) {
364                    # The user has no access to the entry.
365                    self::p404();
366               }
367               else
368               {
369                    $_ctx->preview = true;
370                    self::post($post_url);
371               }
372          }
373     }
374     
375     public static function feed($args)
376     {
377          $type = null;
378          $cat_url = false;
379          $post_id = null;
380          $subtitle = '';
381         
382          $mime = 'application/xml';
383         
384          $_ctx =& $GLOBALS['_ctx'];
385          $core =& $GLOBALS['core'];
386         
387          if (preg_match('!^([a-z]{2}(-[a-z]{2})?)/(.*)$!',$args,$m)) {
388               $params = new ArrayObject(array('lang' => $m[1]));
389               
390               $args = $m[3];
391               
392               $core->callBehavior('publicFeedBeforeGetLangs',$params,$args);
393               
394               $_ctx->langs = $core->blog->getLangs($params);
395               
396               if ($_ctx->langs->isEmpty()) {
397                    # The specified language does not exist.
398                    self::p404();
399                    return;
400               } else {
401                    $_ctx->cur_lang = $m[1];
402               }
403          }
404         
405          if (preg_match('#^rss2/xslt$#',$args,$m))
406          {
407               # RSS XSLT stylesheet
408               self::serveDocument('rss2.xsl','text/xml');
409               return;
410          }
411          elseif (preg_match('#^(?:category/(.+)/)?(atom|rss2)(/comments)?$#',$args,$m))
412          {
413               # All posts or comments feed
414               $type = $m[2];
415               if (!empty($m[1])) {
416                    $cat_url = $m[1];
417               }
418          }
419          else
420          {
421               # The specified Feed URL is malformed.
422               self::p404();
423               return;
424          }
425         
426          if ($cat_url)
427          {
428               $params = new ArrayObject(array(
429                    'cat_url' => $cat_url,
430                    'post_type' => 'post'));
431               
432               $core->callBehavior('publicFeedBeforeGetCategories',$params,$args);
433               
434               $_ctx->categories = $core->blog->getCategories($params);
435               
436               if ($_ctx->categories->isEmpty()) {
437                    # The specified category does no exist.
438                    self::p404();
439                    return;
440               }
441               
442               $subtitle = ' - '.$_ctx->categories->cat_title;
443          }
444          elseif ($post_id)
445          {
446               $params = new ArrayObject(array(
447                    'post_id' => $post_id,
448                    'post_type' => ''));
449                   
450               $core->callBehavior('publicFeedBeforeGetPosts',$params,$args);
451               
452               $_ctx->posts = $core->blog->getPosts($params);
453               
454               if ($_ctx->posts->isEmpty()) {
455                    # The specified post does not exist.
456                    self::p404();
457                    return;
458               }
459               
460               $subtitle = ' - '.$_ctx->posts->post_title;
461          }
462         
463          $tpl = $type;
464          $_ctx->nb_entry_per_page = $core->blog->settings->system->nb_post_per_feed;
465          $_ctx->short_feed_items = $core->blog->settings->system->short_feed_items;
466          $tpl .= '.xml';
467         
468          if ($type == 'atom') {
469               $mime = 'application/atom+xml';
470          }
471         
472          $_ctx->feed_subtitle = $subtitle;
473         
474          header('X-Robots-Tag: '.context::robotsPolicy($core->blog->settings->system->robots_policy,''));
475          self::serveDocument($tpl,$mime);
476          if (!$comments && !$cat_url) {
477               $core->blog->publishScheduledEntries();
478          }
479     }
480     
481     public static function rsd($args)
482     {
483          $core =& $GLOBALS['core'];
484          http::cache($GLOBALS['mod_files'],$GLOBALS['mod_ts']);
485         
486          header('Content-Type: text/xml; charset=UTF-8');
487          echo
488          '<?xml version="1.0" encoding="UTF-8"?>'."\n".
489          '<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">'."\n".
490          "<service>\n".
491          "  <engineName>Dotclear</engineName>\n".
492          "  <engineLink>http://www.dotclear.org/</engineLink>\n".
493          '  <homePageLink>'.html::escapeHTML($core->blog->url)."</homePageLink>\n";
494         
495          if ($core->blog->settings->system->enable_xmlrpc)
496          {
497               $u = sprintf(DC_XMLRPC_URL,$core->blog->url,$core->blog->id);
498               
499               echo
500               "  <apis>\n".
501               '    <api name="WordPress" blogID="1" preferred="true" apiLink="'.$u.'"/>'."\n".
502               '    <api name="Movable Type" blogID="1" preferred="false" apiLink="'.$u.'"/>'."\n".
503               '    <api name="MetaWeblog" blogID="1" preferred="false" apiLink="'.$u.'"/>'."\n".
504               '    <api name="Blogger" blogID="1" preferred="false" apiLink="'.$u.'"/>'."\n".
505               "  </apis>\n";
506          }
507         
508          echo
509          "</service>\n".
510          "</rsd>\n";
511     }
512     
513     public static function xmlrpc($args)
514     {
515          $core =& $GLOBALS['core'];
516          $blog_id = preg_replace('#^([^/]*).*#','$1',$args);
517          $server = new dcXmlRpc($core,$blog_id);
518          $server->serve();
519     }
520     
521     public static function pluginInclude($args)
522     {
523          preg_match('#^([^/]+)/(.+)$#',$args,$m);
524          if (count($m) < 3) {
525               self::p404();
526               exit;
527          }
528          $p = $m[1];
529          $file = $m[2];
530          $allow_types = array('png','jpg','jpeg','gif','css','js','swf');
531          $pf = DC_PLUGINS_ROOT.'/'.path::clean($p.'/public/'.$file);
532          if (!$GLOBALS['core']->plugins->moduleExists($p) ||
533               $pf === false || !is_file($pf) || !is_readable($pf)) {
534               self::p404();
535               exit;
536          }
537
538          if (!in_array(files::getExtension($pf),$allow_types)) {
539               header('Content-Type: text/plain');
540               http::head(404,'Not Found');
541               exit;
542          }
543
544          http::$cache_max_age = 7200;
545          http::cache(array_merge(array($pf),get_included_files()));
546
547          header('Content-Type: '.files::getMimeType($pf));
548          header('Content-Length: '.filesize($pf));
549          readfile($pf);
550          exit;
551
552     }
553}
554?>
Note: See TracBrowser for help on using the repository browser.

Sites map