Subversion Repositories php_users

Rev

Rev 18 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
16 rodolico 1
<?php
2
 
3
require_once( 'UsersDataSourceMySQLi.class.php' );
4
 
5
/*
6
   Copyright (c) 2021, Daily Data, Inc. Redistribution and use in 
7
   source and binary forms, with or without modification, are permitted
8
   provided that the following conditions are met:
9
 
10
   * Redistributions of source code must retain the above copyright 
11
     notice, this list of conditions and the following disclaimer.
12
   * Redistributions in binary form must reproduce the above copyright 
13
     notice, this list of conditions and the following disclaimer in the 
14
     documentation and/or other materials provided with the distribution.
15
 
16
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
17
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
22
   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 
28
*/
29
 
30
/*
31
 * UsersDataSourceMySQLi.class.php
32
 * 
33
 * Authors: R. W. Rodolico
34
 * 
35
 */
36
 
37
/**
38
 * usersPermissionsDataSource class
39
 * 
40
 * usersPermissionsDataSource provides the data access capabilities for
41
 * the usersPermissions class
42
 * class.
43
 * 
44
 * To build a data access class for UsersPermissions, the following 5
45
 * methods must exist.
46
 * getPassword(username)
47
 * getRecord(username)
48
 * getAllUsers()
49
 * getARecord
50
 * update
51
 * 
52
 * Additionally, where appropriate, the following function is useful
53
 * buildTable()
54
 * 
55
 * This particular instance provides an interface to MySQL using
56
 * the mysqli libraries.
57
 * 
58
 * Create an instance of this, then pass the variable to several Users
59
 * calls.
60
 * 
61
 * @author R. W. Rodolico <rodo@unixservertech.com>
62
 * 
63
 * @version 0.9.0 (beta)
64
 * @copyright 2021 Daily Data, Inc.
65
 * 
66
 */
67
 
68
class usersPermissionsDataSource extends usersDataSource {
69
 
70
      /**
20 rodolico 71
       * extends usersDataSource
16 rodolico 72
       * 
20 rodolico 73
       * Adds the new fields needed for permissions. First, creates array
74
       * $permissions, then does a recursive merge into 
75
       * usersDataSource::$configuration. 
76
       * NOTE: we must merge this before we merge in $dbDef so the
77
       * developer can modify permissions also
16 rodolico 78
       * 
79
       * @param mysqli $dbConnection Existing mysqli database connection
80
       * @param string[] $dbDef Array to be merged with $configuration
81
       * @param string[] $dbLoginInfo Array containing username, hostname, etc.. to make mysqli connection_aborted
82
       * 
83
       * @return null
84
       * 
85
       */
86
      public function __construct( $dbConnection = null, $dbDef = array(), $dbLoginInfo = array() ) {
87
 
20 rodolico 88
      $permissions = array(
89
         'tables' => array(
90
            'permissions categories' => array(
91
               'table'     => '_permissions_categories',   // table name for user records
92
               'id'        => '_permission_category_id', // ID column name
93
               'display'   => array(      // fields which are displayed to select
94
                  'description'
95
                  ),         
96
               'fields' => array(
97
                  'name'  => array(
98
                        'dbColumn'     => 'name',
99
                        'type'         => 'varchar',
100
                        'size'         => 16,
101
                        'required'     => true
102
                        )
103
                  ),
104
               ), // permissions categories table
105
            'permissions' => array(
106
               'table'     => '_permissions',   // table name for user records
107
               'id'        => '_permission_id', // ID column name
108
               'display'   => array(      // fields which are displayed to select
109
                  'description'
110
                  ),         
111
               'fields' => array(
112
                  'name'  => array(
113
                        'dbColumn'     => 'name',
114
                        'type'         => 'varchar',
115
                        'size'         => 16,
116
                        'required'     => true
117
                        ),
118
                  'description'  => array(
119
                        'dbColumn'     => 'description',
120
                        'type'         => 'varchar',
121
                        'size'         => 64,
122
                        'required'     => true
123
                        ),
124
                  'permission category' => array(
125
                        'dbColumn'     => '_permission_category_id',
126
                        'type'         => 'int unsigned',
127
                        'required'     => true,
128
                        ),
129
                  'default'  => array(
130
                        'dbColumn'     => 'default_value',
131
                        'type'         => 'boolean',
132
                        'required'     => true
133
                        ),
134
               )
135
            ), // permissions table
136
            'users permissions' => array(
137
               'table'     => '_users_permissions',   // table name for user records
138
               'id'        => '_user_permission_id', // ID column name
139
               'fields' => array(
140
                  'user_id'  => array(
141
                        'dbColumn'     => '_user_id',
142
                        'type'         => 'int unsigned',
143
                        'required'     => true,
144
                        'references'   => 'users',
145
                        ),
146
                  'permission_id'  => array(
147
                        'dbColumn'     => '_permission_id',
148
                        'type'         => 'int unsigned',
149
                        'required'     => true,
150
                        'references'   => 'permissions',
151
                        ),
152
                  'value'  => array(
153
                        'dbColumn'     => 'value',
154
                        'type'         => 'boolean',
155
                        'required'     => true,
156
                        ),
157
               )
158
            ) // users permissions table
159
         ),
160
         'views' => array(
161
            'users permissions' => array( 
162
               'name' => '_view_users_permissions' 
163
               )
164
            ) // users permissions view
165
         );
166
         $this->configuration = array_merge_recursive( $this->configuration, $permissions );
16 rodolico 167
 
168
         parent::__construct( $dbConnection, $dbDef, $dbLoginInfo );
169
 
170
      } // constructor
171
 
172
      /**
173
       * Function will build tables when called
174
       * 
175
       * Calls parent::buildTable first, then creates a view. The query
176
       * for the view is created using sprintf so we can allow the developers
177
       * to modify the table names, etc...
178
       * 
179
       */
180
      public function buildTable() {
181
         parent::buildTable();
182
         // add a unique constraint on users permissions for user id and permission id
20 rodolico 183
         // we do it this way since there is no way to do it automagically
184
         // without rewriting the $configuration code
16 rodolico 185
         $query = sprintf( 'alter table %s add unique key (%s,%s)',
186
            $this->configuration['tables']['users permissions']['table'],
187
            $this->configuration['tables']['users permissions']['fields']['user_id']['dbColumn'],
188
            $this->configuration['tables']['users permissions']['fields']['permission_id']['dbColumn']
189
            );
190
         $this->doSQL( $query );
191
         // create a convenience view
192
         $query = sprintf( "create or replace view %s as 
193
            select 
194
               %s.%s users_id,      /* users id */
195
               %s.%s user,          /* users login */
196
               %s.%s permission_id, /* permissions id */
197
               %s.%s permission,    /* permissions name */
198
               %s.%s description,   /* permissions description */
199
               %s.%s category,      /* permissions_categories name */
200
               ifnull(%s.%s,0)  value /* actual value */
201
            from 
202
               %s /* users */
203
               join %s   /* permissions (permissions_id */
204
               left join %s using (%s,%s)   /* users_permissions (users_id) */
205
               join %s using (%s)   /* permissions_categories( permissions_categories_id) */",
206
            $this->configuration['views']['users permissions']['name'],
207
            $this->configuration['tables']['users']['table'],
208
            $this->configuration['tables']['users']['id'],
209
            $this->configuration['tables']['users']['table'],
210
            $this->configuration['tables']['users']['fields']['login']['dbColumn'],
211
            $this->configuration['tables']['permissions']['table'],
212
            $this->configuration['tables']['permissions']['id'],
213
            $this->configuration['tables']['permissions']['table'],
214
            $this->configuration['tables']['permissions']['fields']['name']['dbColumn'],
215
            $this->configuration['tables']['permissions']['table'],
216
            $this->configuration['tables']['permissions']['fields']['description']['dbColumn'],
217
            $this->configuration['tables']['permissions categories']['table'],
218
            $this->configuration['tables']['permissions categories']['fields']['name']['dbColumn'],
219
            $this->configuration['tables']['users permissions']['table'],
220
            $this->configuration['tables']['users permissions']['fields']['value']['dbColumn'],
221
            $this->configuration['tables']['users']['table'],
222
            $this->configuration['tables']['permissions']['table'],
223
            $this->configuration['tables']['users permissions']['table'],
224
            $this->configuration['tables']['users']['id'],
225
            $this->configuration['tables']['permissions']['id'],
226
            $this->configuration['tables']['permissions categories']['table'],
227
            $this->configuration['tables']['permissions categories']['id']
228
          );
229
         $this->doSQL( $query );
230
      }
231
 
232
      /**
233
       * Adds a permission to the permissions table
234
       * 
235
       * This simply adds a permission to the permissions table, adding the 
236
       * category if it doesn't exist already.
237
       * 
238
       * @parameter string $category Category to place the permission into
239
       * @parameter string $name The short name of the permission
240
       * @parameter string $description The long (display) name for the permission
241
       * @parameter boolean $defaultValue The default value for the permission
242
       */
243
      public function addPermission ( $category, $name, $description, $defaultValue = 0 ) {
244
         $categoryID = $this->getAField( 
245
               $this->configuration['tables']['permissions categories']['table'],
246
               $this->configuration['tables']['permissions categories']['id'],
247
               $this->configuration['tables']['permissions categories']['fields']['name']['dbColumn'],
248
               $category
249
            );
250
         if ( ! $categoryID ) { // we did not find the category, so add it
251
            $this->doSQL( sprintf( "insert into %s ( %s ) values ( %s )",
252
               $this->configuration['tables']['permissions categories']['table'],
253
               $this->configuration['tables']['permissions categories']['fields']['name']['dbColumn'],
254
               $this->escapeString($category)
255
               )
256
            );
257
            $categoryID = $this->getAField( 
258
                  $this->configuration['tables']['permissions categories']['table'],
259
                  $this->configuration['tables']['permissions categories']['id'],
260
                  $this->configuration['tables']['permissions categories']['fields']['name']['dbColumn'],
261
                  $category
262
               );
263
         } // if category not found
264
         $query = sprintf( "insert into %s ( %s,%s,%s,%s ) values ( %s,%s,%s,%s )",
265
               $this->configuration['tables']['permissions']['table'],
266
               $this->configuration['tables']['permissions']['fields']['name']['dbColumn'],
267
               $this->configuration['tables']['permissions']['fields']['description']['dbColumn'],
268
               $this->configuration['tables']['permissions']['fields']['permission category']['dbColumn'],
269
               $this->configuration['tables']['permissions']['fields']['default']['dbColumn'],
270
               $this->escapeString($name),
271
               $this->escapeString($description),
272
               $this->escapeString($categoryID),
273
               $defaultValue
274
         );
275
         $this->doSQL( $query );
276
         $permissionsID = $this->getAField( 
277
               $this->configuration['tables']['permissions']['table'],
278
               $this->configuration['tables']['permissions']['id'],
279
               $this->configuration['tables']['permissions']['fields']['name']['dbColumn'],
280
               $this->escapeString($name)
281
            );
282
      } // addPermission
283
 
284
      /**
285
       * Sets any unset user permissions
286
       * 
287
       * This will set any missing permissions which have a true value in the
288
       * users permissions join table. This will NOT modify any existing records
289
       * but will add new records if they do not exist in the table.
290
       * 
291
       * @parameters string $user_id If set, will limit to only one user (not implemented)
292
       */
293
      public function setUsersPermissions ( $user_id = null ) {
294
         $query = sprintf(
295
            "insert into %s (%s,%s,%s)
296
            select
297
               %s.%s,
298
               %s.%s,
299
               %s.%s
300
            from
301
               %s
302
               join %s
303
            where
304
               %s.%s
305
               and not exists
306
                  (
307
                     select 1
308
                     from %s
309
                     where
310
                        %s.%s = %s.%s
311
                        and %s.%s = %s.%s
312
                  )",
313
            $this->configuration['tables']['users permissions']['table'],
314
            $this->configuration['tables']['users permissions']['fields']['user_id']['dbColumn'],
315
            $this->configuration['tables']['users permissions']['fields']['permission_id']['dbColumn'],
316
            $this->configuration['tables']['users permissions']['fields']['value']['dbColumn'],
317
            $this->configuration['tables']['users']['table'],
318
            $this->configuration['tables']['users']['id'],
319
            $this->configuration['tables']['permissions']['table'],
320
            $this->configuration['tables']['permissions']['id'],
321
            $this->configuration['tables']['permissions']['table'],
322
            $this->configuration['tables']['permissions']['fields']['default']['dbColumn'],
323
            $this->configuration['tables']['users']['table'],
324
            $this->configuration['tables']['permissions']['table'],
325
            $this->configuration['tables']['permissions']['table'],
326
            $this->configuration['tables']['permissions']['fields']['default']['dbColumn'],
327
            $this->configuration['tables']['users permissions']['table'],
328
            $this->configuration['tables']['users permissions']['table'],
329
            $this->configuration['tables']['users permissions']['fields']['user_id']['dbColumn'],
330
            $this->configuration['tables']['users']['table'],
331
            $this->configuration['tables']['users']['id'],
332
            $this->configuration['tables']['users permissions']['table'],
333
            $this->configuration['tables']['users permissions']['fields']['permission_id']['dbColumn'],
334
            $this->configuration['tables']['permissions']['table'],
335
            $this->configuration['tables']['permissions']['id']
336
            );
337
            $this->doSQL($query, true );
338
      } // setUsersPermissions
17 rodolico 339
 
340
      public function getARecord( $whereFields, $fieldList = null ) {
341
         $id = isset( $whereFields['id'] ) ? $whereFields['id'] : null;
342
         $result = parent::getARecord( $whereFields, $fieldList );
343
         if ( $result && isset( $id ) ) {
344
            $result['permissions'] = $this->getPermissions( $id );
345
         }
346
         return $result;
347
      }
348
 
20 rodolico 349
 
350
      /**
351
       * Gets permissions for one user
352
       * 
353
       * NOTE: if $id is -1, indicating a new user, simply retrieves all
354
       * permissions from the permissions table with the default value
355
       * 
356
       * WARNING: this uses the view, which is not as flexible as the
357
       * tables as far as modifying programmatically
358
       * 
359
       * The return value is an associative array, where the key is
360
       * the permission (short) name and the value is 0 or 1 (boolean
361
       * true/false)
362
       * 
363
       * @param integer $id the user id of the record we want.
364
       * 
365
       * @returns string[] Array of associative arrays with all data
366
       */
17 rodolico 367
      public function getPermissions ( $id ) {
20 rodolico 368
         $query = '';
369
         if ( $id == -1 ) {
370
            $query = "select name permission,default_value value from _permissions";
371
         } else {
372
            $query = "select permission,value from _view_users_permissions where users_id = $id";
373
         }
17 rodolico 374
         $results = $this->doSQL( $query );
375
         $values = $results->fetch_all(MYSQLI_ASSOC);
376
         return array_column( $values, 'value', 'permission' );
377
      }
20 rodolico 378
 
379
      /**
380
       * Gets all permissions with names, group names, etc... from database
381
       * 
382
       * NOTE: if $id is -1, indicating a new user, simply retrieves all
383
       * permissions from the permissions table with the default value
384
       * 
385
       * WARNING: this uses the view, which is not as flexible as the
386
       * tables as far as modifying programmatically
387
       * 
388
       * @param integer $id the user id of the record we want.
389
       * @returns string[] Array of associative arrays with all data
390
       */
17 rodolico 391
      public function getFullPermissions( $id ) {
20 rodolico 392
         $query = '';
393
         if ( $id == -1 ) {
394
            $query = "select _permission_id permission_id, _permissions.name permission, description, _permissions_categories.name category, default_value value from _permissions join _permissions_categories using (_permission_category_id)";
395
         } else {
396
            $query = "select permission_id,permission,description,category,value from _view_users_permissions where users_id = $id order by category,description";
397
         }
17 rodolico 398
         $results = $this->doSQL( $query );
399
         return $results->fetch_all(MYSQLI_ASSOC);
400
      }
401
 
20 rodolico 402
      /**
403
       * Adds/Updates a group of permissions for a user
404
       * 
405
       * @param integer $userID The user ID to update
406
       * @param string[] $newData An array where the key is the field name and the value is the new value to use
407
       */
408
      public function updatePermissions ( $userID, $newData ) {
17 rodolico 409
         $query = '';
410
         foreach ( $newData as $key => $value ) {
20 rodolico 411
            $query = sprintf(
412
                  "insert into %s 
413
                     ( %s,%s,%s ) 
414
                     select %s, %s, %s 
415
                     from %s
416
                     where %s = %s 
417
                  on duplicate key update %s = %s",
418
               $this->configuration['tables']['users permissions']['table'],
419
               $this->configuration['tables']['users permissions']['fields']['user_id']['dbColumn'],
420
               $this->configuration['tables']['users permissions']['fields']['permission_id']['dbColumn'],
421
               $this->configuration['tables']['users permissions']['fields']['value']['dbColumn'],
422
               $userID,
423
               $this->configuration['tables']['permissions']['id'],
424
               $value,
425
               $this->configuration['tables']['table'],
426
               $this->configuration['tables']['permissions']['fields']['name']['dbColumn'],
427
               $this->excapeString($key),
428
               $this->configuration['tables']['users permissions']['fields']['value']['dbColumn'],
429
               $value
430
            );
431
            //$query = "insert into _users_permissions ( _user_id,_permission_id,value) select $userID, _permission_id, $value from _permissions where name = '$key' on duplicate key update value = $value";
18 rodolico 432
            $this->doSQL( $query, 'In updatePermissions' );
17 rodolico 433
         }
434
      } // update
16 rodolico 435
 
436
}
437
 
438
?>