├── 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 | <xsl:value-of select="$title"/> (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 | -------------------------------------------------------------------------------- /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 |
33 | '; ?> 34 | 35 | 36 | 37 |
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 | <?php echo $title; ?> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 33 | 34 | 35 |
36 | 49 | 50 | 55 | 56 |
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('

Para 1

Para 2

'); 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 '' . $matches[1] . ''; 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)) === 'file->body, 0, 5) === '%PDF-') 183 | { 184 | return 'application/pdf'; 185 | } 186 | elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-') 187 | { 188 | return 'application/postscript'; 189 | } 190 | elseif (substr($this->file->body, 0, 6) === 'GIF87a' 191 | || substr($this->file->body, 0, 6) === 'GIF89a') 192 | { 193 | return 'image/gif'; 194 | } 195 | elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") 196 | { 197 | return 'image/png'; 198 | } 199 | elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") 200 | { 201 | return 'image/jpeg'; 202 | } 203 | elseif (substr($this->file->body, 0, 2) === "\x42\x4D") 204 | { 205 | return 'image/bmp'; 206 | } 207 | elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00") 208 | { 209 | return 'image/vnd.microsoft.icon'; 210 | } 211 | else 212 | { 213 | return $this->text_or_binary(); 214 | } 215 | } 216 | 217 | /** 218 | * Sniff images 219 | * 220 | * @return string Actual Content-Type 221 | */ 222 | public function image() 223 | { 224 | if (substr($this->file->body, 0, 6) === 'GIF87a' 225 | || substr($this->file->body, 0, 6) === 'GIF89a') 226 | { 227 | return 'image/gif'; 228 | } 229 | elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") 230 | { 231 | return 'image/png'; 232 | } 233 | elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") 234 | { 235 | return 'image/jpeg'; 236 | } 237 | elseif (substr($this->file->body, 0, 2) === "\x42\x4D") 238 | { 239 | return 'image/bmp'; 240 | } 241 | elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00") 242 | { 243 | return 'image/vnd.microsoft.icon'; 244 | } 245 | else 246 | { 247 | return false; 248 | } 249 | } 250 | 251 | /** 252 | * Sniff HTML 253 | * 254 | * @return string Actual Content-Type 255 | */ 256 | public function feed_or_html() 257 | { 258 | $len = strlen($this->file->body); 259 | $pos = strspn($this->file->body, "\x09\x0A\x0D\x20"); 260 | 261 | while ($pos < $len) 262 | { 263 | switch ($this->file->body[$pos]) 264 | { 265 | case "\x09": 266 | case "\x0A": 267 | case "\x0D": 268 | case "\x20": 269 | $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos); 270 | continue 2; 271 | 272 | case '<': 273 | $pos++; 274 | break; 275 | 276 | default: 277 | return 'text/html'; 278 | } 279 | 280 | if (substr($this->file->body, $pos, 3) === '!--') 281 | { 282 | $pos += 3; 283 | if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false) 284 | { 285 | $pos += 3; 286 | } 287 | else 288 | { 289 | return 'text/html'; 290 | } 291 | } 292 | elseif (substr($this->file->body, $pos, 1) === '!') 293 | { 294 | if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false) 295 | { 296 | $pos++; 297 | } 298 | else 299 | { 300 | return 'text/html'; 301 | } 302 | } 303 | elseif (substr($this->file->body, $pos, 1) === '?') 304 | { 305 | if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false) 306 | { 307 | $pos += 2; 308 | } 309 | else 310 | { 311 | return 'text/html'; 312 | } 313 | } 314 | elseif (substr($this->file->body, $pos, 3) === 'rss' 315 | || substr($this->file->body, $pos, 7) === 'rdf:RDF') 316 | { 317 | return 'application/rss+xml'; 318 | } 319 | elseif (substr($this->file->body, $pos, 4) === 'feed') 320 | { 321 | return 'application/atom+xml'; 322 | } 323 | else 324 | { 325 | return 'text/html'; 326 | } 327 | } 328 | 329 | return 'text/html'; 330 | } 331 | } 332 | 333 | -------------------------------------------------------------------------------- /libraries/Zend/Cache/Backend.php: -------------------------------------------------------------------------------- 1 | (int) lifetime : 36 | * - Cache lifetime (in seconds) 37 | * - If null, the cache is valid forever 38 | * 39 | * =====> (int) logging : 40 | * - if set to true, a logging is activated throw Zend_Log 41 | * 42 | * @var array directives 43 | */ 44 | protected $_directives = array( 45 | 'lifetime' => 3600, 46 | 'logging' => false, 47 | 'logger' => null 48 | ); 49 | 50 | /** 51 | * Available options 52 | * 53 | * @var array available options 54 | */ 55 | protected $_options = array(); 56 | 57 | /** 58 | * Constructor 59 | * 60 | * @param array $options Associative array of options 61 | * @throws Zend_Cache_Exception 62 | * @return void 63 | */ 64 | public function __construct(array $options = array()) 65 | { 66 | while (list($name, $value) = each($options)) { 67 | $this->setOption($name, $value); 68 | } 69 | } 70 | 71 | /** 72 | * Set the frontend directives 73 | * 74 | * @param array $directives Assoc of directives 75 | * @throws Zend_Cache_Exception 76 | * @return void 77 | */ 78 | public function setDirectives($directives) 79 | { 80 | if (!is_array($directives)) Zend_Cache::throwException('Directives parameter must be an array'); 81 | while (list($name, $value) = each($directives)) { 82 | if (!is_string($name)) { 83 | Zend_Cache::throwException("Incorrect option name : $name"); 84 | } 85 | $name = strtolower($name); 86 | if (array_key_exists($name, $this->_directives)) { 87 | $this->_directives[$name] = $value; 88 | } 89 | 90 | } 91 | 92 | $this->_loggerSanity(); 93 | } 94 | 95 | /** 96 | * Set an option 97 | * 98 | * @param string $name 99 | * @param mixed $value 100 | * @throws Zend_Cache_Exception 101 | * @return void 102 | */ 103 | public function setOption($name, $value) 104 | { 105 | if (!is_string($name)) { 106 | Zend_Cache::throwException("Incorrect option name : $name"); 107 | } 108 | $name = strtolower($name); 109 | if (array_key_exists($name, $this->_options)) { 110 | $this->_options[$name] = $value; 111 | } 112 | } 113 | 114 | /** 115 | * Returns an option 116 | * 117 | * @param string $name Optional, the options name to return 118 | * @throws Zend_Cache_Exceptions 119 | * @return mixed 120 | */ 121 | public function getOption($name) 122 | { 123 | $name = strtolower($name); 124 | 125 | if (array_key_exists($name, $this->_options)) { 126 | return $this->_options[$name]; 127 | } 128 | 129 | if (array_key_exists($name, $this->_directives)) { 130 | return $this->_directives[$name]; 131 | } 132 | 133 | Zend_Cache::throwException("Incorrect option name : {$name}"); 134 | } 135 | 136 | /** 137 | * Get the life time 138 | * 139 | * if $specificLifetime is not false, the given specific life time is used 140 | * else, the global lifetime is used 141 | * 142 | * @param int $specificLifetime 143 | * @return int Cache life time 144 | */ 145 | public function getLifetime($specificLifetime) 146 | { 147 | if ($specificLifetime === false) { 148 | return $this->_directives['lifetime']; 149 | } 150 | return $specificLifetime; 151 | } 152 | 153 | /** 154 | * Return true if the automatic cleaning is available for the backend 155 | * 156 | * DEPRECATED : use getCapabilities() instead 157 | * 158 | * @deprecated 159 | * @return boolean 160 | */ 161 | public function isAutomaticCleaningAvailable() 162 | { 163 | return true; 164 | } 165 | 166 | /** 167 | * Determine system TMP directory and detect if we have read access 168 | * 169 | * inspired from Zend_File_Transfer_Adapter_Abstract 170 | * 171 | * @return string 172 | * @throws Zend_Cache_Exception if unable to determine directory 173 | */ 174 | public function getTmpDir() 175 | { 176 | $tmpdir = array(); 177 | foreach (array($_ENV, $_SERVER) as $tab) { 178 | foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $key) { 179 | if (isset($tab[$key]) && is_string($tab[$key])) { 180 | if (($key == 'windir') or ($key == 'SystemRoot')) { 181 | $dir = realpath($tab[$key] . '\\temp'); 182 | } else { 183 | $dir = realpath($tab[$key]); 184 | } 185 | if ($this->_isGoodTmpDir($dir)) { 186 | return $dir; 187 | } 188 | } 189 | } 190 | } 191 | $upload = ini_get('upload_tmp_dir'); 192 | if ($upload) { 193 | $dir = realpath($upload); 194 | if ($this->_isGoodTmpDir($dir)) { 195 | return $dir; 196 | } 197 | } 198 | if (function_exists('sys_get_temp_dir')) { 199 | $dir = sys_get_temp_dir(); 200 | if ($this->_isGoodTmpDir($dir)) { 201 | return $dir; 202 | } 203 | } 204 | // Attemp to detect by creating a temporary file 205 | $tempFile = tempnam(md5(uniqid(rand(), TRUE)), ''); 206 | if ($tempFile) { 207 | $dir = realpath(dirname($tempFile)); 208 | unlink($tempFile); 209 | if ($this->_isGoodTmpDir($dir)) { 210 | return $dir; 211 | } 212 | } 213 | if ($this->_isGoodTmpDir('/tmp')) { 214 | return '/tmp'; 215 | } 216 | if ($this->_isGoodTmpDir('\\temp')) { 217 | return '\\temp'; 218 | } 219 | Zend_Cache::throwException('Could not determine temp directory, please specify a cache_dir manually'); 220 | } 221 | 222 | /** 223 | * Verify if the given temporary directory is readable and writable 224 | * 225 | * @param string $dir temporary directory 226 | * @return boolean true if the directory is ok 227 | */ 228 | protected function _isGoodTmpDir($dir) 229 | { 230 | if (is_readable($dir)) { 231 | if (is_writable($dir)) { 232 | return true; 233 | } 234 | } 235 | return false; 236 | } 237 | 238 | /** 239 | * Make sure if we enable logging that the Zend_Log class 240 | * is available. 241 | * Create a default log object if none is set. 242 | * 243 | * @throws Zend_Cache_Exception 244 | * @return void 245 | */ 246 | protected function _loggerSanity() 247 | { 248 | if (!isset($this->_directives['logging']) || !$this->_directives['logging']) { 249 | return; 250 | } 251 | 252 | if (isset($this->_directives['logger'])) { 253 | if ($this->_directives['logger'] instanceof Zend_Log) { 254 | return; 255 | } 256 | Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.'); 257 | } 258 | 259 | // Create a default logger to the standard output stream 260 | require_once 'Zend/Log.php'; 261 | require_once 'Zend/Log/Writer/Stream.php'; 262 | require_once 'Zend/Log/Filter/Priority.php'; 263 | $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output')); 264 | $logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<=')); 265 | $this->_directives['logger'] = $logger; 266 | } 267 | 268 | /** 269 | * Log a message at the WARN (4) priority. 270 | * 271 | * @param string $message 272 | * @throws Zend_Cache_Exception 273 | * @return void 274 | */ 275 | protected function _log($message, $priority = 4) 276 | { 277 | if (!$this->_directives['logging']) { 278 | return; 279 | } 280 | 281 | if (!isset($this->_directives['logger'])) { 282 | Zend_Cache::throwException('Logging is enabled but logger is not set.'); 283 | } 284 | $logger = $this->_directives['logger']; 285 | if (!$logger instanceof Zend_Log) { 286 | Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.'); 287 | } 288 | $logger->log($message, $priority); 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /libraries/language-detect/unicode_blocks.dat: -------------------------------------------------------------------------------- 1 | a:145:{i:0;a:3:{i:0;s:6:"0x0000";i:1;s:6:"0x007F";i:2;s:11:"Basic Latin";}i:1;a:3:{i:0;s:6:"0x0080";i:1;s:6:"0x00FF";i:2;s:18:"Latin-1 Supplement";}i:2;a:3:{i:0;s:6:"0x0100";i:1;s:6:"0x017F";i:2;s:16:"Latin Extended-A";}i:3;a:3:{i:0;s:6:"0x0180";i:1;s:6:"0x024F";i:2;s:16:"Latin Extended-B";}i:4;a:3:{i:0;s:6:"0x0250";i:1;s:6:"0x02AF";i:2;s:14:"IPA Extensions";}i:5;a:3:{i:0;s:6:"0x02B0";i:1;s:6:"0x02FF";i:2;s:24:"Spacing Modifier Letters";}i:6;a:3:{i:0;s:6:"0x0300";i:1;s:6:"0x036F";i:2;s:27:"Combining Diacritical Marks";}i:7;a:3:{i:0;s:6:"0x0370";i:1;s:6:"0x03FF";i:2;s:16:"Greek and Coptic";}i:8;a:3:{i:0;s:6:"0x0400";i:1;s:6:"0x04FF";i:2;s:8:"Cyrillic";}i:9;a:3:{i:0;s:6:"0x0500";i:1;s:6:"0x052F";i:2;s:19:"Cyrillic Supplement";}i:10;a:3:{i:0;s:6:"0x0530";i:1;s:6:"0x058F";i:2;s:8:"Armenian";}i:11;a:3:{i:0;s:6:"0x0590";i:1;s:6:"0x05FF";i:2;s:6:"Hebrew";}i:12;a:3:{i:0;s:6:"0x0600";i:1;s:6:"0x06FF";i:2;s:6:"Arabic";}i:13;a:3:{i:0;s:6:"0x0700";i:1;s:6:"0x074F";i:2;s:6:"Syriac";}i:14;a:3:{i:0;s:6:"0x0750";i:1;s:6:"0x077F";i:2;s:17:"Arabic Supplement";}i:15;a:3:{i:0;s:6:"0x0780";i:1;s:6:"0x07BF";i:2;s:6:"Thaana";}i:16;a:3:{i:0;s:6:"0x0900";i:1;s:6:"0x097F";i:2;s:10:"Devanagari";}i:17;a:3:{i:0;s:6:"0x0980";i:1;s:6:"0x09FF";i:2;s:7:"Bengali";}i:18;a:3:{i:0;s:6:"0x0A00";i:1;s:6:"0x0A7F";i:2;s:8:"Gurmukhi";}i:19;a:3:{i:0;s:6:"0x0A80";i:1;s:6:"0x0AFF";i:2;s:8:"Gujarati";}i:20;a:3:{i:0;s:6:"0x0B00";i:1;s:6:"0x0B7F";i:2;s:5:"Oriya";}i:21;a:3:{i:0;s:6:"0x0B80";i:1;s:6:"0x0BFF";i:2;s:5:"Tamil";}i:22;a:3:{i:0;s:6:"0x0C00";i:1;s:6:"0x0C7F";i:2;s:6:"Telugu";}i:23;a:3:{i:0;s:6:"0x0C80";i:1;s:6:"0x0CFF";i:2;s:7:"Kannada";}i:24;a:3:{i:0;s:6:"0x0D00";i:1;s:6:"0x0D7F";i:2;s:9:"Malayalam";}i:25;a:3:{i:0;s:6:"0x0D80";i:1;s:6:"0x0DFF";i:2;s:7:"Sinhala";}i:26;a:3:{i:0;s:6:"0x0E00";i:1;s:6:"0x0E7F";i:2;s:4:"Thai";}i:27;a:3:{i:0;s:6:"0x0E80";i:1;s:6:"0x0EFF";i:2;s:3:"Lao";}i:28;a:3:{i:0;s:6:"0x0F00";i:1;s:6:"0x0FFF";i:2;s:7:"Tibetan";}i:29;a:3:{i:0;s:6:"0x1000";i:1;s:6:"0x109F";i:2;s:7:"Myanmar";}i:30;a:3:{i:0;s:6:"0x10A0";i:1;s:6:"0x10FF";i:2;s:8:"Georgian";}i:31;a:3:{i:0;s:6:"0x1100";i:1;s:6:"0x11FF";i:2;s:11:"Hangul Jamo";}i:32;a:3:{i:0;s:6:"0x1200";i:1;s:6:"0x137F";i:2;s:8:"Ethiopic";}i:33;a:3:{i:0;s:6:"0x1380";i:1;s:6:"0x139F";i:2;s:19:"Ethiopic Supplement";}i:34;a:3:{i:0;s:6:"0x13A0";i:1;s:6:"0x13FF";i:2;s:8:"Cherokee";}i:35;a:3:{i:0;s:6:"0x1400";i:1;s:6:"0x167F";i:2;s:37:"Unified Canadian Aboriginal Syllabics";}i:36;a:3:{i:0;s:6:"0x1680";i:1;s:6:"0x169F";i:2;s:5:"Ogham";}i:37;a:3:{i:0;s:6:"0x16A0";i:1;s:6:"0x16FF";i:2;s:5:"Runic";}i:38;a:3:{i:0;s:6:"0x1700";i:1;s:6:"0x171F";i:2;s:7:"Tagalog";}i:39;a:3:{i:0;s:6:"0x1720";i:1;s:6:"0x173F";i:2;s:7:"Hanunoo";}i:40;a:3:{i:0;s:6:"0x1740";i:1;s:6:"0x175F";i:2;s:5:"Buhid";}i:41;a:3:{i:0;s:6:"0x1760";i:1;s:6:"0x177F";i:2;s:8:"Tagbanwa";}i:42;a:3:{i:0;s:6:"0x1780";i:1;s:6:"0x17FF";i:2;s:5:"Khmer";}i:43;a:3:{i:0;s:6:"0x1800";i:1;s:6:"0x18AF";i:2;s:9:"Mongolian";}i:44;a:3:{i:0;s:6:"0x1900";i:1;s:6:"0x194F";i:2;s:5:"Limbu";}i:45;a:3:{i:0;s:6:"0x1950";i:1;s:6:"0x197F";i:2;s:6:"Tai Le";}i:46;a:3:{i:0;s:6:"0x1980";i:1;s:6:"0x19DF";i:2;s:11:"New Tai Lue";}i:47;a:3:{i:0;s:6:"0x19E0";i:1;s:6:"0x19FF";i:2;s:13:"Khmer Symbols";}i:48;a:3:{i:0;s:6:"0x1A00";i:1;s:6:"0x1A1F";i:2;s:8:"Buginese";}i:49;a:3:{i:0;s:6:"0x1D00";i:1;s:6:"0x1D7F";i:2;s:19:"Phonetic Extensions";}i:50;a:3:{i:0;s:6:"0x1D80";i:1;s:6:"0x1DBF";i:2;s:30:"Phonetic Extensions Supplement";}i:51;a:3:{i:0;s:6:"0x1DC0";i:1;s:6:"0x1DFF";i:2;s:38:"Combining Diacritical Marks Supplement";}i:52;a:3:{i:0;s:6:"0x1E00";i:1;s:6:"0x1EFF";i:2;s:25:"Latin Extended Additional";}i:53;a:3:{i:0;s:6:"0x1F00";i:1;s:6:"0x1FFF";i:2;s:14:"Greek Extended";}i:54;a:3:{i:0;s:6:"0x2000";i:1;s:6:"0x206F";i:2;s:19:"General Punctuation";}i:55;a:3:{i:0;s:6:"0x2070";i:1;s:6:"0x209F";i:2;s:27:"Superscripts and Subscripts";}i:56;a:3:{i:0;s:6:"0x20A0";i:1;s:6:"0x20CF";i:2;s:16:"Currency Symbols";}i:57;a:3:{i:0;s:6:"0x20D0";i:1;s:6:"0x20FF";i:2;s:39:"Combining Diacritical Marks for Symbols";}i:58;a:3:{i:0;s:6:"0x2100";i:1;s:6:"0x214F";i:2;s:18:"Letterlike Symbols";}i:59;a:3:{i:0;s:6:"0x2150";i:1;s:6:"0x218F";i:2;s:12:"Number Forms";}i:60;a:3:{i:0;s:6:"0x2190";i:1;s:6:"0x21FF";i:2;s:6:"Arrows";}i:61;a:3:{i:0;s:6:"0x2200";i:1;s:6:"0x22FF";i:2;s:22:"Mathematical Operators";}i:62;a:3:{i:0;s:6:"0x2300";i:1;s:6:"0x23FF";i:2;s:23:"Miscellaneous Technical";}i:63;a:3:{i:0;s:6:"0x2400";i:1;s:6:"0x243F";i:2;s:16:"Control Pictures";}i:64;a:3:{i:0;s:6:"0x2440";i:1;s:6:"0x245F";i:2;s:29:"Optical Character Recognition";}i:65;a:3:{i:0;s:6:"0x2460";i:1;s:6:"0x24FF";i:2;s:22:"Enclosed Alphanumerics";}i:66;a:3:{i:0;s:6:"0x2500";i:1;s:6:"0x257F";i:2;s:11:"Box Drawing";}i:67;a:3:{i:0;s:6:"0x2580";i:1;s:6:"0x259F";i:2;s:14:"Block Elements";}i:68;a:3:{i:0;s:6:"0x25A0";i:1;s:6:"0x25FF";i:2;s:16:"Geometric Shapes";}i:69;a:3:{i:0;s:6:"0x2600";i:1;s:6:"0x26FF";i:2;s:21:"Miscellaneous Symbols";}i:70;a:3:{i:0;s:6:"0x2700";i:1;s:6:"0x27BF";i:2;s:8:"Dingbats";}i:71;a:3:{i:0;s:6:"0x27C0";i:1;s:6:"0x27EF";i:2;s:36:"Miscellaneous Mathematical Symbols-A";}i:72;a:3:{i:0;s:6:"0x27F0";i:1;s:6:"0x27FF";i:2;s:21:"Supplemental Arrows-A";}i:73;a:3:{i:0;s:6:"0x2800";i:1;s:6:"0x28FF";i:2;s:16:"Braille Patterns";}i:74;a:3:{i:0;s:6:"0x2900";i:1;s:6:"0x297F";i:2;s:21:"Supplemental Arrows-B";}i:75;a:3:{i:0;s:6:"0x2980";i:1;s:6:"0x29FF";i:2;s:36:"Miscellaneous Mathematical Symbols-B";}i:76;a:3:{i:0;s:6:"0x2A00";i:1;s:6:"0x2AFF";i:2;s:35:"Supplemental Mathematical Operators";}i:77;a:3:{i:0;s:6:"0x2B00";i:1;s:6:"0x2BFF";i:2;s:32:"Miscellaneous Symbols and Arrows";}i:78;a:3:{i:0;s:6:"0x2C00";i:1;s:6:"0x2C5F";i:2;s:10:"Glagolitic";}i:79;a:3:{i:0;s:6:"0x2C80";i:1;s:6:"0x2CFF";i:2;s:6:"Coptic";}i:80;a:3:{i:0;s:6:"0x2D00";i:1;s:6:"0x2D2F";i:2;s:19:"Georgian Supplement";}i:81;a:3:{i:0;s:6:"0x2D30";i:1;s:6:"0x2D7F";i:2;s:8:"Tifinagh";}i:82;a:3:{i:0;s:6:"0x2D80";i:1;s:6:"0x2DDF";i:2;s:17:"Ethiopic Extended";}i:83;a:3:{i:0;s:6:"0x2E00";i:1;s:6:"0x2E7F";i:2;s:24:"Supplemental Punctuation";}i:84;a:3:{i:0;s:6:"0x2E80";i:1;s:6:"0x2EFF";i:2;s:23:"CJK Radicals Supplement";}i:85;a:3:{i:0;s:6:"0x2F00";i:1;s:6:"0x2FDF";i:2;s:15:"Kangxi Radicals";}i:86;a:3:{i:0;s:6:"0x2FF0";i:1;s:6:"0x2FFF";i:2;s:34:"Ideographic Description Characters";}i:87;a:3:{i:0;s:6:"0x3000";i:1;s:6:"0x303F";i:2;s:27:"CJK Symbols and Punctuation";}i:88;a:3:{i:0;s:6:"0x3040";i:1;s:6:"0x309F";i:2;s:8:"Hiragana";}i:89;a:3:{i:0;s:6:"0x30A0";i:1;s:6:"0x30FF";i:2;s:8:"Katakana";}i:90;a:3:{i:0;s:6:"0x3100";i:1;s:6:"0x312F";i:2;s:8:"Bopomofo";}i:91;a:3:{i:0;s:6:"0x3130";i:1;s:6:"0x318F";i:2;s:25:"Hangul Compatibility Jamo";}i:92;a:3:{i:0;s:6:"0x3190";i:1;s:6:"0x319F";i:2;s:6:"Kanbun";}i:93;a:3:{i:0;s:6:"0x31A0";i:1;s:6:"0x31BF";i:2;s:17:"Bopomofo Extended";}i:94;a:3:{i:0;s:6:"0x31C0";i:1;s:6:"0x31EF";i:2;s:11:"CJK Strokes";}i:95;a:3:{i:0;s:6:"0x31F0";i:1;s:6:"0x31FF";i:2;s:28:"Katakana Phonetic Extensions";}i:96;a:3:{i:0;s:6:"0x3200";i:1;s:6:"0x32FF";i:2;s:31:"Enclosed CJK Letters and Months";}i:97;a:3:{i:0;s:6:"0x3300";i:1;s:6:"0x33FF";i:2;s:17:"CJK Compatibility";}i:98;a:3:{i:0;s:6:"0x3400";i:1;s:6:"0x4DBF";i:2;s:34:"CJK Unified Ideographs Extension A";}i:99;a:3:{i:0;s:6:"0x4DC0";i:1;s:6:"0x4DFF";i:2;s:23:"Yijing Hexagram Symbols";}i:100;a:3:{i:0;s:6:"0x4E00";i:1;s:6:"0x9FFF";i:2;s:22:"CJK Unified Ideographs";}i:101;a:3:{i:0;s:6:"0xA000";i:1;s:6:"0xA48F";i:2;s:12:"Yi Syllables";}i:102;a:3:{i:0;s:6:"0xA490";i:1;s:6:"0xA4CF";i:2;s:11:"Yi Radicals";}i:103;a:3:{i:0;s:6:"0xA700";i:1;s:6:"0xA71F";i:2;s:21:"Modifier Tone Letters";}i:104;a:3:{i:0;s:6:"0xA800";i:1;s:6:"0xA82F";i:2;s:12:"Syloti Nagri";}i:105;a:3:{i:0;s:6:"0xAC00";i:1;s:6:"0xD7AF";i:2;s:16:"Hangul Syllables";}i:106;a:3:{i:0;s:6:"0xD800";i:1;s:6:"0xDB7F";i:2;s:15:"High Surrogates";}i:107;a:3:{i:0;s:6:"0xDB80";i:1;s:6:"0xDBFF";i:2;s:27:"High Private Use Surrogates";}i:108;a:3:{i:0;s:6:"0xDC00";i:1;s:6:"0xDFFF";i:2;s:14:"Low Surrogates";}i:109;a:3:{i:0;s:6:"0xE000";i:1;s:6:"0xF8FF";i:2;s:16:"Private Use Area";}i:110;a:3:{i:0;s:6:"0xF900";i:1;s:6:"0xFAFF";i:2;s:28:"CJK Compatibility Ideographs";}i:111;a:3:{i:0;s:6:"0xFB00";i:1;s:6:"0xFB4F";i:2;s:29:"Alphabetic Presentation Forms";}i:112;a:3:{i:0;s:6:"0xFB50";i:1;s:6:"0xFDFF";i:2;s:27:"Arabic Presentation Forms-A";}i:113;a:3:{i:0;s:6:"0xFE00";i:1;s:6:"0xFE0F";i:2;s:19:"Variation Selectors";}i:114;a:3:{i:0;s:6:"0xFE10";i:1;s:6:"0xFE1F";i:2;s:14:"Vertical Forms";}i:115;a:3:{i:0;s:6:"0xFE20";i:1;s:6:"0xFE2F";i:2;s:20:"Combining Half Marks";}i:116;a:3:{i:0;s:6:"0xFE30";i:1;s:6:"0xFE4F";i:2;s:23:"CJK Compatibility Forms";}i:117;a:3:{i:0;s:6:"0xFE50";i:1;s:6:"0xFE6F";i:2;s:19:"Small Form Variants";}i:118;a:3:{i:0;s:6:"0xFE70";i:1;s:6:"0xFEFF";i:2;s:27:"Arabic Presentation Forms-B";}i:119;a:3:{i:0;s:6:"0xFF00";i:1;s:6:"0xFFEF";i:2;s:29:"Halfwidth and Fullwidth Forms";}i:120;a:3:{i:0;s:6:"0xFFF0";i:1;s:6:"0xFFFF";i:2;s:8:"Specials";}i:121;a:3:{i:0;s:7:"0x10000";i:1;s:7:"0x1007F";i:2;s:18:"Linear B Syllabary";}i:122;a:3:{i:0;s:7:"0x10080";i:1;s:7:"0x100FF";i:2;s:18:"Linear B Ideograms";}i:123;a:3:{i:0;s:7:"0x10100";i:1;s:7:"0x1013F";i:2;s:14:"Aegean Numbers";}i:124;a:3:{i:0;s:7:"0x10140";i:1;s:7:"0x1018F";i:2;s:21:"Ancient Greek Numbers";}i:125;a:3:{i:0;s:7:"0x10300";i:1;s:7:"0x1032F";i:2;s:10:"Old Italic";}i:126;a:3:{i:0;s:7:"0x10330";i:1;s:7:"0x1034F";i:2;s:6:"Gothic";}i:127;a:3:{i:0;s:7:"0x10380";i:1;s:7:"0x1039F";i:2;s:8:"Ugaritic";}i:128;a:3:{i:0;s:7:"0x103A0";i:1;s:7:"0x103DF";i:2;s:11:"Old Persian";}i:129;a:3:{i:0;s:7:"0x10400";i:1;s:7:"0x1044F";i:2;s:7:"Deseret";}i:130;a:3:{i:0;s:7:"0x10450";i:1;s:7:"0x1047F";i:2;s:7:"Shavian";}i:131;a:3:{i:0;s:7:"0x10480";i:1;s:7:"0x104AF";i:2;s:7:"Osmanya";}i:132;a:3:{i:0;s:7:"0x10800";i:1;s:7:"0x1083F";i:2;s:17:"Cypriot Syllabary";}i:133;a:3:{i:0;s:7:"0x10A00";i:1;s:7:"0x10A5F";i:2;s:10:"Kharoshthi";}i:134;a:3:{i:0;s:7:"0x1D000";i:1;s:7:"0x1D0FF";i:2;s:25:"Byzantine Musical Symbols";}i:135;a:3:{i:0;s:7:"0x1D100";i:1;s:7:"0x1D1FF";i:2;s:15:"Musical Symbols";}i:136;a:3:{i:0;s:7:"0x1D200";i:1;s:7:"0x1D24F";i:2;s:30:"Ancient Greek Musical Notation";}i:137;a:3:{i:0;s:7:"0x1D300";i:1;s:7:"0x1D35F";i:2;s:21:"Tai Xuan Jing Symbols";}i:138;a:3:{i:0;s:7:"0x1D400";i:1;s:7:"0x1D7FF";i:2;s:33:"Mathematical Alphanumeric Symbols";}i:139;a:3:{i:0;s:7:"0x20000";i:1;s:7:"0x2A6DF";i:2;s:34:"CJK Unified Ideographs Extension B";}i:140;a:3:{i:0;s:7:"0x2F800";i:1;s:7:"0x2FA1F";i:2;s:39:"CJK Compatibility Ideographs Supplement";}i:141;a:3:{i:0;s:7:"0xE0000";i:1;s:7:"0xE007F";i:2;s:4:"Tags";}i:142;a:3:{i:0;s:7:"0xE0100";i:1;s:7:"0xE01EF";i:2;s:30:"Variation Selectors Supplement";}i:143;a:3:{i:0;s:7:"0xF0000";i:1;s:7:"0xFFFFF";i:2;s:32:"Supplementary Private Use Area-A";}i:144;a:3:{i:0;s:8:"0x100000";i:1;s:8:"0x10FFFF";i:2;s:32:"Supplementary Private Use Area-B";}} --------------------------------------------------------------------------------