PageRenderTime 71ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/flatpress/fp-plugins/prettyurls/plugin.prettyurls.php

https://bitbucket.org/alexandrul/flatpress
PHP | 644 lines | 376 code | 201 blank | 67 comment | 79 complexity | 81ef050970cd054e2c28e038496d62f5 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, MIT
  1. <?php
  2. /*
  3. Plugin Name: PrettyURLs
  4. Plugin URI: http://flatpress.nowherland.it/
  5. Description: Url prettifier (powered by htaccess)
  6. Author: NoWhereMan (E.Vacchi)
  7. Version: 3.0
  8. Author URI: http://www.nowhereland.it
  9. */
  10. /**
  11. * Place where the index is stored
  12. */
  13. define('PRETTYURLS_TITLES', true);
  14. define('PRETTYURLS_PATHINFO', !file_exists(ABS_PATH . '.htaccess'));
  15. define('PRETTYURLS_CACHE', CACHE_DIR . '%%prettyurls-index.tmp');
  16. define('PRETTYURLS_CATS', CACHE_DIR . '%%prettyurls-cats.tmp');
  17. /**
  18. * File existance check
  19. */
  20. # memo
  21. # register_plugin_setup('plugin_id', 'setup_func');
  22. function plugin_prettyurls_setup() {
  23. if (file_exists(ABS_PATH . '.htaccess'))
  24. return 1;
  25. if (!is_writable(ABS_PATH)) {
  26. return -2;
  27. }
  28. return 1;
  29. }
  30. class Plugin_PrettyURLs {
  31. var $index = array();
  32. var $status = 0;
  33. var $date_handled = false;
  34. var $categories = null;
  35. var $fp_params;
  36. function categories($force=true) {
  37. if ($this->categories)
  38. return;
  39. if ($force || !file_exists(PRETTYURLS_CATS)) {
  40. $d = entry_categories_get('defs');
  41. $list = array();
  42. foreach ($d as $k=>$v) {
  43. $list[$k] = sanitize_title($v);
  44. }
  45. io_write_file(PRETTYURLS_CATS, serialize($list));
  46. } else {
  47. $f = io_load_file(PRETTYURLS_CATS);
  48. $list = unserialize($f);
  49. }
  50. $this->categories = $list;
  51. }
  52. function md5($id, $title) {
  53. $date = date_from_id($id);
  54. return md5($date['y'].$date['m'].$date['d'].$title);
  55. }
  56. function permalink($str, $id) {
  57. global $fpdb, $post;
  58. if (PRETTYURLS_TITLES)
  59. $title = sanitize_title($post['subject']);
  60. else
  61. $title = $id;
  62. $date = date_from_id($id);
  63. // yeah, hackish, I know...
  64. return $this->baseurl . "20{$date['y']}/{$date['m']}/{$date['d']}/$title/";
  65. }
  66. function commentlink($str, $id) {
  67. $link = $this->permalink($str, $id);
  68. return $link . "comments/";
  69. }
  70. function feedlink($str, $type) {
  71. return $this->baseurl . "feed/{$type}/";
  72. }
  73. function commentsfeedlink($str, $type, $id) {
  74. $link = $this->commentlink($str, $id);
  75. return $link . "feed/{$type}/";
  76. }
  77. function staticlink($str, $id) {
  78. return $this->baseurl . "$id/";
  79. }
  80. function categorylink($str, $catid) {
  81. if (PRETTYURLS_TITLES) {
  82. if (@$this->categories[$catid])
  83. return $this->baseurl . "category/{$this->categories[$catid]}/";
  84. else return $str;
  85. } else {
  86. return $this->baseurl . "category/{$catid}/";
  87. }
  88. }
  89. function yearlink($str, $y) {
  90. return $this->baseurl . "20$y/";
  91. }
  92. function monthlink($str, $y, $m) {
  93. return $this->yearlink($str, $y) . "$m/";
  94. }
  95. function daylink($str, $y, $m, $d) {
  96. return $this->monthlink($str, $y, $m) . "$d/";
  97. }
  98. function cache_create() {
  99. $this->index = array();
  100. /*
  101. $o =& entry_init();
  102. $entries = $o->getList();
  103. */
  104. $o = new FPDB_Query(array('start'=>0,'count'=>-1,'fullparse'=>false), null);
  105. #foreach ($entries as $id => $contents) {
  106. while ($o->hasMore()) {
  107. list($id, $contents) = $o->getEntry();
  108. $date = date_from_id($id);
  109. echo $contents['subject'], "\n";
  110. $md5 = md5(sanitize_title($contents['subject']));
  111. $this->index[$date['y']][$date['m']][$date['d']][$md5] = $id;
  112. }
  113. #}
  114. $this->cache_save();
  115. io_write_file(PRETTYURLS_CACHE, 'dummy');
  116. }
  117. function handle_categories($matches) {
  118. if (!$this->categories)
  119. return;
  120. if (PRETTYURLS_TITLES) {
  121. if ($c = array_search($matches[1], $this->categories))
  122. $this->fp_params['cat'] = $c;
  123. else return $matches[0];
  124. } else {
  125. $this->fp_params['cat'] = $matches[1];
  126. }
  127. }
  128. /*
  129. named matches are not supported here
  130. */
  131. function handle_date($matches) {
  132. $this->fp_params['y'] = $matches[1];
  133. if (isset($matches[3])) $this->fp_params['m'] = $matches[3] ;
  134. if (isset($matches[5])) $this->fp_params['d'] = $matches[5];
  135. $this->date_handled = true;
  136. }
  137. function handle_static($matches) {
  138. $this->fp_params['page'] = $matches[1];
  139. $this->status = 2;
  140. }
  141. function handle_entry($matches) {
  142. if (PRETTYURLS_TITLES) {
  143. #isset($this->index[
  144. if ($this->cache_get($this->fp_params['y'],$this->fp_params['m'], $this->fp_params['d'], md5($matches[1]))) {
  145. $this->fp_params['entry'] = $this->index[$this->fp_params['y']][$this->fp_params['m']][$this->fp_params['d']][md5($matches[1])];
  146. } else {
  147. // a bit hackish: we make up a fake url when there is no match,
  148. // so that at the higher level the system will 404...
  149. $this->fp_params['entry'] = 'a';
  150. }
  151. } else {
  152. $this->fp_params['entry'] = $matches[1];
  153. }
  154. }
  155. function handle_page($matches) {
  156. $this->fp_params['paged'] = $matches[1];
  157. $this->status = 2;
  158. }
  159. function handle_comment($matches) {
  160. $this->fp_params['comments'] = true;
  161. }
  162. function handle_feed($matches) {
  163. $this->fp_params['feed'] = isset($matches[2])? $matches[2]:'rss2';
  164. }
  165. function get_url() {
  166. $baseurl = BLOG_BASEURL;
  167. $opt = plugin_getoptions('prettyurls', 'mode');
  168. $url = substr($_SERVER['REQUEST_URI'], strlen(BLOG_ROOT)-1);
  169. switch($opt) {
  170. case null:
  171. case 0:
  172. $opt = file_exists(ABS_PATH . '.htaccess') ? 3 : 1;
  173. case 1:
  174. $baseurl .= 'index.php/';
  175. $url = $_SERVER['PATH_INFO'];
  176. break;
  177. case 2:
  178. $baseurl .= '?u=/';
  179. $url = @$_GET['u'];
  180. /* case 3: do nothing, it's BLOG_BASEURL */
  181. }
  182. $this->baseurl = $baseurl;
  183. $this->mode = $opt;
  184. return $url;
  185. }
  186. /*
  187. * here is where the real work is done.
  188. *
  189. * First we load the cache if exists;
  190. *
  191. * We check then if the GET request contains a 'title'
  192. * if so, we'll need date and time to construct the md5 sum
  193. * with which we index the cache array
  194. *
  195. * If that entry exists, we set $_GET['entry'] to that ID,
  196. * so that FlatPress can find it where it is expected
  197. *
  198. */
  199. function cache_init() {
  200. global $fp_params;
  201. $this->fp_params =& $fp_params;
  202. $url = $this->get_url();
  203. if (PRETTYURLS_TITLES) {
  204. #if ($f = io_load_file(PRETTYURLS_CACHE))
  205. $this->index = array(); #unserialize($f);
  206. if (!file_exists(PRETTYURLS_CACHE))
  207. $this->cache_create();
  208. $this->categories(false);
  209. }
  210. if (!defined('MOD_INDEX'))
  211. return;
  212. // # this is not working if you reach flatpress via symlink
  213. // # unless you don't edit manually defaults.php
  214. // if (strpos($_SERVER['REQUEST_URI'], BLOG_ROOT)!==false) {
  215. // $url = $_SERVER['REQUEST_URI'];
  216. // $del = BLOG_ROOT;
  217. // if (strpos($url, 'index.php')!==false)
  218. // $del = $del . 'index.php/';
  219. // $url = substr($url, strlen($del)-1);
  220. // }
  221. // removes querystrings
  222. if (false !== $i = strpos($url, '?'))
  223. $url = substr($url, 0, $i);
  224. // removes anchors
  225. if (false !== $i = strpos($url, '#'))
  226. $url = substr($url, 0, $i);
  227. if (strrpos($url, '/') != (strlen($url)-1)) {
  228. $url .= '/';
  229. }
  230. if ($url=='/')
  231. return;
  232. //date
  233. $url = preg_replace_callback(
  234. '!^/[0-9]{2}(?P<y>[0-9]{2})(/(?P<m>[0-9]{2})(/(?P<d>[0-9]{2}))?)?!',
  235. array(&$this, 'handle_date'),
  236. $url
  237. );
  238. if (!$this->date_handled){
  239. // static page
  240. $url = preg_replace_callback('|^/([a-zA-Z0-9_-]+)/$|', array(&$this, 'handle_static'), $url);
  241. if ($this->status == 2)
  242. return $this->check_url($url);
  243. }
  244. $url = preg_replace_callback('{category/([^/]+)/}', array(&$this, 'handle_categories'), $url);
  245. $url = preg_replace_callback('|page/([0-9]+)/$|', array(&$this, 'handle_page'), $url);
  246. if ($this->status == 2)
  247. return $this->check_url($url);
  248. if ($this->date_handled){
  249. $url = preg_replace_callback('|^/([^/]+)|', array(&$this, 'handle_entry'), $url);
  250. // if status = 2
  251. /*
  252. utils_error(404);
  253. */
  254. $url = preg_replace_callback('|^/comments|', array(&$this, 'handle_comment'), $url);
  255. }
  256. $url = preg_replace_callback('|^/feed(/([^/]*))?|', array(&$this, 'handle_feed'), $url);
  257. $this->check_url($url);
  258. }
  259. function check_url($url) {
  260. if (!empty($url) && $url != '/') {
  261. $this->fp_params = array('entry'=>'entry000000-000000');
  262. $url = apply_filters('prettyurls_unhandled_url', $url);
  263. }
  264. }
  265. function cache_delete_elem($id, $date) {
  266. # is this a title change?
  267. if (false !== ($ids = $this->cache_get( $date['y'] , $date['m'] , $date['d'] )))
  268. $hash = array_search($id, $ids);
  269. else
  270. return;
  271. if ($hash) {
  272. unset($this->index[ $date['y'] ] [ $date['m'] ][ $date['d'] ][ $hash ]);
  273. if (empty($this->index[ $date['y'] ] [ $date['m'] ][ $date['d'] ])) {
  274. unset($this->index[ $date['y'] ] [ $date['m'] ][ $date['d'] ]);
  275. if (empty($this->index[ $date['y'] ] [ $date['m'] ])) {
  276. unset($this->index[ $date['y'] ] [ $date['m'] ]);
  277. if (empty($this->index[ $date['y'] ])) {
  278. unset($this->index[ $date['y'] ]);
  279. }
  280. }
  281. }
  282. }
  283. $this->cache_save();
  284. }
  285. function cache_add($id, $arr) {
  286. $date = date_from_id($id);
  287. $title = sanitize_title($arr['subject']);
  288. $this->cache_delete_elem($id, $date);
  289. $this->index[ $date['y'] ] [ $date['m'] ][ $date['d'] ][ md5($title) ] = $id;
  290. $this->cache_save();
  291. return true;
  292. }
  293. function cache_get($y,$m,$d=null,$h=null) {
  294. if (!isset($this->index[$y][$m])) {
  295. $s = @io_load_file(PRETTYURLS_CACHE.$y.$m);
  296. $this->index[$y][$m] = $s? unserialize($s) : false;
  297. }
  298. if (is_null($d))
  299. return $this->index[$y][$m];
  300. if (is_null($h))
  301. return isset($this->index[$y][$m][$d])? $this->index[$y][$m][$d] : false;
  302. if (isset($this->index[$y][$m][$d]))
  303. return isset($this->index[$y][$m][$d][$h]);
  304. else
  305. return false;
  306. }
  307. function cache_delete($id) {
  308. $date = date_from_id($id);
  309. $this->cache_delete_elem($id, $date);
  310. $this->cache_save();
  311. }
  312. function cache_save() {
  313. if ($this->index) {
  314. foreach ($this->index as $year => $months) {
  315. foreach ($months as $month => $days)
  316. io_write_file(PRETTYURLS_CACHE.$year.$month, serialize($days));
  317. }
  318. }
  319. return true;
  320. }
  321. function nextprevlink($nextprev, $v) {
  322. global $fpdb;
  323. $q =& $fpdb->getQuery();
  324. list($caption, $id) = call_user_func(array(&$q, 'get'.$nextprev));
  325. if (!$id)
  326. return array();
  327. if ($q->single) {
  328. $date = date_from_id($id);
  329. if (PRETTYURLS_TITLES)
  330. $title = sanitize_title($caption);
  331. else $title = $id;
  332. $url = $this->baseurl . "20{$date['y']}/{$date['m']}/{$date['d']}/$title/";
  333. if ($v>0)
  334. $caption = $caption . ' &raquo; ';
  335. else
  336. $caption = ' &laquo; ' . $caption;
  337. return array($caption,$url);
  338. }
  339. // else, we build a complete url
  340. /* todo: clean up this mess... which means cleaning up the mess above. oh, my! */
  341. $l = $this->baseurl ;
  342. if ( ( is_numeric($cid = @$this->fp_params['category']) ) ||
  343. is_numeric($cid = @$this->fp_params['cat']) )
  344. $l = $this->categorylink($l, $cid);
  345. if (isset($this->fp_params['y']) && $this->fp_params['y']) {
  346. $l .= '20'. $this->fp_params['y'] . '/';
  347. if (isset($this->fp_params['m']) && $this->fp_params['m']) {
  348. $l .= $this->fp_params['m'] . '/';
  349. if (isset($this->fp_params['d']) && $this->fp_params['d'])
  350. $l .= $this->fp_params['d'] . '/';
  351. }
  352. }
  353. $page = 1;
  354. if (isset($this->fp_params['paged']) && $this->fp_params['paged']>1) $page = $this->fp_params['paged'];
  355. $page += $v;
  356. if ($page > 0) {
  357. $l .= 'page/' . $page . '/';
  358. }
  359. return array($caption,$l);
  360. }
  361. }
  362. global $plugin_prettyurls;
  363. $plugin_prettyurls = new Plugin_PrettyURLs;
  364. $plugin_prettyurls->categories();
  365. if (!defined('MOD_ADMIN_PANEL')){
  366. if (!function_exists('get_nextpage_link')) :
  367. function get_nextpage_link() {
  368. global $plugin_prettyurls;
  369. return $plugin_prettyurls->nextprevlink('NextPage', 1);
  370. }
  371. function get_prevpage_link() {
  372. global $plugin_prettyurls;
  373. return $plugin_prettyurls->nextprevlink('PrevPage',-1);
  374. }
  375. endif;
  376. }
  377. add_filter('post_link', array(&$plugin_prettyurls,'permalink'), 0, 2);
  378. add_filter('comments_link', array(&$plugin_prettyurls, 'commentlink'), 0, 2);
  379. add_filter('feed_link', array(&$plugin_prettyurls, 'feedlink'), 0, 2);
  380. add_filter('post_comments_feed_link', array(&$plugin_prettyurls, 'commentsfeedlink'), 0, 3);
  381. add_filter('category_link', array(&$plugin_prettyurls,'categorylink'), 0, 2);
  382. add_filter('page_link', array(&$plugin_prettyurls, 'staticlink'), 0, 2);
  383. // date related functions
  384. add_filter('year_link', array(&$plugin_prettyurls,'yearlink'), 0, 2);
  385. add_filter('month_link', array(&$plugin_prettyurls,'monthlink'), 0, 3);
  386. add_filter('day_link', array(&$plugin_prettyurls,'daylink'), 0, 4);
  387. if (PRETTYURLS_TITLES) {
  388. add_filter('publish_post', array(&$plugin_prettyurls, 'cache_add'), 5, 2);
  389. add_filter('delete_post', array(&$plugin_prettyurls, 'cache_delete'));
  390. add_action('update_categories', array(&$plugin_prettyurls, 'categories'));
  391. }
  392. add_filter('init', array(&$plugin_prettyurls, 'cache_init'));
  393. if (class_exists('AdminPanelAction')){
  394. class admin_plugin_prettyurls extends AdminPanelAction {
  395. var $langres = 'plugin:prettyurls';
  396. var $_config = array('mode'=>0);
  397. function setup() {
  398. $this->smarty->assign('admin_resource', "plugin:prettyurls/admin.plugin.prettyurls");
  399. $this->_config['mode'] = plugin_getoptions('prettyurls', 'mode');
  400. $this->smarty->assign('pconfig', $this->_config);
  401. $blogroot = BLOG_ROOT;
  402. $f = ABS_PATH . '.htaccess';
  403. $txt = io_load_file($f);
  404. if (!$txt) {
  405. $txt =<<<STR
  406. # Thanks again WP :)
  407. <IfModule mod_rewrite.c>
  408. RewriteEngine On
  409. RewriteBase {$blogroot}
  410. RewriteCond %{REQUEST_FILENAME} !-f
  411. RewriteCond %{REQUEST_FILENAME} !-d
  412. RewriteRule . {$blogroot}index.php [L]
  413. </IfModule>
  414. STR;
  415. }
  416. $this->smarty->assign('cantsave',
  417. ( !is_writable(ABS_PATH) || (file_exists($f) && !is_writable($f)) )
  418. );
  419. $this->smarty->assign('htaccess', $txt);
  420. }
  421. function onsubmit() {
  422. global $fp_config;
  423. if (isset($_POST['saveopt'])) {
  424. $this->_config['mode'] = (int) $_POST['mode'] ;
  425. plugin_addoption('prettyurls', 'mode', $this->_config['mode']);
  426. if( plugin_saveoptions() )
  427. $this->smarty->assign('success', 2);
  428. else $this->smarty->assign('success', -2);
  429. }
  430. if (isset($_POST['htaccess-submit'])) {
  431. if (!empty($_POST['htaccess']) && io_write_file(ABS_PATH.'.htaccess', $_POST['htaccess'])){
  432. $this->smarty->assign('success', 1);
  433. } else {
  434. $this->smarty->assign('success', -1);
  435. }
  436. }
  437. return 2;
  438. }
  439. }
  440. admin_addpanelaction('plugin', 'prettyurls', true);
  441. }
  442. ?>