├── site_config
├── standard
│ ├── version.txt
│ └── .wikipedia.org.txt
├── index.php
├── custom
│ └── index.php
└── README.txt
├── cache
├── index.php
├── rss
│ └── index.php
└── urls
│ └── index.php
├── images
└── agplv3.png
├── manifest.yml
├── css
├── feed.css
└── feed.xsl
├── libraries
├── Zend
│ ├── Cache
│ │ ├── Exception.php
│ │ ├── Backend
│ │ │ ├── Interface.php
│ │ │ └── ExtendedInterface.php
│ │ └── Backend.php
│ └── Exception.php
├── language-detect
│ ├── LanguageDetect
│ │ └── Exception.php
│ └── unicode_blocks.dat
├── html5
│ ├── Parser.php
│ └── Data.php
├── simplepie
│ ├── LICENSE.txt
│ ├── library
│ │ └── SimplePie
│ │ │ ├── Exception.php
│ │ │ ├── Core.php
│ │ │ ├── Cache
│ │ │ ├── Base.php
│ │ │ ├── File.php
│ │ │ ├── DB.php
│ │ │ └── Memcache.php
│ │ │ ├── Copyright.php
│ │ │ ├── Rating.php
│ │ │ ├── Author.php
│ │ │ ├── Category.php
│ │ │ ├── Credit.php
│ │ │ ├── Restriction.php
│ │ │ ├── Cache.php
│ │ │ ├── Caption.php
│ │ │ ├── Registry.php
│ │ │ ├── Net
│ │ │ └── IPv6.php
│ │ │ ├── XML
│ │ │ └── Declaration
│ │ │ │ └── Parser.php
│ │ │ └── Content
│ │ │ └── Type
│ │ │ └── Sniffer.php
│ └── autoloader.php
├── humble-http-agent
│ └── SimplePie_HumbleHttpAgent.php
├── readability
│ ├── JSLikeHTMLElement.php
│ └── ImageCaching.php
└── feedwriter
│ └── FeedItem.php
├── README.txt
├── admin
├── require_login.php
├── index.php
├── codemirror
│ ├── properties.js
│ └── codemirror.css
├── login.php
└── template.php
├── UPDATING.txt
├── custom_config.php.demo
├── js
├── bootstrap-popover.js
├── bootstrap-tab.js
└── bootstrap-tooltip.js
├── README.md
├── cleancache.php
└── changelog.txt
/site_config/standard/version.txt:
--------------------------------------------------------------------------------
1 | 2013-05-12T22:53:07Z
--------------------------------------------------------------------------------
/site_config/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cache/rss/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/agplv3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dither/full-text-rss/HEAD/images/agplv3.png
--------------------------------------------------------------------------------
/cache/urls/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/site_config/custom/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/site_config/README.txt:
--------------------------------------------------------------------------------
1 | Full-Text RSS Site Patterns
2 | ---------------------------
3 |
4 | Site patterns allow you to specify what should be extracted from specific sites.
5 |
6 | Please see http://help.fivefilters.org/customer/portal/articles/223153-site-patterns for more information.
--------------------------------------------------------------------------------
/manifest.yml:
--------------------------------------------------------------------------------
1 | # This file is only used when deploying Full-Text RSS to AppFog.
2 | # See http://help.fivefilters.org/customer/portal/articles/1143210-hosting
3 | ---
4 | applications:
5 | .:
6 | # name: full-text-rss
7 | framework:
8 | name: php
9 | info:
10 | mem: 512M
11 | description: PHP Application
12 | exec:
13 | infra: aws
14 | # url: ${name}.${target-base}
15 | mem: 512M
16 | instances: 1
17 |
--------------------------------------------------------------------------------
/site_config/standard/.wikipedia.org.txt:
--------------------------------------------------------------------------------
1 | title: //h1[@id='firstHeading']
2 | body: //div[@id = 'bodyContent']
3 | strip_id_or_class: editsection
4 | #strip_id_or_class: toc
5 | strip_id_or_class: vertical-navbox
6 | strip: //table[@id='toc']
7 | strip: //div[@id='catlinks']
8 | strip: //div[@id='jump-to-nav']
9 | strip: //div[@class='thumbcaption']//div[@class='magnify']
10 | strip: //table[@class='navbox']
11 | strip: //table[contains(@class, 'infobox')]
12 | strip: //div[@class='dablink']
13 | strip: //div[@id='contentSub']
14 | strip: //table[contains(@class, 'metadata')]
15 | strip: //*[contains(@class, 'noprint')]
16 | strip: //span[@title='pronunciation:']
17 | prune: no
18 | tidy: no
19 | test_url: http://en.wikipedia.org/wiki/Christopher_Lloyd
--------------------------------------------------------------------------------
/css/feed.css:
--------------------------------------------------------------------------------
1 | /* RSS CSS Document */
2 |
3 | * { margin:0; padding:0; }
4 |
5 | p { padding: .5em 0; }
6 |
7 | h1,h2,h3,h4,h5,h6 { font-size: 1em; padding: .5em 0; }
8 |
9 | html { display:block; padding-bottom:50px; }
10 | body { font:80% Verdana, sans-serif; color:#000; padding:25px 0 0 35px; }
11 |
12 | a { color:#5BAB03; text-decoration:none; }
13 | a:hover { color:#5BAB03; text-decoration: underline;}
14 |
15 | ul { margin-left:1.5em; }
16 | li { margin-bottom:0.4em; }
17 | div#content>ul { list-style-type: none; }
18 | div.article>li>a { font-weight:bold; font-size: 1.3em;}
19 |
20 |
21 | div { line-height:1.6em; }
22 |
23 | div#content { background:#fff; margin-right:15px; padding-left:1em;}
24 | div#content div { margin:0 1em 1em 0; }
25 |
26 | div#explanation { padding:1em 1em 0 1em; border:1px solid #ddd; background:#efefef; margin:0 2em 2em 0; }
27 | div#explanation h1 { font-weight:normal; font-size:1.8em; margin-bottom:0.3em; }
28 | div#explanation p { margin-bottom:1em; }
29 |
30 | .small { font-size: .7em; color: #666; }
--------------------------------------------------------------------------------
/libraries/Zend/Cache/Exception.php:
--------------------------------------------------------------------------------
1 | parse();
22 | return $tokenizer->save();
23 | }
24 | /**
25 | * Parses an HTML fragment.
26 | * @param $text HTML text to parse
27 | * @param $context String name of context element to pretend parsing is in.
28 | * @param $builder Custom builder implementation
29 | * @return Parsed HTML as DOMDocument
30 | */
31 | static public function parseFragment($text, $context = null, $builder = null) {
32 | $tokenizer = new HTML5_Tokenizer($text, $builder);
33 | $tokenizer->parseFragment($context);
34 | return $tokenizer->save();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/admin/require_login.php:
--------------------------------------------------------------------------------
1 | .
23 | */
24 |
25 | // Usage
26 | // -----
27 | // This file is included on pages which require admin privileges - e.g. updating the software.
28 | // The username is 'admin' by default and the password should be set in the custom_config.php file.
29 | session_start();
30 | require_once(dirname(dirname(__FILE__)).'/config.php');
31 |
32 | if (isset($_GET['logout'])) $_SESSION['auth'] = 0;
33 |
34 | if (!isset($_SESSION['auth']) || $_SESSION['auth'] != 1) {
35 | if (isset($admin_page)) {
36 | header('Location: login.php?redirect='.$admin_page);
37 | } else {
38 | header('Location: login.php');
39 | }
40 | exit;
41 | }
--------------------------------------------------------------------------------
/libraries/simplepie/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2004-2007, Ryan Parman and Geoffrey Sneddon.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification, are
5 | permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this list of
8 | conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice, this list
11 | of conditions and the following disclaimer in the documentation and/or other materials
12 | provided with the distribution.
13 |
14 | * Neither the name of the SimplePie Team nor the names of its contributors may be used
15 | to endorse or promote products derived from this software without specific prior
16 | written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
19 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
21 | AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/css/feed.xsl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | (full-text feed)
9 |
12 |
13 |
14 |
15 |
(full-text feed)
16 |
You are viewing an auto-generated full-text RSS feed. RSS feeds allow you to stay up to date with the latest news and features you want from websites. To subscribe to it, you will need a News Reader or other similar device.
17 |
Below is the latest content available from this feed.
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/admin/index.php:
--------------------------------------------------------------------------------
1 | .
23 | */
24 |
25 | // Usage
26 | // -----
27 | // Access this file in your browser
28 |
29 | error_reporting(E_ALL ^ E_NOTICE);
30 | ini_set("display_errors", 1);
31 | @set_time_limit(120);
32 |
33 | ////////////////////////////////
34 | // Load config file
35 | ////////////////////////////////
36 | require_once('../config.php');
37 | require_once('require_login.php');
38 | require_once('template.php');
39 | tpl_header('Admin');
40 |
41 | ?>
42 |
The admin pages are intended to help you manage your copy of Full-Text RSS more easily.
43 |
44 | Update patterns : an easy way to keep site config files up to date.
45 | Edit patterns : need to fine-tune extraction for a certain site? Use this tool.
46 | APC : If APC is enabled, you can use this tool to see what Full-Text RSS caches, and clear the cache if you need to.
47 |
--------------------------------------------------------------------------------
/admin/codemirror/properties.js:
--------------------------------------------------------------------------------
1 | CodeMirror.defineMode("properties", function() {
2 | return {
3 | token: function(stream, state) {
4 | var sol = stream.sol() || state.afterSection;
5 | var eol = stream.eol();
6 |
7 | state.afterSection = false;
8 |
9 | if (sol) {
10 | if (state.nextMultiline) {
11 | state.inMultiline = true;
12 | state.nextMultiline = false;
13 | } else {
14 | state.position = "def";
15 | }
16 | }
17 |
18 | if (eol && ! state.nextMultiline) {
19 | state.inMultiline = false;
20 | state.position = "def";
21 | }
22 |
23 | if (sol) {
24 | while(stream.eatSpace());
25 | }
26 |
27 | var ch = stream.next();
28 |
29 | if (sol && (ch === "#")) {
30 | state.position = "comment";
31 | stream.skipToEnd();
32 | return "comment";
33 | } else if (sol && ch === "[") {
34 | state.afterSection = true;
35 | stream.skipTo("]"); stream.eat("]");
36 | return "header";
37 | } else if (ch === ":") {
38 | state.position = "quote";
39 | return null;
40 | } else if (ch === "\\" && state.position === "quote") {
41 | if (stream.next() !== "u") { // u = Unicode sequence \u1234
42 | // Multiline value
43 | state.nextMultiline = true;
44 | }
45 | }
46 |
47 | return state.position;
48 | },
49 |
50 | startState: function() {
51 | return {
52 | position : "def", // Current position, "def", "quote" or "comment"
53 | nextMultiline : false, // Is the next line multiline value
54 | inMultiline : false, // Is the current line a multiline value
55 | afterSection : false // Did we just open a section
56 | };
57 | }
58 |
59 | };
60 | });
61 |
62 | CodeMirror.defineMIME("text/x-properties", "properties");
63 | CodeMirror.defineMIME("text/x-ini", "properties");
64 |
--------------------------------------------------------------------------------
/admin/login.php:
--------------------------------------------------------------------------------
1 | admin_credentials) || $options->admin_credentials['username'] == '' || $options->admin_credentials['password'] == '') {
6 | die('Admin privileges required This page requires admin privileges but Full-Text RSS has not been configured with admin credentials.
If you are the administrator, please edit your custom_config.php file and enter the credentials in the appropriate section. When you\'ve done that, this page will prompt you for your admin credentials.
');
7 | }
8 |
9 | $name = @$_POST['username'];
10 | $pass = @$_POST['pass'];
11 | $invalid_login = false;
12 |
13 | if ($name || $pass) {
14 | if ($name == $options->admin_credentials['username'] && $pass == $options->admin_credentials['password']) {
15 | // Authentication successful - set session
16 | $_SESSION['auth'] = 1;
17 | if (isset($_POST['redirect']) && preg_match('/^[0-9a-z]+$/', $_POST['redirect'])) {
18 | header('Location: '.$_POST['redirect'].'.php');
19 | } else {
20 | header('Location: index.php');
21 | }
22 | exit;
23 | }
24 | $invalid_login = true;
25 | }
26 | ?>
27 |
28 |
29 | Login
30 |
31 | Invalid login, please try again. If you can\'t remember your admin credentials, open your custom_config.php and you\'ll find them in there.'; ?>
32 |
38 |
39 |
--------------------------------------------------------------------------------
/UPDATING.txt:
--------------------------------------------------------------------------------
1 | Updating Full-Text RSS
2 | ======================
3 |
4 | To update your copy of Full-Text RSS to ensure feeds continue to be processed as they were before, we suggest the following steps:
5 |
6 | 1. Keep your current installation in place for now (we'll deal with it later)
7 |
8 | 2. Extract this updated package to a new folder -- for example, if the last version is in a folder called 'full-text-rss', extract this version to a new folder called 'full-text-rss-updated'
9 |
10 | 3. Upload the new folder to your server
11 |
12 | 4. Access index.php in the new folder through your browser -- for example http://example.org/full-text-rss-updated/index.php
13 |
14 | 5. Enter a URL in the form field to test the updated code
15 |
16 | 6. If you'd configured the last version, copy custom_config.php from your old version to the new installation.
17 |
18 | 7. If you'd added custom site config files (in site_config/custom/), copy those over to the new installation.
19 |
20 | 8. If you'd enabled caching, make sure the cache folder (and its 2 sub folders) is writable. (You might need to change the permissions of these folders to 777 through your FTP client.)
21 |
22 | 9. Test the new copy again to make sure the config values are now applied to the new version.
23 |
24 | 10. Now simply rename the folder with your old copy to 'full-text-rss-old' and then rename the folder with the new copy to 'full-text-rss' (or whatever name you'd given the original folder).
25 |
26 | That's all that's needed. Your feeds should continue to work as they did before. Let us know if you have any trouble: help@fivefilters.org.
27 |
28 | Updating Site Patterns
29 | ======================
30 |
31 | Site patterns are used by Full-Text RSS to improve extraction for certain sites. These are simple text files which are updated more frequently than the Full-Text RSS software itself.
32 |
33 | To make sure your copy of Full-Text RSS is using the latest site patterns, We've created a simple tool to help you get the latest copy of these site patterns from FiveFilters.org. To use it, access the admin/ folder in your browser and follow the instructions.
34 |
35 | Alternatively, you can download the latest set of site config files via GitHub: https://github.com/fivefilters/ftr-site-config
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Exception.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
33 |
34 |
35 |
57 |
58 |
59 | encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
37 | }
38 | $this->url = $url;
39 | $this->useragent = $useragent;
40 | if (preg_match('/^http(s)?:\/\//i', $url))
41 | {
42 | if (!is_array($headers))
43 | {
44 | $headers = array();
45 | }
46 | $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
47 | $headers2 = array();
48 | foreach ($headers as $key => $value) {
49 | $headers2[] = "$key: $value";
50 | }
51 | //TODO: allow for HTTP headers
52 | // curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
53 |
54 | $response = self::$agent->get($url);
55 |
56 | if ($response === false || !isset($response['status_code'])) {
57 | $this->error = 'failed to fetch URL';
58 | $this->success = false;
59 | } else {
60 | // The extra lines at the end are there to satisfy SimplePie's HTTP parser.
61 | // The class expects a full HTTP message, whereas we're giving it only
62 | // headers - the new lines indicate the start of the body.
63 | $parser = new SimplePie_HTTP_Parser($response['headers']."\r\n\r\n");
64 | if ($parser->parse()) {
65 | $this->headers = $parser->headers;
66 | //$this->body = $parser->body;
67 | $this->body = $response['body'];
68 | $this->status_code = $parser->status_code;
69 | }
70 | }
71 | }
72 | else
73 | {
74 | $this->error = 'invalid URL';
75 | $this->success = false;
76 | }
77 | }
78 | }
79 | ?>
--------------------------------------------------------------------------------
/libraries/Zend/Exception.php:
--------------------------------------------------------------------------------
1 | _previous = $previous;
48 | } else {
49 | parent::__construct($msg, (int) $code, $previous);
50 | }
51 | }
52 |
53 | /**
54 | * Overloading
55 | *
56 | * For PHP < 5.3.0, provides access to the getPrevious() method.
57 | *
58 | * @param string $method
59 | * @param array $args
60 | * @return mixed
61 | */
62 | public function __call($method, array $args)
63 | {
64 | if ('getprevious' == strtolower($method)) {
65 | return $this->_getPrevious();
66 | }
67 | return null;
68 | }
69 |
70 | /**
71 | * String representation of the exception
72 | *
73 | * @return string
74 | */
75 | public function __toString()
76 | {
77 | if (version_compare(PHP_VERSION, '5.3.0', '<')) {
78 | if (null !== ($e = $this->getPrevious())) {
79 | return $e->__toString()
80 | . "\n\nNext "
81 | . parent::__toString();
82 | }
83 | }
84 | return parent::__toString();
85 | }
86 |
87 | /**
88 | * Returns previous Exception
89 | *
90 | * @return Exception|null
91 | */
92 | protected function _getPrevious()
93 | {
94 | return $this->_previous;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/custom_config.php.demo:
--------------------------------------------------------------------------------
1 | debug = true;
4 | $options->default_entries = 15;
5 | $options->max_entries = 40;
6 | $options->summary = 'user';
7 | $options->rewrite_relative_urls = true;
8 | $options->exclude_items_on_fail = 'user';
9 | $options->multipage = true;
10 | $options->caching = true;
11 | $options->cache_dir = dirname(__FILE__).'/cache';
12 | $options->error_message = '[unable to retrieve full-text content]';
13 | $options->keep_enclosures = true;
14 | $options->detect_language = 1;
15 | $options->registration_key = '';
16 | $options->admin_credentials = array('username'=>'admin0', 'password'=>'admin0');
17 | // Non-empty example: array('example.com', 'anothersite.org');
18 | $options->allowed_urls = array();
19 | $options->blocked_urls = array();
20 | $options->favour_feed_titles = 'user';
21 | $options->xss_filter = 'user';
22 | $options->allowed_parsers = array('libxml', 'html5lib');
23 | $options->cors = false;
24 | $options->apc = true;
25 | $options->smart_cache = true;
26 | $options->cache_ttl = 60*60;
27 | $options->http_cache_ttl = 3*24*60*60;
28 | $options->fingerprints = array(
29 | // Posterous
30 | ' array('hostname'=>'fingerprint.posterous.com', 'head'=>true),
31 | // Blogger
32 | ' array('hostname'=>'fingerprint.blogspot.com', 'head'=>true),
33 | ' array('hostname'=>'fingerprint.blogspot.com', 'head'=>true),
34 | // WordPress (self-hosted and hosted)
35 | ' path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'library';
68 | }
69 |
70 | /**
71 | * Autoloader
72 | *
73 | * @param string $class The name of the class to attempt to load.
74 | */
75 | public function autoload($class)
76 | {
77 | // Only load the class if it starts with "SimplePie"
78 | if (strpos($class, 'SimplePie') !== 0)
79 | {
80 | return;
81 | }
82 |
83 | $filename = $this->path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
84 | include $filename;
85 | }
86 | }
--------------------------------------------------------------------------------
/js/bootstrap-popover.js:
--------------------------------------------------------------------------------
1 | /* ===========================================================
2 | * bootstrap-popover.js v2.0.3
3 | * http://twitter.github.com/bootstrap/javascript.html#popovers
4 | * ===========================================================
5 | * Copyright 2012 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * =========================================================== */
19 |
20 |
21 | !function ($) {
22 |
23 | "use strict"; // jshint ;_;
24 |
25 |
26 | /* POPOVER PUBLIC CLASS DEFINITION
27 | * =============================== */
28 |
29 | var Popover = function ( element, options ) {
30 | this.init('popover', element, options)
31 | }
32 |
33 |
34 | /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
35 | ========================================== */
36 |
37 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
38 |
39 | constructor: Popover
40 |
41 | , setContent: function () {
42 | var $tip = this.tip()
43 | , title = this.getTitle()
44 | , content = this.getContent()
45 |
46 | $tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
47 | $tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
48 |
49 | $tip.removeClass('fade top bottom left right in')
50 | }
51 |
52 | , hasContent: function () {
53 | return this.getTitle() || this.getContent()
54 | }
55 |
56 | , getContent: function () {
57 | var content
58 | , $e = this.$element
59 | , o = this.options
60 |
61 | content = $e.attr('data-content')
62 | || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
63 |
64 | return content
65 | }
66 |
67 | , tip: function () {
68 | if (!this.$tip) {
69 | this.$tip = $(this.options.template)
70 | }
71 | return this.$tip
72 | }
73 |
74 | })
75 |
76 |
77 | /* POPOVER PLUGIN DEFINITION
78 | * ======================= */
79 |
80 | $.fn.popover = function (option) {
81 | return this.each(function () {
82 | var $this = $(this)
83 | , data = $this.data('popover')
84 | , options = typeof option == 'object' && option
85 | if (!data) $this.data('popover', (data = new Popover(this, options)))
86 | if (typeof option == 'string') data[option]()
87 | })
88 | }
89 |
90 | $.fn.popover.Constructor = Popover
91 |
92 | $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
93 | placement: 'right'
94 | , content: ''
95 | , template: ''
96 | })
97 |
98 | }(window.jQuery);
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Full-Text RSS
2 | =============
3 |
4 | ### NOTE
5 |
6 | This is a our public version of Full-Text RSS available to download for free from .
7 |
8 | For best extraction results, and to help us sustain the project, you can purchase the most up-to-date version at - so if you like this free version, please consider supporting us by purchasing the latest release.
9 |
10 | If you have no need for the latest release, but would still like to contribute something, you can donate via [Gittip](https://www.gittip.com/fivefilters/) or [Flattr](https://flattr.com/profile/k1m).
11 |
12 | ### About
13 |
14 | See for a description of the code.
15 |
16 | ### Installation
17 |
18 | 1. Extract the files in this ZIP archive to a folder on your computer.
19 |
20 | 2. FTP the files up to your server
21 |
22 | 3. Access index.php through your browser. E.g. http://example.org/full-text-rss/index.php
23 |
24 | 4. Enter a URL in the form field to test the code
25 |
26 | 5. If you get an RSS feed with full-text content, all is working well. :)
27 |
28 | ### Configuration (optional)
29 |
30 | 1. Save a copy of config.php as custom_config.php and edit custom_config.php
31 |
32 | 2. If you decide to enable caching, make sure the cache folder (and its 2 sub folders) is writable. (You might need to change the permissions of these folders to 777 through your FTP client.)
33 |
34 | ### Site-specific extraction rules
35 |
36 | This free version does not contain the site config files we include with purchased copies, but these are now all available [online](https://github.com/fivefilters/ftr-site-config). If you'd like to keep yours up to date using Git, follow the steps below:
37 |
38 | 1. Change into the site_config/standard/ folder
39 | 2. Delete everything in there
40 | 3. Using the command line, enter: `git clone https://github.com/fivefilters/ftr-site-config.git .`
41 | 4. Git should now download the latest site config files for you.
42 | 5. To update the site config files again, you can simply run `git pull` from the directory.
43 |
44 | ### Code example
45 |
46 | If you're developing an application which requires content extraction, you can call Full-Text RSS as a web service from within your application. Here's how to do it in PHP:
47 |
48 | rss->channel->item);
69 |
70 | $title = $json->rss->channel->item->title;
71 | // Note: this works when you're processing an article.
72 | // If the input URL is a feed, ->item will be an array.
73 |
74 | echo $title;
75 |
76 | ### Different language?
77 |
78 | Although we don't have examples in other programming languages, the essential steps should be:
79 |
80 | 1. Construct the request URL using URL where you installed Full-Text RSS and the article or feed URL (see $ftr, $article, $request in example above).
81 |
82 | 2. Fetch the resulting URL using an HTTP GET request.
83 |
84 | 3. Parse the HTTP response body as JSON and grab what you need.
--------------------------------------------------------------------------------
/libraries/readability/JSLikeHTMLElement.php:
--------------------------------------------------------------------------------
1 | registerNodeClass('DOMElement', 'JSLikeHTMLElement');
16 | * $doc->loadHTML('');
17 | * $elem = $doc->getElementsByTagName('div')->item(0);
18 | *
19 | * // print innerHTML
20 | * echo $elem->innerHTML; // prints 'Para 1
Para 2
'
21 | * echo "\n\n";
22 | *
23 | * // set innerHTML
24 | * $elem->innerHTML = 'FiveFilters.org ';
25 | * echo $elem->innerHTML; // prints 'FiveFilters.org '
26 | * echo "\n\n";
27 | *
28 | * // print document (with our changes)
29 | * echo $doc->saveXML();
30 | * @endcode
31 | *
32 | * @author Keyvan Minoukadeh - http://www.keyvan.net - keyvan@keyvan.net
33 | * @see http://fivefilters.org (the project this was written for)
34 | */
35 | class JSLikeHTMLElement extends DOMElement
36 | {
37 | /**
38 | * Used for setting innerHTML like it's done in JavaScript:
39 | * @code
40 | * $div->innerHTML = 'Chapter 2 The story begins...
';
41 | * @endcode
42 | */
43 | public function __set($name, $value) {
44 | if ($name == 'innerHTML') {
45 | // first, empty the element
46 | for ($x=$this->childNodes->length-1; $x>=0; $x--) {
47 | $this->removeChild($this->childNodes->item($x));
48 | }
49 | // $value holds our new inner HTML
50 | if ($value != '') {
51 | $f = $this->ownerDocument->createDocumentFragment();
52 | // appendXML() expects well-formed markup (XHTML)
53 | $result = @$f->appendXML($value); // @ to suppress PHP warnings
54 | if ($result) {
55 | if ($f->hasChildNodes()) $this->appendChild($f);
56 | } else {
57 | // $value is probably ill-formed
58 | $f = new DOMDocument();
59 | $value = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8');
60 | // Using will generate a warning, but so will bad HTML
61 | // (and by this point, bad HTML is what we've got).
62 | // We use it (and suppress the warning) because an HTML fragment will
63 | // be wrapped around tags which we don't really want to keep.
64 | // Note: despite the warning, if loadHTML succeeds it will return true.
65 | $result = @$f->loadHTML(''.$value.' ');
66 | if ($result) {
67 | $import = $f->getElementsByTagName('htmlfragment')->item(0);
68 | foreach ($import->childNodes as $child) {
69 | $importedNode = $this->ownerDocument->importNode($child, true);
70 | $this->appendChild($importedNode);
71 | }
72 | } else {
73 | // oh well, we tried, we really did. :(
74 | // this element is now empty
75 | }
76 | }
77 | }
78 | } else {
79 | $trace = debug_backtrace();
80 | trigger_error('Undefined property via __set(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE);
81 | }
82 | }
83 |
84 | /**
85 | * Used for getting innerHTML like it's done in JavaScript:
86 | * @code
87 | * $string = $div->innerHTML;
88 | * @endcode
89 | */
90 | public function __get($name)
91 | {
92 | if ($name == 'innerHTML') {
93 | $inner = '';
94 | foreach ($this->childNodes as $child) {
95 | $inner .= $this->ownerDocument->saveXML($child);
96 | }
97 | return $inner;
98 | }
99 |
100 | $trace = debug_backtrace();
101 | trigger_error('Undefined property via __get(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE);
102 | return null;
103 | }
104 |
105 | public function __toString()
106 | {
107 | return '['.$this->tagName.']';
108 | }
109 | }
110 | ?>
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Cache/Base.php:
--------------------------------------------------------------------------------
1 | ` copyright tags as defined in Media RSS
47 | *
48 | * Used by {@see SimplePie_Enclosure::get_copyright()}
49 | *
50 | * This class can be overloaded with {@see SimplePie::set_copyright_class()}
51 | *
52 | * @package SimplePie
53 | * @subpackage API
54 | */
55 | class SimplePie_Copyright
56 | {
57 | /**
58 | * Copyright URL
59 | *
60 | * @var string
61 | * @see get_url()
62 | */
63 | var $url;
64 |
65 | /**
66 | * Attribution
67 | *
68 | * @var string
69 | * @see get_attribution()
70 | */
71 | var $label;
72 |
73 | /**
74 | * Constructor, used to input the data
75 | *
76 | * For documentation on all the parameters, see the corresponding
77 | * properties and their accessors
78 | */
79 | public function __construct($url = null, $label = null)
80 | {
81 | $this->url = $url;
82 | $this->label = $label;
83 | }
84 |
85 | /**
86 | * String-ified version
87 | *
88 | * @return string
89 | */
90 | public function __toString()
91 | {
92 | // There is no $this->data here
93 | return md5(serialize($this));
94 | }
95 |
96 | /**
97 | * Get the copyright URL
98 | *
99 | * @return string|null URL to copyright information
100 | */
101 | public function get_url()
102 | {
103 | if ($this->url !== null)
104 | {
105 | return $this->url;
106 | }
107 | else
108 | {
109 | return null;
110 | }
111 | }
112 |
113 | /**
114 | * Get the attribution text
115 | *
116 | * @return string|null
117 | */
118 | public function get_attribution()
119 | {
120 | if ($this->label !== null)
121 | {
122 | return $this->label;
123 | }
124 | else
125 | {
126 | return null;
127 | }
128 | }
129 | }
130 |
131 |
--------------------------------------------------------------------------------
/js/bootstrap-tab.js:
--------------------------------------------------------------------------------
1 | /* ========================================================
2 | * bootstrap-tab.js v2.0.3
3 | * http://twitter.github.com/bootstrap/javascript.html#tabs
4 | * ========================================================
5 | * Copyright 2012 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ======================================================== */
19 |
20 |
21 | !function ($) {
22 |
23 | "use strict"; // jshint ;_;
24 |
25 |
26 | /* TAB CLASS DEFINITION
27 | * ==================== */
28 |
29 | var Tab = function ( element ) {
30 | this.element = $(element)
31 | }
32 |
33 | Tab.prototype = {
34 |
35 | constructor: Tab
36 |
37 | , show: function () {
38 | var $this = this.element
39 | , $ul = $this.closest('ul:not(.dropdown-menu)')
40 | , selector = $this.attr('data-target')
41 | , previous
42 | , $target
43 | , e
44 |
45 | if (!selector) {
46 | selector = $this.attr('href')
47 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
48 | }
49 |
50 | if ( $this.parent('li').hasClass('active') ) return
51 |
52 | previous = $ul.find('.active a').last()[0]
53 |
54 | e = $.Event('show', {
55 | relatedTarget: previous
56 | })
57 |
58 | $this.trigger(e)
59 |
60 | if (e.isDefaultPrevented()) return
61 |
62 | $target = $(selector)
63 |
64 | this.activate($this.parent('li'), $ul)
65 | this.activate($target, $target.parent(), function () {
66 | $this.trigger({
67 | type: 'shown'
68 | , relatedTarget: previous
69 | })
70 | })
71 | }
72 |
73 | , activate: function ( element, container, callback) {
74 | var $active = container.find('> .active')
75 | , transition = callback
76 | && $.support.transition
77 | && $active.hasClass('fade')
78 |
79 | function next() {
80 | $active
81 | .removeClass('active')
82 | .find('> .dropdown-menu > .active')
83 | .removeClass('active')
84 |
85 | element.addClass('active')
86 |
87 | if (transition) {
88 | element[0].offsetWidth // reflow for transition
89 | element.addClass('in')
90 | } else {
91 | element.removeClass('fade')
92 | }
93 |
94 | if ( element.parent('.dropdown-menu') ) {
95 | element.closest('li.dropdown').addClass('active')
96 | }
97 |
98 | callback && callback()
99 | }
100 |
101 | transition ?
102 | $active.one($.support.transition.end, next) :
103 | next()
104 |
105 | $active.removeClass('in')
106 | }
107 | }
108 |
109 |
110 | /* TAB PLUGIN DEFINITION
111 | * ===================== */
112 |
113 | $.fn.tab = function ( option ) {
114 | return this.each(function () {
115 | var $this = $(this)
116 | , data = $this.data('tab')
117 | if (!data) $this.data('tab', (data = new Tab(this)))
118 | if (typeof option == 'string') data[option]()
119 | })
120 | }
121 |
122 | $.fn.tab.Constructor = Tab
123 |
124 |
125 | /* TAB DATA-API
126 | * ============ */
127 |
128 | $(function () {
129 | $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
130 | e.preventDefault()
131 | $(this).tab('show')
132 | })
133 | })
134 |
135 | }(window.jQuery);
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Rating.php:
--------------------------------------------------------------------------------
1 | ` or `` tags as defined in Media RSS and iTunes RSS respectively
47 | *
48 | * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
49 | *
50 | * This class can be overloaded with {@see SimplePie::set_rating_class()}
51 | *
52 | * @package SimplePie
53 | * @subpackage API
54 | */
55 | class SimplePie_Rating
56 | {
57 | /**
58 | * Rating scheme
59 | *
60 | * @var string
61 | * @see get_scheme()
62 | */
63 | var $scheme;
64 |
65 | /**
66 | * Rating value
67 | *
68 | * @var string
69 | * @see get_value()
70 | */
71 | var $value;
72 |
73 | /**
74 | * Constructor, used to input the data
75 | *
76 | * For documentation on all the parameters, see the corresponding
77 | * properties and their accessors
78 | */
79 | public function __construct($scheme = null, $value = null)
80 | {
81 | $this->scheme = $scheme;
82 | $this->value = $value;
83 | }
84 |
85 | /**
86 | * String-ified version
87 | *
88 | * @return string
89 | */
90 | public function __toString()
91 | {
92 | // There is no $this->data here
93 | return md5(serialize($this));
94 | }
95 |
96 | /**
97 | * Get the organizational scheme for the rating
98 | *
99 | * @return string|null
100 | */
101 | public function get_scheme()
102 | {
103 | if ($this->scheme !== null)
104 | {
105 | return $this->scheme;
106 | }
107 | else
108 | {
109 | return null;
110 | }
111 | }
112 |
113 | /**
114 | * Get the value of the rating
115 | *
116 | * @return string|null
117 | */
118 | public function get_value()
119 | {
120 | if ($this->value !== null)
121 | {
122 | return $this->value;
123 | }
124 | else
125 | {
126 | return null;
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/libraries/Zend/Cache/Backend/Interface.php:
--------------------------------------------------------------------------------
1 | infinite lifetime)
68 | * @return boolean true if no problem
69 | */
70 | public function save($data, $id, $tags = array(), $specificLifetime = false);
71 |
72 | /**
73 | * Remove a cache record
74 | *
75 | * @param string $id Cache id
76 | * @return boolean True if no problem
77 | */
78 | public function remove($id);
79 |
80 | /**
81 | * Clean some cache records
82 | *
83 | * Available modes are :
84 | * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
85 | * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
86 | * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
87 | * ($tags can be an array of strings or a single string)
88 | * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
89 | * ($tags can be an array of strings or a single string)
90 | * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
91 | * ($tags can be an array of strings or a single string)
92 | *
93 | * @param string $mode Clean mode
94 | * @param array $tags Array of tags
95 | * @return boolean true if no problem
96 | */
97 | public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array());
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Author.php:
--------------------------------------------------------------------------------
1 | name = $name;
91 | $this->link = $link;
92 | $this->email = $email;
93 | }
94 |
95 | /**
96 | * String-ified version
97 | *
98 | * @return string
99 | */
100 | public function __toString()
101 | {
102 | // There is no $this->data here
103 | return md5(serialize($this));
104 | }
105 |
106 | /**
107 | * Author's name
108 | *
109 | * @return string|null
110 | */
111 | public function get_name()
112 | {
113 | if ($this->name !== null)
114 | {
115 | return $this->name;
116 | }
117 | else
118 | {
119 | return null;
120 | }
121 | }
122 |
123 | /**
124 | * Author's link
125 | *
126 | * @return string|null
127 | */
128 | public function get_link()
129 | {
130 | if ($this->link !== null)
131 | {
132 | return $this->link;
133 | }
134 | else
135 | {
136 | return null;
137 | }
138 | }
139 |
140 | /**
141 | * Author's email address
142 | *
143 | * @return string|null
144 | */
145 | public function get_email()
146 | {
147 | if ($this->email !== null)
148 | {
149 | return $this->email;
150 | }
151 | else
152 | {
153 | return null;
154 | }
155 | }
156 | }
157 |
158 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Category.php:
--------------------------------------------------------------------------------
1 | term = $term;
91 | $this->scheme = $scheme;
92 | $this->label = $label;
93 | }
94 |
95 | /**
96 | * String-ified version
97 | *
98 | * @return string
99 | */
100 | public function __toString()
101 | {
102 | // There is no $this->data here
103 | return md5(serialize($this));
104 | }
105 |
106 | /**
107 | * Get the category identifier
108 | *
109 | * @return string|null
110 | */
111 | public function get_term()
112 | {
113 | if ($this->term !== null)
114 | {
115 | return $this->term;
116 | }
117 | else
118 | {
119 | return null;
120 | }
121 | }
122 |
123 | /**
124 | * Get the categorization scheme identifier
125 | *
126 | * @return string|null
127 | */
128 | public function get_scheme()
129 | {
130 | if ($this->scheme !== null)
131 | {
132 | return $this->scheme;
133 | }
134 | else
135 | {
136 | return null;
137 | }
138 | }
139 |
140 | /**
141 | * Get the human readable label
142 | *
143 | * @return string|null
144 | */
145 | public function get_label()
146 | {
147 | if ($this->label !== null)
148 | {
149 | return $this->label;
150 | }
151 | else
152 | {
153 | return $this->get_term();
154 | }
155 | }
156 | }
157 |
158 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Credit.php:
--------------------------------------------------------------------------------
1 | ` as defined in Media RSS
47 | *
48 | * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
49 | *
50 | * This class can be overloaded with {@see SimplePie::set_credit_class()}
51 | *
52 | * @package SimplePie
53 | * @subpackage API
54 | */
55 | class SimplePie_Credit
56 | {
57 | /**
58 | * Credited role
59 | *
60 | * @var string
61 | * @see get_role()
62 | */
63 | var $role;
64 |
65 | /**
66 | * Organizational scheme
67 | *
68 | * @var string
69 | * @see get_scheme()
70 | */
71 | var $scheme;
72 |
73 | /**
74 | * Credited name
75 | *
76 | * @var string
77 | * @see get_name()
78 | */
79 | var $name;
80 |
81 | /**
82 | * Constructor, used to input the data
83 | *
84 | * For documentation on all the parameters, see the corresponding
85 | * properties and their accessors
86 | */
87 | public function __construct($role = null, $scheme = null, $name = null)
88 | {
89 | $this->role = $role;
90 | $this->scheme = $scheme;
91 | $this->name = $name;
92 | }
93 |
94 | /**
95 | * String-ified version
96 | *
97 | * @return string
98 | */
99 | public function __toString()
100 | {
101 | // There is no $this->data here
102 | return md5(serialize($this));
103 | }
104 |
105 | /**
106 | * Get the role of the person receiving credit
107 | *
108 | * @return string|null
109 | */
110 | public function get_role()
111 | {
112 | if ($this->role !== null)
113 | {
114 | return $this->role;
115 | }
116 | else
117 | {
118 | return null;
119 | }
120 | }
121 |
122 | /**
123 | * Get the organizational scheme
124 | *
125 | * @return string|null
126 | */
127 | public function get_scheme()
128 | {
129 | if ($this->scheme !== null)
130 | {
131 | return $this->scheme;
132 | }
133 | else
134 | {
135 | return null;
136 | }
137 | }
138 |
139 | /**
140 | * Get the credited person/entity's name
141 | *
142 | * @return string|null
143 | */
144 | public function get_name()
145 | {
146 | if ($this->name !== null)
147 | {
148 | return $this->name;
149 | }
150 | else
151 | {
152 | return null;
153 | }
154 | }
155 | }
156 |
157 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Restriction.php:
--------------------------------------------------------------------------------
1 | ` as defined in Media RSS
47 | *
48 | * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
49 | *
50 | * This class can be overloaded with {@see SimplePie::set_restriction_class()}
51 | *
52 | * @package SimplePie
53 | * @subpackage API
54 | */
55 | class SimplePie_Restriction
56 | {
57 | /**
58 | * Relationship ('allow'/'deny')
59 | *
60 | * @var string
61 | * @see get_relationship()
62 | */
63 | var $relationship;
64 |
65 | /**
66 | * Type of restriction
67 | *
68 | * @var string
69 | * @see get_type()
70 | */
71 | var $type;
72 |
73 | /**
74 | * Restricted values
75 | *
76 | * @var string
77 | * @see get_value()
78 | */
79 | var $value;
80 |
81 | /**
82 | * Constructor, used to input the data
83 | *
84 | * For documentation on all the parameters, see the corresponding
85 | * properties and their accessors
86 | */
87 | public function __construct($relationship = null, $type = null, $value = null)
88 | {
89 | $this->relationship = $relationship;
90 | $this->type = $type;
91 | $this->value = $value;
92 | }
93 |
94 | /**
95 | * String-ified version
96 | *
97 | * @return string
98 | */
99 | public function __toString()
100 | {
101 | // There is no $this->data here
102 | return md5(serialize($this));
103 | }
104 |
105 | /**
106 | * Get the relationship
107 | *
108 | * @return string|null Either 'allow' or 'deny'
109 | */
110 | public function get_relationship()
111 | {
112 | if ($this->relationship !== null)
113 | {
114 | return $this->relationship;
115 | }
116 | else
117 | {
118 | return null;
119 | }
120 | }
121 |
122 | /**
123 | * Get the type
124 | *
125 | * @return string|null
126 | */
127 | public function get_type()
128 | {
129 | if ($this->type !== null)
130 | {
131 | return $this->type;
132 | }
133 | else
134 | {
135 | return null;
136 | }
137 | }
138 |
139 | /**
140 | * Get the list of restricted things
141 | *
142 | * @return string|null
143 | */
144 | public function get_value()
145 | {
146 | if ($this->value !== null)
147 | {
148 | return $this->value;
149 | }
150 | else
151 | {
152 | return null;
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/libraries/Zend/Cache/Backend/ExtendedInterface.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | // Usage
23 | // -----
24 | // Set up your scheduler (e.g. cron) to request this file periodically.
25 | // Note: this file must _not_ be named cleancache.php so please rename it.
26 | // We ask you to do this to prevent others from initiating
27 | // the cache cleanup process. It will not run if it's called cleancache.php.
28 |
29 | error_reporting(E_ALL ^ E_NOTICE);
30 | ini_set("display_errors", 1);
31 | @set_time_limit(200);
32 |
33 | // check file name
34 | if (basename(__FILE__) == 'cleancache.php') die('cleancache.php must be renamed');
35 |
36 | // set include path
37 | set_include_path(realpath(dirname(__FILE__).'/libraries').PATH_SEPARATOR.get_include_path());
38 |
39 | // Autoloading of classes allows us to include files only when they're
40 | // needed. If we've got a cached copy, for example, only Zend_Cache is loaded.
41 | function __autoload($class_name) {
42 | static $mapping = array(
43 | 'Zend_Cache' => 'Zend/Cache.php'
44 | );
45 | if (isset($mapping[$class_name])) {
46 | //echo "Loading $class_name\n ";
47 | require_once $mapping[$class_name];
48 | return true;
49 | } else {
50 | return false;
51 | }
52 | }
53 | require_once dirname(__FILE__).'/config.php';
54 | if (!$options->caching) die('Caching is disabled');
55 |
56 | // clean APC cache
57 | if ($options->apc && function_exists('apc_delete')) {
58 | $_apc_data = apc_cache_info('user');
59 | foreach ($_apc_data['cache_list'] as $_apc_item) {
60 | if ($_apc_item['ttl'] > 0 && ($_apc_item['ttl'] + $_apc_item['creation_time'] < time())) {
61 | apc_delete($_apc_item['info']);
62 | }
63 | }
64 | }
65 |
66 | // clean rss (non-key) cache
67 | $frontendOptions = array(
68 | 'lifetime' => 20*60,
69 | 'automatic_serialization' => false,
70 | 'write_control' => false,
71 | 'automatic_cleaning_factor' => 0,
72 | 'ignore_user_abort' => false
73 | );
74 | $backendOptions = array(
75 | 'cache_dir' => $options->cache_dir.'/rss/',
76 | 'file_locking' => false,
77 | 'read_control' => true,
78 | 'read_control_type' => 'strlen',
79 | 'hashed_directory_level' => $options->cache_directory_level,
80 | 'hashed_directory_perm' => 0777,
81 | 'cache_file_perm' => 0664,
82 | 'file_name_prefix' => 'ff'
83 | );
84 | $cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
85 | $cache->clean(Zend_Cache::CLEANING_MODE_OLD);
86 |
87 | // clean rss (key) cache
88 | $frontendOptions = array(
89 | 'lifetime' => 20*60,
90 | 'automatic_serialization' => false,
91 | 'write_control' => false,
92 | 'automatic_cleaning_factor' => 0,
93 | 'ignore_user_abort' => false
94 | );
95 | $backendOptions = array(
96 | 'cache_dir' => $options->cache_dir.'/rss-with-key/',
97 | 'file_locking' => false,
98 | 'read_control' => true,
99 | 'read_control_type' => 'strlen',
100 | 'hashed_directory_level' => $options->cache_directory_level,
101 | 'hashed_directory_perm' => 0777,
102 | 'cache_file_perm' => 0664,
103 | 'file_name_prefix' => 'ff'
104 | );
105 | $cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
106 | $cache->clean(Zend_Cache::CLEANING_MODE_OLD);
107 |
108 | // clean rss (urls) cache
109 | $frontendOptions = array(
110 | 'lifetime' => 60*60,
111 | 'automatic_serialization' => false,
112 | 'write_control' => false,
113 | 'automatic_cleaning_factor' => 0,
114 | 'ignore_user_abort' => false
115 | );
116 | $backendOptions = array(
117 | 'cache_dir' => $options->cache_dir.'/urls/',
118 | 'file_locking' => false,
119 | 'read_control' => true,
120 | 'read_control_type' => 'strlen',
121 | 'hashed_directory_level' => $options->cache_directory_level,
122 | 'hashed_directory_perm' => 0777,
123 | 'cache_file_perm' => 0664,
124 | 'file_name_prefix' => 'ff'
125 | );
126 | $cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
127 | $cache->clean(Zend_Cache::CLEANING_MODE_OLD);
128 |
129 | ?>
--------------------------------------------------------------------------------
/libraries/html5/Data.php:
--------------------------------------------------------------------------------
1 | 0xFFFD, // REPLACEMENT CHARACTER
15 | 0x0D => 0x000A, // LINE FEED (LF)
16 | 0x80 => 0x20AC, // EURO SIGN ('€')
17 | 0x81 => 0x0081, //
18 | 0x82 => 0x201A, // SINGLE LOW-9 QUOTATION MARK ('‚')
19 | 0x83 => 0x0192, // LATIN SMALL LETTER F WITH HOOK ('ƒ')
20 | 0x84 => 0x201E, // DOUBLE LOW-9 QUOTATION MARK ('„')
21 | 0x85 => 0x2026, // HORIZONTAL ELLIPSIS ('…')
22 | 0x86 => 0x2020, // DAGGER ('†')
23 | 0x87 => 0x2021, // DOUBLE DAGGER ('‡')
24 | 0x88 => 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT ('ˆ')
25 | 0x89 => 0x2030, // PER MILLE SIGN ('‰')
26 | 0x8A => 0x0160, // LATIN CAPITAL LETTER S WITH CARON ('Š')
27 | 0x8B => 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK ('‹')
28 | 0x8C => 0x0152, // LATIN CAPITAL LIGATURE OE ('Œ')
29 | 0x8D => 0x008D, //
30 | 0x8E => 0x017D, // LATIN CAPITAL LETTER Z WITH CARON ('Ž')
31 | 0x8F => 0x008F, //
32 | 0x90 => 0x0090, //
33 | 0x91 => 0x2018, // LEFT SINGLE QUOTATION MARK ('‘')
34 | 0x92 => 0x2019, // RIGHT SINGLE QUOTATION MARK ('’')
35 | 0x93 => 0x201C, // LEFT DOUBLE QUOTATION MARK ('“')
36 | 0x94 => 0x201D, // RIGHT DOUBLE QUOTATION MARK ('”')
37 | 0x95 => 0x2022, // BULLET ('•')
38 | 0x96 => 0x2013, // EN DASH ('–')
39 | 0x97 => 0x2014, // EM DASH ('—')
40 | 0x98 => 0x02DC, // SMALL TILDE ('˜')
41 | 0x99 => 0x2122, // TRADE MARK SIGN ('™')
42 | 0x9A => 0x0161, // LATIN SMALL LETTER S WITH CARON ('š')
43 | 0x9B => 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK ('›')
44 | 0x9C => 0x0153, // LATIN SMALL LIGATURE OE ('œ')
45 | 0x9D => 0x009D, //
46 | 0x9E => 0x017E, // LATIN SMALL LETTER Z WITH CARON ('ž')
47 | 0x9F => 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS ('Ÿ')
48 | );
49 |
50 | protected static $namedCharacterReferences;
51 |
52 | protected static $namedCharacterReferenceMaxLength;
53 |
54 | /**
55 | * Returns the "real" Unicode codepoint of a malformed character
56 | * reference.
57 | */
58 | public static function getRealCodepoint($ref) {
59 | if (!isset(self::$realCodepointTable[$ref])) return false;
60 | else return self::$realCodepointTable[$ref];
61 | }
62 |
63 | public static function getNamedCharacterReferences() {
64 | if (!self::$namedCharacterReferences) {
65 | self::$namedCharacterReferences = unserialize(
66 | file_get_contents(dirname(__FILE__) . '/named-character-references.ser'));
67 | }
68 | return self::$namedCharacterReferences;
69 | }
70 |
71 | /**
72 | * Converts a Unicode codepoint to sequence of UTF-8 bytes.
73 | * @note Shamelessly stolen from HTML Purifier, which is also
74 | * shamelessly stolen from Feyd (which is in public domain).
75 | */
76 | public static function utf8chr($code) {
77 | /* We don't care: we live dangerously
78 | * if($code > 0x10FFFF or $code < 0x0 or
79 | ($code >= 0xD800 and $code <= 0xDFFF) ) {
80 | // bits are set outside the "valid" range as defined
81 | // by UNICODE 4.1.0
82 | return "\xEF\xBF\xBD";
83 | }*/
84 |
85 | $x = $y = $z = $w = 0;
86 | if ($code < 0x80) {
87 | // regular ASCII character
88 | $x = $code;
89 | } else {
90 | // set up bits for UTF-8
91 | $x = ($code & 0x3F) | 0x80;
92 | if ($code < 0x800) {
93 | $y = (($code & 0x7FF) >> 6) | 0xC0;
94 | } else {
95 | $y = (($code & 0xFC0) >> 6) | 0x80;
96 | if($code < 0x10000) {
97 | $z = (($code >> 12) & 0x0F) | 0xE0;
98 | } else {
99 | $z = (($code >> 12) & 0x3F) | 0x80;
100 | $w = (($code >> 18) & 0x07) | 0xF0;
101 | }
102 | }
103 | }
104 | // set up the actual character
105 | $ret = '';
106 | if($w) $ret .= chr($w);
107 | if($z) $ret .= chr($z);
108 | if($y) $ret .= chr($y);
109 | $ret .= chr($x);
110 |
111 | return $ret;
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Cache.php:
--------------------------------------------------------------------------------
1 | 'SimplePie_Cache_MySQL',
66 | 'memcache' => 'SimplePie_Cache_Memcache',
67 | );
68 |
69 | /**
70 | * Don't call the constructor. Please.
71 | */
72 | private function __construct() { }
73 |
74 | /**
75 | * Create a new SimplePie_Cache object
76 | *
77 | * @param string $location URL location (scheme is used to determine handler)
78 | * @param string $filename Unique identifier for cache object
79 | * @param string $extension 'spi' or 'spc'
80 | * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
81 | */
82 | public static function get_handler($location, $filename, $extension)
83 | {
84 | $type = explode(':', $location, 2);
85 | $type = $type[0];
86 | if (!empty(self::$handlers[$type]))
87 | {
88 | $class = self::$handlers[$type];
89 | return new $class($location, $filename, $extension);
90 | }
91 |
92 | return new SimplePie_Cache_File($location, $filename, $extension);
93 | }
94 |
95 | /**
96 | * Create a new SimplePie_Cache object
97 | *
98 | * @deprecated Use {@see get_handler} instead
99 | */
100 | public function create($location, $filename, $extension)
101 | {
102 | trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
103 | return self::get_handler($location, $filename, $extension);
104 | }
105 |
106 | /**
107 | * Register a handler
108 | *
109 | * @param string $type DSN type to register for
110 | * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
111 | */
112 | public static function register($type, $class)
113 | {
114 | self::$handlers[$type] = $class;
115 | }
116 |
117 | /**
118 | * Parse a URL into an array
119 | *
120 | * @param string $url
121 | * @return array
122 | */
123 | public static function parse_URL($url)
124 | {
125 | $params = parse_url($url);
126 | $params['extras'] = array();
127 | if (isset($params['query']))
128 | {
129 | parse_str($params['query'], $params['extras']);
130 | }
131 | return $params;
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/libraries/readability/ImageCaching.php:
--------------------------------------------------------------------------------
1 | lower_limit_setting = self::LOWER_LIMIT;
17 | $this->upper_limit_setting = self::UPPER_LIMIT;
18 | $opts = array(
19 | 'http' => array(
20 | 'method'=>"GET",
21 | 'header'=>"Accept-language: en\r\n" .
22 | "Connection: close\r\n" .
23 | "User-Agent: Opera/9.80 (Windows NT 6.1; Win64; x64; Edition Next) Presto/2.12.388 Version/12.15\r\n"
24 | )
25 | );
26 | $this->context_get = stream_context_create($opts);
27 | }
28 |
29 | public function setAllowedSizes($lower, $upper) {
30 | if ($lower > $upper) {
31 | $tmp = $upper; $upper = $lower; $lower = $tmp;
32 | }
33 | if ($lower && $lower > self::LOWER_MIN && $lower < self::UPPER_MAX) $this->lower_limit_setting = $lower;
34 | if ($upper && $upper > self::LOWER_MIN && $upper < self::UPPER_MAX) $this->upper_limit_setting = $upper;
35 | }
36 |
37 | public function cacheFromString(&$html) {
38 | $callback = function ($matches) {
39 | $data_uri = '';
40 | $url = $matches[1];
41 | if (!preg_match('!^https?://!i', $url) || strlen($url) < 12) return $matches[0];
42 | $url = filter_var($url, FILTER_SANITIZE_URL);
43 | if (!$this->images[$url]){
44 | $data_uri = $this->getImageDataURI($url);
45 | if (strlen($data_uri) > 1)
46 | $this->images[$url] = $data_uri;
47 | else
48 | return $matches[0];
49 | } else {
50 | $data_uri = $this->images[$url];
51 | }
52 | if (strlen($data_uri) > 1)
53 | return ' ';
54 | else
55 | return $matches[0];
56 | };
57 |
58 | $html = preg_replace_callback('/< *img[^>]+src *= *["\']?([^"\'>]*)[^>]*>/i', $callback, $html);
59 | }
60 |
61 | public function cacheFromDocument(&$document) {
62 | $imageNodes = $document->getElementsByTagName('img');
63 | for ($node = null, $nodeIndex = 0; ($node = $imageNodes->item($nodeIndex)); $nodeIndex++) {
64 | $url = $node->getAttribute('src');
65 | $node->removeAttribute('class');
66 | $node->removeAttribute('id');
67 | if (!preg_match('!^https?://!i', $url) || strlen($url) < 12) continue;
68 | $url = filter_var($url, FILTER_SANITIZE_URL);
69 | $data_uri = '';
70 | if (!$this->images[$url]){
71 | $data_uri = $this->getImageDataURI($url);
72 | if (strlen($data_uri) > 1)
73 | $this->images[$url] = $data_uri;
74 | else
75 | continue;
76 | } else {
77 | $data_uri = $this->images[$url];
78 | }
79 | if (strlen($data_uri) > 1) {
80 | $node->setAttribute('src', $data_uri);
81 | $node->setAttribute('alt', $url);
82 | }
83 | }
84 | }
85 |
86 | protected function getFileSize($image) {
87 | $contentLength = 0;
88 | $status = 0;
89 | $matches = array();
90 |
91 | if (!function_exists('curl_init'))
92 | return 0;
93 |
94 | $ch = curl_init($image);
95 | curl_setopt($ch, CURLOPT_NOBODY, true);
96 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
97 | curl_setopt($ch, CURLOPT_HEADER, true);
98 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
99 | curl_setopt($ch, CURLOPT_USERAGENT, "Opera/9.80 (Windows NT 6.1; Win64; x64; Edition Next) Presto/2.12.388 Version/12.15");
100 | $data = curl_exec($ch);
101 | curl_close($ch);
102 | if ($data === false)
103 | return 0;
104 |
105 | if (preg_match('/^HTTP\/1\.[01] (\d\d\d)/', $data, $matches))
106 | $status = (int) $matches[1];
107 | if ($status === 200 && preg_match('/Content-Length: (\d+)/', $data, $matches))
108 | $contentLength = (int) $matches[1];
109 |
110 | return $contentLength;
111 | }
112 |
113 | protected function getImageDataURI($image, $mime = '') {
114 | $image = filter_var($image, FILTER_SANITIZE_URL);
115 | if (!preg_match('!^https?://!i', $image))
116 | return '';
117 |
118 | $ext = substr(strrchr($image, ".") , 1, 3);
119 | if (strcasecmp($ext, 'jpg') === 0 || strcasecmp($ext, 'png') === 0 || strcasecmp($ext, 'jpe') === 0 || strcasecmp($ext, 'gif') === 0) {
120 | $size = $this->getFileSize($image);
121 | if ($size < $this->lower_limit_setting || $size > $this->upper_limit_setting)
122 | return '';
123 | $content = @file_get_contents($image, false, $this->context_get);
124 | if (function_exists('finfo_open'))
125 | $mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($content);
126 | if (!preg_match('/^image/i', $mime)) return '';
127 | return 'data:' . $mime . ';base64,' . base64_encode($content);
128 | }
129 | return '';
130 | }
131 | }
132 | ?>
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Cache/File.php:
--------------------------------------------------------------------------------
1 | location = $location;
92 | $this->filename = $name;
93 | $this->extension = $type;
94 | $this->name = "$this->location/$this->filename.$this->extension";
95 | }
96 |
97 | /**
98 | * Save data to the cache
99 | *
100 | * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
101 | * @return bool Successfulness
102 | */
103 | public function save($data)
104 | {
105 | if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
106 | {
107 | if ($data instanceof SimplePie)
108 | {
109 | $data = $data->data;
110 | }
111 |
112 | $data = serialize($data);
113 | return (bool) file_put_contents($this->name, $data);
114 | }
115 | return false;
116 | }
117 |
118 | /**
119 | * Retrieve the data saved to the cache
120 | *
121 | * @return array Data for SimplePie::$data
122 | */
123 | public function load()
124 | {
125 | if (file_exists($this->name) && is_readable($this->name))
126 | {
127 | return unserialize(file_get_contents($this->name));
128 | }
129 | return false;
130 | }
131 |
132 | /**
133 | * Retrieve the last modified time for the cache
134 | *
135 | * @return int Timestamp
136 | */
137 | public function mtime()
138 | {
139 | if (file_exists($this->name))
140 | {
141 | return filemtime($this->name);
142 | }
143 | return false;
144 | }
145 |
146 | /**
147 | * Set the last modified time to the current time
148 | *
149 | * @return bool Success status
150 | */
151 | public function touch()
152 | {
153 | if (file_exists($this->name))
154 | {
155 | return touch($this->name);
156 | }
157 | return false;
158 | }
159 |
160 | /**
161 | * Remove the cache
162 | *
163 | * @return bool Success status
164 | */
165 | public function unlink()
166 | {
167 | if (file_exists($this->name))
168 | {
169 | return unlink($this->name);
170 | }
171 | return false;
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Cache/DB.php:
--------------------------------------------------------------------------------
1 | get_items();
64 | $items_by_id = array();
65 |
66 | if (!empty($items))
67 | {
68 | foreach ($items as $item)
69 | {
70 | $items_by_id[$item->get_id()] = $item;
71 | }
72 |
73 | if (count($items_by_id) !== count($items))
74 | {
75 | $items_by_id = array();
76 | foreach ($items as $item)
77 | {
78 | $items_by_id[$item->get_id(true)] = $item;
79 | }
80 | }
81 |
82 | if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
83 | {
84 | $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
85 | }
86 | elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
87 | {
88 | $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
89 | }
90 | elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
91 | {
92 | $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
93 | }
94 | elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
95 | {
96 | $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
97 | }
98 | else
99 | {
100 | $channel = null;
101 | }
102 |
103 | if ($channel !== null)
104 | {
105 | if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
106 | {
107 | unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
108 | }
109 | if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
110 | {
111 | unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
112 | }
113 | if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
114 | {
115 | unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
116 | }
117 | if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
118 | {
119 | unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
120 | }
121 | if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
122 | {
123 | unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
124 | }
125 | }
126 | if (isset($data->data['items']))
127 | {
128 | unset($data->data['items']);
129 | }
130 | if (isset($data->data['ordered_items']))
131 | {
132 | unset($data->data['ordered_items']);
133 | }
134 | }
135 | return array(serialize($data->data), $items_by_id);
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/libraries/feedwriter/FeedItem.php:
--------------------------------------------------------------------------------
1 |
9 | * @link http://www.ajaxray.com/projects/rss
10 | */
11 | class FeedItem
12 | {
13 | private $elements = array(); //Collection of feed elements
14 | private $version;
15 |
16 | /**
17 | * Constructor
18 | *
19 | * @param contant (RSS1/RSS2/ATOM) RSS2 is default.
20 | */
21 | function __construct($version = RSS2)
22 | {
23 | $this->version = $version;
24 | }
25 |
26 | /**
27 | * Set element (overwrites existing elements with $elementName)
28 | *
29 | * @access public
30 | * @param srting The tag name of an element
31 | * @param srting The content of tag
32 | * @param array Attributes(if any) in 'attrName' => 'attrValue' format
33 | * @return void
34 | */
35 | public function setElement($elementName, $content, $attributes = null)
36 | {
37 | if (isset($this->elements[$elementName])) {
38 | unset($this->elements[$elementName]);
39 | }
40 | $this->addElement($elementName, $content, $attributes);
41 | }
42 |
43 | /**
44 | * Add an element to elements array
45 | *
46 | * @access public
47 | * @param srting The tag name of an element
48 | * @param srting The content of tag
49 | * @param array Attributes(if any) in 'attrName' => 'attrValue' format
50 | * @return void
51 | */
52 | public function addElement($elementName, $content, $attributes = null)
53 | {
54 | $i = 0;
55 | if (isset($this->elements[$elementName])) {
56 | $i = count($this->elements[$elementName]);
57 | } else {
58 | $this->elements[$elementName] = array();
59 | }
60 | $this->elements[$elementName][$i]['name'] = $elementName;
61 | $this->elements[$elementName][$i]['content'] = $content;
62 | $this->elements[$elementName][$i]['attributes'] = $attributes;
63 | }
64 |
65 | /**
66 | * Set multiple feed elements from an array.
67 | * Elements which have attributes cannot be added by this method
68 | *
69 | * @access public
70 | * @param array array of elements in 'tagName' => 'tagContent' format.
71 | * @return void
72 | */
73 | public function addElementArray($elementArray)
74 | {
75 | if(! is_array($elementArray)) return;
76 | foreach ($elementArray as $elementName => $content)
77 | {
78 | $this->addElement($elementName, $content);
79 | }
80 | }
81 |
82 | /**
83 | * Return the collection of elements in this feed item
84 | *
85 | * @access public
86 | * @return array
87 | */
88 | public function getElements()
89 | {
90 | return $this->elements;
91 | }
92 |
93 | // Wrapper functions ------------------------------------------------------
94 |
95 | /**
96 | * Set the 'dscription' element of feed item
97 | *
98 | * @access public
99 | * @param string The content of 'description' element
100 | * @return void
101 | */
102 | public function setDescription($description)
103 | {
104 | $tag = ($this->version == ATOM)? 'summary' : 'description';
105 | $this->setElement($tag, $description);
106 | }
107 |
108 | /**
109 | * @desc Set the 'title' element of feed item
110 | * @access public
111 | * @param string The content of 'title' element
112 | * @return void
113 | */
114 | public function setTitle($title)
115 | {
116 | $this->setElement('title', $title);
117 | }
118 |
119 | /**
120 | * Set the 'date' element of feed item
121 | *
122 | * @access public
123 | * @param string The content of 'date' element
124 | * @return void
125 | */
126 | public function setDate($date)
127 | {
128 | if(! is_numeric($date))
129 | {
130 | $date = strtotime($date);
131 | }
132 |
133 | if($this->version == ATOM)
134 | {
135 | $tag = 'updated';
136 | $value = date(DATE_ATOM, $date);
137 | }
138 | elseif($this->version == RSS2)
139 | {
140 | $tag = 'pubDate';
141 | $value = date(DATE_RSS, $date);
142 | }
143 | else
144 | {
145 | $tag = 'dc:date';
146 | $value = date("Y-m-d", $date);
147 | }
148 |
149 | $this->setElement($tag, $value);
150 | }
151 |
152 | /**
153 | * Set the 'link' element of feed item
154 | *
155 | * @access public
156 | * @param string The content of 'link' element
157 | * @return void
158 | */
159 | public function setLink($link)
160 | {
161 | if($this->version == RSS2 || $this->version == RSS1)
162 | {
163 | $this->setElement('link', $link);
164 | }
165 | else
166 | {
167 | $this->setElement('link','',array('href'=>$link));
168 | $this->setElement('id', FeedWriter::uuid($link,'urn:uuid:'));
169 | }
170 |
171 | }
172 |
173 | /**
174 | * Set the 'encloser' element of feed item
175 | * For RSS 2.0 only
176 | *
177 | * @access public
178 | * @param string The url attribute of encloser tag
179 | * @param string The length attribute of encloser tag
180 | * @param string The type attribute of encloser tag
181 | * @return void
182 | */
183 | public function setEncloser($url, $length, $type)
184 | {
185 | $attributes = array('url'=>$url, 'length'=>$length, 'type'=>$type);
186 | $this->setElement('enclosure','',$attributes);
187 | }
188 |
189 | } // end of class FeedItem
190 | ?>
191 |
--------------------------------------------------------------------------------
/admin/codemirror/codemirror.css:
--------------------------------------------------------------------------------
1 | .CodeMirror {
2 | line-height: 1em;
3 | font-family: monospace;
4 |
5 | /* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
6 | position: relative;
7 | /* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
8 | overflow: hidden;
9 | }
10 |
11 | .CodeMirror-scroll {
12 | overflow-x: auto;
13 | overflow-y: hidden;
14 | height: 300px;
15 | /* This is needed to prevent an IE[67] bug where the scrolled content
16 | is visible outside of the scrolling box. */
17 | position: relative;
18 | outline: none;
19 | }
20 |
21 | /* Vertical scrollbar */
22 | .CodeMirror-scrollbar {
23 | float: right;
24 | overflow-x: hidden;
25 | overflow-y: scroll;
26 |
27 | /* This corrects for the 1px gap introduced to the left of the scrollbar
28 | by the rule for .CodeMirror-scrollbar-inner. */
29 | margin-left: -1px;
30 | }
31 | .CodeMirror-scrollbar-inner {
32 | /* This needs to have a nonzero width in order for the scrollbar to appear
33 | in Firefox and IE9. */
34 | width: 1px;
35 | }
36 | .CodeMirror-scrollbar.cm-sb-overlap {
37 | /* Ensure that the scrollbar appears in Lion, and that it overlaps the content
38 | rather than sitting to the right of it. */
39 | position: absolute;
40 | z-index: 1;
41 | float: none;
42 | right: 0;
43 | min-width: 12px;
44 | }
45 | .CodeMirror-scrollbar.cm-sb-nonoverlap {
46 | min-width: 12px;
47 | }
48 | .CodeMirror-scrollbar.cm-sb-ie7 {
49 | min-width: 18px;
50 | }
51 |
52 | .CodeMirror-gutter {
53 | position: absolute; left: 0; top: 0;
54 | z-index: 10;
55 | background-color: #f7f7f7;
56 | border-right: 1px solid #eee;
57 | min-width: 2em;
58 | height: 100%;
59 | }
60 | .CodeMirror-gutter-text {
61 | color: #aaa;
62 | text-align: right;
63 | padding: .4em .2em .4em .4em;
64 | white-space: pre !important;
65 | cursor: default;
66 | }
67 | .CodeMirror-lines {
68 | padding: .4em;
69 | white-space: pre;
70 | cursor: text;
71 | }
72 | .CodeMirror-lines * {
73 | /* Necessary for throw-scrolling to decelerate properly on Safari. */
74 | pointer-events: none;
75 | }
76 |
77 | .CodeMirror pre {
78 | -moz-border-radius: 0;
79 | -webkit-border-radius: 0;
80 | -o-border-radius: 0;
81 | border-radius: 0;
82 | border-width: 0; margin: 0; padding: 0; background: transparent;
83 | font-family: inherit;
84 | font-size: inherit;
85 | padding: 0; margin: 0;
86 | white-space: pre;
87 | word-wrap: normal;
88 | line-height: inherit;
89 | color: inherit;
90 | }
91 |
92 | .CodeMirror-wrap pre {
93 | word-wrap: break-word;
94 | white-space: pre-wrap;
95 | word-break: normal;
96 | }
97 | .CodeMirror-wrap .CodeMirror-scroll {
98 | overflow-x: hidden;
99 | }
100 |
101 | .CodeMirror textarea {
102 | outline: none !important;
103 | }
104 |
105 | .CodeMirror pre.CodeMirror-cursor {
106 | z-index: 10;
107 | position: absolute;
108 | visibility: hidden;
109 | border-left: 1px solid black;
110 | border-right: none;
111 | width: 0;
112 | }
113 | .cm-keymap-fat-cursor pre.CodeMirror-cursor {
114 | width: auto;
115 | border: 0;
116 | background: transparent;
117 | background: rgba(0, 200, 0, .4);
118 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
119 | }
120 | /* Kludge to turn off filter in ie9+, which also accepts rgba */
121 | .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
122 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
123 | }
124 | .CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
125 | .CodeMirror-focused pre.CodeMirror-cursor {
126 | visibility: visible;
127 | }
128 |
129 | div.CodeMirror-selected { background: #d9d9d9; }
130 | .CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
131 |
132 | .CodeMirror-searching {
133 | background: #ffa;
134 | background: rgba(255, 255, 0, .4);
135 | }
136 |
137 | /* Default theme */
138 |
139 | .cm-s-default span.cm-keyword {color: #708;}
140 | .cm-s-default span.cm-atom {color: #219;}
141 | .cm-s-default span.cm-number {color: #164;}
142 | .cm-s-default span.cm-def {color: #00f;}
143 | .cm-s-default span.cm-variable {color: black;}
144 | .cm-s-default span.cm-variable-2 {color: #05a;}
145 | .cm-s-default span.cm-variable-3 {color: #085;}
146 | .cm-s-default span.cm-property {color: black;}
147 | .cm-s-default span.cm-operator {color: black;}
148 | .cm-s-default span.cm-comment {color: #a50;}
149 | .cm-s-default span.cm-string {color: #a11;}
150 | .cm-s-default span.cm-string-2 {color: #f50;}
151 | .cm-s-default span.cm-meta {color: #555;}
152 | .cm-s-default span.cm-error {color: #f00;}
153 | .cm-s-default span.cm-qualifier {color: #555;}
154 | .cm-s-default span.cm-builtin {color: #30a;}
155 | .cm-s-default span.cm-bracket {color: #cc7;}
156 | .cm-s-default span.cm-tag {color: #170;}
157 | .cm-s-default span.cm-attribute {color: #00c;}
158 | .cm-s-default span.cm-header {color: blue;}
159 | .cm-s-default span.cm-quote {color: #090;}
160 | .cm-s-default span.cm-hr {color: #999;}
161 | .cm-s-default span.cm-link {color: #00c;}
162 |
163 | span.cm-header, span.cm-strong {font-weight: bold;}
164 | span.cm-em {font-style: italic;}
165 | span.cm-emstrong {font-style: italic; font-weight: bold;}
166 | span.cm-link {text-decoration: underline;}
167 |
168 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
169 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
170 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Caption.php:
--------------------------------------------------------------------------------
1 | ` captions as defined in Media RSS.
48 | *
49 | * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
50 | *
51 | * This class can be overloaded with {@see SimplePie::set_caption_class()}
52 | *
53 | * @package SimplePie
54 | * @subpackage API
55 | */
56 | class SimplePie_Caption
57 | {
58 | /**
59 | * Content type
60 | *
61 | * @var string
62 | * @see get_type()
63 | */
64 | var $type;
65 |
66 | /**
67 | * Language
68 | *
69 | * @var string
70 | * @see get_language()
71 | */
72 | var $lang;
73 |
74 | /**
75 | * Start time
76 | *
77 | * @var string
78 | * @see get_starttime()
79 | */
80 | var $startTime;
81 |
82 | /**
83 | * End time
84 | *
85 | * @var string
86 | * @see get_endtime()
87 | */
88 | var $endTime;
89 |
90 | /**
91 | * Caption text
92 | *
93 | * @var string
94 | * @see get_text()
95 | */
96 | var $text;
97 |
98 | /**
99 | * Constructor, used to input the data
100 | *
101 | * For documentation on all the parameters, see the corresponding
102 | * properties and their accessors
103 | */
104 | public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
105 | {
106 | $this->type = $type;
107 | $this->lang = $lang;
108 | $this->startTime = $startTime;
109 | $this->endTime = $endTime;
110 | $this->text = $text;
111 | }
112 |
113 | /**
114 | * String-ified version
115 | *
116 | * @return string
117 | */
118 | public function __toString()
119 | {
120 | // There is no $this->data here
121 | return md5(serialize($this));
122 | }
123 |
124 | /**
125 | * Get the end time
126 | *
127 | * @return string|null Time in the format 'hh:mm:ss.SSS'
128 | */
129 | public function get_endtime()
130 | {
131 | if ($this->endTime !== null)
132 | {
133 | return $this->endTime;
134 | }
135 | else
136 | {
137 | return null;
138 | }
139 | }
140 |
141 | /**
142 | * Get the language
143 | *
144 | * @link http://tools.ietf.org/html/rfc3066
145 | * @return string|null Language code as per RFC 3066
146 | */
147 | public function get_language()
148 | {
149 | if ($this->lang !== null)
150 | {
151 | return $this->lang;
152 | }
153 | else
154 | {
155 | return null;
156 | }
157 | }
158 |
159 | /**
160 | * Get the start time
161 | *
162 | * @return string|null Time in the format 'hh:mm:ss.SSS'
163 | */
164 | public function get_starttime()
165 | {
166 | if ($this->startTime !== null)
167 | {
168 | return $this->startTime;
169 | }
170 | else
171 | {
172 | return null;
173 | }
174 | }
175 |
176 | /**
177 | * Get the text of the caption
178 | *
179 | * @return string|null
180 | */
181 | public function get_text()
182 | {
183 | if ($this->text !== null)
184 | {
185 | return $this->text;
186 | }
187 | else
188 | {
189 | return null;
190 | }
191 | }
192 |
193 | /**
194 | * Get the content type (not MIME type)
195 | *
196 | * @return string|null Either 'text' or 'html'
197 | */
198 | public function get_type()
199 | {
200 | if ($this->type !== null)
201 | {
202 | return $this->type;
203 | }
204 | else
205 | {
206 | return null;
207 | }
208 | }
209 | }
210 |
211 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Cache/Memcache.php:
--------------------------------------------------------------------------------
1 | options = array(
91 | 'host' => '127.0.0.1',
92 | 'port' => 11211,
93 | 'extras' => array(
94 | 'timeout' => 3600, // one hour
95 | 'prefix' => 'simplepie_',
96 | ),
97 | );
98 | $parsed = SimplePie_Cache::parse_URL($location);
99 | $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
100 | $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
101 | $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
102 | $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
103 |
104 | $this->cache = new Memcache();
105 | $this->cache->addServer($this->options['host'], (int) $this->options['port']);
106 | }
107 |
108 | /**
109 | * Save data to the cache
110 | *
111 | * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
112 | * @return bool Successfulness
113 | */
114 | public function save($data)
115 | {
116 | if ($data instanceof SimplePie)
117 | {
118 | $data = $data->data;
119 | }
120 | return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
121 | }
122 |
123 | /**
124 | * Retrieve the data saved to the cache
125 | *
126 | * @return array Data for SimplePie::$data
127 | */
128 | public function load()
129 | {
130 | $data = $this->cache->get($this->name);
131 |
132 | if ($data !== false)
133 | {
134 | return unserialize($data);
135 | }
136 | return false;
137 | }
138 |
139 | /**
140 | * Retrieve the last modified time for the cache
141 | *
142 | * @return int Timestamp
143 | */
144 | public function mtime()
145 | {
146 | $data = $this->cache->get($this->name);
147 |
148 | if ($data !== false)
149 | {
150 | // essentially ignore the mtime because Memcache expires on it's own
151 | return time();
152 | }
153 |
154 | return false;
155 | }
156 |
157 | /**
158 | * Set the last modified time to the current time
159 | *
160 | * @return bool Success status
161 | */
162 | public function touch()
163 | {
164 | $data = $this->cache->get($this->name);
165 |
166 | if ($data !== false)
167 | {
168 | return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
169 | }
170 |
171 | return false;
172 | }
173 |
174 | /**
175 | * Remove the cache
176 | *
177 | * @return bool Success status
178 | */
179 | public function unlink()
180 | {
181 | return $this->cache->delete($this->name, 0);
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Registry.php:
--------------------------------------------------------------------------------
1 | 'SimplePie_Cache',
63 | 'Locator' => 'SimplePie_Locator',
64 | 'Parser' => 'SimplePie_Parser',
65 | 'File' => 'SimplePie_File',
66 | 'Sanitize' => 'SimplePie_Sanitize',
67 | 'Item' => 'SimplePie_Item',
68 | 'Author' => 'SimplePie_Author',
69 | 'Category' => 'SimplePie_Category',
70 | 'Enclosure' => 'SimplePie_Enclosure',
71 | 'Caption' => 'SimplePie_Caption',
72 | 'Copyright' => 'SimplePie_Copyright',
73 | 'Credit' => 'SimplePie_Credit',
74 | 'Rating' => 'SimplePie_Rating',
75 | 'Restriction' => 'SimplePie_Restriction',
76 | 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
77 | 'Source' => 'SimplePie_Source',
78 | 'Misc' => 'SimplePie_Misc',
79 | 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
80 | 'Parse_Date' => 'SimplePie_Parse_Date',
81 | );
82 |
83 | /**
84 | * Class mapping
85 | *
86 | * @see register()
87 | * @var array
88 | */
89 | protected $classes = array();
90 |
91 | /**
92 | * Legacy classes
93 | *
94 | * @see register()
95 | * @var array
96 | */
97 | protected $legacy = array();
98 |
99 | /**
100 | * Constructor
101 | *
102 | * No-op
103 | */
104 | public function __construct() { }
105 |
106 | /**
107 | * Register a class
108 | *
109 | * @param string $type See {@see $default} for names
110 | * @param string $class Class name, must subclass the corresponding default
111 | * @param bool $legacy Whether to enable legacy support for this class
112 | * @return bool Successfulness
113 | */
114 | public function register($type, $class, $legacy = false)
115 | {
116 | if (!is_subclass_of($class, $this->default[$type]))
117 | {
118 | return false;
119 | }
120 |
121 | $this->classes[$type] = $class;
122 |
123 | if ($legacy)
124 | {
125 | $this->legacy[] = $class;
126 | }
127 |
128 | return true;
129 | }
130 |
131 | /**
132 | * Get the class registered for a type
133 | *
134 | * Where possible, use {@see create()} or {@see call()} instead
135 | *
136 | * @param string $type
137 | * @return string|null
138 | */
139 | public function get_class($type)
140 | {
141 | if (!empty($this->classes[$type]))
142 | {
143 | return $this->classes[$type];
144 | }
145 | if (!empty($this->default[$type]))
146 | {
147 | return $this->default[$type];
148 | }
149 |
150 | return null;
151 | }
152 |
153 | /**
154 | * Create a new instance of a given type
155 | *
156 | * @param string $type
157 | * @param array $parameters Parameters to pass to the constructor
158 | * @return object Instance of class
159 | */
160 | public function &create($type, $parameters = array())
161 | {
162 | $class = $this->get_class($type);
163 |
164 | if (in_array($class, $this->legacy))
165 | {
166 | switch ($type)
167 | {
168 | case 'locator':
169 | // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
170 | // Specified: file, timeout, useragent, max_checked_feeds
171 | $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
172 | array_splice($parameters, 3, 1, $replacement);
173 | break;
174 | }
175 | }
176 |
177 | if (!method_exists($class, '__construct'))
178 | {
179 | $instance = new $class;
180 | }
181 | else
182 | {
183 | $reflector = new ReflectionClass($class);
184 | $instance = $reflector->newInstanceArgs($parameters);
185 | }
186 |
187 | if (method_exists($instance, 'set_registry'))
188 | {
189 | $instance->set_registry($this);
190 | }
191 | return $instance;
192 | }
193 |
194 | /**
195 | * Call a static method for a type
196 | *
197 | * @param string $type
198 | * @param string $method
199 | * @param array $parameters
200 | * @return mixed
201 | */
202 | public function &call($type, $method, $parameters = array())
203 | {
204 | $class = $this->get_class($type);
205 |
206 | if (in_array($class, $this->legacy))
207 | {
208 | switch ($type)
209 | {
210 | case 'Cache':
211 | // For backwards compatibility with old non-static
212 | // Cache::create() methods
213 | if ($method === 'get_handler')
214 | {
215 | $result = @call_user_func_array(array($class, 'create'), $parameters);
216 | return $result;
217 | }
218 | break;
219 | }
220 | }
221 |
222 | $result = call_user_func_array(array($class, $method), $parameters);
223 | return $result;
224 | }
225 | }
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Net/IPv6.php:
--------------------------------------------------------------------------------
1 |
55 | * @author elfrink at introweb dot nl
56 | * @author Josh Peck
57 | * @author Geoffrey Sneddon
58 | */
59 | class SimplePie_Net_IPv6
60 | {
61 | /**
62 | * Uncompresses an IPv6 address
63 | *
64 | * RFC 4291 allows you to compress concecutive zero pieces in an address to
65 | * '::'. This method expects a valid IPv6 address and expands the '::' to
66 | * the required number of zero pieces.
67 | *
68 | * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
69 | * ::1 -> 0:0:0:0:0:0:0:1
70 | *
71 | * @author Alexander Merz
72 | * @author elfrink at introweb dot nl
73 | * @author Josh Peck
74 | * @copyright 2003-2005 The PHP Group
75 | * @license http://www.opensource.org/licenses/bsd-license.php
76 | * @param string $ip An IPv6 address
77 | * @return string The uncompressed IPv6 address
78 | */
79 | public static function uncompress($ip)
80 | {
81 | $c1 = -1;
82 | $c2 = -1;
83 | if (substr_count($ip, '::') === 1)
84 | {
85 | list($ip1, $ip2) = explode('::', $ip);
86 | if ($ip1 === '')
87 | {
88 | $c1 = -1;
89 | }
90 | else
91 | {
92 | $c1 = substr_count($ip1, ':');
93 | }
94 | if ($ip2 === '')
95 | {
96 | $c2 = -1;
97 | }
98 | else
99 | {
100 | $c2 = substr_count($ip2, ':');
101 | }
102 | if (strpos($ip2, '.') !== false)
103 | {
104 | $c2++;
105 | }
106 | // ::
107 | if ($c1 === -1 && $c2 === -1)
108 | {
109 | $ip = '0:0:0:0:0:0:0:0';
110 | }
111 | // ::xxx
112 | else if ($c1 === -1)
113 | {
114 | $fill = str_repeat('0:', 7 - $c2);
115 | $ip = str_replace('::', $fill, $ip);
116 | }
117 | // xxx::
118 | else if ($c2 === -1)
119 | {
120 | $fill = str_repeat(':0', 7 - $c1);
121 | $ip = str_replace('::', $fill, $ip);
122 | }
123 | // xxx::xxx
124 | else
125 | {
126 | $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
127 | $ip = str_replace('::', $fill, $ip);
128 | }
129 | }
130 | return $ip;
131 | }
132 |
133 | /**
134 | * Compresses an IPv6 address
135 | *
136 | * RFC 4291 allows you to compress concecutive zero pieces in an address to
137 | * '::'. This method expects a valid IPv6 address and compresses consecutive
138 | * zero pieces to '::'.
139 | *
140 | * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
141 | * 0:0:0:0:0:0:0:1 -> ::1
142 | *
143 | * @see uncompress()
144 | * @param string $ip An IPv6 address
145 | * @return string The compressed IPv6 address
146 | */
147 | public static function compress($ip)
148 | {
149 | // Prepare the IP to be compressed
150 | $ip = self::uncompress($ip);
151 | $ip_parts = self::split_v6_v4($ip);
152 |
153 | // Replace all leading zeros
154 | $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
155 |
156 | // Find bunches of zeros
157 | if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
158 | {
159 | $max = 0;
160 | $pos = null;
161 | foreach ($matches[0] as $match)
162 | {
163 | if (strlen($match[0]) > $max)
164 | {
165 | $max = strlen($match[0]);
166 | $pos = $match[1];
167 | }
168 | }
169 |
170 | $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
171 | }
172 |
173 | if ($ip_parts[1] !== '')
174 | {
175 | return implode(':', $ip_parts);
176 | }
177 | else
178 | {
179 | return $ip_parts[0];
180 | }
181 | }
182 |
183 | /**
184 | * Splits an IPv6 address into the IPv6 and IPv4 representation parts
185 | *
186 | * RFC 4291 allows you to represent the last two parts of an IPv6 address
187 | * using the standard IPv4 representation
188 | *
189 | * Example: 0:0:0:0:0:0:13.1.68.3
190 | * 0:0:0:0:0:FFFF:129.144.52.38
191 | *
192 | * @param string $ip An IPv6 address
193 | * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
194 | */
195 | private static function split_v6_v4($ip)
196 | {
197 | if (strpos($ip, '.') !== false)
198 | {
199 | $pos = strrpos($ip, ':');
200 | $ipv6_part = substr($ip, 0, $pos);
201 | $ipv4_part = substr($ip, $pos + 1);
202 | return array($ipv6_part, $ipv4_part);
203 | }
204 | else
205 | {
206 | return array($ip, '');
207 | }
208 | }
209 |
210 | /**
211 | * Checks an IPv6 address
212 | *
213 | * Checks if the given IP is a valid IPv6 address
214 | *
215 | * @param string $ip An IPv6 address
216 | * @return bool true if $ip is a valid IPv6 address
217 | */
218 | public static function check_ipv6($ip)
219 | {
220 | $ip = self::uncompress($ip);
221 | list($ipv6, $ipv4) = self::split_v6_v4($ip);
222 | $ipv6 = explode(':', $ipv6);
223 | $ipv4 = explode('.', $ipv4);
224 | if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
225 | {
226 | foreach ($ipv6 as $ipv6_part)
227 | {
228 | // The section can't be empty
229 | if ($ipv6_part === '')
230 | return false;
231 |
232 | // Nor can it be over four characters
233 | if (strlen($ipv6_part) > 4)
234 | return false;
235 |
236 | // Remove leading zeros (this is safe because of the above)
237 | $ipv6_part = ltrim($ipv6_part, '0');
238 | if ($ipv6_part === '')
239 | $ipv6_part = '0';
240 |
241 | // Check the value is valid
242 | $value = hexdec($ipv6_part);
243 | if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
244 | return false;
245 | }
246 | if (count($ipv4) === 4)
247 | {
248 | foreach ($ipv4 as $ipv4_part)
249 | {
250 | $value = (int) $ipv4_part;
251 | if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
252 | return false;
253 | }
254 | }
255 | return true;
256 | }
257 | else
258 | {
259 | return false;
260 | }
261 | }
262 |
263 | /**
264 | * Checks if the given IP is a valid IPv6 address
265 | *
266 | * @codeCoverageIgnore
267 | * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
268 | * @see check_ipv6
269 | * @param string $ip An IPv6 address
270 | * @return bool true if $ip is a valid IPv6 address
271 | */
272 | public static function checkIPv6($ip)
273 | {
274 | return self::check_ipv6($ip);
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/js/bootstrap-tooltip.js:
--------------------------------------------------------------------------------
1 | /* ===========================================================
2 | * bootstrap-tooltip.js v2.0.3
3 | * http://twitter.github.com/bootstrap/javascript.html#tooltips
4 | * Inspired by the original jQuery.tipsy by Jason Frame
5 | * ===========================================================
6 | * Copyright 2012 Twitter, Inc.
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================== */
20 |
21 |
22 | !function ($) {
23 |
24 | "use strict"; // jshint ;_;
25 |
26 |
27 | /* TOOLTIP PUBLIC CLASS DEFINITION
28 | * =============================== */
29 |
30 | var Tooltip = function (element, options) {
31 | this.init('tooltip', element, options)
32 | }
33 |
34 | Tooltip.prototype = {
35 |
36 | constructor: Tooltip
37 |
38 | , init: function (type, element, options) {
39 | var eventIn
40 | , eventOut
41 |
42 | this.type = type
43 | this.$element = $(element)
44 | this.options = this.getOptions(options)
45 | this.enabled = true
46 |
47 | if (this.options.trigger != 'manual') {
48 | eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
49 | eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
50 | this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
51 | this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
52 | }
53 |
54 | this.options.selector ?
55 | (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
56 | this.fixTitle()
57 | }
58 |
59 | , getOptions: function (options) {
60 | options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
61 |
62 | if (options.delay && typeof options.delay == 'number') {
63 | options.delay = {
64 | show: options.delay
65 | , hide: options.delay
66 | }
67 | }
68 |
69 | return options
70 | }
71 |
72 | , enter: function (e) {
73 | var self = $(e.currentTarget)[this.type](this._options).data(this.type)
74 |
75 | if (!self.options.delay || !self.options.delay.show) return self.show()
76 |
77 | clearTimeout(this.timeout)
78 | self.hoverState = 'in'
79 | this.timeout = setTimeout(function() {
80 | if (self.hoverState == 'in') self.show()
81 | }, self.options.delay.show)
82 | }
83 |
84 | , leave: function (e) {
85 | var self = $(e.currentTarget)[this.type](this._options).data(this.type)
86 |
87 | if (!self.options.delay || !self.options.delay.hide) return self.hide()
88 |
89 | clearTimeout(this.timeout)
90 | self.hoverState = 'out'
91 | this.timeout = setTimeout(function() {
92 | if (self.hoverState == 'out') self.hide()
93 | }, self.options.delay.hide)
94 | }
95 |
96 | , show: function () {
97 | var $tip
98 | , inside
99 | , pos
100 | , actualWidth
101 | , actualHeight
102 | , placement
103 | , tp
104 |
105 | if (this.hasContent() && this.enabled) {
106 | $tip = this.tip()
107 | this.setContent()
108 |
109 | if (this.options.animation) {
110 | $tip.addClass('fade')
111 | }
112 |
113 | placement = typeof this.options.placement == 'function' ?
114 | this.options.placement.call(this, $tip[0], this.$element[0]) :
115 | this.options.placement
116 |
117 | inside = /in/.test(placement)
118 |
119 | $tip
120 | .remove()
121 | .css({ top: 0, left: 0, display: 'block' })
122 | .appendTo(inside ? this.$element : document.body)
123 |
124 | pos = this.getPosition(inside)
125 |
126 | actualWidth = $tip[0].offsetWidth
127 | actualHeight = $tip[0].offsetHeight
128 |
129 | switch (inside ? placement.split(' ')[1] : placement) {
130 | case 'bottom':
131 | tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
132 | break
133 | case 'top':
134 | tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
135 | break
136 | case 'left':
137 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
138 | break
139 | case 'right':
140 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
141 | break
142 | }
143 |
144 | $tip
145 | .css(tp)
146 | .addClass(placement)
147 | .addClass('in')
148 | }
149 | }
150 |
151 | , isHTML: function(text) {
152 | // html string detection logic adapted from jQuery
153 | return typeof text != 'string'
154 | || ( text.charAt(0) === "<"
155 | && text.charAt( text.length - 1 ) === ">"
156 | && text.length >= 3
157 | ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
158 | }
159 |
160 | , setContent: function () {
161 | var $tip = this.tip()
162 | , title = this.getTitle()
163 |
164 | $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
165 | $tip.removeClass('fade in top bottom left right')
166 | }
167 |
168 | , hide: function () {
169 | var that = this
170 | , $tip = this.tip()
171 |
172 | $tip.removeClass('in')
173 |
174 | function removeWithAnimation() {
175 | var timeout = setTimeout(function () {
176 | $tip.off($.support.transition.end).remove()
177 | }, 500)
178 |
179 | $tip.one($.support.transition.end, function () {
180 | clearTimeout(timeout)
181 | $tip.remove()
182 | })
183 | }
184 |
185 | $.support.transition && this.$tip.hasClass('fade') ?
186 | removeWithAnimation() :
187 | $tip.remove()
188 | }
189 |
190 | , fixTitle: function () {
191 | var $e = this.$element
192 | if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
193 | $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
194 | }
195 | }
196 |
197 | , hasContent: function () {
198 | return this.getTitle()
199 | }
200 |
201 | , getPosition: function (inside) {
202 | return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
203 | width: this.$element[0].offsetWidth
204 | , height: this.$element[0].offsetHeight
205 | })
206 | }
207 |
208 | , getTitle: function () {
209 | var title
210 | , $e = this.$element
211 | , o = this.options
212 |
213 | title = $e.attr('data-original-title')
214 | || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
215 |
216 | return title
217 | }
218 |
219 | , tip: function () {
220 | return this.$tip = this.$tip || $(this.options.template)
221 | }
222 |
223 | , validate: function () {
224 | if (!this.$element[0].parentNode) {
225 | this.hide()
226 | this.$element = null
227 | this.options = null
228 | }
229 | }
230 |
231 | , enable: function () {
232 | this.enabled = true
233 | }
234 |
235 | , disable: function () {
236 | this.enabled = false
237 | }
238 |
239 | , toggleEnabled: function () {
240 | this.enabled = !this.enabled
241 | }
242 |
243 | , toggle: function () {
244 | this[this.tip().hasClass('in') ? 'hide' : 'show']()
245 | }
246 |
247 | }
248 |
249 |
250 | /* TOOLTIP PLUGIN DEFINITION
251 | * ========================= */
252 |
253 | $.fn.tooltip = function ( option ) {
254 | return this.each(function () {
255 | var $this = $(this)
256 | , data = $this.data('tooltip')
257 | , options = typeof option == 'object' && option
258 | if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
259 | if (typeof option == 'string') data[option]()
260 | })
261 | }
262 |
263 | $.fn.tooltip.Constructor = Tooltip
264 |
265 | $.fn.tooltip.defaults = {
266 | animation: true
267 | , placement: 'top'
268 | , selector: false
269 | , template: ''
270 | , trigger: 'hover'
271 | , title: ''
272 | , delay: 0
273 | }
274 |
275 | }(window.jQuery);
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/XML/Declaration/Parser.php:
--------------------------------------------------------------------------------
1 | data = $data;
119 | $this->data_length = strlen($this->data);
120 | }
121 |
122 | /**
123 | * Parse the input data
124 | *
125 | * @access public
126 | * @return bool true on success, false on failure
127 | */
128 | public function parse()
129 | {
130 | while ($this->state && $this->state !== 'emit' && $this->has_data())
131 | {
132 | $state = $this->state;
133 | $this->$state();
134 | }
135 | $this->data = '';
136 | if ($this->state === 'emit')
137 | {
138 | return true;
139 | }
140 | else
141 | {
142 | $this->version = '';
143 | $this->encoding = '';
144 | $this->standalone = '';
145 | return false;
146 | }
147 | }
148 |
149 | /**
150 | * Check whether there is data beyond the pointer
151 | *
152 | * @access private
153 | * @return bool true if there is further data, false if not
154 | */
155 | public function has_data()
156 | {
157 | return (bool) ($this->position < $this->data_length);
158 | }
159 |
160 | /**
161 | * Advance past any whitespace
162 | *
163 | * @return int Number of whitespace characters passed
164 | */
165 | public function skip_whitespace()
166 | {
167 | $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
168 | $this->position += $whitespace;
169 | return $whitespace;
170 | }
171 |
172 | /**
173 | * Read value
174 | */
175 | public function get_value()
176 | {
177 | $quote = substr($this->data, $this->position, 1);
178 | if ($quote === '"' || $quote === "'")
179 | {
180 | $this->position++;
181 | $len = strcspn($this->data, $quote, $this->position);
182 | if ($this->has_data())
183 | {
184 | $value = substr($this->data, $this->position, $len);
185 | $this->position += $len + 1;
186 | return $value;
187 | }
188 | }
189 | return false;
190 | }
191 |
192 | public function before_version_name()
193 | {
194 | if ($this->skip_whitespace())
195 | {
196 | $this->state = 'version_name';
197 | }
198 | else
199 | {
200 | $this->state = false;
201 | }
202 | }
203 |
204 | public function version_name()
205 | {
206 | if (substr($this->data, $this->position, 7) === 'version')
207 | {
208 | $this->position += 7;
209 | $this->skip_whitespace();
210 | $this->state = 'version_equals';
211 | }
212 | else
213 | {
214 | $this->state = false;
215 | }
216 | }
217 |
218 | public function version_equals()
219 | {
220 | if (substr($this->data, $this->position, 1) === '=')
221 | {
222 | $this->position++;
223 | $this->skip_whitespace();
224 | $this->state = 'version_value';
225 | }
226 | else
227 | {
228 | $this->state = false;
229 | }
230 | }
231 |
232 | public function version_value()
233 | {
234 | if ($this->version = $this->get_value())
235 | {
236 | $this->skip_whitespace();
237 | if ($this->has_data())
238 | {
239 | $this->state = 'encoding_name';
240 | }
241 | else
242 | {
243 | $this->state = 'emit';
244 | }
245 | }
246 | else
247 | {
248 | $this->state = false;
249 | }
250 | }
251 |
252 | public function encoding_name()
253 | {
254 | if (substr($this->data, $this->position, 8) === 'encoding')
255 | {
256 | $this->position += 8;
257 | $this->skip_whitespace();
258 | $this->state = 'encoding_equals';
259 | }
260 | else
261 | {
262 | $this->state = 'standalone_name';
263 | }
264 | }
265 |
266 | public function encoding_equals()
267 | {
268 | if (substr($this->data, $this->position, 1) === '=')
269 | {
270 | $this->position++;
271 | $this->skip_whitespace();
272 | $this->state = 'encoding_value';
273 | }
274 | else
275 | {
276 | $this->state = false;
277 | }
278 | }
279 |
280 | public function encoding_value()
281 | {
282 | if ($this->encoding = $this->get_value())
283 | {
284 | $this->skip_whitespace();
285 | if ($this->has_data())
286 | {
287 | $this->state = 'standalone_name';
288 | }
289 | else
290 | {
291 | $this->state = 'emit';
292 | }
293 | }
294 | else
295 | {
296 | $this->state = false;
297 | }
298 | }
299 |
300 | public function standalone_name()
301 | {
302 | if (substr($this->data, $this->position, 10) === 'standalone')
303 | {
304 | $this->position += 10;
305 | $this->skip_whitespace();
306 | $this->state = 'standalone_equals';
307 | }
308 | else
309 | {
310 | $this->state = false;
311 | }
312 | }
313 |
314 | public function standalone_equals()
315 | {
316 | if (substr($this->data, $this->position, 1) === '=')
317 | {
318 | $this->position++;
319 | $this->skip_whitespace();
320 | $this->state = 'standalone_value';
321 | }
322 | else
323 | {
324 | $this->state = false;
325 | }
326 | }
327 |
328 | public function standalone_value()
329 | {
330 | if ($standalone = $this->get_value())
331 | {
332 | switch ($standalone)
333 | {
334 | case 'yes':
335 | $this->standalone = true;
336 | break;
337 |
338 | case 'no':
339 | $this->standalone = false;
340 | break;
341 |
342 | default:
343 | $this->state = false;
344 | return;
345 | }
346 |
347 | $this->skip_whitespace();
348 | if ($this->has_data())
349 | {
350 | $this->state = false;
351 | }
352 | else
353 | {
354 | $this->state = 'emit';
355 | }
356 | }
357 | else
358 | {
359 | $this->state = false;
360 | }
361 | }
362 | }
363 |
--------------------------------------------------------------------------------
/changelog.txt:
--------------------------------------------------------------------------------
1 | FiveFilters.org: Full-Text RSS
2 | http://fivefilters.org/content-only/
3 | CHANGELOG
4 | ------------------------------------
5 | 3.2 (2013-05-14)
6 | - A short excerpt from the first few lines of the extracted content can now be included in the output (pass &summary=1 in querystring, see $options->summary in config file for more info)
7 | - Full content can now be excluded from the output (pass &content=0 in querystring, see $options->content in config file for more info)
8 | - Site config files can now be automatically updated from our GitHub repository (URL to call visible in admin area)
9 | - Site config files updated for better extraction
10 | - PHP Readability updated to be more lenient when pruning HTML
11 | - Language detection library updated
12 | - HTML meta refresh redirects now also followed
13 | - APC stats (if APC is available on your server) now visible in admin area
14 | - Bug fix: Duplicate find_string and replace_string values in site config files no longer removed (thanks Fabrizio!)
15 | - Bug fix: MIME type actions now applied when following single page URLs
16 | - Other minor fixes/improvements
17 |
18 | 3.1 (2013-03-06)
19 | - PHP Readability updated to preserve more images/videos
20 | - Site config files updated for better extraction
21 | - SimplePie updated
22 | - New config option favour_feed_titles and request parameter use_extracted_title to allow extracted titles to be used in generated feed
23 | - Remove image lazy loading (looks for markup used by http://wordpress.org/extend/plugins/lazy-load/)
24 | - elements appearing inside - elements are now preserved in generated feed
25 | -
elements now preserved
26 | - Allow multiple elements (previously only one was preserved)
27 | - Bug fix: No more self-closing iframe elements
28 | - Bug fix: Fixed manifest.yml to prevent error message when deploying to AppFog
29 | - Other minor fixes/improvements
30 |
31 | 3.0 (2012-09-04)
32 | - Multi-page support - next_page_link now supported in site config (enable/disable with $options->multipage)
33 | - HTML5 parser available - use parser: html5lib in site config, also see $options->allowed_parsers
34 | - Updated site patterns for better extraction
35 | - New global site config to be applied to all sites (global.txt)
36 | - APC caching of site config files to improve performance, if APC available - see $options->apc
37 | - Site config editor in admin/ - easily find, edit, test, and test site config files, or add new ones
38 | - Debug mode to see what's happening behind the scenes - see $options->debug
39 | - Removed deprecated config options: restrict, message_to_prepend_with_key, message_to_append_with_key, error_message_with_key
40 | - Removed extraction with CSS via querystring
41 | - Removed config option: $options->alternative_url
42 | - Bug fix: allow extraction of a single element
43 | - Bug fix: redirect handling improved
44 | - Strip 'http://' prefix when API key is supplied
45 | - Site config merging (custom + standard + fingerprint + global)
46 | - Site config command replace_string(find): replace can now be split over two lines: find_string: find, replace_string: replace
47 | - YouTube and Vimeo URLs now return iframe embed code
48 | - We now look for OpenGraph title and date elements
49 | - Improved extraction from AJAX pages - we now look for AJAX triggers embedded in HTML, per Google spec
50 | - JSONP support - use &format=json&callback=functionName in querystring
51 | - New config option to enable Cross-Origin Resource Sharing (CORS): $option->cors
52 | - New config option to enable XSS filtering, if required: $option->xss_filter
53 | - Zend_Cache updated
54 | - Smart caching - experimental feature to store cache IDs in APC first, and write output to disk on subsequent request (see $options->smart_cache)
55 | - Easier cloud deploy - manifest.yml added for AppFog
56 | - Override most config options with environment variables, e.g. ftr_max_entries: 3
57 |
58 | 2.9.5 (2012-04-29)
59 | - Language detection using Text_LanguageDetect or PHP-CLD (dc:language field in output and $options->detect_language in config)
60 | - New site patterns added and old ones updated
61 | - Experimental tool for simpler site pattern updates (access admin/ folder)
62 | - Plus other fixes/improvements
63 |
64 | 2.9.1 (2011-11-02)
65 | - Fix: Character encoding issue affecting some non-English articles (makefulltextfeed.php and SimplePie/Misc.php changed)
66 |
67 | 2.9 (2011-11-01)
68 | - New site patterns added and old ones updated
69 | - New config option: require_key - restrict access to those with password/key
70 | - New config option: rewrite_url - URL rewrite rules to be applied before HTTP request
71 | - New site config options to extract author(s) and publication date (matches included in feed item as and )
72 | - New site config option: replace_string([string to find]): [replacement string]
73 | - New site identification method: site fingerprints (HTML fragments linked to site config)
74 | - Update check now also checks for new site patterns
75 | - Effective URL (URL after redirects/rewrites) now included in feed item as
76 | - Prevent indexing of generated feeds by search engines
77 | - Enclosure support (enclosures preserved as elements)
78 | - Better handling of non-HTML content types
79 | - Sending custom User-Agent HTTP header for matching sites now supported
80 | - CSS extraction deprecated in favour of site patterns (still works, but form field removed and feature may disappear in 3.0)
81 | - Fix: Improved character-encoding detection
82 | - Fix: URL parsing issues for certain URLs (SimplePie updated)
83 | - Fix: Author and other Dublin Core () elements now appear in JSON output
84 | - Fix: Minor fixes for PHP Readability
85 | - Plus other minor fixes/improvements
86 |
87 | 2.8 (2011-05-30)
88 | - Tidy no longer stripping HTML5 elements
89 | - JSON output (pass &format=json in querystring)
90 | - New site patterns added and old ones updated
91 | - New site config option to force full-page retrieval on multi-page articles: single_page_link
92 | - User Guide (PDF) now included (although still a work in progress)
93 | - URL placeholders now accepted in message_to_prepend/append config options
94 | - Plus minor fixes...
95 |
96 | 2.7 (2011-03-21)
97 | - Site patterns for better control over extraction (see site_config/README.txt)
98 | - hNews support (improves content extraction for sites using hNews microformatting)
99 | - Cookie Jar now used to store and sends cookies when following HTTP redirects
100 | - Better handling of certain cases where HTML Tidy fails to clean up properly
101 | - Bug fix: curl_multi_select() timing out in certain environments (fixed in HumbleHttpAgent.php)
102 | - Bug fix: broken HTTP header parsing in some environments (fixed in SimplePie_HumbleHttpAgent.php)
103 | - Bug fix: invalid API URL shown (fixed in index.php)
104 | - Plus other minor fixes...
105 |
106 | 2.6 (2011-03-02)
107 | - Rewriting of hash-bang (#!) URLs (see http://www.tbray.org/ongoing/When/201x/2011/02/09/Hash-Blecch for an explanation)
108 | - Improved parallel fetching support (HumbleHttpAgent uses curl_multi_* functions if PECL HTTP extension is not present)
109 | - Improved HTTP redirect support (now handled in HumbleHttpAgent, no longer relies on PHP)
110 | - Improved performance for single page (non-feed) requests: (SimplePie connected to HumbleHttpAgent)
111 | - Improved memory use for processing large feeds (HumbleHttpAgent's stored responses cleared as they're retrieved)
112 | - Bug fix: exclude on fail option no longer requires valid key
113 | - Bug fix: workaround for PHP bug http://bugs.php.net/51192 (fixed in makefulltextfeed.php)
114 | - Plus other minor changes...
115 |
116 | 2.5 (2011-01-08)
117 | - New option: custom extraction pattern (CSS selectors)
118 | - New option: allowed URLs (restrict service to pre-defined feeds/domains)
119 | - New option: exclude items on fail (remove items from feed if content extraction fails)
120 | - Remove 'http://' from URL before form submission (prevents errors on hosts which have overly vigilant security software)
121 | - Allow overriding of index.php with custom_index.php
122 | - config.php now required (override with custom_config.php)
123 | - index.php now uses config.php to determine what to display
124 | - Bug fix: occasional fatal error in IRI::__toString() (IRI updated)
125 | - Bug fix: workaround for PHP bug http://bugs.php.net/51192 (fixed in HumbleHttpAgent.php)
126 |
127 | 2.2 (2010-10-30)
128 | - Character-encoding detection improved (minor change)
129 | - Rewriting of relative URLs improved (tracks redirect URLs)
130 | - Minor changes to prevent errors in certain hosting environments
131 | - Compatibility test file updated with more tests
132 |
133 | 2.1 (2010-09-13)
134 | - Better content extraction (using PHP Readability 1.7.1)
135 | - Parallel HTTP requests (using Humble HTTP Agent)
136 | - Auto loading of necessary classes
137 | - Rewriting of relative URLs (using IRI)
138 | - Added compatibility test file (to check if server meets requirements)
139 | - Character-encoding support improved (using SimplePie)
140 |
141 | 1.5 (2010-05-30)
142 | - Support for PHP 5.3 (thanks Murilo!)
143 | - Character-encoding support improved (favours iconv over mb_convert_encoding)
144 |
145 | 1.0 (2010-03-05)
146 | - Better support for different character-encodings
147 | - Auto-cleanup of cache files
148 | - Very basic option for load distribution (if you're planning on installing the code on multiple servers)
149 | - Separate config file (see config-sample.php)
--------------------------------------------------------------------------------
/libraries/simplepie/library/SimplePie/Content/Type/Sniffer.php:
--------------------------------------------------------------------------------
1 | file = $file;
77 | }
78 |
79 | /**
80 | * Get the Content-Type of the specified file
81 | *
82 | * @return string Actual Content-Type
83 | */
84 | public function get_type()
85 | {
86 | if (isset($this->file->headers['content-type']))
87 | {
88 | if (!isset($this->file->headers['content-encoding'])
89 | && ($this->file->headers['content-type'] === 'text/plain'
90 | || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
91 | || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
92 | || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
93 | {
94 | return $this->text_or_binary();
95 | }
96 |
97 | if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
98 | {
99 | $official = substr($this->file->headers['content-type'], 0, $pos);
100 | }
101 | else
102 | {
103 | $official = $this->file->headers['content-type'];
104 | }
105 | $official = trim(strtolower($official));
106 |
107 | if ($official === 'unknown/unknown'
108 | || $official === 'application/unknown')
109 | {
110 | return $this->unknown();
111 | }
112 | elseif (substr($official, -4) === '+xml'
113 | || $official === 'text/xml'
114 | || $official === 'application/xml')
115 | {
116 | return $official;
117 | }
118 | elseif (substr($official, 0, 6) === 'image/')
119 | {
120 | if ($return = $this->image())
121 | {
122 | return $return;
123 | }
124 | else
125 | {
126 | return $official;
127 | }
128 | }
129 | elseif ($official === 'text/html')
130 | {
131 | return $this->feed_or_html();
132 | }
133 | else
134 | {
135 | return $official;
136 | }
137 | }
138 | else
139 | {
140 | return $this->unknown();
141 | }
142 | }
143 |
144 | /**
145 | * Sniff text or binary
146 | *
147 | * @return string Actual Content-Type
148 | */
149 | public function text_or_binary()
150 | {
151 | if (substr($this->file->body, 0, 2) === "\xFE\xFF"
152 | || substr($this->file->body, 0, 2) === "\xFF\xFE"
153 | || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
154 | || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
155 | {
156 | return 'text/plain';
157 | }
158 | elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
159 | {
160 | return 'application/octect-stream';
161 | }
162 | else
163 | {
164 | return 'text/plain';
165 | }
166 | }
167 |
168 | /**
169 | * Sniff unknown
170 | *
171 | * @return string Actual Content-Type
172 | */
173 | public function unknown()
174 | {
175 | $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
176 | if (strtolower(substr($this->file->body, $ws, 14)) === 'file->body, $ws, 5)) === 'file->body, $ws, 7)) === '