root/branches/multiuser/util.php

Revision 1606, 38.3 kB (checked in by mdodoo, 3 years ago)

This was really annoying, and took more time than the previous commit. For some reason, "svn diff" does not work correctly on my machine.

  • Property svn:eol-style set to native
  • Property svn:eolstyle set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1<?php
2
3###############################################################################
4# Gregarius - A PHP based RSS aggregator.
5# Copyright (C) 2003 - 2006 Marco Bonetti
6#
7###############################################################################
8# This program is free software and open source software; you can redistribute
9# it and/or modify it under the terms of the GNU General Public License as
10# published by the Free Software Foundation; either version 2 of the License,
11# or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful, but WITHOUT
14# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16# more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  or visit
21# http://www.gnu.org/licenses/gpl.html
22#
23###############################################################################
24# E-mail:      mbonetti at gmail dot com
25# Web page:    http://gregarius.net/
26#
27###############################################################################
28
29
30
31function getLastModif() {
32        return getProperty('__meta__','meta.lastupdate');
33}
34
35function getETag() {
36    return md5(getLastModif().$_SERVER['PHP_SELF']);
37}
38
39
40function rss_error($message, $severity = RSS_ERROR_ERROR, $render = false) {
41    if ($render) {
42        echo "<p class=\"error\">$message</p>\n";
43        return;
44    }
45
46    if (!isset($GLOBALS['rss'])) {
47        rss_require('cls/rss.php');
48    }
49
50    $GLOBALS['rss'] -> error($message, $severity);
51}
52
53/** this functions checks whether a URI exists */
54function getHttpResponseCode($forUri) {
55    return getUrl($forUri, 255);
56}
57
58function getContentType($link, & $contentType) {
59    $url_parts = @ parse_url($link);
60    if (empty ($url_parts["host"])) {
61        return (false);
62    }
63    if (!empty ($url_parts["path"])) {
64        $documentpath = $url_parts["path"];
65    } else {
66        $documentpath = "/";
67    }
68    if (!empty ($url_parts["query"])) {
69        $documentpath .= "?".$url_parts["query"];
70    }
71    $host = $url_parts["host"];
72    $port = (array_key_exists('port', $url_parts) ? $url_parts["port"] : "80");
73
74    $socket = @ fsockopen($host, $port, $errno, $errstr, 30);
75    if (!$socket) {
76        return (false);
77    }
78
79    $ret = false;
80    fwrite($socket, "GET ".$documentpath." HTTP/1.0\r\nHost: $host\r\n\r\n");
81    while (!feof($socket)) {
82        $line = fgets($socket, 100);
83        if (preg_match("/Content-Type: (.*)/i", $line, $matches)) {
84            $contentType = $matches[1];
85            $ret = true;
86            break;
87        }
88    }
89
90    return $ret;
91}
92
93// basically strips folder resources from URIs.
94// http://pear.php.net/package/HTTP_Client/ --> http://pear.php.net/
95function get_host($url, & $host) {
96    $ret = preg_match("/^(http:\/\/)?([^\/]+)/i", $url, $matches);
97    $host = $matches[2];
98
99    //ensure we have a slash
100    if (substr($host, -1) != "/") {
101        $host .= "/";
102    }
103
104    return $ret;
105}
106
107/**
108 * Builds a title out of an already encoded string.
109 */
110function makeTitle($title) {
111    // Let us find out if the user has set a title.
112    $userTitle = _TITLE_;
113    if (getConfig('rss.output.title')) {
114        $userTitle = getConfig('rss.output.title');
115    }
116    $ret = "". $userTitle ."";
117    if ($title) {
118        if (is_array($title)) {
119            foreach($title as $token) {
120                $ret .= " ".TITLE_SEP." ".$token;
121            }
122        } else {
123            $ret .= " ".TITLE_SEP." ".$title;
124        }
125    }
126    return $ret;
127}
128
129/*** update the given feed(s) **/
130function update($id) {
131    $kses_allowed = getConfig('rss.input.allowed'); //getAllowedTags();
132    $updatedIds = array ();
133
134
135    $sql = "select id, url, title, mode from ".getTable("channels");
136    if ($id != "" && is_numeric($id)) {
137        $sql .= " where id=$id";
138        $sql .= " and not(mode & ".RSS_MODE_DELETED_STATE.") ";
139    } else {
140        $sql .= " where not(mode & ".RSS_MODE_DELETED_STATE.") ";
141    }
142
143    if (getConfig('rss.config.absoluteordering')) {
144        $sql .= " order by parent, position";
145    } else {
146        $sql .= " order by parent, title";
147    }
148
149    $res = rss_query($sql);
150    while (list ($cid, $url, $title, $mode) = rss_fetch_row($res)) {
151
152        // suppress warnings because Magpie is rather noisy
153        $old_level = error_reporting(E_ERROR);
154        $rss = fetch_rss($url);
155
156        //reset
157        error_reporting($old_level);
158
159        if (!$rss && $id != "" && is_numeric($id)) {
160            return array (magpie_error(), array ());
161        }
162        elseif (!$rss || !($rss->rss_origin & MAGPIE_FEED_ORIGIN_HTTP_200) ) {
163            continue; // no need to do anything if we do not get a 200 OK from the feed
164        }
165
166        // base URL for items in this feed.
167        if (array_key_exists('link', $rss->channel)) {
168            $baseUrl = $rss->channel['link'];
169        } else {
170            $baseUrl = $url; // The feed is invalid
171        }
172
173        // Keep track of guids we've handled, because some feeds (hello,
174        // Technorati!) have this insane habit of serving the same item
175        // twice in the same feed.
176        $guids = array();
177
178        // Allow updates in this feed?
179        $allowUpdates = getProperty($cid,'rss.input.allowupdates');
180        if ($allowUpdates === null) {
181            $allowUpdates = getConfig('rss.input.allowupdates');
182        }
183
184        $itemIdsInFeed = array(); // This variable will store the item id's of the elements in the feed
185        foreach ($rss->items as $item) {
186
187            $item = rss_plugin_hook('rss.plugins.rssitem', $item);
188            // a plugin might delete this item
189            if(!isset($item))
190                continue;
191
192            // item title: strip out html tags
193            $title = array_key_exists('title', $item) ? strip_tags($item['title']) : "";
194            //$title = str_replace('& ', '&amp; ', $title);
195
196
197            $description = "";
198            // item content, if any
199            if (array_key_exists('content', $item) && is_array($item['content']) && array_key_exists('encoded', $item['content'])) {
200                $description = $item['content']['encoded'];
201            }
202            elseif (array_key_exists('description', $item)) {
203                $description = $item['description'];
204            }
205            elseif (array_key_exists('atom_content', $item)) {
206                $description = $item['atom_content'];
207            }
208            elseif (array_key_exists('summary', $item)) {
209                $description = $item['summary'];
210            }
211            else {
212                $description = "";
213            }
214
215            $md5sum = "";
216            $guid = "";
217
218            if(array_key_exists('guid', $item) && $item['guid'] != "") {
219                $guid = $item['guid'];
220            }
221            elseif(array_key_exists('id', $item) && $item['id'] != "") {
222                $guid = $item['id'];
223            }
224            $guid = trim($guid);
225            $guid = rss_real_escape_string($guid);
226
227            // skip this one if it's an  in-feed-dupe
228            if ($guid && isset($guids[$guid])) {
229                continue;
230            }
231            elseif($guid) {
232                $guids[$guid] = true;
233            }
234
235            if ($description != "") {
236                $md5sum = md5($description);
237                $description = kses($description, $kses_allowed); // strip out tags
238
239                if ($baseUrl != "") {
240                    $description = relative_to_absolute($description, $baseUrl);
241                }
242            }
243
244            // Now let plugins modify the description
245            $description = rss_plugin_hook('rss.plugins.import.description', $description);
246
247
248            // link
249            if (array_key_exists('link', $item) && $item['link'] != "") {
250                $url = $item['link'];
251            }
252            elseif (array_key_exists('guid', $item) && $item['guid'] != "") {
253                $url = $item['guid'];
254            }
255            elseif (array_key_exists('link_', $item) && $item['link_'] != "") {
256                $url = $item['link_'];
257            }
258            else {
259                // fall back to something basic
260                $url = md5($title);
261            }
262
263            // make sure the url is properly escaped
264            $url = htmlentities($url, ENT_QUOTES );
265
266            $url = rss_real_escape_string($url);
267
268            // author
269            if (array_key_exists('dc', $item) && array_key_exists('creator', $item['dc'])) {
270                // RSS 1.0
271                $author = $item['dc']['creator'];
272            } else if (array_key_exists('author_name', $item)) {
273                // Atom 0.3
274                $author = $item['author_name'];
275            } else {
276                $author = "";
277            }
278
279            $author = trim(strip_tags($author));
280
281            // pubdate
282            $cDate = -1;
283            if (array_key_exists('dc', $item) && array_key_exists('date', $item['dc'])) {
284                // RSS 1.0
285                $cDate = parse_w3cdtf($item['dc']['date']);
286            }
287            elseif (array_key_exists('pubdate', $item)) {
288                // RSS 2.0 (?)
289                // We use the second param of strtotime here as a workaround
290                // of a PHP bug with strtotime. If the pubdate field doesn't
291                // contain seconds, the strtotime function will use the current
292                // time to fill in seconds in PHP4. This interferes with the
293                // update mechanism of gregarius. See ticket #328 for the full
294                // gory details. Giving a known date as a second param to
295                // strtotime fixes this problem, hence the 0 here.
296                $cDate = strtotime($item['pubdate'], 0);
297            }
298            elseif (array_key_exists('published',$item)) {
299                // atom 1.0
300                $cDate = parse_iso8601($item['published']);
301            }
302            elseif (array_key_exists('issued', $item)) {
303                //Atom, alternative
304                $cDate = parse_iso8601($item['issued']);
305            }
306            elseif (array_key_exists('updated', $item)) {
307                //Atom, alternative
308                $cDate = parse_iso8601($item['updated']);
309            }
310            elseif (array_key_exists('created', $item)) {
311                // atom 0.3
312                $cDate = parse_iso8601($item['created']);
313            }
314
315            // enclosure
316            if (array_key_exists('enclosure@url', $item) ) {
317                $enclosure = $item['enclosure@url'];
318            } else {
319                $enclosure = "";
320            }
321
322            // drop items with an url exceeding our column length: we couldn't provide a
323            // valid link back anyway.
324            if (strlen($url) >= 255) {
325                continue;
326            }
327
328            $dbtitle = rss_real_escape_string($title);
329            if (strlen($dbtitle) >= 255) {
330                $dbtitle=substr($dbtitle,0,254);
331            }
332
333            if ($cDate > 0) {
334                $sec = "FROM_UNIXTIME($cDate)";
335            } else {
336                $sec = "null";
337            }
338
339            // check whether we already have this item
340            if ($guid) {
341                $sql = "select id, i2u.flgunread,i2u.flgdeleted, md5sum, guid, pubdate "
342                ."from "
343                .getTable('item2user') ." i2u "
344                ."left join "
345                .getTable('item') ." i "
346                ." on (i2u.fkiid=i.id) "
347                ." where cid=$cid and guid='$guid'";
348            } else {
349                                $sql = "select id, i2u.flgunread,i2u.flgdeleted, md5sum, guid, pubdate "
350                ."from "
351                .getTable('item2user') ." i2u "
352                ."left join "
353                .getTable('item') ." i "
354                ." on (i2u.fkiid=i.id) "
355                ." where cid=$cid and url='$url' and title='$dbtitle'"
356                ." and (pubdate is NULL OR pubdate=$sec)";
357            }
358
359            $subres = rss_query($sql);
360            list ($indb, $unread,$deleted, $dbmd5sum, $dbGuid, $dbPubDate) = rss_fetch_row($subres);
361
362            if ($indb) {
363                $itemIdsInFeed[] = $indb;
364                if (!$deleted && $md5sum != $dbmd5sum) {
365                    // the md5sums do not match.
366                    if($allowUpdates) { // Are we allowed update items in the db?
367                        list ($cid, $indb, $description) =
368                            rss_plugin_hook('rss.plugins.items.updated', array ($cid, $indb, $description));
369
370                        $sql = "update ".getTable("item")
371                               ." set "." description='".rss_real_escape_string($description)."', "
372                               //." unread = unread | ".RSS_MODE_UNREAD_STATE
373                               ." md5sum='$md5sum'" . " where cid=$cid and id=$indb";
374                                               
375                        rss_query($sql);
376                       
377                        rss_query("update " .getTable('item2user') . " i2u set i2u.flgunread=1 where i2u.fkiid=$indb");
378                        $updatedIds[] = $indb;
379                        continue;
380                    }
381                }
382            } else { // $indb = "" . This must be new item then. In you go.
383
384                list ($cid, $dbtitle, $url, $description) =
385                    rss_plugin_hook('rss.plugins.items.new', array ($cid, $dbtitle, $url, $description));
386
387                $sql = "insert into ".getTable("item")
388                       ." (cid, added, title, url, enclosure,"
389                       ." description, author, pubdate, md5sum, guid) "
390                       ." values ("."$cid, now(), '$dbtitle', "
391                       ." '$url', '".rss_real_escape_string($enclosure)."', '"
392                       .rss_real_escape_string($description)."', '"
393                       .rss_real_escape_string($author)."', "
394                       ." $sec, '$md5sum', '$guid')";
395
396                rss_query($sql);
397
398                $newIid = rss_insert_id();
399                $uid=$GLOBALS['rssuser']->getUserId();
400                $prv=($mode & RSS_MODE_PRIVATE_STATE) ?"1":"0";
401                rss_query(
402                        "insert into " .getTable('item2user')
403                        ."  (fkiid,fkuid,fkcid,flgunread,flgprivate) "
404                        ." values ($newIid, $uid, $cid, 1, $prv) "
405                );
406               
407                $itemIdsInFeed[] = $newIid;
408                $updatedIds[] = $newIid;
409                rss_plugin_hook('rss.plugins.items.newiid',array($newIid,$item,$cid));
410            } // end handling of this item
411
412        } // end handling of all the items in this feed
413        $sql = "update " .getTable("channels") . " set "." itemsincache = '"
414               . serialize($itemIdsInFeed) . "' where id=$cid";
415        rss_query($sql);
416
417
418    } // end handling all the feeds we were asked to handle
419
420    if ($id != "" && is_numeric($id)) {
421        if ($rss) {
422            // when everything went well, return the error code
423            // and numer of new items
424            return array ($rss->rss_origin, $updatedIds);
425        } else {
426            return array (-1, array ());
427        }
428    } else {
429        return array (-1, $updatedIds);
430    }
431}
432
433function getRootFolder() {
434    $sql = "select id from ".getTable("folders")."where name = '' order by position asc limit 1";
435    list($root) = rss_fetch_row(rss_query($sql));
436
437    if (!$root) {
438        $root = 0;
439    }
440
441    return $root;
442}
443
444function add_channel($url, $folderid = 0, $title_=null,$descr_=null,$tags = null) {
445    if (!$url || strlen($url) <= 7) {
446        return array (-2, "Invalid URL $url");
447    }
448    if (!is_numeric($folderid)) {
449        return array (-2, "Invalid folderid $folderid");
450    }
451
452    $url = sanitize(str_replace('&amp;','&',$url), RSS_SANITIZER_URL);
453
454    $urlDB = rss_real_escape_string($url); //htmlentities($url);
455
456    $res = rss_query("select count(*) as channel_exists from ".getTable("channels")." where url='$urlDB'");
457    list ($channel_exists) = rss_fetch_row($res);
458    if ($channel_exists > 0) {
459        // fatal
460        return array (-2, "Looks like you are already subscribed to this channel");
461    }
462
463    $res = rss_query("select 1+max(position) as np from ".getTable("channels"));
464    list ($np) = rss_fetch_row($res);
465
466    if (!$np) {
467        $np = "0";
468    }
469
470    // Here we go!
471    //error_reporting(E_ALL);
472    $old_level = error_reporting(E_ERROR);
473    $rss = fetch_rss($url);
474    error_reporting($old_level);
475
476
477    if ($rss) {
478        if ($title_) {
479            $title = rss_real_escape_string($title_);
480        }
481        elseif (is_object($rss) && array_key_exists('title#', $rss->channel)) {
482                if (array_key_exists('title', $rss->channel)) {
483                $title = rss_real_escape_string($rss->channel['title']);
484            } else {
485                $title = " ";
486            }
487        }
488        else {
489            $title = "";
490        }
491
492        if (is_object($rss) && array_key_exists('link', $rss->channel)) {
493            $siteurl = rss_real_escape_string(htmlentities($rss->channel['link']));
494        } else {
495            $siteurl = "";
496        }
497
498        if ($descr_) {
499            $descr = rss_real_escape_string($descr_);
500        }
501        elseif  (is_object($rss) && array_key_exists('description', $rss->channel)) {
502            $descr = rss_real_escape_string($rss->channel['description']);
503        }
504        else {
505            $descr = "";
506        }
507
508        //lets see if this server has a favicon
509        $icon = "";
510        if (getConfig('rss.output.showfavicons')) {
511            // if we got nothing so far, lets try to fall back to
512            // favicons
513            if ($icon == "" && $siteurl != "") {
514                $match = get_host($siteurl, $host);
515                $uri = "http://".$host."favicon.ico";
516                if ($match && getContentType($uri, $contentType)) {
517                    if (preg_match("/image\/x-icon/", $contentType)) {
518                        $icon = $uri;
519                    }
520                }
521            }
522        }
523
524        $private = preg_match('|(https?://)([^:]+:[^@]+@)(.+)$|',$url);
525
526        if ($title != "") {
527            $title = strip_tags($title);
528            $descr = strip_tags($descr);
529
530            // add channel to root folder by default
531            if(!$folderid) {
532                $folderid = getRootFolder();
533            }
534
535            list($title,$urlDB,$siteurl,$folderid,$descr,$icon) =
536                rss_plugin_hook('rss.plugins.feed.new',
537                                array ($title,$urlDB,$siteurl,$folderid,$descr,$icon));
538
539            $mode = RSS_MODE_UNREAD_STATE;
540            if ($private) {
541                $mode |= RSS_MODE_PRIVATE_STATE;
542            }
543           
544            $sql = "insert into ".getTable("channels")
545                   ." (title, url, siteurl, parent, descr, dateadded, icon, position, mode, daterefreshed)"
546                   ." values ('$title', '$urlDB', '$siteurl', $folderid, '$descr', now(), '$icon', $np, $mode, '0000-00-00 00:00:00')";
547
548            rss_query($sql);
549            $newid = rss_insert_id();
550
551            if ($icon && cacheFavicon($icon)) {
552                rss_query("update " . getTable("channels") . " set icon='blob:".$icon."'"
553                          ." where id=$newid");
554            }
555
556            if($tags != ""){
557                __exp__submitTag($newid,$tags,"'channel'");
558            }
559
560            return array ($newid, "");
561
562        } else {
563            // non-fatal, will look further
564            return array (-1, "I'm sorry, I couldn't extract a valid RSS feed from <a href=\"$url\">$url</a>.");
565        }
566    } else {
567        global $MAGPIE_ERROR;
568        $retError = "I'm sorry, I couldn't retrieve <a href=\"$url\">$url</a>.";
569        if ($MAGPIE_ERROR) {
570            $retError .= "\n<br />$MAGPIE_ERROR\n";
571        }
572        // non-fatal, will look further
573        return array (-1, $retError);
574    }
575}
576
577/**
578 * Replaces relative urls with absolute ones for anchors and images
579 * Credits: Julien Mudry
580 */
581function relative_to_absolute($content, $feed_url) {
582    preg_match('/(http|https|ftp):\/\//', $feed_url, $protocol);
583    $server_url = preg_replace("/(http|https|ftp|news):\/\//", "", $feed_url);
584    $server_url = preg_replace("/\/.*/", "", $server_url);
585
586    if ($server_url == '') {
587        return $content;
588    }
589
590    if (isset($protocol[0])) {
591        $new_content = preg_replace('/href="\//', 'href="'.$protocol[0].$server_url.'/', $content);
592        $new_content = preg_replace('/src="\//', 'src="'.$protocol[0].$server_url.'/', $new_content);
593    } else {
594        $new_content = $content;
595    }
596    return $new_content;
597}
598
599/**
600 * parse an ISO 8601 date, losely based on parse_w3cdtf from MagpieRSS
601 */
602function parse_iso8601($date_str) {
603# regex to match wc3dtf
604    $pat = "/(\d{4})-?(\d{2})-?(\d{2})T?(\d{2}):?(\d{2})(:?(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/";
605
606    if (preg_match($pat, $date_str, $match)) {
607        list ($year, $month, $day, $hours, $minutes, $seconds)
608        = array ($match[1], $match[2], $match[3], $match[4], $match[5], $match[6]);
609
610        // calc epoch for current date assuming GMT
611
612        $epoch = gmmktime($hours, $minutes, intval($seconds), $month, $day, $year);
613
614        $offset = 0;
615        if ($match[10] == 'Z') {
616            // zulu time, aka GMT
617
618        } else {
619            list ($tz_mod, $tz_hour, $tz_min) = array ($match[8], $match[9], $match[10]);
620
621            // zero out the variables
622
623            if (!$tz_hour) {
624                $tz_hour = 0;
625            }
626            if (!$tz_min) {
627                $tz_min = 0;
628            }
629
630            $offset_secs = (($tz_hour * 60) + $tz_min) * 60;
631
632            // is timezone ahead of GMT?     then subtract offset
633
634
635            if ($tz_mod == '+') {
636                $offset_secs = $offset_secs * -1;
637            }
638
639            $offset = $offset_secs;
640        }
641        $epoch = $epoch + $offset;
642        return $epoch;
643    } else {
644        return -1;
645    }
646}
647
648/**
649 * Returns the relative path of the install dir, e.g:
650 * http://host.com/thing/ -> "/thing/"
651 * http://host.com/ -> "/"
652 */
653function getPath($path='') {
654    static $ret;
655    if ($ret === NULL) {
656        $ret = dirname($_SERVER['PHP_SELF']);
657        if (defined('RSS_FILE_LOCATION') && eregi(RSS_FILE_LOCATION."\$", $ret)) {
658            $ret = substr($ret, 0, strlen($ret) - strlen(RSS_FILE_LOCATION));
659        }
660        if (substr($ret, -1) == "\\") { // Take off trailing backslash
661            $ret = substr($ret, 0, -1);
662        }
663        if (substr($ret, -1) != "/") {  // Add a frontslash
664            $ret .= "/";
665        }
666    }
667    return $ret . $path;
668
669}
670$dummy = getPath();
671
672/**
673 * builds an url for an archive link
674 */
675function makeArchiveUrl($ts, $channel, $cid, $dayView) {
676    $ret = getPath();
677    if (getConfig('rss.output.usemodrewrite')) {
678        if ($channel) {
679            $ret .= "$channel/";
680        }
681        $ret .= rss_date(($dayView ? 'Y/m/d/' : 'Y/m/'), $ts, false);
682    } else {
683        $ret .= "feed.php?";
684        if ($cid) {
685            $ret .= "channel=$cid&amp;";
686        }
687        $ret .= "y=".rss_date('Y', $ts, false)
688                ."&amp;m=".rss_date('m', $ts, false)
689                . ($dayView ? ("&amp;d=".rss_date('d', $ts, false)) : "");
690    }
691    return $ret;
692}
693
694/**
695 * Fetches a remote URL and returns the content
696 */
697function getUrl($url, $maxlen = 0) {
698    //Bug: in windows, scheme returned by parse_url contains the drive letter
699    //of the file so a test like !isset(scheme) does not work
700    //maybe it would be better to only use is_file() which only detect
701    //local files?
702    $urlParts = parse_url($url);
703    if (@is_file($url) || (!isset($urlParts['scheme']) && !isset($urlParts['host'])) ) {
704        //local file!
705        $c = "";
706        $h = @fopen($url, "r");
707        if ($h) {
708            while (!feof($h)) {
709                $c .= @fread($h, 8192);
710            }
711        }
712        @fclose($h);
713        return $c;
714    }
715
716    rss_require('extlib/Snoopy.class.inc');
717    $client = new Snoopy();
718    $client->agent = MAGPIE_USER_AGENT;
719    $client->use_gzip = getConfig('rss.output.compression');
720
721    if ($maxlen) {
722        $client->maxlength = $maxlen;
723    }
724    @ $client->fetch($url);
725    return $client->results;
726}
727
728/**
729 * Feed Autodiscovery
730 *
731 * returns an array of all (hopefully) rss/atom/rdf feeds in the document,
732 * pointed by $url.
733 * See http://diveintomark.org/archives/2002/06/02/important_change_to_the_link_tag
734 *
735 * @param string $url URL of a web document containing <link> elements
736 * @return array Array of feed URLs
737 */
738function extractFeeds($url) {
739    $cnt = getUrl($url);
740    $ret = array ();
741    //find all link tags
742    if (preg_match_all('|<link\s+\w*=["\'][^"\']+["\']+[^>]*>|Uis', $cnt, $res)) {
743        while (list ($id, $match) = each($res[0])) {
744            // we only want '<link alternate=...'
745            if (strpos(strtolower($match), 'alternate') &&
746                    !strpos(strtolower($match), 'stylesheet')  && // extract the attributes
747                    preg_match_all('|([a-zA-Z]*)=["\']([^"\']*)|', $match, $res2, PREG_SET_ORDER)) {
748                $tmp = array ();
749                //populate the return array: attr_name => attr_value
750                while (list ($id2, $match2) = each($res2)) {
751                    $attr = strtolower(trim($match2[1]));
752                    $val = trim($match2[2]);
753                    // make sure we have absolute URI's
754                    if (($attr == "href") && strcasecmp(substr($val, 0, 4), "http") != 0) {
755                        // Check to see if the relative url starts with "//"
756                        if(substr($val,0,2) == "//") {
757                            $val = preg_replace('/\/\/.*/', $val, $url);
758                        } else {
759                            $urlParts = parse_url($url);
760                            if ($urlParts && is_array($urlParts) && strlen($val)) {
761                                if ($val[0] != '/') {
762                                    $val = '/'.$val;
763                                }
764                                $val = $urlParts['scheme'] . '://'
765                                       .$urlParts['host'] . $val;
766                            } else {
767                                $val = ($url.$val);
768                            }
769                        }
770                    }
771                    $tmp[$attr] = $val;
772                }
773                $ret[] = $tmp;
774            }
775        }
776    }
777    return $ret;
778}
779
780function real_strip_slashes($string) {
781    if (stripslashes($string) == $string) {
782        return $string;
783    }
784    return real_strip_slashes(stripslashes($string));
785}
786
787function rss_htmlspecialchars($in) {
788    return htmlspecialchars($in, ENT_NOQUOTES,
789                            (getConfig('rss.output.encoding') ? getConfig('rss.output.encoding') : DEFAULT_OUTPUT_ENCODING));
790}
791
792function firstNwords($text, $count=7) {
793    $new = "";
794    $expr = '/(.+?\s+){1,' . $count . '}/';
795    if ( preg_match($expr, $text, $matches) ) {
796        $result = $matches[0] . '...';
797        $new = preg_replace('/(\r\n|\r|\n)/', ' ', $result);
798        $new = strip_tags($new);
799    }
800    return $new;
801}
802
803/** Props: mr at bbp dot biz - http://ch2.php.net/substr */
804function html_substr($posttext, $minimum_length = 200, $length_offset = 20, $cut_words = FALSE, $dots = TRUE) {
805
806    // $minimum_length:
807    // The approximate length you want the concatenated text to be
808
809
810    // $length_offset:
811    // The variation in how long the text can be in this example text
812    // length will be between 200 and 200-20=180 characters and the
813    // character where the last tag ends
814
815    // Reset tag counter & quote checker
816    $tag_counter = 0;
817    $quotes_on = FALSE;
818    // Check if the text is too long
819    if (strlen($posttext) > $minimum_length) {
820        // Reset the tag_counter and pass through (part of) the entire text
821        $c = 0;
822        for ($i = 0; $i < strlen($posttext); $i++) {
823            // Load the current character and the next one
824            // if the string has not arrived at the last character
825            $current_char = substr($posttext,$i,1);
826            if ($i < strlen($posttext) - 1) {
827                $next_char = substr($posttext,$i + 1,1);
828            } else {
829                $next_char = "";
830            }
831            // First check if quotes are on
832            if (!$quotes_on) {
833                // Check if it's a tag
834                // On a "<" add 3 if it's an opening tag (like <a href...)
835                // or add only 1 if it's an ending tag (like </a>)
836                if ($current_char == '<') {
837                    if ($next_char == '/') {
838                        $tag_counter += 1;
839                    } else {
840                        $tag_counter += 3;
841                    }
842                }
843                // Slash signifies an ending (like </a> or ... />)
844                // substract 2
845                if ($current_char == '/' && $tag_counter <> 0)
846                    $tag_counter -= 2;
847                // On a ">" substract 1
848                if ($current_char == '>')
849                    $tag_counter -= 1;
850                // If quotes are encountered, start ignoring the tags
851                // (for directory slashes)
852                if ($current_char == '"')
853                    $quotes_on = TRUE;
854            } else {
855                // IF quotes are encountered again, turn it back off
856                if ($current_char == '"')
857                    $quotes_on = FALSE;
858            }
859
860            // Count only the chars outside html tags
861            if($tag_counter == 2 || $tag_counter == 0) {
862                $c++;
863            }
864
865            // Check if the counter has reached the minimum length yet,
866            // then wait for the tag_counter to become 0, and chop the string there
867            if ($c > $minimum_length - $length_offset && $tag_counter == 0 && ($next_char == ' ' || $cut_words == TRUE)) {
868                $posttext = substr($posttext,0,$i + 1);
869                if($dots) {
870                    $posttext .= '...';
871                }
872                return $posttext;
873            }
874        }
875    }
876    return $posttext;
877}
878
879
880function showViewForm($curValue) {
881
882    //default: read and unread!
883    $readAndUndredaSelected = " selected=\"selected\"";
884    $unreadOnlySelected = "";
885    if ($curValue == SHOW_UNREAD_ONLY) {
886        $readAndUndredaSelected = "";
887        $unreadOnlySelected = " selected=\"selected\"";
888    }
889
890    // post back to self, we should be able to handle the request, shouldn't we.
891    echo "\n<form action=\"".$_SERVER['REQUEST_URI']
892    ."\" method=\"post\" id=\"frmShow\">\n"
893    ."<p><label for=\"".SHOW_WHAT."\">".__('Show items: ')."</label>\n"
894    ."<select name=\"".SHOW_WHAT."\" id=\"".SHOW_WHAT."\" "." onchange=\"document.getElementById('frmShow').submit();\">\n"
895    ."\t<option value=\"".SHOW_UNREAD_ONLY."\"$unreadOnlySelected>".__('Unread only')."</option>\n"
896    ."\t<option value=\"".SHOW_READ_AND_UNREAD."\"$readAndUndredaSelected>".__('Read and unread')."</option>\n"
897    ."</select></p>\n</form>\n";
898}
899
900
901
902function getUnreadCount($cid, $fid) {
903    static $_uccache = array();
904    $key_ = "key $cid $fid key";
905    if (isset($_uccache[$key_])) {
906        return $_uccache[$key_];
907    }
908
909    $sql = "select count(*) from " . getTable("item2user") ."i2u "
910                . "inner join " . getTable('channels') . "c on i2u.fkcid=c.id "
911                ." where i2u.fkuid = " . rss_user_id()
912                ." and i2u.flgunread=1 and i2u.flgdeleted=0 "
913                ." and not(c.mode & ".RSS_MODE_DELETED_STATE.") ";
914
915    if (hidePrivate()) {
916        $sql .= " and i2u.flgprivate=0";
917    }
918
919    if ($cid) {
920        $sql .= " and c.id=$cid ";
921    }
922    elseif ($fid) {
923        $sql .= " and c.parent=$fid ";
924    }
925
926    $res = rss_query($sql);
927
928    list ($_uccache[$key_]) = rss_fetch_row($res);
929    return $_uccache[$key_];
930}
931
932function rss_locale_date ($fmt, $ts, $addTZOffset = true) {
933
934    if (isset($_SERVER["WINDIR"])) {
935        //%e doesnt' exists under windows!
936        $fmt=str_replace("%e","%#d",$fmt);
937    }
938
939    if ($addTZOffset) {
940        return utf8_encode(strftime($fmt, $ts +3600 * getConfig('rss.config.tzoffset')));
941    }
942    return utf8_encode(strftime($fmt, $ts));
943}
944
945function rss_date($fmt, $ts, $addTZOffset = true) {
946    if ($addTZOffset) {
947        return date($fmt, $ts +3600 * getConfig('rss.config.tzoffset'));
948    }
949    return date($fmt, $ts);
950
951}
952
953function _pf($msg) {
954    if (defined('PROFILING') && PROFILING && isset($GLOBALS['rss']) && method_exists($GLOBALS['rss'], "_pf")) {
955        $GLOBALS['rss'] -> _pf($msg);
956    }
957}
958
959
960function guessTransportProto() {
961
962    if (defined ('RSS_SERVER_PROTO')) {
963        return RSS_SERVER_PROTO;
964    }
965
966    if (array_key_exists("SERVER_PORT",$_SERVER)) {
967        if ($_SERVER["SERVER_PORT"] == 443) {
968            $proto = "https://";
969        } else {
970            $proto = "http://";
971        }
972    } else {
973        // best effort
974        $proto = "http://";
975    }
976    return $proto;
977}
978
979function rss_redirect($url = "") {
980    header("Location: " .
981           (guessTransportProto() . $_SERVER['HTTP_HOST'] . getPath() . $url));
982}
983
984/*
985fixes #117.
986http://www.php.net/manual/en/function.getallheaders.php
987*/
988function rss_getallheaders() {
989    $headers = array();
990    foreach($_SERVER as $h=>$v) {
991        if(ereg('HTTP_(.+)',$h,$hp)) {
992            $headers[$hp[1]]=$v;
993        }
994    }
995    return $headers;
996}
997
998// moved from ajax.php
999function __exp__submitTag($id,$tags,$type = "'item'") {
1000    $ftags = utf8_encode( preg_replace(ALLOWED_TAGS_REGEXP,'', trim($tags)));
1001    $tarr = array_slice(explode(" ",$ftags),0,MAX_TAGS_PER_ITEM);
1002    $ftags = implode(" ",__priv__updateTags($id,$tarr,$type));
1003    return "$id,". $ftags;
1004}
1005
1006function __priv__updateTags($fid,$tags,$type) {
1007    rss_query("delete from " .getTable('metatag')
1008              . " where fid=$fid and ttype=$type");
1009    $ret = array();
1010    foreach($tags as $tag) {
1011        $ttag = trim($tag);
1012        if ($ttag == "" || in_array($ttag,$ret)) {
1013            continue;
1014        }
1015        rss_query( "insert into ". getTable('tag')
1016                   . " (tag) values ('$ttag')", false );
1017        $tid = 0;
1018        if(rss_is_sql_error(RSS_SQL_ERROR_DUPLICATE_ROW)) {
1019            list($tid)=rss_fetch_row(rss_query("select id from "
1020                                               .getTable('tag') . " where tag='$ttag'"));
1021        } else {
1022            $tid = rss_insert_id();
1023        }
1024        if ($tid) {
1025            rss_query( "insert into ". getTable('metatag')
1026                       . " (fid,tid,ttype,tdate) values ($fid,$tid,$type,now())" );
1027            if (rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR)) {
1028                $ret[] = $ttag;
1029            }
1030        }
1031    }
1032
1033    rss_invalidate_cache();
1034
1035    sort($ret);
1036    return $ret;
1037}
1038
1039
1040
1041/**
1042 * this was taken straight from WordPress
1043 */
1044function utf8_uri_encode( $utf8_string ) {
1045    $unicode = '';
1046    $values = array();
1047    $num_octets = 1;
1048
1049    for ($i = 0; $i < strlen( $utf8_string ); $i++ ) {
1050
1051        $value = ord( $utf8_string[ $i ] );
1052
1053        if ( $value < 128 ) {
1054            $unicode .= chr($value);
1055        } else {
1056            if ( count( $values ) == 0 )
1057                $num_octets = ( $value < 224 ) ? 2 : 3;
1058
1059            $values[] = $value;
1060
1061            if ( count( $values ) == $num_octets ) {
1062                if ($num_octets == 3) {
1063                    $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]);
1064                } else {
1065                    $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]);
1066                }
1067
1068                $values = array();
1069                $num_octets = 1;
1070            }
1071        }
1072    }
1073
1074    return $unicode;
1075}
1076
1077/*
1078// Deprecated in favor of the new core.php functionalities
1079function ETagHandler($key) {
1080    // This function should be used inline for speed. However if you have already
1081    // included util.php you might as well use it.
1082    if (array_key_exists('HTTP_IF_NONE_MATCH',$_SERVER) &&
1083            $_SERVER['HTTP_IF_NONE_MATCH'] == $key) {
1084        header("HTTP/1.1 304 Not Modified");
1085        flush();
1086        exit();
1087    } else {
1088        header("ETag: $key");
1089        // ob_start('ob_gzhandler');
1090    }
1091}
1092*/
1093//these two eval_ functions taken from the comments at http://us3.php.net/eval
1094
1095function eval_mixed_helper($arr) {
1096    return ("echo stripslashes(\"".addslashes($arr[1])."\");");
1097}
1098
1099function eval_mixed($string) {
1100    $string = "<? ?>".$string."<? ?>";
1101    $string = preg_replace("/<\?=\s+(.*?)\s+\?>/", "<? echo $1; ?>", $string);
1102    $string = str_replace('?>', '', str_replace( array('<?php', '<?'), '', preg_replace_callback( "/\?>((.|\n)*?)<\?(php)?/","eval_mixed_helper",$string) ) );
1103    return $string;
1104}
1105
1106
1107function rss_svn_rev($prefix='.') {
1108    static $ret;
1109    if ($ret != NULL) {
1110        return $ret;
1111    }
1112    if (file_exists(GREGARIUS_HOME .'.svn/dir-wcprops')) {
1113        $raw=getUrl(GREGARIUS_HOME .'.svn/dir-wcprops');
1114        if ($raw && preg_match('#ver/([0-9]+)/#',$raw,$matches) && isset($matches[1])) {
1115            $ret = $prefix . $matches[1];
1116        }
1117    } else {
1118        $ret = "";
1119    }
1120    return $ret;
1121}
1122
1123function cacheFavicon($icon) {
1124         // Make sure only real favicons get fetched into the DB
1125         if (! preg_match('#^https?://.+$#',$icon)) {
1126                return false;
1127         }
1128         
1129    $icon_ = rss_real_escape_string($icon);
1130    $binIcon = getUrl($icon);
1131    if ($binIcon) {
1132        $sql = "delete from " . getTable('cache')
1133               ." where cachetype='icon' and cachekey='$icon_'";
1134        rss_query($sql);
1135        $sql = "insert into ". getTable('cache')
1136               ."(cachekey,timestamp,cachetype,data) values "
1137               ."('$icon_',now(),'icon','".rss_real_escape_string($binIcon)."')";
1138        rss_query($sql);
1139        return rss_is_sql_error(RSS_SQL_ERROR_NO_ERROR);
1140    }
1141    return false;
1142}
1143
1144function sanitize($input, $rules = 0) {
1145    $ret = $input;
1146    if ($rules & RSS_SANITIZER_SIMPLE_SQL) {
1147        $ret = rss_real_escape_string($ret);
1148    }
1149    if ($rules & RSS_SANITIZER_NO_SPACES) {
1150        $ret = preg_replace('#\s#','',$ret);
1151        // also strip out SQL comments
1152        $ret = preg_replace('#/\*.*\*/#','',$ret);
1153    }
1154    if ($rules & RSS_SANITIZER_NUMERIC) {
1155        $ret = preg_replace('#[^0-9\.-]#','',$ret);
1156    }
1157    if ($rules & RSS_SANITIZER_CHARACTERS) {
1158        $ret = preg_replace('#[^a-zA-Z]#','',$ret);
1159    }
1160    if ($rules & RSS_SANITIZER_CHARACTERS_EXT) {
1161        $ret = preg_replace('#[^a-zA-Z_]#','',$ret);
1162    }
1163    if ($rules & RSS_SANITIZER_WORDS) {
1164        $ret = preg_replace('#[^a-zA-Z0-9\-\._]#','',$ret);
1165    }
1166    if ($rules & RSS_SANITIZER_URL) {
1167        // filter out "unsafe" characters: {,},|,\,^,<,>
1168        $ret = preg_replace('#[{}\|\\\^<>]#','',$ret);
1169    }
1170    return $ret;
1171}
1172
1173function hidePrivate() {
1174        if (!isset($GLOBALS['rssuser'])) {
1175                require_once('cls/user.php');
1176        }
1177        return !rss_user_check_user_level(RSS_USER_LEVEL_PRIVATE);
1178}
1179
1180// Send a crappy 404 (to save bandwidth) for webbots
1181function rss_404() {
1182        header("HTTP/1.1 404 Not Found");
1183        echo "404 Page Not Found\n";
1184}
1185
1186?>
Note: See TracBrowser for help on using the browser.