bug 937 fixed: makes sure a user won't see the thumbnail of a photo that has a

higher privacy level than user privacy level.

For an acceptable solution at performance level, I have implemented a cache:
for a given user, each album has a representative_picture_id. This cache also
avoids to perform numerous "order by rand()" SQL queries which is the case
when $conf['allow_random_representative'] = true;


git-svn-id: http://piwigo.org/svn/trunk@8802 68402e56-0260-453c-a942-63ccdbb3a9ee
This commit is contained in:
plegall 2011-01-20 13:32:34 +00:00
parent d59827398d
commit dfb0b9d1fa
10 changed files with 246 additions and 78 deletions

View file

@ -882,17 +882,6 @@ function get_fs($path, $recursive = true)
return $fs;
}
/**
* stupidly returns the current microsecond since Unix epoch
*/
function micro_seconds()
{
$t1 = explode(' ', microtime());
$t2 = explode('.', $t1[0]);
$t2 = $t1[1].substr($t2[1], 0, 6);
return $t2;
}
/**
* synchronize base users list and related users list
*

View file

@ -27,90 +27,68 @@
*
*/
if ($page['section']=='recent_cats')
{
// $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE
$query = '
// $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE
$query = '
SELECT
c.*, nb_images, date_last, max_date_last, count_images, count_categories
FROM '.CATEGORIES_TABLE.' c INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.'
ON id = cat_id and user_id = '.$user['id'].'
WHERE date_last >= '.pwg_db_get_recent_period_expression($user['recent_period']).'
'.get_sql_condition_FandF
(
array
(
'visible_categories' => 'id',
),
'AND'
).'
;';
c.*,
user_representative_picture_id,
nb_images,
date_last,
max_date_last,
count_images,
count_categories
FROM '.CATEGORIES_TABLE.' c
INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' ucc ON id = cat_id AND user_id = '.$user['id'];
if ('recent_cats' == $page['section'])
{
$query.= '
WHERE date_last >= '.pwg_db_get_recent_period_expression($user['recent_period']);
}
else
{
// $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE
$query = '
SELECT
c.*, nb_images, date_last, max_date_last, count_images, count_categories
FROM '.CATEGORIES_TABLE.' c INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.'
ON id = cat_id and user_id = '.$user['id'].'
WHERE id_uppercat '.
(!isset($page['category']) ? 'is NULL' : '= '.$page['category']['id']).'
'.get_sql_condition_FandF
(
array
(
'visible_categories' => 'id',
),
'AND'
).'
ORDER BY rank
;';
$query.= '
WHERE id_uppercat '.(!isset($page['category']) ? 'is NULL' : '= '.$page['category']['id']);
}
$query.= get_sql_condition_FandF(
array(
'visible_categories' => 'id',
),
'AND'
);
if ('recent_cats' != $page['section'])
{
$query.= '
ORDER BY rank';
}
$query.= '
;';
$result = pwg_query($query);
$categories = array();
$category_ids = array();
$image_ids = array();
$user_representative_updates_for = array();
while ($row = pwg_db_fetch_assoc($result))
{
$row['is_child_date_last'] = @$row['max_date_last']>@$row['date_last'];
if (isset($row['representative_picture_id'])
and is_numeric($row['representative_picture_id']))
if (!empty($row['user_representative_picture_id']))
{
$image_id = $row['user_representative_picture_id'];
}
else if (!empty($row['representative_picture_id']))
{ // if a representative picture is set, it has priority
$image_id = $row['representative_picture_id'];
}
else if ($conf['allow_random_representative'])
{// searching a random representant among elements in sub-categories
if ($row['count_images']>0)
{
$query = '
SELECT image_id
FROM '.CATEGORIES_TABLE.' AS c INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic
ON ic.category_id = c.id';
$query.= '
WHERE (c.id='.$row['id'].' OR uppercats LIKE \''.$row['uppercats'].',%\')'
.get_sql_condition_FandF
(
array
(
'forbidden_categories' => 'c.id',
'visible_categories' => 'c.id',
'visible_images' => 'image_id'
),
"\n AND"
).'
ORDER BY '.DB_RANDOM_FUNCTION.'()
LIMIT 1
;';
$subresult = pwg_query($query);
if (pwg_db_num_rows($subresult) > 0)
{
list($image_id) = pwg_db_fetch_row($subresult);
}
}
{
// searching a random representant among elements in sub-categories
$image_id = get_random_image_in_category($row);
}
else
{ // searching a random representant among representant of sub-categories
@ -143,6 +121,11 @@ SELECT image_id
if (isset($image_id))
{
if ($row['user_representative_picture_id'] != $image_id)
{
$user_representative_updates_for[ $user['id'].'#'.$row['id'] ] = $image_id;
}
$row['representative_picture_id'] = $image_id;
array_push($image_ids, $image_id);
array_push($categories, $row);
@ -193,17 +176,98 @@ if ($page['section']=='recent_cats')
if (count($categories) > 0)
{
$thumbnail_src_of = array();
$new_image_ids = array();
$query = '
SELECT id, path, tn_ext
SELECT id, path, tn_ext, level
FROM '.IMAGES_TABLE.'
WHERE id IN ('.implode(',', $image_ids).')
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$thumbnail_src_of[$row['id']] = get_thumbnail_url($row);
if ($row['level'] <= $user['level'])
{
$thumbnail_src_of[$row['id']] = get_thumbnail_url($row);
}
else
{
// problem: we must not display the thumbnail of a photo which has a
// higher privacy level than user privacy level
//
// * what is the represented category?
// * find a random photo matching user permissions
// * register it at user_representative_picture_id
// * set it as the representative_picture_id for the category
foreach ($categories as &$category)
{
if ($row['id'] == $category['representative_picture_id'])
{
if ($category['count_images']>0)
{
// searching a random representant among elements in sub-categories
$image_id = get_random_image_in_category($category);
if (isset($image_id))
{
if (!in_array($image_id, $image_ids))
{
array_push($new_image_ids, $image_id);
}
$user_representative_updates_for[ $user['id'].'#'.$category['id'] ] = $image_id;
$category['representative_picture_id'] = $image_id;
}
}
}
}
unset($category);
}
}
if (count($new_image_ids) > 0)
{
$query = '
SELECT id, path, tn_ext
FROM '.IMAGES_TABLE.'
WHERE id IN ('.implode(',', $new_image_ids).')
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$thumbnail_src_of[$row['id']] = get_thumbnail_url($row);
}
}
}
if (count($user_representative_updates_for))
{
$updates = array();
foreach ($user_representative_updates_for as $user_cat => $image_id)
{
list($user_id, $cat_id) = explode('#', $user_cat);
array_push(
$updates,
array(
'user_id' => $user_id,
'cat_id' => $cat_id,
'user_representative_picture_id' => $image_id,
)
);
}
mass_updates(
USER_CACHE_CATEGORIES_TABLE,
array(
'primary' => array('user_id', 'cat_id'),
'update' => array('user_representative_picture_id')
),
$updates
);
}
if (count($categories) > 0)

View file

@ -33,6 +33,17 @@ include_once( PHPWG_ROOT_PATH .'include/functions_plugins.inc.php' );
//----------------------------------------------------------- generic functions
/**
* stupidly returns the current microsecond since Unix epoch
*/
function micro_seconds()
{
$t1 = explode(' ', microtime());
$t2 = explode('.', $t1[0]);
$t2 = $t1[1].substr($t2[1], 0, 6);
return $t2;
}
// The function get_moment returns a float value coresponding to the number
// of seconds since the unix epoch (1st January 1970) and the microseconds
// are precised : e.g. 1052343429.89276600

View file

@ -495,4 +495,42 @@ function get_display_images_count($cat_nb_images, $cat_count_images, $cat_count_
return $display_text;
}
/**
* Find a random photo among all photos below a given album in the tree (not
* only photo directly associated to the album but also to sub-albums)
*
* we need $category['uppercats'], $category['id'], $category['count_images']
*/
function get_random_image_in_category($category)
{
$image_id = null;
if ($category['count_images']>0)
{
$query = '
SELECT image_id
FROM '.CATEGORIES_TABLE.' AS c
INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.category_id = c.id
WHERE (c.id='.$category['id'].' OR uppercats LIKE \''.$category['uppercats'].',%\')'
.get_sql_condition_FandF
(
array
(
'forbidden_categories' => 'c.id',
'visible_categories' => 'c.id',
'visible_images' => 'image_id',
),
"\n AND"
).'
ORDER BY '.DB_RANDOM_FUNCTION.'()
LIMIT 1
;';
$result = pwg_query($query);
if (pwg_db_num_rows($result) > 0)
{
list($image_id) = pwg_db_fetch_row($result);
}
}
return $image_id;
}
?>

View file

@ -0,0 +1,53 @@
<?php
// +-----------------------------------------------------------------------+
// | Piwigo - a PHP based photo gallery |
// +-----------------------------------------------------------------------+
// | Copyright(C) 2008-2011 Piwigo Team http://piwigo.org |
// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
// +-----------------------------------------------------------------------+
// | 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. |
// +-----------------------------------------------------------------------+
if (!defined('PHPWG_ROOT_PATH'))
{
die('Hacking attempt!');
}
$upgrade_description = 'New colum user_cache_categories.user_representative_picture_id';
// Add column
$query = 'ALTER TABLE '.USER_CACHE_CATEGORIES_TABLE.' ADD COLUMN ';
if ('mysql' == $conf['dblayer'])
{
$query.= ' `user_representative_picture_id` mediumint(8) unsigned default NULL';
}
if (in_array($conf['dblayer'], array('pgsql', 'sqlite', 'pdo-sqlite')))
{
$query.= ' "user_representative_picture_id" INTEGER';
}
$query.= ';';
pwg_query($query);
echo
"\n"
. $upgrade_description
."\n"
;
?>

View file

@ -368,6 +368,7 @@ CREATE TABLE `piwigo_user_cache_categories` (
`nb_images` mediumint(8) unsigned NOT NULL default '0',
`count_images` mediumint(8) unsigned default '0',
`count_categories` mediumint(8) unsigned default '0',
`user_representative_picture_id` mediumint(8) unsigned default NULL,
PRIMARY KEY (`user_id`,`cat_id`)
) TYPE=MyISAM;

View file

@ -425,6 +425,7 @@ CREATE TABLE piwigo_user_cache_categories
"nb_images" INTEGER default 0 NOT NULL,
"count_images" INTEGER default 0,
"count_categories" INTEGER default 0,
"user_representative_picture_id" INTEGER,
PRIMARY KEY ("user_id","cat_id")
);

View file

@ -514,6 +514,7 @@ CREATE TABLE "piwigo_user_cache_categories"
"nb_images" INTEGER default 0 NOT NULL,
"count_images" INTEGER default 0,
"count_categories" INTEGER default 0,
"user_representative_picture_id" INTEGER,
PRIMARY KEY ("user_id","cat_id")
);

View file

@ -425,6 +425,7 @@ CREATE TABLE piwigo_user_cache_categories
"nb_images" INTEGER default 0 NOT NULL,
"count_images" INTEGER default 0,
"count_categories" INTEGER default 0,
"user_representative_picture_id" INTEGER,
PRIMARY KEY ("user_id","cat_id")
);
@ -535,3 +536,4 @@ CREATE TABLE piwigo_comments
CREATE INDEX "comments_i2" ON "piwigo_comments" ("validation_date");
CREATE INDEX "comments_i1" ON "piwigo_comments" ("image_id");

View file

@ -282,6 +282,14 @@ DELETE FROM '.FAVORITES_TABLE.'
UPDATE '.CATEGORIES_TABLE.'
SET representative_picture_id = '.$page['image_id'].'
WHERE id = '.$page['category']['id'].'
;';
pwg_query($query);
$query = '
UPDATE '.USER_CACHE_CATEGORIES_TABLE.'
SET user_representative_picture_id = NULL
WHERE user_id = '.$user['id'].'
AND cat_id = '.$page['category']['id'].'
;';
pwg_query($query);
}