1<?php
2# Copyright (c) 2003-2005, Jannis Hermanns (on behalf the Serendipity Developer Team)
3# All rights reserved.  See LICENSE file for licensing details
4
5if (IN_serendipity !== true) {
6    die ("Don't hack!");
7}
8
9/**
10 * Converts a string into a filename that can be used safely in HTTP URLs
11 *
12 * @access public
13 * @param   string  input string
14 * @param   boolean Shall dots in the filename be removed? (Required for certain regex rules)
15 * @return  string  output string
16 */
17function serendipity_makeFilename($str, $stripDots = false) {
18    static $from = array(
19                     ' ',
20                     '%',
21
22                     '�',
23                     '�',
24
25                     '�',
26                     '�',
27
28                     '�',
29                     '�',
30
31                     '�',
32
33                     '�',
34                     '�',
35                     '�',
36
37                     '�',
38                     '�',
39                     '�',
40
41                     '�',
42                     '�',
43                     '�',
44                     '�',
45
46                     '�',
47                     '�',
48                     '�',
49                     '�',
50
51                     '�',
52                     '�',
53                     '�',
54
55                     '�',
56                     '�',
57
58                     '�',
59
60                     '�');
61
62    static $to   = array(
63                     '-',
64                     '%25',
65
66                     'AE',
67                     'ae',
68
69                     'OE',
70                     'oe',
71
72                     'UE',
73                     'ue',
74
75                     'ss',
76
77                     'e',
78                     'e',
79                     'e',
80
81                     'i',
82                     'i',
83                     'i',
84
85                     'a',
86                     'a',
87                     'a',
88                     'a',
89
90                     'o',
91                     'o',
92                     'o',
93                     'o',
94
95                     'u',
96                     'u',
97                     'u',
98
99                     'c',
100                     'C',
101
102                     'n',
103
104                     'y');
105
106    if (isset($GLOBALS['i18n_filename_utf8'])) {
107        $str = str_replace(' ', '_', $str);
108        $str = str_replace('&', '%25', $str);
109        $str = str_replace('/', '%2F', $str);
110        $str = urlencode($str);
111    } else {
112        if (isset($GLOBALS['i18n_filename_from'])) {
113            // Replace international chars not detected by every locale.
114            // The array of chars is defined in the language file.
115            $str = str_replace($GLOBALS['i18n_filename_from'], $GLOBALS['i18n_filename_to'], $str);
116
117            if (LANG_CHARSET == 'UTF-8') {
118                // URLs need to be 7bit - since this function takes care of the most common ISO-8859-1
119                // characters, try to UTF8-decode the string first.
120                $str = utf8_decode($str);
121            }
122        } else {
123            // Replace international chars not detected by every locale
124            if (LANG_CHARSET == 'UTF-8') {
125                // URLs need to be 7bit - since this function takes care of the most common ISO-8859-1
126                // characters, try to UTF8-decode the string first.
127                $str = utf8_decode($str);
128            }
129
130            $str = str_replace($from, $to, $str);
131        }
132
133        // Nuke chars not allowed in our URI
134        $str = preg_replace('#[^' . PAT_FILENAME . ']#i', '', $str);
135    }
136
137    // Check if dots are allowed
138    if ($stripDots) {
139        $str = str_replace('.', '', $str);
140    }
141
142    // Remove consecutive separators
143    $str = preg_replace('#'. $to[0] .'{2,}#s', $to[0], $str);
144
145    // Remove excess separators
146    $str = trim($str, $to[0]);
147
148    if (empty($str)) {
149        if (isset($GLOBALS['i18n_unknown'])) {
150            $str = $GLOBALS['i18n_unknown'];
151        } else {
152            $str = 'unknown';
153        }
154    }
155
156    return $str;
157}
158
159/**
160 * Initialize permalinks, if the user did not specify those yet
161 *
162 * @access public
163 * @return null
164 */
165function serendipity_initPermalinks() {
166    global $serendipity;
167
168    if (!isset($serendipity['permalinkStructure'])) {
169        $serendipity['permalinkStructure'] = 'archives/%id%-%title%.html';
170    }
171
172    if (!isset($serendipity['permalinkFeedAuthorStructure'])) {
173        $serendipity['permalinkFeedAuthorStructure'] = 'feeds/authors/%id%-%realname%.rss';
174    }
175
176    if (!isset($serendipity['permalinkFeedCategoryStructure'])) {
177        $serendipity['permalinkFeedCategoryStructure'] = 'feeds/categories/%id%-%name%.rss';
178    }
179
180    if (!isset($serendipity['permalinkCategoryStructure'])) {
181        $serendipity['permalinkCategoryStructure'] = 'categories/%id%-%name%';
182    }
183
184    if (!isset($serendipity['permalinkAuthorStructure'])) {
185        $serendipity['permalinkAuthorStructure'] = 'authors/%id%-%realname%';
186    }
187
188    if (!isset($serendipity['permalinkArchivesPath'])) {
189        $serendipity['permalinkArchivesPath'] = 'archives';
190    }
191
192    if (!isset($serendipity['permalinkArchivePath'])) {
193        $serendipity['permalinkArchivePath'] = 'archive';
194    }
195
196    if (!isset($serendipity['permalinkCategoriesPath'])) {
197        $serendipity['permalinkCategoriesPath'] = 'categories';
198    }
199
200    if (!isset($serendipity['permalinkAuthorsPath'])) {
201        $serendipity['permalinkAuthorsPath'] = 'authors';
202    }
203
204    if (!isset($serendipity['permalinkUnsubscribePath'])) {
205        $serendipity['permalinkUnsubscribePath'] = 'unsubscribe';
206    }
207
208    if (!isset($serendipity['permalinkDeletePath'])) {
209        $serendipity['permalinkDeletePath'] = 'delete';
210    }
211
212    if (!isset($serendipity['permalinkApprovePath'])) {
213        $serendipity['permalinkApprovePath'] = 'approve';
214    }
215
216    if (!isset($serendipity['permalinkFeedsPath'])) {
217        $serendipity['permalinkFeedsPath'] = 'feeds';
218    }
219
220    if (!isset($serendipity['permalinkPluginPath'])) {
221        $serendipity['permalinkPluginPath'] = 'plugin';
222    }
223
224    if (!isset($serendipity['permalinkAdminPath'])) {
225        $serendipity['permalinkAdminPath'] = 'admin';
226    }
227
228    if (!isset($serendipity['permalinkSearchPath'])) {
229        $serendipity['permalinkSearchPath'] = 'search';
230    }
231
232    if (!isset($serendipity['permalinkCommentsPath'])) {
233        $serendipity['permalinkCommentsPath'] = 'comments';
234    }
235
236    /* URI paths
237     * These could be defined in the language headers, except that would break
238     * backwards URL compatibility
239     */
240    @define('PATH_ARCHIVES',    $serendipity['permalinkArchivesPath']);
241    @define('PATH_ARCHIVE',     $serendipity['permalinkArchivePath']);
242    @define('PATH_CATEGORIES',  $serendipity['permalinkCategoriesPath']);
243    @define('PATH_UNSUBSCRIBE', $serendipity['permalinkUnsubscribePath']);
244    @define('PATH_DELETE',      $serendipity['permalinkDeletePath']);
245    @define('PATH_APPROVE',     $serendipity['permalinkApprovePath']);
246    @define('PATH_FEEDS',       $serendipity['permalinkFeedsPath']);
247    @define('PATH_PLUGIN',      $serendipity['permalinkPluginPath']);
248    @define('PATH_ADMIN',       $serendipity['permalinkAdminPath']);
249    @define('PATH_SEARCH',      $serendipity['permalinkSearchPath']);
250    @define('PATH_COMMENTS',    $serendipity['permalinkCommentsPath']);
251
252    /* URI patterns
253     * Note that it's important to use @ as the pattern delimiter. DO NOT use shortcuts
254     * like \d or \s, since mod_rewrite will use the regexps as well and chokes on them.
255     * If you add new patterns, remember to add the new rules to the *.tpl files and
256     * function serendipity_installFiles().
257     */
258    @define('PAT_FILENAME',       '0-9a-z\.\_!;,\+\-\%');
259    @define('PAT_FILENAME_MATCH', '[' . PAT_FILENAME . ']+');
260    @define('PAT_DIRNAME_MATCH',  '[' . PAT_FILENAME . '/]*');
261    @define('PAT_CSS',            '@/(serendipity\.css|serendipity_admin\.css)@');
262    @define('PAT_JS',             '@/(serendipity\.js|serendipity_admin\.js)@');
263    @define('PAT_FEED',           '@/(index|atom[0-9]*|rss|b2rss|b2rdf).(rss|rdf|rss2|xml)@');
264    @define('PAT_COMMENTSUB',     '@/([0-9]+)[_\-][' . PAT_FILENAME . ']*\.html@i');
265
266    return true;
267}
268
269/**
270 * Build an array containing all regular expression permalinks
271 *
272 * @access public
273 * @param   boolean     If set to true, the list of permalinks will be returned. If false, all permalinks will be applied as Constants
274 * @return  array       (conditional on $return) List of permalinks
275 */
276function &serendipity_permalinkPatterns($return = false) {
277    global $serendipity;
278
279    $PAT = array();
280
281    $PAT['UNSUBSCRIBE']              = '@/'  . $serendipity['permalinkUnsubscribePath'].'/(.*)/([0-9]+)@';
282    $PAT['APPROVE']                  = '@/'  . $serendipity['permalinkApprovePath'].'/(.*)/(.*)/([0-9]+)@';
283    $PAT['DELETE']                   = '@/'  . $serendipity['permalinkDeletePath'].'/(.*)/(.*)/([0-9]+)@';
284    $PAT['ARCHIVES']                 = '@/'  . $serendipity['permalinkArchivesPath'].'([/A-Za-z0-9]+)\.html@';
285    $PAT['FEEDS']                    = '@/'  . $serendipity['permalinkFeedsPath'].'/@';
286    $PAT['ADMIN']                    = '@/(' . $serendipity['permalinkAdminPath'] . '|entries)(/.+)?$@';
287    $PAT['ARCHIVE']                  = '@/'  . $serendipity['permalinkArchivePath'] . '/?@';
288    $PAT['CATEGORIES']               = '@/'  . $serendipity['permalinkCategoriesPath'].'/([0-9;]+)@';
289    $PAT['PLUGIN']                   = '@/(' . $serendipity['permalinkPluginPath'] . '|plugin)/(.*)@';
290    $PAT['SEARCH']                   = '@/'  . $serendipity['permalinkSearchPath'] . '/(.*)@';
291    $PAT['COMMENTS']                 = '@/'  . $serendipity['permalinkCommentsPath'] . '/(.*)@';
292    $PAT['PERMALINK']                = '@('  . serendipity_makePermalinkRegex($serendipity['permalinkStructure'], 'entry') . ')/?@i';
293    $PAT['PERMALINK_CATEGORIES']     = '@'   . serendipity_makePermalinkRegex($serendipity['permalinkCategoryStructure'], 'category') . '@i';
294    $PAT['PERMALINK_FEEDCATEGORIES'] = '@'   . serendipity_makePermalinkRegex($serendipity['permalinkFeedCategoryStructure'], 'category') . '@i';
295    $PAT['PERMALINK_FEEDAUTHORS']    = '@'   . serendipity_makePermalinkRegex($serendipity['permalinkFeedAuthorStructure'], 'author') . '@i';
296    $PAT['PERMALINK_AUTHORS']        = '@'   . serendipity_makePermalinkRegex($serendipity['permalinkAuthorStructure'], 'author') . '@i';
297
298    if ($return) {
299        return $PAT;
300    } else {
301        foreach($PAT AS $constant => $value) {
302            define('PAT_' . $constant, $value);
303        }
304
305        $return = true;
306        return $return;
307    }
308}
309
310/**
311 * Search the reference to a specific permalink
312 *
313 * This query will show the Entry/Category/Author-ID to a permalink, if that permalink
314 * does not contain %id%.
315 *
316 * @access public
317 * @param   string      The permalink configuration string
318 * @param   string      The URL to check
319 * @param   string      A default return value if no permalink is found
320 * @param   string      The type of a permalink (entry|category|author)
321 * @return  string      The ID of the permalink type
322 */
323function serendipity_searchPermalink($struct, $url, $default, $type = 'entry') {
324    global $serendipity;
325
326    if (stristr($struct, '%id%') === FALSE) {
327        $url = preg_replace('@^(' . preg_quote($serendipity['serendipityHTTPPath'], '@') . '(' . preg_quote($serendipity['indexFile'], '@') . ')?\??(url=)?/?)([^&?]+).*@', '\4', $url);
328        // If no entryid is submitted, we rely on a new DB call to fetch the permalink.
329        $pq = "SELECT entry_id, data
330                 FROM {$serendipity['dbPrefix']}permalinks
331                WHERE (permalink = '" . serendipity_db_escape_string($url) . "'
332                   OR permalink = '" . serendipity_db_escape_string($default) . "')
333                  AND type      = '" . serendipity_db_escape_string($type) . "'
334                  AND entry_id  > 0
335                LIMIT 1";
336// echo $pq; // DEBUG
337// die($pq); // DEBUG
338        $permalink = serendipity_db_query($pq, true, 'both', false, false, false, true);
339
340        if (is_array($permalink)) {
341            return $permalink['entry_id'];
342        }
343    }
344
345    return $default;
346}
347
348/**
349 * Create a permalink for the given input data
350 *
351 * You can pass an entry array, or an author array to this function
352 * and then get a permalink valid for that array
353 *
354 * @access public
355 * @param   array       The input data used for building the permalink
356 * @param   string      The type of the permalink (entry|category|author)
357 * @return  string      The permalink
358 */
359function serendipity_getPermalink(&$data, $type = 'entry') {
360    switch($type) {
361        case 'entry':
362            return serendipity_archiveURL(
363                        $data['id'],
364                        $data['title'],
365                        '',
366                        false,
367                        array('timestamp' => $data['timestamp'])
368            );
369            break;
370
371        case 'category':
372            return serendipity_categoryURL($data, '', false);
373            break;
374
375        case 'author':
376            return serendipity_authorURL($data, '', false);
377            break;
378    }
379
380    return false;
381}
382
383/**
384 * Update a permalink with new data
385 *
386 * @access public
387 * @param   array       The input data used for building the permalink
388 * @param   string      The type of the permalink (entry|category|author)
389 * @return  string      The database result
390 */
391function serendipity_updatePermalink(&$data, $type = 'entry') {
392    global $serendipity;
393
394    $link = serendipity_getPermalink($data, $type);
395    return(serendipity_db_query(sprintf("UPDATE {$serendipity['dbPrefix']}permalinks
396                                            SET permalink = '%s'
397                                          WHERE entry_id  = %s
398                                            AND type      = '%s'",
399
400                                            serendipity_db_escape_string($link),
401                                            (int)$data['id'],
402                                            serendipity_db_escape_string($type))));
403}
404
405/**
406 * Insert a new Permalink into the database for latter retrieval
407 *
408 * This function is basically only used if you have no '%id%' value in your permalink config.
409 *
410 * @access public
411 * @param   array       The input data used for building the permalink
412 * @param   string      The type of the permalink (entry|category|author)
413 * @return  string      The permalink
414 */
415function serendipity_insertPermalink(&$data, $type = 'entry') {
416    global $serendipity;
417
418    $link = serendipity_getPermalink($data, $type);
419
420    switch($type) {
421        case 'entry':
422            $idfield = 'id';
423            break;
424
425        case 'author':
426            $idfield = 'authorid';
427            break;
428
429        case 'category':
430            $idfield = 'categoryid';
431            break;
432    }
433
434    return(serendipity_db_query(sprintf("INSERT INTO {$serendipity['dbPrefix']}permalinks
435                                                    (permalink, entry_id, type)
436                                             VALUES ('%s', '%s', '%s')",
437
438                                            serendipity_db_escape_string($link),
439                                            (int)$data[$idfield],
440                                            serendipity_db_escape_string($type))));
441}
442
443/**
444 * Build all permalinks for all current entries, authors and categories
445 *
446 * @access public
447 * @return null
448 */
449function serendipity_buildPermalinks() {
450    global $serendipity;
451
452    $entries = serendipity_db_query("SELECT id, title, timestamp FROM {$serendipity['dbPrefix']}entries");
453
454    if (is_array($entries)) {
455        serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}permalinks WHERE type = 'entry'");
456
457        foreach($entries AS $entry) {
458            serendipity_insertPermalink($entry, 'entry');
459        }
460    }
461
462    $authors = serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}authors");
463
464    if (is_array($authors)) {
465        serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}permalinks WHERE type = 'author'");
466
467        foreach($authors AS $author) {
468            serendipity_insertPermalink($author, 'author');
469        }
470    }
471
472    $categories = serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}category");
473
474    if (is_array($categories)) {
475        serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}permalinks WHERE type = 'category'");
476
477        foreach($categories AS $category) {
478            serendipity_insertPermalink($category, 'category');
479        }
480    }
481}
482
483/**
484 * Uses logic to figure out how the URI should look, based on current rewrite rule
485 *
486 * @access public
487 * @param   string      The URL part that you want to format to "pretty urls"
488 * @param   string      The path/URL you want as a prefix for your pretty URL
489 * @param   boolean     If set to TRUE this will bypass all pretty URLs and format the link so that it works everywhere
490 * @return  string      The rewritten URL
491 */
492function serendipity_rewriteURL($path, $key='baseURL', $forceNone = false) {
493    global $serendipity;
494    return $serendipity[$key] . ($serendipity['rewrite'] == 'none' || ($serendipity['rewrite'] != 'none' && $forceNone) ? $serendipity['indexFile'] . '?/' : '') . $path;
495}
496
497/**
498 * Format a permalink according to the configured format
499 *
500 * @access public
501 * @param   string      The URL format to use
502 * @param   array       The input data to format a permalink
503 * @param   string      The type of the permalink (entry|category|author)
504 * @return  string      The formatted permalink
505 */
506function serendipity_makePermalink($format, $data, $type = 'entry') {
507    global $serendipity;
508    static $entryKeys    = array('%id%', '%lowertitle%', '%title%', '%day%', '%month%', '%year%');
509    static $authorKeys   = array('%id%', '%username%', '%realname%', '%email%');
510    static $categoryKeys = array('%id%', '%name%', '%parentname%', '%description%');
511
512    switch($type) {
513        case 'entry':
514            if (!isset($data['entry']['timestamp']) && preg_match('@(%day%|%month%|%year%)@', $format)) {
515                // We need the timestamp to build the URI, but no timestamp has been submitted. Thus we need to fetch the data.
516                $ts = serendipity_db_query("SELECT timestamp FROM {$serendipity['dbPrefix']}entries WHERE id = " . (int)$data['id'], true);
517                if (is_array($ts)) {
518                    $data['entry']['timestamp'] = $ts['timestamp'];
519                } else {
520                    $data['entry']['timestamp'] = time();
521                }
522            }
523
524            $ts = serendipity_serverOffsetHour($data['entry']['timestamp']);
525
526            $ftitle  = serendipity_makeFilename($data['title']);
527            $fltitle = strtolower($ftitle);
528
529            $replacements =
530                array(
531                    (int)$data['id'],
532                    $fltitle,
533                    $ftitle,
534                    date('d', $ts),
535                    date('m', $ts),
536                    date('Y', $ts)
537                );
538            return str_replace($entryKeys, $replacements, $format);
539            break;
540
541        case 'author':
542            $replacements =
543                array(
544                    (int)$data['authorid'],
545                    serendipity_makeFilename($data['username'], true),
546                    serendipity_makeFilename($data['realname'], true),
547                    serendipity_makeFilename($data['email'], true)
548                );
549            return str_replace($authorKeys, $replacements, $format);
550            break;
551
552        case 'category':
553            $parent_path = array();
554
555            // This is expensive. Only lookup if required.
556            if (strstr($format, '%parentname%')) {
557                $parents = serendipity_getCategoryRoot($data['categoryid']);
558                if (is_array($parents)) {
559                    foreach($parents AS $parent) {
560                        $parent_path[] = serendipity_makeFilename($parent['category_name'], true);
561                    }
562                }
563            }
564
565            $replacements =
566                array(
567                    (int)$data['categoryid'],
568                    serendipity_makeFilename($data['category_name'], true),
569                    implode('/', $parent_path),
570                    serendipity_makeFilename($data['category_description'], true)
571                );
572            return str_replace($categoryKeys, $replacements, $format);
573            break;
574    }
575
576    return false;
577}
578
579/**
580 * Convert a permalink configuration into a regular expression for use in rewrite rules
581 *
582 * @access public
583 * @param   string      The URL format to use
584 * @param   string      The type of the permalink (entry|category|author)
585 * @return  string      The regular expression to a permalink URL
586 */
587function serendipity_makePermalinkRegex($format, $type = 'entry') {
588    static $entryKeys           = array('%id%',     '%lowertitle%',     '%title%',          '%day%',      '%month%',    '%year%');
589    static $entryRegexValues    = array('([0-9]+)', PAT_FILENAME_MATCH, PAT_FILENAME_MATCH, '[0-9]{1,2}', '[0-9]{1,2}', '[0-9]{4}');
590
591    static $authorKeys          = array('%id%',     '%username%',       '%realname%',       '%email%');
592    static $authorRegexValues   = array('([0-9]+)', PAT_FILENAME_MATCH, PAT_FILENAME_MATCH, PAT_FILENAME_MATCH);
593
594    static $categoryKeys        = array('%id%',     '%name%',            '%parentname%',     '%description%');
595    static $categoryRegexValues = array('([0-9;]+)', PAT_FILENAME_MATCH, PAT_DIRNAME_MATCH,  PAT_FILENAME_MATCH);
596
597    switch($type) {
598        case 'entry':
599            return str_replace($entryKeys, $entryRegexValues, preg_quote($format));
600            break;
601
602        case 'author':
603            return str_replace($authorKeys, $authorRegexValues, preg_quote($format));
604            break;
605
606        case 'category':
607            return str_replace($categoryKeys, $categoryRegexValues, preg_quote($format));
608            break;
609    }
610}
611
612/**
613 * Create a permalink for an entry permalink
614 *
615 * @access public
616 * @param   int     The entry ID
617 * @param   string  The entry title
618 * @param   string  The base URL/path key
619 * @param   boolean Shall the link be rewritten to a pretty URL?
620 * @param   array   Additional entry data
621 * @return  string  The permalink
622 */
623function serendipity_archiveURL($id, $title, $key = 'baseURL', $checkrewrite = true, $entryData = null) {
624    global $serendipity;
625    $path = serendipity_makePermalink($serendipity['permalinkStructure'], array('id'=> $id, 'title' => $title, 'entry' => $entryData));
626    if ($checkrewrite) {
627        $path = serendipity_rewriteURL($path, $key);
628    }
629    return $path;
630}
631
632/**
633 * Create a permalink for an authors permalink
634 *
635 * @access public
636 * @param   array   The author data
637 * @param   string  The base URL/path key
638 * @param   boolean Shall the link be rewritten to a pretty URL?
639 * @return  string  The permalink
640 */
641function serendipity_authorURL(&$data, $key = 'baseURL', $checkrewrite = true) {
642    global $serendipity;
643    $path = serendipity_makePermalink($serendipity['permalinkAuthorStructure'], $data, 'author');
644    if ($checkrewrite) {
645        $path = serendipity_rewriteURL($path, $key);
646    }
647    return $path;
648}
649
650/**
651 * Create a permalink for an category permalink
652 *
653 * @access public
654 * @param   array   The category data
655 * @param   string  The base URL/path key
656 * @param   boolean Shall the link be rewritten to a pretty URL?
657 * @return  string  The permalink
658 */
659function serendipity_categoryURL(&$data, $key = 'baseURL', $checkrewrite = true) {
660    global $serendipity;
661    $path = serendipity_makePermalink($serendipity['permalinkCategoryStructure'], $data, 'category');
662    if ($checkrewrite) {
663        $path = serendipity_rewriteURL($path, $key);
664    }
665    return $path;
666}
667
668/**
669 * Create a permalink for an RSS feed permalink
670 *
671 * @access public
672 * @param   array   The entry data
673 * @param   string  The base URL/path key
674 * @param   boolean Shall the link be rewritten to a pretty URL?
675 * @return  string  The permalink
676 */
677function serendipity_feedCategoryURL(&$data, $key = 'baseURL', $checkrewrite = true) {
678    global $serendipity;
679    $path = serendipity_makePermalink($serendipity['permalinkFeedCategoryStructure'], $data, 'category');
680    if ($checkrewrite) {
681        $path = serendipity_rewriteURL($path, $key);
682    }
683    return $path;
684}
685
686/**
687 * Create a permalink for an RSS authors' feed permalink
688 *
689 * @access public
690 * @param   array   The entry data
691 * @param   string  The base URL/path key
692 * @param   boolean Shall the link be rewritten to a pretty URL?
693 * @return  string  The permalink
694 */
695function serendipity_feedAuthorURL(&$data, $key = 'baseURL', $checkrewrite = true) {
696    global $serendipity;
697    $path = serendipity_makePermalink($serendipity['permalinkFeedAuthorStructure'], $data, 'author');
698    if ($checkrewrite) {
699        $path = serendipity_rewriteURL($path, $key);
700    }
701    return $path;
702}
703
704/**
705 * Create a permalink for an archive date
706 *
707 * @access public
708 * @param   string  The archive's date
709 * @param   boolean If true, only summary archive
710 * @param   string  The base URL/path key
711 * @return  string  The permalink
712 */
713function serendipity_archiveDateUrl($range, $summary=false, $key='baseURL') {
714    return serendipity_rewriteURL(PATH_ARCHIVES . '/' . $range . ($summary ? '/summary' : '') . '.html', $key);
715}
716
717/**
718 * Returns the URL to the current page that is being viewed
719 *
720 * @access public
721 * @return string   the current URL
722 */
723function serendipity_currentURL($strict = false) {
724    global $serendipity;
725
726    // All that URL getting humpty-dumpty is necessary to allow a user to change the template in the
727    // articles view. POSTing data to that page only works with mod_rewrite and not the ErrorDocument
728    // redirection, so we need to generate the ErrorDocument-URI here.
729
730    $uri = @parse_url($_SERVER['REQUEST_URI']);
731    $qst = '';
732    if (!empty($uri['query'])) {
733        $qst = '&amp;' . str_replace('&', '&amp;', $uri['query']);
734    }
735    $uri['path'] = preg_replace('@^' . preg_quote($serendipity['serendipityHTTPPath']) . '@i', ($strict ? '/' : ''), $uri['path']);
736    $uri['path'] = preg_replace('@^(&amp;)?' . preg_quote($serendipity['indexFile']) . '(&amp;)@i', '', $uri['path']);
737    $url = $serendipity['serendipityHTTPPath'] . $serendipity['indexFile'] . '?' . $uri['path'] . $qst;
738    $url = str_replace(
739        array(
740            $serendipity['indexFile'] . '&amp;',
741            '"',
742            "'",
743            '<',
744            '>',
745            '`'
746        ),
747
748        array(
749            '',
750            '',
751            '',
752            '',
753            ''
754        ),
755
756        $url); // Kill possible looped repitions and bad characters which could occur
757
758    if ($strict) {
759        $url = preg_replace('@(//+)@', '/', $url);
760    }
761
762    return $url;
763}
764
765/**
766 * Get the URI Arguments for the current HTTP Request
767 *
768 * @access public
769 * @param   string      The URI made for this request
770 * @param   boolean     If enabled, then no Dots are allowed in the URL for permalinks
771 * @return
772 */
773function serendipity_getUriArguments($uri, $wildcard = false) {
774    global $serendipity;
775    static $indexFile = null;
776
777    if ($indexFile === null) {
778        $_indexFile = explode('.', $serendipity['indexFile']);
779        $indexFile = $_indexFile[0];
780    }
781
782    /* Explode the path into sections, to later be able to check for arguments and add our own */
783    preg_match('/^'. preg_quote($serendipity['serendipityHTTPPath'], '/') . '(' . preg_quote($serendipity['indexFile'], '/') . '\?\/)?(' . ($wildcard ? '.+' : '[!;,_a-z0-9\-*\/%\+]+') . ')/i', $uri, $_res);
784    if (strlen($_res[2]) != 0) {
785        $args = explode('/', $_res[2]);
786        if ($args[0] == $indexFile || $args[0] == $serendipity['indexFile']) {
787            unset($args[0]);
788        }
789        $args = array_unique($args);
790        return $args;
791    } else {
792        return array();
793    }
794}
795
796