source: extensions/Icy_Picture_Modify/include/functions_icy_picture_modify.inc.php @ 16495

Revision 16495, 13.6 KB checked in by icy, 7 years ago (diff)

Version 2.0.0, advance ACL . Code copied from git/master.

I could not use merging with git svn . Stupidly copy-&-paste ;)

Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24/*
25 * Check if the current image is editable by the current user. The input
26 * data $image_id and $user_id must be validated befored being used here.
27 * @return bool
28 * @author icy
29 *
30*/
31function icy_check_image_owner($image_id)
32{
33  global $user;
34  return $user['id'] == icy_get_user_owner_of_image($image_id);
35}
36
37/*
38 * Check if an image does exist
39 * @return bool
40 * @author icy
41 *
42*/
43function icy_image_exists($image_id)
44{
45  if (!preg_match(PATTERN_ID, $image_id))
46  {
47    return false;
48  }
49  $query = '
50SELECT COUNT(id)
51  FROM '.IMAGES_TABLE.'
52  WHERE id = '.$image_id.'
53;';
54  list($count) = pwg_db_fetch_row(pwg_query($query));
55  return ($count > 0 ? true: false);
56}
57
58/*
59 * Check if an image is editable by current user
60 * @icy_acl   access rules (provided by icy module)
61 * @image_id  identity of the image
62 * @return    boolean value
63 * @author    icy
64 */
65function icy_image_editable($image_id) {
66  return icy_acl("edit_image_of", $image_id, icy_get_user_owner_of_image($image_id));
67}
68
69function icy_image_deletable($image_id) {
70  return icy_acl("delete_image_of", $image_id, icy_get_user_owner_of_image($image_id));
71}
72
73
74/*
75 * Return list of visible/uploadable categories
76 * @author  icy
77 */
78function icy_acl_get_data($symbol) {
79  global $user, $ICY_ACL;
80
81  // Load ACL setting for this user
82  $this_user = $user['username'];
83  $my_acl = $ICY_ACL['default'];
84  if (array_key_exists($this_user, $ICY_ACL)) {
85    $my_acl = array_replace($my_acl, $ICY_ACL[$this_user]);
86  }
87
88  // Load ACL setting for the symbol
89  if (!array_key_exists($symbol, $my_acl)) {
90    return NULL;
91  }
92
93  return $my_acl[$symbol];
94}
95
96/*
97 *
98 * visible: upload, assosiate,...
99 * @symbol    must be ended by "_to" or "_from"
100 */
101function icy_acl_get_categories($symbol) {
102  global $user, $conf;
103
104  $all_categories = array();
105  $symbol_categories = array();
106  $symbol_settings = NULL;
107
108  // It's always EMPTY array for any kind of guests
109  if ($user['id'] == $conf['guest_id']) {
110    return $symbol_categories;
111  }
112
113  // check if $symbol is valid
114  if (!preg_match("/_(to|from)$/", $symbol)) {
115    return $symbol_categories;
116  }
117
118  $symbol_settings = icy_acl_get_data($symbol);
119  if (!$symbol_settings) {
120    return $symbol_categories;
121  }
122
123  // all known categories in the system
124  $query = 'SELECT id FROM '.CATEGORIES_TABLE.';';
125  $all_categories = array_unique(array_from_query($query, 'id'));
126  $forbidden_categories = explode(',',calculate_permissions($user['id'], $user['status']));
127
128  // ICY_ACL allows user to access all categories. In this case,
129  // the plugin 'community' plays an empty role (we just supress it)
130  if (icy_acl_symbol_data_wide_open($symbol_settings)) {
131    $symbol_categories = $all_categories;
132  }
133  elseif (is_array($symbol_settings)) {
134    $symbol_categories = array_values(array_intersect($symbol_settings, $all_categories));
135  }
136  else {
137    // not wide-open, not an-array. So waht!?
138    $symbol_settings = array();
139  }
140
141  // Make sure categories are in our sytem
142  // remove all forbidden categories from the list
143  if (in_array('sub', icy_acl_get_data($symbol))) {
144    // FIXME: (get_subcat_ids) requires a 0-based array
145    // FIXME: + array(0) is really a trick :) In Piwigo 2.4, (get_subcat_ids)
146    // FIXME: will generate NOTICE (SQL syntax error) if $symbol_categories is empty.
147    $symbol_categories = array_merge($symbol_categories, get_subcat_ids($symbol_categories + array(0)));
148  }
149  $symbol_categories = array_diff($symbol_categories, $forbidden_categories);
150  return array_values($symbol_categories);
151}
152/*
153 * FIXME: Test if current user is logged in
154 * FIXME: $guestowner must be provided explicitly
155 *
156 * Check if the current user has permission to do something
157 * @symbol     Action to be checked
158 * @guestdata  Object of the action
159 * @guestowner Owner of @guestdata
160 *
161 * There are two cases of @symbol:
162 * - _from/_to: action on an category
163 * - _of      : action on the author
164 * - others   : boolean flag
165 *
166 * There are three cases of symbol data
167 * - Array of categories (' identities)    [_from/_to]
168 *    $guestowner is simply ignored
169 * - Array of usernames (list of authors)  [_of]
170 *    $guestowner must be specified
171 * - Others: {"any", "owner", TRUE, FALSE} [others]
172 */
173 function icy_acl($symbol, $guestdata = NULL, $guestowner = NULL) {
174  global $user, $ICY_ACL, $conf;
175
176  // Load ACL setting for this user
177  $this_user = $user['id'];
178
179  if ($user['id'] == $conf['guest_id']) {
180    return FALSE;
181  }
182  elseif (is_admin()) {
183    return TRUE;
184  }
185
186  $symbol_settings = icy_acl_get_data($symbol);
187
188
189  if (! preg_match("/_(to|from|of)$/", $symbol)) {
190    return is_bool($symbol_settings) ? $symbol_settings: FALSE;
191  }
192
193  if (! is_array($symbol_settings) ) {
194    return FALSE;
195  } elseif (icy_acl_symbol_data_wide_open($symbol_settings)) {
196    return TRUE;
197  }
198
199  if (preg_match("/_(to|from)$/", $symbol)) {
200    return in_array($guestdata, $symbol_settings);
201  }
202  elseif (preg_match("/_of$/", $symbol)) {
203    $guestowner = icy_get_username_of($guestowner);
204    // Replace 'owner' by the $guestowner. For example
205    //  array('owner','ruby', 12) => array($guestowner, 'ruby', 12)
206    array_walk($symbol_settings,
207     create_function('&$val, $key',
208       'if ($val == "owner") {$val = "'.$user['username'].'";}'));
209    return in_array($guestowner, $symbol_settings);
210  }
211}
212
213function icy_acl_symbol_data_wide_open($symbol_data) {
214  return (is_array($symbol_data) and in_array("any", $symbol_data));
215}
216
217/*
218 * Write some logs for debugging
219 * @notes     Data will be written to STDERRR (default)
220 *            or to file `<ROOT>/_data/icy.log`
221 * @author    icy
222 */
223function icy_log($st, $stderr = FALSE) {
224  if ($stderr === TRUE) {
225    $_f_log = "php://stderr";
226  }
227  else {
228    $_f_log = PHPWG_ROOT_PATH.'_data/icy.log';
229  }
230
231  $_f_handle = fopen($_f_log, 'a');
232  if ($_f_handle) {
233    $new_line = "\n";
234    fwrite($_f_handle, "piwigo/icy_picture_modify: $st". $new_line );
235    if ($stderr !== TRUE) {
236      fclose($_f_handle);
237    }
238  }
239}
240
241/*
242 * Get UserId from their UserName
243 * @user_name   username as string
244 * @author      icy
245 */
246function icy_get_user_id_from_name($user_name) {
247  $user_name = pwg_db_real_escape_string($user_name);
248
249  $query = '
250SELECT id
251  FROM '.USERS_TABLE.'
252  WHERE username = "'.$user_name.'"
253  LIMIT 1
254;';
255
256  list($user_id) = pwg_db_fetch_row(pwg_query($query));
257
258  // FIXME: Is this the best way?
259  if ($user_id == NULL) $user_id = 0;
260
261  #! icy_log("icy_get_user_id_from_name: map userid <= username: $user_name <= $user_id");
262  return $user_id;
263}
264
265/*
266 * Rerturn the owner id of an image
267 * @author    icy
268 * @image_id  identity of the image
269 */
270function icy_get_user_owner_of_image($image_id) {
271  // FIXME: Clean this up!!!
272  if (!preg_match(PATTERN_ID, $image_id))
273    bad_request('invalid picture identifier');
274
275  $query = '
276SELECT added_by
277  FROM '.IMAGES_TABLE.'
278  WHERE id = '.$image_id.'
279  LIMIT 1
280;';
281
282  list($owner) = pwg_db_fetch_row(pwg_query($query));
283  #! icy_log("icy_get_user_owner_of_image: image_id, added_by = $image_id, $owner");
284  return $owner ? $owner : 0;
285}
286
287/*
288 * Return the username from user_id
289 */
290function icy_get_username_of($user_id) {
291  if (!preg_match(PATTERN_ID, $user_id))
292    bad_request('invalid user identifier');
293
294  $query = '
295SELECT username
296  FROM '.USERS_TABLE.'
297  WHERE id = '.$user_id.'
298  LIMIT 1
299;';
300
301  list($username) = pwg_db_fetch_row(pwg_query($query));
302  #! icy_log("icy_get_username_of: user_id, user_name = $user_id, $username");
303  return $username;
304}
305
306/*
307 * Check if a plugin is enabled
308 * @plugin_name   name of the plugin
309 * @author        icy
310 */
311function icy_plugin_enabled($plugin_name) {
312  $return = false;
313
314  $query = '
315SELECT count(id)
316  FROM '.PLUGINS_TABLE.'
317  WHERE id = "'.pwg_db_real_escape_string($plugin_name).'"
318  AND state="active"
319  LIMIT 1
320;';
321
322  list($count) = pwg_db_fetch_row(pwg_query($query));
323  $return = ($count == 1 ? true : false);
324
325  // we need the file ^^
326  if ($plugin_name == "community")
327    $return = $return
328                and is_file(PHPWG_PLUGINS_PATH
329                  .'community/include/functions_community.inc.php');
330
331  return $return;
332}
333
334/*
335 * Load ICY_ACL configuration from files
336 * @author   icy
337 */
338function icy_acl_load_configuration($force = FALSE) {
339  global $ICY_ACL;
340  $conf_path = PHPWG_ROOT_PATH.PWG_LOCAL_DIR.'config/icy_acl.zml';
341
342  if (($force == FALSE)
343      and isset($ICY_ACL['default'])
344      and isset($_SESSION['icy_picture_modify_acl_mtime'])
345      and ($_SESSION['icy_picture_modify_acl_mtime'] == filemtime($conf_path))) {
346    #! icy_log("icy_acl_load_configuration: configuration is up-to-date");
347    return FALSE;
348  }
349
350  $ICY_ACL = icy_zml_parser(<<<EOF
351default:
352  edit_image_of: owner
353  delete_image_of:
354  upload_image_to: sub
355  moderate_image: no
356  create_gallery_to: sub
357  associate_image_to:
358  present_image_to: sub
359EOF
360);
361
362  if (file_exists($conf_path)) {
363    #! icy_log("icy_acl_load_configuration: now loading ACL from $conf_path");
364    $ICY_ACL = array_replace($ICY_ACL, icy_zml_parser(file($conf_path)));
365    $_SESSION['icy_picture_modify_acl_mtime'] = filemtime($conf_path);
366  }
367
368  return TRUE;
369}
370
371/*
372 * Return array of variable from a `.zml` array  / string
373 * Syntax of the `.zml` file can be found in `doc/zaml.md`
374 * @author icy
375 */
376function icy_zml_parser($data) {
377  $acl = array();
378  $author = 'default';
379  $acl[$author] = array();
380
381  if (is_string($data)) {
382    $data = preg_split("/[\r\n]/", $data);
383  }
384
385  foreach($data as $line) {
386    # AUTHOR:
387    if (preg_match('/^([^[:space:]:]+):$/', $line, $gs)) {
388      $author = trim($gs[1]);
389      if (! array_key_exists($author, $acl)) {
390        $acl[$author] = array();
391      }
392      continue;
393    }
394
395    # AUTHOR: @REFERENCE
396    if (preg_match('/^([^[:space:]:]+):[[:space:]]+@([^[:space:]:]+)$/', $line, $gs)) {
397      $ref_author = trim($gs[2]);
398      if (!array_key_exists($ref_author, $acl)) {
399        continue;
400      }
401      $author = trim($gs[1]);
402      if (! array_key_exists($author, $acl)) {
403        $acl[$author] = array();
404      }
405      $acl[$author] = array_replace($acl[$ref_author], $acl[$author]);
406    }
407
408    # <two spaces> KEY: [VALUE]
409    if (preg_match('/  ([^:]+):(.*)$/', $line, $gs)) {
410      $key = $gs[1];
411      $val = trim($gs[2]);
412      if (in_array($val, array("","false","no"))) {
413        $val = FALSE;
414      }
415      elseif (in_array($val, array("yes", "true"))) {
416        $val = TRUE;
417      }
418      else {
419        $val = array_unique(preg_split("/[[:space:],:;]+/", $val));
420      }
421      $acl[$author][$key] = $val;
422    }
423
424    # Other line is ignored :)
425  }
426  return $acl;
427}
428
429/*
430 * Overwrite the ACl setings from community plugin
431 * @author: icy
432 */
433function icy_acl_fix_community($force = FALSE) {
434  global $user, $_SESSION;
435
436  if (!icy_plugin_enabled("community")) {
437    return TRUE;
438  }
439
440  require_once(PHPWG_PLUGINS_PATH.'community/include/functions_community.inc.php');
441
442  # <community_support>
443  $cache_key = community_get_cache_key();
444  if (!isset($cache_key))  {
445    $cache_key = community_update_cache_key();
446  }
447
448  if (($force == FALSE)
449      and isset($_SESSION['community_user_permissions'])
450      and isset($_SESSION['community_user_permissions']['icy_acl_fixed'])) {
451    #! icy_log("icy_fix_community_acl: the fix is up-to-date " . print_r($_SESSION['community_user_permissions'], true));
452    return TRUE;
453  }
454
455  # icy_log("WARNING: icy_fix_community_acl: the fix is out-of-date. will fix it again");
456  # </community_support>
457
458  $return = array(
459    'create_categories' => array(),
460    'upload_categories' => array(),
461    'permission_ids' => array(),
462    );
463
464  $return['upload_whole_gallery'] = icy_acl_symbol_data_wide_open(icy_acl_get_data("upload_image_to"));
465  $return['create_whole_gallery'] = icy_acl_symbol_data_wide_open(icy_acl_get_data("create_gallery_to"));
466  $return['upload_categories'] = icy_acl_get_categories("upload_image_to");
467  $return['create_categories'] = icy_acl_get_categories("create_gallery_to");
468  $return['permission_ids'] = array();
469  $return['icy_acl_fixed'] = 1;
470
471  $_SESSION['community_user_permissions'] = $return;
472  $_SESSION['community_cache_key'] = $cache_key;
473  $_SESSION['community_user_id'] = $user['id'];
474}
475
476
477if (!function_exists('array_replace')) {
478  function array_replace() {
479    $array=array();
480    $n=func_num_args();
481    while ($n-- >0) $array+=func_get_arg($n);
482    return $array;
483  }
484}
485?>
Note: See TracBrowser for help on using the repository browser.