From 44558d23036e619f1dea147c781ac8d85285e8bf Mon Sep 17 00:00:00 2001 From: vitalif Date: Mon, 3 Aug 2009 12:42:04 +0000 Subject: [PATCH] initial FoF 0.5 --- LICENSE | 340 ++ add-single.php | 21 + add-tag.php | 32 + add.php | 103 + classes/fof-prefs.php | 109 + delete.php | 26 + favicon.php | 24 + fof-config-sample.php | 48 + fof-db.php | 790 +++ fof-main.php | 1152 ++++ fof-render.php | 201 + fof.css | 377 ++ fof.js | 908 +++ footer.php | 4 + header.php | 93 + image/feed-icon.png | Bin 0 -> 763 bytes image/grippy.png | Bin 0 -> 186 bytes image/star-off.gif | Bin 0 -> 585 bytes image/star-on.gif | Bin 0 -> 1008 bytes image/star-pending.gif | Bin 0 -> 261 bytes image/throbber.gif | Bin 0 -> 9198 bytes index.php | 20 + install.php | 363 ++ item.php | 24 + items.php | 136 + login.php | 73 + logout.php | 22 + opml.php | 48 + plugins/autotag.php | 24 + plugins/balancetags.php | 123 + plugins/delicious.php | 13 + plugins/delicious.png | Bin 0 -> 133 bytes plugins/enclosures.php | 29 + plugins/fixdivs.php | 11 + plugins/mediaplayer.swf | Bin 0 -> 32008 bytes plugins/mini_podcast.png | Bin 0 -> 1202 bytes plugins/place_audio.png | Bin 0 -> 851 bytes plugins/place_video.png | Bin 0 -> 36713 bytes plugins/plain.php | 15 + plugins/share-off.gif | Bin 0 -> 553 bytes plugins/share-on.gif | Bin 0 -> 4746 bytes plugins/sharing.php | 20 + plugins/wordpress.php | 21 + plugins/wordpress.png | Bin 0 -> 539 bytes prefs.php | 345 ++ prototype/prototype.js | 4184 ++++++++++++++ set-prefs.php | 26 + shared.php | 231 + sidebar.php | 309 ++ simplepie/simplepie.inc | 10781 ++++++++++++++++++++++++++++++++++++ simplepie/simplepie.patch | 15 + uninstall.php | 87 + update-quiet.php | 60 + update-single.php | 35 + update.php | 73 + view-action.php | 53 + 56 files changed, 21369 insertions(+) create mode 100644 LICENSE create mode 100644 add-single.php create mode 100644 add-tag.php create mode 100644 add.php create mode 100644 classes/fof-prefs.php create mode 100644 delete.php create mode 100644 favicon.php create mode 100644 fof-config-sample.php create mode 100644 fof-db.php create mode 100644 fof-main.php create mode 100644 fof-render.php create mode 100644 fof.css create mode 100644 fof.js create mode 100644 footer.php create mode 100644 header.php create mode 100644 image/feed-icon.png create mode 100644 image/grippy.png create mode 100644 image/star-off.gif create mode 100644 image/star-on.gif create mode 100644 image/star-pending.gif create mode 100644 image/throbber.gif create mode 100644 index.php create mode 100644 install.php create mode 100644 item.php create mode 100644 items.php create mode 100644 login.php create mode 100644 logout.php create mode 100644 opml.php create mode 100644 plugins/autotag.php create mode 100644 plugins/balancetags.php create mode 100644 plugins/delicious.php create mode 100644 plugins/delicious.png create mode 100644 plugins/enclosures.php create mode 100644 plugins/fixdivs.php create mode 100644 plugins/mediaplayer.swf create mode 100644 plugins/mini_podcast.png create mode 100644 plugins/place_audio.png create mode 100644 plugins/place_video.png create mode 100644 plugins/plain.php create mode 100644 plugins/share-off.gif create mode 100644 plugins/share-on.gif create mode 100644 plugins/sharing.php create mode 100644 plugins/wordpress.php create mode 100644 plugins/wordpress.png create mode 100644 prefs.php create mode 100644 prototype/prototype.js create mode 100644 set-prefs.php create mode 100644 shared.php create mode 100644 sidebar.php create mode 100644 simplepie/simplepie.inc create mode 100644 simplepie/simplepie.patch create mode 100644 uninstall.php create mode 100644 update-quiet.php create mode 100644 update-single.php create mode 100644 update.php create mode 100644 view-action.php diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/add-single.php b/add-single.php new file mode 100644 index 0000000..a842fef --- /dev/null +++ b/add-single.php @@ -0,0 +1,21 @@ + diff --git a/add-tag.php b/add-tag.php new file mode 100644 index 0000000..e310abd --- /dev/null +++ b/add-tag.php @@ -0,0 +1,32 @@ + diff --git a/add.php b/add.php new file mode 100644 index 0000000..dae45fc --- /dev/null +++ b/add.php @@ -0,0 +1,103 @@ +success) + { + echo "Cannot open $opml
"; + return false; + } + + $content = $sfile->body; + + $feeds = fof_opml_to_array($content); +} + +if($_FILES['opml_file']['tmp_name']) +{ + if(!$content_array = file($_FILES['opml_file']['tmp_name'])) + { + echo "Cannot open uploaded file
"; + } + else + { + $content = implode("", $content_array); + $feeds = fof_opml_to_array($content); + } +} + +$add_feed_url = "http"; +if($_SERVER["HTTPS"] == "on") +{ + $add_feed_url = "https"; +} +$add_feed_url .= "://" . $_SERVER["HTTP_HOST"] . $_SERVER["SCRIPT_NAME"]; +?> + +
If your browser is cool, you can register Feed on Feeds as a Feed Reader. If it is not cool, you can still use the FoF subscribe bookmarklet to subscribe to any page with a feed. Just add it as a bookmark and then click on it when you are at a page you'd like to subscribe to!
+ +
+ + + +
+
+ +
+ +When adding feeds, mark items as unread

+ +RSS or weblog URL:

+ +OPML URL: + +

+ + +OPML filename: + +
+ +\nwindow.onload = ajaxadd;\nfeedslist = ["); + +foreach($feeds as $feed) +{ + $feedjson[] = "{'url': '" . addslashes($feed) . "'}"; +} + +print(join($feedjson, ", ")); +print("];\n"); +} +print("
"); + +include("footer.php"); +?> diff --git a/classes/fof-prefs.php b/classes/fof-prefs.php new file mode 100644 index 0000000..83d76b3 --- /dev/null +++ b/classes/fof-prefs.php @@ -0,0 +1,109 @@ +user_id = $user_id; + + $result = fof_safe_query("select user_prefs from $FOF_USER_TABLE where user_id = %d", $user_id); + $row = mysql_fetch_array($result); + $prefs = unserialize($row['user_prefs']); + if(!is_array($prefs)) $prefs = array(); + $this->prefs = $prefs; + + if($user_id != 1) + { + $result = fof_safe_query("select user_prefs from $FOF_USER_TABLE where user_id = 1"); + $row = mysql_fetch_array($result); + $admin_prefs = unserialize($row['user_prefs']); + if(!is_array($admin_prefs)) $admin_prefs = array(); + $this->admin_prefs = $admin_prefs; + } + else + { + $this->admin_prefs = $prefs; + } + + $this->populate_defaults(); + + if($user_id == 1) + { + $this->prefs = array_merge($this->prefs, $this->admin_prefs); + } + } + + function &instance() + { + static $instance; + if(!isset($instance)) $instance = new FoF_Prefs(fof_current_user()); + + return $instance; + } + + function populate_defaults() + { + $defaults = array( + "favicons" => true, + "keyboard" => false, + "direction" => "desc", + "howmany" => 50, + "sharing" => "no", + "feed_order" => "feed_title", + "feed_direction" => "asc", + ); + + $admin_defaults = array( + "purge" => 30, + "autotimeout" => 30, + "manualtimeout" => 15, + "logging" => false, + ); + + $this->stuff_array($this->prefs, $defaults); + $this->stuff_array($this->admin_prefs, $admin_defaults); + } + + function stuff_array(&$array, $defaults) + { + foreach($defaults as $k => $v) + { + if(!isset($array[$k])) $array[$k] = $v; + } + } + + function get($k) + { + return $this->prefs[$k]; + } + + function set($k, $v) + { + $this->prefs[$k] = $v; + } + + function save() + { + fof_db_save_prefs($this->user_id, $this->prefs); + } +} + +?> diff --git a/delete.php b/delete.php new file mode 100644 index 0000000..d9e0bac --- /dev/null +++ b/delete.php @@ -0,0 +1,26 @@ + + +Deleted. + + diff --git a/favicon.php b/favicon.php new file mode 100644 index 0000000..b6f2f7e --- /dev/null +++ b/favicon.php @@ -0,0 +1,24 @@ + diff --git a/fof-config-sample.php b/fof-config-sample.php new file mode 100644 index 0000000..0a84f4b --- /dev/null +++ b/fof-config-sample.php @@ -0,0 +1,48 @@ + diff --git a/fof-db.php b/fof-db.php new file mode 100644 index 0000000..c3d2cbc --- /dev/null +++ b/fof-db.php @@ -0,0 +1,790 @@ +
Cannot connect to database. Please update configuration in fof-config.php. Mysql says: " . mysql_error() . ""); + mysql_select_db(FOF_DB_DBNAME, $fof_connection) or die("

Cannot select database. Please update configuration in fof-config.php. Mysql says: " . mysql_error() . ""); +} + +function fof_db_optimize() +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_TAG_TABLE, $FOF_USER_TABLE; + + fof_db_query("optimize table $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_TAG_TABLE, $FOF_USER_TABLE"); +} + +function fof_safe_query(/* $query, [$args...]*/) +{ + $args = func_get_args(); + $query = array_shift($args); + if(is_array($args[0])) $args = $args[0]; + $args = array_map('mysql_real_escape_string', $args); + $query = vsprintf($query, $args); + + return fof_db_query($query); +} + +function fof_db_query($sql, $live=0) +{ + global $fof_connection; + + list($usec, $sec) = explode(" ", microtime()); + $t1 = (float)$sec + (float)$usec; + + $result = mysql_query($sql, $fof_connection); + + if(is_resource($result)) $num = mysql_num_rows($result); + if($result) $affected = mysql_affected_rows(); + + list($usec, $sec) = explode(" ", microtime()); + $t2 = (float)$sec + (float)$usec; + $elapsed = $t2 - $t1; + $logmessage = sprintf("%.3f: [%s] (%d / %d)", $elapsed, $sql, $num, $affected); + fof_log($logmessage, "query"); + + if($live) + { + return $result; + } + else + { + if(mysql_errno()) + { + //echo "
";
+            //print_r(debug_backtrace());
+            //echo "
"; + die("Cannot query database. Have you run install.php to create or upgrade your installation? MySQL says: ". mysql_error() . ""); + } + return $result; + } +} + +function fof_db_get_row($result) +{ + return mysql_fetch_array($result); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Feed level stuff +//////////////////////////////////////////////////////////////////////////////// + +function fof_db_feed_mark_cached($feed_id) +{ + global $FOF_FEED_TABLE; + + $result = fof_safe_query("update $FOF_FEED_TABLE set feed_cache_date = %d where feed_id = %d", time(), $feed_id); +} + +function fof_db_feed_mark_attempted_cache($feed_id) +{ + global $FOF_FEED_TABLE; + + $result = fof_safe_query("update $FOF_FEED_TABLE set feed_cache_attempt_date = %d where feed_id = %d", time(), $feed_id); +} + +function fof_db_feed_update_metadata($feed_id, $url, $title, $link, $description, $image, $image_cache_date) +{ + global $FOF_FEED_TABLE; + + $sql = "update $FOF_FEED_TABLE set feed_url = '%s', feed_title = '%s', feed_link = '%s', feed_description = '%s'"; + $args = array($url, $title, $link, $description); + + if($image) + { + $sql .= ", feed_image = '%s' "; + $args[] = $image; + } + else + { + $sql .= ", feed_image = NULL "; + } + + $sql .= ", feed_image_cache_date = %d "; + $args[] = $image_cache_date; + + $sql .= "where feed_id = %d"; + $args[] = $feed_id; + + $result = fof_safe_query($sql, $args); +} + +function fof_db_get_latest_item_age($user_id) +{ + global $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TABLE; + + $result = fof_db_query("SELECT max( item_cached ) AS \"max_date\", $FOF_ITEM_TABLE.feed_id as \"id\" FROM $FOF_ITEM_TABLE GROUP BY $FOF_ITEM_TABLE.feed_id"); + return $result; +} + +function fof_db_get_subscriptions($user_id) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + return(fof_safe_query("select * from $FOF_FEED_TABLE, $FOF_SUBSCRIPTION_TABLE where $FOF_SUBSCRIPTION_TABLE.user_id = %d and $FOF_FEED_TABLE.feed_id = $FOF_SUBSCRIPTION_TABLE.feed_id order by feed_title", $user_id)); +} + +function fof_db_get_feeds() +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + return(fof_db_query("select * from $FOF_FEED_TABLE order by feed_title")); +} + +function fof_db_get_item_count($user_id) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + return(fof_safe_query("select count(*) as count, $FOF_ITEM_TABLE.feed_id as id from $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE where $FOF_SUBSCRIPTION_TABLE.user_id = %d and $FOF_ITEM_TABLE.feed_id = $FOF_SUBSCRIPTION_TABLE.feed_id group by id", $user_id)); +} + +function fof_db_get_unread_item_count($user_id) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + return(fof_safe_query("select count(*) as count, $FOF_ITEM_TABLE.feed_id as id from $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE, $FOF_FEED_TABLE where $FOF_ITEM_TABLE.item_id = $FOF_ITEM_TAG_TABLE.item_id and $FOF_SUBSCRIPTION_TABLE.user_id = $user_id and $FOF_ITEM_TAG_TABLE.tag_id = 1 and $FOF_ITEM_TAG_TABLE.user_id = %d and $FOF_FEED_TABLE.feed_id = $FOF_SUBSCRIPTION_TABLE.feed_id and $FOF_ITEM_TABLE.feed_id = $FOF_FEED_TABLE.feed_id group by id", $user_id)); +} + +function fof_db_get_starred_item_count($user_id) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + return(fof_safe_query("select count(*) as count, $FOF_ITEM_TABLE.feed_id as id from $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE, $FOF_FEED_TABLE where $FOF_ITEM_TABLE.item_id = $FOF_ITEM_TAG_TABLE.item_id and $FOF_SUBSCRIPTION_TABLE.user_id = $user_id and $FOF_ITEM_TAG_TABLE.tag_id = 2 and $FOF_ITEM_TAG_TABLE.user_id = %d and $FOF_FEED_TABLE.feed_id = $FOF_SUBSCRIPTION_TABLE.feed_id and $FOF_ITEM_TABLE.feed_id = $FOF_FEED_TABLE.feed_id group by id", $user_id)); +} + +function fof_db_get_subscribed_users($feed_id) +{ + global $FOF_SUBSCRIPTION_TABLE; + + return(fof_safe_query("select user_id from $FOF_SUBSCRIPTION_TABLE where $FOF_SUBSCRIPTION_TABLE.feed_id = %d", $feed_id)); +} + +function fof_db_is_subscribed($user_id, $feed_url) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + $result = fof_safe_query("select $FOF_SUBSCRIPTION_TABLE.feed_id from $FOF_FEED_TABLE, $FOF_SUBSCRIPTION_TABLE where feed_url='%s' and $FOF_SUBSCRIPTION_TABLE.feed_id = $FOF_FEED_TABLE.feed_id and $FOF_SUBSCRIPTION_TABLE.user_id = %d", $feed_url, $user_id); + + if(mysql_num_rows($result) == 0) + { + return false; + } + + return true; +} + +function fof_db_get_feed_by_url($feed_url) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + $result = fof_safe_query("select * from $FOF_FEED_TABLE where feed_url='%s'", $feed_url); + + if(mysql_num_rows($result) == 0) + { + return NULL; + } + + $row = mysql_fetch_array($result); + + return $row; +} + +function fof_db_get_feed_by_id($feed_id) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + $result = fof_safe_query("select * from $FOF_FEED_TABLE where feed_id=%d", $feed_id); + + $row = mysql_fetch_array($result); + + return $row; +} + +function fof_db_add_feed($url, $title, $link, $description) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $fof_connection; + + fof_safe_query("insert into $FOF_FEED_TABLE (feed_url,feed_title,feed_link,feed_description) values ('%s', '%s', '%s', '%s')", $url, $title, $link, $description); + + return(mysql_insert_id($fof_connection)); +} + +function fof_db_add_subscription($user_id, $feed_id) +{ + global $FOF_SUBSCRIPTION_TABLE; + + fof_safe_query("insert into $FOF_SUBSCRIPTION_TABLE (feed_id, user_id) values (%d, %d)", $feed_id, $user_id); +} + +function fof_db_delete_subscription($user_id, $feed_id) +{ + global $FOF_SUBSCRIPTION_TABLE, $FOF_ITEM_TAG_TABLE; + + $result = fof_db_get_items($user_id, $feed_id, $what="all", NULL, NULL); + + foreach($result as $r) + { + $items[] = $r['item_id']; + } + + $itemclause = join(", ", $items); + + fof_safe_query("delete from $FOF_SUBSCRIPTION_TABLE where feed_id = %d and user_id = %d", $feed_id, $user_id); + + fof_safe_query("delete from $FOF_ITEM_TAG_TABLE where user_id = %d and item_id in ($itemclause)", $user_id); +} + +function fof_db_delete_feed($feed_id) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE; + + fof_safe_query("delete from $FOF_FEED_TABLE where feed_id = %d", $feed_id); + fof_safe_query("delete from $FOF_ITEM_TABLE where feed_id = %d", $feed_id); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Item level stuff +//////////////////////////////////////////////////////////////////////////////// + +function fof_db_find_item($feed_id, $item_guid) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $fof_connection; + + $result = fof_safe_query("select item_id from $FOF_ITEM_TABLE where feed_id=%d and item_guid='%s'", $feed_id, $item_guid); + $row = mysql_fetch_array($result); + + if(mysql_num_rows($result) == 0) + { + return NULL; + } + else + { + return($row['item_id']); + } +} + +function fof_db_add_item($feed_id, $guid, $link, $title, $content, $cached, $published, $updated) +{ + global $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_SUBSCRIPTION_TABLE, $fof_connection; + + fof_safe_query("insert into $FOF_ITEM_TABLE (feed_id, item_link, item_guid, item_title, item_content, item_cached, item_published, item_updated) values (%d, '%s', '%s' ,'%s', '%s', %d, %d, %d)", + $feed_id, $link, $guid, $title, $content, $cached, $published, $updated); + + return(mysql_insert_id($fof_connection)); +} + +function fof_db_get_items($user_id=1, $feed=NULL, $what="unread", $when=NULL, $start=NULL, $limit=NULL, $order="desc", $search=NULL) +{ + global $FOF_SUBSCRIPTION_TABLE, $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $FOF_TAG_TABLE; + + $prefs = fof_prefs(); + $offset = $prefs['tzoffset']; + + if(!is_null($when) && $when != "") + { + if($when == "today") + { + $whendate = fof_todays_date(); + } + else + { + $whendate = $when; + } + + $whendate = explode("/", $whendate); + $begin = gmmktime(0, 0, 0, $whendate[1], $whendate[2], $whendate[0]) - ($offset * 60 * 60); + $end = $begin + (24 * 60 * 60); + } + + if(is_numeric($start)) + { + if(!is_numeric($limit)) + { + $limit = $prefs["howmany"]; + } + + $limit_clause = " limit $start, $limit "; + } + + $args = array(); + $select = "SELECT i.* , f.* "; + $from = "FROM $FOF_FEED_TABLE f, $FOF_ITEM_TABLE i, $FOF_SUBSCRIPTION_TABLE s "; + $where = sprintf("WHERE s.user_id = %d AND s.feed_id = f.feed_id AND f.feed_id = i.feed_id ", $user_id); + + if(!is_null($feed) && $feed != "") + { + $where .= sprintf("AND f.feed_id = %d ", $feed); + } + + if(!is_null($when) && $when != "") + { + $where .= sprintf("AND i.item_published > %d and i.item_published < %d ", $begin, $end); + } + + if($what != "all") + { + $tags = split(" ", $what); + $in = implode(", ", array_fill(0, count($tags), "'%s'")); + $from .= ", $FOF_TAG_TABLE t, $FOF_ITEM_TAG_TABLE it "; + $where .= sprintf("AND it.user_id = %d ", $user_id); + $where .= "AND it.tag_id = t.tag_id AND ( t.tag_name IN ( $in ) ) AND i.item_id = it.item_id "; + $group = sprintf("GROUP BY i.item_id HAVING COUNT( i.item_id ) = %d ", count($tags)); + $args = array_merge($args, $tags); + } + + if(!is_null($search) && $search != "") + { + $where .= "AND (i.item_title like '%%%s%%' or i.item_content like '%%%s%%' )"; + $args[] = $search; + $args[] = $search; + } + + $order_by = "order by i.item_published desc $limit_clause "; + + $query = $select . $from . $where . $group . $order_by; + + $result = fof_safe_query($query, $args); + + if(mysql_num_rows($result) == 0) + { + return array(); + } + + while($row = mysql_fetch_assoc($result)) + { + $array[] = $row; + } + + $array = fof_multi_sort($array, 'item_published', $order != "asc"); + + $i = 0; + foreach($array as $item) + { + $ids[] = $item['item_id']; + $lookup[$item['item_id']] = $i; + $array[$i]['tags'] = array(); + + $i++; + } + + $items = join($ids, ", "); + + $result = fof_safe_query("select $FOF_TAG_TABLE.tag_name, $FOF_ITEM_TAG_TABLE.item_id from $FOF_TAG_TABLE, $FOF_ITEM_TAG_TABLE where $FOF_TAG_TABLE.tag_id = $FOF_ITEM_TAG_TABLE.tag_id and $FOF_ITEM_TAG_TABLE.item_id in (%s) and $FOF_ITEM_TAG_TABLE.user_id = %d", $items, $user_id); + + while($row = fof_db_get_row($result)) + { + $item_id = $row['item_id']; + $tag = $row['tag_name']; + + $array[$lookup[$item_id]]['tags'][] = $tag; + } + + return $array; +} + +function fof_db_get_item($user_id, $item_id) +{ + global $FOF_SUBSCRIPTION_TABLE, $FOF_FEED_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $FOF_TAG_TABLE; + + $query = "select $FOF_FEED_TABLE.feed_image as feed_image, $FOF_FEED_TABLE.feed_title as feed_title, $FOF_FEED_TABLE.feed_link as feed_link, $FOF_FEED_TABLE.feed_description as feed_description, $FOF_ITEM_TABLE.item_id as item_id, $FOF_ITEM_TABLE.item_link as item_link, $FOF_ITEM_TABLE.item_title as item_title, $FOF_ITEM_TABLE.item_cached, $FOF_ITEM_TABLE.item_published, $FOF_ITEM_TABLE.item_updated, $FOF_ITEM_TABLE.item_content as item_content from $FOF_FEED_TABLE, $FOF_ITEM_TABLE where $FOF_ITEM_TABLE.feed_id=$FOF_FEED_TABLE.feed_id and $FOF_ITEM_TABLE.item_id = %d"; + + $result = fof_safe_query($query, $item_id); + + $item = mysql_fetch_assoc($result); + + $item['tags'] = array(); + + if($user_id) + { + $result = fof_safe_query("select $FOF_TAG_TABLE.tag_name from $FOF_TAG_TABLE, $FOF_ITEM_TAG_TABLE where $FOF_TAG_TABLE.tag_id = $FOF_ITEM_TAG_TABLE.tag_id and $FOF_ITEM_TAG_TABLE.item_id = %d and $FOF_ITEM_TAG_TABLE.user_id = %d", $item_id, $user_id); + + while($row = fof_db_get_row($result)) + { + $item['tags'][] = $row['tag_name']; + } + } + + return $item; +} + +//////////////////////////////////////////////////////////////////////////////// +// Tag stuff +//////////////////////////////////////////////////////////////////////////////// + +function fof_db_get_subscription_to_tags() +{ + $r = array(); + global $FOF_SUBSCRIPTION_TABLE; + $result = fof_safe_query("select * from $FOF_SUBSCRIPTION_TABLE"); + while($row = fof_db_get_row($result)) + { + $prefs = unserialize($row['subscription_prefs']); + $tags = $prefs['tags']; + if(!is_array($r[$row['feed_id']])) $r[$row['feed_id']] = array(); + $r[$row['feed_id']][$row['user_id']] = $tags; + } + + return $r; +} + +function fof_db_tag_feed($user_id, $feed_id, $tag_id) +{ + global $FOF_SUBSCRIPTION_TABLE; + + $result = fof_safe_query("select subscription_prefs from $FOF_SUBSCRIPTION_TABLE where feed_id = %d and user_id = %d", $feed_id, $user_id); + $row = fof_db_get_row($result); + $prefs = unserialize($row['subscription_prefs']); + + if(!is_array($prefs['tags']) || !in_array($tag_id, $prefs['tags'])) $prefs['tags'][] = $tag_id; + + fof_safe_query("update $FOF_SUBSCRIPTION_TABLE set subscription_prefs = '%s' where feed_id = %d and user_id = %d", serialize($prefs), $feed_id, $user_id); +} + +function fof_db_untag_feed($user_id, $feed_id, $tag_id) +{ + global $FOF_SUBSCRIPTION_TABLE; + + $result = fof_safe_query("select subscription_prefs from $FOF_SUBSCRIPTION_TABLE where feed_id = %d and user_id = %d", $feed_id, $user_id); + $row = fof_db_get_row($result); + $prefs = unserialize($row['subscription_prefs']); + + if(is_array($prefs['tags'])) + { + $prefs['tags'] = array_diff($prefs['tags'], array($tag_id)); + } + + fof_safe_query("update $FOF_SUBSCRIPTION_TABLE set subscription_prefs = '%s' where feed_id = %d and user_id = %d", serialize($prefs), $feed_id, $user_id); +} + +function fof_db_get_item_tags($user_id, $item_id) +{ + global $FOF_TAG_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $fof_connection; + + $result = fof_safe_query("select $FOF_TAG_TABLE.tag_name from $FOF_TAG_TABLE, $FOF_ITEM_TAG_TABLE where $FOF_TAG_TABLE.tag_id = $FOF_ITEM_TAG_TABLE.tag_id and $FOF_ITEM_TAG_TABLE.item_id = %d and $FOF_ITEM_TAG_TABLE.user_id = %d", $item_id, $user_id); + + return $result; +} + +function fof_db_item_has_tags($item_id) +{ + global $FOF_TAG_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $fof_connection; + + $result = fof_safe_query("select count(*) as \"count\" from $FOF_ITEM_TAG_TABLE where item_id=%d and tag_id <= 2", $item_id); + $row = mysql_fetch_array($result); + + return $row["count"]; +} + +function fof_db_get_unread_count($user_id) +{ + global $FOF_ITEM_TAG_TABLE; + + $result = fof_safe_query("select count(*) as \"count\" from $FOF_ITEM_TAG_TABLE where tag_id = 1 and user_id = %d", $user_id); + $row = mysql_fetch_array($result); + + return $row["count"]; +} + +function fof_db_get_tag_unread($user_id) +{ + global $FOF_TAG_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE; + + $result = fof_safe_query("SELECT count(*) as count, it2.tag_id FROM $FOF_ITEM_TABLE i, $FOF_ITEM_TAG_TABLE it , $FOF_ITEM_TAG_TABLE it2 where it.item_id = it2.item_id and it.tag_id = 1 and i.item_id = it.item_id and i.item_id = it2.item_id and it.user_id = %d and it2.user_id = %d group by it2.tag_id", $user_id, $user_id); + + $counts = array(); + while($row = fof_db_get_row($result)) + { + $counts[$row['tag_id']] = $row['count']; + } + + return $counts; +} + +function fof_db_get_tags($user_id) +{ + global $FOF_TAG_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $fof_connection; + + $sql = "SELECT $FOF_TAG_TABLE.tag_id, $FOF_TAG_TABLE.tag_name, count( $FOF_ITEM_TAG_TABLE.item_id ) as count + FROM $FOF_TAG_TABLE + LEFT JOIN $FOF_ITEM_TAG_TABLE ON $FOF_TAG_TABLE.tag_id = $FOF_ITEM_TAG_TABLE.tag_id + WHERE $FOF_ITEM_TAG_TABLE.user_id = %d + GROUP BY $FOF_TAG_TABLE.tag_id order by $FOF_TAG_TABLE.tag_name"; + + $result = fof_safe_query($sql, $user_id); + + return $result; +} + +function fof_db_get_tag_id_map() +{ + global $FOF_TAG_TABLE; + + $sql = "select * from $FOF_TAG_TABLE"; + + $result = fof_safe_query($sql); + + $tags = array(); + + while($row = fof_db_get_row($result)) + { + $tags[$row['tag_id']] = $row['tag_name']; + } + + return $tags; +} + +function fof_db_create_tag($user_id, $tag) +{ + global $FOF_TAG_TABLE, $fof_connection; + + fof_safe_query("insert into $FOF_TAG_TABLE (tag_name) values ('%s')", $tag); + + return(mysql_insert_id($fof_connection)); +} + +function fof_db_get_tag_by_name($user_id, $tag) +{ + global $FOF_TAG_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $fof_connection; + + $result = fof_safe_query("select $FOF_TAG_TABLE.tag_id from $FOF_TAG_TABLE where $FOF_TAG_TABLE.tag_name = '%s'", $tag); + + if(mysql_num_rows($result) == 0) + { + return NULL; + } + + $row = mysql_fetch_array($result); + + return $row['tag_id']; +} + +function fof_db_mark_unread($user_id, $items) +{ + fof_db_tag_items($user_id, 1, $items); +} + +function fof_db_mark_read($user_id, $items) +{ + fof_db_untag_items($user_id, 1, $items); +} + +function fof_db_mark_feed_read($user_id, $feed_id) +{ + global $FOF_ITEM_TAG_TABLE; + + $result = fof_db_get_items($user_id, $feed_id, $what="all"); + + foreach($result as $r) + { + $items[] = $r['item_id']; + } + + fof_db_untag_items($user_id, 1, $items); +} + +function fof_db_mark_feed_unread($user_id, $feed, $what) +{ + global $FOF_ITEM_TAG_TABLE; + + fof_log("fof_db_mark_feed_unread($user_id, $feed, $what)"); + + if($what == "all") + { + $result = fof_db_get_items($user_id, $feed, "all"); + } + if($what == "today") + { + $result = fof_db_get_items($user_id, $feed, "all", "today"); + } + + foreach((array)$result as $r) + { + $items[] = $r['item_id']; + } + + fof_db_tag_items($user_id, 1, $items); +} + +function fof_db_mark_item_unread($users, $id) +{ + global $FOF_ITEM_TAG_TABLE; + + if(count($users) == 0) return; + + foreach($users as $user) + { + $sql[] = sprintf("(%d, 1, %d)", $user, $id); + } + + $values = implode ( ",", $sql ); + + $sql = "insert into $FOF_ITEM_TAG_TABLE (user_id, tag_id, item_id) values " . $values; + + $result = fof_db_query($sql, 1); + + if(!$result && (mysql_errno() != 1062)) + { + die("Cannot query database. Have you run install.php to create or upgrade your installation? MySQL says: ". mysql_error() . ""); + } +} + +function fof_db_tag_items($user_id, $tag_id, $items) +{ + global $FOF_ITEM_TAG_TABLE; + + if(!$items) return; + + if(!is_array($items)) $items = array($items); + + foreach($items as $item) + { + $sql[] = sprintf("(%d, %d, %d)", $user_id, $tag_id, $item); + } + + $values = implode ( ",", $sql ); + + $sql = "insert into $FOF_ITEM_TAG_TABLE (user_id, tag_id, item_id) values " . $values; + + $result = fof_db_query($sql, 1); + + if(!$result && (mysql_errno() != 1062)) + { + die("Cannot query database. Have you run install.php to create or upgrade your installation? MySQL says: ". mysql_error() . ""); + } +} + +function fof_db_untag_items($user_id, $tag_id, $items) +{ + global $FOF_ITEM_TAG_TABLE; + + if(!$items) return; + + if(!is_array($items)) $items = array($items); + + foreach($items as $item) + { + $sql[] = " item_id = %d "; + $args[] = $item; + } + + $values = implode ( " or ", $sql ); + + $sql = "delete from $FOF_ITEM_TAG_TABLE where user_id = %d and tag_id = %d and ( $values )"; + + array_unshift($args, $tag_id); + array_unshift($args, $user_id); + + fof_safe_query($sql, $args); +} + + +//////////////////////////////////////////////////////////////////////////////// +// User stuff +//////////////////////////////////////////////////////////////////////////////// + +function fof_db_get_users() +{ + global $FOF_USER_TABLE; + + $result = fof_safe_query("select user_name, user_id, user_prefs from $FOF_USER_TABLE"); + + while($row = fof_db_get_row($result)) + { + $users[$row['user_id']['user_name']] = $row['user_name']; + $users[$row['user_id']['user_prefs']] = unserialize($row['user_prefs']); + } +} + +function fof_db_add_user($username, $password) +{ + global $FOF_USER_TABLE; + + $password_hash = md5($password . $username); + + fof_safe_query("insert into $FOF_USER_TABLE (user_name, user_password_hash) values ('%s', '%s')", $username, $password_hash); +} + +function fof_db_change_password($username, $password) +{ + global $FOF_USER_TABLE; + + $password_hash = md5($password . $username); + + fof_safe_query("update $FOF_USER_TABLE set user_password_hash = '%s' where user_name = '%s'", $password_hash, $username); +} + +function fof_db_get_user_id($username) +{ + global $FOF_USER_TABLE; + $result = fof_safe_query("select user_id from $FOF_USER_TABLE where user_name = '%s'", $username); + $row = mysql_fetch_array($result); + + return $row['user_id']; +} + +function fof_db_delete_user($username) +{ + global $FOF_USER_TABLE, $FOF_ITEM_TAG_TABLE, $FOF_SUBSCRIPTION_TABLE; + $user_id = fof_db_get_user_id($username); + + fof_safe_query("delete from $FOF_SUBSCRIPTION_TABLE where user_id = %d", $user_id); + fof_safe_query("delete from $FOF_ITEM_TAG_TABLE where user_id = %d", $user_id); + fof_safe_query("delete from $FOF_USER_TABLE where user_id = %d", $user_id); +} + +function fof_db_save_prefs($user_id, $prefs) +{ + global $FOF_USER_TABLE; + + $prefs = serialize($prefs); + + fof_safe_query("update $FOF_USER_TABLE set user_prefs = '%s' where user_id = %d", $prefs, $user_id); +} + +function fof_db_authenticate($user_name, $user_password_hash) +{ + global $FOF_USER_TABLE, $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE, $fof_connection, $fof_user_id, $fof_user_name, $fof_user_level; + + $result = fof_safe_query("select * from $FOF_USER_TABLE where user_name = '%s' and user_password_hash = '%s'", $user_name, $user_password_hash); + + if(mysql_num_rows($result) == 0) + { + return false; + } + + $row = mysql_fetch_array($result); + + $fof_user_name = $row['user_name']; + $fof_user_id = $row['user_id']; + $fof_user_level = $row['user_level']; + + return true; +} + +?> diff --git a/fof-main.php b/fof-main.php new file mode 100644 index 0000000..abf5b2c --- /dev/null +++ b/fof-main.php @@ -0,0 +1,1152 @@ +admin_prefs; + if(!$p['logging']) return; + + static $log; + if(!isset($log)) $log = @fopen("fof.log", 'a'); + + if(!$log) return; + + $message = str_replace ("\n", "\\n", $message); + $message = str_replace ("\r", "\\r", $message); + + fwrite($log, date('r') . " [$topic] $message\n"); +} + +function require_user() +{ + if(!isset($_COOKIE["user_name"]) || !isset($_COOKIE["user_password_hash"])) + { + Header("Location: login.php"); + exit(); + } + + $user_name = $_COOKIE["user_name"]; + $user_password_hash = $_COOKIE["user_password_hash"]; + + if(!fof_authenticate($user_name, $user_password_hash)) + { + Header("Location: login.php"); + exit(); + } +} + +function fof_authenticate($user_name, $user_password_hash) +{ + global $fof_user_name; + + if(fof_db_authenticate($user_name, $user_password_hash)) + { + setcookie ( "user_name", $fof_user_name, time()+60*60*24*365*10 ); + setcookie ( "user_password_hash", $user_password_hash, time()+60*60*24*365*10 ); + return true; + } +} + +function fof_logout() +{ + setcookie ( "user_name", "", time() ); + setcookie ( "user_password_hash", "", time() ); +} + +function fof_current_user() +{ + global $fof_user_id; + + return $fof_user_id; +} + +function fof_username() +{ + global $fof_user_name; + + return $fof_user_name; +} + +function fof_get_users() +{ + return fof_db_get_users(); +} + +function fof_prefs() +{ + $p =& FoF_Prefs::instance(); + return $p->prefs; +} + +function fof_is_admin() +{ + global $fof_user_level; + + return $fof_user_level == "admin"; +} + +function fof_get_unread_count($user_id) +{ + return fof_db_get_unread_count($user_id); +} + +function fof_get_tags($user_id) +{ + $tags = array(); + + $result = fof_db_get_tags($user_id); + + $counts = fof_db_get_tag_unread($user_id); + + while($row = fof_db_get_row($result)) + { + if(isset($counts[$row['tag_id']])) + $row['unread'] = $counts[$row['tag_id']]; + else + $row['unread'] = 0; + + $tags[] = $row; + } + + return $tags; +} + +function fof_get_item_tags($user_id, $item_id) +{ + $result = fof_db_get_item_tags($user_id, $item_id); + + $tags = array(); + + while($row = fof_db_get_row($result)) + { + $tags[] = $row['tag_name']; + } + + return $tags; +} + +function fof_tag_feed($user_id, $feed_id, $tag) +{ + $tag_id = fof_db_get_tag_by_name($user_id, $tag); + if($tag_id == NULL) + { + $tag_id = fof_db_create_tag($user_id, $tag); + } + + $result = fof_db_get_items($user_id, $feed_id, $what="all", NULL, NULL); + + foreach($result as $r) + { + $items[] = $r['item_id']; + } + + fof_db_tag_items($user_id, $tag_id, $items); + + fof_db_tag_feed($user_id, $feed_id, $tag_id); +} + +function fof_untag_feed($user_id, $feed_id, $tag) +{ + $tag_id = fof_db_get_tag_by_name($user_id, $tag); + if($tag_id == NULL) + { + $tag_id = fof_db_create_tag($user_id, $tag); + } + + $result = fof_db_get_items($user_id, $feed_id, $what="all", NULL, NULL); + + foreach($result as $r) + { + $items[] = $r['item_id']; + } + + fof_db_untag_items($user_id, $tag_id, $items); + + fof_db_untag_feed($user_id, $feed_id, $tag_id); +} + +function fof_tag_item($user_id, $item_id, $tag) +{ + if(is_array($tag)) $tags = $tag; else $tags[] = $tag; + + foreach($tags as $tag) + { + $tag_id = fof_db_get_tag_by_name($user_id, $tag); + if($tag_id == NULL) + { + $tag_id = fof_db_create_tag($user_id, $tag); + } + + fof_db_tag_items($user_id, $tag_id, $item_id); + } +} + +function fof_untag_item($user_id, $item_id, $tag) +{ + $tag_id = fof_db_get_tag_by_name($user_id, $tag); + fof_db_untag_items($user_id, $tag_id, $item_id); +} + +function fof_untag($user_id, $tag) +{ + $tag_id = fof_db_get_tag_by_name($user_id, $tag); + + $result = fof_db_get_items($user_id, $feed_id, $tag, NULL, NULL); + + foreach($result as $r) + { + $items[] = $r['item_id']; + } + + fof_db_untag_items($user_id, $tag_id, $items); +} + +function fof_nice_time_stamp($age) +{ + $age = time() - $age; + + if($age == 0) + { + $agestr = "never"; + $agestrabbr = "∞"; + } + else + { + $seconds = $age % 60; + $minutes = $age / 60 % 60; + $hours = $age / 60 / 60 % 24; + $days = floor($age / 60 / 60 / 24); + + if($seconds) + { + $agestr = "$seconds second"; + if($seconds != 1) $agestr .= "s"; + $agestr .= " ago"; + + $agestrabbr = $seconds . "s"; + } + + if($minutes) + { + $agestr = "$minutes minute"; + if($minutes != 1) $agestr .= "s"; + $agestr .= " ago"; + + $agestrabbr = $minutes . "m"; + } + + if($hours) + { + $agestr = "$hours hour"; + if($hours != 1) $agestr .= "s"; + $agestr .= " ago"; + + $agestrabbr = $hours . "h"; + } + + if($days) + { + $agestr = "$days day"; + if($days != 1) $agestr .= "s"; + $agestr .= " ago"; + + $agestrabbr = $days . "d"; + } + } + + return array($agestr, $agestrabbr); +} + +function fof_get_feeds($user_id, $order = 'feed_title', $direction = 'asc') +{ + $feeds = array(); + + $result = fof_db_get_subscriptions($user_id); + + $i = 0; + + while($row = fof_db_get_row($result)) + { + $id = $row['feed_id']; + $age = $row['feed_cache_date']; + + $feeds[$i]['feed_id'] = $id; + $feeds[$i]['feed_url'] = $row['feed_url']; + $feeds[$i]['feed_title'] = $row['feed_title']; + $feeds[$i]['feed_link'] = $row['feed_link']; + $feeds[$i]['feed_description'] = $row['feed_description']; + $feeds[$i]['feed_image'] = $row['feed_image']; + $feeds[$i]['prefs'] = unserialize($row['subscription_prefs']); + $feeds[$i]['feed_age'] = $age; + + list($agestr, $agestrabbr) = fof_nice_time_stamp($age); + + $feeds[$i]['agestr'] = $agestr; + $feeds[$i]['agestrabbr'] = $agestrabbr; + + $i++; + } + + $tags = fof_db_get_tag_id_map(); + + for($i=0; $i[« $yesterday] "; + if($when != "today") $string .= "[today] "; + if($when != "today") $string .= "[$tomorrow »] "; + } + + if(is_numeric($start)) + { + if(!is_numeric($limit)) $limit = $prefs["howmany"]; + + $earlier = $start + $limit; + $later = $start - $limit; + + $string .= "[« previous $limit] "; + if($later >= 0) $string .= "[current items] "; + if($later >= 0) $string .= "[next $limit »] "; + } + + return $string; +} + +function fof_render_feed_link($row) +{ + $link = $row['feed_link']; + $description = $row['feed_description']; + $title = $row['feed_title']; + $url = $row['feed_url']; + + $s = "$title "; + $s .= "(rss)"; + + return $s; +} + +function fof_opml_to_array($opml) +{ + $rx = "/xmlurl=\"(.*?)\"/mi"; + + if (preg_match_all($rx, $opml, $m)) + { + for($i = 0; $i < count($m[0]) ; $i++) + { + $r[] = $m[1][$i]; + } + } + + return $r; +} + +function fof_prepare_url($url) +{ + $url = trim($url); + + if(substr($url, 0, 7) == "feed://") $url = substr($url, 7); + + if(substr($url, 0, 7) != 'http://' && substr($url, 0, 8) != 'https://') + { + $url = 'http://' . $url; + } + + return $url; +} + +function fof_subscribe($user_id, $url, $unread="today") +{ + if(!$url) return false; + + $url = fof_prepare_url($url); + $feed = fof_db_get_feed_by_url($url); + + if(fof_is_subscribed($user_id, $url)) + { + return "You are already subscribed to " . fof_render_feed_link($feed) . "
"; + } + + if(fof_feed_exists($url)) + { + fof_db_add_subscription($user_id, $feed['feed_id']); + fof_apply_plugin_tags($id, NULL, $user_id); + fof_update_feed($feed['feed_id']); + + if($unread != "no") fof_db_mark_feed_unread($user_id, $feed['feed_id'], $unread); + return 'Subscribed.
'; + } + + $rss = fof_parse($url); + + if (isset($rss->error)) + { + return "Error: " . $rss->error . " try to validate it?
"; + } + else + { + $url = html_entity_decode($rss->subscribe_url(), ENT_QUOTES); + $self = $rss->get_link(0, 'self'); + if($self) $url = html_entity_decode($self, ENT_QUOTES); + + if(fof_feed_exists($url)) + { + $feed = fof_db_get_feed_by_url($url); + + if(fof_is_subscribed($user_id, $url)) + { + return "You are already subscribed to " . fof_render_feed_link($feed) . "
"; + } + + fof_db_add_subscription($user_id, $feed['feed_id']); + if($unread != "no") fof_db_mark_feed_unread($user_id, $feed['feed_id'], $unread); + + return 'Subscribed.
'; + } + + $id = fof_add_feed($url, $rss->get_title(), $rss->get_link(), $rss->get_description() ); + + fof_update_feed($id); + fof_db_add_subscription($user_id, $id); + if($unread != "no") fof_db_mark_feed_unread($user_id, $id, $unread); + + fof_apply_plugin_tags($id, NULL, $user_id); + + return 'Subscribed.
'; + } +} + +function fof_add_feed($url, $title, $link, $description) +{ + if($title == "") $title = "[no title]"; + + $id = fof_db_add_feed($url, $title, $link, $description); + + return $id; +} + +function fof_is_subscribed($user_id, $url) +{ + return(fof_db_is_subscribed($user_id, $url)); +} + +function fof_feed_exists($url) +{ + $feed = fof_db_get_feed_by_url($url); + + return $feed; +} + +function fof_get_subscribed_users($feed_id) +{ + return(fof_db_get_subscribed_users($feed_id)); +} + +function fof_mark_item_unread($feed_id, $id) +{ + $result = fof_get_subscribed_users($feed_id); + + while($row = fof_db_get_row($result)) + { + $users[] = $row['user_id']; + } + + fof_db_mark_item_unread($users, $id); +} + +function fof_parse($url) +{ + $p =& FoF_Prefs::instance(); + $admin_prefs = $p->admin_prefs; + + $pie = new SimplePie(); + $pie->set_cache_duration($admin_prefs["manualtimeout"] * 60); + $pie->set_favicon_handler("favicon.php"); + $pie->set_feed_url($url); + $pie->set_javascript(false); + $pie->remove_div(false); + $pie->init(); + + return $pie; +} + +function fof_apply_tags($feed_id, $item_id) +{ + global $fof_subscription_to_tags; + + if(!isset($fof_subscription_to_tags)) + { + $fof_subscription_to_tags = fof_db_get_subscription_to_tags(); + } + + foreach((array)$fof_subscription_to_tags[$feed_id] as $user_id => $tags) + { + if(is_array($tags)) + { + foreach($tags as $tag) + { + fof_db_tag_items($user_id, $tag, $item_id); + } + } + } +} + +function fof_update_feed($id) +{ + if(!$id) return 0; + + $feed = fof_db_get_feed_by_id($id); + $url = $feed['feed_url']; + fof_log("Updating $url"); + + fof_db_feed_mark_attempted_cache($id); + + $rss = fof_parse($feed['feed_url']); + + if ($rss->error()) + { + fof_log("feed update failed: " . $rss->error(), "update"); + return array(0, "Error: " . $rss->error() . " try to validate it?"); + } + + $sub = html_entity_decode($rss->subscribe_url(), ENT_QUOTES); + $self_link = $rss->get_link(0, 'self'); + if($self_link) $sub = html_entity_decode($self_link, ENT_QUOTES); + + fof_log("subscription url is $sub"); + + $image = $feed['feed_image']; + $image_cache_date = $feed['feed_image_cache_date']; + + if($feed['feed_image_cache_date'] < (time() - (7*24*60*60))) + { + $image = $rss->get_favicon(); + $image_cache_date = time(); + } + + $title = $rss->get_title(); + if($title == "") $title = "[no title]"; + + fof_db_feed_update_metadata($id, $sub, $title, $rss->get_link(), $rss->get_description(), $image, $image_cache_date ); + + $feed_id = $feed['feed_id']; + $n = 0; + + if($rss->get_items()) + { + foreach($rss->get_items() as $item) + { + $link = $item->get_permalink(); + $title = $item->get_title(); + $content = $item->get_content(); + $date = $item->get_date('U'); + if(!$date) $date = time(); + $item_id = $item->get_id(); + + if(!$item_id) + { + $item_id = $link; + } + + $id = fof_db_find_item($feed_id, $item_id); + + if($id == NULL) + { + $n++; + + global $fof_item_prefilters; + foreach($fof_item_prefilters as $filter) + { + list($link, $title, $content) = $filter($item, $link, $title, $content); + } + + $id = fof_db_add_item($feed_id, $item_id, $link, $title, $content, time(), $date, $date); + fof_apply_tags($feed_id, $id); + + $republished = false; + + // this was a failed attempt to avoid duplicates when subscribing to + // a "planet" type feed when you already have some of the feeds in the + // planet subscribed. in the end there were just too many cases where + // dupes still got through (like the 'source' feed url being just slightly + // different from the subscribed url). + // + // maybe a better approach would be simply using the Atom GUID as a + // true *GU* ID. + + /* + $source = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'); + $links = $source[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; + + if(is_array($links)) + { + foreach($links as $link) + { + if($link['attribs']['']['rel'] == 'self') + { + $feed_url = $link['attribs']['']['href']; + + $feed = fof_db_get_feed_by_url($feed_url); + + if($feed) + { + fof_log("was repub from $feed_url"); + + $republished = true; + + $result = fof_get_subscribed_users($feed_id); + + $repub_subscribers = array(); + while($row = fof_db_get_row($result)) + { + $repub_subscribers[] = $row['user_id']; + fof_log("repub_sub: " . $row['user_id']); + } + + $result = fof_get_subscribed_users($feed['feed_id']); + + $original_subscribers = array(); + while($row = fof_db_get_row($result)) + { + $original_subscribers[] = $row['user_id']; + fof_log("orig_sub: " . $row['user_id']); + } + + $new_subscribers = array_diff($repub_subscribers, $original_subscribers); + + fof_db_mark_item_unread($new_subscribers, $id); + + $old_subscribers = array_intersect($original_subscribers, $repub_subscribers); + + foreach($old_subscribers as $user) + { + fof_tag_item($user, $id, 'republished'); + } + } + } + } + } + */ + + if(!$republished) + { + fof_mark_item_unread($feed_id, $id); + } + + fof_apply_plugin_tags($feed_id, $id, NULL); + } + + $ids[] = $id; + } + } + + // optionally purge old items - if 'purge' is set we delete items that are not + // unread or starred, not currently in the feed or within sizeof(feed) items + // of being in the feed, and are over 'purge' many days old + + $p =& FoF_Prefs::instance(); + $admin_prefs = $p->admin_prefs; + + if($admin_prefs['purge'] != "") + { + fof_log('purge is ' . $admin_prefs['purge']); + $count = count($ids); + fof_log('items in feed: ' . $count); + + if(count($ids) != 0) + { + $in = implode ( ", ", $ids ); + + global $FOF_ITEM_TABLE, $FOF_ITEM_TAG_TABLE; + $sql = "select item_id, item_cached from $FOF_ITEM_TABLE where feed_id = $feed_id and item_id not in ($in) order by item_cached desc limit $count, 1000000000"; + $result = fof_db_query($sql); + + while($row = fof_db_get_row($result)) + { + if($row['item_cached'] < (time() - ($admin_prefs['purge'] * 24 * 60 * 60))) + { + if(!fof_item_has_tags($row['item_id'])) + { + $delete[] = $row['item_id']; + } + } + } + + $ndelete = count($delete); + if(count($delete) != 0) + { + $in = implode(", ", $delete); + fof_db_query( "delete from $FOF_ITEM_TABLE where item_id in ($in)" ); + fof_db_query( "delete from $FOF_ITEM_TAG_TABLE where item_id in ($in)" ); + } + } + } + + unset($rss); + + fof_db_feed_mark_cached($feed_id); + + $log = "feed update complete, $n new items, $ndelete items purged"; + if($admin_prefs['purge'] == "") + { + $log .= " (purging disabled)"; + } + fof_log($log, "update"); + + return array($n, ""); +} + +function fof_apply_plugin_tags($feed_id, $item_id = NULL, $user_id = NULL) +{ + $users = array(); + + if($user_id) + { + $users[] = $user_id; + } + else + { + $result = fof_get_subscribed_users($feed_id); + + while($row = fof_db_get_row($result)) + { + $users[] = $row['user_id']; + } + } + + $items = array(); + if($item_id) + { + $items[] = fof_db_get_item($user_id, $item_id); + } + else + { + $result = fof_db_get_items($user_id, $feed_id, $what="all", NULL, NULL); + + foreach($result as $r) + { + $items[] = $r; + } + } + + $userdata = fof_get_users(); + + foreach($users as $user) + { + fof_log("tagging for $user"); + + global $fof_tag_prefilters; + foreach($fof_tag_prefilters as $plugin => $filter) + { + fof_log("considering $plugin $filter"); + + if(!$userdata[$user]['prefs']['plugin_' . $plugin]) + { + foreach($items as $item) + { + $tags = $filter($item['item_link'], $item['item_title'], $item['item_content']); + fof_tag_item($user, $item['item_id'], $tags); + } + } + } + } +} + +function fof_item_has_tags($item_id) +{ + return fof_db_item_has_tags($item_id); +} + +function fof_init_plugins() +{ + global $fof_item_filters, $fof_item_prefilters, $fof_tag_prefilters, $fof_plugin_prefs; + + $fof_item_filters = array(); + $fof_item_prefilters = array(); + $fof_plugin_prefs = array(); + $fof_tag_prefilters = array(); + + $p =& FoF_Prefs::instance(); + + $dirlist = opendir(FOF_DIR . "/plugins"); + while($file=readdir($dirlist)) + { + fof_log("considering " . $file); + if(ereg('\.php$',$file) && !$p->get('plugin_' . substr($file, 0, -4))) + { + fof_log("including " . $file); + + include(FOF_DIR . "/plugins/" . $file); + } + } + + closedir(); +} + +function fof_add_tag_prefilter($plugin, $function) +{ + global $fof_tag_prefilters; + + $fof_tag_prefilters[$plugin] = $function; +} + +function fof_add_item_filter($function) +{ + global $fof_item_filters; + + $fof_item_filters[] = $function; +} + +function fof_add_item_prefilter($function) +{ + global $fof_item_prefilters; + + $fof_item_prefilters[] = $function; +} + +function fof_add_pref($name, $key, $type="string") +{ + global $fof_plugin_prefs; + + $fof_plugin_prefs[] = array($name, $key, $type); +} + +function fof_add_item_widget($function) +{ + global $fof_item_widgets; + + $fof_item_widgets[] = $function; +} + +function fof_get_widgets($item) +{ + global $fof_item_widgets; + + if (!is_array($fof_item_widgets)) + { + return false; + } + + foreach($fof_item_widgets as $widget) + { + $w = $widget($item); + if($w) $widgets[] = $w; + } + + return $widgets; +} + +function fof_get_plugin_prefs() +{ + global $fof_plugin_prefs; + + return $fof_plugin_prefs; +} + +function fof_multi_sort($tab,$key,$rev) +{ + if($rev) + { + $compare = create_function('$a,$b','if (strtolower($a["'.$key.'"]) == strtolower($b["'.$key.'"])) {return 0;}else {return (strtolower($a["'.$key.'"]) > strtolower($b["'.$key.'"])) ? -1 : 1;}'); + } + else + { + $compare = create_function('$a,$b','if (strtolower($a["'.$key.'"]) == strtolower($b["'.$key.'"])) {return 0;}else {return (strtolower($a["'.$key.'"]) < strtolower($b["'.$key.'"])) ? -1 : 1;}'); + } + + usort($tab,$compare) ; + return $tab ; +} + +function fof_todays_date() +{ + $prefs = fof_prefs(); + $offset = $prefs['tzoffset']; + + return gmdate( "Y/m/d", time() + ($offset * 60 * 60) ); +} + +function fof_repair_drain_bamage() +{ + if (ini_get('register_globals')) foreach($_REQUEST as $k=>$v) { unset($GLOBALS[$k]); } + + // thanks to submitter of http://bugs.php.net/bug.php?id=39859 + if (get_magic_quotes_gpc()) { + function undoMagicQuotes($array, $topLevel=true) { + $newArray = array(); + foreach($array as $key => $value) { + if (!$topLevel) { + $key = stripslashes($key); + } + if (is_array($value)) { + $newArray[$key] = undoMagicQuotes($value, false); + } + else { + $newArray[$key] = stripslashes($value); + } + } + return $newArray; + } + $_GET = undoMagicQuotes($_GET); + $_POST = undoMagicQuotes($_POST); + $_COOKIE = undoMagicQuotes($_COOKIE); + $_REQUEST = undoMagicQuotes($_REQUEST); + } +} + +// for PHP 4 compatibility + +if(!function_exists('str_ireplace')) +{ + function str_ireplace($search,$replace,$subject) + { + $search = preg_quote($search, "/"); + return preg_replace("/".$search."/i", $replace, $subject); + } +} +?> diff --git a/fof-render.php b/fof-render.php new file mode 100644 index 0000000..2abcf47 --- /dev/null +++ b/fof-render.php @@ -0,0 +1,201 @@ +]*?>)([^<]*))|((([^<]*))/si'; + preg_match_all($pat,$full_body,$tag_matches); + + /* loop through and highlight $q value in data and recombine with tags */ + for ($i=0; $i< count($tag_matches[0]); $i++) { + /* ignore all text within these tags */ + if ( + (preg_match('/\$3\$4\$5",' '.$tag_matches[3][$i].' '); + $full_body_hl .= substr($holder,1,(strlen($holder)-2)); + } + } + /* return tagged text */ + return $full_body_hl; +} + + +function fof_render_item($item) +{ + $items = true; + + $feed_link = $item['feed_link']; + $feed_title = $item['feed_title']; + $feed_image = $item['feed_image']; + $feed_description = $item['feed_description']; + + $item_link = $item['item_link']; + $item_id = $item['item_id']; + $item_title = $item['item_title']; + $item_content = $item['item_content']; + $item_read = $item['item_read']; + + $prefs = fof_prefs(); + $offset = $prefs['tzoffset']; + + $item_published = gmdate("Y-n-d g:ia", $item['item_published'] + $offset*60*60); + $item_cached = gmdate("Y-n-d g:ia", $item['item_cached'] + $offset*60*60); + $item_updated = gmdate("Y-n-d g:ia", $item['item_updated'] + $offset*60*60); + + if(!$item_title) $item_title = "[no title]"; + + if($_GET['search']) + { + $item_content = do_highlight("$item_content", $_GET['search'], "highlight"); + $item_title = do_highlight("$item_title", $_GET['search'], "highlight"); + } + + $tags = $item['tags']; + + $star = in_array("star", $tags) ? true : false; + $star_image = $star ? "image/star-on.gif" : "image/star-off.gif"; + + $unread = in_array("unread", $tags) ? true : false; +?> + +
+ + + + + + + +

> + + + + + +

+ + + + + + + [x] + + + + add tag + + +
+ + +
+ +
+ + - + +

+ + + + + +

+ + on + +
+ + +
+ + + +
+ +
+ +$widget "; + } +?> + +
+ + + + diff --git a/fof.css b/fof.css new file mode 100644 index 0000000..7c88b8a --- /dev/null +++ b/fof.css @@ -0,0 +1,377 @@ +p +{ + margin: 0; + padding: 5px; +} + +.clearer +{ + clear: both; +} + +#view-page +{ + font-family: georgia; + margin-top: 0; +} + +.header +{ + background: #dddddd; + padding: 5px; +} + +.widgets +{ + font-family: verdana, arial; + background: #f0f0f0; + font-size: 12px; + padding: 4px; + text-align: right; +} + +.widget +{ + margin-left: 10px; +} + +#handle +{ + top: 0px; + bottom: 0px; + position: fixed; + width: 10px; + background: grey; + cursor: e-resize; + background-image: url(image/grippy.png); +} + +#sidebar +{ + font-family: verdana, arial; + font-size: 10px; + margin: 0; + top: 0px; + left: 0px; + height: 100%; + position: fixed; + overflow: scroll; +} + +#nav +{ + font-size: 11px; +} + +#sidebar ul +{ + padding-left: 2em; +} + +#sidebar form +{ + display: inline; +} + +#sidebar p +{ + margin: 5px; +} + +#sidebar table +{ + border-collapse: collapse; + width: 100%; +} + +.heading a +{ + text-decoration: none; +} + +.heading +{ + background: #ccc; + border-bottom: 1px solid grey; +} + +#sidebar td +{ + font-size: 10px; + padding: 2px; +} + + +.odd-row +{ + background: #dddddd; +} + +.unread +{ + font-weight: bold; + color: red; +} + + +.unread-item +{ + font-weight: bold; +} + + +#items +{ + font-family: georgia; +} + +.highlight-on .highlight +{ + background: yellow; +} + +h1 +{ + font-size: 110%; + margin: 0px; + margin-bottom: 5px; + font-weight: normal; +} + +h2 +{ + font-size: 100%; + margin: 0px; + margin-bottom: 5px; + font-weight: normal; + display: inline; +} + +.meta +{ + font-size: 80%; + display: inline; +} + +.header +{ + background-color: #ddd; + padding: 5px; +} + +body +{ + margin: 0px; + padding: 0px; +} + +.body +{ + margin: 0px; + padding: 10px 10px 10px 10px; +} + +.item +{ + border: 2px solid #ddd; + margin: 10px; + margin-bottom: 20px; + clear: both; + overflow: hidden; +} + +.item.selected +{ + border: 1px solid #888; + background-color: #eee; +} + +.selected .header +{ + background-color: #ccc; +} + +#menu-page +{ + margin: 0; + padding: 0; + font-family: verdana; + font-size: 60%; + background: #eee; +} + +#menu-page .menu ul +{ + padding: 1px; + margin: 0; +} + +#menu-page .menu li +{ + display: inline; + padding: 5px; +} + +#menu-page .menu +{ + text-align: center; + background: #eee; +} + +#menu-page a:hover +{ + background: #fff; +} + +.nowrap +{ + white-space: nowrap; +} + +.controls +{ + float: right; +} + +.tags +{ + font-size: 70%; + float: right; +} + +.item.hidden +{ + margin-bottom: 10px; +} + +.hidden .body +{ + display: none; +} + +.hidden .widgets +{ + display: none; +} + + +.shown .downarrow +{ + display: none; +} + +.hidden .uparrow +{ + display: none; +} + +.hidden h1 +{ + font-size: 90%; + display: inline; +} + +.hidden h2 +{ + font-size: 80%; +} + +.hidden .tags +{ + display: none; +} + +.hidden .meta +{ + display: none; +} + +.hidden .dash +{ + display: inline; +} + +.shown .dash +{ + display: none; +} + +#welcome +{ +font: normal 10px Verdana; +background: #ddd; +border-bottom: 1px solid #666; +padding: 5px 7px; +} + +#item-display-controls +{ +font: normal 10px Verdana; +position: fixed; +top: 0; +left: 0; +right: 0; +margin: 0; +padding: 0 5px; +background: #ddd; +border-bottom: 1px solid #666; +z-index: 1; +} + +#item-display-controls li +{ +padding: 5px 4px; +} + +#item-display-controls li a +{ +padding: 0; +} + +#item-display-controls-spacer +{ +font: normal 10px Verdana; +top: 0; +left: 0; +right: 0; +margin: 0; +padding: 0; +} + +#item-display-controls-spacer li +{ +padding: 5px 4px; +} + +#item-display-controls-spacer li a +{ +padding: 0; +} + +.item-date-nav +{ +text-align: center; +clear: both; +padding: 7px 0 0 0; +} + +.inline-list +{ +margin: auto; +padding: 0; +list-style: none; +} + +.inline-list li +{ +float: left; +margin: 0; +padding: 0; +} + +.inline-list li a +{ +display: block; +padding: 2px 5px; +} + diff --git a/fof.js b/fof.js new file mode 100644 index 0000000..1edefaa --- /dev/null +++ b/fof.js @@ -0,0 +1,908 @@ +var curWidth = 0; +var curPos = 0; +var drag = false; +var what; +var when; + +var firstItem; +var item; +var itemElement; +var itemElements; + +// magic from http://peter.michaux.ca/article/3556 + +var getScrollY = function() { + + if (typeof window.pageYOffset == 'number') { + + getScrollY = function() { + return window.pageYOffset; + }; + + } else if ((typeof document.compatMode == 'string') && + (document.compatMode.indexOf('CSS') >= 0) && + (document.documentElement) && + (typeof document.documentElement.scrollTop == 'number')) { + + getScrollY = function() { + return document.documentElement.scrollTop; + }; + + } else if ((document.body) && + (typeof document.body.scrollTop == 'number')) { + + getScrollY = function() { + return document.body.scrollTop; + } + + } else { + + getScrollY = function() { + return NaN; + }; + + } + + return getScrollY(); +} + +var getY = function(e) +{ + var y = NaN; + + if (e.offsetParent) { + y = e.offsetTop + while (e = e.offsetParent) { + y += e.offsetTop + } + } + + return y; +} + +function getWindowHeight() +{ + if( typeof( window.innerHeight ) == 'number' ) { + //Non-IE + return window.innerHeight; + } else if( document.documentElement && document.documentElement.clientHeight ) { + //IE 6+ in 'standards compliant mode' + return document.documentElement.clientHeight; + } else if( document.body && document.body.clientHeight ) { + //IE 4 compatible + return document.body.clientHeight; + } + + return NaN; +} + +function embed_odeo(link) { + document.writeln(''); +} + +function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) { + if (placeholder != '') { + document.writeln(''); + } + else { + document.writeln(''); + } +} + +function embed_flash(bgcolor, width, height, link, loop, type) { + document.writeln(''); +} + +function embed_flv(width, height, link, placeholder, loop, player) { + document.writeln(''); +} + +function embed_wmedia(width, height, link) { + document.writeln(''); +} + +function itemClicked(event) +{ + if(!event) event = window.event; + target = window.event ? window.event.srcElement : event.target; + + if(event.altKey) + { + Event.stop(event); + + unselect(itemElement); + while(target.parentNode) + { + if(Element.hasClassName(target, "item")) + { + break; + } + target = target.parentNode; + } + + if(itemElement == target) + { + itemElement = null; + return false; + } + + Element.addClassName(target, 'selected'); + itemElement = target; + + i = itemElements.indexOf(target); + + if(i == -1) + { + // in case page was partially loaded when itemElements was initialized + itemElements = $$('.item'); + i = itemElements.indexOf(target); + } + + n = itemElements.length; + i++; + + document.title = "Feed on Feeds - " + i + " of " + n; + return false; + } + + return true; +} + +function checkbox(event) +{ + if(!event) event = window.event; + target = window.event ? window.event.srcElement : event.target; + + if(!event.shiftKey) + return true; + + flag_upto(target.id); + + return true; +} + +function select(item) +{ + Element.addClassName(item, 'selected'); + + y = getY(item); + bar = $('item-display-controls').getHeight(); + window.scrollTo(0, y - (bar + 10)); + + i = itemElements.indexOf(item); + + if(i == -1) + { + // in case page was partially loaded when itemElements was initialized + itemElements = $$('.item'); + i = itemElements.indexOf(item); + } + + n = itemElements.length; + i++; + + document.title = "Feed on Feeds - " + i + " of " + n; +} + +function unselect(item) +{ + Element.removeClassName(item, 'selected'); + document.title = "Feed on Feeds"; + +} + +function show_enclosure(e) +{ + if (!e) e = window.event; + target = window.event ? window.event.srcElement : e.target; + Element.extend(target); + div = target.nextSiblings().first(); + Element.show(div); + Element.hide(target); + + return false; +} + +function keyboard(e) +{ + if (!e) e = window.event; + + target = window.event ? window.event.srcElement : e.target; + + if(target != null && target.type != null && (target.type == "textarea" || target.type=="text" || target.type=="password")) + { + return true; + } + + if (e.keyCode) keycode=e.keyCode; + else keycode=e.which; + + if(e.ctrlKey || e.altKey || e.metaKey) return true; + + key = String.fromCharCode(keycode); + + if(!itemElements) itemElements = $$('.item'); + + windowHeight = getWindowHeight(); + + if(key == "H") + { + itemElements.each( + function(i) { + Element.toggleClassName(i, "shown"); + Element.toggleClassName(i, "hidden"); + } + ); + + if(itemElement) + select(itemElement); + + return false; + } + + if(key == "h") + { + if(itemElement) + { + Element.toggleClassName(itemElement, "shown"); + Element.toggleClassName(itemElement, "hidden"); + select(itemElement); + return false; + } + } + + if(key == "s") + { + if(itemElement) + { + toggle_favorite(itemElement.id.substring(1)); + select(itemElement); + return false; + } + } + + if(key == "f") + { + if(itemElement) + { + checkbox = ($('c' + itemElement.id.substring(1))); + checkbox.checked = true; + return false; + } + } + + if(key == "F") + { + itemElements.each( + function(i) { + if(itemElement) + { + if(itemElements.indexOf(i) > itemElements.indexOf(itemElement)) + return; + } + checkbox = ($('c' + i.id.substring(1))); + checkbox.checked = true; + } + ); + + return false; + } + + if(key == "U") + { + itemElements.each( + function(i) { + checkbox = ($('c' + i.id.substring(1))); + checkbox.checked = false; + } + ); + + return false; + } + + if(key == "j") + { + if(itemElement) + { + // is the next element visible yet? scroll if not. + + if(itemElement.nextSibling.id && itemElement.nextSibling.id != "end-of-items") + { + nextElement = itemElement.nextSibling; + scrollHeight = getScrollY(); + y = getY(nextElement); + + if(y > scrollHeight + windowHeight) + { + window.scrollTo(0, scrollHeight + (.8 * windowHeight)); + return false; + } + } + + unselect(itemElement); + checkbox = ($('c' + itemElement.id.substring(1))); + checkbox.checked = true; + + next = itemElement.nextSibling; + + if(next.id && next.id != "end-of-items") + { + itemElement = next; + } + else + { + scrollHeight = getScrollY(); + + e = $('end-of-items'); + + if (e.offsetParent) { + y = e.offsetTop + while (e = e.offsetParent) { + y += e.offsetTop + } + } + + if(y - 10 > scrollHeight + windowHeight) + { + window.scrollTo(0, scrollHeight + (.8 * windowHeight)); + return false; + } + else + { + if(confirm("No more items! Mark flagged as read?")) + { + mark_read(); + } + else + { + item = firstItem; + itemElement = $(item); + select(itemElement); + return false; + } + } + } + + item = itemElement.id; + itemElement = $(item); + + select(itemElement); + + return false; + } + else + { + item = firstItem; + itemElement = $(item); + itemElements = $$('.item'); + + select(itemElement); + + return false; + } + } + + if(key == "J") + { + if(itemElement) + { + unselect(itemElement); + checkbox = ($('c' + itemElement.id.substring(1))); + checkbox.checked = true; + + next = itemElement.nextSibling; + + if(next.id) + { + itemElement = next; + } + else + { + if(confirm("No more items! Mark flagged as read?")) + { + mark_read(); + } + else + { + item = firstItem; + itemElement = $(item); + } + } + + item = itemElement.id; + itemElement = $(item); + + select(itemElement); + + return false; + } + else + { + item = firstItem; + itemElement = $(item); + itemElements = $$('.item'); + + select(itemElement); + + return false; + } + } + + if(key == "n") + { + if(itemElement) + { + unselect(itemElement); + + next = itemElement.nextSibling; + + if(next.id) + { + itemElement = next; + } + else + { + item = firstItem; + itemElement = $(item); + } + + item = itemElement.id; + itemElement = $(item); + + select(itemElement); + + return false; + } + else + { + item = firstItem; + itemElement = $(item); + itemElements = $$('.item'); + + select(itemElement); + + return false; + } + } + + if(key == "N") + { + if(itemElement) unselect(itemElement); + + item = itemElements.last().id; + itemElement = $(item); + + select(itemElement); + + return false; + } + + if(key == "P") + { + if(itemElement) unselect(itemElement); + + item = firstItem; + itemElement = $(item); + itemElements = $$('.item'); + + select(itemElement); + + return false; + } + + if(key == "p") + { + if(itemElement) + { + unselect(itemElement); + + next = itemElement.previousSibling; + + if(next.id) + { + itemElement = next; + } + else + { + item = itemElements.last().id; + itemElement = $(item); + } + + item = itemElement.id; + itemElement = $(item); + + select(itemElement); + + return false; + } + else + { + itemElements = $$('.item'); + item = itemElements.last().id; + itemElement = $(item); + + select(itemElement); + + return false; + } + } + + return true; +} + + + +function startResize(e) +{ + if (!e) e = window.event; + + Event.stop(e); + + drag = true; + curPos=e.clientX; + curWidth=$('sidebar').offsetWidth; + + return false; +} + +function dragResize(e) +{ + if (!e) e = window.event; + + if(drag) + { + Event.stop(e); + + newPos=e.clientX; + var x=newPos-curPos; + var w=curWidth+x; + newWidth=(w<5?5:w); + + $('handle').style.left=newWidth+'px'; + + return false; + } +} + +function completeDrag(e) +{ + if (!e) e = window.event; + + if(drag) + { + Event.stop(e); + + drag = false; + + newPos=e.clientX; + var x=newPos-curPos; + var w=curWidth+x; + newWidth=(w<5?5:w); + + $('sidebar').style.width=newWidth+'px'; + $('handle').style.left=newWidth+'px'; + $('items').style.marginLeft=(newWidth+20)+'px'; + $('item-display-controls').style.left=(newWidth+10)+'px'; + + if(isIE) + { + tables = $$('#sidebar table'); + for(i=0;iUpdate complete!'); + refreshlist(); + } +} + +function continueadd() +{ + if(feed = feedi()) + { + f = feed(); + new Insertion.Bottom($('items'), 'Adding ' + f['url'] + "... "); + $('items').childElements().last().scrollTo(); + + parameters = 'url=' + encodeURIComponent(f['url']) + "&unread=" + document.addform.unread.value; + + new Ajax.Updater('items', 'add-single.php', { + method: 'get', + parameters: parameters, + insertion: Insertion.Bottom, + onComplete: continueadd + }); + } + else + { + new Insertion.Bottom($('items'), '
Done!'); + refreshlist(); + } +} + +function ajaxupdate() +{ + throb(); + feedi = iterate(feedslist); + continueupdate(); +} + +function ajaxadd() +{ + throb(); + feedi = iterate(feedslist); + continueadd(); +} + diff --git a/footer.php b/footer.php new file mode 100644 index 0000000..aa5a7c3 --- /dev/null +++ b/footer.php @@ -0,0 +1,4 @@ + + + + diff --git a/header.php b/header.php new file mode 100644 index 0000000..6af2e93 --- /dev/null +++ b/header.php @@ -0,0 +1,93 @@ + + + + + + Feed on Feeds<?php if($unread_count) echo " ($unread_count)";?> + + + + + + + + + + + + + + + + + + + + +
+ +
diff --git a/image/feed-icon.png b/image/feed-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6c273b4b122bb6daf1ebb6226ea067a9aa08ced2 GIT binary patch literal 763 zcmVad6RmpJ*FIrWk^@ryP3oH^@%GW(r6^pQ6BnK}IR@bZl{|M~Oge>3QLG3InH>4i1$ zi8S_U}ZZWh~-$G3tjk<$W^#^5*P{HspIU=Xfvv_wxCj zLEUaI+FmN)YAyW2gxp~(<$N;Ua4_eAGyU=A;dn9Qc`@vPGUItN>xnh#h&JVPF5z@A z{o1wOZ!hSBH0Xsj-*GVbo<#YdMfJa#@{>aLn?&e|Rqvf->3%u%rf2uVnfSks`ooX< zvufgSHv8t-?3QEqp-}zh&HJfR{_NWLuW9wEX#C^N`K40$v~}*XmGrWJ{_*Dbt!ets zr~1>g?wVxotBLZXX8W&R`?+`d$eZqwOyqn=>WNAH-@)K@MdpiO`PaYtzJv9^nDeA( z@wb=!*|qe&nD^Aa{^ri~taJLTUizX&?~Oq!?I|t*00ApWL_t(|+G5~l)YVgv<?0v z(btiI;l}H)G9s&he1&9>AYTTC+!+iE#eED6w?r5i8Wu7z)Fm-694lpDFkxq4P`Z8P zQGq{Dt%0YDV@SoVq@6WCzun$0FR_7V}y;Q b6%H_HvGXPNde{F2>SgeB^>bP0l+XkKH+3(; literal 0 HcmV?d00001 diff --git a/image/star-off.gif b/image/star-off.gif new file mode 100644 index 0000000000000000000000000000000000000000..210e171bf5bd7e3a13945fd01af5e7498f1c3605 GIT binary patch literal 585 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 literal 0 HcmV?d00001 diff --git a/index.php b/index.php new file mode 100644 index 0000000..eefa22d --- /dev/null +++ b/index.php @@ -0,0 +1,20 @@ + diff --git a/install.php b/install.php new file mode 100644 index 0000000..167ede0 --- /dev/null +++ b/install.php @@ -0,0 +1,363 @@ +=')); +$xml_ok = extension_loaded('xml'); +$pcre_ok = extension_loaded('pcre'); +$mysql_ok = extension_loaded('mysql'); + +$curl_ok = (extension_loaded('curl') && version_compare(get_curl_version(), '7.10.5', '>=')); +$zlib_ok = extension_loaded('zlib'); +$mbstring_ok = extension_loaded('mbstring'); +$iconv_ok = extension_loaded('iconv'); + +?> + + + +feed on feeds - installation + + + + + + + + +
Feed on Feeds - Installation

+ + +OK! Setup complete! Login as admin, and start subscribing!
'; +} +else +{ + if($_GET['password'] != $_GET['password2'] ) + { + echo '
Passwords do not match!


'; + } + +?> + +Checking compatibility... +PHP ok... "; +else +{ + echo "
Your PHP version is too old! Feed on Feeds requires at least PHP 4.3.2. Sorry!"; + echo "
"; + exit; +} + +if($xml_ok) echo "XML ok... "; +else +{ + echo "
Your PHP installation is missing the XML extension! This is required by Feed on Feeds. Sorry!"; + echo ""; + exit; +} + +if($pcre_ok) echo "PCRE ok... "; +else +{ + echo "
Your PHP installation is missing the PCRE extension! This is required by Feed on Feeds. Sorry!"; + echo ""; + exit; +} + +if($mysql_ok) echo "MySQL ok... "; +else +{ + echo "
Your PHP installation is missing the MySQL extension! This is required by Feed on Feeds. Sorry!"; + echo ""; + exit; +} + +if($curl_ok) echo "cURL ok... "; +else +{ + echo "
Your PHP installation is either missing the cURL extension, or it is too old! cURL version 7.10.5 or later is required to be able to subscribe to https or digest authenticated feeds.
"; +} + +if($zlib_ok) echo "Zlib ok... "; +else +{ + echo "
Your PHP installation is missing the Zlib extension! Feed on Feeds will not be able to save bandwidth by requesting compressed feeds.
"; +} + +if($iconv_ok) echo "iconv ok... "; +else +{ + echo "
Your PHP installation is missing the iconv extension! The number of international languages that Feed on Feeds can handle will be reduced.
"; +} + +if($mbstring_ok) echo "mbstring ok... "; +else +{ + echo "
Your PHP installation is missing the mbstring extension! The number of international languages that Feed on Feeds can handle will be reduced.
"; +} + +?> +
Minimum requirements met! +
+ +Creating tables... +" . mysql_error() . "
" ); + } +} + +?> +Tables exist.
+ +"; +} +?> + + +"; +} +?> + + +"; +} +?> + +Inserting initial data... + + + +Done.
+ +Checking cache directory... +Can't create directory " . getcwd() . "/cache/.
You will need to create it yourself, and make it writeable by your PHP process.
Then, reload this page."; + echo ""; + exit; + } +} + +if(!is_writable( "cache" )) +{ + echo "The directory " . getcwd() . "/cache/ exists, but is not writable.
You will need to make it writeable by your PHP process.
Then, reload this page.
"; + echo ""; + exit; +} + +?> + +Cache directory exists and is writable.
+ + + +You now need to choose an initial password for the 'admin' account:
+ +
+ + + +
Password:
Password again:
+ +
+ + + +'admin' account already exists.
+
OK! Setup complete! Login as admin, and start subscribing!
+ + + + diff --git a/item.php b/item.php new file mode 100644 index 0000000..003cade --- /dev/null +++ b/item.php @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/items.php b/items.php new file mode 100644 index 0000000..636fcb4 --- /dev/null +++ b/items.php @@ -0,0 +1,136 @@ +get("order"); +} + +$how = $_GET['how']; +$feed = $_GET['feed']; +$when = $_GET['when']; +$howmany = $_GET['howmany']; + +$title = fof_view_title($_GET['feed'], $what, $_GET['when'], $which, $_GET['howmany'], $_GET['search']); +$noedit = $_GET['noedit']; + +?> + + + +

+ +

+ + + + + + + + +
+ + + + +
+ +firstItem = 'i$item_id'; "; + $first = false; + print '
'; + fof_render_item($row); + print '
'; +} + +if(count($result) == 0) +{ + echo "

No items found.

"; +} + +?> +
+ +
+ + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..59d6448 --- /dev/null +++ b/login.php @@ -0,0 +1,73 @@ + + + + + + Feed on Feeds - Log on + + + + + +
+
+
Feed on Feeds

+ User name:


+ Password:


+
+
Incorrect user name or password
"; ?> +
+
+ + + diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..ec70e71 --- /dev/null +++ b/logout.php @@ -0,0 +1,22 @@ + diff --git a/opml.php b/opml.php new file mode 100644 index 0000000..7d0edcf --- /dev/null +++ b/opml.php @@ -0,0 +1,48 @@ +'; +?> + + + + Feed on Feeds Subscriptions + + + + +HEYO; +} +?> + + + diff --git a/plugins/autotag.php b/plugins/autotag.php new file mode 100644 index 0000000..2d0c8a5 --- /dev/null +++ b/plugins/autotag.php @@ -0,0 +1,24 @@ + diff --git a/plugins/balancetags.php b/plugins/balancetags.php new file mode 100644 index 0000000..d271210 --- /dev/null +++ b/plugins/balancetags.php @@ -0,0 +1,123 @@ +]*)>/",$text,$regex)) { + $newtext .= $tagqueue; + + $i = strpos($text,$regex[0]); + $l = strlen($regex[0]); + + // clear the shifter + $tagqueue = ''; + // Pop or Push + if ($regex[1][0] == "/") { // End Tag + $tag = strtolower(substr($regex[1],1)); + // if too many closing tags + if($stacksize <= 0) { + $tag = ''; + //or close to be safe $tag = '/' . $tag; + } + // if stacktop value = tag close value then pop + else if ($tagstack[$stacksize - 1] == $tag) { // found closing tag + $tag = ''; // Close Tag + // Pop + array_pop ($tagstack); + $stacksize--; + } else { // closing tag not at top, search for it + for ($j=$stacksize-1;$j>=0;$j--) { + if ($tagstack[$j] == $tag) { + // add tag to tagqueue + for ($k=$stacksize-1;$k>=$j;$k--){ + $tagqueue .= ''; + $stacksize--; + } + break; + } + } + $tag = ''; + } + } else { // Begin Tag + $tag = strtolower($regex[1]); + + // Tag Cleaning + + // If self-closing or '', don't do anything. + if((substr($regex[2],-1) == '/') || ($tag == '')) { + } + // ElseIf it's a known single-entity tag but it doesn't close itself, do so + elseif ($tag == 'br' || $tag == 'img' || $tag == 'hr' || $tag == 'input') { + $regex[2] .= '/'; + } else { // Push the tag onto the stack + // If the top of the stack is the same as the tag we want to push, close previous tag + if (($stacksize > 0) && ($tag != 'div') && ($tagstack[$stacksize - 1] == $tag)) { + $tagqueue = ''; + $stacksize--; + } + $stacksize = array_push ($tagstack, $tag); + } + + // Attributes + $attributes = $regex[2]; + if($attributes) { + $attributes = ' '.$attributes; + } + $tag = '<'.$tag.$attributes.'>'; + //If already queuing a close tag, then put this tag on, too + if ($tagqueue) { + $tagqueue .= $tag; + $tag = ''; + } + } + $newtext .= substr($text,0,$i) . $tag; + $text = substr($text,$i+$l); + } + + // Clear Tag Queue + $newtext .= $tagqueue; + + // Add Remaining text + $newtext .= $text; + + // Empty Stack + while($x = array_pop($tagstack)) { + $newtext .= ''; // Add remaining tags to close + } + + // WP fix for the bug with HTML comments + $newtext = str_replace("< !--","', $start)) !== false) + { + $data = substr_replace($data, '', 0, $end + 3); + } + else + { + $data = ''; + } + } + return $output . $data; + } + + function parse_date($dt, $rfc822_tz = true) + { + static $cache = array(); + if (!isset($cache[$dt][$rfc822_tz])) + { + $dt = SimplePie_Misc::uncomment_rfc822($dt); + /* + Capturing subpatterns: + 1: RFC 822 date + 2: RFC 822 day + 3: RFC 822 month + 4: RFC 822 year + 5: ISO 8601 date + 6: ISO 8601 century + 7: ISO 8601 year + 8: ISO 8601 month + 9: ISO 8601 day + 10: ISO 8601 ordinal day + 11: ISO 8601 month + 12: ISO 8601 day + 13: ISO 8601 week + 14: ISO 8601 day of week + 15: Time + 16: Hour + 17: Hour Decimal + 18: Minute + 19: Minute Decimal + 20: Second + 21: Second Decimal + 22: Timezone + 23: Diff ± + 24: Hour + 25: Hour Decimal + 26: Minute + 27: Minute Decimal + 28: Alphabetic Timezone + */ + if (preg_match('/^(?:(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)[,\s]+)?(([0-9]{1,2})\s*(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*([0-9]{4}|[0-9]{2}))|(([0-9]{2})(?:([0-9]{2})(?:(?:-|\s)*(?:([0-9]{2})([0-9]{2})|([0-9]{3})|([0-9]{2})(?:(?:-|\s)*([0-9]{2}))?|W([0-9]{2})(?:(?:-|\s)*([0-9]))?))?)?))((?:T|\s)+([0-9]{2})(?:(?:,|\.)([0-9]*)|(?:\:|\s)*([0-9]{2})(?:(?:,|\.)([0-9]*)|(?:\:|\s)*([0-9]{2})(?:(?:,|\.)([0-9]*))?)?)?(?:\s)*((?:(\+|-)([0-9]{2})(?:(?:,|\.)([0-9]*)|(?:\:|\s)*(?:([0-9]{2})(?:(?:,|\.)([0-9]*))?))?)|(UTC|GMT|EST|CST|MST|PST|EDT|CDT|MDT|PDT|UT|[A-IK-Z]))?)?$/i', $dt, $match)) + { + // Fill all matches + for ($i = count($match); $i <= 28; $i++) + { + $match[$i] = ''; + } + + // Set blank vars + $year = 1970; + $month = 1; + $day = 1; + $hour = 0; + $minute = 0; + $second = 0; + $timezone = false; + + // RFC 822 + if ($match[1] !== '') + { + if (strlen($match[4]) == 2) + { + $year = ($match[4] < 70) ? "20$match[4]" : "19$match[4]"; + } + else + { + $year = $match[4]; + } + switch (strtolower($match[3])) + { + case 'jan': + $month = 1; + break; + + case 'feb': + $month = 2; + break; + + case 'mar': + $month = 3; + break; + + case 'apr': + $month = 4; + break; + + case 'may': + $month = 5; + break; + + case 'jun': + $month = 6; + break; + + case 'jul': + $month = 7; + break; + + case 'aug': + $month = 8; + break; + + case 'sep': + $month = 9; + break; + + case 'oct': + $month = 10; + break; + + case 'nov': + $month = 11; + break; + + case 'dec': + $month = 12; + break; + } + $day = $match[2]; + } + // ISO 8601 + else + { + // Year + if ($match[7] !== '') + { + $year = "$match[6]$match[7]"; + + // Two Digit Month/Day + if ($match[11] !== '') + { + $month = $match[11]; + if ($match[12] !== '') + { + $day = $match[12]; + } + } + + // Four Digit Month/Day + elseif ($match[8] !== '') + { + $month = $match[8]; + $day = $match[9]; + } + + // Ordinal Day + elseif ($match[10] !== '') + { + $day = $match[10]; + } + + // Week Date + elseif ($match[13] !== '') + { + // Week Day + if ($match[14] !== '') + { + $day = $match[14]; + } + + $first_day_of_year = date('w', mktime(0, 0, 0, 1, 1, $year)); + if ($first_day_of_year == 0) + { + $first_day_of_year = 7; + } + + $day = 7 * ($match[13] - 1) + $day - ($first_day_of_year - 1); + } + } + else + { + $year = "$match[6]00"; + } + } + // Time + if ($match[15] !== '') + { + $time = 0; + $time += ($match[16] + ('.' . $match[17])) * 3600; + $time += ($match[18] + ('.' . $match[19])) * 60; + $time += $match[20] + ('.' . $match[21]); + $hour = floor($time / 3600); + $time -= $hour * 3600; + $minute = floor($time / 60); + $time -= $minute * 60; + $second = round($time); + + // Timezone + if ($match[22] !== '') + { + // Alphabetic Timezone + if ($match[28] !== '') + { + // Military + if (strlen($match[28]) == 1) + { + if ($match[28] == 'Z' || $match[28] == 'z' || !$rfc822_tz) + { + $timezone = 0; + } + else + { + $timezone = ord(strtoupper($match[28])); + + if ($timezone > 74) + { + $timezone--; + } + + if ($timezone <= 76) + { + $timezone = -($timezone - 64); + } + else + { + $timezone -= 76; + } + + $timezone *= 3600; + } + } + // Code + else + { + switch (strtoupper($match[28])) + { + case 'UT': + case 'UTC': + case 'GMT': + $timezone = 0; + break; + + case 'EST': + $timezone = -18000; + break; + + case 'CST': + $timezone = -21600; + break; + + case 'MST': + $timezone = -25200; + break; + + case 'PST': + $timezone = -28800; + break; + + case 'EDT': + $timezone = -14400; + break; + + case 'CDT': + $timezone = -18000; + break; + + case 'MDT': + $timezone = -21600; + break; + + case 'PDT': + $timezone = -25200; + break; + } + } + } + // Timezone difference from UTC + else + { + $timezone = 0; + $timezone += ($match[24] + ('.' . $match[25])) * 3600; + $timezone += ($match[26] + ('.' . $match[27])) * 60; + $timezone = (int) round($timezone); + + if ($match[23] == '-') + { + $timezone = -$timezone; + } + } + } + } + if ($timezone === false) + { + $cache[$dt][$rfc822_tz] = mktime($hour, $minute, $second, $month, $day, $year); + } + else + { + $cache[$dt][$rfc822_tz] = gmmktime($hour, $minute, $second, $month, $day, $year) - $timezone; + } + } + elseif (($time = strtotime($dt)) > 0) + { + $cache[$dt][$rfc822_tz] = $time; + } + else + { + $cache[$dt][$rfc822_tz] = false; + } + } + return $cache[$dt][$rfc822_tz]; + } + + /** + * Decode HTML entities + * + * @static + * @access public + * @param string $data Input data + * @return string Output data + */ + function entities_decode($data) + { + $decoder = new SimplePie_Decode_HTML_Entities($data); + return $decoder->parse(); + } + + /** + * Remove RFC822 comments + * + * @author Tomas V.V.Cox + * @author Pierre-Alain Joye + * @author Amir Mohammad Saied + * @copyright 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox,Amir Mohammad Saied + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Validate.php,v 1.104 2006/11/17 16:32:06 amir Exp $ + * @link http://pear.php.net/package/Validate + * @access public + * @param string $data Data to strip comments from + * @return string Comment stripped string + */ + function uncomment_rfc822($data) + { + if ((version_compare(PHP_VERSION, '4.4.6', '>=') && version_compare(PHP_VERSION, '5', '<')) || version_compare(PHP_VERSION, '5.2.2', '>=')) + { + return $data; + } + else + { + return preg_replace('/((?:(?:\\\\"|[^("])*(?:"(?:[^"\\\\\r]|\\\\.)*"\s*)?)*)((?=')) + { + return array_unique($array); + } + else + { + $array = (array) $array; + $new_array = array(); + $new_array_strings = array(); + foreach ($array as $key => $value) + { + if (is_object($value)) + { + if (method_exists($value, '__toString')) + { + $cmp = $value->__toString(); + } + else + { + trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR); + } + } + elseif (is_array($value)) + { + $cmp = (string) reset($value); + } + else + { + $cmp = (string) $value; + } + if (!in_array($cmp, $new_array_strings)) + { + $new_array[$key] = $value; + $new_array_strings[] = $cmp; + } + } + return $new_array; + } + } + + /** + * Converts a unicode codepoint to a UTF-8 character + * + * @static + * @access public + * @param int $codepoint Unicode codepoint + * @return string UTF-8 character + */ + function codepoint_to_utf8($codepoint) + { + static $cache = array(); + $codepoint = (int) $codepoint; + if (isset($cache[$codepoint])) + { + return $cache[$codepoint]; + } + elseif ($codepoint < 0) + { + return $cache[$codepoint] = false; + } + else if ($codepoint <= 0x7f) + { + return $cache[$codepoint] = chr($codepoint); + } + else if ($codepoint <= 0x7ff) + { + return $cache[$codepoint] = chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f)); + } + else if ($codepoint <= 0xffff) + { + return $cache[$codepoint] = chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + } + else if ($codepoint <= 0x10ffff) + { + return $cache[$codepoint] = chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); + } + else + { + // U+FFFD REPLACEMENT CHARACTER + return $cache[$codepoint] = "\xEF\xBF\xBD"; + } + } + + /** + * Re-implementation of PHP 4.2.0's is_a() + * + * @static + * @access public + * @param object $object The tested object + * @param string $class_name The class name + * @return bool Returns true if the object is of this class or has this class as one of its parents, false otherwise + */ + function is_a($object, $class_name) + { + if (function_exists('is_a')) + { + return is_a($object, $class_name); + } + elseif (!is_object($object)) + { + return false; + } + elseif (get_class($object) == strtolower($class_name)) + { + return true; + } + else + { + return is_subclass_of($object, $class_name); + } + } + + /** + * Re-implementation of PHP 5's stripos() + * + * Returns the numeric position of the first occurrence of needle in the + * haystack string. + * + * @static + * @access string + * @param object $haystack + * @param string $needle Note that the needle may be a string of one or more + * characters. If needle is not a string, it is converted to an integer + * and applied as the ordinal value of a character. + * @param int $offset The optional offset parameter allows you to specify which + * character in haystack to start searching. The position returned is still + * relative to the beginning of haystack. + * @return bool If needle is not found, stripos() will return boolean false. + */ + function stripos($haystack, $needle, $offset = 0) + { + if (function_exists('stripos')) + { + return stripos($haystack, $needle, $offset); + } + else + { + if (is_string($needle)) + { + $needle = strtolower($needle); + } + elseif (is_int($needle) || is_bool($needle) || is_double($needle)) + { + $needle = strtolower(chr($needle)); + } + else + { + trigger_error('needle is not a string or an integer', E_USER_WARNING); + return false; + } + + return strpos(strtolower($haystack), $needle, $offset); + } + } +} + +/** + * Decode HTML Entities + * + * This implements HTML5 as of revision 967 (2007-06-28) + * + * @package SimplePie + */ +class SimplePie_Decode_HTML_Entities +{ + /** + * Data to be parsed + * + * @access private + * @var string + */ + var $data = ''; + + /** + * Currently consumed bytes + * + * @access private + * @var string + */ + var $consumed = ''; + + /** + * Position of the current byte being parsed + * + * @access private + * @var int + */ + var $position = 0; + + /** + * Create an instance of the class with the input data + * + * @access public + * @param string $data Input data + */ + function SimplePie_Decode_HTML_Entities($data) + { + $this->data = $data; + } + + /** + * Parse the input data + * + * @access public + * @return string Output data + */ + function parse() + { + while (($this->position = strpos($this->data, '&', $this->position)) !== false) + { + $this->consume(); + $this->entity(); + $this->consumed = ''; + } + return $this->data; + } + + /** + * Consume the next byte + * + * @access private + * @return mixed The next byte, or false, if there is no more data + */ + function consume() + { + if (isset($this->data[$this->position])) + { + $this->consumed .= $this->data[$this->position]; + return $this->data[$this->position++]; + } + else + { + $this->consumed = false; + return false; + } + } + + /** + * Consume a range of characters + * + * @access private + * @param string $chars Characters to consume + * @return mixed A series of characters that match the range, or false + */ + function consume_range($chars) + { + if ($len = strspn($this->data, $chars, $this->position)) + { + $data = substr($this->data, $this->position, $len); + $this->consumed .= $data; + $this->position += $len; + return $data; + } + else + { + $this->consumed = false; + return false; + } + } + + /** + * Unconsume one byte + * + * @access private + */ + function unconsume() + { + $this->consumed = substr($this->consumed, 0, -1); + $this->position--; + } + + /** + * Decode an entity + * + * @access private + */ + function entity() + { + switch ($this->consume()) + { + case "\x09": + case "\x0A": + case "\x0B": + case "\x0B": + case "\x0C": + case "\x20": + case "\x3C": + case "\x26": + case false: + break; + + case "\x23": + switch ($this->consume()) + { + case "\x78": + case "\x58": + $range = '0123456789ABCDEFabcdef'; + $hex = true; + break; + + default: + $range = '0123456789'; + $hex = false; + $this->unconsume(); + break; + } + + if ($codepoint = $this->consume_range($range)) + { + static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8"); + + if ($hex) + { + $codepoint = hexdec($codepoint); + } + else + { + $codepoint = intval($codepoint); + } + + if (isset($windows_1252_specials[$codepoint])) + { + $replacement = $windows_1252_specials[$codepoint]; + } + else + { + $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint); + } + + if ($this->consume() != ';') + { + $this->unconsume(); + } + + $consumed_length = strlen($this->consumed); + $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length); + $this->position += strlen($replacement) - $consumed_length; + } + break; + + default: + static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C"); + + for ($i = 0, $match = null; $i < 9 && $this->consume(); $i++) + { + $consumed = substr($this->consumed, 1); + if (isset($entities[$consumed])) + { + $match = $consumed; + } + } + + if ($match !== null) + { + $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1); + $this->position += strlen($entities[$match]) - strlen($consumed) - 1; + } + break; + } + } +} + +class SimplePie_Locator +{ + var $useragent; + var $timeout; + var $file; + var $local = array(); + var $elsewhere = array(); + var $file_class = 'SimplePie_File'; + var $cached_entities = array(); + var $http_base; + var $base; + var $base_location = 0; + var $checked_feeds = 0; + var $max_checked_feeds = 10; + + function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10) + { + $this->file =& $file; + $this->file_class = $file_class; + $this->useragent = $useragent; + $this->timeout = $timeout; + $this->max_checked_feeds = $max_checked_feeds; + } + + function find($type = SIMPLEPIE_LOCATOR_ALL) + { + if ($this->is_feed($this->file)) + { + return $this->file; + } + + if ($type & ~SIMPLEPIE_LOCATOR_NONE) + { + $this->get_base(); + } + + if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) + { + return $working; + } + + if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links()) + { + if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local)) + { + return $working; + } + + if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local)) + { + return $working; + } + + if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere)) + { + return $working; + } + + if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere)) + { + return $working; + } + } + return null; + } + + function is_feed(&$file) + { + $body = SimplePie_Misc::strip_comments($file->body); + if (preg_match('/<([^\s:]+:)?(rss|RDF|feed)' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/i', $body)) + { + return true; + } + return false; + } + + function get_base() + { + if (isset($this->file->headers['content-location'])) + { + $this->http_base = SimplePie_Misc::absolutize_url(trim($this->file->headers['content-location']), $this->file->url); + } + else + { + $this->http_base = $this->file->url; + } + $this->base = $this->http_base; + $elements = SimplePie_Misc::get_element('base', $this->file->body); + foreach ($elements as $element) + { + if ($element['attribs']['href']['data'] !== '') + { + $this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base); + $this->base_location = $element['offset']; + break; + } + } + } + + function autodiscovery() + { + $links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body)); + $done = array(); + foreach ($links as $link) + { + if ($this->checked_feeds == $this->max_checked_feeds) + { + break; + } + if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data'])) + { + $rel = array_unique(SimplePie_Misc::space_seperated_tokens(strtolower($link['attribs']['rel']['data']))); + + if ($this->base_location < $link['offset']) + { + $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base); + } + else + { + $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); + } + + if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml')))) + { + $this->checked_feeds++; + $feed =& new $this->file_class($href, $this->timeout, 5, null, $this->useragent); + if ($this->is_feed($feed)) + { + return $feed; + } + } + $done[] = $href; + } + } + return null; + } + + function get_links() + { + $links = SimplePie_Misc::get_element('a', $this->file->body); + foreach ($links as $link) + { + if (isset($link['attribs']['href']['data'])) + { + $href = trim($link['attribs']['href']['data']); + $parsed = SimplePie_Misc::parse_url($href); + if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme'])) + { + if ($this->base_location < $link['offset']) + { + $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base); + } + else + { + $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base); + } + + $current = SimplePie_Misc::parse_url($this->file->url); + + if ($parsed['authority'] === '' || $parsed['authority'] == $current['authority']) + { + $this->local[] = $href; + } + else + { + $this->elsewhere[] = $href; + } + } + } + } + $this->local = array_unique($this->local); + $this->elsewhere = array_unique($this->elsewhere); + if (!empty($this->local) || !empty($this->elsewhere)) + { + return true; + } + return null; + } + + function extension(&$array) + { + foreach ($array as $key => $value) + { + if ($this->checked_feeds == $this->max_checked_feeds) + { + break; + } + if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml'))) + { + $this->checked_feeds++; + $feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent); + if ($this->is_feed($feed)) + { + return $feed; + } + else + { + unset($array[$key]); + } + } + } + return null; + } + + function body(&$array) + { + foreach ($array as $key => $value) + { + if ($this->checked_feeds == $this->max_checked_feeds) + { + break; + } + if (preg_match('/(rss|rdf|atom|xml)/i', $value)) + { + $this->checked_feeds++; + $feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent); + if ($this->is_feed($feed)) + { + return $feed; + } + else + { + unset($array[$key]); + } + } + } + return null; + } +} + +class SimplePie_Parser +{ + var $xml; + var $error_code; + var $error_string; + var $current_line; + var $current_column; + var $current_byte; + var $separator = ' '; + var $feed = false; + var $namespace = array(''); + var $element = array(''); + var $xml_base = array(''); + var $xml_base_explicit = array(false); + var $xml_lang = array(''); + var $data = array(); + var $datas = array(array()); + var $current_xhtml_construct = -1; + var $encoding; + + function pre_process(&$data, $encoding) + { + // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character + if (strtoupper($encoding) == 'US-ASCII') + { + $this->encoding = 'UTF-8'; + } + else + { + $this->encoding = $encoding; + } + + // Strip BOM: + // UTF-32 Big Endian BOM + if (strpos($data, "\x0\x0\xFE\xFF") === 0) + { + $data = substr($data, 4); + } + // UTF-32 Little Endian BOM + elseif (strpos($data, "\xFF\xFE\x0\x0") === 0) + { + $data = substr($data, 4); + } + // UTF-16 Big Endian BOM + elseif (strpos($data, "\xFE\xFF") === 0) + { + $data = substr($data, 2); + } + // UTF-16 Little Endian BOM + elseif (strpos($data, "\xFF\xFE") === 0) + { + $data = substr($data, 2); + } + // UTF-8 BOM + elseif (strpos($data, "\xEF\xBB\xBF") === 0) + { + $data = substr($data, 3); + } + + // Make sure the XML prolog is sane and has the correct encoding + $data = preg_replace("/^<\?xml[\x20\x9\xD\xA]+version([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"1.0\"|'1.0'|\"1.1\"|'1.1')([\x20\x9\xD\xA]+encoding([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"[A-Za-z][A-Za-z0-9._\-]*\"|'[A-Za-z][A-Za-z0-9._\-]*'))?([\x20\x9\xD\xA]+standalone([\x20\x9\xD\xA]+)?=([\x20\x9\xD\xA]+)?(\"(yes|no)\"|'(yes|no)'))?([\x20\x9\xD\xA]+)?\?>/", '', $data); + $data = "\n" . $data; + } + + function parse(&$data) + { + $return = true; + + // Create the parser + $this->xml = xml_parser_create_ns($this->encoding, $this->separator); + xml_parser_set_option($this->xml, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->xml, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($this->xml, $this); + xml_set_character_data_handler($this->xml, 'cdata'); + xml_set_element_handler($this->xml, 'tag_open', 'tag_close'); + + // Parse! + if (!xml_parse($this->xml, $data, true)) + { + $this->data = null; + $this->error_code = xml_get_error_code($this->xml); + $this->error_string = xml_error_string($this->error_code); + $return = false; + } + $this->current_line = xml_get_current_line_number($this->xml); + $this->current_column = xml_get_current_column_number($this->xml); + $this->current_byte = xml_get_current_byte_index($this->xml); + xml_parser_free($this->xml); + return $return; + } + + function get_error_code() + { + return $this->error_code; + } + + function get_error_string() + { + return $this->error_string; + } + + function get_current_line() + { + return $this->current_line; + } + + function get_current_column() + { + return $this->current_column; + } + + function get_current_byte() + { + return $this->current_byte; + } + + function get_data() + { + return $this->data; + } + + function tag_open($parser, $tag, $attributes) + { + if ($this->feed === 0) + { + return; + } + elseif ($this->feed == false) + { + if (in_array($tag, array( + SIMPLEPIE_NAMESPACE_ATOM_10 . $this->separator . 'feed', + SIMPLEPIE_NAMESPACE_ATOM_03 . $this->separator . 'feed', + 'rss', + SIMPLEPIE_NAMESPACE_RDF . $this->separator . 'RDF' + ))) + { + $this->feed = 1; + } + } + else + { + $this->feed++; + } + + list($this->namespace[], $this->element[]) = $this->split_ns($tag); + + $attribs = array(); + foreach ($attributes as $name => $value) + { + list($attrib_namespace, $attribute) = $this->split_ns($name); + $attribs[$attrib_namespace][$attribute] = $value; + } + + if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base'])) + { + $this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)); + $this->xml_base_explicit[] = true; + } + else + { + $this->xml_base[] = end($this->xml_base); + $this->xml_base_explicit[] = end($this->xml_base_explicit); + } + + if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang'])) + { + $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang']; + } + else + { + $this->xml_lang[] = end($this->xml_lang); + } + + if ($this->current_xhtml_construct >= 0) + { + $this->current_xhtml_construct++; + if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML) + { + $this->data['data'] .= '<' . end($this->element); + if (isset($attribs[''])) + { + foreach ($attribs[''] as $name => $value) + { + $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"'; + } + } + $this->data['data'] .= '>'; + } + } + else + { + $this->datas[] =& $this->data; + $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][]; + $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang)); + if ((end($this->namespace) == SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] == 'xml') + || (end($this->namespace) == SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] == 'xhtml')) + { + $this->current_xhtml_construct = 0; + } + } + } + + function cdata($parser, $cdata) + { + if ($this->current_xhtml_construct >= 0) + { + $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding); + } + elseif ($this->feed > 1) + { + $this->data['data'] .= $cdata; + } + } + + function tag_close($parser, $tag) + { + if (!$this->feed) + { + return; + } + + if ($this->current_xhtml_construct >= 0) + { + $this->current_xhtml_construct--; + if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param'))) + { + $this->data['data'] .= 'element) . '>'; + } + } + if ($this->current_xhtml_construct == -1) + { + $this->data =& $this->datas[$this->feed]; + array_pop($this->datas); + } + + array_pop($this->element); + array_pop($this->namespace); + array_pop($this->xml_base); + array_pop($this->xml_base_explicit); + array_pop($this->xml_lang); + $this->feed--; + } + + function split_ns($string) + { + static $cache = array(); + if (!isset($cache[$string])) + { + if ($pos = strpos($string, $this->separator)) + { + static $separator_length; + if (!$separator_length) + { + $separator_length = strlen($this->separator); + } + $cache[$string] = array(substr($string, 0, $pos), substr($string, $pos + $separator_length)); + } + else + { + $cache[$string] = array('', $string); + } + } + return $cache[$string]; + } +} + +/** + * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shortern a string while preserving HTML tags + */ +class SimplePie_Sanitize +{ + // Private vars + var $base; + + // Options + var $remove_div = true; + var $image_handler = ''; + var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'); + var $encode_instead_of_strip = false; + var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); + var $strip_comments = false; + var $output_encoding = 'UTF-8'; + var $enable_cache = true; + var $cache_location = './cache'; + var $cache_name_function = 'md5'; + var $cache_class = 'SimplePie_Cache'; + var $file_class = 'SimplePie_File'; + var $timeout = 10; + var $useragent = ''; + var $force_fsockopen = false; + + var $replace_url_attributes = array( + 'a' => 'href', + 'area' => 'href', + 'blockquote' => 'cite', + 'del' => 'cite', + 'form' => 'action', + 'img' => array('longdesc', 'src'), + 'input' => 'src', + 'ins' => 'cite', + 'q' => 'cite' + ); + + function remove_div($enable = true) + { + $this->remove_div = (bool) $enable; + } + + function set_image_handler($page = false) + { + if ($page) + { + $this->image_handler = (string) $page; + } + else + { + $this->image_handler = false; + } + } + + function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache') + { + if (isset($enable_cache)) + { + $this->enable_cache = (bool) $enable_cache; + } + + if ($cache_location) + { + $this->cache_location = (string) $cache_location; + } + + if ($cache_name_function) + { + $this->cache_name_function = (string) $cache_name_function; + } + + if ($cache_class) + { + $this->cache_class = (string) $cache_class; + } + } + + function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false) + { + if ($file_class) + { + $this->file_class = (string) $file_class; + } + + if ($timeout) + { + $this->timeout = (string) $timeout; + } + + if ($useragent) + { + $this->useragent = (string) $useragent; + } + + if ($force_fsockopen) + { + $this->force_fsockopen = (string) $force_fsockopen; + } + } + + function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style')) + { + if ($tags) + { + if (is_array($tags)) + { + $this->strip_htmltags = $tags; + } + else + { + $this->strip_htmltags = explode(',', $tags); + } + } + else + { + $this->strip_htmltags = false; + } + } + + function encode_instead_of_strip($encode = false) + { + $this->encode_instead_of_strip = (bool) $encode; + } + + function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc')) + { + if ($attribs) + { + if (is_array($attribs)) + { + $this->strip_attributes = $attribs; + } + else + { + $this->strip_attributes = explode(',', $attribs); + } + } + else + { + $this->strip_attributes = false; + } + } + + function strip_comments($strip = false) + { + $this->strip_comments = (bool) $strip; + } + + function set_output_encoding($encoding = 'UTF-8') + { + $this->output_encoding = (string) $encoding; + } + + /** + * Set element/attribute key/value pairs of HTML attributes + * containing URLs that need to be resolved relative to the feed + * + * @access public + * @since 1.0 + * @param array $element_attribute Element/attribute key/value pairs + */ + function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite')) + { + $this->replace_url_attributes = (array) $element_attribute; + } + + function sanitize($data, $type, $base = '') + { + $data = trim($data); + if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI) + { + if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML) + { + if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/(\w+)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) + { + $type |= SIMPLEPIE_CONSTRUCT_HTML; + } + else + { + $type |= SIMPLEPIE_CONSTRUCT_TEXT; + } + } + + if ($type & SIMPLEPIE_CONSTRUCT_BASE64) + { + $data = base64_decode($data); + } + + if ($type & SIMPLEPIE_CONSTRUCT_XHTML) + { + if ($this->remove_div) + { + $data = preg_replace('/^/', '', $data); + $data = preg_replace('/<\/div>$/', '', $data); + } + else + { + $data = preg_replace('/^/', '
', $data); + } + } + + if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML)) + { + // Strip comments + if ($this->strip_comments) + { + $data = SimplePie_Misc::strip_comments($data); + } + + // Strip out HTML tags and attributes that might cause various security problems. + // Based on recommendations by Mark Pilgrim at: + // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely + if ($this->strip_htmltags) + { + foreach ($this->strip_htmltags as $tag) + { + $pcre = "/<($tag)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$tag" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>|(\/)?>)/siU'; + while (preg_match($pcre, $data)) + { + $data = preg_replace_callback($pcre, array(&$this, 'do_strip_htmltags'), $data); + } + } + } + + if ($this->strip_attributes) + { + foreach ($this->strip_attributes as $attrib) + { + $data = preg_replace('/ '. trim($attrib) .'=("|")(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|\'|'|<|>|\+|{|})*("|")/i', '', $data); + $data = preg_replace('/ '. trim($attrib) .'=(\'|')(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|"|"|<|>|\+|{|})*(\'|')/i', '', $data); + $data = preg_replace('/ '. trim($attrib) .'=(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|\+|{|})*/i', '', $data); + } + } + + // Replace relative URLs + $this->base = $base; + foreach ($this->replace_url_attributes as $element => $attributes) + { + $data = $this->replace_urls($data, $element, $attributes); + } + + // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags. + if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache) + { + $images = SimplePie_Misc::get_element('img', $data); + foreach ($images as $img) + { + if (isset($img['attribs']['src']['data'])) + { + $image_url = $img['attribs']['src']['data']; + $cache =& new $this->cache_class($this->cache_location, call_user_func($this->cache_name_function, $image_url), 'spi'); + + if ($cache->load()) + { + $img['attribs']['src']['data'] = $this->image_handler . rawurlencode($img['attribs']['src']['data']); + $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); + } + else + { + $file =& new $this->file_class($image_url, $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen); + $headers = $file->headers; + + if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300))) + { + if (!$cache->save(array('headers' => $file->headers, 'body' => $file->body))) + { + trigger_error("$cache->name is not writeable", E_USER_WARNING); + } + $img['attribs']['src']['data'] = $this->image_handler . rawurlencode($img['attribs']['src']['data']); + $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data); + } + } + } + } + } + + // Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data + $data = trim($data); + } + + if ($type & SIMPLEPIE_CONSTRUCT_IRI) + { + $data = SimplePie_Misc::absolutize_url($data, $base); + } + + if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI)) + { + $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); + } + + if ($this->output_encoding != 'UTF-8') + { + $data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding); + } + } + return $data; + } + + function replace_urls($data, $tag, $attributes) + { + if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags)) + { + $elements = SimplePie_Misc::get_element($tag, $data); + foreach ($elements as $element) + { + if (is_array($attributes)) + { + foreach ($attributes as $attribute) + { + if (isset($element['attribs'][$attribute]['data'])) + { + $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base); + $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data); + } + } + } + elseif (isset($element['attribs'][$attributes]['data'])) + { + $element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base); + $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data); + } + } + } + return $data; + } + + function do_strip_htmltags($match) + { + if ($this->encode_instead_of_strip) + { + if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) + { + $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8'); + $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8'); + return "<$match[1]$match[2]>$match[3]</$match[1]>"; + } + else + { + return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8'); + } + } + elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) + { + return $match[4]; + } + else + { + return ''; + } + } +} + +?> \ No newline at end of file diff --git a/simplepie/simplepie.patch b/simplepie/simplepie.patch new file mode 100644 index 0000000..96f843a --- /dev/null +++ b/simplepie/simplepie.patch @@ -0,0 +1,15 @@ +Index: simplepie.inc +=================================================================== +--- simplepie.inc (revision 810) ++++ simplepie.inc (working copy) +@@ -6495,6 +6495,10 @@ + curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects); + } ++ ++ // added by FoF to enable https and digest authentication ++ curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false); ++ curl_setopt($fp, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + + $this->headers = curl_exec($fp); + if (curl_errno($fp) == 23 || curl_errno($fp) == 61) diff --git a/uninstall.php b/uninstall.php new file mode 100644 index 0000000..343d76d --- /dev/null +++ b/uninstall.php @@ -0,0 +1,87 @@ + + + + + + feed on feeds - uninstallation + + + + + + + + + + + +phew! + + diff --git a/update-quiet.php b/update-quiet.php new file mode 100644 index 0000000..1cae51c --- /dev/null +++ b/update-quiet.php @@ -0,0 +1,60 @@ +prefs; + +fof_log("=== update started, timeout = $fof_admin_prefs[autotimeout], purge = $fof_admin_prefs[purge] ===", "update"); + +$result = fof_db_get_feeds(); + +$feeds = array(); + +while($feed = fof_db_get_row($result)) +{ + if((time() - $feed["feed_cache_date"]) > ($fof_admin_prefs["autotimeout"] * 60)) + { + $feeds[] = $feed; + } + else + { + fof_log("skipping $feed[feed_url]", "update"); + } +} + +$feeds = fof_multi_sort($feeds, 'feed_cache_attempt_date', false); + +foreach($feeds as $feed) +{ + $id = $feed['feed_id']; + fof_log("updating $feed[feed_url]", "update"); + fof_update_feed($id); +} + +fof_log("optimizing database", "update"); + +fof_db_optimize(); + +fof_log("=== update complete ===", "update"); + +ob_end_clean(); +?> diff --git a/update-single.php b/update-single.php new file mode 100644 index 0000000..eb00a4c --- /dev/null +++ b/update-single.php @@ -0,0 +1,35 @@ +$count new items"; +} + +if($error) +{ + print " $error
"; +} +else +{ + print " Done.
"; +} + +?> diff --git a/update.php b/update.php new file mode 100644 index 0000000..81f9018 --- /dev/null +++ b/update.php @@ -0,0 +1,73 @@ +"); + +$feed = $_GET['feed']; +$feeds = array(); + +$p =& FoF_Prefs::instance(); +$admin_prefs = $p->admin_prefs; + +if($feed) +{ + $feed = fof_db_get_feed_by_id($feed); + $feeds[] = $feed; +} +else +{ + if($fof_user_id == 1) + { + $result = fof_db_get_feeds(); + } + else + { + $result = fof_db_get_subscriptions(fof_current_user()); + } + while($feed = fof_db_get_row($result)) + { + if((time() - $feed["feed_cache_date"]) < ($admin_prefs["manualtimeout"] * 60)) + { + $title = $feed['feed_title']; + list($timestamp, ) = fof_nice_time_stamp($feed['feed_cache_date']); + + print "$title was just updated $timestamp!
"; + } + else + { + $feeds[] = $feed; + } + } +} + +$feeds = fof_multi_sort($feeds, 'feed_cache_attempt_date', false); + +print(""); + +include("footer.php"); +?> + diff --git a/view-action.php b/view-action.php new file mode 100644 index 0000000..a91ce03 --- /dev/null +++ b/view-action.php @@ -0,0 +1,53 @@ +