aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorplegall <plg@piwigo.org>2005-07-16 14:29:35 +0000
committerplegall <plg@piwigo.org>2005-07-16 14:29:35 +0000
commit9bafdff17166028ed7448487d0ca8a19f3c2fbb3 (patch)
tree331aec15d000a13451bb6fbc1cd1cb6beec0902d
parent315f9c5670b631fcc279c4d6ac00ae9386d67455 (diff)
- new feature : RSS notification feed. Feed generator is an external tool
(FeedCreator class v1.7.2). New file feed.php - new database field : comments.validation_date (datetime). This field is required for notification feed. - new database field : users.feed_id (varchar(50)). users.feed_id is an alias of users.id but is much more complicated to find (50 characters, figures or letters, case sensitive) : the purpose is to keep it secret (as far as possible). - new database field : users.last_feed_check (datetime) - new database field : users.registration_date (datetime) - bug fixed : no need to add the (unavailable) session id to install.php in the installation form. - modified database field : images.date_available become more precise (date to datetime). This precision is needed for notification feed. - new index : comments_i1 (validation_date). Might be useful for feed queries. - new index : comments_i2 (image_id). Useful each time you want to have informations about an element and its associated comments. - version 9.11 of mysqldump outputs database field names and table names with backquote "`" (didn't find how to take them off) git-svn-id: http://piwigo.org/svn/trunk@801 68402e56-0260-453c-a942-63ccdbb3a9ee
-rw-r--r--admin/picture_modify.php3
-rw-r--r--admin/remote_site.php3
-rw-r--r--admin/update.php4
-rw-r--r--category.php10
-rw-r--r--comments.php1
-rw-r--r--doc/ChangeLog33
-rw-r--r--feed.php445
-rw-r--r--include/config_default.inc.php4
-rw-r--r--include/feedcreator.class.php1541
-rw-r--r--include/functions_user.inc.php31
-rw-r--r--include/template.php5
-rw-r--r--install.php9
-rw-r--r--install/dbscheme.txt17
-rw-r--r--install/phpwebgallery_structure.sql382
-rw-r--r--picture.php36
15 files changed, 2312 insertions, 212 deletions
diff --git a/admin/picture_modify.php b/admin/picture_modify.php
index 64d6cf04b..532f5aeee 100644
--- a/admin/picture_modify.php
+++ b/admin/picture_modify.php
@@ -180,7 +180,8 @@ $template->assign_vars(array(
'NAME_IMG'=>isset($_POST['name'])?$_POST['name']:@$row['name'],
'SIZE_IMG'=>@$row['width'].' * '.@$row['height'],
'FILESIZE_IMG'=>@$row['filesize'].' KB',
- 'REGISTRATION_DATE_IMG'=> format_date($row['date_available']),
+ 'REGISTRATION_DATE_IMG'
+ => format_date($row['date_available'], 'mysql_datetime', true),
'AUTHOR_IMG'=>isset($_POST['author'])?$_POST['author']:@$row['author'],
'CREATION_DATE_IMG'=>$date,
'KEYWORDS_IMG'=>isset($_POST['keywords'])?$_POST['keywords']:@$row['keywords'],
diff --git a/admin/remote_site.php b/admin/remote_site.php
index ba8dc67ce..774358ddf 100644
--- a/admin/remote_site.php
+++ b/admin/remote_site.php
@@ -31,7 +31,8 @@ if (!defined('PHPWG_ROOT_PATH'))
}
include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
-define('CURRENT_DATE', date('Y-m-d'));
+list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+define('CURRENT_DATE', $dbnow);
// +-----------------------------------------------------------------------+
// | functions |
// +-----------------------------------------------------------------------+
diff --git a/admin/update.php b/admin/update.php
index bfc3236fc..b0e26a3f7 100644
--- a/admin/update.php
+++ b/admin/update.php
@@ -31,7 +31,9 @@ if (!defined('PHPWG_ROOT_PATH'))
}
include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
-define('CURRENT_DATE', date('Y-m-d'));
+list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+define('CURRENT_DATE', $dbnow);
+
$error_labels = array('PWG-UPDATE-1' => $lang['update_wrong_dirname_short'],
'PWG-UPDATE-2' => $lang['update_missing_tn_short']);
$errors = array();
diff --git a/category.php b/category.php
index 442f9dcb7..700ab652a 100644
--- a/category.php
+++ b/category.php
@@ -293,6 +293,16 @@ $template->assign_block_vars('summary', array(
'U_SUMMARY'=>add_session_id( 'about.php?'.str_replace( '&', '&amp;', $_SERVER['QUERY_STRING'] ) )
));
+// notification feed
+$template->assign_block_vars(
+ 'summary',
+ array(
+ 'TITLE'=>l10n('RSS notification feed'),
+ 'NAME'=>l10n('Notification feed'),
+ 'U_SUMMARY'=>
+ 'feed.php'.(ANONYMOUS != $user['id'] ? '?feed='.$user['feed_id'] : '')
+));
+
//------------------------------------------------------ main part : thumbnails
if (isset($page['cat'])
and ((is_numeric($page['cat']) and $page['cat_nb_images'] != 0)
diff --git a/comments.php b/comments.php
index ea1617479..115bf8572 100644
--- a/comments.php
+++ b/comments.php
@@ -157,6 +157,7 @@ if (isset($_POST['validate']) and count($_POST['comment_id']) > 0)
$query = '
UPDATE '.COMMENTS_TABLE.'
SET validated = \'true\'
+ , validation_date = NOW()
WHERE id IN ('.implode(',', $_POST['comment_id']).')
;';
pwg_query($query);
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 1242d166d..671fa5648 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,36 @@
+2005-06-16 Pierrick LE GALL
+
+ * new feature : RSS notification feed. Feed generator is an
+ external tool (FeedCreator class v1.7.2). New file feed.php
+
+ * new database field : comments.validation_date (datetime). This
+ field is required for notification feed.
+
+ * new database field : users.feed_id (varchar(50)). users.feed_id
+ is an alias of users.id but is much more complicated to find (50
+ characters, figures or letters, case sensitive) : the purpose is
+ to keep it secret (as far as possible).
+
+ * new database field : users.last_feed_check (datetime)
+
+ * new database field : users.registration_date (datetime)
+
+ * bug fixed : no need to add the (unavailable) session id to
+ install.php in the installation form.
+
+ * modified database field : images.date_available become more
+ precise (date to datetime). This precision is needed for
+ notification feed.
+
+ * new index : comments_i1 (validation_date). Might be useful for
+ feed queries.
+
+ * new index : comments_i2 (image_id). Useful each time you want to
+ have informations about an element and its associated comments.
+
+ * version 9.11 of mysqldump outputs database field names and table
+ names with backquote "`" (didn't find how to take them off)
+
2005-06-30 Pierrick LE GALL
* category permissions management comes back! (it disappeared in
diff --git a/feed.php b/feed.php
new file mode 100644
index 000000000..40c833e02
--- /dev/null
+++ b/feed.php
@@ -0,0 +1,445 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch : BSF (Best So Far)
+// | file : $RCSfile$
+// | last update : $Date$
+// | last modifier : $Author$
+// | revision : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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 |
+// | |
+// | 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. |
+// +-----------------------------------------------------------------------+
+
+define('PHPWG_ROOT_PATH','./');
+include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
+
+// +-----------------------------------------------------------------------+
+// | functions |
+// +-----------------------------------------------------------------------+
+
+/**
+ * new comments between two dates, according to authorized categories
+ *
+ * @param string start (mysql datetime format)
+ * @param string end (mysql datetime format)
+ * @param string forbidden categories (comma separated)
+ * @return array comment ids
+ */
+function new_comments($start, $end)
+{
+ global $user;
+
+ $query = '
+SELECT DISTINCT c.id AS comment_id
+ FROM '.COMMENTS_TABLE.' AS c
+ , '.IMAGE_CATEGORY_TABLE.' AS ic
+ WHERE c.image_id = ic.image_id
+ AND c.validation_date > \''.$start.'\'
+ AND c.validation_date <= \''.$end.'\'
+ AND category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+ return array_from_query($query, 'comment_id');
+}
+
+/**
+ * unvalidated at a precise date
+ *
+ * Comments that are registered and not validated yet on a precise date
+ *
+ * @param string date (mysql datetime format)
+ * @return array comment ids
+ */
+function unvalidated_comments($date)
+{
+ $query = '
+SELECT DISTINCT id
+ FROM '.COMMENTS_TABLE.'
+ WHERE date <= \''.$date.'\'
+ AND (validated = \'false\'
+ OR validation_date > \''.$date.'\')
+;';
+ return array_from_query($query, 'id');
+}
+
+/**
+ * new elements between two dates, according to authorized categories
+ *
+ * @param string start (mysql datetime format)
+ * @param string end (mysql datetime format)
+ * @param string forbidden categories (comma separated)
+ * @return array element ids
+ */
+function new_elements($start, $end)
+{
+ global $user;
+
+ $query = '
+SELECT DISTINCT image_id
+ FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON image_id = id
+ WHERE date_available > \''.$start.'\'
+ AND date_available <= \''.$end.'\'
+ AND category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+ return array_from_query($query, 'image_id');
+}
+
+/**
+ * updated categories between two dates, according to authorized categories
+ *
+ * @param string start (mysql datetime format)
+ * @param string end (mysql datetime format)
+ * @param string forbidden categories (comma separated)
+ * @return array element ids
+ */
+function updated_categories($start, $end)
+{
+ global $user;
+
+ $query = '
+SELECT DISTINCT category_id
+ FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON image_id = id
+ WHERE date_available > \''.$start.'\'
+ AND date_available <= \''.$end.'\'
+ AND category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+ return array_from_query($query, 'category_id');
+}
+
+/**
+ * new registered users between two dates
+ *
+ * @param string start (mysql datetime format)
+ * @param string end (mysql datetime format)
+ * @return array user ids
+ */
+function new_users($start, $end)
+{
+ $query = '
+SELECT id
+ FROM '.USERS_TABLE.'
+ WHERE registration_date > \''.$start.'\'
+ AND registration_date <= \''.$end.'\'
+;';
+ return array_from_query($query, 'id');
+}
+
+/**
+ * What's new between two dates ?
+ *
+ * Informations : number of new comments, number of new elements, number of
+ * updated categories. Administrators are also informed about : number of
+ * unvalidated comments, number of new users (TODO : number of unvalidated
+ * elements)
+ *
+ * @param string start date (mysql datetime format)
+ * @param string end date (mysql datetime format)
+ */
+function news($start, $end)
+{
+ global $user;
+
+ $news = array();
+
+ $nb_new_comments = count(new_comments($start, $end));
+ if ($nb_new_comments > 0)
+ {
+ array_push($news, sprintf(l10n('%d new comments'), $nb_new_comments));
+ }
+
+ $nb_new_elements = count(new_elements($start, $end));
+ if ($nb_new_elements > 0)
+ {
+ array_push($news, sprintf(l10n('%d new elements'), $nb_new_elements));
+ }
+
+ $nb_updated_categories = count(updated_categories($start, $end));
+ if ($nb_updated_categories > 0)
+ {
+ array_push($news, sprintf(l10n('%d categories updated'),
+ $nb_updated_categories));
+ }
+
+ if ('admin' == $user['status'])
+ {
+ $nb_unvalidated_comments = count(unvalidated_comments($end));
+ if ($nb_unvalidated_comments > 0)
+ {
+ array_push($news, sprintf(l10n('%d comments to validate'),
+ $nb_unvalidated_comments));
+ }
+
+ $nb_new_users = count(new_users($start, $end));
+ if ($nb_new_users > 0)
+ {
+ array_push($news, sprintf(l10n('%d new users'), $nb_new_users));
+ }
+ }
+
+ return $news;
+}
+
+/**
+ * explodes a MySQL datetime format (2005-07-14 23:01:37) in fields "year",
+ * "month", "day", "hour", "minute", "second".
+ *
+ * @param string mysql datetime format
+ * @return array
+ */
+function explode_mysqldt($mysqldt)
+{
+ $date = array();
+ list($date['year'],
+ $date['month'],
+ $date['day'],
+ $date['hour'],
+ $date['minute'],
+ $date['second'])
+ = preg_split('/[-: ]/', $mysqldt);
+
+ return $date;
+}
+
+/**
+ * creates a MySQL datetime format (2005-07-14 23:01:37) from a Unix
+ * timestamp (number of seconds since 1970-01-01 00:00:00 GMT)
+ *
+ * @param int unix timestamp
+ * @return string mysql datetime format
+ */
+function ts_to_mysqldt($ts)
+{
+ return date('Y-m-d H:i:s', $ts);
+}
+
+/**
+ * creates a Unix timestamp (number of seconds since 1970-01-01 00:00:00
+ * GMT) from a MySQL datetime format (2005-07-14 23:01:37)
+ *
+ * @param string mysql datetime format
+ * @return int timestamp
+ */
+function mysqldt_to_ts($mysqldt)
+{
+ $date = explode_mysqldt($mysqldt);
+ return mktime($date['hour'], $date['minute'], $date['second'],
+ $date['month'], $date['day'], $date['year']);
+}
+
+/**
+ * creates an ISO 8601 format date (2003-01-20T18:05:41+04:00) from Unix
+ * timestamp (number of seconds since 1970-01-01 00:00:00 GMT)
+ *
+ * function copied from Dotclear project http://dotclear.net
+ *
+ * @param int timestamp
+ * @return string ISO 8601 date format
+ */
+function ts_to_iso8601($ts)
+{
+ $tz = date('O',$ts);
+ $tz = substr($tz, 0, -2).':'.substr($tz, -2);
+ return date('Y-m-d\\TH:i:s',$ts).$tz;
+}
+
+// +-----------------------------------------------------------------------+
+// | initialization |
+// +-----------------------------------------------------------------------+
+
+// clean $user array (include/user.inc.php has been executed)
+$user = array();
+
+// echo '<pre>'.generate_key(50).'</pre>';
+if (isset($_GET['feed'])
+ and preg_match('/^[A-Za-z0-9]{50}$/', $_GET['feed']))
+{
+ $query = '
+SELECT id, status, last_feed_check
+ FROM '.USERS_TABLE.'
+ WHERE feed_id = \''.$_GET['feed'].'\'
+;';
+ $user = mysql_fetch_array(pwg_query($query));
+}
+else
+{
+ $user = array('id' => ANONYMOUS,
+ 'status' => 'guest');
+}
+
+$user['forbidden_categories'] = calculate_permissions($user['id'],
+ $user['status']);
+if ('' == $user['forbidden_categories'])
+{
+ $user['forbidden_categories'] = '-1';
+}
+
+list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+
+include_once(PHPWG_ROOT_PATH.'include/feedcreator.class.php');
+
+$rss = new UniversalFeedCreator();
+// $rss->useCached(); // use cached version if age<1 hour
+$rss->title = 'PhpWebGallery notifications';
+$rss->link = 'http://phpwebgallery.net';
+
+// +-----------------------------------------------------------------------+
+// | Feed creation |
+// +-----------------------------------------------------------------------+
+
+if (ANONYMOUS != $user['id'])
+{
+ $news = news($user['last_feed_check'], $dbnow);
+
+ if (count($news) > 0)
+ {
+ // echo '<pre>';
+ // print_r($news);
+ // echo '</pre>';
+
+ $item = new FeedItem();
+ $item->title = sprintf(l10n('New on %s'), $dbnow);
+ $item->link = 'http://phpwebgallery.net';
+
+ // content creation
+ $item->description = '<ul>';
+ foreach ($news as $line)
+ {
+ $item->description.= '<li>'.$line.'</li>';
+ }
+ $item->description.= '</ul>';
+ $item->descriptionHtmlSyndicated = true;
+
+ $item->date = $dbnow;
+ $item->author = 'PhpWebGallery notifier';
+
+ $rss->addItem($item);
+ }
+
+ $query = '
+UPDATE '.USERS_TABLE.'
+ SET last_feed_check = \''.$dbnow.'\'
+ WHERE id = '.$user['id'].'
+;';
+ pwg_query($query);
+}
+else
+{
+ // The feed is filled with periodical blocks of informations. Date
+ // "checkpoints" cut the blocks. The first step is to find those
+ // checkpoints according to the configured feed period.
+ //
+ // checkpoints are first calculated in Unix timestamp (number of seconds
+ // since 1970-01-01 00:00:00 GMT) and then converted to MySQL datetime
+ // format.
+
+ $now = explode_mysqldt($dbnow);
+
+ $checkpoints = array();
+ $checkpoints[0] = mysqldt_to_ts($dbnow);
+
+ // if the feed period was not configured the right way (ie among the list
+ // of possible values), the configuration is overloaded here.
+ if (!in_array($conf['feed_period'],
+ array('hour', 'half day', 'day', 'week', 'month')))
+ {
+ $conf['feed_period'] = 'week';
+ }
+
+ // foreach feed_period possible, we need to find the beginning of the
+ // current period. The variable $timeshift contains the shift to apply to
+ // each checkpoint to find the previous one with strtotime function
+ switch ($conf['feed_period'])
+ {
+ // 2005-07-14 23:36:19 => 2005-07-14 23:00:00
+ case 'hour' :
+ {
+ $checkpoints[1] = mktime($now['hour'],0,0,
+ $now['month'],$now['day'],$now['year']);
+ $timeshift = '1 hour ago';
+ break;
+ }
+ // 2005-07-14 23:36:19 => 2005-07-14 12:00:00
+ case 'half day' :
+ {
+ $checkpoints[1] = mktime(($now['hour'] < 12) ? 0 : 12,0,0,
+ $now['month'],$now['day'],$now['year']);
+ $timeshift = '12 hours ago';
+ break;
+ }
+ // 2005-07-14 23:36:19 => 2005-07-14 00:00:00
+ case 'day' :
+ {
+ $checkpoints[1] = mktime(0,0,0,$now['month'],$now['day'],$now['year']);
+ $timeshift = '1 day ago';
+ break;
+ }
+ // 2005-07-14 23:36:19 => 2005-07-11 00:00:00
+ case 'week' :
+ {
+ $checkpoints[1] = strtotime('last monday', $checkpoints[0]);
+ $timeshift = '1 week ago';
+ break;
+ }
+ // 2005-07-14 23:36:19 => 2005-07-01 00:00:00
+ case 'month' :
+ {
+ $checkpoints[1] = mktime(0,0,0,$now['month'],1,$now['year']);
+ $timeshift = '1 month ago';
+ break;
+ }
+ }
+
+ for ($i = 2; $i <= 11; $i++)
+ {
+ $checkpoints[$i] = strtotime($timeshift, $checkpoints[$i-1]);
+ }
+
+ // converts all timestamp values to MySQL datetime format
+ $checkpoints = array_map('ts_to_mysqldt', $checkpoints);
+
+ for ($i = 1; $i <= max(array_keys($checkpoints)); $i++)
+ {
+ $news = news($checkpoints[$i], $checkpoints[$i-1]);
+
+ if (count($news) > 0)
+ {
+ $item = new FeedItem();
+ $item->title = sprintf(l10n('New from %s to %s'),
+ $checkpoints[$i],
+ $checkpoints[$i-1]);
+ $item->link = 'http://phpwebgallery.net';
+
+ // content creation
+ $item->description = '<ul>';
+ foreach ($news as $line)
+ {
+ $item->description.= '<li>'.$line.'</li>';
+ }
+ $item->description.= '</ul>';
+ $item->descriptionHtmlSyndicated = true;
+
+ $item->date = ts_to_iso8601(mysqldt_to_ts($checkpoints[$i-1]));
+ $item->author = 'PhpWebGallery notifier';
+
+ $rss->addItem($item);
+ }
+ }
+}
+
+// send XML feed
+echo $rss->saveFeed('RSS2.0', '', true);
+?> \ No newline at end of file
diff --git a/include/config_default.inc.php b/include/config_default.inc.php
index 799e6d934..4ef5608c9 100644
--- a/include/config_default.inc.php
+++ b/include/config_default.inc.php
@@ -212,4 +212,8 @@ $conf['show_version'] = true;
// If the array is empty, the "Links" box won't be displayed on the main
// page.
$conf['links'] = array();
+
+// feed_period : how long between two feed refresh ? Possible values are
+// "hour", "half day", "day", "week", "month".
+$conf['feed_period'] = 'week';
?>
diff --git a/include/feedcreator.class.php b/include/feedcreator.class.php
new file mode 100644
index 000000000..da4825b18
--- /dev/null
+++ b/include/feedcreator.class.php
@@ -0,0 +1,1541 @@
+<?php
+/***************************************************************************
+
+FeedCreator class v1.7.2
+originally (c) Kai Blankenhorn
+www.bitfolge.de
+kaib@bitfolge.de
+v1.3 work by Scott Reynen (scott@randomchaos.com) and Kai Blankenhorn
+v1.5 OPML support by Dirk Clemens
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+****************************************************************************
+
+
+Changelog:
+
+v1.7.2 10-11-04
+ license changed to LGPL
+
+v1.7.1
+ fixed a syntax bug
+ fixed left over debug code
+
+v1.7 07-18-04
+ added HTML and JavaScript feeds (configurable via CSS) (thanks to Pascal Van Hecke)
+ added HTML descriptions for all feed formats (thanks to Pascal Van Hecke)
+ added a switch to select an external stylesheet (thanks to Pascal Van Hecke)
+ changed default content-type to application/xml
+ added character encoding setting
+ fixed numerous smaller bugs (thanks to Sören Fuhrmann of golem.de)
+ improved changing ATOM versions handling (thanks to August Trometer)
+ improved the UniversalFeedCreator's useCached method (thanks to Sören Fuhrmann of golem.de)
+ added charset output in HTTP headers (thanks to Sören Fuhrmann of golem.de)
+ added Slashdot namespace to RSS 1.0 (thanks to Sören Fuhrmann of golem.de)
+
+v1.6 05-10-04
+ added stylesheet to RSS 1.0 feeds
+ fixed generator comment (thanks Kevin L. Papendick and Tanguy Pruvot)
+ fixed RFC822 date bug (thanks Tanguy Pruvot)
+ added TimeZone customization for RFC8601 (thanks Tanguy Pruvot)
+ fixed Content-type could be empty (thanks Tanguy Pruvot)
+ fixed author/creator in RSS1.0 (thanks Tanguy Pruvot)
+
+v1.6 beta 02-28-04
+ added Atom 0.3 support (not all features, though)
+ improved OPML 1.0 support (hopefully - added more elements)
+ added support for arbitrary additional elements (use with caution)
+ code beautification :-)
+ considered beta due to some internal changes
+
+v1.5.1 01-27-04
+ fixed some RSS 1.0 glitches (thanks to Stéphane Vanpoperynghe)
+ fixed some inconsistencies between documentation and code (thanks to Timothy Martin)
+
+v1.5 01-06-04
+ added support for OPML 1.0
+ added more documentation
+
+v1.4 11-11-03
+ optional feed saving and caching
+ improved documentation
+ minor improvements
+
+v1.3 10-02-03
+ renamed to FeedCreator, as it not only creates RSS anymore
+ added support for mbox
+ tentative support for echo/necho/atom/pie/???
+
+v1.2 07-20-03
+ intelligent auto-truncating of RSS 0.91 attributes
+ don't create some attributes when they're not set
+ documentation improved
+ fixed a real and a possible bug with date conversions
+ code cleanup
+
+v1.1 06-29-03
+ added images to feeds
+ now includes most RSS 0.91 attributes
+ added RSS 2.0 feeds
+
+v1.0 06-24-03
+ initial release
+
+
+
+***************************************************************************/
+
+/*** GENERAL USAGE *********************************************************
+
+include("feedcreator.class.php");
+
+$rss = new UniversalFeedCreator();
+$rss->useCached(); // use cached version if age<1 hour
+$rss->title = "PHP news";
+$rss->description = "daily news from the PHP scripting world";
+
+//optional
+$rss->descriptionTruncSize = 500;
+$rss->descriptionHtmlSyndicated = true;
+
+$rss->link = "http://www.dailyphp.net/news";
+$rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"];
+
+$image = new FeedImage();
+$image->title = "dailyphp.net logo";
+$image->url = "http://www.dailyphp.net/images/logo.gif";
+$image->link = "http://www.dailyphp.net";
+$image->description = "Feed provided by dailyphp.net. Click to visit.";
+
+//optional
+$image->descriptionTruncSize = 500;
+$image->descriptionHtmlSyndicated = true;
+
+$rss->image = $image;
+
+// get your news items from somewhere, e.g. your database:
+mysql_select_db($dbHost, $dbUser, $dbPass);
+$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");
+while ($data = mysql_fetch_object($res)) {
+ $item = new FeedItem();
+ $item->title = $data->title;
+ $item->link = $data->url;
+ $item->description = $data->short;
+
+ //optional
+ item->descriptionTruncSize = 500;
+ item->descriptionHtmlSyndicated = true;
+
+ $item->date = $data->newsdate;
+ $item->source = "http://www.dailyphp.net";
+ $item->author = "John Doe";
+
+ $rss->addItem($item);
+}
+
+// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated),
+// MBOX, OPML, ATOM, ATOM0.3, HTML, JS
+echo $rss->saveFeed("RSS1.0", "news/feed.xml");
+
+
+***************************************************************************
+* A little setup *
+**************************************************************************/
+
+// your local timezone, set to "" to disable or for GMT
+define("TIME_ZONE","+01:00");
+
+
+
+
+/**
+ * Version string.
+ **/
+define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2");
+
+
+
+/**
+ * A FeedItem is a part of a FeedCreator feed.
+ *
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ * @since 1.3
+ */
+class FeedItem extends HtmlDescribable {
+ /**
+ * Mandatory attributes of an item.
+ */
+ var $title, $description, $link;
+
+ /**
+ * Optional attributes of an item.
+ */
+ var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator;
+
+ /**
+ * Publishing date of an item. May be in one of the following formats:
+ *
+ * RFC 822:
+ * "Mon, 20 Jan 03 18:05:41 +0400"
+ * "20 Jan 03 18:05:41 +0000"
+ *
+ * ISO 8601:
+ * "2003-01-20T18:05:41+04:00"
+ *
+ * Unix:
+ * 1043082341
+ */
+ var $date;
+
+ /**
+ * Any additional elements to include as an assiciated array. All $key => $value pairs
+ * will be included unencoded in the feed item in the form
+ * <$key>$value</$key>
+ * Again: No encoding will be used! This means you can invalidate or enhance the feed
+ * if $value contains markup. This may be abused to embed tags not implemented by
+ * the FeedCreator class used.
+ */
+ var $additionalElements = Array();
+
+ // on hold
+ // var $source;
+}
+
+
+
+/**
+ * An FeedImage may be added to a FeedCreator feed.
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ * @since 1.3
+ */
+class FeedImage extends HtmlDescribable {
+ /**
+ * Mandatory attributes of an image.
+ */
+ var $title, $url, $link;
+
+ /**
+ * Optional attributes of an image.
+ */
+ var $width, $height, $description;
+}
+
+
+
+/**
+ * An HtmlDescribable is an item within a feed that can have a description that may
+ * include HTML markup.
+ */
+class HtmlDescribable {
+ /**
+ * Indicates whether the description field should be rendered in HTML.
+ */
+ var $descriptionHtmlSyndicated;
+
+ /**
+ * Indicates whether and to how many characters a description should be truncated.
+ */
+ var $descriptionTruncSize;
+
+ /**
+ * Returns a formatted description field, depending on descriptionHtmlSyndicated and
+ * $descriptionTruncSize properties
+ * @return string the formatted description
+ */
+ function getDescription() {
+ $descriptionField = new FeedHtmlField($this->description);
+ $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated;
+ $descriptionField->truncSize = $this->descriptionTruncSize;
+ return $descriptionField->output();
+ }
+
+}
+
+
+/**
+ * An FeedHtmlField describes and generates
+ * a feed, item or image html field (probably a description). Output is
+ * generated based on $truncSize, $syndicateHtml properties.
+ * @author Pascal Van Hecke <feedcreator.class.php@vanhecke.info>
+ * @version 1.6
+ */
+class FeedHtmlField {
+ /**
+ * Mandatory attributes of a FeedHtmlField.
+ */
+ var $rawFieldContent;
+
+ /**
+ * Optional attributes of a FeedHtmlField.
+ *
+ */
+ var $truncSize, $syndicateHtml;
+
+ /**
+ * Creates a new instance of FeedHtmlField.
+ * @param $string: if given, sets the rawFieldContent property
+ */
+ function FeedHtmlField($parFieldContent) {
+ if ($parFieldContent) {
+ $this->rawFieldContent = $parFieldContent;
+ }
+ }
+
+
+ /**
+ * Creates the right output, depending on $truncSize, $syndicateHtml properties.
+ * @return string the formatted field
+ */
+ function output() {
+ // when field available and syndicated in html we assume
+ // - valid html in $rawFieldContent and we enclose in CDATA tags
+ // - no truncation (truncating risks producing invalid html)
+ if (!$this->rawFieldContent) {
+ $result = "";
+ } elseif ($this->syndicateHtml) {
+ $result = "<![CDATA[".$this->rawFieldContent."]]>";
+ } else {
+ if ($this->truncSize and is_int($this->truncSize)) {
+ $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize);
+ } else {
+ $result = htmlspecialchars($this->rawFieldContent);
+ }
+ }
+ return $result;
+ }
+
+}
+
+
+
+/**
+ * UniversalFeedCreator lets you choose during runtime which
+ * format to build.
+ * For general usage of a feed class, see the FeedCreator class
+ * below or the example above.
+ *
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class UniversalFeedCreator extends FeedCreator {
+ var $_feed;
+
+ function _setFormat($format) {
+ switch (strtoupper($format)) {
+
+ case "2.0":
+ // fall through
+ case "RSS2.0":
+ $this->_feed = new RSSCreator20();
+ break;
+
+ case "1.0":
+ // fall through
+ case "RSS1.0":
+ $this->_feed = new RSSCreator10();
+ break;
+
+ case "0.91":
+ // fall through
+ case "RSS0.91":
+ $this->_feed = new RSSCreator091();
+ break;
+
+ case "PIE0.1":
+ $this->_feed = new PIECreator01();
+ break;
+
+ case "MBOX":
+ $this->_feed = new MBOXCreator();
+ break;
+
+ case "OPML":
+ $this->_feed = new OPMLCreator();
+ break;
+
+ case "ATOM":
+ // fall through: always the latest ATOM version
+
+ case "ATOM0.3":
+ $this->_feed = new AtomCreator03();
+ break;
+
+ case "HTML":
+ $this->_feed = new HTMLCreator();
+ break;
+
+ case "JS":
+ // fall through
+ case "JAVASCRIPT":
+ $this->_feed = new JSCreator();
+ break;
+
+ default:
+ $this->_feed = new RSSCreator091();
+ break;
+ }
+
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself
+ if (!in_array($key, array("_feed", "contentType", "encoding"))) {
+ $this->_feed->{$key} = $this->{$key};
+ }
+ }
+ }
+
+ /**
+ * Creates a syndication feed based on the items previously added.
+ *
+ * @see FeedCreator::addItem()
+ * @param string format format the feed should comply to. Valid values are:
+ * "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS"
+ * @return string the contents of the feed.
+ */
+ function createFeed($format = "RSS0.91") {
+ $this->_setFormat($format);
+ return $this->_feed->createFeed();
+ }
+
+
+
+ /**
+ * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect
+ * header may be sent to redirect the use to the newly created file.
+ * @since 1.4
+ *
+ * @param string format format the feed should comply to. Valid values are:
+ * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS"
+ * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
+ * @param boolean displayContents optional send the content of the file or not. If true, the file will be sent in the body of the response.
+ */
+ function saveFeed($format="RSS0.91", $filename="", $displayContents=true) {
+ $this->_setFormat($format);
+ $this->_feed->saveFeed($filename, $displayContents);
+ }
+
+
+ /**
+ * Turns on caching and checks if there is a recent version of this feed in the cache.
+ * If there is, an HTTP redirect header is sent.
+ * To effectively use caching, you should create the FeedCreator object and call this method
+ * before anything else, especially before you do the time consuming task to build the feed
+ * (web fetching, for example).
+ *
+ * @param string format format the feed should comply to. Valid values are:
+ * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3".
+ * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
+ * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
+ */
+ function useCached($format="RSS0.91", $filename="", $timeout=3600) {
+ $this->_setFormat($format);
+ $this->_feed->useCached($filename, $timeout);
+ }
+
+}
+
+
+/**
+ * FeedCreator is the abstract base implementation for concrete
+ * implementations that implement a specific format of syndication.
+ *
+ * @abstract
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ * @since 1.4
+ */
+class FeedCreator extends HtmlDescribable {
+
+ /**
+ * Mandatory attributes of a feed.
+ */
+ var $title, $description, $link;
+
+
+ /**
+ * Optional attributes of a feed.
+ */
+ var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays;
+
+ /**
+ * The url of the external xsl stylesheet used to format the naked rss feed.
+ * Ignored in the output when empty.
+ */
+ var $xslStyleSheet = "";
+
+
+ /**
+ * @access private
+ */
+ var $items = Array();
+
+
+ /**
+ * This feed's MIME content type.
+ * @since 1.4
+ * @access private
+ */
+ var $contentType = "application/xml";
+
+
+ /**
+ * This feed's character encoding.
+ * @since 1.6.1
+ **/
+ var $encoding = "ISO-8859-1";
+
+
+ /**
+ * Any additional elements to include as an assiciated array. All $key => $value pairs
+ * will be included unencoded in the feed in the form
+ * <$key>$value</$key>
+ * Again: No encoding will be used! This means you can invalidate or enhance the feed
+ * if $value contains markup. This may be abused to embed tags not implemented by
+ * the FeedCreator class used.
+ */
+ var $additionalElements = Array();
+
+
+ /**
+ * Adds an FeedItem to the feed.
+ *
+ * @param object FeedItem $item The FeedItem to add to the feed.
+ * @access public
+ */
+ function addItem($item) {
+ $this->items[] = $item;
+ }
+
+
+ /**
+ * Truncates a string to a certain length at the most sensible point.
+ * First, if there's a '.' character near the end of the string, the string is truncated after this character.
+ * If there is no '.', the string is truncated after the last ' ' character.
+ * If the string is truncated, " ..." is appended.
+ * If the string is already shorter than $length, it is returned unchanged.
+ *
+ * @static
+ * @param string string A string to be truncated.
+ * @param int length the maximum length the string should be truncated to
+ * @return string the truncated string
+ */
+ function iTrunc($string, $length) {
+ if (strlen($string)<=$length) {
+ return $string;
+ }
+
+ $pos = strrpos($string,".");
+ if ($pos>=$length-4) {
+ $string = substr($string,0,$length-4);
+ $pos = strrpos($string,".");
+ }
+ if ($pos>=$length*0.4) {
+ return substr($string,0,$pos+1)." ...";
+ }
+
+ $pos = strrpos($string," ");
+ if ($pos>=$length-4) {
+ $string = substr($string,0,$length-4);
+ $pos = strrpos($string," ");
+ }
+ if ($pos>=$length*0.4) {
+ return substr($string,0,$pos)." ...";
+ }
+
+ return substr($string,0,$length-4)." ...";
+
+ }
+
+
+ /**
+ * Creates a comment indicating the generator of this feed.
+ * The format of this comment seems to be recognized by
+ * Syndic8.com.
+ */
+ function _createGeneratorComment() {
+ return "<!-- generator=\"".FEEDCREATOR_VERSION."\" -->\n";
+ }
+
+
+ /**
+ * Creates a string containing all additional elements specified in
+ * $additionalElements.
+ * @param elements array an associative array containing key => value pairs
+ * @param indentString string a string that will be inserted before every generated line
+ * @return string the XML tags corresponding to $additionalElements
+ */
+ function _createAdditionalElements($elements, $indentString="") {
+ $ae = "";
+ if (is_array($elements)) {
+ foreach($elements AS $key => $value) {
+ $ae.= $indentString."<$key>$value</$key>\n";
+ }
+ }
+ return $ae;
+ }
+
+ function _createStylesheetReferences() {
+ $xml = "";
+ if (isset($this->cssStyleSheet)) $xml .= "<?xml-stylesheet href=\"".$this->cssStyleSheet."\" type=\"text/css\"?>\n";
+ if ($this->xslStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->xslStyleSheet."\" type=\"text/xsl\"?>\n";
+ return $xml;
+ }
+
+
+ /**
+ * Builds the feed's text.
+ * @abstract
+ * @return string the feed's complete text
+ */
+ function createFeed() {
+ }
+
+ /**
+ * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml.
+ * For example:
+ *
+ * echo $_SERVER["PHP_SELF"]."\n";
+ * echo FeedCreator::_generateFilename();
+ *
+ * would produce:
+ *
+ * /rss/latestnews.php
+ * latestnews.xml
+ *
+ * @return string the feed cache filename
+ * @since 1.4
+ * @access private
+ */
+ function _generateFilename() {
+ $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
+ return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml";
+ }
+
+
+ /**
+ * @since 1.4
+ * @access private
+ */
+ function _redirect($filename) {
+ // attention, heavily-commented-out-area
+
+ // maybe use this in addition to file time checking
+ //Header("Expires: ".date("r",time()+$this->_timeout));
+
+ /* no caching at all, doesn't seem to work as good:
+ Header("Cache-Control: no-cache");
+ Header("Pragma: no-cache");
+ */
+
+ // HTTP redirect, some feed readers' simple HTTP implementations don't follow it
+ //Header("Location: ".$filename);
+
+ Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename));
+ Header("Content-Disposition: inline; filename=".basename($filename));
+ readfile($filename, "r");
+ die();
+ }
+
+ /**
+ * Turns on caching and checks if there is a recent version of this feed in the cache.
+ * If there is, an HTTP redirect header is sent.
+ * To effectively use caching, you should create the FeedCreator object and call this method
+ * before anything else, especially before you do the time consuming task to build the feed
+ * (web fetching, for example).
+ * @since 1.4
+ * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
+ * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
+ */
+ function useCached($filename="", $timeout=3600) {
+ $this->_timeout = $timeout;
+ if ($filename=="") {
+ $filename = $this->_generateFilename();
+ }
+ if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) {
+ $this->_redirect($filename);
+ }
+ }
+
+
+ /**
+ * Saves this feed as a file on the local disk. After the file is saved, a redirect
+ * header may be sent to redirect the user to the newly created file.
+ * @since 1.4
+ *
+ * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
+ * @param redirect boolean optional send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file.
+ */
+ function saveFeed($filename="", $displayContents=true) {
+ if ($filename=="") {
+ $filename = $this->_generateFilename();
+ }
+ $feedFile = fopen($filename, "w+");
+ if ($feedFile) {
+ fputs($feedFile,$this->createFeed());
+ fclose($feedFile);
+ if ($displayContents) {
+ $this->_redirect($filename);
+ }
+ } else {
+ echo "<br /><b>Error creating feed file, please check write permissions.</b><br />";
+ }
+ }
+
+}
+
+
+/**
+ * FeedDate is an internal class that stores a date for a feed or feed item.
+ * Usually, you won't need to use this.
+ */
+class FeedDate {
+ var $unix;
+
+ /**
+ * Creates a new instance of FeedDate representing a given date.
+ * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps.
+ * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used.
+ */
+ function FeedDate($dateString="") {
+ if ($dateString=="") $dateString = date("r");
+
+ if (is_integer($dateString)) {
+ $this->unix = $dateString;
+ return;
+ }
+ if (preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?(\\d{1,2})\\s+([a-zA-Z]{3})\\s+(\\d{4})\\s+(\\d{2}):(\\d{2}):(\\d{2})\\s+(.*)~",$dateString,$matches)) {
+ $months = Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12);
+ $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]);
+ if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
+ $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
+ } else {
+ if (strlen($matches[7])==1) {
+ $oneHour = 3600;
+ $ord = ord($matches[7]);
+ if ($ord < ord("M")) {
+ $tzOffset = (ord("A") - $ord - 1) * $oneHour;
+ } elseif ($ord >= ord("M") AND $matches[7]!="Z") {
+ $tzOffset = ($ord - ord("M")) * $oneHour;
+ } elseif ($matches[7]=="Z") {
+ $tzOffset = 0;
+ }
+ }
+ switch ($matches[7]) {
+ case "UT":
+ case "GMT": $tzOffset = 0;
+ }
+ }
+ $this->unix += $tzOffset;
+ return;
+ }
+ if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) {
+ $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
+ if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
+ $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
+ } else {
+ if ($matches[7]=="Z") {
+ $tzOffset = 0;
+ }
+ }
+ $this->unix += $tzOffset;
+ return;
+ }
+ $this->unix = 0;
+ }
+
+ /**
+ * Gets the date stored in this FeedDate as an RFC 822 date.
+ *
+ * @return a date in RFC 822 format
+ */
+ function rfc822() {
+ //return gmdate("r",$this->unix);
+ $date = gmdate("D, d M Y H:i:s", $this->unix);
+ if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE);
+ return $date;
+ }
+
+ /**
+ * Gets the date stored in this FeedDate as an ISO 8601 date.
+ *
+ * @return a date in ISO 8601 format
+ */
+ function iso8601() {
+ $date = gmdate("Y-m-d\TH:i:sO",$this->unix);
+ $date = substr($date,0,22) . ':' . substr($date,-2);
+ if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date);
+ return $date;
+ }
+
+ /**
+ * Gets the date stored in this FeedDate as unix time stamp.
+ *
+ * @return a date as a unix time stamp
+ */
+ function unix() {
+ return $this->unix;
+ }
+}
+
+
+/**
+ * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0.
+ *
+ * @see http://www.purl.org/rss/1.0/
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class RSSCreator10 extends FeedCreator {
+
+ /**
+ * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
+ * The feed will contain all items previously added in the same order.
+ * @return string the feed's complete text
+ */
+ function createFeed() {
+ $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+ $feed.= $this->_createGeneratorComment();
+ if ($this->cssStyleSheet=="") {
+ $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css";
+ }
+ $feed.= $this->_createStylesheetReferences();
+ $feed.= "<rdf:RDF\n";
+ $feed.= " xmlns=\"http://purl.org/rss/1.0/\"\n";
+ $feed.= " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n";
+ $feed.= " xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n";
+ $feed.= " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
+ $feed.= " <channel rdf:about=\"".$this->syndicationURL."\">\n";
+ $feed.= " <title>".htmlspecialchars($this->title)."</title>\n";
+ $feed.= " <description>".htmlspecialchars($this->description)."</description>\n";
+ $feed.= " <link>".$this->link."</link>\n";
+ if ($this->image!=null) {
+ $feed.= " <image rdf:resource=\"".$this->image->url."\" />\n";
+ }
+ $now = new FeedDate();
+ $feed.= " <dc:date>".htmlspecialchars($now->iso8601())."</dc:date>\n";
+ $feed.= " <items>\n";
+ $feed.= " <rdf:Seq>\n";
+ for ($i=0;$i<count($this->items);$i++) {
+ $feed.= " <rdf:li rdf:resource=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
+ }
+ $feed.= " </rdf:Seq>\n";
+ $feed.= " </items>\n";
+ $feed.= " </channel>\n";
+ if ($this->image!=null) {
+ $feed.= " <image rdf:about=\"".$this->image->url."\">\n";
+ $feed.= " <title>".$this->image->title."</title>\n";
+ $feed.= " <link>".$this->image->link."</link>\n";
+ $feed.= " <url>".$this->image->url."</url>\n";
+ $feed.= " </image>\n";
+ }
+ $feed.= $this->_createAdditionalElements($this->additionalElements, " ");
+
+ for ($i=0;$i<count($this->items);$i++) {
+ $feed.= " <item rdf:about=\"".htmlspecialchars($this->items[$i]->link)."\">\n";
+ //$feed.= " <dc:type>Posting</dc:type>\n";
+ $feed.= " <dc:format>text/html</dc:format>\n";
+ if ($this->items[$i]->date!=null) {
+ $itemDate = new FeedDate($this->items[$i]->date);
+ $feed.= " <dc:date>".htmlspecialchars($itemDate->iso8601())."</dc:date>\n";
+ }
+ if ($this->items[$i]->source!="") {
+ $feed.= " <dc:source>".htmlspecialchars($this->items[$i]->source)."</dc:source>\n";
+ }
+ if ($this->items[$i]->author!="") {
+ $feed.= " <dc:creator>".htmlspecialchars($this->items[$i]->author)."</dc:creator>\n";
+ }
+ $feed.= " <title>".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")))."</title>\n";
+ $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
+ $feed.= " <description>".htmlspecialchars($this->items[$i]->description)."</description>\n";
+ $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " ");
+ $feed.= " </item>\n";
+ }
+ $feed.= "</rdf:RDF>\n";
+ return $feed;
+ }
+}
+
+
+
+/**
+ * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3.
+ *
+ * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class RSSCreator091 extends FeedCreator {
+
+ /**
+ * Stores this RSS feed's version number.
+ * @access private
+ */
+ var $RSSVersion;
+
+ function RSSCreator091() {
+ $this->_setRSSVersion("0.91");
+ $this->contentType = "application/rss+xml";
+ }
+
+ /**
+ * Sets this RSS feed's version number.
+ * @access private
+ */
+ function _setRSSVersion($version) {
+ $this->RSSVersion = $version;
+ }
+
+ /**
+ * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
+ * The feed will contain all items previously added in the same order.
+ * @return string the feed's complete text
+ */
+ function createFeed() {
+ $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+ $feed.= $this->_createGeneratorComment();
+ $feed.= $this->_createStylesheetReferences();
+ $feed.= "<rss version=\"".$this->RSSVersion."\">\n";
+ $feed.= " <channel>\n";
+ $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
+ $this->descriptionTruncSize = 500;
+ $feed.= " <description>".$this->getDescription()."</description>\n";
+ $feed.= " <link>".$this->link."</link>\n";
+ $now = new FeedDate();
+ $feed.= " <lastBuildDate>".htmlspecialchars($now->rfc822())."</lastBuildDate>\n";
+ $feed.= " <generator>".FEEDCREATOR_VERSION."</generator>\n";
+
+ if ($this->image!=null) {
+ $feed.= " <image>\n";
+ $feed.= " <url>".$this->image->url."</url>\n";
+ $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."</title>\n";
+ $feed.= " <link>".$this->image->link."</link>\n";
+ if ($this->image->width!="") {
+ $feed.= " <width>".$this->image->width."</width>\n";
+ }
+ if ($this->image->height!="") {
+ $feed.= " <height>".$this->image->height."</height>\n";
+ }
+ if ($this->image->description!="") {
+ $feed.= " <description>".$this->image->getDescription()."</description>\n";
+ }
+ $feed.= " </image>\n";
+ }
+ if ($this->language!="") {
+ $feed.= " <language>".$this->language."</language>\n";
+ }
+ if ($this->copyright!="") {
+ $feed.= " <copyright>".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."</copyright>\n";
+ }
+ if ($this->editor!="") {
+ $feed.= " <managingEditor>".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."</managingEditor>\n";
+ }
+ if ($this->webmaster!="") {
+ $feed.= " <webMaster>".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."</webMaster>\n";
+ }
+ if ($this->pubDate!="") {
+ $pubDate = new FeedDate($this->pubDate);
+ $feed.= " <pubDate>".htmlspecialchars($pubDate->rfc822())."</pubDate>\n";
+ }
+ if ($this->category!="") {
+ $feed.= " <category>".htmlspecialchars($this->category)."</category>\n";
+ }
+ if ($this->docs!="") {
+ $feed.= " <docs>".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."</docs>\n";
+ }
+ if ($this->ttl!="") {
+ $feed.= " <ttl>".htmlspecialchars($this->ttl)."</ttl>\n";
+ }
+ if ($this->rating!="") {
+ $feed.= " <rating>".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."</rating>\n";
+ }
+ if ($this->skipHours!="") {
+ $feed.= " <skipHours>".htmlspecialchars($this->skipHours)."</skipHours>\n";
+ }
+ if ($this->skipDays!="") {
+ $feed.= " <skipDays>".htmlspecialchars($this->skipDays)."</skipDays>\n";
+ }
+ $feed.= $this->_createAdditionalElements($this->additionalElements, " ");
+
+ for ($i=0;$i<count($this->items);$i++) {
+ $feed.= " <item>\n";
+ $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
+ $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
+ $feed.= " <description>".$this->items[$i]->getDescription()."</description>\n";
+
+ if ($this->items[$i]->author!="") {
+ $feed.= " <author>".htmlspecialchars($this->items[$i]->author)."</author>\n";
+ }
+ /*
+ // on hold
+ if ($this->items[$i]->source!="") {
+ $feed.= " <source>".htmlspecialchars($this->items[$i]->source)."</source>\n";
+ }
+ */
+ if ($this->items[$i]->category!="") {
+ $feed.= " <category>".htmlspecialchars($this->items[$i]->category)."</category>\n";
+ }
+ if ($this->items[$i]->comments!="") {
+ $feed.= " <comments>".htmlspecialchars($this->items[$i]->comments)."</comments>\n";
+ }
+ if ($this->items[$i]->date!="") {
+ $itemDate = new FeedDate($this->items[$i]->date);
+ $feed.= " <pubDate>".htmlspecialchars($itemDate->rfc822())."</pubDate>\n";
+ }
+ if ($this->items[$i]->guid!="") {
+ $feed.= " <guid>".htmlspecialchars($this->items[$i]->guid)."</guid>\n";
+ }
+ $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " ");
+ $feed.= " </item>\n";
+ }
+ $feed.= " </channel>\n";
+ $feed.= "</rss>\n";
+ return $feed;
+ }
+}
+
+
+
+/**
+ * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0.
+ *
+ * @see http://backend.userland.com/rss
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class RSSCreator20 extends RSSCreator091 {
+
+ function RSSCreator20() {
+ parent::_setRSSVersion("2.0");
+ }
+
+}
+
+
+/**
+ * PIECreator01 is a FeedCreator that implements the emerging PIE specification,
+ * as in http://intertwingly.net/wiki/pie/Syntax.
+ *
+ * @deprecated
+ * @since 1.3
+ * @author Scott Reynen <scott@randomchaos.com> and Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class PIECreator01 extends FeedCreator {
+
+ function PIECreator01() {
+ $this->encoding = "utf-8";
+ }
+
+ function createFeed() {
+ $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+ $feed.= $this->_createStylesheetReferences();
+ $feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n";
+ $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
+ $this->truncSize = 500;
+ $feed.= " <subtitle>".$this->getDescription()."</subtitle>\n";
+ $feed.= " <link>".$this->link."</link>\n";
+ for ($i=0;$i<count($this->items);$i++) {
+ $feed.= " <entry>\n";
+ $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
+ $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
+ $itemDate = new FeedDate($this->items[$i]->date);
+ $feed.= " <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
+ $feed.= " <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
+ $feed.= " <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
+ $feed.= " <id>".htmlspecialchars($this->items[$i]->guid)."</id>\n";
+ if ($this->items[$i]->author!="") {
+ $feed.= " <author>\n";
+ $feed.= " <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
+ if ($this->items[$i]->authorEmail!="") {
+ $feed.= " <email>".$this->items[$i]->authorEmail."</email>\n";
+ }
+ $feed.=" </author>\n";
+ }
+ $feed.= " <content type=\"text/html\" xml:lang=\"en-us\">\n";
+ $feed.= " <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items[$i]->getDescription()."</div>\n";
+ $feed.= " </content>\n";
+ $feed.= " </entry>\n";
+ }
+ $feed.= "</feed>\n";
+ return $feed;
+ }
+}
+
+
+/**
+ * AtomCreator03 is a FeedCreator that implements the atom specification,
+ * as in http://www.intertwingly.net/wiki/pie/FrontPage.
+ * Please note that just by using AtomCreator03 you won't automatically
+ * produce valid atom files. For example, you have to specify either an editor
+ * for the feed or an author for every single feed item.
+ *
+ * Some elements have not been implemented yet. These are (incomplete list):
+ * author URL, item author's email and URL, item contents, alternate links,
+ * other link content types than text/html. Some of them may be created with
+ * AtomCreator03::additionalElements.
+ *
+ * @see FeedCreator#additionalElements
+ * @since 1.6
+ * @author Kai Blankenhorn <kaib@bitfolge.de>, Scott Reynen <scott@randomchaos.com>
+ */
+class AtomCreator03 extends FeedCreator {
+
+ function AtomCreator03() {
+ $this->contentType = "application/atom+xml";
+ $this->encoding = "utf-8";
+ }
+
+ function createFeed() {
+ $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+ $feed.= $this->_createGeneratorComment();
+ $feed.= $this->_createStylesheetReferences();
+ $feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\"";
+ if ($this->language!="") {
+ $feed.= " xml:lang=\"".$this->language."\"";
+ }
+ $feed.= ">\n";
+ $feed.= " <title>".htmlspecialchars($this->title)."</title>\n";
+ $feed.= " <tagline>".htmlspecialchars($this->description)."</tagline>\n";
+ $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n";
+ $feed.= " <id>".htmlspecialchars($this->link)."</id>\n";
+ $now = new FeedDate();
+ $feed.= " <modified>".htmlspecialchars($now->iso8601())."</modified>\n";
+ if ($this->editor!="") {
+ $feed.= " <author>\n";
+ $feed.= " <name>".$this->editor."</name>\n";
+ if ($this->editorEmail!="") {
+ $feed.= " <email>".$this->editorEmail."</email>\n";
+ }
+ $feed.= " </author>\n";
+ }
+ $feed.= " <generator>".FEEDCREATOR_VERSION."</generator>\n";
+ $feed.= $this->_createAdditionalElements($this->additionalElements, " ");
+ for ($i=0;$i<count($this->items);$i++) {
+ $feed.= " <entry>\n";
+ $feed.= " <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n";
+ $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
+ if ($this->items[$i]->date=="") {
+ $this->items[$i]->date = time();
+ }
+ $itemDate = new FeedDate($this->items[$i]->date);
+ $feed.= " <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
+ $feed.= " <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
+ $feed.= " <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
+ $feed.= " <id>".htmlspecialchars($this->items[$i]->link)."</id>\n";
+ $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " ");
+ if ($this->items[$i]->author!="") {
+ $feed.= " <author>\n";
+ $feed.= " <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
+ $feed.= " </author>\n";
+ }
+ if ($this->items[$i]->description!="") {
+ $feed.= " <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n";
+ }
+ $feed.= " </entry>\n";
+ }
+ $feed.= "</feed>\n";
+ return $feed;
+ }
+}
+
+
+/**
+ * MBOXCreator is a FeedCreator that implements the mbox format
+ * as described in http://www.qmail.org/man/man5/mbox.html
+ *
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class MBOXCreator extends FeedCreator {
+
+ function MBOXCreator() {
+ $this->contentType = "text/plain";
+ $this->encoding = "ISO-8859-15";
+ }
+
+ function qp_enc($input = "", $line_max = 76) {
+ $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
+ $lines = preg_split("/(?:\r\n|\r|\n)/", $input);
+ $eol = "\r\n";
+ $escape = "=";
+ $output = "";
+ while( list(, $line) = each($lines) ) {
+ //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary
+ $linlen = strlen($line);
+ $newline = "";
+ for($i = 0; $i < $linlen; $i++) {
+ $c = substr($line, $i, 1);
+ $dec = ord($c);
+ if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only
+ $c = "=20";
+ } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
+ $h2 = floor($dec/16); $h1 = floor($dec%16);
+ $c = $escape.$hex["$h2"].$hex["$h1"];
+ }
+ if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
+ $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
+ $newline = "";
+ }
+ $newline .= $c;
+ } // end of for
+ $output .= $newline.$eol;
+ }
+ return trim($output);
+ }
+
+
+ /**
+ * Builds the MBOX contents.
+ * @return string the feed's complete text
+ */
+ function createFeed() {
+ for ($i=0;$i<count($this->items);$i++) {
+ if ($this->items[$i]->author!="") {
+ $from = $this->items[$i]->author;
+ } else {
+ $from = $this->title;
+ }
+ $itemDate = new FeedDate($this->items[$i]->date);
+ $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n";
+ $feed.= "Content-Type: text/plain;\n";
+ $feed.= " charset=\"".$this->encoding."\"\n";
+ $feed.= "Content-Transfer-Encoding: quoted-printable\n";
+ $feed.= "Content-Type: text/plain\n";
+ $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n";
+ $feed.= "Date: ".$itemDate->rfc822()."\n";
+ $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n";
+ $feed.= "\n";
+ $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description));
+ $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body);
+ $feed.= "\n";
+ $feed.= "\n";
+ }
+ return $feed;
+ }
+
+ /**
+ * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types.
+ * @return string the feed cache filename
+ * @since 1.4
+ * @access private
+ */
+ function _generateFilename() {
+ $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
+ return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox";
+ }
+}
+
+
+/**
+ * OPMLCreator is a FeedCreator that implements OPML 1.0.
+ *
+ * @see http://opml.scripting.com/spec
+ * @author Dirk Clemens, Kai Blankenhorn
+ * @since 1.5
+ */
+class OPMLCreator extends FeedCreator {
+
+ function OPMLCreator() {
+ $this->encoding = "utf-8";
+ }
+
+ function createFeed() {
+ $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+ $feed.= $this->_createGeneratorComment();
+ $feed.= $this->_createStylesheetReferences();
+ $feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
+ $feed.= " <head>\n";
+ $feed.= " <title>".htmlspecialchars($this->title)."</title>\n";
+ if ($this->pubDate!="") {
+ $date = new FeedDate($this->pubDate);
+ $feed.= " <dateCreated>".$date->rfc822()."</dateCreated>\n";
+ }
+ if ($this->lastBuildDate!="") {
+ $date = new FeedDate($this->lastBuildDate);
+ $feed.= " <dateModified>".$date->rfc822()."</dateModified>\n";
+ }
+ if ($this->editor!="") {
+ $feed.= " <ownerName>".$this->editor."</ownerName>\n";
+ }
+ if ($this->editorEmail!="") {
+ $feed.= " <ownerEmail>".$this->editorEmail."</ownerEmail>\n";
+ }
+ $feed.= " </head>\n";
+ $feed.= " <body>\n";
+ for ($i=0;$i<count($this->items);$i++) {
+ $feed.= " <outline type=\"rss\" ";
+ $title = htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")));
+ $feed.= " title=\"".$title."\"";
+ $feed.= " text=\"".$title."\"";
+ //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\"";
+ $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\"";
+ $feed.= "/>\n";
+ }
+ $feed.= " </body>\n";
+ $feed.= "</opml>\n";
+ return $feed;
+ }
+}
+
+
+
+/**
+ * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific
+ * location, overriding the createFeed method of the parent FeedCreator.
+ * The HTML produced can be included over http by scripting languages, or serve
+ * as the source for an IFrame.
+ * All output by this class is embedded in <div></div> tags to enable formatting
+ * using CSS.
+ *
+ * @author Pascal Van Hecke
+ * @since 1.7
+ */
+class HTMLCreator extends FeedCreator {
+
+ var $contentType = "text/html";
+
+ /**
+ * Contains HTML to be output at the start of the feed's html representation.
+ */
+ var $header;
+
+ /**
+ * Contains HTML to be output at the end of the feed's html representation.
+ */
+ var $footer ;
+
+ /**
+ * Contains HTML to be output between entries. A separator is only used in
+ * case of multiple entries.
+ */
+ var $separator;
+
+ /**
+ * Used to prefix the stylenames to make sure they are unique
+ * and do not clash with stylenames on the users' page.
+ */
+ var $stylePrefix;
+
+ /**
+ * Determines whether the links open in a new window or not.
+ */
+ var $openInNewWindow = true;
+
+ var $imageAlign ="right";
+
+ /**
+ * In case of very simple output you may want to get rid of the style tags,
+ * hence this variable. There's no equivalent on item level, but of course you can
+ * add strings to it while iterating over the items ($this->stylelessOutput .= ...)
+ * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored
+ * in the function createFeed().
+ */
+ var $stylelessOutput ="";
+
+ /**
+ * Writes the HTML.
+ * @return string the scripts's complete text
+ */
+ function createFeed() {
+ // if there is styleless output, use the content of this variable and ignore the rest
+ if ($this->stylelessOutput!="") {
+ return $this->stylelessOutput;
+ }
+
+ //if no stylePrefix is set, generate it yourself depending on the script name
+ if ($this->stylePrefix=="") {
+ $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_";
+ }
+
+ //set an openInNewWindow_token_to be inserted or not
+ if ($this->openInNewWindow) {
+ $targetInsert = " target='_blank'";
+ }
+
+ // use this array to put the lines in and implode later with "document.write" javascript
+ $feedArray = array();
+ if ($this->image!=null) {
+ $imageStr = "<a href='".$this->image->link."'".$targetInsert.">".
+ "<img src='".$this->image->url."' border='0' alt='".
+ FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
+ "' align='".$this->imageAlign."' ";
+ if ($this->image->width) {
+ $imageStr .=" width='".$this->image->width. "' ";
+ }
+ if ($this->image->height) {
+ $imageStr .=" height='".$this->image->height."' ";
+ }
+ $imageStr .="/></a>";
+ $feedArray[] = $imageStr;
+ }
+
+ if ($this->title) {
+ $feedArray[] = "<div class='".$this->stylePrefix."title'><a href='".$this->link."' ".$targetInsert." class='".$this->stylePrefix."title'>".
+ FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</a></div>";
+ }
+ if ($this->getDescription()) {
+ $feedArray[] = "<div class='".$this->stylePrefix."description'>".
+ str_replace("]]>", "", str_replace("<![CDATA[", "", $this->getDescription())).
+ "</div>";
+ }
+
+ if ($this->header) {
+ $feedArray[] = "<div class='".$this->stylePrefix."header'>".$this->header."</div>";
+ }
+
+ for ($i=0;$i<count($this->items);$i++) {
+ if ($this->separator and $i > 0) {
+ $feedArray[] = "<div class='".$this->stylePrefix."separator'>".$this->separator."</div>";
+ }
+
+ if ($this->items[$i]->title) {
+ if ($this->items[$i]->link) {
+ $feedArray[] =
+ "<div class='".$this->stylePrefix."item_title'><a href='".$this->items[$i]->link."' class='".$this->stylePrefix.
+ "item_title'".$targetInsert.">".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
+ "</a></div>";
+ } else {
+ $feedArray[] =
+ "<div class='".$this->stylePrefix."item_title'>".
+ FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
+ "</div>";
+ }
+ }
+ if ($this->items[$i]->getDescription()) {
+ $feedArray[] =
+ "<div class='".$this->stylePrefix."item_description'>".
+ str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items[$i]->getDescription())).
+ "</div>";
+ }
+ }
+ if ($this->footer) {
+ $feedArray[] = "<div class='".$this->stylePrefix."footer'>".$this->footer."</div>";
+ }
+
+ $feed= "".join($feedArray, "\r\n");
+ return $feed;
+ }
+
+ /**
+ * Overrrides parent to produce .html extensions
+ *
+ * @return string the feed cache filename
+ * @since 1.4
+ * @access private
+ */
+ function _generateFilename() {
+ $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
+ return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html";
+ }
+}
+
+
+/**
+ * JSCreator is a class that writes a js file to a specific
+ * location, overriding the createFeed method of the parent HTMLCreator.
+ *
+ * @author Pascal Van Hecke
+ */
+class JSCreator extends HTMLCreator {
+ var $contentType = "text/javascript";
+
+ /**
+ * writes the javascript
+ * @return string the scripts's complete text
+ */
+ function createFeed()
+ {
+ $feed = parent::createFeed();
+ $feedArray = explode("\n",$feed);
+
+ $jsFeed = "";
+ foreach ($feedArray as $value) {
+ $jsFeed .= "document.write('".trim(addslashes($value))."');\n";
+ }
+ return $jsFeed;
+ }
+
+ /**
+ * Overrrides parent to produce .js extensions
+ *
+ * @return string the feed cache filename
+ * @since 1.4
+ * @access private
+ */
+ function _generateFilename() {
+ $fileInfo = pathinfo($_SERVER["PHP_SELF"]);
+ return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js";
+ }
+
+}
+
+
+
+/*** TEST SCRIPT *********************************************************
+
+//include("feedcreator.class.php");
+
+$rss = new UniversalFeedCreator();
+$rss->useCached();
+$rss->title = "PHP news";
+$rss->description = "daily news from the PHP scripting world";
+
+//optional
+//$rss->descriptionTruncSize = 500;
+//$rss->descriptionHtmlSyndicated = true;
+//$rss->xslStyleSheet = "http://feedster.com/rss20.xsl";
+
+$rss->link = "http://www.dailyphp.net/news";
+$rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF;
+
+$image = new FeedImage();
+$image->title = "dailyphp.net logo";
+$image->url = "http://www.dailyphp.net/images/logo.gif";
+$image->link = "http://www.dailyphp.net";
+$image->description = "Feed provided by dailyphp.net. Click to visit.";
+
+//optional
+$image->descriptionTruncSize = 500;
+$image->descriptionHtmlSyndicated = true;
+
+$rss->image = $image;
+
+// get your news items from somewhere, e.g. your database:
+//mysql_select_db($dbHost, $dbUser, $dbPass);
+//$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC");
+//while ($data = mysql_fetch_object($res)) {
+ $item = new FeedItem();
+ $item->title = "This is an the test title of an item";
+ $item->link = "http://localhost/item/";
+ $item->description = "<b>description in </b><br/>HTML";
+
+ //optional
+ //item->descriptionTruncSize = 500;
+ $item->descriptionHtmlSyndicated = true;
+
+ $item->date = time();
+ $item->source = "http://www.dailyphp.net";
+ $item->author = "John Doe";
+
+ $rss->addItem($item);
+//}
+
+// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS
+echo $rss->saveFeed("RSS0.91", "feed.xml");
+
+
+
+***************************************************************************/
+
+?>
diff --git a/include/functions_user.inc.php b/include/functions_user.inc.php
index 999ef95af..3e8588cf7 100644
--- a/include/functions_user.inc.php
+++ b/include/functions_user.inc.php
@@ -110,6 +110,7 @@ SELECT id
$insert['nb_line_page'] = $conf['nb_line_page'];
$insert['language'] = $conf['default_language'];
$insert['recent_period'] = $conf['recent_period'];
+ $insert['feed_id'] = find_available_feed_id();
$insert['expand'] = boolean_to_string($conf['auto_expand']);
$insert['show_nb_comments'] = boolean_to_string($conf['show_nb_comments']);
if ( $mail_address != '' )
@@ -143,6 +144,13 @@ INSERT INTO '.USERS_TABLE.'
$query.= ')
;';
pwg_query($query);
+
+ $query = '
+UPDATE '.USERS_TABLE.'
+ SET registration_date = NOW()
+ WHERE id = '.mysql_insert_id().'
+;';
+ pwg_query($query);
}
return $errors;
}
@@ -379,4 +387,27 @@ SELECT username
return $username;
}
+
+/**
+ * search an available feed_id
+ *
+ * @return string feed identifier
+ */
+function find_available_feed_id()
+{
+ while (true)
+ {
+ $key = generate_key(50);
+ $query = '
+SELECT COUNT(*)
+ FROM '.USERS_TABLE.'
+ WHERE feed_id = \''.$key.'\'
+;';
+ list($count) = mysql_fetch_row(pwg_query($query));
+ if (0 == $count)
+ {
+ return $key;
+ }
+ }
+}
?>
diff --git a/include/template.php b/include/template.php
index 352914ef3..14f5d4349 100644
--- a/include/template.php
+++ b/include/template.php
@@ -156,11 +156,6 @@ class Template {
// Run the compiled code.
$_str = '';
-// echo '<pre>'.($this->compiled_code[$handle]).'</pre>';
- $fp = @fopen( './log/debug.log', 'a+' );
- fwrite( $fp, "\n\n" );
- fwrite( $fp, $this->compiled_code[$handle] );
- fclose( $fp );
eval($this->compiled_code[$handle]);
$this->output.= $_str;
diff --git a/install.php b/install.php
index 686a860e2..e4e38fafe 100644
--- a/install.php
+++ b/install.php
@@ -306,6 +306,13 @@ if ( isset( $_POST['install'] ))
$query.= ",'admin','".$language."'";
$query.= ",'".$admin_mail."');";
mysql_query($query);
+
+ $query = '
+UPDATE '.USERS_TABLE.'
+ SET feed_id = \''.find_available_feed_id().'\'
+ WHERE id = 1
+;';
+ mysql_query($query);
// guest user
$query = 'INSERT INTO '.USERS_TABLE;
@@ -348,7 +355,7 @@ $template->assign_vars(
'L_END_TITLE'=>$lang['install_end_title'],
'L_END_MESSAGE'=>$lang['install_end_message'],
- 'F_ACTION'=>add_session_id( 'install.php' ),
+ 'F_ACTION'=>'install.php',
'F_DB_HOST'=>$dbhost,
'F_DB_USER'=>$dbuser,
'F_DB_NAME'=>$dbname,
diff --git a/install/dbscheme.txt b/install/dbscheme.txt
index d53e742c4..002059c4d 100644
--- a/install/dbscheme.txt
+++ b/install/dbscheme.txt
@@ -1,4 +1,5 @@
+table:caddie
table:categories
table:comments
table:config
@@ -17,8 +18,10 @@ table:user_group
table:users
table:waiting
+column:user_id table:caddie type:smallint nullable:N length:5 signed:Y
+column:element_id table:caddie type:mediumint nullable:N length:8 signed:Y
column:id table:categories type:smallint nullable:N length:5 signed:N
-column:date_last table:categories type:date nullable:Y
+column:date_last table:categories type:datetime nullable:Y
column:nb_images table:categories type:mediumint nullable:N length:8 signed:N
column:name table:categories type:varchar nullable:N length:255 binary:N
column:id_uppercat table:categories type:smallint nullable:Y length:5 signed:N
@@ -39,6 +42,7 @@ column:date table:comments type:datetime
column:author table:comments type:varchar nullable:Y length:255 binary:N
column:content table:comments type:longtext nullable:Y
column:validated table:comments type:enum('true','false') nullable:N
+column:validation_date table:comments type:datetime nullable:Y
column:param table:config type:varchar nullable:N length:40 binary:N
column:value table:config type:varchar nullable:Y length:255 binary:N
column:comment table:config type:varchar nullable:Y length:255 binary:N
@@ -58,7 +62,7 @@ column:image_id table:image_category type:mediumint
column:category_id table:image_category type:smallint nullable:N length:5 signed:N
column:id table:images type:mediumint nullable:N length:8 signed:N
column:file table:images type:varchar nullable:N length:255 binary:N
-column:date_available table:images type:date nullable:N
+column:date_available table:images type:datetime nullable:N
column:date_creation table:images type:date nullable:Y
column:tn_ext table:images type:varchar nullable:Y length:4 binary:N
column:name table:images type:varchar nullable:Y length:255 binary:N
@@ -91,7 +95,7 @@ column:user_id table:user_group type:smallint
column:group_id table:user_group type:smallint nullable:N length:5 signed:N
column:id table:users type:smallint nullable:N length:5 signed:N
column:username table:users type:varchar nullable:N length:20 binary:Y
-column:password table:users type:varchar nullable:N length:255 binary:N
+column:password table:users type:varchar nullable:Y length:32 binary:N
column:mail_address table:users type:varchar nullable:Y length:255 binary:N
column:nb_image_line table:users type:tinyint nullable:N length:1 signed:N
column:nb_line_page table:users type:tinyint nullable:N length:3 signed:N
@@ -103,6 +107,9 @@ column:expand table:users type:enum('true','false')
column:show_nb_comments table:users type:enum('true','false') nullable:N
column:recent_period table:users type:tinyint nullable:N length:3 signed:N
column:template table:users type:varchar nullable:N length:255 binary:N
+column:last_feed_check table:users type:datetime nullable:Y
+column:feed_id table:users type:varchar nullable:Y length:50 binary:Y
+column:registration_date table:users type:datetime nullable:N
column:id table:waiting type:int nullable:N length:10 signed:N
column:storage_category_id table:waiting type:smallint nullable:N length:5 signed:N
column:file table:waiting type:varchar nullable:N length:255 binary:N
@@ -113,6 +120,8 @@ column:tn_ext table:waiting type:char
column:validated table:waiting type:enum('true','false') nullable:N
column:infos table:waiting type:text nullable:Y
+PK:caddie_pk table:caddie column:user_id
+PK:caddie_pk table:caddie column:element_id
PK:categories_pk table:categories column:id
PK:comments_pk table:comments column:id
PK:config_pk table:config column:param
@@ -137,6 +146,8 @@ PK:users_pk table:users column:id
PK:waiting_pk table:waiting column:id
index:categories_i2 table:categories column:id_uppercat
+index:comments_i2 table:comments column:validation_date
+index:comments_i1 table:comments column:image_id
index:history_i1 table:history column:date
index:image_category_i1 table:image_category column:image_id
index:image_category_i2 table:image_category column:category_id
diff --git a/install/phpwebgallery_structure.sql b/install/phpwebgallery_structure.sql
index 2d92e25e6..9ca7af0a7 100644
--- a/install/phpwebgallery_structure.sql
+++ b/install/phpwebgallery_structure.sql
@@ -1,275 +1,281 @@
--- MySQL dump 8.21
+-- MySQL dump 9.11
--
-- Host: localhost Database: pwg-bsf
----------------------------------------------------------
--- Server version 3.23.49-log
+-- ------------------------------------------------------
+-- Server version 4.0.24_Debian-10-log
--
--- Table structure for table 'phpwebgallery_caddie'
+-- Table structure for table `phpwebgallery_caddie`
--
-DROP TABLE IF EXISTS phpwebgallery_caddie;
-CREATE TABLE phpwebgallery_caddie (
- user_id smallint(5) NOT NULL default '0',
- element_id mediumint(8) NOT NULL default '0',
- PRIMARY KEY (user_id,element_id)
+DROP TABLE IF EXISTS `phpwebgallery_caddie`;
+CREATE TABLE `phpwebgallery_caddie` (
+ `user_id` smallint(5) NOT NULL default '0',
+ `element_id` mediumint(8) NOT NULL default '0',
+ PRIMARY KEY (`user_id`,`element_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_categories'
---
-
-DROP TABLE IF EXISTS phpwebgallery_categories;
-CREATE TABLE phpwebgallery_categories (
- id smallint(5) unsigned NOT NULL auto_increment,
- date_last date default NULL,
- nb_images mediumint(8) unsigned NOT NULL default '0',
- name varchar(255) NOT NULL default '',
- id_uppercat smallint(5) unsigned default NULL,
- comment text,
- dir varchar(255) default NULL,
- rank tinyint(3) unsigned default NULL,
- status enum('public','private') NOT NULL default 'public',
- site_id tinyint(4) unsigned default '1',
- visible enum('true','false') NOT NULL default 'true',
- uploadable enum('true','false') NOT NULL default 'false',
- representative_picture_id mediumint(8) unsigned default NULL,
- uppercats varchar(255) NOT NULL default '',
- commentable enum('true','false') NOT NULL default 'true',
- global_rank varchar(255) default NULL,
- PRIMARY KEY (id),
- KEY categories_i2 (id_uppercat)
+-- Table structure for table `phpwebgallery_categories`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_categories`;
+CREATE TABLE `phpwebgallery_categories` (
+ `id` smallint(5) unsigned NOT NULL auto_increment,
+ `date_last` datetime default NULL,
+ `nb_images` mediumint(8) unsigned NOT NULL default '0',
+ `name` varchar(255) NOT NULL default '',
+ `id_uppercat` smallint(5) unsigned default NULL,
+ `comment` text,
+ `dir` varchar(255) default NULL,
+ `rank` tinyint(3) unsigned default NULL,
+ `status` enum('public','private') NOT NULL default 'public',
+ `site_id` tinyint(4) unsigned default '1',
+ `visible` enum('true','false') NOT NULL default 'true',
+ `uploadable` enum('true','false') NOT NULL default 'false',
+ `representative_picture_id` mediumint(8) unsigned default NULL,
+ `uppercats` varchar(255) NOT NULL default '',
+ `commentable` enum('true','false') NOT NULL default 'true',
+ `global_rank` varchar(255) default NULL,
+ PRIMARY KEY (`id`),
+ KEY `categories_i2` (`id_uppercat`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_comments'
+-- Table structure for table `phpwebgallery_comments`
--
-DROP TABLE IF EXISTS phpwebgallery_comments;
-CREATE TABLE phpwebgallery_comments (
- id int(11) unsigned NOT NULL auto_increment,
- image_id mediumint(8) unsigned NOT NULL default '0',
- date datetime NOT NULL default '0000-00-00 00:00:00',
- author varchar(255) default NULL,
- content longtext,
- validated enum('true','false') NOT NULL default 'false',
- PRIMARY KEY (id)
+DROP TABLE IF EXISTS `phpwebgallery_comments`;
+CREATE TABLE `phpwebgallery_comments` (
+ `id` int(11) unsigned NOT NULL auto_increment,
+ `image_id` mediumint(8) unsigned NOT NULL default '0',
+ `date` datetime NOT NULL default '0000-00-00 00:00:00',
+ `author` varchar(255) default NULL,
+ `content` longtext,
+ `validated` enum('true','false') NOT NULL default 'false',
+ `validation_date` datetime default NULL,
+ PRIMARY KEY (`id`),
+ KEY `comments_i2` (`validation_date`),
+ KEY `comments_i1` (`image_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_config'
+-- Table structure for table `phpwebgallery_config`
--
-DROP TABLE IF EXISTS phpwebgallery_config;
-CREATE TABLE phpwebgallery_config (
- param varchar(40) NOT NULL default '',
- value varchar(255) default NULL,
- comment varchar(255) default NULL,
- PRIMARY KEY (param)
+DROP TABLE IF EXISTS `phpwebgallery_config`;
+CREATE TABLE `phpwebgallery_config` (
+ `param` varchar(40) NOT NULL default '',
+ `value` varchar(255) default NULL,
+ `comment` varchar(255) default NULL,
+ PRIMARY KEY (`param`)
) TYPE=MyISAM COMMENT='configuration table';
--
--- Table structure for table 'phpwebgallery_favorites'
+-- Table structure for table `phpwebgallery_favorites`
--
-DROP TABLE IF EXISTS phpwebgallery_favorites;
-CREATE TABLE phpwebgallery_favorites (
- user_id smallint(5) unsigned NOT NULL default '0',
- image_id mediumint(8) unsigned NOT NULL default '0',
- PRIMARY KEY (user_id,image_id)
+DROP TABLE IF EXISTS `phpwebgallery_favorites`;
+CREATE TABLE `phpwebgallery_favorites` (
+ `user_id` smallint(5) unsigned NOT NULL default '0',
+ `image_id` mediumint(8) unsigned NOT NULL default '0',
+ PRIMARY KEY (`user_id`,`image_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_group_access'
+-- Table structure for table `phpwebgallery_group_access`
--
-DROP TABLE IF EXISTS phpwebgallery_group_access;
-CREATE TABLE phpwebgallery_group_access (
- group_id smallint(5) unsigned NOT NULL default '0',
- cat_id smallint(5) unsigned NOT NULL default '0',
- PRIMARY KEY (group_id,cat_id)
+DROP TABLE IF EXISTS `phpwebgallery_group_access`;
+CREATE TABLE `phpwebgallery_group_access` (
+ `group_id` smallint(5) unsigned NOT NULL default '0',
+ `cat_id` smallint(5) unsigned NOT NULL default '0',
+ PRIMARY KEY (`group_id`,`cat_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_groups'
+-- Table structure for table `phpwebgallery_groups`
--
-DROP TABLE IF EXISTS phpwebgallery_groups;
-CREATE TABLE phpwebgallery_groups (
- id smallint(5) unsigned NOT NULL auto_increment,
- name varchar(255) NOT NULL default '',
- PRIMARY KEY (id)
+DROP TABLE IF EXISTS `phpwebgallery_groups`;
+CREATE TABLE `phpwebgallery_groups` (
+ `id` smallint(5) unsigned NOT NULL auto_increment,
+ `name` varchar(255) NOT NULL default '',
+ PRIMARY KEY (`id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_history'
+-- Table structure for table `phpwebgallery_history`
--
-DROP TABLE IF EXISTS phpwebgallery_history;
-CREATE TABLE phpwebgallery_history (
- date datetime NOT NULL default '0000-00-00 00:00:00',
- login varchar(15) default NULL,
- IP varchar(50) NOT NULL default '',
- category varchar(150) default NULL,
- file varchar(50) default NULL,
- picture varchar(150) default NULL,
- KEY history_i1 (date)
+DROP TABLE IF EXISTS `phpwebgallery_history`;
+CREATE TABLE `phpwebgallery_history` (
+ `date` datetime NOT NULL default '0000-00-00 00:00:00',
+ `login` varchar(15) default NULL,
+ `IP` varchar(50) NOT NULL default '',
+ `category` varchar(150) default NULL,
+ `file` varchar(50) default NULL,
+ `picture` varchar(150) default NULL,
+ KEY `history_i1` (`date`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_image_category'
+-- Table structure for table `phpwebgallery_image_category`
--
-DROP TABLE IF EXISTS phpwebgallery_image_category;
-CREATE TABLE phpwebgallery_image_category (
- image_id mediumint(8) unsigned NOT NULL default '0',
- category_id smallint(5) unsigned NOT NULL default '0',
- PRIMARY KEY (image_id,category_id),
- KEY image_category_i1 (image_id),
- KEY image_category_i2 (category_id)
+DROP TABLE IF EXISTS `phpwebgallery_image_category`;
+CREATE TABLE `phpwebgallery_image_category` (
+ `image_id` mediumint(8) unsigned NOT NULL default '0',
+ `category_id` smallint(5) unsigned NOT NULL default '0',
+ PRIMARY KEY (`image_id`,`category_id`),
+ KEY `image_category_i1` (`image_id`),
+ KEY `image_category_i2` (`category_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_images'
---
-
-DROP TABLE IF EXISTS phpwebgallery_images;
-CREATE TABLE phpwebgallery_images (
- id mediumint(8) unsigned NOT NULL auto_increment,
- file varchar(255) NOT NULL default '',
- date_available date NOT NULL default '0000-00-00',
- date_creation date default NULL,
- tn_ext varchar(4) default '',
- name varchar(255) default NULL,
- comment text,
- author varchar(255) default NULL,
- hit int(10) unsigned NOT NULL default '0',
- filesize mediumint(9) unsigned default NULL,
- width smallint(9) unsigned default NULL,
- height smallint(9) unsigned default NULL,
- keywords varchar(255) default NULL,
- storage_category_id smallint(5) unsigned default NULL,
- representative_ext varchar(4) default NULL,
- date_metadata_update date default NULL,
- average_rate float(5,2) unsigned default NULL,
- path varchar(255) NOT NULL default '',
- PRIMARY KEY (id),
- KEY images_i2 (date_available),
- KEY images_i1 (storage_category_id),
- KEY images_i3 (average_rate),
- KEY images_i4 (hit),
- KEY images_i5 (date_creation)
+-- Table structure for table `phpwebgallery_images`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_images`;
+CREATE TABLE `phpwebgallery_images` (
+ `id` mediumint(8) unsigned NOT NULL auto_increment,
+ `file` varchar(255) NOT NULL default '',
+ `date_available` datetime NOT NULL default '0000-00-00 00:00:00',
+ `date_creation` date default NULL,
+ `tn_ext` varchar(4) default '',
+ `name` varchar(255) default NULL,
+ `comment` text,
+ `author` varchar(255) default NULL,
+ `hit` int(10) unsigned NOT NULL default '0',
+ `filesize` mediumint(9) unsigned default NULL,
+ `width` smallint(9) unsigned default NULL,
+ `height` smallint(9) unsigned default NULL,
+ `keywords` varchar(255) default NULL,
+ `storage_category_id` smallint(5) unsigned default NULL,
+ `representative_ext` varchar(4) default NULL,
+ `date_metadata_update` date default NULL,
+ `average_rate` float(5,2) unsigned default NULL,
+ `path` varchar(255) NOT NULL default '',
+ PRIMARY KEY (`id`),
+ KEY `images_i2` (`date_available`),
+ KEY `images_i1` (`storage_category_id`),
+ KEY `images_i3` (`average_rate`),
+ KEY `images_i4` (`hit`),
+ KEY `images_i5` (`date_creation`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_rate'
+-- Table structure for table `phpwebgallery_rate`
--
-DROP TABLE IF EXISTS phpwebgallery_rate;
-CREATE TABLE phpwebgallery_rate (
- user_id smallint(5) unsigned NOT NULL default '0',
- element_id mediumint(8) unsigned NOT NULL default '0',
- rate tinyint(2) unsigned NOT NULL default '0',
- PRIMARY KEY (user_id,element_id)
+DROP TABLE IF EXISTS `phpwebgallery_rate`;
+CREATE TABLE `phpwebgallery_rate` (
+ `user_id` smallint(5) unsigned NOT NULL default '0',
+ `element_id` mediumint(8) unsigned NOT NULL default '0',
+ `rate` tinyint(2) unsigned NOT NULL default '0',
+ PRIMARY KEY (`user_id`,`element_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_sessions'
+-- Table structure for table `phpwebgallery_sessions`
--
-DROP TABLE IF EXISTS phpwebgallery_sessions;
-CREATE TABLE phpwebgallery_sessions (
- id varchar(255) binary NOT NULL default '',
- user_id smallint(5) unsigned NOT NULL default '0',
- expiration datetime NOT NULL default '0000-00-00 00:00:00',
- PRIMARY KEY (id)
+DROP TABLE IF EXISTS `phpwebgallery_sessions`;
+CREATE TABLE `phpwebgallery_sessions` (
+ `id` varchar(255) binary NOT NULL default '',
+ `user_id` smallint(5) unsigned NOT NULL default '0',
+ `expiration` datetime NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (`id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_sites'
+-- Table structure for table `phpwebgallery_sites`
--
-DROP TABLE IF EXISTS phpwebgallery_sites;
-CREATE TABLE phpwebgallery_sites (
- id tinyint(4) NOT NULL auto_increment,
- galleries_url varchar(255) NOT NULL default '',
- PRIMARY KEY (id),
- UNIQUE KEY sites_ui1 (galleries_url)
+DROP TABLE IF EXISTS `phpwebgallery_sites`;
+CREATE TABLE `phpwebgallery_sites` (
+ `id` tinyint(4) NOT NULL auto_increment,
+ `galleries_url` varchar(255) NOT NULL default '',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `sites_ui1` (`galleries_url`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_user_access'
+-- Table structure for table `phpwebgallery_user_access`
--
-DROP TABLE IF EXISTS phpwebgallery_user_access;
-CREATE TABLE phpwebgallery_user_access (
- user_id smallint(5) unsigned NOT NULL default '0',
- cat_id smallint(5) unsigned NOT NULL default '0',
- PRIMARY KEY (user_id,cat_id)
+DROP TABLE IF EXISTS `phpwebgallery_user_access`;
+CREATE TABLE `phpwebgallery_user_access` (
+ `user_id` smallint(5) unsigned NOT NULL default '0',
+ `cat_id` smallint(5) unsigned NOT NULL default '0',
+ PRIMARY KEY (`user_id`,`cat_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_user_forbidden'
+-- Table structure for table `phpwebgallery_user_forbidden`
--
-DROP TABLE IF EXISTS phpwebgallery_user_forbidden;
-CREATE TABLE phpwebgallery_user_forbidden (
- user_id smallint(5) unsigned NOT NULL default '0',
- need_update enum('true','false') NOT NULL default 'true',
- forbidden_categories text,
- PRIMARY KEY (user_id)
+DROP TABLE IF EXISTS `phpwebgallery_user_forbidden`;
+CREATE TABLE `phpwebgallery_user_forbidden` (
+ `user_id` smallint(5) unsigned NOT NULL default '0',
+ `need_update` enum('true','false') NOT NULL default 'true',
+ `forbidden_categories` text,
+ PRIMARY KEY (`user_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_user_group'
+-- Table structure for table `phpwebgallery_user_group`
--
-DROP TABLE IF EXISTS phpwebgallery_user_group;
-CREATE TABLE phpwebgallery_user_group (
- user_id smallint(5) unsigned NOT NULL default '0',
- group_id smallint(5) unsigned NOT NULL default '0',
- PRIMARY KEY (group_id,user_id)
+DROP TABLE IF EXISTS `phpwebgallery_user_group`;
+CREATE TABLE `phpwebgallery_user_group` (
+ `user_id` smallint(5) unsigned NOT NULL default '0',
+ `group_id` smallint(5) unsigned NOT NULL default '0',
+ PRIMARY KEY (`group_id`,`user_id`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_users'
---
-
-DROP TABLE IF EXISTS phpwebgallery_users;
-CREATE TABLE phpwebgallery_users (
- id smallint(5) unsigned NOT NULL auto_increment,
- username varchar(20) binary NOT NULL default '',
- password varchar(255) NOT NULL default '',
- mail_address varchar(255) default NULL,
- nb_image_line tinyint(1) unsigned NOT NULL default '5',
- nb_line_page tinyint(3) unsigned NOT NULL default '3',
- status enum('admin','guest') NOT NULL default 'guest',
- language varchar(50) NOT NULL default 'english',
- maxwidth smallint(6) default NULL,
- maxheight smallint(6) default NULL,
- expand enum('true','false') NOT NULL default 'false',
- show_nb_comments enum('true','false') NOT NULL default 'false',
- recent_period tinyint(3) unsigned NOT NULL default '7',
- template varchar(255) NOT NULL default 'default',
- PRIMARY KEY (id),
- UNIQUE KEY users_ui1 (username)
+-- Table structure for table `phpwebgallery_users`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_users`;
+CREATE TABLE `phpwebgallery_users` (
+ `id` smallint(5) unsigned NOT NULL auto_increment,
+ `username` varchar(20) binary NOT NULL default '',
+ `password` varchar(32) default NULL,
+ `mail_address` varchar(255) default NULL,
+ `nb_image_line` tinyint(1) unsigned NOT NULL default '5',
+ `nb_line_page` tinyint(3) unsigned NOT NULL default '3',
+ `status` enum('admin','guest') NOT NULL default 'guest',
+ `language` varchar(50) NOT NULL default 'english',
+ `maxwidth` smallint(6) default NULL,
+ `maxheight` smallint(6) default NULL,
+ `expand` enum('true','false') NOT NULL default 'false',
+ `show_nb_comments` enum('true','false') NOT NULL default 'false',
+ `recent_period` tinyint(3) unsigned NOT NULL default '7',
+ `template` varchar(255) NOT NULL default 'default',
+ `last_feed_check` datetime default NULL,
+ `feed_id` varchar(50) binary default NULL,
+ `registration_date` datetime NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `users_ui1` (`username`)
) TYPE=MyISAM;
--
--- Table structure for table 'phpwebgallery_waiting'
+-- Table structure for table `phpwebgallery_waiting`
--
-DROP TABLE IF EXISTS phpwebgallery_waiting;
-CREATE TABLE phpwebgallery_waiting (
- id int(10) unsigned NOT NULL auto_increment,
- storage_category_id smallint(5) unsigned NOT NULL default '0',
- file varchar(255) NOT NULL default '',
- username varchar(255) NOT NULL default '',
- mail_address varchar(255) NOT NULL default '',
- date int(10) unsigned NOT NULL default '0',
- tn_ext char(3) default NULL,
- validated enum('true','false') NOT NULL default 'false',
- infos text,
- PRIMARY KEY (id)
+DROP TABLE IF EXISTS `phpwebgallery_waiting`;
+CREATE TABLE `phpwebgallery_waiting` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `storage_category_id` smallint(5) unsigned NOT NULL default '0',
+ `file` varchar(255) NOT NULL default '',
+ `username` varchar(255) NOT NULL default '',
+ `mail_address` varchar(255) NOT NULL default '',
+ `date` int(10) unsigned NOT NULL default '0',
+ `tn_ext` char(3) default NULL,
+ `validated` enum('true','false') NOT NULL default 'false',
+ `infos` text,
+ PRIMARY KEY (`id`)
) TYPE=MyISAM;
diff --git a/picture.php b/picture.php
index 7ac548088..e1d60d4a4 100644
--- a/picture.php
+++ b/picture.php
@@ -342,23 +342,34 @@ if ( isset( $_POST['content'] ) && !empty($_POST['content']) )
if ( mysql_num_rows( pwg_query( $query ) ) == 0
or $conf['anti-flood_time'] == 0 )
{
- $query = 'INSERT INTO '.COMMENTS_TABLE;
- $query.= ' (author,date,image_id,content,validated) VALUES (';
- $query.= "'".$author."'";
- $query.= ',NOW(),'.$_GET['image_id'];
- $query.= ",'".htmlspecialchars( $_POST['content'], ENT_QUOTES)."'";
- if ( !$conf['comments_validation'] or $user['status'] == 'admin' )
- {
- $query.= ",'true'";
+ list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+
+ $data = array();
+ $data{'author'} = $author;
+ $data{'date'} = $dbnow;
+ $data{'image_id'} = $_GET['image_id'];
+ $data{'content'} = htmlspecialchars( $_POST['content'], ENT_QUOTES);
+
+ if (!$conf['comments_validation'] or $user['status'] == 'admin')
+ {
+ $data{'validated'} = 'true';
+ $data{'validation_date'} = $dbnow;
}
else
{
- $query.= ",'false'";
+ $data{'validated'} = 'false';
}
- $query.= ');';
- pwg_query( $query );
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ $fields = array('author', 'date', 'image_id', 'content', 'validated',
+ 'validation_date');
+ mass_inserts(COMMENTS_TABLE, $fields, array($data));
+
// information message
$message = $lang['comment_added'];
+
+ if (!$conf['comments_validation'] or $user['status'] == 'admin')
+
if ( $conf['comments_validation'] and $user['status'] != 'admin' )
{
$message.= '<br />'.$lang['comment_to_validate'];
@@ -479,7 +490,8 @@ if ( !empty($picture['current']['date_creation']) )
}
// date of availability
-$availability_date = format_date($picture['current']['date_available']);
+$availability_date = format_date($picture['current']['date_available'],
+ 'mysql_datetime');
// size in pixels
if ($picture['current']['is_picture'])